Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix panic in the software renderer with clipped text and scale factor #3059

Merged
merged 4 commits into from
Jul 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to this project are documented in this file.

- Fixed compiler panics when some complex expressions are used for the model expression in `for` (#2977)
- Native style: Fixed support for floating point ranges in Slider.
- Fixed panics in the software renderer related to text rendering.

### Slint Language

Expand Down
17 changes: 13 additions & 4 deletions internal/core/software_renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -231,9 +231,12 @@ impl SoftwareRenderer {
} else {
(euclid::size2(pixel_stride as _, (buffer.len() / pixel_stride) as _), Brush::default())
};
if size.is_empty() {
return Default::default();
}
assert!(
pixel_stride >= size.width as usize
&& buffer.len() >= size.height as usize * pixel_stride + size.width as usize - pixel_stride,
&& buffer.len() >= (size.height as usize * pixel_stride + size.width as usize) - pixel_stride,
"buffer of size {} with stride {pixel_stride} is too small to handle a window of size {size:?}", buffer.len()
);
let buffer_renderer = SceneBuilder::new(
Expand All @@ -254,8 +257,11 @@ impl SoftwareRenderer {
renderer.compute_dirty_regions(component, *origin);
}

let dirty_region =
(renderer.dirty_region.to_rect().cast() * factor).round_out().cast();
let dirty_region = (renderer.dirty_region.to_rect().cast() * factor)
.round_out()
.intersection(&euclid::rect(0., 0., i16::MAX as f32, i16::MAX as f32))
.unwrap_or_default()
.cast();

let to_draw = self.apply_dirty_region(dirty_region, size);

Expand Down Expand Up @@ -1367,7 +1373,10 @@ impl<'a, T: ProcessScene> SceneBuilder<'a, T> {

if let Some(clipped_src) = src_rect.intersection(&physical_clip) {
let geometry = clipped_src.translate(offset).round();
let origin = (geometry.origin - offset.round()).cast::<usize>();
if geometry.is_empty() {
continue;
}
let origin = (geometry.origin - offset.round()).round().cast::<usize>();
let actual_x = origin.x - src_rect.origin.x as usize;
let actual_y = origin.y - src_rect.origin.y as usize;
let stride = glyph.width.get() as u16;
Expand Down
15 changes: 15 additions & 0 deletions tests/screenshots/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,20 @@ fn main() -> std::io::Result<()> {
writeln!(generated_file, "#[path=\"{0}.rs\"] mod r#{0};", module_name)?;
let source = std::fs::read_to_string(&testcase.absolute_path)?;

let needle = "SLINT_SCALE_FACTOR=";
let scale_factor = if let Some(p) = source.find(needle) {
let source = &source[p + needle.len()..];
let scale_factor: f32 = source
.find(char::is_whitespace)
.and_then(|end| source[..end].parse().ok())
.unwrap_or_else(|| {
panic!("Cannot parse {needle} for {}", testcase.relative_path.display())
});
format!("slint::platform::WindowAdapter::window(&*window).dispatch_event(slint::platform::WindowEvent::ScaleFactorChanged {{ scale_factor: {scale_factor}f32 }});")
} else {
String::new()
};

let mut output = std::fs::File::create(
Path::new(&std::env::var_os("OUT_DIR").unwrap()).join(format!("{}.rs", module_name)),
)?;
Expand All @@ -86,6 +100,7 @@ fn main() -> std::io::Result<()> {
use crate::testing;

let window = testing::init_swr();
{scale_factor}
window.set_size(slint::PhysicalSize::new(64, 64));
let screenshot = {reference_path};

Expand Down
124 changes: 124 additions & 0 deletions tests/screenshots/cases/software/basic/text-clipped.slint
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-1.0 OR LicenseRef-Slint-commercial

// SLINT_SCALE_FACTOR=1.5

export component TestCase inherits Window {
width: 64phx;
height: 64phx;
Rectangle {
x: 1.49999997px;
y: 1.5px;
width: 15.33px;
height: 15.33px;
clip: true;
background: pink;
Text {
text: "Hello\nWorld";
font-size: 9.5px;
color: black;
horizontal-alignment: center;
vertical-alignment: center;
}
}

Rectangle {
x: 17.333px;
y: 1.5px;
width: 15.33px;
height: 24.18px;
clip: true;
background: orange;
opacity: 0.9;
Text {
height: 133%;
width: 121%;
text: "Three\nLines\nText";
font-size: 9px;
color: blue;
font-weight: 600;
font-italic: true;
horizontal-alignment: right;
}
}

Rectangle {
x: 33.5px;
y: 1.1px;
width: 28.33px;
height: 25.9px;
clip: true;
background: lightblue;
property <percent> dd;
Text {
height: 100%; width: 100%;
text: "Word wrap and right Align";
wrap: word-wrap;
horizontal-alignment: right;
vertical-alignment: bottom;
font-size: 9.1px;
color: violet;
}
}

Text {
height: 99%; width: 99%;
y: 2.499997px;
x: -20.49997px;
text: "Some long text bottom-right-aligned";
wrap: word-wrap;
overflow: elide;
horizontal-alignment: right;
vertical-alignment: bottom;
font-size: 9px;
color: violet;
}


Text {
height: 99%; width: 99%;
y: 2.499997px;
x: -20.49997px;
text: "Some long text bottom-right-aligned";
wrap: word-wrap;
overflow: elide;
horizontal-alignment: right;
vertical-alignment: bottom;
font-size: 9px;
color: violet;
}

Rectangle {
background: #8234;
x: 38.788px;
y: 30.123px;
width: 30px;
height: 30px;
clip: true;
Text {
y: -2.5px;
x: -2.5px;
width: 110%;
height: 110%;
property <string> t: "tiny tiny text nobody can see\nhelloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo\n this is soooo smallllllllllllllllllll and so tiny"
+" \nnobody can read this anyway.";
text: t+t+t+t;

wrap: word-wrap;
overflow: elide;
horizontal-alignment: left;
font-size: 4px;
letter-spacing: -1px;

color: green;
}
}

Text {
property <float> zero: 0;
text: "Zero";
x: zero * 5px / zero;
}


}
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 3 additions & 1 deletion tests/screenshots/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,9 @@ pub fn screenshot_render_by_line(
euclid::point2(0., 0.),
euclid::point2(buffer.width() as f32, buffer.height() as f32),
)),
Some(r) => renderer.mark_dirty_region(DirtyRegion::from_untyped(&r.to_box2d().cast())),
Some(r) => renderer.mark_dirty_region(
DirtyRegion::from_untyped(&r.to_box2d().cast()) / window.scale_factor(),
),
}
renderer.render_by_line(TestingLineBuffer {
stride: buffer.width() as usize,
Expand Down