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 {
LayoutSVGModelObject::IsOfType(type);
}
AffineTransform LocalSVGTransform() const override {
NOT_DESTROYED();
return local_transform_;
}
const char* GetName() const override {
NOT_DESTROYED();
return "LayoutSVGImage";
......@@ -96,11 +101,6 @@ class LayoutSVGImage final : public LayoutSVGModelObject {
const PhysicalOffset& accumulated_offset,
HitTestAction) override;
AffineTransform LocalSVGTransform() const override {
NOT_DESTROYED();
return local_transform_;
}
FloatSize CalculateObjectSize() const;
bool HasOverriddenIntrinsicSize() const;
......
......@@ -28,6 +28,15 @@ bool HasReferenceFilterEffect(const ObjectPaintProperties& properties) {
} // 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) {
// Spec: An empty viewBox on the <svg> element disables rendering.
DCHECK(layout_svg_container_.GetElement());
......@@ -36,20 +45,20 @@ void SVGContainerPainter::Paint(const PaintInfo& paint_info) {
if (svg_svg_element && svg_svg_element->HasEmptyViewBox())
return;
if (SVGModelObjectPainter(layout_svg_container_)
.CullRectSkipsPainting(paint_info)) {
return;
}
const auto* properties =
layout_svg_container_.FirstFragment().PaintProperties();
PaintInfo paint_info_before_filtering(paint_info);
if (SVGModelObjectPainter::ShouldUseInfiniteCullRect(
layout_svg_container_.StyleRef())) {
if (CanUseCullRect()) {
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();
} else if (properties) {
if (const auto* transform = properties->Transform())
paint_info_before_filtering.TransformCullRect(*transform);
}
ScopedSVGTransformState transform_state(
......
......@@ -22,6 +22,8 @@ class SVGContainerPainter {
void Paint(const PaintInfo&);
private:
bool CanUseCullRect() const;
const LayoutSVGContainer& layout_svg_container_;
};
......
......@@ -31,15 +31,16 @@ void SVGImagePainter::Paint(const PaintInfo& paint_info) {
!layout_svg_image_.ImageResource()->HasImage())
return;
if (SVGModelObjectPainter(layout_svg_image_)
.CullRectSkipsPainting(paint_info)) {
return;
if (SVGModelObjectPainter::CanUseCullRect(layout_svg_image_.StyleRef())) {
if (!paint_info.GetCullRect().IntersectsTransformed(
layout_svg_image_.LocalSVGTransform(),
layout_svg_image_.VisualRectInLocalSVGCoordinates()))
return;
}
// Images cannot have children so do not call TransformCullRect.
ScopedSVGTransformState transform_state(
paint_info, layout_svg_image_,
layout_svg_image_.LocalToSVGParentTransform());
paint_info, layout_svg_image_, layout_svg_image_.LocalSVGTransform());
{
ScopedSVGPaintState paint_state(layout_svg_image_, paint_info);
if (paint_state.ApplyEffects() &&
......
......@@ -11,33 +11,18 @@
namespace blink {
bool SVGModelObjectPainter::ShouldUseInfiniteCullRect(
const ComputedStyle& style) {
bool SVGModelObjectPainter::CanUseCullRect(const ComputedStyle& style) {
// We do not apply cull rect optimizations across transforms for two reasons:
// 1) Performance: We can optimize transform changes by not repainting.
// 2) Complexity: Difficulty updating clips when ancestor transforms change.
// For these reasons, we do not cull painting if there is a transform.
if (style.HasTransform())
return true;
return false;
// If the filter "moves pixels" we may require input from outside the cull
// rect.
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;
// 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());
return true;
}
void SVGModelObjectPainter::RecordHitTestData(const LayoutObject& svg_object,
......
......@@ -29,12 +29,7 @@ class SVGModelObjectPainter {
// Should we use an infinite cull rect when painting an object with the
// specified style.
static bool ShouldUseInfiniteCullRect(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&);
static bool CanUseCullRect(const ComputedStyle&);
void PaintOutline(const PaintInfo&);
......
......@@ -47,9 +47,11 @@ void SVGShapePainter::Paint(const PaintInfo& paint_info) {
layout_svg_shape_.IsShapeEmpty())
return;
if (SVGModelObjectPainter(layout_svg_shape_)
.CullRectSkipsPainting(paint_info)) {
return;
if (SVGModelObjectPainter::CanUseCullRect(layout_svg_shape_.StyleRef())) {
if (!paint_info.GetCullRect().IntersectsTransformed(
layout_svg_shape_.LocalSVGTransform(),
layout_svg_shape_.VisualRectInLocalSVGCoordinates()))
return;
}
// 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