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