LibWeb: Store gradient color stops separately
Gradient display-list commands currently carry a Vector<Gfx::ColorStop>, which keeps command payloads tied to an owning container. Split resolved gradient stops into parallel color and position arrays so the display list can later store those arrays as contiguous inline data. This keeps the painting behavior the same while removing another nested object shape that does not map cleanly to the flat command-buffer format
This commit is contained in:
parent
36a366e2e9
commit
ce6ef14587
3 changed files with 71 additions and 48 deletions
|
|
@ -364,29 +364,23 @@ static SkGradientShader::Interpolation to_skia_interpolation(CSS::ColorInterpola
|
|||
void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& command)
|
||||
{
|
||||
auto const& linear_gradient_data = command.linear_gradient_data;
|
||||
auto const& color_stop_list = linear_gradient_data.color_stops.list;
|
||||
auto const& repeat_length = linear_gradient_data.color_stops.repeat_length;
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
auto const& color_stop_colors = linear_gradient_data.color_stops.colors;
|
||||
auto const& color_stop_positions = linear_gradient_data.color_stops.positions;
|
||||
VERIFY(!color_stop_colors.is_empty());
|
||||
VERIFY(color_stop_colors.size() == color_stop_positions.size());
|
||||
|
||||
Vector<SkColor4f> colors;
|
||||
Vector<SkScalar> positions;
|
||||
auto const first_position = repeat_length.has_value() ? color_stop_list.first().position : 0.f;
|
||||
for (size_t stop_index = 0; stop_index < color_stop_list.size(); stop_index++) {
|
||||
auto const& stop = color_stop_list[stop_index];
|
||||
if (stop_index > 0 && stop == color_stop_list[stop_index - 1])
|
||||
continue;
|
||||
|
||||
colors.append(to_skia_color4f(stop.color));
|
||||
positions.append((stop.position - first_position) / repeat_length.value_or(1));
|
||||
}
|
||||
colors.ensure_capacity(color_stop_colors.size());
|
||||
for (auto color : color_stop_colors)
|
||||
colors.unchecked_append(to_skia_color4f(color));
|
||||
|
||||
auto rect = command.gradient_rect.to_type<float>();
|
||||
auto length = calculate_gradient_length<float>(rect.size(), linear_gradient_data.gradient_angle);
|
||||
|
||||
// Starting and ending points before rotation (0deg / "to top")
|
||||
auto rect_center = rect.center();
|
||||
auto start = rect_center.translated(0, (.5f - first_position) * length);
|
||||
auto end = start.translated(0, repeat_length.value_or(1) * -length);
|
||||
auto start = rect_center.translated(0, (.5f - linear_gradient_data.first_stop_position) * length);
|
||||
auto end = start.translated(0, linear_gradient_data.repeat_length * -length);
|
||||
Array const points { to_skia_point(start), to_skia_point(end) };
|
||||
|
||||
SkMatrix matrix;
|
||||
|
|
@ -394,7 +388,7 @@ void DisplayListPlayerSkia::paint_linear_gradient(PaintLinearGradient const& com
|
|||
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
auto interpolation = to_skia_interpolation(linear_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kRepeat, interpolation, &matrix);
|
||||
auto shader = SkGradientShader::MakeLinear(points.data(), colors.data(), color_space, color_stop_positions.data(), color_stop_positions.size(), SkTileMode::kRepeat, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setDither(true);
|
||||
|
|
@ -711,18 +705,15 @@ void DisplayListPlayerSkia::draw_rect(DrawRect const& command)
|
|||
void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& command)
|
||||
{
|
||||
auto const& radial_gradient_data = command.radial_gradient_data;
|
||||
auto const& color_stop_list = radial_gradient_data.color_stops.list;
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
auto const& color_stop_colors = radial_gradient_data.color_stops.colors;
|
||||
auto const& color_stop_positions = radial_gradient_data.color_stops.positions;
|
||||
VERIFY(!color_stop_colors.is_empty());
|
||||
VERIFY(color_stop_colors.size() == color_stop_positions.size());
|
||||
|
||||
Vector<SkColor4f> colors;
|
||||
Vector<SkScalar> positions;
|
||||
for (size_t stop_index = 0; stop_index < color_stop_list.size(); stop_index++) {
|
||||
auto const& stop = color_stop_list[stop_index];
|
||||
if (stop_index > 0 && stop == color_stop_list[stop_index - 1])
|
||||
continue;
|
||||
colors.append(to_skia_color4f(stop.color));
|
||||
positions.append(stop.position);
|
||||
}
|
||||
colors.ensure_capacity(color_stop_colors.size());
|
||||
for (auto color : color_stop_colors)
|
||||
colors.unchecked_append(to_skia_color4f(color));
|
||||
|
||||
auto const& rect = command.rect;
|
||||
auto center = to_skia_point(command.center.translated(command.rect.location()));
|
||||
|
|
@ -739,7 +730,7 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com
|
|||
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
auto interpolation = to_skia_interpolation(radial_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeRadial(center, size.height(), colors.data(), color_space, positions.data(), positions.size(), tile_mode, interpolation, &matrix);
|
||||
auto shader = SkGradientShader::MakeRadial(center, size.height(), colors.data(), color_space, color_stop_positions.data(), color_stop_positions.size(), tile_mode, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setDither(true);
|
||||
|
|
@ -751,18 +742,15 @@ void DisplayListPlayerSkia::paint_radial_gradient(PaintRadialGradient const& com
|
|||
void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& command)
|
||||
{
|
||||
auto const& conic_gradient_data = command.conic_gradient_data;
|
||||
auto const& color_stop_list = conic_gradient_data.color_stops.list;
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
auto const& color_stop_colors = conic_gradient_data.color_stops.colors;
|
||||
auto const& color_stop_positions = conic_gradient_data.color_stops.positions;
|
||||
VERIFY(!color_stop_colors.is_empty());
|
||||
VERIFY(color_stop_colors.size() == color_stop_positions.size());
|
||||
|
||||
Vector<SkColor4f> colors;
|
||||
Vector<SkScalar> positions;
|
||||
for (size_t stop_index = 0; stop_index < color_stop_list.size(); stop_index++) {
|
||||
auto const& stop = color_stop_list[stop_index];
|
||||
if (stop_index > 0 && stop == color_stop_list[stop_index - 1])
|
||||
continue;
|
||||
colors.append(to_skia_color4f(stop.color));
|
||||
positions.append(stop.position);
|
||||
}
|
||||
colors.ensure_capacity(color_stop_colors.size());
|
||||
for (auto color : color_stop_colors)
|
||||
colors.unchecked_append(to_skia_color4f(color));
|
||||
|
||||
auto const& rect = command.rect;
|
||||
auto center = command.position.translated(rect.location()).to_type<float>();
|
||||
|
|
@ -771,7 +759,7 @@ void DisplayListPlayerSkia::paint_conic_gradient(PaintConicGradient const& comma
|
|||
matrix.setRotate(-90 + conic_gradient_data.start_angle, center.x(), center.y());
|
||||
auto color_space = SkColorSpace::MakeSRGB();
|
||||
auto interpolation = to_skia_interpolation(conic_gradient_data.interpolation_method);
|
||||
auto shader = SkGradientShader::MakeSweep(center.x(), center.y(), colors.data(), color_space, positions.data(), positions.size(), SkTileMode::kRepeat, 0, 360, interpolation, &matrix);
|
||||
auto shader = SkGradientShader::MakeSweep(center.x(), center.y(), colors.data(), color_space, color_stop_positions.data(), color_stop_positions.size(), SkTileMode::kRepeat, 0, 360, interpolation, &matrix);
|
||||
|
||||
SkPaint paint;
|
||||
paint.setDither(true);
|
||||
|
|
|
|||
|
|
@ -6,24 +6,24 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <AK/Span.h>
|
||||
#include <AK/Optional.h>
|
||||
#include <AK/Vector.h>
|
||||
#include <LibGfx/Gradients.h>
|
||||
#include <LibGfx/Color.h>
|
||||
#include <LibWeb/CSS/StyleValues/ColorInterpolationMethodStyleValue.h>
|
||||
#include <LibWeb/Forward.h>
|
||||
|
||||
namespace Web::Painting {
|
||||
|
||||
using ColorStopList = Vector<Gfx::ColorStop, 4>;
|
||||
|
||||
struct ColorStopData {
|
||||
ColorStopList list;
|
||||
Optional<float> repeat_length;
|
||||
Vector<Color, 4> colors;
|
||||
Vector<float, 4> positions;
|
||||
bool repeating { false };
|
||||
};
|
||||
|
||||
struct LinearGradientData {
|
||||
float gradient_angle;
|
||||
float first_stop_position { 0 };
|
||||
float repeat_length { 1 };
|
||||
ColorStopData color_stops;
|
||||
CSS::ColorInterpolationMethodStyleValue::ColorInterpolationMethod interpolation_method;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -21,6 +21,30 @@
|
|||
|
||||
namespace Web::Painting {
|
||||
|
||||
using ColorStopList = Vector<Gfx::ColorStop, 4>;
|
||||
|
||||
struct ResolvedColorStopData {
|
||||
ColorStopList list;
|
||||
Optional<float> repeat_length;
|
||||
bool repeating { false };
|
||||
};
|
||||
|
||||
static ColorStopData to_color_stop_data(ColorStopList const& color_stop_list, bool repeating, auto to_position)
|
||||
{
|
||||
ColorStopData data;
|
||||
data.colors.ensure_capacity(color_stop_list.size());
|
||||
data.positions.ensure_capacity(color_stop_list.size());
|
||||
for (auto const& color_stop : color_stop_list) {
|
||||
auto position = to_position(color_stop.position);
|
||||
if (!data.colors.is_empty() && data.colors.last() == color_stop.color && data.positions.last() == position)
|
||||
continue;
|
||||
data.colors.unchecked_append(color_stop.color);
|
||||
data.positions.unchecked_append(position);
|
||||
}
|
||||
data.repeating = repeating;
|
||||
return data;
|
||||
}
|
||||
|
||||
static ColorStopList replace_transition_hints_with_normal_color_stops(ColorStopList const& color_stop_list)
|
||||
{
|
||||
ColorStopList stops_with_replaced_transition_hints;
|
||||
|
|
@ -125,7 +149,7 @@ static ColorStopList expand_color_stops_for_painting(ColorStopList const& color_
|
|||
return replace_transition_hints_with_normal_color_stops(expanded);
|
||||
}
|
||||
|
||||
static ColorStopData resolve_color_stop_positions(Layout::NodeWithStyle const& node, Vector<CSS::ColorStopListElement> const& color_stop_list, auto resolve_position_to_float, bool repeating)
|
||||
static ResolvedColorStopData resolve_color_stop_positions(Layout::NodeWithStyle const& node, Vector<CSS::ColorStopListElement> const& color_stop_list, auto resolve_position_to_float, bool repeating)
|
||||
{
|
||||
VERIFY(!color_stop_list.is_empty());
|
||||
ColorStopList resolved_color_stops;
|
||||
|
|
@ -234,7 +258,12 @@ LinearGradientData resolve_linear_gradient_data(Layout::NodeWithStyle const& nod
|
|||
// Replace transition hints for painting; keep repeat_length for Skia's native tiling
|
||||
resolved_color_stops.list = replace_transition_hints_with_normal_color_stops(resolved_color_stops.list);
|
||||
|
||||
return { gradient_angle, resolved_color_stops, linear_gradient.interpolation_method() };
|
||||
auto repeat_length = resolved_color_stops.repeat_length.value_or(1);
|
||||
auto first_stop_position = resolved_color_stops.repeat_length.has_value() ? resolved_color_stops.list.first().position : 0.f;
|
||||
auto color_stop_data = to_color_stop_data(resolved_color_stops.list, resolved_color_stops.repeating, [&](float position) {
|
||||
return (position - first_stop_position) / repeat_length;
|
||||
});
|
||||
return { gradient_angle, first_stop_position, repeat_length, move(color_stop_data), linear_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyle const& node, CSS::ConicGradientStyleValue const& conic_gradient)
|
||||
|
|
@ -250,7 +279,10 @@ ConicGradientData resolve_conic_gradient_data(Layout::NodeWithStyle const& node,
|
|||
resolved_color_stops.list = expand_color_stops_for_painting(resolved_color_stops.list, resolved_color_stops.repeat_length);
|
||||
resolved_color_stops.repeat_length = {};
|
||||
|
||||
return { conic_gradient.angle_degrees(), resolved_color_stops, conic_gradient.interpolation_method() };
|
||||
auto color_stop_data = to_color_stop_data(resolved_color_stops.list, resolved_color_stops.repeating, [](float position) {
|
||||
return position;
|
||||
});
|
||||
return { conic_gradient.angle_degrees(), move(color_stop_data), conic_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyle const& node, CSSPixelSize gradient_size, CSS::RadialGradientStyleValue const& radial_gradient)
|
||||
|
|
@ -266,7 +298,10 @@ RadialGradientData resolve_radial_gradient_data(Layout::NodeWithStyle const& nod
|
|||
resolved_color_stops.list = expand_color_stops_for_painting(resolved_color_stops.list, resolved_color_stops.repeat_length);
|
||||
resolved_color_stops.repeat_length = {};
|
||||
|
||||
return { resolved_color_stops, radial_gradient.interpolation_method() };
|
||||
auto color_stop_data = to_color_stop_data(resolved_color_stops.list, resolved_color_stops.repeating, [](float position) {
|
||||
return position;
|
||||
});
|
||||
return { move(color_stop_data), radial_gradient.interpolation_method() };
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue