SkDebugCanvas.cpp revision a27622c18de99fdb2c68e23b01006d3aa2bd1699
1cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
2cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)/*
3cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Copyright 2012 Google Inc.
4cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) *
5cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) * Use of this source code is governed by a BSD-style license that can be
61320f92c476a1ad9d19dba2a48c72b75566198e9Primiano Tucci * found in the LICENSE file.
7cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles) */
8cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
9cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
10cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkColorPriv.h"
11cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkDebugCanvas.h"
12cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkDrawCommand.h"
13cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkDrawFilter.h"
14cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkDevice.h"
15cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)#include "SkXfermode.h"
16cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
17cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)static SkBitmap make_noconfig_bm(int width, int height) {
18cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkBitmap bm;
19cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    bm.setConfig(SkBitmap::kNo_Config, width, height);
20cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    return bm;
21cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
22cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
23cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkDebugCanvas::SkDebugCanvas(int width, int height)
24cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        : INHERITED(make_noconfig_bm(width, height))
25cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        , fOverdrawViz(false)
26cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        , fOverdrawFilter(NULL)
27cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        , fOutstandingSaveCount(0) {
28cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // TODO(chudy): Free up memory from all draw commands in destructor.
29cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fWidth = width;
30cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fHeight = height;
31cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    // do we need fBm anywhere?
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fBm.setConfig(SkBitmap::kNo_Config, fWidth, fHeight);
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    fFilter = false;
34cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fIndex = 0;
35cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fUserMatrix.reset();
36cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
37cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
38cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)SkDebugCanvas::~SkDebugCanvas() {
39cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fCommandVector.deleteAll();
40cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    SkSafeUnref(fOverdrawFilter);
41cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
42cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
43cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
44cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    fCommandVector.push(command);
45cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)}
46cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)
47cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)void SkDebugCanvas::draw(SkCanvas* canvas) {
48cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)    if(!fCommandVector.isEmpty()) {
49cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        for (int i = 0; i < fCommandVector.count(); i++) {
50cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            if (fCommandVector[i]->isVisible()) {
51cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)                fCommandVector[i]->execute(canvas);
52cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)            }
53cedac228d2dd51db4b79ea1e72c7f249408ee061Torne (Richard Coles)        }
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, const SkPaint* paint) {
285    addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint));
286}
287
288void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
289        const SkMatrix& matrix, const SkPaint* paint) {
290    addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
291}
292
293void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
294        const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
295    addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
296}
297
298void SkDebugCanvas::drawData(const void* data, size_t length) {
299    addDrawCommand(new SkDrawDataCommand(data, length));
300}
301
302void SkDebugCanvas::beginCommentGroup(const char* description) {
303    addDrawCommand(new SkBeginCommentGroupCommand(description));
304}
305
306void SkDebugCanvas::addComment(const char* kywd, const char* value) {
307    addDrawCommand(new SkCommentCommand(kywd, value));
308}
309
310void SkDebugCanvas::endCommentGroup() {
311    addDrawCommand(new SkEndCommentGroupCommand());
312}
313
314void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
315    addDrawCommand(new SkDrawOvalCommand(oval, paint));
316}
317
318void SkDebugCanvas::drawPaint(const SkPaint& paint) {
319    addDrawCommand(new SkDrawPaintCommand(paint));
320}
321
322void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
323    addDrawCommand(new SkDrawPathCommand(path, paint));
324}
325
326void SkDebugCanvas::drawPicture(SkPicture& picture) {
327    addDrawCommand(new SkDrawPictureCommand(picture));
328}
329
330void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
331                               const SkPoint pts[], const SkPaint& paint) {
332    addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
333}
334
335void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
336        const SkPoint pos[], const SkPaint& paint) {
337    addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
338}
339
340void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
341        const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
342    addDrawCommand(
343        new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
344}
345
346void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
347    // NOTE(chudy): Messing up when renamed to DrawRect... Why?
348    addDrawCommand(new SkDrawRectCommand(rect, paint));
349}
350
351void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
352    addDrawCommand(new SkDrawRRectCommand(rrect, paint));
353}
354
355void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
356                               const SkPaint* paint = NULL) {
357    addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
358}
359
360void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
361        SkScalar y, const SkPaint& paint) {
362    addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
363}
364
365void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
366        const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
367    addDrawCommand(
368        new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
369}
370
371void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
372        const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
373        SkXfermode*, const uint16_t indices[], int indexCount,
374        const SkPaint& paint) {
375    addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
376                   texs, colors, NULL, indices, indexCount, paint));
377}
378
379void SkDebugCanvas::restore() {
380    addDrawCommand(new SkRestoreCommand());
381}
382
383bool SkDebugCanvas::rotate(SkScalar degrees) {
384    addDrawCommand(new SkRotateCommand(degrees));
385    return true;
386}
387
388int SkDebugCanvas::save(SaveFlags flags) {
389    addDrawCommand(new SkSaveCommand(flags));
390    return true;
391}
392
393int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
394        SaveFlags flags) {
395    addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
396    return true;
397}
398
399bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
400    addDrawCommand(new SkScaleCommand(sx, sy));
401    return true;
402}
403
404void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
405    addDrawCommand(new SkSetMatrixCommand(matrix));
406}
407
408bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
409    addDrawCommand(new SkSkewCommand(sx, sy));
410    return true;
411}
412
413bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
414    addDrawCommand(new SkTranslateCommand(dx, dy));
415    return true;
416}
417
418void SkDebugCanvas::toggleCommand(int index, bool toggle) {
419    SkASSERT(index < fCommandVector.count());
420    fCommandVector[index]->setVisible(toggle);
421}
422