diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/core/SkPaint.cpp | 64 | ||||
-rw-r--r-- | src/core/SkPathEffect.cpp | 180 | ||||
-rw-r--r-- | src/core/SkScalerContext.cpp | 32 | ||||
-rw-r--r-- | src/core/SkStroke.cpp | 29 | ||||
-rw-r--r-- | src/effects/Sk1DPathEffect.cpp | 8 | ||||
-rw-r--r-- | src/effects/Sk2DPathEffect.cpp | 2 | ||||
-rw-r--r-- | src/effects/SkCornerPathEffect.cpp | 2 | ||||
-rw-r--r-- | src/effects/SkDashPathEffect.cpp | 4 | ||||
-rw-r--r-- | src/effects/SkDiscretePathEffect.cpp | 4 | ||||
-rw-r--r-- | src/ports/SkGlobalInitialization_default.cpp | 1 |
10 files changed, 153 insertions, 173 deletions
diff --git a/src/core/SkPaint.cpp b/src/core/SkPaint.cpp index 1b74fa1e44..8a4071f34d 100644 --- a/src/core/SkPaint.cpp +++ b/src/core/SkPaint.cpp @@ -1987,61 +1987,27 @@ SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) { /////////////////////////////////////////////////////////////////////////////// bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const { - SkPath effectPath, strokePath; - const SkPath* path = &src; + SkStrokeRec rec(*this); - SkScalar width = this->getStrokeWidth(); + const SkPath* srcPtr = &src; + SkPath 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 (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec)) { + srcPtr = &tmpPath; } - 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; - } + 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 (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) + return !rec.isHairlineStyle(); } const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, diff --git a/src/core/SkPathEffect.cpp b/src/core/SkPathEffect.cpp index dcce6d6b56..48d165a52e 100644 --- a/src/core/SkPathEffect.cpp +++ b/src/core/SkPathEffect.cpp @@ -10,6 +10,83 @@ #include "SkPathEffect.h" #include "SkPath.h" #include "SkBuffer.h" +#include "SkPaintDefaults.h" + +// must be < 0, since ==0 means hairline, and >0 means normal stroke +#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; + } +} + +void SkStrokeRec::setFillStyle() { + fWidth = kStrokeRec_FillStyleWidth; +} + +#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; @@ -48,7 +125,7 @@ SkPairPathEffect::SkPairPathEffect(SkFlattenableReadBuffer& buffer) { /////////////////////////////////////////////////////////////////////////////// bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { + SkStrokeRec* rec) { // we may have failed to unflatten these, so we have to check if (!fPE0 || !fPE1) { return false; @@ -57,115 +134,22 @@ bool SkComposePathEffect::filterPath(SkPath* dst, const SkPath& src, SkPath tmp; const SkPath* ptr = &src; - if (fPE1->filterPath(&tmp, src, width)) { + if (fPE1->filterPath(&tmp, src, rec)) { ptr = &tmp; } - return fPE0->filterPath(dst, *ptr, width); + return fPE0->filterPath(dst, *ptr, rec); } /////////////////////////////////////////////////////////////////////////////// bool SkSumPathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { + SkStrokeRec* rec) { // use bit-or so that we always call both, even if the first one succeeds - 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(); + return fPE0->filterPath(dst, src, rec) | fPE1->filterPath(dst, src, rec); } /////////////////////////////////////////////////////////////////////////////// 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 50dbfc52b1..d47c314834 100644 --- a/src/core/SkScalerContext.cpp +++ b/src/core/SkScalerContext.cpp @@ -625,26 +625,30 @@ void SkScalerContext::internalGetPath(const SkGlyph& glyph, SkPath* fillPath, path.transform(inverse, &localPath); // now localPath is only affected by the paint settings, and not the canvas matrix - SkScalar width = fRec.fFrameWidth; - + 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); + } + if (fPathEffect) { SkPath effectPath; - - if (fPathEffect->filterPath(&effectPath, localPath, &width)) { + if (fPathEffect->filterPath(&effectPath, localPath, &rec)) { localPath.swap(effectPath); } } - 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); + if (rec.needToApply()) { + SkPath strokePath; + if (rec.applyToPath(&strokePath, localPath)) { + localPath.swap(strokePath); + } } // now return stuff to the caller diff --git a/src/core/SkStroke.cpp b/src/core/SkStroke.cpp index fd7dccc6c7..0084965757 100644 --- a/src/core/SkStroke.cpp +++ b/src/core/SkStroke.cpp @@ -563,12 +563,39 @@ void SkStroke::setJoin(SkPaint::Join join) { #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; + fSwapWithSrc = true; + } 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); - dst->reset(); + AutoTmpPath tmp(src, &dst); + if (radius <= 0) { return; } diff --git a/src/effects/Sk1DPathEffect.cpp b/src/effects/Sk1DPathEffect.cpp index 09e8d135b6..10a9a8434b 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, SkScalar* width) { +bool Sk1DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) { SkPathMeasure meas(src, false); do { SkScalar length = meas.getLength(); @@ -67,10 +67,10 @@ SkPath1DPathEffect::SkPath1DPathEffect(const SkPath& path, SkScalar advance, } bool SkPath1DPathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { + SkStrokeRec* rec) { if (fAdvance > 0) { - *width = -1; - return this->INHERITED::filterPath(dst, src, width); + rec->setFillStyle(); + return this->INHERITED::filterPath(dst, src, rec); } return false; } diff --git a/src/effects/Sk2DPathEffect.cpp b/src/effects/Sk2DPathEffect.cpp index 8693157f16..3f8c998651 100644 --- a/src/effects/Sk2DPathEffect.cpp +++ b/src/effects/Sk2DPathEffect.cpp @@ -31,7 +31,7 @@ Sk2DPathEffect::Sk2DPathEffect(const SkMatrix& mat) : fMatrix(mat) { fMatrixIsInvertible = mat.invert(&fInverse); } -bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* width) { +bool Sk2DPathEffect::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*) { if (!fMatrixIsInvertible) { return false; } diff --git a/src/effects/SkCornerPathEffect.cpp b/src/effects/SkCornerPathEffect.cpp index 474623175b..749384d579 100644 --- a/src/effects/SkCornerPathEffect.cpp +++ b/src/effects/SkCornerPathEffect.cpp @@ -36,7 +36,7 @@ static bool ComputeStep(const SkPoint& a, const SkPoint& b, SkScalar radius, } bool SkCornerPathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { + SkStrokeRec*) { if (fRadius == 0) { return false; } diff --git a/src/effects/SkDashPathEffect.cpp b/src/effects/SkDashPathEffect.cpp index 0cc97b6b15..13c19afab4 100644 --- a/src/effects/SkDashPathEffect.cpp +++ b/src/effects/SkDashPathEffect.cpp @@ -81,9 +81,9 @@ SkDashPathEffect::~SkDashPathEffect() { } bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { + SkStrokeRec* rec) { // we do nothing if the src wants to be filled, or if our dashlength is 0 - if (*width < 0 || fInitialDashLength < 0) { + if (rec->isFillStyle() || fInitialDashLength < 0) { return false; } diff --git a/src/effects/SkDiscretePathEffect.cpp b/src/effects/SkDiscretePathEffect.cpp index 06b9d19c68..0536e5646d 100644 --- a/src/effects/SkDiscretePathEffect.cpp +++ b/src/effects/SkDiscretePathEffect.cpp @@ -26,8 +26,8 @@ SkDiscretePathEffect::SkDiscretePathEffect(SkScalar segLength, SkScalar deviatio } bool SkDiscretePathEffect::filterPath(SkPath* dst, const SkPath& src, - SkScalar* width) { - bool doFill = *width < 0; + SkStrokeRec* rec) { + bool doFill = rec->isFillStyle(); 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 8995d3b1fd..81f88311a4 100644 --- a/src/ports/SkGlobalInitialization_default.cpp +++ b/src/ports/SkGlobalInitialization_default.cpp @@ -68,7 +68,6 @@ void SkFlattenable::InitializeFlattenables() { 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) |