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 |