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() {
ClearPath();
fill_bounding_box_ = FloatRect(center_ - radii_, radii_.ScaledBy(2));
stroke_bounding_box_ = fill_bounding_box_;
if (StyleRef().SvgStyle().HasStroke())
stroke_bounding_box_.Inflate(StrokeWidth() / 2);
stroke_bounding_box_ = CalculateStrokeBoundingBox(kSimple);
}
void LayoutSVGEllipse::CalculateRadiiAndCenter() {
......
......@@ -57,7 +57,7 @@ void LayoutSVGPath::UpdateShapeFromElement() {
FloatRect LayoutSVGPath::HitTestStrokeBoundingBox() const {
if (StyleRef().SvgStyle().HasStroke())
return stroke_bounding_box_;
return ApproximateStrokeBoundingBox(fill_bounding_box_);
return ApproximateStrokeBoundingBox(fill_bounding_box_, kComplex);
}
void LayoutSVGPath::UpdateMarkers() {
......
......@@ -79,9 +79,7 @@ void LayoutSVGRect::UpdateShapeFromElement() {
fill_bounding_box_ = FloatRect(
length_context.ResolveLengthPair(svg_style.X(), svg_style.Y(), style),
bounding_box_size);
stroke_bounding_box_ = fill_bounding_box_;
if (svg_style.HasStroke())
stroke_bounding_box_.Inflate(StrokeWidth() / 2);
stroke_bounding_box_ = CalculateStrokeBoundingBox(kSimple);
}
bool LayoutSVGRect::ShapeDependentStrokeContains(const FloatPoint& point) {
......
......@@ -87,7 +87,7 @@ float LayoutSVGShape::DashScaleFactor() const {
void LayoutSVGShape::UpdateShapeFromElement() {
CreatePath();
fill_bounding_box_ = CalculateObjectBoundingBox();
fill_bounding_box_ = GetPath().BoundingRect();
if (HasNonScalingStroke()) {
// NonScalingStrokeTransform may depend on LocalTransform which in turn may
......@@ -96,7 +96,7 @@ void LayoutSVGShape::UpdateShapeFromElement() {
UpdateNonScalingStrokeData();
}
stroke_bounding_box_ = CalculateStrokeBoundingBox();
stroke_bounding_box_ = CalculateStrokeBoundingBox(kComplex);
}
namespace {
......@@ -111,7 +111,8 @@ bool HasSquareCapStyle(const SVGComputedStyle& svg_style) {
} // namespace
FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
const FloatRect& shape_bbox) const {
const FloatRect& shape_bbox,
StrokeGeometryClass geometry_class) const {
FloatRect stroke_box = shape_bbox;
// Implementation of
......@@ -122,18 +123,19 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
if (stroke_width <= 0)
return stroke_box;
const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
float delta = stroke_width / 2;
if (affected_by_miter_ && HasMiterJoinStyle(svg_style)) {
const float miter = svg_style.StrokeMiterLimit();
if (miter < M_SQRT2 && HasSquareCapStyle(svg_style))
if (geometry_class != kSimple) {
const SVGComputedStyle& svg_style = StyleRef().SvgStyle();
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;
else
delta *= std::max(miter, 1.0f);
} else if (HasSquareCapStyle(svg_style)) {
delta *= M_SQRT2;
}
}
stroke_box.Inflate(delta);
return stroke_box;
}
......@@ -141,17 +143,7 @@ FloatRect LayoutSVGShape::ApproximateStrokeBoundingBox(
FloatRect LayoutSVGShape::HitTestStrokeBoundingBox() const {
if (StyleRef().SvgStyle().HasStroke())
return stroke_bounding_box_;
// 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;
return ApproximateStrokeBoundingBox(fill_bounding_box_, kSimple);
}
bool LayoutSVGShape::ShapeDependentStrokeContains(const FloatPoint& point) {
......@@ -407,33 +399,34 @@ bool LayoutSVGShape::NodeAtPointInternal(const HitTestRequest& request,
return false;
}
FloatRect LayoutSVGShape::CalculateObjectBoundingBox() const {
return GetPath().BoundingRect();
FloatRect LayoutSVGShape::CalculateStrokeBoundingBox(
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_);
FloatRect stroke_bounding_box = fill_bounding_box_;
DCHECK(StyleRef().SvgStyle().HasStroke());
DCHECK(HasNonScalingStroke());
if (StyleRef().SvgStyle().HasStroke()) {
StrokeData stroke_data;
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(),
*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);
}
}
StrokeData stroke_data;
SVGLayoutSupport::ApplyStrokeStyleToStrokeData(stroke_data, StyleRef(), *this,
DashScaleFactor());
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;
}
......
......@@ -134,13 +134,24 @@ class LayoutSVGShape : public LayoutSVGModelObject {
virtual bool ShapeDependentFillContains(const FloatPoint&,
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
// would generate when applied to a shape with the (tight-fitting) bounding
// 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 stroke_bounding_box_;
LayoutSVGShapeRareData& EnsureRareData() const;
private:
......@@ -163,8 +174,7 @@ class LayoutSVGShape : public LayoutSVGModelObject {
HitTestAction) override;
FloatRect StrokeBoundingBox() const final { return stroke_bounding_box_; }
FloatRect CalculateObjectBoundingBox() const;
FloatRect CalculateStrokeBoundingBox() const;
FloatRect CalculateNonScalingStrokeBoundingBox() const;
void UpdateNonScalingStrokeData();
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