• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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