summaryrefslogtreecommitdiff log msg author committer range
path: root/Docs/developer
blob: 753c6cca651362962d14d0dcab33288a33999d81 (plain)
 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178  /** \mainpage NetSurf Documentation for Developers This document contains an overview of the code for NetSurf, and any other information useful to developers. \section overview Source Code Overview The source is split at top level as follows: - \ref content - \ref css - \ref render - Non-platform specific front-end (desktop/) - RISC OS specific code (riscos/) - Unix debug build specific code (debug/) - Misc. useful functions (utils/) \section content Fetching, caching, and converting content (content/) Each URL is stored in a struct ::content. This structure contains a union with fields for each type of data (HTML, CSS, images). The content_* functions provide a general interface for handling these structures. A content of a specified type is created using content_create(), data is fed to it using content_process_data(), terminated by a call to content_convert(), which converts the content into a structure which can be displayed easily. The cache stores this converted content. When content is retrieved from the cache, content_revive() should result in content which can be displayed (eg. by loading any images and styles required and updating pointers to them). Code should not usually use the fetch_* and cache_* functions directly. Instead use fetchcache(), which checks the cache for a url and fetches, converts, and caches it if not present. \section css CSS parser and interfaces (css/) CSS is tokenised by a flex-generated scanner (scanner.l), and then parsed into a memory representation by a lemon-generated parser (parser.y, ruleset.c). Styles are retrieved using css_get_style(). They can be cascaded by css_cascade(). - http://lex.sourceforge.net/ - http://www.hwaci.com/sw/lemon/ \section render HTML processing and layout (render/) This is the process to render an HTML document: First the HTML is parsed to a tree of xmlNodes using the HTML parser in libxml. This happens simultaneously with the fetch [html_process_data()]. Any stylesheets which the document depends on are fetched and parsed. The tree is converted to a 'box tree' by xml_to_box(). The box tree contains a node for each block, inline element, table, etc. The aim of this stage is to determine the 'display' or 'float' CSS property of each element, and create the corresponding node in the box tree. At this stage the style for each element is also calculated (from CSS rules and element attributes). The tree is normalised so that each node only has children of permitted types (eg. TABLE_CELLs must be within TABLE_ROWs) by adding missing boxes. The box tree is passed to the layout engine [layout_document()], which finds the space required by each element and assigns coordinates to the boxes, based on the style of each element and the available width. This includes formatting inline elements into lines, laying out tables, and positioning floats. The layout engine can be invoked again on a already laid out box tree to reformat it to a new width. Coordinates in the box tree are relative to the position of the parent node. The box tree can then be rendered using each node's coordinates. \section links Other Documentation RISC OS specific protocols: - Plugin http://www.ecs.soton.ac.uk/~jmb202/riscos/acorn/funcspec.html http://www.ecs.soton.ac.uk/~jmb202/riscos/acorn/browse-plugins.html - URI http://www.ecs.soton.ac.uk/~jmb202/riscos/acorn/uri.html - URL http://www.vigay.com/inet/inet_url.html - Nested WIMP http://www.ecs.soton.ac.uk/~jmb202/riscos/acorn/nested.html Specifications: - HTML 4.01 http://www.w3.org/TR/html401/ (see also http://www.w3.org/MarkUp/) - XHTML 1.0 http://www.w3.org/TR/xhtml1/ - CSS 2.1 http://www.w3.org/TR/CSS21/ - HTTP/1.1 http://www.w3.org/Protocols/rfc2616/rfc2616.html (see also http://www.w3.org/Protocols/) - HTTP Authentication http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc2617.html - PNG http://www.w3.org/Graphics/PNG/ - URI http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc2396.html (see also http://www.w3.org/Addressing/ and RFC 2616) - Cookies http://wp.netscape.com/newsref/std/cookie_spec.html and http://www.cis.ohio-state.edu/cgi-bin/rfc/rfc2109.html \section libs Libraries Get these compiled for RISC OS with headers from http://netsurf.strcprstskrzkrk.co.uk/developer/ - libxml (XML and HTML parser) http://www.xmlsoft.org/ - libcurl (HTTP, FTP, etc) http://curl.haxx.se/libcurl/ - OSLib (C interface to RISC OS SWIs) http://ro-oslib.sourceforge.net/ - libpng (PNG support) http://www.libpng.org/pub/png/libpng.html - zlib http://www.gzip.org/zlib/ - uri http://www.nongnu.org/uri/ \section addcss Implementing a new CSS property In this section I go through adding a CSS property to NetSurf, using the 'white-space' property as an example. -- James Bursa 1. Read and understand the description of the property in the CSS specification (I have worked from CSS 2, but now 2.1 is probably better). These changes are required in the css directory: 2. Add the property to css_enums. This file is used to generate css_enum.h and css_enum.c: \code css_white_space inherit normal nowrap pre \endcode (I'm not doing pre-wrap and pre-line for now.) 3. Add fields to struct ::css_style to represent the property: \code css_white_space white_space; \endcode 4. Add a parser function for the property to ruleset.c. Declare a new function: \code static void parse_white_space(struct css_style * const s, const struct css_node * const v); \endcode and add it to ::property_table: \code { "white-space", parse_white_space }, \endcode This will cause the function to be called when the parser comes to a rule giving a value for white-space. The function is passed a linked list of struct ::css_node, each of which corresponds to a token in the CSS source, and must update s to correspond to that rule. For white-space, the implementation is simply: \code void parse_white_space(struct css_style * const s, const struct css_node * const v) { css_white_space z; if (v->type != CSS_NODE_IDENT || v->next != 0) return; z = css_white_space_parse(v->data); if (z != CSS_WHITE_SPACE_UNKNOWN) s->white_space = z; } \endcode First we check that the value consists of exactly one identifier, as described in the specification. If it is not, we ignore it, since it may be some future CSS. The css_white_space_parse() function is generated in css_enum.c, and converts a string giving a value to a constant. If the conversion succeeds, the style s is updated. 5. Add defaults for the style to ::css_base_style, ::css_empty_style, and ::css_blank_style in css.c. The value in css_base_style should be the one given as 'Initial' in the spec, and the value in css_empty_style should be inherit. If 'Inherited' is yes in the spec, the value in css_blank_style should be inherit, otherwise it should be the one given as 'Initial'. Thus for white-space, which has "Initial: normal, Inherited: yes" in the spec, we use CSS_WHITE_SPACE_NORMAL in css_base_style and CSS_WHITE_SPACE_INHERIT in the other two. 6. Edit css_cascade() and css_merge() in css.c to handle the property. In both cases for white-space this looks like: \code if (apply->white_space != CSS_WHITE_SPACE_INHERIT) style->white_space = apply->white_space; \endcode Add the property to css_dump_style() (not essential). Now the box, layout and / or redraw code needs to be changed to use the new style property. This varies much more depending on the property. For white-space, convert_xml_to_box() was changed to split text at newlines if white-space was pre, and to replace spaces with hard spaces for nowrap. Additionally, calculate_inline_container_widths() was changed to give the appropriate minimum width for pre and nowrap. */