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 "Color.h" 24 #include "DashArray.h" 25 #include "FloatPoint.h" 26 #include "FloatQuad.h" 27 #include "FloatRect.h" 28 #include "IntRect.h" 29 #include "IntSize.h" 30 #include "NotImplemented.h" 31 #include "SurfaceOpenVG.h" 32 #include "TransformationMatrix.h" 33 #include "VGUtils.h" 34 35 #if PLATFORM(EGL) 36 #include "EGLUtils.h" 37 #endif 38 39 #include <vgu.h> 40 41 #include <wtf/Assertions.h> 42 #include <wtf/MathExtras.h> 43 44 namespace WebCore { 45 46 static bool isNonRotatedAffineTransformation(const TransformationMatrix& matrix) 47 { 48 return matrix.m12() <= FLT_EPSILON && matrix.m13() <= FLT_EPSILON && matrix.m14() <= FLT_EPSILON 49 && matrix.m21() <= FLT_EPSILON && matrix.m23() <= FLT_EPSILON && matrix.m24() <= FLT_EPSILON 50 && matrix.m31() <= FLT_EPSILON && matrix.m32() <= FLT_EPSILON && matrix.m34() <= FLT_EPSILON 51 && matrix.m44() >= 1 - FLT_EPSILON; 52 } 53 54 static VGCapStyle toVGCapStyle(LineCap lineCap) 55 { 56 switch (lineCap) { 57 case RoundCap: 58 return VG_CAP_ROUND; 59 case SquareCap: 60 return VG_CAP_SQUARE; 61 case ButtCap: 62 default: 63 return VG_CAP_BUTT; 64 } 65 } 66 67 static VGJoinStyle toVGJoinStyle(LineJoin lineJoin) 68 { 69 switch (lineJoin) { 70 case RoundJoin: 71 return VG_JOIN_ROUND; 72 case BevelJoin: 73 return VG_JOIN_BEVEL; 74 case MiterJoin: 75 default: 76 return VG_JOIN_MITER; 77 } 78 } 79 80 static VGFillRule toVGFillRule(WindRule fillRule) 81 { 82 return fillRule == RULE_EVENODD ? VG_EVEN_ODD : VG_NON_ZERO; 83 } 84 85 static VGuint colorToVGColor(const Color& color) 86 { 87 VGuint vgColor = color.red(); 88 vgColor = (vgColor << 8) | color.green(); 89 vgColor = (vgColor << 8) | color.blue(); 90 vgColor = (vgColor << 8) | color.alpha(); 91 return vgColor; 92 } 93 94 static void setVGSolidColor(VGPaintMode paintMode, const Color& color) 95 { 96 VGPaint paint = vgCreatePaint(); 97 vgSetParameteri(paint, VG_PAINT_TYPE, VG_PAINT_TYPE_COLOR); 98 vgSetColor(paint, colorToVGColor(color)); 99 vgSetPaint(paint, paintMode); 100 vgDestroyPaint(paint); 101 ASSERT_VG_NO_ERROR(); 102 } 103 104 105 struct PlatformPainterState { 106 TransformationMatrix surfaceTransformationMatrix; 107 CompositeOperator compositeOperation; 108 float opacity; 109 110 bool scissoringEnabled; 111 FloatRect scissorRect; 112 113 Color fillColor; 114 StrokeStyle strokeStyle; 115 Color strokeColor; 116 float strokeThickness; 117 LineCap strokeLineCap; 118 LineJoin strokeLineJoin; 119 float strokeMiterLimit; 120 DashArray strokeDashArray; 121 float strokeDashOffset; 122 123 bool antialiasingEnabled; 124 125 PlatformPainterState() 126 : compositeOperation(CompositeSourceOver) 127 , opacity(1.0) 128 , scissoringEnabled(false) 129 , fillColor(Color::black) 130 , strokeStyle(NoStroke) 131 , strokeThickness(0.0) 132 , strokeLineCap(ButtCap) 133 , strokeLineJoin(MiterJoin) 134 , strokeMiterLimit(4.0) 135 , strokeDashOffset(0.0) 136 , antialiasingEnabled(true) 137 { 138 } 139 140 PlatformPainterState(const PlatformPainterState& state) 141 { 142 surfaceTransformationMatrix = state.surfaceTransformationMatrix; 143 144 scissoringEnabled = state.scissoringEnabled; 145 scissorRect = state.scissorRect; 146 copyPaintState(&state); 147 } 148 149 void copyPaintState(const PlatformPainterState* other) 150 { 151 compositeOperation = other->compositeOperation; 152 opacity = other->opacity; 153 154 fillColor = other->fillColor; 155 strokeStyle = other->strokeStyle; 156 strokeColor = other->strokeColor; 157 strokeThickness = other->strokeThickness; 158 strokeLineCap = other->strokeLineCap; 159 strokeLineJoin = other->strokeLineJoin; 160 strokeMiterLimit = other->strokeMiterLimit; 161 strokeDashArray = other->strokeDashArray; 162 strokeDashOffset = other->strokeDashOffset; 163 164 antialiasingEnabled = other->antialiasingEnabled; 165 } 166 167 void applyState(PainterOpenVG* painter) 168 { 169 ASSERT(painter); 170 171 setVGSolidColor(VG_FILL_PATH, fillColor); 172 setVGSolidColor(VG_STROKE_PATH, strokeColor); 173 174 vgSetf(VG_STROKE_LINE_WIDTH, strokeThickness); 175 vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(strokeLineCap)); 176 vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(strokeLineJoin)); 177 vgSetf(VG_STROKE_MITER_LIMIT, strokeMiterLimit); 178 179 if (antialiasingEnabled) 180 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER); 181 else 182 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED); 183 184 applyBlending(painter); 185 applyStrokeStyle(); 186 187 applyTransformationMatrix(painter); 188 applyScissorRect(); 189 } 190 191 void applyBlending(PainterOpenVG* painter) 192 { 193 VGBlendMode blendMode = VG_BLEND_SRC_OVER; 194 195 switch (compositeOperation) { 196 case CompositeClear: { 197 // Clear means "set to fully transparent regardless of SRC". 198 // We implement that by multiplying DST with white color 199 // (= no changes) and an alpha of 1.0 - opacity, so the destination 200 // pixels will be fully transparent when opacity == 1.0 and 201 // unchanged when opacity == 0.0. 202 blendMode = VG_BLEND_DST_IN; 203 const VGfloat values[] = { 0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0 - opacity }; 204 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 205 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 206 ASSERT_VG_NO_ERROR(); 207 break; 208 } 209 case CompositeCopy: 210 blendMode = VG_BLEND_SRC; 211 break; 212 case CompositeSourceOver: 213 blendMode = VG_BLEND_SRC_OVER; 214 break; 215 case CompositeSourceIn: 216 blendMode = VG_BLEND_SRC_IN; 217 break; 218 case CompositeSourceOut: 219 notImplemented(); 220 break; 221 case CompositeSourceAtop: 222 notImplemented(); 223 break; 224 case CompositeDestinationOver: 225 blendMode = VG_BLEND_DST_OVER; 226 break; 227 case CompositeDestinationIn: 228 blendMode = VG_BLEND_DST_IN; 229 break; 230 case CompositeDestinationOut: 231 notImplemented(); 232 break; 233 case CompositeDestinationAtop: 234 notImplemented(); 235 break; 236 case CompositeXOR: 237 notImplemented(); 238 break; 239 case CompositePlusDarker: 240 blendMode = VG_BLEND_DARKEN; 241 break; 242 case CompositeHighlight: 243 notImplemented(); 244 break; 245 case CompositePlusLighter: 246 blendMode = VG_BLEND_LIGHTEN; 247 break; 248 } 249 250 if (compositeOperation != CompositeClear) { 251 if (opacity >= (1.0 - FLT_EPSILON)) 252 vgSeti(VG_COLOR_TRANSFORM, VG_FALSE); 253 else if (blendMode == VG_BLEND_SRC) { 254 blendMode = VG_BLEND_SRC_OVER; 255 VGfloat values[] = { 1.0, 1.0, 1.0, 0.0, 0.0, 0.0, 0.0, opacity }; 256 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 257 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 258 } else { 259 VGfloat values[] = { 1.0, 1.0, 1.0, opacity, 0.0, 0.0, 0.0, 0.0 }; 260 vgSetfv(VG_COLOR_TRANSFORM_VALUES, 8, values); 261 vgSeti(VG_COLOR_TRANSFORM, VG_TRUE); 262 } 263 ASSERT_VG_NO_ERROR(); 264 } 265 266 vgSeti(VG_BLEND_MODE, blendMode); 267 ASSERT_VG_NO_ERROR(); 268 } 269 270 void applyTransformationMatrix(PainterOpenVG* painter) 271 { 272 // There are *five* separate transforms that can be applied to OpenVG as of 1.1 273 // but it is not clear that we need to set them separately. Instead we set them 274 // all right here and let this be a call to essentially set the world transformation! 275 VGMatrix vgMatrix(surfaceTransformationMatrix); 276 const VGfloat* vgFloatArray = vgMatrix.toVGfloat(); 277 278 vgSeti(VG_MATRIX_MODE, VG_MATRIX_PATH_USER_TO_SURFACE); 279 vgLoadMatrix(vgFloatArray); 280 ASSERT_VG_NO_ERROR(); 281 282 vgSeti(VG_MATRIX_MODE, VG_MATRIX_IMAGE_USER_TO_SURFACE); 283 vgLoadMatrix(vgFloatArray); 284 ASSERT_VG_NO_ERROR(); 285 286 #ifdef OPENVG_VERSION_1_1 287 vgSeti(VG_MATRIX_MODE, VG_MATRIX_GLYPH_USER_TO_SURFACE); 288 vgLoadMatrix(vgFloatArray); 289 ASSERT_VG_NO_ERROR(); 290 #endif 291 } 292 293 void applyScissorRect() 294 { 295 if (scissoringEnabled) { 296 vgSeti(VG_SCISSORING, VG_TRUE); 297 vgSetfv(VG_SCISSOR_RECTS, 4, VGRect(scissorRect).toVGfloat()); 298 } else 299 vgSeti(VG_SCISSORING, VG_FALSE); 300 301 ASSERT_VG_NO_ERROR(); 302 } 303 304 void applyStrokeStyle() 305 { 306 if (strokeStyle == DottedStroke) { 307 VGfloat vgFloatArray[2] = { 1.0, 1.0 }; 308 vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); 309 vgSetf(VG_STROKE_DASH_PHASE, 0.0); 310 } else if (strokeStyle == DashedStroke) { 311 if (!strokeDashArray.size()) { 312 VGfloat vgFloatArray[2] = { 4.0, 3.0 }; 313 vgSetfv(VG_STROKE_DASH_PATTERN, 2, vgFloatArray); 314 } else { 315 Vector<VGfloat> vgFloatArray(strokeDashArray.size()); 316 for (int i = 0; i < strokeDashArray.size(); ++i) 317 vgFloatArray[i] = strokeDashArray[i]; 318 319 vgSetfv(VG_STROKE_DASH_PATTERN, vgFloatArray.size(), vgFloatArray.data()); 320 } 321 vgSetf(VG_STROKE_DASH_PHASE, strokeDashOffset); 322 } else { 323 vgSetfv(VG_STROKE_DASH_PATTERN, 0, 0); 324 vgSetf(VG_STROKE_DASH_PHASE, 0.0); 325 } 326 327 ASSERT_VG_NO_ERROR(); 328 } 329 330 inline bool strokeDisabled() const 331 { 332 return (compositeOperation == CompositeSourceOver 333 && (strokeStyle == NoStroke || !strokeColor.alpha())); 334 } 335 336 inline bool fillDisabled() const 337 { 338 return (compositeOperation == CompositeSourceOver && !fillColor.alpha()); 339 } 340 }; 341 342 343 PainterOpenVG::PainterOpenVG() 344 : m_state(0) 345 , m_surface(0) 346 { 347 } 348 349 PainterOpenVG::PainterOpenVG(SurfaceOpenVG* surface) 350 : m_state(0) 351 , m_surface(0) 352 { 353 ASSERT(surface); 354 begin(surface); 355 } 356 357 PainterOpenVG::~PainterOpenVG() 358 { 359 end(); 360 } 361 362 void PainterOpenVG::begin(SurfaceOpenVG* surface) 363 { 364 if (surface == m_surface) 365 return; 366 367 ASSERT(surface); 368 ASSERT(!m_state); 369 370 m_surface = surface; 371 372 m_stateStack.append(new PlatformPainterState()); 373 m_state = m_stateStack.last(); 374 375 m_surface->setActivePainter(this); 376 m_surface->makeCurrent(); 377 } 378 379 void PainterOpenVG::end() 380 { 381 if (!m_surface) 382 return; 383 384 m_surface->setActivePainter(0); 385 m_surface = 0; 386 387 destroyPainterStates(); 388 } 389 390 void PainterOpenVG::destroyPainterStates() 391 { 392 PlatformPainterState* state = 0; 393 while (!m_stateStack.isEmpty()) { 394 state = m_stateStack.last(); 395 m_stateStack.removeLast(); 396 delete state; 397 } 398 m_state = 0; 399 } 400 401 // Called by friend SurfaceOpenVG, private otherwise. 402 void PainterOpenVG::applyState() 403 { 404 ASSERT(m_state); 405 m_state->applyState(this); 406 } 407 408 /** 409 * Copy the current back buffer image onto the surface. 410 * 411 * Call this method when all painting operations have been completed, 412 * otherwise the surface won't visibly change. 413 */ 414 void PainterOpenVG::blitToSurface() 415 { 416 ASSERT(m_state); // implies m_surface 417 m_surface->flush(); 418 } 419 420 TransformationMatrix PainterOpenVG::transformationMatrix() const 421 { 422 ASSERT(m_state); 423 return m_state->surfaceTransformationMatrix; 424 } 425 426 void PainterOpenVG::concatTransformationMatrix(const TransformationMatrix& matrix) 427 { 428 ASSERT(m_state); 429 m_surface->makeCurrent(); 430 431 // We do the multiplication ourself using WebCore's TransformationMatrix rather than 432 // offloading this to VG via vgMultMatrix to keep things simple and so we can maintain 433 // state ourselves. 434 m_state->surfaceTransformationMatrix.multLeft(matrix); 435 m_state->applyTransformationMatrix(this); 436 } 437 438 void PainterOpenVG::setTransformationMatrix(const TransformationMatrix& matrix) 439 { 440 ASSERT(m_state); 441 m_surface->makeCurrent(); 442 443 m_state->surfaceTransformationMatrix = matrix; 444 m_state->applyTransformationMatrix(this); 445 } 446 447 CompositeOperator PainterOpenVG::compositeOperation() const 448 { 449 ASSERT(m_state); 450 return m_state->compositeOperation; 451 } 452 453 void PainterOpenVG::setCompositeOperation(CompositeOperator op) 454 { 455 ASSERT(m_state); 456 m_surface->makeCurrent(); 457 458 m_state->compositeOperation = op; 459 m_state->applyBlending(this); 460 } 461 462 float PainterOpenVG::opacity() const 463 { 464 ASSERT(m_state); 465 return m_state->opacity; 466 } 467 468 void PainterOpenVG::setOpacity(float opacity) 469 { 470 ASSERT(m_state); 471 m_surface->makeCurrent(); 472 473 m_state->opacity = opacity; 474 m_state->applyBlending(this); 475 } 476 477 float PainterOpenVG::strokeThickness() const 478 { 479 ASSERT(m_state); 480 return m_state->strokeThickness; 481 } 482 483 void PainterOpenVG::setStrokeThickness(float thickness) 484 { 485 ASSERT(m_state); 486 m_surface->makeCurrent(); 487 488 m_state->strokeThickness = thickness; 489 vgSetf(VG_STROKE_LINE_WIDTH, thickness); 490 ASSERT_VG_NO_ERROR(); 491 } 492 493 StrokeStyle PainterOpenVG::strokeStyle() const 494 { 495 ASSERT(m_state); 496 return m_state->strokeStyle; 497 } 498 499 void PainterOpenVG::setStrokeStyle(const StrokeStyle& style) 500 { 501 ASSERT(m_state); 502 m_surface->makeCurrent(); 503 504 m_state->strokeStyle = style; 505 m_state->applyStrokeStyle(); 506 } 507 508 void PainterOpenVG::setLineDash(const DashArray& dashArray, float dashOffset) 509 { 510 ASSERT(m_state); 511 m_surface->makeCurrent(); 512 513 m_state->strokeDashArray = dashArray; 514 m_state->strokeDashOffset = dashOffset; 515 m_state->applyStrokeStyle(); 516 } 517 518 void PainterOpenVG::setLineCap(LineCap lineCap) 519 { 520 ASSERT(m_state); 521 m_surface->makeCurrent(); 522 523 m_state->strokeLineCap = lineCap; 524 vgSeti(VG_STROKE_CAP_STYLE, toVGCapStyle(lineCap)); 525 ASSERT_VG_NO_ERROR(); 526 } 527 528 void PainterOpenVG::setLineJoin(LineJoin lineJoin) 529 { 530 ASSERT(m_state); 531 m_surface->makeCurrent(); 532 533 m_state->strokeLineJoin = lineJoin; 534 vgSeti(VG_STROKE_JOIN_STYLE, toVGJoinStyle(lineJoin)); 535 ASSERT_VG_NO_ERROR(); 536 } 537 538 void PainterOpenVG::setMiterLimit(float miterLimit) 539 { 540 ASSERT(m_state); 541 m_surface->makeCurrent(); 542 543 m_state->strokeMiterLimit = miterLimit; 544 vgSetf(VG_STROKE_MITER_LIMIT, miterLimit); 545 ASSERT_VG_NO_ERROR(); 546 } 547 548 Color PainterOpenVG::strokeColor() const 549 { 550 ASSERT(m_state); 551 return m_state->strokeColor; 552 } 553 554 void PainterOpenVG::setStrokeColor(const Color& color) 555 { 556 ASSERT(m_state); 557 m_surface->makeCurrent(); 558 559 m_state->strokeColor = color; 560 setVGSolidColor(VG_STROKE_PATH, color); 561 } 562 563 Color PainterOpenVG::fillColor() const 564 { 565 ASSERT(m_state); 566 return m_state->fillColor; 567 } 568 569 void PainterOpenVG::setFillColor(const Color& color) 570 { 571 ASSERT(m_state); 572 m_surface->makeCurrent(); 573 574 m_state->fillColor = color; 575 setVGSolidColor(VG_FILL_PATH, color); 576 } 577 578 bool PainterOpenVG::antialiasingEnabled() const 579 { 580 ASSERT(m_state); 581 return m_state->antialiasingEnabled; 582 } 583 584 void PainterOpenVG::setAntialiasingEnabled(bool enabled) 585 { 586 ASSERT(m_state); 587 m_surface->makeCurrent(); 588 589 m_state->antialiasingEnabled = enabled; 590 591 if (enabled) 592 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_FASTER); 593 else 594 vgSeti(VG_RENDERING_QUALITY, VG_RENDERING_QUALITY_NONANTIALIASED); 595 } 596 597 void PainterOpenVG::scale(const FloatSize& scaleFactors) 598 { 599 ASSERT(m_state); 600 m_surface->makeCurrent(); 601 602 TransformationMatrix matrix = m_state->surfaceTransformationMatrix; 603 matrix.scaleNonUniform(scaleFactors.width(), scaleFactors.height()); 604 setTransformationMatrix(matrix); 605 } 606 607 void PainterOpenVG::rotate(float radians) 608 { 609 ASSERT(m_state); 610 m_surface->makeCurrent(); 611 612 TransformationMatrix matrix = m_state->surfaceTransformationMatrix; 613 matrix.rotate(rad2deg(radians)); 614 setTransformationMatrix(matrix); 615 } 616 617 void PainterOpenVG::translate(float dx, float dy) 618 { 619 ASSERT(m_state); 620 m_surface->makeCurrent(); 621 622 TransformationMatrix matrix = m_state->surfaceTransformationMatrix; 623 matrix.translate(dx, dy); 624 setTransformationMatrix(matrix); 625 } 626 627 void PainterOpenVG::intersectScissorRect(const FloatRect& rect) 628 { 629 // Scissor rectangles are defined by float values, but e.g. painting 630 // something red to a float-clipped rectangle and then painting something 631 // white to the same rectangle will leave some red remnants as it is 632 // rendered to full pixels in between. Also, some OpenVG implementations 633 // are likely to clip to integer coordinates anyways because of the above 634 // effect. So considering the above (and confirming through tests) the 635 // visual result is better if we clip to the enclosing integer rectangle 636 // rather than the exact float rectangle for scissoring. 637 if (m_state->scissoringEnabled) 638 m_state->scissorRect.intersect(FloatRect(enclosingIntRect(rect))); 639 else { 640 m_state->scissoringEnabled = true; 641 m_state->scissorRect = FloatRect(enclosingIntRect(rect)); 642 } 643 644 m_state->applyScissorRect(); 645 } 646 647 void PainterOpenVG::intersectClipRect(const FloatRect& rect) 648 { 649 ASSERT(m_state); 650 m_surface->makeCurrent(); 651 652 if (m_state->surfaceTransformationMatrix.isIdentity()) { 653 // No transformation required, skip all the complex stuff. 654 intersectScissorRect(rect); 655 return; 656 } 657 658 // Check if the actual destination rectangle is still rectilinear (can be 659 // represented as FloatRect) so we could apply scissoring instead of 660 // (potentially more expensive) path clipping. Note that scissoring is not 661 // subject to transformations, so we need to do the transformation to 662 // surface coordinates by ourselves. 663 FloatQuad effectiveScissorQuad = 664 m_state->surfaceTransformationMatrix.mapQuad(FloatQuad(rect)); 665 666 if (effectiveScissorQuad.isRectilinear()) 667 intersectScissorRect(effectiveScissorQuad.boundingBox()); 668 else { 669 // The transformed scissorRect cannot be represented as FloatRect 670 // anymore, so we need to perform masking instead. Not yet implemented. 671 notImplemented(); 672 } 673 } 674 675 void PainterOpenVG::drawRect(const FloatRect& rect, VGbitfield specifiedPaintModes) 676 { 677 ASSERT(m_state); 678 679 VGbitfield paintModes = 0; 680 if (!m_state->strokeDisabled()) 681 paintModes |= VG_STROKE_PATH; 682 if (!m_state->fillDisabled()) 683 paintModes |= VG_FILL_PATH; 684 685 paintModes &= specifiedPaintModes; 686 687 if (!paintModes) 688 return; 689 690 m_surface->makeCurrent(); 691 692 VGPath path = vgCreatePath( 693 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 694 1.0 /* scale */, 0.0 /* bias */, 695 5 /* expected number of segments */, 696 5 /* expected number of total coordinates */, 697 VG_PATH_CAPABILITY_APPEND_TO); 698 ASSERT_VG_NO_ERROR(); 699 700 if (vguRect(path, rect.x(), rect.y(), rect.width(), rect.height()) == VGU_NO_ERROR) { 701 vgDrawPath(path, paintModes); 702 ASSERT_VG_NO_ERROR(); 703 } 704 705 vgDestroyPath(path); 706 ASSERT_VG_NO_ERROR(); 707 } 708 709 void PainterOpenVG::drawRoundedRect(const FloatRect& rect, const IntSize& topLeft, const IntSize& topRight, const IntSize& bottomLeft, const IntSize& bottomRight, VGbitfield specifiedPaintModes) 710 { 711 ASSERT(m_state); 712 713 VGbitfield paintModes = 0; 714 if (!m_state->strokeDisabled()) 715 paintModes |= VG_STROKE_PATH; 716 if (!m_state->fillDisabled()) 717 paintModes |= VG_FILL_PATH; 718 719 paintModes &= specifiedPaintModes; 720 721 if (!paintModes) 722 return; 723 724 m_surface->makeCurrent(); 725 726 VGPath path = vgCreatePath( 727 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 728 1.0 /* scale */, 0.0 /* bias */, 729 10 /* expected number of segments */, 730 25 /* expected number of total coordinates */, 731 VG_PATH_CAPABILITY_APPEND_TO); 732 ASSERT_VG_NO_ERROR(); 733 734 // clamp corner arc sizes 735 FloatSize clampedTopLeft = FloatSize(topLeft).shrunkTo(rect.size()).expandedTo(FloatSize()); 736 FloatSize clampedTopRight = FloatSize(topRight).shrunkTo(rect.size()).expandedTo(FloatSize()); 737 FloatSize clampedBottomLeft = FloatSize(bottomLeft).shrunkTo(rect.size()).expandedTo(FloatSize()); 738 FloatSize clampedBottomRight = FloatSize(bottomRight).shrunkTo(rect.size()).expandedTo(FloatSize()); 739 740 // As OpenVG's coordinate system is flipped in comparison to WebKit's, 741 // we have to specify the opposite value for the "clockwise" value. 742 static const VGubyte pathSegments[] = { 743 VG_MOVE_TO_ABS, 744 VG_HLINE_TO_REL, 745 VG_SCCWARC_TO_REL, 746 VG_VLINE_TO_REL, 747 VG_SCCWARC_TO_REL, 748 VG_HLINE_TO_REL, 749 VG_SCCWARC_TO_REL, 750 VG_VLINE_TO_REL, 751 VG_SCCWARC_TO_REL, 752 VG_CLOSE_PATH 753 }; 754 // Also, the rounded rectangle path proceeds from the top to the bottom, 755 // requiring height distances and clamped radius sizes to be flipped. 756 const VGfloat pathData[] = { 757 rect.x() + clampedTopLeft.width(), rect.y(), 758 rect.width() - clampedTopLeft.width() - clampedTopRight.width(), 759 clampedTopRight.width(), clampedTopRight.height(), 0, clampedTopRight.width(), clampedTopRight.height(), 760 rect.height() - clampedTopRight.height() - clampedBottomRight.height(), 761 clampedBottomRight.width(), clampedBottomRight.height(), 0, -clampedBottomRight.width(), clampedBottomRight.height(), 762 -(rect.width() - clampedBottomLeft.width() - clampedBottomRight.width()), 763 clampedBottomLeft.width(), clampedBottomLeft.height(), 0, -clampedBottomLeft.width(), -clampedBottomLeft.height(), 764 -(rect.height() - clampedTopLeft.height() - clampedBottomLeft.height()), 765 clampedTopLeft.width(), clampedTopLeft.height(), 0, clampedTopLeft.width(), -clampedTopLeft.height(), 766 }; 767 768 vgAppendPathData(path, 10, pathSegments, pathData); 769 vgDrawPath(path, paintModes); 770 vgDestroyPath(path); 771 ASSERT_VG_NO_ERROR(); 772 } 773 774 void PainterOpenVG::drawLine(const IntPoint& from, const IntPoint& to) 775 { 776 ASSERT(m_state); 777 778 if (m_state->strokeDisabled()) 779 return; 780 781 m_surface->makeCurrent(); 782 783 VGPath path = vgCreatePath( 784 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 785 1.0 /* scale */, 0.0 /* bias */, 786 2 /* expected number of segments */, 787 4 /* expected number of total coordinates */, 788 VG_PATH_CAPABILITY_APPEND_TO); 789 ASSERT_VG_NO_ERROR(); 790 791 VGUErrorCode errorCode; 792 793 // Try to align lines to pixels, centering them between pixels for odd thickness values. 794 if (fmod(m_state->strokeThickness + 0.5, 2.0) < 1.0) 795 errorCode = vguLine(path, from.x(), from.y(), to.x(), to.y()); 796 else if ((to.y() - from.y()) > (to.x() - from.x())) // more vertical than horizontal 797 errorCode = vguLine(path, from.x() + 0.5, from.y(), to.x() + 0.5, to.y()); 798 else 799 errorCode = vguLine(path, from.x(), from.y() + 0.5, to.x(), to.y() + 0.5); 800 801 if (errorCode == VGU_NO_ERROR) { 802 vgDrawPath(path, VG_STROKE_PATH); 803 ASSERT_VG_NO_ERROR(); 804 } 805 806 vgDestroyPath(path); 807 ASSERT_VG_NO_ERROR(); 808 } 809 810 void PainterOpenVG::drawArc(const IntRect& rect, int startAngle, int angleSpan, VGbitfield specifiedPaintModes) 811 { 812 ASSERT(m_state); 813 814 VGbitfield paintModes = 0; 815 if (!m_state->strokeDisabled()) 816 paintModes |= VG_STROKE_PATH; 817 if (!m_state->fillDisabled()) 818 paintModes |= VG_FILL_PATH; 819 820 paintModes &= specifiedPaintModes; 821 822 if (!paintModes) 823 return; 824 825 m_surface->makeCurrent(); 826 827 VGPath path = vgCreatePath( 828 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 829 1.0 /* scale */, 0.0 /* bias */, 830 2 /* expected number of segments */, 831 4 /* expected number of total coordinates */, 832 VG_PATH_CAPABILITY_APPEND_TO); 833 ASSERT_VG_NO_ERROR(); 834 835 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) { 836 vgDrawPath(path, VG_STROKE_PATH); 837 ASSERT_VG_NO_ERROR(); 838 } 839 840 vgDestroyPath(path); 841 ASSERT_VG_NO_ERROR(); 842 } 843 844 void PainterOpenVG::drawEllipse(const IntRect& rect, VGbitfield specifiedPaintModes) 845 { 846 ASSERT(m_state); 847 848 VGbitfield paintModes = 0; 849 if (!m_state->strokeDisabled()) 850 paintModes |= VG_STROKE_PATH; 851 if (!m_state->fillDisabled()) 852 paintModes |= VG_FILL_PATH; 853 854 paintModes &= specifiedPaintModes; 855 856 if (!paintModes) 857 return; 858 859 m_surface->makeCurrent(); 860 861 VGPath path = vgCreatePath( 862 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 863 1.0 /* scale */, 0.0 /* bias */, 864 4 /* expected number of segments */, 865 12 /* expected number of total coordinates */, 866 VG_PATH_CAPABILITY_APPEND_TO); 867 ASSERT_VG_NO_ERROR(); 868 869 if (vguEllipse(path, rect.x() + rect.width() / 2.0, rect.y() + rect.height() / 2.0, rect.width(), rect.height()) == VGU_NO_ERROR) { 870 vgDrawPath(path, paintModes); 871 ASSERT_VG_NO_ERROR(); 872 } 873 874 vgDestroyPath(path); 875 ASSERT_VG_NO_ERROR(); 876 } 877 878 void PainterOpenVG::drawPolygon(size_t numPoints, const FloatPoint* points, VGbitfield specifiedPaintModes) 879 { 880 ASSERT(m_state); 881 882 VGbitfield paintModes = 0; 883 if (!m_state->strokeDisabled()) 884 paintModes |= VG_STROKE_PATH; 885 if (!m_state->fillDisabled()) 886 paintModes |= VG_FILL_PATH; 887 888 paintModes &= specifiedPaintModes; 889 890 if (!paintModes) 891 return; 892 893 m_surface->makeCurrent(); 894 895 // Path segments: all points + "close path". 896 const VGint numSegments = numPoints + 1; 897 const VGint numCoordinates = numPoints * 2; 898 899 VGPath path = vgCreatePath( 900 VG_PATH_FORMAT_STANDARD, VG_PATH_DATATYPE_F, 901 1.0 /* scale */, 0.0 /* bias */, 902 numSegments /* expected number of segments */, 903 numCoordinates /* expected number of total coordinates */, 904 VG_PATH_CAPABILITY_APPEND_TO); 905 ASSERT_VG_NO_ERROR(); 906 907 Vector<VGfloat> vgPoints(numCoordinates); 908 for (int i = 0; i < numPoints; ++i) { 909 vgPoints[i*2] = points[i].x(); 910 vgPoints[i*2 + 1] = points[i].y(); 911 } 912 913 if (vguPolygon(path, vgPoints.data(), numPoints, VG_TRUE /* closed */) == VGU_NO_ERROR) { 914 vgDrawPath(path, paintModes); 915 ASSERT_VG_NO_ERROR(); 916 } 917 918 vgDestroyPath(path); 919 ASSERT_VG_NO_ERROR(); 920 } 921 922 void PainterOpenVG::save(PainterOpenVG::SaveMode saveMode) 923 { 924 ASSERT(m_state); 925 926 // If the underlying context/surface was switched away by someone without 927 // telling us, it might not correspond to the one assigned to this painter. 928 // Switch back so we can save the state properly. (Should happen rarely.) 929 // Use DontSaveOrApplyPainterState mode in order to avoid recursion. 930 m_surface->makeCurrent(SurfaceOpenVG::DontSaveOrApplyPainterState); 931 932 if (saveMode == PainterOpenVG::CreateNewState) { 933 PlatformPainterState* state = new PlatformPainterState(*m_state); 934 m_stateStack.append(state); 935 m_state = m_stateStack.last(); 936 } else { // if (saveMode == PainterOpenVG::CreateNewStateWithPaintStateOnly) { 937 PlatformPainterState* state = new PlatformPainterState(); 938 state->copyPaintState(m_state); 939 m_stateStack.append(state); 940 m_state = m_stateStack.last(); 941 } 942 } 943 944 void PainterOpenVG::restore() 945 { 946 ASSERT(m_stateStack.size() >= 2); 947 m_surface->makeCurrent(SurfaceOpenVG::DontApplyPainterState); 948 949 PlatformPainterState* state = m_stateStack.last(); 950 m_stateStack.removeLast(); 951 delete state; 952 953 m_state = m_stateStack.last(); 954 m_state->applyState(this); 955 } 956 957 } 958