revert 4046 -- GM:pathfill failed on one bot, maybe uninitialized memory somewhere?



git-svn-id: http://skia.googlecode.com/svn/trunk@4047 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp
index 8a4071f..1b74fa1 100644
--- a/src/core/SkPaint.cpp
+++ b/src/core/SkPaint.cpp
@@ -1987,27 +1987,61 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const {
-    SkStrokeRec rec(*this);
+    SkPath          effectPath, strokePath;
+    const SkPath*   path = &src;
 
-    const SkPath* srcPtr = &src;
-    SkPath tmpPath;
+    SkScalar width = this->getStrokeWidth();
 
-    if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec)) {
-        srcPtr = &tmpPath;
+    switch (this->getStyle()) {
+        case SkPaint::kFill_Style:
+            width = -1; // mark it as no-stroke
+            break;
+        case SkPaint::kStrokeAndFill_Style:
+            if (width == 0) {
+                width = -1; // mark it as no-stroke
+            }
+            break;
+        case SkPaint::kStroke_Style:
+            break;
+        default:
+            SkDEBUGFAIL("unknown paint style");
     }
 
-    if (!rec.applyToPath(dst, *srcPtr)) {
-        if (srcPtr == &tmpPath) {
-            // If path's were copy-on-write, this trick would not be needed.
-            // As it is, we want to save making a deep-copy from tmpPath -> dst
-            // since we know we're just going to delete tmpPath when we return,
-            // so the swap saves that copy.
-            dst->swap(tmpPath);
-        } else {
-            *dst = *srcPtr;
+    if (this->getPathEffect()) {
+        // lie to the pathEffect if our style is strokeandfill, so that it treats us as just fill
+        if (this->getStyle() == SkPaint::kStrokeAndFill_Style) {
+            width = -1; // mark it as no-stroke
+        }
+
+        if (this->getPathEffect()->filterPath(&effectPath, src, &width)) {
+            path = &effectPath;
+        }
+
+        // restore the width if we earlier had to lie, and if we're still set to no-stroke
+        // note: if we're now stroke (width >= 0), then the pathEffect asked for that change
+        // and we want to respect that (i.e. don't overwrite their setting for width)
+        if (this->getStyle() == SkPaint::kStrokeAndFill_Style && width < 0) {
+            width = this->getStrokeWidth();
+            if (width == 0) {
+                width = -1;
+            }
         }
     }
-    return !rec.isHairlineStyle();
+
+    if (width > 0 && !path->isEmpty()) {
+        SkStroke stroker(*this, width);
+        stroker.strokePath(*path, &strokePath);
+        path = &strokePath;
+    }
+
+    if (path == &src) {
+        *dst = src;
+    } else {
+        SkASSERT(path == &effectPath || path == &strokePath);
+        dst->swap(*(SkPath*)path);
+    }
+
+    return width != 0;  // return true if we're filled, or false if we're hairline (width == 0)
 }
 
 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc,
diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp
index 9be6943..dcce6d6 100644
--- a/src/core/SkPathEffect.cpp
+++ b/src/core/SkPathEffect.cpp
@@ -10,78 +10,6 @@
 #include "SkPathEffect.h"
 #include "SkPath.h"
 #include "SkBuffer.h"
-#include "SkPaintDefaults.h"
-
-#define kStrokeRec_FillStyleWidth     (-SK_Scalar1)
-
-SkStrokeRec::SkStrokeRec(InitStyle s) {
-    fWidth          = (kFill_InitStyle == s) ? kStrokeRec_FillStyleWidth : 0;
-    fMiterLimit     = SkPaintDefaults_MiterLimit;
-    fCap            = SkPaint::kDefault_Cap;
-    fJoin           = SkPaint::kDefault_Join;
-    fStrokeAndFill  = false;
-}
-
-SkStrokeRec::SkStrokeRec(const SkStrokeRec& src) {
-    memcpy(this, &src, sizeof(src));
-}
-
-SkStrokeRec::SkStrokeRec(const SkPaint& paint) {
-    switch (paint.getStyle()) {
-        case SkPaint::kFill_Style:
-            fWidth = kStrokeRec_FillStyleWidth;
-            fStrokeAndFill = false;
-            break;
-        case SkPaint::kStroke_Style:
-            fWidth = paint.getStrokeWidth();
-            fStrokeAndFill = false;
-            break;
-        case SkPaint::kStrokeAndFill_Style:
-            fWidth = paint.getStrokeWidth();
-            fStrokeAndFill = true;
-            break;
-        default:
-            SkASSERT(!"unknown paint style");
-            // fall back on just fill
-            fWidth = kStrokeRec_FillStyleWidth;
-            fStrokeAndFill = false;
-            break;
-    }
-
-    // copy these from the paint, regardless of our "style"
-    fMiterLimit = paint.getStrokeMiter();
-    fCap        = paint.getStrokeCap();
-    fJoin       = paint.getStrokeJoin();
-}
-
-SkStrokeRec::Style SkStrokeRec::getStyle() const {
-    if (fWidth < 0) {
-        return kFill_Style;
-    } else if (0 == fWidth) {
-        return kHairline_Style;
-    } else {
-        return fStrokeAndFill ? kStrokeAndFill_Style : kStroke_Style;
-    }
-}
-
-#include "SkStroke.h"
-
-bool SkStrokeRec::applyToPath(SkPath* dst, const SkPath& src) const {
-    if (fWidth <= 0) {  // hairline or fill
-        return false;
-    }
-
-    SkStroke stroker;
-    stroker.setCap(fCap);
-    stroker.setJoin(fJoin);
-    stroker.setMiterLimit(fMiterLimit);
-    stroker.setWidth(fWidth);
-    stroker.setDoFill(fStrokeAndFill);
-    stroker.strokePath(src, dst);
-    return true;
-}
-
-///////////////////////////////////////////////////////////////////////////////
 
 void SkPathEffect::computeFastBounds(SkRect* dst, const SkRect& src) {
     *dst = src;
@@ -120,7 +48,7 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                     SkStrokeRec* rec) {
+                                     SkScalar* width) {
     // we may have failed to unflatten these, so we have to check
     if (!fPE0 || !fPE1) {
         return false;
@@ -129,22 +57,115 @@
     SkPath          tmp;
     const SkPath*   ptr = &src;
 
-    if (fPE1->filterPath(&tmp, src, rec)) {
+    if (fPE1->filterPath(&tmp, src, width)) {
         ptr = &tmp;
     }
-    return fPE0->filterPath(dst, *ptr, rec);
+    return fPE0->filterPath(dst, *ptr, width);
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                 SkStrokeRec* rec) {
+                                 SkScalar* width) {
     // use bit-or so that we always call both, even if the first one succeeds
-    return fPE0->filterPath(dst, src, rec) | fPE1->filterPath(dst, src, rec);
+    return  fPE0->filterPath(dst, src, width) | fPE1->filterPath(dst, src, width);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include "SkStroke.h"
+
+/** \class SkStrokePathEffect
+ 
+ SkStrokePathEffect simulates stroking inside a patheffect, allowing the
+ caller to have explicit control of when to stroke a path. Typically this is
+ used if the caller wants to stroke before another patheffect is applied
+ (using SkComposePathEffect or SkSumPathEffect).
+ */
+class SkStrokePathEffect : public SkPathEffect {
+public:
+    SkStrokePathEffect(const SkPaint&);
+    SkStrokePathEffect(SkScalar width, SkPaint::Style, SkPaint::Join,
+                       SkPaint::Cap, SkScalar miterLimit = -1);
+    
+    // overrides
+    virtual bool filterPath(SkPath* dst, const SkPath& src, SkScalar* width);
+    
+    SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkStrokePathEffect)
+    
+protected:
+    SkStrokePathEffect(SkFlattenableReadBuffer&);
+    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+    
+private:
+    SkScalar    fWidth, fMiter;
+    uint8_t     fStyle, fJoin, fCap;
+    
+    typedef SkPathEffect INHERITED;
+    
+    // illegal
+    SkStrokePathEffect(const SkStrokePathEffect&);
+    SkStrokePathEffect& operator=(const SkStrokePathEffect&);
+};
+
+SkStrokePathEffect::SkStrokePathEffect(const SkPaint& paint)
+    : fWidth(paint.getStrokeWidth()), fMiter(paint.getStrokeMiter()),
+      fStyle(SkToU8(paint.getStyle())), fJoin(SkToU8(paint.getStrokeJoin())),
+      fCap(SkToU8(paint.getStrokeCap())) {
+}
+
+SkStrokePathEffect::SkStrokePathEffect(SkScalar width, SkPaint::Style style,
+                           SkPaint::Join join, SkPaint::Cap cap, SkScalar miter)
+        : fWidth(width), fMiter(miter), fStyle(SkToU8(style)),
+          fJoin(SkToU8(join)), fCap(SkToU8(cap)) {
+    if (miter < 0) {  // signal they want the default
+        fMiter = SkIntToScalar(4);
+    }
+}
+
+bool SkStrokePathEffect::filterPath(SkPath* dst, const SkPath& src,
+                                    SkScalar* width) {
+    if (fWidth < 0 || fStyle == SkPaint::kFill_Style) {
+        return false;
+    }
+
+    if (fStyle == SkPaint::kStroke_Style && fWidth == 0) {  // hairline
+        *width = 0;
+        return true;
+    }
+
+    SkStroke    stroke;
+
+    stroke.setWidth(fWidth);
+    stroke.setMiterLimit(fMiter);
+    stroke.setJoin((SkPaint::Join)fJoin);
+    stroke.setCap((SkPaint::Cap)fCap);
+    stroke.setDoFill(fStyle == SkPaint::kStrokeAndFill_Style);
+
+    stroke.strokePath(src, dst);
+    return true;
+}
+
+void SkStrokePathEffect::flatten(SkFlattenableWriteBuffer& buffer) const {
+    this->INHERITED::flatten(buffer);
+    buffer.writeScalar(fWidth);
+    buffer.writeScalar(fMiter);
+    buffer.write8(fStyle);
+    buffer.write8(fJoin);
+    buffer.write8(fCap);
+}
+
+SkStrokePathEffect::SkStrokePathEffect(SkFlattenableReadBuffer& buffer) {
+    fWidth = buffer.readScalar();
+    fMiter = buffer.readScalar();
+    fStyle = buffer.readU8();
+    fJoin = buffer.readU8();
+    fCap = buffer.readU8();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
 
 SK_DEFINE_FLATTENABLE_REGISTRAR(SkComposePathEffect)
+//SK_DEFINE_FLATTENABLE_REGISTRAR(SkStrokePathEffect)
 SK_DEFINE_FLATTENABLE_REGISTRAR(SkSumPathEffect)
 
diff --git a/src/core/SkScalerContext.cpp b/src/core/SkScalerContext.cpp
index d47c314..50dbfc5 100644
--- a/src/core/SkScalerContext.cpp
+++ b/src/core/SkScalerContext.cpp
@@ -625,30 +625,26 @@
         path.transform(inverse, &localPath);
         // now localPath is only affected by the paint settings, and not the canvas matrix
 
-        SkStrokeRec rec(SkStrokeRec::kFill_InitStyle);
-        
-        if (fRec.fFrameWidth > 0) {
-            rec.setStrokeStyle(fRec.fFrameWidth,
-                               SkToBool(fRec.fFlags & kFrameAndFill_Flag));
-            // glyphs are always closed contours, so cap type is ignored,
-            // so we just pass something.
-            rec.setStrokeParams(SkPaint::kButt_Cap,
-                                (SkPaint::Join)fRec.fStrokeJoin,
-                                fRec.fMiterLimit);
-        }
-        
+        SkScalar width = fRec.fFrameWidth;
+
         if (fPathEffect) {
             SkPath effectPath;
-            if (fPathEffect->filterPath(&effectPath, localPath, &rec)) {
+
+            if (fPathEffect->filterPath(&effectPath, localPath, &width)) {
                 localPath.swap(effectPath);
             }
         }
 
-        if (rec.needToApply()) {
-            SkPath strokePath;
-            if (rec.applyToPath(&strokePath, localPath)) {
-                localPath.swap(strokePath);
-            }
+        if (width > 0) {
+            SkStroke    stroker;
+            SkPath      outline;
+
+            stroker.setWidth(width);
+            stroker.setMiterLimit(fRec.fMiterLimit);
+            stroker.setJoin((SkPaint::Join)fRec.fStrokeJoin);
+            stroker.setDoFill(SkToBool(fRec.fFlags & kFrameAndFill_Flag));
+            stroker.strokePath(localPath, &outline);
+            localPath.swap(outline);
         }
 
         // now return stuff to the caller
diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp
index 0d3885f..fd7dccc 100644
--- a/src/core/SkStroke.cpp
+++ b/src/core/SkStroke.cpp
@@ -563,38 +563,12 @@
     #define APPLY_PROC(proc, pts, count)
 #endif
 
-// If src==dst, then we use a tmp path to record the stroke, and then swap
-// its contents with src when we're done.
-class AutoTmpPath {
-public:
-    AutoTmpPath(const SkPath& src, SkPath** dst) : fSrc(src) {
-        if (&src == *dst) {
-            *dst = &fTmpDst;
-        } else {
-            (*dst)->reset();
-            fSwapWithSrc = false;
-        }
-    }
-    
-    ~AutoTmpPath() {
-        if (fSwapWithSrc) {
-            fTmpDst.swap(*const_cast<SkPath*>(&fSrc));
-        }
-    }
-    
-private:
-    SkPath          fTmpDst;
-    const SkPath&   fSrc;
-    bool            fSwapWithSrc;
-};
-
 void SkStroke::strokePath(const SkPath& src, SkPath* dst) const {
     SkASSERT(&src != NULL && dst != NULL);
 
     SkScalar radius = SkScalarHalf(fWidth);
 
-    AutoTmpPath tmp(src, &dst);
-
+    dst->reset();
     if (radius <= 0) {
         return;
     }
diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp
index 10a9a84..09e8d13 100644
--- a/src/effects/Sk1DPathEffect.cpp
+++ b/src/effects/Sk1DPathEffect.cpp
@@ -10,7 +10,7 @@
 #include "Sk1DPathEffect.h"
 #include "SkPathMeasure.h"
 
-bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) {
+bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
     SkPathMeasure   meas(src, false);
     do {
         SkScalar    length = meas.getLength();
@@ -67,10 +67,10 @@
 }
 
 bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                    SkStrokeRec* rec) {
+                                    SkScalar* width) {
     if (fAdvance > 0) {
-        rec->setFillStyle();
-        return this->INHERITED::filterPath(dst, src, rec);
+        *width = -1;
+        return this->INHERITED::filterPath(dst, src, width);
     }
     return false;
 }
diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp
index 3f8c998..8693157 100644
--- a/src/effects/Sk2DPathEffect.cpp
+++ b/src/effects/Sk2DPathEffect.cpp
@@ -31,7 +31,7 @@
     fMatrixIsInvertible = mat.invert(&fInverse);
 }
 
-bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) {
+bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) {
     if (!fMatrixIsInvertible) {
         return false;
     }
diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp
index 749384d..4746231 100644
--- a/src/effects/SkCornerPathEffect.cpp
+++ b/src/effects/SkCornerPathEffect.cpp
@@ -36,7 +36,7 @@
 }
 
 bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                    SkStrokeRec*) {
+                                    SkScalar* width) {
     if (fRadius == 0) {
         return false;
     }
diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp
index 13c19af..0cc97b6 100644
--- a/src/effects/SkDashPathEffect.cpp
+++ b/src/effects/SkDashPathEffect.cpp
@@ -81,9 +81,9 @@
 }
 
 bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                  SkStrokeRec* rec) {
+                                  SkScalar* width) {
     // we do nothing if the src wants to be filled, or if our dashlength is 0
-    if (rec->isFillStyle() || fInitialDashLength < 0) {
+    if (*width < 0 || fInitialDashLength < 0) {
         return false;
     }
 
diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp
index 0536e56..06b9d19 100644
--- a/src/effects/SkDiscretePathEffect.cpp
+++ b/src/effects/SkDiscretePathEffect.cpp
@@ -26,8 +26,8 @@
 }
 
 bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src,
-                                      SkStrokeRec* rec) {
-    bool doFill = rec->isFillStyle();
+                                      SkScalar* width) {
+    bool doFill = *width < 0;
 
     SkPathMeasure   meas(src, doFill);
     uint32_t        seed = SkScalarRound(meas.getLength());
diff --git a/src/ports/SkGlobalInitialization_default.cpp b/src/ports/SkGlobalInitialization_default.cpp
index 81f8831..8995d3b 100644
--- a/src/ports/SkGlobalInitialization_default.cpp
+++ b/src/ports/SkGlobalInitialization_default.cpp
@@ -68,6 +68,7 @@
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPath2DPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkPixelXorXfermode)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRectShape)
+//    SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkStrokePathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSumPathEffect)
     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkShape)