1bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita/*
2bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * Copyright 2016 Google Inc.
3bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita *
4bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * Use of this source code is governed by a BSD-style license that can be
5bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita * found in the LICENSE file.
6bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita */
7bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
8bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita#include "Sk4fLinearGradient.h"
9bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
10bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitanamespace {
11bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
12bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSk4f premul_4f(const Sk4f& c) {
13bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const float alpha = c[SkPM4f::A];
14bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    // FIXME: portable swizzle?
15bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return c * Sk4f(alpha, alpha, alpha, 1);
16bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
17bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
18bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate <bool do_premul>
19bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkPMColor trunc_from_255(const Sk4f& c) {
20bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkPMColor pmc;
21bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkNx_cast<uint8_t>(c).store(&pmc);
22bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    if (do_premul) {
23bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc),
24bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                SkGetPackedG32(pmc), SkGetPackedB32(pmc));
25bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
26bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return pmc;
27bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
28bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
29bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul>
30bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid fill(const Sk4f& c, DstType* dst, int n);
31bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
32bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
33bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) {
34bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    while (n > 0) {
35bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c.store(dst++);
36bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        n--;
37bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
38bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
39bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
40bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
41bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) {
42bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    fill<SkPM4f, false>(premul_4f(c), dst, n);
43bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
44bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
45bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
46bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) {
47bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    sk_memset32(dst, trunc_from_255<false>(c), n);
48bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
49bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
50bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
51bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) {
52bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    sk_memset32(dst, trunc_from_255<true>(c), n);
53bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
54bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
55bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul>
56bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store(const Sk4f& color, DstType* dst);
57bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
58bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
59bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store<SkPM4f, false>(const Sk4f& c, SkPM4f* dst) {
60bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    c.store(dst);
61bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
62bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
63bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
64bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store<SkPM4f, true>(const Sk4f& c, SkPM4f* dst) {
65bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    store<SkPM4f, false>(premul_4f(c), dst);
66bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
67bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
68bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
69bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store<SkPMColor, false>(const Sk4f& c, SkPMColor* dst) {
70bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    *dst = trunc_from_255<false>(c);
71bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
72bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
73bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
74bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store<SkPMColor, true>(const Sk4f& c, SkPMColor* dst) {
75bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    *dst = trunc_from_255<true>(c);
76bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
77bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
78bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul>
79bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store4x(const Sk4f& c0,
80bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita             const Sk4f& c1,
81bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita             const Sk4f& c2,
82bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita             const Sk4f& c3,
83bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita             DstType* dst) {
84bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    store<DstType, do_premul>(c0, dst++);
85bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    store<DstType, do_premul>(c1, dst++);
86bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    store<DstType, do_premul>(c2, dst++);
87bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    store<DstType, do_premul>(c3, dst++);
88bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
89bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
90bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
91bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid store4x<SkPMColor, false>(const Sk4f& c0,
92bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                               const Sk4f& c1,
93bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                               const Sk4f& c2,
94bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                               const Sk4f& c3,
95bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                               SkPMColor* dst) {
96bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
97bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
98bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
99bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul>
100bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) {
101bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkASSERT(n > 0);
102bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
103bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Sk4f dc2 = dc + dc;
104bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Sk4f dc4 = dc2 + dc2;
105bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
106bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f c0 = c ;
107bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f c1 = c + dc;
108bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f c2 = c0 + dc2;
109bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f c3 = c1 + dc2;
110bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
111bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    while (n >= 4) {
112bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        store4x<DstType, do_premul>(c0, c1, c2, c3, dst);
113bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        dst += 4;
114bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
115bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c0 = c0 + dc4;
116bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c1 = c1 + dc4;
117bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c2 = c2 + dc4;
118bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c3 = c3 + dc4;
119bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        n -= 4;
120bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
121bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    if (n & 2) {
122bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        store<DstType, do_premul>(c0, dst++);
123bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        store<DstType, do_premul>(c1, dst++);
124bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        c0 = c0 + dc2;
125bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
126bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    if (n & 1) {
127bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        store<DstType, do_premul>(c0, dst);
128bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
129bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
130bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
131bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<SkShader::TileMode>
132bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkScalar pinFx(SkScalar);
133bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
134bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
135bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) {
136bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return fx;
137bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
138bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
139bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
140bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkScalar pinFx<SkShader::kRepeat_TileMode>(SkScalar fx) {
141bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkScalar f = SkScalarFraction(fx);
142bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return f < 0 ? f + 1 : f;
143bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
144bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
145bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
146bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
147bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkScalar f = SkScalarMod(fx, 2.0f);
148bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return f < 0 ? f + 2 : f;
149bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
150bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
151bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType>
152bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitafloat dst_component_scale();
153bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
154bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
155bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitafloat dst_component_scale<SkPM4f>() {
156bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return 1;
157bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
158bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
159bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<>
160bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitafloat dst_component_scale<SkPMColor>() {
161bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    return 255;
162bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
163bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
164bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita} // anonymous namespace
165bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
166bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaSkLinearGradient::
167bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
168bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                 const ContextRec& rec)
169bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    : INHERITED(shader, rec) {}
170bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
171bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid SkLinearGradient::
172bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
173bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    // TODO: plumb dithering
174bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkASSERT(count > 0);
175bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    if (fColorsArePremul) {
176bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadePremulSpan<SkPMColor, false>(x, y, dst, count);
177bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    } else {
178bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadePremulSpan<SkPMColor, true>(x, y, dst, count);
179bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
180bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
181bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
182bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid SkLinearGradient::
183bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
184bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    // TONOTDO: plumb dithering
185bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkASSERT(count > 0);
186bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    if (fColorsArePremul) {
187bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadePremulSpan<SkPM4f, false>(x, y, dst, count);
188bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    } else {
189bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadePremulSpan<SkPM4f, true>(x, y, dst, count);
190bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
191bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
192bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
193bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul>
194bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid SkLinearGradient::
195bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::shadePremulSpan(int x, int y,
196bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                         DstType dst[],
197bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                         int count) const {
198bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkLinearGradient& shader =
199bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        static_cast<const SkLinearGradient&>(fShader);
200bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    switch (shader.fTileMode) {
201bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    case kClamp_TileMode:
202bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadeSpanInternal<DstType,
203bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                do_premul,
204bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                kClamp_TileMode>(x, y, dst, count);
205bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        break;
206bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    case kRepeat_TileMode:
207bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadeSpanInternal<DstType,
208bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                do_premul,
209bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                kRepeat_TileMode>(x, y, dst, count);
210bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        break;
211bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    case kMirror_TileMode:
212bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->shadeSpanInternal<DstType,
213bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                do_premul,
214bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                kMirror_TileMode>(x, y, dst, count);
215bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        break;
216bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
217bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
218bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
219bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, bool do_premul, SkShader::TileMode tileMode>
220bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitavoid SkLinearGradient::
221bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::shadeSpanInternal(int x, int y,
222bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                           DstType dst[],
223bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                           int count) const {
224bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkPoint pt;
225bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    fDstToPosProc(fDstToPos,
226bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                  x + SK_ScalarHalf,
227bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                  y + SK_ScalarHalf,
228bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                  &pt);
229bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkScalar fx = pinFx<tileMode>(pt.x());
230bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkScalar dx = fDstToPos.getScaleX();
231bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    LinearIntervalProcessor<DstType, tileMode> proc(fIntervals.begin(),
232bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                    fIntervals.end() - 1,
233bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                    this->findInterval(fx),
234bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                    fx,
235bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                    dx,
236bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                                    SkScalarNearlyZero(dx * count));
237bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    while (count > 0) {
238bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        // What we really want here is SkTPin(advance, 1, count)
239bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        // but that's a significant perf hit for >> stops; investigate.
240bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        const int n = SkScalarTruncToInt(
241bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count)));
242bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
243bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        // The current interval advance can be +inf (e.g. when reaching
244bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        // the clamp mode end intervals) - when that happens, we expect to
245bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        //   a) consume all remaining count in one swoop
246bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        //   b) return a zero color gradient
247bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(SkScalarIsFinite(proc.currentAdvance())
248bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            || (n == count && proc.currentRampIsZero()));
249bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
250bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        if (proc.currentRampIsZero()) {
251bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            fill<DstType, do_premul>(proc.currentColor(),
252bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                     dst, n);
253bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        } else {
254bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            ramp<DstType, do_premul>(proc.currentColor(),
255bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                     proc.currentColorGrad(),
256bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                                     dst, n);
257bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        }
258bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
259bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        proc.advance(SkIntToScalar(n));
260bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        count -= n;
261bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        dst   += n;
262bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
263bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita}
264bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
265bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitatemplate<typename DstType, SkShader::TileMode tileMode>
266bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaclass SkLinearGradient::
267bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaLinearGradient4fContext::LinearIntervalProcessor {
268bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitapublic:
269bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    LinearIntervalProcessor(const Interval* firstInterval,
270bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                            const Interval* lastInterval,
271bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                            const Interval* i,
272bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                            SkScalar fx,
273bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                            SkScalar dx,
274bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita                            bool is_vertical)
275bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        : fDstComponentScale(dst_component_scale<DstType>())
276bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fAdvX((i->fP1 - fx) / dx)
277bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fFirstInterval(firstInterval)
278bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fLastInterval(lastInterval)
279bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fInterval(i)
280bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fDx(dx)
281bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        , fIsVertical(is_vertical)
282bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    {
283bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(firstInterval <= lastInterval);
284bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(i->contains(fx));
285bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        this->compute_interval_props(fx - i->fP0);
286bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
287bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
288bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkScalar currentAdvance() const {
289bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(fAdvX >= 0);
290bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx);
291bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        return fAdvX;
292bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
293bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
294bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    bool currentRampIsZero() const { return fZeroRamp; }
295bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Sk4f& currentColor() const { return fCc; }
296bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Sk4f& currentColorGrad() const { return fDcDx; }
297bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
298bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    void advance(SkScalar advX) {
299bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(advX > 0);
300bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(fAdvX >= 0);
301bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
302bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        if (advX >= fAdvX) {
303bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            advX = this->advance_interval(advX);
304bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        }
305bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(advX < fAdvX);
306bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
307bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fCc = fCc + fDcDx * Sk4f(advX);
308bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fAdvX -= advX;
309bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
310bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
311bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalitaprivate:
312bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    void compute_interval_props(SkScalar t) {
313bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fDc   = Sk4f::Load(fInterval->fDc.fVec);
314bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fCc   = Sk4f::Load(fInterval->fC0.fVec);
315bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fCc   = fCc + fDc * Sk4f(t);
316bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fCc   = fCc * fDstComponentScale;
317bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fDcDx = fDc * fDstComponentScale * Sk4f(fDx);
318bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        fZeroRamp = fIsVertical || fInterval->isZeroRamp();
319bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
320bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
321bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Interval* next_interval(const Interval* i) const {
322bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(i >= fFirstInterval);
323bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(i <= fLastInterval);
324bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        i++;
325bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
326bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        if (tileMode == kClamp_TileMode) {
327bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            SkASSERT(i <= fLastInterval);
328bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            return i;
329bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        }
330bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
331bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        return (i <= fLastInterval) ? i : fFirstInterval;
332bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
333bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
334bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkScalar advance_interval(SkScalar advX) {
335bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(advX >= fAdvX);
336bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
337bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        do {
338bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            advX -= fAdvX;
339bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            fInterval = this->next_interval(fInterval);
340bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            fAdvX = (fInterval->fP1 - fInterval->fP0) / fDx;
341bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita            SkASSERT(fAdvX > 0);
342bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        } while (advX >= fAdvX);
343bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
344bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        compute_interval_props(0);
345bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
346bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        SkASSERT(advX >= 0);
347bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita        return advX;
348bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    }
349bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
350bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Sk4f      fDstComponentScale; // cached dst scale (PMC: 255, PM4f: 1)
351bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
352bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    // Current interval properties.
353bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f            fDc;        // local color gradient (dc/dt)
354bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f            fDcDx;      // dst color gradient (dc/dx)
355bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    Sk4f            fCc;        // current color, interpolated in dst
356bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    SkScalar        fAdvX;      // remaining interval advance in dst
357bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    bool            fZeroRamp;  // current interval color grad is 0
358bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita
359bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Interval* fFirstInterval;
360bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Interval* fLastInterval;
361bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const Interval* fInterval;  // current interval
362bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const SkScalar  fDx;        // 'dx' for consistency with other impls; actually dt/dx
363bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita    const bool      fIsVertical;
364bc590c01b00ef79e1e1f30058e7a70a29419f2a9fmalita};
365