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