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