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" | |
9 #include "Sk4fLinearGradient.h" | 8 #include "Sk4fLinearGradient.h" |
| 9 #include "SkUtils.h" |
| 10 #include "SkXfermode.h" |
10 | 11 |
11 namespace { | 12 namespace { |
12 | 13 |
13 template<typename DstType, bool do_premul> | 14 template<typename DstType, SkColorProfileType, ApplyPremul> |
14 void fill(const Sk4f& c, DstType* dst, int n); | 15 void fill(const Sk4f& c, DstType* dst, int n); |
15 | 16 |
16 template<> | 17 template<> |
17 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { | 18 void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False> |
| 19 (const Sk4f& c, SkPM4f* dst, int n) { |
18 while (n > 0) { | 20 while (n > 0) { |
19 c.store(dst++); | 21 c.store(dst++); |
20 n--; | 22 n--; |
21 } | 23 } |
22 } | 24 } |
23 | 25 |
24 template<> | 26 template<> |
25 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { | 27 void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::True> |
26 fill<SkPM4f, false>(premul_4f(c), dst, n); | 28 (const Sk4f& c, SkPM4f* dst, int n) { |
| 29 fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False>(premul_4f(c), d
st, n); |
27 } | 30 } |
28 | 31 |
29 template<> | 32 template<> |
30 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { | 33 void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False> |
31 sk_memset32(dst, trunc_from_255<false>(c), n); | 34 (const Sk4f& c, SkPMColor* dst, int n) { |
| 35 sk_memset32(dst, trunc_from_4f_255<ApplyPremul::False>(c), n); |
32 } | 36 } |
33 | 37 |
34 template<> | 38 template<> |
35 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { | 39 void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True> |
36 sk_memset32(dst, trunc_from_255<true>(c), n); | 40 (const Sk4f& c, SkPMColor* dst, int n) { |
| 41 sk_memset32(dst, trunc_from_4f_255<ApplyPremul::True>(c), n); |
37 } | 42 } |
38 | 43 |
39 template<typename DstType, bool do_premul> | 44 template<> |
| 45 void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False> |
| 46 (const Sk4f& c, SkPMColor* dst, int n) { |
| 47 // FIXME: this assumes opaque colors. Handle unpremultiplication. |
| 48 sk_memset32(dst, Sk4f_toS32(c), n); |
| 49 } |
| 50 |
| 51 template<> |
| 52 void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True> |
| 53 (const Sk4f& c, SkPMColor* dst, int n) { |
| 54 sk_memset32(dst, Sk4f_toS32(premul_4f(c)), n); |
| 55 } |
| 56 |
| 57 template<> |
| 58 void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False> |
| 59 (const Sk4f& c, uint64_t* dst, int n) { |
| 60 sk_memset64(dst, SkFloatToHalf_01(c), n); |
| 61 } |
| 62 |
| 63 template<> |
| 64 void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True> |
| 65 (const Sk4f& c, uint64_t* dst, int n) { |
| 66 sk_memset64(dst, SkFloatToHalf_01(premul_4f(c)), n); |
| 67 } |
| 68 |
| 69 template<typename DstType, SkColorProfileType profile, ApplyPremul premul> |
40 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { | 70 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { |
41 SkASSERT(n > 0); | 71 SkASSERT(n > 0); |
42 | 72 |
43 const Sk4f dc2 = dc + dc; | 73 const Sk4f dc2 = dc + dc; |
44 const Sk4f dc4 = dc2 + dc2; | 74 const Sk4f dc4 = dc2 + dc2; |
45 | 75 |
46 Sk4f c0 = c ; | 76 Sk4f c0 = c ; |
47 Sk4f c1 = c + dc; | 77 Sk4f c1 = c + dc; |
48 Sk4f c2 = c0 + dc2; | 78 Sk4f c2 = c0 + dc2; |
49 Sk4f c3 = c1 + dc2; | 79 Sk4f c3 = c1 + dc2; |
50 | 80 |
51 while (n >= 4) { | 81 while (n >= 4) { |
52 store4x<DstType, do_premul>(c0, c1, c2, c3, dst); | 82 store4x<DstType, profile, premul>(c0, c1, c2, c3, dst); |
53 dst += 4; | 83 dst += 4; |
54 | 84 |
55 c0 = c0 + dc4; | 85 c0 = c0 + dc4; |
56 c1 = c1 + dc4; | 86 c1 = c1 + dc4; |
57 c2 = c2 + dc4; | 87 c2 = c2 + dc4; |
58 c3 = c3 + dc4; | 88 c3 = c3 + dc4; |
59 n -= 4; | 89 n -= 4; |
60 } | 90 } |
61 if (n & 2) { | 91 if (n & 2) { |
62 store<DstType, do_premul>(c0, dst++); | 92 store<DstType, profile, premul>(c0, dst++); |
63 store<DstType, do_premul>(c1, dst++); | 93 store<DstType, profile, premul>(c1, dst++); |
64 c0 = c0 + dc2; | 94 c0 = c0 + dc2; |
65 } | 95 } |
66 if (n & 1) { | 96 if (n & 1) { |
67 store<DstType, do_premul>(c0, dst); | 97 store<DstType, profile, premul>(c0, dst); |
68 } | 98 } |
69 } | 99 } |
70 | 100 |
71 template<SkShader::TileMode> | 101 template<SkShader::TileMode> |
72 SkScalar pinFx(SkScalar); | 102 SkScalar pinFx(SkScalar); |
73 | 103 |
74 template<> | 104 template<> |
75 SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) { | 105 SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) { |
76 return fx; | 106 return fx; |
77 } | 107 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 void SkLinearGradient:: | 186 void SkLinearGradient:: |
157 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { | 187 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
158 if (!this->isFast()) { | 188 if (!this->isFast()) { |
159 this->INHERITED::shadeSpan(x, y, dst, count); | 189 this->INHERITED::shadeSpan(x, y, dst, count); |
160 return; | 190 return; |
161 } | 191 } |
162 | 192 |
163 // TODO: plumb dithering | 193 // TODO: plumb dithering |
164 SkASSERT(count > 0); | 194 SkASSERT(count > 0); |
165 if (fColorsArePremul) { | 195 if (fColorsArePremul) { |
166 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); | 196 this->shadePremulSpan<SkPMColor, |
| 197 kLinear_SkColorProfileType, |
| 198 ApplyPremul::False>(x, y, dst, count); |
167 } else { | 199 } else { |
168 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); | 200 this->shadePremulSpan<SkPMColor, |
| 201 kLinear_SkColorProfileType, |
| 202 ApplyPremul::True>(x, y, dst, count); |
169 } | 203 } |
170 } | 204 } |
171 | 205 |
172 void SkLinearGradient:: | 206 void SkLinearGradient:: |
173 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { | 207 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
174 if (!this->isFast()) { | 208 if (!this->isFast()) { |
175 this->INHERITED::shadeSpan4f(x, y, dst, count); | 209 this->INHERITED::shadeSpan4f(x, y, dst, count); |
176 return; | 210 return; |
177 } | 211 } |
178 | 212 |
179 // TONOTDO: plumb dithering | 213 // TONOTDO: plumb dithering |
180 SkASSERT(count > 0); | 214 SkASSERT(count > 0); |
181 if (fColorsArePremul) { | 215 if (fColorsArePremul) { |
182 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); | 216 this->shadePremulSpan<SkPM4f, |
| 217 kLinear_SkColorProfileType, |
| 218 ApplyPremul::False>(x, y, dst, count); |
183 } else { | 219 } else { |
184 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); | 220 this->shadePremulSpan<SkPM4f, |
| 221 kLinear_SkColorProfileType, |
| 222 ApplyPremul::True>(x, y, dst, count); |
185 } | 223 } |
186 } | 224 } |
187 | 225 |
188 template<typename DstType, bool do_premul> | 226 template<typename DstType, SkColorProfileType profile, ApplyPremul premul> |
189 void SkLinearGradient:: | 227 void SkLinearGradient:: |
190 LinearGradient4fContext::shadePremulSpan(int x, int y, | 228 LinearGradient4fContext::shadePremulSpan(int x, int y, |
191 DstType dst[], | 229 DstType dst[], |
192 int count) const { | 230 int count) const { |
193 const SkLinearGradient& shader = | 231 const SkLinearGradient& shader = |
194 static_cast<const SkLinearGradient&>(fShader); | 232 static_cast<const SkLinearGradient&>(fShader); |
195 switch (shader.fTileMode) { | 233 switch (shader.fTileMode) { |
196 case kClamp_TileMode: | 234 case kClamp_TileMode: |
197 this->shadeSpanInternal<DstType, | 235 this->shadeSpanInternal<DstType, |
198 do_premul, | 236 profile, |
| 237 premul, |
199 kClamp_TileMode>(x, y, dst, count); | 238 kClamp_TileMode>(x, y, dst, count); |
200 break; | 239 break; |
201 case kRepeat_TileMode: | 240 case kRepeat_TileMode: |
202 this->shadeSpanInternal<DstType, | 241 this->shadeSpanInternal<DstType, |
203 do_premul, | 242 profile, |
| 243 premul, |
204 kRepeat_TileMode>(x, y, dst, count); | 244 kRepeat_TileMode>(x, y, dst, count); |
205 break; | 245 break; |
206 case kMirror_TileMode: | 246 case kMirror_TileMode: |
207 this->shadeSpanInternal<DstType, | 247 this->shadeSpanInternal<DstType, |
208 do_premul, | 248 profile, |
| 249 premul, |
209 kMirror_TileMode>(x, y, dst, count); | 250 kMirror_TileMode>(x, y, dst, count); |
210 break; | 251 break; |
211 } | 252 } |
212 } | 253 } |
213 | 254 |
214 template<typename DstType, bool do_premul, SkShader::TileMode tileMode> | 255 template<typename DstType, SkColorProfileType profile, ApplyPremul premul, |
| 256 SkShader::TileMode tileMode> |
215 void SkLinearGradient:: | 257 void SkLinearGradient:: |
216 LinearGradient4fContext::shadeSpanInternal(int x, int y, | 258 LinearGradient4fContext::shadeSpanInternal(int x, int y, |
217 DstType dst[], | 259 DstType dst[], |
218 int count) const { | 260 int count) const { |
219 SkPoint pt; | 261 SkPoint pt; |
220 fDstToPosProc(fDstToPos, | 262 fDstToPosProc(fDstToPos, |
221 x + SK_ScalarHalf, | 263 x + SK_ScalarHalf, |
222 y + SK_ScalarHalf, | 264 y + SK_ScalarHalf, |
223 &pt); | 265 &pt); |
224 const SkScalar fx = pinFx<tileMode>(pt.x()); | 266 const SkScalar fx = pinFx<tileMode>(pt.x()); |
225 const SkScalar dx = fDstToPos.getScaleX(); | 267 const SkScalar dx = fDstToPos.getScaleX(); |
226 LinearIntervalProcessor<DstType, tileMode> proc(fIntervals.begin(), | 268 LinearIntervalProcessor<DstType, profile, tileMode> proc(fIntervals.begin(), |
227 fIntervals.end() - 1, | 269 fIntervals.end() -
1, |
228 this->findInterval(fx), | 270 this->findInterval(
fx), |
229 fx, | 271 fx, |
230 dx, | 272 dx, |
231 SkScalarNearlyZero(dx * coun
t)); | 273 SkScalarNearlyZero(
dx * count)); |
232 while (count > 0) { | 274 while (count > 0) { |
233 // What we really want here is SkTPin(advance, 1, count) | 275 // What we really want here is SkTPin(advance, 1, count) |
234 // but that's a significant perf hit for >> stops; investigate. | 276 // but that's a significant perf hit for >> stops; investigate. |
235 const int n = SkScalarTruncToInt( | 277 const int n = SkScalarTruncToInt( |
236 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count))); | 278 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count))); |
237 | 279 |
238 // The current interval advance can be +inf (e.g. when reaching | 280 // The current interval advance can be +inf (e.g. when reaching |
239 // the clamp mode end intervals) - when that happens, we expect to | 281 // the clamp mode end intervals) - when that happens, we expect to |
240 // a) consume all remaining count in one swoop | 282 // a) consume all remaining count in one swoop |
241 // b) return a zero color gradient | 283 // b) return a zero color gradient |
242 SkASSERT(SkScalarIsFinite(proc.currentAdvance()) | 284 SkASSERT(SkScalarIsFinite(proc.currentAdvance()) |
243 || (n == count && proc.currentRampIsZero())); | 285 || (n == count && proc.currentRampIsZero())); |
244 | 286 |
245 if (proc.currentRampIsZero()) { | 287 if (proc.currentRampIsZero()) { |
246 fill<DstType, do_premul>(proc.currentColor(), | 288 fill<DstType, profile, premul>(proc.currentColor(), |
247 dst, n); | 289 dst, n); |
248 } else { | 290 } else { |
249 ramp<DstType, do_premul>(proc.currentColor(), | 291 ramp<DstType, profile, premul>(proc.currentColor(), |
250 proc.currentColorGrad(), | 292 proc.currentColorGrad(), |
251 dst, n); | 293 dst, n); |
252 } | 294 } |
253 | 295 |
254 proc.advance(SkIntToScalar(n)); | 296 proc.advance(SkIntToScalar(n)); |
255 count -= n; | 297 count -= n; |
256 dst += n; | 298 dst += n; |
257 } | 299 } |
258 } | 300 } |
259 | 301 |
260 template<typename DstType, SkShader::TileMode tileMode> | 302 template<typename DstType, SkColorProfileType profile, SkShader::TileMode tileMo
de> |
261 class SkLinearGradient:: | 303 class SkLinearGradient:: |
262 LinearGradient4fContext::LinearIntervalProcessor { | 304 LinearGradient4fContext::LinearIntervalProcessor { |
263 public: | 305 public: |
264 LinearIntervalProcessor(const Interval* firstInterval, | 306 LinearIntervalProcessor(const Interval* firstInterval, |
265 const Interval* lastInterval, | 307 const Interval* lastInterval, |
266 const Interval* i, | 308 const Interval* i, |
267 SkScalar fx, | 309 SkScalar fx, |
268 SkScalar dx, | 310 SkScalar dx, |
269 bool is_vertical) | 311 bool is_vertical) |
270 : fDstComponentScale(dst_component_scale<DstType>()) | 312 : fAdvX((i->fP1 - fx) / dx) |
271 , fAdvX((i->fP1 - fx) / dx) | |
272 , fFirstInterval(firstInterval) | 313 , fFirstInterval(firstInterval) |
273 , fLastInterval(lastInterval) | 314 , fLastInterval(lastInterval) |
274 , fInterval(i) | 315 , fInterval(i) |
275 , fDx(dx) | 316 , fDx(dx) |
276 , fIsVertical(is_vertical) | 317 , fIsVertical(is_vertical) |
277 { | 318 { |
278 SkASSERT(firstInterval <= lastInterval); | 319 SkASSERT(firstInterval <= lastInterval); |
279 SkASSERT(in_range(fx, i->fP0, i->fP1)); | 320 SkASSERT(in_range(fx, i->fP0, i->fP1)); |
280 this->compute_interval_props(fx - i->fP0); | 321 this->compute_interval_props(fx - i->fP0); |
281 } | 322 } |
(...skipping 19 matching lines...) Expand all Loading... |
301 | 342 |
302 fCc = fCc + fDcDx * Sk4f(advX); | 343 fCc = fCc + fDcDx * Sk4f(advX); |
303 fAdvX -= advX; | 344 fAdvX -= advX; |
304 } | 345 } |
305 | 346 |
306 private: | 347 private: |
307 void compute_interval_props(SkScalar t) { | 348 void compute_interval_props(SkScalar t) { |
308 fDc = dst_swizzle<DstType>(fInterval->fDc); | 349 fDc = dst_swizzle<DstType>(fInterval->fDc); |
309 fCc = dst_swizzle<DstType>(fInterval->fC0); | 350 fCc = dst_swizzle<DstType>(fInterval->fC0); |
310 fCc = fCc + fDc * Sk4f(t); | 351 fCc = fCc + fDc * Sk4f(t); |
311 fCc = fCc * fDstComponentScale; | 352 fCc = scale_for_dest<DstType, profile>(fCc); |
312 fDcDx = fDc * fDstComponentScale * Sk4f(fDx); | 353 fDcDx = scale_for_dest<DstType, profile>(fDc * Sk4f(fDx)); |
313 fZeroRamp = fIsVertical || fInterval->isZeroRamp(); | 354 fZeroRamp = fIsVertical || fInterval->isZeroRamp(); |
314 } | 355 } |
315 | 356 |
316 const Interval* next_interval(const Interval* i) const { | 357 const Interval* next_interval(const Interval* i) const { |
317 SkASSERT(i >= fFirstInterval); | 358 SkASSERT(i >= fFirstInterval); |
318 SkASSERT(i <= fLastInterval); | 359 SkASSERT(i <= fLastInterval); |
319 i++; | 360 i++; |
320 | 361 |
321 if (tileMode == kClamp_TileMode) { | 362 if (tileMode == kClamp_TileMode) { |
322 SkASSERT(i <= fLastInterval); | 363 SkASSERT(i <= fLastInterval); |
(...skipping 12 matching lines...) Expand all Loading... |
335 fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx; | 376 fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx; |
336 SkASSERT(fAdvX > 0); | 377 SkASSERT(fAdvX > 0); |
337 } while (advX >= fAdvX); | 378 } while (advX >= fAdvX); |
338 | 379 |
339 compute_interval_props(0); | 380 compute_interval_props(0); |
340 | 381 |
341 SkASSERT(advX >= 0); | 382 SkASSERT(advX >= 0); |
342 return advX; | 383 return advX; |
343 } | 384 } |
344 | 385 |
345 const Sk4f fDstComponentScale; // cached dst scale (PMC: 255, PM4f: 1) | |
346 | |
347 // Current interval properties. | 386 // Current interval properties. |
348 Sk4f fDc; // local color gradient (dc/dt) | 387 Sk4f fDc; // local color gradient (dc/dt) |
349 Sk4f fDcDx; // dst color gradient (dc/dx) | 388 Sk4f fDcDx; // dst color gradient (dc/dx) |
350 Sk4f fCc; // current color, interpolated in dst | 389 Sk4f fCc; // current color, interpolated in dst |
351 SkScalar fAdvX; // remaining interval advance in dst | 390 SkScalar fAdvX; // remaining interval advance in dst |
352 bool fZeroRamp; // current interval color grad is 0 | 391 bool fZeroRamp; // current interval color grad is 0 |
353 | 392 |
354 const Interval* fFirstInterval; | 393 const Interval* fFirstInterval; |
355 const Interval* fLastInterval; | 394 const Interval* fLastInterval; |
356 const Interval* fInterval; // current interval | 395 const Interval* fInterval; // current interval |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
395 *ts++ = t4[0]; | 434 *ts++ = t4[0]; |
396 } | 435 } |
397 } else { | 436 } else { |
398 for (int i = 0; i < count; ++i) { | 437 for (int i = 0; i < count; ++i) { |
399 fDstToPosProc(fDstToPos, sx, sy, &pt); | 438 fDstToPosProc(fDstToPos, sx, sy, &pt); |
400 ts[i] = pt.x(); | 439 ts[i] = pt.x(); |
401 sx += SK_Scalar1; | 440 sx += SK_Scalar1; |
402 } | 441 } |
403 } | 442 } |
404 } | 443 } |
| 444 |
| 445 SkShader::Context::BlitProc SkLinearGradient:: |
| 446 LinearGradient4fContext::onChooseBlitProc(const SkImageInfo& info, BlitState* st
ate) { |
| 447 SkXfermode::Mode mode; |
| 448 if (!SkXfermode::AsMode(state->fXfer, &mode)) { |
| 449 return nullptr; |
| 450 } |
| 451 |
| 452 const SkGradientShaderBase& shader = static_cast<const SkGradientShaderBase&
>(fShader); |
| 453 if (mode != SkXfermode::kSrc_Mode && |
| 454 !(mode == SkXfermode::kSrcOver_Mode && shader.colorsAreOpaque())) { |
| 455 return nullptr; |
| 456 } |
| 457 |
| 458 switch (info.colorType()) { |
| 459 case kN32_SkColorType: |
| 460 return D32_BlitProc; |
| 461 case kRGBA_F16_SkColorType: |
| 462 return D64_BlitProc; |
| 463 default: |
| 464 return nullptr; |
| 465 } |
| 466 } |
| 467 |
| 468 void SkLinearGradient:: |
| 469 LinearGradient4fContext::D32_BlitProc(BlitState* state, int x, int y, const SkPi
xmap& dst, |
| 470 int count, const SkAlpha aa[]) { |
| 471 // FIXME: ignoring coverage for now |
| 472 const LinearGradient4fContext* ctx = |
| 473 static_cast<const LinearGradient4fContext*>(state->fCtx); |
| 474 |
| 475 if (dst.info().isLinear()) { |
| 476 if (ctx->fColorsArePremul) { |
| 477 ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPre
mul::False>( |
| 478 x, y, dst.writable_addr32(x, y), count); |
| 479 } else { |
| 480 ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPre
mul::True>( |
| 481 x, y, dst.writable_addr32(x, y), count); |
| 482 } |
| 483 } else { |
| 484 if (ctx->fColorsArePremul) { |
| 485 ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremu
l::False>( |
| 486 x, y, dst.writable_addr32(x, y), count); |
| 487 } else { |
| 488 ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremu
l::True>( |
| 489 x, y, dst.writable_addr32(x, y), count); |
| 490 } |
| 491 } |
| 492 } |
| 493 |
| 494 void SkLinearGradient:: |
| 495 LinearGradient4fContext::D64_BlitProc(BlitState* state, int x, int y, const SkPi
xmap& dst, |
| 496 int count, const SkAlpha aa[]) { |
| 497 // FIXME: ignoring coverage for now |
| 498 const LinearGradient4fContext* ctx = |
| 499 static_cast<const LinearGradient4fContext*>(state->fCtx); |
| 500 |
| 501 if (ctx->fColorsArePremul) { |
| 502 ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::
False>( |
| 503 x, y, dst.writable_addr64(x, y), count); |
| 504 } else { |
| 505 ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::
True>( |
| 506 x, y, dst.writable_addr64(x, y), count); |
| 507 } |
| 508 } |
OLD | NEW |