Home | History | Annotate | Download | only in skia
      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.
    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 
    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 
    158 PlatformContextSkia::State::~State()
    159 {
    160     m_looper->safeUnref();
    161     m_dash->safeUnref();
    162     m_fillShader->safeUnref();
    163     m_strokeShader->safeUnref();
    164 }
    165 
    166 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.
    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 
    191 PlatformContextSkia::~PlatformContextSkia()
    192 {
    193 }
    194 
    195 void PlatformContextSkia::setCanvas(skia::PlatformCanvas* canvas)
    196 {
    197     m_canvas = canvas;
    198 }
    199 
    200 #if OS(WINDOWS)
    201 void PlatformContextSkia::setDrawingToImageBuffer(bool value)
    202 {
    203     m_drawingToImageBuffer = value;
    204 }
    205 
    206 bool PlatformContextSkia::isDrawingToImageBuffer() const
    207 {
    208     return m_drawingToImageBuffer;
    209 }
    210 #endif
    211 
    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)
    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 
    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 
    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 
    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 
    326 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 
    340 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 
    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 
    356 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 
    410 void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
    411 {
    412     SkRefCnt_SafeAssign(m_state->m_looper, dl);
    413 }
    414 
    415 void PlatformContextSkia::setMiterLimit(float ml)
    416 {
    417     m_state->m_miterLimit = ml;
    418 }
    419 
    420 void PlatformContextSkia::setAlpha(float alpha)
    421 {
    422     m_state->m_alpha = alpha;
    423 }
    424 
    425 void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
    426 {
    427     m_state->m_lineCap = lc;
    428 }
    429 
    430 void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
    431 {
    432     m_state->m_lineJoin = lj;
    433 }
    434 
    435 void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
    436 {
    437     m_state->m_xferMode = pdm;
    438 }
    439 
    440 void PlatformContextSkia::setFillColor(SkColor color)
    441 {
    442     m_state->m_fillColor = color;
    443     setFillShader(NULL);
    444 }
    445 
    446 SkDrawLooper* PlatformContextSkia::getDrawLooper() const
    447 {
    448     return m_state->m_looper;
    449 }
    450 
    451 WebCore::StrokeStyle PlatformContextSkia::getStrokeStyle() const
    452 {
    453     return m_state->m_strokeStyle;
    454 }
    455 
    456 void PlatformContextSkia::setStrokeStyle(WebCore::StrokeStyle strokeStyle)
    457 {
    458     m_state->m_strokeStyle = strokeStyle;
    459 }
    460 
    461 void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
    462 {
    463     m_state->m_strokeColor = strokeColor;
    464     setStrokeShader(NULL);
    465 }
    466 
    467 float PlatformContextSkia::getStrokeThickness() const
    468 {
    469     return m_state->m_strokeThickness;
    470 }
    471 
    472 void PlatformContextSkia::setStrokeThickness(float thickness)
    473 {
    474     m_state->m_strokeThickness = thickness;
    475 }
    476 
    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 
    486 int PlatformContextSkia::getTextDrawingMode() const
    487 {
    488     return m_state->m_textDrawingMode;
    489 }
    490 
    491 float PlatformContextSkia::getAlpha() const
    492 {
    493     return m_state->m_alpha;
    494 }
    495 
    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 
    504 void PlatformContextSkia::setUseAntialiasing(bool enable)
    505 {
    506     m_state->m_useAntialiasing = enable;
    507 }
    508 
    509 SkColor PlatformContextSkia::effectiveFillColor() const
    510 {
    511     return m_state->applyAlpha(m_state->m_fillColor);
    512 }
    513 
    514 SkColor PlatformContextSkia::effectiveStrokeColor() const
    515 {
    516     return m_state->applyAlpha(m_state->m_strokeColor);
    517 }
    518 
    519 void PlatformContextSkia::beginPath()
    520 {
    521     m_path.reset();
    522 }
    523 
    524 void PlatformContextSkia::addPath(const SkPath& path)
    525 {
    526     m_path.addPath(path, m_canvas->getTotalMatrix());
    527 }
    528 
    529 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 
    540 void PlatformContextSkia::setFillRule(SkPath::FillType fr)
    541 {
    542     m_path.setFillType(fr);
    543 }
    544 
    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 
    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 
    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::isPrinting()
    574 {
    575     return m_canvas->getTopPlatformDevice().IsVectorial();
    576 }
    577 
    578 #if OS(LINUX) || OS(WINDOWS)
    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 
    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