the widget showing the whole thing. At the same time a DOM tree
is built up from the HTML or XML found in the specified file.
<p>
Let me describe this with an example.
<p>
khtml makes use of the document object model (DOM) for storing the document
in a tree like structure. Imagine some html like
<pre>
<html>
<head>
<style>
h1: { color: red; }
</style>
</head>
<body>
<H1>
some red text
</h1>
more text
<p>
a paragraph with an
<img src="foo.png">
embedded image.
</p>
</body>
</html>
</pre>
In the following I'll show how this input will be processed step by step to generate the visible output
you will finally see on your screen. I'm describing the things as if they happen one after the other,
to make the principle more clear. In reality, to get visible output on the screen as soon as possible,
all these things (from tokenization to the build up and layouting of the rendering tree) happen
more or less in parallel.
<h2>Tokenizer and parser</h2>
<p>
The first thing that happens when you start parsing a new document is that a
DocumentImpl* (for XML documents) or an HTMLDocumentImpl* object will get
created by the Part (in khtml_part.cpp::begin()). A Tokenizer*
object is created as soon as DocumentImpl::open() is called by the part, also
in begin() (can be either an XMLTokenizer or an HTMLTokenizer).
<p>
The XMLTokenizer uses the QXML classes in Qt to parse the document, and it's SAX interface
to parse the stuff into khtmls DOM.
<p>
For HTML, the tokenizer is located in khtmltokenizer.cpp. The tokenizer uses the contents
of a HTML-file as input and breaks this contents up in a linked list of
tokens. The tokenizer recognizes HTML-entities and HTML-tags. Text between
begin- and end-tags is handled distinctly for several tags. The distinctions
are in the way how spaces, linefeeds, HTML-entities and other tags are
handled.
<p>
The tokenizer is completely state-driven on a character by character basis.
All text passed over to the tokenizer is directly tokenized. A complete
HTML-file can be passed to the tokenizer as a whole, character by character
(not very efficient) or in blocks of any (variable) size.
<p>
The HTMLTokenizer creates an HTMLParser which
interprets the stream of tokens provided by the tokenizer
and constructs the tree of Nodes representing the document according
to the Document Object Model.
<p>
<h2>The DOM in khtml</h2>
<p>
Parsing the document given above gives the following DOM tree:
<pre>
HTMLDocumentElement
|--> HTMLHeadElement
| \--> HTMLStyleElement
| \--> CSSStyleSheet
\--> HTMLBodyElement
|--> HTMLHeadingElement
| \--> Text
|--> Text
\--> HTMLParagraphElement
|--> Text
|--> HTMLImageElement
\--> Text
</pre>
<p>
Actually, the classes mentioned above are the interfaces for accessing the
DOM. The actual data is stored in *Impl classes, providing the implementation
for all of the above mentioned elements. So internally we have a tree
looking like:
<pre>
HTMLDocumentElementImpl*
|--> HTMLHeadElementImpl*
| \--> HTMLStyleElementImpl*
| \--> CSSStyleSheetImpl*
\--> HTMLBodyElementImpl*
|--> HTMLHeadingElementImpl*
| \--> TextImpl*
|--> TextImpl*
\--> HTMLParagraphElementImpl*
|--> TextImpl*
|--> HTMLImageElementImpl*
\--> TextImpl*
</pre>
<p>
We use a refcounting scheme to assure that all the objects get deleted, in
case the root element gets deleted (as long as there's no interface class
holding a pointer to the Implementation).
<p>
The interface classes (the ones without the Impl) are defined in the <code>dom/</code>
subdirectory, and are not used by khtml itself at all. The only place they are used are in the
javascript bindings, which uses them to access the DOM tree. The big advantage of having this
separation between interface classes and imlementation classes, is that we can have several
interface objects pointing to the same implementation. This implements the requirement of
explicit sharing of the DOM specs.
<p>
Another advantage is, that (as the implementation classes are not exported) it gives us a lot
more freedom to make changes in the implementation without breaking binary compatibility.
<p>
You will find almost a one to one correspondence between the interface classes and the implementation
classes. In the implementation classes we have added a few more intermediate classes, that can
not be seen from the outside for various reasons (make implementation of shared features easier
or to reduce memory consumption).
<p>
In C++, you can access the whole DOM tree from outside KHTML by using the interface classes.
For a description see the <ahref="http://developer.kde.org/documentation/library/kdeqt/kde3arch/khtml/index.html">introduction to khtml</a> on <ahref="http://developer.kde.org/">developer.kde.org</a>.
One thing that has been omitted in the discussion above is the style sheet defined inside the
<code><style></code> element (as an example of a style sheet) and the image element
(as an example of an external resource that needs to be loaded). This will be done in the following
two sections.
<h2>CSS</h2> The contents of the <code><style></code> element (in this
case the <code>h1 { color: red; }</code> rule) will get passed to the
<ahref="html/html_headimpl.h">HTMLStyleElementImpl object</a>. This object creates an
<ahref="css/cssstylesheetimpl.h">CSSStyleSheetImpl object</a> and passes the
data to it. The <ahref="css/cssparser.h">CSS parser</a> will take
the data, and parse it into a DOM structure for CSS (similar to the one for
HTML, see also the DOM level 2 specs). This will be later on used to define the
look of the HTML elements in the DOM tree.
<p>
Actually "later on" is relative, as we will see later, that this happens partly in parallel to
the build up of the DOM tree.
<h2>Loading external objects</h2>
<p>
Some HTML elements (as <code><img>, <link>, <object>, etc.</code>) contain
references to external objects, that have to be loaded. This is done by the
Loader and related classes (misc/loader.*). Objects that might need to load external objects
inherit from <ahref="misc/loader_client.h">CachedObjectClient</a>, and can ask
the <ahref="misc/loader.h">loader</a> (that also acts as a memory cache) to
download the object they need for them from the web.
<p>
Once the <ahref="misc/loader.h">loader</a> has the requested object ready, it will notify the
<ahref="misc/loader_client.h">CachedObjectClient</a> of this, and the client can
then process the received data.
<h2>Making it visible</h2>
Now once we have the DOM tree, and the associated style sheets and external objects, how
do we get the stuff actually displayed on the screen?
<p>
For this we have a rendering engine, that is completely based on CSS. The first
thing that is done is to collect all style sheets that apply to the document
and create a nice list of style rules that need to be applied to the
elements. This is done in the <ahref="css/cssstyleselector.h">CSSStyleSelector</a> class.
It takes the <ahref="css/html4.css">default HTML style sheet</a> (defined in css/html4.css),
an optional user defined style sheet, and all style sheets from the document,
and combines them to a nice list of parsed style rules (optimised for fast
lookup). The exact rules of how these style sheets should get applied to HTML