Resolve scroll containers through the style cascade

Element.scrollContainer read the inline style= attribute only, so a
scroller declared in a stylesheet was invisible to the scroll tool and to
wheel scrolling, which then fell through to the viewport.

StyleManager now tracks overflow-x and overflow-y alongside display,
visibility, opacity and pointer-events, and exposes scrolls(el, axes) as
an own-element probe. The overflow shorthand is expanded into its
longhands in declaration order, in both the attribute scan and the
materialized style object, so a shorthand and its longhands keep the
precedence of the source text. overlay counts as auto, as in Chrome.

Element.scrollContainer asks the style manager, and the two unused Props
bits hold the new flags, so the per-element memo does not grow.
This commit is contained in:
Adrià Arrufat committed 2026-09-15 09:46:49 +02:00
1 parent d50875fff1
commit b3758045a8
6 files changed
+172 -62

No files matched your search

+36
View File
@@ -398,6 +398,42 @@ test "cdp.input: dispatchMouseEvent mouseWheel scrolls a scroll container, not t
try testing.expect(split.isTrue());
}
test "cdp.input: dispatchMouseEvent mouseWheel scrolls a stylesheet-declared scroll container" {
var ctx = try testing.context();
defer ctx.deinit();
const bc = try ctx.loadBrowserContext(.{});
const page = try bc.session.createPage();
const frame = page.frame().?;
const url = "http://localhost:9582/src/browser/tests/mcp_actions.html";
try frame.navigate(url, .{ .reason = .address_bar, .kind = .{ .push = null } });
try testing.waitForPage(bc);
var ls: lp.js.Local.Scope = undefined;
frame.js.localScope(&ls);
defer ls.deinit();
var try_catch: lp.js.TryCatch = undefined;
try_catch.init(&ls.local);
defer try_catch.deinit();
const rect_x = try (try ls.local.compileAndRun("document.getElementById('sheetleaf').getBoundingClientRect().x", null)).toF64();
const rect_y = try (try ls.local.compileAndRun("document.getElementById('sheetleaf').getBoundingClientRect().y", null)).toF64();
try ctx.processMessage(.{
.id = 1,
.method = "Input.dispatchMouseEvent",
.params = .{ .type = "mouseWheel", .x = rect_x, .y = rect_y, .deltaY = 40 },
});
const result = try ls.local.compileAndRun("document.getElementById('sheetscroll').scrollTop === 40 && document.getElementById('sheetleaf').scrollTop === 0 && window.scrollY === 0", null);
try testing.expect(result.isTrue());
var runner = bc.session.runner(.{});
try runner.waitForScript(frame._frame_id, "window.sheetScrolled === true", 1000);
}
test "cdp.input: dispatchMouseEvent mouseWheel on page content scrolls the viewport" {
var ctx = try testing.context();
defer ctx.deinit();