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