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