Make a scroll or fading viewport's sub-canvas again when the window's scale changes, rather than keep drawing it at the old one
CI / build + test (push) Waiting to run
CI / cargo audit (push) Waiting to run

Prompt opened on a screen at scale 2 and moved to one at scale 1 drew its tab labels and icons at twice their size, with only a couple of letters fitting in each tab, while the star, the + and the menu beside the tab row, and the terminal, came out right. Opened on the second screen directly, the tabs were right too.
The sub-canvases of scrolls (`scroll_canvases`) and fading viewports (`viewport_canvases`) are kept from one frame to the next and reused, resized when their size changes. `Canvas::sub_canvas` copies the parent's `dpi_scale` and layout viewport when it makes one, so a sub-canvas kept across a change of scale went on with the old one. Prompt's tab strip sits in a horizontal scroll, so its labels were drawn at px(13) × 2 on a canvas at scale 1.
`reuse_sub_canvas` takes the pooled sub-canvas only while its `dpi_scale` matches the parent's, resizing it as before, and otherwise makes a new one with `parent.sub_canvas`, which takes the current scale, density and viewport. Both the scroll and the fading viewport go through it.
Not verified: the move of Prompt between the two screens has not been tried with this change.
This commit is contained in:
2026-11-04 13:13:47 +01:00
parent 9900443ff1
commit 0872c9149b
+16 -8
View File
@@ -17,6 +17,20 @@ use crate::widget::{ Element, LaidOutWidget, WidgetHandlers };
use super::DrawCtx;
use super::damage::clamp_rect_to;
/// The previous frame's sub-canvas resized to `width × height`, or a new one when the parent's scale changed since, as a sub-canvas keeps the scale it was made with.
fn reuse_sub_canvas( pooled: Option<Canvas>, parent: &Canvas, width: u32, height: u32 ) -> Canvas
{
match pooled
{
Some( mut sub ) if sub.dpi_scale() == parent.dpi_scale() =>
{
if sub.size() != ( width, height ) { sub.resize( width, height ); }
sub
}
_ => parent.sub_canvas( width, height ),
}
}
pub( crate ) fn layout_and_draw<Msg: Clone>(
element: &Element<Msg>,
canvas: &mut Canvas,
@@ -295,13 +309,9 @@ pub( crate ) fn layout_and_draw<Msg: Clone>(
ctx.scroll_offsets.insert( my_idx, ( ox, oy ) );
}
// Reuse the sub-canvas from the previous frame if its size matches;
// only reallocate when the viewport is resized.
let sw = (rect.width.ceil() as u32).max( 1 );
let sh = (rect.height.ceil() as u32).max( 1 );
let mut sub = ctx.scroll_canvases.remove( &my_idx )
.map( |mut c| { if c.size() != ( sw, sh ) { c.resize( sw, sh ); } c } )
.unwrap_or_else( || canvas.sub_canvas( sw, sh ) );
let mut sub = reuse_sub_canvas( ctx.scroll_canvases.remove( &my_idx ), canvas, sw, sh );
sub.clear();
// Child content fills at least the full viewport on each
@@ -462,9 +472,7 @@ pub( crate ) fn layout_and_draw<Msg: Clone>(
let vh = ( rect.height.ceil() as u32 ).max( 1 );
let seq = ctx.viewport_seq;
ctx.viewport_seq += 1;
let mut sub = ctx.viewport_canvases.remove( &seq )
.map( |mut c| { if c.size() != ( vw, vh ) { c.resize( vw, vh ); } c } )
.unwrap_or_else( || canvas.sub_canvas( vw, vh ) );
let mut sub = reuse_sub_canvas( ctx.viewport_canvases.remove( &seq ), canvas, vw, vh );
if v.local_viewport { sub.set_local_layout_viewport(); }
sub.clear();