SkDebugCanvas.cpp revision 57f74e0aa931e7784d47cba3ecc83020aa8e72b2
1 2/* 3 * Copyright 2012 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9 10#include "SkColorPriv.h" 11#include "SkDebugCanvas.h" 12#include "SkDrawCommand.h" 13#include "SkDrawFilter.h" 14#include "SkDevice.h" 15#include "SkXfermode.h" 16 17SkDebugCanvas::SkDebugCanvas(int width, int height) 18 : INHERITED(width, height) 19 , fPicture(NULL) 20 , fWidth(width) 21 , fHeight(height) 22 , fFilter(false) 23 , fMegaVizMode(false) 24 , fIndex(0) 25 , fOverdrawViz(false) 26 , fOverdrawFilter(NULL) 27 , fOverrideTexFiltering(false) 28 , fTexOverrideFilter(NULL) 29 , fOutstandingSaveCount(0) { 30 fUserMatrix.reset(); 31 32 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped 33 // operations. This can lead to problems in the debugger which expects all 34 // the operations in the captured skp to appear in the debug canvas. To 35 // circumvent this we create a wide open clip here (an empty clip rect 36 // is not sufficient). 37 // Internally, the SkRect passed to clipRect is converted to an SkIRect and 38 // rounded out. The following code creates a nearly maximal rect that will 39 // not get collapsed by the coming conversions (Due to precision loss the 40 // inset has to be surprisingly large). 41 SkIRect largeIRect = SkIRect::MakeLargest(); 42 largeIRect.inset(1024, 1024); 43 SkRect large = SkRect::Make(largeIRect); 44#ifdef SK_DEBUG 45 large.roundOut(&largeIRect); 46 SkASSERT(!largeIRect.isEmpty()); 47#endif 48 // call the base class' version to avoid adding a draw command 49 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle); 50} 51 52SkDebugCanvas::~SkDebugCanvas() { 53 fCommandVector.deleteAll(); 54 SkSafeUnref(fOverdrawFilter); 55 SkSafeUnref(fTexOverrideFilter); 56} 57 58void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) { 59 command->setOffset(this->getOpID()); 60 fCommandVector.push(command); 61} 62 63void SkDebugCanvas::draw(SkCanvas* canvas) { 64 if (!fCommandVector.isEmpty()) { 65 this->drawTo(canvas, fCommandVector.count() - 1); 66 } 67} 68 69void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) { 70 canvas->concat(fUserMatrix); 71} 72 73int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) { 74 SkBitmap bitmap; 75 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1)); 76 77 SkCanvas canvas(bitmap); 78 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y)); 79 applyUserTransform(&canvas); 80 81 int layer = 0; 82 SkColor prev = bitmap.getColor(0,0); 83 for (int i = 0; i < index; i++) { 84 if (fCommandVector[i]->isVisible()) { 85 fCommandVector[i]->execute(&canvas); 86 } 87 if (prev != bitmap.getColor(0,0)) { 88 layer = i; 89 } 90 prev = bitmap.getColor(0,0); 91 } 92 return layer; 93} 94 95static SkPMColor OverdrawXferModeProc(SkPMColor src, SkPMColor dst) { 96 // This table encodes the color progression of the overdraw visualization 97 static const SkPMColor gTable[] = { 98 SkPackARGB32(0x00, 0x00, 0x00, 0x00), 99 SkPackARGB32(0xFF, 128, 158, 255), 100 SkPackARGB32(0xFF, 170, 185, 212), 101 SkPackARGB32(0xFF, 213, 195, 170), 102 SkPackARGB32(0xFF, 255, 192, 127), 103 SkPackARGB32(0xFF, 255, 185, 85), 104 SkPackARGB32(0xFF, 255, 165, 42), 105 SkPackARGB32(0xFF, 255, 135, 0), 106 SkPackARGB32(0xFF, 255, 95, 0), 107 SkPackARGB32(0xFF, 255, 50, 0), 108 SkPackARGB32(0xFF, 255, 0, 0) 109 }; 110 111 for (size_t i = 0; i < SK_ARRAY_COUNT(gTable)-1; ++i) { 112 if (gTable[i] == dst) { 113 return gTable[i+1]; 114 } 115 } 116 117 return gTable[SK_ARRAY_COUNT(gTable)-1]; 118} 119 120// The OverdrawFilter modifies every paint to use an SkProcXfermode which 121// in turn invokes OverdrawXferModeProc 122class SkOverdrawFilter : public SkDrawFilter { 123public: 124 SkOverdrawFilter() { 125 fXferMode = SkProcXfermode::Create(OverdrawXferModeProc); 126 } 127 128 virtual ~SkOverdrawFilter() { 129 delete fXferMode; 130 } 131 132 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE { 133 p->setXfermode(fXferMode); 134 return true; 135 } 136 137protected: 138 SkXfermode* fXferMode; 139 140private: 141 typedef SkDrawFilter INHERITED; 142}; 143 144// SkTexOverrideFilter modifies every paint to use the specified 145// texture filtering mode 146class SkTexOverrideFilter : public SkDrawFilter { 147public: 148 SkTexOverrideFilter() : fFilterLevel(SkPaint::kNone_FilterLevel) { 149 } 150 151 void setFilterLevel(SkPaint::FilterLevel filterLevel) { 152 fFilterLevel = filterLevel; 153 } 154 155 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE { 156 p->setFilterLevel(fFilterLevel); 157 return true; 158 } 159 160protected: 161 SkPaint::FilterLevel fFilterLevel; 162 163private: 164 typedef SkDrawFilter INHERITED; 165}; 166 167class SkDebugClipVisitor : public SkCanvas::ClipVisitor { 168public: 169 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {} 170 171 virtual void clipRect(const SkRect& r, SkRegion::Op, bool doAA) SK_OVERRIDE { 172 SkPaint p; 173 p.setColor(SK_ColorRED); 174 p.setStyle(SkPaint::kStroke_Style); 175 p.setAntiAlias(doAA); 176 fCanvas->drawRect(r, p); 177 } 178 virtual void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) SK_OVERRIDE { 179 SkPaint p; 180 p.setColor(SK_ColorGREEN); 181 p.setStyle(SkPaint::kStroke_Style); 182 p.setAntiAlias(doAA); 183 fCanvas->drawRRect(rr, p); 184 } 185 virtual void clipPath(const SkPath& path, SkRegion::Op, bool doAA) SK_OVERRIDE { 186 SkPaint p; 187 p.setColor(SK_ColorBLUE); 188 p.setStyle(SkPaint::kStroke_Style); 189 p.setAntiAlias(doAA); 190 fCanvas->drawPath(path, p); 191 } 192 193protected: 194 SkCanvas* fCanvas; 195 196private: 197 typedef SkCanvas::ClipVisitor INHERITED; 198}; 199 200// set up the saveLayer commands so that the active ones 201// return true in their 'active' method 202void SkDebugCanvas::markActiveCommands(int index) { 203 fActiveLayers.rewind(); 204 fActiveCulls.rewind(); 205 206 for (int i = 0; i < fCommandVector.count(); ++i) { 207 fCommandVector[i]->setActive(false); 208 } 209 210 for (int i = 0; i < index; ++i) { 211 SkDrawCommand::Action result = fCommandVector[i]->action(); 212 if (SkDrawCommand::kPushLayer_Action == result) { 213 fActiveLayers.push(fCommandVector[i]); 214 } else if (SkDrawCommand::kPopLayer_Action == result) { 215 fActiveLayers.pop(); 216 } else if (SkDrawCommand::kPushCull_Action == result) { 217 fActiveCulls.push(fCommandVector[i]); 218 } else if (SkDrawCommand::kPopCull_Action == result) { 219 fActiveCulls.pop(); 220 } 221 } 222 223 for (int i = 0; i < fActiveLayers.count(); ++i) { 224 fActiveLayers[i]->setActive(true); 225 } 226 227 for (int i = 0; i < fActiveCulls.count(); ++i) { 228 fActiveCulls[i]->setActive(true); 229 } 230} 231 232void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) { 233 SkASSERT(!fCommandVector.isEmpty()); 234 SkASSERT(index < fCommandVector.count()); 235 int i = 0; 236 237 // This only works assuming the canvas and device are the same ones that 238 // were previously drawn into because they need to preserve all saves 239 // and restores. 240 // The visibility filter also requires a full re-draw - otherwise we can 241 // end up drawing the filter repeatedly. 242 if (fIndex < index && !fFilter && !fMegaVizMode) { 243 i = fIndex + 1; 244 } else { 245 for (int j = 0; j < fOutstandingSaveCount; j++) { 246 canvas->restore(); 247 } 248 canvas->clear(SK_ColorTRANSPARENT); 249 canvas->resetMatrix(); 250 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth), 251 SkIntToScalar(fHeight)); 252 canvas->clipRect(rect, SkRegion::kReplace_Op ); 253 applyUserTransform(canvas); 254 fOutstandingSaveCount = 0; 255 } 256 257 // The setting of the draw filter has to go here (rather than in 258 // SkRasterWidget) due to the canvas restores this class performs. 259 // Since the draw filter is stored in the layer stack if we 260 // call setDrawFilter on anything but the root layer odd things happen. 261 if (fOverdrawViz) { 262 if (NULL == fOverdrawFilter) { 263 fOverdrawFilter = new SkOverdrawFilter; 264 } 265 266 if (fOverdrawFilter != canvas->getDrawFilter()) { 267 canvas->setDrawFilter(fOverdrawFilter); 268 } 269 } else if (fOverrideTexFiltering) { 270 if (NULL == fTexOverrideFilter) { 271 fTexOverrideFilter = new SkTexOverrideFilter; 272 } 273 274 if (fTexOverrideFilter != canvas->getDrawFilter()) { 275 canvas->setDrawFilter(fTexOverrideFilter); 276 } 277 } else { 278 canvas->setDrawFilter(NULL); 279 } 280 281 if (fMegaVizMode) { 282 this->markActiveCommands(index); 283 } 284 285 for (; i <= index; i++) { 286 if (i == index && fFilter) { 287 SkPaint p; 288 p.setColor(0xAAFFFFFF); 289 canvas->save(); 290 canvas->resetMatrix(); 291 SkRect mask; 292 mask.set(SkIntToScalar(0), SkIntToScalar(0), 293 SkIntToScalar(fWidth), SkIntToScalar(fHeight)); 294 canvas->clipRect(mask, SkRegion::kReplace_Op, false); 295 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0), 296 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p); 297 canvas->restore(); 298 } 299 300 if (fCommandVector[i]->isVisible()) { 301 if (fMegaVizMode && fCommandVector[i]->active()) { 302 // "active" commands execute their visualization behaviors: 303 // All active saveLayers get replaced with saves so all draws go to the 304 // visible canvas. 305 // All active culls draw their cull box 306 fCommandVector[i]->vizExecute(canvas); 307 } else { 308 fCommandVector[i]->execute(canvas); 309 } 310 311 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount); 312 } 313 } 314 315 if (fMegaVizMode) { 316 SkRect r = SkRect::MakeWH(SkIntToScalar(fWidth), SkIntToScalar(fHeight)); 317 r.outset(SK_Scalar1, SK_Scalar1); 318 319 canvas->save(); 320 // nuke the CTM 321 canvas->setMatrix(SkMatrix::I()); 322 // turn off clipping 323 canvas->clipRect(r, SkRegion::kReplace_Op); 324 325 // visualize existing clips 326 SkDebugClipVisitor visitor(canvas); 327 328 canvas->replayClips(&visitor); 329 330 canvas->restore(); 331 } 332 fMatrix = canvas->getTotalMatrix(); 333 if (!canvas->getClipDeviceBounds(&fClip)) { 334 fClip.setEmpty(); 335 } 336 fIndex = index; 337} 338 339void SkDebugCanvas::deleteDrawCommandAt(int index) { 340 SkASSERT(index < fCommandVector.count()); 341 delete fCommandVector[index]; 342 fCommandVector.remove(index); 343} 344 345SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) { 346 SkASSERT(index < fCommandVector.count()); 347 return fCommandVector[index]; 348} 349 350void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) { 351 SkASSERT(index < fCommandVector.count()); 352 delete fCommandVector[index]; 353 fCommandVector[index] = command; 354} 355 356SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) { 357 SkASSERT(index < fCommandVector.count()); 358 return fCommandVector[index]->Info(); 359} 360 361bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) { 362 SkASSERT(index < fCommandVector.count()); 363 return fCommandVector[index]->isVisible(); 364} 365 366const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const { 367 return fCommandVector; 368} 369 370SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() { 371 return fCommandVector; 372} 373 374// TODO(chudy): Free command string memory. 375SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const { 376 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count()); 377 if (!fCommandVector.isEmpty()) { 378 for (int i = 0; i < fCommandVector.count(); i ++) { 379 commandString->push_back() = fCommandVector[i]->toString(); 380 } 381 } 382 return commandString; 383} 384 385SkTDArray<size_t>* SkDebugCanvas::getDrawCommandOffsets() const { 386 SkTDArray<size_t>* commandOffsets = new SkTDArray<size_t>; 387 if (!fCommandVector.isEmpty()) { 388 for (int i = 0; i < fCommandVector.count(); i ++) { 389 *commandOffsets->push() = fCommandVector[i]->offset(); 390 } 391 } 392 return commandOffsets; 393} 394 395void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkPaint::FilterLevel level) { 396 if (NULL == fTexOverrideFilter) { 397 fTexOverrideFilter = new SkTexOverrideFilter; 398 } 399 400 fOverrideTexFiltering = overrideTexFiltering; 401 fTexOverrideFilter->setFilterLevel(level); 402} 403 404void SkDebugCanvas::clear(SkColor color) { 405 this->addDrawCommand(new SkClearCommand(color)); 406} 407 408void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 409 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle)); 410} 411 412void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 413 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle)); 414} 415 416void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) { 417 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle)); 418} 419 420void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) { 421 this->addDrawCommand(new SkClipRegionCommand(region, op)); 422} 423 424void SkDebugCanvas::didConcat(const SkMatrix& matrix) { 425 switch (matrix.getType()) { 426 case SkMatrix::kTranslate_Mask: 427 this->addDrawCommand(new SkTranslateCommand(matrix.getTranslateX(), 428 matrix.getTranslateY())); 429 break; 430 case SkMatrix::kScale_Mask: 431 this->addDrawCommand(new SkScaleCommand(matrix.getScaleX(), 432 matrix.getScaleY())); 433 break; 434 default: 435 this->addDrawCommand(new SkConcatCommand(matrix)); 436 break; 437 } 438 439 this->INHERITED::didConcat(matrix); 440} 441 442void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left, 443 SkScalar top, const SkPaint* paint = NULL) { 444 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint)); 445} 446 447void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap, 448 const SkRect* src, const SkRect& dst, 449 const SkPaint* paint, 450 SkCanvas::DrawBitmapRectFlags flags) { 451 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags)); 452} 453 454void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap, 455 const SkMatrix& matrix, const SkPaint* paint) { 456 this->addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint)); 457} 458 459void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap, 460 const SkIRect& center, const SkRect& dst, const SkPaint* paint) { 461 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint)); 462} 463 464void SkDebugCanvas::drawData(const void* data, size_t length) { 465 this->addDrawCommand(new SkDrawDataCommand(data, length)); 466} 467 468void SkDebugCanvas::beginCommentGroup(const char* description) { 469 this->addDrawCommand(new SkBeginCommentGroupCommand(description)); 470} 471 472void SkDebugCanvas::addComment(const char* kywd, const char* value) { 473 this->addDrawCommand(new SkCommentCommand(kywd, value)); 474} 475 476void SkDebugCanvas::endCommentGroup() { 477 this->addDrawCommand(new SkEndCommentGroupCommand()); 478} 479 480void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) { 481 this->addDrawCommand(new SkDrawOvalCommand(oval, paint)); 482} 483 484void SkDebugCanvas::drawPaint(const SkPaint& paint) { 485 this->addDrawCommand(new SkDrawPaintCommand(paint)); 486} 487 488void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) { 489 this->addDrawCommand(new SkDrawPathCommand(path, paint)); 490} 491 492void SkDebugCanvas::drawPicture(SkPicture& picture) { 493 this->addDrawCommand(new SkDrawPictureCommand(picture)); 494} 495 496void SkDebugCanvas::drawPoints(PointMode mode, size_t count, 497 const SkPoint pts[], const SkPaint& paint) { 498 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint)); 499} 500 501void SkDebugCanvas::drawPosText(const void* text, size_t byteLength, 502 const SkPoint pos[], const SkPaint& paint) { 503 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint)); 504} 505 506void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength, 507 const SkScalar xpos[], SkScalar constY, const SkPaint& paint) { 508 this->addDrawCommand( 509 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint)); 510} 511 512void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) { 513 // NOTE(chudy): Messing up when renamed to DrawRect... Why? 514 addDrawCommand(new SkDrawRectCommand(rect, paint)); 515} 516 517void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) { 518 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint)); 519} 520 521void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner, 522 const SkPaint& paint) { 523 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint)); 524} 525 526void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top, 527 const SkPaint* paint = NULL) { 528 this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint)); 529} 530 531void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x, 532 SkScalar y, const SkPaint& paint) { 533 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint)); 534} 535 536void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength, 537 const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) { 538 this->addDrawCommand( 539 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint)); 540} 541 542void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount, 543 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[], 544 SkXfermode*, const uint16_t indices[], int indexCount, 545 const SkPaint& paint) { 546 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices, 547 texs, colors, NULL, indices, indexCount, paint)); 548} 549 550void SkDebugCanvas::onPushCull(const SkRect& cullRect) { 551 this->addDrawCommand(new SkPushCullCommand(cullRect)); 552} 553 554void SkDebugCanvas::onPopCull() { 555 this->addDrawCommand(new SkPopCullCommand()); 556} 557 558void SkDebugCanvas::willRestore() { 559 this->addDrawCommand(new SkRestoreCommand()); 560 this->INHERITED::willRestore(); 561} 562 563void SkDebugCanvas::willSave(SaveFlags flags) { 564 this->addDrawCommand(new SkSaveCommand(flags)); 565 this->INHERITED::willSave(flags); 566} 567 568SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint, 569 SaveFlags flags) { 570 this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags)); 571 this->INHERITED::willSaveLayer(bounds, paint, flags); 572 // No need for a full layer. 573 return kNoLayer_SaveLayerStrategy; 574} 575 576void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) { 577 this->addDrawCommand(new SkSetMatrixCommand(matrix)); 578 this->INHERITED::didSetMatrix(matrix); 579} 580 581void SkDebugCanvas::toggleCommand(int index, bool toggle) { 582 SkASSERT(index < fCommandVector.count()); 583 fCommandVector[index]->setVisible(toggle); 584} 585