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