blob: 277e86d84ddb519126ed8f59375905e5a21ce4f4 [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
reed@google.com6ae24e02012-09-26 13:44:13 +000017SkDebugCanvas::SkDebugCanvas(int width, int height)
commit-bot@chromium.orge2543102014-01-31 19:42:58 +000018 : INHERITED(width, height)
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000019 , fPicture(NULL)
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000020 , fWidth(width)
21 , fHeight(height)
22 , fFilter(false)
commit-bot@chromium.org768ac852014-03-03 16:32:17 +000023 , fMegaVizMode(false)
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000024 , fIndex(0)
robertphillips@google.comf4741c12013-02-06 20:13:54 +000025 , fOverdrawViz(false)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000026 , fOverdrawFilter(NULL)
robertphillips@google.com32bbcf82013-10-17 17:56:10 +000027 , fOverrideTexFiltering(false)
28 , fTexOverrideFilter(NULL)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000029 , fOutstandingSaveCount(0) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000030 fUserMatrix.reset();
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) {
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000064 if (!fCommandVector.isEmpty()) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000065 this->drawTo(canvas, fCommandVector.count() - 1);
chudy@google.com902ebe52012-06-29 14:21:22 +000066 }
67}
68
chudy@google.com830b8792012-08-01 15:57:52 +000069void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000070 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +000071}
72
73int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +000074 SkBitmap bitmap;
reed@google.com9ebcac52014-01-24 18:53:42 +000075 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
chudy@google.com902ebe52012-06-29 14:21:22 +000076
chudy@google.com0b5bbb02012-07-31 19:55:32 +000077 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +000078 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
chudy@google.com830b8792012-08-01 15:57:52 +000079 applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000080
81 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +000082 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000083 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000084 if (fCommandVector[i]->isVisible()) {
85 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000086 }
87 if (prev != bitmap.getColor(0,0)) {
88 layer = i;
89 }
90 prev = bitmap.getColor(0,0);
91 }
92 return layer;
93}
94
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +000095class OverdrawXfermode : public SkXfermode {
96public:
97 virtual SkPMColor xferColor(SkPMColor src, SkPMColor dst) const SK_OVERRIDE {
98 // This table encodes the color progression of the overdraw visualization
99 static const SkPMColor gTable[] = {
100 SkPackARGB32(0x00, 0x00, 0x00, 0x00),
101 SkPackARGB32(0xFF, 128, 158, 255),
102 SkPackARGB32(0xFF, 170, 185, 212),
103 SkPackARGB32(0xFF, 213, 195, 170),
104 SkPackARGB32(0xFF, 255, 192, 127),
105 SkPackARGB32(0xFF, 255, 185, 85),
106 SkPackARGB32(0xFF, 255, 165, 42),
107 SkPackARGB32(0xFF, 255, 135, 0),
108 SkPackARGB32(0xFF, 255, 95, 0),
109 SkPackARGB32(0xFF, 255, 50, 0),
110 SkPackARGB32(0xFF, 255, 0, 0)
111 };
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000112
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000113 for (size_t i = 0; i < SK_ARRAY_COUNT(gTable)-1; ++i) {
114 if (gTable[i] == dst) {
115 return gTable[i+1];
116 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000117 }
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000118
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000119 return gTable[SK_ARRAY_COUNT(gTable)-1];
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000120 }
121
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000122 virtual Factory getFactory() const SK_OVERRIDE { return NULL; }
123#ifndef SK_IGNORE_TO_STRING
124 virtual void toString(SkString* str) const { str->set("OverdrawXfermode"); }
125#endif
126};
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000127
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000128class SkOverdrawFilter : public SkDrawFilter {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000129public:
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000130 SkOverdrawFilter() {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000131 fXferMode = SkNEW(OverdrawXfermode);
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000132 }
133
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000134 virtual ~SkOverdrawFilter() {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000135 delete fXferMode;
136 }
137
138 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
139 p->setXfermode(fXferMode);
140 return true;
141 }
142
143protected:
144 SkXfermode* fXferMode;
145
146private:
147 typedef SkDrawFilter INHERITED;
148};
149
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000150// SkTexOverrideFilter modifies every paint to use the specified
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000151// texture filtering mode
152class SkTexOverrideFilter : public SkDrawFilter {
153public:
154 SkTexOverrideFilter() : fFilterLevel(SkPaint::kNone_FilterLevel) {
155 }
156
157 void setFilterLevel(SkPaint::FilterLevel filterLevel) {
158 fFilterLevel = filterLevel;
159 }
160
161 virtual bool filter(SkPaint* p, Type) SK_OVERRIDE {
162 p->setFilterLevel(fFilterLevel);
163 return true;
164 }
165
166protected:
167 SkPaint::FilterLevel fFilterLevel;
168
169private:
170 typedef SkDrawFilter INHERITED;
171};
172
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000173class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
174public:
175 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
176
177 virtual void clipRect(const SkRect& r, SkRegion::Op, bool doAA) SK_OVERRIDE {
178 SkPaint p;
179 p.setColor(SK_ColorRED);
180 p.setStyle(SkPaint::kStroke_Style);
181 p.setAntiAlias(doAA);
182 fCanvas->drawRect(r, p);
183 }
184 virtual void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) SK_OVERRIDE {
185 SkPaint p;
186 p.setColor(SK_ColorGREEN);
187 p.setStyle(SkPaint::kStroke_Style);
188 p.setAntiAlias(doAA);
189 fCanvas->drawRRect(rr, p);
190 }
191 virtual void clipPath(const SkPath& path, SkRegion::Op, bool doAA) SK_OVERRIDE {
192 SkPaint p;
193 p.setColor(SK_ColorBLUE);
194 p.setStyle(SkPaint::kStroke_Style);
195 p.setAntiAlias(doAA);
196 fCanvas->drawPath(path, p);
197 }
198
199protected:
200 SkCanvas* fCanvas;
201
202private:
203 typedef SkCanvas::ClipVisitor INHERITED;
204};
205
206// set up the saveLayer commands so that the active ones
207// return true in their 'active' method
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000208void SkDebugCanvas::markActiveCommands(int index) {
209 fActiveLayers.rewind();
210 fActiveCulls.rewind();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000211
212 for (int i = 0; i < fCommandVector.count(); ++i) {
213 fCommandVector[i]->setActive(false);
214 }
215
216 for (int i = 0; i < index; ++i) {
217 SkDrawCommand::Action result = fCommandVector[i]->action();
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000218 if (SkDrawCommand::kPushLayer_Action == result) {
219 fActiveLayers.push(fCommandVector[i]);
220 } else if (SkDrawCommand::kPopLayer_Action == result) {
221 fActiveLayers.pop();
222 } else if (SkDrawCommand::kPushCull_Action == result) {
223 fActiveCulls.push(fCommandVector[i]);
224 } else if (SkDrawCommand::kPopCull_Action == result) {
225 fActiveCulls.pop();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000226 }
227 }
228
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000229 for (int i = 0; i < fActiveLayers.count(); ++i) {
230 fActiveLayers[i]->setActive(true);
231 }
232
233 for (int i = 0; i < fActiveCulls.count(); ++i) {
234 fActiveCulls[i]->setActive(true);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000235 }
236}
237
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000238void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000239 SkASSERT(!fCommandVector.isEmpty());
240 SkASSERT(index < fCommandVector.count());
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000241 int i = 0;
chudy@google.com830b8792012-08-01 15:57:52 +0000242
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000243 bool pathOpsMode = getAllowSimplifyClip();
244 canvas->setAllowSimplifyClip(pathOpsMode);
chudy@google.com830b8792012-08-01 15:57:52 +0000245 // This only works assuming the canvas and device are the same ones that
246 // were previously drawn into because they need to preserve all saves
247 // and restores.
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000248 // The visibility filter also requires a full re-draw - otherwise we can
249 // end up drawing the filter repeatedly.
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000250 if (fIndex < index && !fFilter && !fMegaVizMode && !pathOpsMode) {
chudy@google.com830b8792012-08-01 15:57:52 +0000251 i = fIndex + 1;
252 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000253 for (int j = 0; j < fOutstandingSaveCount; j++) {
254 canvas->restore();
255 }
junov@google.comdbfac8a2012-12-06 21:47:40 +0000256 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000257 canvas->resetMatrix();
skia.committer@gmail.com04ba4482012-09-07 02:01:30 +0000258 SkRect rect = SkRect::MakeWH(SkIntToScalar(fWidth),
robertphillips@google.com94acc702012-09-06 18:43:21 +0000259 SkIntToScalar(fHeight));
chudy@google.com4c7962e2012-08-14 19:38:31 +0000260 canvas->clipRect(rect, SkRegion::kReplace_Op );
chudy@google.com830b8792012-08-01 15:57:52 +0000261 applyUserTransform(canvas);
tomhudson@google.com0699e022012-11-27 16:09:42 +0000262 fOutstandingSaveCount = 0;
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000263 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000264
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000265 // The setting of the draw filter has to go here (rather than in
266 // SkRasterWidget) due to the canvas restores this class performs.
267 // Since the draw filter is stored in the layer stack if we
268 // call setDrawFilter on anything but the root layer odd things happen.
269 if (fOverdrawViz) {
270 if (NULL == fOverdrawFilter) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000271 fOverdrawFilter = new SkOverdrawFilter;
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000272 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000273
274 if (fOverdrawFilter != canvas->getDrawFilter()) {
275 canvas->setDrawFilter(fOverdrawFilter);
276 }
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000277 } else if (fOverrideTexFiltering) {
278 if (NULL == fTexOverrideFilter) {
279 fTexOverrideFilter = new SkTexOverrideFilter;
280 }
281
282 if (fTexOverrideFilter != canvas->getDrawFilter()) {
283 canvas->setDrawFilter(fTexOverrideFilter);
284 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000285 } else {
286 canvas->setDrawFilter(NULL);
chudy@google.com830b8792012-08-01 15:57:52 +0000287 }
288
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000289 if (fMegaVizMode) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000290 this->markActiveCommands(index);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000291 }
292
chudy@google.com830b8792012-08-01 15:57:52 +0000293 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000294 if (i == index && fFilter) {
295 SkPaint p;
296 p.setColor(0xAAFFFFFF);
297 canvas->save();
298 canvas->resetMatrix();
299 SkRect mask;
300 mask.set(SkIntToScalar(0), SkIntToScalar(0),
301 SkIntToScalar(fWidth), SkIntToScalar(fHeight));
302 canvas->clipRect(mask, SkRegion::kReplace_Op, false);
303 canvas->drawRectCoords(SkIntToScalar(0), SkIntToScalar(0),
304 SkIntToScalar(fWidth), SkIntToScalar(fHeight), p);
305 canvas->restore();
306 }
307
robertphillips@google.com67baba42013-01-02 20:20:31 +0000308 if (fCommandVector[i]->isVisible()) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000309 if (fMegaVizMode && fCommandVector[i]->active()) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000310 // "active" commands execute their visualization behaviors:
311 // All active saveLayers get replaced with saves so all draws go to the
312 // visible canvas.
313 // All active culls draw their cull box
314 fCommandVector[i]->vizExecute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000315 } else {
316 fCommandVector[i]->execute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000317 }
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000318
319 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000320 }
321 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000322
323 if (fMegaVizMode) {
324 SkRect r = SkRect::MakeWH(SkIntToScalar(fWidth), SkIntToScalar(fHeight));
325 r.outset(SK_Scalar1, SK_Scalar1);
326
327 canvas->save();
328 // nuke the CTM
329 canvas->setMatrix(SkMatrix::I());
330 // turn off clipping
331 canvas->clipRect(r, SkRegion::kReplace_Op);
332
333 // visualize existing clips
334 SkDebugClipVisitor visitor(canvas);
335
336 canvas->replayClips(&visitor);
337
338 canvas->restore();
339 }
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000340 if (pathOpsMode) {
341 this->resetClipStackData();
342 const SkClipStack* clipStack = canvas->getClipStack();
343 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
344 const SkClipStack::Element* element;
345 SkPath devPath;
346 while ((element = iter.next())) {
347 SkClipStack::Element::Type type = element->getType();
348 SkPath operand;
349 if (type != SkClipStack::Element::kEmpty_Type) {
350 element->asPath(&operand);
351 }
352 SkRegion::Op elementOp = element->getOp();
353 this->addClipStackData(devPath, operand, elementOp);
354 if (elementOp == SkRegion::kReplace_Op) {
355 devPath = operand;
356 } else {
357 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
358 }
359 }
360 this->lastClipStackData(devPath);
361 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000362 fMatrix = canvas->getTotalMatrix();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000363 if (!canvas->getClipDeviceBounds(&fClip)) {
364 fClip.setEmpty();
365 }
chudy@google.com830b8792012-08-01 15:57:52 +0000366 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000367}
368
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000369void SkDebugCanvas::deleteDrawCommandAt(int index) {
370 SkASSERT(index < fCommandVector.count());
371 delete fCommandVector[index];
372 fCommandVector.remove(index);
373}
374
chudy@google.com902ebe52012-06-29 14:21:22 +0000375SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000376 SkASSERT(index < fCommandVector.count());
377 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000378}
379
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000380void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
381 SkASSERT(index < fCommandVector.count());
382 delete fCommandVector[index];
383 fCommandVector[index] = command;
384}
385
chudy@google.com97cee972012-08-07 20:41:37 +0000386SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000387 SkASSERT(index < fCommandVector.count());
388 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000389}
chudy@google.com902ebe52012-06-29 14:21:22 +0000390
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000391bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000392 SkASSERT(index < fCommandVector.count());
393 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000394}
395
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000396const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000397 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000398}
399
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000400SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
401 return fCommandVector;
402}
403
chudy@google.com902ebe52012-06-29 14:21:22 +0000404// TODO(chudy): Free command string memory.
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000405SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000406 SkTArray<SkString>* commandString = new SkTArray<SkString>(fCommandVector.count());
407 if (!fCommandVector.isEmpty()) {
408 for (int i = 0; i < fCommandVector.count(); i ++) {
409 commandString->push_back() = fCommandVector[i]->toString();
chudy@google.com902ebe52012-06-29 14:21:22 +0000410 }
411 }
412 return commandString;
413}
414
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000415SkTDArray<size_t>* SkDebugCanvas::getDrawCommandOffsets() const {
416 SkTDArray<size_t>* commandOffsets = new SkTDArray<size_t>;
417 if (!fCommandVector.isEmpty()) {
418 for (int i = 0; i < fCommandVector.count(); i ++) {
419 *commandOffsets->push() = fCommandVector[i]->offset();
420 }
421 }
422 return commandOffsets;
423}
424
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000425void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkPaint::FilterLevel level) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000426 if (NULL == fTexOverrideFilter) {
427 fTexOverrideFilter = new SkTexOverrideFilter;
428 }
429
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000430 fOverrideTexFiltering = overrideTexFiltering;
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000431 fTexOverrideFilter->setFilterLevel(level);
432}
433
chudy@google.com902ebe52012-06-29 14:21:22 +0000434void SkDebugCanvas::clear(SkColor color) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000435 this->addDrawCommand(new SkClearCommand(color));
chudy@google.com902ebe52012-06-29 14:21:22 +0000436}
437
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000438void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
439 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000440}
441
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000442void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
443 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000444}
445
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000446void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
447 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000448}
449
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000450void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
451 this->addDrawCommand(new SkClipRegionCommand(region, op));
chudy@google.com902ebe52012-06-29 14:21:22 +0000452}
453
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000454void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000455 switch (matrix.getType()) {
456 case SkMatrix::kTranslate_Mask:
457 this->addDrawCommand(new SkTranslateCommand(matrix.getTranslateX(),
458 matrix.getTranslateY()));
459 break;
460 case SkMatrix::kScale_Mask:
461 this->addDrawCommand(new SkScaleCommand(matrix.getScaleX(),
462 matrix.getScaleY()));
463 break;
464 default:
465 this->addDrawCommand(new SkConcatCommand(matrix));
466 break;
467 }
468
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000469 this->INHERITED::didConcat(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000470}
471
472void SkDebugCanvas::drawBitmap(const SkBitmap& bitmap, SkScalar left,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000473 SkScalar top, const SkPaint* paint = NULL) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000474 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000475}
476
reed@google.com71121732012-09-18 15:14:33 +0000477void SkDebugCanvas::drawBitmapRectToRect(const SkBitmap& bitmap,
skia.committer@gmail.com74758112013-08-17 07:01:54 +0000478 const SkRect* src, const SkRect& dst,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000479 const SkPaint* paint,
480 SkCanvas::DrawBitmapRectFlags flags) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000481 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
chudy@google.com902ebe52012-06-29 14:21:22 +0000482}
483
484void SkDebugCanvas::drawBitmapMatrix(const SkBitmap& bitmap,
commit-bot@chromium.orgeed779d2013-08-16 10:24:37 +0000485 const SkMatrix& matrix, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000486 this->addDrawCommand(new SkDrawBitmapMatrixCommand(bitmap, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000487}
488
489void SkDebugCanvas::drawBitmapNine(const SkBitmap& bitmap,
490 const SkIRect& center, const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000491 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000492}
493
494void SkDebugCanvas::drawData(const void* data, size_t length) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000495 this->addDrawCommand(new SkDrawDataCommand(data, length));
chudy@google.com902ebe52012-06-29 14:21:22 +0000496}
497
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000498void SkDebugCanvas::beginCommentGroup(const char* description) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000499 this->addDrawCommand(new SkBeginCommentGroupCommand(description));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000500}
501
502void SkDebugCanvas::addComment(const char* kywd, const char* value) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000503 this->addDrawCommand(new SkCommentCommand(kywd, value));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000504}
505
506void SkDebugCanvas::endCommentGroup() {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000507 this->addDrawCommand(new SkEndCommentGroupCommand());
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000508}
509
robertphillips@google.com67baba42013-01-02 20:20:31 +0000510void SkDebugCanvas::drawOval(const SkRect& oval, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000511 this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000512}
513
chudy@google.com902ebe52012-06-29 14:21:22 +0000514void SkDebugCanvas::drawPaint(const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000515 this->addDrawCommand(new SkDrawPaintCommand(paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000516}
517
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000518void SkDebugCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000519 this->addDrawCommand(new SkDrawPathCommand(path, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000520}
521
robertphillips9b14f262014-06-04 05:40:44 -0700522void SkDebugCanvas::onDrawPicture(const SkPicture* picture) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000523 this->addDrawCommand(new SkDrawPictureCommand(picture));
chudy@google.com902ebe52012-06-29 14:21:22 +0000524}
525
526void SkDebugCanvas::drawPoints(PointMode mode, size_t count,
robertphillips@google.coma3a09ab2013-03-22 12:25:30 +0000527 const SkPoint pts[], const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000528 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000529}
530
reed@google.come0d9ce82014-04-23 04:00:17 +0000531void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
532 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000533 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000534}
535
reed@google.come0d9ce82014-04-23 04:00:17 +0000536void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
537 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000538 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000539 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000540}
541
bsalomon@google.com7ce564c2013-10-22 16:54:15 +0000542void SkDebugCanvas::drawRect(const SkRect& rect, const SkPaint& paint) {
chudy@google.com902ebe52012-06-29 14:21:22 +0000543 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000544 addDrawCommand(new SkDrawRectCommand(rect, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000545}
546
robertphillips@google.com67baba42013-01-02 20:20:31 +0000547void SkDebugCanvas::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000548 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000549}
550
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000551void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
552 const SkPaint& paint) {
commit-bot@chromium.org3d305202014-02-24 17:28:55 +0000553 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000554}
555
chudy@google.com902ebe52012-06-29 14:21:22 +0000556void SkDebugCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
robertphillips@google.com6ede1fe2013-06-06 23:59:28 +0000557 const SkPaint* paint = NULL) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000558 this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000559}
560
reed@google.come0d9ce82014-04-23 04:00:17 +0000561void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
562 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000563 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000564}
565
reed@google.come0d9ce82014-04-23 04:00:17 +0000566void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
567 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000568 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000569 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000570}
571
572void SkDebugCanvas::drawVertices(VertexMode vmode, int vertexCount,
573 const SkPoint vertices[], const SkPoint texs[], const SkColor colors[],
574 SkXfermode*, const uint16_t indices[], int indexCount,
575 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000576 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
577 texs, colors, NULL, indices, indexCount, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000578}
579
commit-bot@chromium.org210ae2a2014-02-27 17:40:13 +0000580void SkDebugCanvas::onPushCull(const SkRect& cullRect) {
581 this->addDrawCommand(new SkPushCullCommand(cullRect));
582}
583
584void SkDebugCanvas::onPopCull() {
585 this->addDrawCommand(new SkPopCullCommand());
586}
587
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000588void SkDebugCanvas::willRestore() {
589 this->addDrawCommand(new SkRestoreCommand());
590 this->INHERITED::willRestore();
chudy@google.com902ebe52012-06-29 14:21:22 +0000591}
592
Florin Malita5f6102d2014-06-30 10:13:28 -0400593void SkDebugCanvas::willSave() {
594 this->addDrawCommand(new SkSaveCommand());
595 this->INHERITED::willSave();
chudy@google.com902ebe52012-06-29 14:21:22 +0000596}
597
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000598SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
599 SaveFlags flags) {
600 this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
601 this->INHERITED::willSaveLayer(bounds, paint, flags);
602 // No need for a full layer.
603 return kNoLayer_SaveLayerStrategy;
chudy@google.com902ebe52012-06-29 14:21:22 +0000604}
605
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000606void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000607 this->addDrawCommand(new SkSetMatrixCommand(matrix));
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000608 this->INHERITED::didSetMatrix(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000609}
610
chudy@google.com902ebe52012-06-29 14:21:22 +0000611void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000612 SkASSERT(index < fCommandVector.count());
613 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000614}
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000615
616static const char* gFillTypeStrs[] = {
617 "kWinding_FillType",
618 "kEvenOdd_FillType",
619 "kInverseWinding_FillType",
620 "kInverseEvenOdd_FillType"
621};
622
623static const char* gOpStrs[] = {
624 "kDifference_PathOp",
625 "kIntersect_PathOp",
626 "kUnion_PathOp",
627 "kXor_PathOp",
628 "kReverseDifference_PathOp",
629};
630
631static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
632
633void SkDebugCanvas::outputScalar(SkScalar num) {
634 if (num == (int) num) {
635 fClipStackData.appendf("%d", (int) num);
636 } else {
637 SkString str;
638 str.printf("%1.9g", num);
639 int width = (int) str.size();
640 const char* cStr = str.c_str();
641 while (cStr[width - 1] == '0') {
642 --width;
643 }
644 str.resize(width);
645 fClipStackData.appendf("%sf", str.c_str());
646 }
647}
648
649void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
650 for (int index = 0; index < count; ++index) {
651 this->outputScalar(pts[index].fX);
652 fClipStackData.appendf(", ");
653 this->outputScalar(pts[index].fY);
654 if (index + 1 < count) {
655 fClipStackData.appendf(", ");
656 }
657 }
658}
659
660void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
661 this->outputPointsCommon(pts, count);
662 fClipStackData.appendf(");<br>");
663}
664
665void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
666 this->outputPointsCommon(pts, 2);
667 fClipStackData.appendf(", ");
668 this->outputScalar(weight);
669 fClipStackData.appendf(");<br>");
670}
671
672void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
673 SkPath::RawIter iter(path);
674 SkPath::FillType fillType = path.getFillType();
675 fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
676 fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
677 gFillTypeStrs[fillType]);
678 iter.setPath(path);
679 uint8_t verb;
680 SkPoint pts[4];
681 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
682 switch (verb) {
683 case SkPath::kMove_Verb:
684 fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
685 this->outputPoints(&pts[0], 1);
686 continue;
687 case SkPath::kLine_Verb:
688 fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
689 this->outputPoints(&pts[1], 1);
690 break;
691 case SkPath::kQuad_Verb:
692 fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
693 this->outputPoints(&pts[1], 2);
694 break;
695 case SkPath::kConic_Verb:
696 fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
697 this->outputConicPoints(&pts[1], iter.conicWeight());
698 break;
699 case SkPath::kCubic_Verb:
700 fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
701 this->outputPoints(&pts[1], 3);
702 break;
703 case SkPath::kClose_Verb:
704 fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
705 break;
706 default:
707 SkDEBUGFAIL("bad verb");
708 return;
709 }
710 }
711}
712
713void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
714 SkRegion::Op elementOp) {
715 if (elementOp == SkRegion::kReplace_Op) {
716 if (!lastClipStackData(devPath)) {
717 fSaveDevPath = operand;
718 }
719 fCalledAddStackData = false;
720 } else {
721 fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
722 " const char* filename) {<br>");
723 addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
724 addPathData(operand, "pathB");
725 fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
726 kHTML4SpaceIndent, gOpStrs[elementOp]);
727 fClipStackData.appendf("}<br>");
728 fCalledAddStackData = true;
729 }
730}
731
732bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
733 if (fCalledAddStackData) {
734 fClipStackData.appendf("<br>");
735 addPathData(devPath, "pathOut");
736 return true;
737 }
738 return false;
739}