1/*
2 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20#pragma once
21
22#include "FloatConversion.h"
23#include "Path.h"
24
25namespace WebCore {
26
27class RenderSVGResourceMarker;
28
29enum SVGMarkerType {
30 StartMarker,
31 MidMarker,
32 EndMarker
33};
34
35struct MarkerPosition {
36 MarkerPosition(SVGMarkerType useType, const FloatPoint& useOrigin, float useAngle)
37 : type(useType)
38 , origin(useOrigin)
39 , angle(useAngle)
40 {
41 }
42
43 SVGMarkerType type;
44 FloatPoint origin;
45 float angle;
46};
47
48class SVGMarkerData {
49public:
50 SVGMarkerData(Vector<MarkerPosition>& positions, bool reverseStart)
51 : m_positions(positions)
52 , m_elementIndex(0)
53 , m_reverseStart(reverseStart)
54 {
55 }
56
57 static void updateFromPathElement(SVGMarkerData& markerData, const PathElement& element)
58 {
59 // First update the outslope for the previous element.
60 markerData.updateOutslope(element.points[0]);
61
62 // Record the marker for the previous element.
63 if (markerData.m_elementIndex > 0) {
64 SVGMarkerType markerType = markerData.m_elementIndex == 1 ? StartMarker : MidMarker;
65 markerData.m_positions.append(MarkerPosition(markerType, markerData.m_origin, markerData.currentAngle(markerType)));
66 }
67
68 // Update our marker data for this element.
69 markerData.updateMarkerDataForPathElement(element);
70 ++markerData.m_elementIndex;
71 }
72
73 void pathIsDone()
74 {
75 m_positions.append(MarkerPosition(EndMarker, m_origin, currentAngle(EndMarker)));
76 }
77
78private:
79 float currentAngle(SVGMarkerType type) const
80 {
81 // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement
82 FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]);
83 FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]);
84
85 double inAngle = rad2deg(inSlope.slopeAngleRadians());
86 double outAngle = rad2deg(outSlope.slopeAngleRadians());
87
88 switch (type) {
89 case StartMarker:
90 if (m_reverseStart)
91 return narrowPrecisionToFloat(outAngle - 180);
92 return narrowPrecisionToFloat(outAngle);
93 case MidMarker:
94 // WK193015: Prevent bugs due to angles being non-continuous.
95 if (fabs(inAngle - outAngle) > 180)
96 inAngle += 360;
97 return narrowPrecisionToFloat((inAngle + outAngle) / 2);
98 case EndMarker:
99 return narrowPrecisionToFloat(inAngle);
100 }
101
102 ASSERT_NOT_REACHED();
103 return 0;
104 }
105
106 void updateOutslope(const FloatPoint& point)
107 {
108 m_outslopePoints[0] = m_origin;
109 m_outslopePoints[1] = point;
110 }
111
112 void updateMarkerDataForPathElement(const PathElement& element)
113 {
114 FloatPoint* points = element.points;
115
116 switch (element.type) {
117 case PathElementAddQuadCurveToPoint:
118 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>)
119 m_origin = points[1];
120 break;
121 case PathElementAddCurveToPoint:
122 m_inslopePoints[0] = points[1];
123 m_inslopePoints[1] = points[2];
124 m_origin = points[2];
125 break;
126 case PathElementMoveToPoint:
127 m_subpathStart = points[0];
128 FALLTHROUGH;
129 case PathElementAddLineToPoint:
130 updateInslope(points[0]);
131 m_origin = points[0];
132 break;
133 case PathElementCloseSubpath:
134 updateInslope(points[0]);
135 m_origin = m_subpathStart;
136 m_subpathStart = FloatPoint();
137 }
138 }
139
140 void updateInslope(const FloatPoint& point)
141 {
142 m_inslopePoints[0] = m_origin;
143 m_inslopePoints[1] = point;
144 }
145
146 Vector<MarkerPosition>& m_positions;
147 unsigned m_elementIndex;
148 FloatPoint m_origin;
149 FloatPoint m_subpathStart;
150 FloatPoint m_inslopePoints[2];
151 FloatPoint m_outslopePoints[2];
152 bool m_reverseStart;
153};
154
155} // namespace WebCore
156