blob: 1100493212e22e1e80758ff06f8a1eb8c1b1eb7c [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
12namespace {
13
fmalitadc6c9bf2016-03-21 13:16:51 -070014template<DstType dstType, ApplyPremul premul>
15void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Type dst[], int n) {
fmalitabc590c02016-02-22 09:12:33 -080016 SkASSERT(n > 0);
17
18 const Sk4f dc2 = dc + dc;
19 const Sk4f dc4 = dc2 + dc2;
20
21 Sk4f c0 = c ;
22 Sk4f c1 = c + dc;
23 Sk4f c2 = c0 + dc2;
24 Sk4f c3 = c1 + dc2;
25
26 while (n >= 4) {
fmalitadc6c9bf2016-03-21 13:16:51 -070027 DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst);
fmalitabc590c02016-02-22 09:12:33 -080028 dst += 4;
29
30 c0 = c0 + dc4;
31 c1 = c1 + dc4;
32 c2 = c2 + dc4;
33 c3 = c3 + dc4;
34 n -= 4;
35 }
36 if (n & 2) {
fmalitadc6c9bf2016-03-21 13:16:51 -070037 DstTraits<dstType, premul>::store(c0, dst++);
38 DstTraits<dstType, premul>::store(c1, dst++);
fmalitabc590c02016-02-22 09:12:33 -080039 c0 = c0 + dc2;
40 }
41 if (n & 1) {
fmalitadc6c9bf2016-03-21 13:16:51 -070042 DstTraits<dstType, premul>::store(c0, dst);
fmalitabc590c02016-02-22 09:12:33 -080043 }
44}
45
fmalita83aa9202016-03-23 12:28:14 -070046// Planar version of ramp (S32 no-premul only).
47template<>
48void ramp<DstType::S32, ApplyPremul::False>(const Sk4f& c, const Sk4f& dc, SkPMColor dst[], int n) {
49 SkASSERT(n > 0);
50
51 const Sk4f dc4 = dc * 4;
52 const Sk4x4f dc4x = { Sk4f(dc4[0]), Sk4f(dc4[1]), Sk4f(dc4[2]), Sk4f(dc4[3]) };
53 Sk4x4f c4x = Sk4x4f::Transpose(c, c + dc, c + dc * 2, c + dc * 3);
54
55 while (n >= 4) {
mtklein0c902472016-07-20 18:10:07 -070056 ( sk_linear_to_srgb(c4x.r) << 0
57 | sk_linear_to_srgb(c4x.g) << 8
58 | sk_linear_to_srgb(c4x.b) << 16
59 | Sk4f_round(255.0f*c4x.a) << 24).store(dst);
fmalita83aa9202016-03-23 12:28:14 -070060
61 c4x.r += dc4x.r;
62 c4x.g += dc4x.g;
63 c4x.b += dc4x.b;
64 c4x.a += dc4x.a;
65
66 dst += 4;
67 n -= 4;
68 }
69
70 if (n & 2) {
71 DstTraits<DstType::S32, ApplyPremul::False>
72 ::store(Sk4f(c4x.r[0], c4x.g[0], c4x.b[0], c4x.a[0]), dst++);
73 DstTraits<DstType::S32, ApplyPremul::False>
74 ::store(Sk4f(c4x.r[1], c4x.g[1], c4x.b[1], c4x.a[1]), dst++);
75 }
76
77 if (n & 1) {
78 DstTraits<DstType::S32, ApplyPremul::False>
79 ::store(Sk4f(c4x.r[n & 2], c4x.g[n & 2], c4x.b[n & 2], c4x.a[n & 2]), dst);
80 }
81}
82
fmalitabc590c02016-02-22 09:12:33 -080083template<SkShader::TileMode>
84SkScalar pinFx(SkScalar);
85
86template<>
87SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
88 return fx;
89}
90
91template<>
92SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
93 const SkScalar f = SkScalarFraction(fx);
94 return f < 0 ? f + 1 : f;
95}
96
97template<>
98SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
99 const SkScalar f = SkScalarMod(fx, 2.0f);
100 return f < 0 ? f + 2 : f;
101}
102
fmalita6d7e4e82016-09-20 06:55:16 -0700103// true when x is in [k1,k2), or [k2, k1) when the interval is reversed.
104// TODO(fmalita): hoist the reversed interval check out of this helper.
fmalita7520fc42016-03-04 11:01:24 -0800105bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
106 SkASSERT(k1 != k2);
107 return (k1 < k2)
fmalitaafac5812016-11-01 13:41:34 -0700108 ? (x >= k1 && x < k2)
109 : (x >= k2 && x < k1);
fmalita7520fc42016-03-04 11:01:24 -0800110}
111
fmalitabc590c02016-02-22 09:12:33 -0800112} // anonymous namespace
113
114SkLinearGradient::
115LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
116 const ContextRec& rec)
fmalita7520fc42016-03-04 11:01:24 -0800117 : INHERITED(shader, rec) {
fmalita7520fc42016-03-04 11:01:24 -0800118
fmalita7e6fcf82016-03-10 11:18:43 -0800119 // Our fast path expects interval points to be monotonically increasing in x.
fmalita6d7e4e82016-09-20 06:55:16 -0700120 const bool reverseIntervals = this->isFast() && signbit(fDstToPos.getScaleX());
fmalita7e6fcf82016-03-10 11:18:43 -0800121 this->buildIntervals(shader, rec, reverseIntervals);
fmalita7520fc42016-03-04 11:01:24 -0800122
123 SkASSERT(fIntervals.count() > 0);
124 fCachedInterval = fIntervals.begin();
125}
126
fmalita7520fc42016-03-04 11:01:24 -0800127const SkGradientShaderBase::GradientShaderBase4fContext::Interval*
128SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
129 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1));
130
131 if (1) {
132 // Linear search, using the last scanline interval as a starting point.
133 SkASSERT(fCachedInterval >= fIntervals.begin());
134 SkASSERT(fCachedInterval < fIntervals.end());
135 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
136 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) {
137 fCachedInterval += search_dir;
138 if (fCachedInterval >= fIntervals.end()) {
139 fCachedInterval = fIntervals.begin();
140 } else if (fCachedInterval < fIntervals.begin()) {
141 fCachedInterval = fIntervals.end() - 1;
142 }
143 }
144 return fCachedInterval;
145 } else {
146 // Binary search. Seems less effective than linear + caching.
147 const Interval* i0 = fIntervals.begin();
148 const Interval* i1 = fIntervals.end() - 1;
149
150 while (i0 != i1) {
151 SkASSERT(i0 < i1);
152 SkASSERT(in_range(fx, i0->fP0, i1->fP1));
153
154 const Interval* i = i0 + ((i1 - i0) >> 1);
155
156 if (in_range(fx, i0->fP0, i->fP1)) {
157 i1 = i;
158 } else {
159 SkASSERT(in_range(fx, i->fP1, i1->fP1));
160 i0 = i + 1;
161 }
162 }
163
164 SkASSERT(in_range(fx, i0->fP0, i0->fP1));
165 return i0;
166 }
167}
fmalitabc590c02016-02-22 09:12:33 -0800168
169void SkLinearGradient::
170LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800171 if (!this->isFast()) {
172 this->INHERITED::shadeSpan(x, y, dst, count);
173 return;
174 }
175
fmalitabc590c02016-02-22 09:12:33 -0800176 // TODO: plumb dithering
177 SkASSERT(count > 0);
178 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700179 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700180 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800181 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700182 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700183 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800184 }
185}
186
187void SkLinearGradient::
188LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800189 if (!this->isFast()) {
190 this->INHERITED::shadeSpan4f(x, y, dst, count);
191 return;
192 }
193
fmalitabc590c02016-02-22 09:12:33 -0800194 // TONOTDO: plumb dithering
195 SkASSERT(count > 0);
196 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700197 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700198 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800199 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700200 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700201 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800202 }
203}
204
fmalitadc6c9bf2016-03-21 13:16:51 -0700205template<DstType dstType, ApplyPremul premul>
fmalitabc590c02016-02-22 09:12:33 -0800206void SkLinearGradient::
207LinearGradient4fContext::shadePremulSpan(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700208 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800209 int count) const {
210 const SkLinearGradient& shader =
211 static_cast<const SkLinearGradient&>(fShader);
212 switch (shader.fTileMode) {
213 case kClamp_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700214 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700215 premul,
fmalitabc590c02016-02-22 09:12:33 -0800216 kClamp_TileMode>(x, y, dst, count);
217 break;
218 case kRepeat_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700219 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700220 premul,
fmalitabc590c02016-02-22 09:12:33 -0800221 kRepeat_TileMode>(x, y, dst, count);
222 break;
223 case kMirror_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700224 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700225 premul,
fmalitabc590c02016-02-22 09:12:33 -0800226 kMirror_TileMode>(x, y, dst, count);
227 break;
228 }
229}
230
fmalitadc6c9bf2016-03-21 13:16:51 -0700231template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800232void SkLinearGradient::
233LinearGradient4fContext::shadeSpanInternal(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700234 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800235 int count) const {
236 SkPoint pt;
237 fDstToPosProc(fDstToPos,
238 x + SK_ScalarHalf,
239 y + SK_ScalarHalf,
240 &pt);
241 const SkScalar fx = pinFx<tileMode>(pt.x());
242 const SkScalar dx = fDstToPos.getScaleX();
fmalita3a2e45a2016-10-14 08:18:24 -0700243 LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals.begin(),
244 fIntervals.end() - 1,
245 this->findInterval(fx),
246 fx,
247 dx,
248 SkScalarNearlyZero(dx * count));
fmalitabc590c02016-02-22 09:12:33 -0800249 while (count > 0) {
250 // What we really want here is SkTPin(advance, 1, count)
251 // but that's a significant perf hit for >> stops; investigate.
252 const int n = SkScalarTruncToInt(
253 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
254
255 // The current interval advance can be +inf (e.g. when reaching
256 // the clamp mode end intervals) - when that happens, we expect to
257 // a) consume all remaining count in one swoop
258 // b) return a zero color gradient
259 SkASSERT(SkScalarIsFinite(proc.currentAdvance())
260 || (n == count && proc.currentRampIsZero()));
261
262 if (proc.currentRampIsZero()) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700263 DstTraits<dstType, premul>::store(proc.currentColor(),
264 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800265 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700266 ramp<dstType, premul>(proc.currentColor(),
267 proc.currentColorGrad(),
268 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800269 }
270
271 proc.advance(SkIntToScalar(n));
272 count -= n;
273 dst += n;
274 }
275}
276
fmalita3a2e45a2016-10-14 08:18:24 -0700277template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800278class SkLinearGradient::
279LinearGradient4fContext::LinearIntervalProcessor {
280public:
281 LinearIntervalProcessor(const Interval* firstInterval,
282 const Interval* lastInterval,
283 const Interval* i,
284 SkScalar fx,
285 SkScalar dx,
286 bool is_vertical)
fmalitaa928b282016-03-18 10:28:23 -0700287 : fAdvX((i->fP1 - fx) / dx)
fmalitabc590c02016-02-22 09:12:33 -0800288 , fFirstInterval(firstInterval)
289 , fLastInterval(lastInterval)
290 , fInterval(i)
291 , fDx(dx)
292 , fIsVertical(is_vertical)
293 {
fmalita6d7e4e82016-09-20 06:55:16 -0700294 SkASSERT(fAdvX >= 0);
fmalitabc590c02016-02-22 09:12:33 -0800295 SkASSERT(firstInterval <= lastInterval);
fmalita7e6fcf82016-03-10 11:18:43 -0800296 SkASSERT(in_range(fx, i->fP0, i->fP1));
fmalitaafac5812016-11-01 13:41:34 -0700297
298 if (tileMode != kClamp_TileMode && !is_vertical) {
299 const auto spanX = (lastInterval->fP1 - firstInterval->fP0) / dx;
300 SkASSERT(spanX >= 0);
301
302 // If we're in a repeating tile mode and the whole gradient is compressed into a
303 // fraction of a pixel, we just use the average color in zero-ramp mode.
304 // This also avoids cases where we make no progress due to interval advances being
305 // close to zero.
306 static constexpr SkScalar kMinSpanX = .25f;
307 if (spanX < kMinSpanX) {
308 this->init_average_props();
309 return;
310 }
311 }
312
fmalitabc590c02016-02-22 09:12:33 -0800313 this->compute_interval_props(fx - i->fP0);
314 }
315
316 SkScalar currentAdvance() const {
317 SkASSERT(fAdvX >= 0);
fmalitaafac5812016-11-01 13:41:34 -0700318 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx || !isfinite(fAdvX));
fmalitabc590c02016-02-22 09:12:33 -0800319 return fAdvX;
320 }
321
322 bool currentRampIsZero() const { return fZeroRamp; }
323 const Sk4f& currentColor() const { return fCc; }
324 const Sk4f& currentColorGrad() const { return fDcDx; }
325
326 void advance(SkScalar advX) {
327 SkASSERT(advX > 0);
328 SkASSERT(fAdvX >= 0);
329
330 if (advX >= fAdvX) {
331 advX = this->advance_interval(advX);
332 }
333 SkASSERT(advX < fAdvX);
334
335 fCc = fCc + fDcDx * Sk4f(advX);
336 fAdvX -= advX;
337 }
338
339private:
340 void compute_interval_props(SkScalar t) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700341 fZeroRamp = fIsVertical || fInterval->isZeroRamp();
fmalita8f457592016-10-21 06:02:22 -0700342 fCc = DstTraits<dstType, premul>::load(fInterval->fC0);
343
344 if (fInterval->isZeroRamp()) {
345 fDcDx = 0;
346 } else {
347 const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fDc);
348 fCc = fCc + dC * Sk4f(t);
349 fDcDx = dC * fDx;
350 }
fmalitabc590c02016-02-22 09:12:33 -0800351 }
352
fmalitaafac5812016-11-01 13:41:34 -0700353 void init_average_props() {
354 fAdvX = SK_ScalarInfinity;
355 fZeroRamp = true;
356 fDcDx = 0;
357 fCc = Sk4f(0);
358
359 // TODO: precompute the average at interval setup time?
360 for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) {
361 // Each interval contributes its average color to the total/weighted average:
362 //
363 // C = (c0 + c1) / 2 = (c0 + c0 + dc * (p1 - p0)) / 2
364 //
365 // Avg += C * (p1 - p0)
366 //
367 const auto dp = i->fP1 - i->fP0;
368 auto c = DstTraits<dstType, premul>::load(i->fC0);
369 if (!i->fZeroRamp) {
370 c = c + DstTraits<dstType, premul>::load(i->fDc) * dp * 0.5f;
371 }
372 fCc = fCc + c * dp;
373 }
374 }
375
fmalitabc590c02016-02-22 09:12:33 -0800376 const Interval* next_interval(const Interval* i) const {
377 SkASSERT(i >= fFirstInterval);
378 SkASSERT(i <= fLastInterval);
379 i++;
380
381 if (tileMode == kClamp_TileMode) {
382 SkASSERT(i <= fLastInterval);
383 return i;
384 }
385
386 return (i <= fLastInterval) ? i : fFirstInterval;
387 }
388
389 SkScalar advance_interval(SkScalar advX) {
390 SkASSERT(advX >= fAdvX);
391
392 do {
393 advX -= fAdvX;
394 fInterval = this->next_interval(fInterval);
395 fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx;
396 SkASSERT(fAdvX > 0);
397 } while (advX >= fAdvX);
398
399 compute_interval_props(0);
400
401 SkASSERT(advX >= 0);
402 return advX;
403 }
404
fmalitabc590c02016-02-22 09:12:33 -0800405 // Current interval properties.
fmalitabc590c02016-02-22 09:12:33 -0800406 Sk4f fDcDx; // dst color gradient (dc/dx)
407 Sk4f fCc; // current color, interpolated in dst
408 SkScalar fAdvX; // remaining interval advance in dst
409 bool fZeroRamp; // current interval color grad is 0
410
411 const Interval* fFirstInterval;
412 const Interval* fLastInterval;
413 const Interval* fInterval; // current interval
414 const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx
415 const bool fIsVertical;
416};
fmalita7e6fcf82016-03-10 11:18:43 -0800417
418void SkLinearGradient::
419LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
420 SkASSERT(count > 0);
421 SkASSERT(fDstToPosClass != kLinear_MatrixClass);
422
423 SkScalar sx = x + SK_ScalarHalf;
424 const SkScalar sy = y + SK_ScalarHalf;
425 SkPoint pt;
426
427 if (fDstToPosClass != kPerspective_MatrixClass) {
428 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline
429 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
430 fDstToPosProc(fDstToPos, sx, sy, &pt);
431
432 const Sk4f dtdx4 = Sk4f(4 * dtdx);
433 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
434 pt.x() + 1 * dtdx,
435 pt.x() + 2 * dtdx,
436 pt.x() + 3 * dtdx);
437
438 while (count >= 4) {
439 t4.store(ts);
440 t4 = t4 + dtdx4;
441 ts += 4;
442 count -= 4;
443 }
444
445 if (count & 2) {
446 *ts++ = t4[0];
447 *ts++ = t4[1];
448 t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
449 }
450
451 if (count & 1) {
452 *ts++ = t4[0];
453 }
454 } else {
455 for (int i = 0; i < count; ++i) {
456 fDstToPosProc(fDstToPos, sx, sy, &pt);
457 ts[i] = pt.x();
458 sx += SK_Scalar1;
459 }
460 }
461}
fmalitaa928b282016-03-18 10:28:23 -0700462
reed58fc94e2016-03-18 12:42:26 -0700463bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info,
464 BlitState* state) {
fmalitaa928b282016-03-18 10:28:23 -0700465 SkXfermode::Mode mode;
466 if (!SkXfermode::AsMode(state->fXfer, &mode)) {
reed58fc94e2016-03-18 12:42:26 -0700467 return false;
fmalitaa928b282016-03-18 10:28:23 -0700468 }
469
fmalitaa928b282016-03-18 10:28:23 -0700470 if (mode != SkXfermode::kSrc_Mode &&
fmalitaeadf3cf2016-04-07 13:16:13 -0700471 !(mode == SkXfermode::kSrcOver_Mode && (fFlags & kOpaqueAlpha_Flag))) {
reed58fc94e2016-03-18 12:42:26 -0700472 return false;
fmalitaa928b282016-03-18 10:28:23 -0700473 }
474
475 switch (info.colorType()) {
476 case kN32_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700477 state->fBlitBW = D32_BlitBW;
478 return true;
fmalitaa928b282016-03-18 10:28:23 -0700479 case kRGBA_F16_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700480 state->fBlitBW = D64_BlitBW;
481 return true;
fmalitaa928b282016-03-18 10:28:23 -0700482 default:
reed58fc94e2016-03-18 12:42:26 -0700483 return false;
fmalitaa928b282016-03-18 10:28:23 -0700484 }
485}
486
487void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700488LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
489 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700490 // FIXME: ignoring coverage for now
491 const LinearGradient4fContext* ctx =
492 static_cast<const LinearGradient4fContext*>(state->fCtx);
493
reeddabe5d32016-06-21 10:28:14 -0700494 if (!dst.info().gammaCloseToSRGB()) {
fmalitaa928b282016-03-18 10:28:23 -0700495 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700496 ctx->shadePremulSpan<DstType::L32, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700497 x, y, dst.writable_addr32(x, y), count);
498 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700499 ctx->shadePremulSpan<DstType::L32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700500 x, y, dst.writable_addr32(x, y), count);
501 }
502 } else {
503 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700504 ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700505 x, y, dst.writable_addr32(x, y), count);
506 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700507 ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700508 x, y, dst.writable_addr32(x, y), count);
509 }
510 }
511}
512
513void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700514LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
515 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700516 // FIXME: ignoring coverage for now
517 const LinearGradient4fContext* ctx =
518 static_cast<const LinearGradient4fContext*>(state->fCtx);
519
520 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700521 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700522 x, y, dst.writable_addr64(x, y), count);
523 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700524 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700525 x, y, dst.writable_addr64(x, y), count);
526 }
527}