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

Refactor SVGMarkerData

This CL reworks the core of SVGMarkerData so that it first extracts the
"features" of the current segment/PathElement, and then uses those
features to determine the orientation.

The state of SVGMarkerData is also changed from two pairs of points to
two vectors, since this is the representation that's actually used by
CurrentAngle(). It should also be a better representation when handling
of degenerate curves is added.

CurrentAngle() is changed to return a 'double', and the clamping
previously done in the method is now done by the callers. Additionally
The code that computes the bisected angle is split out to a separate
function.

Bug: 450368
Change-Id: Ic9561cab3bbf9c3f5cbc9f3607cfc9bfe90fea05
Reviewed-on: https://chromium-review.googlesource.com/1193847Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Cr-Commit-Position: refs/heads/master@{#587220}
parent 4e05f182
...@@ -56,8 +56,8 @@ class SVGMarkerData { ...@@ -56,8 +56,8 @@ class SVGMarkerData {
} }
void PathIsDone() { void PathIsDone() {
positions_.push_back( float angle = clampTo<float>(CurrentAngle(kEndMarker));
MarkerPosition(kEndMarker, origin_, CurrentAngle(kEndMarker))); positions_.push_back(MarkerPosition(kEndMarker, origin_, angle));
} }
static inline LayoutSVGResourceMarker* MarkerForType( static inline LayoutSVGResourceMarker* MarkerForType(
...@@ -79,97 +79,104 @@ class SVGMarkerData { ...@@ -79,97 +79,104 @@ class SVGMarkerData {
} }
private: private:
float CurrentAngle(SVGMarkerType type) const { static double BisectingAngle(double in_angle, double out_angle) {
// WK193015: Prevent bugs due to angles being non-continuous.
if (fabs(in_angle - out_angle) > 180)
in_angle += 360;
return (in_angle + out_angle) / 2;
}
double CurrentAngle(SVGMarkerType type) const {
// For details of this calculation, see: // For details of this calculation, see:
// http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement // http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
FloatPoint in_slope(inslope_points_[1] - inslope_points_[0]); double in_angle = rad2deg(FloatPoint(in_slope_).SlopeAngleRadians());
FloatPoint out_slope(outslope_points_[1] - outslope_points_[0]); double out_angle = rad2deg(FloatPoint(out_slope_).SlopeAngleRadians());
double in_angle = rad2deg(in_slope.SlopeAngleRadians());
double out_angle = rad2deg(out_slope.SlopeAngleRadians());
switch (type) { switch (type) {
case kStartMarker: case kStartMarker:
if (auto_start_reverse_) if (auto_start_reverse_)
out_angle += 180; out_angle += 180;
return clampTo<float>(out_angle); return out_angle;
case kMidMarker: case kMidMarker:
// WK193015: Prevent bugs due to angles being non-continuous. return BisectingAngle(in_angle, out_angle);
if (fabs(in_angle - out_angle) > 180)
in_angle += 360;
return clampTo<float>((in_angle + out_angle) / 2);
case kEndMarker: case kEndMarker:
return clampTo<float>(in_angle); return in_angle;
} }
NOTREACHED(); NOTREACHED();
return 0; return 0;
} }
void UpdateOutslope(const PathElement& element) { struct SegmentData {
outslope_points_[0] = origin_; FloatSize start_tangent; // Tangent in the start point of the segment.
FloatPoint point = element.type == kPathElementCloseSubpath FloatSize end_tangent; // Tangent in the end point of the segment.
? subpath_start_ FloatPoint position; // The end point of the segment.
: element.points[0]; };
outslope_points_[1] = point;
SegmentData ExtractPathElementFeatures(const PathElement& element) const {
SegmentData data;
const FloatPoint* points = element.points;
switch (element.type) {
case kPathElementAddCurveToPoint:
data.position = points[2];
data.start_tangent = points[0] - origin_;
data.end_tangent = points[2] - points[1];
break;
case kPathElementAddQuadCurveToPoint:
data.position = points[1];
data.start_tangent = points[0] - origin_;
data.end_tangent = points[1] - points[0];
break;
case kPathElementMoveToPoint:
case kPathElementAddLineToPoint:
data.position = points[0];
data.start_tangent = data.position - origin_;
data.end_tangent = data.position - origin_;
break;
case kPathElementCloseSubpath:
data.position = subpath_start_;
data.start_tangent = data.position - origin_;
data.end_tangent = data.position - origin_;
break;
}
return data;
} }
void UpdateFromPathElement(const PathElement& element) { void UpdateFromPathElement(const PathElement& element) {
// First update the outslope for the previous element. SegmentData segment_data = ExtractPathElementFeatures(element);
UpdateOutslope(element);
// First update the outgoing slope for the previous element.
out_slope_ = segment_data.start_tangent;
// Record the marker for the previous element. // Record the marker for the previous element.
if (element_index_ > 0) { if (element_index_ > 0) {
SVGMarkerType marker_type = SVGMarkerType marker_type =
element_index_ == 1 ? kStartMarker : kMidMarker; element_index_ == 1 ? kStartMarker : kMidMarker;
positions_.push_back( float angle = clampTo<float>(CurrentAngle(marker_type));
MarkerPosition(marker_type, origin_, CurrentAngle(marker_type))); positions_.push_back(MarkerPosition(marker_type, origin_, angle));
} }
// Update our marker data for this element. // Update the incoming slope for this marker position.
UpdateMarkerDataForPathElement(element); in_slope_ = segment_data.end_tangent;
++element_index_;
}
void UpdateMarkerDataForPathElement(const PathElement& element) { // Update marker position.
const FloatPoint* points = element.points; origin_ = segment_data.position;
switch (element.type) { // If this is a 'move to' segment, save the point for use with 'close'.
case kPathElementAddQuadCurveToPoint: if (element.type == kPathElementMoveToPoint)
inslope_points_[0] = points[0]; subpath_start_ = element.points[0];
inslope_points_[1] = points[1]; else if (element.type == kPathElementCloseSubpath)
origin_ = points[1]; subpath_start_ = FloatPoint();
break;
case kPathElementAddCurveToPoint:
inslope_points_[0] = points[1];
inslope_points_[1] = points[2];
origin_ = points[2];
break;
case kPathElementMoveToPoint:
subpath_start_ = points[0];
FALLTHROUGH;
case kPathElementAddLineToPoint:
UpdateInslope(points[0]);
origin_ = points[0];
break;
case kPathElementCloseSubpath:
UpdateInslope(subpath_start_);
origin_ = subpath_start_;
subpath_start_ = FloatPoint();
}
}
void UpdateInslope(const FloatPoint& point) { ++element_index_;
inslope_points_[0] = origin_;
inslope_points_[1] = point;
} }
Vector<MarkerPosition>& positions_; Vector<MarkerPosition>& positions_;
unsigned element_index_; unsigned element_index_;
FloatPoint origin_; FloatPoint origin_;
FloatPoint subpath_start_; FloatPoint subpath_start_;
FloatPoint inslope_points_[2]; FloatSize in_slope_;
FloatPoint outslope_points_[2]; FloatSize out_slope_;
bool auto_start_reverse_; bool auto_start_reverse_;
}; };
......
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