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