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#if ENABLE(SVG) 24#include "FloatConversion.h" 25#include "Path.h" 26#include <wtf/MathExtras.h> 27 28namespace WebCore { 29 30class RenderSVGResourceMarker; 31 32enum SVGMarkerType { 33 StartMarker, 34 MidMarker, 35 EndMarker 36}; 37 38struct MarkerPosition { 39 MarkerPosition(SVGMarkerType useType, const FloatPoint& useOrigin, float useAngle) 40 : type(useType) 41 , origin(useOrigin) 42 , angle(useAngle) 43 { 44 } 45 46 SVGMarkerType type; 47 FloatPoint origin; 48 float angle; 49}; 50 51class SVGMarkerData { 52public: 53 SVGMarkerData(Vector<MarkerPosition>& positions) 54 : m_positions(positions) 55 , m_elementIndex(0) 56 { 57 } 58 59 static void updateFromPathElement(void* info, const PathElement* element) 60 { 61 SVGMarkerData* markerData = static_cast<SVGMarkerData*>(info); 62 63 // First update the outslope for the previous element. 64 markerData->updateOutslope(element->points[0]); 65 66 // Record the marker for the previous element. 67 if (markerData->m_elementIndex > 0) { 68 SVGMarkerType markerType = markerData->m_elementIndex == 1 ? StartMarker : MidMarker; 69 markerData->m_positions.append(MarkerPosition(markerType, markerData->m_origin, markerData->currentAngle(markerType))); 70 } 71 72 // Update our marker data for this element. 73 markerData->updateMarkerDataForPathElement(element); 74 ++markerData->m_elementIndex; 75 } 76 77 void pathIsDone() 78 { 79 m_positions.append(MarkerPosition(EndMarker, m_origin, currentAngle(EndMarker))); 80 } 81 82private: 83 float currentAngle(SVGMarkerType type) const 84 { 85 // For details of this calculation, see: http://www.w3.org/TR/SVG/single-page.html#painting-MarkerElement 86 FloatPoint inSlope(m_inslopePoints[1] - m_inslopePoints[0]); 87 FloatPoint outSlope(m_outslopePoints[1] - m_outslopePoints[0]); 88 89 double inAngle = rad2deg(inSlope.slopeAngleRadians()); 90 double outAngle = rad2deg(outSlope.slopeAngleRadians()); 91 92 switch (type) { 93 case StartMarker: 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}; 154 155} 156 157#endif // ENABLE(SVG) 158#endif // SVGMarkerData_h 159