iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / document / html / README
blob1d5fac3de8b2e523b26f0a02d4d8be2b5f21218b
1 This is the "Mikulas' HTML Processor". The parser and renderer we actually use.
2 It's scary, yes.
5 Parser - renderer interaction
6 =============================
8 (See also doc/hacking.txt. Incoherent (and possibly misleaded on some points;
9 don't trust it to the letter) rambling follows.)
11 The parser is written modularily so it is separated from the renderer and can
12 be actually used with a different renderer as well (they do that in Links2,
13 using graphics renderer with the current parser). The entry point from the rest
14 of ELinks is inside the renderer, which sets up couple of callbacks (like "put
15 this text on screen" or "special element indicator", where special element
16 might be a <hr>, a link or a table) and calls the parser.
18 Usually, the renderer just lets the parser chew through the document on its own and
19 only processes the callbacks, sometimes it kicks in though - at that point it
20 does a "management override", skips a chunk of the source and resumes the parser
21 after it's over. Most commonly, it does this with tables - when you hit a table,
22 html_table() does basically nothing and the renderer at that point skips to
23 </table>. What happens with the table you ask? The renderer calls itself
24 recursively on just the table; that means a separate parser instance is run for
25 the table, and for each distinct cell a new renderer instance is called. The
26 table is (parsed and) rendered two times - first to just find out the wanted
27 cell sizes, then it optimizes that and figures out the layout and does a second
28 rendering pass where it uses the calculated cell sizes to actually write the cells
29 to the canvas.
32 Box model plans
33 ===============
35 The design described above - calling the renderer recursively on the table and each cell -
36 is a cheap substitute for the box model. Except for those cases where the
37 renderer basically just writes on the canvas sequentially as the text comes in, moving
38 the pen only rightwards and down; there are only some parameters like
39 indentation and border sizes which affect the rightwards and down motion.
41 It needs to be changed so that the renderer maintains a *box model* - at each
42 moment the text being written out is inside a stack of boxes. This is what
43 the table renderer achieves by just making each box a separate renderer
44 instance - you can't get away without boxes when rendering tables. But boxes
45 are essential for all block elements at the moment you go CSS, and we went CSS
46 and would like to support floating elements.
48 Even without support of the float property, boxes will have an immediate advantage since you will be
49 able to e.g. set their background - now e.g. slashdot looks really ugly since
50 it has background set on some block elements but since we have no box model we set the
51 background only on the rendered text itself, not the rectangular canvas around
52 it.
54 Boxes can probably be implemented by just transmitting information "here a new
55 box (block element) begins" and "here a box ends" from parser to the renderer,
56 and maintaining a box stack with some geometry information in the renderer (and
57 now, you've just got DOM for block elements if you turn this from a temporary
58 stack to a persistent tree; but we might not want to do that, at least not
59 unconditionally).
62 Rendering boxes
63 ~~~~~~~~~~~~~~~
65 When you are actually rendering, you must not apply the attributes on the whole
66 box after rendering; inline elements might have custom attributes and we won't
67 have boxes for those. Also, you don't know the box width until you've already
68 rendered it. Several possibilities occur to me:
70 (i) Dry-run each box to find out the dimensions, prefill the rectangle with
71 attributes and then hard-render. Awfully quadratic, would kill performance.
73 (ii) Post-fill: for each line and each box in stack, remember "content width".
74 After the box is over you look at its each line and post-fill it from the
75 content width to the box width (at both sides).
77 (iii) Maximalistic: assume maximal spread and reduce afterwards. Basically fill
78 the whole line (from starting X coordinate) with the box attributes and when
79 the box is done rendering, fill the rest of all its lines (from ending X
80 coordinate) with the parent's box attributes.
82 I like (iii) most.
85 Boxes and floats
86 ~~~~~~~~~~~~~~~~
88 In order to be able to support floats, you want to be able to revisit previous
89 boxes and resize them based on the new box. To do that, you need to remember
90 parser contexts for all the boxes in the stack (you should have only few of
91 those). If you hit a floating box, you:
93         * dry-render it to find out the dimensions and then do the dimensions
94           negotiation like you'd do with cell tables; or maybe a different one,
95           I didn't read the specs on it; don't put anything on canvas
97         * pop the floating box
99         * duplicate the parent box, so you have a "sibling box" that contains
100           all the content hit so far; limit its parser context to reach
101           only to the start of your floating box
103           Note that you don't want to merge multiple float boxes together.
104           So, an implementation might have something like this instead of the
105           "duplication":
107           struct box {
108                 struct box floaters[];
109           }
111           where floaters are children of this box; normally you have one
112           which is mostly read-only and contains everything rendered so far,
113           and one which points to the next box in your stack. When you process
114           a floating box, it gets a separate entry in the floaters[] array
115           and won't get merged to floaters[0].
117         * wipe the sibling box (floaters[*]) from canvas
119         * rerender the sibling box with calculated geometry constraints
121         * rerender the floating box dtto
123 (This might be modified based on how floats are actually supposed to behave;
124 I'm not sure of that. ;-) ) This algorithm is careful not to keep a list of
125 all sibling boxes in memory since with a simple long document a mere sequence
126 of paragraphs would cost us huge amount of memory. There's probably no way
127 around keeping a list of sibling floating boxes in memory, though.