Home | History | Annotate | Download | only in openvg
      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