SkDebugCanvas.cpp revision 1643b2c9bc5adb4324bb459bb7811f58bc7c2d62
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    fClip = canvas->getTotalClip().getBounds();
332    fIndex = index;
333}
334
335void SkDebugCanvas::deleteDrawCommandAt(int index) {
336    SkASSERT(index < fCommandVector.count());
337    delete fCommandVector[index];
338    fCommandVector.remove(index);
339}
340
341SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
342    SkASSERT(index < fCommandVector.count());
343    return fCommandVector[index];
344}
345
346void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
347    SkASSERT(index < fCommandVector.count());
348    delete fCommandVector[index];
349    fCommandVector[index] = command;
350}
351
352SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
353    SkASSERT(index < fCommandVector.count());
354    return fCommandVector[index]->Info();
355}
356
357bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
358    SkASSERT(index < fCommandVector.count());
359    return fCommandVector[index]->isVisible();
360}
361
362const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
363    return fCommandVector;
364}
365
366SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
367    return fCommandVector;
368}
369
370// TODO(chudy): Free command string memory.
371SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
372    SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
373    if (!fCommandVector.isEmpty()) {
374        for (int i = 0; i < fCommandVector.count(); i ++) {
375            commandString->push_back() = fCommandVector[i]->toString();
376        }
377    }
378    return commandString;
379}
380
381void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkPaint::FilterLevel level) {
382    if (NULL == fTexOverrideFilter) {
383        fTexOverrideFilter = new SkTexOverrideFilter;
384    }
385
386    fOverrideTexFiltering = overrideTexFiltering;
387    fTexOverrideFilter->setFilterLevel(level);
388}
389
390void SkDebugCanvas::clear(SkColor color) {
391    addDrawCommand(new SkClearCommand(color));
392}
393
394void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
395    this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
396}
397
398void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
399    this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
400}
401
402void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
403    this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
404}
405
406void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
407    this->addDrawCommand(new SkClipRegionCommand(region, op));
408}
409
410bool SkDebugCanvas::concat(const SkMatrix& matrix) {
411    addDrawCommand(new SkConcatCommand(matrix));
412    return true;
413}
414
415void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
416                               SkScalar top, const SkPaint* paint = NULL) {
417    addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
418}
419
420void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
421                                         const SkRect* src, const SkRect& dst,
422                                         const SkPaint* paint,
423                                         SkCanvas::DrawBitmapRectFlags flags) {
424    addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
425}
426
427void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
428                                     const SkMatrix& matrix, const SkPaint* paint) {
429    addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
430}
431
432void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
433        const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
434    addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
435}
436
437void SkDebugCanvas::drawData(const void* data, size_t length) {
438    addDrawCommand(new SkDrawDataCommand(data, length));
439}
440
441void SkDebugCanvas::beginCommentGroup(const char* description) {
442    addDrawCommand(new SkBeginCommentGroupCommand(description));
443}
444
445void SkDebugCanvas::addComment(const char* kywd, const char* value) {
446    addDrawCommand(new SkCommentCommand(kywd, value));
447}
448
449void SkDebugCanvas::endCommentGroup() {
450    addDrawCommand(new SkEndCommentGroupCommand());
451}
452
453void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
454    addDrawCommand(new SkDrawOvalCommand(oval, paint));
455}
456
457void SkDebugCanvas::drawPaint(const SkPaint& paint) {
458    addDrawCommand(new SkDrawPaintCommand(paint));
459}
460
461void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
462    addDrawCommand(new SkDrawPathCommand(path, paint));
463}
464
465void SkDebugCanvas::drawPicture(SkPicture& picture) {
466    addDrawCommand(new SkDrawPictureCommand(picture));
467}
468
469void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
470                               const SkPoint pts[], const SkPaint& paint) {
471    addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
472}
473
474void SkDebugCanvas::drawPosText(const void* text, size_t byteLength,
475        const SkPoint pos[], const SkPaint& paint) {
476    addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
477}
478
479void SkDebugCanvas::drawPosTextH(const void* text, size_t byteLength,
480        const SkScalar xpos[], SkScalar constY, const SkPaint& paint) {
481    addDrawCommand(
482        new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
483}
484
485void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
486    // NOTE(chudy): Messing up when renamed to DrawRect... Why?
487    addDrawCommand(new SkDrawRectCommand(rect, paint));
488}
489
490void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
491    addDrawCommand(new SkDrawRRectCommand(rrect, paint));
492}
493
494void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
495                                 const SkPaint& paint) {
496    this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
497}
498
499void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
500                               const SkPaint* paint = NULL) {
501    addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
502}
503
504void SkDebugCanvas::drawText(const void* text, size_t byteLength, SkScalar x,
505        SkScalar y, const SkPaint& paint) {
506    addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
507}
508
509void SkDebugCanvas::drawTextOnPath(const void* text, size_t byteLength,
510        const SkPath& path, const SkMatrix* matrix, const SkPaint& paint) {
511    addDrawCommand(
512        new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
513}
514
515void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
516        const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
517        SkXfermode*, const uint16_t indices[], int indexCount,
518        const SkPaint& paint) {
519    addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
520                   texs, colors, NULL, indices, indexCount, paint));
521}
522
523void SkDebugCanvas::onPushCull(const SkRect& cullRect) {
524    this->addDrawCommand(new SkPushCullCommand(cullRect));
525}
526
527void SkDebugCanvas::onPopCull() {
528    this->addDrawCommand(new SkPopCullCommand());
529}
530
531void SkDebugCanvas::restore() {
532    addDrawCommand(new SkRestoreCommand());
533}
534
535bool SkDebugCanvas::rotate(SkScalar degrees) {
536    addDrawCommand(new SkRotateCommand(degrees));
537    return true;
538}
539
540int SkDebugCanvas::save(SaveFlags flags) {
541    addDrawCommand(new SkSaveCommand(flags));
542    return true;
543}
544
545int SkDebugCanvas::saveLayer(const SkRect* bounds, const SkPaint* paint,
546        SaveFlags flags) {
547    addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
548    return true;
549}
550
551bool SkDebugCanvas::scale(SkScalar sx, SkScalar sy) {
552    addDrawCommand(new SkScaleCommand(sx, sy));
553    return true;
554}
555
556void SkDebugCanvas::setMatrix(const SkMatrix& matrix) {
557    addDrawCommand(new SkSetMatrixCommand(matrix));
558}
559
560bool SkDebugCanvas::skew(SkScalar sx, SkScalar sy) {
561    addDrawCommand(new SkSkewCommand(sx, sy));
562    return true;
563}
564
565bool SkDebugCanvas::translate(SkScalar dx, SkScalar dy) {
566    addDrawCommand(new SkTranslateCommand(dx, dy));
567    return true;
568}
569
570void SkDebugCanvas::toggleCommand(int index, bool toggle) {
571    SkASSERT(index < fCommandVector.count());
572    fCommandVector[index]->setVisible(toggle);
573}
574