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 GrSwizzle_DEFINED
9 #define GrSwizzle_DEFINED
10
11 #include "include/core/SkString.h"
12 #include "include/private/SkColorData.h"
13 #include "src/gpu/GrColor.h"
14
15 class SkRasterPipeline;
16
17 /** Represents a rgba swizzle. It can be converted either into a string or a eight bit int. */
18 class GrSwizzle {
19 public:
GrSwizzle()20 constexpr GrSwizzle() : GrSwizzle("rgba") {}
21 explicit constexpr GrSwizzle(const char c[4]);
22
23 constexpr GrSwizzle(const GrSwizzle&);
24 constexpr GrSwizzle& operator=(const GrSwizzle& that);
25
26 static constexpr GrSwizzle Concat(const GrSwizzle& a, const GrSwizzle& b);
27
28 constexpr bool operator==(const GrSwizzle& that) const { return fKey == that.fKey; }
29 constexpr bool operator!=(const GrSwizzle& that) const { return !(*this == that); }
30
31 /** Compact representation of the swizzle suitable for a key. */
asKey()32 constexpr uint16_t asKey() const { return fKey; }
33
34 /** 4 char null terminated string consisting only of chars 'r', 'g', 'b', 'a', '0', and '1'. */
35 SkString asString() const;
36
37 constexpr char operator[](int i) const {
38 SkASSERT(i >= 0 && i < 4);
39 int idx = (fKey >> (4U * i)) & 0xfU;
40 return IToC(idx);
41 }
42
43 /** Applies this swizzle to the input color and returns the swizzled color. */
44 constexpr std::array<float, 4> applyTo(std::array<float, 4> color) const;
45
46 /** Convenience version for SkRGBA colors. */
47 template <SkAlphaType AlphaType>
applyTo(SkRGBA4f<AlphaType> color)48 constexpr SkRGBA4f<AlphaType> applyTo(SkRGBA4f<AlphaType> color) const {
49 std::array<float, 4> result = this->applyTo(color.array());
50 return {result[0], result[1], result[2], result[3]};
51 }
52
53 void apply(SkRasterPipeline*) const;
54
RGBA()55 static constexpr GrSwizzle RGBA() { return GrSwizzle("rgba"); }
BGRA()56 static constexpr GrSwizzle BGRA() { return GrSwizzle("bgra"); }
RRRA()57 static constexpr GrSwizzle RRRA() { return GrSwizzle("rrra"); }
RGB1()58 static constexpr GrSwizzle RGB1() { return GrSwizzle("rgb1"); }
59
60 private:
GrSwizzle(uint16_t key)61 explicit constexpr GrSwizzle(uint16_t key) : fKey(key) {}
62
63 static constexpr float ComponentIndexToFloat(std::array<float, 4>, int idx);
64 static constexpr int CToI(char c);
65 static constexpr char IToC(int idx);
66
67 uint16_t fKey;
68 };
69
GrSwizzle(const char c[4])70 constexpr GrSwizzle::GrSwizzle(const char c[4])
71 : fKey((CToI(c[0]) << 0) | (CToI(c[1]) << 4) | (CToI(c[2]) << 8) | (CToI(c[3]) << 12)) {}
72
GrSwizzle(const GrSwizzle & that)73 constexpr GrSwizzle::GrSwizzle(const GrSwizzle& that)
74 : fKey(that.fKey) {}
75
76 constexpr GrSwizzle& GrSwizzle::operator=(const GrSwizzle& that) {
77 fKey = that.fKey;
78 return *this;
79 }
80
applyTo(std::array<float,4> color)81 constexpr std::array<float, 4> GrSwizzle::applyTo(std::array<float, 4> color) const {
82 uint32_t key = fKey;
83 // Index of the input color that should be mapped to output r.
84 int idx = (key & 15);
85 float outR = ComponentIndexToFloat(color, idx);
86 key >>= 4;
87 idx = (key & 15);
88 float outG = ComponentIndexToFloat(color, idx);
89 key >>= 4;
90 idx = (key & 15);
91 float outB = ComponentIndexToFloat(color, idx);
92 key >>= 4;
93 idx = (key & 15);
94 float outA = ComponentIndexToFloat(color, idx);
95 return { outR, outG, outB, outA };
96 }
97
ComponentIndexToFloat(std::array<float,4> color,int idx)98 constexpr float GrSwizzle::ComponentIndexToFloat(std::array<float, 4> color, int idx) {
99 if (idx <= 3) {
100 return color[idx];
101 }
102 if (idx == CToI('1')) {
103 return 1.0f;
104 }
105 if (idx == CToI('0')) {
106 return 0.0f;
107 }
108 SkUNREACHABLE;
109 }
110
CToI(char c)111 constexpr int GrSwizzle::CToI(char c) {
112 switch (c) {
113 // r...a must map to 0...3 because other methods use them as indices into fSwiz.
114 case 'r': return 0;
115 case 'g': return 1;
116 case 'b': return 2;
117 case 'a': return 3;
118 case '0': return 4;
119 case '1': return 5;
120 default: SkUNREACHABLE;
121 }
122 }
123
IToC(int idx)124 constexpr char GrSwizzle::IToC(int idx) {
125 switch (idx) {
126 case CToI('r'): return 'r';
127 case CToI('g'): return 'g';
128 case CToI('b'): return 'b';
129 case CToI('a'): return 'a';
130 case CToI('0'): return '0';
131 case CToI('1'): return '1';
132 default: SkUNREACHABLE;
133 }
134 }
135
Concat(const GrSwizzle & a,const GrSwizzle & b)136 constexpr GrSwizzle GrSwizzle::Concat(const GrSwizzle& a, const GrSwizzle& b) {
137 uint16_t key = 0;
138 for (int i = 0; i < 4; ++i) {
139 int idx = (b.fKey >> (4U * i)) & 0xfU;
140 if (idx != CToI('0') && idx != CToI('1')) {
141 SkASSERT(idx >= 0 && idx < 4);
142 // Get the index value stored in a at location idx.
143 idx = ((a.fKey >> (4U * idx)) & 0xfU);
144 }
145 key |= (idx << (4U * i));
146 }
147 return GrSwizzle(key);
148 }
149 #endif
150