diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp')
-rw-r--r-- | chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp | 2605 |
1 files changed, 0 insertions, 2605 deletions
diff --git a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp b/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp deleted file mode 100644 index 45565a55007..00000000000 --- a/chromium/third_party/WebKit/Source/core/rendering/RenderLayerCompositor.cpp +++ /dev/null @@ -1,2605 +0,0 @@ -/* - * Copyright (C) 2009, 2010 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" - -#include "core/rendering/RenderLayerCompositor.h" - -#include "CSSPropertyNames.h" -#include "HTMLNames.h" -#include "RuntimeEnabledFeatures.h" -#include "core/animation/ActiveAnimations.h" -#include "core/animation/DocumentAnimations.h" -#include "core/dom/FullscreenElementStack.h" -#include "core/dom/NodeList.h" -#include "core/html/HTMLCanvasElement.h" -#include "core/html/HTMLIFrameElement.h" -#include "core/html/HTMLVideoElement.h" -#include "core/html/canvas/CanvasRenderingContext.h" -#include "core/inspector/InspectorInstrumentation.h" -#include "core/page/Chrome.h" -#include "core/frame/Frame.h" -#include "core/frame/FrameView.h" -#include "core/page/Page.h" -#include "core/frame/Settings.h" -#include "core/frame/animation/AnimationController.h" -#include "core/page/scrolling/ScrollingConstraints.h" -#include "core/page/scrolling/ScrollingCoordinator.h" -#include "core/rendering/CompositedLayerMapping.h" -#include "core/rendering/HitTestResult.h" -#include "core/rendering/RenderApplet.h" -#include "core/rendering/RenderEmbeddedObject.h" -#include "core/rendering/RenderFullScreen.h" -#include "core/rendering/RenderGeometryMap.h" -#include "core/rendering/RenderIFrame.h" -#include "core/rendering/RenderLayerStackingNode.h" -#include "core/rendering/RenderLayerStackingNodeIterator.h" -#include "core/rendering/RenderReplica.h" -#include "core/rendering/RenderVideo.h" -#include "core/rendering/RenderView.h" -#include "platform/OverscrollTheme.h" -#include "platform/TraceEvent.h" -#include "platform/geometry/TransformState.h" -#include "platform/graphics/GraphicsLayer.h" -#include "platform/scroll/ScrollbarTheme.h" -#include "public/platform/Platform.h" -#include "wtf/TemporaryChange.h" - -#ifndef NDEBUG -#include "core/rendering/RenderTreeAsText.h" -#endif - -namespace WebCore { - -using namespace HTMLNames; - -class OverlapMapContainer { -public: - void add(const IntRect& bounds) - { - m_layerRects.append(bounds); - m_boundingBox.unite(bounds); - } - - bool overlapsLayers(const IntRect& bounds) const - { - // Checking with the bounding box will quickly reject cases when - // layers are created for lists of items going in one direction and - // never overlap with each other. - if (!bounds.intersects(m_boundingBox)) - return false; - for (unsigned i = 0; i < m_layerRects.size(); i++) { - if (m_layerRects[i].intersects(bounds)) - return true; - } - return false; - } - - void unite(const OverlapMapContainer& otherContainer) - { - m_layerRects.append(otherContainer.m_layerRects); - m_boundingBox.unite(otherContainer.m_boundingBox); - } -private: - Vector<IntRect> m_layerRects; - IntRect m_boundingBox; -}; - -class RenderLayerCompositor::OverlapMap { - WTF_MAKE_NONCOPYABLE(OverlapMap); -public: - OverlapMap() - : m_geometryMap(UseTransforms) - { - // Begin by assuming the root layer will be composited so that there - // is something on the stack. The root layer should also never get a - // finishCurrentOverlapTestingContext() call. - beginNewOverlapTestingContext(); - } - - void add(const RenderLayer* layer, const IntRect& bounds) - { - // Layers do not contribute to overlap immediately--instead, they will - // contribute to overlap as soon as they have been recursively processed - // and popped off the stack. - ASSERT(m_overlapStack.size() >= 2); - m_overlapStack[m_overlapStack.size() - 2].add(bounds); - m_layers.add(layer); - } - - bool contains(const RenderLayer* layer) - { - return m_layers.contains(layer); - } - - bool overlapsLayers(const IntRect& bounds) const - { - return m_overlapStack.last().overlapsLayers(bounds); - } - - bool isEmpty() - { - return m_layers.isEmpty(); - } - - void beginNewOverlapTestingContext() - { - // This effectively creates a new "clean slate" for overlap state. - // This is used when we know that a subtree or remaining set of - // siblings does not need to check overlap with things behind it. - m_overlapStack.append(OverlapMapContainer()); - } - - void finishCurrentOverlapTestingContext() - { - // The overlap information on the top of the stack is still necessary - // for checking overlap of any layers outside this context that may - // overlap things from inside this context. Therefore, we must merge - // the information from the top of the stack before popping the stack. - // - // FIXME: we may be able to avoid this deep copy by rearranging how - // overlapMap state is managed. - m_overlapStack[m_overlapStack.size() - 2].unite(m_overlapStack.last()); - m_overlapStack.removeLast(); - } - - RenderGeometryMap& geometryMap() { return m_geometryMap; } - -private: - Vector<OverlapMapContainer> m_overlapStack; - HashSet<const RenderLayer*> m_layers; - RenderGeometryMap m_geometryMap; -}; - -struct CompositingRecursionData { - CompositingRecursionData(RenderLayer* compAncestor, bool testOverlap) - : m_compositingAncestor(compAncestor) - , m_subtreeIsCompositing(false) - , m_hasUnisolatedCompositedBlendingDescendant(false) - , m_testingOverlap(testOverlap) -#ifndef NDEBUG - , m_depth(0) -#endif - { - } - - CompositingRecursionData(const CompositingRecursionData& other) - : m_compositingAncestor(other.m_compositingAncestor) - , m_subtreeIsCompositing(other.m_subtreeIsCompositing) - , m_hasUnisolatedCompositedBlendingDescendant(other.m_hasUnisolatedCompositedBlendingDescendant) - , m_testingOverlap(other.m_testingOverlap) -#ifndef NDEBUG - , m_depth(other.m_depth + 1) -#endif - { - } - - RenderLayer* m_compositingAncestor; - bool m_subtreeIsCompositing; - bool m_hasUnisolatedCompositedBlendingDescendant; - bool m_testingOverlap; -#ifndef NDEBUG - int m_depth; -#endif -}; - - -RenderLayerCompositor::RenderLayerCompositor(RenderView* renderView) - : m_renderView(renderView) - , m_hasAcceleratedCompositing(true) - , m_compositingTriggers(static_cast<ChromeClient::CompositingTriggerFlags>(ChromeClient::AllTriggers)) - , m_showRepaintCounter(false) - , m_needsToRecomputeCompositingRequirements(false) - , m_needsToUpdateLayerTreeGeometry(false) - , m_compositing(false) - , m_compositingLayersNeedRebuild(false) - , m_forceCompositingMode(false) - , m_inPostLayoutUpdate(false) - , m_needsUpdateCompositingRequirementsState(false) - , m_isTrackingRepaints(false) - , m_rootLayerAttachment(RootLayerUnattached) -{ -} - -RenderLayerCompositor::~RenderLayerCompositor() -{ - ASSERT(m_rootLayerAttachment == RootLayerUnattached); -} - -void RenderLayerCompositor::enableCompositingMode(bool enable /* = true */) -{ - if (enable != m_compositing) { - m_compositing = enable; - - if (m_compositing) { - ensureRootLayer(); - notifyIFramesOfCompositingChange(); - } else - destroyRootLayer(); - } -} - -void RenderLayerCompositor::cacheAcceleratedCompositingFlags() -{ - bool hasAcceleratedCompositing = false; - bool showRepaintCounter = false; - bool forceCompositingMode = false; - - if (Settings* settings = m_renderView->document().settings()) { - hasAcceleratedCompositing = settings->acceleratedCompositingEnabled(); - - // We allow the chrome to override the settings, in case the page is rendered - // on a chrome that doesn't allow accelerated compositing. - if (hasAcceleratedCompositing) { - if (Page* page = this->page()) { - m_compositingTriggers = page->chrome().client().allowedCompositingTriggers(); - hasAcceleratedCompositing = m_compositingTriggers; - } - } - - showRepaintCounter = settings->showRepaintCounter(); - forceCompositingMode = settings->forceCompositingMode() && hasAcceleratedCompositing; - - if (forceCompositingMode && !isMainFrame()) - forceCompositingMode = requiresCompositingForScrollableFrame(); - } - - if (hasAcceleratedCompositing != m_hasAcceleratedCompositing || showRepaintCounter != m_showRepaintCounter || forceCompositingMode != m_forceCompositingMode) - setCompositingLayersNeedRebuild(); - - m_hasAcceleratedCompositing = hasAcceleratedCompositing; - m_showRepaintCounter = showRepaintCounter; - m_forceCompositingMode = forceCompositingMode; -} - -bool RenderLayerCompositor::layerSquashingEnabled() const -{ - if (Settings* settings = m_renderView->document().settings()) - return settings->layerSquashingEnabled(); - - return false; -} - -bool RenderLayerCompositor::canRender3DTransforms() const -{ - return hasAcceleratedCompositing() && (m_compositingTriggers & ChromeClient::ThreeDTransformTrigger); -} - -void RenderLayerCompositor::setCompositingLayersNeedRebuild(bool needRebuild) -{ - // FIXME: crbug,com/332248 ideally this could be merged with setNeedsCompositingUpdate(). - if (inCompositingMode()) - m_compositingLayersNeedRebuild = needRebuild; - - m_renderView->frameView()->scheduleAnimation(); -} - -void RenderLayerCompositor::didChangeVisibleRect() -{ - GraphicsLayer* rootLayer = rootGraphicsLayer(); - if (!rootLayer) - return; - - FrameView* frameView = m_renderView ? m_renderView->frameView() : 0; - if (!frameView) - return; - - IntRect visibleRect = m_containerLayer ? IntRect(IntPoint(), frameView->contentsSize()) : frameView->visibleContentRect(); - if (rootLayer->visibleRectChangeRequiresFlush(visibleRect)) { - if (Page* page = this->page()) - page->chrome().client().scheduleCompositingLayerFlush(); - } -} - -void RenderLayerCompositor::updateCompositingRequirementsState() -{ - if (!m_needsUpdateCompositingRequirementsState) - return; - - TRACE_EVENT0("blink_rendering,comp-scroll", "RenderLayerCompositor::updateCompositingRequirementsState"); - - m_needsUpdateCompositingRequirementsState = false; - - if (!rootRenderLayer() || !rootRenderLayer()->acceleratedCompositingForOverflowScrollEnabled()) - return; - - for (HashSet<RenderLayer*>::iterator it = m_outOfFlowPositionedLayers.begin(); it != m_outOfFlowPositionedLayers.end(); ++it) - (*it)->updateHasUnclippedDescendant(); - - const FrameView::ScrollableAreaSet* scrollableAreas = m_renderView->frameView()->scrollableAreas(); - if (!scrollableAreas) - return; - - for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it) - (*it)->updateNeedsCompositedScrolling(); -} - -static RenderVideo* findFullscreenVideoRenderer(Document* document) -{ - Element* fullscreenElement = FullscreenElementStack::currentFullScreenElementFrom(document); - while (fullscreenElement && fullscreenElement->isFrameOwnerElement()) { - document = toHTMLFrameOwnerElement(fullscreenElement)->contentDocument(); - if (!document) - return 0; - fullscreenElement = FullscreenElementStack::currentFullScreenElementFrom(document); - } - if (!fullscreenElement || !isHTMLVideoElement(fullscreenElement)) - return 0; - RenderObject* renderer = fullscreenElement->renderer(); - if (!renderer) - return 0; - return toRenderVideo(renderer); -} - -void RenderLayerCompositor::finishCompositingUpdateForFrameTree(Frame* frame) -{ - for (Frame* child = frame->tree().firstChild(); child; child = child->tree().nextSibling()) - finishCompositingUpdateForFrameTree(child); - - // Update compositing for current frame after all descendant frames are updated. - if (frame && frame->contentRenderer()) { - RenderLayerCompositor* frameCompositor = frame->contentRenderer()->compositor(); - if (frameCompositor && !frameCompositor->isMainFrame()) - frame->contentRenderer()->compositor()->updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - } -} - -void RenderLayerCompositor::updateCompositingLayers(CompositingUpdateType updateType) -{ - // Avoid updating the layers with old values. Compositing layers will be updated after the layout is finished. - if (m_renderView->needsLayout()) - return; - - if (updateType == CompositingUpdateFinishAllDeferredWork && isMainFrame() && m_renderView->frameView()) - finishCompositingUpdateForFrameTree(&m_renderView->frameView()->frame()); - - if (m_forceCompositingMode && !m_compositing) - enableCompositingMode(true); - - if (!m_needsToRecomputeCompositingRequirements && !m_compositing) - return; - - AnimationUpdateBlock animationUpdateBlock(m_renderView->frameView()->frame().animation()); - - TemporaryChange<bool> postLayoutChange(m_inPostLayoutUpdate, true); - - bool needCompositingRequirementsUpdate = false; - bool needHierarchyAndGeometryUpdate = false; - bool needGeometryUpdate = false; - bool needsToUpdateScrollingCoordinator = false; - - // CompositingUpdateFinishAllDeferredWork is the only updateType that will actually do any work in this - // function. All other updateTypes will simply mark that something needed updating, and defer the actual - // update. This way we only need to compute all compositing state once for every frame drawn (if needed). - switch (updateType) { - case CompositingUpdateAfterStyleChange: - case CompositingUpdateAfterLayout: - m_needsToRecomputeCompositingRequirements = true; - break; - case CompositingUpdateOnScroll: - m_needsToRecomputeCompositingRequirements = true; // Overlap can change with scrolling, so need to check for hierarchy updates. - m_needsToUpdateLayerTreeGeometry = true; - break; - case CompositingUpdateOnCompositedScroll: - m_needsToUpdateLayerTreeGeometry = true; - break; - case CompositingUpdateFinishAllDeferredWork: - needCompositingRequirementsUpdate = m_needsToRecomputeCompositingRequirements; - needHierarchyAndGeometryUpdate = m_compositingLayersNeedRebuild; - needGeometryUpdate = m_needsToUpdateLayerTreeGeometry; - needsToUpdateScrollingCoordinator = scrollingCoordinator() ? scrollingCoordinator()->needsToUpdateAfterCompositingChange() : false; - break; - } - - if (!needCompositingRequirementsUpdate && !needHierarchyAndGeometryUpdate && !needGeometryUpdate && !needsToUpdateScrollingCoordinator) - return; - - ASSERT(updateType == CompositingUpdateFinishAllDeferredWork); - - // Only clear the flags if we're updating the entire hierarchy. - m_compositingLayersNeedRebuild = false; - m_needsToUpdateLayerTreeGeometry = false; - m_needsToRecomputeCompositingRequirements = false; - RenderLayer* updateRoot = rootRenderLayer(); - - if (needCompositingRequirementsUpdate) { - // Go through the layers in presentation order, so that we can compute which RenderLayers need compositing layers. - // FIXME: we could maybe do this and the hierarchy udpate in one pass, but the parenting logic would be more complex. - CompositingRecursionData recursionData(updateRoot, true); - bool layersChanged = false; - bool saw3DTransform = false; - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::computeCompositingRequirements"); - OverlapMap overlapTestRequestMap; - - // FIXME: Passing these unclippedDescendants down and keeping track - // of them dynamically, we are requiring a full tree walk. This - // should be removed as soon as proper overlap testing based on - // scrolling and animation bounds is implemented (crbug.com/252472). - Vector<RenderLayer*> unclippedDescendants; - computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants); - } - - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::assignLayersToBackings"); - assignLayersToBackings(updateRoot, layersChanged); - } - - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateHasVisibleNonLayerContentLoop"); - const FrameView::ScrollableAreaSet* scrollableAreas = m_renderView->frameView()->scrollableAreas(); - if (scrollableAreas) { - for (FrameView::ScrollableAreaSet::iterator it = scrollableAreas->begin(); it != scrollableAreas->end(); ++it) - (*it)->updateHasVisibleNonLayerContent(); - } - } - - needHierarchyAndGeometryUpdate |= layersChanged; - } - - if (needHierarchyAndGeometryUpdate) { - // Update the hierarchy of the compositing layers. - Vector<GraphicsLayer*> childList; - { - TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::rebuildCompositingLayerTree"); - rebuildCompositingLayerTree(updateRoot, childList, 0); - } - - // Host the document layer in the RenderView's root layer. - if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && isMainFrame()) { - RenderVideo* video = findFullscreenVideoRenderer(&m_renderView->document()); - if (video && video->hasCompositedLayerMapping()) { - childList.clear(); - childList.append(video->compositedLayerMapping()->mainGraphicsLayer()); - } - } - - if (childList.isEmpty()) - destroyRootLayer(); - else - m_rootContentLayer->setChildren(childList); - } else if (needGeometryUpdate) { - // We just need to do a geometry update. This is only used for position:fixed scrolling; - // most of the time, geometry is updated via RenderLayer::styleChanged(). - updateLayerTreeGeometry(updateRoot); - } - - ASSERT(updateRoot || !m_compositingLayersNeedRebuild); - - if (!hasAcceleratedCompositing()) - enableCompositingMode(false); - - // The scrolling coordinator may realize that it needs updating while compositing was being updated in this function. - needsToUpdateScrollingCoordinator |= scrollingCoordinator() ? scrollingCoordinator()->needsToUpdateAfterCompositingChange() : false; - if (needsToUpdateScrollingCoordinator && isMainFrame() && scrollingCoordinator() && inCompositingMode()) - scrollingCoordinator()->updateAfterCompositingChange(); - - // Inform the inspector that the layer tree has changed. - if (isMainFrame()) - InspectorInstrumentation::layerTreeDidChange(page()); -} - -static bool requiresCompositing(CompositingReasons reasons) -{ - // Any reasons other than overlap or assumed overlap will require the layer to be separately compositing. - return reasons & ~CompositingReasonComboAllOverlapReasons; -} - -static bool requiresSquashing(CompositingReasons reasons) -{ - // If the layer has overlap or assumed overlap, but no other reasons, then it should be squashed. - return !requiresCompositing(reasons) && (reasons & CompositingReasonComboAllOverlapReasons); -} - -static bool requiresCompositingOrSquashing(CompositingReasons reasons) -{ -#ifndef NDEBUG - bool fastAnswer = reasons != CompositingReasonNone; - bool slowAnswer = requiresCompositing(reasons) || requiresSquashing(reasons); - ASSERT(fastAnswer == slowAnswer); -#endif - return reasons != CompositingReasonNone; -} - -void RenderLayerCompositor::addOutOfFlowPositionedLayer(RenderLayer* layer) -{ - m_outOfFlowPositionedLayers.add(layer); -} - -void RenderLayerCompositor::removeOutOfFlowPositionedLayer(RenderLayer* layer) -{ - m_outOfFlowPositionedLayers.remove(layer); -} - -bool RenderLayerCompositor::allocateOrClearCompositedLayerMapping(RenderLayer* layer) -{ - bool compositedLayerMappingChanged = false; - RenderLayer::ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason = RenderLayer::NoNotCompositedReason; - requiresCompositingForPosition(layer->renderer(), layer, &viewportConstrainedNotCompositedReason); - - // FIXME: It would be nice to directly use the layer's compositing reason, - // but allocateOrClearCompositedLayerMapping also gets called without having updated compositing - // requirements fully. - if (needsOwnBacking(layer)) { - enableCompositingMode(); - - if (!layer->hasCompositedLayerMapping()) { - // If we need to repaint, do so before allocating the compositedLayerMapping - repaintOnCompositingChange(layer); - - layer->ensureCompositedLayerMapping(); - compositedLayerMappingChanged = true; - - // At this time, the ScrollingCooridnator only supports the top-level frame. - if (layer->isRootLayer() && isMainFrame()) { - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->frameViewRootLayerDidChange(m_renderView->frameView()); - } - - // If this layer was previously squashed, we need to remove its reference to a groupedMapping right away, so - // that computing repaint rects will know the layer's correct compositingState. - // FIXME: do we need to also remove the layer from it's location in the squashing list of its groupedMapping? - // Need to create a test where a squashed layer pops into compositing. And also to cover all other - // sorts of compositingState transitions. - layer->setGroupedMapping(0); - - // FIXME: it seems premature to compute this before all compositing state has been updated? - // This layer and all of its descendants have cached repaints rects that are relative to - // the repaint container, so change when compositing changes; we need to update them here. - if (layer->parent()) - layer->repainter().computeRepaintRectsIncludingDescendants(); - } - - if (layer->compositedLayerMapping()->updateRequiresOwnBackingStoreForIntrinsicReasons()) - compositedLayerMappingChanged = true; - } else { - if (layer->hasCompositedLayerMapping()) { - // If we're removing the compositedLayerMapping from a reflection, clear the source GraphicsLayer's pointer to - // its replica GraphicsLayer. In practice this should never happen because reflectee and reflection - // are both either composited, or not composited. - if (layer->isReflection()) { - RenderLayer* sourceLayer = toRenderLayerModelObject(layer->renderer()->parent())->layer(); - if (sourceLayer->hasCompositedLayerMapping()) { - ASSERT(sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->replicaLayer() == layer->compositedLayerMapping()->mainGraphicsLayer()); - sourceLayer->compositedLayerMapping()->mainGraphicsLayer()->setReplicatedByLayer(0); - } - } - - removeViewportConstrainedLayer(layer); - - layer->clearCompositedLayerMapping(); - compositedLayerMappingChanged = true; - - // This layer and all of its descendants have cached repaints rects that are relative to - // the repaint container, so change when compositing changes; we need to update them here. - layer->repainter().computeRepaintRectsIncludingDescendants(); - - // If we need to repaint, do so now that we've removed the compositedLayerMapping - repaintOnCompositingChange(layer); - } - } - - if (compositedLayerMappingChanged && layer->renderer()->isRenderPart()) { - RenderLayerCompositor* innerCompositor = frameContentsCompositor(toRenderPart(layer->renderer())); - if (innerCompositor && innerCompositor->inCompositingMode()) - innerCompositor->updateRootLayerAttachment(); - } - - if (compositedLayerMappingChanged) - layer->clipper().clearClipRectsIncludingDescendants(PaintingClipRects); - - // If a fixed position layer gained/lost a compositedLayerMapping or the reason not compositing it changed, - // the scrolling coordinator needs to recalculate whether it can do fast scrolling. - bool nonCompositedReasonChanged = false; - if (layer->renderer()->style()->position() == FixedPosition) { - if (layer->viewportConstrainedNotCompositedReason() != viewportConstrainedNotCompositedReason) { - layer->setViewportConstrainedNotCompositedReason(viewportConstrainedNotCompositedReason); - nonCompositedReasonChanged = true; - } - if (compositedLayerMappingChanged || nonCompositedReasonChanged) { - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView->frameView()); - } - } - - return compositedLayerMappingChanged || nonCompositedReasonChanged; -} - -bool RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer) -{ - updateDirectCompositingReasons(layer); - bool layerChanged = allocateOrClearCompositedLayerMapping(layer); - - if (layerSquashingEnabled()) { - // FIXME: this is not correct... info may be out of date and squashing returning true doesn't indicate that the layer changed - layerChanged = requiresSquashing(layer->compositingReasons()); - } - - // See if we need content or clipping layers. Methods called here should assume - // that the compositing state of descendant layers has not been updated yet. - if (layer->hasCompositedLayerMapping() && layer->compositedLayerMapping()->updateGraphicsLayerConfiguration()) - layerChanged = true; - - return layerChanged; -} - -void RenderLayerCompositor::repaintOnCompositingChange(RenderLayer* layer) -{ - // If the renderer is not attached yet, no need to repaint. - if (layer->renderer() != m_renderView && !layer->renderer()->parent()) - return; - - RenderLayerModelObject* repaintContainer = layer->renderer()->containerForRepaint(); - if (!repaintContainer) - repaintContainer = m_renderView; - - layer->repainter().repaintIncludingNonCompositingDescendants(repaintContainer); -} - -// This method assumes that layout is up-to-date, unlike repaintOnCompositingChange(). -void RenderLayerCompositor::repaintInCompositedAncestor(RenderLayer* layer, const LayoutRect& rect) -{ - RenderLayer* compositedAncestor = layer->enclosingCompositingLayerForRepaint(false /*exclude self*/); - if (compositedAncestor) { - // FIXME: make sure repaintRect is computed correctly for squashed scenario - LayoutPoint offset; - layer->convertToLayerCoords(compositedAncestor, offset); - - LayoutRect repaintRect = rect; - repaintRect.moveBy(offset); - - if (compositedAncestor->compositingState() == PaintsIntoOwnBacking) { - compositedAncestor->repainter().setBackingNeedsRepaintInRect(repaintRect); - } else if (compositedAncestor->compositingState() == PaintsIntoGroupedBacking) { - // FIXME: Need to perform the correct coordinate conversion for repaintRect here, including transforms - compositedAncestor->groupedMapping()->squashingLayer()->setNeedsDisplayInRect(repaintRect); - } else { - ASSERT_NOT_REACHED(); - } - } -} - -// 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) const -{ - if (!canBeComposited(layer)) - return IntRect(); - - RenderLayer::CalculateLayerBoundsFlags flags = RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask; -#if HAVE(COMPOSITOR_FILTER_OUTSETS) - // If the compositor computes its own filter outsets, don't include them in the composited bounds. - if (!layer->paintsWithFilters()) - flags &= ~RenderLayer::IncludeLayerFilterOutsets; -#endif - return layer->calculateLayerBounds(ancestorLayer, 0, flags); -} - -void RenderLayerCompositor::layerWasAdded(RenderLayer* /*parent*/, RenderLayer* /*child*/) -{ - setCompositingLayersNeedRebuild(); -} - -void RenderLayerCompositor::layerWillBeRemoved(RenderLayer* parent, RenderLayer* child) -{ - if (!child->hasCompositedLayerMapping() || parent->renderer()->documentBeingDestroyed()) - return; - - removeViewportConstrainedLayer(child); - repaintInCompositedAncestor(child, child->compositedLayerMapping()->compositedBounds()); - - setCompositingParent(child, 0); - setCompositingLayersNeedRebuild(); -} - -RenderLayer* RenderLayerCompositor::enclosingNonStackingClippingLayer(const RenderLayer* layer) const -{ - for (RenderLayer* curr = layer->parent(); curr != 0; curr = curr->parent()) { - if (curr->stackingNode()->isStackingContainer()) - return 0; - - if (curr->renderer()->hasClipOrOverflowClip()) - return curr; - } - return 0; -} - -void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds, bool& boundsComputed) -{ - if (layer->isRootLayer()) - return; - - if (!boundsComputed) { - // FIXME: If this layer's overlap bounds include its children, we don't need to add its - // children's bounds to the overlap map. - layerBounds = enclosingIntRect(overlapMap.geometryMap().absoluteRect(layer->overlapBounds())); - // Empty rects never intersect, but we need them to for the purposes of overlap testing. - if (layerBounds.isEmpty()) - layerBounds.setSize(IntSize(1, 1)); - boundsComputed = true; - } - - IntRect clipRect = pixelSnappedIntRect(layer->backgroundClipRect(ClipRectsContext(rootRenderLayer(), 0, AbsoluteClipRects)).rect()); // FIXME: Incorrect for CSS regions. - clipRect.intersect(layerBounds); - overlapMap.add(layer, clipRect); -} - -void RenderLayerCompositor::addToOverlapMapRecursive(OverlapMap& overlapMap, RenderLayer* layer, RenderLayer* ancestorLayer) -{ - if (!canBeComposited(layer) || overlapMap.contains(layer)) - return; - - // A null ancestorLayer is an indication that 'layer' has already been pushed. - if (ancestorLayer) - overlapMap.geometryMap().pushMappingsToAncestor(layer, ancestorLayer); - - IntRect bounds; - bool haveComputedBounds = false; - addToOverlapMap(overlapMap, layer, bounds, haveComputedBounds); - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - addToOverlapMapRecursive(overlapMap, curNode->layer(), layer); - - if (ancestorLayer) - overlapMap.geometryMap().popMappingsToAncestor(ancestorLayer); -} - -// 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* ancestorLayer, RenderLayer* layer, OverlapMap* overlapMap, CompositingRecursionData& currentRecursionData, bool& descendantHas3DTransform, Vector<RenderLayer*>& unclippedDescendants) -{ - layer->stackingNode()->updateLayerListsIfNeeded(); - - if (overlapMap) - overlapMap->geometryMap().pushMappingsToAncestor(layer, ancestorLayer); - - // Clear the flag - layer->setHasCompositingDescendant(false); - layer->setHasNonCompositedChild(false); - - // Start by assuming this layer will not need to composite. - CompositingReasons reasonsToComposite = CompositingReasonNone; - - // First accumulate the straightforward compositing reasons. - CompositingReasons directReasons = directReasonsForCompositing(layer); - - // Video is special. It's the only RenderLayer type that can both have - // RenderLayer children and whose children can't use its backing to render - // into. These children (the controls) always need to be promoted into their - // own layers to draw on top of the accelerated video. - if (currentRecursionData.m_compositingAncestor && currentRecursionData.m_compositingAncestor->renderer()->isVideo()) - directReasons |= CompositingReasonLayerForVideoOverlay; - - if (canBeComposited(layer)) - reasonsToComposite |= directReasons; - - // Next, accumulate reasons related to overlap. - // If overlap testing is used, this reason will be overridden. If overlap testing is not - // used, we must assume we overlap if there is anything composited behind us in paint-order. - CompositingReasons overlapCompositingReason = currentRecursionData.m_subtreeIsCompositing ? CompositingReasonAssumedOverlap : CompositingReasonNone; - - if (rootRenderLayer()->compositorDrivenAcceleratedScrollingEnabled()) { - Vector<size_t> unclippedDescendantsToRemove; - for (size_t i = 0; i < unclippedDescendants.size(); i++) { - RenderLayer* unclippedDescendant = unclippedDescendants.at(i); - // If we've reached the containing block of one of the unclipped - // descendants, that element is no longer relevant to whether or not we - // should opt in. Unfortunately we can't easily remove from the list - // while we're iterating, so we have to store it for later removal. - if (unclippedDescendant->renderer()->containingBlock() == layer->renderer()) { - unclippedDescendantsToRemove.append(i); - continue; - } - if (layer->scrollsWithRespectTo(unclippedDescendant)) - reasonsToComposite |= CompositingReasonAssumedOverlap; - } - - // Remove irrelevant unclipped descendants in reverse order so our stored - // indices remain valid. - for (size_t i = 0; i < unclippedDescendantsToRemove.size(); i++) - unclippedDescendants.remove(unclippedDescendantsToRemove.at(unclippedDescendantsToRemove.size() - i - 1)); - - if (reasonsToComposite & CompositingReasonOutOfFlowClipping) - unclippedDescendants.append(layer); - } - - bool haveComputedBounds = false; - IntRect absBounds; - // If we know for sure the layer is going to be composited, don't bother looking it up in the overlap map. - if (overlapMap && !overlapMap->isEmpty() && currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons)) { - // If we're testing for overlap, we only need to composite if we overlap something that is already composited. - absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds())); - - // Empty rects never intersect, but we need them to for the purposes of overlap testing. - if (absBounds.isEmpty()) - absBounds.setSize(IntSize(1, 1)); - haveComputedBounds = true; - overlapCompositingReason = overlapMap->overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone; - } - - reasonsToComposite |= overlapCompositingReason; - - // The children of this layer don't need to composite, unless there is - // a compositing layer among them, so start by inheriting the compositing - // ancestor with m_subtreeIsCompositing set to false. - CompositingRecursionData childRecursionData(currentRecursionData); - childRecursionData.m_subtreeIsCompositing = false; - - bool willBeComposited = canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite); - if (willBeComposited) { - // Tell the parent it has compositing descendants. - currentRecursionData.m_subtreeIsCompositing = true; - // This layer now acts as the ancestor for kids. - childRecursionData.m_compositingAncestor = layer; - - // Here we know that all children and the layer's own contents can blindly paint into - // this layer's backing, until a descendant is composited. So, we don't need to check - // for overlap with anything behind this layer. - if (overlapMap) - overlapMap->beginNewOverlapTestingContext(); - // This layer is going to be composited, so children can safely ignore the fact that there's an - // animation running behind this layer, meaning they can rely on the overlap map testing again. - childRecursionData.m_testingOverlap = true; - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - bool anyDescendantHas3DTransform = false; - bool willHaveForegroundLayer = false; - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) { - computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants); - - // 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 (childRecursionData.m_subtreeIsCompositing) { - reasonsToComposite |= CompositingReasonNegativeZIndexChildren; - - if (!willBeComposited) { - // make layer compositing - childRecursionData.m_compositingAncestor = layer; - overlapMap->beginNewOverlapTestingContext(); - willBeComposited = true; - willHaveForegroundLayer = true; - - // FIXME: temporary solution for the first negative z-index composited child: - // re-compute the absBounds for the child so that we can add the - // negative z-index child's bounds to the new overlap context. - if (overlapMap) { - overlapMap->geometryMap().pushMappingsToAncestor(curNode->layer(), layer); - IntRect childAbsBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(curNode->layer()->overlapBounds())); - bool boundsComputed = true; - overlapMap->beginNewOverlapTestingContext(); - addToOverlapMap(*overlapMap, curNode->layer(), childAbsBounds, boundsComputed); - overlapMap->finishCurrentOverlapTestingContext(); - overlapMap->geometryMap().popMappingsToAncestor(layer); - } - } - } - } - } - - if (overlapMap && willHaveForegroundLayer) { - ASSERT(willBeComposited); - // A foreground layer effectively is a new backing for all subsequent children, so - // we don't need to test for overlap with anything behind this. So, we can finish - // the previous context that was accumulating rects for the negative z-index - // children, and start with a fresh new empty context. - overlapMap->finishCurrentOverlapTestingContext(); - overlapMap->beginNewOverlapTestingContext(); - // This layer is going to be composited, so children can safely ignore the fact that there's an - // animation running behind this layer, meaning they can rely on the overlap map testing again - childRecursionData.m_testingOverlap = true; - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants); - - // Now that the subtree has been traversed, we can check for compositing reasons that depended on the state of the subtree. - - // If we entered compositing mode during the recursion, the root will also need to be composited (as long as accelerated compositing is enabled). - if (layer->isRootLayer()) { - if (inCompositingMode() && m_hasAcceleratedCompositing) - willBeComposited = true; - } - - // All layers (even ones that aren't being composited) need to get added to - // the overlap map. Layers that are not separately composited will paint into their - // compositing ancestor's backing, and so are still considered for overlap. - if (overlapMap && childRecursionData.m_compositingAncestor && !childRecursionData.m_compositingAncestor->isRootLayer()) - addToOverlapMap(*overlapMap, layer, absBounds, haveComputedBounds); - - if (layer->stackingNode()->isStackingContext()) { - layer->setShouldIsolateCompositedDescendants(childRecursionData.m_hasUnisolatedCompositedBlendingDescendant); - } else { - layer->setShouldIsolateCompositedDescendants(false); - currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = childRecursionData.m_hasUnisolatedCompositedBlendingDescendant; - } - - // Now check for reasons to become composited that depend on the state of descendant layers. - CompositingReasons subtreeCompositingReasons = subtreeReasonsForCompositing(layer->renderer(), childRecursionData.m_subtreeIsCompositing, anyDescendantHas3DTransform); - reasonsToComposite |= subtreeCompositingReasons; - if (!willBeComposited && canBeComposited(layer) && requiresCompositingOrSquashing(subtreeCompositingReasons)) { - childRecursionData.m_compositingAncestor = layer; - if (overlapMap) { - // FIXME: this context push is effectively a no-op but needs to exist for - // now, because the code is designed to push overlap information to the - // second-from-top context of the stack. - overlapMap->beginNewOverlapTestingContext(); - addToOverlapMapRecursive(*overlapMap, layer); - } - willBeComposited = true; - } - - // If the original layer is composited, the reflection needs to be, too. - if (layer->reflectionInfo()) { - // FIXME: Shouldn't we call computeCompositingRequirements to handle a reflection overlapping with another renderer? - CompositingReasons reflectionCompositingReason = willBeComposited ? CompositingReasonReflectionOfCompositedParent : CompositingReasonNone; - layer->reflectionInfo()->reflectionLayer()->setCompositingReasons(layer->reflectionInfo()->reflectionLayer()->compositingReasons() | reflectionCompositingReason); - } - - // Subsequent layers in the parent's stacking context may also need to composite. - if (childRecursionData.m_subtreeIsCompositing) - currentRecursionData.m_subtreeIsCompositing = true; - - if (willBeComposited && layer->hasBlendMode()) - currentRecursionData.m_hasUnisolatedCompositedBlendingDescendant = true; - - // Set the flag to say that this SC has compositing children. - layer->setHasCompositingDescendant(childRecursionData.m_subtreeIsCompositing); - - // Turn overlap testing off for later layers if it's already off, or if we have an animating transform. - // Note that if the layer clips its descendants, there's no reason to propagate the child animation to the parent layers. That's because - // we know for sure the animation is contained inside the clipping rectangle, which is already added to the overlap map. - bool isCompositedClippingLayer = canBeComposited(layer) && (reasonsToComposite & CompositingReasonClipsCompositingDescendants); - if ((!childRecursionData.m_testingOverlap && !isCompositedClippingLayer) || isRunningAcceleratedTransformAnimation(layer->renderer())) - currentRecursionData.m_testingOverlap = false; - - if (overlapMap && childRecursionData.m_compositingAncestor == layer && !layer->isRootLayer()) - overlapMap->finishCurrentOverlapTestingContext(); - - if (layer->isRootLayer()) { - // The root layer needs to be composited if anything else in the tree is composited. - // Otherwise, we can disable compositing entirely. - if (childRecursionData.m_subtreeIsCompositing || requiresCompositingOrSquashing(reasonsToComposite) || m_forceCompositingMode) { - willBeComposited = true; - reasonsToComposite |= CompositingReasonRoot; - } else { - enableCompositingMode(false); - willBeComposited = false; - reasonsToComposite = CompositingReasonNone; - } - } - - // At this point we have finished collecting all reasons to composite this layer. - layer->setCompositingReasons(reasonsToComposite); - - if (!willBeComposited && layer->parent()) - layer->parent()->setHasNonCompositedChild(true); - - descendantHas3DTransform |= anyDescendantHas3DTransform || layer->has3DTransform(); - - if (overlapMap) - overlapMap->geometryMap().popMappingsToAncestor(ancestorLayer); -} - -void RenderLayerCompositor::SquashingState::updateSquashingStateForNewMapping(CompositedLayerMappingPtr newCompositedLayerMapping, bool hasNewCompositedLayerMapping, IntPoint newOffsetFromAbsolute) -{ - // The most recent backing is done accumulating any more squashing layers. - if (hasMostRecentMapping) - mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex); - - nextSquashedLayerIndex = 0; - mostRecentMapping = newCompositedLayerMapping; - hasMostRecentMapping = hasNewCompositedLayerMapping; - offsetFromAbsolute = newOffsetFromAbsolute; -} - -static IntPoint computeOffsetFromAbsolute(RenderLayer* layer) -{ - TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); - layer->renderer()->mapLocalToContainer(0, transformState, ApplyContainerFlip); - transformState.flatten(); - return roundedIntPoint(transformState.lastPlanarPoint()); -} - -void RenderLayerCompositor::assignLayersToBackings(RenderLayer* updateRoot, bool& layersChanged) -{ - SquashingState squashingState; - assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged); - if (squashingState.hasMostRecentMapping) - squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex); -} - -void RenderLayerCompositor::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged) -{ - if (allocateOrClearCompositedLayerMapping(layer)) - layersChanged = true; - - if (layer->reflectionInfo() && updateLayerCompositingState(layer->reflectionInfo()->reflectionLayer())) - layersChanged = true; - - // Add this layer to a squashing backing if needed. - if (layerSquashingEnabled()) { - // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than - // the layer's own primary contents. This would happen when we have a composited negative z-index element that needs to - // paint on top of the background, but below the layer's main contents. For now, because we always composite layers - // when they have a composited negative z-index child, such layers will never need squashing so it is not yet an issue. - if (requiresSquashing(layer->compositingReasons())) { - // A layer that is squashed with other layers cannot have its own CompositedLayerMapping. - ASSERT(!layer->hasCompositedLayerMapping()); - ASSERT(squashingState.hasMostRecentMapping); - - IntPoint offsetFromAbsolute = computeOffsetFromAbsolute(layer); - - // FIXME: see if we can refactor this to be clearer - IntSize offsetFromTargetBacking(offsetFromAbsolute.x() - squashingState.offsetFromAbsolute.x(), - offsetFromAbsolute.y() - squashingState.offsetFromAbsolute.y()); - - squashingState.mostRecentMapping->addRenderLayerToSquashingGraphicsLayer(layer, offsetFromTargetBacking, squashingState.nextSquashedLayerIndex); - squashingState.nextSquashedLayerIndex++; - - // FIXME: does this need to be true here? Do we need more logic to decide when it should be true? - layersChanged = true; - - // FIXME: this should be conditioned on whether this layer actually changed status - layer->clipper().clearClipRectsIncludingDescendants(); - } - } - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged); - } - - if (layerSquashingEnabled()) { - // At this point, if the layer is to be "separately" composited, then its backing becomes the most recent in paint-order. - if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) { - ASSERT(!requiresSquashing(layer->compositingReasons())); - IntPoint offsetFromAbsolute = computeOffsetFromAbsolute(layer); - squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping(), offsetFromAbsolute); - } - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged); -} - -void RenderLayerCompositor::setCompositingParent(RenderLayer* childLayer, RenderLayer* parentLayer) -{ - ASSERT(!parentLayer || childLayer->ancestorCompositingLayer() == parentLayer); - ASSERT(childLayer->hasCompositedLayerMapping()); - - // It's possible to be called with a parent that isn't yet composited when we're doing - // partial updates as required by painting or hit testing. Just bail in that case; - // we'll do a full layer update soon. - if (!parentLayer || !parentLayer->hasCompositedLayerMapping()) - return; - - if (parentLayer) { - GraphicsLayer* hostingLayer = parentLayer->compositedLayerMapping()->parentForSublayers(); - GraphicsLayer* hostedLayer = childLayer->compositedLayerMapping()->childForSuperlayers(); - - hostingLayer->addChild(hostedLayer); - } else { - childLayer->compositedLayerMapping()->childForSuperlayers()->removeFromParent(); - } -} - -void RenderLayerCompositor::removeCompositedChildren(RenderLayer* layer) -{ - ASSERT(layer->hasCompositedLayerMapping()); - - GraphicsLayer* hostingLayer = layer->compositedLayerMapping()->parentForSublayers(); - hostingLayer->removeAllChildren(); -} - -bool RenderLayerCompositor::canAccelerateVideoRendering(RenderVideo* o) const -{ - if (!m_hasAcceleratedCompositing) - return false; - - return o->supportsAcceleratedRendering(); -} - -void RenderLayerCompositor::rebuildCompositingLayerTree(RenderLayer* layer, Vector<GraphicsLayer*>& childLayersOfEnclosingLayer, int depth) -{ - // Make the layer compositing if necessary, and set up clipping and content layers. - // Note that we can only do work here that is independent of whether the descendant layers - // have been processed. computeCompositingRequirements() will already have done the repaint if necessary. - - layer->stackingNode()->updateLayerListsIfNeeded(); - - // Used for gathering UMA data about the effect on memory usage of promoting all layers - // that have a webkit-transition on opacity or transform and intersect the viewport. - static double pixelsWithoutPromotingAllTransitions = 0.0; - static double pixelsAddedByPromotingAllTransitions = 0.0; - - if (!depth) { - pixelsWithoutPromotingAllTransitions = 0.0; - pixelsAddedByPromotingAllTransitions = 0.0; - } - - const bool hasCompositedLayerMapping = layer->hasCompositedLayerMapping(); - CompositedLayerMappingPtr currentCompositedLayerMapping = layer->compositedLayerMapping(); - if (hasCompositedLayerMapping) { - // The compositing state of all our children has been updated already, so now - // we can compute and cache the composited bounds for this layer. - currentCompositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - currentCompositedLayerMapping->updateGraphicsLayerConfiguration(); - currentCompositedLayerMapping->updateGraphicsLayerGeometry(); - - if (!layer->parent()) - updateRootLayerPosition(); - - if (currentCompositedLayerMapping->hasUnpositionedOverflowControlsLayers()) - layer->scrollableArea()->positionOverflowControls(); - - pixelsWithoutPromotingAllTransitions += layer->size().height() * layer->size().width(); - } else { - if ((layer->renderer()->style()->transitionForProperty(CSSPropertyOpacity) || - layer->renderer()->style()->transitionForProperty(CSSPropertyWebkitTransform)) && - m_renderView->viewRect().intersects(layer->absoluteBoundingBox())) - pixelsAddedByPromotingAllTransitions += layer->size().height() * layer->size().width(); - } - - // If this layer has a compositedLayerMapping, then that is where we place subsequent children GraphicsLayers. - // Otherwise children continue to append to the child list of the enclosing layer. - Vector<GraphicsLayer*> layerChildren; - Vector<GraphicsLayer*>& childList = hasCompositedLayerMapping ? layerChildren : childLayersOfEnclosingLayer; - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - if (layer->stackingNode()->isStackingContainer()) { - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - rebuildCompositingLayerTree(curNode->layer(), childList, depth + 1); - - // If a negative z-order child is compositing, we get a foreground layer which needs to get parented. - if (hasCompositedLayerMapping && currentCompositedLayerMapping->foregroundLayer()) - childList.append(currentCompositedLayerMapping->foregroundLayer()); - } - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - rebuildCompositingLayerTree(curNode->layer(), childList, depth + 1); - - if (hasCompositedLayerMapping) { - bool parented = false; - if (layer->renderer()->isRenderPart()) - parented = parentFrameContentLayers(toRenderPart(layer->renderer())); - - if (!parented) - currentCompositedLayerMapping->parentForSublayers()->setChildren(layerChildren); - - // If the layer has a clipping layer the overflow controls layers will be siblings of the clipping layer. - // Otherwise, the overflow control layers are normal children. - if (!currentCompositedLayerMapping->hasClippingLayer() && !currentCompositedLayerMapping->hasScrollingLayer()) { - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForHorizontalScrollbar()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForVerticalScrollbar()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - - if (GraphicsLayer* overflowControlLayer = currentCompositedLayerMapping->layerForScrollCorner()) { - overflowControlLayer->removeFromParent(); - currentCompositedLayerMapping->parentForSublayers()->addChild(overflowControlLayer); - } - } - - childLayersOfEnclosingLayer.append(currentCompositedLayerMapping->childForSuperlayers()); - } - - if (!depth) { - int percentageIncreaseInPixels = static_cast<int>(pixelsAddedByPromotingAllTransitions / pixelsWithoutPromotingAllTransitions * 100); - blink::Platform::current()->histogramCustomCounts("Renderer.PixelIncreaseFromTransitions", percentageIncreaseInPixels, 0, 1000, 50); - } -} - -void RenderLayerCompositor::frameViewDidChangeLocation(const IntPoint& contentsOffset) -{ - if (m_overflowControlsHostLayer) - m_overflowControlsHostLayer->setPosition(contentsOffset); -} - -void RenderLayerCompositor::frameViewDidChangeSize() -{ - if (m_containerLayer) { - FrameView* frameView = m_renderView->frameView(); - m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); - - frameViewDidScroll(); - updateOverflowControlsLayers(); - } -} - -enum AcceleratedFixedRootBackgroundHistogramBuckets { - ScrolledMainFrameBucket = 0, - ScrolledMainFrameWithAcceleratedFixedRootBackground = 1, - ScrolledMainFrameWithUnacceleratedFixedRootBackground = 2, - AcceleratedFixedRootBackgroundHistogramMax = 3 -}; - -void RenderLayerCompositor::frameViewDidScroll() -{ - FrameView* frameView = m_renderView->frameView(); - IntPoint scrollPosition = frameView->scrollPosition(); - - if (!m_scrollLayer) - return; - - bool scrollingCoordinatorHandlesOffset = false; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) { - if (Settings* settings = m_renderView->document().settings()) { - if (isMainFrame() || settings->compositedScrollingForFramesEnabled()) - scrollingCoordinatorHandlesOffset = scrollingCoordinator->scrollableAreaScrollLayerDidChange(frameView); - } - } - - // Scroll position = scroll minimum + scroll offset. Adjust the layer's - // position to handle whatever the scroll coordinator isn't handling. - // The minimum scroll position is non-zero for RTL pages with overflow. - if (scrollingCoordinatorHandlesOffset) - m_scrollLayer->setPosition(-frameView->minimumScrollPosition()); - else - m_scrollLayer->setPosition(-scrollPosition); - - - blink::Platform::current()->histogramEnumeration("Renderer.AcceleratedFixedRootBackground", - ScrolledMainFrameBucket, - AcceleratedFixedRootBackgroundHistogramMax); - - if (!m_renderView->rootBackgroundIsEntirelyFixed()) - return; - - blink::Platform::current()->histogramEnumeration("Renderer.AcceleratedFixedRootBackground", - !!fixedRootBackgroundLayer() - ? ScrolledMainFrameWithAcceleratedFixedRootBackground - : ScrolledMainFrameWithUnacceleratedFixedRootBackground, - AcceleratedFixedRootBackgroundHistogramMax); -} - -void RenderLayerCompositor::frameViewDidLayout() -{ -} - -void RenderLayerCompositor::frameViewScrollbarsExistenceDidChange() -{ - if (m_containerLayer) - updateOverflowControlsLayers(); -} - -void RenderLayerCompositor::rootFixedBackgroundsChanged() -{ - if (!supportsFixedRootBackgroundCompositing()) - return; - - // To avoid having to make the fixed root background layer fixed positioned to - // stay put, we position it in the layer tree as follows: - // - // + Overflow controls host - // + Frame clip - // + (Fixed root background) <-- Here. - // + Frame scroll - // + Root content layer - // + Scrollbars - // - // That is, it needs to be the first child of the frame clip, the sibling of - // the frame scroll layer. The compositor does not own the background layer, it - // just positions it (like the foreground layer). - if (GraphicsLayer* backgroundLayer = fixedRootBackgroundLayer()) - m_containerLayer->addChildBelow(backgroundLayer, m_scrollLayer.get()); -} - -bool RenderLayerCompositor::scrollingLayerDidChange(RenderLayer* layer) -{ - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - return scrollingCoordinator->scrollableAreaScrollLayerDidChange(layer->scrollableArea()); - return false; -} - -String RenderLayerCompositor::layerTreeAsText(LayerTreeFlags flags) -{ - // Before dumping the layer tree, finish any pending compositing update. - updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - - if (!m_rootContentLayer) - return String(); - - // We skip dumping the scroll and clip layers to keep layerTreeAsText output - // similar between platforms (unless we explicitly request dumping from the - // root. - GraphicsLayer* rootLayer = m_rootContentLayer.get(); - if (flags & LayerTreeIncludesRootLayer) - rootLayer = rootGraphicsLayer(); - - String layerTreeText = rootLayer->layerTreeAsText(flags); - - // The true root layer is not included in the dump, so if we want to report - // its repaint rects, they must be included here. - if (flags & LayerTreeIncludesRepaintRects) - return m_renderView->frameView()->trackedRepaintRectsAsText() + layerTreeText; - - return layerTreeText; -} - -RenderLayerCompositor* RenderLayerCompositor::frameContentsCompositor(RenderPart* renderer) -{ - if (!renderer->node()->isFrameOwnerElement()) - return 0; - - HTMLFrameOwnerElement* element = toHTMLFrameOwnerElement(renderer->node()); - if (Document* contentDocument = element->contentDocument()) { - if (RenderView* view = contentDocument->renderView()) - return view->compositor(); - } - return 0; -} - -bool RenderLayerCompositor::parentFrameContentLayers(RenderPart* renderer) -{ - RenderLayerCompositor* innerCompositor = frameContentsCompositor(renderer); - if (!innerCompositor || !innerCompositor->inCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame) - return false; - - RenderLayer* layer = renderer->layer(); - if (!layer->hasCompositedLayerMapping()) - return false; - - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - GraphicsLayer* hostingLayer = compositedLayerMapping->parentForSublayers(); - GraphicsLayer* rootLayer = innerCompositor->rootGraphicsLayer(); - if (hostingLayer->children().size() != 1 || hostingLayer->children()[0] != rootLayer) { - hostingLayer->removeAllChildren(); - hostingLayer->addChild(rootLayer); - } - return true; -} - -// This just updates layer geometry without changing the hierarchy. -void RenderLayerCompositor::updateLayerTreeGeometry(RenderLayer* layer) -{ - if (layer->hasCompositedLayerMapping()) { - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - // The compositing state of all our children has been updated already, so now - // we can compute and cache the composited bounds for this layer. - compositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - compositedLayerMapping->updateGraphicsLayerConfiguration(); - compositedLayerMapping->updateGraphicsLayerGeometry(); - - if (!layer->parent()) - updateRootLayerPosition(); - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - updateLayerTreeGeometry(curNode->layer()); -} - -// Recurs down the RenderLayer tree until its finds the compositing descendants of compositingAncestor and updates their geometry. -void RenderLayerCompositor::updateCompositingDescendantGeometry(RenderLayerStackingNode* compositingAncestor, RenderLayer* layer, bool compositedChildrenOnly) -{ - if (layer->stackingNode() != compositingAncestor) { - if (layer->hasCompositedLayerMapping()) { - CompositedLayerMappingPtr compositedLayerMapping = layer->compositedLayerMapping(); - compositedLayerMapping->updateCompositedBounds(); - - if (layer->reflectionInfo()) { - RenderLayer* reflectionLayer = layer->reflectionInfo()->reflectionLayer(); - if (reflectionLayer->hasCompositedLayerMapping()) - reflectionLayer->compositedLayerMapping()->updateCompositedBounds(); - } - - compositedLayerMapping->updateGraphicsLayerGeometry(); - if (compositedChildrenOnly) - return; - } - } - - if (layer->reflectionInfo()) - updateCompositingDescendantGeometry(compositingAncestor, layer->reflectionInfo()->reflectionLayer(), compositedChildrenOnly); - - if (!layer->hasCompositingDescendant()) - return; - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) - updateCompositingDescendantGeometry(compositingAncestor, curNode->layer(), compositedChildrenOnly); -} - - -void RenderLayerCompositor::repaintCompositedLayers(const IntRect* absRect) -{ - recursiveRepaintLayer(rootRenderLayer(), absRect); -} - -void RenderLayerCompositor::recursiveRepaintLayer(RenderLayer* layer, const IntRect* rect) -{ - // FIXME: This method does not work correctly with transforms. - if (layer->compositingState() == PaintsIntoOwnBacking) { - if (rect) - layer->repainter().setBackingNeedsRepaintInRect(*rect); - else - layer->repainter().setBackingNeedsRepaint(); - } - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(layer->stackingNode()); -#endif - - unsigned childrenToVisit = NormalFlowChildren; - if (layer->hasCompositingDescendant()) - childrenToVisit |= PositiveZOrderChildren | NegativeZOrderChildren; - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), childrenToVisit); - while (RenderLayerStackingNode* curNode = iterator.next()) { - if (rect) { - IntRect childRect(*rect); - curNode->layer()->convertToPixelSnappedLayerCoords(layer, childRect); - recursiveRepaintLayer(curNode->layer(), &childRect); - } else { - recursiveRepaintLayer(curNode->layer()); - } - } -} - -RenderLayer* RenderLayerCompositor::rootRenderLayer() const -{ - return m_renderView->layer(); -} - -GraphicsLayer* RenderLayerCompositor::rootGraphicsLayer() const -{ - if (m_overflowControlsHostLayer) - return m_overflowControlsHostLayer.get(); - return m_rootContentLayer.get(); -} - -GraphicsLayer* RenderLayerCompositor::scrollLayer() const -{ - return m_scrollLayer.get(); -} - -void RenderLayerCompositor::setIsInWindow(bool isInWindow) -{ - if (!inCompositingMode()) - return; - - if (isInWindow) { - if (m_rootLayerAttachment != RootLayerUnattached) - return; - - RootLayerAttachment attachment = isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; - attachRootLayer(attachment); - } else { - if (m_rootLayerAttachment == RootLayerUnattached) - return; - - detachRootLayer(); - } -} - -void RenderLayerCompositor::clearMappingForRenderLayerIncludingDescendants(RenderLayer* layer) -{ - if (!layer) - return; - - if (layer->hasCompositedLayerMapping()) { - removeViewportConstrainedLayer(layer); - layer->clearCompositedLayerMapping(); - } - - for (RenderLayer* currLayer = layer->firstChild(); currLayer; currLayer = currLayer->nextSibling()) - clearMappingForRenderLayerIncludingDescendants(currLayer); -} - -void RenderLayerCompositor::clearMappingForAllRenderLayers() -{ - clearMappingForRenderLayerIncludingDescendants(m_renderView->layer()); -} - -void RenderLayerCompositor::updateRootLayerPosition() -{ - if (m_rootContentLayer) { - const IntRect& documentRect = m_renderView->documentRect(); - m_rootContentLayer->setSize(documentRect.size()); - m_rootContentLayer->setPosition(documentRect.location()); -#if USE(RUBBER_BANDING) - if (m_layerForOverhangShadow) - OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); -#endif - } - if (m_containerLayer) { - FrameView* frameView = m_renderView->frameView(); - m_containerLayer->setSize(frameView->unscaledVisibleContentSize()); - } -} - -bool RenderLayerCompositor::has3DContent() const -{ - return layerHas3DContent(rootRenderLayer()); -} - -void RenderLayerCompositor::updateDirectCompositingReasons(RenderLayer* layer) -{ - CompositingReasons layerReasons = layer->compositingReasons(); - - layerReasons &= ~CompositingReasonComboAllDirectReasons; - layerReasons |= directReasonsForCompositing(layer); - layer->setCompositingReasons(layerReasons); -} - -bool RenderLayerCompositor::needsOwnBacking(const RenderLayer* layer) const -{ - if (!canBeComposited(layer)) - return false; - - // If squashing is disabled, then layers that would have been squashed should just be separately composited. - bool needsOwnBackingForDisabledSquashing = !layerSquashingEnabled() && requiresSquashing(layer->compositingReasons()); - - return requiresCompositing(layer->compositingReasons()) || needsOwnBackingForDisabledSquashing || (inCompositingMode() && layer->isRootLayer()); -} - -bool RenderLayerCompositor::canBeComposited(const RenderLayer* layer) const -{ - // FIXME: We disable accelerated compositing for elements in a RenderFlowThread as it doesn't work properly. - // See http://webkit.org/b/84900 to re-enable it. - return m_hasAcceleratedCompositing && layer->isSelfPaintingLayer() && layer->renderer()->flowThreadState() == RenderObject::NotInsideFlowThread; -} - -CompositingReasons RenderLayerCompositor::directReasonsForCompositing(const RenderLayer* layer) const -{ - RenderObject* renderer = layer->renderer(); - CompositingReasons directReasons = CompositingReasonNone; - - if (requiresCompositingForTransform(renderer)) - directReasons |= CompositingReason3DTransform; - - // Only zero or one of the following conditions will be true for a given RenderLayer. - if (requiresCompositingForVideo(renderer)) - directReasons |= CompositingReasonVideo; - else if (requiresCompositingForCanvas(renderer)) - directReasons |= CompositingReasonCanvas; - else if (requiresCompositingForPlugin(renderer)) - directReasons |= CompositingReasonPlugin; - else if (requiresCompositingForFrame(renderer)) - directReasons |= CompositingReasonIFrame; - - if (requiresCompositingForBackfaceVisibilityHidden(renderer)) - directReasons |= CompositingReasonBackfaceVisibilityHidden; - - if (requiresCompositingForAnimation(renderer)) - directReasons |= CompositingReasonAnimation; - - if (requiresCompositingForTransition(renderer)) - directReasons |= CompositingReasonAnimation; - - if (requiresCompositingForFilters(renderer)) - directReasons |= CompositingReasonFilters; - - if (requiresCompositingForPosition(renderer, layer)) - directReasons |= renderer->style()->position() == FixedPosition ? CompositingReasonPositionFixed : CompositingReasonPositionSticky; - - if (requiresCompositingForOverflowScrolling(layer)) - directReasons |= CompositingReasonOverflowScrollingTouch; - - if (requiresCompositingForOverflowScrollingParent(layer)) - directReasons |= CompositingReasonOverflowScrollingParent; - - if (requiresCompositingForOutOfFlowClipping(layer)) - directReasons |= CompositingReasonOutOfFlowClipping; - - return directReasons; -} - -// 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(const RenderLayer* layer) const -{ - if (!layer->hasCompositedLayerMapping() || !layer->parent()) - return false; - - // FIXME: need to double-check if semantics of ancestorCompositingLayer() work correctly here? - const RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); - if (!compositingAncestor) - return false; - - // If the compositingAncestor clips, that will be taken care of by clipsCompositingDescendants(), - // so we only care about clipping between its first child that is our ancestor (the computeClipRoot), - // and layer. - const RenderLayer* computeClipRoot = 0; - const RenderLayer* curr = layer; - while (curr) { - const RenderLayer* next = curr->parent(); - if (next == compositingAncestor) { - computeClipRoot = curr; - break; - } - curr = next; - } - - if (!computeClipRoot || computeClipRoot == layer) - return false; - - return layer->backgroundClipRect(ClipRectsContext(computeClipRoot, 0, TemporaryClipRects)).rect() != PaintInfo::infiniteRect(); // FIXME: Incorrect for CSS regions. -} - -// 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 -{ - return layer->hasCompositingDescendant() && layer->renderer()->hasClipOrOverflowClip(); -} - -bool RenderLayerCompositor::requiresCompositingForScrollableFrame() const -{ - // Need this done first to determine overflow. - ASSERT(!m_renderView->needsLayout()); - if (isMainFrame()) - return false; - - if (!(m_compositingTriggers & ChromeClient::ScrollableInnerFrameTrigger)) - return false; - - FrameView* frameView = m_renderView->frameView(); - return frameView->isScrollable(); -} - -bool RenderLayerCompositor::requiresCompositingForTransform(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::ThreeDTransformTrigger)) - return false; - - RenderStyle* style = renderer->style(); - // Note that we ask the renderer if it has a transform, because the style may have transforms, - // but the renderer may be an inline that doesn't suppport them. - return renderer->hasTransform() && style->transform().has3DOperation(); -} - -bool RenderLayerCompositor::requiresCompositingForVideo(RenderObject* renderer) const -{ - if (RuntimeEnabledFeatures::overlayFullscreenVideoEnabled() && renderer->isVideo()) { - HTMLMediaElement* media = toHTMLMediaElement(renderer->node()); - if (media->isFullscreen()) - return true; - } - - if (!(m_compositingTriggers & ChromeClient::VideoTrigger)) - return false; - - if (renderer->isVideo()) { - RenderVideo* video = toRenderVideo(renderer); - return video->shouldDisplayVideo() && canAccelerateVideoRendering(video); - } - return false; -} - -bool RenderLayerCompositor::requiresCompositingForCanvas(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::CanvasTrigger)) - return false; - - if (renderer->isCanvas()) { - HTMLCanvasElement* canvas = toHTMLCanvasElement(renderer->node()); - return canvas->renderingContext() && canvas->renderingContext()->isAccelerated(); - } - return false; -} - -bool RenderLayerCompositor::requiresCompositingForPlugin(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::PluginTrigger)) - return false; - - bool composite = renderer->isEmbeddedObject() && toRenderEmbeddedObject(renderer)->allowsAcceleratedCompositing(); - if (!composite) - return false; - - // FIXME: this seems bogus. If we don't know the layout position/size of the plugin yet, would't that be handled elsewhere? - m_needsToRecomputeCompositingRequirements = true; - - RenderWidget* pluginRenderer = toRenderWidget(renderer); - // If we can't reliably know the size of the plugin yet, don't change compositing state. - if (pluginRenderer->needsLayout()) - return pluginRenderer->hasLayer() && pluginRenderer->layer()->hasCompositedLayerMapping(); - - // Don't go into compositing mode if height or width are zero, or size is 1x1. - IntRect contentBox = pixelSnappedIntRect(pluginRenderer->contentBoxRect()); - return contentBox.height() * contentBox.width() > 1; -} - -bool RenderLayerCompositor::requiresCompositingForFrame(RenderObject* renderer) const -{ - if (!renderer->isRenderPart()) - return false; - - RenderPart* frameRenderer = toRenderPart(renderer); - - if (!frameRenderer->requiresAcceleratedCompositing()) - return false; - - if (frameRenderer->node() && frameRenderer->node()->isFrameOwnerElement() && toHTMLFrameOwnerElement(frameRenderer->node())->contentFrame() && toHTMLFrameOwnerElement(frameRenderer->node())->contentFrame()->remotePlatformLayer()) - return true; - - // FIXME: this seems bogus. If we don't know the layout position/size of the frame yet, wouldn't that be handled elsehwere? - m_needsToRecomputeCompositingRequirements = true; - - RenderLayerCompositor* innerCompositor = frameContentsCompositor(frameRenderer); - if (!innerCompositor) - return false; - - // If we can't reliably know the size of the iframe yet, don't change compositing state. - if (renderer->needsLayout()) - return frameRenderer->hasLayer() && frameRenderer->layer()->hasCompositedLayerMapping(); - - // Don't go into compositing mode if height or width are zero. - IntRect contentBox = pixelSnappedIntRect(frameRenderer->contentBoxRect()); - return contentBox.height() * contentBox.width() > 0; -} - -bool RenderLayerCompositor::requiresCompositingForBackfaceVisibilityHidden(RenderObject* renderer) const -{ - return canRender3DTransforms() && renderer->style()->backfaceVisibility() == BackfaceVisibilityHidden; -} - -bool RenderLayerCompositor::requiresCompositingForAnimation(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - - if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) - return renderer->animation().isRunningAcceleratableAnimationOnRenderer(renderer); - - return shouldCompositeForActiveAnimations(*renderer); -} - -bool RenderLayerCompositor::requiresCompositingForTransition(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - - if (Settings* settings = m_renderView->document().settings()) { - if (!settings->acceleratedCompositingForTransitionEnabled()) - return false; - } - - return renderer->style()->transitionForProperty(CSSPropertyOpacity) - || renderer->style()->transitionForProperty(CSSPropertyWebkitFilter) - || renderer->style()->transitionForProperty(CSSPropertyWebkitTransform); -} - -CompositingReasons RenderLayerCompositor::subtreeReasonsForCompositing(RenderObject* renderer, bool hasCompositedDescendants, bool has3DTransformedDescendants) const -{ - CompositingReasons subtreeReasons = CompositingReasonNone; - - // FIXME: this seems to be a potentially different layer than the layer for which this was called. May not be an error, but is very confusing. - RenderLayer* layer = toRenderBoxModelObject(renderer)->layer(); - - // When a layer has composited descendants, some effects, like 2d transforms, filters, masks etc must be implemented - // via compositing so that they also apply to those composited descdendants. - if (hasCompositedDescendants) { - if (layer->transform()) - subtreeReasons |= CompositingReasonTransformWithCompositedDescendants; - - if (layer->shouldIsolateCompositedDescendants()) { - ASSERT(layer->stackingNode()->isStackingContext()); - subtreeReasons |= CompositingReasonIsolateCompositedDescendants; - } - - // If the implementation of createsGroup changes, we need to be aware of that in this part of code. - ASSERT((renderer->isTransparent() || renderer->hasMask() || renderer->hasFilter() || renderer->hasBlendMode()) == renderer->createsGroup()); - if (renderer->isTransparent()) - subtreeReasons |= CompositingReasonOpacityWithCompositedDescendants; - if (renderer->hasMask()) - subtreeReasons |= CompositingReasonMaskWithCompositedDescendants; - if (renderer->hasFilter()) - subtreeReasons |= CompositingReasonFilterWithCompositedDescendants; - if (renderer->hasBlendMode()) - subtreeReasons |= CompositingReasonBlendingWithCompositedDescendants; - - if (renderer->hasReflection()) - subtreeReasons |= CompositingReasonReflectionWithCompositedDescendants; - - if (renderer->hasClipOrOverflowClip()) - subtreeReasons |= CompositingReasonClipsCompositingDescendants; - } - - - // A layer with preserve-3d or perspective only needs to be composited if there are descendant layers that - // will be affected by the preserve-3d or perspective. - if (has3DTransformedDescendants) { - if (renderer->style()->transformStyle3D() == TransformStyle3DPreserve3D) - subtreeReasons |= CompositingReasonPreserve3D; - - if (renderer->style()->hasPerspective()) - subtreeReasons |= CompositingReasonPerspective; - } - - return subtreeReasons; -} - -bool RenderLayerCompositor::requiresCompositingForFilters(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::FilterTrigger)) - return false; - - return renderer->hasFilter(); -} - -bool RenderLayerCompositor::requiresCompositingForOverflowScrollingParent(const RenderLayer* layer) const -{ - return !!layer->scrollParent(); -} - -bool RenderLayerCompositor::requiresCompositingForOutOfFlowClipping(const RenderLayer* layer) const -{ - return layer->compositorDrivenAcceleratedScrollingEnabled() && layer->isUnclippedDescendant(); -} - -bool RenderLayerCompositor::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason) const -{ - // position:fixed elements that create their own stacking context (e.g. have an explicit z-index, - // opacity, transform) can get their own composited layer. A stacking context is required otherwise - // z-index and clipping will be broken. - if (!renderer->isPositioned()) - return false; - - EPosition position = renderer->style()->position(); - bool isFixed = renderer->isOutOfFlowPositioned() && position == FixedPosition; - if (isFixed && !layer->stackingNode()->isStackingContainer()) - return false; - - bool isSticky = renderer->isInFlowPositioned() && position == StickyPosition; - if (!isFixed && !isSticky) - return false; - - // FIXME: acceleratedCompositingForFixedPositionEnabled should probably be renamed acceleratedCompositingForViewportConstrainedPositionEnabled(). - if (Settings* settings = m_renderView->document().settings()) { - if (!settings->acceleratedCompositingForFixedPositionEnabled()) - return false; - } - - if (isSticky) - return true; - - RenderObject* container = renderer->container(); - // If the renderer is not hooked up yet then we have to wait until it is. - if (!container) { - m_needsToRecomputeCompositingRequirements = true; - return false; - } - - // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements. - // They will stay fixed wrt the container rather than the enclosing frame. - if (container != m_renderView) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer; - return false; - } - - // If the fixed-position element does not have any scrollable ancestor between it and - // its container, then we do not need to spend compositor resources for it. Start by - // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below. - bool hasScrollableAncestor = false; - - // The FrameView has the scrollbars associated with the top level viewport, so we have to - // check the FrameView in addition to the hierarchy of ancestors. - FrameView* frameView = m_renderView->frameView(); - if (frameView && frameView->isScrollable()) - hasScrollableAncestor = true; - - RenderLayer* ancestor = layer->parent(); - while (ancestor && !hasScrollableAncestor) { - if (frameView->containsScrollableArea(ancestor->scrollableArea())) - hasScrollableAncestor = true; - if (ancestor->renderer() == m_renderView) - break; - ancestor = ancestor->parent(); - } - - if (!hasScrollableAncestor) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors; - return false; - } - - // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done. - if (!m_inPostLayoutUpdate) { - m_needsToRecomputeCompositingRequirements = true; - return layer->hasCompositedLayerMapping(); - } - - bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant(); - if (!paintsContent) { - if (viewportConstrainedNotCompositedReason) - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent; - return false; - } - - // Fixed position elements that are invisible in the current view don't get their own layer. - if (FrameView* frameView = m_renderView->frameView()) { - LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect(); - LayoutRect layerBounds = layer->calculateLayerBounds(rootRenderLayer(), 0, - RenderLayer::DefaultCalculateLayerBoundsFlags - | RenderLayer::ExcludeHiddenDescendants - | RenderLayer::DontConstrainForMask - | RenderLayer::IncludeCompositedDescendants - | RenderLayer::PretendLayerHasOwnBacking); - if (!viewBounds.intersects(enclosingIntRect(layerBounds))) { - if (viewportConstrainedNotCompositedReason) { - *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView; - m_needsToRecomputeCompositingRequirements = true; - } - return false; - } - } - - return true; -} - -bool RenderLayerCompositor::requiresCompositingForOverflowScrolling(const RenderLayer* layer) const -{ - return layer->needsCompositedScrolling(); -} - -bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const -{ - if (!(m_compositingTriggers & ChromeClient::AnimationTrigger)) - return false; - if (!RuntimeEnabledFeatures::webAnimationsCSSEnabled()) - return renderer->animation().isRunningAnimationOnRenderer(renderer, CSSPropertyWebkitTransform); - return hasActiveAnimations(*renderer, CSSPropertyWebkitTransform); -} - -// 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->stackingNode()->hasNegativeZOrderList(); -} - -static void paintScrollbar(Scrollbar* scrollbar, GraphicsContext& context, const IntRect& clip) -{ - if (!scrollbar) - return; - - context.save(); - const IntRect& scrollbarRect = scrollbar->frameRect(); - context.translate(-scrollbarRect.x(), -scrollbarRect.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollbarRect.location()); - scrollbar->paint(&context, transformedClip); - context.restore(); -} - -void RenderLayerCompositor::paintContents(const GraphicsLayer* graphicsLayer, GraphicsContext& context, GraphicsLayerPaintingPhase, const IntRect& clip) -{ - if (graphicsLayer == layerForHorizontalScrollbar()) - paintScrollbar(m_renderView->frameView()->horizontalScrollbar(), context, clip); - else if (graphicsLayer == layerForVerticalScrollbar()) - paintScrollbar(m_renderView->frameView()->verticalScrollbar(), context, clip); - else if (graphicsLayer == layerForScrollCorner()) { - const IntRect& scrollCorner = m_renderView->frameView()->scrollCornerRect(); - context.save(); - context.translate(-scrollCorner.x(), -scrollCorner.y()); - IntRect transformedClip = clip; - transformedClip.moveBy(scrollCorner.location()); - m_renderView->frameView()->paintScrollCorner(&context, transformedClip); - context.restore(); - } -} - -bool RenderLayerCompositor::supportsFixedRootBackgroundCompositing() const -{ - if (Settings* settings = m_renderView->document().settings()) { - if (settings->acceleratedCompositingForFixedRootBackgroundEnabled()) - return true; - } - return false; -} - -bool RenderLayerCompositor::needsFixedRootBackgroundLayer(const RenderLayer* layer) const -{ - if (layer != m_renderView->layer()) - return false; - - return supportsFixedRootBackgroundCompositing() && m_renderView->rootBackgroundIsEntirelyFixed(); -} - -GraphicsLayer* RenderLayerCompositor::fixedRootBackgroundLayer() const -{ - // Get the fixed root background from the RenderView layer's compositedLayerMapping. - RenderLayer* viewLayer = m_renderView->layer(); - if (!viewLayer) - return 0; - - if (viewLayer->compositingState() == PaintsIntoOwnBacking && viewLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground()) - return viewLayer->compositedLayerMapping()->backgroundLayer(); - - return 0; -} - -static void resetTrackedRepaintRectsRecursive(GraphicsLayer* graphicsLayer) -{ - if (!graphicsLayer) - return; - - graphicsLayer->resetTrackedRepaints(); - - for (size_t i = 0; i < graphicsLayer->children().size(); ++i) - resetTrackedRepaintRectsRecursive(graphicsLayer->children()[i]); - - if (GraphicsLayer* replicaLayer = graphicsLayer->replicaLayer()) - resetTrackedRepaintRectsRecursive(replicaLayer); - - if (GraphicsLayer* maskLayer = graphicsLayer->maskLayer()) - resetTrackedRepaintRectsRecursive(maskLayer); - - if (GraphicsLayer* clippingMaskLayer = graphicsLayer->contentsClippingMaskLayer()) - resetTrackedRepaintRectsRecursive(clippingMaskLayer); -} - -void RenderLayerCompositor::resetTrackedRepaintRects() -{ - if (GraphicsLayer* rootLayer = rootGraphicsLayer()) - resetTrackedRepaintRectsRecursive(rootLayer); -} - -void RenderLayerCompositor::setTracksRepaints(bool tracksRepaints) -{ - updateCompositingLayers(CompositingUpdateFinishAllDeferredWork); - m_isTrackingRepaints = tracksRepaints; -} - -bool RenderLayerCompositor::isTrackingRepaints() const -{ - return m_isTrackingRepaints; -} - -void RenderLayerCompositor::didCommitChangesForLayer(const GraphicsLayer*) const -{ - // Nothing to do here yet. -} - -static bool shouldCompositeOverflowControls(FrameView* view) -{ - if (Page* page = view->frame().page()) { - if (ScrollingCoordinator* scrollingCoordinator = page->scrollingCoordinator()) - if (scrollingCoordinator->coordinatesScrollingForFrameView(view)) - return true; - } - - return true; -} - -bool RenderLayerCompositor::requiresHorizontalScrollbarLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->horizontalScrollbar(); -} - -bool RenderLayerCompositor::requiresVerticalScrollbarLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->verticalScrollbar(); -} - -bool RenderLayerCompositor::requiresScrollCornerLayer() const -{ - FrameView* view = m_renderView->frameView(); - return shouldCompositeOverflowControls(view) && view->isScrollCornerVisible(); -} - -#if USE(RUBBER_BANDING) -bool RenderLayerCompositor::requiresOverhangLayers() const -{ - // We don't want a layer if this is a subframe. - if (!isMainFrame()) - return false; - - // We do want a layer if we have a scrolling coordinator and can scroll. - if (scrollingCoordinator() && m_renderView->frameView()->hasOpaqueBackground()) - return true; - - // Chromium always wants a layer. - return true; -} -#endif - -void RenderLayerCompositor::updateOverflowControlsLayers() -{ -#if USE(RUBBER_BANDING) - if (requiresOverhangLayers()) { - if (!m_layerForOverhangShadow) { - m_layerForOverhangShadow = GraphicsLayer::create(graphicsLayerFactory(), this); - OverscrollTheme::theme()->setUpOverhangShadowLayer(m_layerForOverhangShadow.get()); - OverscrollTheme::theme()->updateOverhangShadowLayer(m_layerForOverhangShadow.get(), m_rootContentLayer.get()); - m_scrollLayer->addChild(m_layerForOverhangShadow.get()); - } - } else { - if (m_layerForOverhangShadow) { - m_layerForOverhangShadow->removeFromParent(); - m_layerForOverhangShadow = nullptr; - } - } -#endif - - if (requiresHorizontalScrollbarLayer()) { - if (!m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForHorizontalScrollbar.get()); - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - } - } else if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar->removeFromParent(); - m_layerForHorizontalScrollbar = nullptr; - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - } - - if (requiresVerticalScrollbarLayer()) { - if (!m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForVerticalScrollbar.get()); - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - } - } else if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar->removeFromParent(); - m_layerForVerticalScrollbar = nullptr; - - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - } - - if (requiresScrollCornerLayer()) { - if (!m_layerForScrollCorner) { - m_layerForScrollCorner = GraphicsLayer::create(graphicsLayerFactory(), this); - m_overflowControlsHostLayer->addChild(m_layerForScrollCorner.get()); - } - } else if (m_layerForScrollCorner) { - m_layerForScrollCorner->removeFromParent(); - m_layerForScrollCorner = nullptr; - } - - m_renderView->frameView()->positionScrollbarLayers(); -} - -void RenderLayerCompositor::ensureRootLayer() -{ - RootLayerAttachment expectedAttachment = isMainFrame() ? RootLayerAttachedViaChromeClient : RootLayerAttachedViaEnclosingFrame; - if (expectedAttachment == m_rootLayerAttachment) - return; - - if (!m_rootContentLayer) { - m_rootContentLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - IntRect overflowRect = m_renderView->pixelSnappedLayoutOverflowRect(); - m_rootContentLayer->setSize(FloatSize(overflowRect.maxX(), overflowRect.maxY())); - m_rootContentLayer->setPosition(FloatPoint()); - - // Need to clip to prevent transformed content showing outside this frame - m_rootContentLayer->setMasksToBounds(true); - } - - if (!m_overflowControlsHostLayer) { - ASSERT(!m_scrollLayer); - ASSERT(!m_containerLayer); - - // Create a layer to host the clipping layer and the overflow controls layers. - m_overflowControlsHostLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - - // Create a clipping layer if this is an iframe or settings require to clip. - m_containerLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - bool containerMasksToBounds = !isMainFrame(); - if (Settings* settings = m_renderView->document().settings()) { - if (settings->mainFrameClipsContent()) - containerMasksToBounds = true; - } - m_containerLayer->setMasksToBounds(containerMasksToBounds); - - m_scrollLayer = GraphicsLayer::create(graphicsLayerFactory(), this); - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->setLayerIsContainerForFixedPositionLayers(m_scrollLayer.get(), true); - - // Hook them up - m_overflowControlsHostLayer->addChild(m_containerLayer.get()); - m_containerLayer->addChild(m_scrollLayer.get()); - m_scrollLayer->addChild(m_rootContentLayer.get()); - - frameViewDidChangeSize(); - frameViewDidScroll(); - } - - // Check to see if we have to change the attachment - if (m_rootLayerAttachment != RootLayerUnattached) - detachRootLayer(); - - attachRootLayer(expectedAttachment); -} - -void RenderLayerCompositor::destroyRootLayer() -{ - if (!m_rootContentLayer) - return; - - detachRootLayer(); - -#if USE(RUBBER_BANDING) - if (m_layerForOverhangShadow) { - m_layerForOverhangShadow->removeFromParent(); - m_layerForOverhangShadow = nullptr; - } -#endif - - if (m_layerForHorizontalScrollbar) { - m_layerForHorizontalScrollbar->removeFromParent(); - m_layerForHorizontalScrollbar = nullptr; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), HorizontalScrollbar); - if (Scrollbar* horizontalScrollbar = m_renderView->frameView()->verticalScrollbar()) - m_renderView->frameView()->invalidateScrollbar(horizontalScrollbar, IntRect(IntPoint(0, 0), horizontalScrollbar->frameRect().size())); - } - - if (m_layerForVerticalScrollbar) { - m_layerForVerticalScrollbar->removeFromParent(); - m_layerForVerticalScrollbar = nullptr; - if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) - scrollingCoordinator->scrollableAreaScrollbarLayerDidChange(m_renderView->frameView(), VerticalScrollbar); - if (Scrollbar* verticalScrollbar = m_renderView->frameView()->verticalScrollbar()) - m_renderView->frameView()->invalidateScrollbar(verticalScrollbar, IntRect(IntPoint(0, 0), verticalScrollbar->frameRect().size())); - } - - if (m_layerForScrollCorner) { - m_layerForScrollCorner = nullptr; - m_renderView->frameView()->invalidateScrollCorner(m_renderView->frameView()->scrollCornerRect()); - } - - if (m_overflowControlsHostLayer) { - m_overflowControlsHostLayer = nullptr; - m_containerLayer = nullptr; - m_scrollLayer = nullptr; - } - ASSERT(!m_scrollLayer); - m_rootContentLayer = nullptr; -} - -void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment) -{ - if (!m_rootContentLayer) - return; - - switch (attachment) { - case RootLayerUnattached: - ASSERT_NOT_REACHED(); - break; - case RootLayerAttachedViaChromeClient: { - Frame& frame = m_renderView->frameView()->frame(); - Page* page = frame.page(); - if (!page) - return; - page->chrome().client().attachRootGraphicsLayer(&frame, rootGraphicsLayer()); - break; - } - case RootLayerAttachedViaEnclosingFrame: { - // The layer will get hooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() - // for the frame's renderer in the parent document. - m_renderView->document().ownerElement()->scheduleLayerUpdate(); - break; - } - } - - m_rootLayerAttachment = attachment; -} - -void RenderLayerCompositor::detachRootLayer() -{ - if (!m_rootContentLayer || m_rootLayerAttachment == RootLayerUnattached) - return; - - switch (m_rootLayerAttachment) { - case RootLayerAttachedViaEnclosingFrame: { - // The layer will get unhooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() - // for the frame's renderer in the parent document. - if (m_overflowControlsHostLayer) - m_overflowControlsHostLayer->removeFromParent(); - else - m_rootContentLayer->removeFromParent(); - - if (HTMLFrameOwnerElement* ownerElement = m_renderView->document().ownerElement()) - ownerElement->scheduleLayerUpdate(); - break; - } - case RootLayerAttachedViaChromeClient: { - Frame& frame = m_renderView->frameView()->frame(); - Page* page = frame.page(); - if (!page) - return; - page->chrome().client().attachRootGraphicsLayer(&frame, 0); - } - break; - case RootLayerUnattached: - break; - } - - m_rootLayerAttachment = RootLayerUnattached; -} - -void RenderLayerCompositor::updateRootLayerAttachment() -{ - ensureRootLayer(); -} - -bool RenderLayerCompositor::isMainFrame() const -{ - // FIXME: Frame::isMainFrame() is probably better. - return !m_renderView->document().ownerElement(); -} - -// IFrames are special, because we hook compositing layers together across iframe boundaries -// when both parent and iframe content are composited. So when this frame becomes composited, we have -// to use a synthetic style change to get the iframes into RenderLayers in order to allow them to composite. -void RenderLayerCompositor::notifyIFramesOfCompositingChange() -{ - if (!m_renderView->frameView()) - return; - Frame& frame = m_renderView->frameView()->frame(); - - for (Frame* child = frame.tree().firstChild(); child; child = child->tree().traverseNext(&frame)) { - if (child->document() && child->document()->ownerElement()) - child->document()->ownerElement()->scheduleLayerUpdate(); - } - - // Compositing also affects the answer to RenderIFrame::requiresAcceleratedCompositing(), so - // we need to schedule a style recalc in our parent document. - if (HTMLFrameOwnerElement* ownerElement = m_renderView->document().ownerElement()) - ownerElement->scheduleLayerUpdate(); -} - -bool RenderLayerCompositor::layerHas3DContent(const RenderLayer* layer) const -{ - const RenderStyle* style = layer->renderer()->style(); - RenderLayerStackingNode* stackingNode = const_cast<RenderLayer*>(layer)->stackingNode(); - - if (style && - (style->transformStyle3D() == TransformStyle3DPreserve3D || - style->hasPerspective() || - style->transform().has3DOperation())) - return true; - - stackingNode->updateLayerListsIfNeeded(); - -#if !ASSERT_DISABLED - LayerListMutationDetector mutationChecker(stackingNode); -#endif - - RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), AllChildren); - while (RenderLayerStackingNode* curNode = iterator.next()) { - if (layerHas3DContent(curNode->layer())) - return true; - } - - return false; -} - -static bool isRootmostFixedOrStickyLayer(RenderLayer* layer) -{ - if (layer->renderer()->isStickyPositioned()) - return true; - - if (layer->renderer()->style()->position() != FixedPosition) - return false; - - for (RenderLayerStackingNode* stackingContainerNode = layer->stackingNode()->ancestorStackingContainerNode(); stackingContainerNode; stackingContainerNode = stackingContainerNode->ancestorStackingContainerNode()) { - if (stackingContainerNode->layer()->hasCompositedLayerMapping() && stackingContainerNode->layer()->renderer()->style()->position() == FixedPosition) - return false; - } - - return true; -} - -void RenderLayerCompositor::updateViewportConstraintStatus(RenderLayer* layer) -{ - if (isRootmostFixedOrStickyLayer(layer)) - addViewportConstrainedLayer(layer); - else - removeViewportConstrainedLayer(layer); -} - -void RenderLayerCompositor::addViewportConstrainedLayer(RenderLayer* layer) -{ - m_viewportConstrainedLayers.add(layer); -} - -void RenderLayerCompositor::removeViewportConstrainedLayer(RenderLayer* layer) -{ - if (!m_viewportConstrainedLayers.contains(layer)) - return; - - m_viewportConstrainedLayers.remove(layer); -} - -FixedPositionViewportConstraints RenderLayerCompositor::computeFixedViewportConstraints(RenderLayer* layer) const -{ - ASSERT(layer->hasCompositedLayerMapping()); - - FrameView* frameView = m_renderView->frameView(); - LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); - - FixedPositionViewportConstraints constraints; - - GraphicsLayer* graphicsLayer = layer->compositedLayerMapping()->mainGraphicsLayer(); - - constraints.setLayerPositionAtLastLayout(graphicsLayer->position()); - constraints.setViewportRectAtLastLayout(viewportRect); - - RenderStyle* style = layer->renderer()->style(); - if (!style->left().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); - - if (!style->right().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight); - - if (!style->top().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); - - if (!style->bottom().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom); - - // If left and right are auto, use left. - if (style->left().isAuto() && style->right().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft); - - // If top and bottom are auto, use top. - if (style->top().isAuto() && style->bottom().isAuto()) - constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop); - - return constraints; -} - -StickyPositionViewportConstraints RenderLayerCompositor::computeStickyViewportConstraints(RenderLayer* layer) const -{ - ASSERT(layer->hasCompositedLayerMapping()); - - FrameView* frameView = m_renderView->frameView(); - LayoutRect viewportRect = frameView->viewportConstrainedVisibleContentRect(); - - StickyPositionViewportConstraints constraints; - - RenderBoxModelObject* renderer = toRenderBoxModelObject(layer->renderer()); - - renderer->computeStickyPositionConstraints(constraints, viewportRect); - - GraphicsLayer* graphicsLayer = layer->compositedLayerMapping()->mainGraphicsLayer(); - - constraints.setLayerPositionAtLastLayout(graphicsLayer->position()); - constraints.setStickyOffsetAtLastLayout(renderer->stickyPositionOffset()); - - return constraints; -} - -ScrollingCoordinator* RenderLayerCompositor::scrollingCoordinator() const -{ - if (Page* page = this->page()) - return page->scrollingCoordinator(); - - return 0; -} - -GraphicsLayerFactory* RenderLayerCompositor::graphicsLayerFactory() const -{ - if (Page* page = this->page()) - return page->chrome().client().graphicsLayerFactory(); - return 0; -} - -Page* RenderLayerCompositor::page() const -{ - return m_renderView->frameView()->frame().page(); -} - -String RenderLayerCompositor::debugName(const GraphicsLayer* graphicsLayer) -{ - String name; - if (graphicsLayer == m_rootContentLayer.get()) { - name = "Content Root Layer"; -#if USE(RUBBER_BANDING) - } else if (graphicsLayer == m_layerForOverhangShadow.get()) { - name = "Overhang Areas Shadow"; -#endif - } else if (graphicsLayer == m_overflowControlsHostLayer.get()) { - name = "Overflow Controls Host Layer"; - } else if (graphicsLayer == m_layerForHorizontalScrollbar.get()) { - name = "Horizontal Scrollbar Layer"; - } else if (graphicsLayer == m_layerForVerticalScrollbar.get()) { - name = "Vertical Scrollbar Layer"; - } else if (graphicsLayer == m_layerForScrollCorner.get()) { - name = "Scroll Corner Layer"; - } else if (graphicsLayer == m_containerLayer.get()) { - name = "Frame Clipping Layer"; - } else if (graphicsLayer == m_scrollLayer.get()) { - name = "Frame Scrolling Layer"; - } else { - ASSERT_NOT_REACHED(); - } - - return name; -} - -} // namespace WebCore |