| Index: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
|
| diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
|
| index cded36c119223a695f1dd4a29739292a7a3d101d..0fe7b9cd0925cd63bb83d8814a94f66b3630a3f8 100644
|
| --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
|
| +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
|
| @@ -11,6 +11,7 @@
|
| #include "core/layout/LayoutPart.h"
|
| #include "core/layout/LayoutView.h"
|
| #include "core/layout/svg/LayoutSVGRoot.h"
|
| +#include "core/paint/FindPropertiesNeedingUpdate.h"
|
| #include "core/paint/ObjectPaintProperties.h"
|
| #include "core/paint/PaintLayer.h"
|
| #include "core/paint/SVGRootPainter.h"
|
| @@ -72,52 +73,50 @@ PaintPropertyTreeBuilder::setupInitialContext() {
|
| return context;
|
| }
|
|
|
| -const TransformPaintPropertyNode* updateFrameViewPreTranslation(
|
| +void updateFrameViewPreTranslation(
|
| FrameView& frameView,
|
| PassRefPtr<const TransformPaintPropertyNode> parent,
|
| const TransformationMatrix& matrix,
|
| const FloatPoint3D& origin) {
|
| DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
|
| - if (TransformPaintPropertyNode* existingPreTranslation =
|
| - frameView.preTranslation())
|
| + if (auto* existingPreTranslation = frameView.preTranslation()) {
|
| existingPreTranslation->update(std::move(parent), matrix, origin);
|
| - else
|
| + } else {
|
| frameView.setPreTranslation(
|
| TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
|
| - return frameView.preTranslation();
|
| + }
|
| }
|
|
|
| -const ClipPaintPropertyNode* updateFrameViewContentClip(
|
| +void updateFrameViewContentClip(
|
| FrameView& frameView,
|
| PassRefPtr<const ClipPaintPropertyNode> parent,
|
| PassRefPtr<const TransformPaintPropertyNode> localTransformSpace,
|
| const FloatRoundedRect& clipRect) {
|
| DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
|
| - if (ClipPaintPropertyNode* existingContentClip = frameView.contentClip())
|
| + if (auto* existingContentClip = frameView.contentClip()) {
|
| existingContentClip->update(std::move(parent),
|
| std::move(localTransformSpace), clipRect);
|
| - else
|
| + } else {
|
| frameView.setContentClip(ClipPaintPropertyNode::create(
|
| std::move(parent), std::move(localTransformSpace), clipRect));
|
| - return frameView.contentClip();
|
| + }
|
| }
|
|
|
| -const TransformPaintPropertyNode* updateFrameViewScrollTranslation(
|
| +void updateFrameViewScrollTranslation(
|
| FrameView& frameView,
|
| PassRefPtr<const TransformPaintPropertyNode> parent,
|
| const TransformationMatrix& matrix,
|
| const FloatPoint3D& origin) {
|
| DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
|
| - if (TransformPaintPropertyNode* existingScrollTranslation =
|
| - frameView.scrollTranslation())
|
| + if (auto* existingScrollTranslation = frameView.scrollTranslation()) {
|
| existingScrollTranslation->update(std::move(parent), matrix, origin);
|
| - else
|
| + } else {
|
| frameView.setScrollTranslation(
|
| TransformPaintPropertyNode::create(std::move(parent), matrix, origin));
|
| - return frameView.scrollTranslation();
|
| + }
|
| }
|
|
|
| -ScrollPaintPropertyNode* updateFrameViewScroll(
|
| +void updateFrameViewScroll(
|
| FrameView& frameView,
|
| PassRefPtr<ScrollPaintPropertyNode> parent,
|
| PassRefPtr<const TransformPaintPropertyNode> scrollOffset,
|
| @@ -126,18 +125,18 @@ ScrollPaintPropertyNode* updateFrameViewScroll(
|
| bool userScrollableHorizontal,
|
| bool userScrollableVertical) {
|
| DCHECK(!RuntimeEnabledFeatures::rootLayerScrollingEnabled());
|
| - if (ScrollPaintPropertyNode* existingScroll = frameView.scroll())
|
| + if (auto* existingScroll = frameView.scroll()) {
|
| existingScroll->update(std::move(parent), std::move(scrollOffset), clip,
|
| bounds, userScrollableHorizontal,
|
| userScrollableVertical);
|
| - else
|
| + } else {
|
| frameView.setScroll(ScrollPaintPropertyNode::create(
|
| std::move(parent), std::move(scrollOffset), clip, bounds,
|
| userScrollableHorizontal, userScrollableVertical));
|
| - return frameView.scroll();
|
| + }
|
| }
|
|
|
| -void PaintPropertyTreeBuilder::buildTreeNodes(
|
| +void PaintPropertyTreeBuilder::updateProperties(
|
| FrameView& frameView,
|
| PaintPropertyTreeBuilderContext& context) {
|
| if (RuntimeEnabledFeatures::rootLayerScrollingEnabled()) {
|
| @@ -145,16 +144,25 @@ void PaintPropertyTreeBuilder::buildTreeNodes(
|
| 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());
|
| +#if DCHECK_IS_ON()
|
| + FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(*layoutView);
|
| +#endif
|
| +
|
| + if (layoutView->needsPaintPropertyUpdate()) {
|
| + TransformationMatrix frameTranslate;
|
| + frameTranslate.translate(frameView.x() + layoutView->location().x() +
|
| + context.current.paintOffset.x(),
|
| + frameView.y() + layoutView->location().y() +
|
| + context.current.paintOffset.y());
|
| + layoutView->getMutableForPainting()
|
| + .ensurePaintProperties()
|
| + .updatePaintOffsetTranslation(context.current.transform,
|
| + frameTranslate, FloatPoint3D());
|
| + }
|
| +
|
| + const auto* properties = layoutView->paintProperties();
|
| + DCHECK(properties && properties->paintOffsetTranslation());
|
| + context.current.transform = properties->paintOffsetTranslation();
|
| context.current.paintOffset = LayoutPoint();
|
| context.current.renderingContextID = 0;
|
| context.current.shouldFlattenInheritedTransform = true;
|
| @@ -165,47 +173,61 @@ void PaintPropertyTreeBuilder::buildTreeNodes(
|
| 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());
|
| +#if DCHECK_IS_ON()
|
| + FindFrameViewPropertiesNeedingUpdateScope checkNeedsUpdateScope(&frameView);
|
| +#endif
|
|
|
| - 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);
|
| + if (frameView.needsPaintPropertyUpdate()) {
|
| + 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;
|
| @@ -230,40 +252,47 @@ void PaintPropertyTreeBuilder::updatePaintOffsetTranslation(
|
| return;
|
| }
|
|
|
| + bool usesPaintOffsetTranslation = false;
|
| if (object.isBoxModelObject() &&
|
| context.current.paintOffset != LayoutPoint()) {
|
| // TODO(trchen): Eliminate PaintLayer dependency.
|
| PaintLayer* layer = toLayoutBoxModelObject(object).layer();
|
| - if (layer && layer->paintsWithTransform(GlobalPaintNormalPhase)) {
|
| - // 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);
|
| -
|
| - context.current.transform =
|
| - object.getMutableForPainting()
|
| - .ensurePaintProperties()
|
| - .updatePaintOffsetTranslation(
|
| - context.current.transform,
|
| - TransformationMatrix().translate(roundedPaintOffset.x(),
|
| - roundedPaintOffset.y()),
|
| - FloatPoint3D(),
|
| - context.current.shouldFlattenInheritedTransform,
|
| - context.current.renderingContextID);
|
| - context.current.paintOffset = fractionalPaintOffset;
|
| - return;
|
| + 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 (object.needsPaintPropertyUpdate()) {
|
| + 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();
|
| }
|
| }
|
|
|
| - 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;
|
| + }
|
| }
|
|
|
| static FloatPoint3D transformOrigin(const LayoutBox& box) {
|
| @@ -285,27 +314,31 @@ void PaintPropertyTreeBuilder::updateTransformForNonRootSVG(
|
| DCHECK(object.isSVGForeignObject() ||
|
| context.current.paintOffset == LayoutPoint());
|
|
|
| - // FIXME(pdr): Refactor this so all non-root SVG objects use the same
|
| - // transform function.
|
| - const AffineTransform& transform = object.isSVGForeignObject()
|
| - ? object.localSVGTransform()
|
| - : object.localToSVGParentTransform();
|
| -
|
| - // FIXME(pdr): Check for the presence of a transform instead of the value.
|
| - // Checking for an identity matrix will cause the property tree structure to
|
| - // change during animations if the animation passes through the identity
|
| - // matrix.
|
| - if (!transform.isIdentity()) {
|
| - // The origin is included in the local transform, so leave origin empty.
|
| - context.current.transform =
|
| - object.getMutableForPainting().ensurePaintProperties().updateTransform(
|
| - context.current.transform, TransformationMatrix(transform),
|
| - FloatPoint3D());
|
| - context.current.renderingContextID = 0;
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + // TODO(pdr): Refactor this so all non-root SVG objects use the same
|
| + // transform function.
|
| + const AffineTransform& transform = object.isSVGForeignObject()
|
| + ? object.localSVGTransform()
|
| + : object.localToSVGParentTransform();
|
| + // TODO(pdr): Check for the presence of a transform instead of the value.
|
| + // Checking for an identity matrix will cause the property tree structure
|
| + // to change during animations if the animation passes through the
|
| + // identity matrix.
|
| + if (!transform.isIdentity()) {
|
| + // The origin is included in the local transform, so leave origin empty.
|
| + object.getMutableForPainting().ensurePaintProperties().updateTransform(
|
| + context.current.transform, TransformationMatrix(transform),
|
| + FloatPoint3D());
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearTransform();
|
| + }
|
| + }
|
| +
|
| + if (object.paintProperties() && object.paintProperties()->transform()) {
|
| + context.current.transform = object.paintProperties()->transform();
|
| context.current.shouldFlattenInheritedTransform = false;
|
| - } else {
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearTransform();
|
| + context.current.renderingContextID = 0;
|
| }
|
| }
|
|
|
| @@ -317,42 +350,45 @@ void PaintPropertyTreeBuilder::updateTransform(
|
| return;
|
| }
|
|
|
| - const ComputedStyle& style = object.styleRef();
|
| - if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
|
| - TransformationMatrix matrix;
|
| - style.applyTransform(matrix, toLayoutBox(object).size(),
|
| - ComputedStyle::ExcludeTransformOrigin,
|
| - ComputedStyle::IncludeMotionPath,
|
| - ComputedStyle::IncludeIndependentTransformProperties);
|
| - FloatPoint3D origin = transformOrigin(toLayoutBox(object));
|
| -
|
| - unsigned renderingContextID = context.current.renderingContextID;
|
| - unsigned renderingContextIDForChildren = 0;
|
| - bool flattensInheritedTransform =
|
| - context.current.shouldFlattenInheritedTransform;
|
| - bool childrenFlattenInheritedTransform = true;
|
| -
|
| - // TODO(trchen): transform-style should only be respected if a PaintLayer
|
| - // is created.
|
| - if (style.preserves3D()) {
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + const ComputedStyle& style = object.styleRef();
|
| + if (object.isBox() && (style.hasTransform() || style.preserves3D())) {
|
| + TransformationMatrix matrix;
|
| + style.applyTransform(
|
| + matrix, toLayoutBox(object).size(),
|
| + ComputedStyle::ExcludeTransformOrigin,
|
| + ComputedStyle::IncludeMotionPath,
|
| + ComputedStyle::IncludeIndependentTransformProperties);
|
| +
|
| + // TODO(trchen): transform-style should only be respected if a PaintLayer
|
| + // is created.
|
| // If a node with transform-style: preserve-3d does not exist in an
|
| // existing rendering context, it establishes a new one.
|
| - if (!renderingContextID)
|
| + unsigned renderingContextID = context.current.renderingContextID;
|
| + if (style.preserves3D() && !renderingContextID)
|
| renderingContextID = PtrHash<const LayoutObject>::hash(&object);
|
| - renderingContextIDForChildren = renderingContextID;
|
| - childrenFlattenInheritedTransform = false;
|
| +
|
| + object.getMutableForPainting().ensurePaintProperties().updateTransform(
|
| + context.current.transform, matrix,
|
| + transformOrigin(toLayoutBox(object)),
|
| + context.current.shouldFlattenInheritedTransform, renderingContextID);
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearTransform();
|
| }
|
| + }
|
|
|
| - context.current.transform =
|
| - object.getMutableForPainting().ensurePaintProperties().updateTransform(
|
| - context.current.transform, matrix, origin,
|
| - flattensInheritedTransform, renderingContextID);
|
| - context.current.renderingContextID = renderingContextIDForChildren;
|
| - context.current.shouldFlattenInheritedTransform =
|
| - childrenFlattenInheritedTransform;
|
| - } else {
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearTransform();
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->transform()) {
|
| + context.current.transform = properties->transform();
|
| + unsigned renderingContextID = properties->transform()->renderingContextID();
|
| + if (context.current.renderingContextID != renderingContextID) {
|
| + context.current.renderingContextID = renderingContextID;
|
| + context.current.shouldFlattenInheritedTransform = false;
|
| + } else {
|
| + context.current.renderingContextID = 0;
|
| + context.current.shouldFlattenInheritedTransform = true;
|
| + }
|
| }
|
| }
|
|
|
| @@ -362,118 +398,136 @@ void PaintPropertyTreeBuilder::updateEffect(
|
| const ComputedStyle& style = object.styleRef();
|
|
|
| if (!style.isStackingContext()) {
|
| - if (ObjectPaintProperties* properties =
|
| - object.getMutableForPainting().paintProperties())
|
| - properties->clearEffect();
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearEffect();
|
| + }
|
| return;
|
| }
|
|
|
| - // TODO(trchen): Can't omit effect node if we have 3D children.
|
| - // TODO(trchen): Can't omit effect node if we have blending children.
|
| - bool effectNodeNeeded = false;
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + // TODO(trchen): Can't omit effect node if we have 3D children.
|
| + // TODO(trchen): Can't omit effect node if we have blending children.
|
| + bool effectNodeNeeded = false;
|
| +
|
| + float opacity = style.opacity();
|
| + if (opacity != 1.0f)
|
| + effectNodeNeeded = true;
|
| +
|
| + CompositorFilterOperations filter;
|
| + if (object.isSVG() && !object.isSVGRoot()) {
|
| + // TODO(trchen): SVG caches filters in SVGResources. Implement it.
|
| + } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) {
|
| + // TODO(trchen): Eliminate PaintLayer dependency.
|
| + filter = layer->createCompositorFilterOperationsForFilter(style);
|
| + }
|
|
|
| - float opacity = style.opacity();
|
| - if (opacity != 1.0f)
|
| - effectNodeNeeded = true;
|
| + const ClipPaintPropertyNode* outputClip = rootClipNode();
|
| + // The CSS filter spec didn't specify how filters interact with overflow
|
| + // clips. The implementation here mimics the old Blink/WebKit behavior for
|
| + // backward compatibility.
|
| + // Basically the output of the filter will be affected by clips that applies
|
| + // to the current element. The descendants that paints into the input of the
|
| + // filter ignores any clips collected so far. For example:
|
| + // <div style="overflow:scroll">
|
| + // <div style="filter:blur(1px);">
|
| + // <div>A</div>
|
| + // <div style="position:absolute;">B</div>
|
| + // </div>
|
| + // </div>
|
| + // In this example "A" should be clipped if the filter was not present.
|
| + // With the filter, "A" will be rastered without clipping, but instead
|
| + // the blurred result will be clipped.
|
| + // On the other hand, "B" should not be clipped because the overflow clip is
|
| + // not in its containing block chain, but as the filter output will be
|
| + // clipped, so a blurred "B" may still be invisible.
|
| + if (!filter.isEmpty()) {
|
| + effectNodeNeeded = true;
|
| + outputClip = context.current.clip;
|
| +
|
| + // TODO(trchen): A filter may contain spatial operations such that an
|
| + // output pixel may depend on an input pixel outside of the output clip.
|
| + // We should generate a special clip node to represent this expansion.
|
| + }
|
|
|
| - CompositorFilterOperations filter;
|
| - if (object.isSVG() && !object.isSVGRoot()) {
|
| - // TODO(trchen): SVG caches filters in SVGResources. Implement it.
|
| - } else if (PaintLayer* layer = toLayoutBoxModelObject(object).layer()) {
|
| - // TODO(trchen): Eliminate PaintLayer dependency.
|
| - filter = layer->createCompositorFilterOperationsForFilter(style);
|
| - }
|
| -
|
| - const ClipPaintPropertyNode* outputClip = rootClipNode();
|
| - // The CSS filter spec didn't specify how filters interact with overflow
|
| - // clips. The implementation here mimics the old Blink/WebKit behavior for
|
| - // backward compatibility.
|
| - // Basically the output of the filter will be affected by clips that applies
|
| - // to the current element. The descendants that paints into the input of the
|
| - // filter ignores any clips collected so far. For example:
|
| - // <div style="overflow:scroll">
|
| - // <div style="filter:blur(1px);">
|
| - // <div>A</div>
|
| - // <div style="position:absolute;">B</div>
|
| - // </div>
|
| - // </div>
|
| - // In this example "A" should be clipped if the filter was not present.
|
| - // With the filter, "A" will be rastered without clipping, but instead
|
| - // the blurred result will be clipped.
|
| - // On the other hand, "B" should not be clipped because the overflow clip is
|
| - // not in its containing block chain, but as the filter output will be
|
| - // clipped, so a blurred "B" may still be invisible.
|
| - if (!filter.isEmpty()) {
|
| - effectNodeNeeded = true;
|
| - outputClip = context.current.clip;
|
| -
|
| - // TODO(trchen): A filter may contain spatial operations such that an output
|
| - // pixel may depend on an input pixel outside of the output clip. Need to
|
| - // generate special clip node to hint how to expand clip / cull rect.
|
| + if (effectNodeNeeded) {
|
| + object.getMutableForPainting().ensurePaintProperties().updateEffect(
|
| + context.currentEffect, context.current.transform, outputClip,
|
| + std::move(filter), opacity);
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearEffect();
|
| + }
|
| + }
|
| +
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->effect()) {
|
| + context.currentEffect = properties->effect();
|
| + // TODO(pdr): Once the expansion clip node is created above, it should be
|
| + // used here to update all current clip nodes;
|
| const ClipPaintPropertyNode* expansionHint = context.current.clip;
|
| context.current.clip = context.absolutePosition.clip =
|
| context.fixedPosition.clip = expansionHint;
|
| }
|
| -
|
| - if (!effectNodeNeeded) {
|
| - if (ObjectPaintProperties* properties =
|
| - object.getMutableForPainting().paintProperties())
|
| - properties->clearEffect();
|
| - return;
|
| - }
|
| -
|
| - context.currentEffect =
|
| - object.getMutableForPainting().ensurePaintProperties().updateEffect(
|
| - context.currentEffect, context.current.transform, outputClip,
|
| - std::move(filter), opacity);
|
| }
|
|
|
| void PaintPropertyTreeBuilder::updateCssClip(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| - if (object.hasClip()) {
|
| - // Create clip node for descendants that are not fixed position.
|
| - // We don't have to setup context.absolutePosition.clip here because this
|
| - // object must be a container for absolute position descendants, and will
|
| - // copy from in-flow context later at updateOutOfFlowContext() step.
|
| - DCHECK(object.canContainAbsolutePositionObjects());
|
| - LayoutRect clipRect =
|
| - toLayoutBox(object).clipRect(context.current.paintOffset);
|
| - context.current.clip =
|
| - object.getMutableForPainting().ensurePaintProperties().updateCssClip(
|
| - context.current.clip, context.current.transform,
|
| - FloatRoundedRect(FloatRect(clipRect)));
|
| - return;
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + if (object.hasClip()) {
|
| + // Create clip node for descendants that are not fixed position.
|
| + // We don't have to setup context.absolutePosition.clip here because this
|
| + // object must be a container for absolute position descendants, and will
|
| + // copy from in-flow context later at updateOutOfFlowContext() step.
|
| + DCHECK(object.canContainAbsolutePositionObjects());
|
| + LayoutRect clipRect =
|
| + toLayoutBox(object).clipRect(context.current.paintOffset);
|
| + object.getMutableForPainting().ensurePaintProperties().updateCssClip(
|
| + context.current.clip, context.current.transform,
|
| + FloatRoundedRect(FloatRect(clipRect)));
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearCssClip();
|
| + }
|
| }
|
|
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearCssClip();
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->cssClip())
|
| + context.current.clip = properties->cssClip();
|
| }
|
|
|
| void PaintPropertyTreeBuilder::updateLocalBorderBoxContext(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| - // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since
|
| - // we don't need them at the moment.
|
| - if (!object.isBox() && !object.hasLayer())
|
| - return;
|
| -
|
| - std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset>
|
| - borderBoxContext =
|
| - wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset(
|
| - context.current.paintOffset,
|
| - PropertyTreeState(context.current.transform, context.current.clip,
|
| - context.currentEffect,
|
| - context.current.scroll)));
|
| - object.getMutableForPainting()
|
| - .ensurePaintProperties()
|
| - .setLocalBorderBoxProperties(std::move(borderBoxContext));
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + // Avoid adding an ObjectPaintProperties for non-boxes to save memory, since
|
| + // we don't need them at the moment.
|
| + if (!object.isBox() && !object.hasLayer()) {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearLocalBorderBoxProperties();
|
| + } else {
|
| + std::unique_ptr<ObjectPaintProperties::PropertyTreeStateWithOffset>
|
| + borderBoxContext =
|
| + wrapUnique(new ObjectPaintProperties::PropertyTreeStateWithOffset(
|
| + context.current.paintOffset,
|
| + PropertyTreeState(context.current.transform,
|
| + context.current.clip, context.currentEffect,
|
| + context.current.scroll)));
|
| + object.getMutableForPainting()
|
| + .ensurePaintProperties()
|
| + .setLocalBorderBoxProperties(std::move(borderBoxContext));
|
| + }
|
| + }
|
| }
|
|
|
| // TODO(trchen): Remove this once we bake the paint offset into frameRect.
|
| void PaintPropertyTreeBuilder::updateScrollbarPaintOffset(
|
| const LayoutObject& object,
|
| const PaintPropertyTreeBuilderContext& context) {
|
| + if (!object.needsPaintPropertyUpdate())
|
| + return;
|
| +
|
| IntPoint roundedPaintOffset = roundedIntPoint(context.current.paintOffset);
|
| if (roundedPaintOffset != IntPoint() && object.isBoxModelObject()) {
|
| if (PaintLayerScrollableArea* scrollableArea =
|
| @@ -498,10 +552,14 @@ void PaintPropertyTreeBuilder::updateScrollbarPaintOffset(
|
| void PaintPropertyTreeBuilder::updateMainThreadScrollingReasons(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| + // TODO(pdr): Mark properties as needing an update for main thread scroll
|
| + // reasons and ensure reason changes are propagated to ancestors to account
|
| + // for the parent walk below.
|
| if (context.current.scroll &&
|
| - !object.document().settings()->threadedScrollingEnabled())
|
| + !object.document().settings()->threadedScrollingEnabled()) {
|
| context.current.scroll->addMainThreadScrollingReasons(
|
| MainThreadScrollingReason::kThreadedScrollingDisabled);
|
| + }
|
|
|
| if (object.isBackgroundAttachmentFixedObject()) {
|
| auto* scrollNode = context.current.scroll;
|
| @@ -522,45 +580,50 @@ void PaintPropertyTreeBuilder::updateOverflowClip(
|
| if (!object.isBox())
|
| return;
|
| const LayoutBox& box = toLayoutBox(object);
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + // The <input> elements can't have contents thus CSS overflow property
|
| + // doesn't apply. However for layout purposes we do generate child layout
|
| + // objects for them, e.g. button label. We should clip the overflow from
|
| + // those children. This is called control clip and we technically treat them
|
| + // like overflow clip.
|
| + LayoutRect clipRect;
|
| + if (box.hasControlClip()) {
|
| + clipRect = box.controlClipRect(context.current.paintOffset);
|
| + } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
|
| + (box.isSVGRoot() &&
|
| + toLayoutSVGRoot(box).shouldApplyViewportClip())) {
|
| + clipRect = LayoutRect(pixelSnappedIntRect(
|
| + box.overflowClipRect(context.current.paintOffset)));
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties()) {
|
| + properties->clearInnerBorderRadiusClip();
|
| + properties->clearOverflowClip();
|
| + }
|
| + return;
|
| + }
|
|
|
| - // The <input> elements can't have contents thus CSS overflow property doesn't
|
| - // apply. However for layout purposes we do generate child layout objects for
|
| - // them, e.g. button label. We should clip the overflow from those children.
|
| - // This is called control clip and we technically treat them like overflow
|
| - // clip.
|
| - LayoutRect clipRect;
|
| - if (box.hasControlClip()) {
|
| - clipRect = box.controlClipRect(context.current.paintOffset);
|
| - } else if (box.hasOverflowClip() || box.styleRef().containsPaint() ||
|
| - (box.isSVGRoot() &&
|
| - toLayoutSVGRoot(box).shouldApplyViewportClip())) {
|
| - clipRect = LayoutRect(
|
| - pixelSnappedIntRect(box.overflowClipRect(context.current.paintOffset)));
|
| - } else {
|
| - if (auto* properties = object.getMutableForPainting().paintProperties()) {
|
| + const auto* currentClip = context.current.clip;
|
| + if (box.styleRef().hasBorderRadius()) {
|
| + auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
|
| + LayoutRect(context.current.paintOffset, box.size()));
|
| + object.getMutableForPainting()
|
| + .ensurePaintProperties()
|
| + .updateInnerBorderRadiusClip(context.current.clip,
|
| + context.current.transform, innerBorder);
|
| + currentClip = object.paintProperties()->innerBorderRadiusClip();
|
| + } else if (auto* properties =
|
| + object.getMutableForPainting().paintProperties()) {
|
| properties->clearInnerBorderRadiusClip();
|
| - properties->clearOverflowClip();
|
| }
|
| - return;
|
| - }
|
|
|
| - if (box.styleRef().hasBorderRadius()) {
|
| - auto innerBorder = box.styleRef().getRoundedInnerBorderFor(
|
| - LayoutRect(context.current.paintOffset, box.size()));
|
| - context.current.clip =
|
| - object.getMutableForPainting()
|
| - .ensurePaintProperties()
|
| - .updateInnerBorderRadiusClip(
|
| - context.current.clip, context.current.transform, innerBorder);
|
| - } else if (auto* properties =
|
| - object.getMutableForPainting().paintProperties()) {
|
| - properties->clearInnerBorderRadiusClip();
|
| + object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
|
| + currentClip, context.current.transform,
|
| + FloatRoundedRect(FloatRect(clipRect)));
|
| }
|
|
|
| - context.current.clip =
|
| - object.getMutableForPainting().ensurePaintProperties().updateOverflowClip(
|
| - context.current.clip, context.current.transform,
|
| - FloatRoundedRect(FloatRect(clipRect)));
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->overflowClip())
|
| + context.current.clip = properties->overflowClip();
|
| }
|
|
|
| static FloatPoint perspectiveOrigin(const LayoutBox& box) {
|
| @@ -574,26 +637,31 @@ static FloatPoint perspectiveOrigin(const LayoutBox& box) {
|
| void PaintPropertyTreeBuilder::updatePerspective(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| - const ComputedStyle& style = object.styleRef();
|
| - if (!object.isBox() || !style.hasPerspective()) {
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearPerspective();
|
| - return;
|
| - }
|
| -
|
| - // The perspective node must not flatten (else nothing will get
|
| - // perspective), but it should still extend the rendering context as most
|
| - // transform nodes do.
|
| - TransformationMatrix matrix =
|
| - TransformationMatrix().applyPerspective(style.perspective());
|
| - FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
|
| - toLayoutSize(context.current.paintOffset);
|
| - context.current.transform =
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + const ComputedStyle& style = object.styleRef();
|
| + if (object.isBox() && style.hasPerspective()) {
|
| + // The perspective node must not flatten (else nothing will get
|
| + // perspective), but it should still extend the rendering context as
|
| + // most transform nodes do.
|
| + TransformationMatrix matrix =
|
| + TransformationMatrix().applyPerspective(style.perspective());
|
| + FloatPoint3D origin = perspectiveOrigin(toLayoutBox(object)) +
|
| + toLayoutSize(context.current.paintOffset);
|
| object.getMutableForPainting().ensurePaintProperties().updatePerspective(
|
| context.current.transform, matrix, origin,
|
| context.current.shouldFlattenInheritedTransform,
|
| context.current.renderingContextID);
|
| - context.current.shouldFlattenInheritedTransform = false;
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearPerspective();
|
| + }
|
| + }
|
| +
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->perspective()) {
|
| + context.current.transform = properties->perspective();
|
| + context.current.shouldFlattenInheritedTransform = false;
|
| + }
|
| }
|
|
|
| void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(
|
| @@ -602,66 +670,78 @@ void PaintPropertyTreeBuilder::updateSvgLocalToBorderBoxTransform(
|
| if (!object.isSVGRoot())
|
| return;
|
|
|
| - AffineTransform transformToBorderBox =
|
| - SVGRootPainter(toLayoutSVGRoot(object))
|
| - .transformToPixelSnappedBorderBox(context.current.paintOffset);
|
| -
|
| - // The paint offset is included in |transformToBorderBox| so SVG does not need
|
| - // to handle paint offset internally.
|
| - context.current.paintOffset = LayoutPoint();
|
| -
|
| - if (transformToBorderBox.isIdentity()) {
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearSvgLocalToBorderBoxTransform();
|
| - return;
|
| - }
|
| -
|
| - context.current.transform =
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + AffineTransform transformToBorderBox =
|
| + SVGRootPainter(toLayoutSVGRoot(object))
|
| + .transformToPixelSnappedBorderBox(context.current.paintOffset);
|
| + if (!transformToBorderBox.isIdentity()) {
|
| object.getMutableForPainting()
|
| .ensurePaintProperties()
|
| .updateSvgLocalToBorderBoxTransform(
|
| context.current.transform, transformToBorderBox, FloatPoint3D());
|
| - context.current.shouldFlattenInheritedTransform = false;
|
| - context.current.renderingContextID = 0;
|
| + } else {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearSvgLocalToBorderBoxTransform();
|
| + }
|
| + }
|
| +
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->svgLocalToBorderBoxTransform()) {
|
| + context.current.transform = properties->svgLocalToBorderBoxTransform();
|
| + context.current.shouldFlattenInheritedTransform = false;
|
| + context.current.renderingContextID = 0;
|
| + }
|
| + // The paint offset is included in |transformToBorderBox| so SVG does not need
|
| + // to handle paint offset internally.
|
| + context.current.paintOffset = LayoutPoint();
|
| }
|
|
|
| void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| - if (object.hasOverflowClip()) {
|
| - const LayoutBox& box = toLayoutBox(object);
|
| - const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
|
| - IntSize scrollOffset = box.scrolledContentOffset();
|
| - if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
|
| - TransformationMatrix matrix = TransformationMatrix().translate(
|
| - -scrollOffset.width(), -scrollOffset.height());
|
| - context.current.transform =
|
| - object.getMutableForPainting()
|
| - .ensurePaintProperties()
|
| - .updateScrollTranslation(
|
| - context.current.transform, matrix, FloatPoint3D(),
|
| - context.current.shouldFlattenInheritedTransform,
|
| - context.current.renderingContextID);
|
| -
|
| - IntSize scrollClip = scrollableArea->visibleContentRect().size();
|
| - IntSize scrollBounds = scrollableArea->contentsSize();
|
| - bool userScrollableHorizontal =
|
| - scrollableArea->userInputScrollable(HorizontalScrollbar);
|
| - bool userScrollableVertical =
|
| - scrollableArea->userInputScrollable(VerticalScrollbar);
|
| - context.current.scroll =
|
| - object.getMutableForPainting().ensurePaintProperties().updateScroll(
|
| - context.current.scroll, context.current.transform, scrollClip,
|
| - scrollBounds, userScrollableHorizontal, userScrollableVertical);
|
| -
|
| - context.current.shouldFlattenInheritedTransform = false;
|
| - return;
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + if (object.hasOverflowClip()) {
|
| + const LayoutBox& box = toLayoutBox(object);
|
| + const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
|
| + IntSize scrollOffset = box.scrolledContentOffset();
|
| + if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
|
| + TransformationMatrix matrix = TransformationMatrix().translate(
|
| + -scrollOffset.width(), -scrollOffset.height());
|
| + object.getMutableForPainting()
|
| + .ensurePaintProperties()
|
| + .updateScrollTranslation(
|
| + context.current.transform, matrix, FloatPoint3D(),
|
| + context.current.shouldFlattenInheritedTransform,
|
| + context.current.renderingContextID);
|
| +
|
| + IntSize scrollClip = scrollableArea->visibleContentRect().size();
|
| + IntSize scrollBounds = scrollableArea->contentsSize();
|
| + bool userScrollableHorizontal =
|
| + scrollableArea->userInputScrollable(HorizontalScrollbar);
|
| + bool userScrollableVertical =
|
| + scrollableArea->userInputScrollable(VerticalScrollbar);
|
| + object.getMutableForPainting().ensurePaintProperties().updateScroll(
|
| + context.current.scroll,
|
| + object.paintProperties()->scrollTranslation(), scrollClip,
|
| + scrollBounds, userScrollableHorizontal, userScrollableVertical);
|
| + } else {
|
| + // Ensure pre-existing properties are cleared when there is no
|
| + // scrolling.
|
| + auto* properties = object.getMutableForPainting().paintProperties();
|
| + if (properties) {
|
| + properties->clearScrollTranslation();
|
| + properties->clearScroll();
|
| + }
|
| + }
|
| }
|
| }
|
|
|
| - if (auto* properties = object.getMutableForPainting().paintProperties()) {
|
| - properties->clearScrollTranslation();
|
| - properties->clearScroll();
|
| + if (object.paintProperties() && object.paintProperties()->scroll()) {
|
| + context.current.transform = object.paintProperties()->scrollTranslation();
|
| + const auto* scroll = object.paintProperties()->scroll();
|
| + // TODO(pdr): Remove this const cast.
|
| + context.current.scroll = const_cast<ScrollPaintPropertyNode*>(scroll);
|
| + context.current.shouldFlattenInheritedTransform = false;
|
| }
|
| }
|
|
|
| @@ -701,20 +781,25 @@ void PaintPropertyTreeBuilder::updateOutOfFlowContext(
|
| if (context.fixedPosition.clip == cssClip->parent()) {
|
| context.fixedPosition.clip = cssClip;
|
| } else {
|
| - context.fixedPosition.clip =
|
| - object.getMutableForPainting()
|
| - .ensurePaintProperties()
|
| - .updateCssClipFixedPosition(
|
| - context.fixedPosition.clip,
|
| - const_cast<TransformPaintPropertyNode*>(
|
| - cssClip->localTransformSpace()),
|
| - cssClip->clipRect());
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + object.getMutableForPainting()
|
| + .ensurePaintProperties()
|
| + .updateCssClipFixedPosition(context.fixedPosition.clip,
|
| + const_cast<TransformPaintPropertyNode*>(
|
| + cssClip->localTransformSpace()),
|
| + cssClip->clipRect());
|
| + }
|
| + const auto* properties = object.paintProperties();
|
| + if (properties && properties->cssClipFixedPosition())
|
| + context.fixedPosition.clip = properties->cssClipFixedPosition();
|
| return;
|
| }
|
| }
|
|
|
| - if (auto* properties = object.getMutableForPainting().paintProperties())
|
| - properties->clearCssClipFixedPosition();
|
| + if (object.needsPaintPropertyUpdate()) {
|
| + if (auto* properties = object.getMutableForPainting().paintProperties())
|
| + properties->clearCssClipFixedPosition();
|
| + }
|
| }
|
|
|
| // Override ContainingBlockContext based on the properties of a containing block
|
| @@ -839,12 +924,16 @@ static void deriveBorderBoxFromContainerContext(
|
| }
|
| }
|
|
|
| -void PaintPropertyTreeBuilder::buildTreeNodesForSelf(
|
| +void PaintPropertyTreeBuilder::updatePropertiesForSelf(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| if (!object.isBoxModelObject() && !object.isSVG())
|
| return;
|
|
|
| +#if DCHECK_IS_ON()
|
| + FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
|
| +#endif
|
| +
|
| deriveBorderBoxFromContainerContext(object, context);
|
|
|
| updatePaintOffsetTranslation(object, context);
|
| @@ -856,12 +945,16 @@ void PaintPropertyTreeBuilder::buildTreeNodesForSelf(
|
| updateMainThreadScrollingReasons(object, context);
|
| }
|
|
|
| -void PaintPropertyTreeBuilder::buildTreeNodesForChildren(
|
| +void PaintPropertyTreeBuilder::updatePropertiesForChildren(
|
| const LayoutObject& object,
|
| PaintPropertyTreeBuilderContext& context) {
|
| if (!object.isBoxModelObject() && !object.isSVG())
|
| return;
|
|
|
| +#if DCHECK_IS_ON()
|
| + FindObjectPropertiesNeedingUpdateScope checkNeedsUpdateScope(object);
|
| +#endif
|
| +
|
| updateOverflowClip(object, context);
|
| updatePerspective(object, context);
|
| updateSvgLocalToBorderBoxTransform(object, context);
|
|
|