SkDebugCanvas.cpp revision d9ea09e1f29b303e6fa36079e99729d2951925b9
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
412void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
413    switch (matrix.getType()) {
414        case SkMatrix::kTranslate_Mask:
415            this->addDrawCommand(new SkTranslateCommand(matrix.getTranslateX(),
416                                                        matrix.getTranslateY()));
417            break;
418        case SkMatrix::kScale_Mask:
419            this->addDrawCommand(new SkScaleCommand(matrix.getScaleX(),
420                                                    matrix.getScaleY()));
421            break;
422        default:
423            this->addDrawCommand(new SkConcatCommand(matrix));
424            break;
425    }
426
427    this->INHERITED::didConcat(matrix);
428}
429
430void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
431                               SkScalar top, const SkPaint* paint = NULL) {
432    addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
433}
434
435void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
436                                         const SkRect* src, const SkRect& dst,
437                                         const SkPaint* paint,
438                                         SkCanvas::DrawBitmapRectFlags flags) {
439    addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
440}
441
442void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
443                                     const SkMatrix& matrix, const SkPaint* paint) {
444    addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
445}
446
447void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
448        const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
449    addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
450}
451
452void SkDebugCanvas::drawData(const void* data, size_t length) {
453    addDrawCommand(new SkDrawDataCommand(data, length));
454}
455
456void SkDebugCanvas::beginCommentGroup(const char* description) {
457    addDrawCommand(new SkBeginCommentGroupCommand(description));
458}
459
460void SkDebugCanvas::addComment(const char* kywd, const char* value) {
461    addDrawCommand(new SkCommentCommand(kywd, value));
462}
463
464void SkDebugCanvas::endCommentGroup() {
465    addDrawCommand(new SkEndCommentGroupCommand());
466}
467
468void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
469    addDrawCommand(new SkDrawOvalCommand(oval, paint));
470}
471
472void SkDebugCanvas::drawPaint(const SkPaint& paint) {
473    addDrawCommand(new SkDrawPaintCommand(paint));
474}
475
476void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
477    addDrawCommand(new SkDrawPathCommand(path, paint));
478}
479
480void SkDebugCanvas::drawPicture(SkPicture& picture) {
481    addDrawCommand(new SkDrawPictureCommand(picture));
482}
483
484void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
485                               const SkPoint pts[], const SkPaint& paint) {
486    addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
487}
488
489void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
490        const SkPoint pos[], const SkPaint& paint) {
491    addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
492}
493
494void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
495        const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
496    addDrawCommand(
497        new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
498}
499
500void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
501    // NOTE(chudy): Messing up when renamed to DrawRect... Why?
502    addDrawCommand(new SkDrawRectCommand(rect, paint));
503}
504
505void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
506    addDrawCommand(new SkDrawRRectCommand(rrect, paint));
507}
508
509void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
510                                 const SkPaint& paint) {
511    this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
512}
513
514void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
515                               const SkPaint* paint = NULL) {
516    addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
517}
518
519void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
520        SkScalar y, const SkPaint& paint) {
521    addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
522}
523
524void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
525        const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
526    addDrawCommand(
527        new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
528}
529
530void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
531        const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
532        SkXfermode*, const uint16_t indices[], int indexCount,
533        const SkPaint& paint) {
534    addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
535                   texs, colors, NULL, indices, indexCount, paint));
536}
537
538void SkDebugCanvas::onPushCull(const SkRect& cullRect) {
539    this->addDrawCommand(new SkPushCullCommand(cullRect));
540}
541
542void SkDebugCanvas::onPopCull() {
543    this->addDrawCommand(new SkPopCullCommand());
544}
545
546void SkDebugCanvas::willRestore() {
547    this->addDrawCommand(new SkRestoreCommand());
548    this->INHERITED::willRestore();
549}
550
551void SkDebugCanvas::willSave(SaveFlags flags) {
552    this->addDrawCommand(new SkSaveCommand(flags));
553    this->INHERITED::willSave(flags);
554}
555
556SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
557                                                         SaveFlags flags) {
558    this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
559    this->INHERITED::willSaveLayer(bounds, paint, flags);
560    // No need for a full layer.
561    return kNoLayer_SaveLayerStrategy;
562}
563
564void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
565    addDrawCommand(new SkSetMatrixCommand(matrix));
566    this->INHERITED::didSetMatrix(matrix);
567}
568
569void SkDebugCanvas::toggleCommand(int index, bool toggle) {
570    SkASSERT(index < fCommandVector.count());
571    fCommandVector[index]->setVisible(toggle);
572}
573