summaryrefslogtreecommitdiff
path: root/content/handlers/html/box/manager.c
diff options
context:
space:
mode:
authorJohn-Mark Bell <jmb@netsurf-browser.org>2024-02-04 22:04:37 +0000
committerJohn-Mark Bell <jmb@netsurf-browser.org>2024-02-04 22:38:58 +0000
commit33ab748e87725ee789e5a28f45be905086672918 (patch)
tree00b45a9bb52c2920f2e68b34fabbf2f4c38a1339 /content/handlers/html/box/manager.c
parent1c8b11727a7d4e1300d58671e4101cd4ce727b17 (diff)
downloadnetsurf-33ab748e87725ee789e5a28f45be905086672918.tar.gz
netsurf-33ab748e87725ee789e5a28f45be905086672918.tar.bz2
HTML: determine if (re)selection is needed
Diffstat (limited to 'content/handlers/html/box/manager.c')
-rw-r--r--content/handlers/html/box/manager.c143
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