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