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 40namespace blink { 41 42class AutoLogger { 43public: 44 explicit AutoLogger(LoggingCanvas*); 45 PassRefPtr<JSONObject> logItem(const String& name); 46 PassRefPtr<JSONObject> logItemWithParams(const String& name); 47 ~AutoLogger(); 48 49private: 50 LoggingCanvas* m_canvas; 51 RefPtr<JSONObject> m_logItem; 52}; 53 54AutoLogger::AutoLogger(LoggingCanvas* loggingCanvas) : m_canvas(loggingCanvas) 55{ 56 loggingCanvas->m_depthCount++; 57} 58 59PassRefPtr<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 67PassRefPtr<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 75AutoLogger::~AutoLogger() 76{ 77 m_canvas->m_depthCount--; 78 if (!m_canvas->m_depthCount) 79 m_canvas->m_log->pushObject(m_logItem); 80} 81 82LoggingCanvas::LoggingCanvas(int width, int height) : InterceptingCanvas(width, height) 83{ 84 m_log = JSONArray::create(); 85} 86 87void LoggingCanvas::clear(SkColor color) 88{ 89 AutoLogger logger(this); 90 logger.logItemWithParams("clear")->setString("color", stringForSkColor(color)); 91 this->SkCanvas::clear(color); 92} 93 94void 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 101void 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 111void 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 120void 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 129void 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 138void 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 147void 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 158void 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 170void 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 180void 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 191void 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 202void 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 211void 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 219void 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 227void 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 236void LoggingCanvas::endCommentGroup() 237{ 238 AutoLogger logger(this); 239 logger.logItem("endCommentGroup"); 240 this->SkCanvas::endCommentGroup(); 241} 242 243void 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 253void 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 264void 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 275void 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 287void 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 298void 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 306void LoggingCanvas::onPopCull() 307{ 308 AutoLogger logger(this); 309 logger.logItem("popCull"); 310 this->SkCanvas::onPopCull(); 311} 312 313void 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 323void 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 333void 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 343void 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 351void 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 358void 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 366void 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 391void LoggingCanvas::willSave() 392{ 393 AutoLogger logger(this); 394 RefPtr<JSONObject> params = logger.logItem("save"); 395 this->SkCanvas::willSave(); 396} 397 398SkCanvas::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 409void LoggingCanvas::willRestore() 410{ 411 AutoLogger logger(this); 412 logger.logItem("restore"); 413 this->SkCanvas::willRestore(); 414} 415 416PassRefPtr<JSONArray> LoggingCanvas::log() 417{ 418 return m_log; 419} 420 421PassRefPtr<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 431PassRefPtr<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 441String 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 453PassRefPtr<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 461PassRefPtr<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 469PassRefPtr<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 477PassRefPtr<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 486String 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 501String 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 514PassRefPtr<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 527String 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 540String 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 552String 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 568LoggingCanvas::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 584PassRefPtr<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 608String 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 623PassRefPtr<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 633PassRefPtr<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 647PassRefPtr<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 656String LoggingCanvas::stringForSkColor(const SkColor& color) 657{ 658 String colorString = "#"; 659 appendUnsignedAsHex(color, colorString); 660 return colorString; 661} 662 663void 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 672String 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 693String 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 706String 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 718String 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 730String 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 742String 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 754String 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 767String 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 780PassRefPtr<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 802PassRefPtr<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 810PassRefPtr<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 818String 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 831String 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 843String 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 851String 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 856String 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