Update rive-cpp to 2.0 version
[platform/core/uifw/rive-tizen.git] / submodule / skia / src / shaders / gradients / Sk4fGradientBase.cpp
1 /*
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 "include/core/SkPaint.h"
9 #include "src/shaders/gradients/Sk4fGradientBase.h"
10 #include <functional>
11
12 namespace {
13
14 skvx::float4 pack_color(const SkColor4f& c4f, bool premul, const skvx::float4& component_scale) {
15     auto pm4f = premul ? skvx::float4::Load(c4f.premul().vec())
16                        : skvx::float4::Load(c4f.vec());
17
18     if (premul) {
19         // If the stops are premul, we clamp them to gamut now.
20         // If the stops are unpremul, the colors will eventually go through Sk4f_toL32(),
21         // which ends up clamping to gamut then.
22         pm4f = max(0, min(pm4f, pm4f[3]));
23     }
24
25     return pm4f * component_scale;
26 }
27
28 class IntervalIterator {
29 public:
30     IntervalIterator(const SkGradientShaderBase& shader, bool reverse)
31         : fShader(shader)
32         , fFirstPos(reverse ? SK_Scalar1 : 0)
33         , fBegin(reverse ? shader.fColorCount - 1 : 0)
34         , fAdvance(reverse ? -1 : 1) {
35         SkASSERT(shader.fColorCount > 0);
36     }
37
38     void iterate(const SkColor4f* colors,
39                  std::function<void(const SkColor4f&, const SkColor4f&,
40                                     SkScalar, SkScalar)> func) const {
41         if (!fShader.fOrigPos) {
42             this->iterateImplicitPos(colors, func);
43             return;
44         }
45
46         const int end = fBegin + fAdvance * (fShader.fColorCount - 1);
47         int prev = fBegin;
48         SkScalar prevPos = fFirstPos;
49
50         do {
51             const int curr = prev + fAdvance;
52             SkASSERT(curr >= 0 && curr < fShader.fColorCount);
53
54             const SkScalar currPos = fShader.fOrigPos[curr];
55             if (currPos != prevPos) {
56                 SkASSERT((currPos > prevPos) == (fAdvance > 0));
57                 func(colors[prev], colors[curr], prevPos, currPos);
58             }
59
60             prev = curr;
61             prevPos = currPos;
62         } while (prev != end);
63     }
64
65 private:
66     void iterateImplicitPos(const SkColor4f* colors,
67                             std::function<void(const SkColor4f&, const SkColor4f&,
68                                                SkScalar, SkScalar)> func) const {
69         // When clients don't provide explicit color stop positions (fPos == nullptr),
70         // the color stops are distributed evenly across the unit interval
71         // (implicit positioning).
72         const SkScalar dt = fAdvance * SK_Scalar1 / (fShader.fColorCount - 1);
73         const int end = fBegin + fAdvance * (fShader.fColorCount - 2);
74         int prev = fBegin;
75         SkScalar prevPos = fFirstPos;
76
77         while (prev != end) {
78             const int curr = prev + fAdvance;
79             SkASSERT(curr >= 0 && curr < fShader.fColorCount);
80
81             const SkScalar currPos = prevPos + dt;
82             func(colors[prev], colors[curr], prevPos, currPos);
83             prev = curr;
84             prevPos = currPos;
85         }
86
87         // emit the last interval with a pinned end position, to avoid precision issues
88         func(colors[prev], colors[prev + fAdvance], prevPos, 1 - fFirstPos);
89     }
90
91     const SkGradientShaderBase& fShader;
92     const SkScalar              fFirstPos;
93     const int                   fBegin;
94     const int                   fAdvance;
95 };
96
97 void addMirrorIntervals(const SkGradientShaderBase& shader,
98                         const SkColor4f* colors,
99                         const skvx::float4& componentScale,
100                         bool premulColors, bool reverse,
101                         Sk4fGradientIntervalBuffer::BufferType* buffer) {
102     const IntervalIterator iter(shader, reverse);
103     iter.iterate(colors, [&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) {
104         SkASSERT(buffer->empty() || buffer->back().fT1 == 2 - t0);
105
106         const auto mirror_t0 = 2 - t0;
107         const auto mirror_t1 = 2 - t1;
108         // mirror_p1 & mirror_p1 may collapse for very small values - recheck to avoid
109         // triggering Interval asserts.
110         if (mirror_t0 != mirror_t1) {
111             buffer->emplace_back(pack_color(c0, premulColors, componentScale), mirror_t0,
112                                  pack_color(c1, premulColors, componentScale), mirror_t1);
113         }
114     });
115 }
116
117 } // anonymous namespace
118
119 Sk4fGradientInterval::Sk4fGradientInterval(const skvx::float4& c0, SkScalar t0,
120                                            const skvx::float4& c1, SkScalar t1)
121         : fT0(t0)
122         , fT1(t1) {
123     SkASSERT(t0 != t1);
124     // Either p0 or p1 can be (-)inf for synthetic clamp edge intervals.
125     SkASSERT(SkScalarIsFinite(t0) || SkScalarIsFinite(t1));
126
127     const auto dt = t1 - t0;
128
129     // Clamp edge intervals are always zero-ramp.
130     SkASSERT(SkScalarIsFinite(dt) || all(c0 == c1));
131     SkASSERT(SkScalarIsFinite(t0) || all(c0 == c1));
132     const auto   dc = SkScalarIsFinite(dt) ? (c1 - c0) / dt : 0;
133     const auto bias = c0 - (SkScalarIsFinite(t0) ? t0 * dc : 0);
134
135     bias.store(fCb.vec());
136     dc.store(fCg.vec());
137 }
138
139 void Sk4fGradientIntervalBuffer::init(const SkGradientShaderBase& shader, SkColorSpace* dstCS,
140                                       SkTileMode tileMode, bool premulColors,
141                                       SkScalar alpha, bool reverse) {
142     // The main job here is to build a specialized interval list: a different
143     // representation of the color stops data, optimized for efficient scan line
144     // access during shading.
145     //
146     //   [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1})
147     //
148     // The list may be inverted when requested (such that e.g. points are sorted
149     // in increasing x order when dx < 0).
150     //
151     // Note: the current representation duplicates pos data; we could refactor to
152     //       avoid this if interval storage size becomes a concern.
153     //
154     // Aside from reordering, we also perform two more pre-processing steps at
155     // this stage:
156     //
157     //   1) scale the color components depending on paint alpha and the requested
158     //      interpolation space (note: the interval color storage is SkPMColor4f, but
159     //      that doesn't necessarily mean the colors are premultiplied; that
160     //      property is tracked in fColorsArePremul)
161     //
162     //   2) inject synthetic intervals to support tiling.
163     //
164     //      * for kRepeat, no extra intervals are needed - the iterator just
165     //        wraps around at the end:
166     //
167     //          ->[P0,P1)->..[Pn-1,Pn)->
168     //
169     //      * for kClamp, we add two "infinite" intervals before/after:
170     //
171     //          [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf)
172     //
173     //        (the iterator should never run off the end in this mode)
174     //
175     //      * for kMirror, we extend the range to [0..2] and add a flipped
176     //        interval series - then the iterator operates just as in the
177     //        kRepeat case:
178     //
179     //          ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)->
180     //
181     // TODO: investigate collapsing intervals << 1px.
182
183     const auto count = shader.fColorCount;
184
185     SkASSERT(count > 0);
186
187     fIntervals.reset();
188
189     const skvx::float4 componentScale = premulColors ? skvx::float4(alpha)
190                                                      : skvx::float4(1.0f, 1.0f, 1.0f, alpha);
191     const int first_index = reverse ? count - 1 : 0;
192     const int last_index = count - 1 - first_index;
193     const SkScalar first_pos = reverse ? SK_Scalar1 : 0;
194     const SkScalar last_pos = SK_Scalar1 - first_pos;
195
196     // Transform all of the colors to destination color space
197     SkColor4fXformer xformedColors(shader.fOrigColors4f, count, shader.fColorSpace.get(), dstCS);
198
199     if (tileMode == SkTileMode::kClamp) {
200         // synthetic edge interval: -/+inf .. P0
201         const auto clamp_color = pack_color(xformedColors.fColors[first_index],
202                                             premulColors, componentScale);
203         const SkScalar clamp_pos = reverse ? SK_ScalarInfinity : SK_ScalarNegativeInfinity;
204         fIntervals.emplace_back(clamp_color, clamp_pos,
205                                 clamp_color, first_pos);
206     } else if (tileMode == SkTileMode::kMirror && reverse) {
207         // synthetic mirror intervals injected before main intervals: (2 .. 1]
208         addMirrorIntervals(shader, xformedColors.fColors, componentScale, premulColors, false,
209                            &fIntervals);
210     }
211
212     const IntervalIterator iter(shader, reverse);
213     iter.iterate(xformedColors.fColors,
214                  [&] (const SkColor4f& c0, const SkColor4f& c1, SkScalar t0, SkScalar t1) {
215         SkASSERT(fIntervals.empty() || fIntervals.back().fT1 == t0);
216
217         fIntervals.emplace_back(pack_color(c0, premulColors, componentScale), t0,
218                                 pack_color(c1, premulColors, componentScale), t1);
219     });
220
221     if (tileMode == SkTileMode::kClamp) {
222         // synthetic edge interval: Pn .. +/-inf
223         const auto clamp_color = pack_color(xformedColors.fColors[last_index],
224                                             premulColors, componentScale);
225         const SkScalar clamp_pos = reverse ? SK_ScalarNegativeInfinity : SK_ScalarInfinity;
226         fIntervals.emplace_back(clamp_color, last_pos,
227                                 clamp_color, clamp_pos);
228     } else if (tileMode == SkTileMode::kMirror && !reverse) {
229         // synthetic mirror intervals injected after main intervals: [1 .. 2)
230         addMirrorIntervals(shader, xformedColors.fColors, componentScale, premulColors, true,
231                            &fIntervals);
232     }
233 }
234
235 const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::find(SkScalar t) const {
236     // Binary search.
237     const auto* i0 = fIntervals.begin();
238     const auto* i1 = fIntervals.end() - 1;
239
240     while (i0 != i1) {
241         SkASSERT(i0 < i1);
242         SkASSERT(t >= i0->fT0 && t <= i1->fT1);
243
244         const auto* i = i0 + ((i1 - i0) >> 1);
245
246         if (t > i->fT1) {
247             i0 = i + 1;
248         } else {
249             i1 = i;
250         }
251     }
252
253     SkASSERT(i0->contains(t));
254     return i0;
255 }
256
257 const Sk4fGradientInterval* Sk4fGradientIntervalBuffer::findNext(
258     SkScalar t, const Sk4fGradientInterval* prev, bool increasing) const {
259
260     SkASSERT(!prev->contains(t));
261     SkASSERT(prev >= fIntervals.begin() && prev < fIntervals.end());
262     SkASSERT(t >= fIntervals.front().fT0 && t <= fIntervals.back().fT1);
263
264     const auto* i = prev;
265
266     // Use the |increasing| signal to figure which direction we should search for
267     // the next interval, then perform a linear search.
268     if (increasing) {
269         do {
270             i += 1;
271             if (i >= fIntervals.end()) {
272                 i = fIntervals.begin();
273             }
274         } while (!i->contains(t));
275     } else {
276         do {
277             i -= 1;
278             if (i < fIntervals.begin()) {
279                 i = fIntervals.end() - 1;
280             }
281         } while (!i->contains(t));
282     }
283
284     return i;
285 }
286
287 SkGradientShaderBase::
288 GradientShaderBase4fContext::GradientShaderBase4fContext(const SkGradientShaderBase& shader,
289                                                          const ContextRec& rec)
290     : INHERITED(shader, rec)
291     , fFlags(this->INHERITED::getFlags())
292     , fDither(rec.fPaintDither)
293 {
294     const SkMatrix& inverse = this->getTotalInverse();
295     fDstToPos.setConcat(shader.fPtsToUnit, inverse);
296     SkASSERT(!fDstToPos.hasPerspective());
297     fDstToPosProc = SkMatrixPriv::GetMapXYProc(fDstToPos);
298
299     if (shader.fColorsAreOpaque && this->getPaintAlpha() == SK_AlphaOPAQUE) {
300         fFlags |= kOpaqueAlpha_Flag;
301     }
302
303     fColorsArePremul =
304         (shader.fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag)
305         || shader.fColorsAreOpaque;
306 }
307
308 bool SkGradientShaderBase::
309 GradientShaderBase4fContext::isValid() const {
310     return fDstToPos.isFinite();
311 }