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.


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;
  css_stylesheet_params params;
  /* Set params */
  ...
  code = css_stylesheet_create(&params, &sheet);
  if (code != CSS_OK)
    ...

The arguments are as follows:

+ css_stylesheet_params params
| + uint32_t params_version
| |   Version of the params struct.
| |
| + 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 <link>
| |   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_url_resolution_fn resolve
| |   Function for resolving releative URLs into absolute URLs.
| |
| + void *resolve_pw
| |   Client data passed back to resolve function.
| |
| + css_import_notification_fn import
| |   Import notification function.
| |
| + void *import_pw
| |   Client data passed back to import function.
| |
| + css_color_resolution_fn color
| |   Colour resolution function.
| |
| + void *color_pw
| |   Client data passed back to color function.
| |
| + css_font_resolution_fn font
| |   Font resolution function.
| |
| + void *font_pw
|     Client data passed back to import function.
|
+ 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 <h1> 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(&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(&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.
| 
+ 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_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.
|
+ css_computed_style **result
    Updated to the computed styles for the node.  Array indexed by
    css_pseudo_element.

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.

