| /* |
| * 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/compositing/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/frame/DeprecatedScheduleStyleRecalcDuringCompositingUpdate.h" |
| #include "core/frame/FrameView.h" |
| #include "core/frame/LocalFrame.h" |
| #include "core/frame/Settings.h" |
| #include "core/html/HTMLCanvasElement.h" |
| #include "core/html/HTMLIFrameElement.h" |
| #include "core/html/HTMLMediaElement.h" |
| #include "core/html/canvas/CanvasRenderingContext.h" |
| #include "core/inspector/InspectorInstrumentation.h" |
| #include "core/page/Chrome.h" |
| #include "core/page/Page.h" |
| #include "core/page/scrolling/ScrollingConstraints.h" |
| #include "core/page/scrolling/ScrollingCoordinator.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 "core/rendering/compositing/CompositedLayerMapping.h" |
| #include "core/rendering/compositing/GraphicsLayerUpdater.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.appendVector(otherContainer.m_layerRects); |
| m_boundingBox.unite(otherContainer.m_boundingBox); |
| } |
| private: |
| Vector<IntRect, 64> 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 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); |
| } |
| |
| bool overlapsLayers(const IntRect& bounds) const |
| { |
| return m_overlapStack.last().overlapsLayers(bounds); |
| } |
| |
| 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; |
| RenderGeometryMap m_geometryMap; |
| }; |
| |
| struct CompositingRecursionData { |
| CompositingRecursionData(RenderLayer* compAncestor, RenderLayer* mostRecentCompositedLayer, bool testOverlap) |
| : m_compositingAncestor(compAncestor) |
| , m_mostRecentCompositedLayer(mostRecentCompositedLayer) |
| , 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_mostRecentCompositedLayer(other.m_mostRecentCompositedLayer) |
| , 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; |
| RenderLayer* m_mostRecentCompositedLayer; // in paint order regardless of hierarchy. |
| bool m_subtreeIsCompositing; |
| bool m_hasUnisolatedCompositedBlendingDescendant; |
| bool m_testingOverlap; |
| #ifndef NDEBUG |
| int m_depth; |
| #endif |
| }; |
| |
| RenderLayerCompositor::RenderLayerCompositor(RenderView& renderView) |
| : m_renderView(renderView) |
| , m_compositingReasonFinder(renderView) |
| , m_hasAcceleratedCompositing(true) |
| , m_showRepaintCounter(false) |
| , m_needsToRecomputeCompositingRequirements(false) |
| , m_needsToUpdateLayerTreeGeometry(false) |
| , m_pendingUpdateType(GraphicsLayerUpdater::DoNotForceUpdate) |
| , m_compositing(false) |
| , m_compositingLayersNeedRebuild(false) |
| , m_forceCompositingMode(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()) { |
| m_compositingReasonFinder.updateTriggers(); |
| hasAcceleratedCompositing = m_compositingReasonFinder.hasTriggers(); |
| } |
| } |
| |
| showRepaintCounter = settings->showRepaintCounter(); |
| forceCompositingMode = settings->forceCompositingMode() && hasAcceleratedCompositing; |
| |
| if (forceCompositingMode && !isMainFrame()) |
| forceCompositingMode = m_compositingReasonFinder.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 (RuntimeEnabledFeatures::bleedingEdgeFastPathsEnabled()) |
| return true; |
| if (Settings* settings = m_renderView.document().settings()) |
| return settings->layerSquashingEnabled(); |
| |
| return false; |
| } |
| |
| bool RenderLayerCompositor::canRender3DTransforms() const |
| { |
| return hasAcceleratedCompositing() && m_compositingReasonFinder.has3DTransformTrigger(); |
| } |
| |
| void RenderLayerCompositor::setCompositingLayersNeedRebuild() |
| { |
| // FIXME: crbug,com/332248 ideally this could be merged with setNeedsCompositingUpdate(). |
| if (inCompositingMode()) |
| m_compositingLayersNeedRebuild = true; |
| |
| m_renderView.frameView()->scheduleAnimation(); |
| } |
| |
| void RenderLayerCompositor::updateCompositingRequirementsState() |
| { |
| if (!m_needsUpdateCompositingRequirementsState) |
| return; |
| |
| TRACE_EVENT0("blink_rendering,comp-scroll", "RenderLayerCompositor::updateCompositingRequirementsState"); |
| |
| m_needsUpdateCompositingRequirementsState = false; |
| |
| if (!rootRenderLayer() || !m_renderView.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::fullscreenElementFrom(document); |
| while (fullscreenElement && fullscreenElement->isFrameOwnerElement()) { |
| Document* contentDocument = toHTMLFrameOwnerElement(fullscreenElement)->contentDocument(); |
| if (!contentDocument) |
| return 0; |
| fullscreenElement = FullscreenElementStack::fullscreenElementFrom(*contentDocument); |
| } |
| if (!isHTMLVideoElement(fullscreenElement)) |
| return 0; |
| RenderObject* renderer = fullscreenElement->renderer(); |
| if (!renderer) |
| return 0; |
| return toRenderVideo(renderer); |
| } |
| |
| void RenderLayerCompositor::finishCompositingUpdateForFrameTree(LocalFrame* frame) |
| { |
| for (LocalFrame* 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(); |
| } |
| } |
| |
| void RenderLayerCompositor::setNeedsCompositingUpdate(CompositingUpdateType updateType) |
| { |
| // FIXME: this code was historically part of updateCompositingLayers, and |
| // for now is kept totally equivalent to the previous implementation. We |
| // should carefully clean up the awkward early-exit semantics, balancing between |
| // skipping unnecessary compositing updates and not incorrectly skipping |
| // necessary updates. |
| |
| // Avoid updating the layers with old values. Compositing layers will be updated after the layout is finished. |
| if (m_renderView.needsLayout()) |
| return; |
| |
| if (m_forceCompositingMode && !m_compositing) |
| enableCompositingMode(true); |
| |
| if (!m_needsToRecomputeCompositingRequirements && !m_compositing) |
| return; |
| |
| switch (updateType) { |
| case CompositingUpdateAfterStyleChange: |
| m_needsToRecomputeCompositingRequirements = true; |
| break; |
| case CompositingUpdateAfterLayout: |
| m_needsToRecomputeCompositingRequirements = true; |
| // FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here. |
| m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate; |
| break; |
| case CompositingUpdateOnScroll: |
| m_needsToRecomputeCompositingRequirements = true; // Overlap can change with scrolling, so need to check for hierarchy updates. |
| m_needsToUpdateLayerTreeGeometry = true; |
| // FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here. |
| m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate; |
| break; |
| case CompositingUpdateOnCompositedScroll: |
| m_needsToUpdateLayerTreeGeometry = true; |
| // FIXME: Ideally we'd be smarter about tracking dirtiness and wouldn't need a ForceUpdate here. |
| m_pendingUpdateType = GraphicsLayerUpdater::ForceUpdate; |
| break; |
| case CompositingUpdateAfterCanvasContextChange: |
| m_needsToUpdateLayerTreeGeometry = true; |
| break; |
| } |
| |
| m_renderView.frameView()->scheduleAnimation(); |
| } |
| |
| void RenderLayerCompositor::updateCompositingLayers() |
| { |
| TRACE_EVENT0("blink_rendering", "RenderLayerCompositor::updateCompositingLayers"); |
| |
| // FIXME: We should carefully clean up the awkward early-exit semantics, balancing |
| // between skipping unnecessary compositing updates and not incorrectly skipping |
| // necessary updates. |
| |
| // Avoid updating the layers with old values. Compositing layers will be updated after the layout is finished. |
| // FIXME: Can we assert that we never return here? |
| if (m_renderView.needsLayout()) |
| return; |
| |
| lifecycle().advanceTo(DocumentLifecycle::InCompositingUpdate); |
| |
| updateCompositingLayersInternal(); |
| |
| lifecycle().advanceTo(DocumentLifecycle::CompositingClean); |
| |
| DocumentAnimations::startPendingAnimations(m_renderView.document()); |
| ASSERT(m_renderView.document().lifecycle().state() == DocumentLifecycle::CompositingClean); |
| } |
| |
| void RenderLayerCompositor::updateCompositingLayersInternal() |
| { |
| if (isMainFrame() && m_renderView.frameView()) |
| finishCompositingUpdateForFrameTree(&m_renderView.frameView()->frame()); |
| |
| if (m_forceCompositingMode && !m_compositing) |
| enableCompositingMode(true); |
| |
| if (!m_needsToRecomputeCompositingRequirements && !m_compositing) |
| return; |
| |
| bool needCompositingRequirementsUpdate = m_needsToRecomputeCompositingRequirements; |
| bool needHierarchyAndGeometryUpdate = m_compositingLayersNeedRebuild; |
| bool needGeometryUpdate = m_needsToUpdateLayerTreeGeometry; |
| bool needsToUpdateScrollingCoordinator = scrollingCoordinator() ? scrollingCoordinator()->needsToUpdateAfterCompositingChange() : false; |
| |
| if (!needCompositingRequirementsUpdate && !needHierarchyAndGeometryUpdate && !needGeometryUpdate && !needsToUpdateScrollingCoordinator) |
| return; |
| |
| GraphicsLayerUpdater::UpdateType updateType = m_pendingUpdateType; |
| |
| // Only clear the flags if we're updating the entire hierarchy. |
| m_compositingLayersNeedRebuild = false; |
| m_needsToUpdateLayerTreeGeometry = false; |
| m_needsToRecomputeCompositingRequirements = false; |
| m_pendingUpdateType = GraphicsLayerUpdater::DoNotForceUpdate; |
| |
| 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, 0, 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; |
| IntRect absoluteDecendantBoundingBox; |
| computeCompositingRequirements(0, updateRoot, &overlapTestRequestMap, recursionData, saw3DTransform, unclippedDescendants, absoluteDecendantBoundingBox); |
| } |
| |
| { |
| 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(); |
| } |
| } |
| |
| if (layersChanged) |
| needHierarchyAndGeometryUpdate = true; |
| } |
| |
| if (needHierarchyAndGeometryUpdate) { |
| // Update the hierarchy of the compositing layers. |
| GraphicsLayerVector childList; |
| { |
| TRACE_EVENT0("blink_rendering", "GraphicsLayerUpdater::rebuildTree"); |
| GraphicsLayerUpdater(m_renderView).rebuildTree(*updateRoot, updateType, 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(). |
| TRACE_EVENT0("blink_rendering", "GraphicsLayerUpdater::updateRecursive"); |
| GraphicsLayerUpdater(m_renderView).updateRecursive(*updateRoot, updateType); |
| } |
| |
| 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 & ~CompositingReasonComboSquashableReasons; |
| } |
| |
| 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 & CompositingReasonComboSquashableReasons); |
| } |
| |
| 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, const CompositingStateTransitionType compositedLayerUpdate) |
| { |
| bool compositedLayerMappingChanged = false; |
| bool nonCompositedReasonChanged = updateLayerIfViewportConstrained(layer); |
| |
| // FIXME: It would be nice to directly use the layer's compositing reason, |
| // but allocateOrClearCompositedLayerMapping also gets called without having updated compositing |
| // requirements fully. |
| switch (compositedLayerUpdate) { |
| case AllocateOwnCompositedLayerMapping: |
| ASSERT(!layer->hasCompositedLayerMapping()); |
| enableCompositingMode(); |
| |
| // 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->setLostGroupedMapping(false); |
| 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(); |
| |
| break; |
| case RemoveOwnCompositedLayerMapping: |
| // PutInSquashingLayer means you might have to remove the composited layer mapping first. |
| case PutInSquashingLayer: |
| 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); |
| } |
| |
| break; |
| case RemoveFromSquashingLayer: |
| case NoCompositingStateChange: |
| // Do nothing. |
| break; |
| } |
| |
| if (layer->hasCompositedLayerMapping() && layer->compositedLayerMapping()->updateRequiresOwnBackingStoreForIntrinsicReasons()) |
| compositedLayerMappingChanged = true; |
| |
| 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. |
| if (compositedLayerMappingChanged || nonCompositedReasonChanged) { |
| if (ScrollingCoordinator* scrollingCoordinator = this->scrollingCoordinator()) |
| scrollingCoordinator->frameViewFixedObjectsDidChange(m_renderView.frameView()); |
| } |
| |
| return compositedLayerMappingChanged || nonCompositedReasonChanged; |
| } |
| |
| static IntPoint computeOffsetFromAbsolute(RenderLayer* layer) |
| { |
| TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); |
| layer->renderer()->mapLocalToContainer(0, transformState, ApplyContainerFlip); |
| transformState.flatten(); |
| return roundedIntPoint(transformState.lastPlanarPoint()); |
| } |
| |
| bool RenderLayerCompositor::updateSquashingAssignment(RenderLayer* layer, SquashingState& squashingState, const CompositingStateTransitionType compositedLayerUpdate) |
| { |
| |
| // NOTE: In the future as we generalize this, the background of this layer may need to be assigned to a different backing than |
| // the squashed RenderLayer'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 (compositedLayerUpdate == PutInSquashingLayer) { |
| // A layer that is squashed with other layers cannot have its own CompositedLayerMapping. |
| ASSERT(!layer->hasCompositedLayerMapping()); |
| ASSERT(squashingState.hasMostRecentMapping); |
| |
| IntPoint offsetFromAbsoluteForSquashedLayer = computeOffsetFromAbsolute(layer); |
| |
| IntSize offsetFromSquashingCLM(offsetFromAbsoluteForSquashedLayer.x() - squashingState.offsetFromAbsoluteForSquashingCLM.x(), |
| offsetFromAbsoluteForSquashedLayer.y() - squashingState.offsetFromAbsoluteForSquashingCLM.y()); |
| |
| bool changedSquashingLayer = |
| squashingState.mostRecentMapping->updateSquashingLayerAssignment(layer, offsetFromSquashingCLM, squashingState.nextSquashedLayerIndex); |
| squashingState.nextSquashedLayerIndex++; |
| |
| if (!changedSquashingLayer) |
| return true; |
| |
| layer->clipper().clearClipRectsIncludingDescendants(); |
| |
| // If we need to repaint, do so before allocating the layer to the squashing layer. |
| repaintOnCompositingChange(layer); |
| |
| // 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. |
| |
| // FIXME: what's up with parent()? |
| if (layer->parent()) |
| layer->repainter().computeRepaintRectsIncludingDescendants(); |
| |
| return true; |
| } else if (compositedLayerUpdate == RemoveFromSquashingLayer) { |
| layer->setGroupedMapping(0); |
| |
| // 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 it from a squashed layer |
| repaintOnCompositingChange(layer); |
| |
| layer->setLostGroupedMapping(false); |
| return true; |
| } |
| return false; |
| } |
| |
| bool RenderLayerCompositor::updateLayerIfViewportConstrained(RenderLayer* layer) |
| { |
| RenderLayer::ViewportConstrainedNotCompositedReason viewportConstrainedNotCompositedReason = RenderLayer::NoNotCompositedReason; |
| m_compositingReasonFinder.requiresCompositingForPosition(layer->renderer(), layer, &viewportConstrainedNotCompositedReason, &m_needsToRecomputeCompositingRequirements); |
| |
| if (layer->viewportConstrainedNotCompositedReason() != viewportConstrainedNotCompositedReason) { |
| ASSERT(layer->renderer()->style()->position() == FixedPosition); |
| |
| layer->setViewportConstrainedNotCompositedReason(viewportConstrainedNotCompositedReason); |
| return true; |
| } |
| return false; |
| } |
| |
| bool RenderLayerCompositor::canSquashIntoCurrentSquashingOwner(const RenderLayer* layer, const RenderLayerCompositor::SquashingState& squashingState, const RenderLayer* clippingAncestor) |
| { |
| ASSERT(clippingAncestor); |
| return clippingAncestor == squashingState.clippingAncestorForMostRecentMapping; |
| } |
| |
| RenderLayerCompositor::CompositingStateTransitionType RenderLayerCompositor::computeCompositedLayerUpdate(RenderLayer* layer) |
| { |
| CompositingStateTransitionType update = NoCompositingStateChange; |
| if (needsOwnBacking(layer)) { |
| if (!layer->hasCompositedLayerMapping()) { |
| update = AllocateOwnCompositedLayerMapping; |
| } |
| } else { |
| if (layer->hasCompositedLayerMapping()) |
| update = RemoveOwnCompositedLayerMapping; |
| |
| if (layerSquashingEnabled()) { |
| if (requiresSquashing(layer->compositingReasons())) { |
| // We can't compute at this time whether the squashing layer update is a no-op, |
| // since that requires walking the render layer tree. |
| update = PutInSquashingLayer; |
| } else if (layer->groupedMapping() || layer->lostGroupedMapping()) { |
| update = RemoveFromSquashingLayer; |
| } |
| } |
| } |
| return update; |
| } |
| |
| // These are temporary hacks to work around chicken-egg issues while we continue to refactor the compositing code. |
| // See crbug.com/339892 for a list of tests that fail if this method is removed. |
| void RenderLayerCompositor::applyUpdateLayerCompositingStateChickenEggHacks(RenderLayer* layer, CompositingStateTransitionType compositedLayerUpdate) |
| { |
| // 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()) { |
| setCompositingLayersNeedRebuild(); |
| } else if (compositedLayerUpdate == NoCompositingStateChange) { |
| if (layer->compositingState() == PaintsIntoOwnBacking || layer->compositingState() == HasOwnBackingButPaintsIntoAncestor) |
| setCompositingLayersNeedRebuild(); |
| } |
| |
| if (compositedLayerUpdate != NoCompositingStateChange) |
| allocateOrClearCompositedLayerMapping(layer, computeCompositedLayerUpdate(layer)); |
| } |
| |
| void RenderLayerCompositor::updateLayerCompositingState(RenderLayer* layer, UpdateLayerCompositingStateOptions options) |
| { |
| updateDirectCompositingReasons(layer); |
| CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer); |
| |
| if (compositedLayerUpdate != NoCompositingStateChange) { |
| setCompositingLayersNeedRebuild(); |
| setNeedsToRecomputeCompositingRequirements(); |
| } |
| |
| if (options == UseChickenEggHacks) |
| applyUpdateLayerCompositingStateChickenEggHacks(layer, compositedLayerUpdate); |
| } |
| |
| 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(ExcludeSelf); |
| 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. |
| LayoutRect RenderLayerCompositor::calculateCompositedBounds(const RenderLayer* layer, const RenderLayer* ancestorLayer) const |
| { |
| if (!canBeComposited(layer)) |
| return LayoutRect(); |
| |
| RenderLayer::CalculateLayerBoundsFlags flags = RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask; |
| 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); |
| |
| { |
| // FIXME: This is called from within RenderLayer::removeChild, which is called from RenderObject::RemoveChild. |
| // There's no guarantee that compositor state is up to date. |
| DisableCompositingQueryAsserts disabler; |
| repaintInCompositedAncestor(child, child->compositedLayerMapping()->compositedBounds()); |
| } |
| |
| setCompositingParent(child, 0); |
| setCompositingLayersNeedRebuild(); |
| } |
| |
| void RenderLayerCompositor::addToOverlapMap(OverlapMap& overlapMap, RenderLayer* layer, IntRect& layerBounds) |
| { |
| if (layer->isRootLayer()) |
| return; |
| |
| IntRect clipRect = pixelSnappedIntRect(layer->clipper().backgroundClipRect(ClipRectsContext(rootRenderLayer(), AbsoluteClipRects)).rect()); |
| clipRect.intersect(layerBounds); |
| overlapMap.add(clipRect); |
| } |
| |
| // 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, IntRect& absoluteDecendantBoundingBox) |
| { |
| 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 = m_compositingReasonFinder.directReasons(layer, &m_needsToRecomputeCompositingRequirements); |
| |
| // 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 |= CompositingReasonVideoOverlay; |
| |
| 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 (m_renderView.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); |
| } |
| |
| IntRect absBounds; |
| if (overlapMap && !layer->isRootLayer()) { |
| absBounds = enclosingIntRect(overlapMap->geometryMap().absoluteRect(layer->overlapBounds())); |
| // Setting the absBounds to 1x1 instead of 0x0 makes very little sense, |
| // but removing this code will make JSGameBench sad. |
| // See https://codereview.chromium.org/13912020/ |
| if (absBounds.isEmpty()) |
| absBounds.setSize(IntSize(1, 1)); |
| } |
| absoluteDecendantBoundingBox = absBounds; |
| |
| if (overlapMap && currentRecursionData.m_testingOverlap && !requiresCompositingOrSquashing(directReasons)) |
| overlapCompositingReason = overlapMap->overlapsLayers(absBounds) ? CompositingReasonOverlap : CompositingReasonNone; |
| |
| reasonsToComposite |= overlapCompositingReason; |
| |
| // If the layer is squashable, but would scroll differently than the |
| // most recent backing that it would squash onto, then don't squash it. |
| // Note that this happens before we know all possible compositing reasons |
| // for this layer, but it's OK because we're just forcing the layer conservatively |
| // to be separately composited rather than squashed, anyway. |
| if (currentRecursionData.m_mostRecentCompositedLayer && requiresSquashing(reasonsToComposite) |
| && layer->scrollsWithRespectTo(currentRecursionData.m_mostRecentCompositedLayer)) |
| reasonsToComposite |= CompositingReasonOverlapsWithoutSquashingTarget; |
| |
| // 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 willBeCompositedOrSquashed = canBeComposited(layer) && requiresCompositingOrSquashing(reasonsToComposite); |
| if (willBeCompositedOrSquashed) { |
| // 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()) { |
| IntRect absoluteChildDecendantBoundingBox; |
| computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox); |
| absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox); |
| |
| // 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 (!willBeCompositedOrSquashed) { |
| // make layer compositing |
| childRecursionData.m_compositingAncestor = layer; |
| if (overlapMap) |
| overlapMap->beginNewOverlapTestingContext(); |
| willBeCompositedOrSquashed = 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())); |
| overlapMap->beginNewOverlapTestingContext(); |
| addToOverlapMap(*overlapMap, curNode->layer(), childAbsBounds); |
| overlapMap->finishCurrentOverlapTestingContext(); |
| overlapMap->geometryMap().popMappingsToAncestor(layer); |
| } |
| } |
| } |
| } |
| } |
| |
| if (overlapMap && willHaveForegroundLayer) { |
| ASSERT(willBeCompositedOrSquashed); |
| // 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; |
| } |
| |
| if (requiresCompositing(reasonsToComposite)) { |
| currentRecursionData.m_mostRecentCompositedLayer = layer; |
| childRecursionData.m_mostRecentCompositedLayer = layer; |
| } |
| |
| RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); |
| while (RenderLayerStackingNode* curNode = iterator.next()) { |
| IntRect absoluteChildDecendantBoundingBox; |
| computeCompositingRequirements(layer, curNode->layer(), overlapMap, childRecursionData, anyDescendantHas3DTransform, unclippedDescendants, absoluteChildDecendantBoundingBox); |
| absoluteDecendantBoundingBox.unite(absoluteChildDecendantBoundingBox); |
| } |
| |
| currentRecursionData.m_mostRecentCompositedLayer = childRecursionData.m_mostRecentCompositedLayer; |
| |
| // 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) |
| willBeCompositedOrSquashed = 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); |
| |
| 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 (!willBeCompositedOrSquashed && 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(); |
| addToOverlapMap(*overlapMap, layer, absoluteDecendantBoundingBox); |
| } |
| willBeCompositedOrSquashed = 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 = willBeCompositedOrSquashed ? 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 (willBeCompositedOrSquashed && layer->blendInfo().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) { |
| willBeCompositedOrSquashed = true; |
| reasonsToComposite |= CompositingReasonRoot; |
| } else { |
| enableCompositingMode(false); |
| willBeCompositedOrSquashed = false; |
| reasonsToComposite = CompositingReasonNone; |
| } |
| } |
| |
| if (requiresCompositing(reasonsToComposite)) |
| currentRecursionData.m_mostRecentCompositedLayer = layer; |
| |
| // At this point we have finished collecting all reasons to composite this layer. |
| layer->setCompositingReasons(reasonsToComposite); |
| |
| if (!willBeCompositedOrSquashed && 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 newOffsetFromAbsoluteForSquashingCLM, RenderLayer* newClippingAncestorForMostRecentMapping) |
| { |
| // The most recent backing is done accumulating any more squashing layers. |
| if (hasMostRecentMapping) |
| mostRecentMapping->finishAccumulatingSquashingLayers(nextSquashedLayerIndex); |
| |
| nextSquashedLayerIndex = 0; |
| mostRecentMapping = newCompositedLayerMapping; |
| hasMostRecentMapping = hasNewCompositedLayerMapping; |
| offsetFromAbsoluteForSquashingCLM = newOffsetFromAbsoluteForSquashingCLM; |
| clippingAncestorForMostRecentMapping = newClippingAncestorForMostRecentMapping; |
| } |
| |
| void RenderLayerCompositor::assignLayersToBackings(RenderLayer* updateRoot, bool& layersChanged) |
| { |
| SquashingState squashingState; |
| assignLayersToBackingsInternal(updateRoot, squashingState, layersChanged, updateRoot); |
| if (squashingState.hasMostRecentMapping) |
| squashingState.mostRecentMapping->finishAccumulatingSquashingLayers(squashingState.nextSquashedLayerIndex); |
| } |
| |
| void RenderLayerCompositor::assignLayersToBackingsForReflectionLayer(RenderLayer* reflectionLayer, bool& layersChanged) |
| { |
| CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(reflectionLayer); |
| if (compositedLayerUpdate != NoCompositingStateChange) { |
| layersChanged = true; |
| allocateOrClearCompositedLayerMapping(reflectionLayer, compositedLayerUpdate); |
| } |
| updateDirectCompositingReasons(reflectionLayer); |
| if (reflectionLayer->hasCompositedLayerMapping()) |
| reflectionLayer->compositedLayerMapping()->updateGraphicsLayerConfiguration(); |
| } |
| |
| void RenderLayerCompositor::assignLayersToBackingsInternal(RenderLayer* layer, SquashingState& squashingState, bool& layersChanged, RenderLayer* clippingAncestor) |
| { |
| if (layer->renderer()->hasClipOrOverflowClip()) |
| clippingAncestor = layer; |
| |
| if (layerSquashingEnabled() && requiresSquashing(layer->compositingReasons()) && !canSquashIntoCurrentSquashingOwner(layer, squashingState, clippingAncestor)) |
| layer->setCompositingReasons(layer->compositingReasons() | CompositingReasonOverlapsWithoutSquashingTarget); |
| |
| CompositingStateTransitionType compositedLayerUpdate = computeCompositedLayerUpdate(layer); |
| |
| if (allocateOrClearCompositedLayerMapping(layer, compositedLayerUpdate)) |
| layersChanged = true; |
| |
| // FIXME: special-casing reflection layers here is not right. |
| if (layer->reflectionInfo()) |
| assignLayersToBackingsForReflectionLayer(layer->reflectionInfo()->reflectionLayer(), layersChanged); |
| |
| |
| // Add this layer to a squashing backing if needed. |
| if (layerSquashingEnabled()) { |
| if (updateSquashingAssignment(layer, squashingState, compositedLayerUpdate)) |
| layersChanged = true; |
| } |
| |
| if (layer->stackingNode()->isStackingContainer()) { |
| RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NegativeZOrderChildren); |
| while (RenderLayerStackingNode* curNode = iterator.next()) |
| assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, clippingAncestor); |
| } |
| |
| 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 offsetFromAbsoluteForSquashingCLM = computeOffsetFromAbsolute(layer); |
| squashingState.updateSquashingStateForNewMapping(layer->compositedLayerMapping(), layer->hasCompositedLayerMapping(), offsetFromAbsoluteForSquashingCLM, clippingAncestor); |
| } |
| } |
| |
| RenderLayerStackingNodeIterator iterator(*layer->stackingNode(), NormalFlowChildren | PositiveZOrderChildren); |
| while (RenderLayerStackingNode* curNode = iterator.next()) |
| assignLayersToBackingsInternal(curNode->layer(), squashingState, layersChanged, clippingAncestor); |
| } |
| |
| 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(); |
| } |
| |
| 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); |
| } |
| |
| void RenderLayerCompositor::frameViewScrollbarsExistenceDidChange() |
| { |
| if (m_containerLayer) |
| updateOverflowControlsLayers(); |
| } |
| |
| void RenderLayerCompositor::rootFixedBackgroundsChanged() |
| { |
| if (!supportsFixedRootBackgroundCompositing()) |
| return; |
| |
| // crbug.com/343132. |
| DisableCompositingQueryAsserts disabler; |
| |
| // 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 |
| // + LocalFrame clip |
| // + (Fixed root background) <-- Here. |
| // + LocalFrame 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(); |
| |
| 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; |
| } |
| |
| // FIXME: What does this function do? It needs a clearer name. |
| 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; |
| } |
| |
| // 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(GraphicsLayerUpdater::ForceUpdate); |
| 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() |
| { |
| recursiveRepaintLayer(rootRenderLayer()); |
| } |
| |
| void RenderLayerCompositor::recursiveRepaintLayer(RenderLayer* layer) |
| { |
| // FIXME: This method does not work correctly with transforms. |
| if (layer->compositingState() == PaintsIntoOwnBacking) |
| 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()) |
| 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(); |
| } |
| |
| GraphicsLayer* RenderLayerCompositor::containerLayer() const |
| { |
| return m_containerLayer.get(); |
| } |
| |
| GraphicsLayer* RenderLayerCompositor::ensureRootTransformLayer() |
| { |
| ASSERT(rootGraphicsLayer()); |
| |
| if (!m_rootTransformLayer.get()) { |
| m_rootTransformLayer = GraphicsLayer::create(graphicsLayerFactory(), this); |
| m_overflowControlsHostLayer->addChild(m_rootTransformLayer.get()); |
| m_rootTransformLayer->addChild(m_containerLayer.get()); |
| updateOverflowControlsLayers(); |
| } |
| |
| return m_rootTransformLayer.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 |= m_compositingReasonFinder.directReasons(layer, &m_needsToRecomputeCompositingRequirements); |
| 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; |
| } |
| |
| // 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; |
| |
| const RenderLayer* compositingAncestor = layer->ancestorCompositingLayer(); |
| if (!compositingAncestor) |
| return false; |
| |
| RenderObject* clippingContainer = layer->renderer()->clippingContainer(); |
| if (!clippingContainer) |
| return false; |
| |
| if (compositingAncestor->renderer()->isDescendantOf(clippingContainer)) |
| return false; |
| |
| return true; |
| } |
| |
| // 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(); |
| } |
| |
| 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 |= CompositingReasonPreserve3DWith3DDescendants; |
| |
| if (renderer->style()->hasPerspective()) |
| subtreeReasons |= CompositingReasonPerspectiveWith3DDescendants; |
| } |
| |
| return subtreeReasons; |
| } |
| |
| bool RenderLayerCompositor::isRunningAcceleratedTransformAnimation(RenderObject* renderer) const |
| { |
| if (!m_compositingReasonFinder.hasAnimationTrigger()) |
| return false; |
| 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(); |
| m_isTrackingRepaints = tracksRepaints; |
| } |
| |
| bool RenderLayerCompositor::isTrackingRepaints() const |
| { |
| return m_isTrackingRepaints; |
| } |
| |
| 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 |
| GraphicsLayer* controlsParent = m_rootTransformLayer.get() ? m_rootTransformLayer.get() : m_overflowControlsHostLayer.get(); |
| |
| if (requiresHorizontalScrollbarLayer()) { |
| if (!m_layerForHorizontalScrollbar) { |
| m_layerForHorizontalScrollbar = GraphicsLayer::create(graphicsLayerFactory(), this); |
| controlsParent->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); |
| controlsParent->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); |
| controlsParent->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; |
| m_rootTransformLayer = nullptr; |
| } |
| |
| void RenderLayerCompositor::attachRootLayer(RootLayerAttachment attachment) |
| { |
| if (!m_rootContentLayer) |
| return; |
| |
| switch (attachment) { |
| case RootLayerUnattached: |
| ASSERT_NOT_REACHED(); |
| break; |
| case RootLayerAttachedViaChromeClient: { |
| LocalFrame& frame = m_renderView.frameView()->frame(); |
| Page* page = frame.page(); |
| if (!page) |
| return; |
| page->chrome().client().attachRootGraphicsLayer(rootGraphicsLayer()); |
| break; |
| } |
| case RootLayerAttachedViaEnclosingFrame: { |
| HTMLFrameOwnerElement* ownerElement = m_renderView.document().ownerElement(); |
| ASSERT(ownerElement); |
| DeprecatedScheduleStyleRecalcDuringCompositingUpdate marker(ownerElement->document().lifecycle()); |
| // The layer will get hooked up via CompositedLayerMapping::updateGraphicsLayerConfiguration() |
| // for the frame's renderer in the parent 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()) { |
| DeprecatedScheduleStyleRecalcDuringCompositingUpdate marker(ownerElement->document().lifecycle()); |
| ownerElement->scheduleLayerUpdate(); |
| } |
| break; |
| } |
| case RootLayerAttachedViaChromeClient: { |
| LocalFrame& frame = m_renderView.frameView()->frame(); |
| Page* page = frame.page(); |
| if (!page) |
| return; |
| page->chrome().client().attachRootGraphicsLayer(0); |
| } |
| break; |
| case RootLayerUnattached: |
| break; |
| } |
| |
| m_rootLayerAttachment = RootLayerUnattached; |
| } |
| |
| void RenderLayerCompositor::updateRootLayerAttachment() |
| { |
| ensureRootLayer(); |
| } |
| |
| bool RenderLayerCompositor::isMainFrame() const |
| { |
| // FIXME: LocalFrame::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; |
| LocalFrame& frame = m_renderView.frameView()->frame(); |
| |
| for (LocalFrame* child = frame.tree().firstChild(); child; child = child->tree().traverseNext(&frame)) { |
| if (!child->document()) |
| continue; // FIXME: Can this happen? |
| if (HTMLFrameOwnerElement* ownerElement = child->document()->ownerElement()) { |
| DeprecatedScheduleStyleRecalcDuringCompositingUpdate marker(ownerElement->document().lifecycle()); |
| 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->document().renderView()->compositor()->setNeedsToRecomputeCompositingRequirements(); |
| DeprecatedScheduleStyleRecalcDuringCompositingUpdate marker(ownerElement->document().lifecycle()); |
| 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; |
| } |
| |
| void RenderLayerCompositor::updateViewportConstraintStatus(RenderLayer* layer) |
| { |
| if (CompositingReasonFinder::isViewportConstrainedFixedOrStickyLayer(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()); |
| // We should never get here for stickies constrained by an enclosing clipping layer. |
| ASSERT(!layer->enclosingOverflowClipLayer(ExcludeSelf)); |
| |
| 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(); |
| } |
| |
| DocumentLifecycle& RenderLayerCompositor::lifecycle() const |
| { |
| return m_renderView.document().lifecycle(); |
| } |
| |
| String RenderLayerCompositor::debugName(const GraphicsLayer* graphicsLayer) |
| { |
| String name; |
| if (graphicsLayer == m_rootContentLayer.get()) { |
| name = "Content Root Layer"; |
| } else if (graphicsLayer == m_rootTransformLayer.get()) { |
| name = "Root Transform 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 = "LocalFrame Clipping Layer"; |
| } else if (graphicsLayer == m_scrollLayer.get()) { |
| name = "LocalFrame Scrolling Layer"; |
| } else { |
| ASSERT_NOT_REACHED(); |
| } |
| |
| return name; |
| } |
| |
| } // namespace WebCore |