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