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 #ifndef Sk4fGradientPriv_DEFINED 9 #define Sk4fGradientPriv_DEFINED 10 11 #include "SkColor.h" 12 #include "SkColorData.h" 13 #include "SkHalf.h" 14 #include "SkImageInfo.h" 15 #include "SkNx.h" 16 #include "SkUtils.h" 17 18 // Templates shared by various 4f gradient flavors. 19 20 namespace { // NOLINT(google-build-namespaces) 21 22 enum class ApplyPremul { True, False }; 23 24 template <ApplyPremul> 25 struct PremulTraits; 26 27 template <> 28 struct PremulTraits<ApplyPremul::False> { 29 static Sk4f apply(const Sk4f& c) { return c; } 30 }; 31 32 template <> 33 struct PremulTraits<ApplyPremul::True> { 34 static Sk4f apply(const Sk4f& c) { 35 const float alpha = c[3]; 36 // FIXME: portable swizzle? 37 return c * Sk4f(alpha, alpha, alpha, 1); 38 } 39 }; 40 41 // Struct encapsulating various dest-dependent ops: 42 // 43 // - load() Load a SkPMColor4f value into Sk4f. Normally called once per interval 44 // advance. Also applies a scale and swizzle suitable for DstType. 45 // 46 // - store() Store one Sk4f to dest. Optionally handles premul, color space 47 // conversion, etc. 48 // 49 // - store(count) Store the Sk4f value repeatedly to dest, count times. 50 // 51 // - store4x() Store 4 Sk4f values to dest (opportunistic optimization). 52 // 53 54 template <ApplyPremul premul> 55 struct DstTraits { 56 using PM = PremulTraits<premul>; 57 58 // For L32, prescaling by 255 saves a per-pixel multiplication when premul is not needed. 59 static Sk4f load(const SkPMColor4f& c) { 60 Sk4f c4f = swizzle_rb_if_bgra(Sk4f::Load(c.vec())); 61 return premul == ApplyPremul::False 62 ? c4f * Sk4f(255) 63 : c4f; 64 } 65 66 static void store(const Sk4f& c, SkPMColor* dst, const Sk4f& bias) { 67 if (premul == ApplyPremul::False) { 68 // c is pre-scaled by 255 and pre-biased, just store. 69 SkNx_cast<uint8_t>(c).store(dst); 70 } else { 71 *dst = Sk4f_toL32(PM::apply(c) + bias); 72 } 73 } 74 75 static void store(const Sk4f& c, SkPMColor* dst, int n) { 76 SkPMColor pmc; 77 store(c, &pmc, Sk4f(0)); 78 sk_memset32(dst, pmc, n); 79 } 80 81 static void store4x(const Sk4f& c0, const Sk4f& c1, 82 const Sk4f& c2, const Sk4f& c3, 83 SkPMColor* dst, 84 const Sk4f& bias0, 85 const Sk4f& bias1) { 86 if (premul == ApplyPremul::False) { 87 // colors are pre-scaled and pre-biased. 88 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3); 89 } else { 90 store(c0, dst + 0, bias0); 91 store(c1, dst + 1, bias1); 92 store(c2, dst + 2, bias0); 93 store(c3, dst + 3, bias1); 94 } 95 } 96 97 static Sk4f pre_lerp_bias(const Sk4f& bias) { 98 // We can apply the bias before interpolation when the colors are premultiplied. 99 return premul == ApplyPremul::False ? bias : 0; 100 } 101 }; 102 103 } // anonymous namespace 104 105 #endif // Sk4fGradientPriv_DEFINED 106