From af16c38d2dbe2decfc45015bd4ee020cb52c608b Mon Sep 17 00:00:00 2001 From: Vincent Sanders Date: Mon, 4 Aug 2014 00:36:14 +0100 Subject: fix DOM tree dump debug --- content/content.c | 11 ++- content/content.h | 16 +++- content/content_protected.h | 2 +- desktop/browser.c | 9 ++- desktop/browser.h | 3 +- gtk/scaffolding.c | 61 ++++++-------- gtk/viewdata.c | 2 - render/html.c | 40 +++++++-- riscos/gui.c | 2 +- utils/errors.h | 4 +- utils/libdom.c | 193 +++++++++++++++++++++++++++++++++++++++++++- utils/libdom.h | 10 +++ 12 files changed, 292 insertions(+), 61 deletions(-) diff --git a/content/content.c b/content/content.c index 87dcfa226..4641571bd 100644 --- a/content/content.c +++ b/content/content.c @@ -860,14 +860,17 @@ void content_search_clear(struct hlcache_handle *h) } } - -void content_debug_dump(struct hlcache_handle *h, FILE *f) +/* exported interface documented in content/content.h */ +nserror content_debug_dump(struct hlcache_handle *h, FILE *f, enum content_debug op) { struct content *c = hlcache_handle_get_content(h); assert(c != 0); - if (c->handler->debug_dump != NULL) - c->handler->debug_dump(c, f); + if (c->handler->debug_dump == NULL) { + return NSERROR_NOT_IMPLEMENTED; + } + + return c->handler->debug_dump(c, f, op); } diff --git a/content/content.h b/content/content.h index a2d07926c..752370034 100644 --- a/content/content.h +++ b/content/content.h @@ -87,6 +87,12 @@ typedef enum { CONTENT_MSG_GADGETCLICK/**< A gadget has been clicked on (mainly for file) */ } content_msg; +/** Debugging dump operations */ +enum content_debug { + CONTENT_DEBUG_RENDER, /** Debug the contents rendering. */ + CONTENT_DEBUG_DOM /** Debug teh contents Document Object. */ +}; + /** RFC5988 metadata link */ struct content_rfc5988_link { struct content_rfc5988_link *next; /**< next rfc5988_link in list */ @@ -271,7 +277,15 @@ void content_search(struct hlcache_handle *h, void *context, search_flags_t flags, const char *string); void content_search_clear(struct hlcache_handle *h); -void content_debug_dump(struct hlcache_handle *h, FILE *f); +/** + * Dump debug information to file. + * + * \param h content handle to debug. + * \param f File to write output to. + * \param op Debug operation type. + */ +nserror content_debug_dump(struct hlcache_handle *h, FILE *f, enum content_debug op); + struct content_rfc5988_link *content_find_rfc5988_link(struct hlcache_handle *c, lwc_string *rel); diff --git a/content/content_protected.h b/content/content_protected.h index f5448c803..7d51e1b8c 100644 --- a/content/content_protected.h +++ b/content/content_protected.h @@ -76,7 +76,7 @@ struct content_handler { void (*search)(struct content *c, void *context, search_flags_t flags, const char *string); void (*search_clear)(struct content *c); - void (*debug_dump)(struct content *c, FILE *f); + nserror (*debug_dump)(struct content *c, FILE *f, enum content_debug op); nserror (*clone)(const struct content *old, struct content **newc); bool (*matches_quirks)(const struct content *c, bool quirks); content_type (*type)(void); diff --git a/desktop/browser.c b/desktop/browser.c index b71d3ffd4..1fa9de648 100644 --- a/desktop/browser.c +++ b/desktop/browser.c @@ -664,10 +664,13 @@ void browser_window_set_gadget_filename(struct browser_window *bw, } /* exported interface, documented in browser.h */ -void browser_window_debug_dump(struct browser_window *bw, FILE *f) +nserror browser_window_debug_dump(struct browser_window *bw, FILE *f, enum content_debug op) { - if (bw->current_content != NULL) - content_debug_dump(bw->current_content, f); + if (bw->current_content == NULL) { + return NSERROR_OK; + } + + return content_debug_dump(bw->current_content, f, op); } /** slow script handler diff --git a/desktop/browser.h b/desktop/browser.h index a9985200e..c7d8b7e79 100644 --- a/desktop/browser.h +++ b/desktop/browser.h @@ -42,6 +42,7 @@ struct selection; struct fetch_multipart_data; struct form_control; struct nsurl; +enum content_debug; typedef enum { DRAGGING_NONE, @@ -452,7 +453,7 @@ char * browser_window_get_selection(struct browser_window *bw); * \param bw The browser window * \param f The file to dump to */ -void browser_window_debug_dump(struct browser_window *bw, FILE *f); +nserror browser_window_debug_dump(struct browser_window *bw, FILE *f, enum content_debug op); /* In platform specific theme_install.c. */ #ifdef WITH_THEME_INSTALL diff --git a/gtk/scaffolding.c b/gtk/scaffolding.c index aed323e45..03a14e5dc 100644 --- a/gtk/scaffolding.c +++ b/gtk/scaffolding.c @@ -1318,7 +1318,7 @@ MULTIHANDLER(debugboxtree) bw = nsgtk_get_browser_window(g->top_level); - browser_window_debug_dump(bw, f); + browser_window_debug_dump(bw, f, CONTENT_DEBUG_RENDER); fclose(f); @@ -1331,50 +1331,35 @@ MULTIHANDLER(debugboxtree) MULTIHANDLER(debugdomtree) { - GtkWidget *save_dialog; - - save_dialog = gtk_file_chooser_dialog_new("Save File", g->window, - GTK_FILE_CHOOSER_ACTION_SAVE, - GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, - GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, - NULL); + gchar *fname; + gint handle; + FILE *f; + struct browser_window *bw; - gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(save_dialog), - getenv("HOME") ? getenv("HOME") : "/"); + handle = g_file_open_tmp("nsgtkdomtreeXXXXXX", &fname, NULL); + if ((handle == -1) || (fname == NULL)) { + return TRUE; + } + close(handle); /* in case it was binary mode */ - gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog), - "domtree.txt"); + /* save data to temporary file */ + f = fopen(fname, "w"); + if (f == NULL) { + warn_user("Error saving box tree dump.", + "Unable to open file for writing."); + unlink(fname); + return TRUE; + } - if (gtk_dialog_run(GTK_DIALOG(save_dialog)) == GTK_RESPONSE_ACCEPT) { - gchar *filename = gtk_file_chooser_get_filename( - GTK_FILE_CHOOSER(save_dialog)); - FILE *fh; - LOG(("Saving dom tree to %s...\n", filename)); + bw = nsgtk_get_browser_window(g->top_level); - fh = fopen((const char *) filename, "w"); - if (fh == NULL) { - warn_user("Error saving box tree dump.", - "Unable to open file for writing."); - } else { - struct browser_window *bw; - bw = nsgtk_get_browser_window(g->top_level); - - if (bw->current_content && - content_get_type(bw->current_content) == - CONTENT_HTML) { -#ifdef FIXME - xmlDebugDumpDocument(fh, - html_get_document(bw->current_content)); -#endif - } + browser_window_debug_dump(bw, f, CONTENT_DEBUG_DOM); - fclose(fh); - } + fclose(f); - g_free(filename); - } + nsgtk_viewfile("DOM Tree Debug", "domtree", fname); - gtk_widget_destroy(save_dialog); + g_free(fname); return TRUE; } diff --git a/gtk/viewdata.c b/gtk/viewdata.c index 1eb78ccf1..6989b9a16 100644 --- a/gtk/viewdata.c +++ b/gtk/viewdata.c @@ -483,8 +483,6 @@ window_init_fname(const char *title, ret = window_init(title, leafname, ndata, ndata_len); - free(ndata); - return ret; } diff --git a/render/html.c b/render/html.c index 9e576486f..12c173f0d 100644 --- a/render/html.c +++ b/render/html.c @@ -1971,17 +1971,43 @@ static bool html_drop_file_at_point(struct content *c, int x, int y, char *file) /** * Dump debug info concerning the html_content * - * \param bw The browser window - * \param bw The file to dump to + * \param bw The browser window + * \param f The file to dump to */ -static void html_debug_dump(struct content *c, FILE *f) +static nserror +html_debug_dump(struct content *c, FILE *f, enum content_debug op) { - html_content *html = (html_content *) c; + html_content *htmlc = (html_content *)c; + dom_node *html; + dom_exception exc; /* returned by libdom functions */ + nserror ret; + + assert(htmlc != NULL); - assert(html != NULL); - assert(html->layout != NULL); + if (op == CONTENT_DEBUG_RENDER) { + assert(htmlc->layout != NULL); + box_dump(f, htmlc->layout, 0, true); + ret = NSERROR_OK; + } else { + if (htmlc->document == NULL) { + LOG(("No document to dump")); + return NSERROR_DOM; + } + + exc = dom_document_get_document_element(htmlc->document, (void *) &html); + if ((exc != DOM_NO_ERR) || (html == NULL)) { + LOG(("Unable to obtain root node")); + return NSERROR_DOM; + } + + ret = libdom_dump_structure(html, f, 0); + + LOG(("DOM structure dump returning %d", ret)); + + dom_node_unref(html); + } - box_dump(f, html->layout, 0, true); + return ret; } diff --git a/riscos/gui.c b/riscos/gui.c index 3253f796f..2e337e5a2 100644 --- a/riscos/gui.c +++ b/riscos/gui.c @@ -2370,7 +2370,7 @@ void ro_gui_dump_browser_window(struct browser_window *bw) return; } - browser_window_debug_dump(bw, stream); + browser_window_debug_dump(bw, stream, CONTENT_DEBUG_RENDER); fclose(stream); diff --git a/utils/errors.h b/utils/errors.h index aa0179a37..b9e157c66 100644 --- a/utils/errors.h +++ b/utils/errors.h @@ -77,7 +77,9 @@ typedef enum { NSERROR_NOSPACE, /**< Insufficient space */ - NSERROR_BAD_SIZE /**< Bad size */ + NSERROR_BAD_SIZE, /**< Bad size */ + + NSERROR_NOT_IMPLEMENTED, /**< Functionality is not implemented */ } nserror; #endif diff --git a/utils/libdom.c b/utils/libdom.c index 245c9b229..d6b26b46b 100644 --- a/utils/libdom.c +++ b/utils/libdom.c @@ -21,11 +21,11 @@ */ #include +#include #include #include "utils/config.h" #include "utils/log.h" - #include "utils/libdom.h" /* exported interface documented in libdom.h */ @@ -196,7 +196,7 @@ dom_node *libdom_find_first_element(dom_node *parent, lwc_string *element_name) /* exported interface documented in libdom.h */ /* TODO: return appropriate errors */ -nserror libdom_iterate_child_elements(dom_node *parent, +nserror libdom_iterate_child_elements(dom_node *parent, libdom_iterate_cb cb, void *ctx) { dom_nodelist *children; @@ -309,6 +309,195 @@ static void ignore_dom_msg(uint32_t severity, void *ctx, const char *msg, ...) { } + + +/** + * Dump attribute/value for an element node + * + * \param node The element node to dump attribute details for + * \param attribute The attribute to dump + * \return true on success, or false on error + */ +static bool dump_dom_element_attribute(dom_node *node, FILE *f, const char *attribute) +{ + dom_exception exc; + dom_string *attr = NULL; + dom_string *attr_value = NULL; + dom_node_type type; + const char *string; + size_t length; + + /* Should only have element nodes here */ + exc = dom_node_get_node_type(node, &type); + if (exc != DOM_NO_ERR) { + fprintf(f, " Exception raised for node_get_node_type\n"); + return false; + } + assert(type == DOM_ELEMENT_NODE); + + /* Create a dom_string containing required attribute name. */ + exc = dom_string_create_interned((uint8_t *)attribute, + strlen(attribute), &attr); + if (exc != DOM_NO_ERR) { + fprintf(f, " Exception raised for dom_string_create\n"); + return false; + } + + /* Get class attribute's value */ + exc = dom_element_get_attribute(node, attr, &attr_value); + if (exc != DOM_NO_ERR) { + fprintf(f, " Exception raised for element_get_attribute\n"); + dom_string_unref(attr); + return false; + } else if (attr_value == NULL) { + /* Element lacks required attribute */ + dom_string_unref(attr); + return true; + } + + /* Finished with the attr dom_string */ + dom_string_unref(attr); + + /* Get attribute value's string data */ + string = dom_string_data(attr_value); + length = dom_string_byte_length(attr_value); + + /* Print attribute info */ + fprintf(f, " %s=\"%.*s\"", attribute, (int)length, string); + + /* Finished with the attr_value dom_string */ + dom_string_unref(attr_value); + + return true; +} + + +/** + * Print a line in a DOM structure dump for an element + * + * \param node The node to dump + * \param depth The node's depth + * \return true on success, or false on error + */ +static bool dump_dom_element(dom_node *node, FILE *f, int depth) +{ + dom_exception exc; + dom_string *node_name = NULL; + dom_node_type type; + int i; + const char *string; + size_t length; + + /* Only interested in element nodes */ + exc = dom_node_get_node_type(node, &type); + if (exc != DOM_NO_ERR) { + fprintf(f, "Exception raised for node_get_node_type\n"); + return false; + } else if (type != DOM_ELEMENT_NODE) { + /* Nothing to print */ + return true; + } + + /* Get element name */ + exc = dom_node_get_node_name(node, &node_name); + if (exc != DOM_NO_ERR) { + fprintf(f, "Exception raised for get_node_name\n"); + return false; + } else if (node_name == NULL) { + fprintf(f, "Broken: root_name == NULL\n"); + return false; + } + + /* Print ASCII tree structure for current node */ + if (depth > 0) { + for (i = 0; i < depth; i++) { + fprintf(f, "| "); + } + fprintf(f, "+-"); + } + + /* Get string data and print element name */ + string = dom_string_data(node_name); + length = dom_string_byte_length(node_name); + fprintf(f, "[%.*s]", (int)length, string); + + if (length == 5 && strncmp(string, "title", 5) == 0) { + /* Title tag, gather the title */ + dom_string *str; + exc = dom_node_get_text_content(node, &str); + if (exc == DOM_NO_ERR && str != NULL) { + fprintf(f, " $%.*s$", (int)dom_string_byte_length(str), + dom_string_data(str)); + dom_string_unref(str); + } + } + + /* Finished with the node_name dom_string */ + dom_string_unref(node_name); + + /* Print the element's id & class, if it has them */ + if (dump_dom_element_attribute(node, f, "id") == false || + dump_dom_element_attribute(node, f, "class") == false) { + /* Error occured */ + fprintf(f, "\n"); + return false; + } + + fprintf(f, "\n"); + return true; +} + + +/* exported interface documented in libdom.h */ +nserror libdom_dump_structure(dom_node *node, FILE *f, int depth) +{ + dom_exception exc; + dom_node *child; + nserror ret; + dom_node *next_child; + + /* Print this node's entry */ + if (dump_dom_element(node, f, depth) == false) { + /* There was an error; return */ + return NSERROR_DOM; + } + + /* Get the node's first child */ + exc = dom_node_get_first_child(node, &child); + if (exc != DOM_NO_ERR) { + fprintf(f, "Exception raised for node_get_first_child\n"); + return NSERROR_DOM; + } else if (child != NULL) { + /* node has children; decend to children's depth */ + depth++; + + /* Loop though all node's children */ + do { + /* Visit node's descendents */ + ret = libdom_dump_structure(child, f, depth); + if (ret !=NSERROR_OK) { + /* There was an error; return */ + dom_node_unref(child); + return NSERROR_DOM; + } + + /* Go to next sibling */ + exc = dom_node_get_next_sibling(child, &next_child); + if (exc != DOM_NO_ERR) { + fprintf(f, "Exception raised for node_get_next_sibling\n"); + dom_node_unref(child); + return NSERROR_DOM; + } + + dom_node_unref(child); + child = next_child; + } while (child != NULL); /* No more children */ + } + + return NSERROR_OK; +} + + /* exported interface documented in libdom.h */ nserror libdom_parse_file(const char *filename, const char *encoding, dom_document **doc) { diff --git a/utils/libdom.h b/utils/libdom.h index dc8eacd12..4f78cd2e9 100644 --- a/utils/libdom.h +++ b/utils/libdom.h @@ -25,6 +25,7 @@ #define NETSURF_UTILS_LIBDOM_H_ #include +#include #include @@ -77,4 +78,13 @@ nserror libdom_parse_file(const char *filename, const char *encoding, */ nserror libdom_hubbub_error_to_nserror(dom_hubbub_error error); +/** + * Walk though a DOM (sub)tree, in depth first order, printing DOM structure. + * + * \param node The root node to start from. + * \param f The file to write output into. + * \param depth The depth of 'node' in the (sub)tree. + */ +nserror libdom_dump_structure(dom_node *node, FILE *f, int depth); + #endif -- cgit v1.2.3