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