Using the LibCSS API ==================== This document explains how to use LibCSS. In addition to this document, please see the examples and the headers (found in /usr/local/include/libcss or a similar location). Experience with C is assumed. Using the library consists of the following general steps: 1. Initialize the library. 2. Load one or more CSS files. 3. Use the Selection API to determine styles. 4. Use the computed styles. 5. Shut down the library. Please see example1.c for a demonstration of these steps. Initialize the library ---------------------- The library is initialized using css_initialise(): css_initialise("Aliases", myrealloc, 0); The first argument is the pathname of an Aliases file, which maps character encoding names to their canonical form. For an example, see test/data/Aliases. The 2nd argument is an allocation function. All allocations required by library initialization will be made by calling this function. It takes the same arguments as realloc(); a pointer and a size. If pointer is NULL a new block is being requested. If size is 0 the block should be freed. Otherwise an existing block is being resized. In many cases this function can simply call realloc(). The allocation function also takes a private data pointer, which is the third argument to css_initialise(). This is not used by LibCSS but may be used to communicate context to the allocation function. The allocation function pointer and private data pointer are arguments to many LibCSS functions and work in the same way. css_initialise() returns a css_error value. It is CSS_OK if everything worked, and an error code otherwise. The error codes are defined in libcss/errors.h. Many LibCSS functions return a css_error value. Checking the return value of every call that does is advised, for example: css_error code; code = css_initialise("../test/data/Aliases", myrealloc, 0); if (code != CSS_OK) { fprintf(stderr, "ERROR: css_initialise failed: %s\n", css_error_to_string(code)); exit(EXIT_FAILURE); } LibCSS depends on LibWapcaplet. This must be initialized before LibCSS. For example: lwc_code = lwc_initialise(myrealloc, NULL, 0); if (lwc_code != lwc_error_ok) ... Load one or more CSS files -------------------------- A stylesheet is represented by the opaque type css_stylesheet. To create one, use css_stylesheet_create(), for example: css_stylesheet *sheet; code = css_stylesheet_create(CSS_LEVEL_DEFAULT, "UTF-8", "", NULL, false, false, myrealloc, 0, resolve_url, 0, &sheet); if (code != CSS_OK) ... The arguments are as follows: css_language_level level Which version of CSS the stylesheet should be treated as. It currently has no effect and is reserved for future use. The recommended value is CSS_LEVEL_DEFAULT. const char *charset The encoding of the stylesheet data, or NULL if LibCSS should attempt to detect it. If the encoding is known, for example from the Content-Type header or a file attribute, then it should be supplied here. const char *url The URL that the stylesheet was retrieved from. LibCSS uses this along with the resolve function (see below) to convert relative URLs in the stylesheet (e.g. imports, background images) to absolute URLs. If the stylesheet has no URL, use "". const char *title This is intended for the stylesheet title (for example from the tag). The title is not used by LibCSS but may be retrieved using css_stylesheet_get_title(). May be NULL if there is no title. bool allow_quirks bool inline_style css_allocator_fn alloc void *alloc_pw css_url_resolution_fn resolve void *resolve_pw css_stylesheet **stylesheet Updated with the newly created stylesheet object. Once the stylesheet has been created, CSS source data can be added to it. LibCSS parses the data into internal structures. Only data in memory is supported; you must handle reading from files or the network if required. Data is added using css_stylesheet_append_data(), for example: code = css_stylesheet_append_data(sheet, data, length); if (code != CSS_OK && code != CSS_NEEDDATA) ... The second argument is a pointer to a buffer containing some CSS to be parsed, with length in bytes given in the 3rd argument. This function may be called repeatedly with more data from the same stylesheet, for example as data arrives over the network. The return value may be CSS_NEEDDATA instead of CSS_OK. This indicates that more data may be expected. The two states can be treated identically. When all the data has been supplied, css_stylesheet_data_done() completes the processing: code = css_stylesheet_data_done(sheet); if (code != CSS_OK) ... The stylesheet is now in memory and ready for further use. Use the Selection API to determine styles ----------------------------------------- The Selection API is currently the only way to get information about styles from stylesheets that have been loaded. It takes a document node as input and returns the computed style that applies to that node. For example, it can be used to answer the question "What style should this

element have?" CSS selectors can be complex and apply to certain arrangments of elements within a document tree. Therefore LibCSS has to be able to navigate your document tree and read attributes of it to determine if a style applies. It does this through a series of functions that you supply. In this way LibCSS is independent of the representation of the document. For example, with the style rule: table h2 { color: red; } when requesting the style for an h2 element node, LibCSS will search its ancestors for a table element to determine if this style applies. The first step in using the Selection API is creating a selection context. This is a list of the stylesheets to be used. A context is created using css_select_ctx_create(): css_select_ctx *select_ctx; code = css_select_ctx_create(myrealloc, 0, &select_ctx); if (code != CSS_OK) ... Stylesheets are added to the context using css_select_ctx_append_sheet(): code = css_select_ctx_append_sheet(select_ctx, sheet, CSS_ORIGIN_AUTHOR, CSS_MEDIA_ALL); if (code != CSS_OK) ... When adding a stylesheet, the origin and media can be specified. These are used in the computation of styles as defined in the CSS specification. Alternatively stylesheets may be added using css_select_ctx_insert_sheet(). After the context has been prepared, an empty computed style is created: css_computed_style *style; code = css_computed_style_create(myrealloc, 0, &style); if (code != CSS_OK) ... The style is then determined for a document node using css_select_style(): code = css_select_style(select_ctx, element_node, 0, CSS_MEDIA_SCREEN, NULL, style, &select_handler, 0); if (code != CSS_OK) ... The arguments are as follows: css_select_ctx *ctx The selection context, as described above. void *node A pointer to the document node for which the style is required. This is a void pointer and may therefore be of any desired type. LibCSS can not use it directly; instead it gets information about it through the functions given in the handler argument, described below. Usually this will be a node in a document tree. uint32_t pseudo_element uint64_t media The media that the style should apply to. The computed style will only consider stylesheets or @media blocks that include this media. See the CSS specification for more details. const css_stylesheet *inline_style css_computed_style *result Updated to the computed style for the node. css_select_handler *handler This is a table of functions that are used to get information from and to navigate the document tree, in order to determine if a CSS selector matches the document node. Further details are below. void *pw A private data pointer that is passed to each of the handler functions. The types of the handler functions that need to be supplied and the definition of css_select_handler are given in libcss/select.h. The functions all have the following in common: * the first argument is the private data pointer that was the last argument to css_select_style() * the second argument is the document node that is being queried is some way * the last one or two arguments are pointers that must be updated with the required information * the return value is a css_error and should be CSS_OK if everything worked and an error code otherwise For example, the node_name function, which determines the element name of a node, could be this: css_error node_name(void *pw, void *n, lwc_string **name) { my_document_node *node = n; *name = lwc_string_ref(node->name); return CSS_OK; } where my_document_node is your document tree node type (e.g. a struct of some sort). Use the computed styles ----------------------- After the style has been computed by css_select_style() the CSS properties can finally be retrieved. This is done using the property accessor functions declared in libcss/computed.h. Note that although struct css_computed_style is declared in computed.h, its members must not be used directly. The accessors carry out various additional work to read the properties correctly. For example, the css_computed_color() accessor retrieves the color property: uint8_t color_type; css_color color_shade; color_type = css_computed_color(style, &color_shade); In this case color_type can be CSS_COLOR_INHERIT or CSS_COLOR_COLOR. In the latter case, color_shade contains the actual color in RRGGBBAA format. Together these two variables encode the possible values for the property given by the CSS specification.