blob: d0a8806d40a2a09c9c9a4a3212eab48aa9925fcd [file] [log] [blame]
Mike Reed41232232018-03-07 17:02:47 -05001/*
2 * Copyright 2018 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
Mike Kleinc0bd9f92019-04-23 12:05:21 -05008#include "include/core/SkPathMeasure.h"
9#include "include/effects/SkTrimPathEffect.h"
10#include "src/core/SkReadBuffer.h"
11#include "src/core/SkWriteBuffer.h"
12#include "src/effects/SkTrimPE.h"
Mike Reed41232232018-03-07 17:02:47 -050013
Florin Malita827af662018-03-09 16:08:58 -050014namespace {
15
16class Segmentator : public SkNoncopyable {
17public:
18 Segmentator(const SkPath& src, SkPath* dst)
19 : fMeasure(src, false)
20 , fDst(dst) {}
21
22 void add(SkScalar start, SkScalar stop) {
23 SkASSERT(start < stop);
24
25 // TODO: we appear to skip zero-length contours.
26 do {
27 const auto nextOffset = fCurrentSegmentOffset + fMeasure.getLength();
28
29 if (start < nextOffset) {
30 fMeasure.getSegment(start - fCurrentSegmentOffset,
31 stop - fCurrentSegmentOffset,
32 fDst, true);
33
34 if (stop < nextOffset)
35 break;
36 }
37
38 fCurrentSegmentOffset = nextOffset;
39 } while (fMeasure.nextContour());
40 }
41
42private:
43 SkPathMeasure fMeasure;
44 SkPath* fDst;
45
46 SkScalar fCurrentSegmentOffset = 0;
47
48 using INHERITED = SkNoncopyable;
49};
50
51} // namespace
52
53SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode)
54 : fStartT(startT), fStopT(stopT), fMode(mode) {}
Mike Reed41232232018-03-07 17:02:47 -050055
Mike Reed6d10f8b2018-08-16 13:22:16 -040056bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
Mike Reed41232232018-03-07 17:02:47 -050057 const SkRect* cullRect) const {
Florin Malita827af662018-03-09 16:08:58 -050058 if (fStartT >= fStopT) {
59 SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal);
60 return true;
Mike Reed41232232018-03-07 17:02:47 -050061 }
Florin Malita827af662018-03-09 16:08:58 -050062
63 // First pass: compute the total len.
64 SkScalar len = 0;
65 SkPathMeasure meas(src, false);
66 do {
67 len += meas.getLength();
68 } while (meas.nextContour());
69
70 const auto arcStart = len * fStartT,
71 arcStop = len * fStopT;
72
73 // Second pass: actually add segments.
74 Segmentator segmentator(src, dst);
75 if (fMode == SkTrimPathEffect::Mode::kNormal) {
76 if (arcStart < arcStop) segmentator.add(arcStart, arcStop);
77 } else {
78 if (0 < arcStart) segmentator.add(0, arcStart);
79 if (arcStop < len) segmentator.add(arcStop, len);
80 }
81
Mike Reed41232232018-03-07 17:02:47 -050082 return true;
83}
84
85void SkTrimPE::flatten(SkWriteBuffer& buffer) const {
86 buffer.writeScalar(fStartT);
87 buffer.writeScalar(fStopT);
Florin Malita827af662018-03-09 16:08:58 -050088 buffer.writeUInt(static_cast<uint32_t>(fMode));
Mike Reed41232232018-03-07 17:02:47 -050089}
90
91sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) {
Florin Malita827af662018-03-09 16:08:58 -050092 const auto start = buffer.readScalar(),
93 stop = buffer.readScalar();
94 const auto mode = buffer.readUInt();
95
96 return SkTrimPathEffect::Make(start, stop,
97 (mode & 1) ? SkTrimPathEffect::Mode::kInverted : SkTrimPathEffect::Mode::kNormal);
Mike Reed41232232018-03-07 17:02:47 -050098}
99
Mike Reed41232232018-03-07 17:02:47 -0500100//////////////////////////////////////////////////////////////////////////////////////////////////
101
Florin Malita827af662018-03-09 16:08:58 -0500102sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) {
Mike Reed41232232018-03-07 17:02:47 -0500103 if (!SkScalarsAreFinite(startT, stopT)) {
104 return nullptr;
105 }
Florin Malita827af662018-03-09 16:08:58 -0500106
107 if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) {
Mike Reed41232232018-03-07 17:02:47 -0500108 return nullptr;
109 }
Florin Malita827af662018-03-09 16:08:58 -0500110
111 startT = SkTPin(startT, 0.f, 1.f);
112 stopT = SkTPin(stopT, 0.f, 1.f);
113
114 if (startT >= stopT && mode == Mode::kInverted) {
115 return nullptr;
116 }
117
118 return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode));
Mike Reed41232232018-03-07 17:02:47 -0500119}