1
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
10 #include "SkColorPriv.h"
11 #include "SkDebugCanvas.h"
12 #include "SkDrawCommand.h"
13 #include "SkDevice.h"
14 #include "SkPaintFilterCanvas.h"
15 #include "SkXfermode.h"
16
17 namespace {
18
19 class OverdrawXfermode : public SkXfermode {
20 public:
xferColor(SkPMColor src,SkPMColor dst) const21 SkPMColor xferColor(SkPMColor src, SkPMColor dst) const override {
22 // This table encodes the color progression of the overdraw visualization
23 static const SkPMColor gTable[] = {
24 SkPackARGB32(0x00, 0x00, 0x00, 0x00),
25 SkPackARGB32(0xFF, 128, 158, 255),
26 SkPackARGB32(0xFF, 170, 185, 212),
27 SkPackARGB32(0xFF, 213, 195, 170),
28 SkPackARGB32(0xFF, 255, 192, 127),
29 SkPackARGB32(0xFF, 255, 185, 85),
30 SkPackARGB32(0xFF, 255, 165, 42),
31 SkPackARGB32(0xFF, 255, 135, 0),
32 SkPackARGB32(0xFF, 255, 95, 0),
33 SkPackARGB32(0xFF, 255, 50, 0),
34 SkPackARGB32(0xFF, 255, 0, 0)
35 };
36
37
38 int idx;
39 if (SkColorGetR(dst) < 64) { // 0
40 idx = 0;
41 } else if (SkColorGetG(dst) < 25) { // 10
42 idx = 9; // cap at 9 for upcoming increment
43 } else if ((SkColorGetB(dst)+21)/42 > 0) { // 1-6
44 idx = 7 - (SkColorGetB(dst)+21)/42;
45 } else { // 7-9
46 idx = 10 - (SkColorGetG(dst)+22)/45;
47 }
48 ++idx;
49 SkASSERT(idx < (int)SK_ARRAY_COUNT(gTable));
50
51 return gTable[idx];
52 }
53
getFactory() const54 Factory getFactory() const override { return NULL; }
55 #ifndef SK_IGNORE_TO_STRING
toString(SkString * str) const56 void toString(SkString* str) const override { str->set("OverdrawXfermode"); }
57 #endif
58 };
59
60 class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
61 public:
DebugPaintFilterCanvas(int width,int height,bool overdrawViz,bool overrideFilterQuality,SkFilterQuality quality)62 DebugPaintFilterCanvas(int width, int height, bool overdrawViz, bool overrideFilterQuality,
63 SkFilterQuality quality)
64 : INHERITED(width, height)
65 , fOverdrawXfermode(overdrawViz ? SkNEW(OverdrawXfermode) : NULL)
66 , fOverrideFilterQuality(overrideFilterQuality)
67 , fFilterQuality(quality) { }
68
69 protected:
onFilterPaint(SkPaint * paint,Type) const70 void onFilterPaint(SkPaint* paint, Type) const override {
71 if (NULL != fOverdrawXfermode.get()) {
72 paint->setAntiAlias(false);
73 paint->setXfermode(fOverdrawXfermode.get());
74 }
75
76 if (fOverrideFilterQuality) {
77 paint->setFilterQuality(fFilterQuality);
78 }
79 }
80
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)81 void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
82 // We need to replay the picture onto this canvas in order to filter its internal paints.
83 this->SkCanvas::onDrawPicture(picture, matrix, paint);
84 }
85
86 private:
87 SkAutoTUnref<SkXfermode> fOverdrawXfermode;
88
89 bool fOverrideFilterQuality;
90 SkFilterQuality fFilterQuality;
91
92 typedef SkPaintFilterCanvas INHERITED;
93 };
94
95 }
96
SkDebugCanvas(int width,int height)97 SkDebugCanvas::SkDebugCanvas(int width, int height)
98 : INHERITED(width, height)
99 , fPicture(NULL)
100 , fFilter(false)
101 , fMegaVizMode(false)
102 , fOverdrawViz(false)
103 , fOverrideFilterQuality(false)
104 , fFilterQuality(kNone_SkFilterQuality) {
105 fUserMatrix.reset();
106
107 // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
108 // operations. This can lead to problems in the debugger which expects all
109 // the operations in the captured skp to appear in the debug canvas. To
110 // circumvent this we create a wide open clip here (an empty clip rect
111 // is not sufficient).
112 // Internally, the SkRect passed to clipRect is converted to an SkIRect and
113 // rounded out. The following code creates a nearly maximal rect that will
114 // not get collapsed by the coming conversions (Due to precision loss the
115 // inset has to be surprisingly large).
116 SkIRect largeIRect = SkIRect::MakeLargest();
117 largeIRect.inset(1024, 1024);
118 SkRect large = SkRect::Make(largeIRect);
119 #ifdef SK_DEBUG
120 SkASSERT(!large.roundOut().isEmpty());
121 #endif
122 // call the base class' version to avoid adding a draw command
123 this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
124 }
125
~SkDebugCanvas()126 SkDebugCanvas::~SkDebugCanvas() {
127 fCommandVector.deleteAll();
128 }
129
addDrawCommand(SkDrawCommand * command)130 void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
131 fCommandVector.push(command);
132 }
133
draw(SkCanvas * canvas)134 void SkDebugCanvas::draw(SkCanvas* canvas) {
135 if (!fCommandVector.isEmpty()) {
136 this->drawTo(canvas, fCommandVector.count() - 1);
137 }
138 }
139
applyUserTransform(SkCanvas * canvas)140 void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
141 canvas->concat(fUserMatrix);
142 }
143
getCommandAtPoint(int x,int y,int index)144 int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
145 SkBitmap bitmap;
146 bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
147
148 SkCanvas canvas(bitmap);
149 canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
150 this->applyUserTransform(&canvas);
151
152 int layer = 0;
153 SkColor prev = bitmap.getColor(0,0);
154 for (int i = 0; i < index; i++) {
155 if (fCommandVector[i]->isVisible()) {
156 fCommandVector[i]->setUserMatrix(fUserMatrix);
157 fCommandVector[i]->execute(&canvas);
158 }
159 if (prev != bitmap.getColor(0,0)) {
160 layer = i;
161 }
162 prev = bitmap.getColor(0,0);
163 }
164 return layer;
165 }
166
167 class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
168 public:
SkDebugClipVisitor(SkCanvas * canvas)169 SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
170
clipRect(const SkRect & r,SkRegion::Op,bool doAA)171 void clipRect(const SkRect& r, SkRegion::Op, bool doAA) override {
172 SkPaint p;
173 p.setColor(SK_ColorRED);
174 p.setStyle(SkPaint::kStroke_Style);
175 p.setAntiAlias(doAA);
176 fCanvas->drawRect(r, p);
177 }
clipRRect(const SkRRect & rr,SkRegion::Op,bool doAA)178 void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) override {
179 SkPaint p;
180 p.setColor(SK_ColorGREEN);
181 p.setStyle(SkPaint::kStroke_Style);
182 p.setAntiAlias(doAA);
183 fCanvas->drawRRect(rr, p);
184 }
clipPath(const SkPath & path,SkRegion::Op,bool doAA)185 void clipPath(const SkPath& path, SkRegion::Op, bool doAA) override {
186 SkPaint p;
187 p.setColor(SK_ColorBLUE);
188 p.setStyle(SkPaint::kStroke_Style);
189 p.setAntiAlias(doAA);
190 fCanvas->drawPath(path, p);
191 }
192
193 protected:
194 SkCanvas* fCanvas;
195
196 private:
197 typedef SkCanvas::ClipVisitor INHERITED;
198 };
199
200 // set up the saveLayer commands so that the active ones
201 // return true in their 'active' method
markActiveCommands(int index)202 void SkDebugCanvas::markActiveCommands(int index) {
203 fActiveLayers.rewind();
204
205 for (int i = 0; i < fCommandVector.count(); ++i) {
206 fCommandVector[i]->setActive(false);
207 }
208
209 for (int i = 0; i < index; ++i) {
210 SkDrawCommand::Action result = fCommandVector[i]->action();
211 if (SkDrawCommand::kPushLayer_Action == result) {
212 fActiveLayers.push(fCommandVector[i]);
213 } else if (SkDrawCommand::kPopLayer_Action == result) {
214 fActiveLayers.pop();
215 }
216 }
217
218 for (int i = 0; i < fActiveLayers.count(); ++i) {
219 fActiveLayers[i]->setActive(true);
220 }
221
222 }
223
drawTo(SkCanvas * canvas,int index)224 void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
225 SkASSERT(!fCommandVector.isEmpty());
226 SkASSERT(index < fCommandVector.count());
227
228 int saveCount = canvas->save();
229
230 SkRect windowRect = SkRect::MakeWH(SkIntToScalar(canvas->getBaseLayerSize().width()),
231 SkIntToScalar(canvas->getBaseLayerSize().height()));
232
233 bool pathOpsMode = getAllowSimplifyClip();
234 canvas->setAllowSimplifyClip(pathOpsMode);
235 canvas->clear(SK_ColorTRANSPARENT);
236 canvas->resetMatrix();
237 if (!windowRect.isEmpty()) {
238 canvas->clipRect(windowRect, SkRegion::kReplace_Op);
239 }
240 this->applyUserTransform(canvas);
241
242 if (fPaintFilterCanvas) {
243 fPaintFilterCanvas->addCanvas(canvas);
244 canvas = fPaintFilterCanvas.get();
245 }
246
247 if (fMegaVizMode) {
248 this->markActiveCommands(index);
249 }
250
251 for (int i = 0; i <= index; i++) {
252 if (i == index && fFilter) {
253 canvas->clear(0xAAFFFFFF);
254 }
255
256 if (fCommandVector[i]->isVisible()) {
257 if (fMegaVizMode && fCommandVector[i]->active()) {
258 // "active" commands execute their visualization behaviors:
259 // All active saveLayers get replaced with saves so all draws go to the
260 // visible canvas.
261 // All active culls draw their cull box
262 fCommandVector[i]->vizExecute(canvas);
263 } else {
264 fCommandVector[i]->setUserMatrix(fUserMatrix);
265 fCommandVector[i]->execute(canvas);
266 }
267 }
268 }
269
270 if (fMegaVizMode) {
271 canvas->save();
272 // nuke the CTM
273 canvas->resetMatrix();
274 // turn off clipping
275 if (!windowRect.isEmpty()) {
276 SkRect r = windowRect;
277 r.outset(SK_Scalar1, SK_Scalar1);
278 canvas->clipRect(r, SkRegion::kReplace_Op);
279 }
280 // visualize existing clips
281 SkDebugClipVisitor visitor(canvas);
282
283 canvas->replayClips(&visitor);
284
285 canvas->restore();
286 }
287 if (pathOpsMode) {
288 this->resetClipStackData();
289 const SkClipStack* clipStack = canvas->getClipStack();
290 SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
291 const SkClipStack::Element* element;
292 SkPath devPath;
293 while ((element = iter.next())) {
294 SkClipStack::Element::Type type = element->getType();
295 SkPath operand;
296 if (type != SkClipStack::Element::kEmpty_Type) {
297 element->asPath(&operand);
298 }
299 SkRegion::Op elementOp = element->getOp();
300 this->addClipStackData(devPath, operand, elementOp);
301 if (elementOp == SkRegion::kReplace_Op) {
302 devPath = operand;
303 } else {
304 Op(devPath, operand, (SkPathOp) elementOp, &devPath);
305 }
306 }
307 this->lastClipStackData(devPath);
308 }
309 fMatrix = canvas->getTotalMatrix();
310 if (!canvas->getClipDeviceBounds(&fClip)) {
311 fClip.setEmpty();
312 }
313
314 canvas->restoreToCount(saveCount);
315
316 if (fPaintFilterCanvas) {
317 fPaintFilterCanvas->removeAll();
318 }
319 }
320
deleteDrawCommandAt(int index)321 void SkDebugCanvas::deleteDrawCommandAt(int index) {
322 SkASSERT(index < fCommandVector.count());
323 delete fCommandVector[index];
324 fCommandVector.remove(index);
325 }
326
getDrawCommandAt(int index)327 SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
328 SkASSERT(index < fCommandVector.count());
329 return fCommandVector[index];
330 }
331
setDrawCommandAt(int index,SkDrawCommand * command)332 void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
333 SkASSERT(index < fCommandVector.count());
334 delete fCommandVector[index];
335 fCommandVector[index] = command;
336 }
337
getCommandInfo(int index) const338 const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
339 SkASSERT(index < fCommandVector.count());
340 return fCommandVector[index]->Info();
341 }
342
getDrawCommandVisibilityAt(int index)343 bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
344 SkASSERT(index < fCommandVector.count());
345 return fCommandVector[index]->isVisible();
346 }
347
getDrawCommands() const348 const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
349 return fCommandVector;
350 }
351
getDrawCommands()352 SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
353 return fCommandVector;
354 }
355
updatePaintFilterCanvas()356 void SkDebugCanvas::updatePaintFilterCanvas() {
357 if (!fOverdrawViz && !fOverrideFilterQuality) {
358 fPaintFilterCanvas.reset(NULL);
359 return;
360 }
361
362 const SkImageInfo info = this->imageInfo();
363 fPaintFilterCanvas.reset(SkNEW_ARGS(DebugPaintFilterCanvas, (info.width(),
364 info.height(),
365 fOverdrawViz,
366 fOverrideFilterQuality,
367 fFilterQuality)));
368 }
369
setOverdrawViz(bool overdrawViz)370 void SkDebugCanvas::setOverdrawViz(bool overdrawViz) {
371 if (fOverdrawViz == overdrawViz) {
372 return;
373 }
374
375 fOverdrawViz = overdrawViz;
376 this->updatePaintFilterCanvas();
377 }
378
overrideTexFiltering(bool overrideTexFiltering,SkFilterQuality quality)379 void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality quality) {
380 if (fOverrideFilterQuality == overrideTexFiltering && fFilterQuality == quality) {
381 return;
382 }
383
384 fOverrideFilterQuality = overrideTexFiltering;
385 fFilterQuality = quality;
386 this->updatePaintFilterCanvas();
387 }
388
onClipPath(const SkPath & path,SkRegion::Op op,ClipEdgeStyle edgeStyle)389 void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
390 this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
391 }
392
onClipRect(const SkRect & rect,SkRegion::Op op,ClipEdgeStyle edgeStyle)393 void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
394 this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
395 }
396
onClipRRect(const SkRRect & rrect,SkRegion::Op op,ClipEdgeStyle edgeStyle)397 void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
398 this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
399 }
400
onClipRegion(const SkRegion & region,SkRegion::Op op)401 void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
402 this->addDrawCommand(new SkClipRegionCommand(region, op));
403 }
404
didConcat(const SkMatrix & matrix)405 void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
406 this->addDrawCommand(new SkConcatCommand(matrix));
407 this->INHERITED::didConcat(matrix);
408 }
409
onDrawBitmap(const SkBitmap & bitmap,SkScalar left,SkScalar top,const SkPaint * paint)410 void SkDebugCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
411 SkScalar top, const SkPaint* paint) {
412 this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
413 }
414
onDrawBitmapRect(const SkBitmap & bitmap,const SkRect * src,const SkRect & dst,const SkPaint * paint,DrawBitmapRectFlags flags)415 void SkDebugCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
416 const SkPaint* paint, DrawBitmapRectFlags flags) {
417 this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint, flags));
418 }
419
onDrawBitmapNine(const SkBitmap & bitmap,const SkIRect & center,const SkRect & dst,const SkPaint * paint)420 void SkDebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
421 const SkRect& dst, const SkPaint* paint) {
422 this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
423 }
424
onDrawImage(const SkImage * image,SkScalar left,SkScalar top,const SkPaint * paint)425 void SkDebugCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
426 const SkPaint* paint) {
427 SkDebugf("SkDebugCanvas::onDrawImage unimplemented\n");
428 }
429
onDrawImageRect(const SkImage * image,const SkRect * src,const SkRect & dst,const SkPaint * paint)430 void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
431 const SkPaint* paint) {
432 SkDebugf("SkDebugCanvas::onDrawImageRect unimplemented\n");
433 }
434
beginCommentGroup(const char * description)435 void SkDebugCanvas::beginCommentGroup(const char* description) {
436 this->addDrawCommand(new SkBeginCommentGroupCommand(description));
437 }
438
addComment(const char * kywd,const char * value)439 void SkDebugCanvas::addComment(const char* kywd, const char* value) {
440 this->addDrawCommand(new SkCommentCommand(kywd, value));
441 }
442
endCommentGroup()443 void SkDebugCanvas::endCommentGroup() {
444 this->addDrawCommand(new SkEndCommentGroupCommand());
445 }
446
onDrawOval(const SkRect & oval,const SkPaint & paint)447 void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
448 this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
449 }
450
onDrawPaint(const SkPaint & paint)451 void SkDebugCanvas::onDrawPaint(const SkPaint& paint) {
452 this->addDrawCommand(new SkDrawPaintCommand(paint));
453 }
454
onDrawPath(const SkPath & path,const SkPaint & paint)455 void SkDebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
456 this->addDrawCommand(new SkDrawPathCommand(path, paint));
457 }
458
onDrawPicture(const SkPicture * picture,const SkMatrix * matrix,const SkPaint * paint)459 void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
460 const SkMatrix* matrix,
461 const SkPaint* paint) {
462 this->addDrawCommand(new SkBeginDrawPictureCommand(picture, matrix, paint));
463 this->INHERITED::onDrawPicture(picture, matrix, paint);
464 this->addDrawCommand(new SkEndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
465 }
466
onDrawPoints(PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint)467 void SkDebugCanvas::onDrawPoints(PointMode mode, size_t count,
468 const SkPoint pts[], const SkPaint& paint) {
469 this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
470 }
471
onDrawPosText(const void * text,size_t byteLength,const SkPoint pos[],const SkPaint & paint)472 void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
473 const SkPaint& paint) {
474 this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
475 }
476
onDrawPosTextH(const void * text,size_t byteLength,const SkScalar xpos[],SkScalar constY,const SkPaint & paint)477 void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
478 SkScalar constY, const SkPaint& paint) {
479 this->addDrawCommand(
480 new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
481 }
482
onDrawRect(const SkRect & rect,const SkPaint & paint)483 void SkDebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
484 // NOTE(chudy): Messing up when renamed to DrawRect... Why?
485 addDrawCommand(new SkDrawRectCommand(rect, paint));
486 }
487
onDrawRRect(const SkRRect & rrect,const SkPaint & paint)488 void SkDebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
489 this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
490 }
491
onDrawDRRect(const SkRRect & outer,const SkRRect & inner,const SkPaint & paint)492 void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
493 const SkPaint& paint) {
494 this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
495 }
496
onDrawSprite(const SkBitmap & bitmap,int left,int top,const SkPaint * paint)497 void SkDebugCanvas::onDrawSprite(const SkBitmap& bitmap, int left, int top, const SkPaint* paint) {
498 this->addDrawCommand(new SkDrawSpriteCommand(bitmap, left, top, paint));
499 }
500
onDrawText(const void * text,size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint)501 void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
502 const SkPaint& paint) {
503 this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
504 }
505
onDrawTextOnPath(const void * text,size_t byteLength,const SkPath & path,const SkMatrix * matrix,const SkPaint & paint)506 void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
507 const SkMatrix* matrix, const SkPaint& paint) {
508 this->addDrawCommand(
509 new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
510 }
511
onDrawTextBlob(const SkTextBlob * blob,SkScalar x,SkScalar y,const SkPaint & paint)512 void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
513 const SkPaint& paint) {
514 this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
515 }
516
onDrawPatch(const SkPoint cubics[12],const SkColor colors[4],const SkPoint texCoords[4],SkXfermode * xmode,const SkPaint & paint)517 void SkDebugCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
518 const SkPoint texCoords[4], SkXfermode* xmode,
519 const SkPaint& paint) {
520 this->addDrawCommand(new SkDrawPatchCommand(cubics, colors, texCoords, xmode, paint));
521 }
522
onDrawVertices(VertexMode vmode,int vertexCount,const SkPoint vertices[],const SkPoint texs[],const SkColor colors[],SkXfermode *,const uint16_t indices[],int indexCount,const SkPaint & paint)523 void SkDebugCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
524 const SkPoint texs[], const SkColor colors[],
525 SkXfermode*, const uint16_t indices[], int indexCount,
526 const SkPaint& paint) {
527 this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
528 texs, colors, NULL, indices, indexCount, paint));
529 }
530
willRestore()531 void SkDebugCanvas::willRestore() {
532 this->addDrawCommand(new SkRestoreCommand());
533 this->INHERITED::willRestore();
534 }
535
willSave()536 void SkDebugCanvas::willSave() {
537 this->addDrawCommand(new SkSaveCommand());
538 this->INHERITED::willSave();
539 }
540
willSaveLayer(const SkRect * bounds,const SkPaint * paint,SaveFlags flags)541 SkCanvas::SaveLayerStrategy SkDebugCanvas::willSaveLayer(const SkRect* bounds, const SkPaint* paint,
542 SaveFlags flags) {
543 this->addDrawCommand(new SkSaveLayerCommand(bounds, paint, flags));
544 this->INHERITED::willSaveLayer(bounds, paint, flags);
545 // No need for a full layer.
546 return kNoLayer_SaveLayerStrategy;
547 }
548
didSetMatrix(const SkMatrix & matrix)549 void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
550 this->addDrawCommand(new SkSetMatrixCommand(matrix));
551 this->INHERITED::didSetMatrix(matrix);
552 }
553
toggleCommand(int index,bool toggle)554 void SkDebugCanvas::toggleCommand(int index, bool toggle) {
555 SkASSERT(index < fCommandVector.count());
556 fCommandVector[index]->setVisible(toggle);
557 }
558
559 static const char* gFillTypeStrs[] = {
560 "kWinding_FillType",
561 "kEvenOdd_FillType",
562 "kInverseWinding_FillType",
563 "kInverseEvenOdd_FillType"
564 };
565
566 static const char* gOpStrs[] = {
567 "kDifference_PathOp",
568 "kIntersect_PathOp",
569 "kUnion_PathOp",
570 "kXor_PathOp",
571 "kReverseDifference_PathOp",
572 };
573
574 static const char kHTML4SpaceIndent[] = " ";
575
outputScalar(SkScalar num)576 void SkDebugCanvas::outputScalar(SkScalar num) {
577 if (num == (int) num) {
578 fClipStackData.appendf("%d", (int) num);
579 } else {
580 SkString str;
581 str.printf("%1.9g", num);
582 int width = (int) str.size();
583 const char* cStr = str.c_str();
584 while (cStr[width - 1] == '0') {
585 --width;
586 }
587 str.resize(width);
588 fClipStackData.appendf("%sf", str.c_str());
589 }
590 }
591
outputPointsCommon(const SkPoint * pts,int count)592 void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
593 for (int index = 0; index < count; ++index) {
594 this->outputScalar(pts[index].fX);
595 fClipStackData.appendf(", ");
596 this->outputScalar(pts[index].fY);
597 if (index + 1 < count) {
598 fClipStackData.appendf(", ");
599 }
600 }
601 }
602
outputPoints(const SkPoint * pts,int count)603 void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
604 this->outputPointsCommon(pts, count);
605 fClipStackData.appendf(");<br>");
606 }
607
outputConicPoints(const SkPoint * pts,SkScalar weight)608 void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
609 this->outputPointsCommon(pts, 2);
610 fClipStackData.appendf(", ");
611 this->outputScalar(weight);
612 fClipStackData.appendf(");<br>");
613 }
614
addPathData(const SkPath & path,const char * pathName)615 void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
616 SkPath::RawIter iter(path);
617 SkPath::FillType fillType = path.getFillType();
618 fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
619 fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
620 gFillTypeStrs[fillType]);
621 iter.setPath(path);
622 uint8_t verb;
623 SkPoint pts[4];
624 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
625 switch (verb) {
626 case SkPath::kMove_Verb:
627 fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
628 this->outputPoints(&pts[0], 1);
629 continue;
630 case SkPath::kLine_Verb:
631 fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
632 this->outputPoints(&pts[1], 1);
633 break;
634 case SkPath::kQuad_Verb:
635 fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
636 this->outputPoints(&pts[1], 2);
637 break;
638 case SkPath::kConic_Verb:
639 fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
640 this->outputConicPoints(&pts[1], iter.conicWeight());
641 break;
642 case SkPath::kCubic_Verb:
643 fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
644 this->outputPoints(&pts[1], 3);
645 break;
646 case SkPath::kClose_Verb:
647 fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
648 break;
649 default:
650 SkDEBUGFAIL("bad verb");
651 return;
652 }
653 }
654 }
655
addClipStackData(const SkPath & devPath,const SkPath & operand,SkRegion::Op elementOp)656 void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
657 SkRegion::Op elementOp) {
658 if (elementOp == SkRegion::kReplace_Op) {
659 if (!lastClipStackData(devPath)) {
660 fSaveDevPath = operand;
661 }
662 fCalledAddStackData = false;
663 } else {
664 fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
665 " const char* filename) {<br>");
666 addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
667 addPathData(operand, "pathB");
668 fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
669 kHTML4SpaceIndent, gOpStrs[elementOp]);
670 fClipStackData.appendf("}<br>");
671 fCalledAddStackData = true;
672 }
673 }
674
lastClipStackData(const SkPath & devPath)675 bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
676 if (fCalledAddStackData) {
677 fClipStackData.appendf("<br>");
678 addPathData(devPath, "pathOut");
679 return true;
680 }
681 return false;
682 }
683