blob: 354c941a869c060e5ddcf158193921a8604ceae7 [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"
fmalitabc590c02016-02-22 09:12:33 -080010
Ben Wagner8a1036c2016-11-09 15:00:49 -050011#include <cmath>
12
fmalitabc590c02016-02-22 09:12:33 -080013namespace {
14
fmalitadc6c9bf2016-03-21 13:16:51 -070015template<DstType dstType, ApplyPremul premul>
16void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Type dst[], int n) {
fmalitabc590c02016-02-22 09:12:33 -080017 SkASSERT(n > 0);
18
19 const Sk4f dc2 = dc + dc;
20 const Sk4f dc4 = dc2 + dc2;
21
22 Sk4f c0 = c ;
23 Sk4f c1 = c + dc;
24 Sk4f c2 = c0 + dc2;
25 Sk4f c3 = c1 + dc2;
26
27 while (n >= 4) {
fmalitadc6c9bf2016-03-21 13:16:51 -070028 DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst);
fmalitabc590c02016-02-22 09:12:33 -080029 dst += 4;
30
31 c0 = c0 + dc4;
32 c1 = c1 + dc4;
33 c2 = c2 + dc4;
34 c3 = c3 + dc4;
35 n -= 4;
36 }
37 if (n & 2) {
fmalitadc6c9bf2016-03-21 13:16:51 -070038 DstTraits<dstType, premul>::store(c0, dst++);
39 DstTraits<dstType, premul>::store(c1, dst++);
fmalitabc590c02016-02-22 09:12:33 -080040 c0 = c0 + dc2;
41 }
42 if (n & 1) {
fmalitadc6c9bf2016-03-21 13:16:51 -070043 DstTraits<dstType, premul>::store(c0, dst);
fmalitabc590c02016-02-22 09:12:33 -080044 }
45}
46
fmalita83aa9202016-03-23 12:28:14 -070047// Planar version of ramp (S32 no-premul only).
48template<>
49void ramp<DstType::S32, ApplyPremul::False>(const Sk4f& c, const Sk4f& dc, SkPMColor dst[], int n) {
50 SkASSERT(n > 0);
51
52 const Sk4f dc4 = dc * 4;
53 const Sk4x4f dc4x = { Sk4f(dc4[0]), Sk4f(dc4[1]), Sk4f(dc4[2]), Sk4f(dc4[3]) };
54 Sk4x4f c4x = Sk4x4f::Transpose(c, c + dc, c + dc * 2, c + dc * 3);
55
56 while (n >= 4) {
mtklein0c902472016-07-20 18:10:07 -070057 ( sk_linear_to_srgb(c4x.r) << 0
58 | sk_linear_to_srgb(c4x.g) << 8
59 | sk_linear_to_srgb(c4x.b) << 16
60 | Sk4f_round(255.0f*c4x.a) << 24).store(dst);
fmalita83aa9202016-03-23 12:28:14 -070061
62 c4x.r += dc4x.r;
63 c4x.g += dc4x.g;
64 c4x.b += dc4x.b;
65 c4x.a += dc4x.a;
66
67 dst += 4;
68 n -= 4;
69 }
70
71 if (n & 2) {
72 DstTraits<DstType::S32, ApplyPremul::False>
73 ::store(Sk4f(c4x.r[0], c4x.g[0], c4x.b[0], c4x.a[0]), dst++);
74 DstTraits<DstType::S32, ApplyPremul::False>
75 ::store(Sk4f(c4x.r[1], c4x.g[1], c4x.b[1], c4x.a[1]), dst++);
76 }
77
78 if (n & 1) {
79 DstTraits<DstType::S32, ApplyPremul::False>
80 ::store(Sk4f(c4x.r[n & 2], c4x.g[n & 2], c4x.b[n & 2], c4x.a[n & 2]), dst);
81 }
82}
83
fmalitabc590c02016-02-22 09:12:33 -080084template<SkShader::TileMode>
85SkScalar pinFx(SkScalar);
86
87template<>
88SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
89 return fx;
90}
91
92template<>
93SkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
Florin Malita0fdde542016-11-14 15:54:04 -050094 SkScalar f = SkScalarFraction(fx);
95 if (f < 0) {
96 f = SkTMin(f + 1, nextafterf(1, 0));
97 }
98 SkASSERT(f >= 0);
99 SkASSERT(f < 1.0f);
100 return f;
fmalitabc590c02016-02-22 09:12:33 -0800101}
102
103template<>
104SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
Florin Malita0fdde542016-11-14 15:54:04 -0500105 SkScalar f = SkScalarMod(fx, 2.0f);
106 if (f < 0) {
107 f = SkTMin(f + 2, nextafterf(2, 0));
108 }
109 SkASSERT(f >= 0);
110 SkASSERT(f < 2.0f);
111 return f;
fmalitabc590c02016-02-22 09:12:33 -0800112}
113
Florin Malitae659c7f2017-02-09 13:46:55 -0500114// true when x is in [k1,k2], or [k2, k1] when the interval is reversed.
fmalita6d7e4e82016-09-20 06:55:16 -0700115// TODO(fmalita): hoist the reversed interval check out of this helper.
fmalita7520fc42016-03-04 11:01:24 -0800116bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
117 SkASSERT(k1 != k2);
118 return (k1 < k2)
Florin Malitae659c7f2017-02-09 13:46:55 -0500119 ? (x >= k1 && x <= k2)
120 : (x >= k2 && x <= k1);
fmalita7520fc42016-03-04 11:01:24 -0800121}
122
fmalitabc590c02016-02-22 09:12:33 -0800123} // anonymous namespace
124
125SkLinearGradient::
126LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
127 const ContextRec& rec)
fmalita7520fc42016-03-04 11:01:24 -0800128 : INHERITED(shader, rec) {
fmalita7520fc42016-03-04 11:01:24 -0800129
fmalita7e6fcf82016-03-10 11:18:43 -0800130 // Our fast path expects interval points to be monotonically increasing in x.
Ben Wagner8a1036c2016-11-09 15:00:49 -0500131 const bool reverseIntervals = this->isFast() && std::signbit(fDstToPos.getScaleX());
fmalita7e6fcf82016-03-10 11:18:43 -0800132 this->buildIntervals(shader, rec, reverseIntervals);
fmalita7520fc42016-03-04 11:01:24 -0800133
134 SkASSERT(fIntervals.count() > 0);
135 fCachedInterval = fIntervals.begin();
136}
137
fmalita7520fc42016-03-04 11:01:24 -0800138const SkGradientShaderBase::GradientShaderBase4fContext::Interval*
139SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
140 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1));
141
142 if (1) {
143 // Linear search, using the last scanline interval as a starting point.
144 SkASSERT(fCachedInterval >= fIntervals.begin());
145 SkASSERT(fCachedInterval < fIntervals.end());
146 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
147 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) {
148 fCachedInterval += search_dir;
149 if (fCachedInterval >= fIntervals.end()) {
150 fCachedInterval = fIntervals.begin();
151 } else if (fCachedInterval < fIntervals.begin()) {
152 fCachedInterval = fIntervals.end() - 1;
153 }
154 }
155 return fCachedInterval;
156 } else {
157 // Binary search. Seems less effective than linear + caching.
158 const Interval* i0 = fIntervals.begin();
159 const Interval* i1 = fIntervals.end() - 1;
160
161 while (i0 != i1) {
162 SkASSERT(i0 < i1);
163 SkASSERT(in_range(fx, i0->fP0, i1->fP1));
164
165 const Interval* i = i0 + ((i1 - i0) >> 1);
166
167 if (in_range(fx, i0->fP0, i->fP1)) {
168 i1 = i;
169 } else {
170 SkASSERT(in_range(fx, i->fP1, i1->fP1));
171 i0 = i + 1;
172 }
173 }
174
175 SkASSERT(in_range(fx, i0->fP0, i0->fP1));
176 return i0;
177 }
178}
fmalitabc590c02016-02-22 09:12:33 -0800179
180void SkLinearGradient::
181LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800182 if (!this->isFast()) {
183 this->INHERITED::shadeSpan(x, y, dst, count);
184 return;
185 }
186
fmalitabc590c02016-02-22 09:12:33 -0800187 // TODO: plumb dithering
188 SkASSERT(count > 0);
189 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700190 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700191 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800192 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700193 this->shadePremulSpan<DstType::L32,
fmalitaa928b282016-03-18 10:28:23 -0700194 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800195 }
196}
197
198void SkLinearGradient::
199LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
fmalita7e6fcf82016-03-10 11:18:43 -0800200 if (!this->isFast()) {
201 this->INHERITED::shadeSpan4f(x, y, dst, count);
202 return;
203 }
204
fmalitabc590c02016-02-22 09:12:33 -0800205 // TONOTDO: plumb dithering
206 SkASSERT(count > 0);
207 if (fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700208 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700209 ApplyPremul::False>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800210 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700211 this->shadePremulSpan<DstType::F32,
fmalitaa928b282016-03-18 10:28:23 -0700212 ApplyPremul::True>(x, y, dst, count);
fmalitabc590c02016-02-22 09:12:33 -0800213 }
214}
215
fmalitadc6c9bf2016-03-21 13:16:51 -0700216template<DstType dstType, ApplyPremul premul>
fmalitabc590c02016-02-22 09:12:33 -0800217void SkLinearGradient::
218LinearGradient4fContext::shadePremulSpan(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700219 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800220 int count) const {
221 const SkLinearGradient& shader =
222 static_cast<const SkLinearGradient&>(fShader);
223 switch (shader.fTileMode) {
224 case kClamp_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700225 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700226 premul,
fmalitabc590c02016-02-22 09:12:33 -0800227 kClamp_TileMode>(x, y, dst, count);
228 break;
229 case kRepeat_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700230 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700231 premul,
fmalitabc590c02016-02-22 09:12:33 -0800232 kRepeat_TileMode>(x, y, dst, count);
233 break;
234 case kMirror_TileMode:
fmalitadc6c9bf2016-03-21 13:16:51 -0700235 this->shadeSpanInternal<dstType,
fmalitaa928b282016-03-18 10:28:23 -0700236 premul,
fmalitabc590c02016-02-22 09:12:33 -0800237 kMirror_TileMode>(x, y, dst, count);
238 break;
239 }
240}
241
fmalitadc6c9bf2016-03-21 13:16:51 -0700242template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800243void SkLinearGradient::
244LinearGradient4fContext::shadeSpanInternal(int x, int y,
fmalitadc6c9bf2016-03-21 13:16:51 -0700245 typename DstTraits<dstType, premul>::Type dst[],
fmalitabc590c02016-02-22 09:12:33 -0800246 int count) const {
247 SkPoint pt;
248 fDstToPosProc(fDstToPos,
249 x + SK_ScalarHalf,
250 y + SK_ScalarHalf,
251 &pt);
252 const SkScalar fx = pinFx<tileMode>(pt.x());
253 const SkScalar dx = fDstToPos.getScaleX();
fmalita3a2e45a2016-10-14 08:18:24 -0700254 LinearIntervalProcessor<dstType, premul, tileMode> proc(fIntervals.begin(),
255 fIntervals.end() - 1,
256 this->findInterval(fx),
257 fx,
258 dx,
259 SkScalarNearlyZero(dx * count));
fmalitabc590c02016-02-22 09:12:33 -0800260 while (count > 0) {
261 // What we really want here is SkTPin(advance, 1, count)
262 // but that's a significant perf hit for >> stops; investigate.
263 const int n = SkScalarTruncToInt(
264 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
265
266 // The current interval advance can be +inf (e.g. when reaching
267 // the clamp mode end intervals) - when that happens, we expect to
268 // a) consume all remaining count in one swoop
269 // b) return a zero color gradient
270 SkASSERT(SkScalarIsFinite(proc.currentAdvance())
271 || (n == count && proc.currentRampIsZero()));
272
273 if (proc.currentRampIsZero()) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700274 DstTraits<dstType, premul>::store(proc.currentColor(),
275 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800276 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700277 ramp<dstType, premul>(proc.currentColor(),
278 proc.currentColorGrad(),
279 dst, n);
fmalitabc590c02016-02-22 09:12:33 -0800280 }
281
282 proc.advance(SkIntToScalar(n));
283 count -= n;
284 dst += n;
285 }
286}
287
fmalita3a2e45a2016-10-14 08:18:24 -0700288template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode>
fmalitabc590c02016-02-22 09:12:33 -0800289class SkLinearGradient::
290LinearGradient4fContext::LinearIntervalProcessor {
291public:
292 LinearIntervalProcessor(const Interval* firstInterval,
293 const Interval* lastInterval,
294 const Interval* i,
295 SkScalar fx,
296 SkScalar dx,
297 bool is_vertical)
Florin Malita69d8d662017-02-08 15:35:42 -0500298 : fAdvX(is_vertical ? SK_ScalarInfinity : (i->fP1 - fx) / dx)
fmalitabc590c02016-02-22 09:12:33 -0800299 , fFirstInterval(firstInterval)
300 , fLastInterval(lastInterval)
301 , fInterval(i)
302 , fDx(dx)
303 , fIsVertical(is_vertical)
304 {
fmalita6d7e4e82016-09-20 06:55:16 -0700305 SkASSERT(fAdvX >= 0);
fmalitabc590c02016-02-22 09:12:33 -0800306 SkASSERT(firstInterval <= lastInterval);
fmalita7e6fcf82016-03-10 11:18:43 -0800307 SkASSERT(in_range(fx, i->fP0, i->fP1));
fmalitaafac5812016-11-01 13:41:34 -0700308
309 if (tileMode != kClamp_TileMode && !is_vertical) {
310 const auto spanX = (lastInterval->fP1 - firstInterval->fP0) / dx;
311 SkASSERT(spanX >= 0);
312
313 // If we're in a repeating tile mode and the whole gradient is compressed into a
314 // fraction of a pixel, we just use the average color in zero-ramp mode.
315 // This also avoids cases where we make no progress due to interval advances being
316 // close to zero.
317 static constexpr SkScalar kMinSpanX = .25f;
318 if (spanX < kMinSpanX) {
319 this->init_average_props();
320 return;
321 }
322 }
323
fmalitabc590c02016-02-22 09:12:33 -0800324 this->compute_interval_props(fx - i->fP0);
325 }
326
327 SkScalar currentAdvance() const {
328 SkASSERT(fAdvX >= 0);
Ben Wagner8a1036c2016-11-09 15:00:49 -0500329 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx || !std::isfinite(fAdvX));
fmalitabc590c02016-02-22 09:12:33 -0800330 return fAdvX;
331 }
332
333 bool currentRampIsZero() const { return fZeroRamp; }
334 const Sk4f& currentColor() const { return fCc; }
335 const Sk4f& currentColorGrad() const { return fDcDx; }
336
337 void advance(SkScalar advX) {
338 SkASSERT(advX > 0);
339 SkASSERT(fAdvX >= 0);
340
341 if (advX >= fAdvX) {
342 advX = this->advance_interval(advX);
343 }
344 SkASSERT(advX < fAdvX);
345
346 fCc = fCc + fDcDx * Sk4f(advX);
347 fAdvX -= advX;
348 }
349
350private:
351 void compute_interval_props(SkScalar t) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700352 fZeroRamp = fIsVertical || fInterval->isZeroRamp();
fmalita8f457592016-10-21 06:02:22 -0700353 fCc = DstTraits<dstType, premul>::load(fInterval->fC0);
354
355 if (fInterval->isZeroRamp()) {
356 fDcDx = 0;
357 } else {
358 const Sk4f dC = DstTraits<dstType, premul>::load(fInterval->fDc);
359 fCc = fCc + dC * Sk4f(t);
360 fDcDx = dC * fDx;
361 }
fmalitabc590c02016-02-22 09:12:33 -0800362 }
363
fmalitaafac5812016-11-01 13:41:34 -0700364 void init_average_props() {
365 fAdvX = SK_ScalarInfinity;
366 fZeroRamp = true;
367 fDcDx = 0;
368 fCc = Sk4f(0);
369
370 // TODO: precompute the average at interval setup time?
371 for (const auto* i = fFirstInterval; i <= fLastInterval; ++i) {
372 // Each interval contributes its average color to the total/weighted average:
373 //
374 // C = (c0 + c1) / 2 = (c0 + c0 + dc * (p1 - p0)) / 2
375 //
376 // Avg += C * (p1 - p0)
377 //
378 const auto dp = i->fP1 - i->fP0;
379 auto c = DstTraits<dstType, premul>::load(i->fC0);
380 if (!i->fZeroRamp) {
381 c = c + DstTraits<dstType, premul>::load(i->fDc) * dp * 0.5f;
382 }
383 fCc = fCc + c * dp;
384 }
385 }
386
fmalitabc590c02016-02-22 09:12:33 -0800387 const Interval* next_interval(const Interval* i) const {
388 SkASSERT(i >= fFirstInterval);
389 SkASSERT(i <= fLastInterval);
390 i++;
391
392 if (tileMode == kClamp_TileMode) {
393 SkASSERT(i <= fLastInterval);
394 return i;
395 }
396
397 return (i <= fLastInterval) ? i : fFirstInterval;
398 }
399
400 SkScalar advance_interval(SkScalar advX) {
401 SkASSERT(advX >= fAdvX);
402
403 do {
404 advX -= fAdvX;
405 fInterval = this->next_interval(fInterval);
406 fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx;
407 SkASSERT(fAdvX > 0);
408 } while (advX >= fAdvX);
409
410 compute_interval_props(0);
411
412 SkASSERT(advX >= 0);
413 return advX;
414 }
415
fmalitabc590c02016-02-22 09:12:33 -0800416 // Current interval properties.
fmalitabc590c02016-02-22 09:12:33 -0800417 Sk4f fDcDx; // dst color gradient (dc/dx)
418 Sk4f fCc; // current color, interpolated in dst
419 SkScalar fAdvX; // remaining interval advance in dst
420 bool fZeroRamp; // current interval color grad is 0
421
422 const Interval* fFirstInterval;
423 const Interval* fLastInterval;
424 const Interval* fInterval; // current interval
425 const SkScalar fDx; // 'dx' for consistency with other impls; actually dt/dx
426 const bool fIsVertical;
427};
fmalita7e6fcf82016-03-10 11:18:43 -0800428
429void SkLinearGradient::
430LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
431 SkASSERT(count > 0);
432 SkASSERT(fDstToPosClass != kLinear_MatrixClass);
433
434 SkScalar sx = x + SK_ScalarHalf;
435 const SkScalar sy = y + SK_ScalarHalf;
436 SkPoint pt;
437
438 if (fDstToPosClass != kPerspective_MatrixClass) {
439 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanline
440 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
441 fDstToPosProc(fDstToPos, sx, sy, &pt);
442
443 const Sk4f dtdx4 = Sk4f(4 * dtdx);
444 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
445 pt.x() + 1 * dtdx,
446 pt.x() + 2 * dtdx,
447 pt.x() + 3 * dtdx);
448
449 while (count >= 4) {
450 t4.store(ts);
451 t4 = t4 + dtdx4;
452 ts += 4;
453 count -= 4;
454 }
455
456 if (count & 2) {
457 *ts++ = t4[0];
458 *ts++ = t4[1];
459 t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
460 }
461
462 if (count & 1) {
463 *ts++ = t4[0];
464 }
465 } else {
466 for (int i = 0; i < count; ++i) {
467 fDstToPosProc(fDstToPos, sx, sy, &pt);
Florin Malita52bab302017-02-08 17:03:56 -0500468 // Perspective may yield NaN values.
469 // Short of a better idea, drop to 0.
470 ts[i] = SkScalarIsNaN(pt.x()) ? 0 : pt.x();
fmalita7e6fcf82016-03-10 11:18:43 -0800471 sx += SK_Scalar1;
472 }
473 }
474}
fmalitaa928b282016-03-18 10:28:23 -0700475
reed58fc94e2016-03-18 12:42:26 -0700476bool SkLinearGradient::LinearGradient4fContext::onChooseBlitProcs(const SkImageInfo& info,
477 BlitState* state) {
Mike Reed6a015542016-11-09 10:38:09 -0500478 if (state->fMode != SkBlendMode::kSrc &&
479 !(state->fMode == SkBlendMode::kSrcOver && (fFlags & kOpaqueAlpha_Flag))) {
reed58fc94e2016-03-18 12:42:26 -0700480 return false;
fmalitaa928b282016-03-18 10:28:23 -0700481 }
482
483 switch (info.colorType()) {
484 case kN32_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700485 state->fBlitBW = D32_BlitBW;
486 return true;
fmalitaa928b282016-03-18 10:28:23 -0700487 case kRGBA_F16_SkColorType:
reed58fc94e2016-03-18 12:42:26 -0700488 state->fBlitBW = D64_BlitBW;
489 return true;
fmalitaa928b282016-03-18 10:28:23 -0700490 default:
reed58fc94e2016-03-18 12:42:26 -0700491 return false;
fmalitaa928b282016-03-18 10:28:23 -0700492 }
493}
494
495void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700496LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
497 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700498 // FIXME: ignoring coverage for now
499 const LinearGradient4fContext* ctx =
500 static_cast<const LinearGradient4fContext*>(state->fCtx);
501
reeddabe5d32016-06-21 10:28:14 -0700502 if (!dst.info().gammaCloseToSRGB()) {
fmalitaa928b282016-03-18 10:28:23 -0700503 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700504 ctx->shadePremulSpan<DstType::L32, 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::L32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700508 x, y, dst.writable_addr32(x, y), count);
509 }
510 } else {
511 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700512 ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700513 x, y, dst.writable_addr32(x, y), count);
514 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700515 ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700516 x, y, dst.writable_addr32(x, y), count);
517 }
518 }
519}
520
521void SkLinearGradient::
reed58fc94e2016-03-18 12:42:26 -0700522LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixmap& dst,
523 int count) {
fmalitaa928b282016-03-18 10:28:23 -0700524 // FIXME: ignoring coverage for now
525 const LinearGradient4fContext* ctx =
526 static_cast<const LinearGradient4fContext*>(state->fCtx);
527
528 if (ctx->fColorsArePremul) {
fmalitadc6c9bf2016-03-21 13:16:51 -0700529 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>(
fmalitaa928b282016-03-18 10:28:23 -0700530 x, y, dst.writable_addr64(x, y), count);
531 } else {
fmalitadc6c9bf2016-03-21 13:16:51 -0700532 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>(
fmalitaa928b282016-03-18 10:28:23 -0700533 x, y, dst.writable_addr64(x, y), count);
534 }
535}