blob: 34e582e187754b5661236df25ed1bad16d356bbc [file] [log] [blame]
chudy@google.com902ebe52012-06-29 14:21:22 +00001/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
ethannicholas891ad662016-02-12 07:15:45 -08008#include "SkCanvasPriv.h"
bungemand3ebb482015-08-05 13:57:49 -07009#include "SkClipStack.h"
chudy@google.com902ebe52012-06-29 14:21:22 +000010#include "SkDebugCanvas.h"
11#include "SkDrawCommand.h"
robertphillips@google.com6dec8fc2012-11-21 17:11:02 +000012#include "SkDevice.h"
fmalita65cdb572015-03-26 07:24:48 -070013#include "SkPaintFilterCanvas.h"
robertphillipsf42fca42016-01-27 05:00:04 -080014#include "SkOverdrawMode.h"
fmalita65cdb572015-03-26 07:24:48 -070015
ethannicholas402cd912016-02-10 12:57:30 -080016#define SKDEBUGCANVAS_VERSION 1
17#define SKDEBUGCANVAS_ATTRIBUTE_VERSION "version"
18#define SKDEBUGCANVAS_ATTRIBUTE_COMMANDS "commands"
19
fmalita65cdb572015-03-26 07:24:48 -070020class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
21public:
halcanary385fe4d2015-08-26 13:07:48 -070022 DebugPaintFilterCanvas(int width,
23 int height,
24 bool overdrawViz,
25 bool overrideFilterQuality,
fmalita65cdb572015-03-26 07:24:48 -070026 SkFilterQuality quality)
27 : INHERITED(width, height)
robertphillipsf42fca42016-01-27 05:00:04 -080028 , fOverdrawXfermode(overdrawViz ? SkOverdrawMode::Create() : nullptr)
fmalita65cdb572015-03-26 07:24:48 -070029 , fOverrideFilterQuality(overrideFilterQuality)
halcanary385fe4d2015-08-26 13:07:48 -070030 , fFilterQuality(quality) {}
fmalita65cdb572015-03-26 07:24:48 -070031
32protected:
fmalita32cdc322016-01-12 07:21:11 -080033 bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type) const override {
34 if (*paint) {
fmalitabad23dc2016-01-11 13:58:29 -080035 if (nullptr != fOverdrawXfermode.get()) {
fmalita32cdc322016-01-12 07:21:11 -080036 paint->writable()->setAntiAlias(false);
37 paint->writable()->setXfermode(fOverdrawXfermode.get());
fmalitabad23dc2016-01-11 13:58:29 -080038 }
fmalita65cdb572015-03-26 07:24:48 -070039
fmalitabad23dc2016-01-11 13:58:29 -080040 if (fOverrideFilterQuality) {
fmalita32cdc322016-01-12 07:21:11 -080041 paint->writable()->setFilterQuality(fFilterQuality);
fmalitabad23dc2016-01-11 13:58:29 -080042 }
fmalita65cdb572015-03-26 07:24:48 -070043 }
fmalitabad23dc2016-01-11 13:58:29 -080044 return true;
fmalita65cdb572015-03-26 07:24:48 -070045 }
46
mtkleinf0599002015-07-13 06:18:39 -070047 void onDrawPicture(const SkPicture* picture,
48 const SkMatrix* matrix,
49 const SkPaint* paint) override {
fmalita65cdb572015-03-26 07:24:48 -070050 // We need to replay the picture onto this canvas in order to filter its internal paints.
51 this->SkCanvas::onDrawPicture(picture, matrix, paint);
52 }
53
54private:
55 SkAutoTUnref<SkXfermode> fOverdrawXfermode;
56
57 bool fOverrideFilterQuality;
58 SkFilterQuality fFilterQuality;
59
60 typedef SkPaintFilterCanvas INHERITED;
61};
62
kkinnunen26e54002015-01-05 12:58:56 -080063SkDebugCanvas::SkDebugCanvas(int width, int height)
64 : INHERITED(width, height)
halcanary96fcdcc2015-08-27 07:41:13 -070065 , fPicture(nullptr)
commit-bot@chromium.org1735d662013-12-04 13:42:46 +000066 , fFilter(false)
commit-bot@chromium.org768ac852014-03-03 16:32:17 +000067 , fMegaVizMode(false)
robertphillips@google.comf4741c12013-02-06 20:13:54 +000068 , fOverdrawViz(false)
fmalita65cdb572015-03-26 07:24:48 -070069 , fOverrideFilterQuality(false)
ethannicholas0a0520a2016-02-12 12:06:53 -080070 , fFilterQuality(kNone_SkFilterQuality)
71 , fClipVizColor(SK_ColorTRANSPARENT) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +000072 fUserMatrix.reset();
robertphillips@google.com8b157172013-11-07 22:20:31 +000073
74 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
75 // operations. This can lead to problems in the debugger which expects all
76 // the operations in the captured skp to appear in the debug canvas. To
77 // circumvent this we create a wide open clip here (an empty clip rect
78 // is not sufficient).
79 // Internally, the SkRect passed to clipRect is converted to an SkIRect and
80 // rounded out. The following code creates a nearly maximal rect that will
81 // not get collapsed by the coming conversions (Due to precision loss the
82 // inset has to be surprisingly large).
83 SkIRect largeIRect = SkIRect::MakeLargest();
84 largeIRect.inset(1024, 1024);
robertphillips@google.com6c1e49a2013-11-10 15:08:45 +000085 SkRect large = SkRect::Make(largeIRect);
robertphillips@google.com8b157172013-11-07 22:20:31 +000086#ifdef SK_DEBUG
reedb07a94f2014-11-19 05:03:18 -080087 SkASSERT(!large.roundOut().isEmpty());
robertphillips@google.com8b157172013-11-07 22:20:31 +000088#endif
robertphillips@google.com8f90a892014-02-28 18:19:39 +000089 // call the base class' version to avoid adding a draw command
90 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
chudy@google.com902ebe52012-06-29 14:21:22 +000091}
92
chudy@google.com9cda6f72012-08-07 15:08:33 +000093SkDebugCanvas::~SkDebugCanvas() {
robertphillips@google.com67baba42013-01-02 20:20:31 +000094 fCommandVector.deleteAll();
chudy@google.com9cda6f72012-08-07 15:08:33 +000095}
chudy@google.com902ebe52012-06-29 14:21:22 +000096
97void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
robertphillips@google.com67baba42013-01-02 20:20:31 +000098 fCommandVector.push(command);
chudy@google.com902ebe52012-06-29 14:21:22 +000099}
100
101void SkDebugCanvas::draw(SkCanvas* canvas) {
commit-bot@chromium.org1735d662013-12-04 13:42:46 +0000102 if (!fCommandVector.isEmpty()) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000103 this->drawTo(canvas, fCommandVector.count() - 1);
chudy@google.com902ebe52012-06-29 14:21:22 +0000104 }
105}
106
chudy@google.com830b8792012-08-01 15:57:52 +0000107void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
bungeman@google.come8cc6e82013-01-17 16:30:56 +0000108 canvas->concat(fUserMatrix);
chudy@google.com830b8792012-08-01 15:57:52 +0000109}
110
111int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000112 SkBitmap bitmap;
reed@google.com9ebcac52014-01-24 18:53:42 +0000113 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
chudy@google.com902ebe52012-06-29 14:21:22 +0000114
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000115 SkCanvas canvas(bitmap);
robertphillips@google.com94acc702012-09-06 18:43:21 +0000116 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700117 this->applyUserTransform(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000118
119 int layer = 0;
chudy@google.com751961d2012-07-31 20:07:42 +0000120 SkColor prev = bitmap.getColor(0,0);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000121 for (int i = 0; i < index; i++) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000122 if (fCommandVector[i]->isVisible()) {
robertphillips70171682014-10-16 14:28:28 -0700123 fCommandVector[i]->setUserMatrix(fUserMatrix);
robertphillips@google.com67baba42013-01-02 20:20:31 +0000124 fCommandVector[i]->execute(&canvas);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000125 }
126 if (prev != bitmap.getColor(0,0)) {
127 layer = i;
128 }
129 prev = bitmap.getColor(0,0);
130 }
131 return layer;
132}
133
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000134class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
135public:
136 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
137
mtklein36352bf2015-03-25 18:17:31 -0700138 void clipRect(const SkRect& r, SkRegion::Op, bool doAA) override {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000139 SkPaint p;
140 p.setColor(SK_ColorRED);
141 p.setStyle(SkPaint::kStroke_Style);
142 p.setAntiAlias(doAA);
143 fCanvas->drawRect(r, p);
144 }
mtklein36352bf2015-03-25 18:17:31 -0700145 void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) override {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000146 SkPaint p;
147 p.setColor(SK_ColorGREEN);
148 p.setStyle(SkPaint::kStroke_Style);
149 p.setAntiAlias(doAA);
150 fCanvas->drawRRect(rr, p);
151 }
mtklein36352bf2015-03-25 18:17:31 -0700152 void clipPath(const SkPath& path, SkRegion::Op, bool doAA) override {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000153 SkPaint p;
154 p.setColor(SK_ColorBLUE);
155 p.setStyle(SkPaint::kStroke_Style);
156 p.setAntiAlias(doAA);
157 fCanvas->drawPath(path, p);
158 }
159
160protected:
161 SkCanvas* fCanvas;
162
163private:
164 typedef SkCanvas::ClipVisitor INHERITED;
165};
166
167// set up the saveLayer commands so that the active ones
168// return true in their 'active' method
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000169void SkDebugCanvas::markActiveCommands(int index) {
170 fActiveLayers.rewind();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000171
172 for (int i = 0; i < fCommandVector.count(); ++i) {
173 fCommandVector[i]->setActive(false);
174 }
175
176 for (int i = 0; i < index; ++i) {
177 SkDrawCommand::Action result = fCommandVector[i]->action();
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000178 if (SkDrawCommand::kPushLayer_Action == result) {
179 fActiveLayers.push(fCommandVector[i]);
180 } else if (SkDrawCommand::kPopLayer_Action == result) {
181 fActiveLayers.pop();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000182 }
183 }
184
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000185 for (int i = 0; i < fActiveLayers.count(); ++i) {
186 fActiveLayers[i]->setActive(true);
187 }
188
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000189}
190
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000191void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000192 SkASSERT(!fCommandVector.isEmpty());
193 SkASSERT(index < fCommandVector.count());
kkinnunen26a00de2015-01-13 23:09:19 -0800194
195 int saveCount = canvas->save();
196
kkinnunen26e54002015-01-05 12:58:56 -0800197 SkRect windowRect = SkRect::MakeWH(SkIntToScalar(canvas->getBaseLayerSize().width()),
198 SkIntToScalar(canvas->getBaseLayerSize().height()));
chudy@google.com830b8792012-08-01 15:57:52 +0000199
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000200 bool pathOpsMode = getAllowSimplifyClip();
201 canvas->setAllowSimplifyClip(pathOpsMode);
ethannicholascecbbe22016-02-17 11:49:43 -0800202 canvas->clear(SK_ColorWHITE);
kkinnunen26a00de2015-01-13 23:09:19 -0800203 canvas->resetMatrix();
204 if (!windowRect.isEmpty()) {
205 canvas->clipRect(windowRect, SkRegion::kReplace_Op);
commit-bot@chromium.orga27622c2013-08-05 16:31:27 +0000206 }
kkinnunen26a00de2015-01-13 23:09:19 -0800207 this->applyUserTransform(canvas);
robertphillips@google.comf4741c12013-02-06 20:13:54 +0000208
fmalita65cdb572015-03-26 07:24:48 -0700209 if (fPaintFilterCanvas) {
210 fPaintFilterCanvas->addCanvas(canvas);
211 canvas = fPaintFilterCanvas.get();
chudy@google.com830b8792012-08-01 15:57:52 +0000212 }
213
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000214 if (fMegaVizMode) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000215 this->markActiveCommands(index);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000216 }
217
kkinnunen26a00de2015-01-13 23:09:19 -0800218 for (int i = 0; i <= index; i++) {
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000219 if (i == index && fFilter) {
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700220 canvas->clear(0xAAFFFFFF);
chudy@google.com0b5bbb02012-07-31 19:55:32 +0000221 }
222
robertphillips@google.com67baba42013-01-02 20:20:31 +0000223 if (fCommandVector[i]->isVisible()) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000224 if (fMegaVizMode && fCommandVector[i]->active()) {
commit-bot@chromium.org1643b2c2014-03-03 23:25:41 +0000225 // "active" commands execute their visualization behaviors:
226 // All active saveLayers get replaced with saves so all draws go to the
227 // visible canvas.
228 // All active culls draw their cull box
229 fCommandVector[i]->vizExecute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000230 } else {
robertphillips70171682014-10-16 14:28:28 -0700231 fCommandVector[i]->setUserMatrix(fUserMatrix);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000232 fCommandVector[i]->execute(canvas);
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000233 }
chudy@google.com902ebe52012-06-29 14:21:22 +0000234 }
235 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000236
ethannicholas0a0520a2016-02-12 12:06:53 -0800237 if (SkColorGetA(fClipVizColor) != 0) {
238 canvas->save();
239 #define LARGE_COORD 1000000000
240 canvas->clipRect(SkRect::MakeLTRB(-LARGE_COORD, -LARGE_COORD, LARGE_COORD, LARGE_COORD),
241 SkRegion::kReverseDifference_Op);
242 SkPaint clipPaint;
243 clipPaint.setColor(fClipVizColor);
244 canvas->drawPaint(clipPaint);
245 canvas->restore();
246 }
247
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000248 if (fMegaVizMode) {
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000249 canvas->save();
250 // nuke the CTM
robertphillipsa8d7f0b2014-08-29 08:03:56 -0700251 canvas->resetMatrix();
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000252 // turn off clipping
kkinnunen26e54002015-01-05 12:58:56 -0800253 if (!windowRect.isEmpty()) {
254 SkRect r = windowRect;
255 r.outset(SK_Scalar1, SK_Scalar1);
256 canvas->clipRect(r, SkRegion::kReplace_Op);
257 }
commit-bot@chromium.org768ac852014-03-03 16:32:17 +0000258 // visualize existing clips
259 SkDebugClipVisitor visitor(canvas);
260
261 canvas->replayClips(&visitor);
262
263 canvas->restore();
264 }
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000265 if (pathOpsMode) {
266 this->resetClipStackData();
267 const SkClipStack* clipStack = canvas->getClipStack();
268 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
269 const SkClipStack::Element* element;
270 SkPath devPath;
271 while ((element = iter.next())) {
272 SkClipStack::Element::Type type = element->getType();
273 SkPath operand;
274 if (type != SkClipStack::Element::kEmpty_Type) {
275 element->asPath(&operand);
276 }
277 SkRegion::Op elementOp = element->getOp();
278 this->addClipStackData(devPath, operand, elementOp);
279 if (elementOp == SkRegion::kReplace_Op) {
280 devPath = operand;
281 } else {
282 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
283 }
284 }
285 this->lastClipStackData(devPath);
286 }
chudy@google.coma9e937c2012-08-03 17:32:05 +0000287 fMatrix = canvas->getTotalMatrix();
commit-bot@chromium.org5c70cdc2014-03-08 03:57:19 +0000288 if (!canvas->getClipDeviceBounds(&fClip)) {
289 fClip.setEmpty();
290 }
kkinnunen26a00de2015-01-13 23:09:19 -0800291
292 canvas->restoreToCount(saveCount);
fmalita65cdb572015-03-26 07:24:48 -0700293
294 if (fPaintFilterCanvas) {
295 fPaintFilterCanvas->removeAll();
296 }
chudy@google.com902ebe52012-06-29 14:21:22 +0000297}
298
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000299void SkDebugCanvas::deleteDrawCommandAt(int index) {
300 SkASSERT(index < fCommandVector.count());
301 delete fCommandVector[index];
302 fCommandVector.remove(index);
303}
304
chudy@google.com902ebe52012-06-29 14:21:22 +0000305SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000306 SkASSERT(index < fCommandVector.count());
307 return fCommandVector[index];
chudy@google.com902ebe52012-06-29 14:21:22 +0000308}
309
robertphillips@google.com50c84da2013-04-01 18:18:49 +0000310void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
311 SkASSERT(index < fCommandVector.count());
312 delete fCommandVector[index];
313 fCommandVector[index] = command;
314}
315
fmalita8c89c522014-11-08 16:18:56 -0800316const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000317 SkASSERT(index < fCommandVector.count());
318 return fCommandVector[index]->Info();
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000319}
chudy@google.com902ebe52012-06-29 14:21:22 +0000320
chudy@google.com7e4cfbf2012-07-17 15:40:51 +0000321bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000322 SkASSERT(index < fCommandVector.count());
323 return fCommandVector[index]->isVisible();
chudy@google.com902ebe52012-06-29 14:21:22 +0000324}
325
robertphillips@google.com8a1cdae2012-11-19 20:44:29 +0000326const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000327 return fCommandVector;
chudy@google.com902ebe52012-06-29 14:21:22 +0000328}
329
robertphillips@google.comfebc0ec2013-03-11 22:53:11 +0000330SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
331 return fCommandVector;
332}
333
joshualitt6b3cf732016-02-17 11:20:26 -0800334Json::Value SkDebugCanvas::toJSON(UrlDataManager& urlDataManager, int n, SkCanvas* canvas) {
ethannicholas402cd912016-02-10 12:57:30 -0800335 Json::Value result = Json::Value(Json::objectValue);
336 result[SKDEBUGCANVAS_ATTRIBUTE_VERSION] = Json::Value(SKDEBUGCANVAS_VERSION);
337 Json::Value commands = Json::Value(Json::arrayValue);
ethannicholas0a0520a2016-02-12 12:06:53 -0800338 for (int i = 0; i < this->getSize() && i <= n; i++) {
joshualitt6b3cf732016-02-17 11:20:26 -0800339 commands[i] = this->getDrawCommandAt(i)->drawToAndCollectJSON(canvas, urlDataManager);
ethannicholas402cd912016-02-10 12:57:30 -0800340 }
341 result[SKDEBUGCANVAS_ATTRIBUTE_COMMANDS] = commands;
342 return result;
343}
344
fmalita65cdb572015-03-26 07:24:48 -0700345void SkDebugCanvas::updatePaintFilterCanvas() {
346 if (!fOverdrawViz && !fOverrideFilterQuality) {
halcanary96fcdcc2015-08-27 07:41:13 -0700347 fPaintFilterCanvas.reset(nullptr);
fmalita65cdb572015-03-26 07:24:48 -0700348 return;
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000349 }
350
fmalita65cdb572015-03-26 07:24:48 -0700351 const SkImageInfo info = this->imageInfo();
halcanary385fe4d2015-08-26 13:07:48 -0700352 fPaintFilterCanvas.reset(new DebugPaintFilterCanvas(info.width(), info.height(), fOverdrawViz,
353 fOverrideFilterQuality, fFilterQuality));
fmalita65cdb572015-03-26 07:24:48 -0700354}
355
356void SkDebugCanvas::setOverdrawViz(bool overdrawViz) {
357 if (fOverdrawViz == overdrawViz) {
358 return;
359 }
360
361 fOverdrawViz = overdrawViz;
362 this->updatePaintFilterCanvas();
363}
364
365void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality quality) {
366 if (fOverrideFilterQuality == overrideTexFiltering && fFilterQuality == quality) {
367 return;
368 }
369
370 fOverrideFilterQuality = overrideTexFiltering;
371 fFilterQuality = quality;
372 this->updatePaintFilterCanvas();
robertphillips@google.com32bbcf82013-10-17 17:56:10 +0000373}
374
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000375void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
376 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000377}
378
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000379void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
380 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
chudy@google.com902ebe52012-06-29 14:21:22 +0000381}
382
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000383void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
384 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000385}
386
robertphillips@google.com8f90a892014-02-28 18:19:39 +0000387void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
388 this->addDrawCommand(new SkClipRegionCommand(region, op));
chudy@google.com902ebe52012-06-29 14:21:22 +0000389}
390
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000391void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
robertphillips9bafc302015-02-13 11:13:00 -0800392 this->addDrawCommand(new SkConcatCommand(matrix));
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000393 this->INHERITED::didConcat(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000394}
395
reed41af9662015-01-05 07:49:08 -0800396void SkDebugCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
397 SkScalar top, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000398 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000399}
400
reed41af9662015-01-05 07:49:08 -0800401void SkDebugCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700402 const SkPaint* paint, SrcRectConstraint constraint) {
reeda5517e22015-07-14 10:54:12 -0700403 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint,
404 (SrcRectConstraint)constraint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000405}
406
reed41af9662015-01-05 07:49:08 -0800407void SkDebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
408 const SkRect& dst, const SkPaint* paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000409 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000410}
411
reed41af9662015-01-05 07:49:08 -0800412void SkDebugCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
413 const SkPaint* paint) {
fmalita651c9202015-07-22 10:23:01 -0700414 this->addDrawCommand(new SkDrawImageCommand(image, left, top, paint));
reed41af9662015-01-05 07:49:08 -0800415}
416
417void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
reed562fe472015-07-28 07:35:14 -0700418 const SkPaint* paint, SrcRectConstraint constraint) {
fmalita651c9202015-07-22 10:23:01 -0700419 this->addDrawCommand(new SkDrawImageRectCommand(image, src, dst, paint, constraint));
reed41af9662015-01-05 07:49:08 -0800420}
421
reed41af9662015-01-05 07:49:08 -0800422void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000423 this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000424}
425
reed41af9662015-01-05 07:49:08 -0800426void SkDebugCanvas::onDrawPaint(const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000427 this->addDrawCommand(new SkDrawPaintCommand(paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000428}
429
reed41af9662015-01-05 07:49:08 -0800430void SkDebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000431 this->addDrawCommand(new SkDrawPathCommand(path, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000432}
433
mtkleinf0f14112014-12-12 08:46:25 -0800434void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
435 const SkMatrix* matrix,
robertphillipsb3f319f2014-08-13 10:46:23 -0700436 const SkPaint* paint) {
fmalita160ebb22015-04-01 20:58:37 -0700437 this->addDrawCommand(new SkBeginDrawPictureCommand(picture, matrix, paint));
ethannicholas891ad662016-02-12 07:15:45 -0800438 SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
439 picture->playback(this);
fmalita160ebb22015-04-01 20:58:37 -0700440 this->addDrawCommand(new SkEndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
chudy@google.com902ebe52012-06-29 14:21:22 +0000441}
442
reed41af9662015-01-05 07:49:08 -0800443void SkDebugCanvas::onDrawPoints(PointMode mode, size_t count,
444 const SkPoint pts[], const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000445 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000446}
447
reed@google.come0d9ce82014-04-23 04:00:17 +0000448void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
449 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000450 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000451}
452
reed@google.come0d9ce82014-04-23 04:00:17 +0000453void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
454 SkScalar constY, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000455 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000456 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000457}
458
reed41af9662015-01-05 07:49:08 -0800459void SkDebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
chudy@google.com902ebe52012-06-29 14:21:22 +0000460 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000461 addDrawCommand(new SkDrawRectCommand(rect, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000462}
463
reed41af9662015-01-05 07:49:08 -0800464void SkDebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000465 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
robertphillips@google.com67baba42013-01-02 20:20:31 +0000466}
467
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000468void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
469 const SkPaint& paint) {
commit-bot@chromium.org3d305202014-02-24 17:28:55 +0000470 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
commit-bot@chromium.orgab582732014-02-21 12:20:45 +0000471}
472
reed@google.come0d9ce82014-04-23 04:00:17 +0000473void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
474 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000475 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000476}
477
reed@google.come0d9ce82014-04-23 04:00:17 +0000478void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
479 const SkMatrix* matrix, const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000480 this->addDrawCommand(
commit-bot@chromium.org7a115912013-06-18 20:20:55 +0000481 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000482}
483
fmalitab7425172014-08-26 07:56:44 -0700484void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
485 const SkPaint& paint) {
486 this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
487}
488
robertphillips9bafc302015-02-13 11:13:00 -0800489void SkDebugCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
490 const SkPoint texCoords[4], SkXfermode* xmode,
491 const SkPaint& paint) {
492 this->addDrawCommand(new SkDrawPatchCommand(cubics, colors, texCoords, xmode, paint));
493}
494
reed41af9662015-01-05 07:49:08 -0800495void SkDebugCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
496 const SkPoint texs[], const SkColor colors[],
497 SkXfermode*, const uint16_t indices[], int indexCount,
498 const SkPaint& paint) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000499 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
halcanary96fcdcc2015-08-27 07:41:13 -0700500 texs, colors, nullptr, indices, indexCount, paint));
chudy@google.com902ebe52012-06-29 14:21:22 +0000501}
502
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000503void SkDebugCanvas::willRestore() {
504 this->addDrawCommand(new SkRestoreCommand());
505 this->INHERITED::willRestore();
chudy@google.com902ebe52012-06-29 14:21:22 +0000506}
507
Florin Malita5f6102d2014-06-30 10:13:28 -0400508void SkDebugCanvas::willSave() {
509 this->addDrawCommand(new SkSaveCommand());
510 this->INHERITED::willSave();
chudy@google.com902ebe52012-06-29 14:21:22 +0000511}
512
reed4960eee2015-12-18 07:09:18 -0800513SkCanvas::SaveLayerStrategy SkDebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
514 this->addDrawCommand(new SkSaveLayerCommand(rec));
515 (void)this->INHERITED::getSaveLayerStrategy(rec);
commit-bot@chromium.orge54a23f2014-03-12 20:21:48 +0000516 // No need for a full layer.
517 return kNoLayer_SaveLayerStrategy;
chudy@google.com902ebe52012-06-29 14:21:22 +0000518}
519
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000520void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
commit-bot@chromium.org57f74e02014-03-25 23:31:33 +0000521 this->addDrawCommand(new SkSetMatrixCommand(matrix));
commit-bot@chromium.org44c48d02014-03-13 20:03:58 +0000522 this->INHERITED::didSetMatrix(matrix);
chudy@google.com902ebe52012-06-29 14:21:22 +0000523}
524
chudy@google.com902ebe52012-06-29 14:21:22 +0000525void SkDebugCanvas::toggleCommand(int index, bool toggle) {
robertphillips@google.com67baba42013-01-02 20:20:31 +0000526 SkASSERT(index < fCommandVector.count());
527 fCommandVector[index]->setVisible(toggle);
chudy@google.com902ebe52012-06-29 14:21:22 +0000528}
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000529
530static const char* gFillTypeStrs[] = {
531 "kWinding_FillType",
532 "kEvenOdd_FillType",
533 "kInverseWinding_FillType",
534 "kInverseEvenOdd_FillType"
535};
536
537static const char* gOpStrs[] = {
scroggo5965b732015-04-07 06:53:21 -0700538 "kDifference_PathOp",
539 "kIntersect_PathOp",
540 "kUnion_PathOp",
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000541 "kXor_PathOp",
scroggo5965b732015-04-07 06:53:21 -0700542 "kReverseDifference_PathOp",
commit-bot@chromium.org2a67e122014-05-19 13:53:10 +0000543};
544
545static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
546
547void SkDebugCanvas::outputScalar(SkScalar num) {
548 if (num == (int) num) {
549 fClipStackData.appendf("%d", (int) num);
550 } else {
551 SkString str;
552 str.printf("%1.9g", num);
553 int width = (int) str.size();
554 const char* cStr = str.c_str();
555 while (cStr[width - 1] == '0') {
556 --width;
557 }
558 str.resize(width);
559 fClipStackData.appendf("%sf", str.c_str());
560 }
561}
562
563void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
564 for (int index = 0; index < count; ++index) {
565 this->outputScalar(pts[index].fX);
566 fClipStackData.appendf(", ");
567 this->outputScalar(pts[index].fY);
568 if (index + 1 < count) {
569 fClipStackData.appendf(", ");
570 }
571 }
572}
573
574void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
575 this->outputPointsCommon(pts, count);
576 fClipStackData.appendf(");<br>");
577}
578
579void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
580 this->outputPointsCommon(pts, 2);
581 fClipStackData.appendf(", ");
582 this->outputScalar(weight);
583 fClipStackData.appendf(");<br>");
584}
585
586void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
587 SkPath::RawIter iter(path);
588 SkPath::FillType fillType = path.getFillType();
589 fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
590 fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
591 gFillTypeStrs[fillType]);
592 iter.setPath(path);
593 uint8_t verb;
594 SkPoint pts[4];
595 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
596 switch (verb) {
597 case SkPath::kMove_Verb:
598 fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
599 this->outputPoints(&pts[0], 1);
600 continue;
601 case SkPath::kLine_Verb:
602 fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
603 this->outputPoints(&pts[1], 1);
604 break;
605 case SkPath::kQuad_Verb:
606 fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
607 this->outputPoints(&pts[1], 2);
608 break;
609 case SkPath::kConic_Verb:
610 fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
611 this->outputConicPoints(&pts[1], iter.conicWeight());
612 break;
613 case SkPath::kCubic_Verb:
614 fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
615 this->outputPoints(&pts[1], 3);
616 break;
617 case SkPath::kClose_Verb:
618 fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
619 break;
620 default:
621 SkDEBUGFAIL("bad verb");
622 return;
623 }
624 }
625}
626
627void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
628 SkRegion::Op elementOp) {
629 if (elementOp == SkRegion::kReplace_Op) {
630 if (!lastClipStackData(devPath)) {
631 fSaveDevPath = operand;
632 }
633 fCalledAddStackData = false;
634 } else {
635 fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
636 " const char* filename) {<br>");
637 addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
638 addPathData(operand, "pathB");
639 fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
640 kHTML4SpaceIndent, gOpStrs[elementOp]);
641 fClipStackData.appendf("}<br>");
642 fCalledAddStackData = true;
643 }
644}
645
646bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
647 if (fCalledAddStackData) {
648 fClipStackData.appendf("<br>");
649 addPathData(devPath, "pathOut");
650 return true;
651 }
652 return false;
653}