[pango] Bug 682421 - Arabic is broken with gravity hint=line when gravity is east/north



commit 59edf0e36ad88b1f3fdeda91b9c1614aafc7150f
Author: Behdad Esfahbod <behdad behdad org>
Date:   Thu Aug 23 11:04:04 2012 -0400

    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.

 modules/basic/basic-fc.c |  150 ++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 124 insertions(+), 26 deletions(-)
---
diff --git a/modules/basic/basic-fc.c b/modules/basic/basic-fc.c
index e263b4c..40f181f 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);



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