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 "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 #if ENABLE(SKIA_GPU)
     55 #include "GrContext.h"
     56 #include "SkGpuDevice.h"
     57 #include "SkGpuDeviceFactory.h"
     58 #endif
     59 
     60 #include <wtf/MathExtras.h>
     61 #include <wtf/OwnArrayPtr.h>
     62 #include <wtf/Vector.h>
     63 
     64 #if ENABLE(ACCELERATED_2D_CANVAS)
     65 #include "GLES2Canvas.h"
     66 #include "SharedGraphicsContext3D.h"
     67 #endif
     68 
     69 namespace WebCore {
     70 
     71 extern bool isPathSkiaSafe(const SkMatrix& transform, const SkPath& path);
     72 
     73 // State -----------------------------------------------------------------------
     74 
     75 // Encapsulates the additional painting state information we store for each
     76 // pushed graphics state.
     77 struct PlatformContextSkia::State {
     78     State();
     79     State(const State&);
     80     ~State();
     81 
     82     // Common shader state.
     83     float m_alpha;
     84     SkXfermode::Mode m_xferMode;
     85     bool m_useAntialiasing;
     86     SkDrawLooper* m_looper;
     87 
     88     // Fill.
     89     SkColor m_fillColor;
     90     SkShader* m_fillShader;
     91 
     92     // Stroke.
     93     StrokeStyle m_strokeStyle;
     94     SkColor m_strokeColor;
     95     SkShader* m_strokeShader;
     96     float m_strokeThickness;
     97     int m_dashRatio;  // Ratio of the length of a dash to its width.
     98     float m_miterLimit;
     99     SkPaint::Cap m_lineCap;
    100     SkPaint::Join m_lineJoin;
    101     SkDashPathEffect* m_dash;
    102 
    103     // Text. (See TextModeFill & friends in GraphicsContext.h.)
    104     TextDrawingModeFlags m_textDrawingMode;
    105 
    106     // Helper function for applying the state's alpha value to the given input
    107     // color to produce a new output color.
    108     SkColor applyAlpha(SkColor) const;
    109 
    110     // If non-empty, the current State is clipped to this image.
    111     SkBitmap m_imageBufferClip;
    112     // If m_imageBufferClip is non-empty, this is the region the image is clipped to.
    113     FloatRect m_clip;
    114 
    115     // This is a list of clipping paths which are currently active, in the
    116     // order in which they were pushed.
    117     WTF::Vector<SkPath> m_antiAliasClipPaths;
    118     InterpolationQuality m_interpolationQuality;
    119 
    120     // If we currently have a canvas (non-antialiased path) clip applied.
    121     bool m_canvasClipApplied;
    122 
    123     PlatformContextSkia::State cloneInheritedProperties();
    124 private:
    125     // Not supported.
    126     void operator=(const State&);
    127 };
    128 
    129 // Note: Keep theses default values in sync with GraphicsContextState.
    130 PlatformContextSkia::State::State()
    131     : m_alpha(1)
    132     , m_xferMode(SkXfermode::kSrcOver_Mode)
    133     , m_useAntialiasing(true)
    134     , m_looper(0)
    135     , m_fillColor(0xFF000000)
    136     , m_fillShader(0)
    137     , m_strokeStyle(SolidStroke)
    138     , m_strokeColor(Color::black)
    139     , m_strokeShader(0)
    140     , m_strokeThickness(0)
    141     , m_dashRatio(3)
    142     , m_miterLimit(4)
    143     , m_lineCap(SkPaint::kDefault_Cap)
    144     , m_lineJoin(SkPaint::kDefault_Join)
    145     , m_dash(0)
    146     , m_textDrawingMode(TextModeFill)
    147     , m_interpolationQuality(InterpolationHigh)
    148     , m_canvasClipApplied(false)
    149 {
    150 }
    151 
    152 PlatformContextSkia::State::State(const State& other)
    153     : m_alpha(other.m_alpha)
    154     , m_xferMode(other.m_xferMode)
    155     , m_useAntialiasing(other.m_useAntialiasing)
    156     , m_looper(other.m_looper)
    157     , m_fillColor(other.m_fillColor)
    158     , m_fillShader(other.m_fillShader)
    159     , m_strokeStyle(other.m_strokeStyle)
    160     , m_strokeColor(other.m_strokeColor)
    161     , m_strokeShader(other.m_strokeShader)
    162     , m_strokeThickness(other.m_strokeThickness)
    163     , m_dashRatio(other.m_dashRatio)
    164     , m_miterLimit(other.m_miterLimit)
    165     , m_lineCap(other.m_lineCap)
    166     , m_lineJoin(other.m_lineJoin)
    167     , m_dash(other.m_dash)
    168     , m_textDrawingMode(other.m_textDrawingMode)
    169     , m_imageBufferClip(other.m_imageBufferClip)
    170     , m_clip(other.m_clip)
    171     , m_antiAliasClipPaths(other.m_antiAliasClipPaths)
    172     , m_interpolationQuality(other.m_interpolationQuality)
    173     , m_canvasClipApplied(other.m_canvasClipApplied)
    174 {
    175     // Up the ref count of these. SkSafeRef does nothing if its argument is 0.
    176     SkSafeRef(m_looper);
    177     SkSafeRef(m_dash);
    178     SkSafeRef(m_fillShader);
    179     SkSafeRef(m_strokeShader);
    180 }
    181 
    182 PlatformContextSkia::State::~State()
    183 {
    184     SkSafeUnref(m_looper);
    185     SkSafeUnref(m_dash);
    186     SkSafeUnref(m_fillShader);
    187     SkSafeUnref(m_strokeShader);
    188 }
    189 
    190 // Returns a new State with all of this object's inherited properties copied.
    191 PlatformContextSkia::State PlatformContextSkia::State::cloneInheritedProperties()
    192 {
    193     PlatformContextSkia::State state(*this);
    194 
    195     // Everything is inherited except for the clip paths.
    196     state.m_antiAliasClipPaths.clear();
    197 
    198     return state;
    199 }
    200 
    201 SkColor PlatformContextSkia::State::applyAlpha(SkColor c) const
    202 {
    203     int s = roundf(m_alpha * 256);
    204     if (s >= 256)
    205         return c;
    206     if (s < 0)
    207         return 0;
    208 
    209     int a = SkAlphaMul(SkColorGetA(c), s);
    210     return (c & 0x00FFFFFF) | (a << 24);
    211 }
    212 
    213 // PlatformContextSkia ---------------------------------------------------------
    214 
    215 // Danger: canvas can be NULL.
    216 PlatformContextSkia::PlatformContextSkia(SkCanvas* canvas)
    217     : m_canvas(canvas)
    218     , m_printing(false)
    219     , m_drawingToImageBuffer(false)
    220     , m_useGPU(false)
    221 #if ENABLE(ACCELERATED_2D_CANVAS)
    222     , m_gpuCanvas(0)
    223 #endif
    224     , m_backingStoreState(None)
    225 {
    226     m_stateStack.append(State());
    227     m_state = &m_stateStack.last();
    228 }
    229 
    230 PlatformContextSkia::~PlatformContextSkia()
    231 {
    232 #if ENABLE(ACCELERATED_2D_CANVAS)
    233     if (m_gpuCanvas) {
    234 #if ENABLE(SKIA_GPU)
    235         // make sure everything related to this platform context has been flushed
    236         if (!m_useGPU) {
    237             SharedGraphicsContext3D* context = m_gpuCanvas->context();
    238             context->makeContextCurrent();
    239             context->grContext()->flush(0);
    240         }
    241 #endif
    242         m_gpuCanvas->drawingBuffer()->setWillPublishCallback(0);
    243     }
    244 #endif
    245 }
    246 
    247 void PlatformContextSkia::setCanvas(SkCanvas* canvas)
    248 {
    249     m_canvas = canvas;
    250 }
    251 
    252 void PlatformContextSkia::setDrawingToImageBuffer(bool value)
    253 {
    254     m_drawingToImageBuffer = value;
    255 }
    256 
    257 bool PlatformContextSkia::isDrawingToImageBuffer() const
    258 {
    259     return m_drawingToImageBuffer;
    260 }
    261 
    262 void PlatformContextSkia::save()
    263 {
    264     ASSERT(!hasImageResamplingHint());
    265 
    266     m_stateStack.append(m_state->cloneInheritedProperties());
    267     m_state = &m_stateStack.last();
    268 
    269     // The clip image only needs to be applied once. Reset the image so that we
    270     // don't attempt to clip multiple times.
    271     m_state->m_imageBufferClip.reset();
    272 
    273     // Save our native canvas.
    274     canvas()->save();
    275 }
    276 
    277 void PlatformContextSkia::beginLayerClippedToImage(const FloatRect& rect,
    278                                                    const ImageBuffer* imageBuffer)
    279 {
    280     // Skia doesn't support clipping to an image, so we create a layer. The next
    281     // time restore is invoked the layer and |imageBuffer| are combined to
    282     // create the resulting image.
    283     m_state->m_clip = rect;
    284     SkRect bounds = { SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()),
    285                       SkFloatToScalar(rect.maxX()), SkFloatToScalar(rect.maxY()) };
    286 
    287     canvas()->clipRect(bounds);
    288     canvas()->saveLayerAlpha(&bounds, 255,
    289                              static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag));
    290     // Copy off the image as |imageBuffer| may be deleted before restore is invoked.
    291     const SkBitmap* bitmap = imageBuffer->context()->platformContext()->bitmap();
    292     if (!bitmap->pixelRef()) {
    293         // The bitmap owns it's pixels. This happens when we've allocated the
    294         // pixels in some way and assigned them directly to the bitmap (as
    295         // happens when we allocate a DIB). In this case the assignment operator
    296         // does not copy the pixels, rather the copied bitmap ends up
    297         // referencing the same pixels. As the pixels may not live as long as we
    298         // need it to, we copy the image.
    299         bitmap->copyTo(&m_state->m_imageBufferClip, SkBitmap::kARGB_8888_Config);
    300     } else {
    301         // If there is a pixel ref, we can safely use the assignment operator.
    302         m_state->m_imageBufferClip = *bitmap;
    303     }
    304 }
    305 
    306 void PlatformContextSkia::clipPathAntiAliased(const SkPath& clipPath)
    307 {
    308     // If we are currently tracking any anti-alias clip paths, then we already
    309     // have a layer in place and don't need to add another.
    310     bool haveLayerOutstanding = m_state->m_antiAliasClipPaths.size();
    311 
    312     // See comments in applyAntiAliasedClipPaths about how this works.
    313     m_state->m_antiAliasClipPaths.append(clipPath);
    314 
    315     if (!haveLayerOutstanding) {
    316         SkRect bounds = clipPath.getBounds();
    317         canvas()->saveLayerAlpha(&bounds, 255, static_cast<SkCanvas::SaveFlags>(SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kFullColorLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag));
    318         // Guards state modification during clipped operations.
    319         // The state is popped in applyAntiAliasedClipPaths().
    320         canvas()->save();
    321     }
    322 }
    323 
    324 void PlatformContextSkia::restore()
    325 {
    326     if (!m_state->m_imageBufferClip.empty()) {
    327         applyClipFromImage(m_state->m_clip, m_state->m_imageBufferClip);
    328         canvas()->restore();
    329     }
    330 
    331     if (!m_state->m_antiAliasClipPaths.isEmpty())
    332         applyAntiAliasedClipPaths(m_state->m_antiAliasClipPaths);
    333 
    334     m_stateStack.removeLast();
    335     m_state = &m_stateStack.last();
    336 
    337     // Restore our native canvas.
    338     canvas()->restore();
    339 }
    340 
    341 void PlatformContextSkia::drawRect(SkRect rect)
    342 {
    343     SkPaint paint;
    344     int fillcolorNotTransparent = m_state->m_fillColor & 0xFF000000;
    345     if (fillcolorNotTransparent) {
    346         setupPaintForFilling(&paint);
    347         canvas()->drawRect(rect, paint);
    348     }
    349 
    350     if (m_state->m_strokeStyle != NoStroke
    351         && (m_state->m_strokeColor & 0xFF000000)) {
    352         // We do a fill of four rects to simulate the stroke of a border.
    353         SkColor oldFillColor = m_state->m_fillColor;
    354 
    355         // setFillColor() will set the shader to NULL, so save a ref to it now.
    356         SkShader* oldFillShader = m_state->m_fillShader;
    357         SkSafeRef(oldFillShader);
    358         setFillColor(m_state->m_strokeColor);
    359         paint.reset();
    360         setupPaintForFilling(&paint);
    361         SkRect topBorder = { rect.fLeft, rect.fTop, rect.fRight, rect.fTop + 1 };
    362         canvas()->drawRect(topBorder, paint);
    363         SkRect bottomBorder = { rect.fLeft, rect.fBottom - 1, rect.fRight, rect.fBottom };
    364         canvas()->drawRect(bottomBorder, paint);
    365         SkRect leftBorder = { rect.fLeft, rect.fTop + 1, rect.fLeft + 1, rect.fBottom - 1 };
    366         canvas()->drawRect(leftBorder, paint);
    367         SkRect rightBorder = { rect.fRight - 1, rect.fTop + 1, rect.fRight, rect.fBottom - 1 };
    368         canvas()->drawRect(rightBorder, paint);
    369         setFillColor(oldFillColor);
    370         setFillShader(oldFillShader);
    371         SkSafeUnref(oldFillShader);
    372     }
    373 }
    374 
    375 void PlatformContextSkia::setupPaintCommon(SkPaint* paint) const
    376 {
    377 #if defined(SK_DEBUG)
    378     {
    379         SkPaint defaultPaint;
    380         SkASSERT(*paint == defaultPaint);
    381     }
    382 #endif
    383 
    384     paint->setAntiAlias(m_state->m_useAntialiasing);
    385     paint->setXfermodeMode(m_state->m_xferMode);
    386     paint->setLooper(m_state->m_looper);
    387 }
    388 
    389 void PlatformContextSkia::setupPaintForFilling(SkPaint* paint) const
    390 {
    391     setupPaintCommon(paint);
    392     paint->setColor(m_state->applyAlpha(m_state->m_fillColor));
    393     paint->setShader(m_state->m_fillShader);
    394 }
    395 
    396 float PlatformContextSkia::setupPaintForStroking(SkPaint* paint, SkRect* rect, int length) const
    397 {
    398     setupPaintCommon(paint);
    399     float width = m_state->m_strokeThickness;
    400 
    401     paint->setColor(m_state->applyAlpha(m_state->m_strokeColor));
    402     paint->setShader(m_state->m_strokeShader);
    403     paint->setStyle(SkPaint::kStroke_Style);
    404     paint->setStrokeWidth(SkFloatToScalar(width));
    405     paint->setStrokeCap(m_state->m_lineCap);
    406     paint->setStrokeJoin(m_state->m_lineJoin);
    407     paint->setStrokeMiter(SkFloatToScalar(m_state->m_miterLimit));
    408 
    409     if (m_state->m_dash)
    410         paint->setPathEffect(m_state->m_dash);
    411     else {
    412         switch (m_state->m_strokeStyle) {
    413         case NoStroke:
    414         case SolidStroke:
    415             break;
    416         case DashedStroke:
    417             width = m_state->m_dashRatio * width;
    418             // Fall through.
    419         case DottedStroke:
    420             // Truncate the width, since we don't want fuzzy dots or dashes.
    421             int dashLength = static_cast<int>(width);
    422             // Subtract off the endcaps, since they're rendered separately.
    423             int distance = length - 2 * static_cast<int>(m_state->m_strokeThickness);
    424             int phase = 1;
    425             if (dashLength > 1) {
    426                 // Determine how many dashes or dots we should have.
    427                 int numDashes = distance / dashLength;
    428                 int remainder = distance % dashLength;
    429                 // Adjust the phase to center the dashes within the line.
    430                 if (numDashes % 2 == 0) {
    431                     // Even:  shift right half a dash, minus half the remainder
    432                     phase = (dashLength - remainder) / 2;
    433                 } else {
    434                     // Odd:  shift right a full dash, minus half the remainder
    435                     phase = dashLength - remainder / 2;
    436                 }
    437             }
    438             SkScalar dashLengthSk = SkIntToScalar(dashLength);
    439             SkScalar intervals[2] = { dashLengthSk, dashLengthSk };
    440             paint->setPathEffect(new SkDashPathEffect(intervals, 2, SkIntToScalar(phase)))->unref();
    441         }
    442     }
    443 
    444     return width;
    445 }
    446 
    447 void PlatformContextSkia::setDrawLooper(SkDrawLooper* dl)
    448 {
    449     SkRefCnt_SafeAssign(m_state->m_looper, dl);
    450 }
    451 
    452 void PlatformContextSkia::setMiterLimit(float ml)
    453 {
    454     m_state->m_miterLimit = ml;
    455 }
    456 
    457 void PlatformContextSkia::setAlpha(float alpha)
    458 {
    459     m_state->m_alpha = alpha;
    460 }
    461 
    462 void PlatformContextSkia::setLineCap(SkPaint::Cap lc)
    463 {
    464     m_state->m_lineCap = lc;
    465 }
    466 
    467 void PlatformContextSkia::setLineJoin(SkPaint::Join lj)
    468 {
    469     m_state->m_lineJoin = lj;
    470 }
    471 
    472 void PlatformContextSkia::setXfermodeMode(SkXfermode::Mode pdm)
    473 {
    474     m_state->m_xferMode = pdm;
    475 }
    476 
    477 void PlatformContextSkia::setFillColor(SkColor color)
    478 {
    479     m_state->m_fillColor = color;
    480     setFillShader(0);
    481 }
    482 
    483 SkDrawLooper* PlatformContextSkia::getDrawLooper() const
    484 {
    485     return m_state->m_looper;
    486 }
    487 
    488 StrokeStyle PlatformContextSkia::getStrokeStyle() const
    489 {
    490     return m_state->m_strokeStyle;
    491 }
    492 
    493 void PlatformContextSkia::setStrokeStyle(StrokeStyle strokeStyle)
    494 {
    495     m_state->m_strokeStyle = strokeStyle;
    496 }
    497 
    498 void PlatformContextSkia::setStrokeColor(SkColor strokeColor)
    499 {
    500     m_state->m_strokeColor = strokeColor;
    501     setStrokeShader(0);
    502 }
    503 
    504 float PlatformContextSkia::getStrokeThickness() const
    505 {
    506     return m_state->m_strokeThickness;
    507 }
    508 
    509 void PlatformContextSkia::setStrokeThickness(float thickness)
    510 {
    511     m_state->m_strokeThickness = thickness;
    512 }
    513 
    514 void PlatformContextSkia::setStrokeShader(SkShader* strokeShader)
    515 {
    516     if (strokeShader)
    517         m_state->m_strokeColor = Color::black;
    518 
    519     if (strokeShader != m_state->m_strokeShader) {
    520         SkSafeUnref(m_state->m_strokeShader);
    521         m_state->m_strokeShader = strokeShader;
    522         SkSafeRef(m_state->m_strokeShader);
    523     }
    524 }
    525 
    526 TextDrawingModeFlags PlatformContextSkia::getTextDrawingMode() const
    527 {
    528     return m_state->m_textDrawingMode;
    529 }
    530 
    531 float PlatformContextSkia::getAlpha() const
    532 {
    533     return m_state->m_alpha;
    534 }
    535 
    536 int PlatformContextSkia::getNormalizedAlpha() const
    537 {
    538     int alpha = roundf(m_state->m_alpha * 256);
    539     if (alpha > 255)
    540         alpha = 255;
    541     else if (alpha < 0)
    542         alpha = 0;
    543     return alpha;
    544 }
    545 
    546 void PlatformContextSkia::setTextDrawingMode(TextDrawingModeFlags mode)
    547 {
    548     // TextModeClip is never used, so we assert that it isn't set:
    549     // https://bugs.webkit.org/show_bug.cgi?id=21898
    550     ASSERT(!(mode & TextModeClip));
    551     m_state->m_textDrawingMode = mode;
    552 }
    553 
    554 void PlatformContextSkia::setUseAntialiasing(bool enable)
    555 {
    556     m_state->m_useAntialiasing = enable;
    557 }
    558 
    559 SkColor PlatformContextSkia::effectiveFillColor() const
    560 {
    561     return m_state->applyAlpha(m_state->m_fillColor);
    562 }
    563 
    564 SkColor PlatformContextSkia::effectiveStrokeColor() const
    565 {
    566     return m_state->applyAlpha(m_state->m_strokeColor);
    567 }
    568 
    569 void PlatformContextSkia::canvasClipPath(const SkPath& path)
    570 {
    571     m_state->m_canvasClipApplied = true;
    572     m_canvas->clipPath(path);
    573 }
    574 
    575 void PlatformContextSkia::setFillShader(SkShader* fillShader)
    576 {
    577     if (fillShader)
    578         m_state->m_fillColor = Color::black;
    579 
    580     if (fillShader != m_state->m_fillShader) {
    581         SkSafeUnref(m_state->m_fillShader);
    582         m_state->m_fillShader = fillShader;
    583         SkSafeRef(m_state->m_fillShader);
    584     }
    585 }
    586 
    587 InterpolationQuality PlatformContextSkia::interpolationQuality() const
    588 {
    589     return m_state->m_interpolationQuality;
    590 }
    591 
    592 void PlatformContextSkia::setInterpolationQuality(InterpolationQuality interpolationQuality)
    593 {
    594     m_state->m_interpolationQuality = interpolationQuality;
    595 }
    596 
    597 void PlatformContextSkia::setDashPathEffect(SkDashPathEffect* dash)
    598 {
    599     if (dash != m_state->m_dash) {
    600         SkSafeUnref(m_state->m_dash);
    601         m_state->m_dash = dash;
    602     }
    603 }
    604 
    605 void PlatformContextSkia::paintSkPaint(const SkRect& rect,
    606                                        const SkPaint& paint)
    607 {
    608     m_canvas->drawRect(rect, paint);
    609 }
    610 
    611 const SkBitmap* PlatformContextSkia::bitmap() const
    612 {
    613     return &m_canvas->getDevice()->accessBitmap(false);
    614 }
    615 
    616 bool PlatformContextSkia::isNativeFontRenderingAllowed()
    617 {
    618 #if ENABLE(SKIA_GPU)
    619     return false;
    620 #else
    621     return skia::SupportsPlatformPaint(m_canvas);
    622 #endif
    623 }
    624 
    625 void PlatformContextSkia::getImageResamplingHint(IntSize* srcSize, FloatSize* dstSize) const
    626 {
    627     *srcSize = m_imageResamplingHintSrcSize;
    628     *dstSize = m_imageResamplingHintDstSize;
    629 }
    630 
    631 void PlatformContextSkia::setImageResamplingHint(const IntSize& srcSize, const FloatSize& dstSize)
    632 {
    633     m_imageResamplingHintSrcSize = srcSize;
    634     m_imageResamplingHintDstSize = dstSize;
    635 }
    636 
    637 void PlatformContextSkia::clearImageResamplingHint()
    638 {
    639     m_imageResamplingHintSrcSize = IntSize();
    640     m_imageResamplingHintDstSize = FloatSize();
    641 }
    642 
    643 bool PlatformContextSkia::hasImageResamplingHint() const
    644 {
    645     return !m_imageResamplingHintSrcSize.isEmpty() && !m_imageResamplingHintDstSize.isEmpty();
    646 }
    647 
    648 void PlatformContextSkia::applyClipFromImage(const FloatRect& rect, const SkBitmap& imageBuffer)
    649 {
    650     // NOTE: this assumes the image mask contains opaque black for the portions that are to be shown, as such we
    651     // only look at the alpha when compositing. I'm not 100% sure this is what WebKit expects for image clipping.
    652     SkPaint paint;
    653     paint.setXfermodeMode(SkXfermode::kDstIn_Mode);
    654     m_canvas->drawBitmap(imageBuffer, SkFloatToScalar(rect.x()), SkFloatToScalar(rect.y()), &paint);
    655 }
    656 
    657 void PlatformContextSkia::applyAntiAliasedClipPaths(WTF::Vector<SkPath>& paths)
    658 {
    659     // Anti-aliased clipping:
    660     //
    661     // Skia's clipping is 1-bit only. Consider what would happen if it were 8-bit:
    662     // We have a square canvas, filled with white and we declare a circular
    663     // clipping path. Then we fill twice with a black rectangle. The fractional
    664     // pixels would first get the correct color (white * alpha + black * (1 -
    665     // alpha)), but the second fill would apply the alpha to the already
    666     // modified color and the result would be too dark.
    667     //
    668     // This, anti-aliased clipping needs to be performed after the drawing has
    669     // been done. In order to do this, we create a new layer of the canvas in
    670     // clipPathAntiAliased and store the clipping path. All drawing is done to
    671     // the layer's bitmap while it's in effect. When WebKit calls restore() to
    672     // undo the clipping, this function is called.
    673     //
    674     // Here, we walk the list of clipping paths backwards and, for each, we
    675     // clear outside of the clipping path. We only need a single extra layer
    676     // for any number of clipping paths.
    677     //
    678     // When we call restore on the SkCanvas, the layer's bitmap is composed
    679     // into the layer below and we end up with correct, anti-aliased clipping.
    680 
    681     m_canvas->restore();
    682 
    683     SkPaint paint;
    684     paint.setXfermodeMode(SkXfermode::kClear_Mode);
    685     paint.setAntiAlias(true);
    686     paint.setStyle(SkPaint::kFill_Style);
    687 
    688     for (size_t i = paths.size() - 1; i < paths.size(); --i) {
    689         paths[i].toggleInverseFillType();
    690         m_canvas->drawPath(paths[i], paint);
    691     }
    692 
    693     m_canvas->restore();
    694 }
    695 
    696 bool PlatformContextSkia::canAccelerate() const
    697 {
    698     return !m_state->m_fillShader; // Can't accelerate with a fill gradient or pattern.
    699 }
    700 
    701 bool PlatformContextSkia::canvasClipApplied() const
    702 {
    703     return m_state->m_canvasClipApplied;
    704 }
    705 
    706 class WillPublishCallbackImpl : public DrawingBuffer::WillPublishCallback {
    707 public:
    708     static PassOwnPtr<WillPublishCallback> create(PlatformContextSkia* pcs)
    709     {
    710         return adoptPtr(new WillPublishCallbackImpl(pcs));
    711     }
    712 
    713     virtual void willPublish()
    714     {
    715         m_pcs->prepareForHardwareDraw();
    716     }
    717 
    718 private:
    719     explicit WillPublishCallbackImpl(PlatformContextSkia* pcs)
    720         : m_pcs(pcs)
    721     {
    722     }
    723 
    724     PlatformContextSkia* m_pcs;
    725 };
    726 
    727 void PlatformContextSkia::setSharedGraphicsContext3D(SharedGraphicsContext3D* context, DrawingBuffer* drawingBuffer, const WebCore::IntSize& size)
    728 {
    729 #if ENABLE(ACCELERATED_2D_CANVAS)
    730     if (context && drawingBuffer) {
    731         m_useGPU = true;
    732         m_gpuCanvas = new GLES2Canvas(context, drawingBuffer, size);
    733         m_uploadTexture.clear();
    734         drawingBuffer->setWillPublishCallback(WillPublishCallbackImpl::create(this));
    735 
    736 #if ENABLE(SKIA_GPU)
    737         m_useGPU = false;
    738         context->makeContextCurrent();
    739         m_gpuCanvas->bindFramebuffer();
    740 
    741         GrContext* gr = context->grContext();
    742         gr->resetContext();
    743         drawingBuffer->setGrContext(gr);
    744 
    745         GrPlatformSurfaceDesc drawBufDesc;
    746         drawingBuffer->getGrPlatformSurfaceDesc(&drawBufDesc);
    747         GrTexture* drawBufTex = static_cast<GrTexture*>(gr->createPlatformSurface(drawBufDesc));
    748         SkDeviceFactory* factory = new SkGpuDeviceFactory(gr, drawBufTex);
    749         drawBufTex->unref();
    750 
    751         SkDevice* device = factory->newDevice(m_canvas, SkBitmap::kARGB_8888_Config, drawingBuffer->size().width(), drawingBuffer->size().height(), false, false);
    752         m_canvas->setDevice(device)->unref();
    753         m_canvas->setDeviceFactory(factory);
    754 #endif
    755     } else {
    756         syncSoftwareCanvas();
    757         m_uploadTexture.clear();
    758         m_gpuCanvas.clear();
    759         m_useGPU = false;
    760     }
    761 #endif
    762 }
    763 
    764 void PlatformContextSkia::prepareForSoftwareDraw() const
    765 {
    766     if (!m_useGPU) {
    767 #if ENABLE(SKIA_GPU)
    768         if (m_gpuCanvas)
    769             m_gpuCanvas->context()->makeContextCurrent();
    770 #endif
    771         return;
    772     }
    773 
    774     if (m_backingStoreState == Hardware) {
    775         // Depending on the blend mode we need to do one of a few things:
    776 
    777         // * For associative blend modes, we can draw into an initially empty
    778         // canvas and then composite the results on top of the hardware drawn
    779         // results before the next hardware draw or swapBuffers().
    780 
    781         // * For non-associative blend modes we have to do a readback and then
    782         // software draw.  When we re-upload in this mode we have to blow
    783         // away whatever is in the hardware backing store (do a copy instead
    784         // of a compositing operation).
    785 
    786         if (m_state->m_xferMode == SkXfermode::kSrcOver_Mode) {
    787             // Note that we have rendering results in both the hardware and software backing stores.
    788             m_backingStoreState = Mixed;
    789         } else {
    790             readbackHardwareToSoftware();
    791             // When we switch back to hardware copy the results, don't composite.
    792             m_backingStoreState = Software;
    793         }
    794     } else if (m_backingStoreState == Mixed) {
    795         if (m_state->m_xferMode != SkXfermode::kSrcOver_Mode) {
    796             // Have to composite our currently software drawn data...
    797             uploadSoftwareToHardware(CompositeSourceOver);
    798             // then do a readback so we can hardware draw stuff.
    799             readbackHardwareToSoftware();
    800             m_backingStoreState = Software;
    801         }
    802     } else if (m_backingStoreState == None) {
    803         m_backingStoreState = Software;
    804     }
    805 }
    806 
    807 void PlatformContextSkia::prepareForHardwareDraw() const
    808 {
    809     if (!m_useGPU)
    810         return;
    811 
    812     if (m_backingStoreState == Software) {
    813         // Last drawn in software; upload everything we've drawn.
    814         uploadSoftwareToHardware(CompositeCopy);
    815     } else if (m_backingStoreState == Mixed) {
    816         // Stuff in software/hardware, composite the software stuff on top of
    817         // the hardware stuff.
    818         uploadSoftwareToHardware(CompositeSourceOver);
    819     }
    820     m_backingStoreState = Hardware;
    821 }
    822 
    823 void PlatformContextSkia::syncSoftwareCanvas() const
    824 {
    825     if (!m_useGPU) {
    826 #if ENABLE(SKIA_GPU)
    827         if (m_gpuCanvas)
    828             m_gpuCanvas->context()->makeContextCurrent();
    829 #endif
    830         return;
    831     }
    832 
    833     if (m_backingStoreState == Hardware)
    834         readbackHardwareToSoftware();
    835     else if (m_backingStoreState == Mixed) {
    836         // Have to composite our currently software drawn data..
    837         uploadSoftwareToHardware(CompositeSourceOver);
    838         // then do a readback.
    839         readbackHardwareToSoftware();
    840         m_backingStoreState = Software;
    841     }
    842     m_backingStoreState = Software;
    843 }
    844 
    845 void PlatformContextSkia::markDirtyRect(const IntRect& rect)
    846 {
    847     if (!m_useGPU)
    848         return;
    849 
    850     switch (m_backingStoreState) {
    851     case Software:
    852     case Mixed:
    853         m_softwareDirtyRect.unite(rect);
    854         return;
    855     case Hardware:
    856         return;
    857     default:
    858         ASSERT_NOT_REACHED();
    859     }
    860 }
    861 
    862 void PlatformContextSkia::uploadSoftwareToHardware(CompositeOperator op) const
    863 {
    864 #if ENABLE(ACCELERATED_2D_CANVAS)
    865     const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(false);
    866     SkAutoLockPixels lock(bitmap);
    867     SharedGraphicsContext3D* context = m_gpuCanvas->context();
    868     if (!m_uploadTexture || m_uploadTexture->tiles().totalSizeX() < bitmap.width() || m_uploadTexture->tiles().totalSizeY() < bitmap.height())
    869         m_uploadTexture = context->createTexture(Texture::BGRA8, bitmap.width(), bitmap.height());
    870 
    871     m_uploadTexture->updateSubRect(bitmap.getPixels(), m_softwareDirtyRect);
    872     AffineTransform identity;
    873     gpuCanvas()->drawTexturedRect(m_uploadTexture.get(), m_softwareDirtyRect, m_softwareDirtyRect, identity, 1.0, ColorSpaceDeviceRGB, op, false);
    874     // Clear out the region of the software canvas we just uploaded.
    875     m_canvas->save();
    876     m_canvas->resetMatrix();
    877     SkRect bounds = m_softwareDirtyRect;
    878     m_canvas->clipRect(bounds, SkRegion::kReplace_Op);
    879     m_canvas->drawARGB(0, 0, 0, 0, SkXfermode::kClear_Mode);
    880     m_canvas->restore();
    881     m_softwareDirtyRect.setWidth(0); // Clear dirty rect.
    882 #endif
    883 }
    884 
    885 void PlatformContextSkia::readbackHardwareToSoftware() const
    886 {
    887 #if ENABLE(ACCELERATED_2D_CANVAS)
    888     const SkBitmap& bitmap = m_canvas->getDevice()->accessBitmap(true);
    889     SkAutoLockPixels lock(bitmap);
    890     int width = bitmap.width(), height = bitmap.height();
    891     OwnArrayPtr<uint32_t> buf = adoptArrayPtr(new uint32_t[width]);
    892     SharedGraphicsContext3D* context = m_gpuCanvas->context();
    893     m_gpuCanvas->bindFramebuffer();
    894     // Flips the image vertically.
    895     for (int y = 0; y < height; ++y) {
    896         uint32_t* pixels = bitmap.getAddr32(0, y);
    897         if (context->supportsBGRA())
    898             context->readPixels(0, height - 1 - y, width, 1, Extensions3D::BGRA_EXT, GraphicsContext3D::UNSIGNED_BYTE, pixels);
    899         else {
    900             context->readPixels(0, height - 1 - y, width, 1, GraphicsContext3D::RGBA, GraphicsContext3D::UNSIGNED_BYTE, pixels);
    901             for (int i = 0; i < width; ++i) {
    902                 uint32_t pixel = pixels[i];
    903                 // Swizzles from RGBA -> BGRA.
    904                 pixels[i] = (pixel & 0xFF00FF00) | ((pixel & 0x00FF0000) >> 16) | ((pixel & 0x000000FF) << 16);
    905             }
    906         }
    907     }
    908     m_softwareDirtyRect.unite(IntRect(0, 0, width, height)); // Mark everything as dirty.
    909 #endif
    910 }
    911 
    912 } // namespace WebCore
    913