Index: third_party/WebKit/WebCore/rendering/RenderLayerCompositor.cpp |
=================================================================== |
--- third_party/WebKit/WebCore/rendering/RenderLayerCompositor.cpp (revision 9391) |
+++ third_party/WebKit/WebCore/rendering/RenderLayerCompositor.cpp (working copy) |
@@ -1,747 +1,747 @@ |
-/* |
- * Copyright (C) 2009 Apple Inc. All rights reserved. |
- * |
- * Redistribution and use in source and binary forms, with or without |
- * modification, are permitted provided that the following conditions |
- * are met: |
- * 1. Redistributions of source code must retain the above copyright |
- * notice, this list of conditions and the following disclaimer. |
- * 2. Redistributions in binary form must reproduce the above copyright |
- * notice, this list of conditions and the following disclaimer in the |
- * documentation and/or other materials provided with the distribution. |
- * |
- * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
- * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
- */ |
- |
-#include "config.h" |
- |
-#if USE(ACCELERATED_COMPOSITING) |
-#include "RenderLayerCompositor.h" |
- |
-#include "AnimationController.h" |
-#include "ChromeClient.h" |
-#include "CSSPropertyNames.h" |
-#include "FrameView.h" |
-#include "GraphicsLayer.h" |
-#include "HitTestRequest.h" |
-#include "HitTestResult.h" |
-#include "Page.h" |
-#include "RenderLayerBacking.h" |
-#include "RenderView.h" |
- |
-#if PROFILE_LAYER_REBUILD |
-#include <wtf/CurrentTime.h> |
-#endif |
- |
-#ifndef NDEBUG |
-#include "CString.h" |
-#include "RenderTreeAsText.h" |
-#endif |
- |
-namespace WebCore { |
- |
-struct CompositingState { |
- CompositingState(RenderLayer* compAncestor) |
- : m_subtreeIsCompositing(false) |
- , m_compositingAncestor(compAncestor) |
-#ifndef NDEBUG |
- , m_depth(0) |
-#endif |
- { |
- } |
- |
- bool m_subtreeIsCompositing; |
- RenderLayer* m_compositingAncestor; |
-#ifndef NDEBUG |
- int m_depth; |
-#endif |
-}; |
- |
-static TransformationMatrix flipTransform() |
-{ |
- TransformationMatrix flipper; |
- flipper.flipY(); |
- return flipper; |
-} |
- |
-RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) |
- : m_renderView(renderView) |
- , m_rootPlatformLayer(0) |
- , m_compositing(false) |
- , m_rootLayerAttached(false) |
- , m_compositingLayersNeedUpdate(false) |
-#if PROFILE_LAYER_REBUILD |
- , m_rootLayerUpdateCount(0) |
-#endif // PROFILE_LAYER_REBUILD |
-{ |
-} |
- |
-RenderLayerCompositor::~RenderLayerCompositor() |
-{ |
- ASSERT(!m_rootLayerAttached); |
- delete m_rootPlatformLayer; |
-} |
- |
-void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) |
-{ |
- if (enable != m_compositing) { |
- m_compositing = enable; |
- |
- // We never go out of compositing mode for a given page, |
- // but if all the layers disappear, we'll just be left with |
- // the empty root layer, which has minimal overhead. |
- if (m_compositing) |
- ensureRootPlatformLayer(); |
- } |
-} |
- |
-void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate) |
-{ |
- if (inCompositingMode()) |
- m_compositingLayersNeedUpdate = needUpdate; |
-} |
- |
-void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) |
-{ |
- if (!m_compositingLayersNeedUpdate) |
- return; |
- |
- ASSERT(inCompositingMode()); |
- |
- if (!updateRoot) { |
- // Only clear the flag if we're updating the entire hierarchy |
- m_compositingLayersNeedUpdate = false; |
- updateRoot = rootRenderLayer(); |
- } |
- |
-#if PROFILE_LAYER_REBUILD |
- ++m_rootLayerUpdateCount; |
- |
- double startTime = WTF::currentTime(); |
-#endif |
- |
- // Go through the layers in presentation order, so that we can compute which |
- // RLs need compositing layers. |
- // FIXME: we could maybe do this in one pass, but the parenting logic would be more |
- // complex. |
- { |
- CompositingState compState(updateRoot); |
- computeCompositingRequirements(updateRoot, compState); |
- } |
- |
- // Now create and parent the compositing layers. |
- { |
- CompositingState compState(updateRoot); |
- rebuildCompositingLayerTree(updateRoot, compState); |
- } |
- |
-#if PROFILE_LAYER_REBUILD |
- double endTime = WTF::currentTime(); |
- if (!updateRoot) |
- fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n" |
- m_rootLayerUpdateCount, 1000.0 * (endTime - startTime)); |
-#endif |
- ASSERT(updateRoot || !m_compositingLayersNeedUpdate); |
-} |
- |
-bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, StyleDifference diff) |
-{ |
- bool needsLayer = needsToBeComposited(layer); |
- bool layerChanged = false; |
- if (needsLayer) { |
- enableCompositingMode(); |
- if (!layer->backing()) { |
- layer->ensureBacking(); |
- layerChanged = true; |
- } |
- } else { |
- if (layer->backing()) { |
- layer->clearBacking(); |
- layerChanged = true; |
- } |
- } |
- |
- if (layerChanged) { |
- // Invalidate the parent in this region. |
- RenderLayer* compLayer = ancestorCompositingLayer(layer); |
- if (compLayer) { |
- // We can't reliably compute a dirty rect, because style may have changed already, |
- // so just dirty the whole parent layer |
- compLayer->setBackingNeedsRepaint(); |
- // The contents of this layer may be moving between the window |
- // and a GraphicsLayer, so we need to make sure the window system |
- // synchronizes those changes on the screen. |
- m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); |
- } |
- |
- layer->renderer()->compositingStateChanged(); |
- } |
- |
- if (!needsLayer) |
- return layerChanged; |
- |
- if (layer->backing()->updateGraphicsLayers(needsContentsCompositingLayer(layer), |
- clippedByAncestor(layer), |
- clipsCompositingDescendants(layer), |
- diff >= StyleDifferenceRepaint)) |
- layerChanged = true; |
- |
- return layerChanged; |
-} |
- |
-// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant |
-// RenderLayers that are rendered by the composited RenderLayer. |
-IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox) |
-{ |
- IntRect boundingBoxRect, unionBounds; |
- boundingBoxRect = unionBounds = layer->boundingBox(layer); |
- |
- ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0)); |
- |
- Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
- if (negZOrderList) { |
- for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- if (!curLayer->isComposited()) { |
- IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); |
- unionBounds.unite(childUnionBounds); |
- } |
- } |
- } |
- |
- Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
- if (posZOrderList) { |
- for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- if (!curLayer->isComposited()) { |
- IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); |
- unionBounds.unite(childUnionBounds); |
- } |
- } |
- } |
- |
- Vector<RenderLayer*>* overflowList = layer->overflowList(); |
- if (overflowList) { |
- for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- if (!curLayer->isComposited()) { |
- IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer); |
- unionBounds.unite(curAbsBounds); |
- } |
- } |
- } |
- |
- if (!layer->isComposited() && layer->transform()) { |
- TransformationMatrix* affineTrans = layer->transform(); |
- boundingBoxRect = affineTrans->mapRect(boundingBoxRect); |
- unionBounds = affineTrans->mapRect(unionBounds); |
- } |
- |
- int ancestorRelX = 0, ancestorRelY = 0; |
- layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY); |
- unionBounds.move(ancestorRelX, ancestorRelY); |
- |
- if (layerBoundingBox) { |
- boundingBoxRect.move(ancestorRelX, ancestorRelY); |
- *layerBoundingBox = boundingBoxRect; |
- } |
- |
- return unionBounds; |
-} |
- |
-void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) |
-{ |
- setCompositingLayersNeedUpdate(); |
-} |
- |
-void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) |
-{ |
- if (child->isComposited()) |
- setCompositingParent(child, 0); |
- |
- // If the document is being torn down (document's renderer() is null), then there's |
- // no need to do any layer updating. |
- if (parent->renderer()->documentBeingDestroyed()) |
- return; |
- |
- RenderLayer* compLayer = parent->renderer()->enclosingCompositingLayer(); |
- if (compLayer) { |
- IntRect ancestorRect = calculateCompositedBounds(child, compLayer); |
- compLayer->setBackingNeedsRepaintInRect(ancestorRect); |
- // The contents of this layer may be moving from a GraphicsLayer to the window, |
- // so we need to make sure the window system synchronizes those changes on the screen. |
- m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); |
- } |
- |
- setCompositingLayersNeedUpdate(); |
-} |
- |
-RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const |
-{ |
- for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) { |
- if (curr->isStackingContext()) |
- return 0; |
- |
- if (curr->renderer()->hasOverflowClip()) |
- return curr; |
- } |
- return 0; |
-} |
- |
-// Recurse through the layers in z-index and overflow order (which is equivalent to painting order) |
-// For the z-order children of a compositing layer: |
-// If a child layers has a compositing layer, then all subsequent layers must |
-// be compositing in order to render above that layer. |
-// |
-// If a child in the negative z-order list is compositing, then the layer itself |
-// must be compositing so that its contents render over that child. |
-// This implies that its positive z-index children must also be compositing. |
-// |
-void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, struct CompositingState& ioCompState) |
-{ |
- layer->updateLayerPosition(); |
- layer->updateZOrderLists(); |
- layer->updateOverflowList(); |
- |
- // Clear the flag |
- layer->setHasCompositingDescendant(false); |
- |
- setForcedCompositingLayer(layer, ioCompState.m_subtreeIsCompositing); |
- |
- const bool isCompositingLayer = needsToBeComposited(layer); |
- ioCompState.m_subtreeIsCompositing = isCompositingLayer; |
- |
- CompositingState childState = ioCompState; |
- if (isCompositingLayer) |
- childState.m_compositingAncestor = layer; |
- |
- // The children of this stacking context don't need to composite, unless there is |
- // a compositing layer among them, so start by assuming false. |
- childState.m_subtreeIsCompositing = false; |
- |
-#ifndef NDEBUG |
- ++childState.m_depth; |
-#endif |
- |
- if (layer->isStackingContext()) { |
- ASSERT(!layer->m_zOrderListsDirty); |
- Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
- if (negZOrderList && negZOrderList->size() > 0) { |
- for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- computeCompositingRequirements(curLayer, childState); |
- |
- // if we have to make a layer for this child, make one now so we can have a contents layer |
- // (since we need to ensure that the -ve z-order child renders underneath our contents) |
- if (childState.m_subtreeIsCompositing) { |
- // make |this| compositing |
- setForcedCompositingLayer(layer, true); |
- childState.m_compositingAncestor = layer; |
- } |
- } |
- } |
- } |
- |
- ASSERT(!layer->m_overflowListDirty); |
- Vector<RenderLayer*>* overflowList = layer->overflowList(); |
- if (overflowList && overflowList->size() > 0) { |
- for (Vector<RenderLayer*>::const_iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- computeCompositingRequirements(curLayer, childState); |
- } |
- } |
- |
- if (layer->isStackingContext()) { |
- Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
- if (posZOrderList && posZOrderList->size() > 0) { |
- for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- computeCompositingRequirements(curLayer, childState); |
- } |
- } |
- } |
- |
- // If we have a software transform, and we have layers under us, we need to also |
- // be composited. Also, if we have opacity < 1, then we need to be a layer so that |
- // the child layers are opaque, then rendered with opacity on this layer. |
- if (childState.m_subtreeIsCompositing && |
- (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) |
- setForcedCompositingLayer(layer, true); |
- |
- // Subsequent layers in the parent stacking context also need to composite. |
- if (childState.m_subtreeIsCompositing) |
- ioCompState.m_subtreeIsCompositing = true; |
- |
- // Set the flag to say that this SC has compositing children. |
- // this can affect the answer to needsToBeComposited() when clipping, |
- // but that's ok here. |
- layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing); |
-} |
- |
-void RenderLayerCompositor::setForcedCompositingLayer(RenderLayer* layer, bool force) |
-{ |
- if (force) { |
- layer->ensureBacking(); |
- layer->backing()->forceCompositingLayer(); |
- } else { |
- if (layer->backing()) |
- layer->backing()->forceCompositingLayer(false); |
- } |
-} |
- |
-RenderLayer* RenderLayerCompositor::ancestorCompositingLayer(const RenderLayer* layer) const |
-{ |
- if (!layer->parent()) |
- return 0; |
- |
- return layer->parent()->renderer()->enclosingCompositingLayer(); |
-} |
- |
-void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) |
-{ |
- ASSERT(childLayer->isComposited()); |
- ASSERT(!parentLayer || parentLayer->isComposited()); |
- |
- if (parentLayer) { |
- GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers(); |
- GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers(); |
- |
- hostingLayer->addChild(hostedLayer); |
- } else |
- childLayer->backing()->childForSuperlayers()->removeFromParent(); |
- |
- // FIXME: setCompositingParent() is only called at present by rebuildCompositingLayerTree(), |
- // which calls updateGraphicsLayerGeometry via updateLayerCompositingState(), so this should |
- // be optimized. |
- if (parentLayer) |
- childLayer->backing()->updateGraphicsLayerGeometry(); |
-} |
- |
-void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) |
-{ |
- ASSERT(layer->isComposited()); |
- |
- GraphicsLayer* hostingLayer = layer->backing()->parentForSublayers(); |
- hostingLayer->removeAllChildren(); |
-} |
- |
-void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) |
-{ |
- ASSERT(layer->isComposited()); |
- |
- GraphicsLayer* layerAnchor = layer->backing()->childForSuperlayers(); |
- |
- if (layerAnchor->parent() != m_rootPlatformLayer) { |
- layerAnchor->removeFromParent(); |
- if (m_rootPlatformLayer) |
- m_rootPlatformLayer->addChild(layerAnchor); |
- } |
-} |
- |
-void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState) |
-{ |
- updateLayerCompositingState(layer, StyleDifferenceEqual); |
- |
- // host the document layer in the RenderView's root layer |
- if (layer->isDocumentLayer()) |
- parentInRootLayer(layer); |
- |
- CompositingState childState = ioCompState; |
- if (layer->isComposited()) |
- childState.m_compositingAncestor = layer; |
- |
-#ifndef NDEBUG |
- ++childState.m_depth; |
-#endif |
- |
- RenderLayerBacking* layerBacking = layer->backing(); |
- |
- // FIXME: make this more incremental |
- if (layer->isComposited()) { |
- layerBacking->parentForSublayers()->removeAllChildren(); |
- layerBacking->updateInternalHierarchy(); |
- } |
- |
- // The children of this stacking context don't need to composite, unless there is |
- // a compositing layer among them, so start by assuming false. |
- childState.m_subtreeIsCompositing = false; |
- |
- if (layer->isStackingContext()) { |
- ASSERT(!layer->m_zOrderListsDirty); |
- |
- Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
- if (negZOrderList && negZOrderList->size() > 0) { |
- for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- rebuildCompositingLayerTree(curLayer, childState); |
- if (curLayer->isComposited()) |
- setCompositingParent(curLayer, childState.m_compositingAncestor); |
- } |
- } |
- |
- if (layerBacking && layerBacking->contentsLayer()) { |
- // we only have a contents layer if we have an m_layer |
- layerBacking->contentsLayer()->removeFromParent(); |
- |
- GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer(); |
- hostingLayer->addChild(layerBacking->contentsLayer()); |
- } |
- } |
- |
- ASSERT(!layer->m_overflowListDirty); |
- Vector<RenderLayer*>* overflowList = layer->overflowList(); |
- if (overflowList && overflowList->size() > 0) { |
- for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- rebuildCompositingLayerTree(curLayer, childState); |
- if (curLayer->isComposited()) |
- setCompositingParent(curLayer, childState.m_compositingAncestor); |
- } |
- } |
- |
- if (layer->isStackingContext()) { |
- Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
- if (posZOrderList && posZOrderList->size() > 0) { |
- for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- rebuildCompositingLayerTree(curLayer, childState); |
- if (curLayer->isComposited()) |
- setCompositingParent(curLayer, childState.m_compositingAncestor); |
- } |
- } |
- } |
-} |
- |
-void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& absRect) |
-{ |
- recursiveRepaintLayerRect(rootRenderLayer(), absRect); |
-} |
- |
-void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect) |
-{ |
- if (layer->isComposited()) |
- layer->setBackingNeedsRepaintInRect(rect); |
- |
- if (layer->hasCompositingDescendant()) { |
- Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
- if (negZOrderList) { |
- for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- int x = 0, y = 0; |
- curLayer->convertToLayerCoords(layer, x, y); |
- IntRect childRect(rect); |
- childRect.move(-x, -y); |
- recursiveRepaintLayerRect(curLayer, childRect); |
- } |
- } |
- |
- Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
- if (posZOrderList) { |
- for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- int x = 0, y = 0; |
- curLayer->convertToLayerCoords(layer, x, y); |
- IntRect childRect(rect); |
- childRect.move(-x, -y); |
- recursiveRepaintLayerRect(curLayer, childRect); |
- } |
- } |
- |
- Vector<RenderLayer*>* overflowList = layer->overflowList(); |
- if (overflowList) { |
- for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
- RenderLayer* curLayer = (*it); |
- int x = 0, y = 0; |
- curLayer->convertToLayerCoords(layer, x, y); |
- IntRect childRect(rect); |
- childRect.move(-x, -y); |
- recursiveRepaintLayerRect(curLayer, childRect); |
- } |
- } |
- } |
-} |
- |
-RenderLayer* RenderLayerCompositor::rootRenderLayer() const |
-{ |
- return m_renderView->layer(); |
-} |
- |
-GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const |
-{ |
- return m_rootPlatformLayer; |
-} |
- |
-void RenderLayerCompositor::didMoveOnscreen() |
-{ |
- if (!m_rootPlatformLayer) |
- return; |
- |
- Frame* frame = m_renderView->frameView()->frame(); |
- Page* page = frame ? frame->page() : 0; |
- if (!page) |
- return; |
- |
- page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer); |
- m_rootLayerAttached = true; |
-} |
- |
-void RenderLayerCompositor::willMoveOffscreen() |
-{ |
- if (!m_rootPlatformLayer || !m_rootLayerAttached) |
- return; |
- |
- Frame* frame = m_renderView->frameView()->frame(); |
- Page* page = frame ? frame->page() : 0; |
- if (!page) |
- return; |
- |
- page->chrome()->client()->attachRootGraphicsLayer(frame, 0); |
- m_rootLayerAttached = false; |
-} |
- |
-void RenderLayerCompositor::updateRootLayerPosition() |
-{ |
- if (m_rootPlatformLayer) |
- m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); |
-} |
- |
-bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const |
-{ |
- return requiresCompositingLayer(layer) || (layer->backing() && layer->backing()->forcedCompositingLayer()); |
-} |
- |
-static bool requiresCompositingLayerForTransform(RenderObject*) |
-{ |
- // 2D transforms are rendered in software, unless animating (which is tested separately). |
- return false; |
-} |
- |
-#define VERBOSE_COMPOSITINGLAYER 0 |
- |
-// Note: this specifies whether the RL needs a compositing layer for intrinsic reasons. |
-// Use needsToBeComposited() to determine if a RL actually needs a compositing layer. |
-// static |
-bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const |
-{ |
- // FIXME: cache the result of these tests? |
-#if VERBOSE_COMPOSITINGLAYER |
- bool gotReason = false; |
- |
- if (!gotReason && inCompositingMode() && layer->isDocumentLayer()) { |
- fprintf(stderr, "RenderLayer %p requires compositing layer because: it's the document root\n", layer); |
- gotReason = true; |
- } |
- |
- if (!gotReason && requiresCompositingLayerForTransform(layer->renderer())) { |
- fprintf(stderr, "RenderLayer %p requires compositing layer because: it has 3d transform, perspective, backface, or animating transform\n", layer); |
- gotReason = true; |
- } |
- |
- if (!gotReason && clipsCompositingDescendants(layer)) { |
- fprintf(stderr, "RenderLayer %p requires compositing layer because: it has overflow clip\n", layer); |
- gotReason = true; |
- } |
- |
- if (!gotReason && requiresCompositingForAnimation(layer)) { |
- fprintf(stderr, "RenderLayer %p requires compositing layer because: it has a running transition for opacity or transform\n", layer); |
- gotReason = true; |
- } |
- |
- if (!gotReason) |
- fprintf(stderr, "RenderLayer %p does not require compositing layer\n", layer); |
-#endif |
- |
- // the root layer always has a compositing layer (for now). |
- return (inCompositingMode() && layer->isDocumentLayer()) || |
- requiresCompositingLayerForTransform(layer->renderer()) || |
- clipsCompositingDescendants(layer) || |
- requiresCompositingForAnimation(layer); |
-} |
- |
-// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips, |
-// up to the enclosing compositing ancestor. This is required because compositing layers are parented |
-// according to the z-order hierarchy, yet clipping goes down the renderer hierarchy. |
-// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, |
-// but a sibling in the z-order hierarchy. |
-bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const |
-{ |
- if (!layer->isComposited() || !layer->parent()) |
- return false; |
- |
- RenderLayer* compositingAncestor = ancestorCompositingLayer(layer); |
- |
- // We need ancestor clipping if something clips between this layer and its compositing, stacking context ancestor |
- for (RenderLayer* curLayer = layer->parent(); curLayer && curLayer != compositingAncestor; curLayer = curLayer->parent()) { |
- // FIXME: need to look at hasClip() too eventually |
- if (curLayer->renderer()->hasOverflowClip()) |
- return true; |
- |
- // Clip is reset for an absolutely positioned element. |
- // FIXME: many cases are broken. We need more of the logic in calculateClipRects() here |
- if (curLayer->renderer()->style()->position() == AbsolutePosition) |
- break; |
- } |
- |
- return false; |
-} |
- |
-// Return true if the given layer is a stacking context and has compositing child |
-// layers that it needs to clip. In this case we insert a clipping GraphicsLayer |
-// into the hierarchy between this layer and its children in the z-order hierarchy. |
-bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const |
-{ |
- // FIXME: need to look at hasClip() too eventually |
- return layer->hasCompositingDescendant() && |
- layer->isStackingContext() && |
- layer->renderer()->hasOverflowClip(); |
-} |
- |
-bool RenderLayerCompositor::requiresCompositingForAnimation(const RenderLayer* layer) const |
-{ |
- AnimationController* animController = layer->renderer()->animation(); |
- if (animController) |
- return animController->isAnimatingPropertyOnRenderer(layer->renderer(), CSSPropertyOpacity) || |
- animController->isAnimatingPropertyOnRenderer(layer->renderer(), CSSPropertyWebkitTransform); |
- return false; |
-} |
- |
-// If an element has negative z-index children, those children render in front of the |
-// layer background, so we need an extra 'contents' layer for the foreground of the layer |
-// object. |
-bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const |
-{ |
- return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0); |
-} |
- |
-void RenderLayerCompositor::ensureRootPlatformLayer() |
-{ |
- if (m_rootPlatformLayer) |
- return; |
- |
- m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0); |
- m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); |
- m_rootPlatformLayer->setPosition(FloatPoint(0, 0)); |
- |
- if (GraphicsLayer::graphicsContextsFlipped()) |
- m_rootPlatformLayer->setChildrenTransform(flipTransform()); |
- |
- // Need to clip to prevent transformed content showing outside this frame |
- m_rootPlatformLayer->setMasksToBounds(true); |
- |
- didMoveOnscreen(); |
-} |
- |
-} // namespace WebCore |
- |
-#endif // USE(ACCELERATED_COMPOSITING) |
- |
+/* |
+ * Copyright (C) 2009 Apple Inc. All rights reserved. |
+ * |
+ * Redistribution and use in source and binary forms, with or without |
+ * modification, are permitted provided that the following conditions |
+ * are met: |
+ * 1. Redistributions of source code must retain the above copyright |
+ * notice, this list of conditions and the following disclaimer. |
+ * 2. Redistributions in binary form must reproduce the above copyright |
+ * notice, this list of conditions and the following disclaimer in the |
+ * documentation and/or other materials provided with the distribution. |
+ * |
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR |
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+ */ |
+ |
+#include "config.h" |
+ |
+#if USE(ACCELERATED_COMPOSITING) |
+#include "RenderLayerCompositor.h" |
+ |
+#include "AnimationController.h" |
+#include "ChromeClient.h" |
+#include "CSSPropertyNames.h" |
+#include "FrameView.h" |
+#include "GraphicsLayer.h" |
+#include "HitTestRequest.h" |
+#include "HitTestResult.h" |
+#include "Page.h" |
+#include "RenderLayerBacking.h" |
+#include "RenderView.h" |
+ |
+#if PROFILE_LAYER_REBUILD |
+#include <wtf/CurrentTime.h> |
+#endif |
+ |
+#ifndef NDEBUG |
+#include "CString.h" |
+#include "RenderTreeAsText.h" |
+#endif |
+ |
+namespace WebCore { |
+ |
+struct CompositingState { |
+ CompositingState(RenderLayer* compAncestor) |
+ : m_subtreeIsCompositing(false) |
+ , m_compositingAncestor(compAncestor) |
+#ifndef NDEBUG |
+ , m_depth(0) |
+#endif |
+ { |
+ } |
+ |
+ bool m_subtreeIsCompositing; |
+ RenderLayer* m_compositingAncestor; |
+#ifndef NDEBUG |
+ int m_depth; |
+#endif |
+}; |
+ |
+static TransformationMatrix flipTransform() |
+{ |
+ TransformationMatrix flipper; |
+ flipper.flipY(); |
+ return flipper; |
+} |
+ |
+RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) |
+ : m_renderView(renderView) |
+ , m_rootPlatformLayer(0) |
+ , m_compositing(false) |
+ , m_rootLayerAttached(false) |
+ , m_compositingLayersNeedUpdate(false) |
+#if PROFILE_LAYER_REBUILD |
+ , m_rootLayerUpdateCount(0) |
+#endif // PROFILE_LAYER_REBUILD |
+{ |
+} |
+ |
+RenderLayerCompositor::~RenderLayerCompositor() |
+{ |
+ ASSERT(!m_rootLayerAttached); |
+ delete m_rootPlatformLayer; |
+} |
+ |
+void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) |
+{ |
+ if (enable != m_compositing) { |
+ m_compositing = enable; |
+ |
+ // We never go out of compositing mode for a given page, |
+ // but if all the layers disappear, we'll just be left with |
+ // the empty root layer, which has minimal overhead. |
+ if (m_compositing) |
+ ensureRootPlatformLayer(); |
+ } |
+} |
+ |
+void RenderLayerCompositor::setCompositingLayersNeedUpdate(bool needUpdate) |
+{ |
+ if (inCompositingMode()) |
+ m_compositingLayersNeedUpdate = needUpdate; |
+} |
+ |
+void RenderLayerCompositor::updateCompositingLayers(RenderLayer* updateRoot) |
+{ |
+ if (!m_compositingLayersNeedUpdate) |
+ return; |
+ |
+ ASSERT(inCompositingMode()); |
+ |
+ if (!updateRoot) { |
+ // Only clear the flag if we're updating the entire hierarchy |
+ m_compositingLayersNeedUpdate = false; |
+ updateRoot = rootRenderLayer(); |
+ } |
+ |
+#if PROFILE_LAYER_REBUILD |
+ ++m_rootLayerUpdateCount; |
+ |
+ double startTime = WTF::currentTime(); |
+#endif |
+ |
+ // Go through the layers in presentation order, so that we can compute which |
+ // RLs need compositing layers. |
+ // FIXME: we could maybe do this in one pass, but the parenting logic would be more |
+ // complex. |
+ { |
+ CompositingState compState(updateRoot); |
+ computeCompositingRequirements(updateRoot, compState); |
+ } |
+ |
+ // Now create and parent the compositing layers. |
+ { |
+ CompositingState compState(updateRoot); |
+ rebuildCompositingLayerTree(updateRoot, compState); |
+ } |
+ |
+#if PROFILE_LAYER_REBUILD |
+ double endTime = WTF::currentTime(); |
+ if (!updateRoot) |
+ fprintf(stderr, "Update %d: computeCompositingRequirements for the world took %fms\n" |
+ m_rootLayerUpdateCount, 1000.0 * (endTime - startTime)); |
+#endif |
+ ASSERT(updateRoot || !m_compositingLayersNeedUpdate); |
+} |
+ |
+bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, StyleDifference diff) |
+{ |
+ bool needsLayer = needsToBeComposited(layer); |
+ bool layerChanged = false; |
+ if (needsLayer) { |
+ enableCompositingMode(); |
+ if (!layer->backing()) { |
+ layer->ensureBacking(); |
+ layerChanged = true; |
+ } |
+ } else { |
+ if (layer->backing()) { |
+ layer->clearBacking(); |
+ layerChanged = true; |
+ } |
+ } |
+ |
+ if (layerChanged) { |
+ // Invalidate the parent in this region. |
+ RenderLayer* compLayer = ancestorCompositingLayer(layer); |
+ if (compLayer) { |
+ // We can't reliably compute a dirty rect, because style may have changed already, |
+ // so just dirty the whole parent layer |
+ compLayer->setBackingNeedsRepaint(); |
+ // The contents of this layer may be moving between the window |
+ // and a GraphicsLayer, so we need to make sure the window system |
+ // synchronizes those changes on the screen. |
+ m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); |
+ } |
+ |
+ layer->renderer()->compositingStateChanged(); |
+ } |
+ |
+ if (!needsLayer) |
+ return layerChanged; |
+ |
+ if (layer->backing()->updateGraphicsLayers(needsContentsCompositingLayer(layer), |
+ clippedByAncestor(layer), |
+ clipsCompositingDescendants(layer), |
+ diff >= StyleDifferenceRepaint)) |
+ layerChanged = true; |
+ |
+ return layerChanged; |
+} |
+ |
+// The bounds of the GraphicsLayer created for a compositing layer is the union of the bounds of all the descendant |
+// RenderLayers that are rendered by the composited RenderLayer. |
+IntRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer, IntRect* layerBoundingBox) |
+{ |
+ IntRect boundingBoxRect, unionBounds; |
+ boundingBoxRect = unionBounds = layer->boundingBox(layer); |
+ |
+ ASSERT(layer->isStackingContext() || (!layer->m_posZOrderList || layer->m_posZOrderList->size() == 0)); |
+ |
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
+ if (negZOrderList) { |
+ for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ if (!curLayer->isComposited()) { |
+ IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); |
+ unionBounds.unite(childUnionBounds); |
+ } |
+ } |
+ } |
+ |
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
+ if (posZOrderList) { |
+ for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ if (!curLayer->isComposited()) { |
+ IntRect childUnionBounds = calculateCompositedBounds(curLayer, layer); |
+ unionBounds.unite(childUnionBounds); |
+ } |
+ } |
+ } |
+ |
+ Vector<RenderLayer*>* overflowList = layer->overflowList(); |
+ if (overflowList) { |
+ for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ if (!curLayer->isComposited()) { |
+ IntRect curAbsBounds = calculateCompositedBounds(curLayer, layer); |
+ unionBounds.unite(curAbsBounds); |
+ } |
+ } |
+ } |
+ |
+ if (!layer->isComposited() && layer->transform()) { |
+ TransformationMatrix* affineTrans = layer->transform(); |
+ boundingBoxRect = affineTrans->mapRect(boundingBoxRect); |
+ unionBounds = affineTrans->mapRect(unionBounds); |
+ } |
+ |
+ int ancestorRelX = 0, ancestorRelY = 0; |
+ layer->convertToLayerCoords(ancestorLayer, ancestorRelX, ancestorRelY); |
+ unionBounds.move(ancestorRelX, ancestorRelY); |
+ |
+ if (layerBoundingBox) { |
+ boundingBoxRect.move(ancestorRelX, ancestorRelY); |
+ *layerBoundingBox = boundingBoxRect; |
+ } |
+ |
+ return unionBounds; |
+} |
+ |
+void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) |
+{ |
+ setCompositingLayersNeedUpdate(); |
+} |
+ |
+void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) |
+{ |
+ if (child->isComposited()) |
+ setCompositingParent(child, 0); |
+ |
+ // If the document is being torn down (document's renderer() is null), then there's |
+ // no need to do any layer updating. |
+ if (parent->renderer()->documentBeingDestroyed()) |
+ return; |
+ |
+ RenderLayer* compLayer = parent->renderer()->enclosingCompositingLayer(); |
+ if (compLayer) { |
+ IntRect ancestorRect = calculateCompositedBounds(child, compLayer); |
+ compLayer->setBackingNeedsRepaintInRect(ancestorRect); |
+ // The contents of this layer may be moving from a GraphicsLayer to the window, |
+ // so we need to make sure the window system synchronizes those changes on the screen. |
+ m_renderView->frameView()->setNeedsOneShotDrawingSynchronization(); |
+ } |
+ |
+ setCompositingLayersNeedUpdate(); |
+} |
+ |
+RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const |
+{ |
+ for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) { |
+ if (curr->isStackingContext()) |
+ return 0; |
+ |
+ if (curr->renderer()->hasOverflowClip()) |
+ return curr; |
+ } |
+ return 0; |
+} |
+ |
+// Recurse through the layers in z-index and overflow order (which is equivalent to painting order) |
+// For the z-order children of a compositing layer: |
+// If a child layers has a compositing layer, then all subsequent layers must |
+// be compositing in order to render above that layer. |
+// |
+// If a child in the negative z-order list is compositing, then the layer itself |
+// must be compositing so that its contents render over that child. |
+// This implies that its positive z-index children must also be compositing. |
+// |
+void RenderLayerCompositor::computeCompositingRequirements(RenderLayer* layer, struct CompositingState& ioCompState) |
+{ |
+ layer->updateLayerPosition(); |
+ layer->updateZOrderLists(); |
+ layer->updateOverflowList(); |
+ |
+ // Clear the flag |
+ layer->setHasCompositingDescendant(false); |
+ |
+ setForcedCompositingLayer(layer, ioCompState.m_subtreeIsCompositing); |
+ |
+ const bool isCompositingLayer = needsToBeComposited(layer); |
+ ioCompState.m_subtreeIsCompositing = isCompositingLayer; |
+ |
+ CompositingState childState = ioCompState; |
+ if (isCompositingLayer) |
+ childState.m_compositingAncestor = layer; |
+ |
+ // The children of this stacking context don't need to composite, unless there is |
+ // a compositing layer among them, so start by assuming false. |
+ childState.m_subtreeIsCompositing = false; |
+ |
+#ifndef NDEBUG |
+ ++childState.m_depth; |
+#endif |
+ |
+ if (layer->isStackingContext()) { |
+ ASSERT(!layer->m_zOrderListsDirty); |
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
+ if (negZOrderList && negZOrderList->size() > 0) { |
+ for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ computeCompositingRequirements(curLayer, childState); |
+ |
+ // if we have to make a layer for this child, make one now so we can have a contents layer |
+ // (since we need to ensure that the -ve z-order child renders underneath our contents) |
+ if (childState.m_subtreeIsCompositing) { |
+ // make |this| compositing |
+ setForcedCompositingLayer(layer, true); |
+ childState.m_compositingAncestor = layer; |
+ } |
+ } |
+ } |
+ } |
+ |
+ ASSERT(!layer->m_overflowListDirty); |
+ Vector<RenderLayer*>* overflowList = layer->overflowList(); |
+ if (overflowList && overflowList->size() > 0) { |
+ for (Vector<RenderLayer*>::const_iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ computeCompositingRequirements(curLayer, childState); |
+ } |
+ } |
+ |
+ if (layer->isStackingContext()) { |
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
+ if (posZOrderList && posZOrderList->size() > 0) { |
+ for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ computeCompositingRequirements(curLayer, childState); |
+ } |
+ } |
+ } |
+ |
+ // If we have a software transform, and we have layers under us, we need to also |
+ // be composited. Also, if we have opacity < 1, then we need to be a layer so that |
+ // the child layers are opaque, then rendered with opacity on this layer. |
+ if (childState.m_subtreeIsCompositing && |
+ (layer->renderer()->hasTransform() || layer->renderer()->style()->opacity() < 1)) |
+ setForcedCompositingLayer(layer, true); |
+ |
+ // Subsequent layers in the parent stacking context also need to composite. |
+ if (childState.m_subtreeIsCompositing) |
+ ioCompState.m_subtreeIsCompositing = true; |
+ |
+ // Set the flag to say that this SC has compositing children. |
+ // this can affect the answer to needsToBeComposited() when clipping, |
+ // but that's ok here. |
+ layer->setHasCompositingDescendant(childState.m_subtreeIsCompositing); |
+} |
+ |
+void RenderLayerCompositor::setForcedCompositingLayer(RenderLayer* layer, bool force) |
+{ |
+ if (force) { |
+ layer->ensureBacking(); |
+ layer->backing()->forceCompositingLayer(); |
+ } else { |
+ if (layer->backing()) |
+ layer->backing()->forceCompositingLayer(false); |
+ } |
+} |
+ |
+RenderLayer* RenderLayerCompositor::ancestorCompositingLayer(const RenderLayer* layer) const |
+{ |
+ if (!layer->parent()) |
+ return 0; |
+ |
+ return layer->parent()->renderer()->enclosingCompositingLayer(); |
+} |
+ |
+void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) |
+{ |
+ ASSERT(childLayer->isComposited()); |
+ ASSERT(!parentLayer || parentLayer->isComposited()); |
+ |
+ if (parentLayer) { |
+ GraphicsLayer* hostingLayer = parentLayer->backing()->parentForSublayers(); |
+ GraphicsLayer* hostedLayer = childLayer->backing()->childForSuperlayers(); |
+ |
+ hostingLayer->addChild(hostedLayer); |
+ } else |
+ childLayer->backing()->childForSuperlayers()->removeFromParent(); |
+ |
+ // FIXME: setCompositingParent() is only called at present by rebuildCompositingLayerTree(), |
+ // which calls updateGraphicsLayerGeometry via updateLayerCompositingState(), so this should |
+ // be optimized. |
+ if (parentLayer) |
+ childLayer->backing()->updateGraphicsLayerGeometry(); |
+} |
+ |
+void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) |
+{ |
+ ASSERT(layer->isComposited()); |
+ |
+ GraphicsLayer* hostingLayer = layer->backing()->parentForSublayers(); |
+ hostingLayer->removeAllChildren(); |
+} |
+ |
+void RenderLayerCompositor::parentInRootLayer(RenderLayer* layer) |
+{ |
+ ASSERT(layer->isComposited()); |
+ |
+ GraphicsLayer* layerAnchor = layer->backing()->childForSuperlayers(); |
+ |
+ if (layerAnchor->parent() != m_rootPlatformLayer) { |
+ layerAnchor->removeFromParent(); |
+ if (m_rootPlatformLayer) |
+ m_rootPlatformLayer->addChild(layerAnchor); |
+ } |
+} |
+ |
+void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, struct CompositingState& ioCompState) |
+{ |
+ updateLayerCompositingState(layer, StyleDifferenceEqual); |
+ |
+ // host the document layer in the RenderView's root layer |
+ if (layer->isRootLayer()) |
+ parentInRootLayer(layer); |
+ |
+ CompositingState childState = ioCompState; |
+ if (layer->isComposited()) |
+ childState.m_compositingAncestor = layer; |
+ |
+#ifndef NDEBUG |
+ ++childState.m_depth; |
+#endif |
+ |
+ RenderLayerBacking* layerBacking = layer->backing(); |
+ |
+ // FIXME: make this more incremental |
+ if (layer->isComposited()) { |
+ layerBacking->parentForSublayers()->removeAllChildren(); |
+ layerBacking->updateInternalHierarchy(); |
+ } |
+ |
+ // The children of this stacking context don't need to composite, unless there is |
+ // a compositing layer among them, so start by assuming false. |
+ childState.m_subtreeIsCompositing = false; |
+ |
+ if (layer->isStackingContext()) { |
+ ASSERT(!layer->m_zOrderListsDirty); |
+ |
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
+ if (negZOrderList && negZOrderList->size() > 0) { |
+ for (Vector<RenderLayer*>::const_iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ rebuildCompositingLayerTree(curLayer, childState); |
+ if (curLayer->isComposited()) |
+ setCompositingParent(curLayer, childState.m_compositingAncestor); |
+ } |
+ } |
+ |
+ if (layerBacking && layerBacking->contentsLayer()) { |
+ // we only have a contents layer if we have an m_layer |
+ layerBacking->contentsLayer()->removeFromParent(); |
+ |
+ GraphicsLayer* hostingLayer = layerBacking->clippingLayer() ? layerBacking->clippingLayer() : layerBacking->graphicsLayer(); |
+ hostingLayer->addChild(layerBacking->contentsLayer()); |
+ } |
+ } |
+ |
+ ASSERT(!layer->m_overflowListDirty); |
+ Vector<RenderLayer*>* overflowList = layer->overflowList(); |
+ if (overflowList && overflowList->size() > 0) { |
+ for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ rebuildCompositingLayerTree(curLayer, childState); |
+ if (curLayer->isComposited()) |
+ setCompositingParent(curLayer, childState.m_compositingAncestor); |
+ } |
+ } |
+ |
+ if (layer->isStackingContext()) { |
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
+ if (posZOrderList && posZOrderList->size() > 0) { |
+ for (Vector<RenderLayer*>::const_iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ rebuildCompositingLayerTree(curLayer, childState); |
+ if (curLayer->isComposited()) |
+ setCompositingParent(curLayer, childState.m_compositingAncestor); |
+ } |
+ } |
+ } |
+} |
+ |
+void RenderLayerCompositor::repaintCompositedLayersAbsoluteRect(const IntRect& absRect) |
+{ |
+ recursiveRepaintLayerRect(rootRenderLayer(), absRect); |
+} |
+ |
+void RenderLayerCompositor::recursiveRepaintLayerRect(RenderLayer* layer, const IntRect& rect) |
+{ |
+ if (layer->isComposited()) |
+ layer->setBackingNeedsRepaintInRect(rect); |
+ |
+ if (layer->hasCompositingDescendant()) { |
+ Vector<RenderLayer*>* negZOrderList = layer->negZOrderList(); |
+ if (negZOrderList) { |
+ for (Vector<RenderLayer*>::iterator it = negZOrderList->begin(); it != negZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ int x = 0, y = 0; |
+ curLayer->convertToLayerCoords(layer, x, y); |
+ IntRect childRect(rect); |
+ childRect.move(-x, -y); |
+ recursiveRepaintLayerRect(curLayer, childRect); |
+ } |
+ } |
+ |
+ Vector<RenderLayer*>* posZOrderList = layer->posZOrderList(); |
+ if (posZOrderList) { |
+ for (Vector<RenderLayer*>::iterator it = posZOrderList->begin(); it != posZOrderList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ int x = 0, y = 0; |
+ curLayer->convertToLayerCoords(layer, x, y); |
+ IntRect childRect(rect); |
+ childRect.move(-x, -y); |
+ recursiveRepaintLayerRect(curLayer, childRect); |
+ } |
+ } |
+ |
+ Vector<RenderLayer*>* overflowList = layer->overflowList(); |
+ if (overflowList) { |
+ for (Vector<RenderLayer*>::iterator it = overflowList->begin(); it != overflowList->end(); ++it) { |
+ RenderLayer* curLayer = (*it); |
+ int x = 0, y = 0; |
+ curLayer->convertToLayerCoords(layer, x, y); |
+ IntRect childRect(rect); |
+ childRect.move(-x, -y); |
+ recursiveRepaintLayerRect(curLayer, childRect); |
+ } |
+ } |
+ } |
+} |
+ |
+RenderLayer* RenderLayerCompositor::rootRenderLayer() const |
+{ |
+ return m_renderView->layer(); |
+} |
+ |
+GraphicsLayer* RenderLayerCompositor::rootPlatformLayer() const |
+{ |
+ return m_rootPlatformLayer; |
+} |
+ |
+void RenderLayerCompositor::didMoveOnscreen() |
+{ |
+ if (!m_rootPlatformLayer) |
+ return; |
+ |
+ Frame* frame = m_renderView->frameView()->frame(); |
+ Page* page = frame ? frame->page() : 0; |
+ if (!page) |
+ return; |
+ |
+ page->chrome()->client()->attachRootGraphicsLayer(frame, m_rootPlatformLayer); |
+ m_rootLayerAttached = true; |
+} |
+ |
+void RenderLayerCompositor::willMoveOffscreen() |
+{ |
+ if (!m_rootPlatformLayer || !m_rootLayerAttached) |
+ return; |
+ |
+ Frame* frame = m_renderView->frameView()->frame(); |
+ Page* page = frame ? frame->page() : 0; |
+ if (!page) |
+ return; |
+ |
+ page->chrome()->client()->attachRootGraphicsLayer(frame, 0); |
+ m_rootLayerAttached = false; |
+} |
+ |
+void RenderLayerCompositor::updateRootLayerPosition() |
+{ |
+ if (m_rootPlatformLayer) |
+ m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); |
+} |
+ |
+bool RenderLayerCompositor::needsToBeComposited(const RenderLayer* layer) const |
+{ |
+ return requiresCompositingLayer(layer) || (layer->backing() && layer->backing()->forcedCompositingLayer()); |
+} |
+ |
+static bool requiresCompositingLayerForTransform(RenderObject*) |
+{ |
+ // 2D transforms are rendered in software, unless animating (which is tested separately). |
+ return false; |
+} |
+ |
+#define VERBOSE_COMPOSITINGLAYER 0 |
+ |
+// Note: this specifies whether the RL needs a compositing layer for intrinsic reasons. |
+// Use needsToBeComposited() to determine if a RL actually needs a compositing layer. |
+// static |
+bool RenderLayerCompositor::requiresCompositingLayer(const RenderLayer* layer) const |
+{ |
+ // FIXME: cache the result of these tests? |
+#if VERBOSE_COMPOSITINGLAYER |
+ bool gotReason = false; |
+ |
+ if (!gotReason && inCompositingMode() && layer->isRootLayer()) { |
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it's the document root\n", layer); |
+ gotReason = true; |
+ } |
+ |
+ if (!gotReason && requiresCompositingLayerForTransform(layer->renderer())) { |
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has 3d transform, perspective, backface, or animating transform\n", layer); |
+ gotReason = true; |
+ } |
+ |
+ if (!gotReason && clipsCompositingDescendants(layer)) { |
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has overflow clip\n", layer); |
+ gotReason = true; |
+ } |
+ |
+ if (!gotReason && requiresCompositingForAnimation(layer)) { |
+ fprintf(stderr, "RenderLayer %p requires compositing layer because: it has a running transition for opacity or transform\n", layer); |
+ gotReason = true; |
+ } |
+ |
+ if (!gotReason) |
+ fprintf(stderr, "RenderLayer %p does not require compositing layer\n", layer); |
+#endif |
+ |
+ // The root layer always has a compositing layer, but it may not have backing. |
+ return (inCompositingMode() && layer->isRootLayer()) || |
+ requiresCompositingLayerForTransform(layer->renderer()) || |
+ clipsCompositingDescendants(layer) || |
+ requiresCompositingForAnimation(layer); |
+} |
+ |
+// Return true if the given layer has some ancestor in the RenderLayer hierarchy that clips, |
+// up to the enclosing compositing ancestor. This is required because compositing layers are parented |
+// according to the z-order hierarchy, yet clipping goes down the renderer hierarchy. |
+// Thus, a RenderLayer can be clipped by a RenderLayer that is an ancestor in the renderer hierarchy, |
+// but a sibling in the z-order hierarchy. |
+bool RenderLayerCompositor::clippedByAncestor(RenderLayer* layer) const |
+{ |
+ if (!layer->isComposited() || !layer->parent()) |
+ return false; |
+ |
+ RenderLayer* compositingAncestor = ancestorCompositingLayer(layer); |
+ |
+ // We need ancestor clipping if something clips between this layer and its compositing, stacking context ancestor |
+ for (RenderLayer* curLayer = layer->parent(); curLayer && curLayer != compositingAncestor; curLayer = curLayer->parent()) { |
+ // FIXME: need to look at hasClip() too eventually |
+ if (curLayer->renderer()->hasOverflowClip()) |
+ return true; |
+ |
+ // Clip is reset for an absolutely positioned element. |
+ // FIXME: many cases are broken. We need more of the logic in calculateClipRects() here |
+ if (curLayer->renderer()->style()->position() == AbsolutePosition) |
+ break; |
+ } |
+ |
+ return false; |
+} |
+ |
+// Return true if the given layer is a stacking context and has compositing child |
+// layers that it needs to clip. In this case we insert a clipping GraphicsLayer |
+// into the hierarchy between this layer and its children in the z-order hierarchy. |
+bool RenderLayerCompositor::clipsCompositingDescendants(const RenderLayer* layer) const |
+{ |
+ // FIXME: need to look at hasClip() too eventually |
+ return layer->hasCompositingDescendant() && |
+ layer->isStackingContext() && |
+ layer->renderer()->hasOverflowClip(); |
+} |
+ |
+bool RenderLayerCompositor::requiresCompositingForAnimation(const RenderLayer* layer) const |
+{ |
+ AnimationController* animController = layer->renderer()->animation(); |
+ if (animController) |
+ return animController->isAnimatingPropertyOnRenderer(layer->renderer(), CSSPropertyOpacity) || |
+ animController->isAnimatingPropertyOnRenderer(layer->renderer(), CSSPropertyWebkitTransform); |
+ return false; |
+} |
+ |
+// If an element has negative z-index children, those children render in front of the |
+// layer background, so we need an extra 'contents' layer for the foreground of the layer |
+// object. |
+bool RenderLayerCompositor::needsContentsCompositingLayer(const RenderLayer* layer) const |
+{ |
+ return (layer->m_negZOrderList && layer->m_negZOrderList->size() > 0); |
+} |
+ |
+void RenderLayerCompositor::ensureRootPlatformLayer() |
+{ |
+ if (m_rootPlatformLayer) |
+ return; |
+ |
+ m_rootPlatformLayer = GraphicsLayer::createGraphicsLayer(0); |
+ m_rootPlatformLayer->setSize(FloatSize(m_renderView->docWidth(), m_renderView->docHeight())); |
+ m_rootPlatformLayer->setPosition(FloatPoint(0, 0)); |
+ |
+ if (GraphicsLayer::graphicsContextsFlipped()) |
+ m_rootPlatformLayer->setChildrenTransform(flipTransform()); |
+ |
+ // Need to clip to prevent transformed content showing outside this frame |
+ m_rootPlatformLayer->setMasksToBounds(true); |
+ |
+ didMoveOnscreen(); |
+} |
+ |
+} // namespace WebCore |
+ |
+#endif // USE(ACCELERATED_COMPOSITING) |
+ |