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