blob: 6a04006264966c3277e238a5a2e7c297e5d3e920 [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
kkinnunen26e54002015-01-05 12:58:56 -080017SkDebugCanvas::SkDebugCanvas(int width, int height)
18 : 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 , fFilter(false)
commit-bot@chromium.org768ac852014-03-03 16:32:17 +000021 , fMegaVizMode(false)
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000022 , fIndex(0)
robertphillips@google.comf4741c12013-02-06 20:13:54 +000023 , fOverdrawViz(false)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000024 , fOverdrawFilter(NULL)
robertphillips@google.com32bbcf82013-10-17 17:56:10 +000025 , fOverrideTexFiltering(false)
26 , fTexOverrideFilter(NULL)
scroggo@google.com06d6ac62013-02-08 21:16:19 +000027 , fOutstandingSaveCount(0) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000028 fUserMatrix.reset();
robertphillips70171682014-10-16 14:28:28 -070029 fDrawNeedsReset = false;
robertphillips@google.com8b157172013-11-07 22:20:31 +000030
31 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
32 // operations. This can lead to problems in the debugger which expects all
33 // the operations in the captured skp to appear in the debug canvas. To
34 // circumvent this we create a wide open clip here (an empty clip rect
35 // is not sufficient).
36 // Internally, the SkRect passed to clipRect is converted to an SkIRect and
37 // rounded out. The following code creates a nearly maximal rect that will
38 // not get collapsed by the coming conversions (Due to precision loss the
39 // inset has to be surprisingly large).
40 SkIRect largeIRect = SkIRect::MakeLargest();
41 largeIRect.inset(1024, 1024);
robertphillips@google.com6c1e49a2013-11-10 15:08:45 +000042 SkRect large = SkRect::Make(largeIRect);
robertphillips@google.com8b157172013-11-07 22:20:31 +000043#ifdef SK_DEBUG
reedb07a94f2014-11-19 05:03:18 -080044 SkASSERT(!large.roundOut().isEmpty());
robertphillips@google.com8b157172013-11-07 22:20:31 +000045#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +000046 // call the base class' version to avoid adding a draw command
47 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
chudy@google.com902ebe52012-06-29 14:21:22 +000048}
49
chudy@google.com9cda6f72012-08-07 15:08:33 +000050SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000051 fCommandVector.deleteAll();
robertphillips@google.comf4741c12013-02-06 20:13:54 +000052 SkSafeUnref(fOverdrawFilter);
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000053 SkSafeUnref(fTexOverrideFilter);
chudy@google.com9cda6f72012-08-07 15:08:33 +000054}
chudy@google.com902ebe52012-06-29 14:21:22 +000055
56void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +000057 command->setOffset(this->getOpID());
robertphillips@google.com67baba42013-01-02 20:20:31 +000058 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000059}
60
61void SkDebugCanvas::draw(SkCanvas* canvas) {
robertphillipsb9750892014-10-21 10:31:38 -070062 fDrawNeedsReset = true;
63
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));
robertphillipsa8d7f0b2014-08-29 08:03:56 -070079 this->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()) {
robertphillips70171682014-10-16 14:28:28 -070085 fCommandVector[i]->setUserMatrix(fUserMatrix);
robertphillips@google.com67baba42013-01-02 20:20:31 +000086 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +000087 }
88 if (prev != bitmap.getColor(0,0)) {
89 layer = i;
90 }
91 prev = bitmap.getColor(0,0);
92 }
93 return layer;
94}
95
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +000096class OverdrawXfermode : public SkXfermode {
97public:
mtklein72c9faa2015-01-09 10:06:39 -080098 SkPMColor xferColor(SkPMColor src, SkPMColor dst) const SK_OVERRIDE {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +000099 // This table encodes the color progression of the overdraw visualization
100 static const SkPMColor gTable[] = {
101 SkPackARGB32(0x00, 0x00, 0x00, 0x00),
102 SkPackARGB32(0xFF, 128, 158, 255),
103 SkPackARGB32(0xFF, 170, 185, 212),
104 SkPackARGB32(0xFF, 213, 195, 170),
105 SkPackARGB32(0xFF, 255, 192, 127),
106 SkPackARGB32(0xFF, 255, 185, 85),
107 SkPackARGB32(0xFF, 255, 165, 42),
108 SkPackARGB32(0xFF, 255, 135, 0),
109 SkPackARGB32(0xFF, 255, 95, 0),
110 SkPackARGB32(0xFF, 255, 50, 0),
111 SkPackARGB32(0xFF, 255, 0, 0)
112 };
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000113
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000114 for (size_t i = 0; i < SK_ARRAY_COUNT(gTable)-1; ++i) {
115 if (gTable[i] == dst) {
116 return gTable[i+1];
117 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000118 }
skia.committer@gmail.com60bd7512014-04-18 03:03:54 +0000119
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000120 return gTable[SK_ARRAY_COUNT(gTable)-1];
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000121 }
122
mtklein72c9faa2015-01-09 10:06:39 -0800123 Factory getFactory() const SK_OVERRIDE { return NULL; }
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000124#ifndef SK_IGNORE_TO_STRING
125 virtual void toString(SkString* str) const { str->set("OverdrawXfermode"); }
126#endif
127};
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000128
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000129class SkOverdrawFilter : public SkDrawFilter {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000130public:
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000131 SkOverdrawFilter() {
commit-bot@chromium.orgcc277b72014-04-17 15:19:32 +0000132 fXferMode = SkNEW(OverdrawXfermode);
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000133 }
134
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000135 virtual ~SkOverdrawFilter() {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000136 delete fXferMode;
137 }
138
mtklein72c9faa2015-01-09 10:06:39 -0800139 bool filter(SkPaint* p, Type) SK_OVERRIDE {
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000140 p->setXfermode(fXferMode);
141 return true;
142 }
143
144protected:
145 SkXfermode* fXferMode;
146
147private:
148 typedef SkDrawFilter INHERITED;
149};
150
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000151// SkTexOverrideFilter modifies every paint to use the specified
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000152// texture filtering mode
153class SkTexOverrideFilter : public SkDrawFilter {
154public:
155 SkTexOverrideFilter() : fFilterLevel(SkPaint::kNone_FilterLevel) {
156 }
157
158 void setFilterLevel(SkPaint::FilterLevel filterLevel) {
159 fFilterLevel = filterLevel;
160 }
161
mtklein72c9faa2015-01-09 10:06:39 -0800162 bool filter(SkPaint* p, Type) SK_OVERRIDE {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000163 p->setFilterLevel(fFilterLevel);
164 return true;
165 }
166
167protected:
168 SkPaint::FilterLevel fFilterLevel;
169
170private:
171 typedef SkDrawFilter INHERITED;
172};
173
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000174class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
175public:
176 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
177
mtklein72c9faa2015-01-09 10:06:39 -0800178 void clipRect(const SkRect& r, SkRegion::Op, bool doAA) SK_OVERRIDE {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000179 SkPaint p;
180 p.setColor(SK_ColorRED);
181 p.setStyle(SkPaint::kStroke_Style);
182 p.setAntiAlias(doAA);
183 fCanvas->drawRect(r, p);
184 }
mtklein72c9faa2015-01-09 10:06:39 -0800185 void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) SK_OVERRIDE {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000186 SkPaint p;
187 p.setColor(SK_ColorGREEN);
188 p.setStyle(SkPaint::kStroke_Style);
189 p.setAntiAlias(doAA);
190 fCanvas->drawRRect(rr, p);
191 }
mtklein72c9faa2015-01-09 10:06:39 -0800192 void clipPath(const SkPath& path, SkRegion::Op, bool doAA) SK_OVERRIDE {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000193 SkPaint p;
194 p.setColor(SK_ColorBLUE);
195 p.setStyle(SkPaint::kStroke_Style);
196 p.setAntiAlias(doAA);
197 fCanvas->drawPath(path, p);
198 }
199
200protected:
201 SkCanvas* fCanvas;
202
203private:
204 typedef SkCanvas::ClipVisitor INHERITED;
205};
206
207// set up the saveLayer commands so that the active ones
208// return true in their 'active' method
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000209void SkDebugCanvas::markActiveCommands(int index) {
210 fActiveLayers.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();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000222 }
223 }
224
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000225 for (int i = 0; i < fActiveLayers.count(); ++i) {
226 fActiveLayers[i]->setActive(true);
227 }
228
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000229}
230
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000231void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000232 SkASSERT(!fCommandVector.isEmpty());
233 SkASSERT(index < fCommandVector.count());
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000234 int i = 0;
kkinnunen26e54002015-01-05 12:58:56 -0800235 SkRect windowRect = SkRect::MakeWH(SkIntToScalar(canvas->getBaseLayerSize().width()),
236 SkIntToScalar(canvas->getBaseLayerSize().height()));
chudy@google.com830b8792012-08-01 15:57:52 +0000237
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000238 bool pathOpsMode = getAllowSimplifyClip();
239 canvas->setAllowSimplifyClip(pathOpsMode);
chudy@google.com830b8792012-08-01 15:57:52 +0000240 // This only works assuming the canvas and device are the same ones that
241 // were previously drawn into because they need to preserve all saves
242 // and restores.
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000243 // The visibility filter also requires a full re-draw - otherwise we can
244 // end up drawing the filter repeatedly.
robertphillips70171682014-10-16 14:28:28 -0700245 if (fIndex < index && !fFilter && !fMegaVizMode && !pathOpsMode && !fDrawNeedsReset) {
chudy@google.com830b8792012-08-01 15:57:52 +0000246 i = fIndex + 1;
247 } else {
tomhudson@google.com0699e022012-11-27 16:09:42 +0000248 for (int j = 0; j < fOutstandingSaveCount; j++) {
249 canvas->restore();
250 }
junov@google.comdbfac8a2012-12-06 21:47:40 +0000251 canvas->clear(SK_ColorTRANSPARENT);
chudy@google.com830b8792012-08-01 15:57:52 +0000252 canvas->resetMatrix();
kkinnunen26e54002015-01-05 12:58:56 -0800253 if (!windowRect.isEmpty()) {
254 canvas->clipRect(windowRect, SkRegion::kReplace_Op);
255 }
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700256 this->applyUserTransform(canvas);
robertphillips70171682014-10-16 14:28:28 -0700257 fDrawNeedsReset = false;
tomhudson@google.com0699e022012-11-27 16:09:42 +0000258 fOutstandingSaveCount = 0;
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000259 }
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000260
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000261 // The setting of the draw filter has to go here (rather than in
262 // SkRasterWidget) due to the canvas restores this class performs.
263 // Since the draw filter is stored in the layer stack if we
264 // call setDrawFilter on anything but the root layer odd things happen.
265 if (fOverdrawViz) {
266 if (NULL == fOverdrawFilter) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000267 fOverdrawFilter = new SkOverdrawFilter;
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000268 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000269
270 if (fOverdrawFilter != canvas->getDrawFilter()) {
271 canvas->setDrawFilter(fOverdrawFilter);
272 }
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000273 } else if (fOverrideTexFiltering) {
274 if (NULL == fTexOverrideFilter) {
275 fTexOverrideFilter = new SkTexOverrideFilter;
276 }
277
278 if (fTexOverrideFilter != canvas->getDrawFilter()) {
279 canvas->setDrawFilter(fTexOverrideFilter);
280 }
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000281 } else {
282 canvas->setDrawFilter(NULL);
chudy@google.com830b8792012-08-01 15:57:52 +0000283 }
284
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000285 if (fMegaVizMode) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000286 this->markActiveCommands(index);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000287 }
288
chudy@google.com830b8792012-08-01 15:57:52 +0000289 for (; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000290 if (i == index && fFilter) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700291 canvas->clear(0xAAFFFFFF);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000292 }
293
robertphillips@google.com67baba42013-01-02 20:20:31 +0000294 if (fCommandVector[i]->isVisible()) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000295 if (fMegaVizMode && fCommandVector[i]->active()) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000296 // "active" commands execute their visualization behaviors:
297 // All active saveLayers get replaced with saves so all draws go to the
298 // visible canvas.
299 // All active culls draw their cull box
300 fCommandVector[i]->vizExecute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000301 } else {
robertphillips70171682014-10-16 14:28:28 -0700302 fCommandVector[i]->setUserMatrix(fUserMatrix);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000303 fCommandVector[i]->execute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000304 }
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000305
306 fCommandVector[i]->trackSaveState(&fOutstandingSaveCount);
chudy@google.com902ebe52012-06-29 14:21:22 +0000307 }
308 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000309
310 if (fMegaVizMode) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000311 canvas->save();
312 // nuke the CTM
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700313 canvas->resetMatrix();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000314 // turn off clipping
kkinnunen26e54002015-01-05 12:58:56 -0800315 if (!windowRect.isEmpty()) {
316 SkRect r = windowRect;
317 r.outset(SK_Scalar1, SK_Scalar1);
318 canvas->clipRect(r, SkRegion::kReplace_Op);
319 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000320 // visualize existing clips
321 SkDebugClipVisitor visitor(canvas);
322
323 canvas->replayClips(&visitor);
324
325 canvas->restore();
326 }
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000327 if (pathOpsMode) {
328 this->resetClipStackData();
329 const SkClipStack* clipStack = canvas->getClipStack();
330 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
331 const SkClipStack::Element* element;
332 SkPath devPath;
333 while ((element = iter.next())) {
334 SkClipStack::Element::Type type = element->getType();
335 SkPath operand;
336 if (type != SkClipStack::Element::kEmpty_Type) {
337 element->asPath(&operand);
338 }
339 SkRegion::Op elementOp = element->getOp();
340 this->addClipStackData(devPath, operand, elementOp);
341 if (elementOp == SkRegion::kReplace_Op) {
342 devPath = operand;
343 } else {
344 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
345 }
346 }
347 this->lastClipStackData(devPath);
348 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000349 fMatrix = canvas->getTotalMatrix();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000350 if (!canvas->getClipDeviceBounds(&fClip)) {
351 fClip.setEmpty();
352 }
chudy@google.com830b8792012-08-01 15:57:52 +0000353 fIndex = index;
chudy@google.com902ebe52012-06-29 14:21:22 +0000354}
355
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000356void SkDebugCanvas::deleteDrawCommandAt(int index) {
357 SkASSERT(index < fCommandVector.count());
358 delete fCommandVector[index];
359 fCommandVector.remove(index);
360}
361
chudy@google.com902ebe52012-06-29 14:21:22 +0000362SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000363 SkASSERT(index < fCommandVector.count());
364 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000365}
366
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000367void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
368 SkASSERT(index < fCommandVector.count());
369 delete fCommandVector[index];
370 fCommandVector[index] = command;
371}
372
fmalita8c89c522014-11-08 16:18:56 -0800373const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000374 SkASSERT(index < fCommandVector.count());
375 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000376}
chudy@google.com902ebe52012-06-29 14:21:22 +0000377
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000378bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000379 SkASSERT(index < fCommandVector.count());
380 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000381}
382
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000383const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000384 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000385}
386
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000387SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
388 return fCommandVector;
389}
390
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000391void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkPaint::FilterLevel level) {
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000392 if (NULL == fTexOverrideFilter) {
393 fTexOverrideFilter = new SkTexOverrideFilter;
394 }
395
skia.committer@gmail.comf84ad8f2013-10-18 07:01:59 +0000396 fOverrideTexFiltering = overrideTexFiltering;
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000397 fTexOverrideFilter->setFilterLevel(level);
398}
399
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000400void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
401 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000402}
403
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000404void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
405 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000406}
407
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000408void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
409 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000410}
411
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000412void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
413 this->addDrawCommand(new SkClipRegionCommand(region, op));
chudy@google.com902ebe52012-06-29 14:21:22 +0000414}
415
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000416void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
commit-bot@chromium.orgd9ea09e2014-03-25 17:32:26 +0000417 switch (matrix.getType()) {
418 case SkMatrix::kTranslate_Mask:
419 this->addDrawCommand(new SkTranslateCommand(matrix.getTranslateX(),
420 matrix.getTranslateY()));
421 break;
422 case SkMatrix::kScale_Mask:
423 this->addDrawCommand(new SkScaleCommand(matrix.getScaleX(),
424 matrix.getScaleY()));
425 break;
426 default:
427 this->addDrawCommand(new SkConcatCommand(matrix));
428 break;
429 }
430
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000431 this->INHERITED::didConcat(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000432}
433
reed41af9662015-01-05 07:49:08 -0800434void SkDebugCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
435 SkScalar top, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000436 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000437}
438
reed41af9662015-01-05 07:49:08 -0800439void SkDebugCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
440 const SkPaint* paint, DrawBitmapRectFlags flags) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000441 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
chudy@google.com902ebe52012-06-29 14:21:22 +0000442}
443
reed41af9662015-01-05 07:49:08 -0800444void SkDebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
445 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000446 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000447}
448
reed41af9662015-01-05 07:49:08 -0800449void SkDebugCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
450 const SkPaint* paint) {
451 SkDebugf("SkDebugCanvas::onDrawImage unimplemented\n");
452}
453
454void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
455 const SkPaint* paint) {
456 SkDebugf("SkDebugCanvas::onDrawImageRect unimplemented\n");
457}
458
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000459void SkDebugCanvas::beginCommentGroup(const char* description) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000460 this->addDrawCommand(new SkBeginCommentGroupCommand(description));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000461}
462
463void SkDebugCanvas::addComment(const char* kywd, const char* value) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000464 this->addDrawCommand(new SkCommentCommand(kywd, value));
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000465}
466
467void SkDebugCanvas::endCommentGroup() {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000468 this->addDrawCommand(new SkEndCommentGroupCommand());
robertphillips@google.com0a4805e2013-05-29 13:24:23 +0000469}
470
reed41af9662015-01-05 07:49:08 -0800471void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000472 this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000473}
474
reed41af9662015-01-05 07:49:08 -0800475void SkDebugCanvas::onDrawPaint(const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000476 this->addDrawCommand(new SkDrawPaintCommand(paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000477}
478
reed41af9662015-01-05 07:49:08 -0800479void SkDebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000480 this->addDrawCommand(new SkDrawPathCommand(path, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000481}
482
mtkleinf0f14112014-12-12 08:46:25 -0800483void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
484 const SkMatrix* matrix,
robertphillipsb3f319f2014-08-13 10:46:23 -0700485 const SkPaint* paint) {
486 this->addDrawCommand(new SkDrawPictureCommand(picture, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000487}
488
reed41af9662015-01-05 07:49:08 -0800489void SkDebugCanvas::onDrawPoints(PointMode mode, size_t count,
490 const SkPoint pts[], const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000491 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000492}
493
reed@google.come0d9ce82014-04-23 04:00:17 +0000494void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
495 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000496 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000497}
498
reed@google.come0d9ce82014-04-23 04:00:17 +0000499void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
500 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000501 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000502 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000503}
504
reed41af9662015-01-05 07:49:08 -0800505void SkDebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
chudy@google.com902ebe52012-06-29 14:21:22 +0000506 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000507 addDrawCommand(new SkDrawRectCommand(rect, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000508}
509
reed41af9662015-01-05 07:49:08 -0800510void SkDebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000511 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000512}
513
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000514void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
515 const SkPaint& paint) {
commit-bot@chromium.org3d305202014-02-24 17:28:55 +0000516 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000517}
518
reed41af9662015-01-05 07:49:08 -0800519void SkDebugCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000520 this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000521}
522
reed@google.come0d9ce82014-04-23 04:00:17 +0000523void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
524 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000525 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000526}
527
reed@google.come0d9ce82014-04-23 04:00:17 +0000528void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
529 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000530 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000531 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000532}
533
fmalitab7425172014-08-26 07:56:44 -0700534void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
535 const SkPaint& paint) {
536 this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
537}
538
reed41af9662015-01-05 07:49:08 -0800539void SkDebugCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
540 const SkPoint texs[], const SkColor colors[],
541 SkXfermode*, const uint16_t indices[], int indexCount,
542 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000543 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
544 texs, colors, NULL, indices, indexCount, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000545}
546
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000547void SkDebugCanvas::willRestore() {
548 this->addDrawCommand(new SkRestoreCommand());
549 this->INHERITED::willRestore();
chudy@google.com902ebe52012-06-29 14:21:22 +0000550}
551
Florin Malita5f6102d2014-06-30 10:13:28 -0400552void SkDebugCanvas::willSave() {
553 this->addDrawCommand(new SkSaveCommand());
554 this->INHERITED::willSave();
chudy@google.com902ebe52012-06-29 14:21:22 +0000555}
556
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000557SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
558 SaveFlags flags) {
559 this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
560 this->INHERITED::willSaveLayer(bounds, paint, flags);
561 // No need for a full layer.
562 return kNoLayer_SaveLayerStrategy;
chudy@google.com902ebe52012-06-29 14:21:22 +0000563}
564
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000565void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000566 this->addDrawCommand(new SkSetMatrixCommand(matrix));
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000567 this->INHERITED::didSetMatrix(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000568}
569
chudy@google.com902ebe52012-06-29 14:21:22 +0000570void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000571 SkASSERT(index < fCommandVector.count());
572 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000573}
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000574
575static const char* gFillTypeStrs[] = {
576 "kWinding_FillType",
577 "kEvenOdd_FillType",
578 "kInverseWinding_FillType",
579 "kInverseEvenOdd_FillType"
580};
581
582static const char* gOpStrs[] = {
583 "kDifference_PathOp",
584 "kIntersect_PathOp",
585 "kUnion_PathOp",
586 "kXor_PathOp",
587 "kReverseDifference_PathOp",
588};
589
590static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
591
592void SkDebugCanvas::outputScalar(SkScalar num) {
593 if (num == (int) num) {
594 fClipStackData.appendf("%d", (int) num);
595 } else {
596 SkString str;
597 str.printf("%1.9g", num);
598 int width = (int) str.size();
599 const char* cStr = str.c_str();
600 while (cStr[width - 1] == '0') {
601 --width;
602 }
603 str.resize(width);
604 fClipStackData.appendf("%sf", str.c_str());
605 }
606}
607
608void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
609 for (int index = 0; index < count; ++index) {
610 this->outputScalar(pts[index].fX);
611 fClipStackData.appendf(", ");
612 this->outputScalar(pts[index].fY);
613 if (index + 1 < count) {
614 fClipStackData.appendf(", ");
615 }
616 }
617}
618
619void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
620 this->outputPointsCommon(pts, count);
621 fClipStackData.appendf(");<br>");
622}
623
624void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
625 this->outputPointsCommon(pts, 2);
626 fClipStackData.appendf(", ");
627 this->outputScalar(weight);
628 fClipStackData.appendf(");<br>");
629}
630
631void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
632 SkPath::RawIter iter(path);
633 SkPath::FillType fillType = path.getFillType();
634 fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
635 fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
636 gFillTypeStrs[fillType]);
637 iter.setPath(path);
638 uint8_t verb;
639 SkPoint pts[4];
640 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
641 switch (verb) {
642 case SkPath::kMove_Verb:
643 fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
644 this->outputPoints(&pts[0], 1);
645 continue;
646 case SkPath::kLine_Verb:
647 fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
648 this->outputPoints(&pts[1], 1);
649 break;
650 case SkPath::kQuad_Verb:
651 fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
652 this->outputPoints(&pts[1], 2);
653 break;
654 case SkPath::kConic_Verb:
655 fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
656 this->outputConicPoints(&pts[1], iter.conicWeight());
657 break;
658 case SkPath::kCubic_Verb:
659 fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
660 this->outputPoints(&pts[1], 3);
661 break;
662 case SkPath::kClose_Verb:
663 fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
664 break;
665 default:
666 SkDEBUGFAIL("bad verb");
667 return;
668 }
669 }
670}
671
672void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
673 SkRegion::Op elementOp) {
674 if (elementOp == SkRegion::kReplace_Op) {
675 if (!lastClipStackData(devPath)) {
676 fSaveDevPath = operand;
677 }
678 fCalledAddStackData = false;
679 } else {
680 fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
681 " const char* filename) {<br>");
682 addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
683 addPathData(operand, "pathB");
684 fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
685 kHTML4SpaceIndent, gOpStrs[elementOp]);
686 fClipStackData.appendf("}<br>");
687 fCalledAddStackData = true;
688 }
689}
690
691bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
692 if (fCalledAddStackData) {
693 fClipStackData.appendf("<br>");
694 addPathData(devPath, "pathOut");
695 return true;
696 }
697 return false;
698}