From 5f1229cf184a88d2b03216d6637926ffc3c8d042 Mon Sep 17 00:00:00 2001 From: Witold Filipczyk Date: Thu, 4 May 2023 16:01:38 +0200 Subject: [PATCH] [libdom] spidermonkey document.cpp --- src/ecmascript/libdom/spidermonkey/Makefile | 2 +- .../libdom/spidermonkey/document.cpp | 1966 +++++++++++++++++ .../libdom/spidermonkey/meson.build | 2 +- src/ecmascript/spidermonkey/document.cpp | 3 + 4 files changed, 1971 insertions(+), 2 deletions(-) create mode 100644 src/ecmascript/libdom/spidermonkey/document.cpp diff --git a/src/ecmascript/libdom/spidermonkey/Makefile b/src/ecmascript/libdom/spidermonkey/Makefile index 33441258..59cb4e0b 100644 --- a/src/ecmascript/libdom/spidermonkey/Makefile +++ b/src/ecmascript/libdom/spidermonkey/Makefile @@ -2,7 +2,7 @@ top_builddir=../../.. include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) -OBJS = attr.obj attributes.obj collection.obj console.obj element.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \ +OBJS = attr.obj attributes.obj collection.obj console.obj document.obj element.obj form.obj forms.obj heartbeat.obj history.obj implementation.obj input.obj \ keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj unibar.obj window.obj xhr.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/libdom/spidermonkey/document.cpp b/src/ecmascript/libdom/spidermonkey/document.cpp new file mode 100644 index 00000000..5acba400 --- /dev/null +++ b/src/ecmascript/libdom/spidermonkey/document.cpp @@ -0,0 +1,1966 @@ +/* The SpiderMonkey document object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/libdom/dom.h" + +#include "ecmascript/ecmascript.h" +#include "ecmascript/spidermonkey/util.h" +#include + +#include "bfu/dialog.h" +#include "cache/cache.h" +#include "cookies/cookies.h" +#include "dialogs/menu.h" +#include "dialogs/status.h" +#include "document/html/frames.h" +#include "document/document.h" +#include "document/forms.h" +#include "document/view.h" +#include "ecmascript/css2xpath.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/libdom/parse.h" +#include "ecmascript/spidermonkey/collection.h" +#include "ecmascript/spidermonkey/form.h" +#include "ecmascript/spidermonkey/forms.h" +#include "ecmascript/spidermonkey/implementation.h" +#include "ecmascript/spidermonkey/location.h" +#include "ecmascript/spidermonkey/document.h" +#include "ecmascript/spidermonkey/element.h" +#include "ecmascript/spidermonkey/nodelist.h" +#include "ecmascript/spidermonkey/util.h" +#include "ecmascript/spidermonkey/window.h" +#include "intl/libintl.h" +#include "main/select.h" +#include "osdep/newwin.h" +#include "osdep/sysname.h" +#include "protocol/http/http.h" +#include "protocol/uri.h" +#include "session/history.h" +#include "session/location.h" +#include "session/session.h" +#include "session/task.h" +#include "terminal/tab.h" +#include "terminal/terminal.h" +#include "util/conv.h" +#include "util/memory.h" +#include "util/string.h" +#include "viewer/text/draw.h" +#include "viewer/text/form.h" +#include "viewer/text/link.h" +#include "viewer/text/vs.h" + +#include + +static JSObject *getDoctype(JSContext *ctx, void *node); + +static void document_finalize(JS::GCContext *op, JSObject *obj) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif +} + +JSClassOps document_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + document_finalize, // finalize + nullptr, // call + nullptr, // construct + JS_GlobalObjectTraceHook +}; + + +/* Each @document_class object must have a @window_class parent. */ +JSClass document_class = { + "document", + JSCLASS_HAS_RESERVED_SLOTS(1), + &document_ops +}; + +static bool +document_get_property_anchors(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_collection *anchors = NULL; + dom_exception exc = dom_html_document_get_anchors(doc, &anchors); + + if (exc != DOM_NO_ERR || !anchors) { + args.rval().setNull(); + return true; + } + JSObject *obj = getCollection(ctx, anchors); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_baseURI(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &document_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + char *str = get_uri_string(vs->uri, URI_BASE); + + if (!str) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + + return true; +} + +static bool +document_get_property_body(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_element *body = NULL; + dom_exception exc = dom_html_document_get_body(doc, &body); + + if (exc != DOM_NO_ERR || !body) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, body); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_set_property_body(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return true; +} + +#ifdef CONFIG_COOKIES +static bool +document_get_property_cookie(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + struct view_state *vs; + struct string *cookies; + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + cookies = send_cookies_js(vs->uri); + + if (cookies) { + static char cookiestr[1024]; + + strncpy(cookiestr, cookies->source, 1023); + done_string(cookies); + args.rval().setString(JS_NewStringCopyZ(ctx, cookiestr)); + } else { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + } + + return true; +} + +static bool +document_set_property_cookie(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + struct view_state *vs; + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + char *text = jsval_to_string(ctx, args[0]); + set_cookie(vs->uri, text); + mem_free_if(text); + + return true; +} + +#endif + +static bool +document_get_property_charset(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + args.rval().setString(JS_NewStringCopyZ(ctx, "utf-8")); + + return true; +} + +static bool +document_get_property_childNodes(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &document_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct document *document = vs->doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + + dom_html_document *doc = (dom_html_document *)document->dom; + dom_element *root = NULL; + dom_exception exc = dom_document_get_document_element(doc, &root); + + if (exc != DOM_NO_ERR || !root) { + args.rval().setNull(); + return true; + } + dom_nodelist *nodes = NULL; + exc = dom_node_get_child_nodes(root, &nodes); + dom_node_unref(root); + + if (exc != DOM_NO_ERR || !nodes) { + args.rval().setNull(); + return true; + } + JSObject *obj = getNodeList(ctx, nodes); + args.rval().setObject(*obj); + + return true; +} + + +static bool +document_get_property_doctype(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + + dom_html_document *doc = (dom_html_document *)document->dom; + dom_document_type *dtd; + dom_document_get_doctype(doc, &dtd); + + JSObject *obj = getDoctype(ctx, dtd); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_documentElement(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_element *root = NULL; + dom_exception exc = dom_document_get_document_element(doc, &root); + + if (exc != DOM_NO_ERR || !root) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, root); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_documentURI(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &document_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { + return false; + } + + char *str = get_uri_string(vs->uri, URI_BASE); + + if (!str) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + + return true; +} + +static bool +document_get_property_domain(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + struct view_state *vs; + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &document_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + char *str = get_uri_string(vs->uri, URI_HOST); + + if (!str) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + + return true; +} + +static bool +document_get_property_forms(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_collection *forms = NULL; + dom_exception exc = dom_html_document_get_forms(doc, &forms); + + if (exc != DOM_NO_ERR || !forms) { + args.rval().setNull(); + return true; + } + JSObject *obj = getForms(ctx, forms); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_head(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + args.rval().setNull(); + return true; +} + +static bool +document_get_property_images(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_collection *images = NULL; + dom_exception exc = dom_html_document_get_images(doc, &images); + + if (exc != DOM_NO_ERR || !images) { + args.rval().setNull(); + return true; + } + JSObject *obj = getCollection(ctx, images); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_implementation(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + + JSObject *obj = getImplementation(ctx); + if (!obj) { + args.rval().setNull(); + } else { + args.rval().setObject(*obj); + } + return true; +} + +static bool +document_get_property_links(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_html_document *doc = (dom_html_document *)document->dom; + dom_html_collection *links = NULL; + dom_exception exc = dom_html_document_get_links(doc, &links); + + if (exc != DOM_NO_ERR || !links) { + args.rval().setNull(); + return true; + } + JSObject *obj = getCollection(ctx, links); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_get_property_location(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::RootedObject parent_win(ctx, JS::GetNonCCWObjectGlobal(hobj)); + + assert(JS_InstanceOf(ctx, parent_win, &window_class, NULL)); + if_assert_failed return false; + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + args.rval().setObject(*(JSObject *)(interpreter->location_obj)); + return true; +} + +static bool +document_get_property_nodeType(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + args.rval().setInt32(9); + + return true; +} + + +static bool +document_set_property_location(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + struct view_state *vs; + struct document_view *doc_view; + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + char *url = jsval_to_string(ctx, args[0]); + + if (url) { + location_goto(doc_view, url); + mem_free(url); + } + + return true; +} + + +static bool +document_get_property_referrer(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + struct session *ses; + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + ses = doc_view->session; + + switch (get_opt_int("protocol.http.referer.policy", NULL)) { + case REFERER_NONE: + /* oh well */ + args.rval().setUndefined(); + break; + + case REFERER_FAKE: + args.rval().setString(JS_NewStringCopyZ(ctx, get_opt_str("protocol.http.referer.fake", NULL))); + break; + + case REFERER_TRUE: + /* XXX: Encode as in add_url_to_httset_prop_string(&prop, ) ? --pasky */ + if (ses->referrer) { + char *str = get_uri_string(ses->referrer, URI_HTTP_REFERRER); + + if (str) { + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + } else { + args.rval().setUndefined(); + } + } + break; + + case REFERER_SAME_URL: + char *str = get_uri_string(document->uri, URI_HTTP_REFERRER); + + if (str) { + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + } else { + args.rval().setUndefined(); + } + break; + } + + return true; +} + +static bool +document_get_property_scripts(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + args.rval().setNull(); + + return true; +} + + +static bool +document_get_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + args.rval().setString(JS_NewStringCopyZ(ctx, document->title)); + + return true; +} + +static bool +document_set_property_title(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + JS::RootedObject parent_win(ctx, JS::GetNonCCWObjectGlobal(hobj)); + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + + vs = interpreter->vs; + + if (!vs || !vs->doc_view) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + mem_free_set(&document->title, jsval_to_string(ctx, args[0])); + print_screen_status(doc_view->session); + + return true; +} + +static bool +document_get_property_url(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + + struct view_state *vs; + struct document_view *doc_view; + struct document *document; + + vs = interpreter->vs; + + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + document = doc_view->document; + char *str = get_uri_string(document->uri, URI_ORIGINAL); + + if (str) { + args.rval().setString(JS_NewStringCopyZ(ctx, str)); + mem_free(str); + } else { + args.rval().setUndefined(); + } + + return true; +} + +static bool +document_set_property_url(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct view_state *vs; + struct document_view *doc_view; + + vs = interpreter->vs; + if (!vs) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + doc_view = vs->doc_view; + char *url = jsval_to_string(ctx, args[0]); + if (url) { + location_goto(doc_view, url); + mem_free(url); + } + + return true; +} + + +/* "cookie" is special; it isn't a regular property but we channel it to the + * cookie-module. XXX: Would it work if "cookie" was defined in this array? */ +JSPropertySpec document_props[] = { + JS_PSG("anchors", document_get_property_anchors, JSPROP_ENUMERATE), + JS_PSG("baseURI", document_get_property_baseURI, JSPROP_ENUMERATE), + JS_PSGS("body", document_get_property_body, document_set_property_body, JSPROP_ENUMERATE), +#ifdef CONFIG_COOKIES + JS_PSGS("cookie", document_get_property_cookie, document_set_property_cookie, JSPROP_ENUMERATE), +#endif + + JS_PSG("charset", document_get_property_charset, JSPROP_ENUMERATE), + JS_PSG("characterSet", document_get_property_charset, JSPROP_ENUMERATE), + JS_PSG("childNodes", document_get_property_childNodes, JSPROP_ENUMERATE), + JS_PSG("doctype", document_get_property_doctype, JSPROP_ENUMERATE), + JS_PSG("documentElement", document_get_property_documentElement, JSPROP_ENUMERATE), + JS_PSG("documentURI", document_get_property_documentURI, JSPROP_ENUMERATE), + JS_PSG("domain", document_get_property_domain, JSPROP_ENUMERATE), + JS_PSG("forms", document_get_property_forms, JSPROP_ENUMERATE), + JS_PSG("head", document_get_property_head, JSPROP_ENUMERATE), + JS_PSG("images", document_get_property_images, JSPROP_ENUMERATE), + JS_PSG("implementation", document_get_property_implementation, JSPROP_ENUMERATE), + JS_PSG("inputEncoding", document_get_property_charset, JSPROP_ENUMERATE), + JS_PSG("links", document_get_property_links, JSPROP_ENUMERATE), + JS_PSGS("location", document_get_property_location, document_set_property_location, JSPROP_ENUMERATE), + JS_PSG("nodeType", document_get_property_nodeType, JSPROP_ENUMERATE), + JS_PSG("referrer", document_get_property_referrer, JSPROP_ENUMERATE), + JS_PSG("scripts", document_get_property_scripts, JSPROP_ENUMERATE), + JS_PSGS("title", document_get_property_title, document_set_property_title, JSPROP_ENUMERATE), /* TODO: Charset? */ + JS_PSGS("URL", document_get_property_url, document_set_property_url, JSPROP_ENUMERATE), + JS_PS_END +}; + +static bool document_createComment(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_createDocumentFragment(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_createElement(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_createTextNode(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_write(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_writeln(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_replace(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_getElementById(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_getElementsByClassName(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_getElementsByName(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_getElementsByTagName(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_querySelector(JSContext *ctx, unsigned int argc, JS::Value *rval); +static bool document_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *rval); + +const spidermonkeyFunctionSpec document_funcs[] = { + { "createComment", document_createComment, 1 }, + { "createDocumentFragment", document_createDocumentFragment, 0 }, + { "createElement", document_createElement, 1 }, + { "createTextNode", document_createTextNode, 1 }, + { "write", document_write, 1 }, + { "writeln", document_writeln, 1 }, + { "replace", document_replace, 2 }, + { "getElementById", document_getElementById, 1 }, + { "getElementsByClassName", document_getElementsByClassName, 1 }, + { "getElementsByName", document_getElementsByName, 1 }, + { "getElementsByTagName", document_getElementsByTagName, 1 }, + { "querySelector", document_querySelector, 1 }, + { "querySelectorAll", document_querySelectorAll, 1 }, + { NULL } +}; + + +static bool +document_write_do(JSContext *ctx, unsigned int argc, JS::Value *rval, int newline) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + JS::CallArgs args = JS::CallArgsFromVp(argc, rval); + + if (argc >= 1) { + int element_offset = interpreter->element_offset; + + struct string string; + + if (init_string(&string)) { + for (unsigned int i = 0; i < argc; ++i) { + char *str = jsval_to_string(ctx, args[i]); + + if (str) { + add_to_string(&string, str); + mem_free(str); + } + } + + if (newline) { + add_to_string(&string, "\n"); + } + if (element_offset == interpreter->current_writecode->element_offset) { + add_string_to_string(&interpreter->current_writecode->string, &string); + done_string(&string); + } else { + (void)add_to_ecmascript_string_list(&interpreter->writecode, string.source, string.length, element_offset); + done_string(&string); + interpreter->current_writecode = interpreter->current_writecode->next; + } + interpreter->changed = true; + } + } + +#ifdef CONFIG_LEDS + set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J'); +#endif + + args.rval().setBoolean(false); + + return true; +} + +/* @document_funcs{"write"} */ +static bool +document_write(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + + return document_write_do(ctx, argc, rval, 0); +} + +/* @document_funcs{"writeln"} */ +static bool +document_writeln(JSContext *ctx, unsigned int argc, JS::Value *rval) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return document_write_do(ctx, argc, rval, 1); +} + +/* @document_funcs{"replace"} */ +static bool +document_replace(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 2) { + args.rval().setBoolean(false); + return(true); + } + + struct string needle; + struct string heystack; + + if (!init_string(&needle)) { + return false; + } + if (!init_string(&heystack)) { + done_string(&needle); + return false; + } + + jshandle_value_to_char_string(&needle, ctx, args[0]); + jshandle_value_to_char_string(&heystack, ctx, args[1]); + + //DBG("doc replace %s %s\n", needle.source, heystack.source); + + struct document *document = doc_view->document; + struct cache_entry *cached = document->cached; + struct fragment *f = get_cache_fragment(cached); + + if (f && f->length) + { + struct string f_data; + if (init_string(&f_data)) { + add_bytes_to_string(&f_data, f->data, f->length); + + struct string nu_str; + if (init_string(&nu_str)) { + string_replace(&nu_str, &f_data, &needle, &heystack); + delete_entry_content(cached); + /* TBD: somehow better rerender the document + * now it's places on the session level in doc_loading_callback */ + add_fragment(cached, 0, nu_str.source, nu_str.length); + normalize_cache_entry(cached, nu_str.length); + document->ecmascript_counter++; + done_string(&nu_str); + } + //DBG("doc replace %s %s\n", needle.source, heystack.source); + done_string(&f_data); + } + } + + done_string(&needle); + done_string(&heystack); + + args.rval().setBoolean(true); + + return(true); +} + +static bool +document_createComment(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document; + document = doc_view->document; + dom_document *doc = (dom_document *)document->dom; + + if (!doc) { + args.rval().setNull(); + return true; + } + dom_string *data = NULL; + dom_exception exc; + const char *str; + size_t len; + + str = jsval_to_string(ctx, args[0]); + + if (!str) { + return false; + } + len = strlen(str); + exc = dom_string_create((const uint8_t *)str, len, &data); + mem_free(str); + + if (exc != DOM_NO_ERR || !data) { + args.rval().setNull(); + return true; + } + dom_comment *comment = NULL; + exc = dom_document_create_comment(doc, data, &comment); + dom_string_unref(data); + + if (exc != DOM_NO_ERR || !comment) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, comment); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_createDocumentFragment(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 0) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + + dom_document *doc = (dom_document *)(document->dom); + dom_document_fragment *fragment = NULL; + dom_exception exc = dom_document_create_document_fragment(doc, &fragment); + + if (exc != DOM_NO_ERR || !fragment) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, fragment); + args.rval().setObject(*obj); + + return true; +} + + +static bool +document_createElement(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } +// TODO + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + dom_document *doc = (dom_document *)document->dom; + dom_string *tag_name = NULL; + dom_exception exc; + const char *str; + size_t len; + + str = jsval_to_string(ctx, args[0]); + + if (!str) { + return false; + } + len = strlen(str); + exc = dom_string_create((const uint8_t *)str, len, &tag_name); + mem_free(str); + + if (exc != DOM_NO_ERR || !tag_name) { + args.rval().setNull(); + return true; + } + dom_element *element = NULL; + exc = dom_document_create_element(doc, tag_name, &element); + dom_string_unref(tag_name); + + if (exc != DOM_NO_ERR || !element) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, element); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_createTextNode(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } +// TODO + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + dom_document *doc = (dom_document *)document->dom; + dom_string *data = NULL; + dom_exception exc; + const char *str; + size_t len; + + str = jsval_to_string(ctx, args[0]); + + if (!str) { + return false; + } + len = strlen(str); + exc = dom_string_create((const uint8_t *)str, len, &data); + mem_free(str); + + if (exc != DOM_NO_ERR || !data) { + args.rval().setNull(); + return true; + } + dom_text *text_node = NULL; + exc = dom_document_create_text_node(doc, data, &text_node); + dom_string_unref(data); + + if (exc != DOM_NO_ERR || !text_node) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, text_node); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_getElementById(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + + dom_document *doc = (dom_document *)document->dom; + dom_string *id = NULL; + dom_exception exc; + const char *str; + size_t len; + + str = jsval_to_string(ctx, args[0]); + + if (!str) { + return false; + } + len = strlen(str); + exc = dom_string_create((const uint8_t *)str, len, &id); + mem_free(str); + + if (exc != DOM_NO_ERR || !id) { + args.rval().setNull(); + return true; + } + dom_element *element = NULL; + exc = dom_document_get_element_by_id(doc, id, &element); + dom_string_unref(id); + + if (exc != DOM_NO_ERR || !element) { + args.rval().setNull(); + return true; + } + JSObject *obj = getElement(ctx, element); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_getElementsByClassName(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + +// TODO + args.rval().setNull(); + + return true; +} + +static bool +document_getElementsByName(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + +// TODO + args.rval().setNull(); + + return true; +} + +static bool +document_getElementsByTagName(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } + dom_document *doc = (dom_document *)document->dom; + dom_string *tagname = NULL; + dom_exception exc; + const char *str; + size_t len; + + str = jsval_to_string(ctx, args[0]); + + if (!str) { + return false; + } + len = strlen(str); + exc = dom_string_create((const uint8_t *)str, len, &tagname); + mem_free(str); + + if (exc != DOM_NO_ERR || !tagname) { + args.rval().setNull(); + return true; + } + dom_nodelist *nodes = NULL; + exc = dom_document_get_elements_by_tag_name(doc, tagname, &nodes); + dom_string_unref(tagname); + + if (exc != DOM_NO_ERR || !nodes) { + args.rval().setNull(); + return true; + } + JSObject *obj = getNodeList(ctx, nodes); + args.rval().setObject(*obj); + + return true; +} + +static bool +document_querySelector(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + args.rval().setNull(); + + return true; +} + +static bool +document_querySelectorAll(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + + if (argc != 1) { + args.rval().setBoolean(false); + return true; + } + + JS::Realm *comp = js::GetContextRealm(ctx); + struct ecmascript_interpreter *interpreter = (struct ecmascript_interpreter *)JS::GetRealmPrivate(comp); + struct document_view *doc_view = interpreter->vs->doc_view; + struct document *document = doc_view->document; + + if (!document->dom) { + document->dom = document_parse(document); + } + + if (!document->dom) { + args.rval().setNull(); + return true; + } +// TODO + args.rval().setNull(); + + return true; +} + +JSClassOps doctype_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + nullptr, // finalize + nullptr, // call + nullptr, // construct + JS_GlobalObjectTraceHook +}; + +JSClass doctype_class = { + "doctype", + JSCLASS_HAS_RESERVED_SLOTS(1), + &doctype_ops +}; + +static bool +doctype_get_property_name(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &doctype_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + dom_document_type *dtd = (dom_document_type *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!dtd) { + args.rval().setNull(); + return true; + } + dom_string *name = NULL; + dom_exception exc = dom_document_type_get_name(dtd, &name); + + if (exc != DOM_NO_ERR || !name) { + args.rval().setNull(); + return true; + } + args.rval().setString(JS_NewStringCopyZ(ctx, dom_string_data(name))); + dom_string_unref(name); + + return true; +} + +static bool +doctype_get_property_publicId(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &doctype_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + dom_document_type *dtd = (dom_document_type *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!dtd) { + args.rval().setNull(); + return true; + } + dom_string *public_id = NULL; + dom_exception exc = dom_document_type_get_public_id(dtd, &public_id); + + if (exc != DOM_NO_ERR || !public_id) { + args.rval().setNull(); + return true; + } + args.rval().setString(JS_NewStringCopyZ(ctx, dom_string_data(public_id))); + dom_string_unref(public_id); + + return true; +} + +static bool +doctype_get_property_systemId(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JS::CallArgs args = CallArgsFromVp(argc, vp); + JS::RootedObject hobj(ctx, &args.thisv().toObject()); + JS::Realm *comp = js::GetContextRealm(ctx); + + if (!comp) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + /* This can be called if @obj if not itself an instance of the + * appropriate class but has one in its prototype chain. Fail + * such calls. */ + if (!JS_InstanceOf(ctx, hobj, &doctype_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + dom_document_type *dtd = (dom_document_type *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!dtd) { + args.rval().setNull(); + return true; + } + dom_string *system_id = NULL; + dom_exception exc = dom_document_type_get_system_id(dtd, &system_id); + + if (exc != DOM_NO_ERR || !system_id) { + args.rval().setNull(); + return true; + } + args.rval().setString(JS_NewStringCopyZ(ctx, dom_string_data(system_id))); + dom_string_unref(system_id); + + return true; +} + +JSPropertySpec doctype_props[] = { + JS_PSG("name", doctype_get_property_name, JSPROP_ENUMERATE), + JS_PSG("publicId", doctype_get_property_publicId, JSPROP_ENUMERATE), + JS_PSG("systemId", doctype_get_property_systemId, JSPROP_ENUMERATE), + JS_PS_END +}; + +static JSObject * +getDoctype(JSContext *ctx, void *node) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JSObject *el = JS_NewObject(ctx, &doctype_class); + + if (!el) { + return NULL; + } + + JS::RootedObject r_el(ctx, el); + JS_DefineProperties(ctx, r_el, (JSPropertySpec *) doctype_props); + JS::SetReservedSlot(el, 0, JS::PrivateValue(node)); + + return el; +} + +JSObject * +getDocument(JSContext *ctx, void *doc) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + JSObject *el = JS_NewObject(ctx, &document_class); + + if (!el) { + return NULL; + } + + JS::RootedObject r_el(ctx, el); + + JS_DefineProperties(ctx, r_el, (JSPropertySpec *) document_props); + spidermonkey_DefineFunctions(ctx, el, document_funcs); + + JS::SetReservedSlot(el, 0, JS::PrivateValue(doc)); + + return el; +} diff --git a/src/ecmascript/libdom/spidermonkey/meson.build b/src/ecmascript/libdom/spidermonkey/meson.build index a76044d9..252cfce9 100644 --- a/src/ecmascript/libdom/spidermonkey/meson.build +++ b/src/ecmascript/libdom/spidermonkey/meson.build @@ -1,2 +1,2 @@ -srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'element.cpp', 'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', 'keyboard.cpp', +srcs += files('attr.cpp', 'attributes.cpp', 'collection.cpp', 'console.cpp', 'document.cpp', 'element.cpp', 'form.cpp', 'forms.cpp', 'heartbeat.cpp', 'history.cpp', 'implementation.cpp', 'input.cpp', 'keyboard.cpp', 'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') diff --git a/src/ecmascript/spidermonkey/document.cpp b/src/ecmascript/spidermonkey/document.cpp index 71ed7783..ef93dbcd 100644 --- a/src/ecmascript/spidermonkey/document.cpp +++ b/src/ecmascript/spidermonkey/document.cpp @@ -62,6 +62,8 @@ #include +#ifndef CONFIG_LIBDOM + static xmlpp::Document emptyDoc; static JSObject *getDoctype(JSContext *ctx, void *node); @@ -2177,3 +2179,4 @@ getDocument(JSContext *ctx, void *doc) return el; } +#endif