🐛 Paint layout children in canvas z-order in vector exports (#12171)

This commit is contained in:
Elena Torró 2026-10-08 09:07:33 +02:00 committed by GitHub
parent 30127e57a0
commit b3a62eeb4b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 72 additions and 6 deletions

View File

@ -349,6 +349,13 @@ fn sort_z_index(tree: ShapesPoolRef, element: &Shape, children_ids: Vec<Uuid>) -
}
}
/// Children bottom to top, in the same order the GPU renderer paints them.
pub(crate) fn children_paint_order(tree: ShapesPoolRef, element: &Shape) -> Vec<Uuid> {
let mut ids = sort_z_index(tree, element, element.children_ids(false));
ids.reverse();
ids
}
/// Whether this `render_shape_exit` pass closes the shape's focus scope. A
/// masked group keeps it open across the mask pass.
fn exit_closes_focus_scope(element: &Shape, visited_mask: bool) -> bool {

View File

@ -9,7 +9,7 @@ use super::document::{
};
use super::images::{emit_fills, emit_strokes};
use super::render_tree;
use crate::render::RenderResources;
use crate::render::{children_paint_order, RenderResources};
pub(super) fn render_frame(
builder: &mut SvgLayerCanvas,
@ -104,7 +104,7 @@ fn render_frame_body(
)?;
}
let children: Vec<_> = element.children_ids_iter_forward(false).copied().collect();
let children = children_paint_order(tree, element);
for child_id in &children {
render_tree(builder, shared, child_id, tree, scale)?;
}

View File

@ -1,8 +1,9 @@
use super::fixtures::*;
use crate::shapes::{
radius_to_sigma, BlendMode, Blur, BlurType, Fill, ImageFill, ImageFillTransform, Shadow,
ShadowStyle, SolidColor, StrokeCap, StrokeKind,
radius_to_sigma, AlignContent, AlignItems, BlendMode, Blur, BlurType, Fill, FlexDirection,
ImageFill, ImageFillTransform, JustifyContent, JustifyItems, Shadow, ShadowStyle, SolidColor,
StrokeCap, StrokeKind, WrapType,
};
use crate::state::ShapesPool;
use crate::uuid::Uuid;
@ -222,6 +223,63 @@ fn exports_frame_background_blur_before_children() {
insta::assert_snapshot!(svg);
}
#[test]
fn exports_flex_children_with_first_child_on_top() {
let mut pool = ShapesPool::new();
let frame_id = uid(1);
let first = uid(2);
let second = uid(3);
add_frame(
&mut pool,
frame_id,
Uuid::nil(),
(0.0, 0.0, 200.0, 120.0),
skia::Color::from_rgb(255, 255, 255),
false,
);
pool.get_mut(&frame_id).unwrap().set_flex_layout_data(
FlexDirection::Row,
0.0,
0.0,
AlignItems::Start,
AlignContent::Start,
JustifyItems::Start,
JustifyContent::Start,
WrapType::NoWrap,
0.0,
0.0,
0.0,
0.0,
);
add_solid_rect(
&mut pool,
first,
frame_id,
(20.0, 20.0, 80.0, 80.0),
skia::Color::from_rgb(255, 0, 0),
);
add_solid_rect(
&mut pool,
second,
frame_id,
(40.0, 40.0, 100.0, 100.0),
skia::Color::from_rgb(0, 0, 255),
);
{
let frame = pool.get_mut(&frame_id).unwrap();
frame.add_child(first);
frame.add_child(second);
}
let svg = render(&pool, frame_id);
let first_pos = svg.find("fill=\"red\"").expect("first child");
let second_pos = svg.find("fill=\"blue\"").expect("second child");
assert!(
second_pos < first_pos,
"flex paints its first child on top: {svg}"
);
}
#[test]
fn exports_group_background_blur_selrect_clip() {
let mut pool = ShapesPool::new();

View File

@ -8,6 +8,7 @@ use crate::shapes::{
use crate::state::ShapesPoolRef;
use crate::uuid::Uuid;
use super::children_paint_order;
use super::shape_renderer::ShapeRenderer;
use super::text;
use super::RenderResources;
@ -934,7 +935,7 @@ fn render_frame(
}
// Children (absolute coords, no frame transform).
let children: Vec<Uuid> = element.children_ids_iter_forward(false).copied().collect();
let children = children_paint_order(tree, element);
let child_opts = opts.for_children_of(element);
for child_id in &children {
render_tree_inner(shared, canvas, child_id, tree, scale, &child_opts)?;
@ -988,7 +989,7 @@ fn render_container_drop_shadows(
renderer.draw_fills(element, &element.fills)?;
}
let children: Vec<Uuid> = element.children_ids_iter_forward(false).copied().collect();
let children = children_paint_order(tree, element);
let child_opts = opts.for_children_of(element);
for child_id in &children {
render_tree_inner(shared, canvas, child_id, tree, scale, &child_opts)?;