OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2016 Google Inc. | 2 * Copyright 2016 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
| 8 #include "Sk4fGradientPriv.h" |
8 #include "Sk4fLinearGradient.h" | 9 #include "Sk4fLinearGradient.h" |
9 | 10 |
10 namespace { | 11 namespace { |
11 | 12 |
12 Sk4f premul_4f(const Sk4f& c) { | |
13 const float alpha = c[SkPM4f::A]; | |
14 // FIXME: portable swizzle? | |
15 return c * Sk4f(alpha, alpha, alpha, 1); | |
16 } | |
17 | |
18 template <bool do_premul> | |
19 SkPMColor trunc_from_255(const Sk4f& c) { | |
20 SkPMColor pmc; | |
21 SkNx_cast<uint8_t>(c).store(&pmc); | |
22 if (do_premul) { | |
23 pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc), | |
24 SkGetPackedG32(pmc), SkGetPackedB32(pmc)); | |
25 } | |
26 return pmc; | |
27 } | |
28 | |
29 template<typename DstType, bool do_premul> | 13 template<typename DstType, bool do_premul> |
30 void fill(const Sk4f& c, DstType* dst, int n); | 14 void fill(const Sk4f& c, DstType* dst, int n); |
31 | 15 |
32 template<> | 16 template<> |
33 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { | 17 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { |
34 while (n > 0) { | 18 while (n > 0) { |
35 c.store(dst++); | 19 c.store(dst++); |
36 n--; | 20 n--; |
37 } | 21 } |
38 } | 22 } |
39 | 23 |
40 template<> | 24 template<> |
41 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { | 25 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { |
42 fill<SkPM4f, false>(premul_4f(c), dst, n); | 26 fill<SkPM4f, false>(premul_4f(c), dst, n); |
43 } | 27 } |
44 | 28 |
45 template<> | 29 template<> |
46 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { | 30 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { |
47 sk_memset32(dst, trunc_from_255<false>(c), n); | 31 sk_memset32(dst, trunc_from_255<false>(c), n); |
48 } | 32 } |
49 | 33 |
50 template<> | 34 template<> |
51 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { | 35 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { |
52 sk_memset32(dst, trunc_from_255<true>(c), n); | 36 sk_memset32(dst, trunc_from_255<true>(c), n); |
53 } | 37 } |
54 | 38 |
55 template<typename DstType, bool do_premul> | 39 template<typename DstType, bool do_premul> |
56 void store(const Sk4f& color, DstType* dst); | |
57 | |
58 template<> | |
59 void store<SkPM4f, false>(const Sk4f& c, SkPM4f* dst) { | |
60 c.store(dst); | |
61 } | |
62 | |
63 template<> | |
64 void store<SkPM4f, true>(const Sk4f& c, SkPM4f* dst) { | |
65 store<SkPM4f, false>(premul_4f(c), dst); | |
66 } | |
67 | |
68 template<> | |
69 void store<SkPMColor, false>(const Sk4f& c, SkPMColor* dst) { | |
70 *dst = trunc_from_255<false>(c); | |
71 } | |
72 | |
73 template<> | |
74 void store<SkPMColor, true>(const Sk4f& c, SkPMColor* dst) { | |
75 *dst = trunc_from_255<true>(c); | |
76 } | |
77 | |
78 template<typename DstType, bool do_premul> | |
79 void store4x(const Sk4f& c0, | |
80 const Sk4f& c1, | |
81 const Sk4f& c2, | |
82 const Sk4f& c3, | |
83 DstType* dst) { | |
84 store<DstType, do_premul>(c0, dst++); | |
85 store<DstType, do_premul>(c1, dst++); | |
86 store<DstType, do_premul>(c2, dst++); | |
87 store<DstType, do_premul>(c3, dst++); | |
88 } | |
89 | |
90 template<> | |
91 void store4x<SkPMColor, false>(const Sk4f& c0, | |
92 const Sk4f& c1, | |
93 const Sk4f& c2, | |
94 const Sk4f& c3, | |
95 SkPMColor* dst) { | |
96 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); | |
97 } | |
98 | |
99 template<typename DstType, bool do_premul> | |
100 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { | 40 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
101 SkASSERT(n > 0); | 41 SkASSERT(n > 0); |
102 | 42 |
103 const Sk4f dc2 = dc + dc; | 43 const Sk4f dc2 = dc + dc; |
104 const Sk4f dc4 = dc2 + dc2; | 44 const Sk4f dc4 = dc2 + dc2; |
105 | 45 |
106 Sk4f c0 = c ; | 46 Sk4f c0 = c ; |
107 Sk4f c1 = c + dc; | 47 Sk4f c1 = c + dc; |
108 Sk4f c2 = c0 + dc2; | 48 Sk4f c2 = c0 + dc2; |
109 Sk4f c3 = c1 + dc2; | 49 Sk4f c3 = c1 + dc2; |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
141 const SkScalar f = SkScalarFraction(fx); | 81 const SkScalar f = SkScalarFraction(fx); |
142 return f < 0 ? f + 1 : f; | 82 return f < 0 ? f + 1 : f; |
143 } | 83 } |
144 | 84 |
145 template<> | 85 template<> |
146 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { | 86 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { |
147 const SkScalar f = SkScalarMod(fx, 2.0f); | 87 const SkScalar f = SkScalarMod(fx, 2.0f); |
148 return f < 0 ? f + 2 : f; | 88 return f < 0 ? f + 2 : f; |
149 } | 89 } |
150 | 90 |
151 template<typename DstType> | |
152 float dst_component_scale(); | |
153 | |
154 template<> | |
155 float dst_component_scale<SkPM4f>() { | |
156 return 1; | |
157 } | |
158 | |
159 template<> | |
160 float dst_component_scale<SkPMColor>() { | |
161 return 255; | |
162 } | |
163 | |
164 template<typename DstType> | |
165 Sk4f dst_swizzle(const SkPM4f&); | |
166 | |
167 template<> | |
168 Sk4f dst_swizzle<SkPM4f>(const SkPM4f& c) { | |
169 return c.to4f(); | |
170 } | |
171 | |
172 template<> | |
173 Sk4f dst_swizzle<SkPMColor>(const SkPM4f& c) { | |
174 return c.to4f_pmorder(); | |
175 } | |
176 | |
177 SkPMColor pack_color(SkColor c, bool premul) { | |
178 return premul | |
179 ? SkPreMultiplyColor(c) | |
180 : SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), Sk
ColorGetB(c)); | |
181 } | |
182 | |
183 // true when x is in [k1,k2) | 91 // true when x is in [k1,k2) |
184 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { | 92 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { |
185 SkASSERT(k1 != k2); | 93 SkASSERT(k1 != k2); |
186 return (k1 < k2) | 94 return (k1 < k2) |
187 ? (x >= k1 && x < k2) | 95 ? (x >= k1 && x < k2) |
188 : (x >= k2 && x < k1); | 96 : (x >= k2 && x < k1); |
189 } | 97 } |
190 | 98 |
191 class IntervalBuilder { | |
192 public: | |
193 IntervalBuilder(const SkColor* colors, const SkScalar* pos, int count, bool
reverse) | |
194 : fColors(colors) | |
195 , fPos(pos) | |
196 , fCount(count) | |
197 , fFirstPos(reverse ? SK_Scalar1 : 0) | |
198 , fBegin(reverse ? count - 1 : 0) | |
199 , fAdvance(reverse ? -1 : 1) { | |
200 SkASSERT(colors); | |
201 SkASSERT(count > 1); | |
202 } | |
203 | |
204 template<typename F> | |
205 void build(F func) const { | |
206 if (!fPos) { | |
207 this->buildImplicitPos(func); | |
208 return; | |
209 } | |
210 | |
211 const int end = fBegin + fAdvance * (fCount - 1); | |
212 const SkScalar lastPos = 1 - fFirstPos; | |
213 int prev = fBegin; | |
214 SkScalar prevPos = fFirstPos; | |
215 | |
216 do { | |
217 const int curr = prev + fAdvance; | |
218 SkASSERT(curr >= 0 && curr < fCount); | |
219 | |
220 // TODO: this sanitization should be done in SkGradientShaderBase | |
221 const SkScalar currPos = (fAdvance > 0) | |
222 ? SkTPin(fPos[curr], prevPos, lastPos) | |
223 : SkTPin(fPos[curr], lastPos, prevPos); | |
224 | |
225 if (currPos != prevPos) { | |
226 SkASSERT((currPos - prevPos > 0) == (fAdvance > 0)); | |
227 func(fColors[prev], fColors[curr], prevPos, currPos); | |
228 } | |
229 | |
230 prev = curr; | |
231 prevPos = currPos; | |
232 } while (prev != end); | |
233 } | |
234 | |
235 private: | |
236 template<typename F> | |
237 void buildImplicitPos(F func) const { | |
238 // When clients don't provide explicit color stop positions (fPos == nul
lptr), | |
239 // the color stops are distributed evenly across the unit interval | |
240 // (implicit positioning). | |
241 const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1); | |
242 const int end = fBegin + fAdvance * (fCount - 2); | |
243 int prev = fBegin; | |
244 SkScalar prevPos = fFirstPos; | |
245 | |
246 while (prev != end) { | |
247 const int curr = prev + fAdvance; | |
248 SkASSERT(curr >= 0 && curr < fCount); | |
249 | |
250 const SkScalar currPos = prevPos + dt; | |
251 func(fColors[prev], fColors[curr], prevPos, currPos); | |
252 prev = curr; | |
253 prevPos = currPos; | |
254 } | |
255 | |
256 // emit the last interval with a pinned end position, to avoid precision
issues | |
257 func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos); | |
258 } | |
259 | |
260 const SkColor* fColors; | |
261 const SkScalar* fPos; | |
262 const int fCount; | |
263 const SkScalar fFirstPos; | |
264 const int fBegin; | |
265 const int fAdvance; | |
266 }; | |
267 | |
268 } // anonymous namespace | 99 } // anonymous namespace |
269 | 100 |
270 SkLinearGradient:: | 101 SkLinearGradient:: |
271 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, | 102 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, |
272 const ContextRec& rec) | 103 const ContextRec& rec) |
273 : INHERITED(shader, rec) { | 104 : INHERITED(shader, rec) { |
274 // The main job here is to build a specialized interval list: a different | |
275 // representation of the color stops data, optimized for efficient scan line | |
276 // access during shading. | |
277 // | |
278 // [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1}) | |
279 // | |
280 // The list is sorted in increasing dst order, i.e. X(Pk) < X(Pk+1). This | |
281 // allows us to always traverse left->right when iterating over a scan line. | |
282 // It also means that the interval order matches the color stops when dx >=
0, | |
283 // and is the inverse (pos, colors, order are flipped) when dx < 0. | |
284 // | |
285 // Note: the current representation duplicates pos data; we could refactor t
o | |
286 // avoid this if interval storage size becomes a concern. | |
287 // | |
288 // Aside from reordering, we also perform two more pre-processing steps at | |
289 // this stage: | |
290 // | |
291 // 1) scale the color components depending on paint alpha and the requeste
d | |
292 // interpolation space (note: the interval color storage is SkPM4f, but | |
293 // that doesn't necessarily mean the colors are premultiplied; that | |
294 // property is tracked in fColorsArePremul) | |
295 // | |
296 // 2) inject synthetic intervals to support tiling. | |
297 // | |
298 // * for kRepeat, no extra intervals are needed - the iterator just | |
299 // wraps around at the end: | |
300 // | |
301 // ->[P0,P1)->..[Pn-1,Pn)-> | |
302 // | |
303 // * for kClamp, we add two "infinite" intervals before/after: | |
304 // | |
305 // [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf) | |
306 // | |
307 // (the iterator should never run off the end in this mode) | |
308 // | |
309 // * for kMirror, we extend the range to [0..2] and add a flipped | |
310 // interval series - then the iterator operates just as in the | |
311 // kRepeat case: | |
312 // | |
313 // ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)-> | |
314 // | |
315 // TODO: investigate collapsing intervals << 1px. | |
316 | 105 |
317 SkASSERT(shader.fColorCount > 1); | 106 // Our fast path expects interval points to be monotonically increasing in x
. |
318 SkASSERT(shader.fOrigColors); | 107 const bool reverseIntervals = this->isFast() && fDstToPos.getScaleX() < 0; |
319 | 108 this->buildIntervals(shader, rec, reverseIntervals); |
320 const float paintAlpha = rec.fPaint->getAlpha() * (1.0f / 255); | |
321 const Sk4f componentScale = fColorsArePremul | |
322 ? Sk4f(paintAlpha) | |
323 : Sk4f(1.0f, 1.0f, 1.0f, paintAlpha); | |
324 const bool dx_is_pos = fDstToPos.getScaleX() >= 0; | |
325 const int first_index = dx_is_pos ? 0 : shader.fColorCount - 1; | |
326 const int last_index = shader.fColorCount - 1 - first_index; | |
327 const SkScalar first_pos = dx_is_pos ? 0 : SK_Scalar1; | |
328 const SkScalar last_pos = 1 - first_pos; | |
329 | |
330 if (shader.fTileMode == SkShader::kClamp_TileMode) { | |
331 // synthetic edge interval: -/+inf .. P0 | |
332 const SkPMColor clamp_color = pack_color(shader.fOrigColors[first_index]
, | |
333 fColorsArePremul); | |
334 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMin : SK_ScalarMax; | |
335 fIntervals.emplace_back(clamp_color, clamp_pos, | |
336 clamp_color, first_pos, | |
337 componentScale); | |
338 } else if (shader.fTileMode == SkShader::kMirror_TileMode && !dx_is_pos) { | |
339 // synthetic mirror intervals injected before main intervals: (2 .. 1] | |
340 addMirrorIntervals(shader, componentScale, dx_is_pos); | |
341 } | |
342 | |
343 const IntervalBuilder builder(shader.fOrigColors, | |
344 shader.fOrigPos, | |
345 shader.fColorCount, | |
346 !dx_is_pos); | |
347 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0,
SkScalar p1) { | |
348 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == p0); | |
349 | |
350 fIntervals.emplace_back(pack_color(c0, fColorsArePremul), | |
351 p0, | |
352 pack_color(c1, fColorsArePremul), | |
353 p1, | |
354 componentScale); | |
355 }); | |
356 | |
357 if (shader.fTileMode == SkShader::kClamp_TileMode) { | |
358 // synthetic edge interval: Pn .. +/-inf | |
359 const SkPMColor clamp_color = | |
360 pack_color(shader.fOrigColors[last_index], fColorsArePremul); | |
361 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMax : SK_ScalarMin; | |
362 fIntervals.emplace_back(clamp_color, last_pos, | |
363 clamp_color, clamp_pos, | |
364 componentScale); | |
365 } else if (shader.fTileMode == SkShader::kMirror_TileMode && dx_is_pos) { | |
366 // synthetic mirror intervals injected after main intervals: [1 .. 2) | |
367 addMirrorIntervals(shader, componentScale, dx_is_pos); | |
368 } | |
369 | 109 |
370 SkASSERT(fIntervals.count() > 0); | 110 SkASSERT(fIntervals.count() > 0); |
371 fCachedInterval = fIntervals.begin(); | 111 fCachedInterval = fIntervals.begin(); |
372 } | 112 } |
373 | 113 |
374 void SkLinearGradient:: | |
375 LinearGradient4fContext::addMirrorIntervals(const SkLinearGradient& shader, | |
376 const Sk4f& componentScale, bool dx_
is_pos) { | |
377 // Iterates in reverse order (vs main interval builder) and adds intervals r
eflected in 2. | |
378 const IntervalBuilder builder(shader.fOrigColors, | |
379 shader.fOrigPos, | |
380 shader.fColorCount, | |
381 dx_is_pos); | |
382 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0,
SkScalar p1) { | |
383 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == 2 - p0); | |
384 | |
385 fIntervals.emplace_back(pack_color(c0, fColorsArePremul), | |
386 2 - p0, | |
387 pack_color(c1, fColorsArePremul), | |
388 2 - p1, | |
389 componentScale); | |
390 }); | |
391 } | |
392 | |
393 const SkGradientShaderBase::GradientShaderBase4fContext::Interval* | 114 const SkGradientShaderBase::GradientShaderBase4fContext::Interval* |
394 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { | 115 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { |
395 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); | 116 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); |
396 | 117 |
397 if (1) { | 118 if (1) { |
398 // Linear search, using the last scanline interval as a starting point. | 119 // Linear search, using the last scanline interval as a starting point. |
399 SkASSERT(fCachedInterval >= fIntervals.begin()); | 120 SkASSERT(fCachedInterval >= fIntervals.begin()); |
400 SkASSERT(fCachedInterval < fIntervals.end()); | 121 SkASSERT(fCachedInterval < fIntervals.end()); |
401 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; | 122 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; |
402 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { | 123 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { |
(...skipping 24 matching lines...) Expand all Loading... |
427 } | 148 } |
428 } | 149 } |
429 | 150 |
430 SkASSERT(in_range(fx, i0->fP0, i0->fP1)); | 151 SkASSERT(in_range(fx, i0->fP0, i0->fP1)); |
431 return i0; | 152 return i0; |
432 } | 153 } |
433 } | 154 } |
434 | 155 |
435 void SkLinearGradient:: | 156 void SkLinearGradient:: |
436 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { | 157 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
| 158 if (!this->isFast()) { |
| 159 this->INHERITED::shadeSpan(x, y, dst, count); |
| 160 return; |
| 161 } |
| 162 |
437 // TODO: plumb dithering | 163 // TODO: plumb dithering |
438 SkASSERT(count > 0); | 164 SkASSERT(count > 0); |
439 if (fColorsArePremul) { | 165 if (fColorsArePremul) { |
440 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); | 166 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); |
441 } else { | 167 } else { |
442 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); | 168 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); |
443 } | 169 } |
444 } | 170 } |
445 | 171 |
446 void SkLinearGradient:: | 172 void SkLinearGradient:: |
447 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { | 173 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
| 174 if (!this->isFast()) { |
| 175 this->INHERITED::shadeSpan4f(x, y, dst, count); |
| 176 return; |
| 177 } |
| 178 |
448 // TONOTDO: plumb dithering | 179 // TONOTDO: plumb dithering |
449 SkASSERT(count > 0); | 180 SkASSERT(count > 0); |
450 if (fColorsArePremul) { | 181 if (fColorsArePremul) { |
451 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); | 182 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); |
452 } else { | 183 } else { |
453 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); | 184 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); |
454 } | 185 } |
455 } | 186 } |
456 | 187 |
457 template<typename DstType, bool do_premul> | 188 template<typename DstType, bool do_premul> |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
538 bool is_vertical) | 269 bool is_vertical) |
539 : fDstComponentScale(dst_component_scale<DstType>()) | 270 : fDstComponentScale(dst_component_scale<DstType>()) |
540 , fAdvX((i->fP1 - fx) / dx) | 271 , fAdvX((i->fP1 - fx) / dx) |
541 , fFirstInterval(firstInterval) | 272 , fFirstInterval(firstInterval) |
542 , fLastInterval(lastInterval) | 273 , fLastInterval(lastInterval) |
543 , fInterval(i) | 274 , fInterval(i) |
544 , fDx(dx) | 275 , fDx(dx) |
545 , fIsVertical(is_vertical) | 276 , fIsVertical(is_vertical) |
546 { | 277 { |
547 SkASSERT(firstInterval <= lastInterval); | 278 SkASSERT(firstInterval <= lastInterval); |
548 SkASSERT(i->contains(fx)); | 279 SkASSERT(in_range(fx, i->fP0, i->fP1)); |
549 this->compute_interval_props(fx - i->fP0); | 280 this->compute_interval_props(fx - i->fP0); |
550 } | 281 } |
551 | 282 |
552 SkScalar currentAdvance() const { | 283 SkScalar currentAdvance() const { |
553 SkASSERT(fAdvX >= 0); | 284 SkASSERT(fAdvX >= 0); |
554 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); | 285 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); |
555 return fAdvX; | 286 return fAdvX; |
556 } | 287 } |
557 | 288 |
558 bool currentRampIsZero() const { return fZeroRamp; } | 289 bool currentRampIsZero() const { return fZeroRamp; } |
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
619 Sk4f fCc; // current color, interpolated in dst | 350 Sk4f fCc; // current color, interpolated in dst |
620 SkScalar fAdvX; // remaining interval advance in dst | 351 SkScalar fAdvX; // remaining interval advance in dst |
621 bool fZeroRamp; // current interval color grad is 0 | 352 bool fZeroRamp; // current interval color grad is 0 |
622 | 353 |
623 const Interval* fFirstInterval; | 354 const Interval* fFirstInterval; |
624 const Interval* fLastInterval; | 355 const Interval* fLastInterval; |
625 const Interval* fInterval; // current interval | 356 const Interval* fInterval; // current interval |
626 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx | 357 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx |
627 const bool fIsVertical; | 358 const bool fIsVertical; |
628 }; | 359 }; |
| 360 |
| 361 void SkLinearGradient:: |
| 362 LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const { |
| 363 SkASSERT(count > 0); |
| 364 SkASSERT(fDstToPosClass != kLinear_MatrixClass); |
| 365 |
| 366 SkScalar sx = x + SK_ScalarHalf; |
| 367 const SkScalar sy = y + SK_ScalarHalf; |
| 368 SkPoint pt; |
| 369 |
| 370 if (fDstToPosClass != kPerspective_MatrixClass) { |
| 371 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanli
ne |
| 372 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x(); |
| 373 fDstToPosProc(fDstToPos, sx, sy, &pt); |
| 374 |
| 375 const Sk4f dtdx4 = Sk4f(4 * dtdx); |
| 376 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx, |
| 377 pt.x() + 1 * dtdx, |
| 378 pt.x() + 2 * dtdx, |
| 379 pt.x() + 3 * dtdx); |
| 380 |
| 381 while (count >= 4) { |
| 382 t4.store(ts); |
| 383 t4 = t4 + dtdx4; |
| 384 ts += 4; |
| 385 count -= 4; |
| 386 } |
| 387 |
| 388 if (count & 2) { |
| 389 *ts++ = t4[0]; |
| 390 *ts++ = t4[1]; |
| 391 t4 = SkNx_shuffle<2, 0, 1, 3>(t4); |
| 392 } |
| 393 |
| 394 if (count & 1) { |
| 395 *ts++ = t4[0]; |
| 396 } |
| 397 } else { |
| 398 for (int i = 0; i < count; ++i) { |
| 399 fDstToPosProc(fDstToPos, sx, sy, &pt); |
| 400 ts[i] = pt.x(); |
| 401 sx += SK_Scalar1; |
| 402 } |
| 403 } |
| 404 } |
OLD | NEW |