• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
8 #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"
13 
14 namespace {
15 
16 class Segmentator : public SkNoncopyable {
17 public:
Segmentator(const SkPath & src,SkPath * dst)18     Segmentator(const SkPath& src, SkPath* dst)
19         : fMeasure(src, false)
20         , fDst(dst) {}
21 
add(SkScalar start,SkScalar stop)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 
42 private:
43     SkPathMeasure fMeasure;
44     SkPath*       fDst;
45 
46     SkScalar fCurrentSegmentOffset = 0;
47 
48     using INHERITED = SkNoncopyable;
49 };
50 
51 } // namespace
52 
SkTrimPE(SkScalar startT,SkScalar stopT,SkTrimPathEffect::Mode mode)53 SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode)
54     : fStartT(startT), fStopT(stopT), fMode(mode) {}
55 
onFilterPath(SkPath * dst,const SkPath & src,SkStrokeRec * rec,const SkRect * cullRect) const56 bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec* rec,
57                             const SkRect* cullRect) const {
58     if (fStartT >= fStopT) {
59         SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal);
60         return true;
61     }
62 
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 
82     return true;
83 }
84 
flatten(SkWriteBuffer & buffer) const85 void SkTrimPE::flatten(SkWriteBuffer& buffer) const {
86     buffer.writeScalar(fStartT);
87     buffer.writeScalar(fStopT);
88     buffer.writeUInt(static_cast<uint32_t>(fMode));
89 }
90 
CreateProc(SkReadBuffer & buffer)91 sk_sp<SkFlattenable> SkTrimPE::CreateProc(SkReadBuffer& buffer) {
92     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);
98 }
99 
100 //////////////////////////////////////////////////////////////////////////////////////////////////
101 
Make(SkScalar startT,SkScalar stopT,Mode mode)102 sk_sp<SkPathEffect> SkTrimPathEffect::Make(SkScalar startT, SkScalar stopT, Mode mode) {
103     if (!SkScalarsAreFinite(startT, stopT)) {
104         return nullptr;
105     }
106 
107     if (startT <= 0 && stopT >= 1 && mode == Mode::kNormal) {
108         return nullptr;
109     }
110 
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));
119 }
120