mirror of
https://github.com/netsurf-browser/netsurf
synced 2024-12-22 04:02:34 +03:00
fix DOM tree dump debug
This commit is contained in:
parent
c4d1ece421
commit
af16c38d2d
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
gchar *fname;
|
||||
gint handle;
|
||||
FILE *f;
|
||||
struct browser_window *bw;
|
||||
|
||||
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);
|
||||
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_folder(GTK_FILE_CHOOSER(save_dialog),
|
||||
getenv("HOME") ? getenv("HOME") : "/");
|
||||
|
||||
gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(save_dialog),
|
||||
"domtree.txt");
|
||||
|
||||
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));
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
fclose(fh);
|
||||
}
|
||||
|
||||
g_free(filename);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
gtk_widget_destroy(save_dialog);
|
||||
bw = nsgtk_get_browser_window(g->top_level);
|
||||
|
||||
browser_window_debug_dump(bw, f, CONTENT_DEBUG_DOM);
|
||||
|
||||
fclose(f);
|
||||
|
||||
nsgtk_viewfile("DOM Tree Debug", "domtree", fname);
|
||||
|
||||
g_free(fname);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -483,8 +483,6 @@ window_init_fname(const char *title,
|
||||
|
||||
ret = window_init(title, leafname, ndata, ndata_len);
|
||||
|
||||
free(ndata);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -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(html != NULL);
|
||||
assert(html->layout != NULL);
|
||||
assert(htmlc != NULL);
|
||||
|
||||
box_dump(f, html->layout, 0, true);
|
||||
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);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
193
utils/libdom.c
193
utils/libdom.c
@ -21,11 +21,11 @@
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <dom/dom.h>
|
||||
|
||||
#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)
|
||||
{
|
||||
|
@ -25,6 +25,7 @@
|
||||
#define NETSURF_UTILS_LIBDOM_H_
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <dom/dom.h>
|
||||
|
||||
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user