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.maxX() && p.y() < r.maxY(); 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.maxX() - 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.maxY() - 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 for (Vector<PathPolygon>::const_iterator i = polygons.begin(); i != polygons.end(); ++i) { 238 int npoints = i->size(); 239 if (!npoints) 240 continue; 241 242 POINT* winPoints = 0; 243 if (fill) { 244 if (npoints > 2) 245 winPoints = new POINT[npoints + 1]; 246 } else 247 winPoints = new POINT[npoints]; 248 249 if (winPoints) { 250 if (transformation) { 251 for (int i2 = 0; i2 < npoints; ++i2) { 252 FloatPoint trPoint = transformation->mapPoint(i->at(i2)); 253 winPoints[i2].x = stableRound(trPoint.x()); 254 winPoints[i2].y = stableRound(trPoint.y()); 255 } 256 } else { 257 for (int i2 = 0; i2 < npoints; ++i2) { 258 winPoints[i2].x = stableRound(i->at(i2).x()); 259 winPoints[i2].y = stableRound(i->at(i2).y()); 260 } 261 } 262 263 if (fill && winPoints[npoints - 1] != winPoints[0]) { 264 winPoints[npoints].x = winPoints[0].x; 265 winPoints[npoints].y = winPoints[0].y; 266 ++npoints; 267 } 268 269 if (fill) 270 ::Polygon(dc, winPoints, npoints); 271 else 272 ::Polyline(dc, winPoints, npoints); 273 delete[] winPoints; 274 } 275 } 276 } 277 278 279 int PlatformPathElement::numControlPoints() const 280 { 281 switch (m_type) { 282 case PathMoveTo: 283 case PathLineTo: 284 return 1; 285 case PathQuadCurveTo: 286 case PathArcTo: 287 return 2; 288 case PathBezierCurveTo: 289 return 3; 290 default: 291 ASSERT(m_type == PathCloseSubpath); 292 return 0; 293 } 294 } 295 296 int PlatformPathElement::numPoints() const 297 { 298 switch (m_type) { 299 case PathMoveTo: 300 case PathLineTo: 301 case PathArcTo: 302 return 1; 303 case PathQuadCurveTo: 304 return 2; 305 case PathBezierCurveTo: 306 return 3; 307 default: 308 ASSERT(m_type == PathCloseSubpath); 309 return 0; 310 } 311 } 312 313 void PathPolygon::move(const FloatSize& offset) 314 { 315 for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) 316 i->move(offset); 317 } 318 319 void PathPolygon::transform(const AffineTransform& t) 320 { 321 for (Vector<PathPoint>::iterator i = begin(); i < end(); ++i) 322 *i = t.mapPoint(*i); 323 } 324 325 bool PathPolygon::contains(const FloatPoint& point) const 326 { 327 if (size() < 3) 328 return false; 329 330 // Test intersections between the polygon and the vertical line: x = point.x() 331 332 int intersected = 0; 333 const PathPoint* point1 = &last(); 334 Vector<PathPoint>::const_iterator last = end(); 335 // wasNegative: -1 means unknown, 0 means false, 1 means true. 336 int wasNegative = -1; 337 for (Vector<PathPoint>::const_iterator i = begin(); i != last; ++i) { 338 const PathPoint& point2 = *i; 339 if (point1->x() != point.x()) { 340 if (point2.x() == point.x()) { 341 // We are getting on the vertical line 342 wasNegative = point1->x() < point.x() ? 1 : 0; 343 } else if (point2.x() < point.x() != point1->x() < point.x()) { 344 float y = (point2.y() - point1->y()) / (point2.x() - point1->x()) * (point.x() - point1->x()) + point1->y(); 345 if (y >= point.y()) 346 ++intersected; 347 } 348 } else { 349 // We were on the vertical line 350 351 // handle special case 352 if (point1->y() == point.y()) 353 return true; 354 355 if (point1->y() > point.y()) { 356 if (point2.x() == point.x()) { 357 // see if the point is on this segment 358 if (point2.y() <= point.y()) 359 return true; 360 361 // We are still on the line 362 } else { 363 // We are leaving the line now. 364 // We have to get back to see which side we come from. If we come from 365 // the same side we are leaving, no intersection should be counted 366 if (wasNegative < 0) { 367 Vector<PathPoint>::const_iterator jLast = i; 368 Vector<PathPoint>::const_iterator j = i; 369 do { 370 if (j == begin()) 371 j = last; 372 else 373 --j; 374 if (j->x() != point.x()) { 375 if (j->x() > point.x()) 376 wasNegative = 0; 377 else 378 wasNegative = 1; 379 break; 380 } 381 } while (j != jLast); 382 383 if (wasNegative < 0) 384 return false; 385 } 386 if (wasNegative ? point2.x() > point.x() : point2.x() < point.x()) 387 ++intersected; 388 } 389 } else if (point2.x() == point.x() && point2.y() >= point.y()) 390 return true; 391 } 392 point1 = &point2; 393 } 394 395 return intersected & 1; 396 } 397 398 void PlatformPathElement::move(const FloatSize& offset) 399 { 400 int n = numControlPoints(); 401 for (int i = 0; i < n; ++i) 402 m_data.m_points[i].move(offset); 403 } 404 405 void PlatformPathElement::transform(const AffineTransform& t) 406 { 407 int n = numControlPoints(); 408 for (int i = 0; i < n; ++i) { 409 FloatPoint p = t.mapPoint(m_data.m_points[i]); 410 m_data.m_points[i].set(p.x(), p.y()); 411 } 412 } 413 414 void PlatformPathElement::inflateRectToContainMe(FloatRect& r, const FloatPoint& lastPoint) const 415 { 416 if (m_type == PathArcTo) { 417 const ArcTo& data = m_data.m_arcToData; 418 PathPoint startPoint; 419 startPoint = lastPoint; 420 PathPoint endPoint = data.m_end; 421 if (!data.m_clockwise) 422 std::swap(startPoint, endPoint); 423 424 int q0 = quadrant(startPoint, data.m_center); 425 int q1 = quadrant(endPoint, data.m_center); 426 bool containsExtremes[4] = { false }; // bottom, left, top, right 427 static const PathPoint extremeVectors[4] = { { 0, 1 }, { -1, 0 }, { 0, -1 }, { 1, 0 } }; 428 if (q0 == q1) { 429 if (startPoint.m_x == endPoint.m_x || isQuadrantOnBottom(q0) != startPoint.m_x > endPoint.m_x) { 430 for (int i = 0; i < 4; ++i) 431 containsExtremes[i] = true; 432 } 433 } else { 434 int extreme = q0; 435 int diff = quadrantDiff(q1, q0); 436 for (int i = 0; i < diff; ++i) { 437 containsExtremes[extreme] = true; 438 extreme = nextQuadrant(extreme); 439 } 440 } 441 442 inflateRectToContainPoint(r, startPoint.m_x, startPoint.m_y); 443 inflateRectToContainPoint(r, endPoint.m_x, endPoint.m_y); 444 for (int i = 0; i < 4; ++i) { 445 if (containsExtremes[i]) 446 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); 447 } 448 } else { 449 int n = numPoints(); 450 for (int i = 0; i < n; ++i) 451 inflateRectToContainPoint(r, m_data.m_points[i].m_x, m_data.m_points[i].m_y); 452 } 453 } 454 455 PathElementType PlatformPathElement::type() const 456 { 457 switch (m_type) { 458 case PathMoveTo: 459 return PathElementMoveToPoint; 460 case PathLineTo: 461 return PathElementAddLineToPoint; 462 case PathArcTo: 463 // FIXME: there's no arcTo type for PathElement 464 return PathElementAddLineToPoint; 465 // return PathElementAddQuadCurveToPoint; 466 case PathQuadCurveTo: 467 return PathElementAddQuadCurveToPoint; 468 case PathBezierCurveTo: 469 return PathElementAddCurveToPoint; 470 default: 471 ASSERT(m_type == PathCloseSubpath); 472 return PathElementCloseSubpath; 473 } 474 } 475 476 PlatformPath::PlatformPath() 477 : m_penLifted(true) 478 { 479 m_currentPoint.clear(); 480 } 481 482 void PlatformPath::ensureSubpath() 483 { 484 if (m_penLifted) { 485 m_penLifted = false; 486 m_subpaths.append(PathPolygon()); 487 m_subpaths.last().append(m_currentPoint); 488 } else 489 ASSERT(!m_subpaths.isEmpty()); 490 } 491 492 void PlatformPath::addToSubpath(const PlatformPathElement& e) 493 { 494 if (e.platformType() == PlatformPathElement::PathMoveTo) { 495 m_penLifted = true; 496 m_currentPoint = e.pointAt(0); 497 } else if (e.platformType() == PlatformPathElement::PathCloseSubpath) { 498 m_penLifted = true; 499 if (!m_subpaths.isEmpty()) { 500 if (m_currentPoint != m_subpaths.last()[0]) { 501 // According to W3C, we have to draw a line from current point to the initial point 502 m_subpaths.last().append(m_subpaths.last()[0]); 503 m_currentPoint = m_subpaths.last()[0]; 504 } 505 } else 506 m_currentPoint.clear(); 507 } else { 508 ensureSubpath(); 509 switch (e.platformType()) { 510 case PlatformPathElement::PathLineTo: 511 m_subpaths.last().append(e.pointAt(0)); 512 break; 513 case PlatformPathElement::PathArcTo: 514 addArcPoints(m_subpaths.last(), e.arcTo()); 515 break; 516 case PlatformPathElement::PathQuadCurveTo: 517 { 518 PathPoint control[] = { 519 m_currentPoint, 520 e.pointAt(0), 521 e.pointAt(1), 522 }; 523 // FIXME: magic number? 524 quadCurve(50, m_subpaths.last(), control); 525 } 526 break; 527 case PlatformPathElement::PathBezierCurveTo: 528 { 529 PathPoint control[] = { 530 m_currentPoint, 531 e.pointAt(0), 532 e.pointAt(1), 533 e.pointAt(2), 534 }; 535 // FIXME: magic number? 536 bezier(100, m_subpaths.last(), control); 537 } 538 break; 539 default: 540 ASSERT_NOT_REACHED(); 541 break; 542 } 543 m_currentPoint = m_subpaths.last().last(); 544 } 545 } 546 547 void PlatformPath::append(const PlatformPathElement& e) 548 { 549 e.inflateRectToContainMe(m_boundingRect, lastPoint()); 550 addToSubpath(e); 551 m_elements.append(e); 552 } 553 554 void PlatformPath::append(const PlatformPath& p) 555 { 556 const PlatformPathElements& e = p.elements(); 557 for (PlatformPathElements::const_iterator it(e.begin()); it != e.end(); ++it) { 558 addToSubpath(*it); 559 it->inflateRectToContainMe(m_boundingRect, lastPoint()); 560 m_elements.append(*it); 561 } 562 } 563 564 void PlatformPath::clear() 565 { 566 m_elements.clear(); 567 m_boundingRect = FloatRect(); 568 m_subpaths.clear(); 569 m_currentPoint.clear(); 570 m_penLifted = true; 571 } 572 573 void PlatformPath::strokePath(HDC dc, const AffineTransform* transformation) const 574 { 575 drawPolygons(dc, m_subpaths, false, transformation); 576 } 577 578 void PlatformPath::fillPath(HDC dc, const AffineTransform* transformation) const 579 { 580 HGDIOBJ oldPen = SelectObject(dc, GetStockObject(NULL_PEN)); 581 drawPolygons(dc, m_subpaths, true, transformation); 582 SelectObject(dc, oldPen); 583 } 584 585 void PlatformPath::translate(const FloatSize& size) 586 { 587 for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) 588 it->move(size); 589 590 m_boundingRect.move(size); 591 for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) 592 it->move(size); 593 } 594 595 void PlatformPath::transform(const AffineTransform& t) 596 { 597 for (PlatformPathElements::iterator it(m_elements.begin()); it != m_elements.end(); ++it) 598 it->transform(t); 599 600 m_boundingRect = t.mapRect(m_boundingRect); 601 for (Vector<PathPolygon>::iterator it = m_subpaths.begin(); it != m_subpaths.end(); ++it) 602 it->transform(t); 603 } 604 605 bool PlatformPath::contains(const FloatPoint& point, WindRule rule) const 606 { 607 // optimization: check the bounding rect first 608 if (!containsPoint(m_boundingRect, point)) 609 return false; 610 611 for (Vector<PathPolygon>::const_iterator i = m_subpaths.begin(); i != m_subpaths.end(); ++i) { 612 if (i->contains(point)) 613 return true; 614 } 615 616 return false; 617 } 618 619 void PlatformPath::moveTo(const FloatPoint& point) 620 { 621 PlatformPathElement::MoveTo data = { { point.x(), point.y() } }; 622 PlatformPathElement pe(data); 623 append(pe); 624 } 625 626 void PlatformPath::addLineTo(const FloatPoint& point) 627 { 628 PlatformPathElement::LineTo data = { { point.x(), point.y() } }; 629 PlatformPathElement pe(data); 630 append(pe); 631 } 632 633 void PlatformPath::addQuadCurveTo(const FloatPoint& cp, const FloatPoint& p) 634 { 635 PlatformPathElement::QuadCurveTo data = { { cp.x(), cp.y() }, { p.x(), p.y() } }; 636 PlatformPathElement pe(data); 637 append(pe); 638 } 639 640 void PlatformPath::addBezierCurveTo(const FloatPoint& cp1, const FloatPoint& cp2, const FloatPoint& p) 641 { 642 PlatformPathElement::BezierCurveTo data = { { cp1.x(), cp1.y() }, { cp2.x(), cp2.y() }, { p.x(), p.y() } }; 643 PlatformPathElement pe(data); 644 append(pe); 645 } 646 647 void PlatformPath::addArcTo(const FloatPoint& fp1, const FloatPoint& fp2, float radius) 648 { 649 const PathPoint& p0 = m_currentPoint; 650 PathPoint p1; 651 p1 = fp1; 652 PathPoint p2; 653 p2 = fp2; 654 if (!radius || p0 == p1 || p1 == p2) { 655 addLineTo(p1); 656 return; 657 } 658 659 PathVector v01 = p0 - p1; 660 PathVector v21 = p2 - p1; 661 662 // sin(A - B) = sin(A) * cos(B) - sin(B) * cos(A) 663 double cross = v01.m_x * v21.m_y - v01.m_y * v21.m_x; 664 665 if (fabs(cross) < 1E-10) { 666 // on one line 667 addLineTo(p1); 668 return; 669 } 670 671 double d01 = v01.length(); 672 double d21 = v21.length(); 673 double angle = (piDouble - fabs(asin(cross / (d01 * d21)))) * 0.5; 674 double span = radius * tan(angle); 675 double rate = span / d01; 676 PathPoint startPoint; 677 startPoint.m_x = p1.m_x + v01.m_x * rate; 678 startPoint.m_y = p1.m_y + v01.m_y * rate; 679 680 addLineTo(startPoint); 681 682 PathPoint endPoint; 683 rate = span / d21; 684 endPoint.m_x = p1.m_x + v21.m_x * rate; 685 endPoint.m_y = p1.m_y + v21.m_y * rate; 686 687 PathPoint midPoint; 688 midPoint.m_x = (startPoint.m_x + endPoint.m_x) * 0.5; 689 midPoint.m_y = (startPoint.m_y + endPoint.m_y) * 0.5; 690 691 PathVector vm1 = midPoint - p1; 692 double dm1 = vm1.length(); 693 double d = _hypot(radius, span); 694 695 PathPoint centerPoint; 696 rate = d / dm1; 697 centerPoint.m_x = p1.m_x + vm1.m_x * rate; 698 centerPoint.m_y = p1.m_y + vm1.m_y * rate; 699 700 PlatformPathElement::ArcTo data = { 701 endPoint, 702 centerPoint, 703 { radius, radius }, 704 cross < 0 705 }; 706 PlatformPathElement pe(data); 707 append(pe); 708 } 709 710 void PlatformPath::closeSubpath() 711 { 712 PlatformPathElement pe; 713 append(pe); 714 } 715 716 // add a circular arc centred at p with radius r from start angle sar (radians) to end angle ear 717 void PlatformPath::addEllipse(const FloatPoint& p, float a, float b, float sar, float ear, bool anticlockwise) 718 { 719 float startX, startY, endX, endY; 720 721 normalizeAngle(sar); 722 normalizeAngle(ear); 723 724 getEllipsePointByAngle(sar, a, b, startX, startY); 725 getEllipsePointByAngle(ear, a, b, endX, endY); 726 727 transformArcPoint(startX, startY, p); 728 transformArcPoint(endX, endY, p); 729 730 FloatPoint start(startX, startY); 731 moveTo(start); 732 733 PlatformPathElement::ArcTo data = { { endX, endY }, { p.x(), p.y() }, { a, b }, !anticlockwise }; 734 PlatformPathElement pe(data); 735 append(pe); 736 } 737 738 739 void PlatformPath::addRect(const FloatRect& r) 740 { 741 moveTo(r.location()); 742 743 float right = r.maxX() - 1; 744 float bottom = r.maxY() - 1; 745 addLineTo(FloatPoint(right, r.y())); 746 addLineTo(FloatPoint(right, bottom)); 747 addLineTo(FloatPoint(r.x(), bottom)); 748 addLineTo(r.location()); 749 } 750 751 void PlatformPath::addEllipse(const FloatRect& r) 752 { 753 FloatSize radius(r.width() * 0.5, r.height() * 0.5); 754 addEllipse(r.location() + radius, radius.width(), radius.height(), 0, 0, true); 755 } 756 757 void PlatformPath::apply(void* info, PathApplierFunction function) const 758 { 759 PathElement pelement; 760 FloatPoint points[3]; 761 pelement.points = points; 762 763 for (PlatformPathElements::const_iterator it(m_elements.begin()); it != m_elements.end(); ++it) { 764 pelement.type = it->type(); 765 int n = it->numPoints(); 766 for (int i = 0; i < n; ++i) 767 points[i] = it->pointAt(i); 768 function(info, &pelement); 769 } 770 } 771 772 } // namespace Webcore 773