Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright 2012 Vincent Sanders <vince@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. #include "javascript/jsapi.h"
  20. #include "render/html_internal.h"
  21. #include "content/content.h"
  22. #include "javascript/content.h"
  23. #include "javascript/js.h"
  24.  
  25. #include "utils/log.h"
  26.  
  27. #include "window.h"
  28. #include "event.h"
  29.  
  30. static JSRuntime *rt; /* global runtime */
  31.  
  32. void js_initialise(void)
  33. {
  34.         /* Create a JS runtime. */
  35.  
  36. #if JS_VERSION >= 180
  37.         JS_SetCStringsAreUTF8(); /* we prefer our runtime to be utf-8 */
  38. #endif
  39.  
  40.         rt = JS_NewRuntime(8L * 1024L * 1024L);
  41.         JSLOG("New runtime handle %p", rt);
  42.  
  43.         if (rt != NULL) {
  44.                 /* register script content handler */
  45.                 javascript_init();
  46.         }
  47. }
  48.  
  49. void js_finalise(void)
  50. {
  51.         if (rt != NULL) {
  52.                 JSLOG("destroying runtime handle %p", rt);
  53.                 JS_DestroyRuntime(rt);
  54.         }
  55.         JS_ShutDown();
  56. }
  57.  
  58. /* The error reporter callback. */
  59. static void js_reportError(JSContext *cx, const char *message, JSErrorReport *report)
  60. {
  61.         JSLOG("%s:%u:%s",
  62.               report->filename ? report->filename : "<no filename>",
  63.               (unsigned int) report->lineno,
  64.               message);
  65. }
  66.  
  67. jscontext *js_newcontext(void)
  68. {
  69.         JSContext *cx;
  70.  
  71.         if (rt == NULL) {
  72.                 return NULL;
  73.         }
  74.  
  75.         cx = JS_NewContext(rt, 8192);
  76.         if (cx == NULL) {
  77.                 return NULL;
  78.         }
  79.         JS_SetOptions(cx, JSOPTION_VAROBJFIX | JSOPTION_JIT );
  80.         JS_SetVersion(cx, JSVERSION_LATEST);
  81.         JS_SetErrorReporter(cx, js_reportError);
  82.  
  83.         /*JS_SetGCZeal(cx, 2); */
  84.  
  85.         JSLOG("New Context %p", cx);
  86.  
  87.         return (jscontext *)cx;
  88. }
  89.  
  90. void js_destroycontext(jscontext *ctx)
  91. {
  92.         JSContext *cx = (JSContext *)ctx;
  93.         if (cx != NULL) {
  94.                 JSLOG("Destroying Context %p", cx);
  95.                 JS_DestroyContext(cx);
  96.         }
  97. }
  98.  
  99.  
  100. /** Create new compartment to run scripts within
  101.  *
  102.  * This performs the following actions
  103.  * 1. constructs a new global object by initialising a window class
  104.  * 2. Instantiate the global a window object
  105.  */
  106. jsobject *js_newcompartment(jscontext *ctx, void *win_priv, void *doc_priv)
  107. {
  108.         JSContext *cx = (JSContext *)ctx;
  109.         JSObject *window_proto;
  110.         JSObject *window;
  111.  
  112.         if (cx == NULL) {
  113.                 return NULL;
  114.         }
  115.  
  116.         window_proto = jsapi_InitClass_Window(cx, NULL);
  117.         if (window_proto == NULL) {
  118.                 JSLOG("Unable to initialise window class");
  119.                 return NULL;
  120.         }
  121.  
  122.         window = jsapi_new_Window(cx, window_proto, NULL, win_priv, doc_priv);
  123.  
  124.         return (jsobject *)window;
  125. }
  126.  
  127. bool js_exec(jscontext *ctx, const char *txt, size_t txtlen)
  128. {
  129.         JSContext *cx = (JSContext *)ctx;
  130.         jsval rval;
  131.  
  132.         /* JSLOG("%p \"%s\"",cx ,txt); */
  133.  
  134.         if (ctx == NULL) {
  135.                 return false;
  136.         }
  137.  
  138.         if (txt == NULL) {
  139.                 return false;
  140.         }
  141.  
  142.         if (txtlen == 0) {
  143.                 return false;
  144.         }
  145.  
  146.         if (JS_EvaluateScript(cx,
  147.                               JS_GetGlobalObject(cx),
  148.                               txt, txtlen,
  149.                               "<head>", 0, &rval) == JS_TRUE) {
  150.  
  151.                 return true;
  152.         }
  153.  
  154.         return false;
  155. }
  156.  
  157. dom_exception _dom_event_create(dom_document *doc, dom_event **evt);
  158. #define dom_event_create(d, e) _dom_event_create((dom_document *)(d), (dom_event **) (e))
  159.  
  160. bool js_fire_event(jscontext *ctx, const char *type, dom_document *doc, dom_node *target)
  161. {
  162.         JSContext *cx = (JSContext *)ctx;
  163.         dom_node *node = target;
  164.         JSObject *jsevent;
  165.         jsval rval;
  166.         jsval argv[1];
  167.         JSBool ret = JS_TRUE;
  168.         dom_exception exc;
  169.         dom_event *event;
  170.         dom_string *type_dom;
  171.  
  172.         if (cx == NULL) {
  173.                 return false;
  174.         }
  175.  
  176.         if (node == NULL) {
  177.                 /* deliver manufactured event to window */
  178.                 JSLOG("Dispatching event %s at window", type);
  179.  
  180.                 /* create and initialise and event object */
  181.                 exc = dom_string_create((unsigned char*)type,
  182.                                         strlen(type),
  183.                                         &type_dom);
  184.                 if (exc != DOM_NO_ERR) {
  185.                         return false;
  186.                 }
  187.  
  188.                 exc = dom_event_create(doc, &event);
  189.                 if (exc != DOM_NO_ERR) {
  190.                         return false;
  191.                 }
  192.  
  193.                 exc = dom_event_init(event, type_dom, false, false);
  194.                 dom_string_unref(type_dom);
  195.                 if (exc != DOM_NO_ERR) {
  196.                         return false;
  197.                 }
  198.  
  199.                 jsevent = jsapi_new_Event(cx, NULL, NULL, event);
  200.                 if (jsevent == NULL) {
  201.                         return false;
  202.                 }
  203.  
  204.                 /* dispatch event at the window object */
  205.                 argv[0] = OBJECT_TO_JSVAL(jsevent);
  206.  
  207.                 ret = JS_CallFunctionName(cx,
  208.                                           JS_GetGlobalObject(cx),
  209.                                           "dispatchEvent",
  210.                                           1,
  211.                                           argv,
  212.                                           &rval);
  213.         } else {
  214.                 JSLOG("Dispatching event %s at %p", type, node);
  215.  
  216.                 /* create and initialise and event object */
  217.                 exc = dom_string_create((unsigned char*)type,
  218.                                         strlen(type),
  219.                                         &type_dom);
  220.                 if (exc != DOM_NO_ERR) {
  221.                         return false;
  222.                 }
  223.  
  224.                 exc = dom_event_create(doc, &event);
  225.                 if (exc != DOM_NO_ERR) {
  226.                         return false;
  227.                 }
  228.  
  229.                 exc = dom_event_init(event, type_dom, true, true);
  230.                 dom_string_unref(type_dom);
  231.                 if (exc != DOM_NO_ERR) {
  232.                         return false;
  233.                 }
  234.  
  235.                 dom_event_target_dispatch_event(node, event, &ret);
  236.  
  237.         }
  238.  
  239.         if (ret == JS_TRUE) {
  240.                 return true;
  241.         }
  242.         return false;
  243. }
  244.  
  245. struct js_dom_event_private {
  246.         JSContext *cx; /* javascript context */
  247.         jsval funcval; /* javascript function to call */
  248.         struct dom_node *node; /* dom node event listening on */
  249.         dom_string *type; /* event type */
  250.         dom_event_listener *listener; /* the listener containing this */
  251. };
  252.  
  253. static void
  254. js_dom_event_listener(struct dom_event *event, void *pw)
  255. {
  256.         struct js_dom_event_private *private = pw;
  257.         jsval event_argv[1];
  258.         jsval event_rval;
  259.         JSObject *jsevent;
  260.  
  261.         JSLOG("WOOT dom event with %p", private);
  262.  
  263.         if (!JSVAL_IS_VOID(private->funcval)) {
  264.                 jsevent = jsapi_new_Event(private->cx, NULL, NULL, event);
  265.                 if (jsevent != NULL) {
  266.  
  267.                 /* dispatch event at the window object */
  268.                 event_argv[0] = OBJECT_TO_JSVAL(jsevent);
  269.  
  270.                 JS_CallFunctionValue(private->cx,
  271.                                      NULL,
  272.                                      private->funcval,
  273.                                      1,
  274.                                      event_argv,
  275.                                      &event_rval);
  276.                 }
  277.         }
  278. }
  279.  
  280. /* add a listener to a dom node
  281.  *
  282.  * 1. Create a dom_event_listener From a handle_event function pointer
  283.  *    and a private word In a document context
  284.  *
  285.  * 2. Register for your events on a target (dom nodes are targets)
  286.  *    dom_event_target_add_event_listener(node, evt_name, listener,
  287.  *    capture_or_not)
  288.  *
  289.  */
  290.  
  291. bool
  292. js_dom_event_add_listener(jscontext *ctx,
  293.                           struct dom_document *document,
  294.                           struct dom_node *node,
  295.                           struct dom_string *event_type_dom,
  296.                           void *js_funcval)
  297. {
  298.         JSContext *cx = (JSContext *)ctx;
  299.         dom_exception exc;
  300.         struct js_dom_event_private *private;
  301.  
  302.         private = malloc(sizeof(struct js_dom_event_private));
  303.         if (private == NULL) {
  304.                 return false;
  305.         }
  306.  
  307.         exc = dom_event_listener_create(document,
  308.                                         js_dom_event_listener,
  309.                                         private,
  310.                                         &private->listener);
  311.         if (exc != DOM_NO_ERR) {
  312.                 return false;
  313.         }
  314.  
  315.         private->cx = cx;
  316.         private->funcval = *(jsval *)js_funcval;
  317.         private->node = node;
  318.         private->type = event_type_dom;
  319.  
  320.         JSLOG("adding %p to listener", private);
  321.  
  322.         JSAPI_ADD_VALUE_ROOT(cx, &private->funcval);
  323.         exc = dom_event_target_add_event_listener(private->node,
  324.                                                   private->type,
  325.                                                   private->listener,
  326.                                                   true);
  327.         if (exc != DOM_NO_ERR) {
  328.                 JSLOG("failed to add listener");
  329.                 JSAPI_REMOVE_VALUE_ROOT(cx, &private->funcval);
  330.         }
  331.  
  332.         return true;
  333. }
  334.