Repository navigation
Expand file tree
/
Copy pathSkTrimPathEffect.cpp
More file actions
149 lines (118 loc) · 4.42 KB
/
Copy pathSkTrimPathEffect.cpp
File metadata and controls
149 lines (118 loc) · 4.42 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
/*
* Copyright 2018 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "include/effects/SkTrimPathEffect.h"
#include "include/core/SkFlattenable.h"
#include "include/core/SkPath.h"
#include "include/core/SkPathEffect.h"
#include "include/core/SkPathMeasure.h"
#include "include/core/SkRefCnt.h"
#include "include/core/SkScalar.h"
#include "include/core/SkTypes.h"
#include "include/private/base/SkTPin.h"
#include "src/core/SkReadBuffer.h"
#include "src/core/SkWriteBuffer.h"
#include "src/effects/SkTrimPE.h"
#include <cstddef>
#include <cstdint>
class SkMatrix;
class SkStrokeRec;
struct SkRect;
namespace {
// Returns the number of contours iterated to satisfy the request.
static size_t add_segments(const SkPath& src, SkScalar start, SkScalar stop, SkPath* dst,
bool requires_moveto = true) {
SkASSERT(start < stop);
SkPathMeasure measure(src, false);
SkScalar current_segment_offset = 0;
size_t contour_count = 1;
do {
const auto next_offset = current_segment_offset + measure.getLength();
if (start < next_offset) {
measure.getSegment(start - current_segment_offset,
stop - current_segment_offset,
dst, requires_moveto);
if (stop <= next_offset)
break;
}
contour_count++;
current_segment_offset = next_offset;
} while (measure.nextContour());
return contour_count;
}
} // namespace
SkTrimPE::SkTrimPE(SkScalar startT, SkScalar stopT, SkTrimPathEffect::Mode mode)
: fStartT(startT), fStopT(stopT), fMode(mode) {}
bool SkTrimPE::onFilterPath(SkPath* dst, const SkPath& src, SkStrokeRec*, const SkRect*,
const SkMatrix&) const {
if (fStartT >= fStopT) {
SkASSERT(fMode == SkTrimPathEffect::Mode::kNormal);
return true;
}
// First pass: compute the total len.
SkScalar len = 0;
SkPathMeasure meas(src, false);
do {
len += meas.getLength();
} while (meas.nextContour());
const auto arcStart = len * fStartT,
arcStop = len * fStopT;
// Second pass: actually add segments.
if (fMode == SkTrimPathEffect::Mode::kNormal) {
// Normal mode -> one span.
if (arcStart < arcStop) {
add_segments(src, arcStart, arcStop, dst);
}
} else {
// Inverted mode -> one logical span which wraps around at the end -> two actual spans.
// In order to preserve closed path continuity:
//
// 1) add the second/tail span first
//
// 2) skip the head span move-to for single-closed-contour paths
bool requires_moveto = true;
if (arcStop < len) {
// since we're adding the "tail" first, this is the total number of contours
const auto contour_count = add_segments(src, arcStop, len, dst);
// if the path consists of a single closed contour, we don't want to disconnect
// the two parts with a moveto.
if (contour_count == 1 && src.isLastContourClosed()) {
requires_moveto = false;
}
}
if (0 < arcStart) {
add_segments(src, 0, arcStart, dst, requires_moveto);
}
}
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) {
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);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
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 && mode == Mode::kInverted) {
return nullptr;
}
return sk_sp<SkPathEffect>(new SkTrimPE(startT, stopT, mode));
}