diff --git a/src/ecmascript/libdom/spidermonkey/Makefile b/src/ecmascript/libdom/spidermonkey/Makefile index 53e16f53..7c278fd0 100644 --- a/src/ecmascript/libdom/spidermonkey/Makefile +++ b/src/ecmascript/libdom/spidermonkey/Makefile @@ -3,6 +3,6 @@ include $(top_builddir)/Makefile.config INCLUDES += $(SPIDERMONKEY_CFLAGS) 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 + keyboard.obj localstorage.obj location.obj message.obj navigator.obj nodelist.obj screen.obj style.obj unibar.obj window.obj xhr.obj include $(top_srcdir)/Makefile.lib diff --git a/src/ecmascript/libdom/spidermonkey/element.cpp b/src/ecmascript/libdom/spidermonkey/element.cpp index 195e2e46..80abc67c 100644 --- a/src/ecmascript/libdom/spidermonkey/element.cpp +++ b/src/ecmascript/libdom/spidermonkey/element.cpp @@ -34,6 +34,7 @@ #include "ecmascript/spidermonkey/heartbeat.h" #include "ecmascript/spidermonkey/keyboard.h" #include "ecmascript/spidermonkey/nodelist.h" +#include "ecmascript/spidermonkey/style.h" #include "ecmascript/spidermonkey/window.h" #include "intl/libintl.h" #include "main/select.h" @@ -91,6 +92,7 @@ static bool element_get_property_parentElement(JSContext *ctx, unsigned int argc static bool element_get_property_parentNode(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_previousElementSibling(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool element_get_property_style(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_tagName(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_get_property_textContent(JSContext *ctx, unsigned int argc, JS::Value *vp); static bool element_set_property_textContent(JSContext *ctx, unsigned int argc, JS::Value *vp); @@ -158,6 +160,7 @@ JSPropertySpec element_props[] = { JS_PSG("parentNode", element_get_property_parentNode, JSPROP_ENUMERATE), JS_PSG("previousElementSibling", element_get_property_previousElementSibling, JSPROP_ENUMERATE), JS_PSG("previousSibling", element_get_property_previousSibling, JSPROP_ENUMERATE), + JS_PSG("style", element_get_property_style, JSPROP_ENUMERATE), JS_PSG("tagName", element_get_property_tagName, JSPROP_ENUMERATE), JS_PSGS("textContent", element_get_property_textContent, element_set_property_textContent, JSPROP_ENUMERATE), JS_PSGS("title", element_get_property_title, element_set_property_title, JSPROP_ENUMERATE), @@ -1589,6 +1592,48 @@ element_get_property_previousSibling(JSContext *ctx, unsigned int argc, JS::Valu return true; } +static bool +element_get_property_style(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; + } + + /* 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, &element_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + + dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + + if (!el) { + args.rval().setNull(); + return true; + } + JSObject *style = getStyle(ctx, el); + args.rval().setObject(*style); + + return true; +} + + static bool element_get_property_tagName(JSContext *ctx, unsigned int argc, JS::Value *vp) { diff --git a/src/ecmascript/libdom/spidermonkey/meson.build b/src/ecmascript/libdom/spidermonkey/meson.build index 252cfce9..bddea675 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', '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') +'localstorage.cpp', 'location.cpp', 'message.cpp', 'navigator.cpp', 'nodelist.cpp', 'screen.cpp', 'style.cpp', 'unibar.cpp', 'window.cpp', 'xhr.cpp') diff --git a/src/ecmascript/libdom/spidermonkey/style.cpp b/src/ecmascript/libdom/spidermonkey/style.cpp new file mode 100644 index 00000000..1d5b3461 --- /dev/null +++ b/src/ecmascript/libdom/spidermonkey/style.cpp @@ -0,0 +1,416 @@ +/* The SpiderMonkey style object implementation. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include "elinks.h" + +#include "ecmascript/libdom/dom.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/libdom/corestrings.h" +#include "document/view.h" +#include "ecmascript/ecmascript.h" +#include "ecmascript/libdom/dom.h" +#include "ecmascript/spidermonkey/style.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 +#include +#include +#include + +static bool style_style(JSContext *ctx, unsigned int argc, JS::Value *vp, const char *property); +static bool style_get_property_background(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_backgroundColor(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_color(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_display(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_fontStyle(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_fontWeight(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_lineStyle(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_lineStyleType(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_textAlign(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_textDecoration(JSContext *ctx, unsigned int argc, JS::Value *vp); +static bool style_get_property_whiteSpace(JSContext *ctx, unsigned int argc, JS::Value *vp); + + +static void style_finalize(JS::GCContext *op, JSObject *obj) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif +} + +JSClassOps style_ops = { + nullptr, // addProperty + nullptr, // deleteProperty + nullptr, // enumerate + nullptr, // newEnumerate + nullptr, // resolve + nullptr, // mayResolve + style_finalize, // finalize + nullptr, // call + nullptr, // construct + JS_GlobalObjectTraceHook +}; + +JSClass style_class = { + "style", + JSCLASS_HAS_RESERVED_SLOTS(1), + &style_ops +}; + +static JSPropertySpec style_props[] = { + JS_PSG("background", style_get_property_background, JSPROP_ENUMERATE), + JS_PSG("backgroundColor", style_get_property_backgroundColor, JSPROP_ENUMERATE), + JS_PSG("color", style_get_property_color, JSPROP_ENUMERATE), + JS_PSG("display", style_get_property_display, JSPROP_ENUMERATE), + JS_PSG("fontStyle", style_get_property_fontStyle, JSPROP_ENUMERATE), + JS_PSG("fontWeight", style_get_property_fontWeight, JSPROP_ENUMERATE), + JS_PSG("lineStyle", style_get_property_lineStyle, JSPROP_ENUMERATE), + JS_PSG("lineStyleType", style_get_property_lineStyleType, JSPROP_ENUMERATE), + JS_PSG("textAlign", style_get_property_textAlign, JSPROP_ENUMERATE), + JS_PSG("textDecoration",style_get_property_textDecoration, JSPROP_ENUMERATE), + JS_PSG("whiteSpace", style_get_property_whiteSpace, JSPROP_ENUMERATE), + JS_PS_END +}; + +static bool +style_get_property_background(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "background"); +} + +static bool +style_get_property_backgroundColor(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "background-color"); +} + +static bool +style_get_property_color(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "color"); +} + +static bool +style_get_property_display(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "display"); +} + +static bool +style_get_property_fontStyle(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "font-style"); +} + +static bool +style_get_property_fontWeight(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "font-weight"); +} + +static bool +style_get_property_lineStyle(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "line-style"); +} + +static bool +style_get_property_lineStyleType(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "line-style-type"); +} + +static bool +style_get_property_textAlign(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "text-align"); +} + +static bool +style_get_property_textDecoration(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "text-decoration"); +} + +static bool +style_get_property_whiteSpace(JSContext *ctx, unsigned int argc, JS::Value *vp) +{ +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s\n", __FILE__, __FUNCTION__); +#endif + return style_style(ctx, argc, vp, "white-space"); +} + +const std::map good = { + { "background", true }, + { "background-color", true }, + { "color", true }, + { "display", true }, + { "font-style", true }, + { "font-weight", true }, + { "list-style", true }, + { "list-style-type", true }, + { "text-align", true }, + { "text-decoration", true }, + { "white-space", true } +}; + +static std::string +trimString(std::string str) +{ + const std::string whiteSpaces = " \t\n\r\f\v"; + // Remove leading whitespace + size_t first_non_space = str.find_first_not_of(whiteSpaces); + str.erase(0, first_non_space); + // Remove trailing whitespace + size_t last_non_space = str.find_last_not_of(whiteSpaces); + str.erase(last_non_space + 1); + + return str; +} + +void * +set_elstyle(const char *text) +{ + if (!text || !*text) { + return NULL; + } + std::stringstream str(text); + std::string word; + std::string param, value; + std::map *css = NULL; + + while (!str.eof()) { + getline(str, word, ';'); + std::stringstream params(word); + getline(params, param, ':'); + getline(params, value, ':'); + param = trimString(param); + value = trimString(value); + + if (good.find(param) != good.end()) { + if (!css) { + css = new std::map; + } + if (css) { + (*css)[param] = value; + } + } + } + + return (void *)css; +} + +const char * +get_elstyle(void *m) +{ + std::map *css = static_cast *>(m); + std::string delimiter(""); + std::stringstream output(""); + std::map::iterator it; + + for (it = css->begin(); it != css->end(); it++) { + output << delimiter << it->first << ":" << it->second; + delimiter = ";"; + } + return stracpy(output.str().c_str()); +} + +const char * +get_css_value(const char *text, const char *param) +{ + void *m = set_elstyle(text); + char *res = NULL; + + if (!m) { + return stracpy(""); + } + + std::map *css = static_cast *>(m); + + if (css->find(param) != css->end()) { + res = stracpy((*css)[param].c_str()); + } else { + res = stracpy(""); + } + css->clear(); + delete css; + + return res; +} + +const char * +set_css_value(const char *text, const char *param, const char *value) +{ + void *m = set_elstyle(text); + std::map *css = NULL; + + if (m) { + css = static_cast *>(m); + + if (good.find(param) != good.end()) { + (*css)[param] = value; + } + return get_elstyle(m); + } + + if (good.find(param) != good.end()) { + css = new std::map; + if (!css) { + return stracpy(""); + } + (*css)[param] = value; + return get_elstyle((void *)css); + } + return stracpy(""); +} + + +static bool +style_style(JSContext *ctx, unsigned int argc, JS::Value *vp, const char *property) +{ +#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, &style_class, NULL)) { +#ifdef ECMASCRIPT_DEBUG + fprintf(stderr, "%s:%s %d\n", __FILE__, __FUNCTION__, __LINE__); +#endif + return false; + } + dom_node *el = (dom_node *)JS::GetMaybePtrFromReservedSlot(hobj, 0); + dom_exception exc; + dom_string *style = NULL; + const char *res = NULL; + + if (!el) { + args.rval().setNull(); + return true; + } + exc = dom_element_get_attribute(el, corestring_dom_style, &style); + + if (exc != DOM_NO_ERR) { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + return true; + } + + if (!style || !dom_string_length(style)) { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + + if (style) { + dom_string_unref(style); + } + return true; + } + + res = get_css_value(dom_string_data(style), property); + dom_string_unref(style); + + if (!res) { + args.rval().setString(JS_NewStringCopyZ(ctx, "")); + return true; + } + args.rval().setString(JS_NewStringCopyZ(ctx, res)); + mem_free(res); + + return true; +} + +JSObject * +getStyle(JSContext *ctx, void *node) +{ + JSObject *el = JS_NewObject(ctx, &style_class); + + if (!el) { + return NULL; + } + + JS::RootedObject r_el(ctx, el); + + JS_DefineProperties(ctx, r_el, (JSPropertySpec *) style_props); +// spidermonkey_DefineFunctions(ctx, el, attributes_funcs); + + JS::SetReservedSlot(el, 0, JS::PrivateValue(node)); + + return el; +} diff --git a/src/ecmascript/spidermonkey/style.h b/src/ecmascript/spidermonkey/style.h new file mode 100644 index 00000000..fda3362a --- /dev/null +++ b/src/ecmascript/spidermonkey/style.h @@ -0,0 +1,8 @@ +#ifndef EL__ECMASCRIPT_SPIDERMONKEY_STYLE_H +#define EL__ECMASCRIPT_SPIDERMONKEY_STYLE_H + +#include "ecmascript/spidermonkey/util.h" + +JSObject *getStyle(JSContext *ctx, void *node); + +#endif