diff options
author | John-Mark Bell <jmb@netsurf-browser.org> | 2024-01-21 22:15:04 +0000 |
---|---|---|
committer | John-Mark Bell <jmb@netsurf-browser.org> | 2024-01-21 22:48:45 +0000 |
commit | 0aeccbf5125c4554cc651453beceb4a3d2551de8 (patch) | |
tree | f9d36882d684e73a0e277241f8e0772596ccdfe5 /content/handlers/html/box/manager.c | |
parent | 968db3366eaf291f91a17a46ad9c27d2004c99b9 (diff) | |
download | netsurf-0aeccbf5125c4554cc651453beceb4a3d2551de8.tar.gz netsurf-0aeccbf5125c4554cc651453beceb4a3d2551de8.tar.bz2 |
HTML: track changes on DOM Elements
Diffstat (limited to 'content/handlers/html/box/manager.c')
-rw-r--r-- | content/handlers/html/box/manager.c | 95 |
1 files changed, 89 insertions, 6 deletions
diff --git a/content/handlers/html/box/manager.c b/content/handlers/html/box/manager.c index d8dadf300..6d558e41e 100644 --- a/content/handlers/html/box/manager.c +++ b/content/handlers/html/box/manager.c @@ -6,6 +6,17 @@ #include "utils/corestrings.h" #include "utils/log.h" +/* Flags for DOM Element nodes */ + +#define BM_DOM_FLAG_STRUCTURE_CHANGED 0x00000001 +/* Document structure has changed at this node: recompute style information + * for it, its descendants, its subsequent siblings, and their descendants. + * If styles have changed, rebuild box subtree */ + +#define BM_DOM_FLAG_TEXT_CONTENTS_CHANGED 0x00000002 +/* Text contents of this node have changed: rebuild box subtree */ + + struct box_manager { dom_document *doc; @@ -198,13 +209,65 @@ _find_parent_element_or_document(dom_node *target) return parent; } +static dom_exception +_foreach_element_sibling(dom_node *cur, + dom_exception (*cb)(dom_node *, void *), void *pw) +{ + dom_node *sibling = NULL; + dom_exception exc; + + dom_node_ref(cur); + + do { + exc = dom_node_get_next_sibling(cur, &sibling); + dom_node_unref(cur); + cur = sibling; + sibling = NULL; + + if (exc == DOM_NO_ERR && cur != NULL) { + dom_node_type sibling_type; + + exc = dom_node_get_node_type(cur, &sibling_type); + if (exc == DOM_NO_ERR && + sibling_type == DOM_ELEMENT_NODE) { + exc = cb(cur, pw); + } + } + } while (exc == DOM_NO_ERR && cur != NULL); + + dom_node_unref(cur); + + return exc; +} + +static dom_exception +_set_node_flags(dom_node *node, void *pw) +{ + uintptr_t flags_to_set = (uintptr_t) pw; + uintptr_t node_flags = 0; + dom_exception exc; + + exc = dom_node_get_user_data(node, + corestring_dom___ns_key_bm_node_data, + (void **) &node_flags); + if (exc == DOM_NO_ERR) { + node_flags |= flags_to_set; + exc = dom_node_set_user_data(node, + corestring_dom___ns_key_bm_node_data, + (void *) node_flags, + NULL, + (void **) &node_flags); + } + return exc; +} + static void box_manager_handle_dom_event(dom_event *evt, void *pw) { box_manager *mgr = pw; dom_node *parent = NULL; dom_event_target *target = NULL; - dom_node_type node_type; + dom_node_type target_type; dom_string *evt_type = NULL, *computed_type = NULL; dom_exception exc; @@ -244,9 +307,9 @@ box_manager_handle_dom_event(dom_event *evt, void *pw) } /* 3. The event target must be an Element or Text node */ - exc = dom_node_get_node_type(target, &node_type); - if (exc != DOM_NO_ERR || (node_type != DOM_ELEMENT_NODE && - node_type != DOM_TEXT_NODE)) { + exc = dom_node_get_node_type(target, &target_type); + if (exc != DOM_NO_ERR || (target_type != DOM_ELEMENT_NODE && + target_type != DOM_TEXT_NODE)) { dom_node_unref(target); return; } @@ -258,9 +321,29 @@ box_manager_handle_dom_event(dom_event *evt, void *pw) return; } - /* 5. mark target dirty */ - // XXX: we probably want a uintptr_t's worth of user data containing flags for now + /* 5. update node flags */ + if (target_type == DOM_ELEMENT_NODE) { + /* Mark nodes as structurally changed */ + if (computed_type == corestring_dom_DOMNodeRemoved) { + /* All subsequent sibling elements */ + exc = _foreach_element_sibling((dom_node *) target, + _set_node_flags, + (void *) BM_DOM_FLAG_STRUCTURE_CHANGED); + } else { + /* Just target itself */ + exc = _set_node_flags((dom_node *) target, + (void *) BM_DOM_FLAG_STRUCTURE_CHANGED); + } + } else if (target_type == DOM_TEXT_NODE) { + /* Mark parent as text content changed */ + exc = _set_node_flags((dom_node *) parent, + (void *) BM_DOM_FLAG_TEXT_CONTENTS_CHANGED); + } dom_node_unref(target); + if (exc != DOM_NO_ERR) { + dom_node_unref(parent); + return; + } /* 6. Capture parent node (ensuring we keep a ref) into list of * pending events. */ |