| OLD | NEW |
| 1 | 1 |
| 2 /* | 2 /* |
| 3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
| 4 * | 4 * |
| 5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
| 6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
| 7 */ | 7 */ |
| 8 | 8 |
| 9 | 9 |
| 10 #include "SkColorPriv.h" | 10 #include "SkColorPriv.h" |
| 11 #include "SkDebugCanvas.h" | 11 #include "SkDebugCanvas.h" |
| 12 #include "SkDrawCommand.h" | 12 #include "SkDrawCommand.h" |
| 13 #include "SkDrawFilter.h" | |
| 14 #include "SkDevice.h" | 13 #include "SkDevice.h" |
| 14 #include "SkPaintFilterCanvas.h" |
| 15 #include "SkXfermode.h" | 15 #include "SkXfermode.h" |
| 16 | 16 |
| 17 namespace { |
| 18 |
| 19 class OverdrawXfermode : public SkXfermode { |
| 20 public: |
| 21 SkPMColor xferColor(SkPMColor src, SkPMColor dst) const override { |
| 22 // This table encodes the color progression of the overdraw visualizatio
n |
| 23 static const SkPMColor gTable[] = { |
| 24 SkPackARGB32(0x00, 0x00, 0x00, 0x00), |
| 25 SkPackARGB32(0xFF, 128, 158, 255), |
| 26 SkPackARGB32(0xFF, 170, 185, 212), |
| 27 SkPackARGB32(0xFF, 213, 195, 170), |
| 28 SkPackARGB32(0xFF, 255, 192, 127), |
| 29 SkPackARGB32(0xFF, 255, 185, 85), |
| 30 SkPackARGB32(0xFF, 255, 165, 42), |
| 31 SkPackARGB32(0xFF, 255, 135, 0), |
| 32 SkPackARGB32(0xFF, 255, 95, 0), |
| 33 SkPackARGB32(0xFF, 255, 50, 0), |
| 34 SkPackARGB32(0xFF, 255, 0, 0) |
| 35 }; |
| 36 |
| 37 |
| 38 int idx; |
| 39 if (SkColorGetR(dst) < 64) { // 0 |
| 40 idx = 0; |
| 41 } else if (SkColorGetG(dst) < 25) { // 10 |
| 42 idx = 9; // cap at 9 for upcoming increment |
| 43 } else if ((SkColorGetB(dst)+21)/42 > 0) { // 1-6 |
| 44 idx = 7 - (SkColorGetB(dst)+21)/42; |
| 45 } else { // 7-9 |
| 46 idx = 10 - (SkColorGetG(dst)+22)/45; |
| 47 } |
| 48 ++idx; |
| 49 SkASSERT(idx < (int)SK_ARRAY_COUNT(gTable)); |
| 50 |
| 51 return gTable[idx]; |
| 52 } |
| 53 |
| 54 Factory getFactory() const override { return NULL; } |
| 55 #ifndef SK_IGNORE_TO_STRING |
| 56 virtual void toString(SkString* str) const override { str->set("OverdrawXfer
mode"); } |
| 57 #endif |
| 58 }; |
| 59 |
| 60 class DebugPaintFilterCanvas : public SkPaintFilterCanvas { |
| 61 public: |
| 62 DebugPaintFilterCanvas(int width, int height, bool overdrawViz, bool overrid
eFilterQuality, |
| 63 SkFilterQuality quality) |
| 64 : INHERITED(width, height) |
| 65 , fOverdrawXfermode(overdrawViz ? SkNEW(OverdrawXfermode) : NULL) |
| 66 , fOverrideFilterQuality(overrideFilterQuality) |
| 67 , fFilterQuality(quality) { } |
| 68 |
| 69 protected: |
| 70 void onFilterPaint(SkPaint* paint, Type) const override { |
| 71 if (NULL != fOverdrawXfermode.get()) { |
| 72 paint->setAntiAlias(false); |
| 73 paint->setXfermode(fOverdrawXfermode.get()); |
| 74 } |
| 75 |
| 76 if (fOverrideFilterQuality) { |
| 77 paint->setFilterQuality(fFilterQuality); |
| 78 } |
| 79 } |
| 80 |
| 81 void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const S
kPaint* paint) { |
| 82 // We need to replay the picture onto this canvas in order to filter its
internal paints. |
| 83 this->SkCanvas::onDrawPicture(picture, matrix, paint); |
| 84 } |
| 85 |
| 86 private: |
| 87 SkAutoTUnref<SkXfermode> fOverdrawXfermode; |
| 88 |
| 89 bool fOverrideFilterQuality; |
| 90 SkFilterQuality fFilterQuality; |
| 91 |
| 92 typedef SkPaintFilterCanvas INHERITED; |
| 93 }; |
| 94 |
| 95 } |
| 96 |
| 17 SkDebugCanvas::SkDebugCanvas(int width, int height) | 97 SkDebugCanvas::SkDebugCanvas(int width, int height) |
| 18 : INHERITED(width, height) | 98 : INHERITED(width, height) |
| 19 , fPicture(NULL) | 99 , fPicture(NULL) |
| 20 , fFilter(false) | 100 , fFilter(false) |
| 21 , fMegaVizMode(false) | 101 , fMegaVizMode(false) |
| 22 , fOverdrawViz(false) | 102 , fOverdrawViz(false) |
| 23 , fOverdrawFilter(NULL) | 103 , fOverrideFilterQuality(false) |
| 24 , fOverrideTexFiltering(false) | 104 , fFilterQuality(kNone_SkFilterQuality) { |
| 25 , fTexOverrideFilter(NULL) { | |
| 26 fUserMatrix.reset(); | 105 fUserMatrix.reset(); |
| 27 | 106 |
| 28 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped | 107 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped |
| 29 // operations. This can lead to problems in the debugger which expects all | 108 // operations. This can lead to problems in the debugger which expects all |
| 30 // the operations in the captured skp to appear in the debug canvas. To | 109 // the operations in the captured skp to appear in the debug canvas. To |
| 31 // circumvent this we create a wide open clip here (an empty clip rect | 110 // circumvent this we create a wide open clip here (an empty clip rect |
| 32 // is not sufficient). | 111 // is not sufficient). |
| 33 // Internally, the SkRect passed to clipRect is converted to an SkIRect and | 112 // Internally, the SkRect passed to clipRect is converted to an SkIRect and |
| 34 // rounded out. The following code creates a nearly maximal rect that will | 113 // rounded out. The following code creates a nearly maximal rect that will |
| 35 // not get collapsed by the coming conversions (Due to precision loss the | 114 // not get collapsed by the coming conversions (Due to precision loss the |
| 36 // inset has to be surprisingly large). | 115 // inset has to be surprisingly large). |
| 37 SkIRect largeIRect = SkIRect::MakeLargest(); | 116 SkIRect largeIRect = SkIRect::MakeLargest(); |
| 38 largeIRect.inset(1024, 1024); | 117 largeIRect.inset(1024, 1024); |
| 39 SkRect large = SkRect::Make(largeIRect); | 118 SkRect large = SkRect::Make(largeIRect); |
| 40 #ifdef SK_DEBUG | 119 #ifdef SK_DEBUG |
| 41 SkASSERT(!large.roundOut().isEmpty()); | 120 SkASSERT(!large.roundOut().isEmpty()); |
| 42 #endif | 121 #endif |
| 43 // call the base class' version to avoid adding a draw command | 122 // call the base class' version to avoid adding a draw command |
| 44 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyl
e); | 123 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyl
e); |
| 45 } | 124 } |
| 46 | 125 |
| 47 SkDebugCanvas::~SkDebugCanvas() { | 126 SkDebugCanvas::~SkDebugCanvas() { |
| 48 fCommandVector.deleteAll(); | 127 fCommandVector.deleteAll(); |
| 49 SkSafeUnref(fOverdrawFilter); | |
| 50 SkSafeUnref(fTexOverrideFilter); | |
| 51 } | 128 } |
| 52 | 129 |
| 53 void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) { | 130 void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) { |
| 54 command->setOffset(this->getOpID()); | 131 command->setOffset(this->getOpID()); |
| 55 fCommandVector.push(command); | 132 fCommandVector.push(command); |
| 56 } | 133 } |
| 57 | 134 |
| 58 void SkDebugCanvas::draw(SkCanvas* canvas) { | 135 void SkDebugCanvas::draw(SkCanvas* canvas) { |
| 59 if (!fCommandVector.isEmpty()) { | 136 if (!fCommandVector.isEmpty()) { |
| 60 this->drawTo(canvas, fCommandVector.count() - 1); | 137 this->drawTo(canvas, fCommandVector.count() - 1); |
| (...skipping 20 matching lines...) Expand all Loading... |
| 81 fCommandVector[i]->execute(&canvas); | 158 fCommandVector[i]->execute(&canvas); |
| 82 } | 159 } |
| 83 if (prev != bitmap.getColor(0,0)) { | 160 if (prev != bitmap.getColor(0,0)) { |
| 84 layer = i; | 161 layer = i; |
| 85 } | 162 } |
| 86 prev = bitmap.getColor(0,0); | 163 prev = bitmap.getColor(0,0); |
| 87 } | 164 } |
| 88 return layer; | 165 return layer; |
| 89 } | 166 } |
| 90 | 167 |
| 91 class OverdrawXfermode : public SkXfermode { | |
| 92 public: | |
| 93 SkPMColor xferColor(SkPMColor src, SkPMColor dst) const override { | |
| 94 // This table encodes the color progression of the overdraw visualizatio
n | |
| 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 | |
| 110 int idx; | |
| 111 if (SkColorGetR(dst) < 64) { // 0 | |
| 112 idx = 0; | |
| 113 } else if (SkColorGetG(dst) < 25) { // 10 | |
| 114 idx = 9; // cap at 9 for upcoming increment | |
| 115 } else if ((SkColorGetB(dst)+21)/42 > 0) { // 1-6 | |
| 116 idx = 7 - (SkColorGetB(dst)+21)/42; | |
| 117 } else { // 7-9 | |
| 118 idx = 10 - (SkColorGetG(dst)+22)/45; | |
| 119 } | |
| 120 ++idx; | |
| 121 SkASSERT(idx < (int)SK_ARRAY_COUNT(gTable)); | |
| 122 | |
| 123 return gTable[idx]; | |
| 124 } | |
| 125 | |
| 126 Factory getFactory() const override { return NULL; } | |
| 127 #ifndef SK_IGNORE_TO_STRING | |
| 128 virtual void toString(SkString* str) const override { str->set("OverdrawXfer
mode"); } | |
| 129 #endif | |
| 130 }; | |
| 131 | |
| 132 class SkOverdrawFilter : public SkDrawFilter { | |
| 133 public: | |
| 134 SkOverdrawFilter() { | |
| 135 fXferMode = SkNEW(OverdrawXfermode); | |
| 136 } | |
| 137 | |
| 138 virtual ~SkOverdrawFilter() { | |
| 139 delete fXferMode; | |
| 140 } | |
| 141 | |
| 142 bool filter(SkPaint* p, Type) override { | |
| 143 p->setXfermode(fXferMode); | |
| 144 p->setAntiAlias(false); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 protected: | |
| 149 SkXfermode* fXferMode; | |
| 150 | |
| 151 private: | |
| 152 typedef SkDrawFilter INHERITED; | |
| 153 }; | |
| 154 | |
| 155 // SkTexOverrideFilter modifies every paint to use the specified | |
| 156 // texture filtering mode | |
| 157 class SkTexOverrideFilter : public SkDrawFilter { | |
| 158 public: | |
| 159 SkTexOverrideFilter() : fFilterQuality(kNone_SkFilterQuality) { | |
| 160 } | |
| 161 | |
| 162 void setFilterQuality(SkFilterQuality filterQuality) { | |
| 163 fFilterQuality = filterQuality; | |
| 164 } | |
| 165 | |
| 166 bool filter(SkPaint* p, Type) override { | |
| 167 p->setFilterQuality(fFilterQuality); | |
| 168 return true; | |
| 169 } | |
| 170 | |
| 171 protected: | |
| 172 SkFilterQuality fFilterQuality; | |
| 173 | |
| 174 private: | |
| 175 typedef SkDrawFilter INHERITED; | |
| 176 }; | |
| 177 | |
| 178 class SkDebugClipVisitor : public SkCanvas::ClipVisitor { | 168 class SkDebugClipVisitor : public SkCanvas::ClipVisitor { |
| 179 public: | 169 public: |
| 180 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {} | 170 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {} |
| 181 | 171 |
| 182 void clipRect(const SkRect& r, SkRegion::Op, bool doAA) override { | 172 void clipRect(const SkRect& r, SkRegion::Op, bool doAA) override { |
| 183 SkPaint p; | 173 SkPaint p; |
| 184 p.setColor(SK_ColorRED); | 174 p.setColor(SK_ColorRED); |
| 185 p.setStyle(SkPaint::kStroke_Style); | 175 p.setStyle(SkPaint::kStroke_Style); |
| 186 p.setAntiAlias(doAA); | 176 p.setAntiAlias(doAA); |
| 187 fCanvas->drawRect(r, p); | 177 fCanvas->drawRect(r, p); |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 243 | 233 |
| 244 bool pathOpsMode = getAllowSimplifyClip(); | 234 bool pathOpsMode = getAllowSimplifyClip(); |
| 245 canvas->setAllowSimplifyClip(pathOpsMode); | 235 canvas->setAllowSimplifyClip(pathOpsMode); |
| 246 canvas->clear(SK_ColorTRANSPARENT); | 236 canvas->clear(SK_ColorTRANSPARENT); |
| 247 canvas->resetMatrix(); | 237 canvas->resetMatrix(); |
| 248 if (!windowRect.isEmpty()) { | 238 if (!windowRect.isEmpty()) { |
| 249 canvas->clipRect(windowRect, SkRegion::kReplace_Op); | 239 canvas->clipRect(windowRect, SkRegion::kReplace_Op); |
| 250 } | 240 } |
| 251 this->applyUserTransform(canvas); | 241 this->applyUserTransform(canvas); |
| 252 | 242 |
| 253 // The setting of the draw filter has to go here (rather than in | 243 if (fPaintFilterCanvas) { |
| 254 // SkRasterWidget) due to the canvas restores this class performs. | 244 fPaintFilterCanvas->addCanvas(canvas); |
| 255 // Since the draw filter is stored in the layer stack if we | 245 canvas = fPaintFilterCanvas.get(); |
| 256 // call setDrawFilter on anything but the root layer odd things happen. | |
| 257 if (fOverdrawViz) { | |
| 258 if (NULL == fOverdrawFilter) { | |
| 259 fOverdrawFilter = new SkOverdrawFilter; | |
| 260 } | |
| 261 | |
| 262 if (fOverdrawFilter != canvas->getDrawFilter()) { | |
| 263 canvas->setDrawFilter(fOverdrawFilter); | |
| 264 } | |
| 265 } else if (fOverrideTexFiltering) { | |
| 266 if (NULL == fTexOverrideFilter) { | |
| 267 fTexOverrideFilter = new SkTexOverrideFilter; | |
| 268 } | |
| 269 | |
| 270 if (fTexOverrideFilter != canvas->getDrawFilter()) { | |
| 271 canvas->setDrawFilter(fTexOverrideFilter); | |
| 272 } | |
| 273 } else { | |
| 274 canvas->setDrawFilter(NULL); | |
| 275 } | 246 } |
| 276 | 247 |
| 277 if (fMegaVizMode) { | 248 if (fMegaVizMode) { |
| 278 this->markActiveCommands(index); | 249 this->markActiveCommands(index); |
| 279 } | 250 } |
| 280 | 251 |
| 281 for (int i = 0; i <= index; i++) { | 252 for (int i = 0; i <= index; i++) { |
| 282 if (i == index && fFilter) { | 253 if (i == index && fFilter) { |
| 283 canvas->clear(0xAAFFFFFF); | 254 canvas->clear(0xAAFFFFFF); |
| 284 } | 255 } |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 335 } | 306 } |
| 336 } | 307 } |
| 337 this->lastClipStackData(devPath); | 308 this->lastClipStackData(devPath); |
| 338 } | 309 } |
| 339 fMatrix = canvas->getTotalMatrix(); | 310 fMatrix = canvas->getTotalMatrix(); |
| 340 if (!canvas->getClipDeviceBounds(&fClip)) { | 311 if (!canvas->getClipDeviceBounds(&fClip)) { |
| 341 fClip.setEmpty(); | 312 fClip.setEmpty(); |
| 342 } | 313 } |
| 343 | 314 |
| 344 canvas->restoreToCount(saveCount); | 315 canvas->restoreToCount(saveCount); |
| 316 |
| 317 if (fPaintFilterCanvas) { |
| 318 fPaintFilterCanvas->removeAll(); |
| 319 } |
| 345 } | 320 } |
| 346 | 321 |
| 347 void SkDebugCanvas::deleteDrawCommandAt(int index) { | 322 void SkDebugCanvas::deleteDrawCommandAt(int index) { |
| 348 SkASSERT(index < fCommandVector.count()); | 323 SkASSERT(index < fCommandVector.count()); |
| 349 delete fCommandVector[index]; | 324 delete fCommandVector[index]; |
| 350 fCommandVector.remove(index); | 325 fCommandVector.remove(index); |
| 351 } | 326 } |
| 352 | 327 |
| 353 SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) { | 328 SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) { |
| 354 SkASSERT(index < fCommandVector.count()); | 329 SkASSERT(index < fCommandVector.count()); |
| (...skipping 17 matching lines...) Expand all Loading... |
| 372 } | 347 } |
| 373 | 348 |
| 374 const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const { | 349 const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const { |
| 375 return fCommandVector; | 350 return fCommandVector; |
| 376 } | 351 } |
| 377 | 352 |
| 378 SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() { | 353 SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() { |
| 379 return fCommandVector; | 354 return fCommandVector; |
| 380 } | 355 } |
| 381 | 356 |
| 382 void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQual
ity quality) { | 357 void SkDebugCanvas::updatePaintFilterCanvas() { |
| 383 if (NULL == fTexOverrideFilter) { | 358 if (!fOverdrawViz && !fOverrideFilterQuality) { |
| 384 fTexOverrideFilter = new SkTexOverrideFilter; | 359 fPaintFilterCanvas.reset(NULL); |
| 360 return; |
| 385 } | 361 } |
| 386 | 362 |
| 387 fOverrideTexFiltering = overrideTexFiltering; | 363 const SkImageInfo info = this->imageInfo(); |
| 388 fTexOverrideFilter->setFilterQuality(quality); | 364 fPaintFilterCanvas.reset(SkNEW_ARGS(DebugPaintFilterCanvas, (info.width(), |
| 365 info.height(), |
| 366 fOverdrawViz, |
| 367 fOverrideFilter
Quality, |
| 368 fFilterQuality)
)); |
| 369 } |
| 370 |
| 371 void SkDebugCanvas::setOverdrawViz(bool overdrawViz) { |
| 372 if (fOverdrawViz == overdrawViz) { |
| 373 return; |
| 374 } |
| 375 |
| 376 fOverdrawViz = overdrawViz; |
| 377 this->updatePaintFilterCanvas(); |
| 378 } |
| 379 |
| 380 void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQual
ity quality) { |
| 381 if (fOverrideFilterQuality == overrideTexFiltering && fFilterQuality == qual
ity) { |
| 382 return; |
| 383 } |
| 384 |
| 385 fOverrideFilterQuality = overrideTexFiltering; |
| 386 fFilterQuality = quality; |
| 387 this->updatePaintFilterCanvas(); |
| 389 } | 388 } |
| 390 | 389 |
| 391 void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyl
e edgeStyle) { | 390 void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyl
e edgeStyle) { |
| 392 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle ==
edgeStyle)); | 391 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle ==
edgeStyle)); |
| 393 } | 392 } |
| 394 | 393 |
| 395 void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyl
e edgeStyle) { | 394 void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyl
e edgeStyle) { |
| 396 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle ==
edgeStyle)); | 395 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle ==
edgeStyle)); |
| 397 } | 396 } |
| 398 | 397 |
| (...skipping 274 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 } | 672 } |
| 674 | 673 |
| 675 bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) { | 674 bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) { |
| 676 if (fCalledAddStackData) { | 675 if (fCalledAddStackData) { |
| 677 fClipStackData.appendf("<br>"); | 676 fClipStackData.appendf("<br>"); |
| 678 addPathData(devPath, "pathOut"); | 677 addPathData(devPath, "pathOut"); |
| 679 return true; | 678 return true; |
| 680 } | 679 } |
| 681 return false; | 680 return false; |
| 682 } | 681 } |
| OLD | NEW |