aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools
diff options
context:
space:
mode:
authorGravatar ethannicholas <ethannicholas@google.com>2016-02-09 12:44:06 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-02-09 12:44:06 -0800
commit3cb954245cecf262d740a83913681b9fe4b41555 (patch)
treec334c212efc44b713b4750e44361deaa624a24cc /tools
parenta23659fcee922be39d64ac3abff2cf9a4f97921b (diff)
moved debugger support files from src/utils/debugger to tools/debugger
Diffstat (limited to 'tools')
-rw-r--r--tools/debugger/SkDebugCanvas.cpp624
-rw-r--r--tools/debugger/SkDebugCanvas.h269
-rw-r--r--tools/debugger/SkDrawCommand.cpp989
-rw-r--r--tools/debugger/SkDrawCommand.h586
-rw-r--r--tools/debugger/SkObjectParser.cpp405
-rw-r--r--tools/debugger/SkObjectParser.h134
-rw-r--r--tools/debugger/SkOverdrawMode.cpp324
-rw-r--r--tools/debugger/SkOverdrawMode.h25
8 files changed, 3356 insertions, 0 deletions
diff --git a/tools/debugger/SkDebugCanvas.cpp b/tools/debugger/SkDebugCanvas.cpp
new file mode 100644
index 0000000000..c2dd8f8a19
--- /dev/null
+++ b/tools/debugger/SkDebugCanvas.cpp
@@ -0,0 +1,624 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkClipStack.h"
+#include "SkDebugCanvas.h"
+#include "SkDrawCommand.h"
+#include "SkDevice.h"
+#include "SkPaintFilterCanvas.h"
+#include "SkOverdrawMode.h"
+
+class DebugPaintFilterCanvas : public SkPaintFilterCanvas {
+public:
+ DebugPaintFilterCanvas(int width,
+ int height,
+ bool overdrawViz,
+ bool overrideFilterQuality,
+ SkFilterQuality quality)
+ : INHERITED(width, height)
+ , fOverdrawXfermode(overdrawViz ? SkOverdrawMode::Create() : nullptr)
+ , fOverrideFilterQuality(overrideFilterQuality)
+ , fFilterQuality(quality) {}
+
+protected:
+ bool onFilter(SkTCopyOnFirstWrite<SkPaint>* paint, Type) const override {
+ if (*paint) {
+ if (nullptr != fOverdrawXfermode.get()) {
+ paint->writable()->setAntiAlias(false);
+ paint->writable()->setXfermode(fOverdrawXfermode.get());
+ }
+
+ if (fOverrideFilterQuality) {
+ paint->writable()->setFilterQuality(fFilterQuality);
+ }
+ }
+ return true;
+ }
+
+ void onDrawPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) override {
+ // We need to replay the picture onto this canvas in order to filter its internal paints.
+ this->SkCanvas::onDrawPicture(picture, matrix, paint);
+ }
+
+private:
+ SkAutoTUnref<SkXfermode> fOverdrawXfermode;
+
+ bool fOverrideFilterQuality;
+ SkFilterQuality fFilterQuality;
+
+ typedef SkPaintFilterCanvas INHERITED;
+};
+
+SkDebugCanvas::SkDebugCanvas(int width, int height)
+ : INHERITED(width, height)
+ , fPicture(nullptr)
+ , fFilter(false)
+ , fMegaVizMode(false)
+ , fOverdrawViz(false)
+ , fOverrideFilterQuality(false)
+ , fFilterQuality(kNone_SkFilterQuality) {
+ fUserMatrix.reset();
+
+ // SkPicturePlayback uses the base-class' quickReject calls to cull clipped
+ // operations. This can lead to problems in the debugger which expects all
+ // the operations in the captured skp to appear in the debug canvas. To
+ // circumvent this we create a wide open clip here (an empty clip rect
+ // is not sufficient).
+ // Internally, the SkRect passed to clipRect is converted to an SkIRect and
+ // rounded out. The following code creates a nearly maximal rect that will
+ // not get collapsed by the coming conversions (Due to precision loss the
+ // inset has to be surprisingly large).
+ SkIRect largeIRect = SkIRect::MakeLargest();
+ largeIRect.inset(1024, 1024);
+ SkRect large = SkRect::Make(largeIRect);
+#ifdef SK_DEBUG
+ SkASSERT(!large.roundOut().isEmpty());
+#endif
+ // call the base class' version to avoid adding a draw command
+ this->INHERITED::onClipRect(large, SkRegion::kReplace_Op, kHard_ClipEdgeStyle);
+}
+
+SkDebugCanvas::~SkDebugCanvas() {
+ fCommandVector.deleteAll();
+}
+
+void SkDebugCanvas::addDrawCommand(SkDrawCommand* command) {
+ fCommandVector.push(command);
+}
+
+void SkDebugCanvas::draw(SkCanvas* canvas) {
+ if (!fCommandVector.isEmpty()) {
+ this->drawTo(canvas, fCommandVector.count() - 1);
+ }
+}
+
+void SkDebugCanvas::applyUserTransform(SkCanvas* canvas) {
+ canvas->concat(fUserMatrix);
+}
+
+int SkDebugCanvas::getCommandAtPoint(int x, int y, int index) {
+ SkBitmap bitmap;
+ bitmap.allocPixels(SkImageInfo::MakeN32Premul(1, 1));
+
+ SkCanvas canvas(bitmap);
+ canvas.translate(SkIntToScalar(-x), SkIntToScalar(-y));
+ this->applyUserTransform(&canvas);
+
+ int layer = 0;
+ SkColor prev = bitmap.getColor(0,0);
+ for (int i = 0; i < index; i++) {
+ if (fCommandVector[i]->isVisible()) {
+ fCommandVector[i]->setUserMatrix(fUserMatrix);
+ fCommandVector[i]->execute(&canvas);
+ }
+ if (prev != bitmap.getColor(0,0)) {
+ layer = i;
+ }
+ prev = bitmap.getColor(0,0);
+ }
+ return layer;
+}
+
+class SkDebugClipVisitor : public SkCanvas::ClipVisitor {
+public:
+ SkDebugClipVisitor(SkCanvas* canvas) : fCanvas(canvas) {}
+
+ void clipRect(const SkRect& r, SkRegion::Op, bool doAA) override {
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setAntiAlias(doAA);
+ fCanvas->drawRect(r, p);
+ }
+ void clipRRect(const SkRRect& rr, SkRegion::Op, bool doAA) override {
+ SkPaint p;
+ p.setColor(SK_ColorGREEN);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setAntiAlias(doAA);
+ fCanvas->drawRRect(rr, p);
+ }
+ void clipPath(const SkPath& path, SkRegion::Op, bool doAA) override {
+ SkPaint p;
+ p.setColor(SK_ColorBLUE);
+ p.setStyle(SkPaint::kStroke_Style);
+ p.setAntiAlias(doAA);
+ fCanvas->drawPath(path, p);
+ }
+
+protected:
+ SkCanvas* fCanvas;
+
+private:
+ typedef SkCanvas::ClipVisitor INHERITED;
+};
+
+// set up the saveLayer commands so that the active ones
+// return true in their 'active' method
+void SkDebugCanvas::markActiveCommands(int index) {
+ fActiveLayers.rewind();
+
+ for (int i = 0; i < fCommandVector.count(); ++i) {
+ fCommandVector[i]->setActive(false);
+ }
+
+ for (int i = 0; i < index; ++i) {
+ SkDrawCommand::Action result = fCommandVector[i]->action();
+ if (SkDrawCommand::kPushLayer_Action == result) {
+ fActiveLayers.push(fCommandVector[i]);
+ } else if (SkDrawCommand::kPopLayer_Action == result) {
+ fActiveLayers.pop();
+ }
+ }
+
+ for (int i = 0; i < fActiveLayers.count(); ++i) {
+ fActiveLayers[i]->setActive(true);
+ }
+
+}
+
+void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) {
+ SkASSERT(!fCommandVector.isEmpty());
+ SkASSERT(index < fCommandVector.count());
+
+ int saveCount = canvas->save();
+
+ SkRect windowRect = SkRect::MakeWH(SkIntToScalar(canvas->getBaseLayerSize().width()),
+ SkIntToScalar(canvas->getBaseLayerSize().height()));
+
+ bool pathOpsMode = getAllowSimplifyClip();
+ canvas->setAllowSimplifyClip(pathOpsMode);
+ canvas->clear(SK_ColorTRANSPARENT);
+ canvas->resetMatrix();
+ if (!windowRect.isEmpty()) {
+ canvas->clipRect(windowRect, SkRegion::kReplace_Op);
+ }
+ this->applyUserTransform(canvas);
+
+ if (fPaintFilterCanvas) {
+ fPaintFilterCanvas->addCanvas(canvas);
+ canvas = fPaintFilterCanvas.get();
+ }
+
+ if (fMegaVizMode) {
+ this->markActiveCommands(index);
+ }
+
+ for (int i = 0; i <= index; i++) {
+ if (i == index && fFilter) {
+ canvas->clear(0xAAFFFFFF);
+ }
+
+ if (fCommandVector[i]->isVisible()) {
+ if (fMegaVizMode && fCommandVector[i]->active()) {
+ // "active" commands execute their visualization behaviors:
+ // All active saveLayers get replaced with saves so all draws go to the
+ // visible canvas.
+ // All active culls draw their cull box
+ fCommandVector[i]->vizExecute(canvas);
+ } else {
+ fCommandVector[i]->setUserMatrix(fUserMatrix);
+ fCommandVector[i]->execute(canvas);
+ }
+ }
+ }
+
+ if (fMegaVizMode) {
+ canvas->save();
+ // nuke the CTM
+ canvas->resetMatrix();
+ // turn off clipping
+ if (!windowRect.isEmpty()) {
+ SkRect r = windowRect;
+ r.outset(SK_Scalar1, SK_Scalar1);
+ canvas->clipRect(r, SkRegion::kReplace_Op);
+ }
+ // visualize existing clips
+ SkDebugClipVisitor visitor(canvas);
+
+ canvas->replayClips(&visitor);
+
+ canvas->restore();
+ }
+ if (pathOpsMode) {
+ this->resetClipStackData();
+ const SkClipStack* clipStack = canvas->getClipStack();
+ SkClipStack::Iter iter(*clipStack, SkClipStack::Iter::kBottom_IterStart);
+ const SkClipStack::Element* element;
+ SkPath devPath;
+ while ((element = iter.next())) {
+ SkClipStack::Element::Type type = element->getType();
+ SkPath operand;
+ if (type != SkClipStack::Element::kEmpty_Type) {
+ element->asPath(&operand);
+ }
+ SkRegion::Op elementOp = element->getOp();
+ this->addClipStackData(devPath, operand, elementOp);
+ if (elementOp == SkRegion::kReplace_Op) {
+ devPath = operand;
+ } else {
+ Op(devPath, operand, (SkPathOp) elementOp, &devPath);
+ }
+ }
+ this->lastClipStackData(devPath);
+ }
+ fMatrix = canvas->getTotalMatrix();
+ if (!canvas->getClipDeviceBounds(&fClip)) {
+ fClip.setEmpty();
+ }
+
+ canvas->restoreToCount(saveCount);
+
+ if (fPaintFilterCanvas) {
+ fPaintFilterCanvas->removeAll();
+ }
+}
+
+void SkDebugCanvas::deleteDrawCommandAt(int index) {
+ SkASSERT(index < fCommandVector.count());
+ delete fCommandVector[index];
+ fCommandVector.remove(index);
+}
+
+SkDrawCommand* SkDebugCanvas::getDrawCommandAt(int index) {
+ SkASSERT(index < fCommandVector.count());
+ return fCommandVector[index];
+}
+
+void SkDebugCanvas::setDrawCommandAt(int index, SkDrawCommand* command) {
+ SkASSERT(index < fCommandVector.count());
+ delete fCommandVector[index];
+ fCommandVector[index] = command;
+}
+
+const SkTDArray<SkString*>* SkDebugCanvas::getCommandInfo(int index) const {
+ SkASSERT(index < fCommandVector.count());
+ return fCommandVector[index]->Info();
+}
+
+bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
+ SkASSERT(index < fCommandVector.count());
+ return fCommandVector[index]->isVisible();
+}
+
+const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
+ return fCommandVector;
+}
+
+SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() {
+ return fCommandVector;
+}
+
+void SkDebugCanvas::updatePaintFilterCanvas() {
+ if (!fOverdrawViz && !fOverrideFilterQuality) {
+ fPaintFilterCanvas.reset(nullptr);
+ return;
+ }
+
+ const SkImageInfo info = this->imageInfo();
+ fPaintFilterCanvas.reset(new DebugPaintFilterCanvas(info.width(), info.height(), fOverdrawViz,
+ fOverrideFilterQuality, fFilterQuality));
+}
+
+void SkDebugCanvas::setOverdrawViz(bool overdrawViz) {
+ if (fOverdrawViz == overdrawViz) {
+ return;
+ }
+
+ fOverdrawViz = overdrawViz;
+ this->updatePaintFilterCanvas();
+}
+
+void SkDebugCanvas::overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality quality) {
+ if (fOverrideFilterQuality == overrideTexFiltering && fFilterQuality == quality) {
+ return;
+ }
+
+ fOverrideFilterQuality = overrideTexFiltering;
+ fFilterQuality = quality;
+ this->updatePaintFilterCanvas();
+}
+
+void SkDebugCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
+ this->addDrawCommand(new SkClipPathCommand(path, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void SkDebugCanvas::onClipRect(const SkRect& rect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
+ this->addDrawCommand(new SkClipRectCommand(rect, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void SkDebugCanvas::onClipRRect(const SkRRect& rrect, SkRegion::Op op, ClipEdgeStyle edgeStyle) {
+ this->addDrawCommand(new SkClipRRectCommand(rrect, op, kSoft_ClipEdgeStyle == edgeStyle));
+}
+
+void SkDebugCanvas::onClipRegion(const SkRegion& region, SkRegion::Op op) {
+ this->addDrawCommand(new SkClipRegionCommand(region, op));
+}
+
+void SkDebugCanvas::didConcat(const SkMatrix& matrix) {
+ this->addDrawCommand(new SkConcatCommand(matrix));
+ this->INHERITED::didConcat(matrix);
+}
+
+void SkDebugCanvas::onDrawBitmap(const SkBitmap& bitmap, SkScalar left,
+ SkScalar top, const SkPaint* paint) {
+ this->addDrawCommand(new SkDrawBitmapCommand(bitmap, left, top, paint));
+}
+
+void SkDebugCanvas::onDrawBitmapRect(const SkBitmap& bitmap, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) {
+ this->addDrawCommand(new SkDrawBitmapRectCommand(bitmap, src, dst, paint,
+ (SrcRectConstraint)constraint));
+}
+
+void SkDebugCanvas::onDrawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint) {
+ this->addDrawCommand(new SkDrawBitmapNineCommand(bitmap, center, dst, paint));
+}
+
+void SkDebugCanvas::onDrawImage(const SkImage* image, SkScalar left, SkScalar top,
+ const SkPaint* paint) {
+ this->addDrawCommand(new SkDrawImageCommand(image, left, top, paint));
+}
+
+void SkDebugCanvas::onDrawImageRect(const SkImage* image, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SrcRectConstraint constraint) {
+ this->addDrawCommand(new SkDrawImageRectCommand(image, src, dst, paint, constraint));
+}
+
+void SkDebugCanvas::onDrawOval(const SkRect& oval, const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawOvalCommand(oval, paint));
+}
+
+void SkDebugCanvas::onDrawPaint(const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawPaintCommand(paint));
+}
+
+void SkDebugCanvas::onDrawPath(const SkPath& path, const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawPathCommand(path, paint));
+}
+
+void SkDebugCanvas::onDrawPicture(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint) {
+ this->addDrawCommand(new SkBeginDrawPictureCommand(picture, matrix, paint));
+ this->INHERITED::onDrawPicture(picture, matrix, paint);
+ this->addDrawCommand(new SkEndDrawPictureCommand(SkToBool(matrix) || SkToBool(paint)));
+}
+
+void SkDebugCanvas::onDrawPoints(PointMode mode, size_t count,
+ const SkPoint pts[], const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawPointsCommand(mode, count, pts, paint));
+}
+
+void SkDebugCanvas::onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawPosTextCommand(text, byteLength, pos, paint));
+}
+
+void SkDebugCanvas::onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+ SkScalar constY, const SkPaint& paint) {
+ this->addDrawCommand(
+ new SkDrawPosTextHCommand(text, byteLength, xpos, constY, paint));
+}
+
+void SkDebugCanvas::onDrawRect(const SkRect& rect, const SkPaint& paint) {
+ // NOTE(chudy): Messing up when renamed to DrawRect... Why?
+ addDrawCommand(new SkDrawRectCommand(rect, paint));
+}
+
+void SkDebugCanvas::onDrawRRect(const SkRRect& rrect, const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawRRectCommand(rrect, paint));
+}
+
+void SkDebugCanvas::onDrawDRRect(const SkRRect& outer, const SkRRect& inner,
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawDRRectCommand(outer, inner, paint));
+}
+
+void SkDebugCanvas::onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawTextCommand(text, byteLength, x, y, paint));
+}
+
+void SkDebugCanvas::onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+ const SkMatrix* matrix, const SkPaint& paint) {
+ this->addDrawCommand(
+ new SkDrawTextOnPathCommand(text, byteLength, path, matrix, paint));
+}
+
+void SkDebugCanvas::onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawTextBlobCommand(blob, x, y, paint));
+}
+
+void SkDebugCanvas::onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawPatchCommand(cubics, colors, texCoords, xmode, paint));
+}
+
+void SkDebugCanvas::onDrawVertices(VertexMode vmode, int vertexCount, const SkPoint vertices[],
+ const SkPoint texs[], const SkColor colors[],
+ SkXfermode*, const uint16_t indices[], int indexCount,
+ const SkPaint& paint) {
+ this->addDrawCommand(new SkDrawVerticesCommand(vmode, vertexCount, vertices,
+ texs, colors, nullptr, indices, indexCount, paint));
+}
+
+void SkDebugCanvas::willRestore() {
+ this->addDrawCommand(new SkRestoreCommand());
+ this->INHERITED::willRestore();
+}
+
+void SkDebugCanvas::willSave() {
+ this->addDrawCommand(new SkSaveCommand());
+ this->INHERITED::willSave();
+}
+
+SkCanvas::SaveLayerStrategy SkDebugCanvas::getSaveLayerStrategy(const SaveLayerRec& rec) {
+ this->addDrawCommand(new SkSaveLayerCommand(rec));
+ (void)this->INHERITED::getSaveLayerStrategy(rec);
+ // No need for a full layer.
+ return kNoLayer_SaveLayerStrategy;
+}
+
+void SkDebugCanvas::didSetMatrix(const SkMatrix& matrix) {
+ this->addDrawCommand(new SkSetMatrixCommand(matrix));
+ this->INHERITED::didSetMatrix(matrix);
+}
+
+void SkDebugCanvas::toggleCommand(int index, bool toggle) {
+ SkASSERT(index < fCommandVector.count());
+ fCommandVector[index]->setVisible(toggle);
+}
+
+static const char* gFillTypeStrs[] = {
+ "kWinding_FillType",
+ "kEvenOdd_FillType",
+ "kInverseWinding_FillType",
+ "kInverseEvenOdd_FillType"
+};
+
+static const char* gOpStrs[] = {
+ "kDifference_PathOp",
+ "kIntersect_PathOp",
+ "kUnion_PathOp",
+ "kXor_PathOp",
+ "kReverseDifference_PathOp",
+};
+
+static const char kHTML4SpaceIndent[] = "&nbsp;&nbsp;&nbsp;&nbsp;";
+
+void SkDebugCanvas::outputScalar(SkScalar num) {
+ if (num == (int) num) {
+ fClipStackData.appendf("%d", (int) num);
+ } else {
+ SkString str;
+ str.printf("%1.9g", num);
+ int width = (int) str.size();
+ const char* cStr = str.c_str();
+ while (cStr[width - 1] == '0') {
+ --width;
+ }
+ str.resize(width);
+ fClipStackData.appendf("%sf", str.c_str());
+ }
+}
+
+void SkDebugCanvas::outputPointsCommon(const SkPoint* pts, int count) {
+ for (int index = 0; index < count; ++index) {
+ this->outputScalar(pts[index].fX);
+ fClipStackData.appendf(", ");
+ this->outputScalar(pts[index].fY);
+ if (index + 1 < count) {
+ fClipStackData.appendf(", ");
+ }
+ }
+}
+
+void SkDebugCanvas::outputPoints(const SkPoint* pts, int count) {
+ this->outputPointsCommon(pts, count);
+ fClipStackData.appendf(");<br>");
+}
+
+void SkDebugCanvas::outputConicPoints(const SkPoint* pts, SkScalar weight) {
+ this->outputPointsCommon(pts, 2);
+ fClipStackData.appendf(", ");
+ this->outputScalar(weight);
+ fClipStackData.appendf(");<br>");
+}
+
+void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) {
+ SkPath::RawIter iter(path);
+ SkPath::FillType fillType = path.getFillType();
+ fClipStackData.appendf("%sSkPath %s;<br>", kHTML4SpaceIndent, pathName);
+ fClipStackData.appendf("%s%s.setFillType(SkPath::%s);<br>", kHTML4SpaceIndent, pathName,
+ gFillTypeStrs[fillType]);
+ iter.setPath(path);
+ uint8_t verb;
+ SkPoint pts[4];
+ while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
+ switch (verb) {
+ case SkPath::kMove_Verb:
+ fClipStackData.appendf("%s%s.moveTo(", kHTML4SpaceIndent, pathName);
+ this->outputPoints(&pts[0], 1);
+ continue;
+ case SkPath::kLine_Verb:
+ fClipStackData.appendf("%s%s.lineTo(", kHTML4SpaceIndent, pathName);
+ this->outputPoints(&pts[1], 1);
+ break;
+ case SkPath::kQuad_Verb:
+ fClipStackData.appendf("%s%s.quadTo(", kHTML4SpaceIndent, pathName);
+ this->outputPoints(&pts[1], 2);
+ break;
+ case SkPath::kConic_Verb:
+ fClipStackData.appendf("%s%s.conicTo(", kHTML4SpaceIndent, pathName);
+ this->outputConicPoints(&pts[1], iter.conicWeight());
+ break;
+ case SkPath::kCubic_Verb:
+ fClipStackData.appendf("%s%s.cubicTo(", kHTML4SpaceIndent, pathName);
+ this->outputPoints(&pts[1], 3);
+ break;
+ case SkPath::kClose_Verb:
+ fClipStackData.appendf("%s%s.close();<br>", kHTML4SpaceIndent, pathName);
+ break;
+ default:
+ SkDEBUGFAIL("bad verb");
+ return;
+ }
+ }
+}
+
+void SkDebugCanvas::addClipStackData(const SkPath& devPath, const SkPath& operand,
+ SkRegion::Op elementOp) {
+ if (elementOp == SkRegion::kReplace_Op) {
+ if (!lastClipStackData(devPath)) {
+ fSaveDevPath = operand;
+ }
+ fCalledAddStackData = false;
+ } else {
+ fClipStackData.appendf("<br>static void test(skiatest::Reporter* reporter,"
+ " const char* filename) {<br>");
+ addPathData(fCalledAddStackData ? devPath : fSaveDevPath, "path");
+ addPathData(operand, "pathB");
+ fClipStackData.appendf("%stestPathOp(reporter, path, pathB, %s, filename);<br>",
+ kHTML4SpaceIndent, gOpStrs[elementOp]);
+ fClipStackData.appendf("}<br>");
+ fCalledAddStackData = true;
+ }
+}
+
+bool SkDebugCanvas::lastClipStackData(const SkPath& devPath) {
+ if (fCalledAddStackData) {
+ fClipStackData.appendf("<br>");
+ addPathData(devPath, "pathOut");
+ return true;
+ }
+ return false;
+}
diff --git a/tools/debugger/SkDebugCanvas.h b/tools/debugger/SkDebugCanvas.h
new file mode 100644
index 0000000000..217b52e3ce
--- /dev/null
+++ b/tools/debugger/SkDebugCanvas.h
@@ -0,0 +1,269 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#ifndef SKDEBUGCANVAS_H_
+#define SKDEBUGCANVAS_H_
+
+#include "SkCanvas.h"
+#include "SkDrawCommand.h"
+#include "SkPath.h"
+#include "SkPathOps.h"
+#include "SkPicture.h"
+#include "SkString.h"
+#include "SkTArray.h"
+
+class SkNWayCanvas;
+
+class SK_API SkDebugCanvas : public SkCanvas {
+public:
+ SkDebugCanvas(int width, int height);
+ virtual ~SkDebugCanvas();
+
+ void toggleFilter(bool toggle) { fFilter = toggle; }
+
+ void setMegaVizMode(bool megaVizMode) { fMegaVizMode = megaVizMode; }
+ bool getMegaVizMode() const { return fMegaVizMode; }
+
+ /**
+ * Enable or disable overdraw visualization
+ */
+ void setOverdrawViz(bool overdrawViz);
+ bool getOverdrawViz() const { return fOverdrawViz; }
+
+ bool getAllowSimplifyClip() const { return fAllowSimplifyClip; }
+
+ void setPicture(SkPicture* picture) { fPicture = picture; }
+
+ /**
+ * Enable or disable texure filtering override
+ */
+ void overrideTexFiltering(bool overrideTexFiltering, SkFilterQuality);
+
+ /**
+ Executes all draw calls to the canvas.
+ @param canvas The canvas being drawn to
+ */
+ void draw(SkCanvas* canvas);
+
+ /**
+ Executes the draw calls up to the specified index.
+ @param canvas The canvas being drawn to
+ @param index The index of the final command being executed
+ */
+ void drawTo(SkCanvas* canvas, int index);
+
+ /**
+ Returns the most recently calculated transformation matrix
+ */
+ const SkMatrix& getCurrentMatrix() {
+ return fMatrix;
+ }
+
+ /**
+ Returns the most recently calculated clip
+ */
+ const SkIRect& getCurrentClip() {
+ return fClip;
+ }
+
+ /**
+ Returns the index of the last draw command to write to the pixel at (x,y)
+ */
+ int getCommandAtPoint(int x, int y, int index);
+
+ /**
+ Removes the command at the specified index
+ @param index The index of the command to delete
+ */
+ void deleteDrawCommandAt(int index);
+
+ /**
+ Returns the draw command at the given index.
+ @param index The index of the command
+ */
+ SkDrawCommand* getDrawCommandAt(int index);
+
+ /**
+ Sets the draw command for a given index.
+ @param index The index to overwrite
+ @param command The new command
+ */
+ void setDrawCommandAt(int index, SkDrawCommand* command);
+
+ /**
+ Returns information about the command at the given index.
+ @param index The index of the command
+ */
+ const SkTDArray<SkString*>* getCommandInfo(int index) const;
+
+ /**
+ Returns the visibility of the command at the given index.
+ @param index The index of the command
+ */
+ bool getDrawCommandVisibilityAt(int index);
+
+ /**
+ Returns the vector of draw commands
+ */
+ SK_ATTR_DEPRECATED("please use getDrawCommandAt and getSize instead")
+ const SkTDArray<SkDrawCommand*>& getDrawCommands() const;
+
+ /**
+ Returns the vector of draw commands. Do not use this entry
+ point - it is going away!
+ */
+ SkTDArray<SkDrawCommand*>& getDrawCommands();
+
+ /**
+ Returns length of draw command vector.
+ */
+ int getSize() const {
+ return fCommandVector.count();
+ }
+
+ /**
+ Toggles the visibility / execution of the draw command at index i with
+ the value of toggle.
+ */
+ void toggleCommand(int index, bool toggle);
+
+ void setUserMatrix(SkMatrix matrix) {
+ fUserMatrix = matrix;
+ }
+
+ SkString clipStackData() const { return fClipStackData; }
+
+////////////////////////////////////////////////////////////////////////////////
+// Inherited from SkCanvas
+////////////////////////////////////////////////////////////////////////////////
+
+ static const int kVizImageHeight = 256;
+ static const int kVizImageWidth = 256;
+
+ bool isClipEmpty() const override { return false; }
+ bool isClipRect() const override { return true; }
+ bool getClipBounds(SkRect* bounds) const override {
+ if (bounds) {
+ bounds->setXYWH(0, 0,
+ SkIntToScalar(this->imageInfo().width()),
+ SkIntToScalar(this->imageInfo().height()));
+ }
+ return true;
+ }
+ bool getClipDeviceBounds(SkIRect* bounds) const override {
+ if (bounds) {
+ bounds->setLargest();
+ }
+ return true;
+ }
+
+protected:
+ void willSave() override;
+ SaveLayerStrategy getSaveLayerStrategy(const SaveLayerRec&) override;
+ void willRestore() override;
+
+ void didConcat(const SkMatrix&) override;
+ void didSetMatrix(const SkMatrix&) override;
+
+ void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint&) override;
+ void onDrawText(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint&) override;
+ void onDrawPosText(const void* text, size_t byteLength, const SkPoint pos[],
+ const SkPaint&) override;
+ void onDrawPosTextH(const void* text, size_t byteLength, const SkScalar xpos[],
+ SkScalar constY, const SkPaint&) override;
+ void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
+ const SkMatrix* matrix, const SkPaint&) override;
+ void onDrawTextBlob(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint) override;
+
+ void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode, const SkPaint& paint) override;
+ void onDrawPaint(const SkPaint&) override;
+
+ void onDrawRect(const SkRect&, const SkPaint&) override;
+ void onDrawOval(const SkRect&, const SkPaint&) override;
+ void onDrawRRect(const SkRRect&, const SkPaint&) override;
+ void onDrawPoints(PointMode, size_t count, const SkPoint pts[], const SkPaint&) override;
+ void onDrawVertices(VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xmode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint&) override;
+ void onDrawPath(const SkPath&, const SkPaint&) override;
+ void onDrawBitmap(const SkBitmap&, SkScalar left, SkScalar top, const SkPaint*) override;
+ void onDrawBitmapRect(const SkBitmap&, const SkRect* src, const SkRect& dst, const SkPaint*,
+ SrcRectConstraint) override;
+ void onDrawImage(const SkImage*, SkScalar left, SkScalar top, const SkPaint*) override;
+ void onDrawImageRect(const SkImage*, const SkRect* src, const SkRect& dst,
+ const SkPaint*, SrcRectConstraint) override;
+ void onDrawBitmapNine(const SkBitmap&, const SkIRect& center, const SkRect& dst,
+ const SkPaint*) override;
+ void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) override;
+ void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) override;
+ void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) override;
+ void onClipRegion(const SkRegion& region, SkRegion::Op) override;
+
+ void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) override;
+
+ void markActiveCommands(int index);
+
+private:
+ SkTDArray<SkDrawCommand*> fCommandVector;
+ SkPicture* fPicture;
+ bool fFilter;
+ bool fMegaVizMode;
+ SkMatrix fUserMatrix;
+ SkMatrix fMatrix;
+ SkIRect fClip;
+
+ SkString fClipStackData;
+ bool fCalledAddStackData;
+ SkPath fSaveDevPath;
+
+ bool fOverdrawViz;
+ bool fOverrideFilterQuality;
+ SkFilterQuality fFilterQuality;
+
+ SkAutoTUnref<SkNWayCanvas> fPaintFilterCanvas;
+
+ /**
+ The active saveLayer commands at a given point in the renderering.
+ Only used when "mega" visualization is enabled.
+ */
+ SkTDArray<SkDrawCommand*> fActiveLayers;
+
+ /**
+ Adds the command to the classes vector of commands.
+ @param command The draw command for execution
+ */
+ void addDrawCommand(SkDrawCommand* command);
+
+ /**
+ Applies any panning and zooming the user has specified before
+ drawing anything else into the canvas.
+ */
+ void applyUserTransform(SkCanvas* canvas);
+
+ void resetClipStackData() { fClipStackData.reset(); fCalledAddStackData = false; }
+
+ void addClipStackData(const SkPath& devPath, const SkPath& operand, SkRegion::Op elementOp);
+ void addPathData(const SkPath& path, const char* pathName);
+ bool lastClipStackData(const SkPath& devPath);
+ void outputConicPoints(const SkPoint* pts, SkScalar weight);
+ void outputPoints(const SkPoint* pts, int count);
+ void outputPointsCommon(const SkPoint* pts, int count);
+ void outputScalar(SkScalar num);
+
+ void updatePaintFilterCanvas();
+
+ typedef SkCanvas INHERITED;
+};
+
+#endif
diff --git a/tools/debugger/SkDrawCommand.cpp b/tools/debugger/SkDrawCommand.cpp
new file mode 100644
index 0000000000..17c59e67a6
--- /dev/null
+++ b/tools/debugger/SkDrawCommand.cpp
@@ -0,0 +1,989 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "SkDrawCommand.h"
+#include "SkObjectParser.h"
+#include "SkPicture.h"
+#include "SkTextBlob.h"
+#include "SkTextBlobRunIterator.h"
+
+// TODO(chudy): Refactor into non subclass model.
+
+SkDrawCommand::SkDrawCommand(OpType type)
+ : fOpType(type)
+ , fVisible(true) {
+}
+
+SkDrawCommand::~SkDrawCommand() {
+ fInfo.deleteAll();
+}
+
+const char* SkDrawCommand::GetCommandString(OpType type) {
+ switch (type) {
+ case kBeginDrawPicture_OpType: return "BeginDrawPicture";
+ case kClipPath_OpType: return "ClipPath";
+ case kClipRegion_OpType: return "ClipRegion";
+ case kClipRect_OpType: return "ClipRect";
+ case kClipRRect_OpType: return "ClipRRect";
+ case kConcat_OpType: return "Concat";
+ case kDrawBitmap_OpType: return "DrawBitmap";
+ case kDrawBitmapNine_OpType: return "DrawBitmapNine";
+ case kDrawBitmapRect_OpType: return "DrawBitmapRect";
+ case kDrawClear_OpType: return "DrawClear";
+ case kDrawDRRect_OpType: return "DrawDRRect";
+ case kDrawImage_OpType: return "DrawImage";
+ case kDrawImageRect_OpType: return "DrawImageRect";
+ case kDrawOval_OpType: return "DrawOval";
+ case kDrawPaint_OpType: return "DrawPaint";
+ case kDrawPatch_OpType: return "DrawPatch";
+ case kDrawPath_OpType: return "DrawPath";
+ case kDrawPoints_OpType: return "DrawPoints";
+ case kDrawPosText_OpType: return "DrawPosText";
+ case kDrawPosTextH_OpType: return "DrawPosTextH";
+ case kDrawRect_OpType: return "DrawRect";
+ case kDrawRRect_OpType: return "DrawRRect";
+ case kDrawText_OpType: return "DrawText";
+ case kDrawTextBlob_OpType: return "DrawTextBlob";
+ case kDrawTextOnPath_OpType: return "DrawTextOnPath";
+ case kDrawVertices_OpType: return "DrawVertices";
+ case kEndDrawPicture_OpType: return "EndDrawPicture";
+ case kRestore_OpType: return "Restore";
+ case kSave_OpType: return "Save";
+ case kSaveLayer_OpType: return "SaveLayer";
+ case kSetMatrix_OpType: return "SetMatrix";
+ default:
+ SkDebugf("OpType error 0x%08x\n", type);
+ SkASSERT(0);
+ break;
+ }
+ SkDEBUGFAIL("DrawType UNUSED\n");
+ return nullptr;
+}
+
+SkString SkDrawCommand::toString() const {
+ return SkString(GetCommandString(fOpType));
+}
+
+SkClearCommand::SkClearCommand(SkColor color) : INHERITED(kDrawClear_OpType) {
+ fColor = color;
+ fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
+}
+
+void SkClearCommand::execute(SkCanvas* canvas) const {
+ canvas->clear(fColor);
+}
+
+namespace {
+
+void xlate_and_scale_to_bounds(SkCanvas* canvas, const SkRect& bounds) {
+ const SkISize& size = canvas->getDeviceSize();
+
+ static const SkScalar kInsetFrac = 0.9f; // Leave a border around object
+
+ canvas->translate(size.fWidth/2.0f, size.fHeight/2.0f);
+ if (bounds.width() > bounds.height()) {
+ canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.width()),
+ SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.width()));
+ } else {
+ canvas->scale(SkDoubleToScalar((kInsetFrac*size.fWidth)/bounds.height()),
+ SkDoubleToScalar((kInsetFrac*size.fHeight)/bounds.height()));
+ }
+ canvas->translate(-bounds.centerX(), -bounds.centerY());
+}
+
+
+void render_path(SkCanvas* canvas, const SkPath& path) {
+ canvas->clear(0xFFFFFFFF);
+
+ const SkRect& bounds = path.getBounds();
+ if (bounds.isEmpty()) {
+ return;
+ }
+
+ SkAutoCanvasRestore acr(canvas, true);
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawPath(path, p);
+}
+
+void render_bitmap(SkCanvas* canvas, const SkBitmap& input, const SkRect* srcRect = nullptr) {
+ const SkISize& size = canvas->getDeviceSize();
+
+ SkScalar xScale = SkIntToScalar(size.fWidth-2) / input.width();
+ SkScalar yScale = SkIntToScalar(size.fHeight-2) / input.height();
+
+ if (input.width() > input.height()) {
+ yScale *= input.height() / (float) input.width();
+ } else {
+ xScale *= input.width() / (float) input.height();
+ }
+
+ SkRect dst = SkRect::MakeXYWH(SK_Scalar1, SK_Scalar1,
+ xScale * input.width(),
+ yScale * input.height());
+
+ static const int kNumBlocks = 8;
+
+ canvas->clear(0xFFFFFFFF);
+ SkISize block = {
+ canvas->imageInfo().width()/kNumBlocks,
+ canvas->imageInfo().height()/kNumBlocks
+ };
+ for (int y = 0; y < kNumBlocks; ++y) {
+ for (int x = 0; x < kNumBlocks; ++x) {
+ SkPaint paint;
+ paint.setColor((x+y)%2 ? SK_ColorLTGRAY : SK_ColorDKGRAY);
+ SkRect r = SkRect::MakeXYWH(SkIntToScalar(x*block.width()),
+ SkIntToScalar(y*block.height()),
+ SkIntToScalar(block.width()),
+ SkIntToScalar(block.height()));
+ canvas->drawRect(r, paint);
+ }
+ }
+
+ canvas->drawBitmapRect(input, dst, nullptr);
+
+ if (srcRect) {
+ SkRect r = SkRect::MakeLTRB(srcRect->fLeft * xScale + SK_Scalar1,
+ srcRect->fTop * yScale + SK_Scalar1,
+ srcRect->fRight * xScale + SK_Scalar1,
+ srcRect->fBottom * yScale + SK_Scalar1);
+ SkPaint p;
+ p.setColor(SK_ColorRED);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawRect(r, p);
+ }
+}
+
+void render_rrect(SkCanvas* canvas, const SkRRect& rrect) {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ const SkRect& bounds = rrect.getBounds();
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawRRect(rrect, p);
+ canvas->restore();
+}
+
+void render_drrect(SkCanvas* canvas, const SkRRect& outer, const SkRRect& inner) {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ const SkRect& bounds = outer.getBounds();
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawDRRect(outer, inner, p);
+ canvas->restore();
+}
+
+};
+
+
+SkClipPathCommand::SkClipPathCommand(const SkPath& path, SkRegion::Op op, bool doAA)
+ : INHERITED(kClipPath_OpType) {
+ fPath = path;
+ fOp = op;
+ fDoAA = doAA;
+
+ fInfo.push(SkObjectParser::PathToString(path));
+ fInfo.push(SkObjectParser::RegionOpToString(op));
+ fInfo.push(SkObjectParser::BoolToString(doAA));
+}
+
+void SkClipPathCommand::execute(SkCanvas* canvas) const {
+ canvas->clipPath(fPath, fOp, fDoAA);
+}
+
+bool SkClipPathCommand::render(SkCanvas* canvas) const {
+ render_path(canvas, fPath);
+ return true;
+}
+
+SkClipRegionCommand::SkClipRegionCommand(const SkRegion& region, SkRegion::Op op)
+ : INHERITED(kClipRegion_OpType) {
+ fRegion = region;
+ fOp = op;
+
+ fInfo.push(SkObjectParser::RegionToString(region));
+ fInfo.push(SkObjectParser::RegionOpToString(op));
+}
+
+void SkClipRegionCommand::execute(SkCanvas* canvas) const {
+ canvas->clipRegion(fRegion, fOp);
+}
+
+SkClipRectCommand::SkClipRectCommand(const SkRect& rect, SkRegion::Op op, bool doAA)
+ : INHERITED(kClipRect_OpType) {
+ fRect = rect;
+ fOp = op;
+ fDoAA = doAA;
+
+ fInfo.push(SkObjectParser::RectToString(rect));
+ fInfo.push(SkObjectParser::RegionOpToString(op));
+ fInfo.push(SkObjectParser::BoolToString(doAA));
+}
+
+void SkClipRectCommand::execute(SkCanvas* canvas) const {
+ canvas->clipRect(fRect, fOp, fDoAA);
+}
+
+SkClipRRectCommand::SkClipRRectCommand(const SkRRect& rrect, SkRegion::Op op, bool doAA)
+ : INHERITED(kClipRRect_OpType) {
+ fRRect = rrect;
+ fOp = op;
+ fDoAA = doAA;
+
+ fInfo.push(SkObjectParser::RRectToString(rrect));
+ fInfo.push(SkObjectParser::RegionOpToString(op));
+ fInfo.push(SkObjectParser::BoolToString(doAA));
+}
+
+void SkClipRRectCommand::execute(SkCanvas* canvas) const {
+ canvas->clipRRect(fRRect, fOp, fDoAA);
+}
+
+bool SkClipRRectCommand::render(SkCanvas* canvas) const {
+ render_rrect(canvas, fRRect);
+ return true;
+}
+
+SkConcatCommand::SkConcatCommand(const SkMatrix& matrix)
+ : INHERITED(kConcat_OpType) {
+ fMatrix = matrix;
+
+ fInfo.push(SkObjectParser::MatrixToString(matrix));
+}
+
+void SkConcatCommand::execute(SkCanvas* canvas) const {
+ canvas->concat(fMatrix);
+}
+
+SkDrawBitmapCommand::SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+ const SkPaint* paint)
+ : INHERITED(kDrawBitmap_OpType) {
+ fBitmap = bitmap;
+ fLeft = left;
+ fTop = top;
+ if (paint) {
+ fPaint = *paint;
+ fPaintPtr = &fPaint;
+ } else {
+ fPaintPtr = nullptr;
+ }
+
+ fInfo.push(SkObjectParser::BitmapToString(bitmap));
+ fInfo.push(SkObjectParser::ScalarToString(left, "SkScalar left: "));
+ fInfo.push(SkObjectParser::ScalarToString(top, "SkScalar top: "));
+ if (paint) {
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+}
+
+void SkDrawBitmapCommand::execute(SkCanvas* canvas) const {
+ canvas->drawBitmap(fBitmap, fLeft, fTop, fPaintPtr);
+}
+
+bool SkDrawBitmapCommand::render(SkCanvas* canvas) const {
+ render_bitmap(canvas, fBitmap);
+ return true;
+}
+
+SkDrawBitmapNineCommand::SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint)
+ : INHERITED(kDrawBitmapNine_OpType) {
+ fBitmap = bitmap;
+ fCenter = center;
+ fDst = dst;
+ if (paint) {
+ fPaint = *paint;
+ fPaintPtr = &fPaint;
+ } else {
+ fPaintPtr = nullptr;
+ }
+
+ fInfo.push(SkObjectParser::BitmapToString(bitmap));
+ fInfo.push(SkObjectParser::IRectToString(center));
+ fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
+ if (paint) {
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+}
+
+void SkDrawBitmapNineCommand::execute(SkCanvas* canvas) const {
+ canvas->drawBitmapNine(fBitmap, fCenter, fDst, fPaintPtr);
+}
+
+bool SkDrawBitmapNineCommand::render(SkCanvas* canvas) const {
+ SkRect tmp = SkRect::Make(fCenter);
+ render_bitmap(canvas, fBitmap, &tmp);
+ return true;
+}
+
+SkDrawBitmapRectCommand::SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src,
+ const SkRect& dst, const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint)
+ : INHERITED(kDrawBitmapRect_OpType) {
+ fBitmap = bitmap;
+ if (src) {
+ fSrc = *src;
+ } else {
+ fSrc.setEmpty();
+ }
+ fDst = dst;
+
+ if (paint) {
+ fPaint = *paint;
+ fPaintPtr = &fPaint;
+ } else {
+ fPaintPtr = nullptr;
+ }
+ fConstraint = constraint;
+
+ fInfo.push(SkObjectParser::BitmapToString(bitmap));
+ if (src) {
+ fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
+ }
+ fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
+ if (paint) {
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+ fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
+}
+
+void SkDrawBitmapRectCommand::execute(SkCanvas* canvas) const {
+ canvas->legacy_drawBitmapRect(fBitmap, this->srcRect(), fDst, fPaintPtr, fConstraint);
+}
+
+bool SkDrawBitmapRectCommand::render(SkCanvas* canvas) const {
+ render_bitmap(canvas, fBitmap, this->srcRect());
+ return true;
+}
+
+SkDrawImageCommand::SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top,
+ const SkPaint* paint)
+ : INHERITED(kDrawImage_OpType)
+ , fImage(SkRef(image))
+ , fLeft(left)
+ , fTop(top) {
+
+ fInfo.push(SkObjectParser::ImageToString(image));
+ fInfo.push(SkObjectParser::ScalarToString(left, "Left: "));
+ fInfo.push(SkObjectParser::ScalarToString(top, "Top: "));
+
+ if (paint) {
+ fPaint.set(*paint);
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+}
+
+void SkDrawImageCommand::execute(SkCanvas* canvas) const {
+ canvas->drawImage(fImage, fLeft, fTop, fPaint.getMaybeNull());
+}
+
+bool SkDrawImageCommand::render(SkCanvas* canvas) const {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(0xFFFFFFFF);
+
+ xlate_and_scale_to_bounds(canvas, SkRect::MakeXYWH(fLeft, fTop,
+ SkIntToScalar(fImage->width()),
+ SkIntToScalar(fImage->height())));
+ this->execute(canvas);
+ return true;
+}
+
+SkDrawImageRectCommand::SkDrawImageRectCommand(const SkImage* image, const SkRect* src,
+ const SkRect& dst, const SkPaint* paint,
+ SkCanvas::SrcRectConstraint constraint)
+ : INHERITED(kDrawImageRect_OpType)
+ , fImage(SkRef(image))
+ , fDst(dst)
+ , fConstraint(constraint) {
+
+ if (src) {
+ fSrc.set(*src);
+ }
+
+ if (paint) {
+ fPaint.set(*paint);
+ }
+
+ fInfo.push(SkObjectParser::ImageToString(image));
+ if (src) {
+ fInfo.push(SkObjectParser::RectToString(*src, "Src: "));
+ }
+ fInfo.push(SkObjectParser::RectToString(dst, "Dst: "));
+ if (paint) {
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+ fInfo.push(SkObjectParser::IntToString(fConstraint, "Constraint: "));
+}
+
+void SkDrawImageRectCommand::execute(SkCanvas* canvas) const {
+ canvas->legacy_drawImageRect(fImage, fSrc.getMaybeNull(), fDst, fPaint.getMaybeNull(), fConstraint);
+}
+
+bool SkDrawImageRectCommand::render(SkCanvas* canvas) const {
+ SkAutoCanvasRestore acr(canvas, true);
+ canvas->clear(0xFFFFFFFF);
+
+ xlate_and_scale_to_bounds(canvas, fDst);
+
+ this->execute(canvas);
+ return true;
+}
+
+SkDrawOvalCommand::SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint)
+ : INHERITED(kDrawOval_OpType) {
+ fOval = oval;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::RectToString(oval));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawOvalCommand::execute(SkCanvas* canvas) const {
+ canvas->drawOval(fOval, fPaint);
+}
+
+bool SkDrawOvalCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ xlate_and_scale_to_bounds(canvas, fOval);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawOval(fOval, p);
+ canvas->restore();
+
+ return true;
+}
+
+SkDrawPaintCommand::SkDrawPaintCommand(const SkPaint& paint)
+ : INHERITED(kDrawPaint_OpType) {
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPaintCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPaint(fPaint);
+}
+
+bool SkDrawPaintCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->drawPaint(fPaint);
+ return true;
+}
+
+SkDrawPathCommand::SkDrawPathCommand(const SkPath& path, const SkPaint& paint)
+ : INHERITED(kDrawPath_OpType) {
+ fPath = path;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::PathToString(path));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPathCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPath(fPath, fPaint);
+}
+
+bool SkDrawPathCommand::render(SkCanvas* canvas) const {
+ render_path(canvas, fPath);
+ return true;
+}
+
+SkBeginDrawPictureCommand::SkBeginDrawPictureCommand(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint)
+ : INHERITED(kBeginDrawPicture_OpType)
+ , fPicture(SkRef(picture)) {
+
+ SkString* str = new SkString;
+ str->appendf("SkPicture: L: %f T: %f R: %f B: %f",
+ picture->cullRect().fLeft, picture->cullRect().fTop,
+ picture->cullRect().fRight, picture->cullRect().fBottom);
+ fInfo.push(str);
+
+ if (matrix) {
+ fMatrix.set(*matrix);
+ fInfo.push(SkObjectParser::MatrixToString(*matrix));
+ }
+
+ if (paint) {
+ fPaint.set(*paint);
+ fInfo.push(SkObjectParser::PaintToString(*paint));
+ }
+
+}
+
+void SkBeginDrawPictureCommand::execute(SkCanvas* canvas) const {
+ if (fPaint.isValid()) {
+ SkRect bounds = fPicture->cullRect();
+ if (fMatrix.isValid()) {
+ fMatrix.get()->mapRect(&bounds);
+ }
+ canvas->saveLayer(&bounds, fPaint.get());
+ }
+
+ if (fMatrix.isValid()) {
+ if (!fPaint.isValid()) {
+ canvas->save();
+ }
+ canvas->concat(*fMatrix.get());
+ }
+}
+
+bool SkBeginDrawPictureCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ xlate_and_scale_to_bounds(canvas, fPicture->cullRect());
+
+ canvas->drawPicture(fPicture.get());
+
+ canvas->restore();
+
+ return true;
+}
+
+SkEndDrawPictureCommand::SkEndDrawPictureCommand(bool restore)
+ : INHERITED(kEndDrawPicture_OpType) , fRestore(restore) { }
+
+void SkEndDrawPictureCommand::execute(SkCanvas* canvas) const {
+ if (fRestore) {
+ canvas->restore();
+ }
+}
+
+SkDrawPointsCommand::SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count,
+ const SkPoint pts[], const SkPaint& paint)
+ : INHERITED(kDrawPoints_OpType) {
+ fMode = mode;
+ fCount = count;
+ fPts = new SkPoint[count];
+ memcpy(fPts, pts, count * sizeof(SkPoint));
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::PointsToString(pts, count));
+ fInfo.push(SkObjectParser::ScalarToString(SkIntToScalar((unsigned int)count),
+ "Points: "));
+ fInfo.push(SkObjectParser::PointModeToString(mode));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPointsCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPoints(fMode, fCount, fPts, fPaint);
+}
+
+bool SkDrawPointsCommand::render(SkCanvas* canvas) const {
+ canvas->clear(0xFFFFFFFF);
+ canvas->save();
+
+ SkRect bounds;
+
+ bounds.setEmpty();
+ for (unsigned int i = 0; i < fCount; ++i) {
+ bounds.growToInclude(fPts[i].fX, fPts[i].fY);
+ }
+
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ SkPaint p;
+ p.setColor(SK_ColorBLACK);
+ p.setStyle(SkPaint::kStroke_Style);
+
+ canvas->drawPoints(fMode, fCount, fPts, p);
+ canvas->restore();
+
+ return true;
+}
+
+SkDrawPosTextCommand::SkDrawPosTextCommand(const void* text, size_t byteLength,
+ const SkPoint pos[], const SkPaint& paint)
+ : INHERITED(kDrawPosText_OpType) {
+ size_t numPts = paint.countText(text, byteLength);
+
+ fText = new char[byteLength];
+ memcpy(fText, text, byteLength);
+ fByteLength = byteLength;
+
+ fPos = new SkPoint[numPts];
+ memcpy(fPos, pos, numPts * sizeof(SkPoint));
+
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
+ // TODO(chudy): Test that this works.
+ fInfo.push(SkObjectParser::PointsToString(pos, 1));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPosTextCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPosText(fText, fByteLength, fPos, fPaint);
+}
+
+
+SkDrawPosTextHCommand::SkDrawPosTextHCommand(const void* text, size_t byteLength,
+ const SkScalar xpos[], SkScalar constY,
+ const SkPaint& paint)
+ : INHERITED(kDrawPosTextH_OpType) {
+ size_t numPts = paint.countText(text, byteLength);
+
+ fText = new char[byteLength];
+ memcpy(fText, text, byteLength);
+ fByteLength = byteLength;
+
+ fXpos = new SkScalar[numPts];
+ memcpy(fXpos, xpos, numPts * sizeof(SkScalar));
+
+ fConstY = constY;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
+ fInfo.push(SkObjectParser::ScalarToString(xpos[0], "XPOS: "));
+ fInfo.push(SkObjectParser::ScalarToString(constY, "SkScalar constY: "));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPosTextHCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPosTextH(fText, fByteLength, fXpos, fConstY, fPaint);
+}
+
+static const char* gPositioningLabels[] = {
+ "kDefault_Positioning",
+ "kHorizontal_Positioning",
+ "kFull_Positioning",
+};
+
+SkDrawTextBlobCommand::SkDrawTextBlobCommand(const SkTextBlob* blob, SkScalar x, SkScalar y,
+ const SkPaint& paint)
+ : INHERITED(kDrawTextBlob_OpType)
+ , fBlob(SkRef(blob))
+ , fXPos(x)
+ , fYPos(y)
+ , fPaint(paint) {
+
+ SkAutoTDelete<SkString> runsStr(new SkString);
+ fInfo.push(SkObjectParser::ScalarToString(x, "XPOS: "));
+ fInfo.push(SkObjectParser::ScalarToString(y, "YPOS: "));
+ fInfo.push(SkObjectParser::RectToString(fBlob->bounds(), "Bounds: "));
+ fInfo.push(runsStr);
+ fInfo.push(SkObjectParser::PaintToString(paint));
+
+ unsigned runs = 0;
+ SkPaint runPaint(paint);
+ SkTextBlobRunIterator iter(blob);
+ while (!iter.done()) {
+ SkAutoTDelete<SkString> tmpStr(new SkString);
+ tmpStr->printf("==== Run [%d] ====", runs++);
+ fInfo.push(tmpStr.release());
+
+ fInfo.push(SkObjectParser::IntToString(iter.glyphCount(), "GlyphCount: "));
+ tmpStr.reset(new SkString("GlyphPositioning: "));
+ tmpStr->append(gPositioningLabels[iter.positioning()]);
+ fInfo.push(tmpStr.release());
+
+ iter.applyFontToPaint(&runPaint);
+ fInfo.push(SkObjectParser::PaintToString(runPaint));
+
+ iter.next();
+ }
+
+ runsStr->printf("Runs: %d", runs);
+ // runStr is owned by fInfo at this point.
+ runsStr.release();
+}
+
+void SkDrawTextBlobCommand::execute(SkCanvas* canvas) const {
+ canvas->drawTextBlob(fBlob, fXPos, fYPos, fPaint);
+}
+
+bool SkDrawTextBlobCommand::render(SkCanvas* canvas) const {
+ canvas->clear(SK_ColorWHITE);
+ canvas->save();
+
+ SkRect bounds = fBlob->bounds().makeOffset(fXPos, fYPos);
+ xlate_and_scale_to_bounds(canvas, bounds);
+
+ canvas->drawTextBlob(fBlob.get(), fXPos, fYPos, fPaint);
+
+ canvas->restore();
+
+ return true;
+}
+
+SkDrawPatchCommand::SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xfermode,
+ const SkPaint& paint)
+ : INHERITED(kDrawPatch_OpType) {
+ memcpy(fCubics, cubics, sizeof(fCubics));
+ memcpy(fColors, colors, sizeof(fColors));
+ memcpy(fTexCoords, texCoords, sizeof(fTexCoords));
+ fXfermode.reset(xfermode);
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawPatchCommand::execute(SkCanvas* canvas) const {
+ canvas->drawPatch(fCubics, fColors, fTexCoords, fXfermode, fPaint);
+}
+
+SkDrawRectCommand::SkDrawRectCommand(const SkRect& rect, const SkPaint& paint)
+ : INHERITED(kDrawRect_OpType) {
+ fRect = rect;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::RectToString(rect));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawRectCommand::execute(SkCanvas* canvas) const {
+ canvas->drawRect(fRect, fPaint);
+}
+
+SkDrawRRectCommand::SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint)
+ : INHERITED(kDrawRRect_OpType) {
+ fRRect = rrect;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::RRectToString(rrect));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawRRectCommand::execute(SkCanvas* canvas) const {
+ canvas->drawRRect(fRRect, fPaint);
+}
+
+bool SkDrawRRectCommand::render(SkCanvas* canvas) const {
+ render_rrect(canvas, fRRect);
+ return true;
+}
+
+SkDrawDRRectCommand::SkDrawDRRectCommand(const SkRRect& outer,
+ const SkRRect& inner,
+ const SkPaint& paint)
+ : INHERITED(kDrawDRRect_OpType) {
+ fOuter = outer;
+ fInner = inner;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::RRectToString(outer));
+ fInfo.push(SkObjectParser::RRectToString(inner));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawDRRectCommand::execute(SkCanvas* canvas) const {
+ canvas->drawDRRect(fOuter, fInner, fPaint);
+}
+
+bool SkDrawDRRectCommand::render(SkCanvas* canvas) const {
+ render_drrect(canvas, fOuter, fInner);
+ return true;
+}
+
+SkDrawTextCommand::SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint& paint)
+ : INHERITED(kDrawText_OpType) {
+ fText = new char[byteLength];
+ memcpy(fText, text, byteLength);
+ fByteLength = byteLength;
+ fX = x;
+ fY = y;
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
+ fInfo.push(SkObjectParser::ScalarToString(x, "SkScalar x: "));
+ fInfo.push(SkObjectParser::ScalarToString(y, "SkScalar y: "));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawTextCommand::execute(SkCanvas* canvas) const {
+ canvas->drawText(fText, fByteLength, fX, fY, fPaint);
+}
+
+SkDrawTextOnPathCommand::SkDrawTextOnPathCommand(const void* text, size_t byteLength,
+ const SkPath& path, const SkMatrix* matrix,
+ const SkPaint& paint)
+ : INHERITED(kDrawTextOnPath_OpType) {
+ fText = new char[byteLength];
+ memcpy(fText, text, byteLength);
+ fByteLength = byteLength;
+ fPath = path;
+ if (matrix) {
+ fMatrix = *matrix;
+ } else {
+ fMatrix.setIdentity();
+ }
+ fPaint = paint;
+
+ fInfo.push(SkObjectParser::TextToString(text, byteLength, paint.getTextEncoding()));
+ fInfo.push(SkObjectParser::PathToString(path));
+ if (matrix) {
+ fInfo.push(SkObjectParser::MatrixToString(*matrix));
+ }
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+void SkDrawTextOnPathCommand::execute(SkCanvas* canvas) const {
+ canvas->drawTextOnPath(fText, fByteLength, fPath,
+ fMatrix.isIdentity() ? nullptr : &fMatrix,
+ fPaint);
+}
+
+SkDrawVerticesCommand::SkDrawVerticesCommand(SkCanvas::VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xfermode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint)
+ : INHERITED(kDrawVertices_OpType) {
+ fVmode = vmode;
+
+ fVertexCount = vertexCount;
+
+ fVertices = new SkPoint[vertexCount];
+ memcpy(fVertices, vertices, vertexCount * sizeof(SkPoint));
+
+ if (texs) {
+ fTexs = new SkPoint[vertexCount];
+ memcpy(fTexs, texs, vertexCount * sizeof(SkPoint));
+ } else {
+ fTexs = nullptr;
+ }
+
+ if (colors) {
+ fColors = new SkColor[vertexCount];
+ memcpy(fColors, colors, vertexCount * sizeof(SkColor));
+ } else {
+ fColors = nullptr;
+ }
+
+ fXfermode = xfermode;
+ if (fXfermode) {
+ fXfermode->ref();
+ }
+
+ if (indexCount > 0) {
+ fIndices = new uint16_t[indexCount];
+ memcpy(fIndices, indices, indexCount * sizeof(uint16_t));
+ } else {
+ fIndices = nullptr;
+ }
+
+ fIndexCount = indexCount;
+ fPaint = paint;
+
+ // TODO(chudy)
+ fInfo.push(SkObjectParser::CustomTextToString("To be implemented."));
+ fInfo.push(SkObjectParser::PaintToString(paint));
+}
+
+SkDrawVerticesCommand::~SkDrawVerticesCommand() {
+ delete [] fVertices;
+ delete [] fTexs;
+ delete [] fColors;
+ SkSafeUnref(fXfermode);
+ delete [] fIndices;
+}
+
+void SkDrawVerticesCommand::execute(SkCanvas* canvas) const {
+ canvas->drawVertices(fVmode, fVertexCount, fVertices,
+ fTexs, fColors, fXfermode, fIndices,
+ fIndexCount, fPaint);
+}
+
+SkRestoreCommand::SkRestoreCommand()
+ : INHERITED(kRestore_OpType) {
+ fInfo.push(SkObjectParser::CustomTextToString("No Parameters"));
+}
+
+void SkRestoreCommand::execute(SkCanvas* canvas) const {
+ canvas->restore();
+}
+
+SkSaveCommand::SkSaveCommand()
+ : INHERITED(kSave_OpType) {
+}
+
+void SkSaveCommand::execute(SkCanvas* canvas) const {
+ canvas->save();
+}
+
+SkSaveLayerCommand::SkSaveLayerCommand(const SkCanvas::SaveLayerRec& rec)
+ : INHERITED(kSaveLayer_OpType) {
+ if (rec.fBounds) {
+ fBounds = *rec.fBounds;
+ } else {
+ fBounds.setEmpty();
+ }
+
+ if (rec.fPaint) {
+ fPaint = *rec.fPaint;
+ fPaintPtr = &fPaint;
+ } else {
+ fPaintPtr = nullptr;
+ }
+ fSaveLayerFlags = rec.fSaveLayerFlags;
+
+ if (rec.fBounds) {
+ fInfo.push(SkObjectParser::RectToString(*rec.fBounds, "Bounds: "));
+ }
+ if (rec.fPaint) {
+ fInfo.push(SkObjectParser::PaintToString(*rec.fPaint));
+ }
+ fInfo.push(SkObjectParser::SaveLayerFlagsToString(fSaveLayerFlags));
+}
+
+void SkSaveLayerCommand::execute(SkCanvas* canvas) const {
+ canvas->saveLayer(SkCanvas::SaveLayerRec(fBounds.isEmpty() ? nullptr : &fBounds,
+ fPaintPtr,
+ fSaveLayerFlags));
+}
+
+void SkSaveLayerCommand::vizExecute(SkCanvas* canvas) const {
+ canvas->save();
+}
+
+SkSetMatrixCommand::SkSetMatrixCommand(const SkMatrix& matrix)
+ : INHERITED(kSetMatrix_OpType) {
+ fUserMatrix.reset();
+ fMatrix = matrix;
+
+ fInfo.push(SkObjectParser::MatrixToString(matrix));
+}
+
+void SkSetMatrixCommand::setUserMatrix(const SkMatrix& userMatrix) {
+ fUserMatrix = userMatrix;
+}
+
+void SkSetMatrixCommand::execute(SkCanvas* canvas) const {
+ SkMatrix temp = SkMatrix::Concat(fUserMatrix, fMatrix);
+ canvas->setMatrix(temp);
+}
+
diff --git a/tools/debugger/SkDrawCommand.h b/tools/debugger/SkDrawCommand.h
new file mode 100644
index 0000000000..f67df92de7
--- /dev/null
+++ b/tools/debugger/SkDrawCommand.h
@@ -0,0 +1,586 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKDRAWCOMMAND_H_
+#define SKDRAWCOMMAND_H_
+
+#include "SkCanvas.h"
+#include "SkTLazy.h"
+#include "SkPath.h"
+#include "SkRRect.h"
+#include "SkString.h"
+#include "SkTDArray.h"
+
+class SK_API SkDrawCommand {
+public:
+ enum OpType {
+ kBeginDrawPicture_OpType,
+ kClipPath_OpType,
+ kClipRegion_OpType,
+ kClipRect_OpType,
+ kClipRRect_OpType,
+ kConcat_OpType,
+ kDrawBitmap_OpType,
+ kDrawBitmapNine_OpType,
+ kDrawBitmapRect_OpType,
+ kDrawClear_OpType,
+ kDrawDRRect_OpType,
+ kDrawImage_OpType,
+ kDrawImageRect_OpType,
+ kDrawOval_OpType,
+ kDrawPaint_OpType,
+ kDrawPatch_OpType,
+ kDrawPath_OpType,
+ kDrawPoints_OpType,
+ kDrawPosText_OpType,
+ kDrawPosTextH_OpType,
+ kDrawRect_OpType,
+ kDrawRRect_OpType,
+ kDrawText_OpType,
+ kDrawTextBlob_OpType,
+ kDrawTextOnPath_OpType,
+ kDrawVertices_OpType,
+ kEndDrawPicture_OpType,
+ kRestore_OpType,
+ kSave_OpType,
+ kSaveLayer_OpType,
+ kSetMatrix_OpType,
+
+ kLast_OpType = kSetMatrix_OpType
+ };
+
+ static const int kOpTypeCount = kLast_OpType + 1;
+
+ SkDrawCommand(OpType opType);
+
+ virtual ~SkDrawCommand();
+
+ virtual SkString toString() const;
+
+ virtual const char* toCString() const {
+ return GetCommandString(fOpType);
+ }
+
+ bool isVisible() const {
+ return fVisible;
+ }
+
+ void setVisible(bool toggle) {
+ fVisible = toggle;
+ }
+
+ const SkTDArray<SkString*>* Info() const { return &fInfo; }
+ virtual void execute(SkCanvas*) const = 0;
+ virtual void vizExecute(SkCanvas*) const {}
+
+ virtual void setUserMatrix(const SkMatrix&) {}
+
+ // The next "active" system is only used by save, saveLayer, and restore.
+ // It is used to determine which saveLayers are currently active (at a
+ // given point in the rendering).
+ // saves just return a kPushLayer action but don't track active state
+ // restores just return a kPopLayer action
+ // saveLayers return kPushLayer but also track the active state
+ enum Action {
+ kNone_Action,
+ kPopLayer_Action,
+ kPushLayer_Action,
+ };
+ virtual Action action() const { return kNone_Action; }
+ virtual void setActive(bool active) {}
+ virtual bool active() const { return false; }
+
+ OpType getType() const { return fOpType; }
+
+ virtual bool render(SkCanvas* canvas) const { return false; }
+
+ static const char* GetCommandString(OpType type);
+
+protected:
+ SkTDArray<SkString*> fInfo;
+
+private:
+ OpType fOpType;
+ bool fVisible;
+};
+
+class SkRestoreCommand : public SkDrawCommand {
+public:
+ SkRestoreCommand();
+ void execute(SkCanvas* canvas) const override;
+ Action action() const override { return kPopLayer_Action; }
+
+private:
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkClearCommand : public SkDrawCommand {
+public:
+ SkClearCommand(SkColor color);
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkColor fColor;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkClipPathCommand : public SkDrawCommand {
+public:
+ SkClipPathCommand(const SkPath& path, SkRegion::Op op, bool doAA);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkPath fPath;
+ SkRegion::Op fOp;
+ bool fDoAA;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkClipRegionCommand : public SkDrawCommand {
+public:
+ SkClipRegionCommand(const SkRegion& region, SkRegion::Op op);
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkRegion fRegion;
+ SkRegion::Op fOp;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkClipRectCommand : public SkDrawCommand {
+public:
+ SkClipRectCommand(const SkRect& rect, SkRegion::Op op, bool doAA);
+ void execute(SkCanvas* canvas) const override;
+
+ const SkRect& rect() const { return fRect; }
+ SkRegion::Op op() const { return fOp; }
+ bool doAA() const { return fDoAA; }
+
+private:
+ SkRect fRect;
+ SkRegion::Op fOp;
+ bool fDoAA;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkClipRRectCommand : public SkDrawCommand {
+public:
+ SkClipRRectCommand(const SkRRect& rrect, SkRegion::Op op, bool doAA);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+
+ const SkRRect& rrect() const { return fRRect; }
+ SkRegion::Op op() const { return fOp; }
+ bool doAA() const { return fDoAA; }
+
+private:
+ SkRRect fRRect;
+ SkRegion::Op fOp;
+ bool fDoAA;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkConcatCommand : public SkDrawCommand {
+public:
+ SkConcatCommand(const SkMatrix& matrix);
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkMatrix fMatrix;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawBitmapCommand : public SkDrawCommand {
+public:
+ SkDrawBitmapCommand(const SkBitmap& bitmap, SkScalar left, SkScalar top,
+ const SkPaint* paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkBitmap fBitmap;
+ SkScalar fLeft;
+ SkScalar fTop;
+ SkPaint fPaint;
+ SkPaint* fPaintPtr;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawBitmapNineCommand : public SkDrawCommand {
+public:
+ SkDrawBitmapNineCommand(const SkBitmap& bitmap, const SkIRect& center,
+ const SkRect& dst, const SkPaint* paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkBitmap fBitmap;
+ SkIRect fCenter;
+ SkRect fDst;
+ SkPaint fPaint;
+ SkPaint* fPaintPtr;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawBitmapRectCommand : public SkDrawCommand {
+public:
+ SkDrawBitmapRectCommand(const SkBitmap& bitmap, const SkRect* src,
+ const SkRect& dst, const SkPaint* paint,
+ SkCanvas::SrcRectConstraint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+
+ const SkBitmap& bitmap() const { return fBitmap; }
+
+ // The non-const 'paint' method allows modification of this object's
+ // SkPaint. For this reason the ctor and setPaint method make a local copy.
+ // The 'fPaintPtr' member acts a signal that the local SkPaint is valid
+ // (since only an SkPaint* is passed into the ctor).
+ const SkPaint* paint() const { return fPaintPtr; }
+ SkPaint* paint() { return fPaintPtr; }
+
+ void setPaint(const SkPaint& paint) { fPaint = paint; fPaintPtr = &fPaint; }
+
+ const SkRect* srcRect() const { return fSrc.isEmpty() ? nullptr : &fSrc; }
+ void setSrcRect(const SkRect& src) { fSrc = src; }
+
+ const SkRect& dstRect() const { return fDst; }
+ void setDstRect(const SkRect& dst) { fDst = dst; }
+
+ SkCanvas::SrcRectConstraint constraint() const { return fConstraint; }
+ void setConstraint(SkCanvas::SrcRectConstraint constraint) { fConstraint = constraint; }
+
+private:
+ SkBitmap fBitmap;
+ SkRect fSrc;
+ SkRect fDst;
+ SkPaint fPaint;
+ SkPaint* fPaintPtr;
+ SkCanvas::SrcRectConstraint fConstraint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawImageCommand : public SkDrawCommand {
+public:
+ SkDrawImageCommand(const SkImage* image, SkScalar left, SkScalar top, const SkPaint* paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkAutoTUnref<const SkImage> fImage;
+ SkScalar fLeft;
+ SkScalar fTop;
+ SkTLazy<SkPaint> fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawImageRectCommand : public SkDrawCommand {
+public:
+ SkDrawImageRectCommand(const SkImage* image, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint, SkCanvas::SrcRectConstraint constraint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkAutoTUnref<const SkImage> fImage;
+ SkTLazy<SkRect> fSrc;
+ SkRect fDst;
+ SkTLazy<SkPaint> fPaint;
+ SkCanvas::SrcRectConstraint fConstraint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawOvalCommand : public SkDrawCommand {
+public:
+ SkDrawOvalCommand(const SkRect& oval, const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkRect fOval;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPaintCommand : public SkDrawCommand {
+public:
+ SkDrawPaintCommand(const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPathCommand : public SkDrawCommand {
+public:
+ SkDrawPathCommand(const SkPath& path, const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+
+private:
+ SkPath fPath;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkBeginDrawPictureCommand : public SkDrawCommand {
+public:
+ SkBeginDrawPictureCommand(const SkPicture* picture,
+ const SkMatrix* matrix,
+ const SkPaint* paint);
+
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+
+private:
+ SkAutoTUnref<const SkPicture> fPicture;
+ SkTLazy<SkMatrix> fMatrix;
+ SkTLazy<SkPaint> fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkEndDrawPictureCommand : public SkDrawCommand {
+public:
+ SkEndDrawPictureCommand(bool restore);
+
+ void execute(SkCanvas* canvas) const override;
+
+private:
+ bool fRestore;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPointsCommand : public SkDrawCommand {
+public:
+ SkDrawPointsCommand(SkCanvas::PointMode mode, size_t count, const SkPoint pts[],
+ const SkPaint& paint);
+ virtual ~SkDrawPointsCommand() { delete [] fPts; }
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkCanvas::PointMode fMode;
+ size_t fCount;
+ SkPoint* fPts;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawTextCommand : public SkDrawCommand {
+public:
+ SkDrawTextCommand(const void* text, size_t byteLength, SkScalar x, SkScalar y,
+ const SkPaint& paint);
+ virtual ~SkDrawTextCommand() { delete [] fText; }
+ void execute(SkCanvas* canvas) const override;
+private:
+ char* fText;
+ size_t fByteLength;
+ SkScalar fX;
+ SkScalar fY;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPosTextCommand : public SkDrawCommand {
+public:
+ SkDrawPosTextCommand(const void* text, size_t byteLength, const SkPoint pos[],
+ const SkPaint& paint);
+ virtual ~SkDrawPosTextCommand() { delete [] fPos; delete [] fText; }
+ void execute(SkCanvas* canvas) const override;
+private:
+ char* fText;
+ size_t fByteLength;
+ SkPoint* fPos;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawTextOnPathCommand : public SkDrawCommand {
+public:
+ SkDrawTextOnPathCommand(const void* text, size_t byteLength, const SkPath& path,
+ const SkMatrix* matrix, const SkPaint& paint);
+ virtual ~SkDrawTextOnPathCommand() { delete [] fText; }
+ void execute(SkCanvas* canvas) const override;
+private:
+ char* fText;
+ size_t fByteLength;
+ SkPath fPath;
+ SkMatrix fMatrix;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPosTextHCommand : public SkDrawCommand {
+public:
+ SkDrawPosTextHCommand(const void* text, size_t byteLength, const SkScalar xpos[],
+ SkScalar constY, const SkPaint& paint);
+ virtual ~SkDrawPosTextHCommand() { delete [] fXpos; delete [] fText; }
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkScalar* fXpos;
+ char* fText;
+ size_t fByteLength;
+ SkScalar fConstY;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawTextBlobCommand : public SkDrawCommand {
+public:
+ SkDrawTextBlobCommand(const SkTextBlob* blob, SkScalar x, SkScalar y, const SkPaint& paint);
+
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+
+private:
+ SkAutoTUnref<const SkTextBlob> fBlob;
+ SkScalar fXPos;
+ SkScalar fYPos;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawPatchCommand : public SkDrawCommand {
+public:
+ SkDrawPatchCommand(const SkPoint cubics[12], const SkColor colors[4],
+ const SkPoint texCoords[4], SkXfermode* xmode,
+ const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+
+private:
+ SkPoint fCubics[12];
+ SkColor fColors[4];
+ SkPoint fTexCoords[4];
+ SkAutoTUnref<SkXfermode> fXfermode;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+
+class SkDrawRectCommand : public SkDrawCommand {
+public:
+ SkDrawRectCommand(const SkRect& rect, const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+
+ const SkRect& rect() const { return fRect; }
+ const SkPaint& paint() const { return fPaint; }
+private:
+ SkRect fRect;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawRRectCommand : public SkDrawCommand {
+public:
+ SkDrawRRectCommand(const SkRRect& rrect, const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkRRect fRRect;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawDRRectCommand : public SkDrawCommand {
+public:
+ SkDrawDRRectCommand(const SkRRect& outer, const SkRRect& inner,
+ const SkPaint& paint);
+ void execute(SkCanvas* canvas) const override;
+ bool render(SkCanvas* canvas) const override;
+private:
+ SkRRect fOuter;
+ SkRRect fInner;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkDrawVerticesCommand : public SkDrawCommand {
+public:
+ SkDrawVerticesCommand(SkCanvas::VertexMode vmode, int vertexCount,
+ const SkPoint vertices[], const SkPoint texs[],
+ const SkColor colors[], SkXfermode* xfermode,
+ const uint16_t indices[], int indexCount,
+ const SkPaint& paint);
+ virtual ~SkDrawVerticesCommand();
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkCanvas::VertexMode fVmode;
+ int fVertexCount;
+ SkPoint* fVertices;
+ SkPoint* fTexs;
+ SkColor* fColors;
+ SkXfermode* fXfermode;
+ uint16_t* fIndices;
+ int fIndexCount;
+ SkPaint fPaint;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkSaveCommand : public SkDrawCommand {
+public:
+ SkSaveCommand();
+ void execute(SkCanvas* canvas) const override;
+ Action action() const override { return kPushLayer_Action; }
+private:
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkSaveLayerCommand : public SkDrawCommand {
+public:
+ SkSaveLayerCommand(const SkCanvas::SaveLayerRec&);
+ void execute(SkCanvas* canvas) const override;
+ void vizExecute(SkCanvas* canvas) const override;
+ Action action() const override{ return kPushLayer_Action; }
+ void setActive(bool active) override { fActive = active; }
+ bool active() const override { return fActive; }
+
+ const SkPaint* paint() const { return fPaintPtr; }
+
+private:
+ SkRect fBounds;
+ SkPaint fPaint;
+ SkPaint* fPaintPtr;
+ uint32_t fSaveLayerFlags;
+
+ bool fActive;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+class SkSetMatrixCommand : public SkDrawCommand {
+public:
+ SkSetMatrixCommand(const SkMatrix& matrix);
+ void setUserMatrix(const SkMatrix&) override;
+ void execute(SkCanvas* canvas) const override;
+private:
+ SkMatrix fUserMatrix;
+ SkMatrix fMatrix;
+
+ typedef SkDrawCommand INHERITED;
+};
+
+#endif
diff --git a/tools/debugger/SkObjectParser.cpp b/tools/debugger/SkObjectParser.cpp
new file mode 100644
index 0000000000..6d71a38b7b
--- /dev/null
+++ b/tools/debugger/SkObjectParser.cpp
@@ -0,0 +1,405 @@
+
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkObjectParser.h"
+#include "SkData.h"
+#include "SkFontDescriptor.h"
+#include "SkImage.h"
+#include "SkPath.h"
+#include "SkRRect.h"
+#include "SkShader.h"
+#include "SkStream.h"
+#include "SkStringUtils.h"
+#include "SkTypeface.h"
+#include "SkUtils.h"
+
+/* TODO(chudy): Replace all std::strings with char */
+
+SkString* SkObjectParser::BitmapToString(const SkBitmap& bitmap) {
+ SkString* mBitmap = new SkString("SkBitmap: ");
+ mBitmap->append("W: ");
+ mBitmap->appendS32(bitmap.width());
+ mBitmap->append(" H: ");
+ mBitmap->appendS32(bitmap.height());
+
+ const char* gColorTypeStrings[] = {
+ "None", "A8", "565", "4444", "RGBA", "BGRA", "Index8", "G8"
+ };
+ SkASSERT(kLastEnum_SkColorType + 1 == SK_ARRAY_COUNT(gColorTypeStrings));
+
+ mBitmap->append(" ColorType: ");
+ mBitmap->append(gColorTypeStrings[bitmap.colorType()]);
+
+ if (bitmap.isOpaque()) {
+ mBitmap->append(" opaque");
+ } else {
+ mBitmap->append(" not-opaque");
+ }
+
+ if (bitmap.isImmutable()) {
+ mBitmap->append(" immutable");
+ } else {
+ mBitmap->append(" not-immutable");
+ }
+
+ if (bitmap.isVolatile()) {
+ mBitmap->append(" volatile");
+ } else {
+ mBitmap->append(" not-volatile");
+ }
+
+ mBitmap->append(" genID: ");
+ mBitmap->appendS32(bitmap.getGenerationID());
+
+ return mBitmap;
+}
+
+SkString* SkObjectParser::ImageToString(const SkImage* image) {
+ SkString* str = new SkString("SkImage: ");
+ if (!image) {
+ return str;
+ }
+
+ str->append("W: ");
+ str->appendS32(image->width());
+ str->append(" H: ");
+ str->appendS32(image->height());
+
+ if (image->isOpaque()) {
+ str->append(" opaque");
+ } else {
+ str->append(" not-opaque");
+ }
+
+ str->append(" uniqueID: ");
+ str->appendS32(image->uniqueID());
+
+ return str;
+}
+
+SkString* SkObjectParser::BoolToString(bool doAA) {
+ SkString* mBool = new SkString("Bool doAA: ");
+ if (doAA) {
+ mBool->append("True");
+ } else {
+ mBool->append("False");
+ }
+ return mBool;
+}
+
+SkString* SkObjectParser::CustomTextToString(const char* text) {
+ SkString* mText = new SkString(text);
+ return mText;
+}
+
+SkString* SkObjectParser::IntToString(int x, const char* text) {
+ SkString* mInt = new SkString(text);
+ mInt->append(" ");
+ mInt->appendScalar(SkIntToScalar(x));
+ return mInt;
+}
+
+SkString* SkObjectParser::IRectToString(const SkIRect& rect) {
+ SkString* mRect = new SkString("SkIRect: ");
+ mRect->append("L: ");
+ mRect->appendS32(rect.left());
+ mRect->append(", T: ");
+ mRect->appendS32(rect.top());
+ mRect->append(", R: ");
+ mRect->appendS32(rect.right());
+ mRect->append(", B: ");
+ mRect->appendS32(rect.bottom());
+ return mRect;
+}
+
+SkString* SkObjectParser::MatrixToString(const SkMatrix& matrix) {
+ SkString* str = new SkString("SkMatrix: ");
+#ifndef SK_IGNORE_TO_STRING
+ matrix.toString(str);
+#endif
+ return str;
+}
+
+SkString* SkObjectParser::PaintToString(const SkPaint& paint) {
+ SkString* str = new SkString;
+#ifndef SK_IGNORE_TO_STRING
+ paint.toString(str);
+#endif
+ return str;
+}
+
+SkString* SkObjectParser::PathToString(const SkPath& path) {
+ SkString* mPath = new SkString;
+
+ mPath->appendf("Path (%d) (", path.getGenerationID());
+
+ static const char* gFillStrings[] = {
+ "Winding", "EvenOdd", "InverseWinding", "InverseEvenOdd"
+ };
+
+ mPath->append(gFillStrings[path.getFillType()]);
+ mPath->append(", ");
+
+ static const char* gConvexityStrings[] = {
+ "Unknown", "Convex", "Concave"
+ };
+ SkASSERT(SkPath::kConcave_Convexity == 2);
+
+ mPath->append(gConvexityStrings[path.getConvexity()]);
+ mPath->append(", ");
+
+ if (path.isRect(nullptr)) {
+ mPath->append("isRect, ");
+ } else {
+ mPath->append("isNotRect, ");
+ }
+
+ if (path.isOval(nullptr)) {
+ mPath->append("isOval, ");
+ } else {
+ mPath->append("isNotOval, ");
+ }
+
+ SkRRect rrect;
+ if (path.isRRect(&rrect)) {
+ mPath->append("isRRect, ");
+ } else {
+ mPath->append("isNotRRect, ");
+ }
+
+ mPath->appendS32(path.countVerbs());
+ mPath->append("V, ");
+ mPath->appendS32(path.countPoints());
+ mPath->append("P): ");
+
+ static const char* gVerbStrings[] = {
+ "Move", "Line", "Quad", "Conic", "Cubic", "Close", "Done"
+ };
+ static const int gPtsPerVerb[] = { 1, 1, 2, 2, 3, 0, 0 };
+ static const int gPtOffsetPerVerb[] = { 0, 1, 1, 1, 1, 0, 0 };
+ SkASSERT(SkPath::kDone_Verb == 6);
+
+ SkPath::Iter iter(const_cast<SkPath&>(path), false);
+ SkPath::Verb verb;
+ SkPoint points[4];
+
+ for(verb = iter.next(points, false);
+ verb != SkPath::kDone_Verb;
+ verb = iter.next(points, false)) {
+
+ mPath->append(gVerbStrings[verb]);
+ mPath->append(" ");
+
+ for (int i = 0; i < gPtsPerVerb[verb]; ++i) {
+ mPath->append("(");
+ mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fX);
+ mPath->append(", ");
+ mPath->appendScalar(points[gPtOffsetPerVerb[verb]+i].fY);
+ mPath->append(")");
+ }
+
+ if (SkPath::kConic_Verb == verb) {
+ mPath->append("(");
+ mPath->appendScalar(iter.conicWeight());
+ mPath->append(")");
+ }
+
+ mPath->append(" ");
+ }
+
+ SkString* boundStr = SkObjectParser::RectToString(path.getBounds(), " Bound: ");
+
+ if (boundStr) {
+ mPath->append(*boundStr);
+ delete boundStr;
+ }
+
+ return mPath;
+}
+
+SkString* SkObjectParser::PointsToString(const SkPoint pts[], size_t count) {
+ SkString* mPoints = new SkString("SkPoints pts[]: ");
+ for (unsigned int i = 0; i < count; i++) {
+ mPoints->append("(");
+ mPoints->appendScalar(pts[i].fX);
+ mPoints->append(",");
+ mPoints->appendScalar(pts[i].fY);
+ mPoints->append(")");
+ }
+ return mPoints;
+}
+
+SkString* SkObjectParser::PointModeToString(SkCanvas::PointMode mode) {
+ SkString* mMode = new SkString("SkCanvas::PointMode: ");
+ if (mode == SkCanvas::kPoints_PointMode) {
+ mMode->append("kPoints_PointMode");
+ } else if (mode == SkCanvas::kLines_PointMode) {
+ mMode->append("kLines_Mode");
+ } else if (mode == SkCanvas::kPolygon_PointMode) {
+ mMode->append("kPolygon_PointMode");
+ }
+ return mMode;
+}
+
+SkString* SkObjectParser::RectToString(const SkRect& rect, const char* title) {
+
+ SkString* mRect = new SkString;
+
+ if (nullptr == title) {
+ mRect->append("SkRect: ");
+ } else {
+ mRect->append(title);
+ }
+ mRect->append("(");
+ mRect->appendScalar(rect.left());
+ mRect->append(", ");
+ mRect->appendScalar(rect.top());
+ mRect->append(", ");
+ mRect->appendScalar(rect.right());
+ mRect->append(", ");
+ mRect->appendScalar(rect.bottom());
+ mRect->append(")");
+ return mRect;
+}
+
+SkString* SkObjectParser::RRectToString(const SkRRect& rrect, const char* title) {
+
+ SkString* mRRect = new SkString;
+
+ if (nullptr == title) {
+ mRRect->append("SkRRect (");
+ if (rrect.isEmpty()) {
+ mRRect->append("empty");
+ } else if (rrect.isRect()) {
+ mRRect->append("rect");
+ } else if (rrect.isOval()) {
+ mRRect->append("oval");
+ } else if (rrect.isSimple()) {
+ mRRect->append("simple");
+ } else if (rrect.isNinePatch()) {
+ mRRect->append("nine-patch");
+ } else {
+ SkASSERT(rrect.isComplex());
+ mRRect->append("complex");
+ }
+ mRRect->append("): ");
+ } else {
+ mRRect->append(title);
+ }
+ mRRect->append("(");
+ mRRect->appendScalar(rrect.rect().left());
+ mRRect->append(", ");
+ mRRect->appendScalar(rrect.rect().top());
+ mRRect->append(", ");
+ mRRect->appendScalar(rrect.rect().right());
+ mRRect->append(", ");
+ mRRect->appendScalar(rrect.rect().bottom());
+ mRRect->append(") radii: (");
+ for (int i = 0; i < 4; ++i) {
+ const SkVector& radii = rrect.radii((SkRRect::Corner) i);
+ mRRect->appendScalar(radii.fX);
+ mRRect->append(", ");
+ mRRect->appendScalar(radii.fY);
+ if (i < 3) {
+ mRRect->append(", ");
+ }
+ }
+ mRRect->append(")");
+ return mRRect;
+}
+
+SkString* SkObjectParser::RegionOpToString(SkRegion::Op op) {
+ SkString* mOp = new SkString("SkRegion::Op: ");
+ if (op == SkRegion::kDifference_Op) {
+ mOp->append("kDifference_Op");
+ } else if (op == SkRegion::kIntersect_Op) {
+ mOp->append("kIntersect_Op");
+ } else if (op == SkRegion::kUnion_Op) {
+ mOp->append("kUnion_Op");
+ } else if (op == SkRegion::kXOR_Op) {
+ mOp->append("kXOR_Op");
+ } else if (op == SkRegion::kReverseDifference_Op) {
+ mOp->append("kReverseDifference_Op");
+ } else if (op == SkRegion::kReplace_Op) {
+ mOp->append("kReplace_Op");
+ } else {
+ mOp->append("Unknown Type");
+ }
+ return mOp;
+}
+
+SkString* SkObjectParser::RegionToString(const SkRegion& region) {
+ SkString* mRegion = new SkString("SkRegion: Data unavailable.");
+ return mRegion;
+}
+
+SkString* SkObjectParser::SaveLayerFlagsToString(SkCanvas::SaveLayerFlags saveLayerFlags) {
+ SkString* mFlags = new SkString("SkCanvas::SaveFlags: ");
+ if (saveLayerFlags & SkCanvas::kIsOpaque_SaveLayerFlag) {
+ mFlags->append("kIsOpaque_SaveLayerFlag ");
+ }
+ if (saveLayerFlags & SkCanvas::kPreserveLCDText_SaveLayerFlag) {
+ mFlags->append("kPreserveLCDText_SaveLayerFlag ");
+ }
+ return mFlags;
+}
+
+SkString* SkObjectParser::ScalarToString(SkScalar x, const char* text) {
+ SkString* mScalar = new SkString(text);
+ mScalar->append(" ");
+ mScalar->appendScalar(x);
+ return mScalar;
+}
+
+SkString* SkObjectParser::TextToString(const void* text, size_t byteLength,
+ SkPaint::TextEncoding encoding) {
+
+ SkString* decodedText = new SkString();
+ switch (encoding) {
+ case SkPaint::kUTF8_TextEncoding: {
+ decodedText->append("UTF-8: ");
+ decodedText->append((const char*)text, byteLength);
+ break;
+ }
+ case SkPaint::kUTF16_TextEncoding: {
+ decodedText->append("UTF-16: ");
+ size_t sizeNeeded = SkUTF16_ToUTF8((uint16_t*)text,
+ SkToS32(byteLength / 2),
+ nullptr);
+ SkAutoSTMalloc<0x100, char> utf8(sizeNeeded);
+ SkUTF16_ToUTF8((uint16_t*)text, SkToS32(byteLength / 2), utf8);
+ decodedText->append(utf8, sizeNeeded);
+ break;
+ }
+ case SkPaint::kUTF32_TextEncoding: {
+ decodedText->append("UTF-32: ");
+ const SkUnichar* begin = (const SkUnichar*)text;
+ const SkUnichar* end = (const SkUnichar*)((const char*)text + byteLength);
+ for (const SkUnichar* unichar = begin; unichar < end; ++unichar) {
+ decodedText->appendUnichar(*unichar);
+ }
+ break;
+ }
+ case SkPaint::kGlyphID_TextEncoding: {
+ decodedText->append("GlyphID: ");
+ const uint16_t* begin = (const uint16_t*)text;
+ const uint16_t* end = (const uint16_t*)((const char*)text + byteLength);
+ for (const uint16_t* glyph = begin; glyph < end; ++glyph) {
+ decodedText->append("0x");
+ decodedText->appendHex(*glyph);
+ decodedText->append(" ");
+ }
+ break;
+ }
+ default:
+ decodedText->append("Unknown text encoding.");
+ break;
+ }
+
+ return decodedText;
+}
diff --git a/tools/debugger/SkObjectParser.h b/tools/debugger/SkObjectParser.h
new file mode 100644
index 0000000000..9bdfad5e79
--- /dev/null
+++ b/tools/debugger/SkObjectParser.h
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SKOBJECTPARSER_H_
+#define SKOBJECTPARSER_H_
+
+#include "SkCanvas.h"
+#include "SkString.h"
+
+/** \class SkObjectParser
+
+ The ObjectParser is used to return string information about parameters
+ in each draw command.
+ */
+class SkObjectParser {
+public:
+
+ /**
+ Returns a string about a bitmap's bounds and colortype.
+ @param bitmap SkBitmap
+ */
+ static SkString* BitmapToString(const SkBitmap& bitmap);
+
+ /**
+ Returns a string about a image
+ @param image SkImage
+ */
+ static SkString* ImageToString(const SkImage* image);
+
+ /**
+ Returns a string representation of a boolean.
+ @param doAA boolean
+ */
+ static SkString* BoolToString(bool doAA);
+
+ /**
+ Returns a string representation of the text pointer passed in.
+ */
+ static SkString* CustomTextToString(const char* text);
+
+ /**
+ Returns a string representation of an integer with the text parameter
+ at the front of the string.
+ @param x integer
+ @param text
+ */
+ static SkString* IntToString(int x, const char* text);
+ /**
+ Returns a string representation of the SkIRects coordinates.
+ @param rect SkIRect
+ */
+ static SkString* IRectToString(const SkIRect& rect);
+
+ /**
+ Returns a string representation of an SkMatrix's contents
+ @param matrix SkMatrix
+ */
+ static SkString* MatrixToString(const SkMatrix& matrix);
+
+ /**
+ Returns a string representation of an SkPaint's color
+ @param paint SkPaint
+ */
+ static SkString* PaintToString(const SkPaint& paint);
+
+ /**
+ Returns a string representation of a SkPath's points.
+ @param path SkPath
+ */
+ static SkString* PathToString(const SkPath& path);
+
+ /**
+ Returns a string representation of the points in the point array.
+ @param pts[] Array of SkPoints
+ @param count
+ */
+ static SkString* PointsToString(const SkPoint pts[], size_t count);
+
+ /**
+ Returns a string representation of the SkCanvas PointMode enum.
+ */
+ static SkString* PointModeToString(SkCanvas::PointMode mode);
+
+ /**
+ Returns a string representation of the SkRects coordinates.
+ @param rect SkRect
+ */
+ static SkString* RectToString(const SkRect& rect, const char* title = nullptr);
+
+ /**
+ Returns a string representation of an SkRRect.
+ @param rrect SkRRect
+ */
+ static SkString* RRectToString(const SkRRect& rrect, const char* title = nullptr);
+
+ /**
+ Returns a string representation of the SkRegion enum.
+ @param op SkRegion::op enum
+ */
+ static SkString* RegionOpToString(SkRegion::Op op);
+
+ /**
+ Returns a string representation of the SkRegion.
+ @param region SkRegion
+ */
+ static SkString* RegionToString(const SkRegion& region);
+
+ /**
+ Returns a string representation of the SkCanvas::SaveLayerFlags enum.
+ @param flags SkCanvas::SaveLayerFlags enum
+ */
+ static SkString* SaveLayerFlagsToString(uint32_t saveLayerFlags);
+
+ /**
+ Returns a string representation of an SkScalar with the text parameter
+ at the front of the string.
+ @param x SkScalar
+ @param text
+ */
+ static SkString* ScalarToString(SkScalar x, const char* text);
+
+ /**
+ Returns a string representation of the char pointer passed in.
+ @param text const void* that will be cast to a char*
+ */
+ static SkString* TextToString(const void* text, size_t byteLength,
+ SkPaint::TextEncoding encoding);
+};
+
+#endif
diff --git a/tools/debugger/SkOverdrawMode.cpp b/tools/debugger/SkOverdrawMode.cpp
new file mode 100644
index 0000000000..3b695eca26
--- /dev/null
+++ b/tools/debugger/SkOverdrawMode.cpp
@@ -0,0 +1,324 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkColorPriv.h"
+#include "SkOverdrawMode.h"
+#include "SkString.h"
+#include "SkXfermode.h"
+
+#if SK_SUPPORT_GPU
+#include "GrFragmentProcessor.h"
+#include "GrInvariantOutput.h"
+#include "GrXferProcessor.h"
+#include "glsl/GrGLSLFragmentProcessor.h"
+#include "glsl/GrGLSLFragmentShaderBuilder.h"
+#include "glsl/GrGLSLXferProcessor.h"
+
+ ///////////////////////////////////////////////////////////////////////////////
+ // Fragment Processor
+ ///////////////////////////////////////////////////////////////////////////////
+
+class GLOverdrawFP;
+
+class GrOverdrawFP : public GrFragmentProcessor {
+public:
+ static const GrFragmentProcessor* Create(const GrFragmentProcessor* dst) {
+ return new GrOverdrawFP(dst);
+ }
+
+ ~GrOverdrawFP() override { }
+
+ const char* name() const override { return "Overdraw"; }
+
+ SkString dumpInfo() const override {
+ SkString str;
+ return str;
+ }
+
+private:
+ GrGLSLFragmentProcessor* onCreateGLSLInstance() const override;
+
+ void onGetGLSLProcessorKey(const GrGLSLCaps&, GrProcessorKeyBuilder* b) const override;
+
+ bool onIsEqual(const GrFragmentProcessor&) const override { return true; }
+
+ void onComputeInvariantOutput(GrInvariantOutput* inout) const override {
+ inout->setToUnknown(GrInvariantOutput::kWill_ReadInput);
+ }
+
+ GrOverdrawFP(const GrFragmentProcessor* dst) {
+ this->initClassID<GrOverdrawFP>();
+
+ SkASSERT(dst);
+ SkDEBUGCODE(int dstIndex = )this->registerChildProcessor(dst);
+ SkASSERT(0 == dstIndex);
+ }
+
+ GR_DECLARE_FRAGMENT_PROCESSOR_TEST;
+ typedef GrFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static void add_overdraw_code(GrGLSLFragmentBuilder* fragBuilder,
+ const char* dstColor,
+ const char* outputColor) {
+
+ static const GrGLSLShaderVar gColorTableArgs[] = {
+ // TODO: once kInt_GrSLType lands - switch this over
+ GrGLSLShaderVar("index", kFloat_GrSLType),
+ };
+ SkString colorTableFuncName;
+
+ // The 'colorTable' function exists to work around older GLSL's prohibition
+ // of initialized arrays. It takes an integer index and just returns the
+ // corresponding color.
+ fragBuilder->emitFunction(kVec4f_GrSLType,
+ "colorTable",
+ SK_ARRAY_COUNT(gColorTableArgs),
+ gColorTableArgs,
+ "if (index < 1.5) { return vec4(0.5, 0.617, 1.0, 1.0); }"
+ "if (index < 2.5) { return vec4(0.664, 0.723, 0.83, 1.0); }"
+ "if (index < 3.5) { return vec4(0.832, 0.762, 0.664, 1.0); }"
+ "if (index < 4.5) { return vec4(1, 0.75, 0.496, 1.0); }"
+ "if (index < 5.5) { return vec4(1, 0.723, 0.332, 1.0); }"
+ "if (index < 6.5) { return vec4(1, 0.645, 0.164, 1.0); }"
+ "if (index < 7.5) { return vec4(1, 0.527, 0, 1.0); }"
+ "if (index < 8.5) { return vec4(1, 0.371, 0, 1.0); }"
+ "if (index < 9.5) { return vec4(1, 0.195, 0, 1.0); }"
+ "return vec4(1, 0, 0, 1.0);",
+ &colorTableFuncName);
+
+ fragBuilder->codeAppend("int nextIdx;");
+ fragBuilder->codeAppendf("vec4 dst = %s;", dstColor);
+ fragBuilder->codeAppend("if (dst.r < 0.25) { nextIdx = 1; }");
+ // cap 'idx' at 10
+ fragBuilder->codeAppend("else if (dst.g < 0.0977) { nextIdx = 10; }");
+ fragBuilder->codeAppend("else if (dst.b > 0.08) { nextIdx = 8 - int(6.0 * dst.b + 0.5); }");
+ fragBuilder->codeAppend("else { nextIdx = 11 - int(5.7 * dst.g + 0.5); }");
+ fragBuilder->codeAppendf("%s = %s(float(nextIdx));", outputColor, colorTableFuncName.c_str());
+}
+
+class GLOverdrawFP : public GrGLSLFragmentProcessor {
+public:
+ void emitCode(EmitArgs& args) override {
+ GrGLSLFragmentBuilder* fragBuilder = args.fFragBuilder;
+ SkString dstColor("dstColor");
+ this->emitChild(0, nullptr, &dstColor, args);
+
+ add_overdraw_code(fragBuilder, dstColor.c_str(), args.fOutputColor);
+ }
+
+ static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) { }
+
+private:
+ typedef GrGLSLFragmentProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+GrGLSLFragmentProcessor* GrOverdrawFP::onCreateGLSLInstance() const {
+ return new GLOverdrawFP;
+}
+
+void GrOverdrawFP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
+ GLOverdrawFP::GenKey(*this, caps, b);
+}
+
+const GrFragmentProcessor* GrOverdrawFP::TestCreate(GrProcessorTestData* d) {
+ SkAutoTUnref<const GrFragmentProcessor> dst(GrProcessorUnitTest::CreateChildFP(d));
+ return new GrOverdrawFP(dst);
+}
+
+GR_DEFINE_FRAGMENT_PROCESSOR_TEST(GrOverdrawFP);
+
+///////////////////////////////////////////////////////////////////////////////
+// Xfer Processor
+///////////////////////////////////////////////////////////////////////////////
+
+class OverdrawXP : public GrXferProcessor {
+public:
+ OverdrawXP(const DstTexture* dstTexture, bool hasMixedSamples)
+ : INHERITED(dstTexture, true, hasMixedSamples) {
+ this->initClassID<OverdrawXP>();
+ }
+
+ const char* name() const override { return "Overdraw"; }
+
+ GrGLSLXferProcessor* createGLSLInstance() const override;
+
+private:
+ GrXferProcessor::OptFlags onGetOptimizations(const GrPipelineOptimizations& optimizations,
+ bool doesStencilWrite,
+ GrColor* overrideColor,
+ const GrCaps& caps) const override {
+ // We never look at the color input
+ return GrXferProcessor::kIgnoreColor_OptFlag;
+ }
+
+ void onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const override;
+
+ bool onIsEqual(const GrXferProcessor&) const override { return true; }
+
+ typedef GrXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class GLOverdrawXP : public GrGLSLXferProcessor {
+public:
+ GLOverdrawXP(const OverdrawXP&) { }
+
+ ~GLOverdrawXP() override {}
+
+ static void GenKey(const GrProcessor&, const GrGLSLCaps&, GrProcessorKeyBuilder*) { }
+
+private:
+ void emitBlendCodeForDstRead(GrGLSLXPFragmentBuilder* fragBuilder,
+ GrGLSLUniformHandler* uniformHandler,
+ const char* srcColor,
+ const char* srcCoverage,
+ const char* dstColor,
+ const char* outColor,
+ const char* outColorSecondary,
+ const GrXferProcessor& proc) override {
+ add_overdraw_code(fragBuilder, dstColor, outColor);
+
+ // Apply coverage.
+ INHERITED::DefaultCoverageModulation(fragBuilder, srcCoverage, dstColor, outColor,
+ outColorSecondary, proc);
+ }
+
+ void onSetData(const GrGLSLProgramDataManager&, const GrXferProcessor&) override { };
+
+ typedef GrGLSLXferProcessor INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+void OverdrawXP::onGetGLSLProcessorKey(const GrGLSLCaps& caps, GrProcessorKeyBuilder* b) const {
+ GLOverdrawXP::GenKey(*this, caps, b);
+}
+
+GrGLSLXferProcessor* OverdrawXP::createGLSLInstance() const { return new GLOverdrawXP(*this); }
+
+///////////////////////////////////////////////////////////////////////////////
+class GrOverdrawXPFactory : public GrXPFactory {
+public:
+ static GrXPFactory* Create() { return new GrOverdrawXPFactory(); }
+
+ void getInvariantBlendedColor(const GrProcOptInfo& colorPOI,
+ GrXPFactory::InvariantBlendedColor* blendedColor) const override {
+ blendedColor->fWillBlendWithDst = true;
+ blendedColor->fKnownColorFlags = kNone_GrColorComponentFlags;
+ }
+
+private:
+ GrOverdrawXPFactory() {
+ this->initClassID<GrOverdrawXPFactory>();
+ }
+
+ GrXferProcessor* onCreateXferProcessor(const GrCaps& caps,
+ const GrPipelineOptimizations& optimizations,
+ bool hasMixedSamples,
+ const DstTexture* dstTexture) const override {
+ return new OverdrawXP(dstTexture, hasMixedSamples);
+ }
+
+ bool onWillReadDstColor(const GrCaps& caps,
+ const GrPipelineOptimizations& optimizations,
+ bool hasMixedSamples) const override {
+ return true;
+ }
+
+ bool onIsEqual(const GrXPFactory& xpfBase) const override { return true; }
+
+ GR_DECLARE_XP_FACTORY_TEST;
+
+ typedef GrXPFactory INHERITED;
+};
+
+GR_DEFINE_XP_FACTORY_TEST(GrOverdrawXPFactory);
+
+const GrXPFactory* GrOverdrawXPFactory::TestCreate(GrProcessorTestData* d) {
+ return GrOverdrawXPFactory::Create();
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+class SkOverdrawXfermode : public SkXfermode {
+public:
+ static SkXfermode* Create() {
+ return new SkOverdrawXfermode;
+ }
+
+ SkPMColor xferColor(SkPMColor src, SkPMColor dst) const override {
+ // This table encodes the color progression of the overdraw visualization
+ static const SkPMColor gTable[] = {
+ SkPackARGB32(0x00, 0x00, 0x00, 0x00),
+ SkPackARGB32(0xFF, 128, 158, 255),
+ SkPackARGB32(0xFF, 170, 185, 212),
+ SkPackARGB32(0xFF, 213, 195, 170),
+ SkPackARGB32(0xFF, 255, 192, 127),
+ SkPackARGB32(0xFF, 255, 185, 85),
+ SkPackARGB32(0xFF, 255, 165, 42),
+ SkPackARGB32(0xFF, 255, 135, 0),
+ SkPackARGB32(0xFF, 255, 95, 0),
+ SkPackARGB32(0xFF, 255, 50, 0),
+ SkPackARGB32(0xFF, 255, 0, 0)
+ };
+
+
+ int nextIdx;
+ if (SkColorGetR(dst) < 64) { // dst color is the 0th color so the next color is 1
+ nextIdx = 1;
+ } else if (SkColorGetG(dst) < 25) { // dst color is the 10th color so cap there
+ nextIdx = 10;
+ } else if ((SkColorGetB(dst)+21)/42 > 0) { // dst color is one of 1-6
+ nextIdx = 8 - (SkColorGetB(dst)+21)/42;
+ } else { // dst color is between 7 and 9
+ nextIdx = 11 - (SkColorGetG(dst)+22)/45;
+ }
+ SkASSERT(nextIdx < (int)SK_ARRAY_COUNT(gTable));
+
+ return gTable[nextIdx];
+ }
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkOverdrawXfermode)
+
+#if SK_SUPPORT_GPU
+ const GrFragmentProcessor* getFragmentProcessorForImageFilter(
+ const GrFragmentProcessor* dst) const override {
+ return GrOverdrawFP::Create(dst);
+ }
+
+ GrXPFactory* asXPFactory() const override {
+ return GrOverdrawXPFactory::Create();
+ }
+#endif
+
+#ifndef SK_IGNORE_TO_STRING
+ void toString(SkString* str) const override { str->set("SkOverdrawXfermode"); }
+#endif
+
+private:
+ friend class SkOverdrawMode;
+
+ void flatten(SkWriteBuffer& buffer) const override { }
+
+ typedef SkXfermode INHERITED;
+};
+
+SkFlattenable* SkOverdrawXfermode::CreateProc(SkReadBuffer& buffer) {
+ return Create();
+}
+
+SkXfermode* SkOverdrawMode::Create() { return new SkOverdrawXfermode; }
+
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkOverdrawMode)
+ SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkOverdrawXfermode)
+SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
diff --git a/tools/debugger/SkOverdrawMode.h b/tools/debugger/SkOverdrawMode.h
new file mode 100644
index 0000000000..dba7635f6a
--- /dev/null
+++ b/tools/debugger/SkOverdrawMode.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkOverdrawMode_DEFINED
+#define SkOverdrawMode_DEFINED
+
+#include "SkFlattenable.h"
+
+class SkXfermode;
+
+class SkOverdrawMode {
+public:
+ static SkXfermode* Create();
+
+ SK_DECLARE_FLATTENABLE_REGISTRAR_GROUP();
+
+private:
+ SkOverdrawMode(); // can't be instantiated
+};
+
+#endif