OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2002, 2003 The Karbon Developers | 2 * Copyright (C) 2002, 2003 The Karbon Developers |
3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> | 3 * Copyright (C) 2006 Alexander Kellett <lypanov@kde.org> |
4 * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org> | 4 * Copyright (C) 2006, 2007 Rob Buis <buis@kde.org> |
5 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. | 5 * Copyright (C) 2007, 2009 Apple Inc. All rights reserved. |
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. | 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
(...skipping 29 matching lines...) Expand all Loading... |
40 { | 40 { |
41 // If the path is empty it is still valid, so return true. | 41 // If the path is empty it is still valid, so return true. |
42 if (!m_source->hasMoreData()) | 42 if (!m_source->hasMoreData()) |
43 return true; | 43 return true; |
44 | 44 |
45 SVGPathSegType command = m_source->peekSegmentType(); | 45 SVGPathSegType command = m_source->peekSegmentType(); |
46 // Path must start with moveTo. | 46 // Path must start with moveTo. |
47 return command == PathSegMoveToAbs || command == PathSegMoveToRel; | 47 return command == PathSegMoveToAbs || command == PathSegMoveToRel; |
48 } | 48 } |
49 | 49 |
50 void SVGPathParser::emitMoveToSegment(PathSegmentData& segment) | |
51 { | |
52 if (m_mode == RelativeCoordinates) | |
53 m_currentPoint += segment.targetPoint; | |
54 else | |
55 m_currentPoint = segment.targetPoint; | |
56 m_subPathPoint = m_currentPoint; | |
57 m_consumer->moveTo(m_currentPoint, AbsoluteCoordinates); | |
58 } | |
59 | 50 |
60 void SVGPathParser::emitLineToSegment(PathSegmentData& segment) | 51 class NormalizingConsumer { |
61 { | 52 STACK_ALLOCATED(); |
62 if (m_mode == RelativeCoordinates) | 53 public: |
63 m_currentPoint += segment.targetPoint; | 54 NormalizingConsumer(SVGPathConsumer* consumer) |
64 else | 55 : m_consumer(consumer) |
65 m_currentPoint = segment.targetPoint; | 56 , m_lastCommand(PathSegUnknown) |
66 m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates); | 57 { |
67 } | 58 ASSERT(m_consumer); |
| 59 } |
68 | 60 |
69 void SVGPathParser::emitLineToHorizontalSegment(PathSegmentData& segment) | 61 void emitSegment(PathSegmentData&); |
70 { | |
71 if (m_mode == RelativeCoordinates) | |
72 m_currentPoint += segment.targetPoint; | |
73 else | |
74 m_currentPoint.setX(segment.targetPoint.x()); | |
75 m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates); | |
76 } | |
77 | 62 |
78 void SVGPathParser::emitLineToVerticalSegment(PathSegmentData& segment) | 63 private: |
79 { | 64 bool decomposeArcToCubic(const FloatPoint& currentPoint, const PathSegmentDa
ta&); |
80 if (m_mode == RelativeCoordinates) | |
81 m_currentPoint += segment.targetPoint; | |
82 else | |
83 m_currentPoint.setY(segment.targetPoint.y()); | |
84 m_consumer->lineTo(m_currentPoint, AbsoluteCoordinates); | |
85 } | |
86 | 65 |
87 void SVGPathParser::emitCurveToCubicSegment(PathSegmentData& segment) | 66 RawPtrWillBeMember<SVGPathConsumer> m_consumer; |
88 { | 67 FloatPoint m_controlPoint; |
89 if (m_mode == RelativeCoordinates) { | 68 FloatPoint m_currentPoint; |
90 segment.point1 += m_currentPoint; | 69 FloatPoint m_subPathPoint; |
91 segment.point2 += m_currentPoint; | 70 SVGPathSegType m_lastCommand; |
92 segment.targetPoint += m_currentPoint; | 71 }; |
93 } | |
94 m_consumer->curveToCubic(segment.point1, segment.point2, segment.targetPoint
, AbsoluteCoordinates); | |
95 | |
96 m_controlPoint = segment.point2; | |
97 m_currentPoint = segment.targetPoint; | |
98 } | |
99 | 72 |
100 static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint&
pointToReflect) | 73 static FloatPoint reflectedPoint(const FloatPoint& reflectIn, const FloatPoint&
pointToReflect) |
101 { | 74 { |
102 return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y()
- pointToReflect.y()); | 75 return FloatPoint(2 * reflectIn.x() - pointToReflect.x(), 2 * reflectIn.y()
- pointToReflect.y()); |
103 } | 76 } |
104 | 77 |
105 void SVGPathParser::emitCurveToCubicSmoothSegment(PathSegmentData& segment) | |
106 { | |
107 if (m_lastCommand != PathSegCurveToCubicAbs | |
108 && m_lastCommand != PathSegCurveToCubicRel | |
109 && m_lastCommand != PathSegCurveToCubicSmoothAbs | |
110 && m_lastCommand != PathSegCurveToCubicSmoothRel) | |
111 m_controlPoint = m_currentPoint; | |
112 | |
113 FloatPoint point1 = reflectedPoint(m_currentPoint, m_controlPoint); | |
114 if (m_mode == RelativeCoordinates) { | |
115 segment.point2 += m_currentPoint; | |
116 segment.targetPoint += m_currentPoint; | |
117 } | |
118 | |
119 m_consumer->curveToCubic(point1, segment.point2, segment.targetPoint, Absolu
teCoordinates); | |
120 | |
121 m_controlPoint = segment.point2; | |
122 m_currentPoint = segment.targetPoint; | |
123 } | |
124 | |
125 // Blend the points with a ratio (1/3):(2/3). | 78 // Blend the points with a ratio (1/3):(2/3). |
126 static FloatPoint blendPoints(const FloatPoint& p1, const FloatPoint& p2) | 79 static FloatPoint blendPoints(const FloatPoint& p1, const FloatPoint& p2) |
127 { | 80 { |
128 const float oneOverThree = 1 / 3.f; | 81 const float oneOverThree = 1 / 3.f; |
129 return FloatPoint((p1.x() + 2 * p2.x()) * oneOverThree, (p1.y() + 2 * p2.y()
) * oneOverThree); | 82 return FloatPoint((p1.x() + 2 * p2.x()) * oneOverThree, (p1.y() + 2 * p2.y()
) * oneOverThree); |
130 } | 83 } |
131 | 84 |
132 void SVGPathParser::emitCurveToQuadraticSegment(PathSegmentData& segment) | 85 static inline bool isCubicCommand(SVGPathSegType command) |
133 { | 86 { |
134 m_controlPoint = segment.point1; | 87 return command == PathSegCurveToCubicAbs |
| 88 || command == PathSegCurveToCubicRel |
| 89 || command == PathSegCurveToCubicSmoothAbs |
| 90 || command == PathSegCurveToCubicSmoothRel; |
| 91 } |
135 | 92 |
136 if (m_mode == RelativeCoordinates) { | 93 static inline bool isQuadraticCommand(SVGPathSegType command) |
137 m_controlPoint += m_currentPoint; | 94 { |
| 95 return command == PathSegCurveToQuadraticAbs |
| 96 || command == PathSegCurveToQuadraticRel |
| 97 || command == PathSegCurveToQuadraticSmoothAbs |
| 98 || command == PathSegCurveToQuadraticSmoothRel; |
| 99 } |
| 100 |
| 101 void NormalizingConsumer::emitSegment(PathSegmentData& segment) |
| 102 { |
| 103 SVGPathSegType originalCommand = segment.command; |
| 104 |
| 105 // Convert relative points to absolute points. |
| 106 switch (segment.command) { |
| 107 case PathSegCurveToQuadraticRel: |
| 108 segment.point1 += m_currentPoint; |
138 segment.targetPoint += m_currentPoint; | 109 segment.targetPoint += m_currentPoint; |
| 110 break; |
| 111 case PathSegCurveToCubicRel: |
| 112 segment.point1 += m_currentPoint; |
| 113 /* fall through */ |
| 114 case PathSegCurveToCubicSmoothRel: |
| 115 segment.point2 += m_currentPoint; |
| 116 /* fall through */ |
| 117 case PathSegMoveToRel: |
| 118 case PathSegLineToRel: |
| 119 case PathSegLineToHorizontalRel: |
| 120 case PathSegLineToVerticalRel: |
| 121 case PathSegCurveToQuadraticSmoothRel: |
| 122 case PathSegArcRel: |
| 123 segment.targetPoint += m_currentPoint; |
| 124 break; |
| 125 case PathSegLineToHorizontalAbs: |
| 126 segment.targetPoint.setY(m_currentPoint.y()); |
| 127 break; |
| 128 case PathSegLineToVerticalAbs: |
| 129 segment.targetPoint.setX(m_currentPoint.x()); |
| 130 break; |
| 131 case PathSegClosePath: |
| 132 // Reset m_currentPoint for the next path. |
| 133 segment.targetPoint = m_subPathPoint; |
| 134 break; |
| 135 default: |
| 136 break; |
139 } | 137 } |
140 segment.point1 = blendPoints(m_currentPoint, m_controlPoint); | |
141 FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint); | |
142 | 138 |
143 m_consumer->curveToCubic(segment.point1, point2, segment.targetPoint, Absolu
teCoordinates); | 139 // Update command verb, handle smooth segments and convert quadratic curve |
| 140 // segments to cubics. |
| 141 switch (segment.command) { |
| 142 case PathSegMoveToRel: |
| 143 case PathSegMoveToAbs: |
| 144 m_subPathPoint = segment.targetPoint; |
| 145 segment.command = PathSegMoveToAbs; |
| 146 break; |
| 147 case PathSegLineToRel: |
| 148 case PathSegLineToAbs: |
| 149 case PathSegLineToHorizontalRel: |
| 150 case PathSegLineToHorizontalAbs: |
| 151 case PathSegLineToVerticalRel: |
| 152 case PathSegLineToVerticalAbs: |
| 153 segment.command = PathSegLineToAbs; |
| 154 break; |
| 155 case PathSegClosePath: |
| 156 break; |
| 157 case PathSegCurveToCubicSmoothRel: |
| 158 case PathSegCurveToCubicSmoothAbs: |
| 159 if (!isCubicCommand(m_lastCommand)) |
| 160 segment.point1 = m_currentPoint; |
| 161 else |
| 162 segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); |
| 163 /* fall through */ |
| 164 case PathSegCurveToCubicRel: |
| 165 case PathSegCurveToCubicAbs: |
| 166 m_controlPoint = segment.point2; |
| 167 segment.command = PathSegCurveToCubicAbs; |
| 168 break; |
| 169 case PathSegCurveToQuadraticSmoothRel: |
| 170 case PathSegCurveToQuadraticSmoothAbs: |
| 171 if (!isQuadraticCommand(m_lastCommand)) |
| 172 segment.point1 = m_currentPoint; |
| 173 else |
| 174 segment.point1 = reflectedPoint(m_currentPoint, m_controlPoint); |
| 175 /* fall through */ |
| 176 case PathSegCurveToQuadraticRel: |
| 177 case PathSegCurveToQuadraticAbs: |
| 178 // Save the unmodified control point. |
| 179 m_controlPoint = segment.point1; |
| 180 segment.point1 = blendPoints(m_currentPoint, m_controlPoint); |
| 181 segment.point2 = blendPoints(segment.targetPoint, m_controlPoint); |
| 182 segment.command = PathSegCurveToCubicAbs; |
| 183 break; |
| 184 case PathSegArcRel: |
| 185 case PathSegArcAbs: |
| 186 if (!decomposeArcToCubic(m_currentPoint, segment)) { |
| 187 // On failure, emit a line segment to the target point. |
| 188 segment.command = PathSegLineToAbs; |
| 189 } else { |
| 190 // decomposeArcToCubic() has already emitted the normalized |
| 191 // segments, so set command to PathSegArcAbs, to skip any further |
| 192 // emit. |
| 193 segment.command = PathSegArcAbs; |
| 194 } |
| 195 break; |
| 196 default: |
| 197 ASSERT_NOT_REACHED(); |
| 198 } |
| 199 |
| 200 switch (segment.command) { |
| 201 case PathSegMoveToAbs: |
| 202 m_consumer->moveTo(segment.targetPoint, AbsoluteCoordinates); |
| 203 break; |
| 204 case PathSegLineToAbs: |
| 205 m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates); |
| 206 break; |
| 207 case PathSegClosePath: |
| 208 m_consumer->closePath(); |
| 209 break; |
| 210 case PathSegCurveToCubicAbs: |
| 211 m_consumer->curveToCubic(segment.point1, segment.point2, segment.targetP
oint, AbsoluteCoordinates); |
| 212 break; |
| 213 case PathSegArcAbs: |
| 214 break; |
| 215 default: |
| 216 ASSERT_NOT_REACHED(); |
| 217 } |
144 | 218 |
145 m_currentPoint = segment.targetPoint; | 219 m_currentPoint = segment.targetPoint; |
146 } | |
147 | 220 |
148 void SVGPathParser::emitCurveToQuadraticSmoothSegment(PathSegmentData& segment) | 221 if (!isCubicCommand(originalCommand) && !isQuadraticCommand(originalCommand)
) |
149 { | |
150 if (m_lastCommand != PathSegCurveToQuadraticAbs | |
151 && m_lastCommand != PathSegCurveToQuadraticRel | |
152 && m_lastCommand != PathSegCurveToQuadraticSmoothAbs | |
153 && m_lastCommand != PathSegCurveToQuadraticSmoothRel) | |
154 m_controlPoint = m_currentPoint; | 222 m_controlPoint = m_currentPoint; |
155 | 223 |
156 if (m_mode == RelativeCoordinates) | 224 m_lastCommand = originalCommand; |
157 segment.targetPoint += m_currentPoint; | |
158 | |
159 m_controlPoint = reflectedPoint(m_currentPoint, m_controlPoint); | |
160 FloatPoint point1 = blendPoints(m_currentPoint, m_controlPoint); | |
161 FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint); | |
162 | |
163 m_consumer->curveToCubic(point1, point2, segment.targetPoint, AbsoluteCoordi
nates); | |
164 | |
165 m_currentPoint = segment.targetPoint; | |
166 } | |
167 | |
168 void SVGPathParser::emitArcToSegment(PathSegmentData& segment) | |
169 { | |
170 if (m_mode == RelativeCoordinates) | |
171 segment.targetPoint += m_currentPoint; | |
172 | |
173 if (!decomposeArcToCubic(m_currentPoint, segment)) | |
174 m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates); | |
175 m_currentPoint = segment.targetPoint; | |
176 } | 225 } |
177 | 226 |
178 bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo
l checkForInitialMoveTo) | 227 bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo
l checkForInitialMoveTo) |
179 { | 228 { |
180 ASSERT(m_source); | 229 ASSERT(m_source); |
181 ASSERT(m_consumer); | 230 ASSERT(m_consumer); |
182 | 231 |
183 m_controlPoint = FloatPoint(); | |
184 m_currentPoint = FloatPoint(); | |
185 m_subPathPoint = FloatPoint(); | |
186 | |
187 if (checkForInitialMoveTo && !initialCommandIsMoveTo()) | 232 if (checkForInitialMoveTo && !initialCommandIsMoveTo()) |
188 return false; | 233 return false; |
189 | 234 |
190 m_lastCommand = PathSegUnknown; | 235 NormalizingConsumer normalizer(m_consumer); |
| 236 |
191 while (m_source->hasMoreData()) { | 237 while (m_source->hasMoreData()) { |
192 PathSegmentData segment = m_source->parseSegment(); | 238 PathSegmentData segment = m_source->parseSegment(); |
193 if (segment.command == PathSegUnknown) | 239 if (segment.command == PathSegUnknown) |
194 return false; | 240 return false; |
195 | 241 |
196 if (pathParsingMode == NormalizedParsing) { | 242 if (pathParsingMode == NormalizedParsing) { |
197 m_mode = AbsoluteCoordinates; | 243 normalizer.emitSegment(segment); |
198 | |
199 switch (segment.command) { | |
200 case PathSegMoveToRel: | |
201 m_mode = RelativeCoordinates; | |
202 case PathSegMoveToAbs: | |
203 emitMoveToSegment(segment); | |
204 break; | |
205 case PathSegLineToRel: | |
206 m_mode = RelativeCoordinates; | |
207 case PathSegLineToAbs: | |
208 emitLineToSegment(segment); | |
209 break; | |
210 case PathSegLineToHorizontalRel: | |
211 m_mode = RelativeCoordinates; | |
212 case PathSegLineToHorizontalAbs: | |
213 emitLineToHorizontalSegment(segment); | |
214 break; | |
215 case PathSegLineToVerticalRel: | |
216 m_mode = RelativeCoordinates; | |
217 case PathSegLineToVerticalAbs: | |
218 emitLineToVerticalSegment(segment); | |
219 break; | |
220 case PathSegClosePath: | |
221 m_consumer->closePath(); | |
222 // Reset m_currentPoint for the next path. | |
223 m_currentPoint = m_subPathPoint; | |
224 break; | |
225 case PathSegCurveToCubicRel: | |
226 m_mode = RelativeCoordinates; | |
227 case PathSegCurveToCubicAbs: | |
228 emitCurveToCubicSegment(segment); | |
229 break; | |
230 case PathSegCurveToCubicSmoothRel: | |
231 m_mode = RelativeCoordinates; | |
232 case PathSegCurveToCubicSmoothAbs: | |
233 emitCurveToCubicSmoothSegment(segment); | |
234 break; | |
235 case PathSegCurveToQuadraticRel: | |
236 m_mode = RelativeCoordinates; | |
237 case PathSegCurveToQuadraticAbs: | |
238 emitCurveToQuadraticSegment(segment); | |
239 break; | |
240 case PathSegCurveToQuadraticSmoothRel: | |
241 m_mode = RelativeCoordinates; | |
242 case PathSegCurveToQuadraticSmoothAbs: | |
243 emitCurveToQuadraticSmoothSegment(segment); | |
244 break; | |
245 case PathSegArcRel: | |
246 m_mode = RelativeCoordinates; | |
247 case PathSegArcAbs: | |
248 emitArcToSegment(segment); | |
249 break; | |
250 default: | |
251 ASSERT_NOT_REACHED(); | |
252 } | |
253 } else { | 244 } else { |
254 PathCoordinateMode mode = AbsoluteCoordinates; | 245 PathCoordinateMode mode = AbsoluteCoordinates; |
255 | 246 |
256 switch (segment.command) { | 247 switch (segment.command) { |
257 case PathSegMoveToRel: | 248 case PathSegMoveToRel: |
258 mode = RelativeCoordinates; | 249 mode = RelativeCoordinates; |
259 case PathSegMoveToAbs: | 250 case PathSegMoveToAbs: |
260 m_consumer->moveTo(segment.targetPoint, mode); | 251 m_consumer->moveTo(segment.targetPoint, mode); |
261 break; | 252 break; |
262 case PathSegLineToRel: | 253 case PathSegLineToRel: |
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
303 m_consumer->arcTo(segment.arcRadii().x(), segment.arcRadii().y()
, segment.arcAngle(), segment.arcLarge, segment.arcSweep, segment.targetPoint, m
ode); | 294 m_consumer->arcTo(segment.arcRadii().x(), segment.arcRadii().y()
, segment.arcAngle(), segment.arcLarge, segment.arcSweep, segment.targetPoint, m
ode); |
304 break; | 295 break; |
305 default: | 296 default: |
306 ASSERT_NOT_REACHED(); | 297 ASSERT_NOT_REACHED(); |
307 } | 298 } |
308 } | 299 } |
309 | 300 |
310 if (!m_consumer->continueConsuming()) | 301 if (!m_consumer->continueConsuming()) |
311 return true; | 302 return true; |
312 | 303 |
313 m_lastCommand = segment.command; | |
314 | |
315 if (m_lastCommand != PathSegCurveToCubicAbs | |
316 && m_lastCommand != PathSegCurveToCubicRel | |
317 && m_lastCommand != PathSegCurveToCubicSmoothAbs | |
318 && m_lastCommand != PathSegCurveToCubicSmoothRel | |
319 && m_lastCommand != PathSegCurveToQuadraticAbs | |
320 && m_lastCommand != PathSegCurveToQuadraticRel | |
321 && m_lastCommand != PathSegCurveToQuadraticSmoothAbs | |
322 && m_lastCommand != PathSegCurveToQuadraticSmoothRel) | |
323 m_controlPoint = m_currentPoint; | |
324 | |
325 if (m_source->hasMoreData()) | 304 if (m_source->hasMoreData()) |
326 m_consumer->incrementPathSegmentCount(); | 305 m_consumer->incrementPathSegmentCount(); |
327 } | 306 } |
328 return true; | 307 return true; |
329 } | 308 } |
330 | 309 |
331 // This works by converting the SVG arc to "simple" beziers. | 310 // This works by converting the SVG arc to "simple" beziers. |
332 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons. | 311 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons. |
333 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc
ConversionEndpointToCenter | 312 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc
ConversionEndpointToCenter |
334 bool SVGPathParser::decomposeArcToCubic(const FloatPoint& currentPoint, const Pa
thSegmentData& arcSegment) | 313 bool NormalizingConsumer::decomposeArcToCubic(const FloatPoint& currentPoint, co
nst PathSegmentData& arcSegment) |
335 { | 314 { |
336 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (
a "lineto") joining the endpoints. | 315 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment (
a "lineto") joining the endpoints. |
337 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters | 316 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters |
338 float rx = fabsf(arcSegment.arcRadii().x()); | 317 float rx = fabsf(arcSegment.arcRadii().x()); |
339 float ry = fabsf(arcSegment.arcRadii().y()); | 318 float ry = fabsf(arcSegment.arcRadii().y()); |
340 if (!rx || !ry) | 319 if (!rx || !ry) |
341 return false; | 320 return false; |
342 | 321 |
343 // If the current point and target point for the arc are identical, it shoul
d be treated as a zero length | 322 // If the current point and target point for the arc are identical, it shoul
d be treated as a zero length |
344 // path. This ensures continuity in animations. | 323 // path. This ensures continuity in animations. |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
422 point2 = targetPoint; | 401 point2 = targetPoint; |
423 point2.move(t * sinEndTheta, -t * cosEndTheta); | 402 point2.move(t * sinEndTheta, -t * cosEndTheta); |
424 | 403 |
425 m_consumer->curveToCubic(pointTransform.mapPoint(point1), pointTransform
.mapPoint(point2), | 404 m_consumer->curveToCubic(pointTransform.mapPoint(point1), pointTransform
.mapPoint(point2), |
426 pointTransform.mapPoint(targetPoint), AbsoluteC
oordinates); | 405 pointTransform.mapPoint(targetPoint), AbsoluteC
oordinates); |
427 } | 406 } |
428 return true; | 407 return true; |
429 } | 408 } |
430 | 409 |
431 } | 410 } |
OLD | NEW |