Reverts "Changes DlColor to support wide gamut colors (#54473)" (flutter/engine#54636)

Reverts: flutter/engine#54473
Initiated by: jonahwilliams
Reason for reverting: golden diffs like https://flutter-engine-gold.skia.org/detail?grouping=name%3Dimpeller_Play_AiksTest_BlendModeSrcAlphaLuminosity_OpenGLES%26source_type%3Dflutter-engine&digest=107ccd2cd1170746b1ffc4d31184e789 look incorrect, potentially an alpha issue
Original PR Author: gaaclarke

Reviewed By: {flar}

This change reverts the following previous change:
issue: https://github.com/flutter/flutter/issues/127855
integration test: https://github.com/flutter/engine/pull/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 https://github.com/flutter/engine/pull/54415 when it lands in https://github.com/flutter/engine/pull/54567.

[C++, Objective-C, Java style guides]: https://github.com/flutter/engine/blob/main/CONTRIBUTING.md#style
This commit is contained in:
auto-submit[bot] 2024-08-20 02:19:47 +00:00 committed by GitHub
parent d6f4f4a66e
commit 8aabbdd12f
21 changed files with 143 additions and 433 deletions

View File

@ -42320,7 +42320,6 @@ ORIGIN: ../../../flutter/display_list/dl_builder.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_builder.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_canvas.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_canvas.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_color.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_color.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_op_flags.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/display_list/dl_op_flags.h + ../../../flutter/LICENSE
@ -45200,7 +45199,6 @@ FILE: ../../../flutter/display_list/dl_builder.cc
FILE: ../../../flutter/display_list/dl_builder.h
FILE: ../../../flutter/display_list/dl_canvas.cc
FILE: ../../../flutter/display_list/dl_canvas.h
FILE: ../../../flutter/display_list/dl_color.cc
FILE: ../../../flutter/display_list/dl_color.h
FILE: ../../../flutter/display_list/dl_op_flags.cc
FILE: ../../../flutter/display_list/dl_op_flags.h

View File

@ -35,7 +35,6 @@ source_set("display_list") {
"dl_builder.h",
"dl_canvas.cc",
"dl_canvas.h",
"dl_color.cc",
"dl_color.h",
"dl_op_flags.cc",
"dl_op_flags.h",

View File

@ -1847,7 +1847,7 @@ TEST_F(DisplayListTest, FlutterSvgIssue661BoundsWereEmpty) {
// This is the more practical result. The bounds are "almost" 0,0,100x100
EXPECT_EQ(display_list->bounds().roundOut(), SkIRect::MakeWH(100, 100));
EXPECT_EQ(display_list->op_count(), 19u);
EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 424u);
EXPECT_EQ(display_list->bytes(), sizeof(DisplayList) + 408u);
EXPECT_EQ(display_list->total_depth(), 3u);
}

View File

@ -805,7 +805,7 @@ class DisplayListBuilder final : public virtual DlCanvas,
// kAnyColor is a non-opaque and non-transparent color that will not
// trigger any short-circuit tests about the results of a blend.
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlphaF(0.5f);
static constexpr DlColor kAnyColor = DlColor::kMidGrey().withAlpha(0x80);
static_assert(!kAnyColor.isOpaque());
static_assert(!kAnyColor.isTransparent());
static DlColor GetEffectiveColor(const DlPaint& paint,

View File

@ -1,75 +0,0 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/display_list/dl_color.h"
namespace flutter {
namespace {
const std::array<DlScalar, 12> kP3ToSrgb = {
1.306671048092539, -0.298061942172353,
0.213228303487995, -0.213580156254466, //
-0.117390025596251, 1.127722006101976,
0.109727644608938, -0.109450321455370, //
0.214813187718391, 0.054268702864647,
1.406898424029350, -0.364892765879631};
DlColor transform(const DlColor& color,
const std::array<DlScalar, 12>& matrix,
DlColorSpace color_space) {
return DlColor(color.getAlphaF(),
matrix[0] * color.getRedF() + //
matrix[1] * color.getGreenF() + //
matrix[2] * color.getBlueF() + //
matrix[3], //
matrix[4] * color.getRedF() + //
matrix[5] * color.getGreenF() + //
matrix[6] * color.getBlueF() + //
matrix[7], //
matrix[8] * color.getRedF() + //
matrix[9] * color.getGreenF() + //
matrix[10] * color.getBlueF() + //
matrix[11], //
color_space);
}
} // namespace
DlColor DlColor::withColorSpace(DlColorSpace color_space) const {
switch (color_space_) {
case DlColorSpace::kSRGB:
switch (color_space) {
case DlColorSpace::kSRGB:
return *this;
case DlColorSpace::kExtendedSRGB:
return DlColor(alpha_, red_, green_, blue_,
DlColorSpace::kExtendedSRGB);
case DlColorSpace::kDisplayP3:
FML_CHECK(false) << "not implemented";
return *this;
}
case DlColorSpace::kExtendedSRGB:
switch (color_space) {
case DlColorSpace::kSRGB:
FML_CHECK(false) << "not implemented";
return *this;
case DlColorSpace::kExtendedSRGB:
return *this;
case DlColorSpace::kDisplayP3:
FML_CHECK(false) << "not implemented";
return *this;
}
case DlColorSpace::kDisplayP3:
switch (color_space) {
case DlColorSpace::kSRGB:
FML_CHECK(false) << "not implemented";
return *this;
case DlColorSpace::kExtendedSRGB:
return transform(*this, kP3ToSrgb, DlColorSpace::kExtendedSRGB);
case DlColorSpace::kDisplayP3:
return *this;
}
}
}
} // namespace flutter

View File

@ -9,39 +9,10 @@
namespace flutter {
// These should match the enumerations defined in //lib/ui/painting.dart.
enum class DlColorSpace { kSRGB = 0, kExtendedSRGB = 1, kDisplayP3 = 2 };
/// A representation of a color.
///
/// The color belongs to a DlColorSpace. Using deprecated integer data accessors
/// on colors not in the kSRGB colorspace can lead to data loss. Using the
/// floating point accessors and constructors that were added for wide-gamut
/// support are preferred.
struct DlColor {
public:
constexpr DlColor()
: alpha_(0.f),
red_(0.f),
green_(0.f),
blue_(0.f),
color_space_(DlColorSpace::kSRGB) {}
constexpr explicit DlColor(uint32_t argb)
: alpha_(toF((argb >> 24) & 0xff)),
red_(toF((argb >> 16) & 0xff)),
green_(toF((argb >> 8) & 0xff)),
blue_(toF((argb >> 0) & 0xff)),
color_space_(DlColorSpace::kSRGB) {}
constexpr DlColor(DlScalar alpha,
DlScalar red,
DlScalar green,
DlScalar blue,
DlColorSpace colorspace)
: alpha_(alpha),
red_(red),
green_(green),
blue_(blue),
color_space_(colorspace) {}
constexpr DlColor() : argb_(0xFF000000) {}
constexpr explicit DlColor(uint32_t argb) : argb_(argb) {}
/// @brief Construct a 32 bit color from floating point R, G, B, and A color
/// channels.
@ -58,7 +29,10 @@ struct DlColor {
DlScalar r,
DlScalar g,
DlScalar b) {
return DlColor(a, r, g, b, DlColorSpace::kSRGB);
return DlColor(toC(a) << 24 | //
toC(r) << 16 | //
toC(g) << 8 | //
toC(b));
}
static constexpr uint8_t toAlpha(DlScalar opacity) { return toC(opacity); }
@ -92,58 +66,42 @@ struct DlColor {
static constexpr DlColor kOrangeRed() {return DlColor(0xFFFF4500);};
// clang-format on
constexpr bool isOpaque() const { return alpha_ >= 1.f; }
constexpr bool isTransparent() const { return alpha_ <= 0.f; }
constexpr bool isOpaque() const { return getAlpha() == 0xFF; }
constexpr bool isTransparent() const { return getAlpha() == 0; }
///\deprecated Use floating point accessors to avoid data loss when using wide
/// gamut colors.
constexpr int getAlpha() const { return toC(alpha_); }
///\deprecated Use floating point accessors to avoid data loss when using wide
/// gamut colors.
constexpr int getRed() const { return toC(red_); }
///\deprecated Use floating point accessors to avoid data loss when using wide
/// gamut colors.
constexpr int getGreen() const { return toC(green_); }
///\deprecated Use floating point accessors to avoid data loss when using wide
/// gamut colors.
constexpr int getBlue() const { return toC(blue_); }
constexpr int getAlpha() const { return argb_ >> 24; }
constexpr int getRed() const { return (argb_ >> 16) & 0xFF; }
constexpr int getGreen() const { return (argb_ >> 8) & 0xFF; }
constexpr int getBlue() const { return argb_ & 0xFF; }
constexpr DlScalar getAlphaF() const { return alpha_; }
constexpr DlScalar getRedF() const { return red_; }
constexpr DlScalar getGreenF() const { return green_; }
constexpr DlScalar getBlueF() const { return blue_; }
constexpr DlScalar getAlphaF() const { return toF(getAlpha()); }
constexpr DlScalar getRedF() const { return toF(getRed()); }
constexpr DlScalar getGreenF() const { return toF(getGreen()); }
constexpr DlScalar getBlueF() const { return toF(getBlue()); }
constexpr DlColorSpace getColorSpace() const { return color_space_; }
constexpr uint32_t premultipliedArgb() const {
if (isOpaque()) {
return argb_;
}
DlScalar f = getAlphaF();
return (argb_ & 0xFF000000) | //
toC(getRedF() * f) << 16 | //
toC(getGreenF() * f) << 8 | //
toC(getBlueF() * f);
}
constexpr DlColor withAlpha(uint8_t alpha) const { //
return DlColor((argb() & 0x00FFFFFF) | (alpha << 24));
return DlColor((argb_ & 0x00FFFFFF) | (alpha << 24));
}
constexpr DlColor withRed(uint8_t red) const { //
return DlColor((argb() & 0xFF00FFFF) | (red << 16));
return DlColor((argb_ & 0xFF00FFFF) | (red << 16));
}
constexpr DlColor withGreen(uint8_t green) const { //
return DlColor((argb() & 0xFFFF00FF) | (green << 8));
return DlColor((argb_ & 0xFFFF00FF) | (green << 8));
}
constexpr DlColor withBlue(uint8_t blue) const { //
return DlColor((argb() & 0xFFFFFF00) | (blue << 0));
return DlColor((argb_ & 0xFFFFFF00) | (blue << 0));
}
constexpr DlColor withAlphaF(float alpha) const { //
return DlColor(alpha, red_, green_, blue_, color_space_);
}
constexpr DlColor withRedF(float red) const { //
return DlColor(alpha_, red, green_, blue_, color_space_);
}
constexpr DlColor withGreenF(float green) const { //
return DlColor(alpha_, red_, green, blue_, color_space_);
}
constexpr DlColor withBlueF(float blue) const { //
return DlColor(alpha_, red_, green_, blue, color_space_);
}
/// Performs a colorspace transformation.
///
/// This isn't just a replacement of the color space field, the new color
/// components are calculated.
DlColor withColorSpace(DlColorSpace color_space) const;
constexpr DlColor modulateOpacity(DlScalar opacity) const {
return opacity <= 0 ? withAlpha(0)
@ -151,47 +109,15 @@ struct DlColor {
: withAlpha(round(getAlpha() * opacity));
}
///\deprecated Use floating point accessors to avoid data loss when using wide
/// gamut colors.
constexpr uint32_t argb() const {
return toC(alpha_) << 24 | //
toC(red_) << 16 | //
toC(green_) << 8 | //
toC(blue_) << 0;
}
constexpr uint32_t argb() const { return argb_; }
/// Checks that no difference in color components exceeds the delta.
///
/// This doesn't check against the actual distance between the colors in some
/// space.
bool isClose(DlColor const& other, DlScalar delta = 1.0f / 256.0f) {
return color_space_ == other.color_space_ &&
std::abs(alpha_ - other.alpha_) < delta &&
std::abs(red_ - other.red_) < delta &&
std::abs(green_ - other.green_) < delta &&
std::abs(blue_ - other.blue_) < delta;
}
bool operator==(DlColor const& other) const {
return alpha_ == other.alpha_ && red_ == other.red_ &&
green_ == other.green_ && blue_ == other.blue_ &&
color_space_ == other.color_space_;
}
bool operator!=(DlColor const& other) const {
return !this->operator==(other);
}
bool operator==(uint32_t const& other) const {
return argb() == other && color_space_ == DlColorSpace::kSRGB;
}
bool operator!=(uint32_t const& other) const {
return !this->operator==(other);
}
bool operator==(DlColor const& other) const { return argb_ == other.argb_; }
bool operator!=(DlColor const& other) const { return argb_ != other.argb_; }
bool operator==(uint32_t const& other) const { return argb_ == other; }
bool operator!=(uint32_t const& other) const { return argb_ != other; }
private:
DlScalar alpha_;
DlScalar red_;
DlScalar green_;
DlScalar blue_;
DlColorSpace color_space_;
uint32_t argb_;
static constexpr DlScalar toF(uint8_t comp) { return comp * (1.0f / 255); }
static constexpr uint8_t toC(DlScalar fComp) { return round(fComp * 255); }

View File

@ -3,7 +3,6 @@
// found in the LICENSE file.
#include "flutter/display_list/dl_color.h"
#include "flutter/testing/display_list_testing.h"
#include "flutter/testing/testing.h"
#include "third_party/skia/include/core/SkColor.h"
@ -15,7 +14,7 @@ static void arraysEqual(const uint32_t* ints,
const DlColor* colors,
int count) {
for (int i = 0; i < count; i++) {
EXPECT_EQ(ints[i], colors[i].argb()) << " index:" << i;
EXPECT_TRUE(ints[i] == colors[i].argb());
}
}
@ -35,6 +34,8 @@ TEST(DisplayListColor, ArrayInterchangeableWithUint32) {
DlColor(0xF1F2F3F4),
};
arraysEqual(ints, colors, 5);
arraysEqual(reinterpret_cast<const uint32_t*>(colors),
reinterpret_cast<const DlColor*>(ints), 5);
}
TEST(DisplayListColor, DlColorDirectlyComparesToSkColor) {
@ -47,17 +48,13 @@ TEST(DisplayListColor, DlColorDirectlyComparesToSkColor) {
TEST(DisplayListColor, DlColorFloatConstructor) {
EXPECT_EQ(DlColor::ARGB(1.0f, 1.0f, 1.0f, 1.0f), DlColor(0xFFFFFFFF));
EXPECT_EQ(DlColor::ARGB(0.0f, 0.0f, 0.0f, 0.0f), DlColor(0x00000000));
EXPECT_TRUE(
DlColor::ARGB(0.5f, 0.5f, 0.5f, 0.5f).isClose(DlColor(0x80808080)));
EXPECT_TRUE(
DlColor::ARGB(1.0f, 0.0f, 0.5f, 1.0f).isClose(DlColor(0xFF0080FF)));
EXPECT_EQ(DlColor::ARGB(0.5f, 0.5f, 0.5f, 0.5f), DlColor(0x80808080));
EXPECT_EQ(DlColor::ARGB(1.0f, 0.0f, 0.5f, 1.0f), DlColor(0xFF0080FF));
EXPECT_EQ(DlColor::RGBA(1.0f, 1.0f, 1.0f, 1.0f), DlColor(0xFFFFFFFF));
EXPECT_EQ(DlColor::RGBA(0.0f, 0.0f, 0.0f, 0.0f), DlColor(0x00000000));
EXPECT_TRUE(
DlColor::RGBA(0.5f, 0.5f, 0.5f, 0.5f).isClose(DlColor(0x80808080)));
EXPECT_TRUE(
DlColor::RGBA(1.0f, 0.0f, 0.5f, 1.0f).isClose(DlColor(0xFFFF0080)));
EXPECT_EQ(DlColor::RGBA(0.5f, 0.5f, 0.5f, 0.5f), DlColor(0x80808080));
EXPECT_EQ(DlColor::RGBA(1.0f, 0.0f, 0.5f, 1.0f), DlColor(0xFFFF0080));
}
TEST(DisplayListColor, DlColorComponentGetters) {
@ -127,10 +124,10 @@ TEST(DisplayListColor, DlColorComponentGetters) {
const DlScalar half = 127.0f * (1.0f / 255.0f);
EXPECT_NEAR(test.getAlphaF(), half, 0.00001);
EXPECT_NEAR(test.getRedF(), half, 0.00001);
EXPECT_NEAR(test.getGreenF(), half, 0.00001);
EXPECT_NEAR(test.getBlueF(), half, 0.00001);
EXPECT_EQ(test.getAlphaF(), half);
EXPECT_EQ(test.getRedF(), half);
EXPECT_EQ(test.getGreenF(), half);
EXPECT_EQ(test.getBlueF(), half);
}
{
@ -141,10 +138,12 @@ TEST(DisplayListColor, DlColorComponentGetters) {
EXPECT_EQ(test.getGreen(), 0x80);
EXPECT_EQ(test.getBlue(), 0x80);
EXPECT_EQ(test.getAlphaF(), 0.5);
EXPECT_EQ(test.getRedF(), 0.5);
EXPECT_EQ(test.getGreenF(), 0.5);
EXPECT_EQ(test.getBlueF(), 0.5);
const DlScalar half = 128.0f * (1.0f / 255.0f);
EXPECT_EQ(test.getAlphaF(), half);
EXPECT_EQ(test.getRedF(), half);
EXPECT_EQ(test.getGreenF(), half);
EXPECT_EQ(test.getBlueF(), half);
}
{
@ -155,10 +154,10 @@ TEST(DisplayListColor, DlColorComponentGetters) {
EXPECT_EQ(test.getGreen(), 0x3F);
EXPECT_EQ(test.getBlue(), 0x4F);
EXPECT_NEAR(test.getAlphaF(), 0x1f * (1.0f / 255.0f), 0.00001);
EXPECT_NEAR(test.getRedF(), 0x2f * (1.0f / 255.0f), 0.00001);
EXPECT_NEAR(test.getGreenF(), 0x3f * (1.0f / 255.0f), 0.00001);
EXPECT_NEAR(test.getBlueF(), 0x4f * (1.0f / 255.0f), 0.00001);
EXPECT_EQ(test.getAlphaF(), 0x1f * (1.0f / 255.0f));
EXPECT_EQ(test.getRedF(), 0x2f * (1.0f / 255.0f));
EXPECT_EQ(test.getGreenF(), 0x3f * (1.0f / 255.0f));
EXPECT_EQ(test.getBlueF(), 0x4f * (1.0f / 255.0f));
}
{
@ -169,10 +168,11 @@ TEST(DisplayListColor, DlColorComponentGetters) {
EXPECT_EQ(test.getGreen(), round(0.3f * 255));
EXPECT_EQ(test.getBlue(), round(0.4f * 255));
EXPECT_EQ(test.getAlphaF(), 0.1f);
EXPECT_EQ(test.getRedF(), 0.2f);
EXPECT_EQ(test.getGreenF(), 0.3f);
EXPECT_EQ(test.getBlueF(), 0.4f);
// Unfortunately conversion from float to 8-bit back to float is lossy
EXPECT_EQ(test.getAlphaF(), round(0.1f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getRedF(), round(0.2f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getGreenF(), round(0.3f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getBlueF(), round(0.4f * 255) * (1.0f / 255.0f));
}
{
@ -183,10 +183,11 @@ TEST(DisplayListColor, DlColorComponentGetters) {
EXPECT_EQ(test.getGreen(), round(0.3f * 255));
EXPECT_EQ(test.getBlue(), round(0.4f * 255));
EXPECT_EQ(test.getAlphaF(), 0.1f);
EXPECT_EQ(test.getRedF(), 0.2f);
EXPECT_EQ(test.getGreenF(), 0.3f);
EXPECT_EQ(test.getBlueF(), 0.4f);
// Unfortunately conversion from float to 8-bit back to float is lossy
EXPECT_EQ(test.getAlphaF(), round(0.1f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getRedF(), round(0.2f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getGreenF(), round(0.3f * 255) * (1.0f / 255.0f));
EXPECT_EQ(test.getBlueF(), round(0.4f * 255) * (1.0f / 255.0f));
}
}
@ -229,73 +230,5 @@ TEST(DisplayListColor, DlColorOpaqueTransparent) {
}
}
TEST(DisplayListColor, EqualityWithColorspace) {
EXPECT_TRUE(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB) ==
DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB));
EXPECT_FALSE(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB) ==
DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kExtendedSRGB));
EXPECT_FALSE(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB) !=
DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB));
EXPECT_TRUE(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB) !=
DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kExtendedSRGB));
}
TEST(DisplayListColor, EqualityWithExtendedSRGB) {
EXPECT_TRUE(DlColor(1.0, 1.1, -0.2, 0.1, DlColorSpace::kExtendedSRGB) ==
DlColor(1.0, 1.1, -0.2, 0.1, DlColorSpace::kExtendedSRGB));
EXPECT_FALSE(DlColor(1.0, 1.1, -0.2, 0.1, DlColorSpace::kExtendedSRGB) ==
DlColor(1.0, 1.0, 0.0, 0.0, DlColorSpace::kExtendedSRGB));
}
TEST(DisplayListColor, ColorSpaceSRGBtoSRGB) {
DlColor srgb(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB);
EXPECT_EQ(srgb, srgb.withColorSpace(DlColorSpace::kSRGB));
}
TEST(DisplayListColor, ColorSpaceSRGBtoExtendedSRGB) {
DlColor srgb(0.9, 0.8, 0.7, 0.6, DlColorSpace::kSRGB);
EXPECT_EQ(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kExtendedSRGB),
srgb.withColorSpace(DlColorSpace::kExtendedSRGB));
}
TEST(DisplayListColor, ColorSpaceExtendedSRGBtoExtendedSRGB) {
DlColor xsrgb(0.9, 0.8, 0.7, 0.6, DlColorSpace::kExtendedSRGB);
EXPECT_EQ(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kExtendedSRGB),
xsrgb.withColorSpace(DlColorSpace::kExtendedSRGB));
}
TEST(DisplayListColor, ColorSpaceP3ToP3) {
DlColor p3(0.9, 0.8, 0.7, 0.6, DlColorSpace::kDisplayP3);
EXPECT_EQ(DlColor(0.9, 0.8, 0.7, 0.6, DlColorSpace::kDisplayP3),
p3.withColorSpace(DlColorSpace::kDisplayP3));
}
TEST(DisplayListColor, ColorSpaceP3ToExtendedSRGB) {
DlColor red(0.9, 1.0, 0.0, 0.0, DlColorSpace::kDisplayP3);
EXPECT_TRUE(
DlColor(0.9, 1.0931, -0.2268, -0.1501, DlColorSpace::kExtendedSRGB)
.isClose(red.withColorSpace(DlColorSpace::kExtendedSRGB)))
<< red.withColorSpace(DlColorSpace::kExtendedSRGB);
DlColor green(0.9, 0.0, 1.0, 0.0, DlColorSpace::kDisplayP3);
EXPECT_TRUE(
DlColor(0.9, -0.5116, 1.0183, -0.3106, DlColorSpace::kExtendedSRGB)
.isClose(green.withColorSpace(DlColorSpace::kExtendedSRGB)))
<< green.withColorSpace(DlColorSpace::kExtendedSRGB);
DlColor blue(0.9, 0.0, 0.0, 1.0, DlColorSpace::kDisplayP3);
EXPECT_TRUE(DlColor(0.9, -0.0004, 0.0003, 1.0420, DlColorSpace::kExtendedSRGB)
.isClose(blue.withColorSpace(DlColorSpace::kExtendedSRGB)))
<< blue.withColorSpace(DlColorSpace::kExtendedSRGB);
}
TEST(DisplayListColor, isClose) {
EXPECT_TRUE(DlColor(0xffaabbcc).isClose(DlColor(0xffaabbcc)));
}
TEST(DisplayListColor, isNotClose) {
EXPECT_FALSE(DlColor(0xffaabbcc).isClose(DlColor(0xffaabbcd)));
}
} // namespace testing
} // namespace flutter

View File

@ -267,18 +267,6 @@ void DlVertices::Builder::store_colors(const DlColor colors[]) {
needs_colors_ = false;
}
void DlVertices::Builder::store_colors(const uint32_t colors[]) {
FML_CHECK(is_valid());
FML_CHECK(needs_colors_);
char* pod = reinterpret_cast<char*>(vertices_.get());
DlColor* dlcolors_ptr =
reinterpret_cast<DlColor*>(pod + vertices_->colors_offset_);
for (int i = 0; i < vertices_->vertex_count_; ++i) {
*dlcolors_ptr++ = DlColor(colors[i]);
}
needs_colors_ = false;
}
void DlVertices::Builder::store_indices(const uint16_t indices[]) {
FML_CHECK(is_valid());
FML_CHECK(needs_indices_);

View File

@ -147,7 +147,9 @@ class DlVertices {
///
/// fails if colors have already been supplied or if they were not
/// promised by the flags.has_colors.
void store_colors(const uint32_t colors[]);
void store_colors(const uint32_t colors[]) {
store_colors(reinterpret_cast<const DlColor*>(colors));
}
/// @brief Copies the indicated list of 16-bit indices as vertex indices.
///

View File

@ -28,7 +28,7 @@ std::shared_ptr<DlLinearGradientColorSource> DlColorSource::MakeLinear(
DlTileMode tile_mode,
const SkMatrix* matrix) {
size_t needed = sizeof(DlLinearGradientColorSource) +
(stop_count * (sizeof(DlColor) + sizeof(float)));
(stop_count * (sizeof(uint32_t) + sizeof(float)));
void* storage = ::operator new(needed);
@ -49,7 +49,7 @@ std::shared_ptr<DlRadialGradientColorSource> DlColorSource::MakeRadial(
DlTileMode tile_mode,
const SkMatrix* matrix) {
size_t needed = sizeof(DlRadialGradientColorSource) +
(stop_count * (sizeof(DlColor) + sizeof(float)));
(stop_count * (sizeof(uint32_t) + sizeof(float)));
void* storage = ::operator new(needed);
@ -71,7 +71,7 @@ std::shared_ptr<DlConicalGradientColorSource> DlColorSource::MakeConical(
DlTileMode tile_mode,
const SkMatrix* matrix) {
size_t needed = sizeof(DlConicalGradientColorSource) +
(stop_count * (sizeof(DlColor) + sizeof(float)));
(stop_count * (sizeof(uint32_t) + sizeof(float)));
void* storage = ::operator new(needed);
@ -93,7 +93,7 @@ std::shared_ptr<DlSweepGradientColorSource> DlColorSource::MakeSweep(
DlTileMode tile_mode,
const SkMatrix* matrix) {
size_t needed = sizeof(DlSweepGradientColorSource) +
(stop_count * (sizeof(DlColor) + sizeof(float)));
(stop_count * (sizeof(uint32_t) + sizeof(float)));
void* storage = ::operator new(needed);

View File

@ -327,10 +327,11 @@ class DlGradientColorSourceBase : public DlMatrixColorSourceBase {
stop_count_ != other_base->stop_count_) {
return false;
}
return (memcmp(colors(), other_base->colors(),
stop_count_ * sizeof(colors()[0])) == 0 &&
memcmp(stops(), other_base->stops(),
stop_count_ * sizeof(stops()[0])) == 0);
static_assert(sizeof(colors()[0]) == 4);
static_assert(sizeof(stops()[0]) == 4);
int num_bytes = stop_count_ * 4;
return (memcmp(colors(), other_base->colors(), num_bytes) == 0 &&
memcmp(stops(), other_base->stops(), num_bytes) == 0);
}
void store_color_stops(void* pod,

View File

@ -311,13 +311,9 @@ void DlSkCanvasAdapter::DrawAtlas(const sk_sp<DlImage>& atlas,
const DlPaint* paint) {
SkOptionalPaint sk_paint(paint);
sk_sp<SkImage> sk_image = atlas->skia_image();
std::vector<SkColor> sk_colors;
sk_colors.reserve(count);
for (int i = 0; i < count; ++i) {
sk_colors.push_back(colors[i].argb());
}
delegate_->drawAtlas(sk_image.get(), xform, tex, sk_colors.data(), count,
ToSk(mode), ToSk(sampling), cullRect, sk_paint());
const SkColor* sk_colors = reinterpret_cast<const SkColor*>(colors);
delegate_->drawAtlas(sk_image.get(), xform, tex, sk_colors, count, ToSk(mode),
ToSk(sampling), cullRect, sk_paint());
}
void DlSkCanvasAdapter::DrawDisplayList(const sk_sp<DisplayList> display_list,

View File

@ -69,14 +69,8 @@ sk_sp<SkShader> ToSk(const DlColorSource* source) {
if (!source) {
return nullptr;
}
static auto ToSkColors =
[](const DlGradientColorSourceBase* gradient) -> std::vector<SkColor> {
std::vector<SkColor> sk_colors;
sk_colors.reserve(gradient->stop_count());
for (int i = 0; i < gradient->stop_count(); ++i) {
sk_colors.push_back(gradient->colors()[i].argb());
}
return sk_colors;
static auto ToSkColors = [](const DlGradientColorSourceBase* gradient) {
return reinterpret_cast<const SkColor*>(gradient->colors());
};
switch (source->type()) {
case DlColorSourceType::kColor: {
@ -102,9 +96,8 @@ sk_sp<SkShader> ToSk(const DlColorSource* source) {
FML_DCHECK(linear_source != nullptr);
SkPoint pts[] = {linear_source->start_point(),
linear_source->end_point()};
std::vector<SkColor> skcolors = ToSkColors(linear_source);
return SkGradientShader::MakeLinear(
pts, skcolors.data(), linear_source->stops(),
pts, ToSkColors(linear_source), linear_source->stops(),
linear_source->stop_count(), ToSk(linear_source->tile_mode()), 0,
linear_source->matrix_ptr());
}
@ -114,7 +107,7 @@ sk_sp<SkShader> ToSk(const DlColorSource* source) {
FML_DCHECK(radial_source != nullptr);
return SkGradientShader::MakeRadial(
radial_source->center(), radial_source->radius(),
ToSkColors(radial_source).data(), radial_source->stops(),
ToSkColors(radial_source), radial_source->stops(),
radial_source->stop_count(), ToSk(radial_source->tile_mode()), 0,
radial_source->matrix_ptr());
}
@ -125,7 +118,7 @@ sk_sp<SkShader> ToSk(const DlColorSource* source) {
return SkGradientShader::MakeTwoPointConical(
conical_source->start_center(), conical_source->start_radius(),
conical_source->end_center(), conical_source->end_radius(),
ToSkColors(conical_source).data(), conical_source->stops(),
ToSkColors(conical_source), conical_source->stops(),
conical_source->stop_count(), ToSk(conical_source->tile_mode()), 0,
conical_source->matrix_ptr());
}
@ -135,7 +128,7 @@ sk_sp<SkShader> ToSk(const DlColorSource* source) {
FML_DCHECK(sweep_source != nullptr);
return SkGradientShader::MakeSweep(
sweep_source->center().x(), sweep_source->center().y(),
ToSkColors(sweep_source).data(), sweep_source->stops(),
ToSkColors(sweep_source), sweep_source->stops(),
sweep_source->stop_count(), ToSk(sweep_source->tile_mode()),
sweep_source->start(), sweep_source->end(), 0,
sweep_source->matrix_ptr());
@ -282,18 +275,11 @@ sk_sp<SkMaskFilter> ToSk(const DlMaskFilter* filter) {
}
sk_sp<SkVertices> ToSk(const std::shared_ptr<DlVertices>& vertices) {
std::vector<SkColor> sk_colors;
const SkColor* sk_colors_ptr = nullptr;
if (vertices->colors()) {
sk_colors.reserve(vertices->vertex_count());
for (int i = 0; i < vertices->vertex_count(); ++i) {
sk_colors.push_back(vertices->colors()[i].argb());
}
sk_colors_ptr = sk_colors.data();
}
const SkColor* sk_colors =
reinterpret_cast<const SkColor*>(vertices->colors());
return SkVertices::MakeCopy(ToSk(vertices->mode()), vertices->vertex_count(),
vertices->vertices(),
vertices->texture_coordinates(), sk_colors_ptr,
vertices->texture_coordinates(), sk_colors,
vertices->index_count(), vertices->indices());
}

View File

@ -19,7 +19,9 @@ inline SkBlendMode ToSk(DlBlendMode mode) {
}
inline SkColor ToSk(DlColor color) {
return color.argb();
// This is safe because both SkColor and DlColor are backed by ARGB uint32_t.
// See dl_sk_conversions_unittests.cc.
return reinterpret_cast<SkColor&>(color);
}
inline SkPaint::Style ToSk(DlDrawStyle style) {

View File

@ -250,13 +250,9 @@ void DlSkCanvasDispatcher::drawAtlas(const sk_sp<DlImage> atlas,
if (!skia_atlas) {
return;
}
std::vector<SkColor> sk_colors;
sk_colors.reserve(count);
for (int i = 0; i < count; ++i) {
sk_colors.push_back(colors[i].argb());
}
canvas_->drawAtlas(skia_atlas.get(), xform, tex, sk_colors.data(), count,
ToSk(mode), ToSk(sampling), cullRect,
const SkColor* sk_colors = reinterpret_cast<const SkColor*>(colors);
canvas_->drawAtlas(skia_atlas.get(), xform, tex, sk_colors, count, ToSk(mode),
ToSk(sampling), cullRect,
safe_paint(render_with_attributes));
}
void DlSkCanvasDispatcher::drawDisplayList(

View File

@ -156,23 +156,6 @@ const int kHorizontalMiterDiamondPointCount =
(sizeof(kHorizontalMiterDiamondPoints) /
sizeof(kHorizontalMiterDiamondPoints[0]));
namespace {
constexpr uint8_t toC(DlScalar fComp) {
return round(fComp * 255);
}
constexpr uint32_t PremultipliedArgb(const DlColor& color) {
if (color.isOpaque()) {
return color.argb();
}
DlScalar f = color.getAlphaF();
return (color.argb() & 0xFF000000) | //
toC(color.getRedF() * f) << 16 | //
toC(color.getGreenF() * f) << 8 | //
toC(color.getBlueF() * f);
}
} // namespace
class SkImageSampling {
public:
static constexpr SkSamplingOptions kNearestNeighbor =
@ -2543,7 +2526,7 @@ class CanvasCompareTester {
const SkRect ref_bounds,
const std::string& info,
const DlColor bg = DlColor::kTransparent()) {
uint32_t untouched = PremultipliedArgb(bg);
uint32_t untouched = bg.premultipliedArgb();
int pixels_touched = 0;
int pixels_oob = 0;
SkIRect i_bounds = ref_bounds.roundOut();
@ -2628,7 +2611,7 @@ class CanvasCompareTester {
int width = kTestWidth,
int height = kTestHeight,
bool printMismatches = false) {
uint32_t untouched = PremultipliedArgb(bg);
uint32_t untouched = bg.premultipliedArgb();
ASSERT_EQ(test_result->width(), width) << info;
ASSERT_EQ(test_result->height(), height) << info;
SkIRect i_bounds =

View File

@ -114,9 +114,9 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
}},
{"SetColor",
{
{0, 4 + sizeof(DlColor), 0,
{0, 8, 0,
[](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorGREEN)); }},
{0, 4 + sizeof(DlColor), 0,
{0, 8, 0,
[](DlOpReceiver& r) { r.setColor(DlColor(SK_ColorBLUE)); }},
// Reset attribute to default as last entry
@ -137,13 +137,14 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
{"SetColorSource",
{
{0, 96, 0, [](DlOpReceiver& r) { r.setColorSource(&kTestSource1); }},
{0, 152, 0,
// stop_count * (sizeof(float) + sizeof(uint32_t)) = 80
{0, 80 + 6 * 4, 0,
[](DlOpReceiver& r) { r.setColorSource(kTestSource2.get()); }},
{0, 152, 0,
{0, 80 + 6 * 4, 0,
[](DlOpReceiver& r) { r.setColorSource(kTestSource3.get()); }},
{0, 160, 0,
{0, 88 + 6 * 4, 0,
[](DlOpReceiver& r) { r.setColorSource(kTestSource4.get()); }},
{0, 152, 0,
{0, 80 + 6 * 4, 0,
[](DlOpReceiver& r) { r.setColorSource(kTestSource5.get()); }},
// Reset attribute to default as last entry
@ -218,11 +219,11 @@ std::vector<DisplayListInvocationGroup> CreateAllAttributesOps() {
}},
{"SetColorFilter",
{
{0, 40, 0,
{0, 24, 0,
[](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter1); }},
{0, 40, 0,
{0, 24, 0,
[](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter2); }},
{0, 40, 0,
{0, 24, 0,
[](DlOpReceiver& r) { r.setColorFilter(&kTestBlendColorFilter3); }},
{0, 96, 0,
[](DlOpReceiver& r) {
@ -550,15 +551,15 @@ std::vector<DisplayListInvocationGroup> CreateAllRenderingOps() {
}},
{"DrawColor",
{
{1, 32, 1,
{1, 16, 1,
[](DlOpReceiver& r) {
r.drawColor(DlColor(SK_ColorBLUE), DlBlendMode::kSrcIn);
}},
{1, 32, 1,
{1, 16, 1,
[](DlOpReceiver& r) {
r.drawColor(DlColor(SK_ColorBLUE), DlBlendMode::kDstOut);
}},
{1, 32, 1,
{1, 16, 1,
[](DlOpReceiver& r) {
r.drawColor(DlColor(SK_ColorCYAN), DlBlendMode::kSrcIn);
}},
@ -929,7 +930,7 @@ std::vector<DisplayListInvocationGroup> CreateAllRenderingOps() {
DlBlendMode::kSrcIn, kNearestSampling, &cull_rect,
false);
}},
{1, 128, 1,
{1, 48 + 32 + 8 + 8, 1,
[](DlOpReceiver& r) {
static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}};
static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}};
@ -938,7 +939,7 @@ std::vector<DisplayListInvocationGroup> CreateAllRenderingOps() {
DlBlendMode::kSrcIn, kNearestSampling, nullptr,
false);
}},
{1, 144, 1,
{1, 64 + 32 + 8 + 8, 1,
[](DlOpReceiver& r) {
static SkRSXform xforms[] = {{1, 0, 0, 0}, {0, 1, 0, 0}};
static SkRect texs[] = {{10, 10, 20, 20}, {20, 20, 30, 30}};
@ -996,27 +997,27 @@ std::vector<DisplayListInvocationGroup> CreateAllRenderingOps() {
}},
{"DrawShadow",
{
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, false, 1.0);
}},
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath2, DlColor(SK_ColorGREEN), 1.0, false, 1.0);
}},
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath1, DlColor(SK_ColorBLUE), 1.0, false, 1.0);
}},
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 2.0, false, 1.0);
}},
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, true, 1.0);
}},
{1, 64, 1,
{1, 48, 1,
[](DlOpReceiver& r) {
r.drawShadow(kTestPath1, DlColor(SK_ColorGREEN), 1.0, false, 2.5);
}},

View File

@ -194,7 +194,12 @@ void DlDispatcherBase::setDrawStyle(flutter::DlDrawStyle style) {
// |flutter::DlOpReceiver|
void DlDispatcherBase::setColor(flutter::DlColor color) {
paint_.color = skia_conversions::ToColor(color);
paint_.color = {
color.getRedF(),
color.getGreenF(),
color.getBlueF(),
color.getAlphaF(),
};
}
// |flutter::DlOpReceiver|
@ -1364,7 +1369,12 @@ void TextFrameDispatcher::setDrawStyle(flutter::DlDrawStyle style) {
// |flutter::DlOpReceiver|
void TextFrameDispatcher::setColor(flutter::DlColor color) {
paint_.color = skia_conversions::ToColor(color);
paint_.color = {
color.getRedF(),
color.getGreenF(),
color.getBlueF(),
color.getAlphaF(),
};
}
// |flutter::DlOpReceiver|

View File

@ -164,8 +164,6 @@ Size ToSize(const SkPoint& point) {
}
Color ToColor(const flutter::DlColor& color) {
FML_DCHECK(color.getColorSpace() == flutter::DlColorSpace::kExtendedSRGB ||
color.getColorSpace() == flutter::DlColorSpace::kSRGB);
return {
static_cast<Scalar>(color.getRedF()), //
static_cast<Scalar>(color.getGreenF()), //

View File

@ -45,15 +45,10 @@ void CanvasGradient::initLinear(const tonic::Float32List& end_points,
SkPoint p0 = SkPoint::Make(end_points[0], end_points[1]);
SkPoint p1 = SkPoint::Make(end_points[2], end_points[3]);
std::vector<DlColor> dl_colors;
dl_colors.reserve(colors.num_elements());
for (int i = 0; i < colors.num_elements(); ++i) {
/// TODO(gaaclarke): Make this preserve wide gamut colors.
dl_colors.emplace_back(DlColor(colors[i]));
}
const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());
dl_shader_ = DlColorSource::MakeLinear(
p0, p1, colors.num_elements(), dl_colors.data(), color_stops.data(),
p0, p1, colors.num_elements(), colors_array, color_stops.data(),
tile_mode, has_matrix ? &sk_matrix : nullptr);
// Just a sanity check, all gradient shaders should be thread-safe
FML_DCHECK(dl_shader_->isUIThreadSafe());
@ -78,15 +73,11 @@ void CanvasGradient::initRadial(double center_x,
sk_matrix = ToSkMatrix(matrix4);
}
std::vector<DlColor> dl_colors;
dl_colors.reserve(colors.num_elements());
for (int i = 0; i < colors.num_elements(); ++i) {
dl_colors.emplace_back(DlColor(colors[i]));
}
const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());
dl_shader_ = DlColorSource::MakeRadial(
SkPoint::Make(SafeNarrow(center_x), SafeNarrow(center_y)),
SafeNarrow(radius), colors.num_elements(), dl_colors.data(),
SafeNarrow(radius), colors.num_elements(), colors_array,
color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr);
// Just a sanity check, all gradient shaders should be thread-safe
FML_DCHECK(dl_shader_->isUIThreadSafe());
@ -112,17 +103,13 @@ void CanvasGradient::initSweep(double center_x,
sk_matrix = ToSkMatrix(matrix4);
}
std::vector<DlColor> dl_colors;
dl_colors.reserve(colors.num_elements());
for (int i = 0; i < colors.num_elements(); ++i) {
dl_colors.emplace_back(DlColor(colors[i]));
}
const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());
dl_shader_ = DlColorSource::MakeSweep(
SkPoint::Make(SafeNarrow(center_x), SafeNarrow(center_y)),
SafeNarrow(start_angle) * 180.0f / static_cast<float>(M_PI),
SafeNarrow(end_angle) * 180.0f / static_cast<float>(M_PI),
colors.num_elements(), dl_colors.data(), color_stops.data(), tile_mode,
colors.num_elements(), colors_array, color_stops.data(), tile_mode,
has_matrix ? &sk_matrix : nullptr);
// Just a sanity check, all gradient shaders should be thread-safe
FML_DCHECK(dl_shader_->isUIThreadSafe());
@ -150,17 +137,13 @@ void CanvasGradient::initTwoPointConical(double start_x,
sk_matrix = ToSkMatrix(matrix4);
}
std::vector<DlColor> dl_colors;
dl_colors.reserve(colors.num_elements());
for (int i = 0; i < colors.num_elements(); ++i) {
dl_colors.emplace_back(DlColor(colors[i]));
}
const DlColor* colors_array = reinterpret_cast<const DlColor*>(colors.data());
dl_shader_ = DlColorSource::MakeConical(
SkPoint::Make(SafeNarrow(start_x), SafeNarrow(start_y)),
SafeNarrow(start_radius),
SkPoint::Make(SafeNarrow(end_x), SafeNarrow(end_y)),
SafeNarrow(end_radius), colors.num_elements(), dl_colors.data(),
SafeNarrow(end_radius), colors.num_elements(), colors_array,
color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr);
// Just a sanity check, all gradient shaders should be thread-safe
FML_DCHECK(dl_shader_->isUIThreadSafe());

View File

@ -326,24 +326,7 @@ std::ostream& operator<<(std::ostream& os, const DlFilterMode& mode) {
}
std::ostream& operator<<(std::ostream& os, const DlColor& color) {
const char* color_space;
switch(color.getColorSpace()) {
case flutter::DlColorSpace::kSRGB:
color_space = "srgb";
break;
case flutter::DlColorSpace::kExtendedSRGB:
color_space = "srgb_xr";
break;
case flutter::DlColorSpace::kDisplayP3:
color_space = "p3";
break;
}
return os << "DlColor(" << //
color.getAlphaF() << ", " << //
color.getRedF() << ", " << //
color.getGreenF() << ", " << //
color.getBlueF() << ", " << //
color_space << ")";
return os << "DlColor(" << std::hex << color.argb() << std::dec << ")";
}
std::ostream& operator<<(std::ostream& os, DlImageSampling sampling) {