From 51c9115e9bb1fb8c8c38b78ad7be75e948dc55f9 Mon Sep 17 00:00:00 2001 From: Pierre Tachoire Date: Fri, 24 Jul 2026 11:48:32 +0200 Subject: [PATCH 1/2] derive scrollWidth/scrollHeight from element content MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both aliased clientWidth/clientHeight, computed from the element's own box without looking at its children, so any "measure, mutate, re-measure" loop never terminated. The marquee idiom on readthetrieb.com is the reported case: while (lane.scrollWidth < track.offsetWidth * 2) lane.innerHTML += lane.innerHTML; Doubling the markup left scrollWidth unchanged, so the loop spun while innerHTML grew the DOM exponentially and wedged the page in under a second. Return max(clientSize, contentSize), summing the direct child elements. - No layout-mode detection: getStyle() sees only the inline style attribute, so display:flex or white-space:nowrap from a stylesheet is invisible. Each axis assumes the arrangement that produces overflow — width lays children in a row, height stacks them — bounding content extent per axis rather than modelling one layout. - Text children are not measured. Estimating a run from its length needs a per-character advance that tracks font-size, or shrink-to-fit loops stop converging, and it reports overflow for nearly every element holding text. - Direct children only, so cost is O(fan-out), with a shared VisibilityCache collapsing N ancestor walks into one. - / keep their synthetic defaults, so page-level overflow and infinite-scroll checks are unaffected; only inner containers change. Tests in element/position.html cover growth per child, text contributing to neither axis, hidden elements, the root carve-out, and both loops terminating. --- src/browser/tests/element/position.html | 176 +++++++++++++++++++++++- src/browser/webapi/Element.zig | 106 +++++++++++++- 2 files changed, 277 insertions(+), 5 deletions(-) diff --git a/src/browser/tests/element/position.html b/src/browser/tests/element/position.html index e8137bbad..6a846dfa8 100644 --- a/src/browser/tests/element/position.html +++ b/src/browser/tests/element/position.html @@ -24,12 +24,186 @@ { const test1 = $('#test1'); - // In dummy layout, scroll dimensions equal client dimensions (no overflow) + // Both scroll dimensions are approximated from the content, so neither falls + // below the element's own box but either may exceed it. + testing.expectTrue(test1.scrollWidth >= test1.clientWidth); + testing.expectTrue(test1.scrollHeight >= test1.clientHeight); + + // test1 holds only a text node, and text is not measured on either axis, so + // both still match the element's own box. testing.expectEqual(test1.clientWidth, test1.scrollWidth); testing.expectEqual(test1.clientHeight, test1.scrollHeight); } + + + + + + +