Apr 2001, S.Geerken@ping.de
Last update: Nov 2001

=======
DwStyle
=======

Styles of Dillo Widgets


Note
====

DwStyle has derived from DwPageAttr, and its current structure is very
similar to it. In future, there will be some changes and extensions,
namely:

   - image maps will be handled differently (done),
   - margins, borders, paddings (done),
   - background colors/images, and
   - cursors and tooltips will perhaps move into DwStyle.

Furthermore, widgets will probably refer to different styles for
different states.


Overview
========

DwStyle provides some resources and attributes for drawing widgets, as
well as for parts of a widget (e.g. DwPage uses DwStyle's for its
words). Creating a style is done by filling a DwStyle with the
attributes (except the ref_count), and calling Dw_style_new:

   DwStyle style_attrs, *style;

   style_attrs.foo = bar;
   // etc.
   style = a_Dw_style_new (&style_attrs, random_window);
   // do something with style

After this, the attributes of style should not be changed anymore,
since styles are often shared between different widgets etc. (see
below). Most times, you simply copy the attributes of another style,
and modify them:

   style_attrs = *another_style;
   style_attrs.foo = bar;
   style = a_Dw_style_new (&style_attrs, random_window);

The font structure can be created by Dw_style_font_new, in a similar
way (the GdkFont in font_attrs will be ignored), and colors by
Dw_style_color_new, passing 0xrrggbb as an argument. Note that fonts
and colors are only intended to be used in conjunction with DwStyle.


Lengths and Percentages
=======================

DwStyleLength is a simple data type for lengths and percentages:

   - A length refers to an absolute measurement. It is used to
     represent the HTML type %Pixels; and the CSS type <lenght>.

     For CSS lenghts, there are two units: (i) pixels and absolute
     units, which have to be converted to pixels (a pixels is, unlike
     in the CSS specification, treated as absolute unit), and (ii) the
     relative units "em" and "ex" (see below).

   - A percentage refers to a value relative to another value. It is
     used for the HTML type %Lenght; (except %Pixels;), and the CSS
     type <percentage>.

   - A relative length can be used in lists of HTML MultiLengths.

Since many values in CSS may be either lenghts or percentages, a
single type is very useful.

Useful macros and functions
---------------------------
Macros for creating lenghts:

   DW_STYLE_CREATE_LENGTH (n)      Returns a lenght of n pixels.

   DW_STYLE_CREATE_EX_LENGTH (n)   Returns a length of n times the
                                   'x-height'

   DW_STYLE_CREATE_EM_LENGTH (n)   Returns a length of n times the
                                   'font-size'

   DW_STYLE_CREATE_PERCENTAGE (n)  Returns a percentage, n is relative
                                   to 1, not to 100.

   DW_STYLE_CREATE_RELATIVE (n)    Returns a relative length.

   DW_STYLE_UNDEF_LENGTH           Used to indicate unspecified sizes,
                                   errors, and the end of a list of
                                   lengths.

Furthermore, there are some functions in html.c:

   DwStyleLength Html_parse_length (gchar *attr);

      Returns a length or a percentage, or DW_STYLE_UNDEF_LENGTH in
      case of an error.

   DwStyleLength* Html_parse_multi_length (gchar *attr);

      Returns a vector of lenghts/percentages. The caller has to free
      the result when it is not longer used.

Macros for examining lengths:

   DW_STYLE_IS_LENGTH (l)          Returns TRUE if l is a length.

   DW_STYLE_IS_PERCENTAGE (l)      Returns TRUE if l is a percentage.

   DW_STYLE_IS_RELATIVE (l)        Returns TRUE if l is a relative
                                   length.

   DW_STYLE_GET_LENGTH (l, f)      Returns the value of a length in
                                   pixels, as an integer. f is the
                                   font, this is used if l is based on
                                   font sizes.

   DW_STYLE_GET_PERCENTAGE (l)     Returns the value of a percentage,
                                   relative to 1, as a float.

   DW_STYLE_GET_RELATIVE (l)       Returns the value of a relative
                                   length, as a float.


Representation
--------------
Notes:

   1. This is not part of the interface, and may change! Use the
      macros described above.
   2. Negative numbers may not work yet.

DwStyleLenght is represented by an integer (n is the number of bits of
an integer):

   - Undefined lengths are represented by 0.

   - Lenghts in pixel:

      +---+ - - - +---+---+---+---+
      |     int value     | 0 | 1 |
      +---+ - - - +---+---+---+---+
       n-1          3   2   1   0

   - Lenghts in in x-height:

      +---+ - - - +---+---+---+---+
      |  real value   | 0 | 1 | 1 |
      +---+ - - - +---+---+---+---+
       n-1          3    2   1   0

   - Lenghts in in font-size:

      +---+ - - - +---+---+---+---+
      |  real value   | 1 | 1 | 1 |
      +---+ - - - +---+---+---+---+
       n-1          3   2   1   0

   - Percentages:

      +---+ - - - +---+---+---+---+
      |  real value   | 0 | 1 | 0 |
      +---+ - - - +---+---+---+---+
       n-1          3   2   1   0

   - Relative lengths:

      +---+ - - - +---+---+---+---+
      |  real value   | 1 | 1 | 0 |
      +---+ - - - +---+---+---+---+
       n-1          3   2   1   0

A "real value" is a fixed point number consisting of (m is the number
of bits of the value, not the whole integer):

   +---+ - - - +---+---+ - - - +---+
   | integer part  |     rest      |
   +---+ - - - +---+---+ - - - +---+
     m           16  15          0

For *internal* use, there are two converting macros,
DW_STYLE_REAL_TO_FLOAT and DW_STYLE_FLOAT_TO_REAL.


DwStyle Boxes
=============

The CSS Box Model
-----------------
For borders, margins etc., DwStyle uses the box model defined by
CSS2. DwStyle contains some members defining these attributes. A
widget must use these values for any calculation of sizes, there are
some helper functions (see dw_style.h). A DwStyle box looks quite
similar to a CSS box:

                   
                 ,-- margin.left
                 |   ,-- border.left
                 |   |   ,-- padding.left
                 |---+---+---|
                 +---------------------------------------+ ---
                 |                                       |  |  margin.top
                 |   +-------------------------------+   | -+-
                 |   |          Border               |   |  |  border.top
                 |   |   +-----------------------+   |   | -+-
                 |   |   |        Padding        |   |   |  |  padding.top
   new widget    |   |   |   +---------------+   |   |   | ---
   allocation -->|   |   |   |               |   |   |   |
                 |   |   |   |    Content    |   |   |   |
  former widget ------------>|               |   |   |   |
   allocation    |   |   |   +---------------+   |   |   | ---
                 |   |   |                       |   |   |  |  margin.bottom
                 |   |   +-----------------------+   |   | -+-
                 |   |                               |   |  |  border.bottom
                 |   +-------------------------------+   | -+-
                 |                                       |  |  padding.bottom
                 +---------------------------------------+ ---
                                             |---+---+---|
                              padding.right  --'   |   |
                                    border.right --'   |
                                        margin.right --'

Background colors
-----------------
The background color is stored in style->background_color, which be
NULL (the background color of the parent widget is shining through).

For toplevel widgets, this color is set as the background color of the
viewport, for other widgets, a filled rectangle is drawn, covering the
content and padding. (This is compliant with CSS2, the background
color of the toplevel element covers the whole canvas.)

Drawing
-------
There is a new function Dw_widget_draw_widget_box, which should be
called at the beginning of Dw_foo_draw. For parts referring to styles
(e.g. words in a page), Dw_widget_draw_box should be used.


Notes on Memory Management
==========================

Memory management is done by reference counting, a_Dw_style_new
returns a pointer to DwStyle with an increased reference counter, so
you should care about calling Dw_style_unref if it is not used
anymore. You do *not* need to care about the reference counters of
fonts and styles.

In detail:

   - a_Dw_style_ref is called in

        * a_Dw_widget_set_style, to assign a style to a widget,

        * a_Dw_page_add_text, a_Dw_page_add_widget,
          a_Dw_page_add_anchor, to assign a style to a word,

        * and Html_push_tag (often the reference counter is again
          decreased shortly after this).

   - a_Dw_unref_style is called in:

        * Dw_page_destroy, Dw_widget_destroy, Html_cleanup_tag,
          Html_pop_tag, Html_close,

        * a_Dw_widget_set_style, Html_set_top_font (and several
          Html_tag_open_... functions), these functions overwrite an
          existing style.


HTML Stack
==========

(This is not DwStyle specific, but may be useful if you are working on
the HTML parser.)

The topmost element of the HTML stack contains a (reference to a)
style which will be used to add the text to the current page. If you
use a style only for a short while (see Html_tag_open_frame for an
example), you may use it this way:

   style_attrs = *html->stack[html->stack_top].style;
   style_attrs.foo = bar;
   style = a_Dw_style_new (&style_attrs, random_window);

Do not forget to unref it afterwards. A good choice for random_window
is html->bw->main_window->window.

In many cases, you want to set the style for the content of an element
(e.g. <A>), then you must store it in the stack:

   DwStyle style_attrs, *old_style;

   old_style = html->stack[html->stack_top].style;
   style_attrs = *old_style;
   style_attrs.foo = bar;
   html->stack[html->stack_top].style =
      a_Dw_style_new (&style_attrs, random_window);
   a_Dw_style_unref (old_style);

The macro HTML_SET_TOP_ATTR can be used for single attributes, for
changing more attributes, this code should be copied for efficiency.
