This adds a checkbox to the debugger to allow seeing the effect pathops has on the...
authorcommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 19 May 2014 13:53:10 +0000 (13:53 +0000)
committercommit-bot@chromium.org <commit-bot@chromium.org@2bbb7eff-a529-9590-31e7-b0007b416f81>
Mon, 19 May 2014 13:53:10 +0000 (13:53 +0000)
Once in place, this CL found a bug in the pathops code where it was not handling empty clip stack elements correctly. The Cl also has the change to SkCanvas to fix this bug.

R=robertphillips@google.com, reed@google.com

Author: caryclark@google.com

Review URL: https://codereview.chromium.org/282283002

git-svn-id: http://skia.googlecode.com/svn/trunk@14774 2bbb7eff-a529-9590-31e7-b0007b416f81

12 files changed:
debugger/QT/SkDebuggerGUI.cpp
debugger/QT/SkDebuggerGUI.h
debugger/QT/SkInspectorWidget.cpp
debugger/QT/SkInspectorWidget.h
debugger/QT/SkSettingsWidget.cpp
debugger/QT/SkSettingsWidget.h
debugger/SkDebugger.cpp
debugger/SkDebugger.h
include/core/SkCanvas.h
src/core/SkCanvas.cpp
src/utils/debugger/SkDebugCanvas.cpp
src/utils/debugger/SkDebugCanvas.h

index 01d165a3d330b6994253e908cab7ac1b6902e974..0f816eec7cebd55d8b726e903f180158b9642437 100644 (file)
@@ -101,6 +101,7 @@ SkDebuggerGUI::SkDebuggerGUI(QWidget *parent) :
     connect(fSettingsWidget.getRasterCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionRasterWidget(bool)));
     connect(fSettingsWidget.getOverdrawVizCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionOverdrawVizWidget(bool)));
     connect(fSettingsWidget.getMegaVizCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionMegaVizWidget(bool)));
+    connect(fSettingsWidget.getPathOpsCheckBox(), SIGNAL(toggled(bool)), this, SLOT(actionPathOpsWidget(bool)));
     connect(&fActionPause, SIGNAL(toggled(bool)), this, SLOT(pauseDrawing(bool)));
     connect(&fActionCreateBreakpoint, SIGNAL(activated()), this, SLOT(toggleBreakpoint()));
     connect(&fActionShowDeletes, SIGNAL(triggered()), this, SLOT(showDeletes()));
@@ -415,6 +416,7 @@ void SkDebuggerGUI::actionProfile() {
     }
 
     setupOverviewText(picture->typeTimes(), picture->totTime(), kNumRepeats);
+    setupClipStackText();
 }
 
 void SkDebuggerGUI::actionCancel() {
@@ -535,6 +537,11 @@ void SkDebuggerGUI::actionMegaVizWidget(bool isToggled) {
     fCanvasWidget.update();
 }
 
+void SkDebuggerGUI::actionPathOpsWidget(bool isToggled) {
+    fDebugger.setPathOps(isToggled);
+    fCanvasWidget.update();
+}
+
 void SkDebuggerGUI::actionTextureFilter() {
     SkPaint::FilterLevel level;
     bool enabled = fSettingsWidget.getFilterOverride(&level);
@@ -662,6 +669,7 @@ void SkDebuggerGUI::registerListClick(QListWidgetItem *item) {
                 fInspectorWidget.setText(info, SkInspectorWidget::kDetail_TabType);
                 fInspectorWidget.setDisabled(false);
             }
+            setupClipStackText();
         }
 
     }
@@ -1043,6 +1051,12 @@ void SkDebuggerGUI::setupOverviewText(const SkTDArray<double>* typeTimes,
     fInspectorWidget.setText(overview.c_str(), SkInspectorWidget::kOverview_TabType);
 }
 
+void SkDebuggerGUI::setupClipStackText() {
+    SkString clipStack;
+    fDebugger.getClipStackText(&clipStack);
+    fInspectorWidget.setText(clipStack.c_str(), SkInspectorWidget::kClipStack_TabType);
+}
+
 void SkDebuggerGUI::setupComboBox(SkTArray<SkString>* command) {
     fFilter.clear();
     fFilter.addItem("--Filter By Available Commands--");
index 41c5e242e20e563db3d23070e8e8ebd6833d9b8a..a137ee7cfbb47df0f9091d6362d0876152ca25d7 100644 (file)
@@ -151,6 +151,11 @@ private slots:
      */
     void actionMegaVizWidget(bool isToggled);
 
+    /**
+        Toggles using path ops to simplify the clip stack
+     */
+    void actionPathOpsWidget(bool );
+
     /**
         Applies the new texture filter override
      */
@@ -343,6 +348,11 @@ private:
      */
     void setupOverviewText(const SkTDArray<double>* typeTimes, double totTime, int numRuns);
 
+    /**
+        Fills in the clip stack pane with text
+     */
+    void setupClipStackText();
+
     /**
         Render the supplied picture several times tracking the time consumed
         by each command.
index 6cf121241af07ad46bbd4564afb023d0390f2a3b..6bcac1db357bf592f4212c3508d02de5479552f9 100644 (file)
@@ -23,6 +23,7 @@ SkInspectorWidget::SkInspectorWidget() : QWidget()
     QString tabNames[kTotalTabCount];
     tabNames[kOverview_TabType] = "Overview";
     tabNames[kDetail_TabType] = "Details";
+    tabNames[kClipStack_TabType] = "Clip Stack";
 
     for (int i = 0; i < kTotalTabCount; i++) {
         fTabTexts[i].setReadOnly(true);
index 1b962356f7021ebd8a5821645268f412a18485d1..96a6da38e17bb3b8ec764642f211f3c0f4fa1da8 100644 (file)
@@ -31,6 +31,7 @@ public:
     enum TabType {
         kOverview_TabType,
         kDetail_TabType,
+        kClipStack_TabType,
         kTotalTabCount,
     };
 
index 29026cf07c17052e1188b5d6b4e11a7f7254d927..dc9dc6e45cea9c11fe2047353a4f89e0e5617a13 100644 (file)
@@ -56,6 +56,10 @@ SkSettingsWidget::SkSettingsWidget() : QWidget()
     fRasterLabel.setMinimumWidth(178);
     fRasterLabel.setMaximumWidth(178);
 
+    fPathOpsLabel.setText("PathOps: ");
+    fPathOpsLabel.setMinimumWidth(178);
+    fPathOpsLabel.setMaximumWidth(178);
+
     fRasterCheckBox.setChecked(true);
 
     fOverdrawVizLabel.setText("     Overdraw Viz: ");
@@ -112,6 +116,8 @@ SkSettingsWidget::SkSettingsWidget() : QWidget()
 
     fRasterLayout.addWidget(&fRasterLabel);
     fRasterLayout.addWidget(&fRasterCheckBox);
+    fRasterLayout.addWidget(&fPathOpsLabel);
+    fRasterLayout.addWidget(&fPathOpsCheckBox);
 
     fVizLayout.addWidget(&fOverdrawVizLabel);
     fVizLayout.addWidget(&fOverdrawVizCheckBox);
index 660da77cfd0033bdd6c53371d4e3d0970cacded9..f35df9401007235e390c809b700855700ced8e0f 100644 (file)
@@ -74,6 +74,10 @@ public:
         return &fMegaVizCheckBox;
     }
 
+    QCheckBox* getPathOpsCheckBox() {
+        return &fPathOpsCheckBox;
+    }
+
 private slots:
     void updateCommand(int newCommand);
     void updateHit(int newHit);
@@ -122,6 +126,8 @@ private:
     QCheckBox fOverdrawVizCheckBox;
     QLabel fMegaVizLabel;
     QCheckBox fMegaVizCheckBox;
+    QLabel fPathOpsLabel;
+    QCheckBox fPathOpsCheckBox;
 
 #if SK_SUPPORT_GPU
     QHBoxLayout fGLLayout;
index f4730d61b5306116c2eb933f9a96d2cce04c3357..394c0ad7c82e70c25949947b985ca4ab8bdb3ead 100644 (file)
@@ -49,6 +49,8 @@ SkPicture* SkDebugger::copyPicture() {
     fDebugCanvas->setMegaVizMode(false);
     bool overDraw = fDebugCanvas->getOverdrawViz();
     fDebugCanvas->setOverdrawViz(false);
+    bool pathOps = fDebugCanvas->getAllowSimplifyClip();
+    fDebugCanvas->setAllowSimplifyClip(false);
     int saveCount = fDebugCanvas->getOutstandingSaveCount();
     fDebugCanvas->setOutstandingSaveCount(0);
 
@@ -62,6 +64,7 @@ SkPicture* SkDebugger::copyPicture() {
     fDebugCanvas->setMegaVizMode(vizMode);
     fDebugCanvas->setOverdrawViz(overDraw);
     fDebugCanvas->setOutstandingSaveCount(saveCount);
+    fDebugCanvas->setAllowSimplifyClip(pathOps);
 
     return recorder.endRecording();
 }
@@ -148,3 +151,8 @@ void SkDebugger::getOverviewText(const SkTDArray<double>* typeTimes,
     overview->appendS32(pictureHeight());
     overview->append("px");
 }
+
+void SkDebugger::getClipStackText(SkString* clipStack) {
+    clipStack->set(fDebugCanvas->clipStackData());
+}
+
index 94300d83657170542150f55d829970fc8c1f6fd5..ffb2953272d8e674e6f1041c7a8a63012dbacf52 100644 (file)
@@ -111,6 +111,12 @@ public:
         }
     }
 
+    void setPathOps(bool pathOps) {
+        if (NULL != fDebugCanvas) {
+            fDebugCanvas->setAllowSimplifyClip(pathOps);
+        }
+    }
+
     void setMegaViz(bool megaViz) {
         if (NULL != fDebugCanvas) {
             fDebugCanvas->setMegaVizMode(megaViz);
@@ -126,6 +132,8 @@ public:
     void getOverviewText(const SkTDArray<double>* typeTimes, double totTime,
                          SkString* overview, int numRuns);
 
+    void getClipStackText(SkString* clipStack);
+
 private:
     SkDebugCanvas* fDebugCanvas;
     SkPicture* fPicture;
index fa19176eeb99a90faff4c8965bdf2a52cee32674..81dcfe19b0fcfeca4c22815de439b7d6acc0c31d 100644 (file)
@@ -1319,6 +1319,7 @@ private:
     friend class SkDrawIter;        // needs setupDrawForLayerDevice()
     friend class AutoDrawLooper;
     friend class SkLua;             // needs top layer size and offset
+    friend class SkDebugCanvas;     // needs experimental fAllowSimplifyClip
     friend class SkDeferredDevice;  // needs getTopDevice()
 
     SkBaseDevice* createLayerDevice(const SkImageInfo&);
index 57cf850fa0d6dfbccbcc1560158b7b3049ebbba6..65002125a36d6f0e75a9a0ac0987b3938ff50fac 100644 (file)
@@ -1544,11 +1544,10 @@ void SkCanvas::onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edg
         const SkClipStack::Element* element;
         while ((element = iter.next())) {
             SkClipStack::Element::Type type = element->getType();
-            if (type == SkClipStack::Element::kEmpty_Type) {
-                continue;
-            }
             SkPath operand;
-            element->asPath(&operand);
+            if (type != SkClipStack::Element::kEmpty_Type) {
+                element->asPath(&operand);
+            }
             SkRegion::Op elementOp = element->getOp();
             if (elementOp == SkRegion::kReplace_Op) {
                 devPath = operand;
index 14fbf8888a6d149f7d6e9b304ad403daefbbe708..89a388e11003d0958131367356d91444a3f9a506 100644 (file)
@@ -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) {
+        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();
@@ -588,3 +612,128 @@ 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;
+}
index d4fded7c1a8dae3bc5beb9b5c83cd11c08b448e6..be1b8608bee2ef79beab555f3c32d100ebbf207d 100644 (file)
@@ -12,6 +12,7 @@
 
 #include "SkCanvas.h"
 #include "SkDrawCommand.h"
+#include "SkPathOps.h"
 #include "SkPicture.h"
 #include "SkTArray.h"
 #include "SkString.h"
@@ -37,6 +38,8 @@ public:
     void setOutstandingSaveCount(int saveCount) { fOutstandingSaveCount = saveCount; }
     int getOutstandingSaveCount() const { return fOutstandingSaveCount; }
 
+    bool getAllowSimplifyClip() const { return fAllowSimplifyClip; }
+
     void setPicture(SkPicture* picture) { fPicture = picture; }
 
     /**
@@ -151,6 +154,8 @@ public:
         fUserMatrix = matrix;
     }
 
+    SkString clipStackData() const { return fClipStackData; }
+
 ////////////////////////////////////////////////////////////////////////////////
 // Inherited from SkCanvas
 ////////////////////////////////////////////////////////////////////////////////
@@ -266,6 +271,10 @@ private:
     SkMatrix fMatrix;
     SkIRect fClip;
 
+    SkString fClipStackData;
+    bool fCalledAddStackData;
+    SkPath fSaveDevPath;
+
     bool fOverdrawViz;
     SkDrawFilter* fOverdrawFilter;
 
@@ -311,6 +320,16 @@ private:
         return 0;
     }
 
+    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);
+   
     typedef SkCanvas INHERITED;
 };