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
46namespace WebCore {
47
48GraphicsContext* 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
62PassRefPtr<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
70GraphicsContextSnapshot::GraphicsContextSnapshot(PassRefPtr<SkPicture> picture, bool isCertainlyOpaque)
71    : m_picture(picture)
72    , m_isCertainlyOpaque(isCertainlyOpaque)
73{
74}
75
76
77class SnapshotPlayer : public SkDrawPictureCallback {
78    WTF_MAKE_NONCOPYABLE(SnapshotPlayer);
79public:
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
93private:
94    RefPtr<SkPicture> m_picture;
95    SkCanvas* m_canvas;
96};
97
98class FragmentSnapshotPlayer : public SnapshotPlayer {
99public:
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
123private:
124    unsigned m_fromStep;
125    unsigned m_toStep;
126    unsigned m_stepCount;
127};
128
129class ProfilingSnapshotPlayer : public SnapshotPlayer {
130public:
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
162private:
163    GraphicsContextSnapshot::Timings* m_timingsVector;
164    Vector<double>* m_currentTimings;
165};
166
167class LoggingCanvas : public SkCanvas {
168public:
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
468private:
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
974static 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
988PassRefPtr<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
997PassOwnPtr<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
1005PassOwnPtr<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
1014PassOwnPtr<ImageBuffer> GraphicsContextSnapshot::createImageBuffer() const
1015{
1016    return ImageBuffer::create(IntSize(m_picture->width(), m_picture->height()), m_isCertainlyOpaque ? Opaque : NonOpaque);
1017}
1018
1019PassRefPtr<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