blob: b07b383781a3d584b155fcd4fcc8f5ee6fdd485c [file] [log] [blame]
chudy@google.com902ebe52012-06-29 14:21:22 +00001
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
robertphillips@google.comf4741c12013-02-06 20:13:54 +000010#include "SkColorPriv.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000011#include "SkDebugCanvas.h"
12#include "SkDrawCommand.h"
robertphillips@google.comf4741c12013-02-06 20:13:54 +000013#include "SkDrawFilter.h"
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +000014#include "SkDevice.h"
robertphillips@google.comf4741c12013-02-06 20:13:54 +000015#include "SkXfermode.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000016
robertphillipsa8d7f0b2014-08-29 08:03:56 -070017SkDebugCanvas::SkDebugCanvas(int windowWidth, int windowHeight)
18 : INHERITED(windowWidth, windowHeight)
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000019 , fPicture(NULL)
robertphillipsa8d7f0b2014-08-29 08:03:56 -070020 , fWindowSize(SkISize::Make(windowWidth, windowHeight))
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000021 , fFilter(false)
commit-bot@chromium.org768ac852014-03-03 16:32:17 +000022 , fMegaVizMode(false)
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000023 , fIndex(0)
robertphillips@google.comf4741c12013-02-06 20:13:54 +000024 , fOverdrawViz(false)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000025 , fOverdrawFilter(NULL)
robertphillips@google.com32bbcf82013-10-17 17:56:10 +000026 , fOverrideTexFiltering(false)
27 , fTexOverrideFilter(NULL)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000028 , fOutstandingSaveCount(0) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000029 fUserMatrix.reset();
robertphillips70171682014-10-16 14:28:28 -070030 fDrawNeedsReset = false;
robertphillips@google.com8b157172013-11-07 22:20:31 +000031
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);
robertphillips@google.com6c1e49a2013-11-10 15:08:45 +000043 SkRect large = SkRect::Make(largeIRect);
robertphillips@google.com8b157172013-11-07 22:20:31 +000044#ifdef SK_DEBUG
45 large.roundOut(&largeIRect);
46 SkASSERT(!largeIRect.isEmpty());
47#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +000048 // call the base class' version to avoid adding a draw command
49 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
chudy@google.com902ebe52012-06-29 14:21:22 +000050}
51
chudy@google.com9cda6f72012-08-07 15:08:33 +000052SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000053 fCommandVector.deleteAll();
robertphillips@google.comf4741c12013-02-06 20:13:54 +000054 SkSafeUnref(fOverdrawFilter);
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000055 SkSafeUnref(fTexOverrideFilter);
chudy@google.com9cda6f72012-08-07 15:08:33 +000056}
chudy@google.com902ebe52012-06-29 14:21:22 +000057
58void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000059 command->setOffset(this->getOpID());
robertphillips@google.com67baba42013-01-02 20:20:31 +000060 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000061}
62
63void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillipsb9750892014-10-21 10:31:38 -070064 fDrawNeedsReset = true;
65
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000066 if (!fCommandVector.isEmpty()) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000067 this->drawTo(canvas, fCommandVector.count() - 1);
chudy@google.com902ebe52012-06-29 14:21:22 +000068 }
69}
70
chudy@google.com830b8792012-08-01 15:57:52 +000071void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000072 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +000073}
74
75int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000076 SkBitmap bitmap;
reed@google.com9ebcac52014-01-24 18:53:42 +000077 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
chudy@google.com902ebe52012-06-29 14:21:22 +000078
chudy@google.com0b5bbb02012-07-31 19:55:32 +000079 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000080 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
robertphillipsa8d7f0b2014-08-29 08:03:56 -070081 this->applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000082
83 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000084 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000085 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000086 if (fCommandVector[i]->isVisible()) {
robertphillips70171682014-10-16 14:28:28 -070087 fCommandVector[i]->setUserMatrix(fUserMatrix);
robertphillips@google.com67baba42013-01-02 20:20:31 +000088 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000089 }
90 if (prev != bitmap.getColor(0,0)) {
91 layer = i;
92 }
93 prev = bitmap.getColor(0,0);
94 }
95 return layer;
96}
97
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +000098class OverdrawXfermode : public SkXfermode {
99public:
100 virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const SK_OVERRIDE {
101 // This table encodes the color progression of the overdraw visualization
102 static const SkPMColor gTable[] = {
103 SkPackARGB32(0x00, 0x00, 0x00, 0x00),
104 SkPackARGB32(0xFF, 128, 158, 255),
105 SkPackARGB32(0xFF, 170, 185, 212),
106 SkPackARGB32(0xFF, 213, 195, 170),
107 SkPackARGB32(0xFF, 255, 192, 127),
108 SkPackARGB32(0xFF, 255, 185, 85),
109 SkPackARGB32(0xFF, 255, 165, 42),
110 SkPackARGB32(0xFF, 255, 135, 0),
111 SkPackARGB32(0xFF, 255, 95, 0),
112 SkPackARGB32(0xFF, 255, 50, 0),
113 SkPackARGB32(0xFF, 255, 0, 0)
114 };
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000115
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000116 for (size_t i = 0; i < SK_ARRAY_COUNT(gTable)-1; ++i) {
117 if (gTable[i] == dst) {
118 return gTable[i+1];
119 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000120 }
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000121
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000122 return gTable[SK_ARRAY_COUNT(gTable)-1];
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000123 }
124
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000125 virtual Factory getFactory() const SK_OVERRIDE { return NULL; }
126#ifndef SK_IGNORE_TO_STRING
127 virtual void toString(SkString* str) const { str->set("OverdrawXfermode"); }
128#endif
129};
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000130
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000131class SkOverdrawFilter : public SkDrawFilter {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000132public:
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000133 SkOverdrawFilter() {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000134 fXferMode = SkNEW(OverdrawXfermode);
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000135 }
136
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000137 virtual ~SkOverdrawFilter() {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000138 delete fXferMode;
139 }
140
141 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
142 p->setXfermode(fXferMode);
143 return true;
144 }
145
146protected:
147 SkXfermode* fXferMode;
148
149private:
150 typedef SkDrawFilter INHERITED;
151};
152
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000153// SkTexOverrideFilter modifies every paint to use the specified
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000154// texture filtering mode
155class SkTexOverrideFilter : public SkDrawFilter {
156public:
157 SkTexOverrideFilter() : fFilterLevel(SkPaint::kNone_FilterLevel) {
158 }
159
160 void setFilterLevel(SkPaint::FilterLevel filterLevel) {
161 fFilterLevel = filterLevel;
162 }
163
164 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
165 p->setFilterLevel(fFilterLevel);
166 return true;
167 }
168
169protected:
170 SkPaint::FilterLevel fFilterLevel;
171
172private:
173 typedef SkDrawFilter INHERITED;
174};
175
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000176class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
177public:
178 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
179
180 virtual void clipRect(const SkRect& r, SkRegion::Op, bool doAA) SK_OVERRIDE {
181 SkPaint p;
182 p.setColor(SK_ColorRED);
183 p.setStyle(SkPaint::kStroke_Style);
184 p.setAntiAlias(doAA);
185 fCanvas->drawRect(r, p);
186 }
187 virtual void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) SK_OVERRIDE {
188 SkPaint p;
189 p.setColor(SK_ColorGREEN);
190 p.setStyle(SkPaint::kStroke_Style);
191 p.setAntiAlias(doAA);
192 fCanvas->drawRRect(rr, p);
193 }
194 virtual void clipPath(const SkPath& path, SkRegion::Op, bool doAA) SK_OVERRIDE {
195 SkPaint p;
196 p.setColor(SK_ColorBLUE);
197 p.setStyle(SkPaint::kStroke_Style);
198 p.setAntiAlias(doAA);
199 fCanvas->drawPath(path, p);
200 }
201
202protected:
203 SkCanvas* fCanvas;
204
205private:
206 typedef SkCanvas::ClipVisitor INHERITED;
207};
208
209// set up the saveLayer commands so that the active ones
210// return true in their 'active' method
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000211void SkDebugCanvas::markActiveCommands(int index) {
212 fActiveLayers.rewind();
213 fActiveCulls.rewind();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000214
215 for (int i = 0; i < fCommandVector.count(); ++i) {
216 fCommandVector[i]->setActive(false);
217 }
218
219 for (int i = 0; i < index; ++i) {
220 SkDrawCommand::Action result = fCommandVector[i]->action();
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000221 if (SkDrawCommand::kPushLayer_Action == result) {
222 fActiveLayers.push(fCommandVector[i]);
223 } else if (SkDrawCommand::kPopLayer_Action == result) {
224 fActiveLayers.pop();
225 } else if (SkDrawCommand::kPushCull_Action == result) {
226 fActiveCulls.push(fCommandVector[i]);
227 } else if (SkDrawCommand::kPopCull_Action == result) {
228 fActiveCulls.pop();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000229 }
230 }
231
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000232 for (int i = 0; i < fActiveLayers.count(); ++i) {
233 fActiveLayers[i]->setActive(true);
234 }
235
236 for (int i = 0; i < fActiveCulls.count(); ++i) {
237 fActiveCulls[i]->setActive(true);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000238 }
239}
240
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000241void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000242 SkASSERT(!fCommandVector.isEmpty());
243 SkASSERT(index < fCommandVector.count());
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000244 int i = 0;
chudy@google.com830b8792012-08-01 15:57:52 +0000245
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000246 bool pathOpsMode = getAllowSimplifyClip();
247 canvas->setAllowSimplifyClip(pathOpsMode);
chudy@google.com830b8792012-08-01 15:57:52 +0000248 // This only works assuming the canvas and device are the same ones that
249 // were previously drawn into because they need to preserve all saves
250 // and restores.
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000251 // The visibility filter also requires a full re-draw - otherwise we can
252 // end up drawing the filter repeatedly.
robertphillips70171682014-10-16 14:28:28 -0700253 if (fIndex < index && !fFilter && !fMegaVizMode && !pathOpsMode && !fDrawNeedsReset) {
chudy@google.com830b8792012-08-01 15:57:52 +0000254 i = fIndex + 1;
255 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000256 for (int j = 0; j < fOutstandingSaveCount; j++) {
257 canvas->restore();
258 }
junov@google.comdbfac8a2012-12-06 21:47:40 +0000259 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000260 canvas->resetMatrix();
robertphillips70171682014-10-16 14:28:28 -0700261 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWindowSize.fWidth),
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700262 SkIntToScalar(fWindowSize.fHeight));
263 canvas->clipRect(rect, SkRegion::kReplace_Op);
264 this->applyUserTransform(canvas);
robertphillips70171682014-10-16 14:28:28 -0700265 fDrawNeedsReset = false;
tomhudson@google.com0699e022012-11-27 16:09:42 +0000266 fOutstandingSaveCount = 0;
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000267 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000268
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000269 // The setting of the draw filter has to go here (rather than in
270 // SkRasterWidget) due to the canvas restores this class performs.
271 // Since the draw filter is stored in the layer stack if we
272 // call setDrawFilter on anything but the root layer odd things happen.
273 if (fOverdrawViz) {
274 if (NULL == fOverdrawFilter) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000275 fOverdrawFilter = new SkOverdrawFilter;
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000276 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000277
278 if (fOverdrawFilter != canvas->getDrawFilter()) {
279 canvas->setDrawFilter(fOverdrawFilter);
280 }
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000281 } else if (fOverrideTexFiltering) {
282 if (NULL == fTexOverrideFilter) {
283 fTexOverrideFilter = new SkTexOverrideFilter;
284 }
285
286 if (fTexOverrideFilter != canvas->getDrawFilter()) {
287 canvas->setDrawFilter(fTexOverrideFilter);
288 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000289 } else {
290 canvas->setDrawFilter(NULL);
chudy@google.com830b8792012-08-01 15:57:52 +0000291 }
292
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000293 if (fMegaVizMode) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000294 this->markActiveCommands(index);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000295 }
296
chudy@google.com830b8792012-08-01 15:57:52 +0000297 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000298 if (i == index && fFilter) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700299 canvas->clear(0xAAFFFFFF);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000300 }
301
robertphillips@google.com67baba42013-01-02 20:20:31 +0000302 if (fCommandVector[i]->isVisible()) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000303 if (fMegaVizMode && fCommandVector[i]->active()) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000304 // "active" commands execute their visualization behaviors:
305 // All active saveLayers get replaced with saves so all draws go to the
306 // visible canvas.
307 // All active culls draw their cull box
308 fCommandVector[i]->vizExecute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000309 } else {
robertphillips70171682014-10-16 14:28:28 -0700310 fCommandVector[i]->setUserMatrix(fUserMatrix);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000311 fCommandVector[i]->execute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000312 }
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000313
314 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000315 }
316 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000317
318 if (fMegaVizMode) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700319 SkRect r = SkRect::MakeWH(SkIntToScalar(fWindowSize.fWidth),
320 SkIntToScalar(fWindowSize.fHeight));
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000321 r.outset(SK_Scalar1, SK_Scalar1);
322
323 canvas->save();
324 // nuke the CTM
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700325 canvas->resetMatrix();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000326 // turn off clipping
327 canvas->clipRect(r, SkRegion::kReplace_Op);
328
329 // visualize existing clips
330 SkDebugClipVisitor visitor(canvas);
331
332 canvas->replayClips(&visitor);
333
334 canvas->restore();
335 }
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000336 if (pathOpsMode) {
337 this->resetClipStackData();
338 const SkClipStack* clipStack = canvas->getClipStack();
339 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
340 const SkClipStack::Element* element;
341 SkPath devPath;
342 while ((element = iter.next())) {
343 SkClipStack::Element::Type type = element->getType();
344 SkPath operand;
345 if (type != SkClipStack::Element::kEmpty_Type) {
346 element->asPath(&operand);
347 }
348 SkRegion::Op elementOp = element->getOp();
349 this->addClipStackData(devPath, operand, elementOp);
350 if (elementOp == SkRegion::kReplace_Op) {
351 devPath = operand;
352 } else {
353 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
354 }
355 }
356 this->lastClipStackData(devPath);
357 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000358 fMatrix = canvas->getTotalMatrix();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000359 if (!canvas->getClipDeviceBounds(&fClip)) {
360 fClip.setEmpty();
361 }
chudy@google.com830b8792012-08-01 15:57:52 +0000362 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000363}
364
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000365void SkDebugCanvas::deleteDrawCommandAt(int index) {
366 SkASSERT(index < fCommandVector.count());
367 delete fCommandVector[index];
368 fCommandVector.remove(index);
369}
370
chudy@google.com902ebe52012-06-29 14:21:22 +0000371SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000372 SkASSERT(index < fCommandVector.count());
373 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000374}
375
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000376void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
377 SkASSERT(index < fCommandVector.count());
378 delete fCommandVector[index];
379 fCommandVector[index] = command;
380}
381
fmalita8c89c522014-11-08 16:18:56 -0800382const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000383 SkASSERT(index < fCommandVector.count());
384 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000385}
chudy@google.com902ebe52012-06-29 14:21:22 +0000386
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000387bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000388 SkASSERT(index < fCommandVector.count());
389 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000390}
391
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000392const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000393 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000394}
395
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000396SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
397 return fCommandVector;
398}
399
chudy@google.com902ebe52012-06-29 14:21:22 +0000400// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000401SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000402 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
403 if (!fCommandVector.isEmpty()) {
404 for (int i = 0; i < fCommandVector.count(); i ++) {
405 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000406 }
407 }
408 return commandString;
409}
410
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000411SkTDArray<size_t>* SkDebugCanvas::getDrawCommandOffsets() const {
412 SkTDArray<size_t>* commandOffsets = new SkTDArray<size_t>;
413 if (!fCommandVector.isEmpty()) {
414 for (int i = 0; i < fCommandVector.count(); i ++) {
415 *commandOffsets->push() = fCommandVector[i]->offset();
416 }
417 }
418 return commandOffsets;
419}
420
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000421void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkPaint::FilterLevel level) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000422 if (NULL == fTexOverrideFilter) {
423 fTexOverrideFilter = new SkTexOverrideFilter;
424 }
425
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000426 fOverrideTexFiltering = overrideTexFiltering;
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000427 fTexOverrideFilter->setFilterLevel(level);
428}
429
chudy@google.com902ebe52012-06-29 14:21:22 +0000430void SkDebugCanvas::clear(SkColor color) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000431 this->addDrawCommand(new SkClearCommand(color));
chudy@google.com902ebe52012-06-29 14:21:22 +0000432}
433
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000434void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
435 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000436}
437
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000438void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
439 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000440}
441
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000442void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
443 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000444}
445
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000446void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
447 this->addDrawCommand(new SkClipRegionCommand(region, op));
chudy@google.com902ebe52012-06-29 14:21:22 +0000448}
449
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000450void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000451 switch (matrix.getType()) {
452 case SkMatrix::kTranslate_Mask:
453 this->addDrawCommand(new SkTranslateCommand(matrix.getTranslateX(),
454 matrix.getTranslateY()));
455 break;
456 case SkMatrix::kScale_Mask:
457 this->addDrawCommand(new SkScaleCommand(matrix.getScaleX(),
458 matrix.getScaleY()));
459 break;
460 default:
461 this->addDrawCommand(new SkConcatCommand(matrix));
462 break;
463 }
464
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000465 this->INHERITED::didConcat(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000466}
467
468void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000469 SkScalar top, const SkPaint* paint = NULL) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000470 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000471}
472
reed@google.com71121732012-09-18 15:14:33 +0000473void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
skia.committer@gmail.com74758112013-08-17 07:01:54 +0000474 const SkRect* src, const SkRect& dst,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000475 const SkPaint* paint,
476 SkCanvas::DrawBitmapRectFlags flags) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000477 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
chudy@google.com902ebe52012-06-29 14:21:22 +0000478}
479
480void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000481 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000482 this->addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000483}
484
485void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
486 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000487 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000488}
489
490void SkDebugCanvas::drawData(const void* data, size_t length) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000491 this->addDrawCommand(new SkDrawDataCommand(data, length));
chudy@google.com902ebe52012-06-29 14:21:22 +0000492}
493
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000494void SkDebugCanvas::beginCommentGroup(const char* description) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000495 this->addDrawCommand(new SkBeginCommentGroupCommand(description));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000496}
497
498void SkDebugCanvas::addComment(const char* kywd, const char* value) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000499 this->addDrawCommand(new SkCommentCommand(kywd, value));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000500}
501
502void SkDebugCanvas::endCommentGroup() {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000503 this->addDrawCommand(new SkEndCommentGroupCommand());
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000504}
505
robertphillips@google.com67baba42013-01-02 20:20:31 +0000506void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000507 this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000508}
509
chudy@google.com902ebe52012-06-29 14:21:22 +0000510void SkDebugCanvas::drawPaint(const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000511 this->addDrawCommand(new SkDrawPaintCommand(paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000512}
513
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000514void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000515 this->addDrawCommand(new SkDrawPathCommand(path, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000516}
517
robertphillipsb3f319f2014-08-13 10:46:23 -0700518void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
519 const SkMatrix* matrix,
520 const SkPaint* paint) {
521 this->addDrawCommand(new SkDrawPictureCommand(picture, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000522}
523
524void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
robertphillips@google.coma3a09ab2013-03-22 12:25:30 +0000525 const SkPoint pts[], const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000526 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000527}
528
reed@google.come0d9ce82014-04-23 04:00:17 +0000529void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
530 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000531 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000532}
533
reed@google.come0d9ce82014-04-23 04:00:17 +0000534void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
535 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000536 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000537 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000538}
539
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000540void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
chudy@google.com902ebe52012-06-29 14:21:22 +0000541 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000542 addDrawCommand(new SkDrawRectCommand(rect, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000543}
544
robertphillips@google.com67baba42013-01-02 20:20:31 +0000545void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000546 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000547}
548
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000549void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
550 const SkPaint& paint) {
commit-bot@chromium.org3d305202014-02-24 17:28:55 +0000551 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000552}
553
chudy@google.com902ebe52012-06-29 14:21:22 +0000554void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000555 const SkPaint* paint = NULL) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000556 this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000557}
558
reed@google.come0d9ce82014-04-23 04:00:17 +0000559void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
560 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000561 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000562}
563
reed@google.come0d9ce82014-04-23 04:00:17 +0000564void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
565 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000566 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000567 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000568}
569
fmalitab7425172014-08-26 07:56:44 -0700570void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
571 const SkPaint& paint) {
572 this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
573}
574
chudy@google.com902ebe52012-06-29 14:21:22 +0000575void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
576 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
577 SkXfermode*, const uint16_t indices[], int indexCount,
578 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000579 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
580 texs, colors, NULL, indices, indexCount, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000581}
582
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000583void SkDebugCanvas::onPushCull(const SkRect& cullRect) {
584 this->addDrawCommand(new SkPushCullCommand(cullRect));
585}
586
587void SkDebugCanvas::onPopCull() {
588 this->addDrawCommand(new SkPopCullCommand());
589}
590
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000591void SkDebugCanvas::willRestore() {
592 this->addDrawCommand(new SkRestoreCommand());
593 this->INHERITED::willRestore();
chudy@google.com902ebe52012-06-29 14:21:22 +0000594}
595
Florin Malita5f6102d2014-06-30 10:13:28 -0400596void SkDebugCanvas::willSave() {
597 this->addDrawCommand(new SkSaveCommand());
598 this->INHERITED::willSave();
chudy@google.com902ebe52012-06-29 14:21:22 +0000599}
600
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000601SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
602 SaveFlags flags) {
603 this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
604 this->INHERITED::willSaveLayer(bounds, paint, flags);
605 // No need for a full layer.
606 return kNoLayer_SaveLayerStrategy;
chudy@google.com902ebe52012-06-29 14:21:22 +0000607}
608
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000609void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000610 this->addDrawCommand(new SkSetMatrixCommand(matrix));
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000611 this->INHERITED::didSetMatrix(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000612}
613
chudy@google.com902ebe52012-06-29 14:21:22 +0000614void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000615 SkASSERT(index < fCommandVector.count());
616 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000617}
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000618
619static const char* gFillTypeStrs[] = {
620 "kWinding_FillType",
621 "kEvenOdd_FillType",
622 "kInverseWinding_FillType",
623 "kInverseEvenOdd_FillType"
624};
625
626static const char* gOpStrs[] = {
627 "kDifference_PathOp",
628 "kIntersect_PathOp",
629 "kUnion_PathOp",
630 "kXor_PathOp",
631 "kReverseDifference_PathOp",
632};
633
634static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
635
636void SkDebugCanvas::outputScalar(SkScalar num) {
637 if (num == (int) num) {
638 fClipStackData.appendf("%d", (int) num);
639 } else {
640 SkString str;
641 str.printf("%1.9g", num);
642 int width = (int) str.size();
643 const char* cStr = str.c_str();
644 while (cStr[width - 1] == '0') {
645 --width;
646 }
647 str.resize(width);
648 fClipStackData.appendf("%sf", str.c_str());
649 }
650}
651
652void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
653 for (int index = 0; index < count; ++index) {
654 this->outputScalar(pts[index].fX);
655 fClipStackData.appendf(", ");
656 this->outputScalar(pts[index].fY);
657 if (index + 1 < count) {
658 fClipStackData.appendf(", ");
659 }
660 }
661}
662
663void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
664 this->outputPointsCommon(pts, count);
665 fClipStackData.appendf(");<br>");
666}
667
668void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
669 this->outputPointsCommon(pts, 2);
670 fClipStackData.appendf(", ");
671 this->outputScalar(weight);
672 fClipStackData.appendf(");<br>");
673}
674
675void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
676 SkPath::RawIter iter(path);
677 SkPath::FillType fillType = path.getFillType();
678 fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
679 fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
680 gFillTypeStrs[fillType]);
681 iter.setPath(path);
682 uint8_t verb;
683 SkPoint pts[4];
684 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
685 switch (verb) {
686 case SkPath::kMove_Verb:
687 fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
688 this->outputPoints(&pts[0], 1);
689 continue;
690 case SkPath::kLine_Verb:
691 fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
692 this->outputPoints(&pts[1], 1);
693 break;
694 case SkPath::kQuad_Verb:
695 fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
696 this->outputPoints(&pts[1], 2);
697 break;
698 case SkPath::kConic_Verb:
699 fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
700 this->outputConicPoints(&pts[1], iter.conicWeight());
701 break;
702 case SkPath::kCubic_Verb:
703 fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
704 this->outputPoints(&pts[1], 3);
705 break;
706 case SkPath::kClose_Verb:
707 fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
708 break;
709 default:
710 SkDEBUGFAIL("bad verb");
711 return;
712 }
713 }
714}
715
716void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
717 SkRegion::Op elementOp) {
718 if (elementOp == SkRegion::kReplace_Op) {
719 if (!lastClipStackData(devPath)) {
720 fSaveDevPath = operand;
721 }
722 fCalledAddStackData = false;
723 } else {
724 fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
725 " const char* filename) {<br>");
726 addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
727 addPathData(operand, "pathB");
728 fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
729 kHTML4SpaceIndent, gOpStrs[elementOp]);
730 fClipStackData.appendf("}<br>");
731 fCalledAddStackData = true;
732 }
733}
734
735bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
736 if (fCalledAddStackData) {
737 fClipStackData.appendf("<br>");
738 addPathData(devPath, "pathOut");
739 return true;
740 }
741 return false;
742}