SkDebugCanvas.cpp revision 44c48d062f7996b5b46917e1b312a32ad101f326
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    addDrawCommand(new SkConcatCommand(matrix));
414    this->INHERITED::didConcat(matrix);
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::willRestore() {
534    this->addDrawCommand(new SkRestoreCommand());
535    this->INHERITED::willRestore();
536}
537
538void SkDebugCanvas::didRotate(SkScalar degrees) {
539    addDrawCommand(new SkRotateCommand(degrees));
540    this->INHERITED::didRotate(degrees);
541}
542
543void SkDebugCanvas::willSave(SaveFlags flags) {
544    this->addDrawCommand(new SkSaveCommand(flags));
545    this->INHERITED::willSave(flags);
546}
547
548SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
549                                                         SaveFlags flags) {
550    this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
551    this->INHERITED::willSaveLayer(bounds, paint, flags);
552    // No need for a full layer.
553    return kNoLayer_SaveLayerStrategy;
554}
555
556void SkDebugCanvas::didScale(SkScalar sx, SkScalar sy) {
557    addDrawCommand(new SkScaleCommand(sx, sy));
558    this->INHERITED::didScale(sx, sy);
559}
560
561void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
562    addDrawCommand(new SkSetMatrixCommand(matrix));
563    this->INHERITED::didSetMatrix(matrix);
564}
565
566void SkDebugCanvas::didSkew(SkScalar sx, SkScalar sy) {
567    addDrawCommand(new SkSkewCommand(sx, sy));
568    this->INHERITED::didSkew(sx, sy);
569}
570
571void SkDebugCanvas::didTranslate(SkScalar dx, SkScalar dy) {
572    addDrawCommand(new SkTranslateCommand(dx, dy));
573    this->INHERITED::didTranslate(dx, dy);
574}
575
576void SkDebugCanvas::toggleCommand(int index, bool toggle) {
577    SkASSERT(index < fCommandVector.count());
578    fCommandVector[index]->setVisible(toggle);
579}
580