Improve modern layout and viewport rendering

This commit is contained in:
SGavrl committed 2026-07-30 20:24:57 +00:00
1 parent aff0172987
commit 10b8492116
22 files changed
+5978 -450

No files matched your search

+83 -8
View File
@@ -406,25 +406,47 @@ pub async fn handle(
.get_session_page(session_id)
.map(|page| (page.viewport.0 as f64, page.viewport.1 as f64))
.unwrap_or((1280.0, 720.0));
let content_height = ctx
let mut page_x = 0.0;
let mut page_y = 0.0;
let mut content_width = width;
let mut content_height = height;
if let Some(values) = ctx
.get_session_page_mut(session_id)
.map(|p| p.evaluate("document.documentElement && document.documentElement.scrollHeight"))
.and_then(|v| v.as_f64())
.filter(|n| *n > 0.0)
.unwrap_or(height);
.map(|page| {
page.evaluate(
"[window.scrollX, window.scrollY, \
document.documentElement && document.documentElement.scrollWidth, \
document.documentElement && document.documentElement.scrollHeight]",
)
})
.and_then(|value| value.as_array().cloned())
{
page_x = values.first().and_then(Value::as_f64).unwrap_or(0.0);
page_y = values.get(1).and_then(Value::as_f64).unwrap_or(0.0);
content_width = values
.get(2)
.and_then(Value::as_f64)
.filter(|value| *value > 0.0)
.unwrap_or(width);
content_height = values
.get(3)
.and_then(Value::as_f64)
.filter(|value| *value > 0.0)
.unwrap_or(height);
}
let layout_viewport = json!({
"pageX": 0, "pageY": 0,
"pageX": page_x, "pageY": page_y,
"clientWidth": width, "clientHeight": height,
});
let visual_viewport = json!({
"offsetX": 0.0, "offsetY": 0.0,
"pageX": 0.0, "pageY": 0.0,
"pageX": page_x, "pageY": page_y,
"clientWidth": width, "clientHeight": height,
"scale": 1.0, "zoom": 1.0,
});
let content_size = json!({
"x": 0.0, "y": 0.0,
"width": width, "height": content_height,
"width": content_width, "height": content_height,
});
Ok(json!({
"layoutViewport": layout_viewport,
@@ -606,6 +628,59 @@ mod tests {
assert_eq!(content["height"].as_f64(), Some(720.0));
}
#[cfg(feature = "render")]
#[tokio::test]
async fn cdp_metrics_and_capture_follow_the_scrolled_viewport() {
let mut ctx = CdpContext::new();
let page_id = ctx.create_page();
let session_id = format!("{page_id}-session");
ctx.sessions.insert(session_id.clone(), page_id);
let session = Some(session_id);
ctx.get_session_page_mut(&session)
.expect("page")
.set_viewport((100.0, 80.0));
handle(
"navigate",
&json!({
"url": "data:text/html,<html style='margin:0'><body style='margin:0'><div style='height:80px;background:red'></div><div style='height:80px;background:blue'></div><div style='position:fixed;left:0;top:0;width:20px;height:20px;background:green'></div></body></html>",
"waitUntil": "load",
}),
&mut ctx,
&session,
)
.await
.expect("navigate");
let top = handle("captureScreenshot", &json!({}), &mut ctx, &session)
.await
.expect("top capture");
ctx.get_session_page_mut(&session)
.expect("page")
.evaluate("return (window.scrollTo(0, 80), window.scrollY)");
let metrics = handle("getLayoutMetrics", &json!({}), &mut ctx, &session)
.await
.expect("metrics");
assert_eq!(metrics["layoutViewport"]["pageY"].as_f64(), Some(80.0));
assert_eq!(metrics["visualViewport"]["pageY"].as_f64(), Some(80.0));
assert_eq!(metrics["contentSize"]["width"].as_f64(), Some(100.0));
assert!(
metrics["contentSize"]["height"].as_f64().unwrap_or_default() >= 160.0,
"contentSize must expose the scrollable document: {metrics}"
);
let scrolled = handle("captureScreenshot", &json!({}), &mut ctx, &session)
.await
.expect("scrolled capture");
let top_data = top["data"].as_str().expect("top png");
let scrolled_data = scrolled["data"].as_str().expect("scrolled png");
assert_ne!(
top_data, scrolled_data,
"CDP captureScreenshot must paint the current scroll offset"
);
}
#[tokio::test]
async fn unknown_page_method_still_errors() {
let mut ctx = CdpContext::new();