Hi!
Below are some notes on how CSS may be implemented in dillo. It mainly
focusses on how the different parts "play together", many details for
the single modules are left out, there should be enough room for
different implementations. There are also some simplifications,
e.g. the user-agent defined style sheet may be implemented in a
different way. I've left out XML/CSS parsing, which should be possible
by this design, but makes many changes of the HTML parser necessary.
Please post comments, bugs, anticipated problems, ambiguities etc.
Sebastian
======================================================================
-------------------------------------------
A Possible Implementation of CSS in Dillo
-------------------------------------------
The User's View
===============
An important goal is asynchronous HTML/CSS parsing: when the HTML
parser reads a tag referring to an external style sheet, it
continues to render the document _without_ the style sheet, while the
style sheet (if it is not already in the cache) is retrieved and
parsed parallel to this, and then applied on the current rendered part
of the document. If the time difference is large enough, the user will
notice a sudden change of colors, fonts, etc., but will be able to
read the content with less delay time (which may be several seconds).
Overview
========
The following diagram shows the associations between the data
structures, and there multiplicities. Worth to notice is that for
every document (represented currently by DilloHtmlLB), there is one
document tree (Document) and one CSS cascade. The details are
described below.
+-----------+
| DilloHTML |
+-----------+
0..1 | | 1
,-------' `------.
| |
1 V V *
+-------------+ +----------------+ 0..1 +---------+
| DilloHtmlLB | | DilloHtmlState |------>| Element |
+-------------+ +----------------+ 1 +---------+
1 | | 1 |
| | |
| | 1 +----------+
| `------------------------------->| Document |
| +----------+
| ^ 1
| +-------------+ |
`----------------->| CSS cascade |------'
1 +-------------+ 1
The Role of DwStyle
===================
The DwStyle structure will represent style attributes in one of the
following ways (for the exact terminology, see [CSS2] chapter 6.1):
1. Absolute values are represented directly. Examples are absolute
lengths. The value "auto" is handled the same way.
2. Some relative values are immediately computed, this may depend
on attributes of the parent element. Examples are relative line
heights, i.e. "line-height: 150%" will be computed into an
absolute (pixel) value.
3. Other relative sizes are represented this way in DwStyle,
examples are relative widths and heights.
Whether 2 or 3 applies to a specific attribute is determined by two
factors:
1. If the attribute value is independent of certain values, which
changes affect only the level of Dw (important: window size),
they can, for simplicity, put into category 2. Otherwise, they
must belong to 3. The latter may not be inherited, for the
reason, see next point.
2. Since only *computed* values may be inherited, attributes,
which values are inherited, may not be part of category 2,
since Dw will not be able to handle them correctly.
The Document Tree
=================
The document tree has two purposes:
1. representation of the document structure, needed for the
evaluation of CSS selectors, and
2. near-complete encapsulation of the dillo widget.
The HTML parser accesses for most elements only the document tree, and
not anymore Dw. The interface is similar to a small subset of the
Document Object Model (see [DOM2]), and provides methods for the
following purposes:
1. construction of nodes (mainly elements and text), adding them to
other nodes,
2. examining the structure (e.g. for evaluating CSS selectors),
3. assigning style attributes,
4. drawing, and
5. changing the state.
Some notes about the latter three points: The document tree is in most
cases able to construct and access the Dw structures simply by style
attributes. E.g., if the attribute "display" has the value "table", it
"knows" that it must create a DwTable and add it to the DwPage
associated with the parent node. This way, the HTML parser may be
simplified, much functionality can be replaced by a user-agent-defined
style sheet, as in [CSS2] appendix A.
Since this is not in all cases possible, two back-doors are kept open:
1. It is possible to add a special type of element to the tree,
with a specified DwWidget. The tag will processed this
way.
2. DwStyle will be extended by non-standard attributes, when
necessary. For better distinction, they will be preceded by
"x_". Examples are "x_link" and "x_colspan".
An element may have a state, which is used as pseudo-element in the
style evaluation (see below). This is how the dynamic pseudo-classes
([CSS2] chapter 5.11.3) are handled. Changing this is e.g. done when
the user clicks on a not yet visited link, the state then switches
from "link" to "visited".
The CSS Cascade
===============
"CSS cascade" is a module, which is responsible for evaluating CSS
selectors ([CSS2] chapter 5). The evaluation function gets the element
node, the default attributes (DwStyle), and a "pseudo-element" as
argument, and returns a DwStyle with the values described in the
section "DwStyle". The caller is responsible to determine the default
attributes (those which are not changed, if no rule is found), either
by setting them to default values, or copying them from the parent
element.
About the "pseudo-element": An evaluation with this argument set to
non-NULL must only evaluate the rules containing this
"pseudo-element".
Of course, there is the need of a CSS parser. A "cascade" may combine
several style documents, from different origins (see [CSS2] chapter
6.4), so that the parser always adds rules to a cascade. There is no
need for an incremental parser, instead, a document is always parsed
as a whole (see below).
In some cases, it is necessary to add element-specific rules to the
cascade, either for evaluating the "style" attribute, or to process
(mostly deprecated) HTML elements and attributes.
Pseudo Elements and Generated Content
=====================================
Content is generated in two cases:
1. if the ":before" and ":after" pseudo elements are used ([CSS2]
chapter 5.12.3), and
2. for list items.
Content generation is the task of the document tree. For dealing with
":before" and ":after", one document element refers to three DwStyle:
(i) two from the evaluation of ":before" and ":after", and
(ii) one actual style.
The actual style may be affected by the state of the element.
(There are many things missing for pseudo elements, they have to be
specified, and some may not be implemented in dillo).
What Actually Happens in Different Situations
=============================================
Adding Elements to the Tree
---------------------------
This happens after the parser has read an opening tag:
1. The HTML parser evaluates the element attributes to create one
or two new, element-specific rules, and inserts them into the
CSS cascade.
2. The HTML parser adds a new element to the current document
element.
3. The CSS cascade determines the style, based on the style of the
parent, where some attributes are set to default values.
4. This style is attached to the new element, and the element is
drawn (e.g. the appropiate DwWidget methods are called).
Handling the is
written, following is done:
1. The HTML parser passes the stash content to the CSS parser,
which inserts the new rules into the CSS cascade.
2. The styles for the whole document are recalculated, and the
document is redrawn.
Handling the Element
---------------------------
An external style sheet is read by a special cache client, which
writes the content into the buffer, and is associated with the
document tree and the CSS cascade. If the data has been fully
retrieved, the process is similar to
it is likely that the content of