diff options
Diffstat (limited to 'khtml/DESIGN.html')
-rw-r--r-- | khtml/DESIGN.html | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/khtml/DESIGN.html b/khtml/DESIGN.html new file mode 100644 index 000000000..a02e85a1b --- /dev/null +++ b/khtml/DESIGN.html @@ -0,0 +1,346 @@ +<html> +<head> +<title>Internal design of khtml</title> +<style> +dt { font-weight: bold; } +</style> +<body bgcolor=white> +<h1>Internal design of khtml</h1> + +<p> +This document tries to give a short overview about the internal design of the khtml +library. I've written this, because the lib has gotten quite big, and it is hard at first to find your +way in the source code. This doesn't mean that you'll understand khtml after reading this +document, but it'll hopefully make it easier for you to read the source code. +</p> +<p> +The library is build up out of several different parts. Basically, when you use the lib, you +create an instance of a KHTMLPart, and feed data to it. That's more or less all you need to +know if you want to use khtml for another application. If you want to start hacking khtml, +here's a sketch of the objects that will get constructed, when eg. running testkhtml with +a url argument. +</p> +<p> +In the following I'll assume that you're familiar with all the buzzwords used in current web +techology. In case you aren't here's a more or less complete list of references: +</p> +<blockquote> +<p> +<b>Document Object model (DOM):</b><br> +<a href="http://www.w3.org/DOM/">DOM Level1 and 2</a><br> +We support DOM Level2 except for the events model at the moment. +</p> +<p> +<b>HTML:</b><br> +<a href="http://www.w3.org/TR/html4/">HTML4 specs</a><br> +<a href="http://www.w3.org/TR/xhtml1/">xhtml specs</a><br> +We support almost all of HTML4 and xhtml. +</p> +<p> +<b>Cascading style sheets (CSS):</b><br> +<a href="http://www.w3.org/TR/REC-CSS2/">CSS2 specs</a><br> +We support almost all of CSS1, and most parts of CSS2. +</p> +<p> +<b>Javascript:</b><br> +<a href="http://msdn.microsoft.com/workshop/author/dhtml/reference/objects.asp">Microsoft javascript bindings</a><br> +<a href="http://docs.sun.com/source/816-6408-10/index.html">Netscape javascript reference</a><br> +Netscapes javascript bindings are outdated. We shouldn't follow them. Let's focus on getting the bindings +compatible to IE. +<a href="http://mozilla.org/docs/dom/domref/">Mozilla JS/DOM reference</a> +</p> +</blockquote> + +<p> +<a href="khtml_part.h">KHTMLPart</a> creates one instance of a +<a href="khtmlview.h">KHTMLView</a> (derived from QScrollView), +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 <a href="http://developer.kde.org/documentation/library/kdeqt/kde3arch/khtml/index.html">introduction to khtml</a> on <a href="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 +<a href="html/html_headimpl.h">HTMLStyleElementImpl object</a>. This object creates an +<a href="css/cssstylesheetimpl.h">CSSStyleSheetImpl object</a> and passes the +data to it. The <a href="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 <a href="misc/loader_client.h">CachedObjectClient</a>, and can ask +the <a href="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 <a href="misc/loader.h">loader</a> has the requested object ready, it will notify the +<a href="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 <a href="css/cssstyleselector.h">CSSStyleSelector</a> class. +It takes the <a href="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 +or XML documents can be found in the CSS2 specs. +<p> +Once we have this list, we can get a <a +href="rendering/render_style.h">RenderStyle object</a> +for every DOM element from the <a +href="css/cssstyleselector.h">CSSStyleSelector</a> by calling +"styleForElement(DOM::ElementImpl *)". +The style object describes in a compact form all the +<a href="css/css_properties.in">CSS properties</a> +that should get applied to the Node. +<p> +After that, a rendering tree gets built up. Using the style object, the +<a href="xml/dom_nodeimpl.h">DOM Node</a> creates an appropriate render object +(all these are defined in the rendering subdirectory) and adds it to the +rendering tree. This will give another tree like structure, that resembles in +it's general structure the DOM tree, but might have some significant +differences too. First of all, so called + <a href="http://www.w3.org/TR/REC-CSS2/visuren.html#anonymous-block-level">anonymous boxes</a> - (see + <a href="http://www.w3.org/TR/REC-CSS2/">CSS specs</a>) that +have no DOM counterpart might get inserted into the rendering tree to satisfy +DOM requirements. Second, the display property of the style affects which type +of rendering object is chosen to represent the current DOM object. + +<p> +In the above example we would get the following rendering tree: +<pre> +RenderRoot* + \--> RenderBody* + |--> RenderFlow* (<H1>) + | \--> RenderText* ("some red text") + |--> RenderFlow* (anonymous box) + | \--> RenderText* ("more text") + \--> RenderFlow* (<P>) + |--> RenderText* ("a paragraph with an") + |--> RenderImage* + \--> RenderText* ("embedded image.") +</pre> + +<p> +A call to of <a href="rendering/render_root.cpp">layout()</a> on the +<a href="rendering/render_root.h">RenderRoot </a> (the root of the rendering tree) +object causes the rendering tree to layout itself into the available space +(width) given by the the KHTMLView. After that, the drawContents() method of +KHTMLView can call RenderRoot->print() with appropriate parameters to actually +paint the document. This is not 100% correct, when parsing incrementally, but +is exactly what happens when you resize the document. + + +As you can see, the conversion to the rendering tree removed the head part of +the HTML code, and inserted an anonymous render object around the string "more +text". For an explanation why this is done, see the CSS specs. +<p> + +<h2>Directory structure</h2> + +A short explanation of the subdirectories in khtml. +<dl> +<dt><a href="css/">css:</a> +<dd>Contains all the stuff relevant to the CSS part of DOM Level2 (implementation classes only), +the <a href="css/cssparser.h">CSS parser</a>, and the stuff to create +RenderStyle object out of Nodes and the CSS style sheets. +<dt><a href="dom/">dom: </a> +<dd>Contains the external DOM API (the DOM interface classes) for all of the DOM +<dt><a href="ecma/">ecma:</a> +<dd>The javascript bindings to the DOM and khtml. +<dt><a href="html/">html:</a> +<dd>The html subpart of the DOM (implementation only), the HTML tokenizer and parser and a class +that defines the DTD to use for HTML (used mainly in the parser). +<dt><a href="java/">java:</a> +<dd>Java related stuff. +<dt><a href="misc/">misc:</a> +<dd>Some misc stuff needed in khtml. Contains the image loader, some misc definitions and the +decoder class that converts the incoming stream to unicode. +<dt><a href="rendering">rendering:</a> +<dd>Everything thats related to bringing a DOM tree with CSS declarations to the screen. Contains +the definition of the objects used in the rendering tree, the layouting code, and the RenderStyle objects. +<dt><a href="xml/">xml:</a> +<dd>The XML part of the DOM implementation, the xml tokenizer. +</dl> + +<h2>Exception handling</h2> +To save on library size, C++-exceptions are only enabled in the dom/ subdirectory, +since exceptions are mandated by the DOM API. In the rest of KHTML's code, +we pass an error flag (usually called "exceptionCode"), and the class that +is part of dom/* checks for this flag and throws the exception. + +<h2>Final words...</h2> +<p> +All the above is to give you a quick introduction into the way khtml brings an HTML/XML file to the screen. +It is by no way complete or even 100% correct. I left out many problems, I will perhaps add either on request +or when I find some time to do so. Let me name some of the missing things: +<ul> +<li>The decoder to convert the incoming stream to Unicode +<li>interaction with konqueror/applications +<li>javascript +<li>dynamic reflow and how to use the DOM to manipulate khtmls visual output +<li>mouse/event handling +<li>real interactions when parsing incrementally +<li>java +</ul> + +Still I hope that this short introduction will make it easier for you to get a first hold of khtml and the way it works. +<p> +Now before I finish let me add a small <b>warning</b> and <b>advice</b> to all of you who plan hacking khtml themselves: +<p> +khtml is by now a quite big library and it takes some time to understand how it works. Don't let yourself get frustrated +if you don't immediately understand how it works. On the other hand, it is by now one of the libraries that +get used a lot, that probably has the biggest number of remaining bugs (even though it's sometimes hard to +know if some behavior is really a bug). +<blockquote> +Some parts of it's code are however <b>extremely touchy</b> (especially the layouting algorithms), +and making changes there (that might fix a bug on one web page) might introduce severe bugs. +All the people developing khtml have already spend huge amounts of time searching for such bugs, +that only showed up on some web pages, and thus were found only a week after the change that +introduced the bug was made. This can be very frustrating for us, and we'd appreciate if people +that are not completely familiar with khtml post changes touching these critical regions to kfm-devel +for review before applying them. +</blockquote> + +<div style="margin-top: 2em; font-size: large;"> +And now have fun hacking khtml. +<div style="margin-left: 10em; margin-bottom: 1em;">Lars</div> +</div> +</body> +</html> |