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