Commit ad2a6976 authored by Fredrik Söderqvist's avatar Fredrik Söderqvist Committed by Commit Bot

Rework CullRect handling in SVG painters

Hoist the actual CullRect intersection test into the actual painter and
only share the 'can use cull rect' test. This allows moving the check
for hidden containers into a more appropriate place thus avoid checking
for them when they are guaranteed not to exist. Is also avoids calling
ShouldUseInfiniteCullRect() twice in SVGContainerPainter.

Align SVGImagePainter to SVGShapePainter by using LocalSVGTransform()
rather than LocalToSVGParentTransform() since they are both 'leaves'.

Bug: 109224
Change-Id: I92af163bb8d82a22c37f2cb58911240c07e6402b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2431929Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#811623}
parent e710cb36
...@@ -69,6 +69,11 @@ class LayoutSVGImage final : public LayoutSVGModelObject { ...@@ -69,6 +69,11 @@ class LayoutSVGImage final : public LayoutSVGModelObject {
LayoutSVGModelObject::IsOfType(type); LayoutSVGModelObject::IsOfType(type);
} }
AffineTransform LocalSVGTransform() const override {
NOT_DESTROYED();
return local_transform_;
}
const char* GetName() const override { const char* GetName() const override {
NOT_DESTROYED(); NOT_DESTROYED();
return "LayoutSVGImage"; return "LayoutSVGImage";
...@@ -96,11 +101,6 @@ class LayoutSVGImage final : public LayoutSVGModelObject { ...@@ -96,11 +101,6 @@ class LayoutSVGImage final : public LayoutSVGModelObject {
const PhysicalOffset& accumulated_offset, const PhysicalOffset& accumulated_offset,
HitTestAction) override; HitTestAction) override;
AffineTransform LocalSVGTransform() const override {
NOT_DESTROYED();
return local_transform_;
}
FloatSize CalculateObjectSize() const; FloatSize CalculateObjectSize() const;
bool HasOverriddenIntrinsicSize() const; bool HasOverriddenIntrinsicSize() const;
......
...@@ -28,6 +28,15 @@ bool HasReferenceFilterEffect(const ObjectPaintProperties& properties) { ...@@ -28,6 +28,15 @@ bool HasReferenceFilterEffect(const ObjectPaintProperties& properties) {
} // namespace } // namespace
bool SVGContainerPainter::CanUseCullRect() const {
// LayoutSVGHiddenContainer's visual rect is always empty but we need to
// paint its descendants so we cannot skip painting.
if (layout_svg_container_.IsSVGHiddenContainer())
return false;
return SVGModelObjectPainter::CanUseCullRect(
layout_svg_container_.StyleRef());
}
void SVGContainerPainter::Paint(const PaintInfo& paint_info) { void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
// Spec: An empty viewBox on the <svg> element disables rendering. // Spec: An empty viewBox on the <svg> element disables rendering.
DCHECK(layout_svg_container_.GetElement()); DCHECK(layout_svg_container_.GetElement());
...@@ -36,20 +45,20 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) { ...@@ -36,20 +45,20 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
if (svg_svg_element && svg_svg_element->HasEmptyViewBox()) if (svg_svg_element && svg_svg_element->HasEmptyViewBox())
return; return;
if (SVGModelObjectPainter(layout_svg_container_)
.CullRectSkipsPainting(paint_info)) {
return;
}
const auto* properties = const auto* properties =
layout_svg_container_.FirstFragment().PaintProperties(); layout_svg_container_.FirstFragment().PaintProperties();
PaintInfo paint_info_before_filtering(paint_info); PaintInfo paint_info_before_filtering(paint_info);
if (SVGModelObjectPainter::ShouldUseInfiniteCullRect( if (CanUseCullRect()) {
layout_svg_container_.StyleRef())) { if (!paint_info.GetCullRect().IntersectsTransformed(
layout_svg_container_.LocalToSVGParentTransform(),
layout_svg_container_.VisualRectInLocalSVGCoordinates()))
return;
if (properties) {
if (const auto* transform = properties->Transform())
paint_info_before_filtering.TransformCullRect(*transform);
}
} else {
paint_info_before_filtering.ApplyInfiniteCullRect(); paint_info_before_filtering.ApplyInfiniteCullRect();
} else if (properties) {
if (const auto* transform = properties->Transform())
paint_info_before_filtering.TransformCullRect(*transform);
} }
ScopedSVGTransformState transform_state( ScopedSVGTransformState transform_state(
......
...@@ -22,6 +22,8 @@ class SVGContainerPainter { ...@@ -22,6 +22,8 @@ class SVGContainerPainter {
void Paint(const PaintInfo&); void Paint(const PaintInfo&);
private: private:
bool CanUseCullRect() const;
const LayoutSVGContainer& layout_svg_container_; const LayoutSVGContainer& layout_svg_container_;
}; };
......
...@@ -31,15 +31,16 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) { ...@@ -31,15 +31,16 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
!layout_svg_image_.ImageResource()->HasImage()) !layout_svg_image_.ImageResource()->HasImage())
return; return;
if (SVGModelObjectPainter(layout_svg_image_) if (SVGModelObjectPainter::CanUseCullRect(layout_svg_image_.StyleRef())) {
.CullRectSkipsPainting(paint_info)) { if (!paint_info.GetCullRect().IntersectsTransformed(
return; layout_svg_image_.LocalSVGTransform(),
layout_svg_image_.VisualRectInLocalSVGCoordinates()))
return;
} }
// Images cannot have children so do not call TransformCullRect. // Images cannot have children so do not call TransformCullRect.
ScopedSVGTransformState transform_state( ScopedSVGTransformState transform_state(
paint_info, layout_svg_image_, paint_info, layout_svg_image_, layout_svg_image_.LocalSVGTransform());
layout_svg_image_.LocalToSVGParentTransform());
{ {
ScopedSVGPaintState paint_state(layout_svg_image_, paint_info); ScopedSVGPaintState paint_state(layout_svg_image_, paint_info);
if (paint_state.ApplyEffects() && if (paint_state.ApplyEffects() &&
......
...@@ -11,33 +11,18 @@ ...@@ -11,33 +11,18 @@
namespace blink { namespace blink {
bool SVGModelObjectPainter::ShouldUseInfiniteCullRect( bool SVGModelObjectPainter::CanUseCullRect(const ComputedStyle& style) {
const ComputedStyle& style) {
// We do not apply cull rect optimizations across transforms for two reasons: // We do not apply cull rect optimizations across transforms for two reasons:
// 1) Performance: We can optimize transform changes by not repainting. // 1) Performance: We can optimize transform changes by not repainting.
// 2) Complexity: Difficulty updating clips when ancestor transforms change. // 2) Complexity: Difficulty updating clips when ancestor transforms change.
// For these reasons, we do not cull painting if there is a transform. // For these reasons, we do not cull painting if there is a transform.
if (style.HasTransform()) if (style.HasTransform())
return true; return false;
// If the filter "moves pixels" we may require input from outside the cull // If the filter "moves pixels" we may require input from outside the cull
// rect. // rect.
if (style.HasFilter() && style.Filter().HasFilterThatMovesPixels()) if (style.HasFilter() && style.Filter().HasFilterThatMovesPixels())
return true;
return false;
}
bool SVGModelObjectPainter::CullRectSkipsPainting(const PaintInfo& paint_info) {
if (ShouldUseInfiniteCullRect(layout_svg_model_object_.StyleRef()))
return false; return false;
return true;
// LayoutSVGHiddenContainer's visual rect is always empty but we need to
// paint its descendants so we cannot skip painting.
if (layout_svg_model_object_.IsSVGHiddenContainer())
return false;
return !paint_info.GetCullRect().IntersectsTransformed(
layout_svg_model_object_.LocalToSVGParentTransform(),
layout_svg_model_object_.VisualRectInLocalSVGCoordinates());
} }
void SVGModelObjectPainter::RecordHitTestData(const LayoutObject& svg_object, void SVGModelObjectPainter::RecordHitTestData(const LayoutObject& svg_object,
......
...@@ -29,12 +29,7 @@ class SVGModelObjectPainter { ...@@ -29,12 +29,7 @@ class SVGModelObjectPainter {
// Should we use an infinite cull rect when painting an object with the // Should we use an infinite cull rect when painting an object with the
// specified style. // specified style.
static bool ShouldUseInfiniteCullRect(const ComputedStyle&); static bool CanUseCullRect(const ComputedStyle&);
// If the object is outside the cull rect, painting can be skipped in most
// cases. An important exception is when there is a transform style: see the
// comment in the implementation.
bool CullRectSkipsPainting(const PaintInfo&);
void PaintOutline(const PaintInfo&); void PaintOutline(const PaintInfo&);
......
...@@ -47,9 +47,11 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) { ...@@ -47,9 +47,11 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
layout_svg_shape_.IsShapeEmpty()) layout_svg_shape_.IsShapeEmpty())
return; return;
if (SVGModelObjectPainter(layout_svg_shape_) if (SVGModelObjectPainter::CanUseCullRect(layout_svg_shape_.StyleRef())) {
.CullRectSkipsPainting(paint_info)) { if (!paint_info.GetCullRect().IntersectsTransformed(
return; layout_svg_shape_.LocalSVGTransform(),
layout_svg_shape_.VisualRectInLocalSVGCoordinates()))
return;
} }
// Shapes cannot have children so do not call TransformCullRect. // Shapes cannot have children so do not call TransformCullRect.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment