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