Flutter Engine
The Flutter Engine
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 <sstream>
11#include <type_traits>
12
17
18namespace impeller {
19
20#define _IMPELLER_ASSERT_BLEND_MODE(blend_mode) \
21 auto enum_##blend_mode = static_cast<std::underlying_type_t<BlendMode>>( \
22 BlendMode::k##blend_mode); \
23 if (i != enum_##blend_mode) { \
24 return false; \
25 } \
26 ++i;
27
28static constexpr inline bool ValidateBlendModes() {
29 std::underlying_type_t<BlendMode> i = 0;
30 // Ensure the order of the blend modes match.
32 // Ensure the total number of blend modes match.
33 if (i - 1 !=
34 static_cast<std::underlying_type_t<BlendMode>>(BlendMode::kLast)) {
35 return false;
36 }
37 return true;
38}
39static_assert(ValidateBlendModes(),
40 "IMPELLER_FOR_EACH_BLEND_MODE must match impeller::BlendMode.");
41
42#define _IMPELLER_BLEND_MODE_NAME_LIST(blend_mode) #blend_mode,
43
44static constexpr const char* kBlendModeNames[] = {
46
47const char* BlendModeToString(BlendMode blend_mode) {
48 return kBlendModeNames[static_cast<std::underlying_type_t<BlendMode>>(
49 blend_mode)];
50}
51
53 Scalar R = rgb.red;
54 Scalar G = rgb.green;
55 Scalar B = rgb.blue;
56
57 Scalar v = 0.0;
58 Scalar x = 0.0;
59 Scalar f = 0.0;
60
61 int64_t i = 0;
62
63 x = fmin(R, G);
64 x = fmin(x, B);
65
66 v = fmax(R, G);
67 v = fmax(v, B);
68
69 if (v == x) {
70 return ColorHSB(0.0, 0.0, v, rgb.alpha);
71 }
72
73 f = (R == x) ? G - B : ((G == x) ? B - R : R - G);
74 i = (R == x) ? 3 : ((G == x) ? 5 : 1);
75
76 return ColorHSB(((i - f / (v - x)) / 6.0), (v - x) / v, v, rgb.alpha);
77}
78
80 Scalar h = hue * 6.0;
83
84 Scalar m = 0.0;
85 Scalar n = 0.0;
86 Scalar f = 0.0;
87
88 int64_t i = 0;
89
90 if (h == 0) {
91 h = 0.01;
92 }
93
94 if (h == 0.0) {
95 return Color(v, v, v, alpha);
96 }
97
98 i = static_cast<int64_t>(floor(h));
99
100 f = h - i;
101
102 if (!(i & 1)) {
103 f = 1 - f;
104 }
105
106 m = v * (1 - s);
107 n = v * (1 - s * f);
108
109 switch (i) {
110 case 6:
111 case 0:
112 return Color(v, n, m, alpha);
113 case 1:
114 return Color(n, v, m, alpha);
115 case 2:
116 return Color(m, v, n, alpha);
117 case 3:
118 return Color(m, n, v, alpha);
119 case 4:
120 return Color(n, m, v, alpha);
121 case 5:
122 return Color(v, m, n, alpha);
123 }
124 return Color(0, 0, 0, alpha);
125}
126
127Color::Color(const ColorHSB& hsbColor) : Color(hsbColor.ToRGBA()) {}
128
130 : red(value.x), green(value.y), blue(value.z), alpha(value.w) {}
131
132static constexpr inline Color Min(Color c, float threshold) {
133 return Color(std::min(c.red, threshold), std::min(c.green, threshold),
134 std::min(c.blue, threshold), std::min(c.alpha, threshold));
135}
136
137// The following HSV utilities correspond to the W3C blend definitions
138// implemented in: impeller/compiler/shader_lib/impeller/blending.glsl
139
140static constexpr inline Scalar Luminosity(Vector3 color) {
141 return color.x * 0.3f + color.y * 0.59f + color.z * 0.11f;
142}
143
144static constexpr inline Vector3 ClipColor(Vector3 color) {
146 Scalar mn = std::min(std::min(color.x, color.y), color.z);
147 Scalar mx = std::max(std::max(color.x, color.y), color.z);
148 // `lum - mn` and `mx - lum` will always be >= 0 in the following conditions,
149 // so adding a tiny value is enough to make these divisions safe.
150 if (mn < 0.0f) {
151 color = lum + (((color - lum) * lum) / (lum - mn + kEhCloseEnough));
152 }
153 if (mx > 1.0) {
154 color =
155 lum + (((color - lum) * (1.0f - lum)) / (mx - lum + kEhCloseEnough));
156 }
157 return color;
158}
159
160static constexpr inline Vector3 SetLuminosity(Vector3 color,
162 Scalar relative_lum = luminosity - Luminosity(color);
163 return ClipColor(color + relative_lum);
164}
165
166static constexpr inline Scalar Saturation(Vector3 color) {
167 return std::max(std::max(color.x, color.y), color.z) -
169}
170
171static constexpr inline Vector3 SetSaturation(Vector3 color,
173 Scalar mn = std::min(std::min(color.x, color.y), color.z);
174 Scalar mx = std::max(std::max(color.x, color.y), color.z);
175 return (mn < mx) ? ((color - mn) * saturation) / (mx - mn) : Vector3();
176}
177
178static constexpr inline Vector3 ComponentChoose(Vector3 a,
179 Vector3 b,
181 Scalar cutoff) {
182 return Vector3(value.x > cutoff ? b.x : a.x, //
183 value.y > cutoff ? b.y : a.y, //
184 value.z > cutoff ? b.z : a.z //
185 );
186}
187
188static constexpr inline Vector3 ToRGB(Color color) {
189 return {color.red, color.green, color.blue};
190}
191
192static constexpr inline Color FromRGB(Vector3 color, Scalar alpha) {
193 return {color.x, color.y, color.z, alpha};
194}
195
196/// Composite a blended color onto the destination.
197/// All three parameters are unpremultiplied. Returns a premultiplied result.
198///
199/// This routine is the same as `IPApplyBlendedColor` in the Impeller shader
200/// library.
201static constexpr inline Color ApplyBlendedColor(Color dst,
202 Color src,
203 Vector3 blend_result) {
204 dst = dst.Premultiply();
205 src =
206 // Use the blended color for areas where the source and destination
207 // colors overlap.
208 FromRGB(blend_result, src.alpha * dst.alpha).Premultiply() +
209 // Use the original source color for any remaining non-overlapping areas.
210 src.Premultiply() * (1.0f - dst.alpha);
211
212 // Source-over composite the blended source color atop the destination.
213 return src + dst * (1.0f - src.alpha);
214}
215
216static constexpr inline Color DoColorBlend(
217 Color dst,
218 Color src,
219 const std::function<Vector3(Vector3, Vector3)>& blend_rgb_func) {
220 const Vector3 blend_result = blend_rgb_func(ToRGB(dst), ToRGB(src));
221 return ApplyBlendedColor(dst, src, blend_result).Unpremultiply();
222}
223
224static constexpr inline Color DoColorBlendComponents(
225 Color dst,
226 Color src,
227 const std::function<Scalar(Scalar, Scalar)>& blend_func) {
228 Vector3 blend_result = Vector3(blend_func(dst.red, src.red), //
229 blend_func(dst.green, src.green), //
230 blend_func(dst.blue, src.blue)); //
231 return ApplyBlendedColor(dst, src, blend_result).Unpremultiply();
232}
233
235 Color dst = *this;
236
237 switch (blend_mode) {
241 return src;
243 return dst;
245 // r = s + (1-sa)*d
246 return (src.Premultiply() + dst.Premultiply() * (1 - src.alpha))
247 .Unpremultiply();
249 // r = d + (1-da)*s
250 return (dst.Premultiply() + src.Premultiply() * (1 - dst.alpha))
251 .Unpremultiply();
253 // r = s * da
254 return (src.Premultiply() * dst.alpha).Unpremultiply();
256 // r = d * sa
257 return (dst.Premultiply() * src.alpha).Unpremultiply();
259 // r = s * ( 1- da)
260 return (src.Premultiply() * (1 - dst.alpha)).Unpremultiply();
262 // r = d * (1-sa)
263 return (dst.Premultiply() * (1 - src.alpha)).Unpremultiply();
265 // r = s*da + d*(1-sa)
266 return (src.Premultiply() * dst.alpha +
267 dst.Premultiply() * (1 - src.alpha))
268 .Unpremultiply();
270 // r = d*sa + s*(1-da)
271 return (dst.Premultiply() * src.alpha +
272 src.Premultiply() * (1 - dst.alpha))
273 .Unpremultiply();
274 case BlendMode::kXor:
275 // r = s*(1-da) + d*(1-sa)
276 return (src.Premultiply() * (1 - dst.alpha) +
277 dst.Premultiply() * (1 - src.alpha))
278 .Unpremultiply();
279 case BlendMode::kPlus:
280 // r = min(s + d, 1)
281 return (Min(src.Premultiply() + dst.Premultiply(), 1)).Unpremultiply();
283 // r = s*d
284 return (src.Premultiply() * dst.Premultiply()).Unpremultiply();
285 case BlendMode::kScreen: {
286 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
287 return s + d - s * d;
288 });
289 }
291 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
292 // The same as HardLight, but with the source and destination reversed.
293 Vector3 screen_src = 2.0 * d - 1.0;
294 Vector3 screen = screen_src + s - screen_src * s;
295 return ComponentChoose(s * (2.0 * d), //
296 screen, //
297 d, //
298 0.5);
299 });
301 return DoColorBlend(
302 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Min(s); });
304 return DoColorBlend(
305 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d.Max(s); });
308 if (d < kEhCloseEnough) {
309 return 0.0f;
310 }
311 if (1.0 - s < kEhCloseEnough) {
312 return 1.0f;
313 }
314 return std::min(1.0f, d / (1.0f - s));
315 });
318 if (1.0 - d < kEhCloseEnough) {
319 return 1.0f;
320 }
321 if (s < kEhCloseEnough) {
322 return 0.0f;
323 }
324 return 1.0f - std::min(1.0f, (1.0f - d) / s);
325 });
327 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
328 Vector3 screen_src = 2.0 * s - 1.0;
329 Vector3 screen = screen_src + d - screen_src * d;
330 return ComponentChoose(d * (2.0 * s), //
331 screen, //
332 s, //
333 0.5);
334 });
336 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
337 Vector3 D = ComponentChoose(((16.0 * d - 12.0) * d + 4.0) * d, //
339 std::sqrt(d.z)), //
340 d, //
341 0.25);
342 return ComponentChoose(d - (1.0 - 2.0 * s) * d * (1.0 - d), //
343 d + (2.0 * s - 1.0) * (D - d), //
344 s, //
345 0.5);
346 });
348 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
349 return (d - s).Abs();
350 });
352 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
353 return d + s - 2.0f * d * s;
354 });
356 return DoColorBlend(
357 dst, src, [](Vector3 d, Vector3 s) -> Vector3 { return d * s; });
358 case BlendMode::kHue: {
359 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
361 });
362 }
364 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
366 });
368 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
369 return SetLuminosity(s, Luminosity(d));
370 });
372 return DoColorBlend(dst, src, [](Vector3 d, Vector3 s) -> Vector3 {
373 return SetLuminosity(d, Luminosity(s));
374 });
375 }
376}
377
378Color Color::ApplyColorMatrix(const ColorMatrix& color_matrix) const {
379 auto* c = color_matrix.array;
380 return Color(
381 c[0] * red + c[1] * green + c[2] * blue + c[3] * alpha + c[4],
382 c[5] * red + c[6] * green + c[7] * blue + c[8] * alpha + c[9],
383 c[10] * red + c[11] * green + c[12] * blue + c[13] * alpha + c[14],
384 c[15] * red + c[16] * green + c[17] * blue + c[18] * alpha + c[19])
385 .Clamp01();
386}
387
389 static auto conversion = [](Scalar component) {
390 if (component <= 0.0031308) {
391 return component * 12.92;
392 }
393 return 1.055 * pow(component, (1.0 / 2.4)) - 0.055;
394 };
395
396 return Color(conversion(red), conversion(green), conversion(blue), alpha);
397}
398
400 static auto conversion = [](Scalar component) {
401 if (component <= 0.04045) {
402 return component / 12.92;
403 }
404 return pow((component + 0.055) / 1.055, 2.4);
405 };
406
407 return Color(conversion(red), conversion(green), conversion(blue), alpha);
408}
409
410std::string ColorToString(const Color& color) {
411 return SPrintF("R=%.1f,G=%.1f,B=%.1f,A=%.1f", //
412 color.red, //
413 color.green, //
414 color.blue, //
415 color.alpha //
416 );
417}
418
419} // namespace impeller
#define _IMPELLER_ASSERT_BLEND_MODE(blend_mode)
Definition: color.cc:20
#define _IMPELLER_BLEND_MODE_NAME_LIST(blend_mode)
Definition: color.cc:42
#define IMPELLER_FOR_EACH_BLEND_MODE(V)
Definition: color.h:19
DlColor color
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auto & d
Definition: main.cc:19
static bool b
struct MyStruct s
struct MyStruct a[10]
uint8_t value
Dart_NativeFunction function
Definition: fuchsia.cc:51
static void luminosity(float dr, float dg, float db, float *sr, float *sg, float *sb)
Definition: hsl.cpp:130
static void saturation(float dr, float dg, float db, float *sr, float *sg, float *sb)
Definition: hsl.cpp:105
static float max(float r, float g, float b)
Definition: hsl.cpp:49
static float lum(float r, float g, float b)
Definition: hsl.cpp:52
static float min(float r, float g, float b)
Definition: hsl.cpp:48
#define R(r)
double y
double x
SK_API sk_sp< SkShader > Color(SkColor)
dst
Definition: cp.py:12
static constexpr const char * kBlendModeNames[]
Definition: color.cc:44
static constexpr Color Min(Color c, float threshold)
Definition: color.cc:132
static constexpr bool ValidateBlendModes()
Definition: color.cc:28
static constexpr Vector3 SetSaturation(Vector3 color, Scalar saturation)
Definition: color.cc:171
float Scalar
Definition: scalar.h:18
constexpr float kEhCloseEnough
Definition: constants.h:56
static constexpr Scalar Saturation(Vector3 color)
Definition: color.cc:166
static constexpr Vector3 ToRGB(Color color)
Definition: color.cc:188
const char * BlendModeToString(BlendMode blend_mode)
Definition: color.cc:47
std::string SPrintF(const char *format,...)
Definition: strings.cc:12
static constexpr Color FromRGB(Vector3 color, Scalar alpha)
Definition: color.cc:192
static constexpr Vector3 SetLuminosity(Vector3 color, Scalar luminosity)
Definition: color.cc:160
static constexpr Color ApplyBlendedColor(Color dst, Color src, Vector3 blend_result)
Definition: color.cc:201
static constexpr Color DoColorBlend(Color dst, Color src, const std::function< Vector3(Vector3, Vector3)> &blend_rgb_func)
Definition: color.cc:216
BlendMode
Definition: color.h:59
std::string ColorToString(const Color &color)
Definition: color.cc:410
static constexpr Color DoColorBlendComponents(Color dst, Color src, const std::function< Scalar(Scalar, Scalar)> &blend_func)
Definition: color.cc:224
static constexpr Vector3 ComponentChoose(Vector3 a, Vector3 b, Vector3 value, Scalar cutoff)
Definition: color.cc:178
static constexpr Vector3 ClipColor(Vector3 color)
Definition: color.cc:144
static constexpr Scalar Luminosity(Vector3 color)
Definition: color.cc:140
SIN Vec< N, float > sqrt(const Vec< N, float > &x)
Definition: SkVx.h:706
SIN Vec< N, float > floor(const Vec< N, float > &x)
Definition: SkVx.h:703
SkScalar w
SkScalar h
Definition: SkMD5.cpp:125
static ColorHSB FromRGB(Color rgb)
Definition: color.cc:52
Scalar alpha
Definition: color.h:945
constexpr ColorHSB(Scalar h, Scalar s, Scalar b, Scalar a)
Definition: color.h:947
Scalar brightness
Definition: color.h:940
Color ToRGBA() const
Definition: color.cc:79
Scalar saturation
Definition: color.h:935
Scalar array[20]
Definition: color.h:118
Scalar blue
Definition: color.h:138
static constexpr Color BlackTransparent()
Definition: color.h:272
Scalar alpha
Definition: color.h:143
Color LinearToSRGB() const
Convert the color from linear space to sRGB space.
Definition: color.cc:388
Color ApplyColorMatrix(const ColorMatrix &color_matrix) const
A color filter that transforms colors through a 4x5 color matrix.
Definition: color.cc:378
Scalar red
Definition: color.h:128
constexpr Color Unpremultiply() const
Definition: color.h:218
constexpr Color()
Definition: color.h:145
Scalar green
Definition: color.h:133
constexpr Color Premultiply() const
Definition: color.h:214
Color SRGBToLinear() const
Convert the color from sRGB space to linear space.
Definition: color.cc:399
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:234