[pango/break-tailoring: 2/2] Add an allow-line-breaks attribute




commit 96719ced78c0726da321ef32649961f7c339e72d
Author: Matthias Clasen <mclasen redhat com>
Date:   Sat Aug 21 13:17:58 2021 -0400

    Add an allow-line-breaks attribute
    
    This is more flexible than the boolean allow-breaks attribute,
    it lets you say: strip line breaks, but keep the char breaks.
    
    Tests included.

 docs/pango_markup.md            |  8 ++++---
 pango/break.c                   | 29 +++++++++++++++++++++-----
 pango/pango-attributes.c        | 46 +++++++++++++++++++++++++++++++++++++++++
 pango/pango-attributes.h        |  5 +++++
 pango/pango-layout.c            |  1 +
 pango/pango-markup.c            | 20 ++++++++++++++----
 tests/breaks/thirteen.break     |  2 ++
 tests/breaks/thirteen.expected  |  6 ++++++
 tests/markups/valid-24.expected | 21 +++++++++++++++++++
 tests/markups/valid-24.markup   |  1 +
 tests/test-common.c             |  1 +
 tests/testattributes.c          |  1 +
 12 files changed, 129 insertions(+), 12 deletions(-)
---
diff --git a/docs/pango_markup.md b/docs/pango_markup.md
index 8143570d..614fc6db 100644
--- a/docs/pango_markup.md
+++ b/docs/pango_markup.md
@@ -187,12 +187,14 @@ insert_hyphens
   lines in the middle of words. Available since Pango 1.44.
 
 allow_breaks
-: 'true' or 'false' to indicate whether breaking lines is allowed. Available
-  since Pango 1.44.
+: 'true' or 'false' to indicate whether breaking lines is allowed, or one of the
+  values 'non', 'char', 'line' or 'mandatory' to indicate what kinds of line break
+  opportunities are allowed. Available since Pango 1.44. Values other than 'true'
+  and 'false' are possible since Pango 1.50.
 
 break_before
 break_after
-: The value can be one of 'none','char', 'line', or 'mandatory', to override
+: The value can be one of 'none', 'char', 'line', or 'mandatory', to override
   the line break classification at the beginning or end of the span. Available
   since Pango 1.50.
 
diff --git a/pango/break.c b/pango/break.c
index 96fef800..b6b32846 100644
--- a/pango/break.c
+++ b/pango/break.c
@@ -1850,6 +1850,17 @@ break_attrs (const char   *text,
       PangoAttribute *attr = l->data;
 
       if (attr->klass->type == PANGO_ATTR_ALLOW_BREAKS)
+        {
+          PangoAttribute *attr2;
+
+          attr2 = pango_attr_allow_line_breaks_new (((PangoAttrInt*)attr)->value
+                                                    ? PANGO_LINE_BREAK_MANDATORY
+                                                    : PANGO_LINE_BREAK_NONE);
+          attr2->start_index = attr->start_index;
+          attr2->end_index = attr->end_index;
+          pango_attr_list_insert (&allow_breaks, attr2);
+        }
+      else if (attr->klass->type == PANGO_ATTR_ALLOW_LINE_BREAKS)
         pango_attr_list_insert (&allow_breaks, pango_attribute_copy (attr));
       else if (attr->klass->type == PANGO_ATTR_LINE_BREAK)
         pango_attr_list_insert (&line_breaks, pango_attribute_copy (attr));
@@ -1862,9 +1873,15 @@ break_attrs (const char   *text,
       _pango_attr_list_get_iterator (&allow_breaks, &iter);
       do
         {
-          const PangoAttribute *attr = pango_attr_iterator_get (&iter, PANGO_ATTR_ALLOW_BREAKS);
+          const PangoAttribute *attr = pango_attr_iterator_get (&iter, PANGO_ATTR_ALLOW_LINE_BREAKS);
+          PangoLineBreak allowed;
+
+          if (!attr)
+            continue;
+
+          allowed = ((PangoAttrInt*)attr)->value;
 
-          if (attr && ((PangoAttrInt*)attr)->value == 0)
+          if (allowed != PANGO_LINE_BREAK_MANDATORY)
             {
               int start, end;
               int start_pos, end_pos;
@@ -1883,9 +1900,9 @@ break_attrs (const char   *text,
 
               for (pos = start_pos + 1; pos < end_pos; pos++)
                 {
-                  log_attrs[pos].is_mandatory_break = FALSE;
-                  log_attrs[pos].is_line_break = FALSE;
-                  log_attrs[pos].is_char_break = FALSE;
+                  log_attrs[pos].is_mandatory_break &= allowed >= PANGO_LINE_BREAK_MANDATORY;
+                  log_attrs[pos].is_line_break &= allowed >= PANGO_LINE_BREAK_LINE;
+                  log_attrs[pos].is_char_break &= allowed >= PANGO_LINE_BREAK_CHAR;
 
                   tailored = TRUE;
                 }
@@ -1922,6 +1939,7 @@ break_attrs (const char   *text,
               log_attrs[pos].is_char_break = TRUE;
               log_attrs[pos].is_line_break = before >= PANGO_LINE_BREAK_LINE;
               log_attrs[pos].is_mandatory_break = before == PANGO_LINE_BREAK_MANDATORY;
+
               tailored = TRUE;
            }
 
@@ -1934,6 +1952,7 @@ break_attrs (const char   *text,
               log_attrs[pos].is_char_break = TRUE;
               log_attrs[pos].is_line_break = after >= PANGO_LINE_BREAK_LINE;
               log_attrs[pos].is_mandatory_break = after == PANGO_LINE_BREAK_MANDATORY;
+
               tailored = TRUE;
             }
         }
diff --git a/pango/pango-attributes.c b/pango/pango-attributes.c
index 97ec8ad4..ba97c8b4 100644
--- a/pango/pango-attributes.c
+++ b/pango/pango-attributes.c
@@ -1228,6 +1228,10 @@ pango_attr_background_alpha_new (guint16 alpha)
  * If breaks are disabled, the range will be kept in a
  * single run, as far as possible.
  *
+ * See [func@Pango.attr_allow_line_breaks_new] and
+ * [func@Pango.attr_line_breaks_new] for more flexible
+ * control over line breaks.
+ *
  * Return value: (transfer full): the newly allocated
  *   `PangoAttribute`, which should be freed with
  *   [method@Pango.Attribute.destroy]
@@ -1302,6 +1306,47 @@ pango_attr_show_new (PangoShowFlags flags)
   return pango_attr_int_new (&klass, (int)flags);
 }
 
+/**
+ * pango_attr_allow_line_breaks_new:
+ * @allowed: what line breaks to allow
+ *
+ * Create a new allow-line-breaks attribute.
+ *
+ * In contrast to [func@Pango.attr_allow_breaks_new],
+ * this attribute allows some control over which of the
+ * algorithmically determined line break opportunities
+ * to keep, and which to remove:
+ *
+ * `PANGO_LINE_BREAK_NONE`
+ * : All break opportunities are removed.
+ * `PANGO_LINE_BEAK_CHAR`
+ * : Only break opportunities during character breaking
+ *   are retained.
+ * `PANGO_LINE_BREAK_LINE`
+ * : Regular line break opportunities are retained, mandatory
+ *   breaks are removed.
+ * `PANGO_LINE_BREAK_MANDATORY:
+ * : All line break opportunities are retained.
+ *
+ * Return value: (transfer full): the newly allocated
+ *   `PangoAttribute`, which should be freed with
+ *   [method@Pango.Attribute.destroy]
+ *
+ * Since: 1.50
+ */
+PangoAttribute *
+pango_attr_allow_line_breaks_new (PangoLineBreak allowed)
+{
+  static const PangoAttrClass klass = {
+    PANGO_ATTR_ALLOW_LINE_BREAKS,
+    pango_attr_int_copy,
+    pango_attr_int_destroy,
+    pango_attr_int_equal,
+  };
+
+  return pango_attr_int_new (&klass, allowed);
+}
+
 /**
  * pango_attr_line_break_new:
  * @before: override for the beginning of the range
@@ -1343,6 +1388,7 @@ pango_attr_line_break_new (PangoLineBreak before,
 
   return pango_attr_int_new (&klass, before | (after << 16));
 }
+
 /**
  * pango_attr_overline_new:
  * @overline: the overline style
diff --git a/pango/pango-attributes.h b/pango/pango-attributes.h
index 96bd3e01..fc9a2dc7 100644
--- a/pango/pango-attributes.h
+++ b/pango/pango-attributes.h
@@ -77,6 +77,8 @@ typedef struct _PangoAttrFontFeatures PangoAttrFontFeatures;
  * @PANGO_ATTR_OVERLINE_COLOR: overline color ([struct@Pango.AttrColor]). Since 1.46
  * @PANGO_ATTR_LINE_HEIGHT: line height factor ([struct@Pango.AttrFloat]). Since: 1.50
  * @PANGO_ATTR_ABSOLUTE_LINE_HEIGHT: line height ([struct@Pango.AttrInt]). Since: 1.50
+ * @PANGO_ATTR_ALLOW_LINE_BREAKS: what algorithmically determined line breaks to allow 
([struct@Pango.AttrInt]). Since 1.50
+ * @PANGO_ATTR_LINE_BREAK: override line breaks at the ends of the range ([struct@Pango.AttrInt]). Since 1.50
  *
  * The `PangoAttrType` distinguishes between different types of attributes.
  *
@@ -120,6 +122,7 @@ typedef enum
   PANGO_ATTR_OVERLINE_COLOR,    /* PangoAttrColor */
   PANGO_ATTR_LINE_HEIGHT,       /* PangoAttrFloat */
   PANGO_ATTR_ABSOLUTE_LINE_HEIGHT, /* PangoAttrInt */
+  PANGO_ATTR_ALLOW_LINE_BREAKS,  /* PangoAttrInt */
   PANGO_ATTR_LINE_BREAK,        /* PangoAttrInt */
 } PangoAttrType;
 
@@ -541,6 +544,8 @@ PangoAttribute *        pango_attr_background_alpha_new         (guint16
 PANGO_AVAILABLE_IN_1_44
 PangoAttribute *        pango_attr_allow_breaks_new             (gboolean                     allow_breaks);
 PANGO_AVAILABLE_IN_1_50
+PangoAttribute *        pango_attr_allow_line_breaks_new        (PangoLineBreak               allow);
+PANGO_AVAILABLE_IN_1_50
 PangoAttribute *        pango_attr_line_break_new               (PangoLineBreak               before,
                                                                  PangoLineBreak               after);
 
diff --git a/pango/pango-layout.c b/pango/pango-layout.c
index 0bfa213d..b1f5387c 100644
--- a/pango/pango-layout.c
+++ b/pango/pango-layout.c
@@ -4313,6 +4313,7 @@ affects_break_or_shape (PangoAttribute *attr,
     {
     /* Affects breaks */
     case PANGO_ATTR_ALLOW_BREAKS:
+    case PANGO_ATTR_ALLOW_LINE_BREAKS:
     case PANGO_ATTR_LINE_BREAK:
     /* Affects shaping */
     case PANGO_ATTR_INSERT_HYPHENS:
diff --git a/pango/pango-markup.c b/pango/pango-markup.c
index 75215379..f70e4227 100644
--- a/pango/pango-markup.c
+++ b/pango/pango-markup.c
@@ -1697,11 +1697,23 @@ span_parse_func     (MarkupData            *md G_GNUC_UNUSED,
   if (G_UNLIKELY (allow_breaks))
     {
       gboolean b = FALSE;
+      PangoLineBreak allowed;
 
-      if (!span_parse_boolean ("allow_breaks", allow_breaks, &b, line_number, error))
-       goto error;
-
-      add_attribute (tag, pango_attr_allow_breaks_new (b));
+      if (span_parse_boolean ("allow_breaks", allow_breaks, &b, line_number, NULL))
+        add_attribute (tag, pango_attr_allow_breaks_new (b));
+      else if (span_parse_enum ("allow_breaks", allow_breaks, PANGO_TYPE_LINE_BREAK, (int*)(void*)&allowed, 
line_number, NULL))
+        add_attribute (tag, pango_attr_allow_line_breaks_new (allowed));
+      else
+        {
+          g_set_error (error,
+                       G_MARKUP_ERROR,
+                       G_MARKUP_ERROR_INVALID_CONTENT,
+                       _("Value of 'allow_breaks' attribute on <span> tag on line %d "
+                         "could not be parsed; should be a boolean, or one of "
+                         "'none', 'char', 'line', 'mandatory', not '%s'"),
+                       line_number, allow_breaks);
+          goto error;
+        }
     }
 
   if (G_UNLIKELY (break_before || break_after))
diff --git a/tests/breaks/thirteen.break b/tests/breaks/thirteen.break
new file mode 100644
index 00000000..c92bf4f9
--- /dev/null
+++ b/tests/breaks/thirteen.break
@@ -0,0 +1,2 @@
+# test line break attributes
+the file <span allow_breaks='char' break_after='mandatory'><span break_before='mandatory' 
break_after='line'>/path/</span><span break_after='line'>to/</span><span break_after='line'>my/</span>home 
</span>is cursed.
diff --git a/tests/breaks/thirteen.expected b/tests/breaks/thirteen.expected
new file mode 100644
index 00000000..89f5fe8d
--- /dev/null
+++ b/tests/breaks/thirteen.expected
@@ -0,0 +1,6 @@
+Text:         ⁦t⁩ ⁦h⁩ ⁦e⁩  [ ]  ⁦f⁩ ⁦i⁩ ⁦l⁩ ⁦e⁩  [ ]  ⁦/⁩  ⁦p⁩ ⁦a⁩ ⁦t⁩ ⁦h⁩  ⁦/⁩  ⁦t⁩ ⁦o⁩  ⁦/⁩  ⁦m⁩ ⁦y⁩  ⁦/⁩  
⁦h⁩ ⁦o⁩ ⁦m⁩ ⁦e⁩  [ ]  ⁦i⁩ ⁦s⁩  [ ]  ⁦c⁩ ⁦u⁩ ⁦r⁩ ⁦s⁩ ⁦e⁩ ⁦d⁩  ⁦.⁩ [0x0a] 
+Breaks:     c  c c c    lc c c c c    Lc c  c c c c  lc c c  lc c c  lc c c c c    Lc c c    lc c c c c c c  
c      c
+Whitespace:        x             x                                            x         x                    
w      w
+Words:      bs     be   bs       be   b  bs       be bs   be bs   be bs       be   bs   be   bs           be 
b      b
+Sentences:  bs                                                                                               
e      b
+Graphemes:  b  b b b    b  b b b b    b  b  b b b b  b  b b  b  b b  b  b b b b    b  b b    b  b b b b b b  
b      b
diff --git a/tests/markups/valid-24.expected b/tests/markups/valid-24.expected
new file mode 100644
index 00000000..73420aad
--- /dev/null
+++ b/tests/markups/valid-24.expected
@@ -0,0 +1,21 @@
+one two three four
+
+
+---
+
+range 0 4
+[0,18]allow-line-breaks=2
+range 4 7
+[0,18]allow-line-breaks=2
+[4,7]line-break=4, 3
+range 7 18
+[0,18]allow-line-breaks=2
+range 18 2147483647
+
+
+---
+
+[0:4] (null) Normal
+[4:7] (null) Normal
+[7:18] (null) Normal
+[18:2147483647] (null) Normal
diff --git a/tests/markups/valid-24.markup b/tests/markups/valid-24.markup
new file mode 100644
index 00000000..08d6a040
--- /dev/null
+++ b/tests/markups/valid-24.markup
@@ -0,0 +1 @@
+<span allow_breaks='char'>one <span break_before='mandatory' break_after='line'>two</span> three four</span>
diff --git a/tests/test-common.c b/tests/test-common.c
index 52f4cda2..06c89e81 100644
--- a/tests/test-common.c
+++ b/tests/test-common.c
@@ -140,6 +140,7 @@ print_attribute (PangoAttribute *attr, GString *string)
     case PANGO_ATTR_FOREGROUND_ALPHA:
     case PANGO_ATTR_BACKGROUND_ALPHA:
     case PANGO_ATTR_ALLOW_BREAKS:
+    case PANGO_ATTR_ALLOW_LINE_BREAKS:
     case PANGO_ATTR_INSERT_HYPHENS:
     case PANGO_ATTR_SHOW:
       g_string_append_printf (string, "%d", ((PangoAttrInt *)attr)->value);
diff --git a/tests/testattributes.c b/tests/testattributes.c
index 5149766f..423e4c31 100644
--- a/tests/testattributes.c
+++ b/tests/testattributes.c
@@ -70,6 +70,7 @@ test_attributes_basic (void)
   test_copy (pango_attr_show_new (PANGO_SHOW_SPACES));
   test_copy (pango_attr_insert_hyphens_new (FALSE));
   test_copy (pango_attr_line_break_new (PANGO_LINE_BREAK_CHAR, PANGO_LINE_BREAK_MANDATORY));
+  test_copy (pango_attr_allow_line_breaks_new (PANGO_LINE_BREAK_LINE));
 }
 
 static void


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