summaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorVincent Sanders <vince@kyllikki.org>2019-05-04 22:46:29 +0100
committerVincent Sanders <vince@kyllikki.org>2019-05-04 22:48:50 +0100
commite8cd7c661499c8bfca26026e6291f1ed81c29194 (patch)
treeb4019628e9f1312b55a44fc76e42ed887d36f69d /docs
parent5dca74b911df9dae01c7f0b77b6bdce6ece94bcf (diff)
downloadnetsurf-e8cd7c661499c8bfca26026e6291f1ed81c29194.tar.gz
netsurf-e8cd7c661499c8bfca26026e6291f1ed81c29194.tar.bz2
add some more javascript binding documentation
Diffstat (limited to 'docs')
-rw-r--r--docs/jsbinding.md174
1 files changed, 133 insertions, 41 deletions
diff --git a/docs/jsbinding.md b/docs/jsbinding.md
index 59d569114..42d61a676 100644
--- a/docs/jsbinding.md
+++ b/docs/jsbinding.md
@@ -1,17 +1,17 @@
-Javascript bindings
+JavaScript bindings
===================
-In order for javascript programs to to interact with the page contents
+In order for JavaScript programs to to interact with the page contents
it must use the Document Object Model (DOM) and Cascading Style Sheet
Object Model (CSSOM) API.
-These interfaces are described using web Interface Description
-Language (IDL) within the relevant specifications
+These interfaces are described using Web Interface Description
+Language (WebIDL) within the relevant specifications
(e.g. https://dom.spec.whatwg.org/).
-Each interface described by the webIDL must be bound (connected) to
+Each interface described by the WebIDL must be bound (connected) to
the browsers internal representation for the DOM or CSS, etc. These
-bindings desciptions are processed together with the WebIDL by the
+bindings descriptions are processed together with the WebIDL by the
nsgenbind tool to generate source code.
A list of [DOM and CSSOM methods](unimplemented.html) is available
@@ -23,17 +23,17 @@ WebIDL
The [WebIDL specification](http://www.w3.org/TR/WebIDL/) defines the
interface description language used. The WebIDL is being updated and
an [editors draft](https://heycam.github.io/webidl/) is available but
-use is inconsistant.
+use is inconsistent.
-These descriptions should be periodicaly updated to keep the browser
+These descriptions should be periodically updated to keep the browser
interfaces current.
There is a content/handlers/javascript/WebIDL/Makefile which attempts
-to automaticaly update the IDL files by scraping the web specs.
+to automatically update the IDL files by scraping the web specs.
This tool needs a great deal of hand holding, not least because many of the
source documents list the IDL fragments multiple times, some even have
-appendicies with the entrire IDL repeated.
+appendices with the entire IDL repeated.
The IDL uses some slightly different terms than other object orientated
systems.
@@ -45,58 +45,150 @@ The IDL uses some slightly different terms than other object orientated
operation | method | method | functions that can be called
attribute | property | property | Variables set per instance
+JavaScript implementation
+-------------------------
+
+NetSurf consumes the Duktape JS engine in order to run the JS code which
+is used within the browser. Duktape is exceedingly well documented and
+its API docs at https://duktape.org/api.html are incredibly useful.
+
+It'll be worthwhile learning about how duktape stacks work in order to
+work on bindings in NetSurf
+
+Dukky
+-----
+
+Wrappering around and layering between duktape and the browser is a
+set of functionality we call `dukky`. This defines a variety of
+conventions and capabilities which are common to almost all bindings.
+The header `dukky.h` provides the interface to these functions.
+
+Normally these functions are used by automatically generated content,
+but if a binding needs to add DOM nodes back into the JavaScript
+environment (for example when returning them from a method
+implementation) `dukky_push_node()` should be used or when calling a
+function in a JS context `dukky_pcall()`
+Dukky automatically terminates any JS call which lasts for more than
+10 seconds. If you are calling a JS function from outside any of the
+"normal" means by which dukky might call code on your behalf
+(`js_exec()`, events, etc) then you should be sure to use
+`dukky_pcall()` and pass in `true` in `reset_timeout` otherwise your
+code may unexpectedly terminate early.
Interface binding introduction
------------------------------
The binding files are processed by the nsgenbind tool to generate c
-source code which implements the interfaces within the javascript
+source code which implements the interfaces within the JavaScript
engine.
-The bindings are specific to a javascript engine, the DOM library, the
+The bindings are specific to a JavaScript engine, the DOM library, the
CSS library and the browser. In this case that is the tuple of
duktape, libdom, libcss and NetSurf.
In principle other engines or libraries could be substituted
-(historicaly NetSurf unsucessfully tried to use spidermonkey) but the
+(historically NetSurf unsuccessfully tried to use spidermonkey) but the
engineering to do so is formidable.
-The bindings are kept the sorce rpository within the duktape
-javascript handler content/handlers/javascript/duktape/
+The bindings are kept the main [NetSurf source code
+repository](http://git.netsurf-browser.org/netsurf.git/) within the
+duktape JavaScript handler directory `content/handlers/javascript/duktape/`
-The root binding which contains all the interfaces initroduced into
-the javascript programs initial execution context is nesurf.bnd this
+The root binding which contains all the interfaces introduced into
+the JavaScript programs initial execution context is nesurf.bnd this
references all the WebIDL to be bound and includes all additional
binding definitions to implement the interfaces.
The bindings are a Domain Specific Language (DSL) which allows
-implementations to be added to each WebIDL method.
+implementations to be added to each WebIDL method. nsgenbind
+documentation contains a [full description of the
+language](https://ci.netsurf-browser.org/jenkins/view/Categorized/job/docs-nsgenbind/doxygen/index.html).
-Javascript implementation
--------------------------
+The main focus on creating binding is to implement the content within
+getter, setter and method stanzas. These correspond to implementations
+of the WebIDL operations on an interface.
-NetSurf consumes the Duktape JS engine in order to run the JS code which
-is used within the browser. Duktape is exceedingly well documented and
-its API docs at https://duktape.org/api.html are incredibly useful.
+The binding implementations are in the form of C code fragments
+directly pasted into the generated code with generated setup code
+surrounding it.
-It'll be worthwhile learning about how duktape stacks work in order to
-work on bindings in NetSurf
+### Simple getter and setter example
-Dukky
------
+The Window interface (class) in the HTML specification has an
+attribute called `name`.
+
+The full WebIDL for the Window interface is defined in the
+`content/handlers/javascript/WebIDL/html.idl` file but the
+fragment for our example is just:
+
+ interface Window : EventTarget {
+ attribute DOMString name;
+ };
+
+This indicates there is an attribute called `name` which is a string
+(technicaly a DOMString but the implementation does not differentiate
+between string types) which means it has both a setter and a getter.
+
+attributes can be marked readonly which would mean there is only a
+getter required for them. For example the Plugin interface has a
+'name' attribute defined as:
+
+ interface Plugin {
+ readonly attribute DOMString name;
+ };
+
+The getter and setter for the Window class attribute will be added to
+`Window.bnd`. The entries added will be of the form:
+
+ getter Window::name()
+ %{
+ %}
+
+ setter Window::name()
+ %{
+ %}
+
+The top level `netsurf.bnd` binding includes `Window.bnd` (using a
+`#include` directive) which contains the implementation of the Window
+class. This is purely to split the bindings up into logical units.
+
+The nsgenbind tool generates code that automatically allows acess to
+the classes private data structure elements through a variable called
+`priv` and the duktape stack in the variable `ctx`.
+
+The getter binding code must place the retrived value on the duktape
+stack and return 1 to indicate this or 0 if it failed.
+
+So for the name attribute case the complete getter binding is:
+
+ getter Window::name()
+ %{
+ const char *name;
+ browser_window_get_name(priv->win, &name);
+ duk_push_string(ctx, name);
+ return 1;
+ %}
+
+This uses the browser_window_get_name() interface to retrieve the name
+string for the window (identified using the private context) and then
+adds it to the duktape stack. The return value indicates the sucess of
+the operation.
+
+The setter must retrive the value to set from the duktap stack and
+update the internal private data structure with that value and return
+0 to indicate success.
+
+So for the name attribute case the complete setter binding is:
+
+ setter Window::name()
+ %{
+ const char *name;
+ name = duk_to_string(ctx, -1);
+ browser_window_set_name(priv->win, name);
+ return 0;
+ %}
+
+
+### Simple method example
-Wrappering around and layering between duktape and the browser is a set of
-functionality we call `dukky`. This defines a variety of conventions and
-capabilities which are common to almost all bindings. The header `dukky.h`
-provides the interface to these functions. Normally these functions are
-subsequently used by automatically generated content, but if your bindings
-need to add DOM nodes back into the JavaScript environment (for example when
-returning them from a method implementation) you will want `dukky_push_node()`
-or when calling a function in a JS context you'll likely want `dukky_pcall()`
-
-Dukky automatically terminates any JS call which lasts for more than 10
-seconds. If you are calling a JS function from outside any of the "normal"
-means by which dukky might call code on your behalf (`js_exec()`, events, etc)
-then you should be sure to use `dukky_pcall()` and pass in `true` in
-`reset_timeout` otherwise your code may unexpectedly terminate early.