OLD | NEW |
| (Empty) |
1 /* libs/graphics/effects/SkDashPathEffect.cpp | |
2 ** | |
3 ** Copyright 2006, The Android Open Source Project | |
4 ** | |
5 ** Licensed under the Apache License, Version 2.0 (the "License"); | |
6 ** you may not use this file except in compliance with the License. | |
7 ** You may obtain a copy of the License at | |
8 ** | |
9 ** http://www.apache.org/licenses/LICENSE-2.0 | |
10 ** | |
11 ** Unless required by applicable law or agreed to in writing, software | |
12 ** distributed under the License is distributed on an "AS IS" BASIS, | |
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
14 ** See the License for the specific language governing permissions and | |
15 ** limitations under the License. | |
16 */ | |
17 | |
18 #include "SkDashPathEffect.h" | |
19 #include "SkBuffer.h" | |
20 #include "SkPathMeasure.h" | |
21 | |
22 static inline int is_even(int x) | |
23 { | |
24 return (~x) << 31; | |
25 } | |
26 | |
27 static SkScalar FindFirstInterval(const SkScalar intervals[], SkScalar phase, in
t32_t* index) | |
28 { | |
29 int i; | |
30 | |
31 for (i = 0; phase > intervals[i]; i++) | |
32 phase -= intervals[i]; | |
33 *index = i; | |
34 return intervals[i] - phase; | |
35 } | |
36 | |
37 SkDashPathEffect::SkDashPathEffect(const SkScalar intervals[], int count, SkScal
ar phase, bool scaleToFit) | |
38 : fScaleToFit(scaleToFit) | |
39 { | |
40 SkASSERT(intervals); | |
41 SkASSERT(count > 1 && SkAlign2(count) == count); | |
42 | |
43 fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * count); | |
44 fCount = count; | |
45 | |
46 SkScalar len = 0; | |
47 for (int i = 0; i < count; i++) | |
48 { | |
49 SkASSERT(intervals[i] >= 0); | |
50 fIntervals[i] = intervals[i]; | |
51 len += intervals[i]; | |
52 } | |
53 fIntervalLength = len; | |
54 | |
55 if (len > 0) // we don't handle 0 length dash arrays | |
56 { | |
57 if (phase < 0) | |
58 { | |
59 phase = -phase; | |
60 if (phase > len) | |
61 phase = SkScalarMod(phase, len); | |
62 phase = len - phase; | |
63 } | |
64 else if (phase >= len) | |
65 phase = SkScalarMod(phase, len); | |
66 | |
67 SkASSERT(phase >= 0 && phase < len); | |
68 fInitialDashLength = FindFirstInterval(intervals, phase, &fInitialDashIn
dex); | |
69 | |
70 SkASSERT(fInitialDashLength >= 0); | |
71 SkASSERT(fInitialDashIndex >= 0 && fInitialDashIndex < fCount); | |
72 } | |
73 else | |
74 fInitialDashLength = -1; // signal bad dash intervals | |
75 } | |
76 | |
77 SkDashPathEffect::~SkDashPathEffect() | |
78 { | |
79 sk_free(fIntervals); | |
80 } | |
81 | |
82 bool SkDashPathEffect::filterPath(SkPath* dst, const SkPath& src, SkScalar* widt
h) | |
83 { | |
84 // we do nothing if the src wants to be filled, or if our dashlength is 0 | |
85 if (*width < 0 || fInitialDashLength < 0) | |
86 return false; | |
87 | |
88 SkPathMeasure meas(src, false); | |
89 const SkScalar* intervals = fIntervals; | |
90 | |
91 do { | |
92 bool skipFirstSegment = meas.isClosed(); | |
93 bool addedSegment = false; | |
94 SkScalar length = meas.getLength(); | |
95 int index = fInitialDashIndex; | |
96 SkScalar scale = SK_Scalar1; | |
97 | |
98 if (fScaleToFit) | |
99 { | |
100 if (fIntervalLength >= length) | |
101 scale = SkScalarDiv(length, fIntervalLength); | |
102 else | |
103 { | |
104 SkScalar div = SkScalarDiv(length, fIntervalLength); | |
105 int n = SkScalarFloor(div); | |
106 scale = SkScalarDiv(length, n * fIntervalLength); | |
107 } | |
108 } | |
109 | |
110 SkScalar distance = 0; | |
111 SkScalar dlen = SkScalarMul(fInitialDashLength, scale); | |
112 | |
113 while (distance < length) | |
114 { | |
115 SkASSERT(dlen >= 0); | |
116 addedSegment = false; | |
117 if (is_even(index) && dlen > 0 && !skipFirstSegment) | |
118 { | |
119 addedSegment = true; | |
120 meas.getSegment(distance, distance + dlen, dst, true); | |
121 } | |
122 distance += dlen; | |
123 | |
124 // clear this so we only respect it the first time around | |
125 skipFirstSegment = false; | |
126 | |
127 // wrap around our intervals array if necessary | |
128 index += 1; | |
129 SkASSERT(index <= fCount); | |
130 if (index == fCount) | |
131 index = 0; | |
132 | |
133 // fetch our next dlen | |
134 dlen = SkScalarMul(intervals[index], scale); | |
135 } | |
136 | |
137 // extend if we ended on a segment and we need to join up with the (skip
ped) initial segment | |
138 if (meas.isClosed() && is_even(fInitialDashIndex) && fInitialDashLength
> 0) | |
139 meas.getSegment(0, SkScalarMul(fInitialDashLength, scale), dst, !add
edSegment); | |
140 } while (meas.nextContour()); | |
141 return true; | |
142 } | |
143 | |
144 SkFlattenable::Factory SkDashPathEffect::getFactory() | |
145 { | |
146 return fInitialDashLength < 0 ? NULL : CreateProc; | |
147 } | |
148 | |
149 void SkDashPathEffect::flatten(SkFlattenableWriteBuffer& buffer) | |
150 { | |
151 SkASSERT(fInitialDashLength >= 0); | |
152 | |
153 buffer.write32(fCount); | |
154 buffer.write32(fInitialDashIndex); | |
155 buffer.writeScalar(fInitialDashLength); | |
156 buffer.writeScalar(fIntervalLength); | |
157 buffer.write32(fScaleToFit); | |
158 buffer.writeMul4(fIntervals, fCount * sizeof(fIntervals[0])); | |
159 } | |
160 | |
161 SkFlattenable* SkDashPathEffect::CreateProc(SkFlattenableReadBuffer& buffer) | |
162 { | |
163 return SkNEW_ARGS(SkDashPathEffect, (buffer)); | |
164 } | |
165 | |
166 SkDashPathEffect::SkDashPathEffect(SkFlattenableReadBuffer& buffer) | |
167 { | |
168 fCount = buffer.readS32(); | |
169 fInitialDashIndex = buffer.readS32(); | |
170 fInitialDashLength = buffer.readScalar(); | |
171 fIntervalLength = buffer.readScalar(); | |
172 fScaleToFit = (buffer.readS32() != 0); | |
173 | |
174 fIntervals = (SkScalar*)sk_malloc_throw(sizeof(SkScalar) * fCount); | |
175 buffer.read(fIntervals, fCount * sizeof(fIntervals[0])); | |
176 } | |
177 | |
178 | |
OLD | NEW |