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