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