Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 93e5c81

Browse files
authored
Changes DlColor to support wide gamut colors (#54473)
issue: flutter/flutter#127855 integration test: #54415 This is the engine side changes required for wide gamut framework support. It changes the internal representation of DlColor to be floats. It will be married with #54415 when it lands in #54567. [C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
1 parent 5355c0b commit 93e5c81

21 files changed

+436
-146
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42320,6 +42320,7 @@ ORIGIN: ../../../flutter/display_list/dl_builder.cc + ../../../flutter/LICENSE
4232042320
ORIGIN: ../../../flutter/display_list/dl_builder.h + ../../../flutter/LICENSE
4232142321
ORIGIN: ../../../flutter/display_list/dl_canvas.cc + ../../../flutter/LICENSE
4232242322
ORIGIN: ../../../flutter/display_list/dl_canvas.h + ../../../flutter/LICENSE
42323+
ORIGIN: ../../../flutter/display_list/dl_color.cc + ../../../flutter/LICENSE
4232342324
ORIGIN: ../../../flutter/display_list/dl_color.h + ../../../flutter/LICENSE
4232442325
ORIGIN: ../../../flutter/display_list/dl_op_flags.cc + ../../../flutter/LICENSE
4232542326
ORIGIN: ../../../flutter/display_list/dl_op_flags.h + ../../../flutter/LICENSE
@@ -45199,6 +45200,7 @@ FILE: ../../../flutter/display_list/dl_builder.cc
4519945200
FILE: ../../../flutter/display_list/dl_builder.h
4520045201
FILE: ../../../flutter/display_list/dl_canvas.cc
4520145202
FILE: ../../../flutter/display_list/dl_canvas.h
45203+
FILE: ../../../flutter/display_list/dl_color.cc
4520245204
FILE: ../../../flutter/display_list/dl_color.h
4520345205
FILE: ../../../flutter/display_list/dl_op_flags.cc
4520445206
FILE: ../../../flutter/display_list/dl_op_flags.h

display_list/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ source_set("display_list") {
3535
"dl_builder.h",
3636
"dl_canvas.cc",
3737
"dl_canvas.h",
38+
"dl_color.cc",
3839
"dl_color.h",
3940
"dl_op_flags.cc",
4041
"dl_op_flags.h",

display_list/display_list_unittests.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1847,7 +1847,7 @@ TEST_F(DisplayListTest, FlutterSvgIssue661BoundsWereEmpty) {
18471847
// This is the more practical result. The bounds are "almost" 0,0,100x100
18481848
EXPECT_EQ(display_list->bounds().roundOut(), SkIRect::MakeWH(100, 100));
18491849
EXPECT_EQ(display_list->op_count(), 19u);
1850-
EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 408u);
1850+
EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 424u);
18511851
EXPECT_EQ(display_list->total_depth(), 3u);
18521852
}
18531853

display_list/dl_builder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,7 +805,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
805805

806806
// kAnyColor is a non-opaque and non-transparent color that will not
807807
// trigger any short-circuit tests about the results of a blend.
808-
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x80);
808+
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlphaF(0.5f);
809809
static_assert(!kAnyColor.isOpaque());
810810
static_assert(!kAnyColor.isTransparent());
811811
static DlColor GetEffectiveColor(const DlPaint& paint,

display_list/dl_color.cc

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
5+
#include "flutter/display_list/dl_color.h"
6+
7+
namespace flutter {
8+
9+
namespace {
10+
const std::array<DlScalar, 12> kP3ToSrgb = {
11+
1.306671048092539, -0.298061942172353,
12+
0.213228303487995, -0.213580156254466, //
13+
-0.117390025596251, 1.127722006101976,
14+
0.109727644608938, -0.109450321455370, //
15+
0.214813187718391, 0.054268702864647,
16+
1.406898424029350, -0.364892765879631};
17+
18+
DlColor transform(const DlColor& color,
19+
const std::array<DlScalar, 12>& matrix,
20+
DlColorSpace color_space) {
21+
return DlColor(color.getAlphaF(),
22+
matrix[0] * color.getRedF() + //
23+
matrix[1] * color.getGreenF() + //
24+
matrix[2] * color.getBlueF() + //
25+
matrix[3], //
26+
matrix[4] * color.getRedF() + //
27+
matrix[5] * color.getGreenF() + //
28+
matrix[6] * color.getBlueF() + //
29+
matrix[7], //
30+
matrix[8] * color.getRedF() + //
31+
matrix[9] * color.getGreenF() + //
32+
matrix[10] * color.getBlueF() + //
33+
matrix[11], //
34+
color_space);
35+
}
36+
} // namespace
37+
38+
DlColor DlColor::withColorSpace(DlColorSpace color_space) const {
39+
switch (color_space_) {
40+
case DlColorSpace::kSRGB:
41+
switch (color_space) {
42+
case DlColorSpace::kSRGB:
43+
return *this;
44+
case DlColorSpace::kExtendedSRGB:
45+
return DlColor(alpha_, red_, green_, blue_,
46+
DlColorSpace::kExtendedSRGB);
47+
case DlColorSpace::kDisplayP3:
48+
FML_CHECK(false) << "not implemented";
49+
return *this;
50+
}
51+
case DlColorSpace::kExtendedSRGB:
52+
switch (color_space) {
53+
case DlColorSpace::kSRGB:
54+
FML_CHECK(false) << "not implemented";
55+
return *this;
56+
case DlColorSpace::kExtendedSRGB:
57+
return *this;
58+
case DlColorSpace::kDisplayP3:
59+
FML_CHECK(false) << "not implemented";
60+
return *this;
61+
}
62+
case DlColorSpace::kDisplayP3:
63+
switch (color_space) {
64+
case DlColorSpace::kSRGB:
65+
FML_CHECK(false) << "not implemented";
66+
return *this;
67+
case DlColorSpace::kExtendedSRGB:
68+
return transform(*this, kP3ToSrgb, DlColorSpace::kExtendedSRGB);
69+
case DlColorSpace::kDisplayP3:
70+
return *this;
71+
}
72+
}
73+
}
74+
75+
} // namespace flutter

display_list/dl_color.h

Lines changed: 113 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,39 @@
99

1010
namespace flutter {
1111

12+
// These should match the enumerations defined in //lib/ui/painting.dart.
13+
enum class DlColorSpace { kSRGB = 0, kExtendedSRGB = 1, kDisplayP3 = 2 };
14+
15+
/// A representation of a color.
16+
///
17+
/// The color belongs to a DlColorSpace. Using deprecated integer data accessors
18+
/// on colors not in the kSRGB colorspace can lead to data loss. Using the
19+
/// floating point accessors and constructors that were added for wide-gamut
20+
/// support are preferred.
1221
struct DlColor {
1322
public:
14-
constexpr DlColor() : argb_(0xFF000000) {}
15-
constexpr explicit DlColor(uint32_t argb) : argb_(argb) {}
23+
constexpr DlColor()
24+
: alpha_(0.f),
25+
red_(0.f),
26+
green_(0.f),
27+
blue_(0.f),
28+
color_space_(DlColorSpace::kSRGB) {}
29+
constexpr explicit DlColor(uint32_t argb)
30+
: alpha_(toF((argb >> 24) & 0xff)),
31+
red_(toF((argb >> 16) & 0xff)),
32+
green_(toF((argb >> 8) & 0xff)),
33+
blue_(toF((argb >> 0) & 0xff)),
34+
color_space_(DlColorSpace::kSRGB) {}
35+
constexpr DlColor(DlScalar alpha,
36+
DlScalar red,
37+
DlScalar green,
38+
DlScalar blue,
39+
DlColorSpace colorspace)
40+
: alpha_(alpha),
41+
red_(red),
42+
green_(green),
43+
blue_(blue),
44+
color_space_(colorspace) {}
1645

1746
/// @brief Construct a 32 bit color from floating point R, G, B, and A color
1847
/// channels.
@@ -29,10 +58,7 @@ struct DlColor {
2958
DlScalar r,
3059
DlScalar g,
3160
DlScalar b) {
32-
return DlColor(toC(a) << 24 | //
33-
toC(r) << 16 | //
34-
toC(g) << 8 | //
35-
toC(b));
61+
return DlColor(a, r, g, b, DlColorSpace::kSRGB);
3662
}
3763

3864
static constexpr uint8_t toAlpha(DlScalar opacity) { return toC(opacity); }
@@ -66,58 +92,106 @@ struct DlColor {
6692
static constexpr DlColor kOrangeRed() {return DlColor(0xFFFF4500);};
6793
// clang-format on
6894

69-
constexpr bool isOpaque() const { return getAlpha() == 0xFF; }
70-
constexpr bool isTransparent() const { return getAlpha() == 0; }
71-
72-
constexpr int getAlpha() const { return argb_ >> 24; }
73-
constexpr int getRed() const { return (argb_ >> 16) & 0xFF; }
74-
constexpr int getGreen() const { return (argb_ >> 8) & 0xFF; }
75-
constexpr int getBlue() const { return argb_ & 0xFF; }
76-
77-
constexpr DlScalar getAlphaF() const { return toF(getAlpha()); }
78-
constexpr DlScalar getRedF() const { return toF(getRed()); }
79-
constexpr DlScalar getGreenF() const { return toF(getGreen()); }
80-
constexpr DlScalar getBlueF() const { return toF(getBlue()); }
81-
82-
constexpr uint32_t premultipliedArgb() const {
83-
if (isOpaque()) {
84-
return argb_;
85-
}
86-
DlScalar f = getAlphaF();
87-
return (argb_ & 0xFF000000) | //
88-
toC(getRedF() * f) << 16 | //
89-
toC(getGreenF() * f) << 8 | //
90-
toC(getBlueF() * f);
91-
}
95+
constexpr bool isOpaque() const { return alpha_ >= 1.f; }
96+
constexpr bool isTransparent() const { return alpha_ <= 0.f; }
97+
98+
///\deprecated Use floating point accessors to avoid data loss when using wide
99+
/// gamut colors.
100+
constexpr int getAlpha() const { return toC(alpha_); }
101+
///\deprecated Use floating point accessors to avoid data loss when using wide
102+
/// gamut colors.
103+
constexpr int getRed() const { return toC(red_); }
104+
///\deprecated Use floating point accessors to avoid data loss when using wide
105+
/// gamut colors.
106+
constexpr int getGreen() const { return toC(green_); }
107+
///\deprecated Use floating point accessors to avoid data loss when using wide
108+
/// gamut colors.
109+
constexpr int getBlue() const { return toC(blue_); }
110+
111+
constexpr DlScalar getAlphaF() const { return alpha_; }
112+
constexpr DlScalar getRedF() const { return red_; }
113+
constexpr DlScalar getGreenF() const { return green_; }
114+
constexpr DlScalar getBlueF() const { return blue_; }
115+
116+
constexpr DlColorSpace getColorSpace() const { return color_space_; }
92117

93118
constexpr DlColor withAlpha(uint8_t alpha) const { //
94-
return DlColor((argb_ & 0x00FFFFFF) | (alpha << 24));
119+
return DlColor((argb() & 0x00FFFFFF) | (alpha << 24));
95120
}
96121
constexpr DlColor withRed(uint8_t red) const { //
97-
return DlColor((argb_ & 0xFF00FFFF) | (red << 16));
122+
return DlColor((argb() & 0xFF00FFFF) | (red << 16));
98123
}
99124
constexpr DlColor withGreen(uint8_t green) const { //
100-
return DlColor((argb_ & 0xFFFF00FF) | (green << 8));
125+
return DlColor((argb() & 0xFFFF00FF) | (green << 8));
101126
}
102127
constexpr DlColor withBlue(uint8_t blue) const { //
103-
return DlColor((argb_ & 0xFFFFFF00) | (blue << 0));
128+
return DlColor((argb() & 0xFFFFFF00) | (blue << 0));
129+
}
130+
constexpr DlColor withAlphaF(float alpha) const { //
131+
return DlColor(alpha, red_, green_, blue_, color_space_);
132+
}
133+
constexpr DlColor withRedF(float red) const { //
134+
return DlColor(alpha_, red, green_, blue_, color_space_);
135+
}
136+
constexpr DlColor withGreenF(float green) const { //
137+
return DlColor(alpha_, red_, green, blue_, color_space_);
104138
}
139+
constexpr DlColor withBlueF(float blue) const { //
140+
return DlColor(alpha_, red_, green_, blue, color_space_);
141+
}
142+
/// Performs a colorspace transformation.
143+
///
144+
/// This isn't just a replacement of the color space field, the new color
145+
/// components are calculated.
146+
DlColor withColorSpace(DlColorSpace color_space) const;
105147

106148
constexpr DlColor modulateOpacity(DlScalar opacity) const {
107149
return opacity <= 0 ? withAlpha(0)
108150
: opacity >= 1 ? *this
109151
: withAlpha(round(getAlpha() * opacity));
110152
}
111153

112-
constexpr uint32_t argb() const { return argb_; }
154+
///\deprecated Use floating point accessors to avoid data loss when using wide
155+
/// gamut colors.
156+
constexpr uint32_t argb() const {
157+
return toC(alpha_) << 24 | //
158+
toC(red_) << 16 | //
159+
toC(green_) << 8 | //
160+
toC(blue_) << 0;
161+
}
113162

114-
bool operator==(DlColor const& other) const { return argb_ == other.argb_; }
115-
bool operator!=(DlColor const& other) const { return argb_ != other.argb_; }
116-
bool operator==(uint32_t const& other) const { return argb_ == other; }
117-
bool operator!=(uint32_t const& other) const { return argb_ != other; }
163+
/// Checks that no difference in color components exceeds the delta.
164+
///
165+
/// This doesn't check against the actual distance between the colors in some
166+
/// space.
167+
bool isClose(DlColor const& other, DlScalar delta = 1.0f / 256.0f) {
168+
return color_space_ == other.color_space_ &&
169+
std::abs(alpha_ - other.alpha_) < delta &&
170+
std::abs(red_ - other.red_) < delta &&
171+
std::abs(green_ - other.green_) < delta &&
172+
std::abs(blue_ - other.blue_) < delta;
173+
}
174+
bool operator==(DlColor const& other) const {
175+
return alpha_ == other.alpha_ && red_ == other.red_ &&
176+
green_ == other.green_ && blue_ == other.blue_ &&
177+
color_space_ == other.color_space_;
178+
}
179+
bool operator!=(DlColor const& other) const {
180+
return !this->operator==(other);
181+
}
182+
bool operator==(uint32_t const& other) const {
183+
return argb() == other && color_space_ == DlColorSpace::kSRGB;
184+
}
185+
bool operator!=(uint32_t const& other) const {
186+
return !this->operator==(other);
187+
}
118188

119189
private:
120-
uint32_t argb_;
190+
DlScalar alpha_;
191+
DlScalar red_;
192+
DlScalar green_;
193+
DlScalar blue_;
194+
DlColorSpace color_space_;
121195

122196
static constexpr DlScalar toF(uint8_t comp) { return comp * (1.0f / 255); }
123197
static constexpr uint8_t toC(DlScalar fComp) { return round(fComp * 255); }

0 commit comments

Comments
 (0)