Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(204)

Side by Side Diff: Source/core/svg/SVGPathParser.cpp

Issue 1028183003: Pass segment to decomposeArcToCubic and let it handle exceptional cases (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/svg/SVGPathParser.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 149 matching lines...) Expand 10 before | Expand all | Expand 10 after
160 FloatPoint point1 = blendPoints(m_currentPoint, m_controlPoint); 160 FloatPoint point1 = blendPoints(m_currentPoint, m_controlPoint);
161 FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint); 161 FloatPoint point2 = blendPoints(segment.targetPoint, m_controlPoint);
162 162
163 m_consumer->curveToCubic(point1, point2, segment.targetPoint, AbsoluteCoordi nates); 163 m_consumer->curveToCubic(point1, point2, segment.targetPoint, AbsoluteCoordi nates);
164 164
165 m_currentPoint = segment.targetPoint; 165 m_currentPoint = segment.targetPoint;
166 } 166 }
167 167
168 void SVGPathParser::emitArcToSegment(PathSegmentData& segment) 168 void SVGPathParser::emitArcToSegment(PathSegmentData& segment)
169 { 169 {
170 // If rx = 0 or ry = 0 then this arc is treated as a straight line segment ( a "lineto") joining the endpoints.
171 // http://www.w3.org/TR/SVG/implnote.html#ArcOutOfRangeParameters
172 // If the current point and target point for the arc are identical, it shoul d be treated as a zero length
173 // path. This ensures continuity in animations.
174 float rx = fabsf(segment.arcRadii().x());
175 float ry = fabsf(segment.arcRadii().y());
176
177 if (m_mode == RelativeCoordinates) 170 if (m_mode == RelativeCoordinates)
178 segment.targetPoint += m_currentPoint; 171 segment.targetPoint += m_currentPoint;
179 172
180 if (!rx || !ry || segment.targetPoint == m_currentPoint) { 173 if (!decomposeArcToCubic(m_currentPoint, segment))
181 m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates); 174 m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates);
182 m_currentPoint = segment.targetPoint;
183 return;
184 }
185
186 float angle = segment.arcAngle();
187 FloatPoint point1 = m_currentPoint;
188 m_currentPoint = segment.targetPoint; 175 m_currentPoint = segment.targetPoint;
189 if (!decomposeArcToCubic(angle, rx, ry, point1, segment.targetPoint, segment .arcLarge, segment.arcSweep))
190 m_consumer->lineTo(segment.targetPoint, AbsoluteCoordinates);
191 } 176 }
192 177
193 bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo l checkForInitialMoveTo) 178 bool SVGPathParser::parsePathDataFromSource(PathParsingMode pathParsingMode, boo l checkForInitialMoveTo)
194 { 179 {
195 ASSERT(m_source); 180 ASSERT(m_source);
196 ASSERT(m_consumer); 181 ASSERT(m_consumer);
197 182
198 m_controlPoint = FloatPoint(); 183 m_controlPoint = FloatPoint();
199 m_currentPoint = FloatPoint(); 184 m_currentPoint = FloatPoint();
200 m_subPathPoint = FloatPoint(); 185 m_subPathPoint = FloatPoint();
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
339 324
340 if (m_source->hasMoreData()) 325 if (m_source->hasMoreData())
341 m_consumer->incrementPathSegmentCount(); 326 m_consumer->incrementPathSegmentCount();
342 } 327 }
343 return true; 328 return true;
344 } 329 }
345 330
346 // This works by converting the SVG arc to "simple" beziers. 331 // This works by converting the SVG arc to "simple" beziers.
347 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons. 332 // Partly adapted from Niko's code in kdelibs/kdecore/svgicons.
348 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc ConversionEndpointToCenter 333 // See also SVG implementation notes: http://www.w3.org/TR/SVG/implnote.html#Arc ConversionEndpointToCenter
349 bool SVGPathParser::decomposeArcToCubic(float angle, float rx, float ry, const F loatPoint& start, const FloatPoint& end, bool largeArcFlag, bool sweepFlag) 334 bool SVGPathParser::decomposeArcToCubic(const FloatPoint& currentPoint, const Pa thSegmentData& arcSegment)
350 { 335 {
351 FloatSize midPointDistance = start - end; 336 // 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
338 float rx = fabsf(arcSegment.arcRadii().x());
339 float ry = fabsf(arcSegment.arcRadii().y());
340 if (!rx || !ry)
341 return false;
342
343 // 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.
345 if (arcSegment.targetPoint == currentPoint)
346 return false;
347
348 float angle = arcSegment.arcAngle();
349
350 FloatSize midPointDistance = currentPoint - arcSegment.targetPoint;
352 midPointDistance.scale(0.5f); 351 midPointDistance.scale(0.5f);
353 352
354 AffineTransform pointTransform; 353 AffineTransform pointTransform;
355 pointTransform.rotate(-angle); 354 pointTransform.rotate(-angle);
356 355
357 FloatPoint transformedMidPoint = pointTransform.mapPoint(FloatPoint(midPoint Distance.width(), midPointDistance.height())); 356 FloatPoint transformedMidPoint = pointTransform.mapPoint(FloatPoint(midPoint Distance.width(), midPointDistance.height()));
358 float squareRx = rx * rx; 357 float squareRx = rx * rx;
359 float squareRy = ry * ry; 358 float squareRy = ry * ry;
360 float squareX = transformedMidPoint.x() * transformedMidPoint.x(); 359 float squareX = transformedMidPoint.x() * transformedMidPoint.x();
361 float squareY = transformedMidPoint.y() * transformedMidPoint.y(); 360 float squareY = transformedMidPoint.y() * transformedMidPoint.y();
362 361
363 // Check if the radii are big enough to draw the arc, scale radii if not. 362 // Check if the radii are big enough to draw the arc, scale radii if not.
364 // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii 363 // http://www.w3.org/TR/SVG/implnote.html#ArcCorrectionOutOfRangeRadii
365 float radiiScale = squareX / squareRx + squareY / squareRy; 364 float radiiScale = squareX / squareRx + squareY / squareRy;
366 if (radiiScale > 1) { 365 if (radiiScale > 1) {
367 rx *= sqrtf(radiiScale); 366 rx *= sqrtf(radiiScale);
368 ry *= sqrtf(radiiScale); 367 ry *= sqrtf(radiiScale);
369 } 368 }
370 369
371 pointTransform.makeIdentity(); 370 pointTransform.makeIdentity();
372 pointTransform.scale(1 / rx, 1 / ry); 371 pointTransform.scale(1 / rx, 1 / ry);
373 pointTransform.rotate(-angle); 372 pointTransform.rotate(-angle);
374 373
375 FloatPoint point1 = pointTransform.mapPoint(start); 374 FloatPoint point1 = pointTransform.mapPoint(currentPoint);
376 FloatPoint point2 = pointTransform.mapPoint(end); 375 FloatPoint point2 = pointTransform.mapPoint(arcSegment.targetPoint);
377 FloatSize delta = point2 - point1; 376 FloatSize delta = point2 - point1;
378 377
379 float d = delta.width() * delta.width() + delta.height() * delta.height(); 378 float d = delta.width() * delta.width() + delta.height() * delta.height();
380 float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f); 379 float scaleFactorSquared = std::max(1 / d - 0.25f, 0.f);
381 380
382 float scaleFactor = sqrtf(scaleFactorSquared); 381 float scaleFactor = sqrtf(scaleFactorSquared);
383 if (sweepFlag == largeArcFlag) 382 if (arcSegment.arcSweep == arcSegment.arcLarge)
384 scaleFactor = -scaleFactor; 383 scaleFactor = -scaleFactor;
385 384
386 delta.scale(scaleFactor); 385 delta.scale(scaleFactor);
387 FloatPoint centerPoint = point1 + point2; 386 FloatPoint centerPoint = point1 + point2;
388 centerPoint.scale(0.5f, 0.5f); 387 centerPoint.scale(0.5f, 0.5f);
389 centerPoint.move(-delta.height(), delta.width()); 388 centerPoint.move(-delta.height(), delta.width());
390 389
391 float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians(); 390 float theta1 = FloatPoint(point1 - centerPoint).slopeAngleRadians();
392 float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians(); 391 float theta2 = FloatPoint(point2 - centerPoint).slopeAngleRadians();
393 392
394 float thetaArc = theta2 - theta1; 393 float thetaArc = theta2 - theta1;
395 if (thetaArc < 0 && sweepFlag) 394 if (thetaArc < 0 && arcSegment.arcSweep)
396 thetaArc += twoPiFloat; 395 thetaArc += twoPiFloat;
397 else if (thetaArc > 0 && !sweepFlag) 396 else if (thetaArc > 0 && !arcSegment.arcSweep)
398 thetaArc -= twoPiFloat; 397 thetaArc -= twoPiFloat;
399 398
400 pointTransform.makeIdentity(); 399 pointTransform.makeIdentity();
401 pointTransform.rotate(angle); 400 pointTransform.rotate(angle);
402 pointTransform.scale(rx, ry); 401 pointTransform.scale(rx, ry);
403 402
404 // Some results of atan2 on some platform implementations are not exact enou gh. So that we get more 403 // Some results of atan2 on some platform implementations are not exact enou gh. So that we get more
405 // cubic curves than expected here. Adding 0.001f reduces the count of sgeme nts to the correct count. 404 // cubic curves than expected here. Adding 0.001f reduces the count of sgeme nts to the correct count.
406 int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f))); 405 int segments = ceilf(fabsf(thetaArc / (piOverTwoFloat + 0.001f)));
407 for (int i = 0; i < segments; ++i) { 406 for (int i = 0; i < segments; ++i) {
(...skipping 15 matching lines...) Expand all
423 point2 = targetPoint; 422 point2 = targetPoint;
424 point2.move(t * sinEndTheta, -t * cosEndTheta); 423 point2.move(t * sinEndTheta, -t * cosEndTheta);
425 424
426 m_consumer->curveToCubic(pointTransform.mapPoint(point1), pointTransform .mapPoint(point2), 425 m_consumer->curveToCubic(pointTransform.mapPoint(point1), pointTransform .mapPoint(point2),
427 pointTransform.mapPoint(targetPoint), AbsoluteC oordinates); 426 pointTransform.mapPoint(targetPoint), AbsoluteC oordinates);
428 } 427 }
429 return true; 428 return true;
430 } 429 }
431 430
432 } 431 }
OLDNEW
« no previous file with comments | « Source/core/svg/SVGPathParser.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698