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 enum SVGMarkerType { 30 StartMarker, 31 MidMarker, 32 EndMarker 33 }; 34 35 struct MarkerPosition { MarkerPositionMarkerPosition36 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 48 class SVGMarkerData { 49 public: SVGMarkerData(Vector<MarkerPosition> & positions)50 SVGMarkerData(Vector<MarkerPosition>& positions) 51 : m_positions(positions) 52 , m_elementIndex(0) 53 { 54 } 55 updateFromPathElement(void * info,const PathElement * element)56 static void updateFromPathElement(void* info, const PathElement* element) 57 { 58 SVGMarkerData* markerData = static_cast<SVGMarkerData*>(info); 59 60 // First update the outslope for the previous element. 61 markerData->updateOutslope(element->points[0]); 62 63 // Record the marker for the previous element. 64 if (markerData->m_elementIndex > 0) { 65 SVGMarkerType markerType = markerData->m_elementIndex == 1 ? StartMarker : MidMarker; 66 markerData->m_positions.append(MarkerPosition(markerType, markerData->m_origin, markerData->currentAngle(markerType))); 67 } 68 69 // Update our marker data for this element. 70 markerData->updateMarkerDataForPathElement(element); 71 ++markerData->m_elementIndex; 72 } 73 pathIsDone()74 void pathIsDone() 75 { 76 m_positions.append(MarkerPosition(EndMarker, m_origin, currentAngle(EndMarker))); 77 } 78 79 private: currentAngle(SVGMarkerType type)80 float currentAngle(SVGMarkerType type) const 81 { 82 // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement 83 FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]); 84 FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]); 85 86 double inAngle = rad2deg(inSlope.slopeAngleRadians()); 87 double outAngle = rad2deg(outSlope.slopeAngleRadians()); 88 89 switch (type) { 90 case StartMarker: 91 return narrowPrecisionToFloat(outAngle); 92 case MidMarker: 93 // WK193015: Prevent bugs due to angles being non-continuous. 94 if (fabs(inAngle - outAngle) > 180) 95 inAngle += 360; 96 return narrowPrecisionToFloat((inAngle + outAngle) / 2); 97 case EndMarker: 98 return narrowPrecisionToFloat(inAngle); 99 } 100 101 ASSERT_NOT_REACHED(); 102 return 0; 103 } 104 updateOutslope(const FloatPoint & point)105 void updateOutslope(const FloatPoint& point) 106 { 107 m_outslopePoints[0] = m_origin; 108 m_outslopePoints[1] = point; 109 } 110 updateMarkerDataForPathElement(const PathElement * element)111 void updateMarkerDataForPathElement(const PathElement* element) 112 { 113 FloatPoint* points = element->points; 114 115 switch (element->type) { 116 case PathElementAddQuadCurveToPoint: 117 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=33115 (PathElementAddQuadCurveToPoint not handled for <marker>) 118 m_origin = points[1]; 119 break; 120 case PathElementAddCurveToPoint: 121 m_inslopePoints[0] = points[1]; 122 m_inslopePoints[1] = points[2]; 123 m_origin = points[2]; 124 break; 125 case PathElementMoveToPoint: 126 m_subpathStart = points[0]; 127 case PathElementAddLineToPoint: 128 updateInslope(points[0]); 129 m_origin = points[0]; 130 break; 131 case PathElementCloseSubpath: 132 updateInslope(points[0]); 133 m_origin = m_subpathStart; 134 m_subpathStart = FloatPoint(); 135 } 136 } 137 updateInslope(const FloatPoint & point)138 void updateInslope(const FloatPoint& point) 139 { 140 m_inslopePoints[0] = m_origin; 141 m_inslopePoints[1] = point; 142 } 143 144 Vector<MarkerPosition>& m_positions; 145 unsigned m_elementIndex; 146 FloatPoint m_origin; 147 FloatPoint m_subpathStart; 148 FloatPoint m_inslopePoints[2]; 149 FloatPoint m_outslopePoints[2]; 150 }; 151 152 } 153 154 #endif // SVGMarkerData_h 155