Home | History | Annotate | Download | only in graphics
      1 /*
      2  * Copyright (C) 2013 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 #include "platform/graphics/GraphicsContextRecorder.h"
     33 
     34 #include "platform/graphics/ImageBuffer.h"
     35 #include "platform/graphics/ImageSource.h"
     36 #include "platform/image-decoders/ImageDecoder.h"
     37 #include "platform/image-decoders/ImageFrame.h"
     38 #include "platform/image-encoders/skia/PNGImageEncoder.h"
     39 #include "third_party/skia/include/core/SkBitmapDevice.h"
     40 #include "third_party/skia/include/core/SkPictureRecorder.h"
     41 #include "third_party/skia/include/core/SkStream.h"
     42 #include "wtf/HexNumber.h"
     43 #include "wtf/text/Base64.h"
     44 #include "wtf/text/TextEncoding.h"
     45 
     46 namespace WebCore {
     47 
     48 GraphicsContext* GraphicsContextRecorder::record(const IntSize& size, bool isCertainlyOpaque)
     49 {
     50     ASSERT(!m_picture);
     51     ASSERT(!m_recorder);
     52     ASSERT(!m_context);
     53     m_isCertainlyOpaque = isCertainlyOpaque;
     54     m_recorder = adoptPtr(new SkPictureRecorder);
     55     SkCanvas* canvas = m_recorder->beginRecording(size.width(), size.height(), 0, 0);
     56     m_context = adoptPtr(new GraphicsContext(canvas));
     57     m_context->setTrackOpaqueRegion(isCertainlyOpaque);
     58     m_context->setCertainlyOpaque(isCertainlyOpaque);
     59     return m_context.get();
     60 }
     61 
     62 PassRefPtr<GraphicsContextSnapshot> GraphicsContextRecorder::stop()
     63 {
     64     m_context.clear();
     65     m_picture = adoptRef(m_recorder->endRecording());
     66     m_recorder.clear();
     67     return adoptRef(new GraphicsContextSnapshot(m_picture.release(), m_isCertainlyOpaque));
     68 }
     69 
     70 GraphicsContextSnapshot::GraphicsContextSnapshot(PassRefPtr<SkPicture> picture, bool isCertainlyOpaque)
     71     : m_picture(picture)
     72     , m_isCertainlyOpaque(isCertainlyOpaque)
     73 {
     74 }
     75 
     76 
     77 class SnapshotPlayer : public SkDrawPictureCallback {
     78     WTF_MAKE_NONCOPYABLE(SnapshotPlayer);
     79 public:
     80     explicit SnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
     81         : m_picture(picture)
     82         , m_canvas(canvas)
     83     {
     84     }
     85 
     86     SkCanvas* canvas() { return m_canvas; }
     87 
     88     void play()
     89     {
     90         m_picture->draw(m_canvas, this);
     91     }
     92 
     93 private:
     94     RefPtr<SkPicture> m_picture;
     95     SkCanvas* m_canvas;
     96 };
     97 
     98 class FragmentSnapshotPlayer : public SnapshotPlayer {
     99 public:
    100     FragmentSnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
    101         : SnapshotPlayer(picture, canvas)
    102     {
    103     }
    104 
    105     void play(unsigned fromStep, unsigned toStep)
    106     {
    107         m_fromStep = fromStep;
    108         m_toStep = toStep;
    109         m_stepCount = 0;
    110         SnapshotPlayer::play();
    111     }
    112 
    113     virtual bool abortDrawing() OVERRIDE
    114     {
    115         ++m_stepCount;
    116         if (m_stepCount == m_fromStep) {
    117             const SkBitmap& bitmap = canvas()->getDevice()->accessBitmap(true);
    118             bitmap.eraseARGB(0, 0, 0, 0); // FIXME: get layers background color, it might make resulting image a bit more plausable.
    119         }
    120         return m_toStep && m_stepCount > m_toStep;
    121     }
    122 
    123 private:
    124     unsigned m_fromStep;
    125     unsigned m_toStep;
    126     unsigned m_stepCount;
    127 };
    128 
    129 class ProfilingSnapshotPlayer : public SnapshotPlayer {
    130 public:
    131     ProfilingSnapshotPlayer(PassRefPtr<SkPicture> picture, SkCanvas* canvas)
    132         : SnapshotPlayer(picture, canvas)
    133     {
    134     }
    135 
    136     void play(GraphicsContextSnapshot::Timings* timingsVector, unsigned minRepeatCount, double minDuration)
    137     {
    138         m_timingsVector = timingsVector;
    139         m_timingsVector->reserveCapacity(minRepeatCount);
    140 
    141         double now = WTF::monotonicallyIncreasingTime();
    142         double stopTime = now + minDuration;
    143         for (unsigned step = 0; step < minRepeatCount || now < stopTime; ++step) {
    144             m_timingsVector->append(Vector<double>());
    145             m_currentTimings = &m_timingsVector->last();
    146             if (m_timingsVector->size() > 1)
    147                 m_currentTimings->reserveCapacity(m_timingsVector->begin()->size());
    148             SnapshotPlayer::play();
    149             now = WTF::monotonicallyIncreasingTime();
    150             m_currentTimings->append(now);
    151         }
    152     }
    153 
    154     virtual bool abortDrawing() OVERRIDE
    155     {
    156         m_currentTimings->append(WTF::monotonicallyIncreasingTime());
    157         return false;
    158     }
    159 
    160     const GraphicsContextSnapshot::Timings& timingsVector() const { return *m_timingsVector; }
    161 
    162 private:
    163     GraphicsContextSnapshot::Timings* m_timingsVector;
    164     Vector<double>* m_currentTimings;
    165 };
    166 
    167 class LoggingCanvas : public SkCanvas {
    168 public:
    169     LoggingCanvas(int width, int height) : SkCanvas(width, height)
    170     {
    171         m_log = JSONArray::create();
    172     }
    173 
    174     void clear(SkColor color) OVERRIDE
    175     {
    176         addItemWithParams("clear")->setString("color", stringForSkColor(color));
    177     }
    178 
    179     void drawPaint(const SkPaint& paint) OVERRIDE
    180     {
    181         addItemWithParams("drawPaint")->setObject("paint", objectForSkPaint(paint));
    182     }
    183 
    184     void drawPoints(PointMode mode, size_t count, const SkPoint pts[], const SkPaint& paint) OVERRIDE
    185     {
    186         RefPtr<JSONObject> params = addItemWithParams("drawPoints");
    187         params->setString("pointMode", pointModeName(mode));
    188         params->setArray("points", arrayForSkPoints(count, pts));
    189         params->setObject("paint", objectForSkPaint(paint));
    190     }
    191 
    192     void drawRect(const SkRect& rect, const SkPaint& paint) OVERRIDE
    193     {
    194         RefPtr<JSONObject> params = addItemWithParams("drawRect");
    195         params->setObject("rect", objectForSkRect(rect));
    196         params->setObject("paint", objectForSkPaint(paint));
    197     }
    198 
    199     void drawOval(const SkRect& oval, const SkPaint& paint) OVERRIDE
    200     {
    201         RefPtr<JSONObject> params = addItemWithParams("drawOval");
    202         params->setObject("oval", objectForSkRect(oval));
    203         params->setObject("paint", objectForSkPaint(paint));
    204     }
    205 
    206     void drawRRect(const SkRRect& rrect, const SkPaint& paint) OVERRIDE
    207     {
    208         RefPtr<JSONObject> params = addItemWithParams("drawRRect");
    209         params->setObject("rrect", objectForSkRRect(rrect));
    210         params->setObject("paint", objectForSkPaint(paint));
    211     }
    212 
    213     void drawPath(const SkPath& path, const SkPaint& paint) OVERRIDE
    214     {
    215         RefPtr<JSONObject> params = addItemWithParams("drawPath");
    216         params->setObject("path", objectForSkPath(path));
    217         params->setObject("paint", objectForSkPaint(paint));
    218     }
    219 
    220     void drawBitmap(const SkBitmap& bitmap, SkScalar left, SkScalar top, const SkPaint* paint) OVERRIDE
    221     {
    222         RefPtr<JSONObject> params = addItemWithParams("drawBitmap");
    223         params->setNumber("left", left);
    224         params->setNumber("top", top);
    225         params->setObject("bitmap", objectForSkBitmap(bitmap));
    226         params->setObject("paint", objectForSkPaint(*paint));
    227     }
    228 
    229     void drawBitmapRectToRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst, const SkPaint* paint, DrawBitmapRectFlags flags) OVERRIDE
    230     {
    231         RefPtr<JSONObject> params = addItemWithParams("drawBitmapRectToRect");
    232         params->setObject("bitmap", objectForSkBitmap(bitmap));
    233         params->setObject("src", objectForSkRect(*src));
    234         params->setObject("dst", objectForSkRect(dst));
    235         params->setObject("paint", objectForSkPaint(*paint));
    236         params->setNumber("flags", flags);
    237     }
    238 
    239     void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m, const SkPaint* paint) OVERRIDE
    240     {
    241         RefPtr<JSONObject> params = addItemWithParams("drawBitmapMatrix");
    242         params->setObject("bitmap", objectForSkBitmap(bitmap));
    243         params->setArray("matrix", arrayForSkMatrix(m));
    244         params->setObject("paint", objectForSkPaint(*paint));
    245     }
    246 
    247     void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center, const SkRect& dst, const SkPaint* paint) OVERRIDE
    248     {
    249         RefPtr<JSONObject> params = addItemWithParams("drawBitmapNine");
    250         params->setObject("bitmap", objectForSkBitmap(bitmap));
    251         params->setObject("center", objectForSkIRect(center));
    252         params->setObject("dst", objectForSkRect(dst));
    253         params->setObject("paint", objectForSkPaint(*paint));
    254     }
    255 
    256     void drawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) OVERRIDE
    257     {
    258         RefPtr<JSONObject> params = addItemWithParams("drawSprite");
    259         params->setObject("bitmap", objectForSkBitmap(bitmap));
    260         params->setNumber("left", left);
    261         params->setNumber("top", top);
    262         params->setObject("paint", objectForSkPaint(*paint));
    263     }
    264 
    265     void drawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], SkXfermode* xmode,
    266         const uint16_t indices[], int indexCount, const SkPaint& paint) OVERRIDE
    267     {
    268         RefPtr<JSONObject> params = addItemWithParams("drawVertices");
    269         params->setObject("paint", objectForSkPaint(paint));
    270     }
    271 
    272     void drawData(const void* data, size_t length) OVERRIDE
    273     {
    274         RefPtr<JSONObject> params = addItemWithParams("drawData");
    275         params->setNumber("length", length);
    276     }
    277 
    278     void beginCommentGroup(const char* description) OVERRIDE
    279     {
    280         RefPtr<JSONObject> params = addItemWithParams("beginCommentGroup");
    281         params->setString("description", description);
    282     }
    283 
    284     void addComment(const char* keyword, const char* value) OVERRIDE
    285     {
    286         RefPtr<JSONObject> params = addItemWithParams("addComment");
    287         params->setString("key", keyword);
    288         params->setString("value", value);
    289     }
    290 
    291     void endCommentGroup() OVERRIDE
    292     {
    293         addItem("endCommentGroup");
    294     }
    295 
    296     void onDrawDRRect(const SkRRect& outer, const SkRRect& inner, const SkPaint& paint) OVERRIDE
    297     {
    298         RefPtr<JSONObject> params = addItemWithParams("drawDRRect");
    299         params->setObject("outer", objectForSkRRect(outer));
    300         params->setObject("inner", objectForSkRRect(inner));
    301         params->setObject("paint", objectForSkPaint(paint));
    302     }
    303 
    304     void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y, const SkPaint& paint) OVERRIDE
    305     {
    306         RefPtr<JSONObject> params = addItemWithParams("drawText");
    307         params->setString("text", stringForText(text, byteLength, paint));
    308         params->setNumber("x", x);
    309         params->setNumber("y", y);
    310         params->setObject("paint", objectForSkPaint(paint));
    311     }
    312 
    313     void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[], const SkPaint& paint) OVERRIDE
    314     {
    315         RefPtr<JSONObject> params = addItemWithParams("drawPosText");
    316         params->setString("text", stringForText(text, byteLength, paint));
    317         size_t pointsCount = paint.countText(text, byteLength);
    318         params->setArray("pos", arrayForSkPoints(pointsCount, pos));
    319         params->setObject("paint", objectForSkPaint(paint));
    320     }
    321 
    322     void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[], SkScalar constY, const SkPaint& paint) OVERRIDE
    323     {
    324         RefPtr<JSONObject> params = addItemWithParams("drawPosTextH");
    325         params->setString("text", stringForText(text, byteLength, paint));
    326         size_t pointsCount = paint.countText(text, byteLength);
    327         params->setArray("xpos", arrayForSkScalars(pointsCount, xpos));
    328         params->setNumber("constY", constY);
    329         params->setObject("paint", objectForSkPaint(paint));
    330     }
    331 
    332     void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) OVERRIDE
    333     {
    334         RefPtr<JSONObject> params = addItemWithParams("drawTextOnPath");
    335         params->setString("text", stringForText(text, byteLength, paint));
    336         params->setObject("path", objectForSkPath(path));
    337         params->setArray("matrix", arrayForSkMatrix(*matrix));
    338         params->setObject("paint", objectForSkPaint(paint));
    339     }
    340 
    341     void onPushCull(const SkRect& cullRect) OVERRIDE
    342     {
    343         RefPtr<JSONObject> params = addItemWithParams("pushCull");
    344         params->setObject("cullRect", objectForSkRect(cullRect));
    345     }
    346 
    347     void onPopCull() OVERRIDE
    348     {
    349         addItem("popCull");
    350     }
    351 
    352     void onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE
    353     {
    354         RefPtr<JSONObject> params = addItemWithParams("clipRect");
    355         params->setObject("rect", objectForSkRect(rect));
    356         params->setString("SkRegion::Op", regionOpName(op));
    357         params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
    358     }
    359 
    360     void onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE
    361     {
    362         RefPtr<JSONObject> params = addItemWithParams("clipRRect");
    363         params->setObject("rrect", objectForSkRRect(rrect));
    364         params->setString("SkRegion::Op", regionOpName(op));
    365         params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
    366     }
    367 
    368     void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle style) OVERRIDE
    369     {
    370         RefPtr<JSONObject> params = addItemWithParams("clipPath");
    371         params->setObject("path", objectForSkPath(path));
    372         params->setString("SkRegion::Op", regionOpName(op));
    373         params->setBoolean("softClipEdgeStyle", kSoft_ClipEdgeStyle == style);
    374     }
    375 
    376     void onClipRegion(const SkRegion& region, SkRegion::Op op) OVERRIDE
    377     {
    378         RefPtr<JSONObject> params = addItemWithParams("clipRegion");
    379         params->setString("op", regionOpName(op));
    380     }
    381 
    382     void onDrawPicture(const SkPicture* picture) OVERRIDE
    383     {
    384         addItemWithParams("drawPicture")->setObject("picture", objectForSkPicture(*picture));
    385     }
    386 
    387     void didSetMatrix(const SkMatrix& matrix) OVERRIDE
    388     {
    389         RefPtr<JSONObject> params = addItemWithParams("setMatrix");
    390         params->setArray("matrix", arrayForSkMatrix(matrix));
    391         this->SkCanvas::didSetMatrix(matrix);
    392     }
    393 
    394     void didConcat(const SkMatrix& matrix) OVERRIDE
    395     {
    396         switch (matrix.getType()) {
    397         case SkMatrix::kTranslate_Mask:
    398             translate(matrix.getTranslateX(), matrix.getTranslateY());
    399             break;
    400         case SkMatrix::kScale_Mask:
    401             scale(matrix.getScaleX(), matrix.getScaleY());
    402             break;
    403         default:
    404             concat(matrix);
    405         }
    406         this->SkCanvas::didConcat(matrix);
    407     }
    408 
    409     void willRestore() OVERRIDE
    410     {
    411         addItem("restore");
    412         this->SkCanvas::willRestore();
    413     }
    414 
    415     SaveLayerStrategy willSaveLayer(const SkRect* bounds, const SkPaint* paint, SaveFlags flags) OVERRIDE
    416     {
    417         RefPtr<JSONObject> params = addItemWithParams("saveLayer");
    418         if (bounds)
    419             params->setObject("bounds", objectForSkRect(*bounds));
    420         params->setObject("paint", objectForSkPaint(*paint));
    421         params->setString("saveFlags", saveFlagsToString(flags));
    422         this->SkCanvas::willSaveLayer(bounds, paint, flags);
    423         return kNoLayer_SaveLayerStrategy;
    424     }
    425 
    426     void willSave() OVERRIDE
    427     {
    428         RefPtr<JSONObject> params = addItemWithParams("save");
    429         this->SkCanvas::willSave();
    430     }
    431 
    432     bool isClipEmpty() const OVERRIDE
    433     {
    434         return false;
    435     }
    436 
    437     bool isClipRect() const OVERRIDE
    438     {
    439         return true;
    440     }
    441 
    442 #ifdef SK_SUPPORT_LEGACY_GETCLIPTYPE
    443     ClipType getClipType() const OVERRIDE
    444     {
    445         return kRect_ClipType;
    446     }
    447 #endif
    448 
    449     bool getClipBounds(SkRect* bounds) const OVERRIDE
    450     {
    451         if (bounds)
    452             bounds->setXYWH(0, 0, SkIntToScalar(this->imageInfo().fWidth), SkIntToScalar(this->imageInfo().fHeight));
    453         return true;
    454     }
    455 
    456     bool getClipDeviceBounds(SkIRect* bounds) const OVERRIDE
    457     {
    458         if (bounds)
    459             bounds->setLargest();
    460         return true;
    461     }
    462 
    463     PassRefPtr<JSONArray> log()
    464     {
    465         return m_log;
    466     }
    467 
    468 private:
    469     RefPtr<JSONArray> m_log;
    470 
    471     PassRefPtr<JSONObject> addItem(const String& name)
    472     {
    473         RefPtr<JSONObject> item = JSONObject::create();
    474         item->setString("method", name);
    475         m_log->pushObject(item);
    476         return item.release();
    477     }
    478 
    479     PassRefPtr<JSONObject> addItemWithParams(const String& name)
    480     {
    481         RefPtr<JSONObject> item = addItem(name);
    482         RefPtr<JSONObject> params = JSONObject::create();
    483         item->setObject("params", params);
    484         return params.release();
    485     }
    486 
    487     PassRefPtr<JSONObject> objectForSkRect(const SkRect& rect)
    488     {
    489         RefPtr<JSONObject> rectItem = JSONObject::create();
    490         rectItem->setNumber("left", rect.left());
    491         rectItem->setNumber("top", rect.top());
    492         rectItem->setNumber("right", rect.right());
    493         rectItem->setNumber("bottom", rect.bottom());
    494         return rectItem.release();
    495     }
    496 
    497     PassRefPtr<JSONObject> objectForSkIRect(const SkIRect& rect)
    498     {
    499         RefPtr<JSONObject> rectItem = JSONObject::create();
    500         rectItem->setNumber("left", rect.left());
    501         rectItem->setNumber("top", rect.top());
    502         rectItem->setNumber("right", rect.right());
    503         rectItem->setNumber("bottom", rect.bottom());
    504         return rectItem.release();
    505     }
    506 
    507     String pointModeName(PointMode mode)
    508     {
    509         switch (mode) {
    510         case SkCanvas::kPoints_PointMode: return "Points";
    511         case SkCanvas::kLines_PointMode: return "Lines";
    512         case SkCanvas::kPolygon_PointMode: return "Polygon";
    513         default:
    514             ASSERT_NOT_REACHED();
    515             return "?";
    516         };
    517     }
    518 
    519     PassRefPtr<JSONObject> objectForSkPoint(const SkPoint& point)
    520     {
    521         RefPtr<JSONObject> pointItem = JSONObject::create();
    522         pointItem->setNumber("x", point.x());
    523         pointItem->setNumber("y", point.y());
    524         return pointItem.release();
    525     }
    526 
    527     PassRefPtr<JSONArray> arrayForSkPoints(size_t count, const SkPoint points[])
    528     {
    529         RefPtr<JSONArray> pointsArrayItem = JSONArray::create();
    530         for (size_t i = 0; i < count; ++i)
    531             pointsArrayItem->pushObject(objectForSkPoint(points[i]));
    532         return pointsArrayItem.release();
    533     }
    534 
    535     PassRefPtr<JSONObject> objectForSkPicture(const SkPicture& picture)
    536     {
    537         RefPtr<JSONObject> pictureItem = JSONObject::create();
    538         pictureItem->setNumber("width", picture.width());
    539         pictureItem->setNumber("height", picture.height());
    540         return pictureItem.release();
    541     }
    542 
    543     PassRefPtr<JSONObject> objectForRadius(const SkRRect& rrect, SkRRect::Corner corner)
    544     {
    545         RefPtr<JSONObject> radiusItem = JSONObject::create();
    546         SkVector radius = rrect.radii(corner);
    547         radiusItem->setNumber("xRadius", radius.x());
    548         radiusItem->setNumber("yRadius", radius.y());
    549         return radiusItem.release();
    550     }
    551 
    552     String rrectTypeName(SkRRect::Type type)
    553     {
    554         switch (type) {
    555         case SkRRect::kEmpty_Type: return "Empty";
    556         case SkRRect::kRect_Type: return "Rect";
    557         case SkRRect::kOval_Type: return "Oval";
    558         case SkRRect::kSimple_Type: return "Simple";
    559         case SkRRect::kNinePatch_Type: return "Nine-patch";
    560         case SkRRect::kComplex_Type: return "Complex";
    561         default:
    562             ASSERT_NOT_REACHED();
    563             return "?";
    564         };
    565     }
    566 
    567     String radiusName(SkRRect::Corner corner)
    568     {
    569         switch (corner) {
    570         case SkRRect::kUpperLeft_Corner: return "upperLeftRadius";
    571         case SkRRect::kUpperRight_Corner: return "upperRightRadius";
    572         case SkRRect::kLowerRight_Corner: return "lowerRightRadius";
    573         case SkRRect::kLowerLeft_Corner: return "lowerLeftRadius";
    574         default:
    575             ASSERT_NOT_REACHED();
    576             return "?";
    577         }
    578     }
    579 
    580     PassRefPtr<JSONObject> objectForSkRRect(const SkRRect& rrect)
    581     {
    582         RefPtr<JSONObject> rrectItem = JSONObject::create();
    583         rrectItem->setString("type", rrectTypeName(rrect.type()));
    584         rrectItem->setNumber("left", rrect.rect().left());
    585         rrectItem->setNumber("top", rrect.rect().top());
    586         rrectItem->setNumber("right", rrect.rect().right());
    587         rrectItem->setNumber("bottom", rrect.rect().bottom());
    588         for (int i = 0; i < 4; ++i)
    589             rrectItem->setObject(radiusName((SkRRect::Corner) i), objectForRadius(rrect, (SkRRect::Corner) i));
    590         return rrectItem.release();
    591     }
    592 
    593     String fillTypeName(SkPath::FillType type)
    594     {
    595         switch (type) {
    596         case SkPath::kWinding_FillType: return "Winding";
    597         case SkPath::kEvenOdd_FillType: return "EvenOdd";
    598         case SkPath::kInverseWinding_FillType: return "InverseWinding";
    599         case SkPath::kInverseEvenOdd_FillType: return "InverseEvenOdd";
    600         default:
    601             ASSERT_NOT_REACHED();
    602             return "?";
    603         };
    604     }
    605 
    606     String convexityName(SkPath::Convexity convexity)
    607     {
    608         switch (convexity) {
    609         case SkPath::kUnknown_Convexity: return "Unknown";
    610         case SkPath::kConvex_Convexity: return "Convex";
    611         case SkPath::kConcave_Convexity: return "Concave";
    612         default:
    613             ASSERT_NOT_REACHED();
    614             return "?";
    615         };
    616     }
    617 
    618     String verbName(SkPath::Verb verb)
    619     {
    620         switch (verb) {
    621         case SkPath::kMove_Verb: return "Move";
    622         case SkPath::kLine_Verb: return "Line";
    623         case SkPath::kQuad_Verb: return "Quad";
    624         case SkPath::kConic_Verb: return "Conic";
    625         case SkPath::kCubic_Verb: return "Cubic";
    626         case SkPath::kClose_Verb: return "Close";
    627         case SkPath::kDone_Verb: return "Done";
    628         default:
    629             ASSERT_NOT_REACHED();
    630             return "?";
    631         };
    632     }
    633 
    634     struct VerbParams {
    635         String name;
    636         unsigned pointCount;
    637         unsigned pointOffset;
    638 
    639         VerbParams(const String& name, unsigned pointCount, unsigned pointOffset)
    640             : name(name)
    641             , pointCount(pointCount)
    642             , pointOffset(pointOffset) { }
    643     };
    644 
    645     VerbParams segmentParams(SkPath::Verb verb)
    646     {
    647         switch (verb) {
    648         case SkPath::kMove_Verb: return VerbParams("Move", 1, 0);
    649         case SkPath::kLine_Verb: return VerbParams("Line", 1, 1);
    650         case SkPath::kQuad_Verb: return VerbParams("Quad", 2, 1);
    651         case SkPath::kConic_Verb: return VerbParams("Conic", 2, 1);
    652         case SkPath::kCubic_Verb: return VerbParams("Cubic", 3, 1);
    653         case SkPath::kClose_Verb: return VerbParams("Close", 0, 0);
    654         case SkPath::kDone_Verb: return VerbParams("Done", 0, 0);
    655         default:
    656             ASSERT_NOT_REACHED();
    657             return VerbParams("?", 0, 0);
    658         };
    659     }
    660 
    661     PassRefPtr<JSONObject> objectForSkPath(const SkPath& path)
    662     {
    663         RefPtr<JSONObject> pathItem = JSONObject::create();
    664         pathItem->setString("fillType", fillTypeName(path.getFillType()));
    665         pathItem->setString("convexity", convexityName(path.getConvexity()));
    666         pathItem->setBoolean("isRect", path.isRect(0));
    667         SkPath::Iter iter(path, false);
    668         SkPoint points[4];
    669         RefPtr<JSONArray> pathPointsArray = JSONArray::create();
    670         for (SkPath::Verb verb = iter.next(points, false); verb != SkPath::kDone_Verb; verb = iter.next(points, false)) {
    671             VerbParams verbParams = segmentParams(verb);
    672             RefPtr<JSONObject> pathPointItem = JSONObject::create();
    673             pathPointItem->setString("verb", verbParams.name);
    674             ASSERT(verbParams.pointCount + verbParams.pointOffset <= WTF_ARRAY_LENGTH(points));
    675             pathPointItem->setArray("points", arrayForSkPoints(verbParams.pointCount, points + verbParams.pointOffset));
    676             if (SkPath::kConic_Verb == verb)
    677                 pathPointItem->setNumber("conicWeight", iter.conicWeight());
    678             pathPointsArray->pushObject(pathPointItem);
    679         }
    680         pathItem->setArray("pathPoints", pathPointsArray);
    681         pathItem->setObject("bounds", objectForSkRect(path.getBounds()));
    682         return pathItem.release();
    683     }
    684 
    685     String configName(SkBitmap::Config config)
    686     {
    687         switch (config) {
    688         case SkBitmap::kNo_Config: return "None";
    689         case SkBitmap::kA8_Config: return "A8";
    690         case SkBitmap::kIndex8_Config: return "Index8";
    691         case SkBitmap::kRGB_565_Config: return "RGB565";
    692         case SkBitmap::kARGB_4444_Config: return "ARGB4444";
    693         case SkBitmap::kARGB_8888_Config: return "ARGB8888";
    694         default:
    695             ASSERT_NOT_REACHED();
    696             return "?";
    697         };
    698     }
    699 
    700     PassRefPtr<JSONObject> objectForBitmapData(const SkBitmap& bitmap)
    701     {
    702         RefPtr<JSONObject> dataItem = JSONObject::create();
    703         Vector<unsigned char> output;
    704         WebCore::PNGImageEncoder::encode(bitmap, &output);
    705         dataItem->setString("base64", WTF::base64Encode(reinterpret_cast<char*>(output.data()), output.size()));
    706         dataItem->setString("mimeType", "image/png");
    707         return dataItem.release();
    708     }
    709 
    710     PassRefPtr<JSONObject> objectForSkBitmap(const SkBitmap& bitmap)
    711     {
    712         RefPtr<JSONObject> bitmapItem = JSONObject::create();
    713         bitmapItem->setNumber("width", bitmap.width());
    714         bitmapItem->setNumber("height", bitmap.height());
    715         bitmapItem->setString("config", configName(bitmap.config()));
    716         bitmapItem->setBoolean("opaque", bitmap.isOpaque());
    717         bitmapItem->setBoolean("immutable", bitmap.isImmutable());
    718         bitmapItem->setBoolean("volatile", bitmap.isVolatile());
    719         bitmapItem->setNumber("genID", bitmap.getGenerationID());
    720         bitmapItem->setObject("data", objectForBitmapData(bitmap));
    721         return bitmapItem.release();
    722     }
    723 
    724     PassRefPtr<JSONObject> objectForSkShader(const SkShader& shader)
    725     {
    726         RefPtr<JSONObject> shaderItem = JSONObject::create();
    727         const SkMatrix localMatrix = shader.getLocalMatrix();
    728         if (!localMatrix.isIdentity())
    729             shaderItem->setArray("localMatrix", arrayForSkMatrix(localMatrix));
    730         return shaderItem.release();
    731     }
    732 
    733     String stringForSkColor(const SkColor& color)
    734     {
    735         String colorString = "#";
    736         appendUnsignedAsHex(color, colorString);
    737         return colorString;
    738     }
    739 
    740     void appendFlagToString(String* flagsString, bool isSet, const String& name)
    741     {
    742         if (!isSet)
    743             return;
    744         if (flagsString->length())
    745             flagsString->append("|");
    746         flagsString->append(name);
    747     }
    748 
    749     String stringForSkPaintFlags(const SkPaint& paint)
    750     {
    751         if (!paint.getFlags())
    752             return "none";
    753         String flagsString = "";
    754         appendFlagToString(&flagsString, paint.isAntiAlias(), "AntiAlias");
    755         appendFlagToString(&flagsString, paint.isDither(), "Dither");
    756         appendFlagToString(&flagsString, paint.isUnderlineText(), "UnderlinText");
    757         appendFlagToString(&flagsString, paint.isStrikeThruText(), "StrikeThruText");
    758         appendFlagToString(&flagsString, paint.isFakeBoldText(), "FakeBoldText");
    759         appendFlagToString(&flagsString, paint.isLinearText(), "LinearText");
    760         appendFlagToString(&flagsString, paint.isSubpixelText(), "SubpixelText");
    761         appendFlagToString(&flagsString, paint.isDevKernText(), "DevKernText");
    762         appendFlagToString(&flagsString, paint.isLCDRenderText(), "LCDRenderText");
    763         appendFlagToString(&flagsString, paint.isEmbeddedBitmapText(), "EmbeddedBitmapText");
    764         appendFlagToString(&flagsString, paint.isAutohinted(), "Autohinted");
    765         appendFlagToString(&flagsString, paint.isVerticalText(), "VerticalText");
    766         appendFlagToString(&flagsString, paint.getFlags() & SkPaint::kGenA8FromLCD_Flag, "GenA8FromLCD");
    767         return flagsString;
    768     }
    769 
    770     String filterLevelName(SkPaint::FilterLevel filterLevel)
    771     {
    772         switch (filterLevel) {
    773         case SkPaint::kNone_FilterLevel: return "None";
    774         case SkPaint::kLow_FilterLevel: return "Low";
    775         case SkPaint::kMedium_FilterLevel: return "Medium";
    776         case SkPaint::kHigh_FilterLevel: return "High";
    777         default:
    778             ASSERT_NOT_REACHED();
    779             return "?";
    780         };
    781     }
    782 
    783     String textAlignName(SkPaint::Align align)
    784     {
    785         switch (align) {
    786         case SkPaint::kLeft_Align: return "Left";
    787         case SkPaint::kCenter_Align: return "Center";
    788         case SkPaint::kRight_Align: return "Right";
    789         default:
    790             ASSERT_NOT_REACHED();
    791             return "?";
    792         };
    793     }
    794 
    795     String strokeCapName(SkPaint::Cap cap)
    796     {
    797         switch (cap) {
    798         case SkPaint::kButt_Cap: return "Butt";
    799         case SkPaint::kRound_Cap: return "Round";
    800         case SkPaint::kSquare_Cap: return "Square";
    801         default:
    802             ASSERT_NOT_REACHED();
    803             return "?";
    804         };
    805     }
    806 
    807     String strokeJoinName(SkPaint::Join join)
    808     {
    809         switch (join) {
    810         case SkPaint::kMiter_Join: return "Miter";
    811         case SkPaint::kRound_Join: return "Round";
    812         case SkPaint::kBevel_Join: return "Bevel";
    813         default:
    814             ASSERT_NOT_REACHED();
    815             return "?";
    816         };
    817     }
    818 
    819     String styleName(SkPaint::Style style)
    820     {
    821         switch (style) {
    822         case SkPaint::kFill_Style: return "Fill";
    823         case SkPaint::kStroke_Style: return "Stroke";
    824         case SkPaint::kStrokeAndFill_Style: return "StrokeAndFill";
    825         default:
    826             ASSERT_NOT_REACHED();
    827             return "?";
    828         };
    829     }
    830 
    831     String textEncodingName(SkPaint::TextEncoding encoding)
    832     {
    833         switch (encoding) {
    834         case SkPaint::kUTF8_TextEncoding: return "UTF-8";
    835         case SkPaint::kUTF16_TextEncoding: return "UTF-16";
    836         case SkPaint::kUTF32_TextEncoding: return "UTF-32";
    837         case SkPaint::kGlyphID_TextEncoding: return "GlyphID";
    838         default:
    839             ASSERT_NOT_REACHED();
    840             return "?";
    841         };
    842     }
    843 
    844     String hintingName(SkPaint::Hinting hinting)
    845     {
    846         switch (hinting) {
    847         case SkPaint::kNo_Hinting: return "None";
    848         case SkPaint::kSlight_Hinting: return "Slight";
    849         case SkPaint::kNormal_Hinting: return "Normal";
    850         case SkPaint::kFull_Hinting: return "Full";
    851         default:
    852             ASSERT_NOT_REACHED();
    853             return "?";
    854         };
    855     }
    856 
    857     PassRefPtr<JSONObject> objectForSkPaint(const SkPaint& paint)
    858     {
    859         RefPtr<JSONObject> paintItem = JSONObject::create();
    860         paintItem->setNumber("textSize", paint.getTextSize());
    861         paintItem->setNumber("textScaleX", paint.getTextScaleX());
    862         paintItem->setNumber("textSkewX", paint.getTextSkewX());
    863         if (SkShader* shader = paint.getShader())
    864             paintItem->setObject("shader", objectForSkShader(*shader));
    865         paintItem->setString("color", stringForSkColor(paint.getColor()));
    866         paintItem->setNumber("strokeWidth", paint.getStrokeWidth());
    867         paintItem->setNumber("strokeMiter", paint.getStrokeMiter());
    868         paintItem->setString("flags", stringForSkPaintFlags(paint));
    869         paintItem->setString("filterLevel", filterLevelName(paint.getFilterLevel()));
    870         paintItem->setString("textAlign", textAlignName(paint.getTextAlign()));
    871         paintItem->setString("strokeCap", strokeCapName(paint.getStrokeCap()));
    872         paintItem->setString("strokeJoin", strokeJoinName(paint.getStrokeJoin()));
    873         paintItem->setString("styleName", styleName(paint.getStyle()));
    874         paintItem->setString("textEncoding", textEncodingName(paint.getTextEncoding()));
    875         paintItem->setString("hinting", hintingName(paint.getHinting()));
    876         return paintItem.release();
    877     }
    878 
    879     PassRefPtr<JSONArray> arrayForSkMatrix(const SkMatrix& matrix)
    880     {
    881         RefPtr<JSONArray> matrixArray = JSONArray::create();
    882         for (int i = 0; i < 9; ++i)
    883             matrixArray->pushNumber(matrix[i]);
    884         return matrixArray.release();
    885     }
    886 
    887     PassRefPtr<JSONArray> arrayForSkScalars(size_t n, const SkScalar scalars[])
    888     {
    889         RefPtr<JSONArray> scalarsArray = JSONArray::create();
    890         for (size_t i = 0; i < n; ++i)
    891             scalarsArray->pushNumber(scalars[i]);
    892         return scalarsArray.release();
    893     }
    894 
    895     String regionOpName(SkRegion::Op op)
    896     {
    897         switch (op) {
    898         case SkRegion::kDifference_Op: return "kDifference_Op";
    899         case SkRegion::kIntersect_Op: return "kIntersect_Op";
    900         case SkRegion::kUnion_Op: return "kUnion_Op";
    901         case SkRegion::kXOR_Op: return "kXOR_Op";
    902         case SkRegion::kReverseDifference_Op: return "kReverseDifference_Op";
    903         case SkRegion::kReplace_Op: return "kReplace_Op";
    904         default: return "Unknown type";
    905         };
    906     }
    907 
    908     void translate(SkScalar dx, SkScalar dy)
    909     {
    910         RefPtr<JSONObject> params = addItemWithParams("translate");
    911         params->setNumber("dx", dx);
    912         params->setNumber("dy", dy);
    913     }
    914 
    915     void scale(SkScalar scaleX, SkScalar scaleY)
    916     {
    917         RefPtr<JSONObject> params = addItemWithParams("scale");
    918         params->setNumber("scaleX", scaleX);
    919         params->setNumber("scaleY", scaleY);
    920     }
    921 
    922     void concat(const SkMatrix& matrix)
    923     {
    924         RefPtr<JSONObject> params = addItemWithParams("concat");
    925         params->setArray("matrix", arrayForSkMatrix(matrix));
    926     }
    927 
    928     String saveFlagsToString(SkCanvas::SaveFlags flags)
    929     {
    930         String flagsString = "";
    931         if (flags & SkCanvas::kHasAlphaLayer_SaveFlag)
    932             flagsString.append("kHasAlphaLayer_SaveFlag ");
    933         if (flags & SkCanvas::kFullColorLayer_SaveFlag)
    934             flagsString.append("kFullColorLayer_SaveFlag ");
    935         if (flags & SkCanvas::kClipToLayer_SaveFlag)
    936             flagsString.append("kClipToLayer_SaveFlag ");
    937         return flagsString;
    938     }
    939 
    940     String textEncodingCanonicalName(SkPaint::TextEncoding encoding)
    941     {
    942         String name = textEncodingName(encoding);
    943         if (encoding == SkPaint::kUTF16_TextEncoding || encoding == SkPaint::kUTF32_TextEncoding)
    944             name.append("LE");
    945         return name;
    946     }
    947 
    948     String stringForUTFText(const void* text, size_t length, SkPaint::TextEncoding encoding)
    949     {
    950         return WTF::TextEncoding(textEncodingCanonicalName(encoding)).decode((const char*)text, length);
    951     }
    952 
    953     String stringForText(const void* text, size_t byteLength, const SkPaint& paint)
    954     {
    955         SkPaint::TextEncoding encoding = paint.getTextEncoding();
    956         switch (encoding) {
    957         case SkPaint::kUTF8_TextEncoding:
    958         case SkPaint::kUTF16_TextEncoding:
    959         case SkPaint::kUTF32_TextEncoding:
    960             return stringForUTFText(text, byteLength, encoding);
    961         case SkPaint::kGlyphID_TextEncoding: {
    962             WTF::Vector<SkUnichar> dataVector(byteLength / 2);
    963             SkUnichar* textData = dataVector.data();
    964             paint.glyphsToUnichars(static_cast<const uint16_t*>(text), byteLength / 2, textData);
    965             return WTF::UTF32LittleEndianEncoding().decode(reinterpret_cast<const char*>(textData), byteLength * 2);
    966         }
    967         default:
    968             ASSERT_NOT_REACHED();
    969             return "?";
    970         }
    971     }
    972 };
    973 
    974 static bool decodeBitmap(const void* data, size_t length, SkBitmap* result)
    975 {
    976     RefPtr<SharedBuffer> buffer = SharedBuffer::create(static_cast<const char*>(data), length);
    977     OwnPtr<ImageDecoder> imageDecoder = ImageDecoder::create(*buffer, ImageSource::AlphaPremultiplied, ImageSource::GammaAndColorProfileIgnored);
    978     if (!imageDecoder)
    979         return false;
    980     imageDecoder->setData(buffer.get(), true);
    981     ImageFrame* frame = imageDecoder->frameBufferAtIndex(0);
    982     if (!frame)
    983         return true;
    984     *result = frame->getSkBitmap();
    985     return true;
    986 }
    987 
    988 PassRefPtr<GraphicsContextSnapshot> GraphicsContextSnapshot::load(const char* data, size_t size)
    989 {
    990     SkMemoryStream stream(data, size);
    991     RefPtr<SkPicture> picture = adoptRef(SkPicture::CreateFromStream(&stream, decodeBitmap));
    992     if (!picture)
    993         return nullptr;
    994     return adoptRef(new GraphicsContextSnapshot(picture, false));
    995 }
    996 
    997 PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::replay(unsigned fromStep, unsigned toStep) const
    998 {
    999     OwnPtr<ImageBuffer> imageBuffer = createImageBuffer();
   1000     FragmentSnapshotPlayer player(m_picture, imageBuffer->context()->canvas());
   1001     player.play(fromStep, toStep);
   1002     return imageBuffer.release();
   1003 }
   1004 
   1005 PassOwnPtr<GraphicsContextSnapshot::Timings> GraphicsContextSnapshot::profile(unsigned minRepeatCount, double minDuration) const
   1006 {
   1007     OwnPtr<GraphicsContextSnapshot::Timings> timings = adoptPtr(new GraphicsContextSnapshot::Timings());
   1008     OwnPtr<ImageBuffer> imageBuffer = createImageBuffer();
   1009     ProfilingSnapshotPlayer player(m_picture, imageBuffer->context()->canvas());
   1010     player.play(timings.get(), minRepeatCount, minDuration);
   1011     return timings.release();
   1012 }
   1013 
   1014 PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::createImageBuffer() const
   1015 {
   1016     return ImageBuffer::create(IntSize(m_picture->width(), m_picture->height()), m_isCertainlyOpaque ? Opaque : NonOpaque);
   1017 }
   1018 
   1019 PassRefPtr<JSONArray> GraphicsContextSnapshot::snapshotCommandLog() const
   1020 {
   1021     LoggingCanvas canvas(m_picture->width(), m_picture->height());
   1022     FragmentSnapshotPlayer player(m_picture, &canvas);
   1023     player.play(0, 0);
   1024     return canvas.log();
   1025 }
   1026 
   1027 }
   1028