From 9e3d8745775fcc34a9248e558d4ce80bbeddad7a Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Fri, 26 Jan 2024 18:43:33 +0100 Subject: [PATCH] [document] Added function scan document This function must calculate dimensions of nodes in document. Every node has a rectangle. x0,y0 is the left up corner, x1,y1 - the right bottom. In theory every child of given node is contained in this rectangle. --- src/document/document.h | 2 + src/document/html/renderer.c | 2 +- src/document/libdom/renderer2.c | 338 +++++++++++++++++++++++++++++++- src/document/libdom/renderer2.h | 10 + src/viewer/text/draw.c | 15 +- 5 files changed, 364 insertions(+), 3 deletions(-) diff --git a/src/document/document.h b/src/document/document.h index 8396a6da..1d1732c4 100644 --- a/src/document/document.h +++ b/src/document/document.h @@ -21,6 +21,7 @@ struct ecmascript_timeout; struct el_form_control; struct frame_desc; struct frameset_desc; +struct hash; struct image; struct module; struct screen_char; @@ -241,6 +242,7 @@ struct document { void *element_map_rev; struct string text; void *forms_nodeset; + struct hash *hh; #endif #ifdef CONFIG_CSS diff --git a/src/document/html/renderer.c b/src/document/html/renderer.c index f4e7ab8c..6daafa27 100644 --- a/src/document/html/renderer.c +++ b/src/document/html/renderer.c @@ -274,8 +274,8 @@ get_format_screen_char(struct html_context *html_context, && html_context->options->underline_links) { schar_cache.attr |= SCREEN_ATTR_UNDERLINE; } + schar_cache.element_offset = (html_top->name && html_context->document && html_context->document->text.source) ? html_top->name - html_context->document->text.source : 0; - schar_cache.element_offset = (elformat.top_name && html_context->document && html_context->document->text.source) ? elformat.top_name - html_context->document->text.source : 0; return &schar_cache; } diff --git a/src/document/libdom/renderer2.c b/src/document/libdom/renderer2.c index 2f062e5f..3d386f2c 100644 --- a/src/document/libdom/renderer2.c +++ b/src/document/libdom/renderer2.c @@ -19,7 +19,9 @@ #include "document/libdom/doc.h" #include "document/libdom/mapa.h" #include "document/libdom/renderer2.h" +#include "document/view.h" #include "ecmascript/libdom/parse.h" +#include "util/hash.h" #include "util/string.h" static int in_script = 0; @@ -289,6 +291,172 @@ render_xhtml_document(struct cache_entry *cached, struct document *document, str dump_xhtml(cached, document, 0); } +static struct node_rect *get_element(struct document *doc, int offset); + +static void +walk_tree2(struct document *document, dom_node *node) +{ + dom_node *child = NULL; + /* Get the node's first child */ + dom_exception exc = dom_node_get_first_child(node, &child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_first_child\n"); + return; + } + + while (child != NULL) { + /* Loop though all node's children */ + dom_node *next_child; + + /* Visit node's descendents */ + walk_tree2(document, child); + + /* Go to next sibling */ + exc = dom_node_get_next_sibling(child, &next_child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_next_sibling\n"); + dom_node_unref(child); + return; + } + dom_node_unref(child); + child = next_child; + } + + int offset = find_offset(document->element_map_rev, node); + + if (offset <= 0) { + return; + } + struct node_rect *tab = get_element(document, offset); + + if (!tab) { + return; + } + exc = dom_node_get_first_child(node, &child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_first_child\n"); + return; + } + + while (child != NULL) { + /* Loop though all node's children */ + dom_node *next_child; + int offset_i = find_offset(document->element_map_rev, child); + + if (offset_i <= 0) { + goto next; + } + struct node_rect *rect_i = get_element(document, offset_i); + + if (!rect_i) { + goto next; + } + + if (rect_i->x0 == INT_MAX) { + goto next; + } + + if (tab->x0 > rect_i->x0) { + tab->x0 = rect_i->x0; + } + if (tab->y0 > rect_i->y0) { + tab->y0 = rect_i->y0; + } + if (tab->x1 < rect_i->x1) { + tab->x1 = rect_i->x1; + } + if (tab->y1 < rect_i->y1) { + tab->y1 = rect_i->y1; + } +next: + /* Go to next sibling */ + exc = dom_node_get_next_sibling(child, &next_child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_next_sibling\n"); + dom_node_unref(child); + return; + } + dom_node_unref(child); + child = next_child; + } +} + +static void +walk_tree2_color(struct terminal *term, struct el_box *box, struct document *document, int vx, int vy, dom_node *node) +{ + dom_node *child = NULL; + /* Get the node's first child */ + dom_exception exc = dom_node_get_first_child(node, &child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_first_child\n"); + return; + } + int offset = find_offset(document->element_map_rev, node); + + if (offset <= 0) { + return; + } + struct node_rect *tab = get_element(document, offset); + + if (!tab) { + return; + } + + if (tab->y0 >= document->height) { + return; + } + + if (tab->x0 >= document->data[tab->y0].length) { + return; + } + struct screen_char *sc = &document->data[tab->y0].ch.chars[tab->x0]; + int ymax = int_min(document->height, tab->y1 + 1); + int y, x; + + for (y = int_max(vy, tab->y0); + y < int_min(ymax, box->height + vy); + y++) { + int st = int_max(vx, tab->x0); + int xmax = int_min(box->width + vx, tab->x1 + 1); + + for (x = st; x < xmax; x++) { + if (x >= document->data[y].length || (document->data[y].ch.chars[x].data == ' ' && document->data[y].ch.chars[x].element_offset == 0)) { + draw_space(term, box->x + x - vx, box->y + y - vy, sc); + } + } + } + exc = dom_node_get_first_child(node, &child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_first_child\n"); + return; + } + + while (child != NULL) { + /* Loop though all node's children */ + dom_node *next_child; + + /* Visit node's descendents */ + walk_tree2_color(term, box, document, vx, vy, child); + + /* Go to next sibling */ + exc = dom_node_get_next_sibling(child, &next_child); + + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for node_get_next_sibling\n"); + dom_node_unref(child); + return; + } + dom_node_unref(child); + child = next_child; + } +} + void dump_xhtml(struct cache_entry *cached, struct document *document, int parse) { @@ -301,7 +469,6 @@ dump_xhtml(struct cache_entry *cached, struct document *document, int parse) if (!document->dom) { return; } - doc = document->dom; in_script = 0; @@ -372,3 +539,172 @@ dump_xhtml(struct cache_entry *cached, struct document *document, int parse) render_html_document(cached, document, &document->text); } } + +void +walk2(struct document *document) +{ + dom_exception exc; /* returned by libdom functions */ + dom_document *doc = NULL; /* document, loaded into libdom */ + dom_node *root = NULL; /* root element of document */ + + if (!document->dom) { + return; + } + doc = document->dom; + + /* Get root element */ + exc = dom_document_get_document_element(doc, &root); + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for get_document_element\n"); + //dom_node_unref(doc); + return; + } else if (root == NULL) { + fprintf(stderr, "Broken: root == NULL\n"); + //dom_node_unref(doc); + return; + } + walk_tree2(document, root); + dom_node_unref(root); +} + +static int prev_offset = 0; +static struct node_rect *prev_element = NULL; + +static struct node_rect * +get_element(struct document *document, int offset) +{ + if (offset == prev_offset) { + return prev_element; + } + struct hash_item *item = get_hash_item(document->hh, (const char *)&offset, sizeof(offset)); + + if (item) { + prev_offset = offset; + prev_element = item->value; + + return prev_element; + } + struct node_rect *n = mem_alloc(sizeof(*n)); + + if (!n) { + return NULL; + } + n->x0 = INT_MAX; + n->y0 = INT_MAX; + n->x1 = 0; + n->y1 = 0; + n->offset = offset; + + char *key = memacpy((const char *)&offset, sizeof(offset)); + + if (key) { + item = add_hash_item(document->hh, key, sizeof(offset), n); + } + if (!item) { + mem_free(n); + return NULL; + } + prev_offset = offset; + prev_element = n; + + return n; +} +//static void dump_results(struct document *document); + +void +scan_document(struct document_view *doc_view) +{ + int y, x; + + if (doc_view->document->hh) { + free_hash(&doc_view->document->hh); + } + doc_view->document->hh = init_hash8(); + + if (!doc_view->document->hh) { + return; + } + + if (!doc_view || !doc_view->document) { + return; + } + + prev_offset = 0; + prev_element = NULL; + + for (y = 0; y < doc_view->document->height; y++) { + for (x = 0; x < doc_view->document->data[y].length; x++) { + int offset = doc_view->document->data[y].ch.chars[x].element_offset; + + if (!offset) { + continue; + } + struct node_rect *tab = get_element(doc_view->document, offset); + + if (!tab) { + continue; + } + + if (tab->x0 > x) { + tab->x0 = x; + } + if (tab->y0 > y) { + tab->y0 = y; + } + if (tab->x1 < x) { + tab->x1 = x; + } + if (tab->y1 < y) { + tab->y1 = x; + } + } + } +// dump_results(doc_view->document); + prev_offset = 0; + prev_element = NULL; + walk2(doc_view->document); +// dump_results(doc_view->document); +} + +#if 0 +static void +dump_results(struct document *document) +{ + struct hash_item *item; + int i; + + foreach_hash_item(item, *(document->hh), i) { + struct node_rect *rect = item->value; + + fprintf(stderr, "%d:(%d,%d):(%d,%d)\n", rect->offset, rect->x0, rect->y0, rect->x1, rect->y1); + } + fprintf(stderr, "=============================\n"); +} +#endif + +void +try_to_color(struct terminal *term, struct el_box *box, struct document *document, int vx, int vy) +{ + dom_exception exc; /* returned by libdom functions */ + dom_document *doc = NULL; /* document, loaded into libdom */ + dom_node *root = NULL; /* root element of document */ + + if (!document->dom) { + return; + } + doc = document->dom; + + /* Get root element */ + exc = dom_document_get_document_element(doc, &root); + if (exc != DOM_NO_ERR) { + fprintf(stderr, "Exception raised for get_document_element\n"); + //dom_node_unref(doc); + return; + } else if (root == NULL) { + fprintf(stderr, "Broken: root == NULL\n"); + //dom_node_unref(doc); + return; + } + walk_tree2_color(term, box, document, vx, vy, root); + dom_node_unref(root); +} diff --git a/src/document/libdom/renderer2.h b/src/document/libdom/renderer2.h index bf17b824..7f280019 100644 --- a/src/document/libdom/renderer2.h +++ b/src/document/libdom/renderer2.h @@ -7,10 +7,20 @@ extern "C" { struct cache_entry; struct document; +struct document_view; +struct el_box; struct string; +struct terminal; + +struct node_rect { + int x0, y0, x1, y1, offset; +}; void render_xhtml_document(struct cache_entry *cached, struct document *document, struct string *buffer); void dump_xhtml(struct cache_entry *cached, struct document *document, int parse); +void walk2(struct document *document); +void scan_document(struct document_view *doc_view); +void try_to_color(struct terminal *term, struct el_box *box, struct document *document, int vx, int vy); #ifdef __cplusplus } diff --git a/src/viewer/text/draw.c b/src/viewer/text/draw.c index 36f5bfae..bc30c4e0 100644 --- a/src/viewer/text/draw.c +++ b/src/viewer/text/draw.c @@ -19,6 +19,7 @@ #include "document/document.h" #include "document/html/frames.h" #include "document/html/iframes.h" +#include "document/libdom/renderer2.h" #include "document/options.h" #include "document/refresh.h" #include "document/renderer.h" @@ -36,6 +37,7 @@ #include "terminal/tab.h" #include "terminal/terminal.h" #include "util/error.h" +#include "util/hash.h" #include "util/lists.h" #include "util/memory.h" #include "util/string.h" @@ -417,6 +419,7 @@ draw_doc(struct session *ses, struct document_view *doc_view, int active) if (ses->navigate_mode == NAVIGATE_LINKWISE) check_vs(doc_view); } + for (y = int_max(vy, 0); y < int_min(doc_view->document->height, box->height + vy); y++) { @@ -441,6 +444,7 @@ draw_doc(struct session *ses, struct document_view *doc_view, int active) } } } + for (i = st; i < max; i++) { if (doc_view->document->data[y].ch.chars[i].data != ' ') { first = &doc_view->document->data[y].ch.chars[i]; @@ -458,6 +462,10 @@ draw_doc(struct session *ses, struct document_view *doc_view, int active) last); } } +#if 0 + try_to_color(term, box, doc_view->document, vx, vy); +#endif + draw_view_status(ses, doc_view, active); if (has_search_word(doc_view)) doc_view->last_x = doc_view->last_y = -1; @@ -618,11 +626,16 @@ refresh_view(struct session *ses, struct document_view *doc_view, int frames) * form field has changed, @ses might not be in the current * tab: consider SELECT pop-ups behind which -remote loads * another tab, or setTimeout in ECMAScript. */ - if (ses->tab == get_current_tab(ses->tab->term)) { if (doc_view->parent_doc_view) { +#ifdef CONFIG_LIBDOM + scan_document(doc_view->parent_doc_view); +#endif draw_doc(ses, doc_view->parent_doc_view, 0); } else { +#ifdef CONFIG_LIBDOM + scan_document(doc_view); +#endif draw_doc(ses, doc_view, 1); } if (frames) draw_frames(ses);