1 /* 2 * Copyright (c) 2011, 2015, 2016, Oracle and/or its affiliates. All rights reserved. 3 */ 4 #include "config.h" 5 #include <math.h> 6 #include <stdio.h> 7 #include <wtf/MathExtras.h> 8 #include <wtf/Vector.h> 9 10 #include "AffineTransform.h" 11 #include "Color.h" 12 #include "FloatRect.h" 13 #include "FloatSize.h" 14 #include "FloatRoundedRect.h" 15 #include "Font.h" 16 #include "FontRanges.h" //XXX: FontData.h -> FontRanges.h 17 #include "GraphicsContext.h" 18 #include "GraphicsContextJava.h" 19 #include "Gradient.h" 20 #include "IntRect.h" 21 #include "JavaEnv.h" 22 #include "Logging.h" 23 #include "NotImplemented.h" 24 #include "Path.h" 25 #include "Pattern.h" 26 #include "RenderingQueue.h" 27 #include "Font.h" //XXX: SimpleFontData.h -> Font.h 28 #include "TransformationMatrix.h" 29 30 #include "com_sun_webkit_graphics_GraphicsDecoder.h" 31 #include "com_sun_webkit_graphics_WCPath.h" 32 33 34 #ifndef M_PI 35 #define M_PI 3.14159265358979323846 36 #endif 37 38 namespace WebCore { 39 40 41 static void setGradient(Gradient &gradient, PlatformGraphicsContext* context, jint id) 42 { 43 Vector<Gradient::ColorStop, 2> stops = gradient.getStops(); //XXX recheck; 44 int nStops = stops.size(); 45 46 AffineTransform gt = gradient.gradientSpaceTransform(); 47 FloatPoint p0(gt.mapPoint(gradient.p0())); 48 FloatPoint p1(gt.mapPoint(gradient.p1())); 49 50 context->rq().freeSpace(4 * 11 + 8 * nStops) 51 << id 52 << (jfloat)p0.x() 53 << (jfloat)p0.y() 54 << (jfloat)p1.x() 55 << (jfloat)p1.y() 56 << (jint)gradient.isRadial(); 57 58 if (gradient.isRadial()) { 59 context->rq() 60 << (jfloat)(gt.xScale()*gradient.startRadius()) 61 << (jfloat)(gt.xScale()*gradient.endRadius()); 62 } 63 context->rq() 64 << (jint)0 //is not proportional 65 << (jint)gradient.spreadMethod() 66 << (jint)nStops; 67 68 for (int i = 0; i < nStops; i++) { 69 Gradient::ColorStop cs = stops[i]; 70 int rgba = 71 ((int)(cs.alpha * 255 + 0.5)) << 24 | 72 ((int)(cs.red * 255 + 0.5)) << 16 | 73 ((int)(cs.green * 255 + 0.5)) << 8 | 74 ((int)(cs.blue * 255 + 0.5)); 75 76 context->rq() 77 << (jint)rgba << (jfloat)cs.stop; 78 } 79 } 80 81 class GraphicsContextPlatformPrivate : public PlatformGraphicsContext { 82 }; 83 84 void GraphicsContext::platformInit(PlatformGraphicsContext* context) //XXX , bool shouldUseContextColors) // todo tav new param 85 { 86 m_data = static_cast<GraphicsContextPlatformPrivate *>(context); 87 } 88 89 PlatformGraphicsContext* GraphicsContext::platformContext() const 90 { 91 return m_data; 92 } 93 94 void GraphicsContext::platformDestroy() 95 { 96 delete m_data; 97 } 98 99 void GraphicsContext::savePlatformState() 100 { 101 if (paintingDisabled()) 102 return; 103 104 platformContext()->rq().freeSpace(4) 105 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SAVESTATE; 106 } 107 108 void GraphicsContext::restorePlatformState() 109 { 110 if (paintingDisabled()) 111 return; 112 113 platformContext()->rq().freeSpace(4) 114 << (jint)com_sun_webkit_graphics_GraphicsDecoder_RESTORESTATE; 115 } 116 117 // Draws a filled rectangle with a stroked border. 118 void GraphicsContext::drawRect(const FloatRect& rect, float borderThickness) // todo tav rect changed from IntRect to FloatRect 119 { 120 if (paintingDisabled()) 121 return; 122 123 platformContext()->rq().freeSpace(20) 124 << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWRECT 125 << (jint)rect.x() << (jint)rect.y() << (jint)rect.width() << (jint)rect.height(); 126 } 127 128 // FIXME: Now that this is refactored, it should be shared by all contexts. 129 static void adjustLineToPixelBoundaries(FloatPoint& p1, FloatPoint& p2, float strokeWidth, StrokeStyle style) 130 { 131 // For odd widths, we add in 0.5 to the appropriate x/y so that the float arithmetic 132 // works out. For example, with a border width of 3, KHTML will pass us (y1+y2)/2, e.g., 133 // (50+53)/2 = 103/2 = 51 when we want 51.5. It is always true that an even width gave 134 // us a perfect position, but an odd width gave us a position that is off by exactly 0.5. 135 if (style == DottedStroke || style == DashedStroke) { 136 if (p1.x() == p2.x()) { 137 p1.setY(p1.y() + strokeWidth); 138 p2.setY(p2.y() - strokeWidth); 139 } 140 else { 141 p1.setX(p1.x() + strokeWidth); 142 p2.setX(p2.x() - strokeWidth); 143 } 144 } 145 146 if (static_cast<int>(strokeWidth) % 2) { 147 if (p1.x() == p2.x()) { 148 // We're a vertical line. Adjust our x. 149 p1.setX(p1.x() + 0.5); 150 p2.setX(p2.x() + 0.5); 151 } 152 else { 153 // We're a horizontal line. Adjust our y. 154 p1.setY(p1.y() + 0.5); 155 p2.setY(p2.y() + 0.5); 156 } 157 } 158 } 159 160 // This is only used to draw borders. 161 void GraphicsContext::drawLine(const FloatPoint& point1, const FloatPoint& point2) // todo tav points changed from IntPoint to FloatPoint 162 { 163 if (paintingDisabled() || strokeStyle() == NoStroke) 164 return; 165 166 platformContext()->rq().freeSpace(20) 167 << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWLINE 168 << (jint)point1.x() << (jint)point1.y() << (jint)point2.x() << (jint)point2.y(); 169 } 170 171 // This method is only used to draw the little circles used in lists. 172 void GraphicsContext::drawEllipse(const FloatRect& rect) 173 { 174 if (paintingDisabled()) 175 return; 176 177 platformContext()->rq().freeSpace(20) 178 << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWELLIPSE 179 << (jint)rect.x() << (jint)rect.y() << (jint)rect.width() << (jint)rect.height(); //XXX float to int conversion 180 } 181 182 // FIXME: This function needs to be adjusted to match the functionality on the Mac side. 183 //void GraphicsContext::strokeArc(const IntRect& rect, int startAngle, int angleSpan) 184 //{ 185 // if (paintingDisabled() || strokeStyle() == NoStroke) 186 // return; 187 // 188 // platformContext()->rq().freeSpace(28) 189 // << (jint)com_sun_webkit_graphics_GraphicsDecoder_STROKEARC 190 // << (jint)rect.x() << (jint)rect.y() << (jint)rect.width() << (jint)rect.height() 191 // << (jint)startAngle << (jint)angleSpan; 192 //} 193 194 void GraphicsContext::drawConvexPolygon(size_t npoints, const FloatPoint* points, bool shouldAntialias) 195 { 196 if (paintingDisabled() || npoints <= 1) 197 return; 198 199 Path path; 200 path.moveTo(FloatPoint(points[0].x(), points[0].y())); 201 for (int i = 1; i < npoints; i++) { 202 path.addLineTo(FloatPoint(points[i].x(), points[i].y())); 203 } 204 path.closeSubpath(); 205 platformContext()->rq().freeSpace(12) 206 << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWPOLYGON 207 << copyPath(path.platformPath()) 208 << (jint)com_sun_webkit_graphics_WCPath_RULE_NONZERO // default rule for the path 209 << (jint)((shouldAntialias)?-1:0); 210 } 211 212 void GraphicsContext::fillRect(const FloatRect& rect, const Color& color, ColorSpace) 213 { 214 if (paintingDisabled()) 215 return; 216 217 platformContext()->rq().freeSpace(24) 218 << (jint)com_sun_webkit_graphics_GraphicsDecoder_FILLRECT_FFFFI 219 << rect.x() << rect.y() 220 << rect.width() << rect.height() 221 << (jint)color.rgb(); 222 } 223 224 void GraphicsContext::fillRect(const FloatRect& rect) 225 { 226 if (paintingDisabled()) 227 return; 228 229 if (m_state.fillPattern && m_state.fillPattern->tileImage()) { 230 Image *img = m_state.fillPattern->tileImage(); 231 FloatRect destRect( 232 rect.x(), 233 rect.y(), 234 m_state.fillPattern->repeatX() ? rect.width() : img->width(), 235 m_state.fillPattern->repeatY() ? rect.height() : img->height()); 236 img->drawPattern( 237 this, 238 FloatRect(0., 0., img->width(), img->height()), 239 m_state.fillPattern->getPatternSpaceTransform(), 240 FloatPoint(), 241 ColorSpaceDeviceRGB, //any 242 CompositeCopy, //any 243 destRect); 244 } else { 245 if (m_state.fillGradient) { 246 setGradient( 247 *m_state.fillGradient, 248 platformContext(), 249 com_sun_webkit_graphics_GraphicsDecoder_SET_FILL_GRADIENT); 250 } 251 252 platformContext()->rq().freeSpace(20) 253 << (jint)com_sun_webkit_graphics_GraphicsDecoder_FILLRECT_FFFF 254 << rect.x() << rect.y() 255 << rect.width() << rect.height(); 256 } 257 } 258 259 void GraphicsContext::clip(const FloatRect& rect) 260 { 261 if (paintingDisabled()) 262 return; 263 264 m_state.clipBounds.intersect(m_state.transform.mapRect(rect)); 265 platformContext()->rq().freeSpace(20) 266 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETCLIP_IIII 267 << (jint)rect.x() << (jint)rect.y() << (jint)rect.width() << (jint)rect.height(); 268 } 269 270 IntRect GraphicsContext::clipBounds() const 271 { 272 // Transformation has inverse effect on clip bounds. 273 return enclosingIntRect(m_state.transform.inverse().mapRect(m_state.clipBounds)); 274 } 275 276 void GraphicsContext::clipConvexPolygon(size_t numberOfPoints, const FloatPoint* points, bool antialias) 277 { 278 if (paintingDisabled() || numberOfPoints <= 1) 279 return; 280 281 bool oldAntialias = shouldAntialias(); 282 if (oldAntialias != antialias) 283 setPlatformShouldAntialias(antialias); 284 285 Path path; 286 path.moveTo(points[0]); 287 for (size_t i = 1; i < numberOfPoints; ++i) 288 path.addLineTo(points[i]); 289 path.closeSubpath(); 290 291 clipPath(path, RULE_NONZERO); 292 293 if (oldAntialias != antialias) 294 setPlatformShouldAntialias(oldAntialias); 295 } 296 297 void GraphicsContext::drawFocusRing(const Path&, int width, int offset, const Color&) 298 { 299 //utaTODO: IMPLEMENT!!! 300 } 301 302 void GraphicsContext::drawFocusRing(const Vector<IntRect>& rects, int width, int offset, const Color& color) 303 { 304 if (paintingDisabled()) 305 return; 306 307 unsigned rectCount = rects.size(); 308 // We can't draw all the focus rects because webkit can have several rings 309 // nested into each other. We can't draw a union of all the rects as well 310 // as it results in the problems like 6683162. An alternative could be to 311 // construct a Path object, add all the focus rings to it and then 312 // "flatten" it, but it can only be done with Area classes which are not 313 // available here. That's why a simple algorithm here: unite all the 314 // intersecting rects, while leaving standalone rects as is. 315 Vector<IntRect> toDraw; 316 for (unsigned i = 0; i < rectCount; i++) { 317 IntRect focusRect = rects[i]; 318 focusRect.inflate(offset); 319 bool needAdd = true; 320 for (int j = 0; j < toDraw.size(); j++) { 321 IntRect rect = toDraw[j]; 322 if (rect.contains(focusRect)) { 323 needAdd = false; 324 break; 325 } else if (focusRect.contains(rect)) { 326 toDraw.remove(j); 327 } else if (rect.intersects(focusRect)) { 328 focusRect.unite(rect); 329 toDraw.remove(j); 330 } 331 } 332 if (needAdd) { 333 toDraw.append(focusRect); 334 } 335 } 336 337 platformContext()->rq().freeSpace(24*toDraw.size()); 338 for (int i = 0; i < toDraw.size(); i++) { 339 IntRect focusRect = toDraw[i]; 340 platformContext()->rq() << (jint)com_sun_webkit_graphics_GraphicsDecoder_DRAWFOCUSRING 341 << (jint)focusRect.x() << (jint)focusRect.y() 342 << (jint)focusRect.width() << (jint)focusRect.height() 343 << (jint)color.rgb(); 344 } 345 } 346 347 FloatRect GraphicsContext::computeLineBoundsForText(const FloatPoint& point, float width, bool printing) 348 { 349 // NotImplemented(); // todo tav implement 350 return FloatRect(); 351 } 352 353 void GraphicsContext::updateDocumentMarkerResources() 354 { 355 // NotImplemented(); // todo tav implement 356 } 357 358 void GraphicsContext::drawLineForText(const FloatPoint& origin, float width, bool printing, bool doubleLines) 359 { 360 if (paintingDisabled() || width <= 0) 361 return; 362 363 // This is a workaround for http://bugs.webkit.org/show_bug.cgi?id=15659 364 StrokeStyle savedStrokeStyle = strokeStyle(); 365 setStrokeStyle(SolidStroke); 366 367 FloatPoint endPoint = origin + FloatPoint(width, 0); 368 drawLine( 369 IntPoint(origin.x(), origin.y()), 370 IntPoint(endPoint.x(), endPoint.y())); 371 372 setStrokeStyle(savedStrokeStyle); 373 } 374 375 static inline void drawLineTo(GraphicsContext &gc, IntPoint &curPos, double x, double y) 376 { 377 IntPoint endPoint(x, y); 378 gc.drawLine(curPos, endPoint); 379 curPos = endPoint; 380 } 381 382 // 383 // Draws an error underline that looks like one of: 384 // 385 // H E H 386 // /\ /\ /\ /\ /\ - 387 // A/ \ / \ / \ A/ \ / \ | 388 // \ \ / \ / /D \ \ / \ | 389 // \ \/ C \/ / \ \/ C \ | height = heightSquares * square 390 // \ /\ F / \ F /\ \ | 391 // \ / \ / \ / \ \G | 392 // \ / \ / \ / \ / | 393 // \/ \/ \/ \/ - 394 // B B 395 // |---| 396 // unitWidth = (heightSquares - 1) * square 397 // 398 // The x, y, width, height passed in give the desired bounding box; 399 // x/width are adjusted to make the underline a integer number of units 400 // wide. 401 // 402 static inline void drawErrorUnderline(GraphicsContext &gc, double x, double y, double width, double height) 403 { 404 static const double heightSquares = 2.5; 405 406 double square = height / heightSquares; 407 double halfSquare = 0.5 * square; 408 409 double unitWidth = (heightSquares - 1.0) * square; 410 int widthUnits = static_cast<int>((width + 0.5 * unitWidth) / unitWidth); 411 412 x += 0.5 * (width - widthUnits * unitWidth); 413 width = widthUnits * unitWidth; 414 415 double bottom = y + height; 416 double top = y; 417 418 // Bottom of squiggle 419 IntPoint curPos(x - halfSquare, top + halfSquare); // A 420 421 int i = 0; 422 for (i = 0; i < widthUnits; i += 2) { 423 double middle = x + (i + 1) * unitWidth; 424 double right = x + (i + 2) * unitWidth; 425 426 drawLineTo(gc, curPos, middle, bottom); // B 427 428 if (i + 2 == widthUnits) 429 drawLineTo(gc, curPos, right + halfSquare, top + halfSquare); // D 430 else if (i + 1 != widthUnits) 431 drawLineTo(gc, curPos, right, top + square); // C 432 } 433 434 // Top of squiggle 435 for (i -= 2; i >= 0; i -= 2) { 436 double left = x + i * unitWidth; 437 double middle = x + (i + 1) * unitWidth; 438 double right = x + (i + 2) * unitWidth; 439 440 if (i + 1 == widthUnits) 441 drawLineTo(gc, curPos, middle + halfSquare, bottom - halfSquare); // G 442 else { 443 if (i + 2 == widthUnits) 444 drawLineTo(gc, curPos, right, top); // E 445 446 drawLineTo(gc, curPos, middle, bottom - halfSquare); // F 447 } 448 449 drawLineTo(gc, curPos, left, top); // H 450 } 451 } 452 453 void GraphicsContext::drawLineForDocumentMarker(const FloatPoint& origin, float width, DocumentMarkerLineStyle style) 454 { 455 savePlatformState(); //fake stroke 456 switch (style) { //XXX: DocumentMarkerAutocorrectionReplacementLineStyle not handled in switch 457 case DocumentMarkerSpellingLineStyle: 458 { 459 static Color red(255, 0, 0); 460 setStrokeColor(red, ColorSpaceDeviceRGB); 461 } 462 break; 463 case DocumentMarkerGrammarLineStyle: 464 { 465 static Color green(0, 255, 0); 466 setStrokeColor(green, ColorSpaceDeviceRGB); 467 } 468 break; 469 } 470 drawErrorUnderline(*this, origin.x(), origin.y(), width, cMisspellingLineThickness); 471 restorePlatformState(); //fake stroke 472 } 473 474 FloatRect GraphicsContext::roundToDevicePixels(const FloatRect& frect, RoundingMode) 475 { 476 FloatRect result; 477 result.setX(static_cast<float>(round(frect.x()))); 478 result.setY(static_cast<float>(round(frect.y()))); 479 result.setWidth(static_cast<float>(round(frect.width()))); 480 result.setHeight(static_cast<float>(round(frect.height()))); 481 return result; 482 } 483 484 void GraphicsContext::translate(float x, float y) 485 { 486 if (paintingDisabled()) 487 return; 488 489 m_state.transform.translate(x, y); 490 platformContext()->rq().freeSpace(12) 491 << (jint)com_sun_webkit_graphics_GraphicsDecoder_TRANSLATE 492 << x << y; 493 } 494 495 void GraphicsContext::setPlatformFillColor(const Color& col, ColorSpace) 496 { 497 if (paintingDisabled()) 498 return; 499 500 platformContext()->rq().freeSpace(8) 501 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETFILLCOLOR 502 << (jint)col.rgb(); 503 } 504 505 506 507 const Vector<Gradient::ColorStop, 2>& Gradient::getStops() const 508 { 509 return m_stops; 510 } 511 512 void GraphicsContext::setPlatformTextDrawingMode(TextDrawingModeFlags mode) 513 { 514 if (paintingDisabled()) 515 return; 516 517 platformContext()->rq().freeSpace(16) 518 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_TEXT_MODE 519 << (jint)(mode & TextModeFill) 520 << (jint)(mode & TextModeStroke) 521 << (jint)0; 522 //utatodo: 523 //<< (jint)(mode & TextModeClip); 524 } 525 526 void GraphicsContext::setPlatformStrokeStyle(StrokeStyle style) 527 { 528 if (paintingDisabled()) 529 return; 530 531 platformContext()->rq().freeSpace(8) 532 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETSTROKESTYLE 533 << (jint)style; 534 } 535 536 void GraphicsContext::setPlatformStrokeColor(const Color& col, ColorSpace) 537 { 538 if (paintingDisabled()) 539 return; 540 541 platformContext()->rq().freeSpace(8) 542 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETSTROKECOLOR 543 << (jint)col.rgb(); 544 } 545 546 void GraphicsContext::setPlatformStrokeThickness(float strokeThickness) 547 { 548 if (paintingDisabled()) 549 return; 550 551 platformContext()->rq().freeSpace(8) 552 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETSTROKEWIDTH 553 << strokeThickness; 554 } 555 556 void GraphicsContext::setImageInterpolationQuality(InterpolationQuality interpolationQuality) 557 { 558 m_state.interpolationQuality = interpolationQuality; 559 } 560 561 InterpolationQuality GraphicsContext::imageInterpolationQuality() const 562 { 563 return m_state.interpolationQuality; 564 } 565 566 void GraphicsContext::setPlatformShouldAntialias(bool b) 567 { 568 notImplemented(); 569 } 570 571 void GraphicsContext::setURLForRect(const URL& link, const IntRect& destRect) 572 { 573 notImplemented(); 574 } 575 576 void GraphicsContext::concatCTM(const AffineTransform& at) 577 { 578 if (paintingDisabled()) 579 return; 580 581 m_state.transform.multiply(at); 582 platformContext()->rq().freeSpace(28) 583 << (jint)com_sun_webkit_graphics_GraphicsDecoder_CONCATTRANSFORM_FFFFFF 584 << (float)at.a() << (float)at.b() << (float)at.c() << (float)at.d() << (float)at.e() << (float)at.f(); 585 } 586 587 //void GraphicsContext::addInnerRoundedRectClip(const IntRect& r, int thickness) 588 //{ 589 // if (paintingDisabled()) 590 // return; 591 // 592 // FloatRect rect(r); 593 // Path path; 594 // path.addEllipse(rect); 595 // rect.inflate(-thickness); 596 // path.addEllipse(rect); 597 // clipPath(path, RULE_EVENODD); 598 //} 599 600 void GraphicsContext::setPlatformShadow(const FloatSize& s, float blur, const Color& color, ColorSpace) 601 { 602 if (paintingDisabled()) 603 return; 604 605 float width = s.width(); 606 float height = s.height(); 607 if (shadowsIgnoreTransforms()) { 608 // Meaning that this graphics context is associated with a CanvasRenderingContext 609 // We flip the height since JavaFX Prism and HTML5 Canvas have opposite Y axis 610 height = -height; 611 } 612 613 platformContext()->rq().freeSpace(20) 614 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETSHADOW 615 << width << height << blur << (jint)color.rgb(); 616 } 617 618 void GraphicsContext::clearPlatformShadow() 619 { 620 setPlatformShadow(FloatSize(0, 0), 0, Color(), ColorSpaceDeviceRGB /* ? */); 621 } 622 623 bool GraphicsContext::supportsTransparencyLayers() 624 { 625 return true; 626 } 627 628 void GraphicsContext::beginPlatformTransparencyLayer(float opacity) 629 { 630 if (paintingDisabled()) 631 return; 632 633 platformContext()->rq().freeSpace(8) 634 << (jint)com_sun_webkit_graphics_GraphicsDecoder_BEGINTRANSPARENCYLAYER 635 << opacity; 636 } 637 638 void GraphicsContext::endPlatformTransparencyLayer() 639 { 640 if (paintingDisabled()) 641 return; 642 643 platformContext()->rq().freeSpace(4) 644 << (jint)com_sun_webkit_graphics_GraphicsDecoder_ENDTRANSPARENCYLAYER; 645 } 646 647 void GraphicsContext::clearRect(const FloatRect& rect) 648 { 649 if (paintingDisabled()) 650 return; 651 652 platformContext()->rq().freeSpace(20) 653 << (jint)com_sun_webkit_graphics_GraphicsDecoder_CLEARRECT_FFFF 654 << rect.x() << rect.y() 655 << rect.width() << rect.height(); 656 } 657 658 void GraphicsContext::strokeRect(const FloatRect& rect, float lineWidth) 659 { 660 if (paintingDisabled()) 661 return; 662 663 if (m_state.strokeGradient) { 664 setGradient( 665 *m_state.strokeGradient, 666 platformContext(), 667 com_sun_webkit_graphics_GraphicsDecoder_SET_STROKE_GRADIENT); 668 } 669 670 platformContext()->rq().freeSpace(24) 671 << (jint)com_sun_webkit_graphics_GraphicsDecoder_STROKERECT_FFFFF 672 << rect.x() << rect.y() << rect.width() << rect.height() << lineWidth; 673 } 674 675 void GraphicsContext::setLineDash(const DashArray& dashes, float dashOffset) 676 { 677 if (paintingDisabled()) { 678 return; 679 } 680 size_t size = dashes.size(); 681 682 platformContext()->rq().freeSpace((3 + size) * 4) 683 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_LINE_DASH 684 << dashOffset 685 << (jint)size; 686 687 for (size_t i = 0; i < size; i++) { 688 platformContext()->rq() 689 << dashes.at(i); 690 } 691 } 692 693 void GraphicsContext::setLineCap(LineCap cap) 694 { 695 if (paintingDisabled()) { 696 return; 697 } 698 699 platformContext()->rq().freeSpace(8) 700 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_LINE_CAP 701 << (jint)cap; 702 } 703 704 void GraphicsContext::setLineJoin(LineJoin join) 705 { 706 if (paintingDisabled()) 707 return; 708 709 platformContext()->rq().freeSpace(8) 710 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_LINE_JOIN 711 << (jint)join; 712 } 713 714 void GraphicsContext::setMiterLimit(float limit) 715 { 716 if (paintingDisabled()) 717 return; 718 719 platformContext()->rq().freeSpace(8) 720 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_MITER_LIMIT 721 << (jfloat)limit; 722 } 723 724 void GraphicsContext::setAlpha(float alpha) 725 { 726 m_state.globalAlpha = alpha; 727 platformContext()->rq().freeSpace(8) 728 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETALPHA 729 << alpha; 730 } 731 732 float GraphicsContext::getAlpha() 733 { 734 return m_state.globalAlpha; 735 } 736 737 void GraphicsContext::setPlatformCompositeOperation(CompositeOperator op, BlendMode bm) 738 { 739 if (paintingDisabled()) 740 return; 741 742 platformContext()->rq().freeSpace(8) 743 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SETCOMPOSITE 744 << (jint)op; 745 //utatodo: add BlendMode 746 } 747 748 void GraphicsContext::strokePath(const Path& path) 749 { 750 if (paintingDisabled()) 751 return; 752 753 if (m_state.strokeGradient) { 754 setGradient( 755 *m_state.strokeGradient, 756 platformContext(), 757 com_sun_webkit_graphics_GraphicsDecoder_SET_STROKE_GRADIENT); 758 } 759 760 platformContext()->rq().freeSpace(12) 761 << (jint)com_sun_webkit_graphics_GraphicsDecoder_STROKE_PATH 762 << copyPath(path.platformPath()) 763 << (jint)fillRule(); 764 } 765 766 static void setClipPath( 767 GraphicsContext &gc, 768 GraphicsContextState& state, 769 const Path& path, 770 WindRule wrule, 771 bool isOut) 772 { 773 if (gc.paintingDisabled() || path.isEmpty()) 774 return; 775 776 state.clipBounds.intersect(state.transform.mapRect(path.fastBoundingRect())); 777 gc.platformContext()->rq().freeSpace(16) 778 << jint(com_sun_webkit_graphics_GraphicsDecoder_CLIP_PATH) 779 << copyPath(path.platformPath()) 780 << jint(wrule == RULE_EVENODD 781 ? com_sun_webkit_graphics_WCPath_RULE_EVENODD 782 : com_sun_webkit_graphics_WCPath_RULE_NONZERO) 783 << jint(isOut); 784 } 785 786 void GraphicsContext::canvasClip(const Path& path, WindRule fillRule) 787 { 788 clip(path, fillRule); 789 } 790 791 void GraphicsContext::clip(const Path& path, WindRule wrule) 792 { 793 setClipPath(*this, m_state, path, wrule, false); 794 } 795 796 void GraphicsContext::clipPath(const Path &path, WindRule wrule) 797 { 798 setClipPath(*this, m_state, path, wrule, false); 799 } 800 801 void GraphicsContext::clipOut(const Path& path) 802 { 803 setClipPath(*this, m_state, path, RULE_EVENODD, true); 804 } 805 806 void GraphicsContext::clipOut(const FloatRect& rect) 807 { 808 Path path; 809 path.addRoundedRect(rect, FloatSize()); 810 clipOut(path); 811 } 812 813 void GraphicsContext::fillPath(const Path& path) 814 { 815 if (paintingDisabled()) 816 return; 817 818 if (m_state.fillPattern && m_state.fillPattern->tileImage()) { 819 savePlatformState(); //fake clip isolation 820 clipPath(path, m_state.fillRule); 821 FloatRect rect(path.boundingRect()); 822 823 Image *img = m_state.fillPattern->tileImage(); 824 FloatRect destRect( 825 rect.x(), 826 rect.y(), 827 m_state.fillPattern->repeatX() ? rect.width() : img->width(), 828 m_state.fillPattern->repeatY() ? rect.height() : img->height()); 829 img->drawPattern( 830 this, 831 FloatRect(0., 0., img->width(), img->height()), 832 m_state.fillPattern->getPatternSpaceTransform(), 833 FloatPoint(), 834 ColorSpaceDeviceRGB, //any 835 CompositeCopy, //any 836 destRect); 837 restorePlatformState(); 838 } else { 839 if (m_state.fillGradient) { 840 setGradient( 841 *m_state.fillGradient, 842 platformContext(), 843 com_sun_webkit_graphics_GraphicsDecoder_SET_FILL_GRADIENT); 844 } 845 846 platformContext()->rq().freeSpace(12) 847 << (jint)com_sun_webkit_graphics_GraphicsDecoder_FILL_PATH 848 << copyPath(path.platformPath()) 849 << (jint)fillRule(); 850 } 851 } 852 853 void GraphicsContext::rotate(float radians) 854 { 855 if (paintingDisabled()) 856 return; 857 858 m_state.transform.rotate(radians); 859 platformContext()->rq().freeSpace(2 * 4) 860 << (jint)com_sun_webkit_graphics_GraphicsDecoder_ROTATE 861 << radians; 862 863 } 864 865 void GraphicsContext::scale(const FloatSize& size) 866 { 867 if (paintingDisabled()) 868 return; 869 870 m_state.transform.scale(size.width(), size.height()); 871 platformContext()->rq().freeSpace(12) 872 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SCALE 873 << size.width() << size.height(); 874 } 875 876 void GraphicsContext::fillRoundedRect(const FloatRoundedRect& rect, const Color& color, ColorSpace, BlendMode) // todo tav Int to Float 877 { 878 if (paintingDisabled()) 879 return; 880 881 platformContext()->rq().freeSpace(56) 882 << (jint)com_sun_webkit_graphics_GraphicsDecoder_FILL_ROUNDED_RECT 883 << (jfloat)rect.rect().x() << (jfloat)rect.rect().y() 884 << (jfloat)rect.rect().width() << (jfloat)rect.rect().height() 885 << (jfloat)rect.radii().topLeft().width() << (jfloat)rect.radii().topLeft().height() 886 << (jfloat)rect.radii().topRight().width() << (jfloat)rect.radii().topRight().height() 887 << (jfloat)rect.radii().bottomLeft().width() << (jfloat)rect.radii().bottomLeft().height() 888 << (jfloat)rect.radii().bottomRight().width() << (jfloat)rect.radii().bottomRight().height() 889 << (jint)color.rgb(); 890 } 891 892 #if ENABLE(3D_RENDERING) && USE(TEXTURE_MAPPER) 893 TransformationMatrix GraphicsContext::get3DTransform() const 894 { 895 // FIXME: Can we approximate the transformation better than this? 896 return getCTM().toTransformationMatrix(); 897 } 898 899 void GraphicsContext::concat3DTransform(const TransformationMatrix& transform) 900 { 901 concatCTM(transform.toAffineTransform()); 902 } 903 904 void GraphicsContext::set3DTransform(const TransformationMatrix& transform) 905 { 906 setCTM(transform.toAffineTransform()); 907 } 908 #endif 909 910 //utatodo: do we need the Java-only m_state.transform? 911 AffineTransform GraphicsContext::getCTM(IncludeDeviceScale) const 912 { 913 return m_state.transform; 914 } 915 916 917 void GraphicsContext::setCTM(const AffineTransform& tm) 918 { 919 if (paintingDisabled()) 920 return; 921 922 m_state.transform = tm; 923 platformContext()->rq().freeSpace(28) 924 << (jint)com_sun_webkit_graphics_GraphicsDecoder_SET_TRANSFORM 925 << (float)tm.a() << (float)tm.b() << (float)tm.c() << (float)tm.d() << (float)tm.e() << (float)tm.f(); 926 } 927 928 void Gradient::platformDestroy() 929 { 930 } 931 932 void Gradient::fill(GraphicsContext *gc, const FloatRect &rect) 933 { 934 gc->setFillGradient(*this); 935 gc->fillRect(rect); 936 } 937 938 } // namespace WebCore