[pango/markup-percentage] Support size as percentage in markup



commit ebf0930e448abff0e0ae6b1ab632d8017b605ae0
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Jul 5 20:56:02 2019 -0400

    Support size as percentage in markup
    
    Test included.
    
    Closes https://gitlab.gnome.org/GNOME/pango/issues/23

 docs/pango_markup.sgml          |  3 +-
 pango/pango-attributes.c        | 10 +++---
 pango/pango-markup.c            | 76 ++++++++++++++++++++++++++++++-----------
 tests/markups/valid-12.expected | 20 +++++++++++
 tests/markups/valid-12.markup   |  1 +
 5 files changed, 84 insertions(+), 26 deletions(-)
---
diff --git a/docs/pango_markup.sgml b/docs/pango_markup.sgml
index c2ba377c..8bbdaad8 100644
--- a/docs/pango_markup.sgml
+++ b/docs/pango_markup.sgml
@@ -79,7 +79,8 @@ A font family name
 <listitem><para>
 Font size in 1024ths of a point, or one of the absolute sizes 
 'xx-small', 'x-small', 'small', 'medium', 'large', 'x-large',
-'xx-large', or one of the relative sizes 'smaller' or 'larger'.
+'xx-large', or one of the relative sizes 'smaller' or 'larger',
+or a percentage like '150%'.
 If you want to specify a absolute size, it's usually easier
 to take advantage of the ability to specify a partial
 font description using 'font'; you can use
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index df3104f0..1d0f1ee3 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -1897,8 +1897,7 @@ pango_attr_iterator_get_font (PangoAttrIterator     *iterator,
 
   PangoFontMask mask = 0;
   gboolean have_language = FALSE;
-  gdouble scale = 0;
-  gboolean have_scale = FALSE;
+  double scale = 1.0;
 
   g_return_if_fail (iterator != NULL);
   g_return_if_fail (desc != NULL);
@@ -1976,10 +1975,9 @@ pango_attr_iterator_get_font (PangoAttrIterator     *iterator,
            }
          break;
        case PANGO_ATTR_SCALE:
-         if (!have_scale)
+          if (!(mask & PANGO_FONT_MASK_SIZE))
            {
-             have_scale = TRUE;
-             scale = ((PangoAttrFloat *)attr)->value;
+             scale *= ((PangoAttrFloat *)attr)->value;
            }
          break;
        case PANGO_ATTR_LANGUAGE:
@@ -2020,7 +2018,7 @@ pango_attr_iterator_get_font (PangoAttrIterator     *iterator,
        }
     }
 
-  if (have_scale)
+  if (scale != 1.0)
     {
       if (pango_font_description_get_size_is_absolute (desc))
         pango_font_description_set_absolute_size (desc, scale * pango_font_description_get_size (desc));
diff --git a/pango/pango-markup.c b/pango/pango-markup.c
index 7420fa85..2d24eda3 100644
--- a/pango/pango-markup.c
+++ b/pango/pango-markup.c
@@ -64,15 +64,19 @@ struct _OpenTag
 {
   GSList *attrs;
   gsize start_index;
+  /* Our impact on scale_factor, so we know whether we
+   * need to create an attribute ourselves on close
+   */
+  gboolean has_scale;
   /* Current total scale level; reset whenever
    * an absolute size is set.
    * Each "larger" ups it 1, each "smaller" decrements it 1
    */
   gint scale_level;
-  /* Our impact on scale_level, so we know whether we
-   * need to create an attribute ourselves on close
+  /* Current scale factor; reset whenever
+   * an absolute size is set.
    */
-  gint scale_level_delta;
+  gint scale_factor;
   /* Base scale factor currently in effect
    * or size that this tag
    * forces, or parent's scale factor or size.
@@ -203,7 +207,8 @@ open_tag_set_absolute_font_size (OpenTag *ot,
   ot->base_font_size = font_size;
   ot->has_base_font_size = TRUE;
   ot->scale_level = 0;
-  ot->scale_level_delta = 0;
+  ot->scale_factor = 1.0;
+  ot->has_scale = FALSE;
 }
 
 static void
@@ -213,7 +218,8 @@ open_tag_set_absolute_font_scale (OpenTag *ot,
   ot->base_scale_factor = scale;
   ot->has_base_font_size = FALSE;
   ot->scale_level = 0;
-  ot->scale_level_delta = 0;
+  ot->scale_factor = 1.0;
+  ot->has_scale = FALSE;
 }
 
 static OpenTag*
@@ -231,7 +237,7 @@ markup_data_open_tag (MarkupData   *md)
   ot = g_slice_new (OpenTag);
   ot->attrs = NULL;
   ot->start_index = md->index;
-  ot->scale_level_delta = 0;
+  ot->has_scale = FALSE;
 
   if (parent == NULL)
     {
@@ -239,6 +245,7 @@ markup_data_open_tag (MarkupData   *md)
       ot->base_font_size = 0;
       ot->has_base_font_size = FALSE;
       ot->scale_level = 0;
+      ot->scale_factor = 1.0;
     }
   else
     {
@@ -246,6 +253,7 @@ markup_data_open_tag (MarkupData   *md)
       ot->base_font_size = parent->base_font_size;
       ot->has_base_font_size = parent->has_base_font_size;
       ot->scale_level = parent->scale_level;
+      ot->scale_factor = parent->scale_factor;
     }
 
   md->tag_stack = g_slist_prepend (md->tag_stack, ot);
@@ -285,7 +293,7 @@ markup_data_close_tag (MarkupData *md)
       tmp_list = g_slist_next (tmp_list);
     }
 
-  if (ot->scale_level_delta != 0)
+  if (ot->has_scale)
     {
       /* We affected relative font size; create an appropriate
        * attribute and reverse our effects on the current level
@@ -298,7 +306,7 @@ markup_data_close_tag (MarkupData *md)
           * as the base size to be scaled from
           */
          a = pango_attr_size_new (scale_factor (ot->scale_level,
-                                                1.0) *
+                                                 ot->scale_factor) *
                                   ot->base_font_size);
        }
       else
@@ -307,7 +315,8 @@ markup_data_close_tag (MarkupData *md)
           * as the base size to be scaled from
           */
          a = pango_attr_scale_new (scale_factor (ot->scale_level,
-                                                 ot->base_scale_factor));
+                                                 ot->scale_factor *
+                                                  ot->base_scale_factor));
        }
 
       a->start_index = ot->start_index;
@@ -870,7 +879,7 @@ big_parse_func      (MarkupData            *md G_GNUC_UNUSED,
   /* Grow text one level */
   if (tag)
     {
-      tag->scale_level_delta += 1;
+      tag->has_scale = TRUE;
       tag->scale_level += 1;
     }
 
@@ -1257,27 +1266,56 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
          const char *end;
          gint n;
 
-         if ((end = size, !_pango_scan_int (&end, &n)) || *end != '\0' || n < 0)
+          end = size;
+
+          if (_pango_scan_int (&end, &n) && n > 0)
+            {
+              if (*end == '\0')
+                {
+                 add_attribute (tag, pango_attr_size_new (n));
+                 if (tag)
+                   open_tag_set_absolute_font_size (tag, n);
+                }
+              else if (*end == '%' && *(end + 1) == '\0')
+                {
+                  if (tag)
+                    {
+                      tag->has_scale = TRUE;
+                      tag->base_scale_factor = ((double)n) / 100;
+                    }
+                }
+              else
+                {
+                 g_set_error (error,
+                               G_MARKUP_ERROR,
+                               G_MARKUP_ERROR_INVALID_CONTENT,
+                               _("Value of 'size' attribute on <span> tag on line %d "
+                                 "could not be parsed; should be an integer no more than %d,"
+                                 " a percentage, "
+                                 " or a string such as 'small', not '%s'"),
+                               line_number, INT_MAX, size);
+                  goto error;
+                }
+            }
+          else
            {
              g_set_error (error,
                           G_MARKUP_ERROR,
                           G_MARKUP_ERROR_INVALID_CONTENT,
                           _("Value of 'size' attribute on <span> tag on line %d "
                             "could not be parsed; should be an integer no more than %d,"
+                             " a percentage,"
                             " or a string such as 'small', not '%s'"),
                           line_number, INT_MAX, size);
              goto error;
            }
 
-         add_attribute (tag, pango_attr_size_new (n));
-         if (tag)
-           open_tag_set_absolute_font_size (tag, n);
        }
       else if (strcmp (size, "smaller") == 0)
        {
          if (tag)
            {
-             tag->scale_level_delta -= 1;
+             tag->has_scale = TRUE;
              tag->scale_level -= 1;
            }
        }
@@ -1285,7 +1323,7 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
        {
          if (tag)
            {
-             tag->scale_level_delta += 1;
+             tag->has_scale = TRUE;
              tag->scale_level += 1;
            }
        }
@@ -1605,7 +1643,7 @@ sub_parse_func      (MarkupData            *md G_GNUC_UNUSED,
   /* Shrink font, and set a negative rise */
   if (tag)
     {
-      tag->scale_level_delta -= 1;
+      tag->has_scale = TRUE;
       tag->scale_level -= 1;
     }
 
@@ -1627,7 +1665,7 @@ sup_parse_func      (MarkupData            *md G_GNUC_UNUSED,
   /* Shrink font, and set a positive rise */
   if (tag)
     {
-      tag->scale_level_delta -= 1;
+      tag->has_scale = TRUE;
       tag->scale_level -= 1;
     }
 
@@ -1649,7 +1687,7 @@ small_parse_func    (MarkupData            *md G_GNUC_UNUSED,
   /* Shrink text one level */
   if (tag)
     {
-      tag->scale_level_delta -= 1;
+      tag->has_scale = TRUE;
       tag->scale_level -= 1;
     }
 
diff --git a/tests/markups/valid-12.expected b/tests/markups/valid-12.expected
new file mode 100644
index 00000000..83239d1e
--- /dev/null
+++ b/tests/markups/valid-12.expected
@@ -0,0 +1,20 @@
+Blue text is cool!
+
+
+---
+
+range 0 9
+[0 9] scale 2.000000
+[0 9] foreground #00000000ffff
+range 9 13
+range 13 17
+[13 17] style 2
+range 17 2147483647
+
+
+---
+
+[0:9] (null) Normal 0
+[9:13] (null) Normal 0
+[13:17] (null) Italic 0
+[17:2147483647] (null) Italic 0
diff --git a/tests/markups/valid-12.markup b/tests/markups/valid-12.markup
new file mode 100644
index 00000000..9a95ec32
--- /dev/null
+++ b/tests/markups/valid-12.markup
@@ -0,0 +1 @@
+<span foreground="blue" size="200%">Blue text</span> is <span style="italic">cool</span>!


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]