diff options
author | Behdad Esfahbod <behdad@gnome.org> | 2007-01-16 09:52:02 +0000 |
---|---|---|
committer | Behdad Esfahbod <behdad@src.gnome.org> | 2007-01-16 09:52:02 +0000 |
commit | 56e7902a63f2036ea46a386c9d80827d6420f143 (patch) | |
tree | 6363106a16cc800436c945d09d88bbad951b5997 | |
parent | 7a102793913cb7a1a0eefbbfc9d5c0d04c9eb868 (diff) | |
download | pango-56e7902a63f2036ea46a386c9d80827d6420f143.tar.gz |
New attribute types PANGO_ATTR_GRAVITY and PANGO_ATTR_GRAVITY_HINT. New
2007-01-16 Behdad Esfahbod <behdad@gnome.org>
* pango/pango-attributes.h:
* pango/pango-attributes.c:
New attribute types PANGO_ATTR_GRAVITY and PANGO_ATTR_GRAVITY_HINT.
New public functions:
pango_attr_gravity_new()
pango_attr_gravity_hint_new()
* pango/pango-context.c (update_attr_iterator),
(itemize_state_init), (itemize_state_add_character),
(get_shaper_and_font), (itemize_state_update_for_new_run):
Handle gravity and gravity_hint attributes.
* pango/pango-utils.h:
* pango/pango-utils.c:
New public function:
pango_parse_enum()
* pango/pango-markup.c (span_parse_func): Parse gravity and
gravity_hint attributes for <span>. Optimize a bit.
* pango/pango-markup.c (parse_absolute_size), (attr_strcmp),
(span_parse_int), (span_parse_boolean), (span_parse_color),
(span_parse_enum), (span_parse_func): Use pango_scan_int(),
pango_color_parse(), and pango_parse_enum(). Also, ignore '-' and
'_' differences when matching attribute names for <span>.
* examples/renderdemo.c (parse_enum), (parse_ellipsis),
(parse_gravity), (parse_gravity_hint), (parse_hinting),
(parse_wrap): Use a generic parse_enum() that uses pango_parse_enum().
* modules/basic/basic-fc.c (basic_engine_shape):
* pango/pangofc-fontmap.c (pango_fc_make_pattern):
Use PANGO_GRAVITY_IS_VERTICAL().
* pango/pango.def:
* docs/pango-sections.txt:
* docs/tmpl/text-attributes.sgml:
* docs/tmpl/utils.sgml:
Update.
svn path=/trunk/; revision=2145
-rw-r--r-- | ChangeLog | 44 | ||||
-rw-r--r-- | docs/pango-sections.txt | 5 | ||||
-rw-r--r-- | docs/tmpl/text-attributes.sgml | 38 | ||||
-rw-r--r-- | docs/tmpl/utils.sgml | 13 | ||||
-rw-r--r-- | examples/renderdemo.c | 122 | ||||
-rw-r--r-- | modules/basic/basic-fc.c | 13 | ||||
-rw-r--r-- | pango/pango-attributes.c | 55 | ||||
-rw-r--r-- | pango/pango-attributes.h | 11 | ||||
-rw-r--r-- | pango/pango-context.c | 60 | ||||
-rw-r--r-- | pango/pango-markup.c | 527 | ||||
-rw-r--r-- | pango/pango-utils.c | 78 | ||||
-rw-r--r-- | pango/pango-utils.h | 6 | ||||
-rw-r--r-- | pango/pango.def | 3 | ||||
-rw-r--r-- | pango/pangofc-fontmap.c | 13 |
14 files changed, 587 insertions, 401 deletions
@@ -1,3 +1,47 @@ +2007-01-16 Behdad Esfahbod <behdad@gnome.org> + + * pango/pango-attributes.h: + * pango/pango-attributes.c: + New attribute types PANGO_ATTR_GRAVITY and PANGO_ATTR_GRAVITY_HINT. + New public functions: + + pango_attr_gravity_new() + pango_attr_gravity_hint_new() + + * pango/pango-context.c (update_attr_iterator), + (itemize_state_init), (itemize_state_add_character), + (get_shaper_and_font), (itemize_state_update_for_new_run): + Handle gravity and gravity_hint attributes. + + * pango/pango-utils.h: + * pango/pango-utils.c: + New public function: + + pango_parse_enum() + + * pango/pango-markup.c (span_parse_func): Parse gravity and + gravity_hint attributes for <span>. Optimize a bit. + + * pango/pango-markup.c (parse_absolute_size), (attr_strcmp), + (span_parse_int), (span_parse_boolean), (span_parse_color), + (span_parse_enum), (span_parse_func): Use pango_scan_int(), + pango_color_parse(), and pango_parse_enum(). Also, ignore '-' and + '_' differences when matching attribute names for <span>. + + * examples/renderdemo.c (parse_enum), (parse_ellipsis), + (parse_gravity), (parse_gravity_hint), (parse_hinting), + (parse_wrap): Use a generic parse_enum() that uses pango_parse_enum(). + + * modules/basic/basic-fc.c (basic_engine_shape): + * pango/pangofc-fontmap.c (pango_fc_make_pattern): + Use PANGO_GRAVITY_IS_VERTICAL(). + + * pango/pango.def: + * docs/pango-sections.txt: + * docs/tmpl/text-attributes.sgml: + * docs/tmpl/utils.sgml: + Update. + 2007-01-15 Behdad Esfahbod <behdad@gnome.org> Bug 323173 – Add layout of mixed direction text for vertical layout diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt index 64da609e..d9d68e9c 100644 --- a/docs/pango-sections.txt +++ b/docs/pango-sections.txt @@ -345,7 +345,6 @@ pango_attr_shape_new pango_attr_shape_new_with_data PangoAttrDataCopyFunc pango_attr_scale_new -pango_attr_fallback_new PANGO_SCALE_XX_SMALL PANGO_SCALE_X_SMALL PANGO_SCALE_SMALL @@ -355,6 +354,9 @@ PANGO_SCALE_X_LARGE PANGO_SCALE_XX_LARGE pango_attr_rise_new pango_attr_letter_spacing_new +pango_attr_fallback_new +pango_attr_gravity_new +pango_attr_gravity_hint_new PangoColor PANGO_TYPE_COLOR pango_color_parse @@ -964,6 +966,7 @@ pango_scan_string pango_scan_int pango_config_key_get pango_lookup_aliases +pango_parse_enum pango_parse_style pango_parse_variant pango_parse_weight diff --git a/docs/tmpl/text-attributes.sgml b/docs/tmpl/text-attributes.sgml index bcb109c6..79f9ac94 100644 --- a/docs/tmpl/text-attributes.sgml +++ b/docs/tmpl/text-attributes.sgml @@ -52,6 +52,8 @@ attribute is listed in parentheses after the description. @PANGO_ATTR_UNDERLINE_COLOR: underline color (#PangoAttrColor) @PANGO_ATTR_STRIKETHROUGH_COLOR: strikethrough color (#PangoAttrColor) @PANGO_ATTR_ABSOLUTE_SIZE: font size in pixels scaled by %PANGO_SCALE (#PangoAttrInt) +@PANGO_ATTR_GRAVITY: base text gravity (#PangoAttrInt) +@PANGO_ATTR_GRAVITY_HINT: gravity hint (#PangoAttrInt) <!-- ##### MACRO PANGO_TYPE_ATTR_TYPE ##### --> <para> @@ -434,15 +436,6 @@ user data. @Returns: -<!-- ##### FUNCTION pango_attr_fallback_new ##### --> -<para> - -</para> - -@enable_fallback: -@Returns: - - <!-- ##### MACRO PANGO_SCALE_XX_SMALL ##### --> <para> The scale factor for three shrinking steps (1 / (1.2 * 1.2 * 1.2)). @@ -510,6 +503,33 @@ The scale factor for three magnification steps (1.2 * 1.2 * 1.2). @Returns: +<!-- ##### FUNCTION pango_attr_fallback_new ##### --> +<para> + +</para> + +@enable_fallback: +@Returns: + + +<!-- ##### FUNCTION pango_attr_gravity_new ##### --> +<para> + +</para> + +@gravity: +@Returns: + + +<!-- ##### FUNCTION pango_attr_gravity_hint_new ##### --> +<para> + +</para> + +@hint: +@Returns: + + <!-- ##### STRUCT PangoColor ##### --> <para> The #PangoColor structure is used to diff --git a/docs/tmpl/utils.sgml b/docs/tmpl/utils.sgml index d836f661..f53c776f 100644 --- a/docs/tmpl/utils.sgml +++ b/docs/tmpl/utils.sgml @@ -104,6 +104,19 @@ backends and modules, but may be useful for other purposes too. @n_families: +<!-- ##### FUNCTION pango_parse_enum ##### --> +<para> + +</para> + +@type: +@str: +@value: +@warn: +@possible_values: +@Returns: + + <!-- ##### FUNCTION pango_parse_style ##### --> <para> diff --git a/examples/renderdemo.c b/examples/renderdemo.c index 21773e4e..75a5ca4a 100644 --- a/examples/renderdemo.c +++ b/examples/renderdemo.c @@ -333,61 +333,57 @@ do_output (PangoContext *context, pango_matrix_free (orig_matrix); } - static gboolean -parse_ellipsis (const char *name, - const char *arg, - gpointer data, - GError **error) +parse_enum (GType *type, + int *value, + const char *name, + const char *arg, + gpointer data, + GError **error) { - static GEnumClass *class = NULL; - gboolean ret = TRUE; - GEnumValue *value; + char *possible_values = NULL; + gboolean ret; - if (!class) - class = g_type_class_ref (PANGO_TYPE_ELLIPSIZE_MODE); + ret = pango_parse_enum (type, + arg, + value, + FALSE, + &possible_values); - value = g_enum_get_value_by_nick (class, arg); - if (value) - opt_ellipsize = value->value; - else + if (!ret && error) { - g_set_error(error, - G_OPTION_ERROR, - G_OPTION_ERROR_BAD_VALUE, - "Argument for --ellipsize must be one of none/start/middle/end"); - ret = FALSE; + g_set_error(error, + G_OPTION_ERROR, + G_OPTION_ERROR_BAD_VALUE, + "Argument for %s must be one of %s", + name, + possible_values); + ret = FALSE; } + g_free (possible_values); + return ret; } static gboolean +parse_ellipsis (const char *name, + const char *arg, + gpointer data, + GError **error) +{ + return parse_enum (PANGO_TYPE_ELLIPSIZE_MODE, &opt_ellipsize, + name, arg, data, error); +} + +static gboolean parse_gravity (const char *name, const char *arg, gpointer data, GError **error) { - static GEnumClass *class = NULL; - gboolean ret = TRUE; - GEnumValue *value; - - if (!class) - class = g_type_class_ref (PANGO_TYPE_GRAVITY); - - value = g_enum_get_value_by_nick (class, arg); - if (value) - opt_gravity = value->value; - else - { - g_set_error(error, - G_OPTION_ERROR, - G_OPTION_ERROR_BAD_VALUE, - "Argument for --gravity must be one of south/east/north/west/auto"); - ret = FALSE; - } - - return ret; + return parse_enum (PANGO_TYPE_GRAVITY, &opt_gravity, + name, arg, data, error); } static gboolean @@ -396,26 +392,8 @@ parse_gravity_hint (const char *name, gpointer data, GError **error) { - static GEnumClass *class = NULL; - gboolean ret = TRUE; - GEnumValue *value; - - if (!class) - class = g_type_class_ref (PANGO_TYPE_GRAVITY_HINT); - - value = g_enum_get_value_by_nick (class, arg); - if (value) - opt_gravity_hint = value->value; - else - { - g_set_error(error, - G_OPTION_ERROR, - G_OPTION_ERROR_BAD_VALUE, - "Argument for --gravity-hint must be one of natural/strong/line"); - ret = FALSE; - } - - return ret; + return parse_enum (PANGO_TYPE_GRAVITY_HINT, &opt_gravity_hint, + name, arg, data, error); } static gboolean @@ -424,12 +402,8 @@ parse_hinting (const char *name, gpointer data, GError **error) { - static GEnumClass *class = NULL; gboolean ret = TRUE; - if (!class) - class = g_type_class_ref (PANGO_TYPE_ELLIPSIZE_MODE); - if (strcmp (arg, "none") == 0) opt_hinting = HINT_NONE; else if (strcmp (arg, "auto") == 0) @@ -454,28 +428,12 @@ parse_wrap (const char *name, gpointer data, GError **error) { - static GEnumClass *class = NULL; - gboolean ret = TRUE; - GEnumValue *value; - - if (!class) - class = g_type_class_ref (PANGO_TYPE_WRAP_MODE); - - value = g_enum_get_value_by_nick (class, arg); - if (value) + gboolean ret; + if ((ret = parse_enum (PANGO_TYPE_WRAP_MODE, &opt_wrap, + name, arg, data, error))) { - opt_wrap = value->value; opt_wrap_set = TRUE; } - else - { - g_set_error(error, - G_OPTION_ERROR, - G_OPTION_ERROR_BAD_VALUE, - "Argument for --wrap must be one of word/char/word-char"); - ret = FALSE; - } - return ret; } diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c index 3551e282..81a90360 100644 --- a/modules/basic/basic-fc.c +++ b/modules/basic/basic-fc.c @@ -332,18 +332,7 @@ basic_engine_shape (PangoEngineShape *engine, if (!face) return; - switch (analysis->gravity) - { - case PANGO_GRAVITY_SOUTH: - case PANGO_GRAVITY_NORTH: - default: - vertical = FALSE; - break; - case PANGO_GRAVITY_EAST: - case PANGO_GRAVITY_WEST: - vertical = TRUE; - break; - } + vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity); if (vertical) { fallback_shape (engine, font, text, length, analysis, glyphs); diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c index 7f997461..ea46dd6a 100644 --- a/pango/pango-attributes.c +++ b/pango/pango-attributes.c @@ -968,6 +968,61 @@ pango_attr_shape_new (const PangoRectangle *ink_rect, NULL, NULL, NULL); } +/** + * pango_attr_gravity_new: + * @gravity: the gravity value; should not be %PANGO_GRAVITY_AUTO. + * + * Create a new gravity attribute. + * + * Return value: the newly allocated #PangoAttribute, which should be + * freed with pango_attribute_destroy(). + * + * Since: 1.16 + **/ +PangoAttribute * +pango_attr_gravity_new (PangoGravity gravity) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_GRAVITY, + pango_attr_int_copy, + pango_attr_int_destroy, + pango_attr_int_equal + }; + + g_return_val_if_fail (gravity != PANGO_GRAVITY_AUTO, NULL); + + return pango_attr_int_new (&klass, (int)gravity); +} + +/** + * pango_attr_gravity_hint_new: + * @hint: the gravity hint value. + * + * Create a new gravity hint attribute. + * + * Return value: the newly allocated #PangoAttribute, which should be + * freed with pango_attribute_destroy(). + * + * Since: 1.16 + **/ +PangoAttribute * +pango_attr_gravity_hint_new (PangoGravityHint hint) +{ + static const PangoAttrClass klass = { + PANGO_ATTR_GRAVITY_HINT, + pango_attr_int_copy, + pango_attr_int_destroy, + pango_attr_int_equal + }; + + return pango_attr_int_new (&klass, (int)hint); +} + + +/* + * Attribute List + */ + GType pango_attr_list_get_type (void) { diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h index 4dc31af6..3c07275e 100644 --- a/pango/pango-attributes.h +++ b/pango/pango-attributes.h @@ -86,9 +86,11 @@ typedef enum PANGO_ATTR_SCALE, /* PangoAttrFloat */ PANGO_ATTR_FALLBACK, /* PangoAttrInt */ PANGO_ATTR_LETTER_SPACING, /* PangoAttrInt */ - PANGO_ATTR_UNDERLINE_COLOR, /* PangoAttrColor */ - PANGO_ATTR_STRIKETHROUGH_COLOR, /* PangoAttrColor */ - PANGO_ATTR_ABSOLUTE_SIZE /* PangoAttrSize */ + PANGO_ATTR_UNDERLINE_COLOR, /* PangoAttrColor */ + PANGO_ATTR_STRIKETHROUGH_COLOR,/* PangoAttrColor */ + PANGO_ATTR_ABSOLUTE_SIZE, /* PangoAttrSize */ + PANGO_ATTR_GRAVITY, /* PangoAttrInt */ + PANGO_ATTR_GRAVITY_HINT /* PangoAttrInt */ } PangoAttrType; typedef enum { @@ -219,6 +221,9 @@ PangoAttribute *pango_attr_shape_new_with_data (const PangoRectangle *ink_ PangoAttrDataCopyFunc copy_func, GDestroyNotify destroy_func); +PangoAttribute *pango_attr_gravity_new (PangoGravity gravity); +PangoAttribute *pango_attr_gravity_hint_new (PangoGravityHint hint); + GType pango_attr_list_get_type (void) G_GNUC_CONST; PangoAttrList * pango_attr_list_new (void); PangoAttrList * pango_attr_list_ref (PangoAttrList *list); diff --git a/pango/pango-context.c b/pango/pango-context.c index 32197e5f..53b86302 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -663,6 +663,8 @@ struct _ItemizeState guint8 embedding; PangoGravity gravity; + PangoGravityHint gravity_hint; + PangoGravity resolved_gravity; PangoGravity font_desc_gravity; gboolean centered_baseline; @@ -723,7 +725,7 @@ static void update_attr_iterator (ItemizeState *state) { PangoLanguage *old_lang; - PangoAttribute *fallback; + PangoAttribute *attr; int end_index; pango_attr_iterator_range (state->attr_iter, NULL, &end_index); @@ -748,8 +750,14 @@ update_attr_iterator (ItemizeState *state) if (!state->lang) state->lang = state->context->language; - fallback = find_attribute (state->extra_attrs, PANGO_ATTR_FALLBACK); - state->enable_fallback = (fallback == NULL || ((PangoAttrInt *)fallback)->value); + attr = find_attribute (state->extra_attrs, PANGO_ATTR_FALLBACK); + state->enable_fallback = (attr == NULL || ((PangoAttrInt *)attr)->value); + + attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY); + state->gravity = attr == NULL ? PANGO_GRAVITY_AUTO : ((PangoAttrInt *)attr)->value; + + attr = find_attribute (state->extra_attrs, PANGO_ATTR_GRAVITY_HINT); + state->gravity_hint = attr == NULL ? state->context->gravity_hint : ((PangoAttrInt *)attr)->value; state->changed |= FONT_CHANGED; if (state->lang != old_lang) @@ -850,6 +858,8 @@ itemize_state_init (ItemizeState *state, state->font_desc_gravity = PANGO_GRAVITY_AUTO; state->gravity = PANGO_GRAVITY_AUTO; + state->gravity_hint = state->context->gravity_hint; + state->resolved_gravity = PANGO_GRAVITY_AUTO; state->derived_lang = NULL; state->lang_engine = NULL; state->current_fonts = NULL; @@ -970,7 +980,7 @@ itemize_state_add_character (ItemizeState *state, state->item->analysis.font = font; state->item->analysis.level = state->embedding; - state->item->analysis.gravity = state->gravity; + state->item->analysis.gravity = state->resolved_gravity; /* The level vs. gravity dance: * - If gravity is SOUTH, leave level untouched. @@ -1099,19 +1109,10 @@ get_shaper_and_font (ItemizeState *state, */ PangoScript script; - switch (state->gravity) - { - case PANGO_GRAVITY_SOUTH: - case PANGO_GRAVITY_NORTH: - case PANGO_GRAVITY_AUTO: - default: - script = state->script; - break; - case PANGO_GRAVITY_EAST: - case PANGO_GRAVITY_WEST: - script = PANGO_SCRIPT_COMMON; - break; - } + if (PANGO_GRAVITY_IS_VERTICAL (state->resolved_gravity)) + script = PANGO_SCRIPT_COMMON; + else + script = state->script; get_engines (state->context, state->derived_lang, script, &state->exact_engines, &state->fallback_engines); @@ -1212,25 +1213,34 @@ get_lang_map (PangoLanguage *lang) static void itemize_state_update_for_new_run (ItemizeState *state) { + /* This block should be moved to update_attr_iterator, but I'm too lazy to + * do it right now */ if (state->changed & (FONT_CHANGED | SCRIPT_CHANGED)) { - PangoGravity old_gravity = state->gravity; + PangoGravity old_gravity = state->resolved_gravity; if (state->font_desc_gravity != PANGO_GRAVITY_AUTO) - state->gravity = state->font_desc_gravity; + state->resolved_gravity = state->font_desc_gravity; else { - PangoGravity gravity = state->context->resolved_gravity; + PangoGravity gravity; + PangoGravityHint gravity_hint; + + gravity = state->gravity; + if (G_LIKELY (gravity == PANGO_GRAVITY_AUTO)) + gravity = state->context->resolved_gravity; + + gravity_hint = state->gravity_hint; gravity = pango_gravity_get_for_script (state->script, - state->context->resolved_gravity, - state->context->gravity_hint); - state->gravity = gravity; + gravity, + gravity_hint); + state->resolved_gravity = gravity; } - if (old_gravity != state->gravity) + if (old_gravity != state->resolved_gravity) { - pango_font_description_set_gravity (state->font_desc, state->gravity); + pango_font_description_set_gravity (state->font_desc, state->resolved_gravity); state->changed |= FONT_CHANGED; } } diff --git a/pango/pango-markup.c b/pango/pango-markup.c index 8f925830..e53bb592 100644 --- a/pango/pango-markup.c +++ b/pango/pango-markup.c @@ -26,6 +26,7 @@ #include "pango-attributes.h" #include "pango-font.h" +#include "pango-enum-types.h" #include "pango-impl-utils.h" /* FIXME */ @@ -783,33 +784,19 @@ parse_absolute_size (OpenTag *tag, double factor; if (strcmp (size, "xx-small") == 0) - { - level = XXSmall; - } + level = XXSmall; else if (strcmp (size, "x-small") == 0) - { - level = XSmall; - } + level = XSmall; else if (strcmp (size, "small") == 0) - { - level = Small; - } + level = Small; else if (strcmp (size, "medium") == 0) - { - level = Medium; - } + level = Medium; else if (strcmp (size, "large") == 0) - { - level = Large; - } + level = Large; else if (strcmp (size, "x-large") == 0) - { - level = XLarge; - } + level = XLarge; else if (strcmp (size, "xx-large") == 0) - { - level = XXLarge; - } + level = XXLarge; else return FALSE; @@ -824,15 +811,143 @@ parse_absolute_size (OpenTag *tag, return TRUE; } -#define CHECK_DUPLICATE(var) G_STMT_START{ \ - if ((var) != NULL) { \ - g_set_error (error, G_MARKUP_ERROR, \ - G_MARKUP_ERROR_INVALID_CONTENT, \ - _("Attribute '%s' occurs twice on <span> tag " \ - "on line %d char %d, may only occur once"), \ - names[i], line_number, char_number); \ - return FALSE; \ - }}G_STMT_END +/* a string compare func that ignores '-' vs '_' differences */ +static gint +attr_strcmp (gconstpointer pa, + gconstpointer pb) +{ + const char *a = pa; + const char *b = pb; + + int ca; + int cb; + + while (*a && *b) + { + ca = *a++; + cb = *b++; + + if (ca == cb) + continue; + + ca = ca == '_' ? '-' : ca; + cb = cb == '_' ? '-' : cb; + + if (ca != cb) + return cb - ca; + } + + ca = *a; + cb = *b; + + return cb - ca; +} + +static gboolean +span_parse_int (const char *attr_name, + const char *attr_val, + int *val, + int line_number, + GError **error) +{ + const char *end = attr_val; + + if (!pango_scan_int (&end, val) || *end != '\0') + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Value of '%s' attribute on <span> tag " + "on line %d could not be parsed; " + "should be an integer, not '%s'"), + attr_name, line_number, attr_val); + return FALSE; + } + + return TRUE; +} + +static gboolean +span_parse_boolean (const char *attr_name, + const char *attr_val, + gboolean *val, + int line_number, + GError **error) +{ + const char *end = attr_val; + + if (strcmp (attr_val, "true") == 0 || + strcmp (attr_val, "yes") == 0 || + strcmp (attr_val, "t") == 0 || + strcmp (attr_val, "y") == 0) + *val = TRUE; + else if (strcmp (attr_val, "false") == 0 || + strcmp (attr_val, "no") == 0 || + strcmp (attr_val, "f") == 0 || + strcmp (attr_val, "n") == 0) + *val = FALSE; + else + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Value of '%s' attribute on <span> tag " + "line %d should have one of " + "'true/yes/t/y' or 'false/no/f/n': '%s' is not valid"), + attr_name, line_number, attr_val); + return FALSE; + } + + return TRUE; +} + +static gboolean +span_parse_color (const char *attr_name, + const char *attr_val, + PangoColor *color, + int line_number, + GError **error) +{ + if (!pango_color_parse (color, attr_val)) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("Value of '%s' attribute on <span> tag " + "on line %d could not be parsed; " + "should be a color specification, not '%s'"), + attr_name, line_number, attr_val); + return FALSE; + } + + return TRUE; +} + +static gboolean +span_parse_enum (const char *attr_name, + const char *attr_val, + GType type, + int *val, + int line_number, + GError **error) +{ + char *possible_values = NULL; + + if (!pango_parse_enum (type, attr_val, val, FALSE, &possible_values)) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + _("'%s' is not a valid value for the '%s' " + "attribute on <span> tag, line %d; valid " + "values are %s"), + attr_val, attr_name, line_number, possible_values); + g_free (possible_values); + return FALSE; + } + + return TRUE; +} static gboolean span_parse_func (MarkupData *md, @@ -844,6 +959,7 @@ span_parse_func (MarkupData *md, { int line_number, char_number; int i; + const char *family = NULL; const char *size = NULL; const char *style = NULL; @@ -861,101 +977,72 @@ span_parse_func (MarkupData *md, const char *letter_spacing = NULL; const char *lang = NULL; const char *fallback = NULL; + const char *gravity = NULL; + const char *gravity_hint = NULL; g_markup_parse_context_get_position (context, &line_number, &char_number); +#define CHECK_DUPLICATE(var) G_STMT_START{ \ + if ((var) != NULL) { \ + g_set_error (error, G_MARKUP_ERROR, \ + G_MARKUP_ERROR_INVALID_CONTENT, \ + _("Attribute '%s' occurs twice on <span> tag " \ + "on line %d char %d, may only occur once"), \ + names[i], line_number, char_number); \ + return FALSE; \ + }}G_STMT_END +#define CHECK_ATTRIBUTE2(var, name) \ + if (attr_strcmp (names[i], (name)) == 0) { \ + CHECK_DUPLICATE (var); \ + (var) = values[i]; \ + found = TRUE; \ + break; \ + } +#define CHECK_ATTRIBUTE(var) CHECK_ATTRIBUTE2 (var, G_STRINGIFY (var)) + i = 0; while (names[i]) { - if (strcmp (names[i], "font_family") == 0 || - strcmp (names[i], "face") == 0) - { - CHECK_DUPLICATE (family); - family = values[i]; - } - else if (strcmp (names[i], "size") == 0) - { - CHECK_DUPLICATE (size); - size = values[i]; - } - else if (strcmp (names[i], "style") == 0) - { - CHECK_DUPLICATE (style); - style = values[i]; - } - else if (strcmp (names[i], "weight") == 0) - { - CHECK_DUPLICATE (weight); - weight = values[i]; - } - else if (strcmp (names[i], "variant") == 0) - { - CHECK_DUPLICATE (variant); - variant = values[i]; - } - else if (strcmp (names[i], "stretch") == 0) - { - CHECK_DUPLICATE (stretch); - stretch = values[i]; - } - else if (strcmp (names[i], "font_desc") == 0) - { - CHECK_DUPLICATE (desc); - desc = values[i]; - } - else if (strcmp (names[i], "foreground") == 0 || - strcmp (names[i], "color") == 0) - { - CHECK_DUPLICATE (foreground); - foreground = values[i]; - } - else if (strcmp (names[i], "background") == 0) - { - CHECK_DUPLICATE (background); - background = values[i]; - } - else if (strcmp (names[i], "underline") == 0) - { - CHECK_DUPLICATE (underline); - underline = values[i]; - } - else if (strcmp (names[i], "underline_color") == 0) - { - CHECK_DUPLICATE (underline_color); - underline_color = values[i]; - } - else if (strcmp (names[i], "strikethrough") == 0) - { - CHECK_DUPLICATE (strikethrough); - strikethrough = values[i]; - } - else if (strcmp (names[i], "strikethrough_color") == 0) - { - CHECK_DUPLICATE (strikethrough_color); - strikethrough_color = values[i]; - } - else if (strcmp (names[i], "rise") == 0) - { - CHECK_DUPLICATE (rise); - rise = values[i]; - } - else if (strcmp (names[i], "letter_spacing") == 0) - { - CHECK_DUPLICATE (letter_spacing); - letter_spacing = values[i]; - } - else if (strcmp (names[i], "lang") == 0) - { - CHECK_DUPLICATE (lang); - lang = values[i]; - } - else if (strcmp (names[i], "fallback") == 0) - { - CHECK_DUPLICATE (fallback); - fallback = values[i]; - } - else + gboolean found = FALSE; + + switch (names[i][0]) { + case 'f': + CHECK_ATTRIBUTE2(family, "face"); + CHECK_ATTRIBUTE (fallback); + CHECK_ATTRIBUTE2(desc, "font_desc"); + CHECK_ATTRIBUTE2(family, "font_family"); + CHECK_ATTRIBUTE (foreground); + break; + case 's': + CHECK_ATTRIBUTE (size); + CHECK_ATTRIBUTE (stretch); + CHECK_ATTRIBUTE (strikethrough); + CHECK_ATTRIBUTE (strikethrough_color); + CHECK_ATTRIBUTE (style); + break; + case 'g': + CHECK_ATTRIBUTE (gravity); + CHECK_ATTRIBUTE (gravity_hint); + break; + case 'l': + CHECK_ATTRIBUTE (lang); + CHECK_ATTRIBUTE (letter_spacing); + break; + case 'u': + CHECK_ATTRIBUTE (underline); + CHECK_ATTRIBUTE (underline_color); + break; + default: + CHECK_ATTRIBUTE (background); + CHECK_ATTRIBUTE2(foreground, "color"); + CHECK_ATTRIBUTE (rise); + CHECK_ATTRIBUTE (variant); + CHECK_ATTRIBUTE (weight); + break; + } + + if (!found) { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_UNKNOWN_ATTRIBUTE, @@ -969,7 +1056,7 @@ span_parse_func (MarkupData *md, } /* Parse desc first, then modify it with other font-related attributes. */ - if (desc) + if (G_UNLIKELY (desc)) { PangoFontDescription *parsed; @@ -983,12 +1070,12 @@ span_parse_func (MarkupData *md, } } - if (family) + if (G_UNLIKELY (family)) { add_attribute (tag, pango_attr_family_new (family)); } - if (size) + if (G_UNLIKELY (size)) { if (g_ascii_isdigit (*size)) { @@ -1044,7 +1131,7 @@ span_parse_func (MarkupData *md, } } - if (style) + if (G_UNLIKELY (style)) { PangoStyle pango_style; @@ -1063,7 +1150,7 @@ span_parse_func (MarkupData *md, } } - if (weight) + if (G_UNLIKELY (weight)) { PangoWeight pango_weight; @@ -1083,7 +1170,7 @@ span_parse_func (MarkupData *md, } } - if (variant) + if (G_UNLIKELY (variant)) { PangoVariant pango_variant; @@ -1102,7 +1189,7 @@ span_parse_func (MarkupData *md, } } - if (stretch) + if (G_UNLIKELY (stretch)) { PangoStretch pango_stretch; @@ -1122,191 +1209,117 @@ span_parse_func (MarkupData *md, } } - if (foreground) + if (G_UNLIKELY (foreground)) { PangoColor color; - if (!pango_color_parse (&color, foreground)) - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Could not parse foreground color specification " - "'%s' on line %d"), - foreground, line_number); - goto error; - } + if (!span_parse_color ("foreground", foreground, &color, line_number, error)) + goto error; add_attribute (tag, pango_attr_foreground_new (color.red, color.green, color.blue)); } - if (background) + if (G_UNLIKELY (background)) { PangoColor color; - if (!pango_color_parse (&color, background)) - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Could not parse background color specification " - "'%s' on line %d"), - background, line_number); - goto error; - } + if (!span_parse_color ("background", background, &color, line_number, error)) + goto error; add_attribute (tag, pango_attr_background_new (color.red, color.green, color.blue)); } - if (underline) + if (G_UNLIKELY (underline)) { PangoUnderline ul = PANGO_UNDERLINE_NONE; - if (strcmp (underline, "single") == 0) - ul = PANGO_UNDERLINE_SINGLE; - else if (strcmp (underline, "double") == 0) - ul = PANGO_UNDERLINE_DOUBLE; - else if (strcmp (underline, "low") == 0) - ul = PANGO_UNDERLINE_LOW; - else if (strcmp (underline, "error") == 0) - ul = PANGO_UNDERLINE_ERROR; - else if (strcmp (underline, "none") == 0) - ul = PANGO_UNDERLINE_NONE; - else - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("'%s' is not a valid value for the 'underline' " - "attribute on <span> tag, line %d; valid " - "values are for example 'single', " - "'double', 'low', 'none'"), - underline, line_number); - goto error; - } + if (!span_parse_enum ("underline", underline, PANGO_TYPE_UNDERLINE, &ul, line_number, error)) + goto error; add_attribute (tag, pango_attr_underline_new (ul)); } - if (underline_color) + if (G_UNLIKELY (underline_color)) { PangoColor color; - if (!pango_color_parse (&color, underline_color)) - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Could not parse underline_color color specification " - "'%s' on line %d"), - underline_color, line_number); - goto error; - } + if (!span_parse_color ("underline_color", underline_color, &color, line_number, error)) + goto error; add_attribute (tag, pango_attr_underline_color_new (color.red, color.green, color.blue)); } - if (strikethrough) + if (G_UNLIKELY (gravity)) { - if (strcmp (strikethrough, "true") == 0) - add_attribute (tag, pango_attr_strikethrough_new (TRUE)); - else if (strcmp (strikethrough, "false") == 0) - add_attribute (tag, pango_attr_strikethrough_new (FALSE)); - else - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("'strikethrough' attribute on <span> tag " - "line %d should have one of the values " - "'true' or 'false': '%s' is not valid"), - line_number, strikethrough); - goto error; - } + PangoGravity gr = PANGO_GRAVITY_SOUTH; + + if (!span_parse_enum ("gravity", gravity, PANGO_TYPE_GRAVITY, &gr, line_number, error)) + goto error; + + add_attribute (tag, pango_attr_gravity_new (gr)); + } + + if (G_UNLIKELY (gravity_hint)) + { + PangoGravityHint hint = PANGO_GRAVITY_HINT_NATURAL; + + if (!span_parse_enum ("gravity_hint", gravity_hint, PANGO_TYPE_GRAVITY_HINT, &hint, line_number, error)) + goto error; + + add_attribute (tag, pango_attr_gravity_hint_new (hint)); + } + + if (G_UNLIKELY (strikethrough)) + { + gboolean b = FALSE; + + if (!span_parse_boolean ("strikethrough", strikethrough, &b, line_number, error)) + goto error; + + add_attribute (tag, pango_attr_strikethrough_new (b)); } - if (strikethrough_color) + if (G_UNLIKELY (strikethrough_color)) { PangoColor color; - if (!pango_color_parse (&color, strikethrough_color)) - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Could not parse strikethrough_color color specification " - "'%s' on line %d"), - strikethrough_color, line_number); - goto error; - } + if (!span_parse_color ("strikethrough_color", strikethrough_color, &color, line_number, error)) + goto error; add_attribute (tag, pango_attr_strikethrough_color_new (color.red, color.green, color.blue)); } - if (fallback) + if (G_UNLIKELY (fallback)) { - if (strcmp (fallback, "true") == 0) - add_attribute (tag, pango_attr_fallback_new (TRUE)); - else if (strcmp (fallback, "false") == 0) - add_attribute (tag, pango_attr_fallback_new (FALSE)); - else - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("'fallback' attribute on <span> tag " - "line %d should have one of the values " - "'true' or 'false': '%s' is not valid"), - line_number, fallback); - goto error; - } + gboolean b = FALSE; + + if (!span_parse_boolean ("fallback", fallback, &b, line_number, error)) + goto error; + + add_attribute (tag, pango_attr_fallback_new (b)); } - if (rise) + if (G_UNLIKELY (rise)) { - char *end = NULL; - glong n; - - n = strtol (rise, &end, 10); + gint n = 0; - if (*end != '\0') - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Value of 'rise' attribute on <span> tag " - "on line %d could not be parsed; " - "should be an integer, not '%s'"), - line_number, rise); - goto error; - } + if (!span_parse_int ("rise", rise, &n, line_number, error)) + goto error; add_attribute (tag, pango_attr_rise_new (n)); } - if (letter_spacing) + if (G_UNLIKELY (letter_spacing)) { - char *end = NULL; - glong n; + gint n = 0; - n = strtol (letter_spacing, &end, 10); - - if (*end != '\0') - { - g_set_error (error, - G_MARKUP_ERROR, - G_MARKUP_ERROR_INVALID_CONTENT, - _("Value of 'letter_spacing' attribute on <span> tag " - "on line %d could not be parsed; " - "should be an integer, not '%s'"), - line_number, letter_spacing); - goto error; - } + if (!span_parse_int ("letter_spacing", letter_spacing, &n, line_number, error)) + goto error; add_attribute (tag, pango_attr_letter_spacing_new (n)); } - if (lang) + if (G_UNLIKELY (lang)) { add_attribute (tag, pango_attr_language_new (pango_language_from_string (lang))); diff --git a/pango/pango-utils.c b/pango/pango-utils.c index ce778a8f..01e20403 100644 --- a/pango/pango-utils.c +++ b/pango/pango-utils.c @@ -454,6 +454,8 @@ pango_scan_string (const char **pos, GString *out) case 't': c = '\t'; break; + default: + break; } quoted = FALSE; @@ -720,6 +722,82 @@ pango_get_lib_subdirectory (void) #endif } + +/** + * pango_parse_enum: + * @type: enum type to parse, eg. %PANGO_TYPE_ELLIPSIZE_MODE. + * @str: string to parse. May be %NULL. + * @value: integer to store the result in, or %NULL. + * @warn: if %TRUE, issue a g_warning() on bad input. + * @possible_values: place to store list of possible values on failure, or %NULL. + * + * Parses an enum type and stored the result in @value. + * + * If @str does not match the nick name of any of the possible values for the + * enum, %FALSE is returned, a warning is issued if @warn is %TRUE, and a + * string representing the list of possible values is stored in + * @possible_values. The list is slash-separated, eg. + * "none/start/middle/end". If failed and @possible_values is not %NULL, + * returned string should be freed using g_free(). + * + * Return value: %TRUE if @str was successfully parsed. + * + * Since: 1.16 + **/ +gboolean +pango_parse_enum (GType type, + const char *str, + int *value, + gboolean warn, + char **possible_values) +{ + GEnumClass *class = NULL; + gboolean ret = TRUE; + GEnumValue *v = NULL; + + class = g_type_class_ref (type); + + if (G_LIKELY (str)) + v = g_enum_get_value_by_nick (class, str); + + if (v) + { + if (G_LIKELY (value)) + *value = v->value; + } + else + { + ret = FALSE; + if (warn || possible_values) + { + int i; + GString *s = g_string_new (NULL); + + for (i = 0, v = g_enum_get_value (class, i); v; + i++ , v = g_enum_get_value (class, i)) + { + if (i) + g_string_append_c (s, '/'); + g_string_append (s, v->value_nick); + } + + if (warn) + g_warning ("%s must be one of %s", + G_ENUM_CLASS_TYPE_NAME(class), + s->str); + + if (possible_values) + *possible_values = s->str; + + g_string_free (s, possible_values ? FALSE : TRUE); + } + } + + g_type_class_unref (class); + + return ret; +} + /** * pango_parse_style: * @str: a string to parse. diff --git a/pango/pango-utils.h b/pango/pango-utils.h index 2d409c05..7756f093 100644 --- a/pango/pango-utils.h +++ b/pango/pango-utils.h @@ -48,6 +48,12 @@ void pango_lookup_aliases (const char *fontname, int *n_families); #endif /* PANGO_ENABLE_BACKEND */ +gboolean pango_parse_enum (GType type, + const char *str, + int *value, + gboolean warn, + char **possible_values); + /* Functions for parsing textual representations * of PangoFontDescription fields. They return TRUE if the input string * contains a valid value, which then has been assigned to the corresponding diff --git a/pango/pango.def b/pango/pango.def index dd37bf94..7b3aa3ec 100644 --- a/pango/pango.def +++ b/pango/pango.def @@ -5,6 +5,8 @@ EXPORTS pango_attr_family_new pango_attr_font_desc_new pango_attr_foreground_new + pango_attr_gravity_hint_new + pango_attr_gravity_new pango_attr_iterator_copy pango_attr_iterator_destroy pango_attr_iterator_get @@ -298,6 +300,7 @@ EXPORTS pango_matrix_transform_rectangle pango_matrix_translate pango_module_register + pango_parse_enum pango_parse_markup pango_parse_stretch pango_parse_style diff --git a/pango/pangofc-fontmap.c b/pango/pangofc-fontmap.c index a1e4ee35..e901f07a 100644 --- a/pango/pangofc-fontmap.c +++ b/pango/pangofc-fontmap.c @@ -823,18 +823,7 @@ pango_fc_make_pattern (const PangoFontDescription *description, #endif gravity = pango_font_description_get_gravity (description); - switch (gravity) - { - case PANGO_GRAVITY_SOUTH: - case PANGO_GRAVITY_NORTH: - default: - vertical = FcFalse; - break; - case PANGO_GRAVITY_EAST: - case PANGO_GRAVITY_WEST: - vertical = FcTrue; - break; - } + vertical = PANGO_GRAVITY_IS_VERTICAL (gravity) ? FcTrue : FcFalse; /* The reason for passing in FC_SIZE as well as FC_PIXEL_SIZE is * to work around a bug in libgnomeprint where it doesn't look |