| 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 |