/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */

/*
 * This file is part of The Croco Library
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of version 2.1 of 
 * the GNU Lesser General Public
 * License as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the 
 * GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 * USA
 *
 * Author: Dodji Seketeli.
 * see COPYRIGHTS file for copyright information
 */

#include <string.h>
#include "cr-style.h"

/**
 *@file
 *The definition of the #CRStyle class.
 */

/**
 *A property ID.
 *Each supported css property has an ID which is
 *an entry into a property "population" jump table.
 *each entry of the property population jump table
 *contains code to transform the literal form of
 *a property value into a strongly typed value.
 */
enum CRPropertyID {
        PROP_ID_NOT_KNOWN = 0,
        PROP_ID_PADDING_TOP,
        PROP_ID_PADDING_RIGHT,
        PROP_ID_PADDING_BOTTOM,
        PROP_ID_PADDING_LEFT,
        PROP_ID_PADDING,
        PROP_ID_BORDER_TOP_WIDTH,
        PROP_ID_BORDER_RIGHT_WIDTH,
        PROP_ID_BORDER_BOTTOM_WIDTH,
        PROP_ID_BORDER_LEFT_WIDTH,
        PROP_ID_BORDER_WIDTH,
        PROP_ID_BORDER_TOP_STYLE,
        PROP_ID_BORDER_RIGHT_STYLE,
        PROP_ID_BORDER_BOTTOM_STYLE,
        PROP_ID_BORDER_LEFT_STYLE,
        PROP_ID_BORDER_STYLE,
        PROP_ID_BORDER_TOP_COLOR,
        PROP_ID_BORDER_RIGHT_COLOR,
        PROP_ID_BORDER_BOTTOM_COLOR,
        PROP_ID_BORDER_LEFT_COLOR,
        PROP_ID_BORDER_TOP,
        PROP_ID_BORDER_RIGHT,
        PROP_ID_BORDER_BOTTOM,
        PROP_ID_BORDER_LEFT,
        PROP_ID_BORDER,
        PROP_ID_MARGIN_TOP,
        PROP_ID_MARGIN_RIGHT,
        PROP_ID_MARGIN_BOTTOM,
        PROP_ID_MARGIN_LEFT,
        PROP_ID_MARGIN,
        PROP_ID_DISPLAY,
        PROP_ID_POSITION,
        PROP_ID_TOP,
        PROP_ID_RIGHT,
        PROP_ID_BOTTOM,
        PROP_ID_LEFT,
        PROP_ID_FLOAT,
        PROP_ID_WIDTH,
        PROP_ID_COLOR,
        PROP_ID_BACKGROUND_COLOR,
        PROP_ID_FONT_FAMILY,
        PROP_ID_FONT_SIZE,
        PROP_ID_FONT_STYLE,
        PROP_ID_FONT_WEIGHT,
	PROP_ID_WHITE_SPACE,
        /*should be the last one. */
        NB_PROP_IDS
};

typedef struct _CRPropertyDesc CRPropertyDesc;

struct _CRPropertyDesc {
        const gchar *name;
        enum CRPropertyID prop_id;
};

static CRPropertyDesc gv_prop_table[] = {
        {"padding-top", PROP_ID_PADDING_TOP},
        {"padding-right", PROP_ID_PADDING_RIGHT},
        {"padding-bottom", PROP_ID_PADDING_BOTTOM},
        {"padding-left", PROP_ID_PADDING_LEFT},
        {"padding", PROP_ID_PADDING},
        {"border-top-width", PROP_ID_BORDER_TOP_WIDTH},
        {"border-right-width", PROP_ID_BORDER_RIGHT_WIDTH},
        {"border-bottom-width", PROP_ID_BORDER_BOTTOM_WIDTH},
        {"border-left-width", PROP_ID_BORDER_LEFT_WIDTH},
        {"border-width", PROP_ID_BORDER_WIDTH},
        {"border-top-style", PROP_ID_BORDER_TOP_STYLE},
        {"border-right-style", PROP_ID_BORDER_RIGHT_STYLE},
        {"border-bottom-style", PROP_ID_BORDER_BOTTOM_STYLE},
        {"border-left-style", PROP_ID_BORDER_LEFT_STYLE},
        {"border-style", PROP_ID_BORDER_STYLE},
        {"border-top", PROP_ID_BORDER_TOP},
        {"border-right", PROP_ID_BORDER_RIGHT},
        {"border-bottom", PROP_ID_BORDER_BOTTOM},
        {"border-left", PROP_ID_BORDER_LEFT},
        {"border", PROP_ID_BORDER},
        {"margin-top", PROP_ID_MARGIN_TOP},
        {"margin-right", PROP_ID_MARGIN_RIGHT},
        {"margin-bottom", PROP_ID_MARGIN_BOTTOM},
        {"margin-left", PROP_ID_MARGIN_LEFT},
        {"margin", PROP_ID_MARGIN},
        {"display", PROP_ID_DISPLAY},
        {"position", PROP_ID_POSITION},
        {"top", PROP_ID_TOP},
        {"right", PROP_ID_RIGHT},
        {"bottom", PROP_ID_BOTTOM},
        {"left", PROP_ID_LEFT},
        {"float", PROP_ID_FLOAT},
        {"width", PROP_ID_WIDTH},
        {"color", PROP_ID_COLOR},
        {"border-top-color", PROP_ID_BORDER_TOP_COLOR},
        {"border-right-color", PROP_ID_BORDER_RIGHT_COLOR},
        {"border-bottom-color", PROP_ID_BORDER_BOTTOM_COLOR},
        {"border-left-color", PROP_ID_BORDER_LEFT_COLOR},
        {"background-color", PROP_ID_BACKGROUND_COLOR},
        {"font-family", PROP_ID_FONT_FAMILY},
        {"font-size", PROP_ID_FONT_SIZE},
        {"font-style", PROP_ID_FONT_STYLE},
        {"font-weight", PROP_ID_FONT_WEIGHT},
	{"white-space", PROP_ID_WHITE_SPACE},
        /*must be the last one */
        {NULL, (enum CRPropertyID) 0}
};

/**
 *A the key/value pair of this hash table
 *are:
 *key => name of the css property found in gv_prop_table
 *value => matching property id found in gv_prop_table.
 *So this hash table is here just to retrieval of a property id
 *from a property name.
 */
static GHashTable *gv_prop_hash = NULL;

/**
 *incremented by each new instance of #CRStyle
 *and decremented at the it destroy time.
 *When this reaches zero, gv_prop_hash is destroyed.
 */
static gulong gv_prop_hash_ref_count = 0;

struct CRNumPropEnumDumpInfo {
        enum CRNumProp code;
        const gchar *str;
};

static struct CRNumPropEnumDumpInfo gv_num_props_dump_infos[] = {
        {NUM_PROP_TOP, "top"},
        {NUM_PROP_RIGHT, "right"},
        {NUM_PROP_BOTTOM, "bottom"},
        {NUM_PROP_LEFT, "left"},
        {NUM_PROP_PADDING_TOP, "padding-top"},
        {NUM_PROP_PADDING_RIGHT, "padding-right"},
        {NUM_PROP_PADDING_BOTTOM, "padding-bottom"},
        {NUM_PROP_PADDING_LEFT, "padding-left"},
        {NUM_PROP_BORDER_TOP, "border-top"},
        {NUM_PROP_BORDER_RIGHT, "border-right"},
        {NUM_PROP_BORDER_BOTTOM, "border-bottom"},
        {NUM_PROP_BORDER_LEFT, "border-left"},
        {NUM_PROP_MARGIN_TOP, "margin-top"},
        {NUM_PROP_MARGIN_RIGHT, "margin-right"},
        {NUM_PROP_MARGIN_BOTTOM, "margin-bottom"},
        {NUM_PROP_MARGIN_LEFT, "margin-left"},
        {NUM_PROP_WIDTH, "width"},
        {(enum CRNumProp) 0, NULL}
};

struct CRRgbPropEnumDumpInfo {
        enum CRRgbProp code;
        const gchar *str;
};

static struct CRRgbPropEnumDumpInfo gv_rgb_props_dump_infos[] = {
        {RGB_PROP_BORDER_TOP_COLOR, "border-top-color"},
        {RGB_PROP_BORDER_RIGHT_COLOR, "border-right-color"},
        {RGB_PROP_BORDER_BOTTOM_COLOR, "bottom-color"},
        {RGB_PROP_BORDER_LEFT_COLOR, "left-color"},
        {RGB_PROP_COLOR, "color"},
        {RGB_PROP_BACKGROUND_COLOR, "background-color"},
        {(enum CRRgbProp) 0, NULL}
};

struct CRBorderStylePropEnumDumpInfo {
        enum CRBorderStyleProp code;
        const gchar *str;

};

static struct CRBorderStylePropEnumDumpInfo gv_border_style_props_dump_infos[]
        = {
        {BORDER_STYLE_PROP_TOP, "border-style-top"},
        {BORDER_STYLE_PROP_RIGHT, "border-style-right"},
        {BORDER_STYLE_PROP_BOTTOM, "boder-style-bottom"},
        {BORDER_STYLE_PROP_LEFT, "border-style-left"},
        {(enum CRBorderStyleProp) 0, NULL}
};

static enum CRStatus
  cr_style_init_properties (void);

enum CRDirection {
        DIR_TOP = 0,
        DIR_RIGHT,
        DIR_BOTTOM,
        DIR_LEFT,

        /*must be the last one */
        NB_DIRS
};

static const gchar *num_prop_code_to_string (enum CRNumProp a_code);

static const gchar *rgb_prop_code_to_string (enum CRRgbProp a_code);

static const gchar *border_style_prop_code_to_string (enum CRBorderStyleProp
                                                      a_code);

static enum CRStatus
set_prop_padding_x_from_value (CRStyle * a_style,
                                 CRTerm * a_value, enum CRDirection a_dir);

static enum CRStatus
set_prop_border_x_width_from_value (CRStyle * a_style,
                                    CRTerm * a_value,
                                    enum CRDirection a_dir);
static enum CRStatus
set_prop_border_width_from_value (CRStyle *a_style,
                                  CRTerm *a_value) ;

static enum CRStatus
set_prop_border_x_style_from_value (CRStyle * a_style,
                                    CRTerm * a_value,
                                    enum CRDirection a_dir);
static enum CRStatus
set_prop_border_style_from_value (CRStyle *a_style,
                                  CRTerm *a_value) ;

static enum CRStatus
set_prop_margin_x_from_value (CRStyle * a_style, CRTerm * a_value,
                                enum CRDirection a_dir);

static enum CRStatus
set_prop_display_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_x_from_value (CRStyle * a_style, CRTerm * a_value,
                         enum CRDirection a_dir);

static enum CRStatus
set_prop_float (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_width (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_color (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_background_color (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value,
                                      enum CRDirection a_dir);

static enum CRStatus
set_prop_border_x_from_value (CRStyle * a_style, CRTerm * a_value,
                                enum CRDirection a_dir);

static enum CRStatus
set_prop_border_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_padding_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_margin_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
init_style_font_size_field (CRStyle * a_style);

static enum CRStatus
set_prop_font_size_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_font_style_from_value (CRStyle * a_style, CRTerm * a_value);

static enum CRStatus
set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value);

static const gchar *
num_prop_code_to_string (enum CRNumProp a_code)
{
        guint len = sizeof (gv_num_props_dump_infos) /
                sizeof (struct CRNumPropEnumDumpInfo);
        if (a_code >= len) {
                cr_utils_trace_info ("A field has been added "
                                     "to 'enum CRNumProp' and no matching"
                                     " entry has been "
                                     "added to gv_num_prop_dump_infos table.\n"
                                     "Please add the missing matching entry");
                return NULL;
        }
        if (gv_num_props_dump_infos[a_code].code != a_code) {
                cr_utils_trace_info ("mismatch between the order of fields in"
                                     " 'enum CRNumProp' and "
                                     "the order of entries in "
                                     "the gv_num_prop_dump_infos table");
                return NULL;
        }
        return gv_num_props_dump_infos[a_code].str;
}

static const gchar *
rgb_prop_code_to_string (enum CRRgbProp a_code)
{
        guint len = sizeof (gv_rgb_props_dump_infos) /
                sizeof (struct CRRgbPropEnumDumpInfo);

        if (a_code >= len) {
                cr_utils_trace_info ("A field has been added "
                                     "to 'enum CRRgbProp' and no matching"
                                     " entry has been "
                                     "added to gv_rgb_prop_dump_infos table.\n"
                                     "Please add the missing matching entry");
                return NULL;
        }
        if (gv_rgb_props_dump_infos[a_code].code != a_code) {
                cr_utils_trace_info ("mismatch between the order of fields in"
                                     " 'enum CRRgbProp' and "
                                     "the order of entries in "
                                     "the gv_rgb_props_dump_infos table");
                return NULL;
        }
        return gv_rgb_props_dump_infos[a_code].str;
}

static const gchar *
border_style_prop_code_to_string (enum CRBorderStyleProp a_code)
{
        guint len = sizeof (gv_border_style_props_dump_infos) /
                sizeof (struct CRBorderStylePropEnumDumpInfo);

        if (a_code >= len) {
                cr_utils_trace_info ("A field has been added "
                                     "to 'enum CRBorderStyleProp' and no matching"
                                     " entry has been "
                                     "added to gv_border_style_prop_dump_infos table.\n"
                                     "Please add the missing matching entry");
                return NULL;
        }
        if (gv_border_style_props_dump_infos[a_code].code != a_code) {
                cr_utils_trace_info ("mismatch between the order of fields in"
                                     " 'enum CRBorderStyleProp' and "
                                     "the order of entries in "
                                     "the gv_border_style_props_dump_infos table");
                return NULL;
        }
        return gv_border_style_props_dump_infos[a_code].str;
}

static enum CRStatus
cr_style_init_properties (void)
{

        if (!gv_prop_hash) {
                gulong i = 0;

                gv_prop_hash = g_hash_table_new (g_str_hash, g_str_equal);
                if (!gv_prop_hash) {
                        cr_utils_trace_info ("Out of memory");
                        return CR_ERROR;
                }

                /*load gv_prop_hash from gv_prop_table */
                for (i = 0; gv_prop_table[i].name; i++) {
                        g_hash_table_insert
                                (gv_prop_hash,
                                 (gpointer) gv_prop_table[i].name,
                                 GINT_TO_POINTER (gv_prop_table[i].prop_id));
                }
        }

        return CR_OK;
}

static enum CRPropertyID
cr_style_get_prop_id (const guchar * a_prop)
{
        gpointer *raw_id = NULL;

        if (!gv_prop_hash) {
                cr_style_init_properties ();
        }

        raw_id = (gpointer *) g_hash_table_lookup (gv_prop_hash, a_prop);
        if (!raw_id) {
                return PROP_ID_NOT_KNOWN;
        }
        return (enum CRPropertyID)GPOINTER_TO_INT (raw_id);
}

static enum CRStatus
set_prop_padding_x_from_value (CRStyle * a_style,
                               CRTerm * a_value, enum CRDirection a_dir)
{
        enum CRStatus status = CR_OK;
        CRNum *num_val = NULL;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        if (a_value->type != TERM_NUMBER && a_value->type != TERM_IDENT)
                return CR_BAD_PARAM_ERROR;

        switch (a_dir) {
        case DIR_TOP:
                num_val = &a_style->num_props[NUM_PROP_PADDING_TOP].sv;
                break;

        case DIR_RIGHT:
                num_val = &a_style->num_props[NUM_PROP_PADDING_RIGHT].sv;
                break;

        case DIR_BOTTOM:
                num_val = &a_style->num_props[NUM_PROP_PADDING_BOTTOM].sv;
                break;

        case DIR_LEFT:
                num_val = &a_style->num_props[NUM_PROP_PADDING_LEFT].sv;
                break;

        default:
                return CR_BAD_PARAM_ERROR;
        }

        if (a_value->type == TERM_IDENT) {
                if (a_value->content.str
                    && a_value->content.str->stryng
		    && a_value->content.str->stryng->str
                    && !strncmp ((const char *) "inherit",
                                 a_value->content.str->stryng->str,
                                 sizeof ("inherit")-1)) {
			status = cr_num_set (num_val, 0.0, NUM_INHERIT);
                        return CR_OK;
                } else
                        return CR_UNKNOWN_TYPE_ERROR;
        }

        g_return_val_if_fail (a_value->type == TERM_NUMBER
                              && a_value->content.num, CR_UNKNOWN_TYPE_ERROR);

        switch (a_value->content.num->type) {
        case NUM_LENGTH_EM:
        case NUM_LENGTH_EX:
        case NUM_LENGTH_PX:
        case NUM_LENGTH_IN:
        case NUM_LENGTH_CM:
        case NUM_LENGTH_MM:
        case NUM_LENGTH_PT:
        case NUM_LENGTH_PC:
        case NUM_PERCENTAGE:
                status = cr_num_copy (num_val, a_value->content.num);
                break;
        default:
                status = CR_UNKNOWN_TYPE_ERROR;
                break;
        }

        return status;
}

static enum CRStatus
set_prop_border_x_width_from_value (CRStyle * a_style,
                                    CRTerm * a_value, 
                                    enum CRDirection a_dir)
{
        enum CRStatus status = CR_OK;
        CRNum *num_val = NULL;

        g_return_val_if_fail (a_value && a_style, CR_BAD_PARAM_ERROR);

        switch (a_dir) {
        case DIR_TOP:
                num_val = &a_style->num_props[NUM_PROP_BORDER_TOP].sv;
                break;

        case DIR_RIGHT:
                num_val = &a_style->num_props[NUM_PROP_BORDER_RIGHT].sv;
                break;

        case DIR_BOTTOM:
                num_val = &a_style->num_props[NUM_PROP_BORDER_BOTTOM].sv;
                break;

        case DIR_LEFT:
                num_val = &a_style->num_props[NUM_PROP_BORDER_LEFT].sv;
                break;

        default:
                return CR_BAD_PARAM_ERROR;
                break;
        }

        if (a_value->type == TERM_IDENT) {
                if (a_value->content.str 
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str) {
                        if (!strncmp ("thin",
                                      a_value->content.str->stryng->str,
                                      sizeof ("thin")-1)) {
                                cr_num_set (num_val, BORDER_THIN,
                                            NUM_LENGTH_PX);
                        } else if (!strncmp 
                                   ("medium",
                                    a_value->content.str->stryng->str,
                                             sizeof ("medium")-1)) {
                                cr_num_set (num_val, BORDER_MEDIUM,
                                            NUM_LENGTH_PX);
                        } else if (!strncmp ("thick",
                                             a_value->content.str->stryng->str,
                                             sizeof ("thick")-1)) {
                                cr_num_set (num_val, BORDER_THICK,
                                            NUM_LENGTH_PX);
                        } else {
                                return CR_UNKNOWN_TYPE_ERROR;
                        }
                }
        } else if (a_value->type == TERM_NUMBER) {
                if (a_value->content.num) {
                        cr_num_copy (num_val, a_value->content.num);
                }
        } else if (a_value->type != TERM_NUMBER
                   || a_value->content.num == NULL) {
                return CR_UNKNOWN_TYPE_ERROR;
        }

        return status;
}

static enum CRStatus
set_prop_border_width_from_value (CRStyle *a_style,
                                  CRTerm *a_value)
{
        CRTerm *cur_term = NULL ;
        int dir;

        g_return_val_if_fail (a_style && a_value,
                              CR_BAD_PARAM_ERROR) ;
        cur_term = a_value ;

        if (!cur_term)
                return CR_ERROR ;

        for (dir = (int) DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
                 enum CRDirection direction = (enum CRDirection)dir;
                 set_prop_border_x_width_from_value (a_style,
                                                    cur_term,
                                                    direction) ;
        }

        cur_term = cur_term->next ;
        if (!cur_term)
                return CR_OK ;
        set_prop_border_x_width_from_value (a_style, cur_term,
                                            DIR_RIGHT) ;
        set_prop_border_x_width_from_value (a_style, cur_term,
                                            DIR_LEFT) ;

        cur_term = cur_term->next ;
        if (!cur_term)
                return CR_OK ;
        set_prop_border_x_width_from_value (a_style, cur_term,
                                            DIR_BOTTOM) ;

        cur_term = cur_term->next ;
        if (!cur_term)
                return CR_OK ;
        set_prop_border_x_width_from_value (a_style, cur_term,
                                            DIR_LEFT) ;

        return CR_OK ;
}

static enum CRStatus
set_prop_border_x_style_from_value (CRStyle * a_style,
                                    CRTerm * a_value, enum CRDirection a_dir)
{
        enum CRStatus status = CR_OK;
        enum CRBorderStyle *border_style_ptr = NULL;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_dir) {
        case DIR_TOP:
                border_style_ptr = &a_style->
                        border_style_props[BORDER_STYLE_PROP_TOP];
                break;

        case DIR_RIGHT:
                border_style_ptr =
                        &a_style->border_style_props[BORDER_STYLE_PROP_RIGHT];
                break;

        case DIR_BOTTOM:
                border_style_ptr = &a_style->
                        border_style_props[BORDER_STYLE_PROP_BOTTOM];
                break;

        case DIR_LEFT:
                border_style_ptr = &a_style->
                        border_style_props[BORDER_STYLE_PROP_LEFT];
                break;

        default:
                break;
        }

        if (a_value->type != TERM_IDENT || !a_value->content.str) {
                return CR_UNKNOWN_TYPE_ERROR;
        }

        if (!strncmp ("none", 
                      a_value->content.str->stryng->str, 
                      sizeof ("none")-1)) {
                *border_style_ptr = BORDER_STYLE_NONE;
        } else if (!strncmp ("hidden",
                             a_value->content.str->stryng->str, 
                             sizeof ("hidden")-1)) {
                *border_style_ptr = BORDER_STYLE_HIDDEN;
        } else if (!strncmp ("dotted",
                             a_value->content.str->stryng->str, 
                             sizeof ("dotted")-1)) {
                *border_style_ptr = BORDER_STYLE_DOTTED;
        } else if (!strncmp ("dashed",
                             a_value->content.str->stryng->str, sizeof ("dashed")-1)) {
                *border_style_ptr = BORDER_STYLE_DASHED;
        } else if (!strncmp ("solid",
                             a_value->content.str->stryng->str, sizeof ("solid")-1)) {
                *border_style_ptr = BORDER_STYLE_SOLID;
        } else if (!strncmp ("double",
                             a_value->content.str->stryng->str, sizeof ("double")-1)) {
                *border_style_ptr = BORDER_STYLE_DOUBLE;
        } else if (!strncmp ("groove",
                             a_value->content.str->stryng->str, sizeof ("groove")-1)) {
                *border_style_ptr = BORDER_STYLE_GROOVE;
        } else if (!strncmp ("ridge",
                             a_value->content.str->stryng->str, 
                             sizeof ("ridge")-1)) {
                *border_style_ptr = BORDER_STYLE_RIDGE;
        } else if (!strncmp ("inset",
                             a_value->content.str->stryng->str, 
                             sizeof ("inset")-1)) {
                *border_style_ptr = BORDER_STYLE_INSET;
        } else if (!strncmp ("outset",
                             a_value->content.str->stryng->str, 
                             sizeof ("outset")-1)) {
                *border_style_ptr = BORDER_STYLE_OUTSET;
        } else if (!strncmp ("inherit",
                             a_value->content.str->stryng->str, 
                             sizeof ("inherit")-1)) {
		*border_style_ptr = BORDER_STYLE_INHERIT;
        } else {
                status = CR_UNKNOWN_TYPE_ERROR;
        }

        return status;
}

static enum CRStatus
set_prop_border_style_from_value (CRStyle *a_style,
                                  CRTerm *a_value)
{
        CRTerm *cur_term = NULL ;
        int dir;

        g_return_val_if_fail (a_style && a_value, 
                              CR_BAD_PARAM_ERROR) ;

        cur_term = a_value ;
        if (!cur_term || cur_term->type != TERM_IDENT) {
                return CR_ERROR ;
        }
        
        for (dir = (int)DIR_TOP ; dir < (int)NB_DIRS ; dir++) {
                enum CRDirection direction = (enum CRDirection)dir;
                set_prop_border_x_style_from_value (a_style, 
                                                    cur_term,
                                                    direction) ;
        }
        
        cur_term = cur_term->next ;
        if (!cur_term || cur_term->type != TERM_IDENT) {
                return CR_OK ;
        }
        
        set_prop_border_x_style_from_value (a_style, cur_term, 
                                            DIR_RIGHT) ;
        set_prop_border_x_style_from_value (a_style, cur_term, 
                                            DIR_LEFT) ;

        cur_term = cur_term->next ;
        if (!cur_term || cur_term->type != TERM_IDENT) {
                return CR_OK ;
        }        
        set_prop_border_x_style_from_value (a_style, cur_term,
                                           DIR_BOTTOM) ;
        
        cur_term = cur_term->next ;
        if (!cur_term || cur_term->type != TERM_IDENT) {
                return CR_OK ;
        }
        set_prop_border_x_style_from_value (a_style, cur_term,
                                            DIR_LEFT) ;
        return CR_OK ;
}

static enum CRStatus
set_prop_margin_x_from_value (CRStyle * a_style, CRTerm * a_value,
                              enum CRDirection a_dir)
{
        enum CRStatus status = CR_OK;
        CRNum *num_val = NULL;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_dir) {
        case DIR_TOP:
                num_val = &a_style->num_props[NUM_PROP_MARGIN_TOP].sv;
                break;

        case DIR_RIGHT:
                num_val = &a_style->num_props[NUM_PROP_MARGIN_RIGHT].sv;
                break;

        case DIR_BOTTOM:
                num_val = &a_style->num_props[NUM_PROP_MARGIN_BOTTOM].sv;
                break;

        case DIR_LEFT:
                num_val = &a_style->num_props[NUM_PROP_MARGIN_LEFT].sv;
                break;

        default:
                break;
        }

        switch (a_value->type) {
        case TERM_IDENT:
                if (a_value->content.str
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str
                    && !strcmp (a_value->content.str->stryng->str,
                                 "inherit")) {
			status = cr_num_set (num_val, 0.0, NUM_INHERIT);
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && !strcmp (a_value->content.str->stryng->str,
                                        "auto")) {
                        status = cr_num_set (num_val, 0.0, NUM_AUTO);
                } else {
                        status = CR_UNKNOWN_TYPE_ERROR;
                }
                break ;

        case TERM_NUMBER:
                status = cr_num_copy (num_val, a_value->content.num);
                break;

        default:
                status = CR_UNKNOWN_TYPE_ERROR;
                break;
        }

        return status;
}

struct CRPropDisplayValPair {
        const gchar *prop_name;
        enum CRDisplayType type;
};

static enum CRStatus
set_prop_display_from_value (CRStyle * a_style, CRTerm * a_value)
{
        static const struct CRPropDisplayValPair disp_vals_map[] = {
                {"none", DISPLAY_NONE},
                {"inline", DISPLAY_INLINE},
                {"block", DISPLAY_BLOCK},
                {"run-in", DISPLAY_RUN_IN},
                {"compact", DISPLAY_COMPACT},
                {"marker", DISPLAY_MARKER},
                {"table", DISPLAY_TABLE},
                {"inline-table", DISPLAY_INLINE_TABLE},
                {"table-row-group", DISPLAY_TABLE_ROW_GROUP},
                {"table-header-group", DISPLAY_TABLE_HEADER_GROUP},
                {"table-footer-group", DISPLAY_TABLE_FOOTER_GROUP},
                {"table-row", DISPLAY_TABLE_ROW},
                {"table-column-group", DISPLAY_TABLE_COLUMN_GROUP},
                {"table-column", DISPLAY_TABLE_COLUMN},
                {"table-cell", DISPLAY_TABLE_CELL},
                {"table-caption", DISPLAY_TABLE_CAPTION},
                {"inherit", DISPLAY_INHERIT},
                {NULL, DISPLAY_NONE}
        };

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_value->type) {
        case TERM_IDENT:
                {
                        int i = 0;

                        if (!a_value->content.str
                            || !a_value->content.str->stryng
                            || !a_value->content.str->stryng->str)
                                break;

                        for (i = 0; disp_vals_map[i].prop_name; i++) {
                                if (!strncmp 
                                    (disp_vals_map[i].prop_name,
                                     a_value->content.str->stryng->str,
                                     strlen (disp_vals_map[i].prop_name))) {
                                        a_style->display =
                                                disp_vals_map[i].type;
                                        break;
                                }
                        }
                }
                break;

        default:
                break;
        }

        return CR_OK;
}

struct CRPropPositionValPair {
        const gchar *name;
        enum CRPositionType type;
};

static enum CRStatus
set_prop_position_from_value (CRStyle * a_style, CRTerm * a_value)
{
        enum CRStatus status = CR_UNKNOWN_PROP_VAL_ERROR;
        static const struct CRPropPositionValPair position_vals_map[] = {
                {"static", POSITION_STATIC},
                {"relative", POSITION_RELATIVE},
                {"absolute", POSITION_ABSOLUTE},
                {"fixed", POSITION_FIXED},
                {"inherit", POSITION_INHERIT},
                {NULL, POSITION_STATIC}
                /*must alwas be the last one */
        };

        g_return_val_if_fail (a_value, CR_BAD_PARAM_ERROR);

        switch (a_value->type) {
        case TERM_IDENT:
                {
                        int i = 0;

                        if (!a_value->content.str
                            || !a_value->content.str->stryng
                            || !a_value->content.str->stryng->str)
                                break;

                        for (i = 0; position_vals_map[i].name; i++) {
                                if (!strncmp (position_vals_map[i].name,
                                              a_value->content.str->stryng->str,
                                              strlen (position_vals_map[i].
                                                      name))) {
                                        a_style->position =
                                                position_vals_map[i].type;
                                        status = CR_OK;
                                        break;
                                }
                        }
                }
                break;

        default:
                break;
        }

        return status;
}

static enum CRStatus
set_prop_x_from_value (CRStyle * a_style, CRTerm * a_value,
                       enum CRDirection a_dir)
{
        CRNum *box_offset = NULL;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        if (!(a_value->type == TERM_NUMBER)
            && !(a_value->type == TERM_IDENT)) {
                return CR_UNKNOWN_PROP_VAL_ERROR;
        }

        switch (a_dir) {
        case DIR_TOP:
                box_offset = &a_style->num_props[NUM_PROP_TOP].sv;
                break;

        case DIR_RIGHT:
                box_offset = &a_style->num_props[NUM_PROP_RIGHT].sv;
                break;

        case DIR_BOTTOM:
                box_offset = &a_style->num_props[NUM_PROP_BOTTOM].sv;
                break;
        case DIR_LEFT:
                box_offset = &a_style->num_props[NUM_PROP_LEFT].sv;
                break;

        default:
                break;
        }

        box_offset->type = NUM_AUTO;

        if (a_value->type == TERM_NUMBER && a_value->content.num) {
                cr_num_copy (box_offset, a_value->content.num);
        } else if (a_value->type == TERM_IDENT
                   && a_value->content.str
                   && a_value->content.str->stryng
                   && a_value->content.str->stryng->str) {
                if (!strncmp ("inherit",
                              a_value->content.str->stryng->str,
                              sizeof ("inherit")-1)) {
                        cr_num_set (box_offset, 0.0, NUM_INHERIT);
                } else if (!strncmp ("auto",
                                     a_value->content.str->stryng->str,
                                     sizeof ("auto")-1)) {
                        box_offset->type = NUM_AUTO;
                }
        }

        return CR_OK;
}

static enum CRStatus
set_prop_float (CRStyle * a_style, CRTerm * a_value)
{
        g_return_val_if_fail (a_style && a_value, 
                              CR_BAD_PARAM_ERROR);

        /*the default float type as specified by the css2 spec */
        a_style->float_type = FLOAT_NONE;

        if (a_value->type != TERM_IDENT 
            || !a_value->content.str
            || !a_value->content.str->stryng
            || !a_value->content.str->stryng->str) { 
                /*unknown type, the float type is set to it's default value */
                return CR_OK;
        }

        if (!strncmp ("none", 
                      a_value->content.str->stryng->str, 
                      sizeof ("none")-1)) {
                a_style->float_type = FLOAT_NONE;
        } else if (!strncmp ("left",
                             a_value->content.str->stryng->str, 
                             sizeof ("left")-1)) {
                a_style->float_type = FLOAT_LEFT;
        } else if (!strncmp ("right",
                             a_value->content.str->stryng->str, 
                             sizeof ("right")-1)) {
                a_style->float_type = FLOAT_RIGHT;
        } else if (!strncmp ("inherit",
                             a_value->content.str->stryng->str, 
                             sizeof ("inherit")-1)) {
		a_style->float_type = FLOAT_INHERIT;
        }
        return CR_OK;
}

static enum CRStatus
set_prop_width (CRStyle * a_style, CRTerm * a_value)
{
	CRNum *width = NULL;
        g_return_val_if_fail (a_style 
                              && a_value, 
                              CR_BAD_PARAM_ERROR);

	width = &a_style->num_props[NUM_PROP_WIDTH].sv;
	cr_num_set (width, 0.0, NUM_AUTO);

        if (a_value->type == TERM_IDENT) {
                if (a_value->content.str 
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str) {
                        if (!strncmp ("auto",
                                      a_value->content.str->stryng->str,
                                      sizeof ("auto")-1)) {
				cr_num_set (width, 0.0, NUM_AUTO);
                        } else if (!strncmp ("inherit",
                                             a_value->content.str->stryng->str,
                                             sizeof ("inherit")-1)) {
				cr_num_set (width, 0.0, NUM_INHERIT);
                        }
                }
        } else if (a_value->type == TERM_NUMBER) {
                if (a_value->content.num) {
                        cr_num_copy (&a_style->num_props[NUM_PROP_WIDTH].sv,
                                     a_value->content.num);
                }
        }
        return CR_OK;
}

static enum CRStatus 
set_prop_color (CRStyle * a_style, CRTerm * a_value)
{
	enum CRStatus status = CR_OK;
	CRRgb *a_rgb = &a_style->rgb_props[RGB_PROP_COLOR].sv;

	g_return_val_if_fail (a_style 
                              && a_value, CR_BAD_PARAM_ERROR);

	status = cr_rgb_set_from_term (a_rgb, a_value);

	return status;
}

static enum CRStatus
set_prop_background_color (CRStyle * a_style, CRTerm * a_value)
{
	enum CRStatus status = CR_OK;
	CRRgb *rgb = &a_style->rgb_props[RGB_PROP_BACKGROUND_COLOR].sv;

	g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

	status = cr_rgb_set_from_term (rgb, a_value);
	return status;
}

/**
 *Sets border-top-color, border-right-color,
 *border-bottom-color or border-left-color properties
 *in the style structure. The value is taken from a
 *css2 term of type IDENT or RGB.
 *@param a_style the style structure to set.
 *@param a_value the css2 term to take the color information from.
 *@param a_dir the direction (TOP, LEFT, RIGHT, or BOTTOM).
 *@return CR_OK upon successful completion, an error code otherwise.
 */
static enum CRStatus
set_prop_border_x_color_from_value (CRStyle * a_style, CRTerm * a_value,
                                    enum CRDirection a_dir)
{
        CRRgb *rgb_color = NULL;
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_dir) {
        case DIR_TOP:
                rgb_color = &a_style->rgb_props[RGB_PROP_BORDER_TOP_COLOR].sv;
                break;

        case DIR_RIGHT:
                rgb_color =
                        &a_style->rgb_props[RGB_PROP_BORDER_RIGHT_COLOR].sv;
                break;

        case DIR_BOTTOM:
                rgb_color =
                        &a_style->rgb_props[RGB_PROP_BORDER_BOTTOM_COLOR].sv;
                break;

        case DIR_LEFT:
                rgb_color =
                        &a_style->rgb_props[RGB_PROP_BORDER_LEFT_COLOR].sv;
                break;

        default:
                cr_utils_trace_info ("unknown DIR type");
                return CR_BAD_PARAM_ERROR;
        }

        status = CR_UNKNOWN_PROP_VAL_ERROR;

        if (a_value->type == TERM_IDENT) {
                if (a_value->content.str 
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str) {
                        status = cr_rgb_set_from_name
                                (rgb_color, 
                                 (const guchar *) a_value->content.str->stryng->str);

                }
                if (status != CR_OK) {
                        cr_rgb_set_from_name (rgb_color, (const guchar *) "black");
                }
        } else if (a_value->type == TERM_RGB) {
                if (a_value->content.rgb) {
                        status = cr_rgb_set_from_rgb
                                (rgb_color, a_value->content.rgb);
                }
        }
        return status;
}

static enum CRStatus
set_prop_border_x_from_value (CRStyle * a_style, CRTerm * a_value,
                              enum CRDirection a_dir)
{
        CRTerm *cur_term = NULL;

        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        for (cur_term = a_value; 
             cur_term; 
             cur_term = cur_term->next) {
                status = set_prop_border_x_width_from_value (a_style,
                                                             cur_term, a_dir);

                if (status != CR_OK) {
                        status = set_prop_border_x_style_from_value
                                (a_style, cur_term, a_dir);
                }
                if (status != CR_OK) {
                        status = set_prop_border_x_color_from_value
                                (a_style, cur_term, a_dir);
                }
        }
        return CR_OK;
}

static enum CRStatus
set_prop_border_from_value (CRStyle * a_style, CRTerm * a_value)
{
        int dir;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        for (dir = 0; dir < (int)NB_DIRS; dir++) {
                set_prop_border_x_from_value (a_style, 
                                              a_value, 
                                              (enum CRDirection)dir);
        }

        return CR_OK;
}

static enum CRStatus
set_prop_padding_from_value (CRStyle * a_style, CRTerm * a_value)
{
        CRTerm *cur_term = NULL;
        int dir;
        enum CRStatus status = CR_OK;
        
        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        cur_term = a_value;

        /*filter the eventual non NUMBER terms some user can have written here*/
        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_ERROR ;

        for (dir = 0; dir < (int)NB_DIRS; dir++) {
                set_prop_padding_x_from_value (a_style,
				            cur_term, (enum CRDirection)dir);
        }
        cur_term = cur_term->next;

        /*filter non NUMBER terms that some users can have written here...*/
        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        /*the user can have just written padding: 1px*/
        if (!cur_term)
                return CR_OK;

        set_prop_padding_x_from_value (a_style, cur_term, DIR_RIGHT);
        set_prop_padding_x_from_value (a_style, cur_term, DIR_LEFT);

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_OK;

        set_prop_padding_x_from_value (a_style, cur_term, DIR_BOTTOM);

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_OK;
        status = set_prop_padding_x_from_value (a_style, cur_term, DIR_LEFT);
        return status;
}

static enum CRStatus
set_prop_margin_from_value (CRStyle * a_style, CRTerm * a_value)
{
        CRTerm *cur_term = NULL;
        int dir;
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        cur_term = a_value;

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }

        if (!cur_term)
                return CR_OK;

        for (dir = 0; dir < (int)NB_DIRS; dir++) {
                set_prop_margin_x_from_value(a_style,
				        cur_term, (enum CRDirection)dir);
        }
        cur_term = cur_term->next;

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_OK;

        set_prop_margin_x_from_value (a_style, cur_term, DIR_RIGHT);
        set_prop_margin_x_from_value (a_style, cur_term, DIR_LEFT);

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_OK;

        set_prop_margin_x_from_value (a_style, cur_term, DIR_BOTTOM);

        while (cur_term && cur_term->type != TERM_NUMBER) {
                cur_term = cur_term->next;
        }
        if (!cur_term)
                return CR_OK;

        status = set_prop_margin_x_from_value (a_style, cur_term, DIR_LEFT);        

        return status;
}

static enum CRStatus
set_prop_font_family_from_value (CRStyle * a_style, CRTerm * a_value)
{
        CRTerm *cur_term = NULL;
        CRFontFamily *font_family = NULL,
                *cur_ff = NULL,
                *cur_ff2 = NULL;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

	if (a_value->type == TERM_IDENT &&
	    a_value->content.str &&
	    a_value->content.str->stryng &&
	    a_value->content.str->stryng->str &&
	    !strcmp ("inherit", a_value->content.str->stryng->str))
	{
		font_family = cr_font_family_new (FONT_FAMILY_INHERIT, NULL);
		goto out;
	}

        for (cur_term = a_value; cur_term; cur_term = cur_term->next) {
                switch (cur_term->type) {
                case TERM_IDENT:
                        {
                                enum CRFontFamilyType font_type;

                                if (cur_term->content.str
                                    && cur_term->content.str->stryng
                                    && cur_term->content.str->stryng->str
                                    && !strcmp 
                                    (cur_term->content.str->stryng->str,
                                     "sans-serif")) {
                                        font_type = FONT_FAMILY_SANS_SERIF;
                                } else if (cur_term->content.str
                                           && cur_term->content.str->stryng
                                           && cur_term->content.str->stryng->str
                                           && !strcmp 
                                           (cur_term->content.str->stryng->str, 
                                            "serif")) {
                                        font_type = FONT_FAMILY_SERIF;
                                } else if (cur_term->content.str
                                           && cur_term->content.str->stryng
                                           && cur_term->content.str->stryng->str
                                           && !strcmp (cur_term->content.str->stryng->str, 
                                                       "cursive")) {
                                        font_type = FONT_FAMILY_CURSIVE;
                                } else if (cur_term->content.str
                                           && cur_term->content.str->stryng
                                           && cur_term->content.str->stryng->str
                                           && !strcmp (cur_term->content.str->stryng->str,
                                                       "fantasy")) {
                                        font_type = FONT_FAMILY_FANTASY;
                                } else if (cur_term->content.str
                                           && cur_term->content.str->stryng
                                           && cur_term->content.str->stryng->str
                                           && !strcmp (cur_term->content.str->stryng->str, 
                                                       "monospace")) {
                                        font_type = FONT_FAMILY_MONOSPACE;
                                } else {
                                        /*
                                         *unknown property value.
                                         *ignore it.
                                         */
                                        continue;
                                }

                                cur_ff = cr_font_family_new (font_type, NULL);
                        }
                        break;

                case TERM_STRING:
                        {
                                if (cur_term->content.str
                                    && cur_term->content.str->stryng
                                    && cur_term->content.str->stryng->str) {
                                        cur_ff = cr_font_family_new
                                                (FONT_FAMILY_NON_GENERIC,
                                                 (guchar *) cur_term->content.str->stryng->str);
                                }
                        }
                        break;

                default:
                        break;
                }

                cur_ff2 = cr_font_family_append (font_family, cur_ff);
                if (cur_ff2) {
                        font_family = cur_ff2;
                }
        }

 out:
        if (font_family) {
                if (a_style->font_family) {
                        cr_font_family_destroy (a_style->font_family);
                        a_style->font_family = NULL ;
                }
                a_style->font_family = font_family;
                font_family = NULL ;
        }

        return CR_OK;
}

static enum CRStatus
init_style_font_size_field (CRStyle * a_style)
{
        g_return_val_if_fail (a_style, CR_BAD_PARAM_ERROR);

        memset (&a_style->font_size, 0, 
               sizeof (CRFontSizeVal)) ;
        /*
        if (!a_style->font_size) {
                a_style->font_size = cr_font_size_new ();
                if (!a_style->font_size) {
                        return CR_INSTANCIATION_FAILED_ERROR;
                }
        } else {
                cr_font_size_clear (a_style->font_size);
        }
        */
        return CR_OK;
}

static enum CRStatus
set_prop_font_size_from_value (CRStyle * a_style, CRTerm * a_value)
{
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_value->type) {
        case TERM_IDENT:
                if (a_value->content.str
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str
                    && !strcmp (a_value->content.str->stryng->str,
                                "xx-small")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_XX_SMALL;

                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "x-small")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_X_SMALL;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "small")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_SMALL;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, "medium")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_MEDIUM;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "large")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_LARGE;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "x-large")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_X_LARGE;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "xx-large")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type =
                                PREDEFINED_ABSOLUTE_FONT_SIZE;
                        a_style->font_size.sv.value.predefined =
                                FONT_SIZE_XX_LARGE;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "larger")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type = RELATIVE_FONT_SIZE;
                        a_style->font_size.sv.value.relative = FONT_SIZE_LARGER;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, 
                                       "smaller")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type = RELATIVE_FONT_SIZE;
                        a_style->font_size.sv.value.relative =
                                FONT_SIZE_SMALLER;
                } else if (a_value->content.str
                           && a_value->content.str->stryng
                           && a_value->content.str->stryng->str
                           && !strcmp (a_value->content.str->stryng->str, "inherit")) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);
			a_style->font_size.sv.type = INHERITED_FONT_SIZE;

                } else {
                        cr_utils_trace_info ("Unknown value of font-size") ;
                        status = init_style_font_size_field (a_style);
                        return CR_UNKNOWN_PROP_VAL_ERROR;
                }
                break;

        case TERM_NUMBER:
                if (a_value->content.num) {
                        status = init_style_font_size_field (a_style);
                        g_return_val_if_fail (status == CR_OK, status);

                        a_style->font_size.sv.type = ABSOLUTE_FONT_SIZE;
                        cr_num_copy (&a_style->font_size.sv.value.absolute,
                                     a_value->content.num) ;
                }
                break;

        default:
                status = init_style_font_size_field (a_style);
                return CR_UNKNOWN_PROP_VAL_ERROR;
        }
        return CR_OK;
}

static enum CRStatus
set_prop_font_style_from_value (CRStyle * a_style, CRTerm * a_value)
{
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_value->type) {
        case TERM_IDENT:
                if (a_value->content.str 
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str) {
                        if (!strcmp (a_value->content.str->stryng->str, "normal")) {
                                a_style->font_style = FONT_STYLE_NORMAL;
                        } else if (!strcmp
                                   (a_value->content.str->stryng->str,
				    "italic")) {
                                a_style->font_style = FONT_STYLE_ITALIC;
                        } else if (!strcmp
                                   (a_value->content.str->stryng->str,
				    "oblique")) {
                                a_style->font_style = FONT_STYLE_OBLIQUE;
                        } else if (!strcmp
                                   (a_value->content.str->stryng->str,
				    "inherit")) {
				a_style->font_style = FONT_STYLE_INHERIT;
                        } else {
                                status = CR_UNKNOWN_PROP_VAL_ERROR;
                        }
                }
                break;

        default:
                status = CR_UNKNOWN_PROP_VAL_ERROR;
                break;
        }

        return status;
}

static enum CRStatus
set_prop_font_weight_from_value (CRStyle * a_style, CRTerm * a_value)
{
        enum CRStatus status = CR_OK;

        g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

        switch (a_value->type) {
        case TERM_IDENT:
                if (a_value->content.str 
                    && a_value->content.str->stryng
                    && a_value->content.str->stryng->str) {
                        if (!strcmp (a_value->content.str->stryng->str, 
                                     "normal")) {
                                a_style->font_weight = FONT_WEIGHT_NORMAL;
                        } else if (!strcmp (a_value->content.str->stryng->str,
                                            "bold")) {
                                a_style->font_weight = FONT_WEIGHT_BOLD;
                        } else if (!strcmp (a_value->content.str->stryng->str,
                                            "bolder")) {
                                a_style->font_weight = FONT_WEIGHT_BOLDER;
                        } else if (!strcmp (a_value->content.str->stryng->str,
                                            "lighter")) {
                                a_style->font_weight = FONT_WEIGHT_LIGHTER;
			} else if (!strcmp (a_value->content.str->stryng->str,
                                            "inherit")) {
                                a_style->font_weight = FONT_WEIGHT_INHERIT;

                        } else {
                                status = CR_UNKNOWN_PROP_VAL_ERROR;
                        }

                }
                break;

        case TERM_NUMBER:
                if (a_value->content.num
                    && (a_value->content.num->type == NUM_GENERIC
                        || a_value->content.num->type == NUM_AUTO)) {
                        if (a_value->content.num->val <= 150) {
                                a_style->font_weight = FONT_WEIGHT_100;
                        } else if (a_value->content.num->val <= 250) {
                                a_style->font_weight = FONT_WEIGHT_200;
                        } else if (a_value->content.num->val <= 350) {
                                a_style->font_weight = FONT_WEIGHT_300;
                        } else if (a_value->content.num->val <= 450) {
                                a_style->font_weight = FONT_WEIGHT_400;
                        } else if (a_value->content.num->val <= 550) {
                                a_style->font_weight = FONT_WEIGHT_500;
                        } else if (a_value->content.num->val <= 650) {
                                a_style->font_weight = FONT_WEIGHT_600;
                        } else if (a_value->content.num->val <= 750) {
                                a_style->font_weight = FONT_WEIGHT_700;
                        } else if (a_value->content.num->val <= 850) {
                                a_style->font_weight = FONT_WEIGHT_800;
                        } else {
                                a_style->font_weight = FONT_WEIGHT_900;
                        }
                }
                break;

        default:
                status = CR_UNKNOWN_PROP_VAL_ERROR;
                break;
        }

        return status;
}

static enum CRStatus
set_prop_white_space_from_value (CRStyle * a_style, CRTerm * a_value)
{
	enum CRStatus status = CR_OK;

	g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);

	switch (a_value->type) {
	case TERM_IDENT:
		if (a_value->content.str && a_value->content.str->stryng) {
			if (!strcmp (a_value->content.str->stryng->str, "normal")) {
				a_style->white_space = WHITE_SPACE_NORMAL;
			} else if (!strcmp (a_value->content.str->stryng->str, 
                                            "pre")) {
				a_style->white_space = WHITE_SPACE_PRE;
			} else if (!strcmp (a_value->content.str->stryng->str,
                                            "nowrap")) {
				a_style->white_space = WHITE_SPACE_NOWRAP;
			} else if (!strcmp (a_value->content.str->stryng->str,
                                            "inherit")) {
				a_style->white_space = WHITE_SPACE_INHERIT;
			} else {
				status = CR_UNKNOWN_PROP_VAL_ERROR;
			}
		}
		break;
	default:
		status = CR_UNKNOWN_PROP_VAL_ERROR;
		break;
	}

	return status;
}

/******************
 *Public methods
 ******************/

/**
 *Default constructor of #CRStyle.
 *@param a_set_props_to_initial_values if TRUE, the style properties
 *will be set to the default values. Only the style properties of the
 *root box should be set to their initial values.
 *Otherwise, the style values are set to their default value.
 *Read the CSS2 spec, chapters 6.1.1 to 6.2.
 */
CRStyle *
cr_style_new (gboolean a_set_props_to_initial_values)
{
        CRStyle *result = NULL;

        result = (CRStyle *) g_try_malloc (sizeof (CRStyle));
        if (!result) {
                cr_utils_trace_info ("Out of memory");
                return NULL;
        }
        memset (result, 0, sizeof (CRStyle));
        gv_prop_hash_ref_count++;

        if (a_set_props_to_initial_values == TRUE) {
                cr_style_set_props_to_initial_values (result);
        } else {
                cr_style_set_props_to_default_values (result);
        }

        return result;
}

/**
 *Sets the style properties to their default values according to the css2 spec
 * i.e inherit if the property is inherited, its initial value otherwise.
 *@param a_this the current instance of #CRStyle.
 *@return CR_OK upon successful completion, an error code otherwise.
 */
enum CRStatus 
cr_style_set_props_to_default_values (CRStyle * a_this)
{
	glong i = 0;

	g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
	
	for (i = 0; i < NB_NUM_PROPS; i++)
	{
		switch (i)
		{
		case NUM_PROP_WIDTH:
		case NUM_PROP_TOP:
		case NUM_PROP_RIGHT:
		case NUM_PROP_BOTTOM:
		case NUM_PROP_LEFT:
			cr_num_set (&a_this->num_props[i].sv, 0, NUM_AUTO);
			break;

		case NUM_PROP_PADDING_TOP:
		case NUM_PROP_PADDING_RIGHT:
		case NUM_PROP_PADDING_BOTTOM:
		case NUM_PROP_PADDING_LEFT:
		case NUM_PROP_BORDER_TOP:
		case NUM_PROP_BORDER_RIGHT:
		case NUM_PROP_BORDER_BOTTOM:
		case NUM_PROP_BORDER_LEFT:
		case NUM_PROP_MARGIN_TOP:
		case NUM_PROP_MARGIN_RIGHT:
		case NUM_PROP_MARGIN_BOTTOM:
		case NUM_PROP_MARGIN_LEFT:
			cr_num_set (&a_this->num_props[i].sv,
				    0, NUM_LENGTH_PX);
			break;

		default:
			cr_utils_trace_info ("Unknown property");
			break;
		}
	}

	for (i = 0; i < NB_RGB_PROPS; i++) {
                
		switch (i) {
			/*default foreground color is black */
		case RGB_PROP_COLOR:
			/*
                         *REVIEW: color is inherited and the default value is
			 *ua dependent.
                         */
			cr_rgb_set_to_inherit (&a_this->rgb_props[i].sv,
                                               TRUE) ;
			break;

			/*default background color is white */
		case RGB_PROP_BACKGROUND_COLOR:
			/* TODO: the default value should be transparent */
			cr_rgb_set (&a_this->rgb_props[i].sv,
				    255, 255, 255, FALSE);
                        cr_rgb_set_to_transparent (&a_this->rgb_props[i].sv,
                                                   TRUE) ;
			break;

		default:
			/* 
                         *TODO: for BORDER_COLOR the initial value should
			 * be the same as COLOR 
                         */
			cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0,
				    FALSE);
			break;
		}
	}

	for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
		a_this->border_style_props[i] = BORDER_STYLE_NONE;
	}

	a_this->display = DISPLAY_INLINE;
	a_this->position = POSITION_STATIC;
	a_this->float_type = FLOAT_NONE;
	a_this->parent_style = NULL;
	a_this->font_style = FONT_STYLE_INHERIT;
	a_this->font_variant = FONT_VARIANT_INHERIT;
	a_this->font_weight = FONT_WEIGHT_INHERIT;
	a_this->font_family = NULL;
        
        cr_font_size_set_to_inherit (&a_this->font_size.sv) ;
        cr_font_size_clear (&a_this->font_size.cv) ;
        cr_font_size_clear (&a_this->font_size.av) ;

        /* To make the inheritance resolution possible and efficient */
        a_this->inherited_props_resolved = FALSE ;
	return CR_OK;
}

/**
 *Sets the style properties to their initial value according to the css2 spec.
 *This function should be used to initialize the style of the root element
 *of an xml tree.
 *Some properties are user agent dependent like font-family, and
 *are not initialized, read the spec to make you renderer compliant.
 *@param a_this the current instance of #CRStyle.
 *@return CR_OK upon successful completion, an error code otherwise.
 */
enum CRStatus 
cr_style_set_props_to_initial_values (CRStyle *a_this)
{
        glong i = 0;

        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);

        for (i = 0; i < NB_NUM_PROPS; i++) {
                switch (i) {
                case NUM_PROP_WIDTH:
                        cr_num_set (&a_this->num_props[i].sv, 800,
                                    NUM_LENGTH_PX) ;
                        break ;
                case NUM_PROP_TOP:
                case NUM_PROP_RIGHT:
                case NUM_PROP_BOTTOM:
                case NUM_PROP_LEFT:
                        cr_num_set (&a_this->num_props[i].sv, 0, NUM_AUTO);
                        break;

                case NUM_PROP_PADDING_TOP:
                case NUM_PROP_PADDING_RIGHT:
                case NUM_PROP_PADDING_BOTTOM:
                case NUM_PROP_PADDING_LEFT:
                case NUM_PROP_BORDER_TOP:
                case NUM_PROP_BORDER_RIGHT:
                case NUM_PROP_BORDER_BOTTOM:
                case NUM_PROP_BORDER_LEFT:
                case NUM_PROP_MARGIN_TOP:
                case NUM_PROP_MARGIN_RIGHT:
                case NUM_PROP_MARGIN_BOTTOM:
                case NUM_PROP_MARGIN_LEFT:
                        cr_num_set (&a_this->num_props[i].sv,
                                    0, NUM_LENGTH_PX);
                        break;

                default:
                        cr_utils_trace_info ("Unknown property");
                        break;
                }
        }

        for (i = 0; i < NB_RGB_PROPS; i++) {

                switch (i) {
                        /*default foreground color is black */
                case RGB_PROP_COLOR:
                        cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0, FALSE);
                        break;

                        /*default background color is white */
                case RGB_PROP_BACKGROUND_COLOR:
                        cr_rgb_set (&a_this->rgb_props[i].sv,
                                    255, 255, 255, FALSE);
                        cr_rgb_set_to_transparent (&a_this->rgb_props[i].sv,
                                                   TRUE) ;                        
                        break;
                default:
                        cr_rgb_set (&a_this->rgb_props[i].sv, 0, 0, 0, FALSE);
                        break;
                }
        }

        for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
                a_this->border_style_props[i] = BORDER_STYLE_NONE;
        }

        a_this->display = DISPLAY_BLOCK;
        a_this->position = POSITION_STATIC;
        a_this->float_type = FLOAT_NONE;
        a_this->font_style = FONT_STYLE_NORMAL;
        a_this->font_variant = FONT_VARIANT_NORMAL;
        a_this->font_weight = FONT_WEIGHT_NORMAL;
        a_this->font_stretch = FONT_STRETCH_NORMAL;
	a_this->white_space = WHITE_SPACE_NORMAL;
        cr_font_size_set_predefined_absolute_font_size
                (&a_this->font_size.sv, FONT_SIZE_MEDIUM) ;
        a_this->inherited_props_resolved = FALSE ;

        return CR_OK;
}

/**
 *Resolves the inherited properties.
 *The function sets the "inherited" properties to either the value of
 *their parent properties.
 *This function is *NOT* recursive. So the inherited properties of
 *the parent style must have been resolved prior to calling this function.
 *@param a_this the instance where 
 *@return CR_OK if a root node is found and the propagation is successful,
 *an error code otherwise
 */
enum CRStatus 
cr_style_resolve_inherited_properties (CRStyle *a_this)
{
	enum CRStatus ret = CR_OK;
	glong i = 0;

	g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);
	g_return_val_if_fail (a_this->parent_style, CR_BAD_PARAM_ERROR) ;

        if (a_this->inherited_props_resolved == TRUE)
                return CR_OK ;

        for (i=0 ; i < NB_NUM_PROPS ;i++) {
                if (a_this->num_props[i].sv.type == NUM_INHERIT) {
                        cr_num_copy (&a_this->num_props[i].cv,
                                     &a_this->parent_style->num_props[i].cv);
                }
        }
	for (i=0; i < NB_RGB_PROPS; i++) {
		if (cr_rgb_is_set_to_inherit (&a_this->rgb_props[i].sv) == TRUE) {
			cr_rgb_copy (
				&a_this->rgb_props[i].cv,
				&a_this->parent_style->rgb_props[i].cv);
		}
	}
	for (i = 0; i < NB_BORDER_STYLE_PROPS; i++) {
		if (a_this->border_style_props[i] == BORDER_STYLE_INHERIT) {
			a_this->border_style_props[i] =
			  a_this->parent_style->border_style_props[i];
		}
	}

	if (a_this->display == DISPLAY_INHERIT) {
		a_this->display = a_this->parent_style->display;
	}
	if (a_this->position == POSITION_INHERIT) {
		a_this->position = a_this->parent_style->position;
	}
	if (a_this->float_type == FLOAT_INHERIT) {
		a_this->float_type = a_this->parent_style->float_type;
	}
	if (a_this->font_style == FONT_STYLE_INHERIT) {
		a_this->font_style = a_this->parent_style->font_style;
	}
	if (a_this->font_variant == FONT_VARIANT_INHERIT) {
		a_this->font_variant = a_this->parent_style->font_variant;
	}
	if (a_this->font_weight == FONT_WEIGHT_INHERIT) {
		a_this->font_weight = a_this->parent_style->font_weight;
	}
	if (a_this->font_stretch == FONT_STRETCH_INHERIT) {
		a_this->font_stretch = a_this->parent_style->font_stretch;
	}
	/*NULL is inherit marker for font_famiy*/
	if (a_this->font_family == NULL)  {
		a_this->font_family = a_this->parent_style->font_family;
	}
        if (a_this->font_size.sv.type == INHERITED_FONT_SIZE) {
                cr_font_size_copy (&a_this->font_size.cv,
                                   &a_this->parent_style->font_size.cv) ;
        }
        a_this->inherited_props_resolved = TRUE ;
	return ret;
}

/**
 *Walks through a css2 property declaration, and populated the
 *according field(s) in the #CRStyle structure.
 *If the properties or their value(s) are/is not known, 
 *sets the corresponding field(s) of #CRStyle to its/their default 
 *value(s)
 *@param a_this the instance of #CRStyle to set.
 *@param a_decl the declaration from which the #CRStyle fields are set.
 *@return CR_OK upon successful completion, an error code otherwise.
 */
enum CRStatus
cr_style_set_style_from_decl (CRStyle * a_this, CRDeclaration * a_decl)
{
        CRTerm *value = NULL;
        enum CRStatus status = CR_OK;

        enum CRPropertyID prop_id = PROP_ID_NOT_KNOWN;

        g_return_val_if_fail (a_this && a_decl
                              && a_decl
                              && a_decl->property
                              && a_decl->property->stryng
                              && a_decl->property->stryng->str,
                              CR_BAD_PARAM_ERROR);

        prop_id = cr_style_get_prop_id
                ((const guchar *) a_decl->property->stryng->str);

        value = a_decl->value;
        switch (prop_id) {
        case PROP_ID_PADDING_TOP:
                status = set_prop_padding_x_from_value
                        (a_this, value, DIR_TOP);
                break;

        case PROP_ID_PADDING_RIGHT:
                status = set_prop_padding_x_from_value
                        (a_this, value, DIR_RIGHT);
                break;
        case PROP_ID_PADDING_BOTTOM:
                status = set_prop_padding_x_from_value
                        (a_this, value, DIR_BOTTOM);
                break;

        case PROP_ID_PADDING_LEFT:
                status = set_prop_padding_x_from_value
                        (a_this, value, DIR_LEFT);
                break;

        case PROP_ID_PADDING:
                status = set_prop_padding_from_value (a_this, value) ;
                break;

        case PROP_ID_BORDER_TOP_WIDTH:
                status = set_prop_border_x_width_from_value (a_this, value,
                                                             DIR_TOP);
                break;

        case PROP_ID_BORDER_RIGHT_WIDTH:
                status = set_prop_border_x_width_from_value (a_this, value,
                                                             DIR_RIGHT);
                break;

        case PROP_ID_BORDER_BOTTOM_WIDTH:
                status = set_prop_border_x_width_from_value (a_this, value,
                                                             DIR_BOTTOM);
                break;

        case PROP_ID_BORDER_LEFT_WIDTH:
                status = set_prop_border_x_width_from_value (a_this, value,
                                                             DIR_LEFT);
                break;

        case PROP_ID_BORDER_WIDTH:
                status = set_prop_border_width_from_value (a_this, value) ;
                break ;

        case PROP_ID_BORDER_TOP_STYLE:
                status = set_prop_border_x_style_from_value (a_this, value,
                                                             DIR_TOP);
                break;

        case PROP_ID_BORDER_RIGHT_STYLE:
                status = set_prop_border_x_style_from_value (a_this, value,
                                                             DIR_RIGHT);
                break;

        case PROP_ID_BORDER_BOTTOM_STYLE:
                status = set_prop_border_x_style_from_value (a_this, value,
                                                             DIR_BOTTOM);
                break;

        case PROP_ID_BORDER_LEFT_STYLE:
                status = set_prop_border_x_style_from_value (a_this, value,
                                                             DIR_LEFT);
                break;

        case PROP_ID_BORDER_STYLE:
                status = set_prop_border_style_from_value (a_this, value) ;
                break ;

        case PROP_ID_BORDER_TOP_COLOR:
                status = set_prop_border_x_color_from_value (a_this, value,
                                                             DIR_TOP);
                break;

        case PROP_ID_BORDER_RIGHT_COLOR:
                status = set_prop_border_x_color_from_value (a_this, value,
                                                             DIR_RIGHT);
                break;

        case PROP_ID_BORDER_BOTTOM_COLOR:
                status = set_prop_border_x_color_from_value (a_this, value,
                                                             DIR_BOTTOM);
                break;

        case PROP_ID_BORDER_LEFT_COLOR:
                status = set_prop_border_x_color_from_value (a_this, value,
                                                             DIR_BOTTOM);
                break;

        case PROP_ID_BORDER_TOP:
                status = set_prop_border_x_from_value (a_this, value,
                                                       DIR_TOP);
                break;

        case PROP_ID_BORDER_RIGHT:
                status = set_prop_border_x_from_value (a_this, value,
                                                       DIR_RIGHT);
                break;

        case PROP_ID_BORDER_BOTTOM:
                status = set_prop_border_x_from_value (a_this, value,
                                                       DIR_BOTTOM);
                break;

        case PROP_ID_BORDER_LEFT:
                status = set_prop_border_x_from_value (a_this, value,
                                                       DIR_LEFT);
                break;

        case PROP_ID_MARGIN_TOP:
                status = set_prop_margin_x_from_value (a_this, value,
                                                       DIR_TOP);
                break;

        case PROP_ID_BORDER:
                status = set_prop_border_from_value (a_this, value);
                break;

        case PROP_ID_MARGIN_RIGHT:
                status = set_prop_margin_x_from_value (a_this, value,
                                                       DIR_RIGHT);
                break;

        case PROP_ID_MARGIN_BOTTOM:
                status = set_prop_margin_x_from_value (a_this, value,
                                                       DIR_BOTTOM);
                break;

        case PROP_ID_MARGIN_LEFT:
                status = set_prop_margin_x_from_value (a_this, value,
                                                       DIR_LEFT);
                break;

        case PROP_ID_MARGIN:
                status = set_prop_margin_from_value (a_this, value);
                break;

        case PROP_ID_DISPLAY:
                status = set_prop_display_from_value (a_this, value);
                break;

        case PROP_ID_POSITION:
                status = set_prop_position_from_value (a_this, value);
                break;

        case PROP_ID_TOP:
                status = set_prop_x_from_value (a_this, value, DIR_TOP);
                break;

        case PROP_ID_RIGHT:
                status = set_prop_x_from_value (a_this, value, DIR_RIGHT);
                break;

        case PROP_ID_BOTTOM:
                status = set_prop_x_from_value (a_this, value, DIR_BOTTOM);
                break;

        case PROP_ID_LEFT:
                status = set_prop_x_from_value (a_this, value, DIR_LEFT);
                break;

        case PROP_ID_FLOAT:
                status = set_prop_float (a_this, value);
                break;

        case PROP_ID_WIDTH:
                status = set_prop_width (a_this, value);
                break;

        case PROP_ID_COLOR:
                status = set_prop_color (a_this, value);
                break;

        case PROP_ID_BACKGROUND_COLOR:
                status = set_prop_background_color (a_this, value);
                break;

        case PROP_ID_FONT_FAMILY:
                status = set_prop_font_family_from_value (a_this, value);
                break;

        case PROP_ID_FONT_SIZE:
                status = set_prop_font_size_from_value (a_this, value);
                break;

        case PROP_ID_FONT_STYLE:
                status = set_prop_font_style_from_value (a_this, value);
                break;

        case PROP_ID_FONT_WEIGHT:
                status = set_prop_font_weight_from_value (a_this, value);
                break;

	case PROP_ID_WHITE_SPACE:
		status = set_prop_white_space_from_value(a_this, value);
		break;

        default:
                return CR_UNKNOWN_TYPE_ERROR;

        }

        return status;
}

/**
 *Increases the reference count
 *of the current instance of #CRStyle.
 *@param a_this the current instance of #CRStyle.
 *@return CR_OK upon successful completion, an error code
 *otherwise.
 */
enum CRStatus
cr_style_ref (CRStyle * a_this)
{
        g_return_val_if_fail (a_this, CR_BAD_PARAM_ERROR);

        a_this->ref_count++;
        return CR_OK;
}

/**
 *Decreases the reference count of
 *the current instance of #CRStyle.
 *If the reference count reaches 0, the
 *instance of #CRStyle is destoyed.
 *@param a_this the current instance of #CRStyle.
 *@return TRUE if the instance has been destroyed, FALSE
 *otherwise.
 */
gboolean
cr_style_unref (CRStyle * a_this)
{
        g_return_val_if_fail (a_this, FALSE);

        if (a_this->ref_count)
                a_this->ref_count--;

        if (!a_this->ref_count) {
                cr_style_destroy (a_this);
                return TRUE;
        }

        return FALSE;
}

/**
 *Duplicates the current instance of #CRStyle .
 *The newly created instance of #CRStyle must be
 *freed using cr_style_destroy ().
 *@param a_this the current instance of #CRStyle.
 *@return the newly duplicated instance of #CRStyle.
 */
CRStyle *
cr_style_dup (CRStyle * a_this)
{
        CRStyle *result = NULL;

        g_return_val_if_fail (a_this, NULL);

        result = cr_style_new (FALSE);
        if (!result) {
                cr_utils_trace_info ("Out of memory");
                return NULL;
        }
        cr_style_copy (result, a_this);
        return result;
}

/**
 *Copies a style data structure into another.
 *TODO: this is actually broken because it's based
 *on memcpy although some data structures of CRStyle should
 *be properly duplicated.
 *@param a_dest the destination style datastructure
 *@param a_src the source style datastructure.
 *@return CR_OK upon successful completion, an error code otherwise
 */
enum CRStatus
cr_style_copy (CRStyle * a_dest, CRStyle * a_src)
{
        g_return_val_if_fail (a_dest && a_src, CR_BAD_PARAM_ERROR);

        memcpy (a_dest, a_src, sizeof (CRStyle));
        return CR_OK;
}

/**
 *dump a CRNumpPropVal in a string.
 *@param a_prop_val the numerical property value to dump
 *@param a_str the string to dump the numerical property into.
 *Note that the string value is appended to a_str.
 *@param a_nb_indent the number white chars of indentation.
 */
enum CRStatus
cr_style_num_prop_val_to_string (CRNumPropVal * a_prop_val,
                                 GString * a_str, guint a_nb_indent)
{
        enum CRStatus status = CR_OK;
        guchar *tmp_str = NULL;
        GString *str = NULL;

        g_return_val_if_fail (a_prop_val && a_str, CR_BAD_PARAM_ERROR);

        str = g_string_new (NULL);
        cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
        g_string_append (str, "NumPropVal {");
        tmp_str = cr_num_to_string (&a_prop_val->sv);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "sv: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;
        
        tmp_str = cr_num_to_string (&a_prop_val->cv);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "cv: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;

        tmp_str = cr_num_to_string (&a_prop_val->av);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "av: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;
        g_string_append (str, "}");
        g_string_append (a_str, str->str);
        status = CR_OK;
      cleanup:

        if (tmp_str) {
                g_free (tmp_str);
                tmp_str = NULL;
        }
        if (str) {
                g_string_free (str, TRUE);
        }
        return status;
}

enum CRStatus
cr_style_rgb_prop_val_to_string (CRRgbPropVal * a_prop_val,
                                 GString * a_str, guint a_nb_indent)
{
        enum CRStatus status = CR_OK;
        guchar *tmp_str = NULL;
        GString *str = NULL;

        g_return_val_if_fail (a_prop_val && a_str, CR_BAD_PARAM_ERROR);

        str = g_string_new (NULL);

        cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
        g_string_append (str, "RGBPropVal {");
        tmp_str = cr_rgb_to_string (&a_prop_val->sv);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "sv: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;
        tmp_str = cr_rgb_to_string (&a_prop_val->cv);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "cv: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;
        tmp_str = cr_rgb_to_string (&a_prop_val->av);
        if (!tmp_str) {
                status = CR_ERROR;
                goto cleanup;
        }
        g_string_append_printf (str, "av: %s ", tmp_str);
        g_free (tmp_str);
        tmp_str = NULL;

        g_string_append (str, "}");
        g_string_append (a_str, str->str);
        status = CR_OK;
      cleanup:

        if (tmp_str) {
                g_free (tmp_str);
                tmp_str = NULL;
        }
        if (str) {
                g_string_free (str, TRUE);
        }
        return status;
}

enum CRStatus
cr_style_border_style_to_string (enum CRBorderStyle a_prop,
                                 GString * a_str, guint a_nb_indent)
{
        gchar *str = NULL;

        g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);

        switch (a_prop) {
        case BORDER_STYLE_NONE:
                str = (gchar *) "border-style-none";
                break;
        case BORDER_STYLE_HIDDEN:
                str = (gchar *) "border-style-hidden";
                break;
        case BORDER_STYLE_DOTTED:
                str = (gchar *) "border-style-dotted";
                break;
        case BORDER_STYLE_DASHED:
                str = (gchar *) "border-style-dashed";
                break;
        case BORDER_STYLE_SOLID:
                str = (gchar *) "border-style-solid";
                break;
        case BORDER_STYLE_DOUBLE:
                str = (gchar *) "border-style-double";
                break;
        case BORDER_STYLE_GROOVE:
                str = (gchar *) "border-style-groove";
                break;
        case BORDER_STYLE_RIDGE:
                str = (gchar *) "border-style-ridge";
                break;
        case BORDER_STYLE_INSET:
                str = (gchar *) "border-style-inset";
                break;
        case BORDER_STYLE_OUTSET:
                str = (gchar *) "border-style-outset";
                break;
        default:
                str = (gchar *) "unknown border style";
                break;
        }
        cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
        g_string_append (a_str, str);
        return CR_OK;
}

enum CRStatus
cr_style_display_type_to_string (enum CRDisplayType a_code,
                                 GString * a_str, guint a_nb_indent)
{
        gchar *str = NULL;

        g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);

        switch (a_code) {
        case DISPLAY_NONE:
                str = (gchar *) "display-none";
                break;
        case DISPLAY_INLINE:
                str = (gchar *) "display-inline";
                break;
        case DISPLAY_BLOCK:
                str = (gchar *) "display-block";
                break;
        case DISPLAY_LIST_ITEM:
                str = (gchar *) "display-list-item";
                break;
        case DISPLAY_RUN_IN:
                str = (gchar *) "display-run-in";
                break;
        case DISPLAY_COMPACT:
                str = (gchar *) "display-compact";
                break;
        case DISPLAY_MARKER:
                str = (gchar *) "display-marker";
                break;
        case DISPLAY_TABLE:
                str = (gchar *) "display-table";
                break;
        case DISPLAY_INLINE_TABLE:
                str = (gchar *) "display-inline-table";
                break;
        case DISPLAY_TABLE_ROW_GROUP:
                str = (gchar *) "display-table-row-group";
                break;
        case DISPLAY_TABLE_HEADER_GROUP:
                str = (gchar *) "display-table-header-group";
                break;
        case DISPLAY_TABLE_FOOTER_GROUP:
                str = (gchar *) "display-table-footer-group";
                break;
        case DISPLAY_TABLE_ROW:
                str = (gchar *) "display-table-row";
                break;
        case DISPLAY_TABLE_COLUMN_GROUP:
                str = (gchar *) "display-table-column-group";
                break;
        case DISPLAY_TABLE_COLUMN:
                str = (gchar *) "display-table-column";
                break;
        case DISPLAY_TABLE_CELL:
                str = (gchar *) "display-table-cell";
                break;
        case DISPLAY_TABLE_CAPTION:
                str = (gchar *) "display-table-caption";
                break;
        case DISPLAY_INHERIT:
                str = (gchar *) "display-inherit";
                break;
        default:
                str = (gchar *) "unknown display property";
                break;
        }
        cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
        g_string_append (a_str, str);
        return CR_OK;

}

enum CRStatus
cr_style_position_type_to_string (enum CRPositionType a_code,
                                  GString * a_str, guint a_nb_indent)
{
        gchar *str = NULL;

        g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);

        switch (a_code) {
        case POSITION_STATIC:
                str = (gchar *) "position-static";
                break;
        case POSITION_RELATIVE:
                str = (gchar *) "position-relative";
                break;
        case POSITION_ABSOLUTE:
                str = (gchar *) "position-absolute";
                break;
        case POSITION_FIXED:
                str = (gchar *) "position-fixed";
                break;
        case POSITION_INHERIT:
                str = (gchar *) "position-inherit";
                break;
        default:
                str = (gchar *) "unknown static property";
        }
        cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
        g_string_append (a_str, str);
        return CR_OK;
}

enum CRStatus
cr_style_float_type_to_string (enum CRFloatType a_code,
                               GString * a_str, guint a_nb_indent)
{
        gchar *str = NULL;

        g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);

        switch (a_code) {
        case FLOAT_NONE:
                str = (gchar *) "float-none";
                break;
        case FLOAT_LEFT:
                str = (gchar *) "float-left";
                break;
        case FLOAT_RIGHT:
                str = (gchar *) "float-right";
                break;
        case FLOAT_INHERIT:
                str = (gchar *) "float-inherit";
                break;
        default:
                str = (gchar *) "unknown float property value";
                break;
        }
        cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
        g_string_append (a_str, str);
        return CR_OK;
}

enum CRStatus
cr_style_white_space_type_to_string (enum CRWhiteSpaceType a_code,
                                     GString * a_str, guint a_nb_indent)
{
        gchar *str = NULL;

        g_return_val_if_fail (a_str, CR_BAD_PARAM_ERROR);

        switch (a_code) {
        case WHITE_SPACE_NORMAL:
                str = (gchar *) "normal";
		break;
	case WHITE_SPACE_PRE:
		str = (gchar *) "pre";
		break;
	case WHITE_SPACE_NOWRAP:
		str = (gchar *) "nowrap";
		break;
	case WHITE_SPACE_INHERIT:
		str = (gchar *) "inherited";
		break;
	default:
		str = (gchar *) "unknown white space property value";
		break;
	}
	cr_utils_dump_n_chars2 (' ', a_str, a_nb_indent);
	g_string_append (a_str, str);
	return CR_OK;
}
 
/**
 *Serializes in instance of #CRStyle into
 *a string
 *@param a_this the instance of #CRStyle to serialize
 *@param a_str the string to serialise the style into.
 *if *a_str is NULL, a new GString is instantiated, otherwise
 *the style serialisation is appended to the existed *a_str
 *@param the number of white space char to use for indentation.
 *@return CR_OK upon successful completion, an error code otherwise.
 */
enum CRStatus
cr_style_to_string (CRStyle * a_this, GString ** a_str, guint a_nb_indent)
{
        const gint INTERNAL_INDENT = 2;
        gint indent = a_nb_indent + INTERNAL_INDENT;
        gchar *tmp_str = NULL;
        GString *str = NULL;
        gint i = 0;

        g_return_val_if_fail (a_this && a_str, CR_BAD_PARAM_ERROR);

        if (!*a_str) {
                str = g_string_new (NULL);
        } else {
                str = *a_str;
        }
        cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
        g_string_append (str, "style {\n");

        /*loop over the num_props and to_string() them */
        for (i = NUM_PROP_TOP; i < NB_NUM_PROPS; i++) {
                /*
                 *to_string() the name of the num_prop
                 *(using num_prop_code_to_string)
                 *before outputting it value
                 */
                cr_utils_dump_n_chars2 (' ', str, indent);
                tmp_str = (gchar *) num_prop_code_to_string ((enum CRNumProp) i);
                if (tmp_str) {
                        g_string_append_printf (str, "%s: ", tmp_str);
                } else {
                        g_string_append (str, "NULL");
                }
                tmp_str = NULL;
                cr_style_num_prop_val_to_string (&a_this->num_props[i], str,
                                                 a_nb_indent +
                                                 INTERNAL_INDENT);
                g_string_append (str, "\n");
        }
        /*loop over the rgb_props and to_string() them all */
        for (i = RGB_PROP_BORDER_TOP_COLOR; i < NB_RGB_PROPS; i++) {
                tmp_str = (gchar *) rgb_prop_code_to_string ((enum CRRgbProp) i);
                cr_utils_dump_n_chars2 (' ', str, indent);
                if (tmp_str) {
                        g_string_append_printf (str, "%s: ", tmp_str);
                } else {
                        g_string_append (str, "NULL: ");
                }
                tmp_str = NULL;
                cr_style_rgb_prop_val_to_string (&a_this->rgb_props[i], str,
                                                 a_nb_indent +
                                                 INTERNAL_INDENT);
                g_string_append (str, "\n");
        }
        /*loop over the border_style_props and to_string() them */
        for (i = BORDER_STYLE_PROP_TOP; i < NB_BORDER_STYLE_PROPS; i++) {
                tmp_str = (gchar *) border_style_prop_code_to_string ((enum CRBorderStyleProp) i);
                cr_utils_dump_n_chars2 (' ', str, indent);
                if (tmp_str) {
                        g_string_append_printf (str, "%s: ", tmp_str);
                } else {
                        g_string_append (str, "NULL: ");
                }
                tmp_str = NULL;
                cr_style_border_style_to_string (a_this->
                                                 border_style_props[i], str,
                                                 0);
                g_string_append (str, "\n");
        }
        cr_utils_dump_n_chars2 (' ', str, indent);
        g_string_append (str, "display: ");
        cr_style_display_type_to_string (a_this->display, str, 0);
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        g_string_append (str, "position: ");
        cr_style_position_type_to_string (a_this->position, str, 0);
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        g_string_append (str, "float-type: ");
        cr_style_float_type_to_string (a_this->float_type, str, 0);
        g_string_append (str, "\n");

	cr_utils_dump_n_chars2 (' ', str, indent);
	g_string_append (str, "white-space: ");
	cr_style_white_space_type_to_string (a_this->white_space, str, 0);
	g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        g_string_append (str, "font-family: ");
        tmp_str = (gchar *) cr_font_family_to_string (a_this->font_family, TRUE);
        if (tmp_str) {
                g_string_append (str, tmp_str);
                g_free (tmp_str);
                tmp_str = NULL;
        } else {
                g_string_append (str, "NULL");
        }
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = cr_font_size_to_string (&a_this->font_size.sv);
        if (tmp_str) {
                g_string_append_printf (str, "font-size {sv:%s, ",
                                        tmp_str) ;
        } else {
                g_string_append (str, "font-size {sv:NULL, ");
        }
        tmp_str = cr_font_size_to_string (&a_this->font_size.cv);
        if (tmp_str) {
                g_string_append_printf (str, "cv:%s, ", tmp_str);
        } else {
                g_string_append (str, "cv:NULL, ");
        }
        tmp_str = cr_font_size_to_string (&a_this->font_size.av);
        if (tmp_str) {
                g_string_append_printf (str, "av:%s}", tmp_str);
        } else {
                g_string_append (str, "av:NULL}");
        }

        tmp_str = NULL;
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = cr_font_size_adjust_to_string (a_this->font_size_adjust);
        if (tmp_str) {
                g_string_append_printf (str, "font-size-adjust: %s", tmp_str);
        } else {
                g_string_append (str, "font-size-adjust: NULL");
        }
        tmp_str = NULL;
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = (gchar *) cr_font_style_to_string (a_this->font_style);
        if (tmp_str) {
                g_string_append_printf (str, "font-style: %s", tmp_str);
        } else {
                g_string_append (str, "font-style: NULL");
        }
        tmp_str = NULL;
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = (gchar *) cr_font_variant_to_string (a_this->font_variant);
        if (tmp_str) {
                g_string_append_printf (str, "font-variant: %s", tmp_str);
        } else {
                g_string_append (str, "font-variant: NULL");
        }
        tmp_str = NULL;
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = (gchar *) cr_font_weight_to_string (a_this->font_weight);
        if (tmp_str) {
                g_string_append_printf (str, "font-weight: %s", tmp_str);
        } else {
                g_string_append (str, "font-weight: NULL");
        }
        tmp_str = NULL;
        g_string_append (str, "\n");

        cr_utils_dump_n_chars2 (' ', str, indent);
        tmp_str = (gchar *) cr_font_stretch_to_string (a_this->font_stretch);
        if (tmp_str) {
                g_string_append_printf (str, "font-stretch: %s", tmp_str);
        } else {
                g_string_append (str, "font-stretch: NULL");
        }
        tmp_str = NULL;
        g_string_append (str, "\n");


        cr_utils_dump_n_chars2 (' ', str, a_nb_indent);
        g_string_append (str, "}");

        return CR_OK;
}

/**
 *Destructor of the #CRStyle class.
 *@param a_this the instance to destroy.
 */
void
cr_style_destroy (CRStyle * a_this)
{
        g_return_if_fail (a_this);

        g_free (a_this);
}

