blob: 45083f725cf2db764a30413c8025048481d6698a [file] [log] [blame]
fmalitabc590c02016-02-22 09:12:33 -08001/*
2 * Copyright 2016 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 "Sk4fLinearGradient.h"
fmalita83aa9202016-03-23 12:28:14 -07009#include "Sk4x4f.h"
fmalitaa928b282016-03-18 10:28:23 -070010#include "SkXfermode.h"
fmalitabc590c02016-02-22 09:12:33 -080011
Ben Wagner8a1036c2016-11-09 15:00:49 -050012#include <cmath>
13
fmalitabc590c02016-02-22 09:12:33 -080014namespace {
15
fmalitadc6c9bf2016-03-21 13:16:51 -070016template<DstType dstType, ApplyPremul premul>
17void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Type dst[], int n) {
fmalitabc590c02016-02-22 09:12:33 -080018 SkASSERT(n > 0);
19
20 const Sk4f dc2 = dc + dc;
21 const Sk4f dc4 = dc2 + dc2;
22
23 Sk4f c0 = c ;
24 Sk4f c1 = c + dc;
25 Sk4f c2 = c0 + dc2;
26 Sk4f c3 = c1 + dc2;
27
28 while (n >= 4) {
fmalitadc6c9bf2016-03-21 13:16:51 -070029 DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst);
fmalitabc590c02016-02-22 09:12:33 -080030 dst += 4;
31
32 c0 = c0 + dc4;
33 c1 = c1 + dc4;
34 c2 = c2 + dc4;
35 c3 = c3 + dc4;
36 n -= 4;
37 }
38 if (n & 2) {
fmalitadc6c9bf2016-03-21 13:16:51 -070039 DstTraits<dstType, premul>::store(c0, dst++);
40 DstTraits<dstType, premul>::store(c1, dst++);
fmalitabc590c02016-02-22 09:12:33 -080041 c0 = c0 + dc2;
42 }
43 if (n & 1) {
fmalitadc6c9bf2016-03-21 13:16:51 -070044 DstTraits<dstType, premul>::store(c0, dst);
fmalitabc590c02016-02-22 09:12:33 -080045 }
46}
47
fmalita83aa9202016-03-23 12:28:14 -070048// Planar version of ramp (S32 no-premul only).
49template<>
50void ramp<DstType::S32, ApplyPremul::False>(const Sk4f& c, const Sk4f& dc, SkPMColor dst[], int n) {
51 SkASSERT(n > 0);
52
53 const Sk4f dc4 = dc * 4;
54 const Sk4x4f dc4x = { Sk4f(dc4[0]), Sk4f(dc4[1]), Sk4f(dc4[2]), Sk4f(dc4[3]) };
55 Sk4x4f c4x = Sk4x4f::Transpose(c, c + dc, c + dc * 2, c + dc * 3);
56
57 while (n >= 4) {
mtklein0c902472016-07-20 18:10:07 -070058 ( sk_linear_to_srgb(c4x.r) << 0
59 | sk_linear_to_srgb(c4x.g) << 8
60 | sk_linear_to_srgb(c4x.b) << 16
61 | Sk4f_round(255.0f*c4x.a) << 24).store(dst);
fmalita83aa9202016-03-23 12:28:14 -070062
63 c4x.r += dc4x.r;
64 c4x.g += dc4x.g;
65 c4x.b += dc4x.b;
66 c4x.a += dc4x.a;
67
68 dst += 4;
69 n -= 4;
70 }
71
72 if (n & 2) {
73 DstTraits<DstType::S32, ApplyPremul::False>
74 ::store(Sk4f(c4x.r[0], c4x.g[0], c4x.b[0], c4x.a[0]), dst++);
75 DstTraits<DstType::S32, ApplyPremul::False>
76 ::store(Sk4f(c4x.r[1], c4x.g[1], c4x.b[1], c4x.a[1]), dst++);
77 }
78
79 if (n & 1) {
80 DstTraits<DstType::S32, ApplyPremul::False>
81 ::store(Sk4f(c4x.r[n & 2], c4x.g[n & 2], c4x.b[n & 2], c4x.a[n & 2]), dst);
82 }
83}
84
fmalitabc590c02016-02-22 09:12:33 -080085template<SkShader::TileMode>
86SkScalar pinFx(SkScalar);
87
88template<>
89SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
90 return fx;
91}
92
93template<>
94SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
Florin Malita0fdde542016-11-14 15:54:04 -050095 SkScalar f = SkScalarFraction(fx);
96 if (f < 0) {
97 f = SkTMin(f + 1, nextafterf(1, 0));
98 }
99 SkASSERT(f >= 0);
100 SkASSERT(f < 1.0f);
101 return f;
fmalitabc590c02016-02-22 09:12:33 -0800102}
103
104template<>
105SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
Florin Malita0fdde542016-11-14 15:54:04 -0500106 SkScalar f = SkScalarMod(fx, 2.0f);
107 if (f < 0) {
108 f = SkTMin(f + 2, nextafterf(2, 0));
109 }
110 SkASSERT(f >= 0);
111 SkASSERT(f < 2.0f);
112 return f;
fmalitabc590c02016-02-22 09:12:33 -0800113}
114
fmalita6d7e4e82016-09-20 06:55:16 -0700115// true when x is in [k1,k2), or [k2, k1) when the interval is reversed.
116// TODO(fmalita): hoist the reversed interval check out of this helper.
fmalita7520fc42016-03-04 11:01:24 -0800117bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
118 SkASSERT(k1 != k2);
119 return (k1 < k2)
fmalitaafac5812016-11-01 13:41:34 -0700120 ? (x >= k1 && x < k2)
121 : (x >= k2 && x < k1);
fmalita7520fc42016-03-04 11:01:24 -0800122}
123
fmalitabc590c02016-02-22 09:12:33 -0800124} // anonymous namespace
125
126SkLinearGradient::
127LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
128 const ContextRec& rec)
fmalita7520fc42016-03-04 11:01:24 -0800129 : INHERITED(shader, rec) {
fmalita7520fc42016-03-04 11:01:24 -0800130
fmalita7e6fcf82016-03-10 11:18:43 -0800131 // Our fast path expects interval points to be monotonically increasing in x.
Ben Wagner8a1036c2016-11-09 15:00:49 -0500132 const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX());
fmalita7e6fcf82016-03-10 11:18:43 -0800133 this->buildIntervals(shader, rec, reverseIntervals);
fmalita7520fc42016-03-04 11:01:24 -0800134
135 SkASSERT(fIntervals.count() > 0);
136 fCachedInterval = fIntervals.begin();
137}
138
fmalita7520fc42016-03-04 11:01:24 -0800139const SkGradientShaderBase::GradientShaderBase4fContext::Interval*
140SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
141 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1));
142
143 if (1) {
144 // Linear search, using the last scanline interval as a starting point.
145 SkASSERT(fCachedInterval >= fIntervals.begin());
146 SkASSERT(fCachedInterval < fIntervals.end());
147 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
148 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) {
149 fCachedInterval += search_dir;
150 if (fCachedInterval >= fIntervals.end()) {
151 fCachedInterval = fIntervals.begin();
152 } else if (fCachedInterval < fIntervals.begin()) {
153 fCachedInterval = fIntervals.end() - 1;
154 }
155 }
156 return fCachedInterval;
157 } else {
158 // Binary search. Seems less effective than linear + caching.
159 const Interval* i0 = fIntervals.begin();
160 const Interval* i1 = fIntervals.end() - 1;
161
162 while (i0 != i1) {
163 SkASSERT(i0 < i1);
164 SkASSERT(in_range(fx, i0->fP0, i1->fP1));
165
166 const Interval* i = i0 + ((i1 - i0) >> 1);
167
168 if (in_range(fx, i0->fP0, i->fP1)) {
169 i1 = i;
170 } else {
171 SkASSERT(in_range(fx, i->fP1, i1->fP1));
172 i0 = i + 1;
173 }
174 }
175
176 SkASSERT(in_range(fx, i0->fP0, i0->fP1));
177 return i0;
178 }
179}
fmalitabc590c02016-02-22 09:12:33 -0800180
181void SkLinearGradient::
182LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800183 if (!this->isFast()) {
184 this->INHERITED::shadeSpan(x, y, dst, count);
185 return;
186 }
187
fmalitabc590c02016-02-22 09:12:33 -0800188 // TODO: plumb dithering
189 SkASSERT(count > 0);
190 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700191 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700192 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800193 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700194 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700195 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800196 }
197}
198
199void SkLinearGradient::
200LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800201 if (!this->isFast()) {
202 this->INHERITED::shadeSpan4f(x, y, dst, count);
203 return;
204 }
205
fmalitabc590c02016-02-22 09:12:33 -0800206 // TONOTDO: plumb dithering
207 SkASSERT(count > 0);
208 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700209 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700210 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800211 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700212 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700213 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800214 }
215}
216
fmalitadc6c9bf2016-03-21 13:16:51 -0700217template<DstType dstType, ApplyPremul premul>
fmalitabc590c02016-02-22 09:12:33 -0800218void SkLinearGradient::
219LinearGradient4fContext::shadePremulSpan(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700220 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800221 int count) const {
222 const SkLinearGradient& shader =
223 static_cast<const SkLinearGradient&>(fShader);
224 switch (shader.fTileMode) {
225 case kClamp_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700226 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700227 premul,
fmalitabc590c02016-02-22 09:12:33 -0800228 kClamp_TileMode>(x, y, dst, count);
229 break;
230 case kRepeat_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700231 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700232 premul,
fmalitabc590c02016-02-22 09:12:33 -0800233 kRepeat_TileMode>(x, y, dst, count);
234 break;
235 case kMirror_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700236 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700237 premul,
fmalitabc590c02016-02-22 09:12:33 -0800238 kMirror_TileMode>(x, y, dst, count);
239 break;
240 }
241}
242
fmalitadc6c9bf2016-03-21 13:16:51 -0700243template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800244void SkLinearGradient::
245LinearGradient4fContext::shadeSpanInternal(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700246 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800247 int count) const {
248 SkPoint pt;
249 fDstToPosProc(fDstToPos,
250 x + SK_ScalarHalf,
251 y + SK_ScalarHalf,
252 &pt);
253 const SkScalar fx = pinFx<tileMode>(pt.x());
254 const SkScalar dx = fDstToPos.getScaleX();
fmalita3a2e45a2016-10-14 08:18:24 -0700255 LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals.begin(),
256 fIntervals.end() - 1,
257 this->findInterval(fx),
258 fx,
259 dx,
260 SkScalarNearlyZero(dx * count));
fmalitabc590c02016-02-22 09:12:33 -0800261 while (count > 0) {
262 // What we really want here is SkTPin(advance, 1, count)
263 // but that's a significant perf hit for >> stops; investigate.
264 const int n = SkScalarTruncToInt(
265 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
266
267 // The current interval advance can be +inf (e.g. when reaching
268 // the clamp mode end intervals) - when that happens, we expect to
269 // a) consume all remaining count in one swoop
270 // b) return a zero color gradient
271 SkASSERT(SkScalarIsFinite(proc.currentAdvance())
272 || (n == count && proc.currentRampIsZero()));
273
274 if (proc.currentRampIsZero()) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700275 DstTraits<dstType, premul>::store(proc.currentColor(),
276 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800277 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700278 ramp<dstType, premul>(proc.currentColor(),
279 proc.currentColorGrad(),
280 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800281 }
282
283 proc.advance(SkIntToScalar(n));
284 count -= n;
285 dst += n;
286 }
287}
288
fmalita3a2e45a2016-10-14 08:18:24 -0700289template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800290class SkLinearGradient::
291LinearGradient4fContext::LinearIntervalProcessor {
292public:
293 LinearIntervalProcessor(const Interval* firstInterval,
294 const Interval* lastInterval,
295 const Interval* i,
296 SkScalar fx,
297 SkScalar dx,
298 bool is_vertical)
fmalitaa928b282016-03-18 10:28:23 -0700299 : fAdvX((i->fP1 - fx) / dx)
fmalitabc590c02016-02-22 09:12:33 -0800300 , fFirstInterval(firstInterval)
301 , fLastInterval(lastInterval)
302 , fInterval(i)
303 , fDx(dx)
304 , fIsVertical(is_vertical)
305 {
fmalita6d7e4e82016-09-20 06:55:16 -0700306 SkASSERT(fAdvX >= 0);
fmalitabc590c02016-02-22 09:12:33 -0800307 SkASSERT(firstInterval <= lastInterval);
fmalita7e6fcf82016-03-10 11:18:43 -0800308 SkASSERT(in_range(fx, i->fP0, i->fP1));
fmalitaafac5812016-11-01 13:41:34 -0700309
310 if (tileMode != kClamp_TileMode && !is_vertical) {
311 const auto spanX = (lastInterval->fP1 - firstInterval->fP0) / dx;
312 SkASSERT(spanX >= 0);
313
314 // If we're in a repeating tile mode and the whole gradient is compressed into a
315 // fraction of a pixel, we just use the average color in zero-ramp mode.
316 // This also avoids cases where we make no progress due to interval advances being
317 // close to zero.
318 static constexpr SkScalar kMinSpanX = .25f;
319 if (spanX < kMinSpanX) {
320 this->init_average_props();
321 return;
322 }
323 }
324
fmalitabc590c02016-02-22 09:12:33 -0800325 this->compute_interval_props(fx - i->fP0);
326 }
327
328 SkScalar currentAdvance() const {
329 SkASSERT(fAdvX >= 0);
Ben Wagner8a1036c2016-11-09 15:00:49 -0500330 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx || !std::isfinite(fAdvX));
fmalitabc590c02016-02-22 09:12:33 -0800331 return fAdvX;
332 }
333
334 bool currentRampIsZero() const { return fZeroRamp; }
335 const Sk4f& currentColor() const { return fCc; }
336 const Sk4f& currentColorGrad() const { return fDcDx; }
337
338 void advance(SkScalar advX) {
339 SkASSERT(advX > 0);
340 SkASSERT(fAdvX >= 0);
341
342 if (advX >= fAdvX) {
343 advX = this->advance_interval(advX);
344 }
345 SkASSERT(advX < fAdvX);
346
347 fCc = fCc + fDcDx * Sk4f(advX);
348 fAdvX -= advX;
349 }
350
351private:
352 void compute_interval_props(SkScalar t) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700353 fZeroRamp = fIsVertical || fInterval->isZeroRamp();
fmalita8f457592016-10-21 06:02:22 -0700354 fCc = DstTraits<dstType, premul>::load(fInterval->fC0);
355
356 if (fInterval->isZeroRamp()) {
357 fDcDx = 0;
358 } else {
359 const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fDc);
360 fCc = fCc + dC * Sk4f(t);
361 fDcDx = dC * fDx;
362 }
fmalitabc590c02016-02-22 09:12:33 -0800363 }
364
fmalitaafac5812016-11-01 13:41:34 -0700365 void init_average_props() {
366 fAdvX = SK_ScalarInfinity;
367 fZeroRamp = true;
368 fDcDx = 0;
369 fCc = Sk4f(0);
370
371 // TODO: precompute the average at interval setup time?
372 for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) {
373 // Each interval contributes its average color to the total/weighted average:
374 //
375 // C = (c0 + c1) / 2 = (c0 + c0 + dc * (p1 - p0)) / 2
376 //
377 // Avg += C * (p1 - p0)
378 //
379 const auto dp = i->fP1 - i->fP0;
380 auto c = DstTraits<dstType, premul>::load(i->fC0);
381 if (!i->fZeroRamp) {
382 c = c + DstTraits<dstType, premul>::load(i->fDc) * dp * 0.5f;
383 }
384 fCc = fCc + c * dp;
385 }
386 }
387
fmalitabc590c02016-02-22 09:12:33 -0800388 const Interval* next_interval(const Interval* i) const {
389 SkASSERT(i >= fFirstInterval);
390 SkASSERT(i <= fLastInterval);
391 i++;
392
393 if (tileMode == kClamp_TileMode) {
394 SkASSERT(i <= fLastInterval);
395 return i;
396 }
397
398 return (i <= fLastInterval) ? i : fFirstInterval;
399 }
400
401 SkScalar advance_interval(SkScalar advX) {
402 SkASSERT(advX >= fAdvX);
403
404 do {
405 advX -= fAdvX;
406 fInterval = this->next_interval(fInterval);
407 fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx;
408 SkASSERT(fAdvX > 0);
409 } while (advX >= fAdvX);
410
411 compute_interval_props(0);
412
413 SkASSERT(advX >= 0);
414 return advX;
415 }
416
fmalitabc590c02016-02-22 09:12:33 -0800417 // Current interval properties.
fmalitabc590c02016-02-22 09:12:33 -0800418 Sk4f fDcDx; // dst color gradient (dc/dx)
419 Sk4f fCc; // current color, interpolated in dst
420 SkScalar fAdvX; // remaining interval advance in dst
421 bool fZeroRamp; // current interval color grad is 0
422
423 const Interval* fFirstInterval;
424 const Interval* fLastInterval;
425 const Interval* fInterval; // current interval
426 const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx
427 const bool fIsVertical;
428};
fmalita7e6fcf82016-03-10 11:18:43 -0800429
430void SkLinearGradient::
431LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
432 SkASSERT(count > 0);
433 SkASSERT(fDstToPosClass != kLinear_MatrixClass);
434
435 SkScalar sx = x + SK_ScalarHalf;
436 const SkScalar sy = y + SK_ScalarHalf;
437 SkPoint pt;
438
439 if (fDstToPosClass != kPerspective_MatrixClass) {
440 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline
441 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
442 fDstToPosProc(fDstToPos, sx, sy, &pt);
443
444 const Sk4f dtdx4 = Sk4f(4 * dtdx);
445 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
446 pt.x() + 1 * dtdx,
447 pt.x() + 2 * dtdx,
448 pt.x() + 3 * dtdx);
449
450 while (count >= 4) {
451 t4.store(ts);
452 t4 = t4 + dtdx4;
453 ts += 4;
454 count -= 4;
455 }
456
457 if (count & 2) {
458 *ts++ = t4[0];
459 *ts++ = t4[1];
460 t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
461 }
462
463 if (count & 1) {
464 *ts++ = t4[0];
465 }
466 } else {
467 for (int i = 0; i < count; ++i) {
468 fDstToPosProc(fDstToPos, sx, sy, &pt);
469 ts[i] = pt.x();
470 sx += SK_Scalar1;
471 }
472 }
473}
fmalitaa928b282016-03-18 10:28:23 -0700474
reed58fc94e2016-03-18 12:42:26 -0700475bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info,
476 BlitState* state) {
Mike Reed6a015542016-11-09 10:38:09 -0500477 if (state->fMode != SkBlendMode::kSrc &&
478 !(state->fMode == SkBlendMode::kSrcOver && (fFlags & kOpaqueAlpha_Flag))) {
reed58fc94e2016-03-18 12:42:26 -0700479 return false;
fmalitaa928b282016-03-18 10:28:23 -0700480 }
481
482 switch (info.colorType()) {
483 case kN32_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700484 state->fBlitBW = D32_BlitBW;
485 return true;
fmalitaa928b282016-03-18 10:28:23 -0700486 case kRGBA_F16_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700487 state->fBlitBW = D64_BlitBW;
488 return true;
fmalitaa928b282016-03-18 10:28:23 -0700489 default:
reed58fc94e2016-03-18 12:42:26 -0700490 return false;
fmalitaa928b282016-03-18 10:28:23 -0700491 }
492}
493
494void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700495LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
496 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700497 // FIXME: ignoring coverage for now
498 const LinearGradient4fContext* ctx =
499 static_cast<const LinearGradient4fContext*>(state->fCtx);
500
reeddabe5d32016-06-21 10:28:14 -0700501 if (!dst.info().gammaCloseToSRGB()) {
fmalitaa928b282016-03-18 10:28:23 -0700502 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700503 ctx->shadePremulSpan<DstType::L32, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700504 x, y, dst.writable_addr32(x, y), count);
505 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700506 ctx->shadePremulSpan<DstType::L32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700507 x, y, dst.writable_addr32(x, y), count);
508 }
509 } else {
510 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700511 ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700512 x, y, dst.writable_addr32(x, y), count);
513 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700514 ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700515 x, y, dst.writable_addr32(x, y), count);
516 }
517 }
518}
519
520void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700521LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
522 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700523 // FIXME: ignoring coverage for now
524 const LinearGradient4fContext* ctx =
525 static_cast<const LinearGradient4fContext*>(state->fCtx);
526
527 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700528 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700529 x, y, dst.writable_addr64(x, y), count);
530 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700531 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700532 x, y, dst.writable_addr64(x, y), count);
533 }
534}