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
make_noconfig_bm(int width,int height)17 static SkBitmap make_noconfig_bm(int width, int height) {
18 SkBitmap bm;
19 bm.setConfig(SkBitmap::kNo_Config, width, height);
20 return bm;
21 }
22
SkDebugCanvas(int width,int height)23 SkDebugCanvas::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
~SkDebugCanvas()55 SkDebugCanvas::~SkDebugCanvas() {
56 fCommandVector.deleteAll();
57 SkSafeUnref(fOverdrawFilter);
58 SkSafeUnref(fTexOverrideFilter);
59 }
60
addDrawCommand(SkDrawCommand * command)61 void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
62 fCommandVector.push(command);
63 }
64
draw(SkCanvas * canvas)65 void SkDebugCanvas::draw(SkCanvas* canvas) {
66 if (!fCommandVector.isEmpty()) {
67 drawTo(canvas, fCommandVector.count() - 1);
68 }
69 }
70
applyUserTransform(SkCanvas * canvas)71 void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
72 canvas->concat(fUserMatrix);
73 }
74
getCommandAtPoint(int x,int y,int index)75 int 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
OverdrawXferModeProc(SkPMColor src,SkPMColor dst)98 static 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
125 class SkOverdrawFilter : public SkDrawFilter {
126 public:
SkOverdrawFilter()127 SkOverdrawFilter() {
128 fXferMode = new SkProcXfermode(OverdrawXferModeProc);
129 }
130
~SkOverdrawFilter()131 virtual ~SkOverdrawFilter() {
132 delete fXferMode;
133 }
134
filter(SkPaint * p,Type)135 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
136 p->setXfermode(fXferMode);
137 return true;
138 }
139
140 protected:
141 SkXfermode* fXferMode;
142
143 private:
144 typedef SkDrawFilter INHERITED;
145 };
146
147 // SkTexOverrideFilter modifies every paint to use the specified
148 // texture filtering mode
149 class SkTexOverrideFilter : public SkDrawFilter {
150 public:
SkTexOverrideFilter()151 SkTexOverrideFilter() : fFilterLevel(SkPaint::kNone_FilterLevel) {
152 }
153
setFilterLevel(SkPaint::FilterLevel filterLevel)154 void setFilterLevel(SkPaint::FilterLevel filterLevel) {
155 fFilterLevel = filterLevel;
156 }
157
filter(SkPaint * p,Type)158 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
159 p->setFilterLevel(fFilterLevel);
160 return true;
161 }
162
163 protected:
164 SkPaint::FilterLevel fFilterLevel;
165
166 private:
167 typedef SkDrawFilter INHERITED;
168 };
169
drawTo(SkCanvas * canvas,int index)170 void 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
deleteDrawCommandAt(int index)244 void SkDebugCanvas::deleteDrawCommandAt(int index) {
245 SkASSERT(index < fCommandVector.count());
246 delete fCommandVector[index];
247 fCommandVector.remove(index);
248 }
249
getDrawCommandAt(int index)250 SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
251 SkASSERT(index < fCommandVector.count());
252 return fCommandVector[index];
253 }
254
setDrawCommandAt(int index,SkDrawCommand * command)255 void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
256 SkASSERT(index < fCommandVector.count());
257 delete fCommandVector[index];
258 fCommandVector[index] = command;
259 }
260
getCommandInfo(int index)261 SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
262 SkASSERT(index < fCommandVector.count());
263 return fCommandVector[index]->Info();
264 }
265
getDrawCommandVisibilityAt(int index)266 bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
267 SkASSERT(index < fCommandVector.count());
268 return fCommandVector[index]->isVisible();
269 }
270
getDrawCommands() const271 const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
272 return fCommandVector;
273 }
274
getDrawCommands()275 SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
276 return fCommandVector;
277 }
278
279 // TODO(chudy): Free command string memory.
getDrawCommandsAsStrings() const280 SkTArray<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
toggleFilter(bool toggle)290 void SkDebugCanvas::toggleFilter(bool toggle) {
291 fFilter = toggle;
292 }
293
overrideTexFiltering(bool overrideTexFiltering,SkPaint::FilterLevel level)294 void 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
clear(SkColor color)303 void SkDebugCanvas::clear(SkColor color) {
304 addDrawCommand(new SkClearCommand(color));
305 }
306
clipPath(const SkPath & path,SkRegion::Op op,bool doAA)307 bool SkDebugCanvas::clipPath(const SkPath& path, SkRegion::Op op, bool doAA) {
308 addDrawCommand(new SkClipPathCommand(path, op, doAA));
309 return true;
310 }
311
clipRect(const SkRect & rect,SkRegion::Op op,bool doAA)312 bool SkDebugCanvas::clipRect(const SkRect& rect, SkRegion::Op op, bool doAA) {
313 addDrawCommand(new SkClipRectCommand(rect, op, doAA));
314 return true;
315 }
316
clipRRect(const SkRRect & rrect,SkRegion::Op op,bool doAA)317 bool SkDebugCanvas::clipRRect(const SkRRect& rrect, SkRegion::Op op, bool doAA) {
318 addDrawCommand(new SkClipRRectCommand(rrect, op, doAA));
319 return true;
320 }
321
clipRegion(const SkRegion & region,SkRegion::Op op)322 bool SkDebugCanvas::clipRegion(const SkRegion& region, SkRegion::Op op) {
323 addDrawCommand(new SkClipRegionCommand(region, op));
324 return true;
325 }
326
concat(const SkMatrix & matrix)327 bool SkDebugCanvas::concat(const SkMatrix& matrix) {
328 addDrawCommand(new SkConcatCommand(matrix));
329 return true;
330 }
331
drawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint=NULL)332 void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
333 SkScalar top, const SkPaint* paint = NULL) {
334 addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
335 }
336
drawBitmapRectToRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,SkCanvas::DrawBitmapRectFlags flags)337 void 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
drawBitmapMatrix(const SkBitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)344 void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
345 const SkMatrix& matrix, const SkPaint* paint) {
346 addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
347 }
348
drawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)349 void 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
drawData(const void * data,size_t length)354 void SkDebugCanvas::drawData(const void* data, size_t length) {
355 addDrawCommand(new SkDrawDataCommand(data, length));
356 }
357
beginCommentGroup(const char * description)358 void SkDebugCanvas::beginCommentGroup(const char* description) {
359 addDrawCommand(new SkBeginCommentGroupCommand(description));
360 }
361
addComment(const char * kywd,const char * value)362 void SkDebugCanvas::addComment(const char* kywd, const char* value) {
363 addDrawCommand(new SkCommentCommand(kywd, value));
364 }
365
endCommentGroup()366 void SkDebugCanvas::endCommentGroup() {
367 addDrawCommand(new SkEndCommentGroupCommand());
368 }
369
drawOval(const SkRect & oval,const SkPaint & paint)370 void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
371 addDrawCommand(new SkDrawOvalCommand(oval, paint));
372 }
373
drawPaint(const SkPaint & paint)374 void SkDebugCanvas::drawPaint(const SkPaint& paint) {
375 addDrawCommand(new SkDrawPaintCommand(paint));
376 }
377
drawPath(const SkPath & path,const SkPaint & paint)378 void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
379 addDrawCommand(new SkDrawPathCommand(path, paint));
380 }
381
drawPicture(SkPicture & picture)382 void SkDebugCanvas::drawPicture(SkPicture& picture) {
383 addDrawCommand(new SkDrawPictureCommand(picture));
384 }
385
drawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)386 void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
387 const SkPoint pts[], const SkPaint& paint) {
388 addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
389 }
390
drawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)391 void 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
drawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)396 void 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
drawRect(const SkRect & rect,const SkPaint & paint)402 void 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
drawRRect(const SkRRect & rrect,const SkPaint & paint)407 void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
408 addDrawCommand(new SkDrawRRectCommand(rrect, paint));
409 }
410
drawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint=NULL)411 void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
412 const SkPaint* paint = NULL) {
413 addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
414 }
415
drawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)416 void 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
drawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)421 void 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
drawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode *,const uint16_t indices[],int indexCount,const SkPaint & paint)427 void 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
restore()435 void SkDebugCanvas::restore() {
436 addDrawCommand(new SkRestoreCommand());
437 }
438
rotate(SkScalar degrees)439 bool SkDebugCanvas::rotate(SkScalar degrees) {
440 addDrawCommand(new SkRotateCommand(degrees));
441 return true;
442 }
443
save(SaveFlags flags)444 int SkDebugCanvas::save(SaveFlags flags) {
445 addDrawCommand(new SkSaveCommand(flags));
446 return true;
447 }
448
saveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)449 int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
450 SaveFlags flags) {
451 addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
452 return true;
453 }
454
scale(SkScalar sx,SkScalar sy)455 bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
456 addDrawCommand(new SkScaleCommand(sx, sy));
457 return true;
458 }
459
setMatrix(const SkMatrix & matrix)460 void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
461 addDrawCommand(new SkSetMatrixCommand(matrix));
462 }
463
skew(SkScalar sx,SkScalar sy)464 bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
465 addDrawCommand(new SkSkewCommand(sx, sy));
466 return true;
467 }
468
translate(SkScalar dx,SkScalar dy)469 bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
470 addDrawCommand(new SkTranslateCommand(dx, dy));
471 return true;
472 }
473
toggleCommand(int index,bool toggle)474 void SkDebugCanvas::toggleCommand(int index, bool toggle) {
475 SkASSERT(index < fCommandVector.count());
476 fCommandVector[index]->setVisible(toggle);
477 }
478