-
Notifications
You must be signed in to change notification settings - Fork 6k
Framework wide color linear gradients #54748
Changes from all commits
408f549
fc754cf
d9c6a96
976963c
5c0887f
0419148
66b244e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -24,13 +24,14 @@ void CanvasGradient::Create(Dart_Handle wrapper) { | |
} | ||
|
||
void CanvasGradient::initLinear(const tonic::Float32List& end_points, | ||
const tonic::Int32List& colors, | ||
const tonic::Float32List& colors, | ||
const tonic::Float32List& color_stops, | ||
DlTileMode tile_mode, | ||
const tonic::Float64List& matrix4) { | ||
FML_DCHECK(end_points.num_elements() == 4); | ||
FML_DCHECK(colors.num_elements() == color_stops.num_elements() || | ||
FML_DCHECK(colors.num_elements() == (color_stops.num_elements() * 4) || | ||
color_stops.data() == nullptr); | ||
int num_colors = colors.num_elements() / 4; | ||
|
||
static_assert(sizeof(SkPoint) == sizeof(float) * 2, | ||
"SkPoint doesn't use floats."); | ||
|
@@ -46,28 +47,32 @@ 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])); | ||
dl_colors.reserve(num_colors); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we have a helper method, or would that involve unnecessary copying? I thought the compiler optimized the case of returning a vector...?? Another way is to create the vector on the local stack and then hand it into the converter method by reference. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You can't have a vector on a stack. It will always allocate memory on the heap. The size is needed to be known at compilation time in order to put something on the stack (without trickery). I have a proposition in an above thread for using an I think avoiding the copying will require DlColorSource some mechanism to read from the tonic collection directly. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The data has to be heap allocated because it is growable, that will happen whether a helper function is used or not. I'm referring to the object itself, but I suppose that the object isn't very big whether it is stack allocated or not. It's a vtable + data pointer + allocated size + used size. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, I see, sorry I thought this was still related to the heap discussion. Yes we could have a helper function and yes C++ would perform the return value optimization. |
||
for (int i = 0; i < colors.num_elements(); i += 4) { | ||
DlScalar a = colors[i + 0]; | ||
DlScalar r = colors[i + 1]; | ||
DlScalar g = colors[i + 2]; | ||
DlScalar b = colors[i + 3]; | ||
dl_colors.emplace_back(DlColor(a, r, g, b, DlColorSpace::kExtendedSRGB)); | ||
} | ||
|
||
dl_shader_ = DlColorSource::MakeLinear( | ||
p0, p1, colors.num_elements(), dl_colors.data(), color_stops.data(), | ||
tile_mode, has_matrix ? &sk_matrix : nullptr); | ||
dl_shader_ = DlColorSource::MakeLinear(p0, p1, num_colors, dl_colors.data(), | ||
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()); | ||
} | ||
|
||
void CanvasGradient::initRadial(double center_x, | ||
double center_y, | ||
double radius, | ||
const tonic::Int32List& colors, | ||
const tonic::Float32List& colors, | ||
const tonic::Float32List& color_stops, | ||
DlTileMode tile_mode, | ||
const tonic::Float64List& matrix4) { | ||
FML_DCHECK(colors.num_elements() == color_stops.num_elements() || | ||
FML_DCHECK(colors.num_elements() == (color_stops.num_elements() * 4) || | ||
color_stops.data() == nullptr); | ||
int num_colors = colors.num_elements() / 4; | ||
|
||
static_assert(sizeof(SkColor) == sizeof(int32_t), | ||
"SkColor doesn't use int32_t."); | ||
|
@@ -79,29 +84,34 @@ void CanvasGradient::initRadial(double center_x, | |
} | ||
|
||
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])); | ||
dl_colors.reserve(num_colors); | ||
for (int i = 0; i < colors.num_elements(); i += 4) { | ||
DlScalar a = colors[i + 0]; | ||
DlScalar r = colors[i + 1]; | ||
DlScalar g = colors[i + 2]; | ||
DlScalar b = colors[i + 3]; | ||
dl_colors.emplace_back(DlColor(a, r, g, b, DlColorSpace::kExtendedSRGB)); | ||
} | ||
|
||
dl_shader_ = DlColorSource::MakeRadial( | ||
SkPoint::Make(SafeNarrow(center_x), SafeNarrow(center_y)), | ||
SafeNarrow(radius), colors.num_elements(), dl_colors.data(), | ||
color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr); | ||
SafeNarrow(radius), num_colors, dl_colors.data(), 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()); | ||
} | ||
|
||
void CanvasGradient::initSweep(double center_x, | ||
double center_y, | ||
const tonic::Int32List& colors, | ||
const tonic::Float32List& colors, | ||
const tonic::Float32List& color_stops, | ||
DlTileMode tile_mode, | ||
double start_angle, | ||
double end_angle, | ||
const tonic::Float64List& matrix4) { | ||
FML_DCHECK(colors.num_elements() == color_stops.num_elements() || | ||
FML_DCHECK(colors.num_elements() == (color_stops.num_elements() * 4) || | ||
color_stops.data() == nullptr); | ||
int num_colors = colors.num_elements() / 4; | ||
|
||
static_assert(sizeof(SkColor) == sizeof(int32_t), | ||
"SkColor doesn't use int32_t."); | ||
|
@@ -113,16 +123,20 @@ void CanvasGradient::initSweep(double center_x, | |
} | ||
|
||
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])); | ||
dl_colors.reserve(num_colors); | ||
for (int i = 0; i < colors.num_elements(); i += 4) { | ||
DlScalar a = colors[i + 0]; | ||
DlScalar r = colors[i + 1]; | ||
DlScalar g = colors[i + 2]; | ||
DlScalar b = colors[i + 3]; | ||
dl_colors.emplace_back(DlColor(a, r, g, b, DlColorSpace::kExtendedSRGB)); | ||
} | ||
|
||
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, | ||
SafeNarrow(end_angle) * 180.0f / static_cast<float>(M_PI), num_colors, | ||
dl_colors.data(), 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()); | ||
|
@@ -134,12 +148,13 @@ void CanvasGradient::initTwoPointConical(double start_x, | |
double end_x, | ||
double end_y, | ||
double end_radius, | ||
const tonic::Int32List& colors, | ||
const tonic::Float32List& colors, | ||
const tonic::Float32List& color_stops, | ||
DlTileMode tile_mode, | ||
const tonic::Float64List& matrix4) { | ||
FML_DCHECK(colors.num_elements() == color_stops.num_elements() || | ||
FML_DCHECK(colors.num_elements() == (color_stops.num_elements() * 4) || | ||
color_stops.data() == nullptr); | ||
int num_colors = colors.num_elements() / 4; | ||
|
||
static_assert(sizeof(SkColor) == sizeof(int32_t), | ||
"SkColor doesn't use int32_t."); | ||
|
@@ -151,17 +166,21 @@ void CanvasGradient::initTwoPointConical(double start_x, | |
} | ||
|
||
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])); | ||
dl_colors.reserve(num_colors); | ||
for (int i = 0; i < colors.num_elements(); i += 4) { | ||
DlScalar a = colors[i + 0]; | ||
DlScalar r = colors[i + 1]; | ||
DlScalar g = colors[i + 2]; | ||
DlScalar b = colors[i + 3]; | ||
dl_colors.emplace_back(DlColor(a, r, g, b, DlColorSpace::kExtendedSRGB)); | ||
} | ||
|
||
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(), | ||
color_stops.data(), tile_mode, has_matrix ? &sk_matrix : nullptr); | ||
SafeNarrow(end_radius), num_colors, dl_colors.data(), 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()); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I remember talking about preserving the CS, but I'm guessing that gradients are going to want to normalize to a similar CS for lerping - and extendedSRGB is probably the best for fractional combinations?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do preserve the colorspace from the users perspective. The conversion to extended srgb only happens when communicating the values to the engine.