Chromium Code Reviews| 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 09c25f88501dfaaccb70aa53b710247eaaa7ce0a..94289d647a7c25acb3fe4b50bcd6eb9476fc1dd2 100644 |
| --- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| +++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp |
| @@ -224,27 +224,40 @@ 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 NeedsPaintPropertiesForPaintOffsetTranslation( |
|
pdr.
2017/04/20 22:56:28
Bikeshed: how about NeedsPaintOffsetTranslation to
chrishtr
2017/04/21 01:20:02
Done. Now there is a nice symmetry: Needs*() and U
|
| + 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; |
| +} |
| + |
| +void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation( |
| + const LayoutBoxModelObject& object, |
| + PaintPropertyTreeBuilderContext& context) { |
| + bool uses_paint_offset_translation = |
| + NeedsPaintPropertiesForPaintOffsetTranslation(object); |
| + if (!object.IsLayoutView() && context.current.paint_offset == LayoutPoint()) |
|
pdr.
2017/04/20 22:56:28
Can you add a comment here? Something like:
// As
chrishtr
2017/04/21 01:20:02
Done. Also cleaned up the code some more.
|
| + uses_paint_offset_translation = false; |
| + |
| + auto* properties = object.GetMutableForPainting().PaintProperties(); |
|
pdr.
2017/04/20 22:56:28
In the future maybe we can refactor the Update* fu
chrishtr
2017/04/21 01:20:02
Agreed.
|
| if (!uses_paint_offset_translation) { |
| - if (auto* properties = object.GetMutableForPainting().PaintProperties()) |
| + if (properties) |
| context.force_subtree_update |= properties->ClearPaintOffsetTranslation(); |
| return; |
| } |
| + DCHECK(properties); |
| // We should use the same subpixel paint offset values for snapping |
| // regardless of whether a transform is present. If there is a transform |
| @@ -257,25 +270,33 @@ void PaintPropertyTreeBuilder::UpdatePaintOffsetTranslation( |
| LayoutPoint fractional_paint_offset = |
| LayoutPoint(context.current.paint_offset - rounded_paint_offset); |
| - auto& properties = object.GetMutableForPainting().EnsurePaintProperties(); |
| - context.force_subtree_update |= properties.UpdatePaintOffsetTranslation( |
| + 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.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.transform = properties->PaintOffsetTranslation(); |
| + context.fixed_position.transform = properties->PaintOffsetTranslation(); |
| context.absolute_position.paint_offset = LayoutPoint(); |
| context.fixed_position.paint_offset = LayoutPoint(); |
| } |
| } |
| +static bool NeedsPaintPropertiesForNonRootSVG(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 |
| // creating a transform node for SVG-specific transforms without 3D. |
| void PaintPropertyTreeBuilder::UpdateTransformForNonRootSVG( |
| @@ -289,13 +310,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 (NeedsPaintPropertiesForNonRootSVG(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 +364,14 @@ static FloatPoint3D TransformOrigin(const LayoutBox& box) { |
| style.TransformOriginZ()); |
| } |
| +static bool NeedsPaintPropertiesForTransform(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 +387,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 (NeedsPaintPropertiesForTransform(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,6 +479,46 @@ static bool ComputeMaskParameters(IntRect& mask_clip, |
| return true; |
| } |
| +static bool NeedsPaintPropertiesForEffect(const LayoutObject& object) { |
|
pdr.
2017/04/20 22:56:28
Do we need to include the "!is_css_isolated_group
chrishtr
2017/04/21 01:20:02
Ah good catch. Added, and simplified UpdateEffect.
|
| + 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; |
| + } |
| + } |
| + |
| + const ComputedStyle& style = object.StyleRef(); |
| + |
| + 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() && |
| + SVGResourcesCache::CachedResourcesForLayoutObject(&object)) |
| + return true; |
| + |
| + if (object.StyleRef().HasMask()) |
| + return true; |
| + |
| + return false; |
| +} |
| + |
| void PaintPropertyTreeBuilder::UpdateEffect( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| @@ -484,74 +542,55 @@ void PaintPropertyTreeBuilder::UpdateEffect( |
| const ClipPaintPropertyNode* output_clip = |
| context.input_clip_of_current_effect; |
| - bool effect_node_needed = false; |
| + if (NeedsPaintPropertiesForEffect(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. |
| @@ -584,66 +623,70 @@ void PaintPropertyTreeBuilder::UpdateEffect( |
| } |
| } |
| +static bool NeedsPaintPropertiesForFilter(const LayoutObject& object) { |
| + // TODO(trchen): SVG caches filters in SVGResources. Implement it. |
| + return object.IsBoxModelObject() && object.StyleRef().HasFilter() && |
| + ToLayoutBoxModelObject(object).Layer(); |
| +} |
| + |
| 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 (NeedsPaintPropertiesForFilter(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 +702,15 @@ void PaintPropertyTreeBuilder::UpdateFilter( |
| } |
| } |
| +static bool NeedsPaintPropertiesForCssClip(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 (NeedsPaintPropertiesForCssClip(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 +718,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 +751,17 @@ void PaintPropertyTreeBuilder::UpdateLocalBorderBoxContext( |
| } |
| } |
| +static bool NeedsPaintPropertiesForScrollbarPaintOffset( |
| + 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 +769,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 (NeedsPaintPropertiesForScrollbarPaintOffset(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 NeedsPaintPropertiesForOverflowScroll(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 |
|
pdr.
2017/04/20 22:56:28
This comment was dropped. Is it wrong?
chrishtr
2017/04/21 01:20:02
It was obsolete, because control clips have subseq
|
| - // 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 (NeedsPaintPropertiesForOverflowScroll(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 +820,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 +838,16 @@ static FloatPoint PerspectiveOrigin(const LayoutBox& box) { |
| border_box_size.Height())); |
| } |
| +static bool NeedsPaintPropertiesForPerspective(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 (NeedsPaintPropertiesForPerspective(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 +855,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 +873,11 @@ void PaintPropertyTreeBuilder::UpdatePerspective( |
| } |
| } |
| +static bool NeedsPaintPropertiesForSVGLocalToBorderBoxTransform( |
| + const LayoutObject& object) { |
| + return object.IsSVGRoot(); |
| +} |
| + |
| void PaintPropertyTreeBuilder::UpdateSvgLocalToBorderBoxTransform( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| @@ -832,8 +888,8 @@ 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 (NeedsPaintPropertiesForSVGLocalToBorderBoxTransform(object)) { |
| + auto& properties = *object.GetMutableForPainting().PaintProperties(); |
| context.force_subtree_update |= |
| properties.UpdateSvgLocalToBorderBoxTransform( |
| context.current.transform, transform_to_border_box, |
| @@ -870,59 +926,58 @@ static MainThreadScrollingReasons GetMainThreadScrollingReasons( |
| ancestor_reasons); |
| } |
| +static bool NeedsPaintPropertiesForScroll(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 (NeedsPaintPropertiesForScroll(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); |
| - bool scroll_node_needed_for_main_thread_reasons = |
| - ancestor_reasons != reasons; |
| - const LayoutBox& box = ToLayoutBox(object); |
| - auto* scrollable_area = box.GetScrollableArea(); |
| - IntSize scroll_offset = box.ScrolledContentOffset(); |
| - if (scroll_node_needed_for_main_thread_reasons || |
| - !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(); |
| @@ -937,6 +992,12 @@ void PaintPropertyTreeBuilder::UpdateScrollAndScrollTranslation( |
| } |
| } |
| +static bool NeedsPaintPropertiesForCssClipFixedPosition( |
| + const LayoutObject& object) { |
| + return !object.IsLayoutView() && !object.CanContainFixedPositionObjects() && |
| + NeedsPaintPropertiesForCssClip(object); |
| +} |
| + |
| void PaintPropertyTreeBuilder::UpdateOutOfFlowContext( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| @@ -963,14 +1024,15 @@ void PaintPropertyTreeBuilder::UpdateOutOfFlowContext( |
| context.fixed_position = context.current; |
| } else if (object.GetMutableForPainting().PaintProperties() && |
| object.PaintProperties()->CssClip()) { |
| + CHECK(NeedsPaintPropertiesForCssClipFixedPosition(object)); |
| // CSS clip applies to all descendants, even if this object is not a |
| // containing block ancestor of the descendant. It is okay for |
| // absolute-position descendants because having CSS clip implies being |
| // 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. |
| @@ -978,17 +1040,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; |
| } |
| } |
| @@ -1111,6 +1170,26 @@ void PaintPropertyTreeBuilder::UpdateForObjectLocationAndSize( |
| box.GetMutableForPainting().SetNeedsPaintPropertyUpdate(); |
| } |
| +void PaintPropertyTreeBuilder::UpdatePaintProperties( |
| + const LayoutObject& object) { |
| + if (NeedsPaintPropertiesForPaintOffsetTranslation(object) || |
| + NeedsPaintPropertiesForTransform(object) || |
| + NeedsPaintPropertiesForEffect(object) || |
| + NeedsPaintPropertiesForNonRootSVG(object) || |
| + NeedsPaintPropertiesForFilter(object) || |
| + NeedsPaintPropertiesForFilter(object) || |
| + NeedsPaintPropertiesForCssClip(object) || |
| + NeedsPaintPropertiesForScrollbarPaintOffset(object) || |
| + NeedsPaintPropertiesForOverflowScroll(object) || |
| + NeedsPaintPropertiesForPerspective(object) || |
| + NeedsPaintPropertiesForSVGLocalToBorderBoxTransform(object) || |
| + NeedsPaintPropertiesForScroll(object) || |
| + NeedsPaintPropertiesForCssClipFixedPosition(object)) |
| + object.GetMutableForPainting().EnsurePaintProperties(); |
| + else |
| + object.GetMutableForPainting().ClearPaintProperties(); |
| +} |
| + |
| void PaintPropertyTreeBuilder::UpdatePropertiesForSelf( |
| const LayoutObject& object, |
| PaintPropertyTreeBuilderContext& context) { |
| @@ -1121,6 +1200,8 @@ void PaintPropertyTreeBuilder::UpdatePropertiesForSelf( |
| context = PaintPropertyTreeBuilderContext(); |
| } |
| + UpdatePaintProperties(object); |
| + |
| // This is not in FindObjectPropertiesNeedingUpdateScope because paint offset |
| // can change without needsPaintPropertyUpdate. |
| UpdateForObjectLocationAndSize(object, context); |