diff options
author | John-Mark Bell <jmb@netsurf-browser.org> | 2024-02-04 22:04:37 +0000 |
---|---|---|
committer | John-Mark Bell <jmb@netsurf-browser.org> | 2024-02-04 22:38:58 +0000 |
commit | 33ab748e87725ee789e5a28f45be905086672918 (patch) | |
tree | 00b45a9bb52c2920f2e68b34fabbf2f4c38a1339 /content | |
parent | 1c8b11727a7d4e1300d58671e4101cd4ce727b17 (diff) | |
download | netsurf-33ab748e87725ee789e5a28f45be905086672918.tar.gz netsurf-33ab748e87725ee789e5a28f45be905086672918.tar.bz2 |
HTML: determine if (re)selection is needed
Diffstat (limited to 'content')
-rw-r--r-- | content/handlers/html/box/manager.c | 143 |
1 files changed, 133 insertions, 10 deletions
diff --git a/content/handlers/html/box/manager.c b/content/handlers/html/box/manager.c index 49e6453c5..fd42de50c 100644 --- a/content/handlers/html/box/manager.c +++ b/content/handlers/html/box/manager.c @@ -44,22 +44,145 @@ struct box_manager size_t pending_queue_slots; }; -static void -box_manager_rebuild_boxes_for_children(box_manager *mgr, dom_node *parent) +typedef struct { - (void) mgr; - (void) parent; + box_manager *mgr; - //XXX: implement - // - // 1. (re)build the structural box tree segment rooted at each of parent's children. - // 2. For each modified box tree segment: - // a. find the immediate containing block(s) for the segment + /* Flag state for our ancestors (and their preceding siblings) */ + uintptr_t flags_ancestor; + /* Flag state for our preceding siblings */ + uintptr_t flags_sibling; + +} rebuild_ctx; + +static dom_exception +_foreach_child(dom_node *parent, + dom_exception (*cb)(dom_node *, void *), void *pw) +{ + dom_node *cur = NULL, *sibling = NULL; + dom_exception exc; + + exc = dom_node_get_first_child(parent, &cur); + if (exc != DOM_NO_ERR || cur == NULL) { + return exc; + } + + do { + dom_node_type node_type; + + exc = dom_node_get_node_type(cur, &node_type); + if (exc == DOM_NO_ERR && node_type == DOM_ELEMENT_NODE) { + exc = cb(cur, pw); + } + if (exc == DOM_NO_ERR) { + exc = dom_node_get_next_sibling(cur, &sibling); + dom_node_unref(cur); + cur = NULL; + + if (exc == DOM_NO_ERR && sibling != NULL) { + cur = sibling; + sibling = NULL; + } + } + } while (exc == DOM_NO_ERR && cur != NULL); + + dom_node_unref(cur); + + return exc; +} + +static dom_exception +_rebuild_boxes_for_element(dom_node *node, void *pw) +{ + rebuild_ctx *ctx = pw; + const uintptr_t flags_ancestor = ctx->flags_ancestor; + const uintptr_t flags_sibling = ctx->flags_sibling; + uintptr_t flags_self = 0; + dom_exception exc; + + /* Invalidate node data, extracting current value */ + exc = dom_node_set_user_data(node, + corestring_dom___ns_key_bm_node_data, + NULL, NULL, (void **) &flags_self); + if (exc != DOM_NO_ERR) { + return exc; + } + + /* Prepare to process children */ + ctx->flags_ancestor |= (ctx->flags_sibling | flags_self); + ctx->flags_sibling = 0; + + /* Process children */ + exc = _foreach_child(node, _rebuild_boxes_for_element, ctx); + + /* Restore values */ + ctx->flags_ancestor = flags_ancestor; + ctx->flags_sibling = flags_sibling; + + { + dom_string *name = NULL; + + exc = dom_node_get_node_name(node, &name); + if (exc == DOM_NO_ERR && name != NULL) { + NSLOG(layout, DBG, "bm: <%.*s>:" + " ancestor: %08"PRIxPTR + " sibling: %08"PRIxPTR + " self: %08"PRIxPTR, + (int) dom_string_byte_length(name), + dom_string_data(name), + flags_ancestor, + flags_sibling, + flags_self); + dom_string_unref(name); + } + } + + /* Consider whether anything has changed that might affect this node's + * box tree segment (noting that we have already done so for the box + * tree segments attached to our descendants) */ + if (flags_ancestor != 0 || flags_sibling != 0 || flags_self != 0) { // XXX: or if there's no style information for this node yet + /* DOM structure has changed: (re)select styles for node */ + + // XXX: if styles have changed, ensure our box tree segment reflects reality + } + + // XXX: regardless, ensure that box tree is in normal form (only need to consider relationship between our box(es) and those of our child elements) + + // XXX: then, if the box tree changed (either because our styles changed, or we needed to normalize things): + // a. find the immediate containing block(s) for our segment // (there may be more than one if posititioned/out-of-flow elements are in play) // b. emit (a) "box tree modified" event(s) referencing the containing block(s) // - // The box tree must always be in normal form so it may be necessary to insert (or remove?) elements between the segment root and its parent box + // Note that our children will also have done this, so there will be + // multiple events if done here and emitted directly; if we want to + // coalesce things, then we'll probably want to fire the events to an + // internal queue that we then flush out after we've finished + // processing the top-level external (e.g. DOM) event. Also, as we're + // (re)building the box tree on the way back up the DOM, it will be + // the case that we do not actually have any containing blocks yet + // (because they'll be constructed when we unwind back up to our + // parent). Given this, some further thought needs to happen here. + // // Layout calculators will receive the "box tree modified" events and deal with them + + /* Update flags for next sibling (if any) */ + ctx->flags_sibling |= flags_self; + + return exc; +} + +static void +box_manager_rebuild_boxes_for_children(box_manager *mgr, dom_node *parent) +{ + rebuild_ctx ctx; + + /* Prepare context */ + ctx.mgr = mgr; + ctx.flags_ancestor = 0; + ctx.flags_sibling = 0; + + // XXX: this recurses. iteration better? + (void) _foreach_child(parent, _rebuild_boxes_for_element, &ctx); } static void |