// This information doesn't appear to be incorporated into CompositingReasons. bool CompositingReasonFinder::requiresCompositingForScrollableFrame() const { // Need this done first to determine overflow. ASSERT(!m_renderView.needsLayout()); if (isMainFrame()) return false; if (!(m_compositingTriggers & ScrollableInnerFrameTrigger)) return false; FrameView* frameView = m_renderView.frameView(); return frameView->isScrollable(); }
void PaintPropertyTreeBuilder::buildTreeNodes( FrameView& frameView, PaintPropertyTreeBuilderContext& context) { if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { LayoutView* layoutView = frameView.layoutView(); if (!layoutView) return; TransformationMatrix frameTranslate; frameTranslate.translate(frameView.x() + layoutView->location().x() + context.current.paintOffset.x(), frameView.y() + layoutView->location().y() + context.current.paintOffset.y()); context.current.transform = layoutView->getMutableForPainting() .ensurePaintProperties() .updatePaintOffsetTranslation(context.current.transform, frameTranslate, FloatPoint3D()); context.current.paintOffset = LayoutPoint(); context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = true; context.absolutePosition = context.current; context.containerForAbsolutePosition = nullptr; // This will get set in updateOutOfFlowContext(). context.fixedPosition = context.current; return; } TransformationMatrix frameTranslate; frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), frameView.y() + context.current.paintOffset.y()); context.current.transform = updateFrameViewPreTranslation( frameView, context.current.transform, frameTranslate, FloatPoint3D()); FloatRoundedRect contentClip( IntRect(IntPoint(), frameView.visibleContentSize())); context.current.clip = updateFrameViewContentClip( frameView, context.current.clip, frameView.preTranslation(), contentClip); // Record the fixed properties before any scrolling occurs. const auto* fixedTransformNode = context.current.transform; auto* fixedScrollNode = context.current.scroll; ScrollOffset scrollOffset = frameView.scrollOffset(); if (frameView.isScrollable() || !scrollOffset.isZero()) { TransformationMatrix frameScroll; frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); context.current.transform = updateFrameViewScrollTranslation( frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); IntSize scrollClip = frameView.visibleContentSize(); IntSize scrollBounds = frameView.contentsSize(); bool userScrollableHorizontal = frameView.userInputScrollable(HorizontalScrollbar); bool userScrollableVertical = frameView.userInputScrollable(VerticalScrollbar); context.current.scroll = updateFrameViewScroll( frameView, context.current.scroll, frameView.scrollTranslation(), scrollClip, scrollBounds, userScrollableHorizontal, userScrollableVertical); } else { // Ensure pre-existing properties are cleared when there is no scrolling. frameView.setScrollTranslation(nullptr); frameView.setScroll(nullptr); } // Initialize the context for current, absolute and fixed position cases. // They are the same, except that scroll translation does not apply to // fixed position descendants. context.current.paintOffset = LayoutPoint(); context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = true; context.absolutePosition = context.current; context.containerForAbsolutePosition = nullptr; context.fixedPosition = context.current; context.fixedPosition.transform = fixedTransformNode; context.fixedPosition.scroll = fixedScrollNode; std::unique_ptr<PropertyTreeState> contentsState( new PropertyTreeState(context.current.transform, context.current.clip, context.currentEffect, context.current.scroll)); frameView.setTotalPropertyTreeStateForContents(std::move(contentsState)); }
void PaintPropertyTreeBuilder::updateFramePropertiesAndContext( FrameView& frameView, PaintPropertyTreeBuilderContext& context) { if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) { // With root layer scrolling, the LayoutView (a LayoutObject) properties are // updated like other objects (see updatePropertiesAndContextForSelf and // updatePropertiesAndContextForChildren) instead of needing LayoutView- // specific property updates here. context.current.paintOffset.moveBy(frameView.location()); context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = true; context.absolutePosition = context.current; context.containerForAbsolutePosition = nullptr; context.fixedPosition = context.current; return; } TransformationMatrix frameTranslate; frameTranslate.translate(frameView.x() + context.current.paintOffset.x(), frameView.y() + context.current.paintOffset.y()); updateFrameViewPreTranslation(frameView, context.current.transform, frameTranslate, FloatPoint3D()); FloatRoundedRect contentClip( IntRect(IntPoint(), frameView.visibleContentSize())); updateFrameViewContentClip(frameView, context.current.clip, frameView.preTranslation(), contentClip); ScrollOffset scrollOffset = frameView.scrollOffset(); if (frameView.isScrollable() || !scrollOffset.isZero()) { TransformationMatrix frameScroll; frameScroll.translate(-scrollOffset.width(), -scrollOffset.height()); updateFrameViewScrollTranslation(frameView, frameView.preTranslation(), frameScroll, FloatPoint3D()); IntSize scrollClip = frameView.visibleContentSize(); IntSize scrollBounds = frameView.contentsSize(); bool userScrollableHorizontal = frameView.userInputScrollable(HorizontalScrollbar); bool userScrollableVertical = frameView.userInputScrollable(VerticalScrollbar); updateFrameViewScroll(frameView, context.current.scroll, frameView.scrollTranslation(), scrollClip, scrollBounds, userScrollableHorizontal, userScrollableVertical); } else { // Ensure pre-existing properties are cleared when there is no scrolling. frameView.setScrollTranslation(nullptr); frameView.setScroll(nullptr); } // Initialize the context for current, absolute and fixed position cases. // They are the same, except that scroll translation does not apply to // fixed position descendants. const auto* fixedTransformNode = frameView.preTranslation() ? frameView.preTranslation() : context.current.transform; auto* fixedScrollNode = context.current.scroll; DCHECK(frameView.preTranslation()); context.current.transform = frameView.preTranslation(); DCHECK(frameView.contentClip()); context.current.clip = frameView.contentClip(); if (const auto* scrollTranslation = frameView.scrollTranslation()) context.current.transform = scrollTranslation; if (auto* scroll = frameView.scroll()) context.current.scroll = scroll; context.current.paintOffset = LayoutPoint(); context.current.renderingContextID = 0; context.current.shouldFlattenInheritedTransform = true; context.absolutePosition = context.current; context.containerForAbsolutePosition = nullptr; context.fixedPosition = context.current; context.fixedPosition.transform = fixedTransformNode; context.fixedPosition.scroll = fixedScrollNode; std::unique_ptr<PropertyTreeState> contentsState( new PropertyTreeState(context.current.transform, context.current.clip, context.currentEffect, context.current.scroll)); frameView.setTotalPropertyTreeStateForContents(std::move(contentsState)); }
bool CompositingReasonFinder::requiresCompositingForPosition(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason, bool* needToRecomputeCompositingRequirements) const { // position:fixed elements that create their own stacking context (e.g. have an explicit z-index, // opacity, transform) can get their own composited layer. A stacking context is required otherwise // z-index and clipping will be broken. if (!renderer->isPositioned()) return false; EPosition position = renderer->style()->position(); bool isFixed = renderer->isOutOfFlowPositioned() && position == FixedPosition; // FIXME: The isStackingContainer check here is redundant. Fixed position elements are always stacking contexts. if (isFixed && !layer->stackingNode()->isStackingContainer()) return false; bool isSticky = renderer->isInFlowPositioned() && position == StickyPosition; if (!isFixed && !isSticky) return false; // FIXME: acceleratedCompositingForFixedPositionEnabled should probably be renamed acceleratedCompositingForViewportConstrainedPositionEnabled(). if (Settings* settings = m_renderView.document().settings()) { if (!settings->acceleratedCompositingForFixedPositionEnabled()) return false; } if (isSticky) return isViewportConstrainedFixedOrStickyLayer(layer); RenderObject* container = renderer->container(); // If the renderer is not hooked up yet then we have to wait until it is. if (!container) { *needToRecomputeCompositingRequirements = true; return false; } // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements. // They will stay fixed wrt the container rather than the enclosing frame. if (container != &m_renderView) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer; return false; } // If the fixed-position element does not have any scrollable ancestor between it and // its container, then we do not need to spend compositor resources for it. Start by // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below. bool hasScrollableAncestor = false; // The FrameView has the scrollbars associated with the top level viewport, so we have to // check the FrameView in addition to the hierarchy of ancestors. FrameView* frameView = m_renderView.frameView(); if (frameView && frameView->isScrollable()) hasScrollableAncestor = true; RenderLayer* ancestor = layer->parent(); while (ancestor && !hasScrollableAncestor) { if (frameView->containsScrollableArea(ancestor->scrollableArea())) hasScrollableAncestor = true; if (ancestor->renderer() == &m_renderView) break; ancestor = ancestor->parent(); } if (!hasScrollableAncestor) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors; return false; } // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done. if (m_renderView.document().lifecycle().state() < DocumentLifecycle::LayoutClean) { *needToRecomputeCompositingRequirements = true; return layer->hasCompositedLayerMapping(); } bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant(); if (!paintsContent) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent; return false; } // Fixed position elements that are invisible in the current view don't get their own layer. if (FrameView* frameView = m_renderView.frameView()) { LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect(); LayoutRect layerBounds = layer->calculateLayerBounds(layer->compositor()->rootRenderLayer(), 0, RenderLayer::DefaultCalculateLayerBoundsFlags | RenderLayer::ExcludeHiddenDescendants | RenderLayer::DontConstrainForMask | RenderLayer::IncludeCompositedDescendants | RenderLayer::PretendLayerHasOwnBacking); if (!viewBounds.intersects(enclosingIntRect(layerBounds))) { if (viewportConstrainedNotCompositedReason) { *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView; *needToRecomputeCompositingRequirements = true; } return false; } } return true; }
bool CompositingReasonFinder::requiresCompositingForPositionFixed(RenderObject* renderer, const RenderLayer* layer, RenderLayer::ViewportConstrainedNotCompositedReason* viewportConstrainedNotCompositedReason, bool* needToRecomputeCompositingRequirements) const { if (!(m_compositingTriggers & ViewportConstrainedPositionedTrigger)) return false; if (renderer->style()->position() != FixedPosition) return false; RenderObject* container = renderer->container(); // If the renderer is not hooked up yet then we have to wait until it is. if (!container) { ASSERT(m_renderView.document().lifecycle().state() < DocumentLifecycle::InCompositingUpdate); // FIXME: Remove this and ASSERT(container) once we get rid of the incremental // allocateOrClearCompositedLayerMapping compositing update. This happens when // adding the renderer to the tree because we setStyle before addChild in // createRendererForElementIfNeeded. *needToRecomputeCompositingRequirements = true; return false; } // Don't promote fixed position elements that are descendants of a non-view container, e.g. transformed elements. // They will stay fixed wrt the container rather than the enclosing frame. if (container != &m_renderView) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNonViewContainer; return false; } // If the fixed-position element does not have any scrollable ancestor between it and // its container, then we do not need to spend compositor resources for it. Start by // assuming we can opt-out (i.e. no scrollable ancestor), and refine the answer below. bool hasScrollableAncestor = false; // The FrameView has the scrollbars associated with the top level viewport, so we have to // check the FrameView in addition to the hierarchy of ancestors. FrameView* frameView = m_renderView.frameView(); if (frameView && frameView->isScrollable()) hasScrollableAncestor = true; RenderLayer* ancestor = layer->parent(); while (ancestor && !hasScrollableAncestor) { if (ancestor->scrollsOverflow()) hasScrollableAncestor = true; if (ancestor->renderer() == &m_renderView) break; ancestor = ancestor->parent(); } if (!hasScrollableAncestor) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForUnscrollableAncestors; return false; } // Subsequent tests depend on layout. If we can't tell now, just keep things the way they are until layout is done. // FIXME: Get rid of this codepath once we get rid of the incremental compositing update in RenderLayer::styleChanged. if (m_renderView.document().lifecycle().state() < DocumentLifecycle::LayoutClean) { *needToRecomputeCompositingRequirements = true; return layer->hasCompositedLayerMapping(); } bool paintsContent = layer->isVisuallyNonEmpty() || layer->hasVisibleDescendant(); if (!paintsContent) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForNoVisibleContent; return false; } // Fixed position elements that are invisible in the current view don't get their own layer. if (FrameView* frameView = m_renderView.frameView()) { ASSERT(m_renderView.document().lifecycle().state() == DocumentLifecycle::InCompositingUpdate); LayoutRect viewBounds = frameView->viewportConstrainedVisibleContentRect(); LayoutRect layerBounds = layer->boundingBoxForCompositing(layer->compositor()->rootRenderLayer(), RenderLayer::ApplyBoundsChickenEggHacks); if (!viewBounds.intersects(enclosingIntRect(layerBounds))) { if (viewportConstrainedNotCompositedReason) *viewportConstrainedNotCompositedReason = RenderLayer::NotCompositedForBoundsOutOfView; return false; } } return true; }