diff options
author | Florin Malita <fmalita@chromium.org> | 2018-03-09 16:08:58 -0500 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2018-03-12 14:07:28 +0000 |
commit | 827af667bbe8e057f9ee08e9f9b598add232b491 (patch) | |
tree | 5e324fbfcb83944332f11834342dfd188f0c5c09 /src/effects | |
parent | 8e03f6930f8e033f3cabfda1a7fba9a6013e3d19 (diff) |
Extend SkTrimPathEffect semantics
Add support for multiple contours, and an explicit "inverted" mode.
Bug: skia:
Change-Id: Iafadbbe9d4692f2467a4ef8585f7fcd9cee9566a
Reviewed-on: https://skia-review.googlesource.com/113270
Reviewed-by: Mike Reed <reed@google.com>
Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'src/effects')
-rw-r--r-- | src/effects/SkTrimPE.h | 9 | ||||
-rw-r--r-- | src/effects/SkTrimPathEffect.cpp | 94 |
2 files changed, 84 insertions, 19 deletions
diff --git a/src/effects/SkTrimPE.h b/src/effects/SkTrimPE.h index 2cd39c4793..fde3292a67 100644 --- a/src/effects/SkTrimPE.h +++ b/src/effects/SkTrimPE.h @@ -10,9 +10,11 @@ #include "SkPathEffect.h" +#include "SkTrimPathEffect.h" + class SkTrimPE : public SkPathEffect { public: - SkTrimPE(SkScalar startT, SkScalar stopT); + SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode); bool filterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*) const override; @@ -23,8 +25,9 @@ protected: void flatten(SkWriteBuffer&) const override; private: - const SkScalar fStartT; - const SkScalar fStopT; + const SkScalar fStartT, + fStopT; + const SkTrimPathEffect::Mode fMode; typedef SkPathEffect INHERITED; }; diff --git a/src/effects/SkTrimPathEffect.cpp b/src/effects/SkTrimPathEffect.cpp index beaa36e17d..01e4a1c579 100644 --- a/src/effects/SkTrimPathEffect.cpp +++ b/src/effects/SkTrimPathEffect.cpp @@ -11,35 +11,90 @@ #include "SkReadBuffer.h" #include "SkWriteBuffer.h" -SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT) : fStartT(startT), fStopT(stopT) { - SkASSERT(startT >= 0 && startT <= 1); - SkASSERT(stopT >= 0 && stopT <= 1); - SkASSERT(startT != stopT); -} +namespace { + +class Segmentator : public SkNoncopyable { +public: + Segmentator(const SkPath& src, SkPath* dst) + : fMeasure(src, false) + , fDst(dst) {} + + void add(SkScalar start, SkScalar stop) { + SkASSERT(start < stop); + + // TODO: we appear to skip zero-length contours. + do { + const auto nextOffset = fCurrentSegmentOffset + fMeasure.getLength(); + + if (start < nextOffset) { + fMeasure.getSegment(start - fCurrentSegmentOffset, + stop - fCurrentSegmentOffset, + fDst, true); + + if (stop < nextOffset) + break; + } + + fCurrentSegmentOffset = nextOffset; + } while (fMeasure.nextContour()); + } + +private: + SkPathMeasure fMeasure; + SkPath* fDst; + + SkScalar fCurrentSegmentOffset = 0; + + using INHERITED = SkNoncopyable; +}; + +} // namespace + +SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode) + : fStartT(startT), fStopT(stopT), fMode(mode) {} bool SkTrimPE::filterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec, const SkRect* cullRect) const { + if (fStartT >= fStopT) { + SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal); + return true; + } + + // First pass: compute the total len. + SkScalar len = 0; SkPathMeasure meas(src, false); - SkScalar length = meas.getLength(); + do { + len += meas.getLength(); + } while (meas.nextContour()); - if (fStartT < fStopT) { - meas.getSegment(fStartT * length, fStopT * length, dst, true); + const auto arcStart = len * fStartT, + arcStop = len * fStopT; + + // Second pass: actually add segments. + Segmentator segmentator(src, dst); + if (fMode == SkTrimPathEffect::Mode::kNormal) { + if (arcStart < arcStop) segmentator.add(arcStart, arcStop); } else { - meas.getSegment(0, fStopT * length, dst, true); - meas.getSegment(fStartT * length, length, dst, true); + if (0 < arcStart) segmentator.add(0, arcStart); + if (arcStop < len) segmentator.add(arcStop, len); } + return true; } void SkTrimPE::flatten(SkWriteBuffer& buffer) const { buffer.writeScalar(fStartT); buffer.writeScalar(fStopT); + buffer.writeUInt(static_cast<uint32_t>(fMode)); } sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) { - SkScalar start = buffer.readScalar(); - SkScalar stop = buffer.readScalar(); - return SkTrimPathEffect::Make(start, stop); + const auto start = buffer.readScalar(), + stop = buffer.readScalar(); + const auto mode = buffer.readUInt(); + + return SkTrimPathEffect::Make(start, stop, + (mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal); } #ifndef SK_IGNORE_TO_STRING @@ -50,14 +105,21 @@ void SkTrimPE::toString(SkString* str) const { ////////////////////////////////////////////////////////////////////////////////////////////////// -sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT) { +sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) { if (!SkScalarsAreFinite(startT, stopT)) { return nullptr; } + + if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) { + return nullptr; + } + startT = SkTPin(startT, 0.f, 1.f); stopT = SkTPin(stopT, 0.f, 1.f); - if (startT == stopT) { + + if (startT >= stopT && mode == Mode::kInverted) { return nullptr; } - return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT)); + + return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode)); } |