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)