1 /* 2 * Copyright (C) Research In Motion Limited 2009-2010. All rights reserved. 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 "PainterOpenVG.h" 22 23 #include "AffineTransform.h" 24 #include "Color.h" 25 #include "DashArray.h" 26 #include "FloatPoint.h" 27 #include "FloatQuad.h" 28 #include "FloatRect.h" 29 #include "IntRect.h" 30 #include "IntSize.h" 31 #include "NotImplemented.h" 32 #include "PlatformPathOpenVG.h" 33 #include "SurfaceOpenVG.h" 34 #include "TiledImageOpenVG.h" 35 #include "VGUtils.h" 36 37 #if PLATFORM(EGL) 38 #include "EGLUtils.h" 39 #endif 40 41 #include <vgu.h> 42 43 #include <wtf/Assertions.h> 44 #include <wtf/MathExtras.h> 45 46 namespace WebCore { 47 48 static bool isNonRotatedAffineTransformation(const AffineTransform& t) 49 { 50 return t.b() <= FLT_EPSILON && t.c() <= FLT_EPSILON; 51 } 52 53 static VGCapStyle toVGCapStyle(LineCap lineCap) 54 { 55 switch (lineCap) { 56 case RoundCap: 57 return VG_CAP_ROUND; 58 case SquareCap: 59 return VG_CAP_SQUARE; 60 case ButtCap: 61 default: 62 return VG_CAP_BUTT; 63 } 64 } 65 66 static VGJoinStyle toVGJoinStyle(LineJoin lineJoin) 67 { 68 switch (lineJoin) { 69 case RoundJoin: 70 return VG_JOIN_ROUND; 71 case BevelJoin: 72 return VG_JOIN_BEVEL; 73 case MiterJoin: 74 default: 75 return VG_JOIN_MITER; 76 } 77 } 78 79 static VGFillRule toVGFillRule(WindRule fillRule) 80 { 81 return fillRule == RULE_EVENODD ? VG_EVEN_ODD : VG_NON_ZERO; 82 } 83 84 static VGuint colorToVGColor(const Color& color) 85 { 86 VGuint vgColor = color.red(); 87 vgColor = (vgColor << 8) | color.green(); 88 vgColor = (vgColor << 8) | color.blue(); 89 vgColor = (vgColor << 8) | color.alpha(); 90 return vgColor; 91 } 92 93 static void setVGSolidColor(VGPaintMode paintMode, const Color& color) 94 { 95 VGPaint paint = vgCreatePaint(); 96 vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); 97 vgSetColor(paint, colorToVGColor(color)); 98 vgSetPaint(paint, paintMode); 99 vgDestroyPaint(paint); 100 ASSERT_VG_NO_ERROR(); 101 } 102 103 104 struct PlatformPainterState { 105 AffineTransform surfaceTransformation; 106 CompositeOperator compositeOperation; 107 float opacity; 108 109 bool scissoringEnabled; 110 FloatRect scissorRect; 111 #ifdef OPENVG_VERSION_1_1 112 bool maskingChangedAndEnabled; 113 VGMaskLayer mask; 114 #endif 115 116 Color fillColor; 117 StrokeStyle strokeStyle; 118 Color strokeColor; 119 float strokeThickness; 120 LineCap strokeLineCap; 121 LineJoin strokeLineJoin; 122 float strokeMiterLimit; 123 DashArray strokeDashArray; 124 float strokeDashOffset; 125 126 TextDrawingModeFlags textDrawingMode; 127 bool antialiasingEnabled; 128 129 PlatformPainterState() 130 : compositeOperation(CompositeSourceOver) 131 , opacity(1.0) 132 , scissoringEnabled(false) 133 #ifdef OPENVG_VERSION_1_1 134 , maskingChangedAndEnabled(false) 135 , mask(VG_INVALID_HANDLE) 136 #endif 137 , fillColor(Color::black) 138 , strokeStyle(NoStroke) 139 , strokeThickness(0.0) 140 , strokeLineCap(ButtCap) 141 , strokeLineJoin(MiterJoin) 142 , strokeMiterLimit(4.0) 143 , strokeDashOffset(0.0) 144 , textDrawingMode(TextModeFill) 145 , antialiasingEnabled(true) 146 { 147 } 148 149 ~PlatformPainterState() 150 { 151 #ifdef OPENVG_VERSION_1_1 152 if (maskingChangedAndEnabled && mask != VG_INVALID_HANDLE) { 153 vgDestroyMaskLayer(mask); 154 ASSERT_VG_NO_ERROR(); 155 mask = VG_INVALID_HANDLE; 156 } 157 #endif 158 } 159 160 PlatformPainterState(const PlatformPainterState& state) 161 { 162 surfaceTransformation = state.surfaceTransformation; 163 164 scissoringEnabled = state.scissoringEnabled; 165 scissorRect = state.scissorRect; 166 #ifdef OPENVG_VERSION_1_1 167 maskingChangedAndEnabled = false; 168 mask = state.mask; 169 #endif 170 copyPaintState(&state); 171 } 172 173 inline bool maskingEnabled() 174 { 175 return maskingChangedAndEnabled || mask != VG_INVALID_HANDLE; 176 } 177 178 void copyPaintState(const PlatformPainterState* other) 179 { 180 compositeOperation = other->compositeOperation; 181 opacity = other->opacity; 182 183 fillColor = other->fillColor; 184 strokeStyle = other->strokeStyle; 185 strokeColor = other->strokeColor; 186 strokeThickness = other->strokeThickness; 187 strokeLineCap = other->strokeLineCap; 188 strokeLineJoin = other->strokeLineJoin; 189 strokeMiterLimit = other->strokeMiterLimit; 190 strokeDashArray = other->strokeDashArray; 191 strokeDashOffset = other->strokeDashOffset; 192 193 textDrawingMode = other->textDrawingMode; 194 antialiasingEnabled = other->antialiasingEnabled; 195 } 196 197 void applyState(PainterOpenVG* painter) 198 { 199 ASSERT(painter); 200 201 setVGSolidColor(VG_FILL_PATH, fillColor); 202 setVGSolidColor(VG_STROKE_PATH, strokeColor); 203 204 vgSetf(VG_STROKE_LINE_WIDTH, strokeThickness); 205 vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(strokeLineCap)); 206 vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(strokeLineJoin)); 207 vgSetf(VG_STROKE_MITER_LIMIT, strokeMiterLimit); 208 209 if (antialiasingEnabled) 210 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER); 211 else 212 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED); 213 214 applyBlending(painter); 215 applyStrokeStyle(); 216 217 applyTransformation(painter); 218 applyScissorRect(); 219 220 #ifdef OPENVG_VERSION_1_1 221 if (maskingEnabled()) { 222 vgSeti(VG_MASKING, VG_TRUE); 223 if (mask != VG_INVALID_HANDLE) 224 vgMask(mask, VG_SET_MASK, 0, 0, painter->surface()->width(), painter->surface()->height()); 225 } else 226 vgSeti(VG_MASKING, VG_FALSE); 227 #endif 228 ASSERT_VG_NO_ERROR(); 229 } 230 231 void applyBlending(PainterOpenVG* painter) 232 { 233 VGBlendMode blendMode = VG_BLEND_SRC_OVER; 234 235 switch (compositeOperation) { 236 case CompositeClear: { 237 // Clear means "set to fully transparent regardless of SRC". 238 // We implement that by multiplying DST with white color 239 // (= no changes) and an alpha of 1.0 - opacity, so the destination 240 // pixels will be fully transparent when opacity == 1.0 and 241 // unchanged when opacity == 0.0. 242 blendMode = VG_BLEND_DST_IN; 243 const VGfloat values[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 - opacity }; 244 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 245 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 246 ASSERT_VG_NO_ERROR(); 247 break; 248 } 249 case CompositeCopy: 250 blendMode = VG_BLEND_SRC; 251 break; 252 case CompositeSourceOver: 253 blendMode = VG_BLEND_SRC_OVER; 254 break; 255 case CompositeSourceIn: 256 blendMode = VG_BLEND_SRC_IN; 257 break; 258 case CompositeSourceOut: 259 notImplemented(); 260 break; 261 case CompositeSourceAtop: 262 notImplemented(); 263 break; 264 case CompositeDestinationOver: 265 blendMode = VG_BLEND_DST_OVER; 266 break; 267 case CompositeDestinationIn: 268 blendMode = VG_BLEND_DST_IN; 269 break; 270 case CompositeDestinationOut: 271 notImplemented(); 272 break; 273 case CompositeDestinationAtop: 274 notImplemented(); 275 break; 276 case CompositeXOR: 277 notImplemented(); 278 break; 279 case CompositePlusDarker: 280 blendMode = VG_BLEND_DARKEN; 281 break; 282 case CompositeHighlight: 283 notImplemented(); 284 break; 285 case CompositePlusLighter: 286 blendMode = VG_BLEND_LIGHTEN; 287 break; 288 } 289 290 if (compositeOperation != CompositeClear) { 291 if (opacity >= (1.0 - FLT_EPSILON)) 292 vgSeti(VG_COLOR_TRANSFORM, VG_FALSE); 293 else if (blendMode == VG_BLEND_SRC) { 294 blendMode = VG_BLEND_SRC_OVER; 295 VGfloat values[] = { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, opacity }; 296 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 297 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 298 } else { 299 VGfloat values[] = { 1.0, 1.0, 1.0, opacity, 0.0, 0.0, 0.0, 0.0 }; 300 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 301 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 302 } 303 ASSERT_VG_NO_ERROR(); 304 } 305 306 vgSeti(VG_BLEND_MODE, blendMode); 307 ASSERT_VG_NO_ERROR(); 308 } 309 310 void applyTransformation(PainterOpenVG* painter) 311 { 312 // There are *five* separate transforms that can be applied to OpenVG as of 1.1 313 // but it is not clear that we need to set them separately. Instead we set them 314 // all right here and let this be a call to essentially set the world transformation! 315 VGMatrix vgMatrix(surfaceTransformation); 316 const VGfloat* vgFloatArray = vgMatrix.toVGfloat(); 317 318 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); 319 vgLoadMatrix(vgFloatArray); 320 ASSERT_VG_NO_ERROR(); 321 322 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); 323 vgLoadMatrix(vgFloatArray); 324 ASSERT_VG_NO_ERROR(); 325 326 #ifdef OPENVG_VERSION_1_1 327 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE); 328 vgLoadMatrix(vgFloatArray); 329 ASSERT_VG_NO_ERROR(); 330 #endif 331 } 332 333 void applyScissorRect() 334 { 335 if (scissoringEnabled) { 336 vgSeti(VG_SCISSORING, VG_TRUE); 337 vgSetfv(VG_SCISSOR_RECTS, 4, VGRect(scissorRect).toVGfloat()); 338 } else 339 vgSeti(VG_SCISSORING, VG_FALSE); 340 341 ASSERT_VG_NO_ERROR(); 342 } 343 344 void applyStrokeStyle() 345 { 346 if (strokeStyle == DottedStroke) { 347 VGfloat vgFloatArray[2] = { 1.0, 1.0 }; 348 vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); 349 vgSetf(VG_STROKE_DASH_PHASE, 0.0); 350 } else if (strokeStyle == DashedStroke) { 351 if (!strokeDashArray.size()) { 352 VGfloat vgFloatArray[2] = { 4.0, 3.0 }; 353 vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); 354 } else { 355 Vector<VGfloat> vgFloatArray(strokeDashArray.size()); 356 for (int i = 0; i < strokeDashArray.size(); ++i) 357 vgFloatArray[i] = strokeDashArray[i]; 358 359 vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data()); 360 } 361 vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset); 362 } else { 363 vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0); 364 vgSetf(VG_STROKE_DASH_PHASE, 0.0); 365 } 366 367 ASSERT_VG_NO_ERROR(); 368 } 369 370 inline bool strokeDisabled() const 371 { 372 return (compositeOperation == CompositeSourceOver 373 && (strokeStyle == NoStroke || !strokeColor.alpha())); 374 } 375 376 inline bool fillDisabled() const 377 { 378 return (compositeOperation == CompositeSourceOver && !fillColor.alpha()); 379 } 380 381 void saveMaskIfNecessary(PainterOpenVG* painter) 382 { 383 #ifdef OPENVG_VERSION_1_1 384 if (maskingChangedAndEnabled) { 385 if (mask != VG_INVALID_HANDLE) { 386 vgDestroyMaskLayer(mask); 387 ASSERT_VG_NO_ERROR(); 388 } 389 mask = vgCreateMaskLayer(painter->surface()->width(), painter->surface()->height()); 390 ASSERT(mask != VG_INVALID_HANDLE); 391 vgCopyMask(mask, 0, 0, 0, 0, painter->surface()->width(), painter->surface()->height()); 392 ASSERT_VG_NO_ERROR(); 393 } 394 #endif 395 } 396 }; 397 398 399 PainterOpenVG::PainterOpenVG() 400 : m_state(0) 401 , m_surface(0) 402 { 403 } 404 405 PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) 406 : m_state(0) 407 , m_surface(0) 408 { 409 ASSERT(surface); 410 begin(surface); 411 } 412 413 PainterOpenVG::~PainterOpenVG() 414 { 415 end(); 416 } 417 418 void PainterOpenVG::begin(SurfaceOpenVG* surface) 419 { 420 if (surface == m_surface) 421 return; 422 423 ASSERT(surface); 424 ASSERT(!m_state); 425 426 m_surface = surface; 427 428 m_stateStack.append(new PlatformPainterState()); 429 m_state = m_stateStack.last(); 430 431 m_surface->setActivePainter(this); 432 m_surface->makeCurrent(); 433 } 434 435 void PainterOpenVG::end() 436 { 437 if (!m_surface) 438 return; 439 440 m_surface->setActivePainter(0); 441 m_surface = 0; 442 443 destroyPainterStates(); 444 } 445 446 void PainterOpenVG::destroyPainterStates() 447 { 448 PlatformPainterState* state = 0; 449 while (!m_stateStack.isEmpty()) { 450 state = m_stateStack.last(); 451 m_stateStack.removeLast(); 452 delete state; 453 } 454 m_state = 0; 455 } 456 457 // Called by friend SurfaceOpenVG, private otherwise. 458 void PainterOpenVG::applyState() 459 { 460 ASSERT(m_state); 461 m_state->applyState(this); 462 } 463 464 /** 465 * Copy the current back buffer image onto the surface. 466 * 467 * Call this method when all painting operations have been completed, 468 * otherwise the surface won't visibly change. 469 */ 470 void PainterOpenVG::blitToSurface() 471 { 472 ASSERT(m_state); // implies m_surface 473 m_surface->flush(); 474 } 475 476 AffineTransform PainterOpenVG::transformation() const 477 { 478 ASSERT(m_state); 479 return m_state->surfaceTransformation; 480 } 481 482 void PainterOpenVG::concatTransformation(const AffineTransform& transformation) 483 { 484 ASSERT(m_state); 485 m_surface->makeCurrent(); 486 487 // We do the multiplication ourself using WebCore's AffineTransform rather 488 // than offloading this to VG via vgMultMatrix() to keep things simple and 489 // so we can maintain state ourselves. 490 m_state->surfaceTransformation.multLeft(transformation); 491 m_state->applyTransformation(this); 492 } 493 494 void PainterOpenVG::setTransformation(const AffineTransform& transformation) 495 { 496 ASSERT(m_state); 497 m_surface->makeCurrent(); 498 499 m_state->surfaceTransformation = transformation; 500 m_state->applyTransformation(this); 501 } 502 503 void PainterOpenVG::transformPath(VGPath dst, VGPath src, const AffineTransform& transformation) 504 { 505 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); 506 507 // Save the transform state 508 VGfloat currentMatrix[9]; 509 vgGetMatrix(currentMatrix); 510 ASSERT_VG_NO_ERROR(); 511 512 // Load the new transform 513 vgLoadMatrix(VGMatrix(transformation).toVGfloat()); 514 ASSERT_VG_NO_ERROR(); 515 516 // Apply the new transform 517 vgTransformPath(dst, src); 518 ASSERT_VG_NO_ERROR(); 519 520 // Restore the transform state 521 vgLoadMatrix(currentMatrix); 522 ASSERT_VG_NO_ERROR(); 523 } 524 525 CompositeOperator PainterOpenVG::compositeOperation() const 526 { 527 ASSERT(m_state); 528 return m_state->compositeOperation; 529 } 530 531 void PainterOpenVG::setCompositeOperation(CompositeOperator op) 532 { 533 ASSERT(m_state); 534 m_surface->makeCurrent(); 535 536 m_state->compositeOperation = op; 537 m_state->applyBlending(this); 538 } 539 540 float PainterOpenVG::opacity() const 541 { 542 ASSERT(m_state); 543 return m_state->opacity; 544 } 545 546 void PainterOpenVG::setOpacity(float opacity) 547 { 548 ASSERT(m_state); 549 m_surface->makeCurrent(); 550 551 m_state->opacity = opacity; 552 m_state->applyBlending(this); 553 } 554 555 float PainterOpenVG::strokeThickness() const 556 { 557 ASSERT(m_state); 558 return m_state->strokeThickness; 559 } 560 561 void PainterOpenVG::setStrokeThickness(float thickness) 562 { 563 ASSERT(m_state); 564 m_surface->makeCurrent(); 565 566 m_state->strokeThickness = thickness; 567 vgSetf(VG_STROKE_LINE_WIDTH, thickness); 568 ASSERT_VG_NO_ERROR(); 569 } 570 571 StrokeStyle PainterOpenVG::strokeStyle() const 572 { 573 ASSERT(m_state); 574 return m_state->strokeStyle; 575 } 576 577 void PainterOpenVG::setStrokeStyle(StrokeStyle style) 578 { 579 ASSERT(m_state); 580 m_surface->makeCurrent(); 581 582 m_state->strokeStyle = style; 583 m_state->applyStrokeStyle(); 584 } 585 586 void PainterOpenVG::setLineDash(const DashArray& dashArray, float dashOffset) 587 { 588 ASSERT(m_state); 589 m_surface->makeCurrent(); 590 591 m_state->strokeDashArray = dashArray; 592 m_state->strokeDashOffset = dashOffset; 593 m_state->applyStrokeStyle(); 594 } 595 596 void PainterOpenVG::setLineCap(LineCap lineCap) 597 { 598 ASSERT(m_state); 599 m_surface->makeCurrent(); 600 601 m_state->strokeLineCap = lineCap; 602 vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(lineCap)); 603 ASSERT_VG_NO_ERROR(); 604 } 605 606 void PainterOpenVG::setLineJoin(LineJoin lineJoin) 607 { 608 ASSERT(m_state); 609 m_surface->makeCurrent(); 610 611 m_state->strokeLineJoin = lineJoin; 612 vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(lineJoin)); 613 ASSERT_VG_NO_ERROR(); 614 } 615 616 void PainterOpenVG::setMiterLimit(float miterLimit) 617 { 618 ASSERT(m_state); 619 m_surface->makeCurrent(); 620 621 m_state->strokeMiterLimit = miterLimit; 622 vgSetf(VG_STROKE_MITER_LIMIT, miterLimit); 623 ASSERT_VG_NO_ERROR(); 624 } 625 626 Color PainterOpenVG::strokeColor() const 627 { 628 ASSERT(m_state); 629 return m_state->strokeColor; 630 } 631 632 void PainterOpenVG::setStrokeColor(const Color& color) 633 { 634 ASSERT(m_state); 635 m_surface->makeCurrent(); 636 637 m_state->strokeColor = color; 638 setVGSolidColor(VG_STROKE_PATH, color); 639 } 640 641 Color PainterOpenVG::fillColor() const 642 { 643 ASSERT(m_state); 644 return m_state->fillColor; 645 } 646 647 void PainterOpenVG::setFillColor(const Color& color) 648 { 649 ASSERT(m_state); 650 m_surface->makeCurrent(); 651 652 m_state->fillColor = color; 653 setVGSolidColor(VG_FILL_PATH, color); 654 } 655 656 TextDrawingModeFlags PainterOpenVG::textDrawingMode() const 657 { 658 ASSERT(m_state); 659 return m_state->textDrawingMode; 660 } 661 662 void PainterOpenVG::setTextDrawingMode(TextDrawingModeFlags mode) 663 { 664 ASSERT(m_state); 665 m_state->textDrawingMode = mode; 666 } 667 668 bool PainterOpenVG::antialiasingEnabled() const 669 { 670 ASSERT(m_state); 671 return m_state->antialiasingEnabled; 672 } 673 674 void PainterOpenVG::setAntialiasingEnabled(bool enabled) 675 { 676 ASSERT(m_state); 677 m_surface->makeCurrent(); 678 679 m_state->antialiasingEnabled = enabled; 680 681 if (enabled) 682 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER); 683 else 684 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED); 685 } 686 687 void PainterOpenVG::scale(const FloatSize& scaleFactors) 688 { 689 ASSERT(m_state); 690 m_surface->makeCurrent(); 691 692 AffineTransform transformation = m_state->surfaceTransformation; 693 transformation.scaleNonUniform(scaleFactors.width(), scaleFactors.height()); 694 setTransformation(transformation); 695 } 696 697 void PainterOpenVG::rotate(float radians) 698 { 699 ASSERT(m_state); 700 m_surface->makeCurrent(); 701 702 AffineTransform transformation = m_state->surfaceTransformation; 703 transformation.rotate(rad2deg(radians)); 704 setTransformation(transformation); 705 } 706 707 void PainterOpenVG::translate(float dx, float dy) 708 { 709 ASSERT(m_state); 710 m_surface->makeCurrent(); 711 712 AffineTransform transformation = m_state->surfaceTransformation; 713 transformation.translate(dx, dy); 714 setTransformation(transformation); 715 } 716 717 void PainterOpenVG::drawPath(const Path& path, VGbitfield specifiedPaintModes, WindRule fillRule) 718 { 719 ASSERT(m_state); 720 721 VGbitfield paintModes = 0; 722 if (!m_state->strokeDisabled()) 723 paintModes |= VG_STROKE_PATH; 724 if (!m_state->fillDisabled()) 725 paintModes |= VG_FILL_PATH; 726 727 paintModes &= specifiedPaintModes; 728 729 if (!paintModes) 730 return; 731 732 m_surface->makeCurrent(); 733 734 vgSeti(VG_FILL_RULE, toVGFillRule(fillRule)); 735 vgDrawPath(path.platformPath()->vgPath(), paintModes); 736 ASSERT_VG_NO_ERROR(); 737 } 738 739 void PainterOpenVG::intersectScissorRect(const FloatRect& rect) 740 { 741 // Scissor rectangles are defined by float values, but e.g. painting 742 // something red to a float-clipped rectangle and then painting something 743 // white to the same rectangle will leave some red remnants as it is 744 // rendered to full pixels in between. Also, some OpenVG implementations 745 // are likely to clip to integer coordinates anyways because of the above 746 // effect. So considering the above (and confirming through tests) the 747 // visual result is better if we clip to the enclosing integer rectangle 748 // rather than the exact float rectangle for scissoring. 749 if (m_state->scissoringEnabled) 750 m_state->scissorRect.intersect(FloatRect(enclosingIntRect(rect))); 751 else { 752 m_state->scissoringEnabled = true; 753 m_state->scissorRect = FloatRect(enclosingIntRect(rect)); 754 } 755 756 m_state->applyScissorRect(); 757 } 758 759 void PainterOpenVG::intersectClipRect(const FloatRect& rect) 760 { 761 ASSERT(m_state); 762 m_surface->makeCurrent(); 763 764 if (m_state->surfaceTransformation.isIdentity()) { 765 // No transformation required, skip all the complex stuff. 766 intersectScissorRect(rect); 767 return; 768 } 769 770 // Check if the actual destination rectangle is still rectilinear (can be 771 // represented as FloatRect) so we could apply scissoring instead of 772 // (potentially more expensive) path clipping. Note that scissoring is not 773 // subject to transformations, so we need to do the transformation to 774 // surface coordinates by ourselves. 775 FloatQuad effectiveScissorQuad = m_state->surfaceTransformation.mapQuad(FloatQuad(rect)); 776 777 if (effectiveScissorQuad.isRectilinear()) 778 intersectScissorRect(effectiveScissorQuad.boundingBox()); 779 else { 780 // The transformed scissorRect cannot be represented as FloatRect 781 // anymore, so we need to perform masking instead. 782 Path scissorRectPath; 783 scissorRectPath.addRect(rect); 784 clipPath(scissorRectPath, PainterOpenVG::IntersectClip); 785 } 786 } 787 788 void PainterOpenVG::clipPath(const Path& path, PainterOpenVG::ClipOperation maskOp, WindRule clipRule) 789 { 790 #ifdef OPENVG_VERSION_1_1 791 ASSERT(m_state); 792 m_surface->makeCurrent(); 793 794 if (m_state->mask != VG_INVALID_HANDLE && !m_state->maskingChangedAndEnabled) { 795 // The parent's mask has been inherited - dispose the handle so that 796 // it won't be overwritten. 797 m_state->maskingChangedAndEnabled = true; 798 m_state->mask = VG_INVALID_HANDLE; 799 } else if (!m_state->maskingEnabled()) { 800 // None of the parent painter states had a mask enabled yet. 801 m_state->maskingChangedAndEnabled = true; 802 vgSeti(VG_MASKING, VG_TRUE); 803 // Make sure not to inherit previous mask state from previously written 804 // (but disabled) masks. For VG_FILL_MASK the first argument is ignored, 805 // we pass VG_INVALID_HANDLE which is what the OpenVG spec suggests. 806 vgMask(VG_INVALID_HANDLE, VG_FILL_MASK, 0, 0, m_surface->width(), m_surface->height()); 807 } 808 809 // Intersect the path from the mask, or subtract it from there. 810 // (In either case we always decrease the visible area, never increase it, 811 // which means masking never has to modify scissor rectangles.) 812 vgSeti(VG_FILL_RULE, toVGFillRule(clipRule)); 813 vgRenderToMask(path.platformPath()->vgPath(), VG_FILL_PATH, (VGMaskOperation) maskOp); 814 ASSERT_VG_NO_ERROR(); 815 #else 816 notImplemented(); 817 #endif 818 } 819 820 void PainterOpenVG::drawRect(const FloatRect& rect, VGbitfield specifiedPaintModes) 821 { 822 ASSERT(m_state); 823 824 VGbitfield paintModes = 0; 825 if (!m_state->strokeDisabled()) 826 paintModes |= VG_STROKE_PATH; 827 if (!m_state->fillDisabled()) 828 paintModes |= VG_FILL_PATH; 829 830 paintModes &= specifiedPaintModes; 831 832 if (!paintModes) 833 return; 834 835 m_surface->makeCurrent(); 836 837 VGPath path = vgCreatePath( 838 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 839 1.0 /* scale */, 0.0 /* bias */, 840 5 /* expected number of segments */, 841 5 /* expected number of total coordinates */, 842 VG_PATH_CAPABILITY_APPEND_TO); 843 ASSERT_VG_NO_ERROR(); 844 845 if (vguRect(path, rect.x(), rect.y(), rect.width(), rect.height()) == VGU_NO_ERROR) { 846 vgDrawPath(path, paintModes); 847 ASSERT_VG_NO_ERROR(); 848 } 849 850 vgDestroyPath(path); 851 ASSERT_VG_NO_ERROR(); 852 } 853 854 void PainterOpenVG::drawRoundedRect(const FloatRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield specifiedPaintModes) 855 { 856 ASSERT(m_state); 857 858 VGbitfield paintModes = 0; 859 if (!m_state->strokeDisabled()) 860 paintModes |= VG_STROKE_PATH; 861 if (!m_state->fillDisabled()) 862 paintModes |= VG_FILL_PATH; 863 864 paintModes &= specifiedPaintModes; 865 866 if (!paintModes) 867 return; 868 869 m_surface->makeCurrent(); 870 871 VGPath path = vgCreatePath( 872 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 873 1.0 /* scale */, 0.0 /* bias */, 874 10 /* expected number of segments */, 875 25 /* expected number of total coordinates */, 876 VG_PATH_CAPABILITY_APPEND_TO); 877 ASSERT_VG_NO_ERROR(); 878 879 // clamp corner arc sizes 880 FloatSize clampedTopLeft = FloatSize(topLeft).shrunkTo(rect.size()).expandedTo(FloatSize()); 881 FloatSize clampedTopRight = FloatSize(topRight).shrunkTo(rect.size()).expandedTo(FloatSize()); 882 FloatSize clampedBottomLeft = FloatSize(bottomLeft).shrunkTo(rect.size()).expandedTo(FloatSize()); 883 FloatSize clampedBottomRight = FloatSize(bottomRight).shrunkTo(rect.size()).expandedTo(FloatSize()); 884 885 // As OpenVG's coordinate system is flipped in comparison to WebKit's, 886 // we have to specify the opposite value for the "clockwise" value. 887 static const VGubyte pathSegments[] = { 888 VG_MOVE_TO_ABS, 889 VG_HLINE_TO_REL, 890 VG_SCCWARC_TO_REL, 891 VG_VLINE_TO_REL, 892 VG_SCCWARC_TO_REL, 893 VG_HLINE_TO_REL, 894 VG_SCCWARC_TO_REL, 895 VG_VLINE_TO_REL, 896 VG_SCCWARC_TO_REL, 897 VG_CLOSE_PATH 898 }; 899 // Also, the rounded rectangle path proceeds from the top to the bottom, 900 // requiring height distances and clamped radius sizes to be flipped. 901 const VGfloat pathData[] = { 902 rect.x() + clampedTopLeft.width(), rect.y(), 903 rect.width() - clampedTopLeft.width() - clampedTopRight.width(), 904 clampedTopRight.width(), clampedTopRight.height(), 0, clampedTopRight.width(), clampedTopRight.height(), 905 rect.height() - clampedTopRight.height() - clampedBottomRight.height(), 906 clampedBottomRight.width(), clampedBottomRight.height(), 0, -clampedBottomRight.width(), clampedBottomRight.height(), 907 -(rect.width() - clampedBottomLeft.width() - clampedBottomRight.width()), 908 clampedBottomLeft.width(), clampedBottomLeft.height(), 0, -clampedBottomLeft.width(), -clampedBottomLeft.height(), 909 -(rect.height() - clampedTopLeft.height() - clampedBottomLeft.height()), 910 clampedTopLeft.width(), clampedTopLeft.height(), 0, clampedTopLeft.width(), -clampedTopLeft.height(), 911 }; 912 913 vgAppendPathData(path, 10, pathSegments, pathData); 914 vgDrawPath(path, paintModes); 915 vgDestroyPath(path); 916 ASSERT_VG_NO_ERROR(); 917 } 918 919 void PainterOpenVG::drawLine(const IntPoint& from, const IntPoint& to) 920 { 921 ASSERT(m_state); 922 923 if (m_state->strokeDisabled()) 924 return; 925 926 m_surface->makeCurrent(); 927 928 VGPath path = vgCreatePath( 929 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 930 1.0 /* scale */, 0.0 /* bias */, 931 2 /* expected number of segments */, 932 4 /* expected number of total coordinates */, 933 VG_PATH_CAPABILITY_APPEND_TO); 934 ASSERT_VG_NO_ERROR(); 935 936 VGUErrorCode errorCode; 937 938 // Try to align lines to pixels, centering them between pixels for odd thickness values. 939 if (fmod(m_state->strokeThickness + 0.5, 2.0) < 1.0) 940 errorCode = vguLine(path, from.x(), from.y(), to.x(), to.y()); 941 else if ((to.y() - from.y()) > (to.x() - from.x())) // more vertical than horizontal 942 errorCode = vguLine(path, from.x() + 0.5, from.y(), to.x() + 0.5, to.y()); 943 else 944 errorCode = vguLine(path, from.x(), from.y() + 0.5, to.x(), to.y() + 0.5); 945 946 if (errorCode == VGU_NO_ERROR) { 947 vgDrawPath(path, VG_STROKE_PATH); 948 ASSERT_VG_NO_ERROR(); 949 } 950 951 vgDestroyPath(path); 952 ASSERT_VG_NO_ERROR(); 953 } 954 955 void PainterOpenVG::drawArc(const IntRect& rect, int startAngle, int angleSpan, VGbitfield specifiedPaintModes) 956 { 957 ASSERT(m_state); 958 959 VGbitfield paintModes = 0; 960 if (!m_state->strokeDisabled()) 961 paintModes |= VG_STROKE_PATH; 962 if (!m_state->fillDisabled()) 963 paintModes |= VG_FILL_PATH; 964 965 paintModes &= specifiedPaintModes; 966 967 if (!paintModes) 968 return; 969 970 m_surface->makeCurrent(); 971 972 VGPath path = vgCreatePath( 973 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 974 1.0 /* scale */, 0.0 /* bias */, 975 2 /* expected number of segments */, 976 4 /* expected number of total coordinates */, 977 VG_PATH_CAPABILITY_APPEND_TO); 978 ASSERT_VG_NO_ERROR(); 979 980 if (vguArc(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height(), -startAngle, -angleSpan, VGU_ARC_OPEN) == VGU_NO_ERROR) { 981 vgDrawPath(path, VG_STROKE_PATH); 982 ASSERT_VG_NO_ERROR(); 983 } 984 985 vgDestroyPath(path); 986 ASSERT_VG_NO_ERROR(); 987 } 988 989 void PainterOpenVG::drawEllipse(const IntRect& rect, VGbitfield specifiedPaintModes) 990 { 991 ASSERT(m_state); 992 993 VGbitfield paintModes = 0; 994 if (!m_state->strokeDisabled()) 995 paintModes |= VG_STROKE_PATH; 996 if (!m_state->fillDisabled()) 997 paintModes |= VG_FILL_PATH; 998 999 paintModes &= specifiedPaintModes; 1000 1001 if (!paintModes) 1002 return; 1003 1004 m_surface->makeCurrent(); 1005 1006 VGPath path = vgCreatePath( 1007 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1008 1.0 /* scale */, 0.0 /* bias */, 1009 4 /* expected number of segments */, 1010 12 /* expected number of total coordinates */, 1011 VG_PATH_CAPABILITY_APPEND_TO); 1012 ASSERT_VG_NO_ERROR(); 1013 1014 if (vguEllipse(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height()) == VGU_NO_ERROR) { 1015 vgDrawPath(path, paintModes); 1016 ASSERT_VG_NO_ERROR(); 1017 } 1018 1019 vgDestroyPath(path); 1020 ASSERT_VG_NO_ERROR(); 1021 } 1022 1023 void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield specifiedPaintModes) 1024 { 1025 ASSERT(m_state); 1026 1027 VGbitfield paintModes = 0; 1028 if (!m_state->strokeDisabled()) 1029 paintModes |= VG_STROKE_PATH; 1030 if (!m_state->fillDisabled()) 1031 paintModes |= VG_FILL_PATH; 1032 1033 paintModes &= specifiedPaintModes; 1034 1035 if (!paintModes) 1036 return; 1037 1038 m_surface->makeCurrent(); 1039 1040 // Path segments: all points + "close path". 1041 const VGint numSegments = numPoints + 1; 1042 const VGint numCoordinates = numPoints * 2; 1043 1044 VGPath path = vgCreatePath( 1045 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 1046 1.0 /* scale */, 0.0 /* bias */, 1047 numSegments /* expected number of segments */, 1048 numCoordinates /* expected number of total coordinates */, 1049 VG_PATH_CAPABILITY_APPEND_TO); 1050 ASSERT_VG_NO_ERROR(); 1051 1052 Vector<VGfloat> vgPoints(numCoordinates); 1053 for (int i = 0; i < numPoints; ++i) { 1054 vgPoints[i*2] = points[i].x(); 1055 vgPoints[i*2 + 1] = points[i].y(); 1056 } 1057 1058 if (vguPolygon(path, vgPoints.data(), numPoints, VG_TRUE /* closed */) == VGU_NO_ERROR) { 1059 vgDrawPath(path, paintModes); 1060 ASSERT_VG_NO_ERROR(); 1061 } 1062 1063 vgDestroyPath(path); 1064 ASSERT_VG_NO_ERROR(); 1065 } 1066 1067 void PainterOpenVG::drawImage(TiledImageOpenVG* tiledImage, const FloatRect& dst, const FloatRect& src) 1068 { 1069 ASSERT(m_state); 1070 m_surface->makeCurrent(); 1071 1072 // If buffers can be larger than the maximum OpenVG image sizes, 1073 // we split them into tiles. 1074 IntRect drawnTiles = tiledImage->tilesInRect(src); 1075 AffineTransform srcToDstTransformation = makeMapBetweenRects( 1076 FloatRect(FloatPoint(0.0, 0.0), src.size()), dst); 1077 srcToDstTransformation.translate(-src.x(), -src.y()); 1078 1079 for (int yIndex = drawnTiles.y(); yIndex < drawnTiles.bottom(); ++yIndex) { 1080 for (int xIndex = drawnTiles.x(); xIndex < drawnTiles.right(); ++xIndex) { 1081 // The srcTile rectangle is an aligned tile cropped by the src rectangle. 1082 FloatRect tile(tiledImage->tileRect(xIndex, yIndex)); 1083 FloatRect srcTile = intersection(src, tile); 1084 1085 save(); 1086 1087 // If the image is drawn in full, all we need is the proper transformation 1088 // in order to get it drawn at the right spot on the surface. 1089 concatTransformation(AffineTransform(srcToDstTransformation).translate(tile.x(), tile.y())); 1090 1091 // If only a part of the tile is drawn, we also need to clip the surface. 1092 if (srcTile != tile) { 1093 // Put boundaries relative to tile origin, as we already 1094 // translated to (x, y) with the transformation matrix. 1095 srcTile.move(-tile.x(), -tile.y()); 1096 intersectClipRect(srcTile); 1097 } 1098 1099 VGImage image = tiledImage->tile(xIndex, yIndex); 1100 if (image != VG_INVALID_HANDLE) { 1101 vgDrawImage(image); 1102 ASSERT_VG_NO_ERROR(); 1103 } 1104 1105 restore(); 1106 } 1107 } 1108 } 1109 1110 #ifdef OPENVG_VERSION_1_1 1111 void PainterOpenVG::drawText(VGFont vgFont, Vector<VGuint>& characters, VGfloat* adjustmentsX, VGfloat* adjustmentsY, const FloatPoint& point) 1112 { 1113 ASSERT(m_state); 1114 1115 VGbitfield paintModes = 0; 1116 1117 if (m_state->textDrawingMode & TextModeClip) 1118 return; // unsupported for every port except CG at the time of writing 1119 if (m_state->textDrawingMode & TextModeFill && !m_state->fillDisabled()) 1120 paintModes |= VG_FILL_PATH; 1121 if (m_state->textDrawingMode & TextModeStroke && !m_state->strokeDisabled()) 1122 paintModes |= VG_STROKE_PATH; 1123 1124 m_surface->makeCurrent(); 1125 1126 FloatPoint effectivePoint = m_state->surfaceTransformation.mapPoint(point); 1127 FloatPoint p = point; 1128 AffineTransform* originalTransformation = 0; 1129 1130 // In case the font isn't drawn at a pixel-exact baseline and we can easily 1131 // fix that (which is the case for non-rotated affine transforms), let's 1132 // align the starting point to the pixel boundary in order to prevent 1133 // font rendering issues such as glyphs that appear off by a pixel. 1134 // This causes us to have inconsistent spacing between baselines in a 1135 // larger paragraph, but that seems to be the least of all evils. 1136 if ((fmod(effectivePoint.x() + 0.01, 1.0) > 0.02 || fmod(effectivePoint.y() + 0.01, 1.0) > 0.02) 1137 && isNonRotatedAffineTransformation(m_state->surfaceTransformation)) 1138 { 1139 originalTransformation = new AffineTransform(m_state->surfaceTransformation); 1140 setTransformation(AffineTransform( 1141 m_state->surfaceTransformation.a(), 0, 1142 0, m_state->surfaceTransformation.d(), 1143 roundf(effectivePoint.x()), roundf(effectivePoint.y()))); 1144 p = FloatPoint(); 1145 } 1146 1147 const VGfloat vgPoint[2] = { p.x(), p.y() }; 1148 vgSetfv(VG_GLYPH_ORIGIN, 2, vgPoint); 1149 ASSERT_VG_NO_ERROR(); 1150 1151 vgDrawGlyphs(vgFont, characters.size(), characters.data(), 1152 adjustmentsX, adjustmentsY, paintModes, VG_TRUE /* allow autohinting */); 1153 ASSERT_VG_NO_ERROR(); 1154 1155 if (originalTransformation) { 1156 setTransformation(*originalTransformation); 1157 delete originalTransformation; 1158 } 1159 } 1160 #endif 1161 1162 TiledImageOpenVG* PainterOpenVG::asNewNativeImage(const IntRect& src, VGImageFormat format) 1163 { 1164 ASSERT(m_state); 1165 m_surface->sharedSurface()->makeCurrent(); 1166 1167 const IntSize vgMaxImageSize(vgGeti(VG_MAX_IMAGE_WIDTH), vgGeti(VG_MAX_IMAGE_HEIGHT)); 1168 ASSERT_VG_NO_ERROR(); 1169 1170 const IntRect rect = intersection(src, IntRect(0, 0, m_surface->width(), m_surface->height())); 1171 TiledImageOpenVG* tiledImage = new TiledImageOpenVG(rect.size(), vgMaxImageSize); 1172 1173 const int numColumns = tiledImage->numColumns(); 1174 const int numRows = tiledImage->numRows(); 1175 1176 // Create the images as resources of the shared surface/context. 1177 for (int yIndex = 0; yIndex < numRows; ++yIndex) { 1178 for (int xIndex = 0; xIndex < numColumns; ++xIndex) { 1179 IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); 1180 VGImage image = vgCreateImage(format, tileRect.width(), tileRect.height(), VG_IMAGE_QUALITY_FASTER); 1181 ASSERT_VG_NO_ERROR(); 1182 1183 tiledImage->setTile(xIndex, yIndex, image); 1184 } 1185 } 1186 1187 // Fill the image contents with our own surface/context being current. 1188 m_surface->makeCurrent(); 1189 1190 for (int yIndex = 0; yIndex < numRows; ++yIndex) { 1191 for (int xIndex = 0; xIndex < numColumns; ++xIndex) { 1192 IntRect tileRect = tiledImage->tileRect(xIndex, yIndex); 1193 1194 vgGetPixels(tiledImage->tile(xIndex, yIndex), 0, 0, 1195 rect.x() + tileRect.x(), rect.y() + tileRect.y(), 1196 tileRect.width(), tileRect.height()); 1197 ASSERT_VG_NO_ERROR(); 1198 } 1199 } 1200 1201 return tiledImage; 1202 } 1203 1204 void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode) 1205 { 1206 ASSERT(m_state); 1207 1208 // If the underlying context/surface was switched away by someone without 1209 // telling us, it might not correspond to the one assigned to this painter. 1210 // Switch back so we can save the state properly. (Should happen rarely.) 1211 // Use DontSaveOrApplyPainterState mode in order to avoid recursion. 1212 m_surface->makeCurrent(SurfaceOpenVG::DontSaveOrApplyPainterState); 1213 1214 if (saveMode == PainterOpenVG::CreateNewState) { 1215 m_state->saveMaskIfNecessary(this); 1216 PlatformPainterState* state = new PlatformPainterState(*m_state); 1217 m_stateStack.append(state); 1218 m_state = m_stateStack.last(); 1219 } else if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) { 1220 m_state->saveMaskIfNecessary(this); 1221 PlatformPainterState* state = new PlatformPainterState(); 1222 state->copyPaintState(m_state); 1223 m_stateStack.append(state); 1224 m_state = m_stateStack.last(); 1225 } else // if (saveMode == PainterOpenVG::KeepCurrentState) 1226 m_state->saveMaskIfNecessary(this); 1227 } 1228 1229 void PainterOpenVG::restore() 1230 { 1231 ASSERT(m_stateStack.size() >= 2); 1232 m_surface->makeCurrent(SurfaceOpenVG::DontApplyPainterState); 1233 1234 PlatformPainterState* state = m_stateStack.last(); 1235 m_stateStack.removeLast(); 1236 delete state; 1237 1238 m_state = m_stateStack.last(); 1239 m_state->applyState(this); 1240 } 1241 1242 } 1243