| // 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/active_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 "third_party/skia/include/core/SkImageFilter.h" |
| #include "ui/gfx/rect_conversions.h" |
| #include <public/WebAnimationDelegate.h> |
| #include <public/WebLayerScrollClient.h> |
| #include <public/WebSize.h> |
| |
| using namespace std; |
| |
| 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_parent(0) |
| , m_layerTreeHost(0) |
| , m_layerAnimationController(LayerAnimationController::create(this)) |
| , m_scrollable(false) |
| , m_shouldScrollOnMainThread(false) |
| , m_haveWheelEventHandlers(false) |
| , m_nonFastScrollableRegionChanged(false) |
| , m_touchEventHandlerRegionChanged(false) |
| , m_anchorPoint(0.5, 0.5) |
| , m_backgroundColor(0) |
| , m_opacity(1.0) |
| , m_filter(0) |
| , m_anchorPointZ(0) |
| , m_isContainerForFixedPositionLayers(false) |
| , m_fixedToContainerLayer(false) |
| , m_isDrawable(false) |
| , m_masksToBounds(false) |
| , m_contentsOpaque(false) |
| , m_doubleSided(true) |
| , m_useLCDText(false) |
| , m_preserves3D(false) |
| , m_useParentBackfaceVisibility(false) |
| , m_drawCheckerboardForMissingTiles(false) |
| , m_forceRenderSurface(false) |
| , m_replicaLayer(0) |
| , m_drawOpacity(0) |
| , m_drawOpacityIsAnimating(false) |
| , m_renderTarget(0) |
| , m_drawTransformIsAnimating(false) |
| , m_screenSpaceTransformIsAnimating(false) |
| , m_isClipped(false) |
| , 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++; |
| } |
| } |
| |
| 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()); |
| |
| // Remove the parent reference from all children. |
| removeAllChildren(); |
| |
| SkSafeUnref(m_filter); |
| } |
| |
| void Layer::setUseLCDText(bool useLCDText) |
| { |
| m_useLCDText = useLCDText; |
| } |
| |
| 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); |
| |
| // If this layer already has active animations, the host needs to be notified. |
| if (host && m_layerAnimationController->hasActiveAnimation()) |
| host->didAddAnimation(); |
| } |
| |
| void Layer::setNeedsCommit() |
| { |
| if (m_layerTreeHost) |
| m_layerTreeHost->setNeedsCommit(); |
| } |
| |
| 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); |
| } |
| |
| void Layer::setParent(Layer* layer) |
| { |
| DCHECK(!layer || !layer->hasAncestor(this)); |
| m_parent = layer; |
| setLayerTreeHost(m_parent ? m_parent->layerTreeHost() : 0); |
| |
| 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, numChildren()); |
| } |
| |
| void Layer::insertChild(scoped_refptr<Layer> child, size_t index) |
| { |
| child->removeFromParent(); |
| child->setParent(this); |
| child->m_stackingOrderChanged = true; |
| |
| index = min(index, m_children.size()); |
| LayerList::iterator iter = m_children.begin(); |
| m_children.insert(iter + index, child); |
| setNeedsCommit(); |
| } |
| |
| void Layer::removeFromParent() |
| { |
| if (m_parent) |
| m_parent->removeChild(this); |
| } |
| |
| void Layer::removeChild(Layer* child) |
| { |
| for (LayerList::iterator iter = m_children.begin(); iter != m_children.end(); ++iter) |
| { |
| if (*iter != child) |
| continue; |
| |
| child->setParent(0); |
| m_children.erase(iter); |
| setNeedsCommit(); |
| 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(layer->parent()); |
| layer->removeFromParent(); |
| } |
| } |
| |
| void Layer::setChildren(const LayerList& children) |
| { |
| if (children == m_children) |
| return; |
| |
| removeAllChildren(); |
| size_t listSize = children.size(); |
| for (size_t i = 0; i < listSize; i++) |
| addChild(children[i]); |
| } |
| |
| 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(); |
| } |
| |
| gfx::Size Layer::contentBounds() const |
| { |
| return 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) |
| m_maskLayer->setLayerTreeHost(0); |
| m_maskLayer = maskLayer; |
| if (m_maskLayer) { |
| m_maskLayer->setLayerTreeHost(m_layerTreeHost); |
| m_maskLayer->setIsMask(true); |
| } |
| setNeedsCommit(); |
| } |
| |
| void Layer::setReplicaLayer(Layer* layer) |
| { |
| if (m_replicaLayer == layer) |
| return; |
| if (m_replicaLayer) |
| m_replicaLayer->setLayerTreeHost(0); |
| m_replicaLayer = layer; |
| if (m_replicaLayer) |
| m_replicaLayer->setLayerTreeHost(m_layerTreeHost); |
| setNeedsCommit(); |
| } |
| |
| void Layer::setFilters(const WebKit::WebFilterOperations& filters) |
| { |
| if (m_filters == filters) |
| return; |
| DCHECK(!m_filter); |
| m_filters = filters; |
| setNeedsCommit(); |
| if (!filters.isEmpty()) |
| LayerTreeHost::setNeedsFilterContext(true); |
| } |
| |
| void Layer::setFilter(SkImageFilter* filter) |
| { |
| if (m_filter == filter) |
| return; |
| DCHECK(m_filters.isEmpty()); |
| SkRefCnt_SafeAssign(m_filter, filter); |
| setNeedsCommit(); |
| if (filter) |
| LayerTreeHost::setNeedsFilterContext(true); |
| } |
| |
| void Layer::setBackgroundFilters(const WebKit::WebFilterOperations& backgroundFilters) |
| { |
| if (m_backgroundFilters == backgroundFilters) |
| return; |
| m_backgroundFilters = backgroundFilters; |
| setNeedsCommit(); |
| if (!backgroundFilters.isEmpty()) |
| LayerTreeHost::setNeedsFilterContext(true); |
| } |
| |
| bool Layer::needsDisplay() const |
| { |
| return m_needsDisplay; |
| } |
| |
| void Layer::setOpacity(float opacity) |
| { |
| if (m_opacity == opacity) |
| return; |
| m_opacity = opacity; |
| setNeedsCommit(); |
| } |
| |
| bool Layer::opacityIsAnimating() const |
| { |
| return m_layerAnimationController->isAnimatingProperty(ActiveAnimation::Opacity); |
| } |
| |
| void Layer::setContentsOpaque(bool opaque) |
| { |
| if (m_contentsOpaque == opaque) |
| return; |
| m_contentsOpaque = opaque; |
| setNeedsDisplay(); |
| } |
| |
| 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(); |
| } |
| |
| bool Layer::transformIsAnimating() const |
| { |
| return m_layerAnimationController->isAnimatingProperty(ActiveAnimation::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; |
| m_nonFastScrollableRegionChanged = true; |
| setNeedsCommit(); |
| } |
| |
| void Layer::setTouchEventHandlerRegion(const Region& region) |
| { |
| if (m_touchEventHandlerRegion == region) |
| return; |
| m_touchEventHandlerRegion = region; |
| m_touchEventHandlerRegionChanged = true; |
| } |
| |
| 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); |
| |
| // 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 (!dirtyRect.IsEmpty()) |
| m_needsDisplay = true; |
| |
| if (drawsContent()) |
| 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->setUseLCDText(m_useLCDText); |
| layer->setMasksToBounds(m_masksToBounds); |
| layer->setScrollable(m_scrollable); |
| layer->setShouldScrollOnMainThread(m_shouldScrollOnMainThread); |
| layer->setHaveWheelEventHandlers(m_haveWheelEventHandlers); |
| // Copying a Region is more expensive than most layer properties, since it involves copying two Vectors that may be |
| // arbitrarily large depending on page content, so we only push the property if it's changed. |
| if (m_nonFastScrollableRegionChanged) { |
| layer->setNonFastScrollableRegion(m_nonFastScrollableRegion); |
| m_nonFastScrollableRegionChanged = false; |
| } |
| if (m_touchEventHandlerRegionChanged) { |
| layer->setTouchEventHandlerRegion(m_touchEventHandlerRegion); |
| m_touchEventHandlerRegionChanged = false; |
| } |
| 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->setScrollOffset(m_scrollOffset); |
| layer->setMaxScrollOffset(m_maxScrollOffset); |
| layer->setSublayerTransform(m_sublayerTransform); |
| if (!transformIsAnimating()) |
| layer->setTransform(m_transform); |
| |
| // 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); |
| |
| layer->setScrollDelta(layer->scrollDelta() - layer->sentScrollDelta()); |
| layer->setSentScrollDelta(gfx::Vector2d()); |
| |
| layer->setStackingOrderChanged(m_stackingOrderChanged); |
| |
| if (maskLayer()) |
| maskLayer()->pushPropertiesTo(layer->maskLayer()); |
| if (replicaLayer()) |
| replicaLayer()->pushPropertiesTo(layer->replicaLayer()); |
| |
| 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() |
| { |
| return LayerImpl::create(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(); |
| } |
| |
| float Layer::contentsScaleX() const |
| { |
| return 1.0; |
| } |
| |
| float Layer::contentsScaleY() const |
| { |
| return 1.0; |
| } |
| |
| void Layer::setRasterScale(float scale) |
| { |
| if (m_rasterScale == scale) |
| return; |
| m_rasterScale = scale; |
| |
| 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; |
| m_rasterScale = 0; |
| setNeedsDisplay(); |
| } |
| |
| 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_renderSurface); |
| m_renderSurface = make_scoped_ptr(new RenderSurface(this)); |
| setRenderTarget(this); |
| } |
| |
| bool Layer::descendantDrawsContent() |
| { |
| for (size_t i = 0; i < m_children.size(); ++i) { |
| if (m_children[i]->drawsContent() || m_children[i]->descendantDrawsContent()) |
| return true; |
| } |
| return false; |
| } |
| |
| int Layer::id() const |
| { |
| return m_layerId; |
| } |
| |
| float Layer::opacity() const |
| { |
| return m_opacity; |
| } |
| |
| void Layer::setOpacityFromAnimation(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; |
| } |
| |
| const gfx::Transform& Layer::transform() const |
| { |
| return m_transform; |
| } |
| |
| void Layer::setTransformFromAnimation(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::addAnimation(scoped_ptr <ActiveAnimation> 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()); |
| if (m_layerTreeHost) { |
| m_layerTreeHost->didAddAnimation(); |
| 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_ptr<LayerAnimationController> layerAnimationController) |
| { |
| m_layerAnimationController = layerAnimationController.Pass(); |
| if (m_layerAnimationController) { |
| m_layerAnimationController->setClient(this); |
| m_layerAnimationController->setForceSync(); |
| } |
| setNeedsCommit(); |
| } |
| |
| scoped_ptr<LayerAnimationController> Layer::releaseLayerAnimationController() |
| { |
| scoped_ptr<LayerAnimationController> toReturn = m_layerAnimationController.Pass(); |
| m_layerAnimationController = LayerAnimationController::create(this); |
| return toReturn.Pass(); |
| } |
| |
| bool Layer::hasActiveAnimation() const |
| { |
| return m_layerAnimationController->hasActiveAnimation(); |
| } |
| |
| void Layer::notifyAnimationStarted(const AnimationEvent& event, double wallClockTime) |
| { |
| m_layerAnimationController->notifyAnimationStarted(event); |
| if (m_layerAnimationDelegate) |
| m_layerAnimationDelegate->notifyAnimationStarted(wallClockTime); |
| } |
| |
| void Layer::notifyAnimationFinished(double wallClockTime) |
| { |
| if (m_layerAnimationDelegate) |
| m_layerAnimationDelegate->notifyAnimationFinished(wallClockTime); |
| } |
| |
| 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 |