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 #ifndef SVGMarkerData_h 21 #define SVGMarkerData_h 22 23 #include "platform/FloatConversion.h" 24 #include "platform/graphics/Path.h" 25 #include "wtf/MathExtras.h" 26 27 namespace WebCore { 28 29 class RenderSVGResourceMarker; 30 31 enum SVGMarkerType { 32 StartMarker, 33 MidMarker, 34 EndMarker 35 }; 36 37 struct MarkerPosition { 38 MarkerPosition(SVGMarkerType useType, const FloatPoint& useOrigin, float useAngle) 39 : type(useType) 40 , origin(useOrigin) 41 , angle(useAngle) 42 { 43 } 44 45 SVGMarkerType type; 46 FloatPoint origin; 47 float angle; 48 }; 49 50 class SVGMarkerData { 51 public: 52 SVGMarkerData(Vector<MarkerPosition>& positions) 53 : m_positions(positions) 54 , m_elementIndex(0) 55 { 56 } 57 58 static void updateFromPathElement(void* info, const PathElement* element) 59 { 60 SVGMarkerData* markerData = static_cast<SVGMarkerData*>(info); 61 62 // First update the outslope for the previous element. 63 markerData->updateOutslope(element->points[0]); 64 65 // Record the marker for the previous element. 66 if (markerData->m_elementIndex > 0) { 67 SVGMarkerType markerType = markerData->m_elementIndex == 1 ? StartMarker : MidMarker; 68 markerData->m_positions.append(MarkerPosition(markerType, markerData->m_origin, markerData->currentAngle(markerType))); 69 } 70 71 // Update our marker data for this element. 72 markerData->updateMarkerDataForPathElement(element); 73 ++markerData->m_elementIndex; 74 } 75 76 void pathIsDone() 77 { 78 m_positions.append(MarkerPosition(EndMarker, m_origin, currentAngle(EndMarker))); 79 } 80 81 private: 82 float currentAngle(SVGMarkerType type) const 83 { 84 // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement 85 FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]); 86 FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]); 87 88 double inAngle = rad2deg(inSlope.slopeAngleRadians()); 89 double outAngle = rad2deg(outSlope.slopeAngleRadians()); 90 91 switch (type) { 92 case StartMarker: 93 return narrowPrecisionToFloat(outAngle); 94 case MidMarker: 95 // WK193015: Prevent bugs due to angles being non-continuous. 96 if (fabs(inAngle - outAngle) > 180) 97 inAngle += 360; 98 return narrowPrecisionToFloat((inAngle + outAngle) / 2); 99 case EndMarker: 100 return narrowPrecisionToFloat(inAngle); 101 } 102 103 ASSERT_NOT_REACHED(); 104 return 0; 105 } 106 107 void updateOutslope(const FloatPoint& point) 108 { 109 m_outslopePoints[0] = m_origin; 110 m_outslopePoints[1] = point; 111 } 112 113 void updateMarkerDataForPathElement(const PathElement* element) 114 { 115 FloatPoint* points = element->points; 116 117 switch (element->type) { 118 case PathElementAddQuadCurveToPoint: 119 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) 120 m_origin = points[1]; 121 break; 122 case PathElementAddCurveToPoint: 123 m_inslopePoints[0] = points[1]; 124 m_inslopePoints[1] = points[2]; 125 m_origin = points[2]; 126 break; 127 case PathElementMoveToPoint: 128 m_subpathStart = points[0]; 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 }; 153 154 } 155 156 #endif // SVGMarkerData_h 157