1 /* 2 * Copyright (C) 2007-2009 Torch Mobile, Inc. 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 #include "config.h" 21 #include "PlatformPathWince.h" 22 23 #include "AffineTransform.h" 24 #include "FloatRect.h" 25 #include "GraphicsContext.h" 26 #include "Path.h" 27 #include "PlatformString.h" 28 #include "WinceGraphicsExtras.h" 29 #include <wtf/MathExtras.h> 30 #include <wtf/OwnPtr.h> 31 32 #include <windows.h> 33 34 namespace WebCore { 35 36 // Implemented in GraphicsContextWince.cpp 37 void getEllipsePointByAngle(double angle, double a, double b, float& x, float& y); 38 39 static void quadCurve(int segments, Vector<PathPoint>& pts, const PathPoint* control) 40 { 41 const float step = 1.0 / segments; 42 register float tA = 0.0; 43 register float tB = 1.0; 44 45 float c1x = control[0].x(); 46 float c1y = control[0].y(); 47 float c2x = control[1].x(); 48 float c2y = control[1].y(); 49 float c3x = control[2].x(); 50 float c3y = control[2].y(); 51 52 const int offset = pts.size(); 53 pts.resize(offset + segments); 54 PathPoint pp; 55 pp.m_x = c1x; 56 pp.m_y = c1y; 57 58 for (int i = 1; i < segments; ++i) { 59 tA += step; 60 tB -= step; 61 62 const float a = tB * tB; 63 const float b = 2.0 * tA * tB; 64 const float c = tA * tA; 65 66 pp.m_x = c1x * a + c2x * b + c3x * c; 67 pp.m_y = c1y * a + c2y * b + c3y * c; 68 69 pts[offset + i - 1] = pp; 70 } 71 72 pp.m_x = c3x; 73 pp.m_y = c3y; 74 pts[offset + segments - 1] = pp; 75 } 76 77 static inline void bezier(int segments, Vector<PathPoint>& pts, const PathPoint* control) 78 { 79 const float step = 1.0 / segments; 80 register float tA = 0.0; 81 register float tB = 1.0; 82 83 float c1x = control[0].x(); 84 float c1y = control[0].y(); 85 float c2x = control[1].x(); 86 float c2y = control[1].y(); 87 float c3x = control[2].x(); 88 float c3y = control[2].y(); 89 float c4x = control[3].x(); 90 float c4y = control[3].y(); 91 92 const int offset = pts.size(); 93 pts.resize(offset + segments); 94 PathPoint pp; 95 pp.m_x = c1x; 96 pp.m_y = c1y; 97 98 for (int i = 1; i < segments; ++i) { 99 tA += step; 100 tB -= step; 101 const float tAsq = tA * tA; 102 const float tBsq = tB * tB; 103 104 const float a = tBsq * tB; 105 const float b = 3.0 * tA * tBsq; 106 const float c = 3.0 * tB * tAsq; 107 const float d = tAsq * tA; 108 109 pp.m_x = c1x * a + c2x * b + c3x * c + c4x * d; 110 pp.m_y = c1y * a + c2y * b + c3y * c + c4y * d; 111 112 pts[offset + i - 1] = pp; 113 } 114 115 pp.m_x = c4x; 116 pp.m_y = c4y; 117 pts[offset + segments - 1] = pp; 118 } 119 120 static bool containsPoint(const FloatRect& r, const FloatPoint& p) 121 { 122 return p.x() >= r.x() && p.y() >= r.y() && p.x() < r.right() && p.y() < r.bottom(); 123 } 124 125 static void normalizeAngle(float& angle) 126 { 127 angle = fmod(angle, 2 * piFloat); 128 if (angle < 0) 129 angle += 2 * piFloat; 130 if (angle < 0.00001f) 131 angle = 0; 132 } 133 134 static void transformArcPoint(float& x, float& y, const FloatPoint& c) 135 { 136 x += c.x(); 137 y += c.y(); 138 } 139 140 static void inflateRectToContainPoint(FloatRect& r, float x, float y) 141 { 142 if (r.isEmpty()) { 143 r.setX(x); 144 r.setY(y); 145 r.setSize(FloatSize(1, 1)); 146 return; 147 } 148 if (x < r.x()) { 149 r.setWidth(r.right() - x); 150 r.setX(x); 151 } else { 152 float w = x - r.x() + 1; 153 if (w > r.width()) 154 r.setWidth(w); 155 } 156 if (y < r.y()) { 157 r.setHeight(r.bottom() - y); 158 r.setY(y); 159 } else { 160 float h = y - r.y() + 1; 161 if (h > r.height()) 162 r.setHeight(h); 163 } 164 } 165 166 // return 0-based value: 0 - first Quadrant ( 0 - 90 degree) 167 static inline int quadrant(const PathPoint& point, const PathPoint& origin) 168 { 169 return point.m_x < origin.m_x ? 170 (point.m_y < origin.m_y ? 2 : 1) 171 : (point.m_y < origin.m_y ? 3 : 0); 172 } 173 174 static inline bool isQuadrantOnLeft(int q) { return q == 1 || q == 2; } 175 static inline bool isQuadrantOnRight(int q) { return q == 0 || q == 3; } 176 static inline bool isQuadrantOnTop(int q) { return q == 2 || q == 3; } 177 static inline bool isQuadrantOnBottom(int q) { return q == 0 || q == 1; } 178 179 static inline int nextQuadrant(int q) { return q == 3 ? 0 : q + 1; } 180 static inline int quadrantDiff(int q1, int q2) 181 { 182 int d = q1 - q2; 183 while (d < 0) 184 d += 4; 185 return d; 186 } 187 188 struct PathVector { 189 float m_x; 190 float m_y; 191 192 PathVector() : m_x(0), m_y(0) {} 193 PathVector(float x, float y) : m_x(x), m_y(y) {} 194 double angle() const { return atan2(m_y, m_x); } 195 operator double () const { return angle(); } 196 double length() const { return _hypot(m_x, m_y); } 197 }; 198 199 PathVector operator-(const PathPoint& p1, const PathPoint& p2) 200 { 201 return PathVector(p1.m_x - p2.m_x, p1.m_y - p2.m_y); 202 } 203 204 static void addArcPoint(PathPolygon& poly, const PathPoint& center, const PathPoint& radius, double angle) 205 { 206 PathPoint p; 207 getEllipsePointByAngle(angle, radius.m_x, radius.m_y, p.m_x, p.m_y); 208 transformArcPoint(p.m_x, p.m_y, center); 209 if (poly.isEmpty() || poly.last() != p) 210 poly.append(p); 211 } 212 213 static void addArcPoints(PathPolygon& poly, const PlatformPathElement::ArcTo& data) 214 { 215 const PathPoint& startPoint = poly.last(); 216 double curAngle = startPoint - data.m_center; 217 double endAngle = data.m_end - data.m_center; 218 double angleStep = 2. / std::max(data.m_radius.m_x, data.m_radius.m_y); 219 if (data.m_clockwise) { 220 if (endAngle <= curAngle || startPoint == data.m_end) 221 endAngle += 2 * piDouble; 222 } else { 223 angleStep = -angleStep; 224 if (endAngle >= curAngle || startPoint == data.m_end) 225 endAngle -= 2 * piDouble; 226 } 227 228 for (curAngle += angleStep; data.m_clockwise ? curAngle < endAngle : curAngle > endAngle; curAngle += angleStep) 229 addArcPoint(poly, data.m_center, data.m_radius, curAngle); 230 231 if (poly.isEmpty() || poly.last() != data.m_end) 232 poly.append(data.m_end); 233 } 234 235 static void drawPolygons(HDC dc, const Vector<PathPolygon>& polygons, bool fill, const AffineTransform* transformation) 236 { 237 MemoryAllocationCanFail canFail; 238 for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { 239 int npoints = i->size(); 240 if (!npoints) 241 continue; 242 243 POINT* winPoints = 0; 244 if (fill) { 245 if (npoints > 2) 246 winPoints = new POINT[npoints + 1]; 247 } else 248 winPoints = new POINT[npoints]; 249 250 if (winPoints) { 251 if (transformation) { 252 for (int i2 = 0; i2 < npoints; ++i2) { 253 FloatPoint trPoint = transformation->mapPoint(i->at(i2)); 254 winPoints[i2].x = stableRound(trPoint.x()); 255 winPoints[i2].y = stableRound(trPoint.y()); 256 } 257 } else { 258 for (int i2 = 0; i2 < npoints; ++i2) { 259 winPoints[i2].x = stableRound(i->at(i2).x()); 260 winPoints[i2].y = stableRound(i->at(i2).y()); 261 } 262 } 263 264 if (fill && winPoints[npoints - 1] != winPoints[0]) { 265 winPoints[npoints].x = winPoints[0].x; 266 winPoints[npoints].y = winPoints[0].y; 267 ++npoints; 268 } 269 270 if (fill) 271 ::Polygon(dc, winPoints, npoints); 272 else 273 ::Polyline(dc, winPoints, npoints); 274 delete[] winPoints; 275 } 276 } 277 } 278 279 280 int PlatformPathElement::numControlPoints() const 281 { 282 switch (m_type) { 283 case PathMoveTo: 284 case PathLineTo: 285 return 1; 286 case PathQuadCurveTo: 287 case PathArcTo: 288 return 2; 289 case PathBezierCurveTo: 290 return 3; 291 default: 292 ASSERT(m_type == PathCloseSubpath); 293 return 0; 294 } 295 } 296 297 int PlatformPathElement::numPoints() const 298 { 299 switch (m_type) { 300 case PathMoveTo: 301 case PathLineTo: 302 case PathArcTo: 303 return 1; 304 case PathQuadCurveTo: 305 return 2; 306 case PathBezierCurveTo: 307 return 3; 308 default: 309 ASSERT(m_type == PathCloseSubpath); 310 return 0; 311 } 312 } 313 314 void PathPolygon::move(const FloatSize& offset) 315 { 316 for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) 317 i->move(offset); 318 } 319 320 void PathPolygon::transform(const AffineTransform& t) 321 { 322 for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) 323 *i = t.mapPoint(*i); 324 } 325 326 bool PathPolygon::contains(const FloatPoint& point) const 327 { 328 if (size() < 3) 329 return false; 330 331 // Test intersections between the polygon and the vertical line: x = point.x() 332 333 int intersected = 0; 334 const PathPoint* point1 = &last(); 335 Vector<PathPoint>::const_iterator last = end(); 336 // wasNegative: -1 means unknown, 0 means false, 1 means true. 337 int wasNegative = -1; 338 for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) { 339 const PathPoint& point2 = *i; 340 if (point1->x() != point.x()) { 341 if (point2.x() == point.x()) { 342 // We are getting on the vertical line 343 wasNegative = point1->x() < point.x() ? 1 : 0; 344 } else if (point2.x() < point.x() != point1->x() < point.x()) { 345 float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y(); 346 if (y >= point.y()) 347 ++intersected; 348 } 349 } else { 350 // We were on the vertical line 351 352 // handle special case 353 if (point1->y() == point.y()) 354 return true; 355 356 if (point1->y() > point.y()) { 357 if (point2.x() == point.x()) { 358 // see if the point is on this segment 359 if (point2.y() <= point.y()) 360 return true; 361 362 // We are still on the line 363 } else { 364 // We are leaving the line now. 365 // We have to get back to see which side we come from. If we come from 366 // the same side we are leaving, no intersection should be counted 367 if (wasNegative < 0) { 368 Vector<PathPoint>::const_iterator jLast = i; 369 Vector<PathPoint>::const_iterator j = i; 370 do { 371 if (j == begin()) 372 j = last; 373 else 374 --j; 375 if (j->x() != point.x()) { 376 if (j->x() > point.x()) 377 wasNegative = 0; 378 else 379 wasNegative = 1; 380 break; 381 } 382 } while (j != jLast); 383 384 if (wasNegative < 0) 385 return false; 386 } 387 if (wasNegative ? point2.x() > point.x() : point2.x() < point.x()) 388 ++intersected; 389 } 390 } else if (point2.x() == point.x() && point2.y() >= point.y()) 391 return true; 392 } 393 point1 = &point2; 394 } 395 396 return intersected & 1; 397 } 398 399 void PlatformPathElement::move(const FloatSize& offset) 400 { 401 int n = numControlPoints(); 402 for (int i = 0; i < n; ++i) 403 m_data.m_points[i].move(offset); 404 } 405 406 void PlatformPathElement::transform(const AffineTransform& t) 407 { 408 int n = numControlPoints(); 409 for (int i = 0; i < n; ++i) { 410 FloatPoint p = t.mapPoint(m_data.m_points[i]); 411 m_data.m_points[i].set(p.x(), p.y()); 412 } 413 } 414 415 void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const 416 { 417 if (m_type == PathArcTo) { 418 const ArcTo& data = m_data.m_arcToData; 419 PathPoint startPoint; 420 startPoint = lastPoint; 421 PathPoint endPoint = data.m_end; 422 if (!data.m_clockwise) 423 std::swap(startPoint, endPoint); 424 425 int q0 = quadrant(startPoint, data.m_center); 426 int q1 = quadrant(endPoint, data.m_center); 427 bool containsExtremes[4] = { false }; // bottom, left, top, right 428 static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; 429 if (q0 == q1) { 430 if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) { 431 for (int i = 0; i < 4; ++i) 432 containsExtremes[i] = true; 433 } 434 } else { 435 int extreme = q0; 436 int diff = quadrantDiff(q1, q0); 437 for (int i = 0; i < diff; ++i) { 438 containsExtremes[extreme] = true; 439 extreme = nextQuadrant(extreme); 440 } 441 } 442 443 inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y); 444 inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y); 445 for (int i = 0; i < 4; ++i) { 446 if (containsExtremes[i]) 447 inflateRectToContainPoint(r, data.m_center.m_x + data.m_radius.m_x * extremeVectors[i].m_x, data.m_center.m_y + data.m_radius.m_y * extremeVectors[i].m_y); 448 } 449 } else { 450 int n = numPoints(); 451 for (int i = 0; i < n; ++i) 452 inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y); 453 } 454 } 455 456 PathElementType PlatformPathElement::type() const 457 { 458 switch (m_type) { 459 case PathMoveTo: 460 return PathElementMoveToPoint; 461 case PathLineTo: 462 return PathElementAddLineToPoint; 463 case PathArcTo: 464 // FIXME: there's no arcTo type for PathElement 465 return PathElementAddLineToPoint; 466 // return PathElementAddQuadCurveToPoint; 467 case PathQuadCurveTo: 468 return PathElementAddQuadCurveToPoint; 469 case PathBezierCurveTo: 470 return PathElementAddCurveToPoint; 471 default: 472 ASSERT(m_type == PathCloseSubpath); 473 return PathElementCloseSubpath; 474 } 475 } 476 477 PlatformPath::PlatformPath() 478 : m_penLifted(true) 479 { 480 m_currentPoint.clear(); 481 } 482 483 void PlatformPath::ensureSubpath() 484 { 485 if (m_penLifted) { 486 m_penLifted = false; 487 m_subpaths.append(PathPolygon()); 488 m_subpaths.last().append(m_currentPoint); 489 } else 490 ASSERT(!m_subpaths.isEmpty()); 491 } 492 493 void PlatformPath::addToSubpath(const PlatformPathElement& e) 494 { 495 if (e.platformType() == PlatformPathElement::PathMoveTo) { 496 m_penLifted = true; 497 m_currentPoint = e.pointAt(0); 498 } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) { 499 m_penLifted = true; 500 if (!m_subpaths.isEmpty()) { 501 if (m_currentPoint != m_subpaths.last()[0]) { 502 // According to W3C, we have to draw a line from current point to the initial point 503 m_subpaths.last().append(m_subpaths.last()[0]); 504 m_currentPoint = m_subpaths.last()[0]; 505 } 506 } else 507 m_currentPoint.clear(); 508 } else { 509 ensureSubpath(); 510 switch (e.platformType()) { 511 case PlatformPathElement::PathLineTo: 512 m_subpaths.last().append(e.pointAt(0)); 513 break; 514 case PlatformPathElement::PathArcTo: 515 addArcPoints(m_subpaths.last(), e.arcTo()); 516 break; 517 case PlatformPathElement::PathQuadCurveTo: 518 { 519 PathPoint control[] = { 520 m_currentPoint, 521 e.pointAt(0), 522 e.pointAt(1), 523 }; 524 // FIXME: magic number? 525 quadCurve(50, m_subpaths.last(), control); 526 } 527 break; 528 case PlatformPathElement::PathBezierCurveTo: 529 { 530 PathPoint control[] = { 531 m_currentPoint, 532 e.pointAt(0), 533 e.pointAt(1), 534 e.pointAt(2), 535 }; 536 // FIXME: magic number? 537 bezier(100, m_subpaths.last(), control); 538 } 539 break; 540 default: 541 ASSERT_NOT_REACHED(); 542 break; 543 } 544 m_currentPoint = m_subpaths.last().last(); 545 } 546 } 547 548 void PlatformPath::append(const PlatformPathElement& e) 549 { 550 e.inflateRectToContainMe(m_boundingRect, lastPoint()); 551 addToSubpath(e); 552 m_elements.append(e); 553 } 554 555 void PlatformPath::append(const PlatformPath& p) 556 { 557 const PlatformPathElements& e = p.elements(); 558 for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) { 559 addToSubpath(*it); 560 it->inflateRectToContainMe(m_boundingRect, lastPoint()); 561 m_elements.append(*it); 562 } 563 } 564 565 void PlatformPath::clear() 566 { 567 m_elements.clear(); 568 m_boundingRect = FloatRect(); 569 m_subpaths.clear(); 570 m_currentPoint.clear(); 571 m_penLifted = true; 572 } 573 574 void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const 575 { 576 drawPolygons(dc, m_subpaths, false, transformation); 577 } 578 579 void PlatformPath::fillPath(HDC dc, const AffineTransform* transformation) const 580 { 581 HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); 582 drawPolygons(dc, m_subpaths, true, transformation); 583 SelectObject(dc, oldPen); 584 } 585 586 void PlatformPath::translate(const FloatSize& size) 587 { 588 for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) 589 it->move(size); 590 591 m_boundingRect.move(size); 592 for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) 593 it->move(size); 594 } 595 596 void PlatformPath::transform(const AffineTransform& t) 597 { 598 for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) 599 it->transform(t); 600 601 m_boundingRect = t.mapRect(m_boundingRect); 602 for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) 603 it->transform(t); 604 } 605 606 bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const 607 { 608 // optimization: check the bounding rect first 609 if (!containsPoint(m_boundingRect, point)) 610 return false; 611 612 for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) { 613 if (i->contains(point)) 614 return true; 615 } 616 617 return false; 618 } 619 620 void PlatformPath::moveTo(const FloatPoint& point) 621 { 622 PlatformPathElement::MoveTo data = { { point.x(), point.y() } }; 623 PlatformPathElement pe(data); 624 append(pe); 625 } 626 627 void PlatformPath::addLineTo(const FloatPoint& point) 628 { 629 PlatformPathElement::LineTo data = { { point.x(), point.y() } }; 630 PlatformPathElement pe(data); 631 append(pe); 632 } 633 634 void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) 635 { 636 PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } }; 637 PlatformPathElement pe(data); 638 append(pe); 639 } 640 641 void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) 642 { 643 PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } }; 644 PlatformPathElement pe(data); 645 append(pe); 646 } 647 648 void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius) 649 { 650 const PathPoint& p0 = m_currentPoint; 651 PathPoint p1; 652 p1 = fp1; 653 PathPoint p2; 654 p2 = fp2; 655 if (!radius || p0 == p1 || p1 == p2) { 656 addLineTo(p1); 657 return; 658 } 659 660 PathVector v01 = p0 - p1; 661 PathVector v21 = p2 - p1; 662 663 // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) 664 double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x; 665 666 if (fabs(cross) < 1E-10) { 667 // on one line 668 addLineTo(p1); 669 return; 670 } 671 672 double d01 = v01.length(); 673 double d21 = v21.length(); 674 double angle = (piDouble - abs(asin(cross / (d01 * d21)))) * 0.5; 675 double span = radius * tan(angle); 676 double rate = span / d01; 677 PathPoint startPoint; 678 startPoint.m_x = p1.m_x + v01.m_x * rate; 679 startPoint.m_y = p1.m_y + v01.m_y * rate; 680 681 addLineTo(startPoint); 682 683 PathPoint endPoint; 684 rate = span / d21; 685 endPoint.m_x = p1.m_x + v21.m_x * rate; 686 endPoint.m_y = p1.m_y + v21.m_y * rate; 687 688 PathPoint midPoint; 689 midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5; 690 midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5; 691 692 PathVector vm1 = midPoint - p1; 693 double dm1 = vm1.length(); 694 double d = _hypot(radius, span); 695 696 PathPoint centerPoint; 697 rate = d / dm1; 698 centerPoint.m_x = p1.m_x + vm1.m_x * rate; 699 centerPoint.m_y = p1.m_y + vm1.m_y * rate; 700 701 PlatformPathElement::ArcTo data = { 702 endPoint, 703 centerPoint, 704 { radius, radius }, 705 cross < 0 706 }; 707 PlatformPathElement pe(data); 708 append(pe); 709 } 710 711 void PlatformPath::closeSubpath() 712 { 713 PlatformPathElement pe; 714 append(pe); 715 } 716 717 // add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear 718 void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise) 719 { 720 float startX, startY, endX, endY; 721 722 normalizeAngle(sar); 723 normalizeAngle(ear); 724 725 getEllipsePointByAngle(sar, a, b, startX, startY); 726 getEllipsePointByAngle(ear, a, b, endX, endY); 727 728 transformArcPoint(startX, startY, p); 729 transformArcPoint(endX, endY, p); 730 731 FloatPoint start(startX, startY); 732 moveTo(start); 733 734 PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise }; 735 PlatformPathElement pe(data); 736 append(pe); 737 } 738 739 740 void PlatformPath::addRect(const FloatRect& r) 741 { 742 moveTo(r.location()); 743 744 float right = r.right() - 1; 745 float bottom = r.bottom() - 1; 746 addLineTo(FloatPoint(right, r.y())); 747 addLineTo(FloatPoint(right, bottom)); 748 addLineTo(FloatPoint(r.x(), bottom)); 749 addLineTo(r.location()); 750 } 751 752 void PlatformPath::addEllipse(const FloatRect& r) 753 { 754 FloatSize radius(r.width() * 0.5, r.height() * 0.5); 755 addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); 756 } 757 758 String PlatformPath::debugString() const 759 { 760 String ret; 761 for (PlatformPathElements::const_iterator i(m_elements.begin()); i != m_elements.end(); ++i) { 762 switch (i->platformType()) { 763 case PlatformPathElement::PathMoveTo: 764 case PlatformPathElement::PathLineTo: 765 ret += String::format("M %f %f\n", i->pointAt(0).m_x, i->pointAt(0).m_y); 766 break; 767 case PlatformPathElement::PathArcTo: 768 ret += String::format("A %f %f %f %f %f %f %c\n" 769 , i->arcTo().m_end.m_x, i->arcTo().m_end.m_y 770 , i->arcTo().m_center.m_x, i->arcTo().m_center.m_y 771 , i->arcTo().m_radius.m_x, i->arcTo().m_radius.m_y 772 , i->arcTo().m_clockwise? 'Y' : 'N'); 773 break; 774 case PlatformPathElement::PathQuadCurveTo: 775 ret += String::format("Q %f %f %f %f\n" 776 , i->pointAt(0).m_x, i->pointAt(0).m_y 777 , i->pointAt(1).m_x, i->pointAt(1).m_y); 778 break; 779 case PlatformPathElement::PathBezierCurveTo: 780 ret += String::format("B %f %f %f %f %f %f\n" 781 , i->pointAt(0).m_x, i->pointAt(0).m_y 782 , i->pointAt(1).m_x, i->pointAt(1).m_y 783 , i->pointAt(2).m_x, i->pointAt(2).m_y); 784 break; 785 default: 786 ASSERT(i->platformType() == PlatformPathElement::PathCloseSubpath); 787 ret += "S\n"; 788 break; 789 } 790 } 791 792 return ret; 793 } 794 795 void PlatformPath::apply(void* info, PathApplierFunction function) const 796 { 797 PathElement pelement; 798 FloatPoint points[3]; 799 pelement.points = points; 800 801 for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) { 802 pelement.type = it->type(); 803 int n = it->numPoints(); 804 for (int i = 0; i < n; ++i) 805 points[i] = it->pointAt(i); 806 function(info, &pelement); 807 } 808 } 809 810 } // namespace Webcore 811