Commit 6e2f6b1d authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Refactor computation of stroke bounds in LayoutSVGShape

Move all stroke bounds related computations into the
CalculateStrokeBoundingBox() method in LayoutSVGShape. Add a new enum
StrokeGeometryClass, and pass that as an argument to the method.
Currently all callsites use a constant argument value. This will be
modified in a future CL.

Split out computation of the bounds for non-scaling-stroke into a new
method CalculateNonScalingStrokeBoundingBox().

Also fold LayoutSVGShape::CalculateObjectBoundingBox() since it only has
a single caller.

Bug: 435097
Change-Id: I538b31f98dc7f0777e2538ef74b5e3553b435a7f
Reviewed-on: https://chromium-review.googlesource.com/c/1276770
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#600733}
parent 389ae87f
...@@ -74,9 +74,7 @@ void LayoutSVGEllipse::UpdateShapeFromElement() { ...@@ -74,9 +74,7 @@ void LayoutSVGEllipse::UpdateShapeFromElement() {
ClearPath(); ClearPath();
fill_bounding_box_ = FloatRect(center_ - radii_, radii_.ScaledBy(2)); fill_bounding_box_ = FloatRect(center_ - radii_, radii_.ScaledBy(2));
stroke_bounding_box_ = fill_bounding_box_; stroke_bounding_box_ = CalculateStrokeBoundingBox(kSimple);
if (StyleRef().SvgStyle().HasStroke())
stroke_bounding_box_.Inflate(StrokeWidth() / 2);
} }
void LayoutSVGEllipse::CalculateRadiiAndCenter() { void LayoutSVGEllipse::CalculateRadiiAndCenter() {
......
...@@ -57,7 +57,7 @@ void LayoutSVGPath::UpdateShapeFromElement() { ...@@ -57,7 +57,7 @@ void LayoutSVGPath::UpdateShapeFromElement() {
FloatRect LayoutSVGPath::HitTestStrokeBoundingBox() const { FloatRect LayoutSVGPath::HitTestStrokeBoundingBox() const {
if (StyleRef().SvgStyle().HasStroke()) if (StyleRef().SvgStyle().HasStroke())
return stroke_bounding_box_; return stroke_bounding_box_;
return ApproximateStrokeBoundingBox(fill_bounding_box_); return ApproximateStrokeBoundingBox(fill_bounding_box_, kComplex);
} }
void LayoutSVGPath::UpdateMarkers() { void LayoutSVGPath::UpdateMarkers() {
......
...@@ -79,9 +79,7 @@ void LayoutSVGRect::UpdateShapeFromElement() { ...@@ -79,9 +79,7 @@ void LayoutSVGRect::UpdateShapeFromElement() {
fill_bounding_box_ = FloatRect( fill_bounding_box_ = FloatRect(
length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style), length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
bounding_box_size); bounding_box_size);
stroke_bounding_box_ = fill_bounding_box_; stroke_bounding_box_ = CalculateStrokeBoundingBox(kSimple);
if (svg_style.HasStroke())
stroke_bounding_box_.Inflate(StrokeWidth() / 2);
} }
bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) { bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) {
......
...@@ -87,7 +87,7 @@ float LayoutSVGShape::DashScaleFactor() const { ...@@ -87,7 +87,7 @@ float LayoutSVGShape::DashScaleFactor() const {
void LayoutSVGShape::UpdateShapeFromElement() { void LayoutSVGShape::UpdateShapeFromElement() {
CreatePath(); CreatePath();
fill_bounding_box_ = CalculateObjectBoundingBox(); fill_bounding_box_ = GetPath().BoundingRect();
if (HasNonScalingStroke()) { if (HasNonScalingStroke()) {
// NonScalingStrokeTransform may depend on LocalTransform which in turn may // NonScalingStrokeTransform may depend on LocalTransform which in turn may
...@@ -96,7 +96,7 @@ void LayoutSVGShape::UpdateShapeFromElement() { ...@@ -96,7 +96,7 @@ void LayoutSVGShape::UpdateShapeFromElement() {
UpdateNonScalingStrokeData(); UpdateNonScalingStrokeData();
} }
stroke_bounding_box_ = CalculateStrokeBoundingBox(); stroke_bounding_box_ = CalculateStrokeBoundingBox(kComplex);
} }
namespace { namespace {
...@@ -111,7 +111,8 @@ bool HasSquareCapStyle(const SVGComputedStyle& svg_style) { ...@@ -111,7 +111,8 @@ bool HasSquareCapStyle(const SVGComputedStyle& svg_style) {
} // namespace } // namespace
FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox( FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
const FloatRect& shape_bbox) const { const FloatRect& shape_bbox,
StrokeGeometryClass geometry_class) const {
FloatRect stroke_box = shape_bbox; FloatRect stroke_box = shape_bbox;
// Implementation of // Implementation of
...@@ -122,18 +123,19 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox( ...@@ -122,18 +123,19 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
if (stroke_width <= 0) if (stroke_width <= 0)
return stroke_box; return stroke_box;
const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
float delta = stroke_width / 2; float delta = stroke_width / 2;
if (affected_by_miter_ && HasMiterJoinStyle(svg_style)) { if (geometry_class != kSimple) {
const float miter = svg_style.StrokeMiterLimit(); const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
if (miter < M_SQRT2 && HasSquareCapStyle(svg_style)) if (affected_by_miter_ && HasMiterJoinStyle(svg_style)) {
const float miter = svg_style.StrokeMiterLimit();
if (miter < M_SQRT2 && HasSquareCapStyle(svg_style))
delta *= M_SQRT2;
else
delta *= std::max(miter, 1.0f);
} else if (HasSquareCapStyle(svg_style)) {
delta *= M_SQRT2; delta *= M_SQRT2;
else }
delta *= std::max(miter, 1.0f);
} else if (HasSquareCapStyle(svg_style)) {
delta *= M_SQRT2;
} }
stroke_box.Inflate(delta); stroke_box.Inflate(delta);
return stroke_box; return stroke_box;
} }
...@@ -141,17 +143,7 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox( ...@@ -141,17 +143,7 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const { FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
if (StyleRef().SvgStyle().HasStroke()) if (StyleRef().SvgStyle().HasStroke())
return stroke_bounding_box_; return stroke_bounding_box_;
return ApproximateStrokeBoundingBox(fill_bounding_box_, kSimple);
// Implementation of
// https://drafts.fxtf.org/css-masking/#compute-stroke-bounding-box
// for the <rect> / <ellipse> / <circle> case except that we ignore whether
// the stroke is none.
// TODO(fs): Fold this into ApproximateStrokeBoundingBox.
FloatRect box = fill_bounding_box_;
const float stroke_width = StrokeWidth();
box.Inflate(stroke_width / 2);
return box;
} }
bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) { bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) {
...@@ -407,33 +399,34 @@ bool LayoutSVGShape::NodeAtPointInternal(const HitTestRequest& request, ...@@ -407,33 +399,34 @@ bool LayoutSVGShape::NodeAtPointInternal(const HitTestRequest& request,
return false; return false;
} }
FloatRect LayoutSVGShape::CalculateObjectBoundingBox() const { FloatRect LayoutSVGShape::CalculateStrokeBoundingBox(
return GetPath().BoundingRect(); StrokeGeometryClass geometry_class) const {
if (!StyleRef().SvgStyle().HasStroke() || IsShapeEmpty())
return fill_bounding_box_;
if (HasNonScalingStroke())
return CalculateNonScalingStrokeBoundingBox();
return ApproximateStrokeBoundingBox(fill_bounding_box_, geometry_class);
} }
FloatRect LayoutSVGShape::CalculateStrokeBoundingBox() const { FloatRect LayoutSVGShape::CalculateNonScalingStrokeBoundingBox() const {
DCHECK(path_); DCHECK(path_);
FloatRect stroke_bounding_box = fill_bounding_box_; DCHECK(StyleRef().SvgStyle().HasStroke());
DCHECK(HasNonScalingStroke());
if (StyleRef().SvgStyle().HasStroke()) { StrokeData stroke_data;
StrokeData stroke_data; SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(), *this,
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(), DashScaleFactor());
*this, DashScaleFactor());
if (HasNonScalingStroke()) {
const auto& non_scaling_transform = NonScalingStrokeTransform();
if (non_scaling_transform.IsInvertible()) {
const auto& non_scaling_stroke = NonScalingStrokePath();
FloatRect stroke_bounding_rect =
non_scaling_stroke.StrokeBoundingRect(stroke_data);
stroke_bounding_rect =
non_scaling_transform.Inverse().MapRect(stroke_bounding_rect);
stroke_bounding_box.Unite(stroke_bounding_rect);
}
} else {
stroke_bounding_box = ApproximateStrokeBoundingBox(stroke_bounding_box);
}
}
FloatRect stroke_bounding_box = fill_bounding_box_;
const auto& non_scaling_transform = NonScalingStrokeTransform();
if (non_scaling_transform.IsInvertible()) {
const auto& non_scaling_stroke = NonScalingStrokePath();
FloatRect stroke_bounding_rect =
non_scaling_stroke.StrokeBoundingRect(stroke_data);
stroke_bounding_rect =
non_scaling_transform.Inverse().MapRect(stroke_bounding_rect);
stroke_bounding_box.Unite(stroke_bounding_rect);
}
return stroke_bounding_box; return stroke_bounding_box;
} }
......
...@@ -134,13 +134,24 @@ class LayoutSVGShape : public LayoutSVGModelObject { ...@@ -134,13 +134,24 @@ class LayoutSVGShape : public LayoutSVGModelObject {
virtual bool ShapeDependentFillContains(const FloatPoint&, virtual bool ShapeDependentFillContains(const FloatPoint&,
const WindRule) const; const WindRule) const;
// Description of the geometry of the shape for stroking.
enum StrokeGeometryClass {
kComplex, // We don't know anything about the geometry => use the generic
// approximation.
kSimple, // We know that the geometry is convex and has no acute angles
// (rect, rounded rect, circle, ellipse) => use the simple
// approximation.
};
// Compute an approximation of the bounding box that this stroke geometry // Compute an approximation of the bounding box that this stroke geometry
// would generate when applied to a shape with the (tight-fitting) bounding // would generate when applied to a shape with the (tight-fitting) bounding
// box |shape_bbox|. // box |shape_bbox|.
FloatRect ApproximateStrokeBoundingBox(const FloatRect& shape_bbox) const; FloatRect ApproximateStrokeBoundingBox(const FloatRect& shape_bbox,
StrokeGeometryClass) const;
FloatRect CalculateStrokeBoundingBox(StrokeGeometryClass) const;
FloatRect fill_bounding_box_; FloatRect fill_bounding_box_;
FloatRect stroke_bounding_box_; FloatRect stroke_bounding_box_;
LayoutSVGShapeRareData& EnsureRareData() const; LayoutSVGShapeRareData& EnsureRareData() const;
private: private:
...@@ -163,8 +174,7 @@ class LayoutSVGShape : public LayoutSVGModelObject { ...@@ -163,8 +174,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
HitTestAction) override; HitTestAction) override;
FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; } FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
FloatRect CalculateObjectBoundingBox() const; FloatRect CalculateNonScalingStrokeBoundingBox() const;
FloatRect CalculateStrokeBoundingBox() const;
void UpdateNonScalingStrokeData(); void UpdateNonScalingStrokeData();
bool UpdateLocalTransform(); bool UpdateLocalTransform();
......
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