• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GraphicsContext.h"
34 #include "ImageBuffer.h"
35 #include "NativeImageSkia.h"
36 #include "PlatformContextSkia.h"
37 #include "SkiaUtils.h"
38 
39 #include "skia/ext/image_operations.h"
40 #include "skia/ext/platform_canvas.h"
41 
42 #include "SkBitmap.h"
43 #include "SkColorPriv.h"
44 #include "SkShader.h"
45 #include "SkDashPathEffect.h"
46 
47 #include <wtf/MathExtras.h>
48 #include <wtf/Vector.h>
49 
50 namespace WebCore
51 {
52 extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path);
53 }
54 
55 // State -----------------------------------------------------------------------
56 
57 // Encapsulates the additional painting state information we store for each
58 // pushed graphics state.
59 struct PlatformContextSkia::State {
60     State();
61     State(const State&);
62     ~State();
63 
64     // Common shader state.
65     float m_alpha;
66     SkXfermode::Mode m_xferMode;
67     bool m_useAntialiasing;
68     SkDrawLooper* m_looper;
69 
70     // Fill.
71     SkColor m_fillColor;
72     SkShader* m_fillShader;
73 
74     // Stroke.
75     WebCore::StrokeStyle m_strokeStyle;
76     SkColor m_strokeColor;
77     SkShader* m_strokeShader;
78     float m_strokeThickness;
79     int m_dashRatio;  // Ratio of the length of a dash to its width.
80     float m_miterLimit;
81     SkPaint::Cap m_lineCap;
82     SkPaint::Join m_lineJoin;
83     SkDashPathEffect* m_dash;
84 
85     // Text. (See cTextFill & friends in GraphicsContext.h.)
86     int m_textDrawingMode;
87 
88     // Helper function for applying the state's alpha value to the given input
89     // color to produce a new output color.
90     SkColor applyAlpha(SkColor) const;
91 
92 #if OS(LINUX) || OS(WINDOWS)
93     // If non-empty, the current State is clipped to this image.
94     SkBitmap m_imageBufferClip;
95     // If m_imageBufferClip is non-empty, this is the region the image is clipped to.
96     WebCore::FloatRect m_clip;
97 #endif
98 
99     // This is a list of clipping paths which are currently active, in the
100     // order in which they were pushed.
101     WTF::Vector<SkPath> m_antiAliasClipPaths;
102 
103 private:
104     // Not supported.
105     void operator=(const State&);
106 };
107 
108 // Note: Keep theses default values in sync with GraphicsContextState.
State()109 PlatformContextSkia::State::State()
110     : m_alpha(1)
111     , m_xferMode(SkXfermode::kSrcOver_Mode)
112     , m_useAntialiasing(true)
113     , m_looper(0)
114     , m_fillColor(0xFF000000)
115     , m_fillShader(0)
116     , m_strokeStyle(WebCore::SolidStroke)
117     , m_strokeColor(WebCore::Color::black)
118     , m_strokeShader(0)
119     , m_strokeThickness(0)
120     , m_dashRatio(3)
121     , m_miterLimit(4)
122     , m_lineCap(SkPaint::kDefault_Cap)
123     , m_lineJoin(SkPaint::kDefault_Join)
124     , m_dash(0)
125     , m_textDrawingMode(WebCore::cTextFill)
126 {
127 }
128 
State(const State & other)129 PlatformContextSkia::State::State(const State& other)
130     : m_alpha(other.m_alpha)
131     , m_xferMode(other.m_xferMode)
132     , m_useAntialiasing(other.m_useAntialiasing)
133     , m_looper(other.m_looper)
134     , m_fillColor(other.m_fillColor)
135     , m_fillShader(other.m_fillShader)
136     , m_strokeStyle(other.m_strokeStyle)
137     , m_strokeColor(other.m_strokeColor)
138     , m_strokeShader(other.m_strokeShader)
139     , m_strokeThickness(other.m_strokeThickness)
140     , m_dashRatio(other.m_dashRatio)
141     , m_miterLimit(other.m_miterLimit)
142     , m_lineCap(other.m_lineCap)
143     , m_lineJoin(other.m_lineJoin)
144     , m_dash(other.m_dash)
145     , m_textDrawingMode(other.m_textDrawingMode)
146 #if OS(LINUX) || OS(WINDOWS)
147     , m_imageBufferClip(other.m_imageBufferClip)
148     , m_clip(other.m_clip)
149 #endif
150 {
151     // Up the ref count of these. saveRef does nothing if 'this' is NULL.
152     m_looper->safeRef();
153     m_dash->safeRef();
154     m_fillShader->safeRef();
155     m_strokeShader->safeRef();
156 }
157 
~State()158 PlatformContextSkia::State::~State()
159 {
160     m_looper->safeUnref();
161     m_dash->safeUnref();
162     m_fillShader->safeUnref();
163     m_strokeShader->safeUnref();
164 }
165 
applyAlpha(SkColor c) const166 SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
167 {
168     int s = roundf(m_alpha * 256);
169     if (s >= 256)
170         return c;
171     if (s < 0)
172         return 0;
173 
174     int a = SkAlphaMul(SkColorGetA(c), s);
175     return (c & 0x00FFFFFF) | (a << 24);
176 }
177 
178 // PlatformContextSkia ---------------------------------------------------------
179 
180 // Danger: canvas can be NULL.
PlatformContextSkia(skia::PlatformCanvas * canvas)181 PlatformContextSkia::PlatformContextSkia(skia::PlatformCanvas* canvas)
182     : m_canvas(canvas)
183 #if OS(WINDOWS)
184     , m_drawingToImageBuffer(false)
185 #endif
186 {
187     m_stateStack.append(State());
188     m_state = &m_stateStack.last();
189 }
190 
~PlatformContextSkia()191 PlatformContextSkia::~PlatformContextSkia()
192 {
193 }
194 
setCanvas(skia::PlatformCanvas * canvas)195 void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
196 {
197     m_canvas = canvas;
198 }
199 
200 #if OS(WINDOWS)
setDrawingToImageBuffer(bool value)201 void PlatformContextSkia::setDrawingToImageBuffer(bool value)
202 {
203     m_drawingToImageBuffer = value;
204 }
205 
isDrawingToImageBuffer() const206 bool PlatformContextSkia::isDrawingToImageBuffer() const
207 {
208     return m_drawingToImageBuffer;
209 }
210 #endif
211 
save()212 void PlatformContextSkia::save()
213 {
214     m_stateStack.append(*m_state);
215     m_state = &m_stateStack.last();
216 
217 #if OS(LINUX) || OS(WINDOWS)
218     // The clip image only needs to be applied once. Reset the image so that we
219     // don't attempt to clip multiple times.
220     m_state->m_imageBufferClip.reset();
221 #endif
222 
223     // Save our native canvas.
224     canvas()->save();
225 }
226 
227 #if OS(LINUX) || OS(WINDOWS)
beginLayerClippedToImage(const WebCore::FloatRect & rect,const WebCore::ImageBuffer * imageBuffer)228 void PlatformContextSkia::beginLayerClippedToImage(const WebCore::FloatRect& rect,
229                                                    const WebCore::ImageBuffer* imageBuffer)
230 {
231     // Skia doesn't support clipping to an image, so we create a layer. The next
232     // time restore is invoked the layer and |imageBuffer| are combined to
233     // create the resulting image.
234     m_state->m_clip = rect;
235     SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
236                       SkFloatToScalar(rect.right()), SkFloatToScalar(rect.bottom()) };
237 
238     canvas()->clipRect(bounds);
239     canvas()->saveLayerAlpha(&bounds, 255,
240                              static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
241     // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
242     const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
243     if (!bitmap->pixelRef()) {
244         // The bitmap owns it's pixels. This happens when we've allocated the
245         // pixels in some way and assigned them directly to the bitmap (as
246         // happens when we allocate a DIB). In this case the assignment operator
247         // does not copy the pixels, rather the copied bitmap ends up
248         // referencing the same pixels. As the pixels may not live as long as we
249         // need it to, we copy the image.
250         bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
251     } else {
252         // If there is a pixel ref, we can safely use the assignment operator.
253         m_state->m_imageBufferClip = *bitmap;
254     }
255 }
256 #endif
257 
clipPathAntiAliased(const SkPath & clipPath)258 void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
259 {
260     // If we are currently tracking any anti-alias clip paths, then we already
261     // have a layer in place and don't need to add another.
262     bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size();
263 
264     // See comments in applyAntiAliasedClipPaths about how this works.
265     m_state->m_antiAliasClipPaths.append(clipPath);
266 
267     if (!haveLayerOutstanding) {
268         SkRect bounds = clipPath.getBounds();
269         canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag));
270     }
271 }
272 
restore()273 void PlatformContextSkia::restore()
274 {
275 #if OS(LINUX) || OS(WINDOWS)
276     if (!m_state->m_imageBufferClip.empty()) {
277         applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
278         canvas()->restore();
279     }
280 #endif
281 
282     if (!m_state->m_antiAliasClipPaths.isEmpty())
283         applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths);
284 
285     m_stateStack.removeLast();
286     m_state = &m_stateStack.last();
287 
288     // Restore our native canvas.
289     canvas()->restore();
290 }
291 
drawRect(SkRect rect)292 void PlatformContextSkia::drawRect(SkRect rect)
293 {
294     SkPaint paint;
295     int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
296     if (fillcolorNotTransparent) {
297         setupPaintForFilling(&paint);
298         canvas()->drawRect(rect, paint);
299     }
300 
301     if (m_state->m_strokeStyle != WebCore::NoStroke &&
302         (m_state->m_strokeColor & 0xFF000000)) {
303         // We do a fill of four rects to simulate the stroke of a border.
304         SkColor oldFillColor = m_state->m_fillColor;
305 
306         // setFillColor() will set the shader to NULL, so save a ref to it now.
307         SkShader* oldFillShader = m_state->m_fillShader;
308         oldFillShader->safeRef();
309         setFillColor(m_state->m_strokeColor);
310         paint.reset();
311         setupPaintForFilling(&paint);
312         SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
313         canvas()->drawRect(topBorder, paint);
314         SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom };
315         canvas()->drawRect(bottomBorder, paint);
316         SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 };
317         canvas()->drawRect(leftBorder, paint);
318         SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
319         canvas()->drawRect(rightBorder, paint);
320         setFillColor(oldFillColor);
321         setFillShader(oldFillShader);
322         oldFillShader->safeUnref();
323     }
324 }
325 
setupPaintCommon(SkPaint * paint) const326 void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
327 {
328 #if defined(SK_DEBUG)
329     {
330         SkPaint defaultPaint;
331         SkASSERT(*paint == defaultPaint);
332     }
333 #endif
334 
335     paint->setAntiAlias(m_state->m_useAntialiasing);
336     paint->setXfermodeMode(m_state->m_xferMode);
337     paint->setLooper(m_state->m_looper);
338 }
339 
setupPaintForFilling(SkPaint * paint) const340 void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
341 {
342     setupPaintCommon(paint);
343     paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
344     paint->setShader(m_state->m_fillShader);
345 }
346 
scalarBound(SkScalar v,SkScalar min,SkScalar max)347 static SkScalar scalarBound(SkScalar v, SkScalar min, SkScalar max)
348 {
349     if (v < min)
350         return min;
351     if (v > max)
352         return max;
353     return v;
354 }
355 
setupPaintForStroking(SkPaint * paint,SkRect * rect,int length) const356 float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
357 {
358     setupPaintCommon(paint);
359     float width = m_state->m_strokeThickness;
360 
361     paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
362     paint->setShader(m_state->m_strokeShader);
363     paint->setStyle(SkPaint::kStroke_Style);
364     // The limits here (512 and 256) were made up but are hopefully large
365     // enough to be reasonable. They are, empirically, small enough not to
366     // cause overflows in Skia.
367     paint->setStrokeWidth(scalarBound(SkFloatToScalar(width), 0, 512));
368     paint->setStrokeCap(m_state->m_lineCap);
369     paint->setStrokeJoin(m_state->m_lineJoin);
370     paint->setStrokeMiter(scalarBound(SkFloatToScalar(m_state->m_miterLimit), 0, 256));
371 
372     if (m_state->m_dash)
373         paint->setPathEffect(m_state->m_dash);
374     else {
375         switch (m_state->m_strokeStyle) {
376         case WebCore::NoStroke:
377         case WebCore::SolidStroke:
378             break;
379         case WebCore::DashedStroke:
380             width = m_state->m_dashRatio * width;
381             // Fall through.
382         case WebCore::DottedStroke:
383             // Truncate the width, since we don't want fuzzy dots or dashes.
384             int dashLength = static_cast<int>(width);
385             // Subtract off the endcaps, since they're rendered separately.
386             int distance = length - 2 * static_cast<int>(m_state->m_strokeThickness);
387             int phase = 1;
388             if (dashLength > 1) {
389                 // Determine how many dashes or dots we should have.
390                 int numDashes = distance / dashLength;
391                 int remainder = distance % dashLength;
392                 // Adjust the phase to center the dashes within the line.
393                 if (numDashes % 2 == 0) {
394                     // Even:  shift right half a dash, minus half the remainder
395                     phase = (dashLength - remainder) / 2;
396                 } else {
397                     // Odd:  shift right a full dash, minus half the remainder
398                     phase = dashLength - remainder / 2;
399                 }
400             }
401             SkScalar dashLengthSk = SkIntToScalar(dashLength);
402             SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
403             paint->setPathEffect(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase)))->unref();
404         }
405     }
406 
407     return width;
408 }
409 
setDrawLooper(SkDrawLooper * dl)410 void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
411 {
412     SkRefCnt_SafeAssign(m_state->m_looper, dl);
413 }
414 
setMiterLimit(float ml)415 void PlatformContextSkia::setMiterLimit(float ml)
416 {
417     m_state->m_miterLimit = ml;
418 }
419 
setAlpha(float alpha)420 void PlatformContextSkia::setAlpha(float alpha)
421 {
422     m_state->m_alpha = alpha;
423 }
424 
setLineCap(SkPaint::Cap lc)425 void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
426 {
427     m_state->m_lineCap = lc;
428 }
429 
setLineJoin(SkPaint::Join lj)430 void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
431 {
432     m_state->m_lineJoin = lj;
433 }
434 
setXfermodeMode(SkXfermode::Mode pdm)435 void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
436 {
437     m_state->m_xferMode = pdm;
438 }
439 
setFillColor(SkColor color)440 void PlatformContextSkia::setFillColor(SkColor color)
441 {
442     m_state->m_fillColor = color;
443     setFillShader(NULL);
444 }
445 
getDrawLooper() const446 SkDrawLooper* PlatformContextSkia::getDrawLooper() const
447 {
448     return m_state->m_looper;
449 }
450 
getStrokeStyle() const451 WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const
452 {
453     return m_state->m_strokeStyle;
454 }
455 
setStrokeStyle(WebCore::StrokeStyle strokeStyle)456 void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
457 {
458     m_state->m_strokeStyle = strokeStyle;
459 }
460 
setStrokeColor(SkColor strokeColor)461 void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
462 {
463     m_state->m_strokeColor = strokeColor;
464     setStrokeShader(NULL);
465 }
466 
getStrokeThickness() const467 float PlatformContextSkia::getStrokeThickness() const
468 {
469     return m_state->m_strokeThickness;
470 }
471 
setStrokeThickness(float thickness)472 void PlatformContextSkia::setStrokeThickness(float thickness)
473 {
474     m_state->m_strokeThickness = thickness;
475 }
476 
setStrokeShader(SkShader * strokeShader)477 void PlatformContextSkia::setStrokeShader(SkShader* strokeShader)
478 {
479     if (strokeShader != m_state->m_strokeShader) {
480         m_state->m_strokeShader->safeUnref();
481         m_state->m_strokeShader = strokeShader;
482         m_state->m_strokeShader->safeRef();
483     }
484 }
485 
getTextDrawingMode() const486 int PlatformContextSkia::getTextDrawingMode() const
487 {
488     return m_state->m_textDrawingMode;
489 }
490 
getAlpha() const491 float PlatformContextSkia::getAlpha() const
492 {
493     return m_state->m_alpha;
494 }
495 
setTextDrawingMode(int mode)496 void PlatformContextSkia::setTextDrawingMode(int mode)
497 {
498   // cTextClip is never used, so we assert that it isn't set:
499   // https://bugs.webkit.org/show_bug.cgi?id=21898
500   ASSERT((mode & WebCore::cTextClip) == 0);
501   m_state->m_textDrawingMode = mode;
502 }
503 
setUseAntialiasing(bool enable)504 void PlatformContextSkia::setUseAntialiasing(bool enable)
505 {
506     m_state->m_useAntialiasing = enable;
507 }
508 
effectiveFillColor() const509 SkColor PlatformContextSkia::effectiveFillColor() const
510 {
511     return m_state->applyAlpha(m_state->m_fillColor);
512 }
513 
effectiveStrokeColor() const514 SkColor PlatformContextSkia::effectiveStrokeColor() const
515 {
516     return m_state->applyAlpha(m_state->m_strokeColor);
517 }
518 
beginPath()519 void PlatformContextSkia::beginPath()
520 {
521     m_path.reset();
522 }
523 
addPath(const SkPath & path)524 void PlatformContextSkia::addPath(const SkPath& path)
525 {
526     m_path.addPath(path, m_canvas->getTotalMatrix());
527 }
528 
currentPathInLocalCoordinates() const529 SkPath PlatformContextSkia::currentPathInLocalCoordinates() const
530 {
531     SkPath localPath = m_path;
532     const SkMatrix& matrix = m_canvas->getTotalMatrix();
533     SkMatrix inverseMatrix;
534     if (!matrix.invert(&inverseMatrix))
535         return SkPath();
536     localPath.transform(inverseMatrix);
537     return localPath;
538 }
539 
setFillRule(SkPath::FillType fr)540 void PlatformContextSkia::setFillRule(SkPath::FillType fr)
541 {
542     m_path.setFillType(fr);
543 }
544 
setFillShader(SkShader * fillShader)545 void PlatformContextSkia::setFillShader(SkShader* fillShader)
546 {
547     if (fillShader != m_state->m_fillShader) {
548         m_state->m_fillShader->safeUnref();
549         m_state->m_fillShader = fillShader;
550         m_state->m_fillShader->safeRef();
551     }
552 }
553 
setDashPathEffect(SkDashPathEffect * dash)554 void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
555 {
556     if (dash != m_state->m_dash) {
557         m_state->m_dash->safeUnref();
558         m_state->m_dash = dash;
559     }
560 }
561 
paintSkPaint(const SkRect & rect,const SkPaint & paint)562 void PlatformContextSkia::paintSkPaint(const SkRect& rect,
563                                        const SkPaint& paint)
564 {
565     m_canvas->drawRect(rect, paint);
566 }
567 
bitmap() const568 const SkBitmap* PlatformContextSkia::bitmap() const
569 {
570     return &m_canvas->getDevice()->accessBitmap(false);
571 }
572 
isPrinting()573 bool PlatformContextSkia::isPrinting()
574 {
575     return m_canvas->getTopPlatformDevice().IsVectorial();
576 }
577 
578 #if OS(LINUX) || OS(WINDOWS)
applyClipFromImage(const WebCore::FloatRect & rect,const SkBitmap & imageBuffer)579 void PlatformContextSkia::applyClipFromImage(const WebCore::FloatRect& rect, const SkBitmap& imageBuffer)
580 {
581     // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
582     // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
583     SkPaint paint;
584     paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
585     m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
586 }
587 #endif
588 
applyAntiAliasedClipPaths(WTF::Vector<SkPath> & paths)589 void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths)
590 {
591     // Anti-aliased clipping:
592     //
593     // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit:
594     // We have a square canvas, filled with white and we declare a circular
595     // clipping path. Then we fill twice with a black rectangle. The fractional
596     // pixels would first get the correct color (white * alpha + black * (1 -
597     // alpha)), but the second fill would apply the alpha to the already
598     // modified color and the result would be too dark.
599     //
600     // This, anti-aliased clipping needs to be performed after the drawing has
601     // been done. In order to do this, we create a new layer of the canvas in
602     // clipPathAntiAliased and store the clipping path. All drawing is done to
603     // the layer's bitmap while it's in effect. When WebKit calls restore() to
604     // undo the clipping, this function is called.
605     //
606     // Here, we walk the list of clipping paths backwards and, for each, we
607     // clear outside of the clipping path. We only need a single extra layer
608     // for any number of clipping paths.
609     //
610     // When we call restore on the SkCanvas, the layer's bitmap is composed
611     // into the layer below and we end up with correct, anti-aliased clipping.
612 
613     SkPaint paint;
614     paint.setXfermodeMode(SkXfermode::kClear_Mode);
615     paint.setAntiAlias(true);
616     paint.setStyle(SkPaint::kFill_Style);
617 
618     for (size_t i = paths.size() - 1; i < paths.size(); --i) {
619         paths[i].setFillType(SkPath::kInverseWinding_FillType);
620         m_canvas->drawPath(paths[i], paint);
621     }
622 
623     m_canvas->restore();
624 }
625