|
|
The NGLayout Document Object Model (DOM) Roadmap
Authors:
Vidur
Apparao, Tom Pixley
Introduction
The Document Object Model (DOM) is a set of interfaces implemented by the
NGLayout content model that allow insertion, deletion and modification of
HTML content. These interfaces are available to both JavaScript developers
and C/C++ programmers (via xpcom).
The majority of these interfaces are specified by the Level
1 W3C Document Object Model specification, while the remaining are
extensions that provide backward compatibility with previous versions of
Communicator.
The NGLayout engine will implement a union of the Communicator
4.0 and and W3C Level 1
Document Object Models. NGLayout's ability to incrementally relayout and
redisplay content allow it to correctly handle arbitrary content modification,
including element insertion/deletion, attribute value modifications and
style changes. The following document describes the current state of implementation
as well as an implementation strategy for a complete DOM.
The Current Implementation
The Core Interfaces
The implementation of the DOM released with the current version of the
NGLayout source base contains most of the Level
1 Core interfaces. These interfaces are implemented directly by the
base NGLayout classes (found in ns/layout). Specifically, the DOM
Document
interface is implemented by the NGLayout nsDocument class, the DOM
Node
interface is implemented by the NGLayout nsHTMLContent class and
the DOM Element
interfaces is implemented by the NGLayout nsHTMLTagContent class.
The Level 1 interfaces have been translated into their xpcom equivalents
(found in ns/dom/public/coreDom) using the following rules:
-
All interfaces inherit from nsISupports.
-
Interface names have been translated to include the nsIDOM prefix.
-
All method signatures have been changed to return a nsresult result
code.
-
wstring parameters and return values have been replaced with nsString.
-
Return values from the original interfaces now become pointers or references.
-
All method names have been changed so that their first character is capitalized.
These interfaces represent the model that C++ developers can use to manipulate
a NGLayout document. Currently, the nsIWebWidget API is not complete
and does not include a mechanism for obtaining the root DOM object for
the document. The specifics of this interface are key to the usage of the
DOM by an application that embeds the NGLayout engine, and will be completed
in the very near future.
JavaScript Classes
These interfaces are also the basis for implementing the classes that make
the DOM visible to JavaScript developers (found in ns/dom/src).
In general, these JavaScript classes are simple wrappers on top of the
corresponding xpcom interfaces. The nsHTMLContent and nsDocument
classes both implement the nsIScriptObjectOwner interface. This
interface provides a method that can be queried for the JavaScript object
representing the document or content object. These JavaScript objects are
created on demand and stored by the document or content object. The JavaScript
object also holds a reference to the corresponding xpcom interface in its
private data.
The rules for generating the JavaScript classes described above are
as follows:
-
A JSClass is created to represent the DOM interface. Instances
of this JSClass are created on demand for each corresponding DOM
object accessed from JavaScript. Currently, the class is initialized (and
the corresponding prototype is created) at JavaScript console creation
time. In the future, these classes will be initialized on demand. The name
of the class is identical to the DOM interface name.
-
Each attribute represented in the W3C DOM IDL is converted into a JavaScript
property, retrieved and set by the property getter and setter methods of
the corresponding JSClass. The JavaScript getter and setter methods
use the reference to the DOM interface stored in the JSObject's
private data, invoke the corresponding getter or setter method in the DOM
interface, and (for getters) convert the returned value to the correct
JavaScript type. For interface return types, a QueryInterface
is carried out to get a nsIScriptObjectOwner and the owned JavaScript
object.
-
Each method represented in the W3C DOM IDL is converted into a JavaScript
method. The JavaScript method use the reference to the DOM interface stored
in the JSObject's private data, invoke the corresponding method
in the DOM interface, and convert the returned value to correct JavaScript
type.
-
Constants in the W3C DOM IDL are converted into static properties of the
JSClass (i.e. properties of the class's constructor).
-
In cases where the W3C DOM IDL does not capture methods or behavior which
are particular to the JavaScript bindings of the DOM, the content objects
will implement the nsIScriptObject interface. This interface allows
the implementing class to handle JavaScript calls directly. For example,
the W3C NodeIterator interface implements the [] operator
in JavaScript. This operator allows the user to address nodes by ordinal
index. This behavior will be provided by implementing the GetProperty
method of the nsIScriptObject interface and resolving values for
property ids that represent ordinal indexes. None of the existing classes
currently implement this interface.
-
For methods and properties that need to exist for backward compatibility,
but are not specified in the Level 1 DOM interfaces, the corresponding
content objects will implement an additional interface. For example, the
IMG elements lowSrc property is reflected into JavaScript in Communicator
4.0, but is not part of the W3C HTML DOM ImageElement interface.
The nsHTMLImage content class will probably implement an additional
interface to allow manipulation of this property and others of its type.
JavaScript Evaluation
Currently, NGLayout does not support the SCRIPT tag. Scripts can be executed,
however, using the JavaScript console. Note that the console is simply
a preliminary, debugging tool that exists in lieu of SCRIPT tag parsing.
This tool will be removed in a final product. The console can be brought
up by selecting the JavaScript Console menu item in the Tools menu of the
NGLayout viewer. Scripts can be loaded into the console and then executed
by choosing the Evaluate All menu item.
While the method of script evaluation will change when NGLayout starts
handling the SCRIPT tag, the underlying mechanism should remain relatively
similar. Currently, script execution through the JavaScript console is
driven by the Viewer application as follows:
-
The first step in evaluation involves obtaining the script context - an
instance of the nsIScriptContext interface obtained from the web
widget by calling its GetScriptContext method. The JavaScript
runtime is initialized and a JSContext for script evaluation is
created when this script context is first instantiated. There is a one-to-one
correspondence between the JSContext and a global object. The
global object is used as the default scoping object for all scripts. In
previous versions of Communicator, the global object is the JavaScript
window object. In the current NGLayout implementation of the DOM,
the global object (implemented in ns/dom/src/nsJSWindow.cpp) is
a JSObject that holds a reference to the nsIWebWidget
interface. (A complete implementation of the Window interface is forthcoming.)
An instance of the global object is created as side-effect of creating
the script context. All JavaScript classes are intialized at this time.
-
The second step involves actually executing a script. This is performed
by invoking the EvaluateString method of the nsIScriptContext,
a thin wrapper on the JS_EvaluateString method from the JavaScript
runtime. The global object defines the scope for the evaluation of the
script. Currently, the global object has a single property that represents
the Document object. Hence, unqualified references to "document" within
the script will resolve to the JavaScript object representing the NGLayout
document.
Implementation Strategy
What's Left
The implementation of the DOM in the released NGLayout source is very preliminary,
but should serve as the model for future work. The following items represent
the major categories of functionality necessary for completion of the DOM:
-
As mentioned above, only the Level 1 Core DOM interfaces have been included
and only a portion of the functionality enabled by these interfaces currently
works. We intend to complete the implementation of the core interfaces,
as well as those detailed in the Level
1 HTML specification. The individual HTML element interfaces will be
implemented by the corresponding content model classes created by NGLayout.
-
Backward compatibility with existing versions of the JavaScript DOM within
Communicator is an important goal of the NGLayout project. Additional interfaces
that incorporate functionality not provided in the W3C DOM will be implemented.
-
The DOM event model will be completed in a form that is usable by both
C++ and JavaScript programmers. This will enable applications that embed
the NGLayout engine to receive events that are targetted at the document
elements. It will also allow scripts to specify event handlers for elements
as in Communicator 4.0. The aim is to provide compatibility with the Communicator
4.0 event model as well as the W3C DOM event model standard (which
is as yet unspecified). Ideally, these two models will not be mutually
exclusive.
-
The W3C DOM standard will eventually include a mechanism for modifying
the CSS style of a document. This will include ways of adding and removing
style rules, modifying existing rules and changing the inline STYLE attribute
of individual elements. The DOM style specification will be implemented
by the NGLayout style system.
-
Some of the functionality required to implement the Window and Navigator
classes from the existing Level 0 DOM involves interaction with the application
containing NGLayout. For example, the creation of new windows and modification
of toolbars fall outside the domain of the core NGLayout engine. Interfaces
that represent the functionality necessary to create these classes will
be specified and implemented by Communicator.
-
The JavaScript
security model from Communicator 4.0 will be implemented, though the
model itself may be modified to incorporate ongoing changes to the Java
Capabilities API and the overall Java security model.
Auto-generation of JavaScript class files
The source files that represent the JavaScript classes corresponding to
the individual DOM interfaces can be found in the directory ns/dom/src.
These source files define the JavaScript classes by using a set of simple
rules applied to the Corba
IDL representing the DOM interfaces. Currently, these rules were applied
by hand. We are currently in the process of modifying an IDL compiler to
auto-generate these class files, as well as the xpcom versions of the interfaces.
The tool and the process for generating the source files will be posted
in a future release.
JavaScript Class Initialization
As stated previously, all JavaScript DOM classes are currently initialized
directly after the JSContext is created. In its final form, the
HTML DOM will contain a large number of interfaces (almost as many as the
number of elements specified in the HTML
4.0 DTD)
and the overhead for intialization of all of these classes on a per document
basis is substantial. The current method of class initialization will be
replaced by an on-demand registration scheme such that classes will be
intialized only when an instance is first required or when a constructor
is needed.
Known Bugs
-
While the Level 1 Core DOM interfaces have been implemented by the document
and content classes, not all methods have been correctly hooked up. Currently,
methods that allow the DOM user to query Document, Node and Element state
work, while methods that modify state do not.
-
In many cases, attributes are only reflected in JavaScript through the
corresponding getter and setter methods. This will be corrected in a future
release in conjunction with the W3C DOM IDL e.g. the Node interfaces
childNodes attribute will be implemented as node.childNodes
in JavaScript and not node.getChildNodes.
-
Currently, IDL methods are incorrectly reflected into JavaScript with their
first character capitalized. This will be corrected in a future release
e.g. the Node interfaces RemoveChild method will be reflected
as node.removeChild and not node.RemoveChild.
-
The nsJSEnvironment class is very much a preliminary implementation.
It both initialized the JavaScript runtime and creates a new JSContext.
This precludes the creation of multiple context per JavaScript runtime.
This class will be fleshed out in greater detail.
|