LibWeb: Draw a scrollbar gutter when the scrollbar is enlarged

This commit is contained in:
Timothy Flynn 2025-04-21 09:10:55 -04:00 committed by Tim Flynn
commit 66e422b4f1
Notes: github-actions[bot] 2025-04-22 15:30:14 +00:00
7 changed files with 53 additions and 35 deletions

View file

@ -403,14 +403,15 @@ struct PaintNestedDisplayList {
}; };
struct PaintScrollBar { struct PaintScrollBar {
int scroll_frame_id; int scroll_frame_id { 0 };
Gfx::IntRect rect; Gfx::IntRect gutter_rect;
Gfx::IntRect thumb_rect;
CSSPixelFraction scroll_size; CSSPixelFraction scroll_size;
bool vertical; bool vertical;
void translate_by(Gfx::IntPoint const& offset) void translate_by(Gfx::IntPoint const& offset)
{ {
rect.translate_by(offset); thumb_rect.translate_by(offset);
} }
}; };

View file

@ -69,10 +69,10 @@ void DisplayListPlayer::execute_impl(DisplayList& display_list, ScrollStateSnaps
auto scroll_offset = scroll_state.own_offset_for_frame_with_id(paint_scroll_bar.scroll_frame_id); auto scroll_offset = scroll_state.own_offset_for_frame_with_id(paint_scroll_bar.scroll_frame_id);
if (paint_scroll_bar.vertical) { if (paint_scroll_bar.vertical) {
auto offset = scroll_offset.y() * paint_scroll_bar.scroll_size; auto offset = scroll_offset.y() * paint_scroll_bar.scroll_size;
paint_scroll_bar.rect.translate_by(0, -offset.to_int() * device_pixels_per_css_pixel); paint_scroll_bar.thumb_rect.translate_by(0, -offset.to_int() * device_pixels_per_css_pixel);
} else { } else {
auto offset = scroll_offset.x() * paint_scroll_bar.scroll_size; auto offset = scroll_offset.x() * paint_scroll_bar.scroll_size;
paint_scroll_bar.rect.translate_by(-offset.to_int() * device_pixels_per_css_pixel, 0); paint_scroll_bar.thumb_rect.translate_by(-offset.to_int() * device_pixels_per_css_pixel, 0);
} }
} }

View file

@ -993,16 +993,23 @@ void DisplayListPlayerSkia::paint_nested_display_list(PaintNestedDisplayList con
void DisplayListPlayerSkia::paint_scrollbar(PaintScrollBar const& command) void DisplayListPlayerSkia::paint_scrollbar(PaintScrollBar const& command)
{ {
auto rect = to_skia_rect(command.rect); auto gutter_rect = to_skia_rect(command.gutter_rect);
auto radius = rect.width() / 2;
auto rrect = SkRRect::MakeRectXY(rect, radius, radius); auto thumb_rect = to_skia_rect(command.thumb_rect);
auto radius = thumb_rect.width() / 2;
auto thumb_rrect = SkRRect::MakeRectXY(thumb_rect, radius, radius);
auto& canvas = surface().canvas(); auto& canvas = surface().canvas();
auto fill_color = Color(Color::NamedColor::DarkGray).with_alpha(128); auto gutter_fill_color = Color(Color::NamedColor::WarmGray).with_alpha(192);
SkPaint fill_paint; SkPaint gutter_fill_paint;
fill_paint.setColor(to_skia_color(fill_color)); gutter_fill_paint.setColor(to_skia_color(gutter_fill_color));
canvas.drawRRect(rrect, fill_paint); canvas.drawRect(gutter_rect, gutter_fill_paint);
auto thumb_fill_color = Color(Color::NamedColor::DarkGray).with_alpha(gutter_rect.isEmpty() ? 128 : 192);
SkPaint thumb_fill_paint;
thumb_fill_paint.setColor(to_skia_color(thumb_fill_color));
canvas.drawRRect(thumb_rrect, thumb_fill_paint);
auto stroke_color = Color(Color::NamedColor::LightGray).with_alpha(128); auto stroke_color = Color(Color::NamedColor::LightGray).with_alpha(128);
SkPaint stroke_paint; SkPaint stroke_paint;
@ -1010,7 +1017,7 @@ void DisplayListPlayerSkia::paint_scrollbar(PaintScrollBar const& command)
stroke_paint.setStrokeWidth(1); stroke_paint.setStrokeWidth(1);
stroke_paint.setAntiAlias(true); stroke_paint.setAntiAlias(true);
stroke_paint.setColor(to_skia_color(stroke_color)); stroke_paint.setColor(to_skia_color(stroke_color));
canvas.drawRRect(rrect, stroke_paint); canvas.drawRRect(thumb_rrect, stroke_paint);
} }
void DisplayListPlayerSkia::apply_opacity(ApplyOpacity const& command) void DisplayListPlayerSkia::apply_opacity(ApplyOpacity const& command)

View file

@ -404,11 +404,12 @@ void DisplayListRecorder::draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a
.thickness = thickness }); .thickness = thickness });
} }
void DisplayListRecorder::paint_scrollbar(int scroll_frame_id, Gfx::IntRect rect, CSSPixelFraction scroll_size, bool vertical) void DisplayListRecorder::paint_scrollbar(int scroll_frame_id, Gfx::IntRect gutter_rect, Gfx::IntRect thumb_rect, CSSPixelFraction scroll_size, bool vertical)
{ {
append(PaintScrollBar { append(PaintScrollBar {
.scroll_frame_id = scroll_frame_id, .scroll_frame_id = scroll_frame_id,
.rect = rect, .gutter_rect = gutter_rect,
.thumb_rect = thumb_rect,
.scroll_size = scroll_size, .scroll_size = scroll_size,
.vertical = vertical }); .vertical = vertical });
} }

View file

@ -146,7 +146,7 @@ public:
void draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness); void draw_triangle_wave(Gfx::IntPoint a_p1, Gfx::IntPoint a_p2, Color color, int amplitude, int thickness);
void paint_scrollbar(int scroll_frame_id, Gfx::IntRect, CSSPixelFraction scroll_size, bool vertical); void paint_scrollbar(int scroll_frame_id, Gfx::IntRect gutter_rect, Gfx::IntRect thumb_rect, CSSPixelFraction scroll_size, bool vertical);
void apply_opacity(float opacity); void apply_opacity(float opacity);
void apply_compositing_and_blending_operator(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator); void apply_compositing_and_blending_operator(Gfx::CompositingAndBlendingOperator compositing_and_blending_operator);

View file

@ -414,16 +414,22 @@ Optional<PaintableBox::ScrollbarData> PaintableBox::compute_scrollbar_data(Scrol
auto min_thumb_length = min(scrollbar_rect_length, 24); auto min_thumb_length = min(scrollbar_rect_length, 24);
auto thumb_length = max(scrollbar_rect_length * (scrollport_size / scroll_overflow_size), min_thumb_length); auto thumb_length = max(scrollbar_rect_length * (scrollport_size / scroll_overflow_size), min_thumb_length);
CSSPixelFraction scroll_size = 0; ScrollbarData scrollbar_data;
if (scroll_overflow_size > scrollport_size)
scroll_size = (scrollbar_rect_length - thumb_length) / (scroll_overflow_size - scrollport_size);
CSSPixelRect rect;
if (is_horizontal)
rect = { padding_rect.left(), padding_rect.bottom() - thickness, thumb_length, thickness };
else
rect = { padding_rect.right() - thickness, padding_rect.top(), thickness, thumb_length };
return PaintableBox::ScrollbarData { rect, scroll_size }; if (scroll_overflow_size > scrollport_size)
scrollbar_data.scroll_length = (scrollbar_rect_length - thumb_length) / (scroll_overflow_size - scrollport_size);
if (is_horizontal) {
if (m_draw_enlarged_horizontal_scrollbar)
scrollbar_data.gutter_rect = { padding_rect.left(), padding_rect.bottom() - thickness, padding_rect.width(), thickness };
scrollbar_data.thumb_rect = { padding_rect.left(), padding_rect.bottom() - thickness, thumb_length, thickness };
} else {
if (m_draw_enlarged_vertical_scrollbar)
scrollbar_data.gutter_rect = { padding_rect.right() - thickness, padding_rect.top(), thickness, padding_rect.height() };
scrollbar_data.thumb_rect = { padding_rect.right() - thickness, padding_rect.top(), thickness, thumb_length };
}
return scrollbar_data;
} }
void PaintableBox::paint(PaintContext& context, PaintPhase phase) const void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
@ -473,15 +479,17 @@ void PaintableBox::paint(PaintContext& context, PaintPhase phase) const
} }
} }
if (g_paint_viewport_scrollbars || !is_viewport()) { if (phase == PaintPhase::Overlay && (g_paint_viewport_scrollbars || !is_viewport()) && computed_values().scrollbar_width() != CSS::ScrollbarWidth::None) {
auto scrollbar_width = computed_values().scrollbar_width(); if (auto scrollbar_data = compute_scrollbar_data(ScrollDirection::Vertical); scrollbar_data.has_value()) {
if (phase == PaintPhase::Overlay && scrollbar_width != CSS::ScrollbarWidth::None) { auto gutter_rect = context.rounded_device_rect(scrollbar_data->gutter_rect).to_type<int>();
if (auto scrollbar_data = compute_scrollbar_data(ScrollDirection::Vertical); scrollbar_data.has_value()) { auto thumb_rect = context.rounded_device_rect(scrollbar_data->thumb_rect).to_type<int>();
context.display_list_recorder().paint_scrollbar(own_scroll_frame_id().value(), context.rounded_device_rect(scrollbar_data->thumb_rect).to_type<int>(), scrollbar_data->scroll_length, true); context.display_list_recorder().paint_scrollbar(own_scroll_frame_id().value(), gutter_rect, thumb_rect, scrollbar_data->scroll_length, true);
} }
if (auto scrollbar_data = compute_scrollbar_data(ScrollDirection::Horizontal); scrollbar_data.has_value()) {
context.display_list_recorder().paint_scrollbar(own_scroll_frame_id().value(), context.rounded_device_rect(scrollbar_data->thumb_rect).to_type<int>(), scrollbar_data->scroll_length, false); if (auto scrollbar_data = compute_scrollbar_data(ScrollDirection::Horizontal); scrollbar_data.has_value()) {
} auto gutter_rect = context.rounded_device_rect(scrollbar_data->gutter_rect).to_type<int>();
auto thumb_rect = context.rounded_device_rect(scrollbar_data->thumb_rect).to_type<int>();
context.display_list_recorder().paint_scrollbar(own_scroll_frame_id().value(), gutter_rect, thumb_rect, scrollbar_data->scroll_length, false);
} }
} }

View file

@ -258,8 +258,9 @@ protected:
virtual CSSPixelRect compute_absolute_paint_rect() const; virtual CSSPixelRect compute_absolute_paint_rect() const;
struct ScrollbarData { struct ScrollbarData {
CSSPixelRect gutter_rect;
CSSPixelRect thumb_rect; CSSPixelRect thumb_rect;
CSSPixelFraction scroll_length; CSSPixelFraction scroll_length { 0 };
}; };
enum class ScrollDirection { enum class ScrollDirection {
Horizontal, Horizontal,