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