Fix use of Clip inside a scrolled Flickable with the GL backend

We're using `Canvas::intersect_scissor` to combine the viewport clip of
the flickable with any child `Clip` element, for example. Unfortunately
`intersect_scissor` has a bug and this patch works around it by doing
the scissor intersection manually. This works because we don't apply a
global transform on the canvas -- all scaling and translation is done
locally in the draw functions.
This commit is contained in:
Simon Hausmann 2021-02-09 10:40:46 +01:00
parent ec90d0c525
commit de9a215a1c

View file

@ -589,7 +589,12 @@ impl GLRenderer {
canvas.clear_rect(0, 0, size.width, size.height, clear_color.into()); canvas.clear_rect(0, 0, size.width, size.height, clear_color.into());
} }
GLItemRenderer { shared_data: self.shared_data.clone(), scale_factor } GLItemRenderer {
shared_data: self.shared_data.clone(),
scale_factor,
saved_scissor_rects: Vec::new(),
current_scissor_rect: None,
}
} }
/// Complete the item rendering by calling this function. This will typically flush any remaining/pending /// Complete the item rendering by calling this function. This will typically flush any remaining/pending
@ -649,6 +654,8 @@ impl GLRenderer {
pub struct GLItemRenderer { pub struct GLItemRenderer {
shared_data: Rc<GLRendererData>, shared_data: Rc<GLRendererData>,
scale_factor: f32, scale_factor: f32,
saved_scissor_rects: Vec<Rect>,
current_scissor_rect: Option<Rect>,
} }
fn rect_to_path(r: Rect) -> femtovg::Path { fn rect_to_path(r: Rect) -> femtovg::Path {
@ -1102,19 +1109,30 @@ impl ItemRenderer for GLItemRenderer {
fn combine_clip(&mut self, pos: Point, rect: Rect) { fn combine_clip(&mut self, pos: Point, rect: Rect) {
let clip_rect = rect.translate([pos.x, pos.y].into()); let clip_rect = rect.translate([pos.x, pos.y].into());
self.shared_data.canvas.borrow_mut().intersect_scissor( // FIXME: Go back to using Canvas::intersect_scissor when https://github.com/femtovg/femtovg/pull/29 is merged
clip_rect.min_x(), let final_clip_rect = if let Some(existing_clip) = self.current_scissor_rect {
clip_rect.min_y(), existing_clip.intersection(&clip_rect).unwrap_or_default()
clip_rect.width(), } else {
clip_rect.height(), clip_rect
};
self.shared_data.canvas.borrow_mut().scissor(
final_clip_rect.min_x(),
final_clip_rect.min_y(),
final_clip_rect.width(),
final_clip_rect.height(),
); );
self.current_scissor_rect = Some(final_clip_rect);
} }
fn save_state(&mut self) { fn save_state(&mut self) {
if let Some(scissor_rect) = self.current_scissor_rect {
self.saved_scissor_rects.push(scissor_rect);
}
self.shared_data.canvas.borrow_mut().save(); self.shared_data.canvas.borrow_mut().save();
} }
fn restore_state(&mut self) { fn restore_state(&mut self) {
self.current_scissor_rect = self.saved_scissor_rects.pop();
self.shared_data.canvas.borrow_mut().restore(); self.shared_data.canvas.borrow_mut().restore();
} }