#include <iostream>
#include <iomanip>
#include <glib.h>
#include <signal.h>
#include <cairo.h>
#include <moz-headless.h>
#include "nsCOMPtr.h"
#include "nsDOMString.h"
#include "nsServiceManagerUtils.h"
#include "nsIDOMDocument.h"
#include "nsIDOMElement.h"
#include "nsIDOMNodeList.h"
#include "inIDOMUtils.h"
#include "nsIDOMCSSRule.h"
#include "nsISupportsArray.h"
#define WIDTH 800
#define HEIGHT 600
using namespace std;
static MozHeadless *headless;
static GMainLoop *mainloop;
static gboolean resized = FALSE;
static cairo_surface_t *surface;
void walkDOM(nsIDOMElement *element, nsIDOMDocument *document, PRUint32 level);
void ouputPrefix(PRUint32 level);
static void net_stop_cb(MozHeadless *headless) {
gint width, height;
moz_headless_get_document_size(headless, &width, &height);
surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
moz_headless_set_surface(headless,
cairo_image_surface_get_data(surface),
width,
height,
width*4);
moz_headless_set_size(headless, width, height);
resized = TRUE;
}
static void updated_cb(MozHeadless *headless,
gint x,
gint y,
gint width,
gint height) {
nsCOMPtr<nsIDOMDocument> document;
moz_headless_get_dom_document(headless, getter_AddRefs(document));
// Get root element
nsCOMPtr<nsIDOMElement> rootElem;
document->GetDocumentElement(getter_AddRefs(rootElem));
if (rootElem) {
walkDOM(rootElem, document, 0);
}
if (resized) g_main_loop_quit (mainloop);
}
static void leave(int sig) {
net_stop_cb(headless);
}
void walkDOM(nsIDOMElement *element, nsIDOMDocument *document, PRUint32 level) {
nsCOMPtr<nsIDOMNode> childNode;
nsCOMPtr<nsIDOMNode> siblingNode;
// Get node local name
nsAutoString localName;
element->GetLocalName(localName);
ouputPrefix(level);
cout << "<" << NS_ConvertUTF16toUTF8(localName).get() << "> Style:" << endl;
// Get node style
nsAutoString style;
element->GetAttribute(NS_LITERAL_STRING("style"), style);
if (style.Length()) {
ouputPrefix(level);
cout << NS_ConvertUTF16toUTF8(style).get() << endl;
}
// Get node CSS declaration
nsCOMPtr<inIDOMUtils> domUtils =
do_GetService("@mozilla.org/inspector/dom-utils;1");
nsCOMPtr<nsISupportsArray> rules;
domUtils->GetCSSStyleRules(element, getter_AddRefs(rules));
PRUint32 count;
rules->Count(&count);
for (PRUint32 i = 0; i < count; ++i) {
nsAutoString dom_style;
nsCOMPtr<nsIDOMCSSRule> domRule =
do_QueryInterface(rules->ElementAt(i));
domRule->GetCssText(dom_style);
ouputPrefix(level);
cout << NS_ConvertUTF16toUTF8(dom_style).get() << endl;
}
// Child nodes traversal
element->GetFirstChild(getter_AddRefs(childNode));
while (childNode) {
nsCOMPtr<nsIDOMElement> childElem = do_QueryInterface(childNode);
// Recursion
if (childElem) {
walkDOM(childElem, document, level+1);
}
childNode->GetNextSibling(getter_AddRefs(siblingNode));
childNode = siblingNode;
}
}
void ouputPrefix(PRUint32 level) {
cout << setfill(' ') << setw(level*4) << "";
}
int main(int argc, char **argv) {
if (argc < 2) {
cout << "Usage: " << argv[0] << " <url>" << endl;
return 1;
}
g_type_init();
mainloop = g_main_loop_new(NULL, FALSE);
headless = moz_headless_new();
moz_headless_set_size(headless, WIDTH, HEIGHT);
g_signal_connect(headless, "net-stop", G_CALLBACK(net_stop_cb), NULL);
g_signal_connect(headless, "updated", G_CALLBACK (updated_cb), NULL);
moz_headless_load_url(headless, argv[1]);
signal(SIGINT, leave);
g_main_loop_run(mainloop);
return 0;
}