aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/effects
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2018-03-09 16:08:58 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-12 14:07:28 +0000
commit827af667bbe8e057f9ee08e9f9b598add232b491 (patch)
tree5e324fbfcb83944332f11834342dfd188f0c5c09 /src/effects
parent8e03f6930f8e033f3cabfda1a7fba9a6013e3d19 (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.h9
-rw-r--r--src/effects/SkTrimPathEffect.cpp94
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));
}