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