Chromium Code Reviews| Index: src/utils/debugger/SkDebugCanvas.cpp |
| diff --git a/src/utils/debugger/SkDebugCanvas.cpp b/src/utils/debugger/SkDebugCanvas.cpp |
| index 14fbf8888a6d149f7d6e9b304ad403daefbbe708..edad6c5076d3183a89b475537c26ae8fdf528ef8 100644 |
| --- a/src/utils/debugger/SkDebugCanvas.cpp |
| +++ b/src/utils/debugger/SkDebugCanvas.cpp |
| @@ -240,12 +240,14 @@ void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) { |
| SkASSERT(index < fCommandVector.count()); |
| int i = 0; |
| + bool pathOpsMode = getAllowSimplifyClip(); |
| + canvas->setAllowSimplifyClip(pathOpsMode); |
| // This only works assuming the canvas and device are the same ones that |
| // were previously drawn into because they need to preserve all saves |
| // and restores. |
| // The visibility filter also requires a full re-draw - otherwise we can |
| // end up drawing the filter repeatedly. |
| - if (fIndex < index && !fFilter && !fMegaVizMode) { |
| + if (fIndex < index && !fFilter && !fMegaVizMode && !pathOpsMode) { |
| i = fIndex + 1; |
| } else { |
| for (int j = 0; j < fOutstandingSaveCount; j++) { |
| @@ -335,6 +337,28 @@ void SkDebugCanvas::drawTo(SkCanvas* canvas, int index) { |
| canvas->restore(); |
| } |
| + if (pathOpsMode) { |
|
robertphillips
2014/05/16 12:21:24
this-> ?
caryclark
2014/05/16 13:49:02
Done.
|
| + 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(); |
|
robertphillips
2014/05/16 12:21:24
this-> ?
caryclark
2014/05/16 13:49:02
Done.
|
| + addClipStackData(devPath, operand, elementOp); |
| + if (elementOp == SkRegion::kReplace_Op) { |
| + devPath = operand; |
| + } else { |
| + Op(devPath, operand, (SkPathOp) elementOp, &devPath); |
| + } |
| + } |
|
robertphillips
2014/05/16 12:21:24
this-> ?
caryclark
2014/05/16 13:49:02
Done.
|
| + lastClipStackData(devPath); |
| + } |
| fMatrix = canvas->getTotalMatrix(); |
| if (!canvas->getClipDeviceBounds(&fClip)) { |
| fClip.setEmpty(); |
| @@ -588,3 +612,111 @@ 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", |
| +}; |
| + |
| +void SkDebugCanvas::output_scalar(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::output_points(const SkPoint* pts, int count) { |
| + for (int index = 0; index < count; ++index) { |
| + output_scalar(pts[index].fX); |
| + fClipStackData.appendf(", "); |
| + output_scalar(pts[index].fY); |
| + if (index + 1 < count) { |
| + fClipStackData.appendf(", "); |
| + } |
| + } |
| + fClipStackData.appendf(");<br>"); |
| +} |
| + |
| +void SkDebugCanvas::addPathData(const SkPath& path, const char* pathName) { |
| + SkPath::RawIter iter(path); |
| + SkPath::FillType fillType = path.getFillType(); |
| + fClipStackData.appendf(" SkPath %s;<br>", pathName); |
| + fClipStackData.appendf(" %s.setFillType(SkPath::%s);<br>", 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.moveTo(", pathName); |
| + output_points(&pts[0], 1); |
| + continue; |
| + case SkPath::kLine_Verb: |
| + fClipStackData.appendf(" %s.lineTo(", pathName); |
| + output_points(&pts[1], 1); |
| + break; |
| + case SkPath::kQuad_Verb: |
| + fClipStackData.appendf(" %s.quadTo(", pathName); |
| + output_points(&pts[1], 2); |
| + break; |
|
robertphillips
2014/05/16 12:21:24
I know it isn't live yet but do we want to handle
caryclark
2014/05/16 13:49:02
Done.
|
| + case SkPath::kCubic_Verb: |
| + fClipStackData.appendf(" %s.cubicTo(", pathName); |
| + output_points(&pts[1], 3); |
| + break; |
| + case SkPath::kClose_Verb: |
| + fClipStackData.appendf(" %s.close();<br>", 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(" testPathOp(reporter, path, pathB, %s, filename);<br>", |
| + 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; |
| +} |