blob: 07c811b42256e2792d8ecf842316f469fd7e4e37 [file] [log] [blame]
// Copyright 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/layer.h"
#include "cc/animation.h"
#include "cc/animation_events.h"
#include "cc/layer_animation_controller.h"
#include "cc/layer_impl.h"
#include "cc/layer_tree_host.h"
#include "cc/layer_tree_impl.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebAnimationDelegate.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebLayerScrollClient.h"
#include "third_party/WebKit/Source/Platform/chromium/public/WebSize.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/rect_conversions.h"
namespace cc {
static int s_nextLayerId = 1;
scoped_refptr<Layer> Layer::create()
{
return make_scoped_refptr(new Layer());
}
Layer::Layer()
: m_needsDisplay(false)
, m_stackingOrderChanged(false)
, m_layerId(s_nextLayerId++)
, m_ignoreSetNeedsCommit(false)
, m_parent(0)
, m_layerTreeHost(0)
, m_scrollable(false)
, m_shouldScrollOnMainThread(false)
, m_haveWheelEventHandlers(false)
, m_anchorPoint(0.5, 0.5)
, m_backgroundColor(0)
, m_opacity(1.0)
, m_anchorPointZ(0)
, m_isContainerForFixedPositionLayers(false)
, m_fixedToContainerLayer(false)
, m_isDrawable(false)
, m_masksToBounds(false)
, m_contentsOpaque(false)
, m_doubleSided(true)
, m_preserves3D(false)
, m_useParentBackfaceVisibility(false)
, m_drawCheckerboardForMissingTiles(false)
, m_forceRenderSurface(false)
, m_replicaLayer(0)
, m_rasterScale(1.0)
, m_automaticallyComputeRasterScale(false)
, m_boundsContainPageScale(false)
, m_layerAnimationDelegate(0)
, m_layerScrollClient(0)
{
if (m_layerId < 0) {
s_nextLayerId = 1;
m_layerId = s_nextLayerId++;
}
m_layerAnimationController = LayerAnimationController::create(m_layerId);
m_layerAnimationController->addObserver(this);
addLayerAnimationEventObserver(m_layerAnimationController.get());
}
Layer::~Layer()
{
// Our parent should be holding a reference to us so there should be no
// way for us to be destroyed while we still have a parent.
DCHECK(!parent());
m_layerAnimationController->removeObserver(this);
// Remove the parent reference from all children and dependents.
removeAllChildren();
if (m_maskLayer) {
DCHECK_EQ(this, m_maskLayer->parent());
m_maskLayer->removeFromParent();
}
if (m_replicaLayer) {
DCHECK_EQ(this, m_replicaLayer->parent());
m_replicaLayer->removeFromParent();
}
}
void Layer::setLayerTreeHost(LayerTreeHost* host)
{
if (m_layerTreeHost == host)
return;
m_layerTreeHost = host;
for (size_t i = 0; i < m_children.size(); ++i)
m_children[i]->setLayerTreeHost(host);
if (m_maskLayer)
m_maskLayer->setLayerTreeHost(host);
if (m_replicaLayer)
m_replicaLayer->setLayerTreeHost(host);
m_layerAnimationController->setAnimationRegistrar(host ? host->animationRegistrar() : 0);
if (host && m_layerAnimationController->hasAnyAnimation())
host->setNeedsCommit();
if (host && (!m_filters.isEmpty() || !m_backgroundFilters.isEmpty() || m_filter))
m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setNeedsCommit()
{
if (m_ignoreSetNeedsCommit)
return;
if (m_layerTreeHost)
m_layerTreeHost->setNeedsCommit();
}
void Layer::setNeedsFullTreeSync()
{
if (m_layerTreeHost)
m_layerTreeHost->setNeedsFullTreeSync();
}
gfx::Rect Layer::layerRectToContentRect(const gfx::RectF& layerRect) const
{
gfx::RectF contentRect = gfx::ScaleRect(layerRect, contentsScaleX(), contentsScaleY());
// Intersect with content rect to avoid the extra pixel because for some
// values x and y, ceil((x / y) * y) may be x + 1.
contentRect.Intersect(gfx::Rect(gfx::Point(), contentBounds()));
return gfx::ToEnclosingRect(contentRect);
}
bool Layer::blocksPendingCommit() const
{
return false;
}
bool Layer::canClipSelf() const
{
return false;
}
bool Layer::blocksPendingCommitRecursive() const
{
if (blocksPendingCommit())
return true;
if (maskLayer() && maskLayer()->blocksPendingCommitRecursive())
return true;
if (replicaLayer() && replicaLayer()->blocksPendingCommitRecursive())
return true;
for (size_t i = 0; i < m_children.size(); ++i)
{
if (m_children[i]->blocksPendingCommitRecursive())
return true;
}
return false;
}
void Layer::setParent(Layer* layer)
{
DCHECK(!layer || !layer->hasAncestor(this));
m_parent = layer;
setLayerTreeHost(m_parent ? m_parent->layerTreeHost() : 0);
forceAutomaticRasterScaleToBeRecomputed();
if (m_maskLayer)
m_maskLayer->forceAutomaticRasterScaleToBeRecomputed();
if (m_replicaLayer && m_replicaLayer->m_maskLayer)
m_replicaLayer->m_maskLayer->forceAutomaticRasterScaleToBeRecomputed();
}
bool Layer::hasAncestor(Layer* ancestor) const
{
for (const Layer* layer = parent(); layer; layer = layer->parent()) {
if (layer == ancestor)
return true;
}
return false;
}
void Layer::addChild(scoped_refptr<Layer> child)
{
insertChild(child, m_children.size());
}
void Layer::insertChild(scoped_refptr<Layer> child, size_t index)
{
child->removeFromParent();
child->setParent(this);
child->m_stackingOrderChanged = true;
index = std::min(index, m_children.size());
m_children.insert(m_children.begin() + index, child);
setNeedsFullTreeSync();
}
void Layer::removeFromParent()
{
if (m_parent)
m_parent->removeChildOrDependent(this);
}
void Layer::removeChildOrDependent(Layer* child)
{
if (m_maskLayer == child) {
m_maskLayer->setParent(NULL);
m_maskLayer = NULL;
setNeedsFullTreeSync();
return;
}
if (m_replicaLayer == child) {
m_replicaLayer->setParent(NULL);
m_replicaLayer = NULL;
setNeedsFullTreeSync();
return;
}
for (LayerList::iterator iter = m_children.begin(); iter != m_children.end(); ++iter)
{
if (*iter != child)
continue;
child->setParent(0);
m_children.erase(iter);
setNeedsFullTreeSync();
return;
}
}
void Layer::replaceChild(Layer* reference, scoped_refptr<Layer> newLayer)
{
DCHECK(reference);
DCHECK_EQ(reference->parent(), this);
if (reference == newLayer)
return;
int referenceIndex = indexOfChild(reference);
if (referenceIndex == -1) {
NOTREACHED();
return;
}
reference->removeFromParent();
if (newLayer) {
newLayer->removeFromParent();
insertChild(newLayer, referenceIndex);
}
}
int Layer::indexOfChild(const Layer* reference)
{
for (size_t i = 0; i < m_children.size(); ++i) {
if (m_children[i] == reference)
return i;
}
return -1;
}
void Layer::setBounds(const gfx::Size& size)
{
if (bounds() == size)
return;
bool firstResize = bounds().IsEmpty() && !size.IsEmpty();
m_bounds = size;
if (firstResize)
setNeedsDisplay();
else
setNeedsCommit();
}
Layer* Layer::rootLayer()
{
Layer* layer = this;
while (layer->parent())
layer = layer->parent();
return layer;
}
void Layer::removeAllChildren()
{
while (m_children.size()) {
Layer* layer = m_children[0].get();
DCHECK_EQ(this, layer->parent());
layer->removeFromParent();
}
}
void Layer::setChildren(const LayerList& children)
{
if (children == m_children)
return;
removeAllChildren();
for (size_t i = 0; i < children.size(); ++i)
addChild(children[i]);
}
Layer* Layer::childAt(size_t index)
{
DCHECK_LT(index, m_children.size());
return m_children[index].get();
}
void Layer::setAnchorPoint(const gfx::PointF& anchorPoint)
{
if (m_anchorPoint == anchorPoint)
return;
m_anchorPoint = anchorPoint;
setNeedsCommit();
}
void Layer::setAnchorPointZ(float anchorPointZ)
{
if (m_anchorPointZ == anchorPointZ)
return;
m_anchorPointZ = anchorPointZ;
setNeedsCommit();
}
void Layer::setBackgroundColor(SkColor backgroundColor)
{
if (m_backgroundColor == backgroundColor)
return;
m_backgroundColor = backgroundColor;
setNeedsCommit();
}
void Layer::calculateContentsScale(
float idealContentsScale,
bool animatingTransformToScreen,
float* contentsScaleX,
float* contentsScaleY,
gfx::Size* contentBounds)
{
*contentsScaleX = 1;
*contentsScaleY = 1;
*contentBounds = bounds();
}
void Layer::setMasksToBounds(bool masksToBounds)
{
if (m_masksToBounds == masksToBounds)
return;
m_masksToBounds = masksToBounds;
setNeedsCommit();
}
void Layer::setMaskLayer(Layer* maskLayer)
{
if (m_maskLayer == maskLayer)
return;
if (m_maskLayer) {
DCHECK_EQ(this, m_maskLayer->parent());
m_maskLayer->removeFromParent();
}
m_maskLayer = maskLayer;
if (m_maskLayer) {
DCHECK(!m_maskLayer->parent());
m_maskLayer->removeFromParent();
m_maskLayer->setParent(this);
m_maskLayer->setIsMask(true);
}
setNeedsFullTreeSync();
}
void Layer::setReplicaLayer(Layer* layer)
{
if (m_replicaLayer == layer)
return;
if (m_replicaLayer) {
DCHECK_EQ(this, m_replicaLayer->parent());
m_replicaLayer->removeFromParent();
}
m_replicaLayer = layer;
if (m_replicaLayer) {
DCHECK(!m_replicaLayer->parent());
m_replicaLayer->removeFromParent();
m_replicaLayer->setParent(this);
}
setNeedsFullTreeSync();
}
void Layer::setFilters(const WebKit::WebFilterOperations& filters)
{
if (m_filters == filters)
return;
DCHECK(!m_filter);
m_filters = filters;
setNeedsCommit();
if (!filters.isEmpty() && m_layerTreeHost)
m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setFilter(const skia::RefPtr<SkImageFilter>& filter)
{
if (m_filter.get() == filter.get())
return;
DCHECK(m_filters.isEmpty());
m_filter = filter;
setNeedsCommit();
if (filter && m_layerTreeHost)
m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setBackgroundFilters(const WebKit::WebFilterOperations& backgroundFilters)
{
if (m_backgroundFilters == backgroundFilters)
return;
m_backgroundFilters = backgroundFilters;
setNeedsCommit();
if (!backgroundFilters.isEmpty() && m_layerTreeHost)
m_layerTreeHost->setNeedsFilterContext();
}
void Layer::setOpacity(float opacity)
{
if (m_opacity == opacity)
return;
m_opacity = opacity;
setNeedsCommit();
}
float Layer::opacity() const
{
return m_opacity;
}
bool Layer::opacityIsAnimating() const
{
return m_layerAnimationController->isAnimatingProperty(Animation::Opacity);
}
void Layer::setContentsOpaque(bool opaque)
{
if (m_contentsOpaque == opaque)
return;
m_contentsOpaque = opaque;
setNeedsCommit();
}
void Layer::setPosition(const gfx::PointF& position)
{
if (m_position == position)
return;
m_position = position;
setNeedsCommit();
}
void Layer::setSublayerTransform(const gfx::Transform& sublayerTransform)
{
if (m_sublayerTransform == sublayerTransform)
return;
m_sublayerTransform = sublayerTransform;
setNeedsCommit();
}
void Layer::setTransform(const gfx::Transform& transform)
{
if (m_transform == transform)
return;
m_transform = transform;
setNeedsCommit();
}
const gfx::Transform& Layer::transform() const
{
return m_transform;
}
bool Layer::transformIsAnimating() const
{
return m_layerAnimationController->isAnimatingProperty(Animation::Transform);
}
void Layer::setScrollOffset(gfx::Vector2d scrollOffset)
{
if (m_scrollOffset == scrollOffset)
return;
m_scrollOffset = scrollOffset;
if (m_layerScrollClient)
m_layerScrollClient->didScroll();
setNeedsCommit();
}
void Layer::setMaxScrollOffset(gfx::Vector2d maxScrollOffset)
{
if (m_maxScrollOffset == maxScrollOffset)
return;
m_maxScrollOffset = maxScrollOffset;
setNeedsCommit();
}
void Layer::setScrollable(bool scrollable)
{
if (m_scrollable == scrollable)
return;
m_scrollable = scrollable;
setNeedsCommit();
}
void Layer::setShouldScrollOnMainThread(bool shouldScrollOnMainThread)
{
if (m_shouldScrollOnMainThread == shouldScrollOnMainThread)
return;
m_shouldScrollOnMainThread = shouldScrollOnMainThread;
setNeedsCommit();
}
void Layer::setHaveWheelEventHandlers(bool haveWheelEventHandlers)
{
if (m_haveWheelEventHandlers == haveWheelEventHandlers)
return;
m_haveWheelEventHandlers = haveWheelEventHandlers;
setNeedsCommit();
}
void Layer::setNonFastScrollableRegion(const Region& region)
{
if (m_nonFastScrollableRegion == region)
return;
m_nonFastScrollableRegion = region;
setNeedsCommit();
}
void Layer::setTouchEventHandlerRegion(const Region& region)
{
if (m_touchEventHandlerRegion == region)
return;
m_touchEventHandlerRegion = region;
}
void Layer::setDrawCheckerboardForMissingTiles(bool checkerboard)
{
if (m_drawCheckerboardForMissingTiles == checkerboard)
return;
m_drawCheckerboardForMissingTiles = checkerboard;
setNeedsCommit();
}
void Layer::setForceRenderSurface(bool force)
{
if (m_forceRenderSurface == force)
return;
m_forceRenderSurface = force;
setNeedsCommit();
}
void Layer::setImplTransform(const gfx::Transform& transform)
{
if (m_implTransform == transform)
return;
m_implTransform = transform;
setNeedsCommit();
}
void Layer::setDoubleSided(bool doubleSided)
{
if (m_doubleSided == doubleSided)
return;
m_doubleSided = doubleSided;
setNeedsCommit();
}
void Layer::setIsDrawable(bool isDrawable)
{
if (m_isDrawable == isDrawable)
return;
m_isDrawable = isDrawable;
setNeedsCommit();
}
void Layer::setNeedsDisplayRect(const gfx::RectF& dirtyRect)
{
m_updateRect.Union(dirtyRect);
m_needsDisplay = true;
// Simply mark the contents as dirty. For non-root layers, the call to
// setNeedsCommit will schedule a fresh compositing pass.
// For the root layer, setNeedsCommit has no effect.
if (drawsContent() && !m_updateRect.IsEmpty())
setNeedsCommit();
}
bool Layer::descendantIsFixedToContainerLayer() const
{
for (size_t i = 0; i < m_children.size(); ++i) {
if (m_children[i]->fixedToContainerLayer() || m_children[i]->descendantIsFixedToContainerLayer())
return true;
}
return false;
}
void Layer::setIsContainerForFixedPositionLayers(bool isContainerForFixedPositionLayers)
{
if (m_isContainerForFixedPositionLayers == isContainerForFixedPositionLayers)
return;
m_isContainerForFixedPositionLayers = isContainerForFixedPositionLayers;
if (m_layerTreeHost && m_layerTreeHost->commitRequested())
return;
// Only request a commit if we have a fixed positioned descendant.
if (descendantIsFixedToContainerLayer())
setNeedsCommit();
}
void Layer::setFixedToContainerLayer(bool fixedToContainerLayer)
{
if (m_fixedToContainerLayer == fixedToContainerLayer)
return;
m_fixedToContainerLayer = fixedToContainerLayer;
setNeedsCommit();
}
void Layer::pushPropertiesTo(LayerImpl* layer)
{
layer->setAnchorPoint(m_anchorPoint);
layer->setAnchorPointZ(m_anchorPointZ);
layer->setBackgroundColor(m_backgroundColor);
layer->setBounds(m_bounds);
layer->setContentBounds(contentBounds());
layer->setContentsScale(contentsScaleX(), contentsScaleY());
layer->setDebugName(m_debugName);
layer->setDoubleSided(m_doubleSided);
layer->setDrawCheckerboardForMissingTiles(m_drawCheckerboardForMissingTiles);
layer->setForceRenderSurface(m_forceRenderSurface);
layer->setDrawsContent(drawsContent());
layer->setFilters(filters());
layer->setFilter(filter());
layer->setBackgroundFilters(backgroundFilters());
layer->setMasksToBounds(m_masksToBounds);
layer->setShouldScrollOnMainThread(m_shouldScrollOnMainThread);
layer->setHaveWheelEventHandlers(m_haveWheelEventHandlers);
layer->setNonFastScrollableRegion(m_nonFastScrollableRegion);
layer->setTouchEventHandlerRegion(m_touchEventHandlerRegion);
layer->setContentsOpaque(m_contentsOpaque);
if (!opacityIsAnimating())
layer->setOpacity(m_opacity);
layer->setPosition(m_position);
layer->setIsContainerForFixedPositionLayers(m_isContainerForFixedPositionLayers);
layer->setFixedToContainerLayer(m_fixedToContainerLayer);
layer->setPreserves3D(preserves3D());
layer->setUseParentBackfaceVisibility(m_useParentBackfaceVisibility);
layer->setSublayerTransform(m_sublayerTransform);
if (!transformIsAnimating())
layer->setTransform(m_transform);
layer->setScrollable(m_scrollable);
layer->setScrollOffset(m_scrollOffset);
layer->setMaxScrollOffset(m_maxScrollOffset);
// If the main thread commits multiple times before the impl thread actually draws, then damage tracking
// will become incorrect if we simply clobber the updateRect here. The LayerImpl's updateRect needs to
// accumulate (i.e. union) any update changes that have occurred on the main thread.
m_updateRect.Union(layer->updateRect());
layer->setUpdateRect(m_updateRect);
if (layer->layerTreeImpl()->settings().implSidePainting) {
DCHECK(layer->layerTreeImpl()->IsPendingTree());
LayerImpl* active_twin = layer->layerTreeImpl()->FindActiveTreeLayerById(id());
// Update the scroll delta from the active layer, which may have
// adjusted its scroll delta prior to this pending layer being created.
// This code is identical to that in LayerImpl::setScrollDelta.
if (active_twin) {
DCHECK(layer->sentScrollDelta().IsZero());
layer->setScrollDelta(active_twin->scrollDelta() - active_twin->sentScrollDelta());
}
} else {
layer->setScrollDelta(layer->scrollDelta() - layer->sentScrollDelta());
layer->setSentScrollDelta(gfx::Vector2d());
}
layer->setStackingOrderChanged(m_stackingOrderChanged);
m_layerAnimationController->pushAnimationUpdatesTo(layer->layerAnimationController());
// Reset any state that should be cleared for the next update.
m_stackingOrderChanged = false;
m_updateRect = gfx::RectF();
}
scoped_ptr<LayerImpl> Layer::createLayerImpl(LayerTreeImpl* treeImpl)
{
return LayerImpl::create(treeImpl, m_layerId);
}
bool Layer::drawsContent() const
{
return m_isDrawable;
}
bool Layer::needMoreUpdates()
{
return false;
}
void Layer::setDebugName(const std::string& debugName)
{
m_debugName = debugName;
setNeedsCommit();
}
void Layer::setRasterScale(float scale)
{
if (m_rasterScale == scale)
return;
m_rasterScale = scale;
// When automatically computed, this acts like a draw property.
if (m_automaticallyComputeRasterScale)
return;
setNeedsDisplay();
}
void Layer::setAutomaticallyComputeRasterScale(bool automatic)
{
if (m_automaticallyComputeRasterScale == automatic)
return;
m_automaticallyComputeRasterScale = automatic;
if (m_automaticallyComputeRasterScale)
forceAutomaticRasterScaleToBeRecomputed();
else
setRasterScale(1);
}
void Layer::forceAutomaticRasterScaleToBeRecomputed()
{
if (!m_automaticallyComputeRasterScale)
return;
if (!m_rasterScale)
return;
m_rasterScale = 0;
setNeedsCommit();
}
void Layer::setBoundsContainPageScale(bool boundsContainPageScale)
{
for (size_t i = 0; i < m_children.size(); ++i)
m_children[i]->setBoundsContainPageScale(boundsContainPageScale);
if (boundsContainPageScale == m_boundsContainPageScale)
return;
m_boundsContainPageScale = boundsContainPageScale;
setNeedsDisplay();
}
void Layer::createRenderSurface()
{
DCHECK(!m_drawProperties.render_surface);
m_drawProperties.render_surface = make_scoped_ptr(new RenderSurface(this));
m_drawProperties.render_target = this;
}
int Layer::id() const
{
return m_layerId;
}
void Layer::OnOpacityAnimated(float opacity)
{
// This is called due to an ongoing accelerated animation. Since this animation is
// also being run on the impl thread, there is no need to request a commit to push
// this value over, so set the value directly rather than calling setOpacity.
m_opacity = opacity;
}
void Layer::OnTransformAnimated(const gfx::Transform& transform)
{
// This is called due to an ongoing accelerated animation. Since this animation is
// also being run on the impl thread, there is no need to request a commit to push
// this value over, so set this value directly rather than calling setTransform.
m_transform = transform;
}
bool Layer::IsActive() const
{
return true;
}
bool Layer::addAnimation(scoped_ptr <Animation> animation)
{
// WebCore currently assumes that accelerated animations will start soon
// after the animation is added. However we cannot guarantee that if we do
// not have a layerTreeHost that will setNeedsCommit().
// Unfortunately, the fix below to guarantee correctness causes performance
// regressions on Android, since Android has shipped for a long time
// with all animations accelerated. For this reason, we will live with
// this bug only on Android until the bug is fixed.
// http://crbug.com/129683
#if !defined(OS_ANDROID)
if (!m_layerTreeHost)
return false;
if (!m_layerTreeHost->settings().acceleratedAnimationEnabled)
return false;
#endif
m_layerAnimationController->addAnimation(animation.Pass());
setNeedsCommit();
return true;
}
void Layer::pauseAnimation(int animationId, double timeOffset)
{
m_layerAnimationController->pauseAnimation(animationId, timeOffset);
setNeedsCommit();
}
void Layer::removeAnimation(int animationId)
{
m_layerAnimationController->removeAnimation(animationId);
setNeedsCommit();
}
void Layer::suspendAnimations(double monotonicTime)
{
m_layerAnimationController->suspendAnimations(monotonicTime);
setNeedsCommit();
}
void Layer::resumeAnimations(double monotonicTime)
{
m_layerAnimationController->resumeAnimations(monotonicTime);
setNeedsCommit();
}
void Layer::setLayerAnimationController(scoped_refptr<LayerAnimationController> layerAnimationController)
{
removeLayerAnimationEventObserver(m_layerAnimationController.get());
m_layerAnimationController->removeObserver(this);
m_layerAnimationController = layerAnimationController;
m_layerAnimationController->setForceSync();
m_layerAnimationController->addObserver(this);
addLayerAnimationEventObserver(m_layerAnimationController.get());
setNeedsCommit();
}
scoped_refptr<LayerAnimationController> Layer::releaseLayerAnimationController()
{
m_layerAnimationController->removeObserver(this);
scoped_refptr<LayerAnimationController> toReturn = m_layerAnimationController;
m_layerAnimationController = LayerAnimationController::create(id());
m_layerAnimationController->addObserver(this);
return toReturn;
}
bool Layer::hasActiveAnimation() const
{
return m_layerAnimationController->hasActiveAnimation();
}
void Layer::notifyAnimationStarted(const AnimationEvent& event, double wallClockTime)
{
FOR_EACH_OBSERVER(LayerAnimationEventObserver, m_layerAnimationObservers,
OnAnimationStarted(event));
if (m_layerAnimationDelegate)
m_layerAnimationDelegate->notifyAnimationStarted(wallClockTime);
}
void Layer::notifyAnimationFinished(double wallClockTime)
{
if (m_layerAnimationDelegate)
m_layerAnimationDelegate->notifyAnimationFinished(wallClockTime);
}
void Layer::addLayerAnimationEventObserver(LayerAnimationEventObserver* animationObserver)
{
if (!m_layerAnimationObservers.HasObserver(animationObserver))
m_layerAnimationObservers.AddObserver(animationObserver);
}
void Layer::removeLayerAnimationEventObserver(LayerAnimationEventObserver* animationObserver)
{
m_layerAnimationObservers.RemoveObserver(animationObserver);
}
Region Layer::visibleContentOpaqueRegion() const
{
if (contentsOpaque())
return visibleContentRect();
return Region();
}
ScrollbarLayer* Layer::toScrollbarLayer()
{
return 0;
}
void sortLayers(std::vector<scoped_refptr<Layer> >::iterator, std::vector<scoped_refptr<Layer> >::iterator, void*)
{
// Currently we don't use z-order to decide what to paint, so there's no need to actually sort Layers.
}
} // namespace cc