From bbec7e8697907a922f80c00b94f54b9b8634d264 Mon Sep 17 00:00:00 2001 From: Behdad Esfahbod Date: Wed, 26 Sep 2012 15:37:20 -0400 Subject: Add pango_shape_full() 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 --- docs/pango-sections.txt | 1 + modules/basic/basic-fc.c | 16 +++++------ pango/pango-context.c | 11 +++++--- pango/pango-engine-private.h | 14 +++++----- pango/pango-engine.c | 19 ++++++++----- pango/pango-engine.h | 12 +++++---- pango/pango-glyph.h | 7 +++++ pango/pango-impl-utils.h | 2 +- pango/pango-layout.c | 4 ++- pango/pango-utils.c | 2 +- pango/pango.def | 1 + pango/shape.c | 63 ++++++++++++++++++++++++++++++++++++++++---- 12 files changed, 115 insertions(+), 37 deletions(-) diff --git a/docs/pango-sections.txt b/docs/pango-sections.txt index 93f256c5..5f6ba73c 100644 --- a/docs/pango-sections.txt +++ b/docs/pango-sections.txt @@ -53,6 +53,7 @@ pango_default_break PangoLogAttr pango_shape +pango_shape_full pango_context_get_type diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c index 1def0552..ef0277ea 100644 --- a/modules/basic/basic-fc.c +++ b/modules/basic/basic-fc.c @@ -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)) diff --git a/pango/pango-context.c b/pango/pango-context.c index 2a1e44f3..341f92a6 100644 --- a/pango/pango-context.c +++ b/pango/pango-context.c @@ -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); diff --git a/pango/pango-engine-private.h b/pango/pango-engine-private.h index 7d743027..760144ec 100644 --- a/pango/pango-engine-private.h +++ b/pango/pango-engine-private.h @@ -27,12 +27,14 @@ 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, diff --git a/pango/pango-engine.c b/pango/pango-engine.c index 7b2c2fd6..8a3369f3 100644 --- a/pango/pango-engine.c +++ b/pango/pango-engine.c @@ -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 diff --git a/pango/pango-engine.h b/pango/pango-engine.h index d14a9827..51ac8c2e 100644 --- a/pango/pango-engine.h +++ b/pango/pango-engine.h @@ -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, diff --git a/pango/pango-glyph.h b/pango/pango-glyph.h index 4af63e78..91bae32a 100644 --- a/pango/pango-glyph.h +++ b/pango/pango-glyph.h @@ -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 diff --git a/pango/pango-impl-utils.h b/pango/pango-impl-utils.h index da3ef1cb..9570da80 100644 --- a/pango/pango-impl-utils.h +++ b/pango/pango-impl-utils.h @@ -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); diff --git a/pango/pango-layout.c b/pango/pango-layout.c index 1cd9c39a..48168d82 100644 --- a/pango/pango-layout.c +++ b/pango/pango-layout.c @@ -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) { diff --git a/pango/pango-utils.c b/pango/pango-utils.c index 112bc388..18ffa263 100644 --- a/pango/pango-utils.c +++ b/pango/pango-utils.c @@ -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) diff --git a/pango/pango.def b/pango/pango.def index e573e3db..ba1289ce 100644 --- a/pango/pango.def +++ b/pango/pango.def @@ -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 diff --git a/pango/shape.c b/pango/shape.c index 0fe3c953..63c36ab7 100644 --- a/pango/shape.c +++ b/pango/shape.c @@ -38,22 +38,75 @@ * #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, gint length, 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; } -- cgit v1.2.1