Commit bbec7e86 authored by Behdad Esfahbod's avatar Behdad Esfahbod

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
parent 1c151fef
......@@ -53,6 +53,7 @@ pango_default_break
PangoLogAttr
<SUBSECTION>
pango_shape
pango_shape_full
<SUBSECTION Private>
pango_context_get_type
......
......@@ -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))
......
......@@ -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);
......
......@@ -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,
......
......@@ -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
......
......@@ -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,
......
......@@ -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
......
......@@ -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);
......
......@@ -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)
{
......
......@@ -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)
......
......@@ -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
......
......@@ -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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment