mirror of
https://github.com/lexmount/moli.git
synced 2026-10-04 16:00:47 +00:00
fix(layout): preserve physical insets in reversed flex scrollers
This commit is contained in:
Generated
+1
-1
@@ -4842,7 +4842,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "taffy"
|
||||
version = "0.13.0"
|
||||
source = "git+https://github.com/ldm0/taffy?rev=2dce934bd3ead3d4db934f6847c6e6b26565d9c7#2dce934bd3ead3d4db934f6847c6e6b26565d9c7"
|
||||
source = "git+https://github.com/ldm0/taffy?rev=082327a5cb0d2ee1fed4c0ac5f339e1c1a51b576#082327a5cb0d2ee1fed4c0ac5f339e1c1a51b576"
|
||||
dependencies = [
|
||||
"arrayvec",
|
||||
"serde",
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ stylo_atoms = { git = "https://github.com/ldm0/stylo", rev = "e6cdff0a2eb7e51a31
|
||||
stylo_dom = { git = "https://github.com/ldm0/stylo", rev = "e6cdff0a2eb7e51a313dabe8dc48a13a08314493" }
|
||||
stylo_static_prefs = { git = "https://github.com/ldm0/stylo", rev = "e6cdff0a2eb7e51a313dabe8dc48a13a08314493" }
|
||||
stylo_traits = { git = "https://github.com/ldm0/stylo", rev = "e6cdff0a2eb7e51a313dabe8dc48a13a08314493" }
|
||||
taffy = { git = "https://github.com/ldm0/taffy", rev = "2dce934bd3ead3d4db934f6847c6e6b26565d9c7" }
|
||||
taffy = { git = "https://github.com/ldm0/taffy", rev = "082327a5cb0d2ee1fed4c0ac5f339e1c1a51b576" }
|
||||
|
||||
[workspace.lints.clippy]
|
||||
disallowed_methods = "deny"
|
||||
|
||||
@@ -2,27 +2,52 @@ use super::*;
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn screenshot_resolves_flex_static_margin_boxes_across_containing_blocks() {
|
||||
assert_flex_geometry_fixture(
|
||||
include_str!("../../../../tests/fixtures/flex-static-position-margins.html"),
|
||||
"collectFlexStaticMarginChecks()",
|
||||
117,
|
||||
6000,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "current_thread")]
|
||||
async fn screenshot_preserves_physical_absolute_insets_in_reversed_flex_scrollers() {
|
||||
assert_flex_geometry_fixture(
|
||||
include_str!("../../../../tests/fixtures/flex-physical-insets.html"),
|
||||
"collectFlexPhysicalInsetChecks()",
|
||||
96,
|
||||
1260,
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
async fn assert_flex_geometry_fixture(
|
||||
fixture: &'static str,
|
||||
collect_checks: &'static str,
|
||||
expected_count: usize,
|
||||
viewport_height: u32,
|
||||
) {
|
||||
run_page_vm_async_test(async move {
|
||||
let loader = crate::network::ResourceRequestClient::new(&FetchConfig::default())?;
|
||||
let mut page = test_page_vm_with_loader_and_document_url(
|
||||
&loader,
|
||||
Vec::new(),
|
||||
Url::parse("https://example.com/flex-static-position-margins.html")?,
|
||||
Url::parse("https://example.com/flex-geometry.html")?,
|
||||
);
|
||||
page.set_viewport_surface(Some(crate::protocol_types::ViewportSurface {
|
||||
inner_width: 1280,
|
||||
inner_height: 6000,
|
||||
inner_height: viewport_height,
|
||||
outer_width: 1280,
|
||||
outer_height: 6000,
|
||||
outer_height: viewport_height,
|
||||
device_pixel_ratio: 1.0,
|
||||
screen_width: 1280,
|
||||
screen_height: 6000,
|
||||
screen_height: viewport_height,
|
||||
screen_avail_width: 1280,
|
||||
screen_avail_height: 6000,
|
||||
screen_avail_height: viewport_height,
|
||||
}))?;
|
||||
page.vm_mut()
|
||||
.set_layout_policy(moli_page_types::LayoutPolicy::OnDemand);
|
||||
let fixture = include_str!("../../../../tests/fixtures/flex-static-position-margins.html");
|
||||
page.vm_mut().eval(&format!(
|
||||
"document.open();document.write({});document.close()",
|
||||
serde_json::to_string(fixture)?
|
||||
@@ -40,10 +65,10 @@ async fn screenshot_resolves_flex_static_margin_boxes_across_containing_blocks()
|
||||
let checks: serde_json::Value = serde_json::from_str(
|
||||
&page
|
||||
.vm_mut()
|
||||
.eval("JSON.stringify(collectFlexStaticMarginChecks())")?,
|
||||
.eval(&format!("JSON.stringify({collect_checks})"))?,
|
||||
)?;
|
||||
let checks = checks.as_array().expect("flex static margin checks");
|
||||
assert_eq!(checks.len(), 117);
|
||||
let checks = checks.as_array().expect("flex geometry checks");
|
||||
assert_eq!(checks.len(), expected_count);
|
||||
for check in checks {
|
||||
assert_eq!(check["actual"], check["expected"], "{check}");
|
||||
let x = check["pixel"][0].as_f64().expect("pixel x") as usize;
|
||||
@@ -59,5 +84,5 @@ async fn screenshot_resolves_flex_static_margin_boxes_across_containing_blocks()
|
||||
Ok::<_, anyhow::Error>(())
|
||||
})
|
||||
.await
|
||||
.expect("flex static-position margin fixture should run");
|
||||
.expect("flex geometry fixture should run");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
<!doctype html>
|
||||
<meta charset="utf-8">
|
||||
<title>Physical absolute insets in reversed flex scroll containers</title>
|
||||
<link rel="help" href="https://drafts.csswg.org/css-position-3/#insets">
|
||||
<style>
|
||||
html, body { margin: 0; padding: 0; overflow: hidden; }
|
||||
.container {
|
||||
position: absolute;
|
||||
display: flex;
|
||||
box-sizing: border-box;
|
||||
width: 200px;
|
||||
height: 160px;
|
||||
border-style: solid;
|
||||
border-width: 2px 5px 4px 3px;
|
||||
padding: 3px 5px 7px 9px;
|
||||
overflow: scroll;
|
||||
font: 0/0 sans-serif;
|
||||
}
|
||||
.item { position: absolute; background: rgb(31, 127, 63); }
|
||||
</style>
|
||||
<body>
|
||||
<script>
|
||||
const cases = [
|
||||
{id:'near', style:'left:11px;top:7px;width:40px;height:20px;margin:2px 8px 6px 4px', expected:[18,11,40,20]},
|
||||
{id:'far', style:'right:13px;bottom:9px;width:40px;height:20px;margin:2px 8px 6px 4px', expected:[119,106,40,20]},
|
||||
{id:'percentage-insets', style:'left:25%;top:25%;width:40px;height:20px;margin:2px 8px 6px 4px', expected:[51.25,38.75,40,20]},
|
||||
{id:'percentage-size', style:'left:0;top:0;width:100%;height:100%', expected:[3,2,177,139]},
|
||||
];
|
||||
let index = 0;
|
||||
for (const direction of ['ltr', 'rtl']) {
|
||||
for (const flexDirection of ['row', 'row-reverse', 'column', 'column-reverse']) {
|
||||
for (const flexWrap of ['nowrap', 'wrap', 'wrap-reverse']) {
|
||||
const container = document.createElement('div');
|
||||
container.className = 'container';
|
||||
container.id = `${direction}-${flexDirection}-${flexWrap}`;
|
||||
container.style.cssText = `left:${(index % 5) * 240}px;top:${Math.floor(index / 5) * 210}px;direction:${direction};flex-direction:${flexDirection};flex-wrap:${flexWrap}`;
|
||||
for (const test of cases) {
|
||||
const item = document.createElement('div');
|
||||
item.className = 'item';
|
||||
item.id = `${container.id}-${test.id}`;
|
||||
item.style.cssText = test.style;
|
||||
// Classic scrollbars reserve 15px. RTL moves the vertical gutter
|
||||
// to the left; reversing flex axes never moves either gutter.
|
||||
const expected = test.expected.slice();
|
||||
if (direction === 'rtl') expected[0] += 15;
|
||||
item.dataset.expected = JSON.stringify(expected);
|
||||
container.append(item);
|
||||
}
|
||||
document.body.append(container);
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
function collectFlexPhysicalInsetChecks() {
|
||||
return Array.from(document.querySelectorAll('.item'), item => {
|
||||
const origin = item.parentElement.getBoundingClientRect();
|
||||
const rect = item.getBoundingClientRect();
|
||||
const expected = JSON.parse(item.dataset.expected);
|
||||
return {
|
||||
id: item.id,
|
||||
actual: [rect.x - origin.x, rect.y - origin.y, rect.width, rect.height],
|
||||
expected,
|
||||
pixel: [origin.x + expected[0] + 2, origin.y + expected[1] + 2],
|
||||
};
|
||||
});
|
||||
}
|
||||
</script>
|
||||
Reference in New Issue
Block a user