Exercise 3: Course 1's Own Real Capstone Document, Run Through Both Versions — Possible Solution
====================================================================
THE TEST
------------------------------
#page's REAL style-tree children (from Course 1's own unmodified
tokenize -> parse -> parse_css -> build_style_tree_full pipeline,
run on the exact capstone document --
,
,
,
each separated by real newline whitespace in the source):
['inline', 'block', 'inline', 'block', 'inline', 'block', 'inline']
naive_page_box = build_layout_tree_naive(styled_root)
check_block_container_invariant(naive_page_box)
fixed_page_box = build_layout_tree(styled_root)
check_block_container_invariant(fixed_page_box)
[c.box_type for c in fixed_page_box.children]
RESULT
------------------------------
check_block_container_invariant(naive_page_box) -> False
check_block_container_invariant(fixed_page_box) -> True
fixed_page_box.children box_types -> ['anonymous', 'block', 'anonymous',
'block', 'anonymous', 'block', 'anonymous']
Four separate anonymous boxes, one per isolated whitespace-only text
node -- not one combined box, and not zero.
WHY THE NAIVE VERSION FAILS THE INVARIANT
------------------------------
check_block_container_invariant(box) returns False specifically when
box.box_type == 'block' and ANY direct child has box_type == 'inline'.
The naive tree's own #page box has SEVEN direct children, alternating
inline/block/inline/block/... -- four of those seven are raw 'inline'
type (the whitespace text nodes), sitting directly among #page's own
children. That's exactly the condition the invariant check flags.
WHY THE FIXED VERSION HAS FOUR SEPARATE ANONYMOUS BOXES, NOT ONE
------------------------------
Each of the four whitespace-only text nodes in the real document is
ISOLATED -- sitting directly between two real block elements (before
, between and
, between
and
, and after ), with
no adjacent inline sibling of its own. Every time build_layout_tree's
own loop encounters one of these lone whitespace nodes, it appends it
to pending_inline; the VERY NEXT child is always a real block element
(,
,
, or nothing at all at the end of the list), which
immediately triggers flush() and packages that single whitespace node
into its own one-item anonymous box before pending_inline is cleared
again for the next child. Since no two whitespace nodes are ever
directly adjacent to each other in this particular document (each one
is always bounded by a block element on at least one side), no two of
them ever accumulate into the SAME anonymous box -- each gets its own,
giving four separate anonymous boxes total, one per whitespace run of
length exactly 1.
WHY THIS WORKS AS AN ANSWER
------------------------------
This confirms the grouping mechanism generalizes correctly from the
chapter's own synthetic, hand-built examples to a real, independently-
produced document that was never specifically constructed to
demonstrate this chapter's own point -- the whitespace-node problem
was simply an honest, unplanned side effect of how real HTML source
text is normally formatted (line breaks between tags), discovered as a
"bonus finding" back in Course 1's own capstone, and this chapter's own
fix resolves it using the exact same mechanism, with no special-casing
needed for the fact that the inline runs here all happen to be length
1 rather than length 2 or 3 like the chapter's own hand-built examples.