blob: 221d0ceb859be94e0ab0fe45afcb5e7fd4b5818c [file] [log] [blame]
/* -*- Mode: C; indent-tabs-mode:nil; c-basic-offset: 8-*- */
/* libcroco - Library for parsing and applying CSS
* Copyright (C) 2006-2019 Free Software Foundation, Inc.
*
* This file is not part of the GNU gettext program, but is used with
* GNU gettext.
*
* The original copyright notice is as follows:
*/
/*
* This file is part of The Croco Library
*
* Copyright (C) 2003-2004 Dodji Seketeli. All Rights Reserved.
*
* 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.
*/
#include <config.h>
#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 tranform 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, 0}
};
/**
*A the key/value pair of this hash table
*are:
*key => name of the the css propertie 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"},
{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"},
{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"},
{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 = g_hash_table_lookup (gv_prop_hash, a_prop);
if (!raw_id) {
return PROP_ID_NOT_KNOWN;
}
return 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 ;
enum CRDirection direction = DIR_TOP ;
g_return_val_if_fail (a_style && a_value,
CR_BAD_PARAM_ERROR) ;
cur_term = a_value ;
if (!cur_term)
return CR_ERROR ;
for (direction = DIR_TOP ;
direction < NB_DIRS ; direction ++) {
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 ;
enum CRDirection direction = DIR_TOP ;
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 (direction = DIR_TOP ;
direction < NB_DIRS ;
direction ++) {
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 successfull 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)
{
enum CRDirection direction = 0;
g_return_val_if_fail (a_style && a_value, CR_BAD_PARAM_ERROR);
for (direction = 0; direction < NB_DIRS; direction++) {
set_prop_border_x_from_value (a_style,
a_value,
direction);
}
return CR_OK;
}
static enum CRStatus
set_prop_padding_from_value (CRStyle * a_style, CRTerm * a_value)
{
CRTerm *cur_term = NULL;
enum CRDirection direction = 0;
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 (direction = 0; direction < NB_DIRS; direction++) {
set_prop_padding_x_from_value (a_style, cur_term, direction);
}
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;
enum CRDirection direction = 0;
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 (direction = 0; direction < NB_DIRS; direction++) {
set_prop_margin_x_from_value (a_style, cur_term, direction);
}
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 = 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 successfull 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 dependant.
*/
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 dependant 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 successfull 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 successfull 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 successfull 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 stuctures of CRStyle should
*be properly duplicated.
*@param a_dest the destination style datastructure
*@param a_src the source style datastructure.
*@return CR_OK upon succesfull 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 propertie 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 instanciated, 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 outputing it value
*/
cr_utils_dump_n_chars2 (' ', str, indent);
tmp_str = (gchar *) num_prop_code_to_string (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 (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 (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);
}