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