53990ec5bc563240dbe8ca39d24e4ea4c2fdefca
[WebKit-https.git] / Source / WebCore / platform / graphics / skia / PlatformContextSkia.cpp
1 /*
2  * Copyright (c) 2008, Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32
33 #include "PlatformContextSkia.h"
34
35 #include "AffineTransform.h"
36 #include "DrawingBuffer.h"
37 #include "Extensions3D.h"
38 #include "GraphicsContext.h"
39 #include "GraphicsContext3D.h"
40 #include "ImageBuffer.h"
41 #include "NativeImageSkia.h"
42 #include "SkiaUtils.h"
43 #include "Texture.h"
44 #include "TilingData.h"
45
46 #include "skia/ext/image_operations.h"
47 #include "skia/ext/platform_canvas.h"
48
49 #include "SkBitmap.h"
50 #include "SkColorPriv.h"
51 #include "SkDashPathEffect.h"
52 #include "SkShader.h"
53
54 #include "GrContext.h"
55 #include "SkGpuDevice.h"
56
57 #include <wtf/MathExtras.h>
58 #include <wtf/Vector.h>
59
60 namespace WebCore {
61
62 extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path);
63
64 // State -----------------------------------------------------------------------
65
66 // Encapsulates the additional painting state information we store for each
67 // pushed graphics state.
68 struct PlatformContextSkia::State {
69     State();
70     State(const State&);
71     ~State();
72
73     // Common shader state.
74     float m_alpha;
75     SkXfermode::Mode m_xferMode;
76     bool m_useAntialiasing;
77     SkDrawLooper* m_looper;
78
79     // Fill.
80     SkColor m_fillColor;
81
82     // Stroke.
83     StrokeStyle m_strokeStyle;
84     SkColor m_strokeColor;
85     float m_strokeThickness;
86     int m_dashRatio;  // Ratio of the length of a dash to its width.
87     float m_miterLimit;
88     SkPaint::Cap m_lineCap;
89     SkPaint::Join m_lineJoin;
90     SkDashPathEffect* m_dash;
91
92     // Text. (See TextModeFill & friends in GraphicsContext.h.)
93     TextDrawingModeFlags m_textDrawingMode;
94
95     // Helper function for applying the state's alpha value to the given input
96     // color to produce a new output color.
97     SkColor applyAlpha(SkColor) const;
98
99     // If non-empty, the current State is clipped to this image.
100     SkBitmap m_imageBufferClip;
101     // If m_imageBufferClip is non-empty, this is the region the image is clipped to.
102     FloatRect m_clip;
103
104     // This is a list of clipping paths which are currently active, in the
105     // order in which they were pushed.
106     WTF::Vector<SkPath> m_antiAliasClipPaths;
107     InterpolationQuality m_interpolationQuality;
108
109     PlatformContextSkia::State cloneInheritedProperties();
110 private:
111     // Not supported.
112     void operator=(const State&);
113 };
114
115 // Note: Keep theses default values in sync with GraphicsContextState.
116 PlatformContextSkia::State::State()
117     : m_alpha(1)
118     , m_xferMode(SkXfermode::kSrcOver_Mode)
119     , m_useAntialiasing(true)
120     , m_looper(0)
121     , m_fillColor(0xFF000000)
122     , m_strokeStyle(SolidStroke)
123     , m_strokeColor(Color::black)
124     , m_strokeThickness(0)
125     , m_dashRatio(3)
126     , m_miterLimit(4)
127     , m_lineCap(SkPaint::kDefault_Cap)
128     , m_lineJoin(SkPaint::kDefault_Join)
129     , m_dash(0)
130     , m_textDrawingMode(TextModeFill)
131     , m_interpolationQuality(InterpolationHigh)
132 {
133 }
134
135 PlatformContextSkia::State::State(const State& other)
136     : m_alpha(other.m_alpha)
137     , m_xferMode(other.m_xferMode)
138     , m_useAntialiasing(other.m_useAntialiasing)
139     , m_looper(other.m_looper)
140     , m_fillColor(other.m_fillColor)
141     , m_strokeStyle(other.m_strokeStyle)
142     , m_strokeColor(other.m_strokeColor)
143     , m_strokeThickness(other.m_strokeThickness)
144     , m_dashRatio(other.m_dashRatio)
145     , m_miterLimit(other.m_miterLimit)
146     , m_lineCap(other.m_lineCap)
147     , m_lineJoin(other.m_lineJoin)
148     , m_dash(other.m_dash)
149     , m_textDrawingMode(other.m_textDrawingMode)
150     , m_imageBufferClip(other.m_imageBufferClip)
151     , m_clip(other.m_clip)
152     , m_antiAliasClipPaths(other.m_antiAliasClipPaths)
153     , m_interpolationQuality(other.m_interpolationQuality)
154 {
155     // Up the ref count of these. SkSafeRef does nothing if its argument is 0.
156     SkSafeRef(m_looper);
157     SkSafeRef(m_dash);
158 }
159
160 PlatformContextSkia::State::~State()
161 {
162     SkSafeUnref(m_looper);
163     SkSafeUnref(m_dash);
164 }
165
166 // Returns a new State with all of this object's inherited properties copied.
167 PlatformContextSkia::State PlatformContextSkia::State::cloneInheritedProperties()
168 {
169     PlatformContextSkia::State state(*this);
170
171     // Everything is inherited except for the clip paths.
172     state.m_antiAliasClipPaths.clear();
173
174     return state;
175 }
176
177 SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
178 {
179     int s = roundf(m_alpha * 256);
180     if (s >= 256)
181         return c;
182     if (s < 0)
183         return 0;
184
185     int a = SkAlphaMul(SkColorGetA(c), s);
186     return (c & 0x00FFFFFF) | (a << 24);
187 }
188
189 // PlatformContextSkia ---------------------------------------------------------
190
191 // Danger: canvas can be NULL.
192 PlatformContextSkia::PlatformContextSkia(SkCanvas* canvas)
193     : m_canvas(canvas)
194     , m_printing(false)
195     , m_drawingToImageBuffer(false)
196     , m_gpuContext(0)
197 {
198     m_stateStack.append(State());
199     m_state = &m_stateStack.last();
200
201     // will be assigned in setGraphicsContext()
202     m_gc = 0;
203 }
204
205 PlatformContextSkia::~PlatformContextSkia()
206 {
207 }
208
209 void PlatformContextSkia::setCanvas(SkCanvas* canvas)
210 {
211     m_canvas = canvas;
212 }
213
214 void PlatformContextSkia::setDrawingToImageBuffer(bool value)
215 {
216     m_drawingToImageBuffer = value;
217 }
218
219 bool PlatformContextSkia::isDrawingToImageBuffer() const
220 {
221     return m_drawingToImageBuffer;
222 }
223
224 void PlatformContextSkia::save()
225 {
226     ASSERT(!hasImageResamplingHint());
227
228     m_stateStack.append(m_state->cloneInheritedProperties());
229     m_state = &m_stateStack.last();
230
231     // The clip image only needs to be applied once. Reset the image so that we
232     // don't attempt to clip multiple times.
233     m_state->m_imageBufferClip.reset();
234
235     // Save our native canvas.
236     canvas()->save();
237 }
238
239 void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect,
240                                                    const ImageBuffer* imageBuffer)
241 {
242     // Skia doesn't support clipping to an image, so we create a layer. The next
243     // time restore is invoked the layer and |imageBuffer| are combined to
244     // create the resulting image.
245     m_state->m_clip = rect;
246     SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
247                       SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) };
248
249     canvas()->clipRect(bounds);
250     canvas()->saveLayerAlpha(&bounds, 255,
251                              static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
252     // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
253     const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
254     if (!bitmap->pixelRef()) {
255         // The bitmap owns it's pixels. This happens when we've allocated the
256         // pixels in some way and assigned them directly to the bitmap (as
257         // happens when we allocate a DIB). In this case the assignment operator
258         // does not copy the pixels, rather the copied bitmap ends up
259         // referencing the same pixels. As the pixels may not live as long as we
260         // need it to, we copy the image.
261         bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
262     } else {
263         // If there is a pixel ref, we can safely use the assignment operator.
264         m_state->m_imageBufferClip = *bitmap;
265     }
266 }
267
268 void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
269 {
270     makeGrContextCurrent();
271     if (m_canvas->getTopDevice()->getDeviceCapabilities() & SkDevice::kVector_Capability) {
272         // When the output is a vector device, like PDF, we don't need antialiased clips.
273         // It's up to the PDF rendering engine to do that. We can simply disable the
274         // antialiased clip code if the output is a vector device.
275         canvas()->clipPath(clipPath);
276         return;
277     }
278
279     // If we are currently tracking any anti-alias clip paths, then we already
280     // have a layer in place and don't need to add another.
281     bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size();
282
283     // See comments in applyAntiAliasedClipPaths about how this works.
284     m_state->m_antiAliasClipPaths.append(clipPath);
285
286     if (!haveLayerOutstanding) {
287         SkRect bounds = clipPath.getBounds();
288         canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag));
289         // Guards state modification during clipped operations.
290         // The state is popped in applyAntiAliasedClipPaths().
291         canvas()->save();
292     }
293 }
294
295 void PlatformContextSkia::restore()
296 {
297     if (!m_state->m_imageBufferClip.empty()) {
298         applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
299         canvas()->restore();
300     }
301
302     if (!m_state->m_antiAliasClipPaths.isEmpty())
303         applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths);
304
305     m_stateStack.removeLast();
306     m_state = &m_stateStack.last();
307
308     // Restore our native canvas.
309     canvas()->restore();
310 }
311
312 void PlatformContextSkia::drawRect(SkRect rect)
313 {
314     SkPaint paint;
315     int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
316     if (fillcolorNotTransparent) {
317         setupPaintForFilling(&paint);
318         canvas()->drawRect(rect, paint);
319     }
320
321     if (m_state->m_strokeStyle != NoStroke
322         && (m_state->m_strokeColor & 0xFF000000)) {
323         // We do a fill of four rects to simulate the stroke of a border.
324         paint.reset();
325         setupPaintForFilling(&paint);
326         // need to jam in the strokeColor
327         paint.setColor(this->effectiveStrokeColor());
328
329         SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
330         canvas()->drawRect(topBorder, paint);
331         SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom };
332         canvas()->drawRect(bottomBorder, paint);
333         SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 };
334         canvas()->drawRect(leftBorder, paint);
335         SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
336         canvas()->drawRect(rightBorder, paint);
337     }
338 }
339
340 void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
341 {
342 #if defined(SK_DEBUG)
343     {
344         SkPaint defaultPaint;
345         SkASSERT(*paint == defaultPaint);
346     }
347 #endif
348
349     paint->setAntiAlias(m_state->m_useAntialiasing);
350     paint->setXfermodeMode(m_state->m_xferMode);
351     paint->setLooper(m_state->m_looper);
352 }
353
354 void PlatformContextSkia::setupShader(SkPaint* paint, Gradient* grad, Pattern* pat, SkColor color) const
355 {
356     SkShader* shader = 0;
357
358     if (grad) {
359         shader = grad->platformGradient();
360         color = SK_ColorBLACK;
361     } else if (pat) {
362         shader = pat->platformPattern(m_gc->getCTM());
363         color = SK_ColorBLACK;
364     }
365
366     paint->setColor(m_state->applyAlpha(color));
367     paint->setShader(shader);
368 }
369
370 void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
371 {
372     setupPaintCommon(paint);
373
374     const GraphicsContextState& state = m_gc->state();
375     setupShader(paint, state.fillGradient.get(), state.fillPattern.get(), m_state->m_fillColor);
376 }
377
378 float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
379 {
380     setupPaintCommon(paint);
381
382     const GraphicsContextState& state = m_gc->state();
383     setupShader(paint, state.strokeGradient.get(), state.strokePattern.get(), m_state->m_strokeColor);
384
385     float width = m_state->m_strokeThickness;
386
387     paint->setStyle(SkPaint::kStroke_Style);
388     paint->setStrokeWidth(SkFloatToScalar(width));
389     paint->setStrokeCap(m_state->m_lineCap);
390     paint->setStrokeJoin(m_state->m_lineJoin);
391     paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
392
393     if (m_state->m_dash)
394         paint->setPathEffect(m_state->m_dash);
395     else {
396         switch (m_state->m_strokeStyle) {
397         case NoStroke:
398         case SolidStroke:
399             break;
400         case DashedStroke:
401             width = m_state->m_dashRatio * width;
402             // Fall through.
403         case DottedStroke:
404             // Truncate the width, since we don't want fuzzy dots or dashes.
405             int dashLength = static_cast<int>(width);
406             // Subtract off the endcaps, since they're rendered separately.
407             int distance = length - 2 * static_cast<int>(m_state->m_strokeThickness);
408             int phase = 1;
409             if (dashLength > 1) {
410                 // Determine how many dashes or dots we should have.
411                 int numDashes = distance / dashLength;
412                 int remainder = distance % dashLength;
413                 // Adjust the phase to center the dashes within the line.
414                 if (numDashes % 2 == 0) {
415                     // Even:  shift right half a dash, minus half the remainder
416                     phase = (dashLength - remainder) / 2;
417                 } else {
418                     // Odd:  shift right a full dash, minus half the remainder
419                     phase = dashLength - remainder / 2;
420                 }
421             }
422             SkScalar dashLengthSk = SkIntToScalar(dashLength);
423             SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
424             paint->setPathEffect(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase)))->unref();
425         }
426     }
427
428     return width;
429 }
430
431 void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
432 {
433     SkRefCnt_SafeAssign(m_state->m_looper, dl);
434 }
435
436 void PlatformContextSkia::setMiterLimit(float ml)
437 {
438     m_state->m_miterLimit = ml;
439 }
440
441 void PlatformContextSkia::setAlpha(float alpha)
442 {
443     m_state->m_alpha = alpha;
444 }
445
446 void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
447 {
448     m_state->m_lineCap = lc;
449 }
450
451 void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
452 {
453     m_state->m_lineJoin = lj;
454 }
455
456 void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
457 {
458     m_state->m_xferMode = pdm;
459 }
460
461 void PlatformContextSkia::setFillColor(SkColor color)
462 {
463     m_state->m_fillColor = color;
464 }
465
466 SkDrawLooper* PlatformContextSkia::getDrawLooper() const
467 {
468     return m_state->m_looper;
469 }
470
471 StrokeStyle PlatformContextSkia::getStrokeStyle() const
472 {
473     return m_state->m_strokeStyle;
474 }
475
476 void PlatformContextSkia::setStrokeStyle(StrokeStyle strokeStyle)
477 {
478     m_state->m_strokeStyle = strokeStyle;
479 }
480
481 void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
482 {
483     m_state->m_strokeColor = strokeColor;
484 }
485
486 float PlatformContextSkia::getStrokeThickness() const
487 {
488     return m_state->m_strokeThickness;
489 }
490
491 void PlatformContextSkia::setStrokeThickness(float thickness)
492 {
493     m_state->m_strokeThickness = thickness;
494 }
495
496 TextDrawingModeFlags PlatformContextSkia::getTextDrawingMode() const
497 {
498     return m_state->m_textDrawingMode;
499 }
500
501 float PlatformContextSkia::getAlpha() const
502 {
503     return m_state->m_alpha;
504 }
505
506 int PlatformContextSkia::getNormalizedAlpha() const
507 {
508     int alpha = roundf(m_state->m_alpha * 256);
509     if (alpha > 255)
510         alpha = 255;
511     else if (alpha < 0)
512         alpha = 0;
513     return alpha;
514 }
515
516 void PlatformContextSkia::setTextDrawingMode(TextDrawingModeFlags mode)
517 {
518     // TextModeClip is never used, so we assert that it isn't set:
519     // https://bugs.webkit.org/show_bug.cgi?id=21898
520     ASSERT(!(mode & TextModeClip));
521     m_state->m_textDrawingMode = mode;
522 }
523
524 void PlatformContextSkia::setUseAntialiasing(bool enable)
525 {
526     m_state->m_useAntialiasing = enable;
527 }
528
529 SkColor PlatformContextSkia::effectiveFillColor() const
530 {
531     return m_state->applyAlpha(m_state->m_fillColor);
532 }
533
534 SkColor PlatformContextSkia::effectiveStrokeColor() const
535 {
536     return m_state->applyAlpha(m_state->m_strokeColor);
537 }
538
539 void PlatformContextSkia::canvasClipPath(const SkPath& path)
540 {
541     m_canvas->clipPath(path);
542 }
543
544 InterpolationQuality PlatformContextSkia::interpolationQuality() const
545 {
546     return m_state->m_interpolationQuality;
547 }
548
549 void PlatformContextSkia::setInterpolationQuality(InterpolationQuality interpolationQuality)
550 {
551     m_state->m_interpolationQuality = interpolationQuality;
552 }
553
554 void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
555 {
556     if (dash != m_state->m_dash) {
557         SkSafeUnref(m_state->m_dash);
558         m_state->m_dash = dash;
559     }
560 }
561
562 void PlatformContextSkia::paintSkPaint(const SkRect& rect,
563                                        const SkPaint& paint)
564 {
565     m_canvas->drawRect(rect, paint);
566 }
567
568 const SkBitmap* PlatformContextSkia::bitmap() const
569 {
570     return &m_canvas->getDevice()->accessBitmap(false);
571 }
572
573 bool PlatformContextSkia::isNativeFontRenderingAllowed()
574 {
575 #if ENABLE(SKIA_TEXT)
576     return false;
577 #else
578     if (useSkiaGPU())
579         return false;
580     return skia::SupportsPlatformPaint(m_canvas);
581 #endif
582 }
583
584 void PlatformContextSkia::getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const
585 {
586     *srcSize = m_imageResamplingHintSrcSize;
587     *dstSize = m_imageResamplingHintDstSize;
588 }
589
590 void PlatformContextSkia::setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize)
591 {
592     m_imageResamplingHintSrcSize = srcSize;
593     m_imageResamplingHintDstSize = dstSize;
594 }
595
596 void PlatformContextSkia::clearImageResamplingHint()
597 {
598     m_imageResamplingHintSrcSize = IntSize();
599     m_imageResamplingHintDstSize = FloatSize();
600 }
601
602 bool PlatformContextSkia::hasImageResamplingHint() const
603 {
604     return !m_imageResamplingHintSrcSize.isEmpty() && !m_imageResamplingHintDstSize.isEmpty();
605 }
606
607 void PlatformContextSkia::applyClipFromImage(const FloatRect& rect, const SkBitmap& imageBuffer)
608 {
609     // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
610     // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
611     SkPaint paint;
612     paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
613     m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
614 }
615
616 void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths)
617 {
618     // Anti-aliased clipping:
619     //
620     // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit:
621     // We have a square canvas, filled with white and we declare a circular
622     // clipping path. Then we fill twice with a black rectangle. The fractional
623     // pixels would first get the correct color (white * alpha + black * (1 -
624     // alpha)), but the second fill would apply the alpha to the already
625     // modified color and the result would be too dark.
626     //
627     // This, anti-aliased clipping needs to be performed after the drawing has
628     // been done. In order to do this, we create a new layer of the canvas in
629     // clipPathAntiAliased and store the clipping path. All drawing is done to
630     // the layer's bitmap while it's in effect. When WebKit calls restore() to
631     // undo the clipping, this function is called.
632     //
633     // Here, we walk the list of clipping paths backwards and, for each, we
634     // clear outside of the clipping path. We only need a single extra layer
635     // for any number of clipping paths.
636     //
637     // When we call restore on the SkCanvas, the layer's bitmap is composed
638     // into the layer below and we end up with correct, anti-aliased clipping.
639
640     m_canvas->restore();
641
642     SkPaint paint;
643     paint.setXfermodeMode(SkXfermode::kClear_Mode);
644     paint.setAntiAlias(true);
645     paint.setStyle(SkPaint::kFill_Style);
646
647     for (size_t i = paths.size() - 1; i < paths.size(); --i) {
648         paths[i].toggleInverseFillType();
649         m_canvas->drawPath(paths[i], paint);
650     }
651
652     m_canvas->restore();
653 }
654
655 void PlatformContextSkia::setGraphicsContext3D(GraphicsContext3D* context, DrawingBuffer* drawingBuffer, const WebCore::IntSize& size)
656 {
657     m_gpuContext = context;
658 #if ENABLE(ACCELERATED_2D_CANVAS)
659     if (context && drawingBuffer) {
660         // use skia gpu rendering if available
661         GrContext* gr = context->grContext();
662         if (gr) {
663             context->makeContextCurrent();
664             drawingBuffer->bind();
665
666             gr->resetContext();
667             drawingBuffer->setGrContext(gr);
668
669             GrPlatformSurfaceDesc drawBufDesc;
670             drawingBuffer->getGrPlatformSurfaceDesc(&drawBufDesc);
671             SkAutoTUnref<GrTexture> drawBufTex(static_cast<GrTexture*>(gr->createPlatformSurface(drawBufDesc)));
672             m_canvas->setDevice(new SkGpuDevice(gr, drawBufTex.get()))->unref();
673         } else
674             m_gpuContext = 0;
675     }
676 #endif
677 }
678
679 void PlatformContextSkia::makeGrContextCurrent()
680 {
681     if (m_gpuContext)
682         m_gpuContext->makeContextCurrent();
683 }
684
685 } // namespace WebCore