Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(722)

Unified Diff: third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp

Issue 2404213004: Implement incremental paint property tree rebuilding (Closed)
Patch Set: Cleanup needsUpdate finder construction, tighten reasons for updating a property subtree, misc clea… Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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);

Powered by Google App Engine
This is Rietveld 408576698