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