summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2012-08-23 11:04:04 -0400
committerBehdad Esfahbod <behdad@behdad.org>2012-08-23 11:04:04 -0400
commit59edf0e36ad88b1f3fdeda91b9c1614aafc7150f (patch)
tree72c80e50809386ef96993a155d23b4ad45bbdd54
parent145f5e161cad5e711cf9907b3a1cdec19e9942e7 (diff)
downloadpango-59edf0e36ad88b1f3fdeda91b9c1614aafc7150f.tar.gz
Bug 682421 - Arabic is broken with gravity hint=line when gravity is east/north
Fix-up gravity and vertical support in HarfBuzz module. Still needs more work for vertical GPOS to work correctly, but this is a huge improvement already.
-rw-r--r--modules/basic/basic-fc.c150
1 files changed, 124 insertions, 26 deletions
diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c
index e263b4c7..40f181f3 100644
--- a/modules/basic/basic-fc.c
+++ b/modules/basic/basic-fc.c
@@ -26,7 +26,6 @@
#include <string.h>
#define PANGO_ENABLE_BACKEND 1 /* XXX */
-#include <glib/gprintf.h>
#include "pango-engine.h"
#include "pango-utils.h"
@@ -110,6 +109,8 @@ release_buffer (hb_buffer_t *buffer, gboolean free_buffer)
typedef struct _PangoFcHbContext {
FT_Face ft_face;
PangoFcFont *fc_font;
+ gboolean vertical;
+ int improper_sign;
} PangoFcHbContext;
static hb_bool_t
@@ -159,9 +160,9 @@ pango_fc_hb_font_get_glyph_contour_point (hb_font_t *font, void *font_data,
}
static hb_position_t
-pango_fc_hb_font_get_glyph_h_advance (hb_font_t *font, void *font_data,
- hb_codepoint_t glyph,
- void *user_data G_GNUC_UNUSED)
+pango_fc_hb_font_get_glyph_advance (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ void *user_data G_GNUC_UNUSED)
{
PangoFcHbContext *context = (PangoFcHbContext *) font_data;
PangoFcFont *fc_font = context->fc_font;
@@ -184,14 +185,75 @@ pango_fc_hb_font_get_glyph_extents (hb_font_t *font, void *font_data,
pango_font_get_glyph_extents ((PangoFont *) fc_font, glyph, &ink, NULL);
- extents->x_bearing = ink.x;
- extents->y_bearing = ink.y;
- extents->width = ink.width;
- extents->height = ink.height;
+ if (G_LIKELY (!context->vertical)) {
+ extents->x_bearing = ink.x;
+ extents->y_bearing = ink.y;
+ extents->width = ink.width;
+ extents->height = ink.height;
+ } else {
+ /* XXX */
+ extents->x_bearing = ink.x;
+ extents->y_bearing = ink.y;
+ extents->width = ink.height;
+ extents->height = ink.width;
+ }
return TRUE;
}
+static hb_bool_t
+pango_fc_hb_font_get_glyph_h_origin (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data G_GNUC_UNUSED)
+{
+ PangoFcHbContext *context = (PangoFcHbContext *) font_data;
+ FT_Face ft_face = context->ft_face;
+ int load_flags = FT_LOAD_DEFAULT;
+
+ if (!context->vertical) return TRUE;
+
+ if (FT_Load_Glyph (ft_face, glyph, load_flags))
+ return FALSE;
+
+ /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+ * have a Y growing upward. Hence the extra negation. */
+ *x = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX);
+ *y = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY));
+
+ /* XXX */
+ *x = -*x;
+ *y = *y;
+
+ return TRUE;
+}
+
+static hb_bool_t
+pango_fc_hb_font_get_glyph_v_origin (hb_font_t *font, void *font_data,
+ hb_codepoint_t glyph,
+ hb_position_t *x, hb_position_t *y,
+ void *user_data G_GNUC_UNUSED)
+{
+ PangoFcHbContext *context = (PangoFcHbContext *) font_data;
+ FT_Face ft_face = context->ft_face;
+ int load_flags = FT_LOAD_DEFAULT;
+
+ if (context->vertical) return TRUE;
+
+ if (FT_Load_Glyph (ft_face, glyph, load_flags))
+ return FALSE;
+
+ /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates
+ * have a Y growing upward. Hence the extra negation. */
+ *x = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX);
+ *y = PANGO_UNITS_26_6 (ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY));
+
+ /* XXX */
+
+ return TRUE;
+}
+
+
static hb_position_t
pango_fc_hb_font_get_h_kerning (hb_font_t *font, void *font_data,
hb_codepoint_t left_glyph, hb_codepoint_t right_glyph,
@@ -215,11 +277,15 @@ pango_fc_get_hb_font_funcs (void)
if (G_UNLIKELY (!funcs)) {
funcs = hb_font_funcs_create ();
hb_font_funcs_set_glyph_func (funcs, pango_fc_hb_font_get_glyph, NULL, NULL);
- /* XXX vertical */
- hb_font_funcs_set_glyph_h_advance_func (funcs, pango_fc_hb_font_get_glyph_h_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_h_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_v_advance_func (funcs, pango_fc_hb_font_get_glyph_advance, NULL, NULL);
+ hb_font_funcs_set_glyph_h_origin_func (funcs, pango_fc_hb_font_get_glyph_h_origin, NULL, NULL);
+ hb_font_funcs_set_glyph_v_origin_func (funcs, pango_fc_hb_font_get_glyph_v_origin, NULL, NULL);
+ hb_font_funcs_set_glyph_h_kerning_func (funcs, pango_fc_hb_font_get_h_kerning, NULL, NULL);
+ /* Don't need v_kerning. */
hb_font_funcs_set_glyph_extents_func (funcs, pango_fc_hb_font_get_glyph_extents, NULL, NULL);
hb_font_funcs_set_glyph_contour_point_func (funcs, pango_fc_hb_font_get_glyph_contour_point, NULL, NULL);
- hb_font_funcs_set_glyph_h_kerning_func (funcs, pango_fc_hb_font_get_h_kerning, NULL, NULL);
+ /* Don't need glyph_name / glyph_from_name */
}
return funcs;
@@ -241,6 +307,7 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
FT_Face ft_face;
hb_font_t *hb_font;
hb_buffer_t *hb_buffer;
+ hb_direction_t hb_direction;
gboolean free_buffer;
gboolean is_hinted;
hb_glyph_info_t *hb_glyph;
@@ -261,6 +328,8 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
/* TODO: Cache hb_font? */
context.ft_face = ft_face;
context.fc_font = fc_font;
+ context.vertical = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity);
+ context.improper_sign = PANGO_GRAVITY_IS_IMPROPER (analysis->gravity) ? -1 : +1;
hb_font = hb_font_create (hb_ft_face_create_cached (ft_face));
hb_font_set_funcs (hb_font,
pango_fc_get_hb_font_funcs (),
@@ -268,7 +337,9 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
NULL);
hb_font_set_scale (hb_font,
/* XXX CTM */
- (((guint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12),
+ context.improper_sign *
+ (((guint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12),
+ context.improper_sign *
-(((guint64) ft_face->size->metrics.y_scale * ft_face->units_per_EM) >> 12));
is_hinted = fc_font->is_hinted;
hb_font_set_ppem (hb_font,
@@ -276,18 +347,28 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
is_hinted ? ft_face->size->metrics.y_ppem : 0);
hb_buffer = acquire_buffer (&free_buffer);
+
+ hb_direction = PANGO_GRAVITY_IS_VERTICAL (analysis->gravity) ? HB_DIRECTION_TTB : HB_DIRECTION_LTR;
+ if (analysis->level % 2)
+ hb_direction = HB_DIRECTION_REVERSE (hb_direction);
+ if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
+ hb_direction = HB_DIRECTION_REVERSE (hb_direction);
+
/* setup buffer */
- hb_buffer_set_direction (hb_buffer, analysis->level % 2 != 0 ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);
+
+ hb_buffer_set_direction (hb_buffer, hb_direction);
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, text, length, 0, length);
hb_shape (hb_font, hb_buffer, NULL, 0);
+ if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
+ hb_buffer_reverse (hb_buffer);
+
/* buffer output */
num_glyphs = hb_buffer_get_length (hb_buffer);
hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);
- hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL);
pango_glyph_string_set_size (glyphs, num_glyphs);
last_cluster = -1;
for (i = 0; i < num_glyphs; i++)
@@ -295,20 +376,37 @@ basic_engine_shape (PangoEngineShape *engine G_GNUC_UNUSED,
glyphs->glyphs[i].glyph = hb_glyph->codepoint;
glyphs->log_clusters[i] = hb_glyph->cluster;
glyphs->glyphs[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
- last_cluster = glyphs->log_clusters[i];
-
- /* XXX
- if (is_hinted)
- advance = PANGO_UNITS_ROUND (advance);
- */
- glyphs->glyphs[i].geometry.width = hb_position->x_advance;
- glyphs->glyphs[i].geometry.x_offset = hb_position->x_offset;
- glyphs->glyphs[i].geometry.y_offset = hb_position->y_offset;
-
hb_glyph++;
- hb_position++;
+ last_cluster = glyphs->log_clusters[i];
}
+ hb_position = hb_buffer_get_glyph_positions (hb_buffer, NULL);
+ if (context.vertical)
+ for (i = 0; i < num_glyphs; i++)
+ {
+ /* XXX
+ if (is_hinted)
+ advance = PANGO_UNITS_ROUND (advance);
+ */
+ glyphs->glyphs[i].geometry.width = hb_position->y_advance;
+ /* XXX */
+ glyphs->glyphs[i].geometry.x_offset = hb_position->y_offset;
+ glyphs->glyphs[i].geometry.y_offset = -hb_position->x_offset;
+ hb_position++;
+ }
+ else /* horizontal */
+ for (i = 0; i < num_glyphs; i++)
+ {
+ /* XXX
+ if (is_hinted)
+ advance = PANGO_UNITS_ROUND (advance);
+ */
+ glyphs->glyphs[i].geometry.width = hb_position->x_advance;
+ glyphs->glyphs[i].geometry.x_offset = hb_position->x_offset;
+ glyphs->glyphs[i].geometry.y_offset = hb_position->y_offset;
+ hb_position++;
+ }
+
release_buffer (hb_buffer, free_buffer);
hb_font_destroy (hb_font);
pango_fc_font_unlock_face (fc_font);