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