New attribute types PANGO_ATTR_GRAVITY and PANGO_ATTR_GRAVITY_HINT. New
authorBehdad Esfahbod <behdad@gnome.org>
Tue, 16 Jan 2007 09:52:02 +0000 (09:52 +0000)
committerBehdad Esfahbod <behdad@src.gnome.org>
Tue, 16 Jan 2007 09:52:02 +0000 (09:52 +0000)
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

14 files changed:
ChangeLog
docs/pango-sections.txt
docs/tmpl/text-attributes.sgml
docs/tmpl/utils.sgml
examples/renderdemo.c
modules/basic/basic-fc.c
pango/pango-attributes.c
pango/pango-attributes.h
pango/pango-context.c
pango/pango-markup.c
pango/pango-utils.c
pango/pango-utils.h
pango/pango.def
pango/pangofc-fontmap.c

index 32f4602..180abbb 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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
index 64da609..d9d68e9 100644 (file)
@@ -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
index bcb109c..79f9ac9 100644 (file)
@@ -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
index d836f66..f53c776 100644 (file)
@@ -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>
 
index 21773e4..75a5ca4 100644 (file)
@@ -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;
 }
 
index 3551e28..81a9036 100644 (file)
@@ -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);
index 7f99746..ea46dd6 100644 (file)
@@ -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)
 {
index 4dc31af..3c07275 100644 (file)
@@ -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);
index 32197e5..53b8630 100644 (file)
@@ -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;
        }
     }
index 8f92583..e53bb59 100644 (file)
@@ -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)));
index ce778a8..01e2040 100644 (file)
@@ -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.
index 2d409c0..7756f09 100644 (file)
@@ -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
index dd37bf9..7b3aa3e 100644 (file)
@@ -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
index a1e4ee3..e901f07 100644 (file)
@@ -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