Flutter Engine Uber Docs
Docs for the entire Flutter Engine repo.
 
Loading...
Searching...
No Matches
color.cc
Go to the documentation of this file.
1// Copyright 2013 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
6
7#include <algorithm>
8#include <cmath>
9#include <functional>
10#include <type_traits>
11
15
16namespace impeller {
17
18#define _IMPELLER_ASSERT_BLEND_MODE(blend_mode) \
19 auto enum_##blend_mode = static_cast<std::underlying_type_t<BlendMode>>( \
20 BlendMode::k##blend_mode); \
21 if (i != enum_##blend_mode) { \
22 return false; \
23 } \
24 ++i;
25
26static constexpr inline bool ValidateBlendModes() {
27 std::underlying_type_t<BlendMode> i = 0;
28 // Ensure the order of the blend modes match.
30 // Ensure the total number of blend modes match.
31 if (i - 1 !=
32 static_cast<std::underlying_type_t<BlendMode>>(BlendMode::kLastMode)) {
33 return false;
34 }
35 return true;
36}
37static_assert(ValidateBlendModes(),
38 "IMPELLER_FOR_EACH_BLEND_MODE must match impeller::BlendMode.");
39
40#define _IMPELLER_BLEND_MODE_NAME_LIST(blend_mode) #blend_mode,
41
44
45const char* BlendModeToString(BlendMode blend_mode) {
46 return kBlendModeNames[static_cast<std::underlying_type_t<BlendMode>>(
47 blend_mode)];
48}
49
50Color::Color(const Vector4& value)
51 : red(value.x), green(value.y), blue(value.z), alpha(value.w) {}
52
53static constexpr inline Color Min(Color c, float threshold) {
54 return Color(std::min(c.red, threshold), std::min(c.green, threshold),
55 std::min(c.blue, threshold), std::min(c.alpha, threshold));
56}
57
58// The following HSV utilities correspond to the W3C blend definitions
59// implemented in: impeller/compiler/shader_lib/impeller/blending.glsl
60
61static constexpr inline Scalar Luminosity(Vector3 color) {
62 return color.x * 0.3f + color.y * 0.59f + color.z * 0.11f;
63}
64
65static constexpr inline Vector3 ClipColor(Vector3 color) {
66 Scalar lum = Luminosity(color);
67 Scalar mn = std::min(std::min(color.x, color.y), color.z);
68 Scalar mx = std::max(std::max(color.x, color.y), color.z);
69 // `lum - mn` and `mx - lum` will always be >= 0 in the following conditions,
70 // so adding a tiny value is enough to make these divisions safe.
71 if (mn < 0.0f) {
72 color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough));
73 }
74 if (mx > 1.0) {
75 color =
76 lum + (((color - lum) * (1.0f - lum)) / (mx - lum + kEhCloseEnough));
77 }
78 return color;
79}
80
81static constexpr inline Vector3 SetLuminosity(Vector3 color,
82 Scalar luminosity) {
83 Scalar relative_lum = luminosity - Luminosity(color);
84 return ClipColor(color + relative_lum);
85}
86
87static constexpr inline Scalar Saturation(Vector3 color) {
88 return std::max(std::max(color.x, color.y), color.z) -
89 std::min(std::min(color.x, color.y), color.z);
90}
91
92static constexpr inline Vector3 SetSaturation(Vector3 color,
93 Scalar saturation) {
94 Scalar mn = std::min(std::min(color.x, color.y), color.z);
95 Scalar mx = std::max(std::max(color.x, color.y), color.z);
96 return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : Vector3();
97}
98
99static constexpr inline Vector3 ComponentChoose(Vector3 a,
100 Vector3 b,
101 Vector3 value,
102 Scalar cutoff) {
103 return Vector3(value.x > cutoff ? b.x : a.x, //
104 value.y > cutoff ? b.y : a.y, //
105 value.z > cutoff ? b.z : a.z //
106 );
107}
108
109static constexpr inline Vector3 ToRGB(Color color) {
110 return {color.red, color.green, color.blue};
111}
112
113static constexpr inline Color FromRGB(Vector3 color, Scalar alpha) {
114 return {color.x, color.y, color.z, alpha};
115}
116
117/// Composite a blended color onto the destination.
118/// All three parameters are unpremultiplied. Returns a premultiplied result.
119///
120/// This routine is the same as `IPApplyBlendedColor` in the Impeller shader
121/// library.
122static constexpr inline Color ApplyBlendedColor(Color dst,
123 Color src,
124 Vector3 blend_result) {
125 dst = dst.Premultiply();
126 src =
127 // Use the blended color for areas where the source and destination
128 // colors overlap.
129 FromRGB(blend_result, src.alpha * dst.alpha).Premultiply() +
130 // Use the original source color for any remaining non-overlapping areas.
131 src.Premultiply() * (1.0f - dst.alpha);
132
133 // Source-over composite the blended source color atop the destination.
134 return src + dst * (1.0f - src.alpha);
135}
136
137static inline Color DoColorBlend(
138 Color dst,
139 Color src,
140 const std::function<Vector3(Vector3, Vector3)>& blend_rgb_func) {
141 const Vector3 blend_result = blend_rgb_func(ToRGB(dst), ToRGB(src));
142 return ApplyBlendedColor(dst, src, blend_result).Unpremultiply();
143}
144
146 Color dst,
147 Color src,
148 const std::function<Scalar(Scalar, Scalar)>& blend_func) {
149 Vector3 blend_result = Vector3(blend_func(dst.red, src.red), //
150 blend_func(dst.green, src.green), //
151 blend_func(dst.blue, src.blue)); //
152 return ApplyBlendedColor(dst, src, blend_result).Unpremultiply();
153}
154
155Color Color::Blend(Color src, BlendMode blend_mode) const {
156 Color dst = *this;
157
158 switch (blend_mode) {
161 case BlendMode::kSrc:
162 return src;
163 case BlendMode::kDst:
164 return dst;
166 // r = s + (1-sa)*d
167 return (src.Premultiply() + dst.Premultiply() * (1 - src.alpha))
168 .Unpremultiply();
170 // r = d + (1-da)*s
171 return (dst.Premultiply() + src.Premultiply() * (1 - dst.alpha))
172 .Unpremultiply();
174 // r = s * da
175 return (src.Premultiply() * dst.alpha).Unpremultiply();
177 // r = d * sa
178 return (dst.Premultiply() * src.alpha).Unpremultiply();
180 // r = s * ( 1- da)
181 return (src.Premultiply() * (1 - dst.alpha)).Unpremultiply();
183 // r = d * (1-sa)
184 return (dst.Premultiply() * (1 - src.alpha)).Unpremultiply();
186 // r = s*da + d*(1-sa)
187 return (src.Premultiply() * dst.alpha +
188 dst.Premultiply() * (1 - src.alpha))
189 .Unpremultiply();
191 // r = d*sa + s*(1-da)
192 return (dst.Premultiply() * src.alpha +
193 src.Premultiply() * (1 - dst.alpha))
194 .Unpremultiply();
195 case BlendMode::kXor:
196 // r = s*(1-da) + d*(1-sa)
197 return (src.Premultiply() * (1 - dst.alpha) +
198 dst.Premultiply() * (1 - src.alpha))
199 .Unpremultiply();
200 case BlendMode::kPlus:
201 // r = min(s + d, 1)
202 return (Min(src.Premultiply() + dst.Premultiply(), 1)).Unpremultiply();
204 // r = s*d
205 return (src.Premultiply() * dst.Premultiply()).Unpremultiply();
206 case BlendMode::kScreen: {
207 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
208 return s + d - s * d;
209 });
210 }
212 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
213 // The same as HardLight, but with the source and destination reversed.
214 Vector3 screen_src = 2.0 * d - 1.0;
215 Vector3 screen = screen_src + s - screen_src * s;
216 return ComponentChoose(s * (2.0 * d), //
217 screen, //
218 d, //
219 0.5);
220 });
222 return DoColorBlend(
223 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Min(s); });
225 return DoColorBlend(
226 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Max(s); });
228 return DoColorBlendComponents(dst, src, [](Scalar d, Scalar s) -> Scalar {
229 if (d < kEhCloseEnough) {
230 return 0.0f;
231 }
232 if (1.0 - s < kEhCloseEnough) {
233 return 1.0f;
234 }
235 return std::min(1.0f, d / (1.0f - s));
236 });
238 return DoColorBlendComponents(dst, src, [](Scalar d, Scalar s) -> Scalar {
239 if (1.0 - d < kEhCloseEnough) {
240 return 1.0f;
241 }
242 if (s < kEhCloseEnough) {
243 return 0.0f;
244 }
245 return 1.0f - std::min(1.0f, (1.0f - d) / s);
246 });
248 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
249 Vector3 screen_src = 2.0 * s - 1.0;
250 Vector3 screen = screen_src + d - screen_src * d;
251 return ComponentChoose(d * (2.0 * s), //
252 screen, //
253 s, //
254 0.5);
255 });
257 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
258 Vector3 D = ComponentChoose(((16.0 * d - 12.0) * d + 4.0) * d, //
259 Vector3(std::sqrt(d.x), std::sqrt(d.y),
260 std::sqrt(d.z)), //
261 d, //
262 0.25);
263 return ComponentChoose(d - (1.0 - 2.0 * s) * d * (1.0 - d), //
264 d + (2.0 * s - 1.0) * (D - d), //
265 s, //
266 0.5);
267 });
269 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
270 return (d - s).Abs();
271 });
273 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
274 return d + s - 2.0f * d * s;
275 });
277 return DoColorBlend(
278 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d * s; });
279 case BlendMode::kHue: {
280 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
282 });
283 }
285 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
287 });
289 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
290 return SetLuminosity(s, Luminosity(d));
291 });
293 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
294 return SetLuminosity(d, Luminosity(s));
295 });
296 }
297}
298
299Color Color::ApplyColorMatrix(const ColorMatrix& color_matrix) const {
300 auto* c = color_matrix.array;
301 return Color(
302 c[0] * red + c[1] * green + c[2] * blue + c[3] * alpha + c[4],
303 c[5] * red + c[6] * green + c[7] * blue + c[8] * alpha + c[9],
304 c[10] * red + c[11] * green + c[12] * blue + c[13] * alpha + c[14],
305 c[15] * red + c[16] * green + c[17] * blue + c[18] * alpha + c[19])
306 .Clamp01();
307}
308
310 static auto conversion = [](Scalar component) {
311 if (component <= 0.0031308) {
312 return component * 12.92;
313 }
314 return 1.055 * pow(component, (1.0 / 2.4)) - 0.055;
315 };
316
317 return Color(conversion(red), conversion(green), conversion(blue), alpha);
318}
319
321 static auto conversion = [](Scalar component) {
322 if (component <= 0.04045) {
323 return component / 12.92;
324 }
325 return pow((component + 0.055) / 1.055, 2.4);
326 };
327
328 return Color(conversion(red), conversion(green), conversion(blue), alpha);
329}
330
331} // namespace impeller
#define _IMPELLER_ASSERT_BLEND_MODE(blend_mode)
Definition color.cc:18
#define _IMPELLER_BLEND_MODE_NAME_LIST(blend_mode)
Definition color.cc:40
#define IMPELLER_FOR_EACH_BLEND_MODE(V)
Definition color.h:19
int32_t value
int32_t x
auto & d
Definition main.cc:28
double y
static constexpr const char * kBlendModeNames[]
Definition color.cc:42
static constexpr Color Min(Color c, float threshold)
Definition color.cc:53
static constexpr bool ValidateBlendModes()
Definition color.cc:26
static constexpr Vector3 SetSaturation(Vector3 color, Scalar saturation)
Definition color.cc:92
float Scalar
Definition scalar.h:19
static Color DoColorBlendComponents(Color dst, Color src, const std::function< Scalar(Scalar, Scalar)> &blend_func)
Definition color.cc:145
constexpr float kEhCloseEnough
Definition constants.h:57
static constexpr Scalar Saturation(Vector3 color)
Definition color.cc:87
static constexpr Vector3 ToRGB(Color color)
Definition color.cc:109
const char * BlendModeToString(BlendMode blend_mode)
Definition color.cc:45
static constexpr Color FromRGB(Vector3 color, Scalar alpha)
Definition color.cc:113
static constexpr Vector3 SetLuminosity(Vector3 color, Scalar luminosity)
Definition color.cc:81
static constexpr Color ApplyBlendedColor(Color dst, Color src, Vector3 blend_result)
Definition color.cc:122
BlendMode
Definition color.h:58
static Color DoColorBlend(Color dst, Color src, const std::function< Vector3(Vector3, Vector3)> &blend_rgb_func)
Definition color.cc:137
static constexpr Vector3 ComponentChoose(Vector3 a, Vector3 b, Vector3 value, Scalar cutoff)
Definition color.cc:99
static constexpr Vector3 ClipColor(Vector3 color)
Definition color.cc:65
static constexpr Scalar Luminosity(Vector3 color)
Definition color.cc:61
Scalar blue
Definition color.h:138
static constexpr Color BlackTransparent()
Definition color.h:275
Scalar alpha
Definition color.h:143
Color LinearToSRGB() const
Convert the color from linear space to sRGB space.
Definition color.cc:309
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
Definition color.cc:299
Scalar red
Definition color.h:128
constexpr Color Unpremultiply() const
Definition color.h:216
constexpr Color()
Definition color.h:145
Scalar green
Definition color.h:133
constexpr Color Premultiply() const
Definition color.h:212
Color SRGBToLinear() const
Convert the color from sRGB space to linear space.
Definition color.cc:320
Color Blend(Color source, BlendMode blend_mode) const
Blends an unpremultiplied destination color into a given unpremultiplied source color to form a new u...
Definition color.cc:155
Scalar array[20]
Definition color.h:118
Vector3 Min(const Vector3 &p) const
Definition vector.h:70
Vector3 Max(const Vector3 &p) const
Definition vector.h:74