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

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

Issue 2831683003: Refactor to centralize code which decides whether ObjectPaintProperties are needed. (Closed)
Patch Set: none Created 3 years, 8 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 2e972ab9b6ea04132c69352a6c00af5979f89f04..99a5ed9e309dd1977f3d5371cc93dafcb64fb835 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -224,56 +224,75 @@ void PaintPropertyTreeBuilder::UpdateProperties(
frame_view.SetTotalPropertyTreeStateForContents(std::move(contents_state));
}
-void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
- const LayoutBoxModelObject& object,
- PaintPropertyTreeBuilderContext& context) {
- bool uses_paint_offset_translation = false;
+static bool NeedsPaintOffsetTranslation(const LayoutObject& object) {
+ if (!object.IsBoxModelObject())
+ return false;
+ const LayoutBoxModelObject& box_model = ToLayoutBoxModelObject(object);
if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
- object.IsLayoutView()) {
+ box_model.IsLayoutView()) {
// Root layer scrolling always creates a translation node for LayoutView to
// ensure fixed and absolute contexts use the correct transform space.
- uses_paint_offset_translation = true;
- } else if (object.HasLayer() &&
- context.current.paint_offset != LayoutPoint() &&
- object.Layer()->PaintsWithTransform(
+ return true;
+ } else if (box_model.HasLayer() &&
+ box_model.Layer()->PaintsWithTransform(
kGlobalPaintFlattenCompositingLayers)) {
- uses_paint_offset_translation = true;
+ return true;
}
+ return false;
+}
- if (!uses_paint_offset_translation) {
+void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation(
+ const LayoutBoxModelObject& object,
+ PaintPropertyTreeBuilderContext& context) {
+ if (NeedsPaintOffsetTranslation(object) &&
+ // As an optimization, skip these paint offset translation nodes when
+ // the offset is an identity. An exception is the layout view because root
+ // layer scrolling needs a transform node to ensure fixed and absolute
+ // descendants use the correct transform space.
+ (object.IsLayoutView() ||
+ context.current.paint_offset != LayoutPoint())) {
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+ // 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 rounded_paint_offset =
+ RoundedIntPoint(context.current.paint_offset);
+ LayoutPoint fractional_paint_offset =
+ LayoutPoint(context.current.paint_offset - rounded_paint_offset);
+
+ context.force_subtree_update |= properties.UpdatePaintOffsetTranslation(
+ context.current.transform,
+ TransformationMatrix().Translate(rounded_paint_offset.X(),
+ rounded_paint_offset.Y()),
+ FloatPoint3D(), context.current.should_flatten_inherited_transform,
+ context.current.rendering_context_id);
+
+ context.current.transform = properties.PaintOffsetTranslation();
+ context.current.paint_offset = fractional_paint_offset;
+ if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
+ object.IsLayoutView()) {
+ context.absolute_position.transform = properties.PaintOffsetTranslation();
+ context.fixed_position.transform = properties.PaintOffsetTranslation();
+ context.absolute_position.paint_offset = LayoutPoint();
+ context.fixed_position.paint_offset = LayoutPoint();
+ }
+ } else {
if (auto* properties = object.GetMutableForPainting().PaintProperties())
context.force_subtree_update |= properties->ClearPaintOffsetTranslation();
- 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 rounded_paint_offset = RoundedIntPoint(context.current.paint_offset);
- LayoutPoint fractional_paint_offset =
- LayoutPoint(context.current.paint_offset - rounded_paint_offset);
-
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
- context.force_subtree_update |= properties.UpdatePaintOffsetTranslation(
- context.current.transform,
- TransformationMatrix().Translate(rounded_paint_offset.X(),
- rounded_paint_offset.Y()),
- FloatPoint3D(), context.current.should_flatten_inherited_transform,
- context.current.rendering_context_id);
-
- context.current.transform = properties.PaintOffsetTranslation();
- context.current.paint_offset = fractional_paint_offset;
- if (RuntimeEnabledFeatures::rootLayerScrollingEnabled() &&
- object.IsLayoutView()) {
- context.absolute_position.transform = properties.PaintOffsetTranslation();
- context.fixed_position.transform = properties.PaintOffsetTranslation();
- context.absolute_position.paint_offset = LayoutPoint();
- context.fixed_position.paint_offset = LayoutPoint();
- }
+static bool NeedsTransformForNonRootSVG(const LayoutObject& object) {
+ // 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.
+ return object.IsSVGChild() &&
+ !object.LocalToSVGParentTransform().IsIdentity();
}
// SVG does not use the general transform update of |updateTransform|, instead
@@ -289,13 +308,9 @@ void PaintPropertyTreeBuilder::UpdateTransformForNonRootSVG(
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
AffineTransform transform = 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()) {
+ if (NeedsTransformForNonRootSVG(object)) {
// The origin is included in the local transform, so leave origin empty.
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
context.force_subtree_update |= properties.UpdateTransform(
context.current.transform, TransformationMatrix(transform),
FloatPoint3D());
@@ -347,6 +362,14 @@ static FloatPoint3D TransformOrigin(const LayoutBox& box) {
style.TransformOriginZ());
}
+static bool NeedsTransform(const LayoutObject& object) {
+ if (!object.IsBox())
+ return false;
+ return object.StyleRef().HasTransform() || object.StyleRef().Preserves3D() ||
+ CompositingReasonsForTransform(ToLayoutBox(object)) !=
+ kCompositingReasonNone;
+}
+
void PaintPropertyTreeBuilder::UpdateTransform(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
@@ -362,44 +385,37 @@ void PaintPropertyTreeBuilder::UpdateTransform(
// direct compositing reason. The latter is required because this is the
// only way to represent compositing both an element and its stacking
// descendants.
- bool has_transform = false;
- if (object.IsBox()) {
+ if (NeedsTransform(object)) {
auto& box = ToLayoutBox(object);
CompositingReasons compositing_reasons =
CompositingReasonsForTransform(box);
- if (style.HasTransform() || style.Preserves3D() ||
- compositing_reasons != kCompositingReasonNone) {
- TransformationMatrix matrix;
- style.ApplyTransform(
- matrix, box.Size(), ComputedStyle::kExcludeTransformOrigin,
- ComputedStyle::kIncludeMotionPath,
- ComputedStyle::kIncludeIndependentTransformProperties);
-
- // 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.
- unsigned rendering_context_id = context.current.rendering_context_id;
- if (style.Preserves3D() && !rendering_context_id)
- rendering_context_id = PtrHash<const LayoutObject>::GetHash(&object);
-
- CompositorElementId compositor_element_id =
- style.HasCurrentTransformAnimation()
- ? CreateDomNodeBasedCompositorElementId(object)
- : CompositorElementId();
-
- auto& properties =
- object.GetMutableForPainting().EnsurePaintProperties();
- context.force_subtree_update |= properties.UpdateTransform(
- context.current.transform, matrix, TransformOrigin(box),
- context.current.should_flatten_inherited_transform,
- rendering_context_id, compositing_reasons, compositor_element_id);
- has_transform = true;
- }
- }
- if (!has_transform) {
+ TransformationMatrix matrix;
+ style.ApplyTransform(
+ matrix, box.Size(), ComputedStyle::kExcludeTransformOrigin,
+ ComputedStyle::kIncludeMotionPath,
+ ComputedStyle::kIncludeIndependentTransformProperties);
+
+ // 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.
+ unsigned rendering_context_id = context.current.rendering_context_id;
+ if (style.Preserves3D() && !rendering_context_id)
+ rendering_context_id = PtrHash<const LayoutObject>::GetHash(&object);
+
+ CompositorElementId compositor_element_id =
+ style.HasCurrentTransformAnimation()
+ ? CreateDomNodeBasedCompositorElementId(object)
+ : CompositorElementId();
+
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+ context.force_subtree_update |= properties.UpdateTransform(
+ context.current.transform, matrix, TransformOrigin(box),
+ context.current.should_flatten_inherited_transform,
+ rendering_context_id, compositing_reasons, compositor_element_id);
+ } else {
if (auto* properties = object.GetMutableForPainting().PaintProperties())
context.force_subtree_update |= properties->ClearTransform();
}
@@ -461,102 +477,121 @@ static bool ComputeMaskParameters(IntRect& mask_clip,
return true;
}
-void PaintPropertyTreeBuilder::UpdateEffect(
- const LayoutObject& object,
- PaintPropertyTreeBuilderContext& context) {
+static bool NeedsEffect(const LayoutObject& object) {
const ComputedStyle& style = object.StyleRef();
const bool is_css_isolated_group =
object.IsBoxModelObject() && style.IsStackingContext();
- if (!is_css_isolated_group && !object.IsSVGChild()) {
- if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
- context.force_subtree_update |= properties->ClearEffect();
- context.force_subtree_update |= properties->ClearMask();
- context.force_subtree_update |= properties->ClearMaskClip();
- }
+
+ if (!is_css_isolated_group && !object.IsSVGChild())
+ return false;
+
+ if (object.IsSVG()) {
+ // This handles SVGRoot objects which have PaintLayers.
+ if (object.IsSVGRoot() && object.HasNonIsolatedBlendingDescendants())
+ return true;
+ if (SVGLayoutSupport::IsIsolationRequired(&object))
+ return true;
+ } else if (object.IsBoxModelObject()) {
+ if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) {
+ if (layer->HasNonIsolatedDescendantWithBlendMode())
+ return true;
+ }
+ }
+
+ SkBlendMode blend_mode = object.IsBlendingAllowed()
+ ? WebCoreCompositeToSkiaComposite(
+ kCompositeSourceOver, style.BlendMode())
+ : SkBlendMode::kSrcOver;
+ if (blend_mode != SkBlendMode::kSrcOver)
+ return true;
+
+ float opacity = style.Opacity();
+ if (opacity != 1.0f)
+ return true;
+
+ if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(style))
+ return true;
+
+ if (object.IsSVGChild()) {
+ if (SVGResources* resources =
+ SVGResourcesCache::CachedResourcesForLayoutObject(&object)) {
+ if (resources->Masker())
+ return true;
}
- return;
}
+ if (object.StyleRef().HasMask())
+ return true;
+
+ return false;
+}
+
+void PaintPropertyTreeBuilder::UpdateEffect(
+ const LayoutObject& object,
+ PaintPropertyTreeBuilderContext& context) {
+ const ComputedStyle& style = object.StyleRef();
+
// TODO(trchen): Can't omit effect node if we have 3D children.
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
const ClipPaintPropertyNode* output_clip =
context.input_clip_of_current_effect;
- bool effect_node_needed = false;
+ if (NeedsEffect(object)) {
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
- // Can't omit effect node if we have paint children with exotic blending.
- if (object.IsSVG()) {
- // This handles SVGRoot objects which have PaintLayers.
- if (object.IsSVGRoot() && object.HasNonIsolatedBlendingDescendants())
- effect_node_needed = true;
- else if (SVGLayoutSupport::IsIsolationRequired(&object))
- effect_node_needed = true;
- } else if (PaintLayer* layer = ToLayoutBoxModelObject(object).Layer()) {
- if (layer->HasNonIsolatedDescendantWithBlendMode())
- effect_node_needed = true;
- }
+ // We may begin to composite our subtree prior to an animation starts,
+ // but a compositor element ID is only needed when an animation is
+ // current.
+ CompositingReasons compositing_reasons = kCompositingReasonNone;
+ if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
+ style)) {
+ compositing_reasons = kCompositingReasonActiveAnimation;
+ }
- SkBlendMode blend_mode = object.IsBlendingAllowed()
- ? WebCoreCompositeToSkiaComposite(
- kCompositeSourceOver, style.BlendMode())
- : SkBlendMode::kSrcOver;
- if (blend_mode != SkBlendMode::kSrcOver)
- effect_node_needed = true;
-
- float opacity = style.Opacity();
- if (opacity != 1.0f)
- effect_node_needed = true;
-
- // We may begin to composite our subtree prior to an animation starts,
- // but a compositor element ID is only needed when an animation is current.
- CompositorElementId compositor_element_id =
- style.HasCurrentOpacityAnimation()
- ? CreateDomNodeBasedCompositorElementId(object)
- : CompositorElementId();
- CompositingReasons compositing_reasons = kCompositingReasonNone;
- if (CompositingReasonFinder::RequiresCompositingForOpacityAnimation(
- style)) {
- compositing_reasons = kCompositingReasonActiveAnimation;
- effect_node_needed = true;
- }
- DCHECK(!style.HasCurrentOpacityAnimation() ||
- compositing_reasons != kCompositingReasonNone);
-
- IntRect mask_clip;
- ColorFilter mask_color_filter;
- bool has_mask = ComputeMaskParameters(mask_clip, mask_color_filter, object,
- context.current.paint_offset);
- if (has_mask) {
- effect_node_needed = true;
-
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
- context.force_subtree_update |= properties.UpdateMaskClip(
- context.current.clip, context.current.transform,
- FloatRoundedRect(mask_clip));
- output_clip = properties.MaskClip();
+ IntRect mask_clip;
+ ColorFilter mask_color_filter;
+ bool has_mask = ComputeMaskParameters(
+ mask_clip, mask_color_filter, object, context.current.paint_offset);
+ if (has_mask) {
+ context.force_subtree_update |= properties.UpdateMaskClip(
+ context.current.clip, context.current.transform,
+ FloatRoundedRect(mask_clip));
+ output_clip = properties.MaskClip();
- // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
- // grouping (i.e. descendant-dependent compositing reason) properly yet.
- // This forces masked subtree always create a layer for now.
- compositing_reasons |= kCompositingReasonIsolateCompositedDescendants;
- } else {
- if (auto* properties = object.GetMutableForPainting().PaintProperties())
- context.force_subtree_update |= properties->ClearMaskClip();
- }
+ // TODO(crbug.com/683425): PaintArtifactCompositor does not handle
+ // grouping (i.e. descendant-dependent compositing reason) properly
+ // yet. This forces masked subtree always create a layer for now.
+ compositing_reasons |= kCompositingReasonIsolateCompositedDescendants;
+ } else {
+ if (auto* properties = object.GetMutableForPainting().PaintProperties())
+ context.force_subtree_update |= properties->ClearMaskClip();
+ }
+
+ SkBlendMode blend_mode =
+ object.IsBlendingAllowed()
+ ? WebCoreCompositeToSkiaComposite(kCompositeSourceOver,
+ style.BlendMode())
+ : SkBlendMode::kSrcOver;
+
+ CompositorElementId compositor_element_id =
+ style.HasCurrentOpacityAnimation()
+ ? CreateDomNodeBasedCompositorElementId(object)
+ : CompositorElementId();
+
+ DCHECK(!style.HasCurrentOpacityAnimation() ||
+ compositing_reasons != kCompositingReasonNone);
- if (effect_node_needed) {
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
context.force_subtree_update |= properties.UpdateEffect(
context.current_effect, context.current.transform, output_clip,
- kColorFilterNone, CompositorFilterOperations(), opacity, blend_mode,
- compositing_reasons, compositor_element_id);
+ kColorFilterNone, CompositorFilterOperations(), style.Opacity(),
+ blend_mode, compositing_reasons, compositor_element_id);
if (has_mask) {
// TODO(crbug.com/683425): PaintArtifactCompositor does not handle
- // grouping (i.e. descendant-dependent compositing reason) properly yet.
- // Adding CompositingReasonSquashingDisallowed forces mask not getting
- // squashed into a child effect. Have no compositing reason otherwise.
+ // grouping (i.e. descendant-dependent compositing reason) properly
+ // yet. Adding CompositingReasonSquashingDisallowed forces mask not
+ // getting squashed into a child effect. Have no compositing reason
+ // otherwise.
context.force_subtree_update |= properties.UpdateMask(
properties.Effect(), context.current.transform, output_clip,
mask_color_filter, CompositorFilterOperations(), 1.f,
@@ -569,6 +604,7 @@ void PaintPropertyTreeBuilder::UpdateEffect(
if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
context.force_subtree_update |= properties->ClearEffect();
context.force_subtree_update |= properties->ClearMask();
+ context.force_subtree_update |= properties->ClearMaskClip();
}
}
}
@@ -584,66 +620,70 @@ void PaintPropertyTreeBuilder::UpdateEffect(
}
}
+static bool NeedsFilter(const LayoutObject& object) {
+ // TODO(trchen): SVG caches filters in SVGResources. Implement it.
+ return object.IsBoxModelObject() && ToLayoutBoxModelObject(object).Layer() &&
+ (object.StyleRef().HasFilter() || object.HasReflection());
+}
+
void PaintPropertyTreeBuilder::UpdateFilter(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
const ComputedStyle& style = object.StyleRef();
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- CompositorFilterOperations filter;
- if (object.IsSVGChild()) {
- // 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);
- }
+ if (NeedsFilter(object)) {
+ CompositorFilterOperations filter =
+ ToLayoutBoxModelObject(object)
+ .Layer()
+ ->CreateCompositorFilterOperationsForFilter(style);
+
+ // 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.
+ const ClipPaintPropertyNode* output_clip = 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.
+
+ // We may begin to composite our subtree prior to an animation starts,
+ // but a compositor element ID is only needed when an animation is
+ // current.
+ CompositorElementId compositor_element_id =
+ style.HasCurrentFilterAnimation()
+ ? CreateDomNodeBasedCompositorElementId(object)
+ : CompositorElementId();
+ CompositingReasons compositing_reasons =
+ CompositingReasonFinder::RequiresCompositingForFilterAnimation(style)
+ ? kCompositingReasonActiveAnimation
+ : kCompositingReasonNone;
+ DCHECK(!style.HasCurrentFilterAnimation() ||
+ compositing_reasons != kCompositingReasonNone);
- // 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.
- const ClipPaintPropertyNode* output_clip = 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.
-
- // We may begin to composite our subtree prior to an animation starts,
- // but a compositor element ID is only needed when an animation is current.
- CompositorElementId compositor_element_id =
- style.HasCurrentFilterAnimation()
- ? CreateDomNodeBasedCompositorElementId(object)
- : CompositorElementId();
- CompositingReasons compositing_reasons =
- CompositingReasonFinder::RequiresCompositingForFilterAnimation(style)
- ? kCompositingReasonActiveAnimation
- : kCompositingReasonNone;
- DCHECK(!style.HasCurrentFilterAnimation() ||
- compositing_reasons != kCompositingReasonNone);
-
- if (compositing_reasons == kCompositingReasonNone && filter.IsEmpty()) {
- if (auto* properties = object.GetMutableForPainting().PaintProperties())
- context.force_subtree_update |= properties->ClearFilter();
- } else {
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
context.force_subtree_update |= properties.UpdateFilter(
context.current_effect, context.current.transform, output_clip,
kColorFilterNone, std::move(filter), 1.f, SkBlendMode::kSrcOver,
compositing_reasons, compositor_element_id);
+ } else {
+ if (auto* properties = object.GetMutableForPainting().PaintProperties())
+ context.force_subtree_update |= properties->ClearFilter();
}
}
@@ -659,11 +699,15 @@ void PaintPropertyTreeBuilder::UpdateFilter(
}
}
+static bool NeedsCssClip(const LayoutObject& object) {
+ return object.HasClip();
+}
+
void PaintPropertyTreeBuilder::UpdateCssClip(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- if (object.HasClip()) {
+ if (NeedsCssClip(object)) {
// 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
@@ -671,7 +715,7 @@ void PaintPropertyTreeBuilder::UpdateCssClip(
DCHECK(object.CanContainAbsolutePositionObjects());
LayoutRect clip_rect =
ToLayoutBox(object).ClipRect(context.current.paint_offset);
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
context.force_subtree_update |= properties.UpdateCssClip(
context.current.clip, context.current.transform,
FloatRoundedRect(FloatRect(clip_rect)));
@@ -704,6 +748,16 @@ void PaintPropertyTreeBuilder::UpdateLocalBorderBoxContext(
}
}
+static bool NeedsScrollbarPaintOffset(const LayoutObject& object) {
+ if (object.IsBoxModelObject()) {
+ if (auto* area = ToLayoutBoxModelObject(object).GetScrollableArea()) {
+ if (area->HorizontalScrollbar() || area->VerticalScrollbar())
+ return true;
+ }
+ }
+ return false;
+}
+
// TODO(trchen): Remove this once we bake the paint offset into frameRect.
void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset(
const LayoutObject& object,
@@ -711,44 +765,49 @@ void PaintPropertyTreeBuilder::UpdateScrollbarPaintOffset(
if (!object.NeedsPaintPropertyUpdate() && !context.force_subtree_update)
return;
- bool needs_scrollbar_paint_offset = false;
- IntPoint rounded_paint_offset = RoundedIntPoint(context.current.paint_offset);
- if (rounded_paint_offset != IntPoint() && object.IsBoxModelObject()) {
- if (auto* area = ToLayoutBoxModelObject(object).GetScrollableArea()) {
- if (area->HorizontalScrollbar() || area->VerticalScrollbar()) {
- auto paint_offset = TransformationMatrix().Translate(
- rounded_paint_offset.X(), rounded_paint_offset.Y());
- auto& properties =
- object.GetMutableForPainting().EnsurePaintProperties();
- context.force_subtree_update |= properties.UpdateScrollbarPaintOffset(
- context.current.transform, paint_offset, FloatPoint3D());
- needs_scrollbar_paint_offset = true;
- }
- }
+ if (NeedsScrollbarPaintOffset(object)) {
+ IntPoint rounded_paint_offset =
+ RoundedIntPoint(context.current.paint_offset);
+ auto paint_offset = TransformationMatrix().Translate(
+ rounded_paint_offset.X(), rounded_paint_offset.Y());
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+ context.force_subtree_update |= properties.UpdateScrollbarPaintOffset(
+ context.current.transform, paint_offset, FloatPoint3D());
+ } else {
+ if (auto* properties = object.GetMutableForPainting().PaintProperties())
+ context.force_subtree_update |= properties->ClearScrollbarPaintOffset();
}
+}
- auto* properties = object.GetMutableForPainting().PaintProperties();
- if (!needs_scrollbar_paint_offset && properties)
- context.force_subtree_update |= properties->ClearScrollbarPaintOffset();
+static bool NeedsOverflowScroll(const LayoutObject& object) {
+ return object.IsBox() && ToLayoutBox(object).ShouldClipOverflow();
}
void PaintPropertyTreeBuilder::UpdateOverflowClip(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
- if (!object.IsBox())
- return;
-
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- const LayoutBox& box = ToLayoutBox(object);
- // 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 clip_rect;
- if (box.ShouldClipOverflow()) {
+ if (NeedsOverflowScroll(object)) {
+ const LayoutBox& box = ToLayoutBox(object);
+ LayoutRect clip_rect;
clip_rect =
LayoutRect(box.OverflowClipRect(context.current.paint_offset));
+
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+ const auto* current_clip = context.current.clip;
+ if (box.StyleRef().HasBorderRadius()) {
+ auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
+ LayoutRect(context.current.paint_offset, box.Size()));
+ context.force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
+ context.current.clip, context.current.transform, inner_border);
+ current_clip = properties.InnerBorderRadiusClip();
+ } else {
+ context.force_subtree_update |= properties.ClearInnerBorderRadiusClip();
+ }
+
+ context.force_subtree_update |=
+ properties.UpdateOverflowClip(current_clip, context.current.transform,
+ FloatRoundedRect(FloatRect(clip_rect)));
} else {
if (auto* properties = object.GetMutableForPainting().PaintProperties()) {
context.force_subtree_update |=
@@ -757,22 +816,6 @@ void PaintPropertyTreeBuilder::UpdateOverflowClip(
}
return;
}
-
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
- const auto* current_clip = context.current.clip;
- if (box.StyleRef().HasBorderRadius()) {
- auto inner_border = box.StyleRef().GetRoundedInnerBorderFor(
- LayoutRect(context.current.paint_offset, box.Size()));
- context.force_subtree_update |= properties.UpdateInnerBorderRadiusClip(
- context.current.clip, context.current.transform, inner_border);
- current_clip = properties.InnerBorderRadiusClip();
- } else {
- context.force_subtree_update |= properties.ClearInnerBorderRadiusClip();
- }
-
- context.force_subtree_update |=
- properties.UpdateOverflowClip(current_clip, context.current.transform,
- FloatRoundedRect(FloatRect(clip_rect)));
}
const auto* properties = object.PaintProperties();
@@ -791,12 +834,16 @@ static FloatPoint PerspectiveOrigin(const LayoutBox& box) {
border_box_size.Height()));
}
+static bool NeedsPerspective(const LayoutObject& object) {
+ return object.IsBox() && object.StyleRef().HasPerspective();
+}
+
void PaintPropertyTreeBuilder::UpdatePerspective(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- const ComputedStyle& style = object.StyleRef();
- if (object.IsBox() && style.HasPerspective()) {
+ if (NeedsPerspective(object)) {
+ const ComputedStyle& style = object.StyleRef();
// The perspective node must not flatten (else nothing will get
// perspective), but it should still extend the rendering context as
// most transform nodes do.
@@ -804,7 +851,7 @@ void PaintPropertyTreeBuilder::UpdatePerspective(
TransformationMatrix().ApplyPerspective(style.Perspective());
FloatPoint3D origin = PerspectiveOrigin(ToLayoutBox(object)) +
ToLayoutSize(context.current.paint_offset);
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
context.force_subtree_update |= properties.UpdatePerspective(
context.current.transform, matrix, origin,
context.current.should_flatten_inherited_transform,
@@ -822,6 +869,10 @@ void PaintPropertyTreeBuilder::UpdatePerspective(
}
}
+static bool NeedsSVGLocalToBorderBoxTransform(const LayoutObject& object) {
+ return object.IsSVGRoot();
+}
+
void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
@@ -832,8 +883,9 @@ void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform(
AffineTransform transform_to_border_box =
SVGRootPainter(ToLayoutSVGRoot(object))
.TransformToPixelSnappedBorderBox(context.current.paint_offset);
- if (!transform_to_border_box.IsIdentity()) {
- auto& properties = object.GetMutableForPainting().EnsurePaintProperties();
+ if (!transform_to_border_box.IsIdentity() &&
+ NeedsSVGLocalToBorderBoxTransform(object)) {
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
context.force_subtree_update |=
properties.UpdateSvgLocalToBorderBoxTransform(
context.current.transform, transform_to_border_box,
@@ -870,56 +922,58 @@ static MainThreadScrollingReasons GetMainThreadScrollingReasons(
ancestor_reasons);
}
+static bool NeedsScrollTranslation(const LayoutObject& object) {
+ if (object.HasOverflowClip()) {
+ const LayoutBox& box = ToLayoutBox(object);
+ auto* scrollable_area = box.GetScrollableArea();
+ IntSize scroll_offset = box.ScrolledContentOffset();
+ if (!scroll_offset.IsZero() || scrollable_area->ScrollsOverflow())
+ return true;
+ }
+ return false;
+}
+
void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- bool needs_scroll_properties = false;
- if (object.HasOverflowClip()) {
+ if (NeedsScrollTranslation(object)) {
+ const LayoutBox& box = ToLayoutBox(object);
+ auto* scrollable_area = box.GetScrollableArea();
+ IntSize scroll_offset = box.ScrolledContentOffset();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+
+ IntSize scroll_clip = scrollable_area->VisibleContentRect().Size();
+ IntSize scroll_bounds = scrollable_area->ContentsSize();
+ bool user_scrollable_horizontal =
+ scrollable_area->UserInputScrollable(kHorizontalScrollbar);
+ bool user_scrollable_vertical =
+ scrollable_area->UserInputScrollable(kVerticalScrollbar);
+
auto ancestor_reasons =
context.current.scroll->GetMainThreadScrollingReasons();
auto reasons = GetMainThreadScrollingReasons(object, ancestor_reasons);
- const LayoutBox& box = ToLayoutBox(object);
- auto* scrollable_area = box.GetScrollableArea();
- IntSize scroll_offset = box.ScrolledContentOffset();
- if (!scroll_offset.IsZero() || scrollable_area->ScrollsOverflow()) {
- needs_scroll_properties = true;
- auto& properties =
- object.GetMutableForPainting().EnsurePaintProperties();
-
- IntSize scroll_clip = scrollable_area->VisibleContentRect().Size();
- IntSize scroll_bounds = scrollable_area->ContentsSize();
- bool user_scrollable_horizontal =
- scrollable_area->UserInputScrollable(kHorizontalScrollbar);
- bool user_scrollable_vertical =
- scrollable_area->UserInputScrollable(kVerticalScrollbar);
-
- // Main thread scrolling reasons depend on their ancestor's reasons
- // so ensure the entire subtree is updated when reasons change.
- if (auto* existing_scroll_translation =
- properties.ScrollTranslation()) {
- auto* existing_scroll_node =
- existing_scroll_translation->ScrollNode();
- if (existing_scroll_node->GetMainThreadScrollingReasons() != reasons)
- context.force_subtree_update = true;
- }
-
- CompositorElementId compositor_element_id =
- CreateDomNodeBasedCompositorElementId(object);
- TransformationMatrix matrix = TransformationMatrix().Translate(
- -scroll_offset.Width(), -scroll_offset.Height());
- context.force_subtree_update |= properties.UpdateScrollTranslation(
- context.current.transform, matrix, FloatPoint3D(),
- context.current.should_flatten_inherited_transform,
- context.current.rendering_context_id, kCompositingReasonNone,
- compositor_element_id, context.current.scroll, scroll_clip,
- scroll_bounds, user_scrollable_horizontal, user_scrollable_vertical,
- reasons, scrollable_area);
+ // Main thread scrolling reasons depend on their ancestor's reasons
+ // so ensure the entire subtree is updated when reasons change.
+ if (auto* existing_scroll_translation = properties.ScrollTranslation()) {
+ auto* existing_scroll_node = existing_scroll_translation->ScrollNode();
+ if (existing_scroll_node->GetMainThreadScrollingReasons() != reasons)
+ context.force_subtree_update = true;
}
- }
- if (!needs_scroll_properties) {
+ CompositorElementId compositor_element_id =
+ CreateDomNodeBasedCompositorElementId(object);
+ TransformationMatrix matrix = TransformationMatrix().Translate(
+ -scroll_offset.Width(), -scroll_offset.Height());
+ context.force_subtree_update |= properties.UpdateScrollTranslation(
+ context.current.transform, matrix, FloatPoint3D(),
+ context.current.should_flatten_inherited_transform,
+ context.current.rendering_context_id, kCompositingReasonNone,
+ compositor_element_id, context.current.scroll, scroll_clip,
+ scroll_bounds, user_scrollable_horizontal, user_scrollable_vertical,
+ reasons, scrollable_area);
+ } else {
// Ensure pre-existing properties are cleared.
if (auto* properties = object.GetMutableForPainting().PaintProperties())
context.force_subtree_update |= properties->ClearScrollTranslation();
@@ -934,6 +988,11 @@ void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation(
}
}
+static bool NeedsCssClipFixedPosition(const LayoutObject& object) {
+ return !object.IsLayoutView() && !object.CanContainFixedPositionObjects() &&
+ NeedsCssClip(object);
+}
+
void PaintPropertyTreeBuilder::UpdateOutOfFlowContext(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
@@ -966,8 +1025,8 @@ void PaintPropertyTreeBuilder::UpdateOutOfFlowContext(
// absolute position container. However for fixed-position descendants we
// need to insert the clip here if we are not a containing block ancestor of
// them.
- auto* css_clip =
- object.GetMutableForPainting().PaintProperties()->CssClip();
+ auto& properties = *object.GetMutableForPainting().PaintProperties();
+ auto* css_clip = properties.CssClip();
// Before we actually create anything, check whether in-flow context and
// fixed-position context has exactly the same clip. Reuse if possible.
@@ -975,17 +1034,14 @@ void PaintPropertyTreeBuilder::UpdateOutOfFlowContext(
context.fixed_position.clip = css_clip;
} else {
if (object.NeedsPaintPropertyUpdate() || context.force_subtree_update) {
- auto& properties =
- object.GetMutableForPainting().EnsurePaintProperties();
context.force_subtree_update |= properties.UpdateCssClipFixedPosition(
context.fixed_position.clip,
const_cast<TransformPaintPropertyNode*>(
css_clip->LocalTransformSpace()),
css_clip->ClipRect());
}
- const auto* properties = object.PaintProperties();
- if (properties && properties->CssClipFixedPosition())
- context.fixed_position.clip = properties->CssClipFixedPosition();
+ if (properties.CssClipFixedPosition())
+ context.fixed_position.clip = properties.CssClipFixedPosition();
return;
}
}
@@ -1108,6 +1164,28 @@ void PaintPropertyTreeBuilder::UpdateForObjectLocationAndSize(
box.GetMutableForPainting().SetNeedsPaintPropertyUpdate();
}
+void PaintPropertyTreeBuilder::UpdatePaintProperties(
+ const LayoutObject& object,
+ PaintPropertyTreeBuilderContext& context) {
+ bool needs_paint_properties =
+ NeedsPaintOffsetTranslation(object) || NeedsTransform(object) ||
+ NeedsEffect(object) || NeedsTransformForNonRootSVG(object) ||
+ NeedsFilter(object) || NeedsCssClip(object) ||
+ NeedsScrollbarPaintOffset(object) || NeedsOverflowScroll(object) ||
+ NeedsPerspective(object) || NeedsSVGLocalToBorderBoxTransform(object) ||
+ NeedsScrollTranslation(object) || NeedsCssClipFixedPosition(object);
+
+ bool had_paint_properties = object.PaintProperties();
+
+ if (needs_paint_properties) {
+ object.GetMutableForPainting().EnsurePaintProperties();
+ } else {
+ object.GetMutableForPainting().ClearPaintProperties();
+ if (had_paint_properties)
+ context.force_subtree_update = true;
+ }
+}
+
void PaintPropertyTreeBuilder::UpdatePropertiesForSelf(
const LayoutObject& object,
PaintPropertyTreeBuilderContext& context) {
@@ -1118,6 +1196,8 @@ void PaintPropertyTreeBuilder::UpdatePropertiesForSelf(
context = PaintPropertyTreeBuilderContext();
}
+ UpdatePaintProperties(object, context);
+
// This is not in FindObjectPropertiesNeedingUpdateScope because paint offset
// can change without needsPaintPropertyUpdate.
UpdateForObjectLocationAndSize(object, context);

Powered by Google App Engine
This is Rietveld 408576698