Add pango_shape_full()
authorBehdad Esfahbod <behdad@behdad.org>
Wed, 26 Sep 2012 19:37:20 +0000 (15:37 -0400)
committerBehdad Esfahbod <behdad@behdad.org>
Wed, 26 Sep 2012 19:37:20 +0000 (15:37 -0400)
Variant of pango_shape() that takes the full paragraph text as input.
This is then passed in entirety to HarfBuzz, which would allow certain
cross-run interactions (in Arabic for example).

When combined with upcoming HarfBuzz 0.9.5+, this fixes:

Red Hat Bug 858736 - [Spanish] Stray dotted circle rendered
https://bugzilla.redhat.com/show_bug.cgi?id=858736

and partially:

Bug 313181 - color changes break arabic shaping
https://bugzilla.gnome.org/show_bug.cgi?id=313181

12 files changed:
docs/pango-sections.txt
modules/basic/basic-fc.c
pango/pango-context.c
pango/pango-engine-private.h
pango/pango-engine.c
pango/pango-engine.h
pango/pango-glyph.h
pango/pango-impl-utils.h
pango/pango-layout.c
pango/pango-utils.c
pango/pango.def
pango/shape.c

index 93f256c..5f6ba73 100644 (file)
@@ -53,6 +53,7 @@ pango_default_break
 PangoLogAttr
 <SUBSECTION>
 pango_shape
+pango_shape_full
 
 <SUBSECTION Private>
 pango_context_get_type
index 1def055..ef0277e 100644 (file)
@@ -295,12 +295,14 @@ pango_fc_get_hb_font_funcs (void)
 
 
 static void
-basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
-                   PangoFont        *font,
-                   const char       *text,
-                   gint              length,
+basic_engine_shape (PangoEngineShape    *engine G_GNUC_UNUSED,
+                   PangoFont           *font,
+                   const char          *item_text,
+                   unsigned int         item_length,
                    const PangoAnalysis *analysis,
-                   PangoGlyphString *glyphs)
+                   PangoGlyphString    *glyphs,
+                   const char          *paragraph_text,
+                   unsigned int         paragraph_length)
 {
   PangoFcHbContext context;
   PangoFcFont *fc_font;
@@ -317,8 +319,6 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
   guint i, num_glyphs;
 
   g_return_if_fail (font != NULL);
-  g_return_if_fail (text != NULL);
-  g_return_if_fail (length >= 0);
   g_return_if_fail (analysis != NULL);
 
   fc_font = PANGO_FC_FONT (font);
@@ -362,7 +362,7 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
   hb_buffer_set_script (hb_buffer, hb_glib_script_to_script (analysis->script));
   hb_buffer_set_language (hb_buffer, hb_language_from_string (pango_language_to_string (analysis->language), -1));
 
-  hb_buffer_add_utf8 (hb_buffer, text, length, 0, length);
+  hb_buffer_add_utf8 (hb_buffer, paragraph_text, paragraph_length, item_text - paragraph_text, item_length);
   hb_shape (hb_font, hb_buffer, NULL, 0);
 
   if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
index 2a1e44f..341f92a 100644 (file)
@@ -1646,6 +1646,7 @@ static void
 update_metrics_from_items (PangoFontMetrics *metrics,
                           PangoLanguage    *language,
                           const char       *text,
+                          unsigned int      text_len,
                           GList            *items)
 
 {
@@ -1671,7 +1672,9 @@ update_metrics_from_items (PangoFontMetrics *metrics,
          pango_font_metrics_unref (raw_metrics);
        }
 
-      pango_shape (text + item->offset, item->length, &item->analysis, glyphs);
+      pango_shape_full (text + item->offset, item->length,
+                       text, text_len,
+                       &item->analysis, glyphs);
       metrics->approximate_char_width += pango_glyph_string_get_width (glyphs);
     }
 
@@ -1716,6 +1719,7 @@ pango_context_get_metrics (PangoContext                 *context,
   PangoFontset *current_fonts = NULL;
   PangoFontMetrics *metrics;
   const char *sample_str;
+  unsigned int text_len;
   GList *items;
 
   g_return_val_if_fail (PANGO_IS_CONTEXT (context), NULL);
@@ -1730,9 +1734,10 @@ pango_context_get_metrics (PangoContext                 *context,
   metrics = get_base_metrics (current_fonts);
 
   sample_str = pango_language_get_sample_string (language);
-  items = itemize_with_font (context, sample_str, 0, strlen (sample_str), desc);
+  text_len = strlen (sample_str);
+  items = itemize_with_font (context, sample_str, 0, text_len, desc);
 
-  update_metrics_from_items (metrics, language, sample_str, items);
+  update_metrics_from_items (metrics, language, sample_str, text_len, items);
 
   g_list_foreach (items, (GFunc)pango_item_free, NULL);
   g_list_free (items);
index 7d74302..760144e 100644 (file)
 
 G_BEGIN_DECLS
 
-void               _pango_engine_shape_shape  (PangoEngineShape *engine,
-                                              PangoFont        *font,
-                                              const char       *text,
-                                              int               length,
-                                              const PangoAnalysis *analysis,
-                                              PangoGlyphString *glyphs);
+void               _pango_engine_shape_shape (PangoEngineShape    *engine,
+                                             PangoFont           *font,
+                                             const char          *item_text,
+                                             unsigned int         item_length,
+                                             const char          *paragraph_text,
+                                             unsigned int         paragraph_len,
+                                             const PangoAnalysis *analysis,
+                                             PangoGlyphString    *glyphs);
 PangoCoverageLevel _pango_engine_shape_covers (PangoEngineShape *engine,
                                               PangoFont        *font,
                                               PangoLanguage    *language,
index 7b2c2fd..8a3369f 100644 (file)
@@ -82,20 +82,25 @@ pango_engine_shape_class_init (PangoEngineShapeClass *class)
 }
 
 void
-_pango_engine_shape_shape (PangoEngineShape *engine,
-                          PangoFont        *font,
-                          const char       *text,
-                          int               length,
+_pango_engine_shape_shape (PangoEngineShape    *engine,
+                          PangoFont           *font,
+                          const char          *item_text,
+                          unsigned int         item_length,
+                          const char          *paragraph_text,
+                          unsigned int         paragraph_len,
                           const PangoAnalysis *analysis,
-                          PangoGlyphString *glyphs)
+                          PangoGlyphString    *glyphs)
 {
   glyphs->num_glyphs = 0;
 
   PANGO_ENGINE_SHAPE_GET_CLASS (engine)->script_shape (engine,
                                                       font,
-                                                      text, length,
+                                                      item_text,
+                                                      item_length,
                                                       analysis,
-                                                      glyphs);
+                                                      glyphs,
+                                                      paragraph_text,
+                                                      paragraph_len);
 }
 
 PangoCoverageLevel
index d14a982..51ac8c2 100644 (file)
@@ -186,12 +186,14 @@ struct _PangoEngineShapeClass
   PangoEngineClass parent_class;
 
   /*< public >*/
-  void (*script_shape) (PangoEngineShape *engine,
-                       PangoFont        *font,
-                       const char       *text,
-                       int               length,
+  void (*script_shape) (PangoEngineShape    *engine,
+                       PangoFont           *font,
+                       const char          *item_text,
+                       unsigned int         item_length,
                        const PangoAnalysis *analysis,
-                       PangoGlyphString *glyphs);
+                       PangoGlyphString    *glyphs,
+                       const char          *paragraph_text,
+                       unsigned int         paragraph_length);
   PangoCoverageLevel (*covers)   (PangoEngineShape *engine,
                                  PangoFont        *font,
                                  PangoLanguage    *language,
index 4af63e7..91bae32 100644 (file)
@@ -128,6 +128,13 @@ void pango_shape (const gchar      *text,
                  const PangoAnalysis *analysis,
                  PangoGlyphString *glyphs);
 
+void pango_shape_full (const gchar      *item_text,
+                      gint              item_length,
+                      const gchar      *paragraph_text,
+                      gint              paragraph_length,
+                      const PangoAnalysis *analysis,
+                      PangoGlyphString *glyphs);
+
 GList *pango_reorder_items (GList *logical_items);
 
 G_END_DECLS
index da3ef1c..9570da8 100644 (file)
@@ -36,7 +36,7 @@ G_BEGIN_DECLS
 
 /* Some functions for handling PANGO_ATTR_SHAPE */
 void _pango_shape_shape (const char       *text,
-                        gint              n_chars,
+                        unsigned int      n_chars,
                         PangoRectangle   *shape_ink,
                         PangoRectangle   *shape_logical,
                         PangoGlyphString *glyphs);
index 1cd9c39..48168d8 100644 (file)
@@ -3181,7 +3181,9 @@ shape_run (PangoLayoutLine *line,
                            state->properties.shape_ink_rect, state->properties.shape_logical_rect,
                            glyphs);
       else
-       pango_shape (layout->text + item->offset, item->length, &item->analysis, glyphs);
+       pango_shape_full (layout->text + item->offset, item->length,
+                         layout->text, layout->length,
+                         &item->analysis, glyphs);
 
       if (state->properties.letter_spacing)
        {
index 112bc38..18ffa26 100644 (file)
@@ -1131,7 +1131,7 @@ pango_extents_to_pixels (PangoRectangle *inclusive,
 
 void
 _pango_shape_shape (const char       *text,
-                   gint              n_chars,
+                   unsigned int      n_chars,
                    PangoRectangle   *shape_ink G_GNUC_UNUSED,
                    PangoRectangle   *shape_logical,
                    PangoGlyphString *glyphs)
index e573e3d..ba1289c 100644 (file)
@@ -369,6 +369,7 @@ EXPORTS
        pango_script_iter_new
        pango_script_iter_next
        pango_shape
+       pango_shape_full
        pango_skip_space
        pango_split_file_list
        pango_stretch_get_type
index 0fe3c95..63c36ab 100644 (file)
  * #PangoAnalysis structure returned from pango_itemize(),
  * convert the characters into glyphs. You may also pass
  * in only a substring of the item from pango_itemize().
+ *
+ * It is recommended that you use pango_shape_full() instead, since
+ * that API allows for shaping interaction happening across text item
+ * boundaries.
  */
 void
 pango_shape (const gchar      *text,
@@ -45,15 +49,64 @@ pango_shape (const gchar      *text,
             const PangoAnalysis *analysis,
             PangoGlyphString *glyphs)
 {
+  pango_shape_full (text, length, text, length, analysis, glyphs);
+}
+
+/**
+ * pango_shape_full:
+ * @item_text:        valid UTF-8 text to shape.
+ * @item_length:      the length (in bytes) of @item_text. -1 means nul-terminated text.
+ * @paragraph_text: (allow-none)  text of the paragraph (see details).  May be %NULL.
+ * @paragraph_length: the length (in bytes) of @paragraph_text. -1 means nul-terminated text.
+ * @analysis:  #PangoAnalysis structure from pango_itemize().
+ * @glyphs:    glyph string in which to store results.
+ *
+ * Given a segment of text and the corresponding
+ * #PangoAnalysis structure returned from pango_itemize(),
+ * convert the characters into glyphs. You may also pass
+ * in only a substring of the item from pango_itemize().
+ *
+ * This is similar to pango_shape(), except it also can optionally take
+ * the full paragraph text as input, which will then be used to perform
+ * certain cross-item shaping interactions.  If you have access to the broader
+ * text of which @item_text is part of, provide the broader text as
+ * @paragraph_text.  If @paragraph_text is %NULL, item text is used instead.
+ *
+ * Since: 1.32
+ */
+void
+pango_shape_full (const gchar      *item_text,
+                 gint              item_length,
+                 const gchar      *paragraph_text,
+                 gint              paragraph_length,
+                 const PangoAnalysis *analysis,
+                 PangoGlyphString *glyphs)
+{
   int i;
   int last_cluster;
 
   glyphs->num_glyphs = 0;
 
+  if (item_length == -1)
+    item_length = strlen (item_text);
+
+  if (!paragraph_text)
+    {
+      paragraph_text = item_text;
+      paragraph_length = item_length;
+    }
+  if (paragraph_length == -1)
+    paragraph_length = strlen (paragraph_text);
+
+  g_return_if_fail (paragraph_text <= item_text);
+  g_return_if_fail (paragraph_text + paragraph_length >= item_text + item_length);
+
   if (G_LIKELY (analysis->shape_engine && analysis->font))
     {
       _pango_engine_shape_shape (analysis->shape_engine, analysis->font,
-                                text, length, analysis, glyphs);
+                                item_text, item_length,
+                                paragraph_text, paragraph_length,
+                                analysis, glyphs);
 
       if (G_UNLIKELY (glyphs->num_glyphs == 0))
        {
@@ -90,9 +143,7 @@ pango_shape (const gchar      *text,
                    engine_name = "(unknown)";
 
                  g_warning ("shaping failure, expect ugly output. shape-engine='%s', font='%s', text='%.*s'",
-                            engine_name,
-                            font_name,
-                            length == -1 ? (gint) strlen (text) : length, text);
+                            engine_name, font_name, item_length, item_text);
 
                  g_object_set_data_full (G_OBJECT (analysis->shape_engine), font_name,
                                          GINT_TO_POINTER (1), NULL);
@@ -113,7 +164,9 @@ pango_shape (const gchar      *text,
       PangoEngineShape *fallback_engine = _pango_get_fallback_shaper ();
 
       _pango_engine_shape_shape (fallback_engine, analysis->font,
-                                text, length, analysis, glyphs);
+                                item_text, item_length,
+                                paragraph_text, paragraph_length,
+                                analysis, glyphs);
       if (G_UNLIKELY (!glyphs->num_glyphs))
         return;
     }