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