static bool shouldCreateSubsequence(const PaintLayer& paintLayer, GraphicsContext& context, const PaintLayerPaintingInfo& paintingInfo, PaintLayerFlags paintFlags) { // Caching is not needed during printing. if (context.printing()) return false; // Don't create subsequence for a composited layer because if it can be cached, // we can skip the whole painting in GraphicsLayer::paint() with CachedDisplayItemList. // This also avoids conflict of PaintLayer::previousXXX() when paintLayer is composited // scrolling and is painted twice for GraphicsLayers of container and scrolling contents. if (paintLayer.compositingState() == PaintsIntoOwnBacking) return false; // Don't create subsequence during special painting to avoid cache conflict with normal painting. if (paintingInfo.globalPaintFlags() & GlobalPaintFlattenCompositingLayers) return false; if (paintFlags & (PaintLayerPaintingReflection | PaintLayerPaintingRootBackgroundOnly | PaintLayerPaintingOverlayScrollbars | PaintLayerUncachedClipRects)) return false; // Create subsequence for only stacking contexts whose painting are atomic. if (!paintLayer.stackingNode()->isStackingContext()) return false; // The layer doesn't have children. Subsequence caching is not worth because normally the actual painting will be cheap. if (!PaintLayerStackingNodeIterator(*paintLayer.stackingNode(), AllChildren).next()) return false; return true; }
TEST_F(PaintLayerClipperTest, NestedContainPaintClip) { setBodyInnerHTML( "<div style='contain: paint; width: 200px; height: 200px; overflow: " "auto'>" " <div id='target' style='contain: paint; height: 400px'>" " </div>" "</div>"); LayoutRect infiniteRect(LayoutRect::infiniteIntRect()); PaintLayer* layer = toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer(); ClipRectsContext context(layer->parent(), PaintingClipRectsIgnoringOverflowClip); LayoutRect layerBounds; ClipRect backgroundRect, foregroundRect; layer->clipper().calculateRects(context, infiniteRect, layerBounds, backgroundRect, foregroundRect); EXPECT_EQ(LayoutRect(0, 0, 200, 400), backgroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), foregroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds); ClipRectsContext contextClip(layer->parent(), PaintingClipRects); layer->clipper().calculateRects(contextClip, infiniteRect, layerBounds, backgroundRect, foregroundRect); EXPECT_EQ(LayoutRect(0, 0, 200, 200), backgroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 200), foregroundRect.rect()); EXPECT_EQ(LayoutRect(0, 0, 200, 400), layerBounds); }
void InspectorLayerTreeAgent::buildLayerIdToNodeIdMap( PaintLayer* root, LayerIdToNodeIdMap& layerIdToNodeIdMap) { if (root->hasCompositedLayerMapping()) { if (Node* node = root->layoutObject()->generatingNode()) { GraphicsLayer* graphicsLayer = root->compositedLayerMapping()->childForSuperlayers(); layerIdToNodeIdMap.set(graphicsLayer->platformLayer()->id(), idForNode(node)); } } for (PaintLayer* child = root->firstChild(); child; child = child->nextSibling()) buildLayerIdToNodeIdMap(child, layerIdToNodeIdMap); if (!root->layoutObject()->isLayoutIFrame()) return; FrameView* childFrameView = toFrameView(toLayoutPart(root->layoutObject())->widget()); LayoutViewItem childLayoutViewItem = childFrameView->layoutViewItem(); if (!childLayoutViewItem.isNull()) { if (PaintLayerCompositor* childCompositor = childLayoutViewItem.compositor()) buildLayerIdToNodeIdMap(childCompositor->rootLayer(), layerIdToNodeIdMap); } }
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { if (object.isBoxModelObject()) { // TODO(trchen): Eliminate PaintLayer dependency. PaintLayer* layer = toLayoutBoxModelObject(object).layer(); if (!layer || !layer->paintsWithTransform(GlobalPaintNormalPhase)) return; } if (context.paintOffset == LayoutPoint()) return; // We should use the same subpixel paint offset values for snapping regardless of whether a // transform is present. If there is a transform we round the paint offset but keep around // the residual fractional component for the transformed content to paint with. // In spv1 this was called "subpixel accumulation". For more information, see // PaintLayer::subpixelAccumulation() and PaintLayerPainter::paintFragmentByApplyingTransform. IntPoint roundedPaintOffset = roundedIntPoint(context.paintOffset); LayoutPoint fractionalPaintOffset = LayoutPoint(context.paintOffset - roundedPaintOffset); RefPtr<TransformPaintPropertyNode> paintOffsetTranslation = TransformPaintPropertyNode::create( TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()), FloatPoint3D(), context.currentTransform); context.currentTransform = paintOffsetTranslation.get(); context.paintOffset = fractionalPaintOffset; object.getMutableForPainting().ensureObjectPaintProperties().setPaintOffsetTranslation(paintOffsetTranslation.release()); }
PaintLayerStackingNode* PaintLayerStackingNodeReverseIterator::next() { if (m_remainingChildren & NegativeZOrderChildren) { Vector<PaintLayerStackingNode*>* negZOrderList = m_root.negZOrderList(); if (negZOrderList && m_index >= 0) return negZOrderList->at(m_index--); m_remainingChildren &= ~NegativeZOrderChildren; setIndexToLastItem(); } if (m_remainingChildren & NormalFlowChildren) { for (; m_currentNormalFlowChild; m_currentNormalFlowChild = m_currentNormalFlowChild->previousSibling()) { if (!m_currentNormalFlowChild->stackingNode()->isStacked() && !m_currentNormalFlowChild->isReflection()) { PaintLayer* normalFlowChild = m_currentNormalFlowChild; m_currentNormalFlowChild = m_currentNormalFlowChild->previousSibling(); return normalFlowChild->stackingNode(); } } m_remainingChildren &= ~NormalFlowChildren; setIndexToLastItem(); } if (m_remainingChildren & PositiveZOrderChildren) { Vector<PaintLayerStackingNode*>* posZOrderList = m_root.posZOrderList(); if (posZOrderList && m_index >= 0) return posZOrderList->at(m_index--); m_remainingChildren &= ~PositiveZOrderChildren; setIndexToLastItem(); } return 0; }
bool CompositorAnimations::startAnimationOnCompositor(const Element& element, int group, double startTime, double timeOffset, const Timing& timing, const Animation& animation, const EffectModel& effect, Vector<int>& startedAnimationIds, double animationPlaybackRate) { ASSERT(startedAnimationIds.isEmpty()); ASSERT(isCandidateForAnimationOnCompositor(timing, element, &animation, effect, animationPlaybackRate)); ASSERT(canStartAnimationOnCompositor(element)); const KeyframeEffectModelBase& keyframeEffect = toKeyframeEffectModelBase(effect); PaintLayer* layer = toLayoutBoxModelObject(element.layoutObject())->layer(); ASSERT(layer); Vector<OwnPtr<WebCompositorAnimation>> animations; CompositorAnimationsImpl::getAnimationOnCompositor(timing, group, startTime, timeOffset, keyframeEffect, animations, animationPlaybackRate); ASSERT(!animations.isEmpty()); for (auto& compositorAnimation : animations) { int id = compositorAnimation->id(); if (RuntimeEnabledFeatures::compositorAnimationTimelinesEnabled()) { WebCompositorAnimationPlayer* compositorPlayer = animation.compositorPlayer(); ASSERT(compositorPlayer); compositorPlayer->addAnimation(compositorAnimation.leakPtr()); } else if (!layer->compositedLayerMapping()->mainGraphicsLayer()->addAnimation(compositorAnimation.release())) { // FIXME: We should know ahead of time whether these animations can be started. for (int startedAnimationId : startedAnimationIds) cancelAnimationOnCompositor(element, animation, startedAnimationId); startedAnimationIds.clear(); return false; } startedAnimationIds.append(id); } ASSERT(!startedAnimationIds.isEmpty()); return true; }
TEST_F(PaintLayerScrollableAreaTest, OpaqueLayersDepromotedOnStyleChange) { RuntimeEnabledFeatures::setCompositeOpaqueScrollersEnabled(true); setBodyInnerHTML( "<style>" "#scroller { overflow: scroll; height: 200px; width: 200px; background: " "white local content-box; }" "#scrolled { height: 300px; }" "</style>" "<div id=\"scroller\"><div id=\"scrolled\"></div></div>"); document().view()->updateAllLifecyclePhases(); EXPECT_TRUE(RuntimeEnabledFeatures::compositeOpaqueScrollersEnabled()); Element* scroller = document().getElementById("scroller"); PaintLayer* paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_TRUE(paintLayer->needsCompositedScrolling()); // Change the background to transparent scroller->setAttribute( HTMLNames::styleAttr, "background: rgba(255,255,255,0.5) local content-box;"); document().view()->updateAllLifecyclePhases(); paintLayer = toLayoutBoxModelObject(scroller->layoutObject())->layer(); ASSERT_TRUE(paintLayer); EXPECT_FALSE(paintLayer->needsCompositedScrolling()); EXPECT_FALSE(paintLayer->graphicsLayerBacking()); EXPECT_FALSE(paintLayer->graphicsLayerBackingForScrolling()); }
void PaintLayerClipper::calculateClipRects(const ClipRectsContext& context, ClipRects& clipRects) const { bool rootLayerScrolls = m_layoutObject.document().settings() && m_layoutObject.document().settings()->rootLayerScrolls(); if (!m_layoutObject.layer()->parent() && !rootLayerScrolls) { // The root layer's clip rect is always infinite. clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect())); return; } bool isClippingRoot = m_layoutObject.layer() == context.rootLayer; // For transformed layers, the root layer was shifted to be us, so there is no need to // examine the parent. We want to cache clip rects with us as the root. PaintLayer* parentLayer = !isClippingRoot ? m_layoutObject.layer()->parent() : 0; // Ensure that our parent's clip has been calculated so that we can examine the values. if (parentLayer) { // FIXME: Why don't we just call getClipRects here? if (context.usesCache() && parentLayer->clipper().cachedClipRects(context)) { clipRects = *parentLayer->clipper().cachedClipRects(context); } else { parentLayer->clipper().calculateClipRects(context, clipRects); } } else { clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect())); } adjustClipRectsForChildren(m_layoutObject, clipRects); if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.hasClip()) { // This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across // some transformed layer boundary, for example, in the PaintLayerCompositor overlapMap, where // clipRects are needed in view space. applyClipRects(context, m_layoutObject, roundedLayoutPoint(m_layoutObject.localToContainerPoint(FloatPoint(), context.rootLayer->layoutObject())), clipRects); } }
AffineTransform SVGLayoutSupport::deprecatedCalculateTransformToLayer( const LayoutObject* layoutObject) { AffineTransform transform; while (layoutObject) { transform = layoutObject->localToSVGParentTransform() * transform; if (layoutObject->isSVGRoot()) break; layoutObject = layoutObject->parent(); } // Continue walking up the layer tree, accumulating CSS transforms. // FIXME: this queries layer compositing state - which is not // supported during layout. Hence, the result may not include all CSS // transforms. PaintLayer* layer = layoutObject ? layoutObject->enclosingLayer() : 0; while (layer && layer->isAllowedToQueryCompositingState()) { // We can stop at compositing layers, to match the backing resolution. // FIXME: should we be computing the transform to the nearest composited // layer, or the nearest composited layer that does not paint into its // ancestor? I think this is the nearest composited ancestor since we will // inherit its transforms in the composited layer tree. if (layer->compositingState() != NotComposited) break; if (TransformationMatrix* layerTransform = layer->transform()) transform = layerTransform->toAffineTransform() * transform; layer = layer->parent(); } return transform; }
// The descendant-dependent flags system is badly broken because we clean dirty // bits in upward tree walks, which means we need to call updateDescendantDependentFlags // at every node in the tree to fully clean all the dirty bits. While we'll in // the process of fixing this issue, updateDescendantDependentFlagsForEntireSubtree // provides a big hammer for actually cleaning all the dirty bits in a subtree. // // FIXME: Remove this function once the descendant-dependent flags system keeps // its dirty bits scoped to subtrees. void updateDescendantDependentFlagsForEntireSubtree(PaintLayer& layer) { layer.updateDescendantDependentFlags(); for (PaintLayer* child = layer.firstChild(); child; child = child->nextSibling()) updateDescendantDependentFlagsForEntireSubtree(*child); }
void PaintLayerClipper::clearClipRectsIncludingDescendants() { m_cache = nullptr; for (PaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) { layer->clipper().clearClipRectsIncludingDescendants(); } }
void PaintLayerClipper::clearClipRectsIncludingDescendants(ClipRectsCacheSlot cacheSlot) { if (m_cache) m_cache->clear(cacheSlot); for (PaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) { layer->clipper().clearClipRectsIncludingDescendants(cacheSlot); } }
BoxReflection boxReflectionForPaintLayer(const PaintLayer& layer, const ComputedStyle& style) { const StyleReflection* reflectStyle = style.boxReflect(); LayoutRect frameLayoutRect = toLayoutBox(layer.layoutObject())->frameRect(); FloatRect frameRect(frameLayoutRect); BoxReflection::ReflectionDirection direction = BoxReflection::VerticalReflection; float offset = 0; switch (reflectStyle->direction()) { case ReflectionAbove: direction = BoxReflection::VerticalReflection; offset = -floatValueForLength(reflectStyle->offset(), frameRect.height()); break; case ReflectionBelow: direction = BoxReflection::VerticalReflection; offset = 2 * frameRect.height() + floatValueForLength(reflectStyle->offset(), frameRect.height()); break; case ReflectionLeft: direction = BoxReflection::HorizontalReflection; offset = -floatValueForLength(reflectStyle->offset(), frameRect.width()); break; case ReflectionRight: direction = BoxReflection::HorizontalReflection; offset = 2 * frameRect.width() + floatValueForLength(reflectStyle->offset(), frameRect.width()); break; } sk_sp<SkPicture> mask; const NinePieceImage& maskNinePiece = reflectStyle->mask(); if (maskNinePiece.hasImage()) { LayoutRect maskRect(LayoutPoint(), frameLayoutRect.size()); LayoutRect maskBoundingRect(maskRect); maskBoundingRect.expand(style.imageOutsets(maskNinePiece)); FloatRect maskBoundingFloatRect(maskBoundingRect); // TODO(jbroman): SkPictureBuilder + DrawingRecorder seems excessive. // If NinePieceImagePainter operated on SkCanvas, we'd only need an // SkPictureRecorder here. SkPictureBuilder recorder(maskBoundingFloatRect); { GraphicsContext& context = recorder.context(); DrawingRecorder drawingRecorder(context, *layer.layoutObject(), DisplayItem::kReflectionMask, maskBoundingFloatRect); NinePieceImagePainter(*layer.layoutObject()) .paint(recorder.context(), maskRect, style, maskNinePiece, SkXfermode::kSrcOver_Mode); } mask = recorder.endRecording(); } return BoxReflection(direction, offset, std::move(mask)); }
void PaintLayerClipper::clearClipRectsIncludingDescendants() { if (m_geometryMapper) m_geometryMapper.reset(new GeometryMapper); m_layer.clearClipRectsCache(); for (PaintLayer* layer = m_layer.firstChild(); layer; layer = layer->nextSibling()) { layer->clipper().clearClipRectsIncludingDescendants(); } }
PaintLayerStackingNode* PaintLayerStackingNode::ancestorStackingContextNode() const { for (PaintLayer* ancestor = layer()->parent(); ancestor; ancestor = ancestor->parent()) { PaintLayerStackingNode* stackingNode = ancestor->stackingNode(); if (stackingNode->isStackingContext()) return stackingNode; } return 0; }
static void fullyInvalidatePaintRecursive(PaintLayer* layer) { if (layer->compositingState() == PaintsIntoOwnBacking) { layer->compositedLayerMapping()->setContentsNeedDisplay(); layer->compositedLayerMapping()->setSquashingContentsNeedDisplay(); } for (PaintLayer* child = layer->firstChild(); child; child = child->nextSibling()) fullyInvalidatePaintRecursive(child); }
void PaintPropertyTreeBuilder::updatePaintOffsetTranslation( const LayoutObject& object, PaintPropertyTreeBuilderContext& context) { bool usesPaintOffsetTranslation = false; if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && object.isLayoutView()) { // Root layer scrolling always creates a translation node for LayoutView to // ensure fixed and absolute contexts use the correct transform space. usesPaintOffsetTranslation = true; } else if (object.isBoxModelObject() && context.current.paintOffset != LayoutPoint()) { // TODO(trchen): Eliminate PaintLayer dependency. PaintLayer* layer = toLayoutBoxModelObject(object).layer(); if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) usesPaintOffsetTranslation = true; } // We should use the same subpixel paint offset values for snapping // regardless of whether a transform is present. If there is a transform // we round the paint offset but keep around the residual fractional // component for the transformed content to paint with. In spv1 this was // called "subpixel accumulation". For more information, see // PaintLayer::subpixelAccumulation() and // PaintLayerPainter::paintFragmentByApplyingTransform. IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset); LayoutPoint fractionalPaintOffset = LayoutPoint(context.current.paintOffset - roundedPaintOffset); if (usesPaintOffsetTranslation) { object.getMutableForPainting() .ensurePaintProperties() .updatePaintOffsetTranslation( context.current.transform, TransformationMatrix().translate(roundedPaintOffset.x(), roundedPaintOffset.y()), FloatPoint3D(), context.current.shouldFlattenInheritedTransform, context.current.renderingContextID); } else { if (auto* properties = object.getMutableForPainting().paintProperties()) properties->clearPaintOffsetTranslation(); } const auto* properties = object.paintProperties(); if (properties && properties->paintOffsetTranslation()) { context.current.transform = properties->paintOffsetTranslation(); context.current.paintOffset = fractionalPaintOffset; if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() && object.isLayoutView()) { context.absolutePosition.transform = properties->paintOffsetTranslation(); context.fixedPosition.transform = properties->paintOffsetTranslation(); context.absolutePosition.paintOffset = LayoutPoint(); context.fixedPosition.paintOffset = LayoutPoint(); } } }
TEST_F(CompositedLayerMappingTest, RotatedInterestRect) { setBodyInnerHTML( "<div id='target' style='width: 200px; height: 200px; will-change: transform; transform: rotateZ(45deg)'></div>"); document().view()->updateAllLifecyclePhases(); Element* element = document().getElementById("target"); PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer(); ASSERT_TRUE(!!paintLayer->graphicsLayerBacking()); EXPECT_RECT_EQ(IntRect(0, 0, 200, 200), recomputeInterestRect(paintLayer->graphicsLayerBacking())); }
GraphicsLayer* PaintLayerCompositor::fixedRootBackgroundLayer() const { // Get the fixed root background from the LayoutView layer's compositedLayerMapping. PaintLayer* viewLayer = m_layoutView.layer(); if (!viewLayer) return nullptr; if (viewLayer->compositingState() == PaintsIntoOwnBacking && viewLayer->compositedLayerMapping()->backgroundLayerPaintsFixedRootBackground()) return viewLayer->compositedLayerMapping()->backgroundLayer(); return nullptr; }
static void checkIsClippingStackingContextAndContainer(LayoutBoxModelObject& obj) { EXPECT_TRUE(obj.canContainFixedPositionObjects()); EXPECT_TRUE(obj.hasClipRelatedProperty()); EXPECT_TRUE(obj.style()->containsPaint()); // TODO(leviw): Ideally, we wouldn't require a paint layer to handle the clipping // and stacking performed by paint containment. ASSERT(obj.layer()); PaintLayer* layer = obj.layer(); EXPECT_TRUE(layer->stackingNode() && layer->stackingNode()->isStackingContext()); }
TEST_F(CompositedLayerMappingTest, TallLayerInterestRect) { setBodyInnerHTML("<div id='target' style='width: 200px; height: 10000px; will-change: transform'></div>"); document().view()->updateAllLifecyclePhases(); Element* element = document().getElementById("target"); PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer(); ASSERT_TRUE(paintLayer->graphicsLayerBacking()); // Screen-space visible content rect is [8, 8, 200, 600]. Mapping back to local, adding 4000px in all directions, then // clipping, yields this rect. EXPECT_RECT_EQ(IntRect(0, 0, 200, 4592), recomputeInterestRect(paintLayer->graphicsLayerBacking())); }
void PaintLayerStackingNode::rebuildZOrderLists() { #if DCHECK_IS_ON() DCHECK(m_layerListMutationAllowed); #endif DCHECK(isDirtyStackingContext()); for (PaintLayer* child = layer()->firstChild(); child; child = child->nextSibling()) child->stackingNode()->collectLayers(m_posZOrderList, m_negZOrderList); // Sort the two lists. if (m_posZOrderList) std::stable_sort(m_posZOrderList->begin(), m_posZOrderList->end(), compareZIndex); if (m_negZOrderList) std::stable_sort(m_negZOrderList->begin(), m_negZOrderList->end(), compareZIndex); // Append layers for top layer elements after normal layer collection, to // ensure they are on top regardless of z-indexes. The layoutObjects of top // layer elements are children of the view, sorted in top layer stacking // order. if (layer()->isRootLayer()) { LayoutBlockFlow* rootBlock = layoutObject()->view(); // If the viewport is paginated, everything (including "top-layer" elements) // gets redirected to the flow thread. So that's where we have to look, in // that case. if (LayoutBlockFlow* multiColumnFlowThread = rootBlock->multiColumnFlowThread()) rootBlock = multiColumnFlowThread; for (LayoutObject* child = rootBlock->firstChild(); child; child = child->nextSibling()) { Element* childElement = (child->node() && child->node()->isElementNode()) ? toElement(child->node()) : 0; if (childElement && childElement->isInTopLayer()) { PaintLayer* layer = toLayoutBoxModelObject(child)->layer(); // Create the buffer if it doesn't exist yet. if (!m_posZOrderList) m_posZOrderList = wrapUnique(new Vector<PaintLayerStackingNode*>); m_posZOrderList->append(layer->stackingNode()); } } } #if ENABLE(ASSERT) updateStackingParentForZOrderLists(this); #endif m_zOrderListsDirty = false; }
bool PaintLayerCompositor::attachFrameContentLayersToIframeLayer(LayoutPart* layoutObject) { PaintLayerCompositor* innerCompositor = frameContentsCompositor(layoutObject); if (!innerCompositor || !innerCompositor->staleInCompositingMode() || innerCompositor->rootLayerAttachment() != RootLayerAttachedViaEnclosingFrame) return false; PaintLayer* layer = layoutObject->layer(); if (!layer->hasCompositedLayerMapping()) return false; layer->compositedLayerMapping()->setSublayers(GraphicsLayerVector(1, innerCompositor->rootGraphicsLayer())); return true; }
static CompositedLayerMapping* mappingFromElement(Element* element) { if (!element) return nullptr; LayoutObject* layoutObject = element->layoutObject(); if (!layoutObject || !layoutObject->isBoxModelObject()) return nullptr; PaintLayer* layer = toLayoutBoxModelObject(layoutObject)->layer(); if (!layer) return nullptr; if (!layer->hasCompositedLayerMapping()) return nullptr; return layer->compositedLayerMapping(); }
TEST_F(PaintLayerTest, PaintingExtentReflectionWithTransform) { setBodyInnerHTML( "<div id='target' style='background-color: blue; position: absolute;" " width: 110px; height: 120px; top: 40px; left: 60px;" " -webkit-box-reflect: below 3px; transform: translateX(30px)'>" "</div>"); PaintLayer* layer = toLayoutBoxModelObject(getLayoutObjectByElementId("target"))->layer(); EXPECT_EQ( LayoutRect(90, 40, 110, 243), layer->paintingExtent(document().layoutView()->layer(), LayoutSize(), 0)); }
void CompositorAnimations::attachCompositedLayers(const Element& element, const Animation& animation) { ASSERT(element.layoutObject()); PaintLayer* layer = toLayoutBoxModelObject(element.layoutObject())->layer(); ASSERT(layer); WebCompositorAnimationPlayer* compositorPlayer = animation.compositorPlayer(); ASSERT(compositorPlayer); ASSERT(layer->compositedLayerMapping()); compositorPlayer->attachLayer(layer->compositedLayerMapping()->mainGraphicsLayer()->platformLayer()); }
bool PaintLayerClipper::shouldRespectOverflowClip(const ClipRectsContext& context) const { PaintLayer* layer = m_layoutObject.layer(); if (layer != context.rootLayer) return true; if (context.respectOverflowClip == IgnoreOverflowClip) return false; if (layer->isRootLayer() && context.respectOverflowClipForViewport == IgnoreOverflowClip) return false; return true; }
void RenderedPosition::positionInGraphicsLayerBacking(CompositedSelectionBound& bound) const { bound.layer = nullptr; bound.edgeTopInLayer = bound.edgeBottomInLayer = FloatPoint(); if (isNull()) return; LayoutRect rect = m_layoutObject->localCaretRect(m_inlineBox, m_offset); PaintLayer* layer = nullptr; bound.edgeTopInLayer = m_layoutObject->localToInvalidationBackingPoint(rect.minXMinYCorner(), &layer); bound.edgeBottomInLayer = m_layoutObject->localToInvalidationBackingPoint(rect.minXMaxYCorner(), nullptr); bound.layer = layer ? layer->graphicsLayerBacking() : nullptr; }
static bool shouldRepaintSubsequence(PaintLayer& paintLayer, const PaintLayerPaintingInfo& paintingInfo, ShouldRespectOverflowClip respectOverflowClip, const LayoutSize& subpixelAccumulation) { bool needsRepaint = false; // Repaint subsequence if the layer is marked for needing repaint. if (paintLayer.needsRepaint()) needsRepaint = true; // Repaint if layer's clip changes. ClipRects& clipRects = paintLayer.clipper().paintingClipRects(paintingInfo.rootLayer, respectOverflowClip, subpixelAccumulation); ClipRects* previousClipRects = paintLayer.previousPaintingClipRects(); if (!needsRepaint && &clipRects != previousClipRects && (!previousClipRects || clipRects != *previousClipRects)) needsRepaint = true; paintLayer.setPreviousPaintingClipRects(clipRects); // Repaint if previously the layer might be clipped by paintDirtyRect and paintDirtyRect changes. if (!needsRepaint && paintLayer.previousPaintResult() == PaintLayerPainter::MayBeClippedByPaintDirtyRect && paintLayer.previousPaintDirtyRect() != paintingInfo.paintDirtyRect) needsRepaint = true; paintLayer.setPreviousPaintDirtyRect(paintingInfo.paintDirtyRect); // Repaint if scroll offset accumulation changes. if (!needsRepaint && paintingInfo.scrollOffsetAccumulation != paintLayer.previousScrollOffsetAccumulationForPainting()) needsRepaint = true; paintLayer.setPreviousScrollOffsetAccumulationForPainting(paintingInfo.scrollOffsetAccumulation); return needsRepaint; }
TEST_F(CompositedLayerMappingTest, TallLayerWholeDocumentInterestRect) { setBodyInnerHTML("<div id='target' style='width: 200px; height: 10000px; will-change: transform'></div>"); document().settings()->setMainFrameClipsContent(false); document().view()->updateAllLifecyclePhases(); Element* element = document().getElementById("target"); PaintLayer* paintLayer = toLayoutBoxModelObject(element->layoutObject())->layer(); ASSERT_TRUE(paintLayer->graphicsLayerBacking()); ASSERT_TRUE(paintLayer->compositedLayerMapping()); // recomputeInterestRect computes the interest rect; computeInterestRect applies the extra setting to paint everything. EXPECT_RECT_EQ(IntRect(0, 0, 200, 4592), recomputeInterestRect(paintLayer->graphicsLayerBacking())); EXPECT_RECT_EQ(IntRect(0, 0, 200, 10000), computeInterestRect(paintLayer->compositedLayerMapping(), paintLayer->graphicsLayerBacking(), IntRect())); }