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