[pango] Bug 341481 - pangocairo kerning problem with nonidentity scaling



commit d9abcaf566e9cd7f702c98958f99f90fd53b4c0b
Author: Behdad Esfahbod <behdad behdad org>
Date:   Tue Nov 17 19:31:23 2009 -0500

    Bug 341481 - pangocairo kerning problem with nonidentity scaling
    
    Finally fix this embarrassing bug.  The fix is a kludge, but it will
    be redone for 1.28 (harfbuzz-ng) anyway.

 pango/pango-ot-buffer.c |   56 +++++++++++++++++++++++++++++++++++++++++-----
 pango/pangofc-font.c    |   19 ++++++++++++++++
 pango/pangofc-private.h |   44 ++++++++++++++++++++++++++++++++++++
 3 files changed, 113 insertions(+), 6 deletions(-)
---
diff --git a/pango/pango-ot-buffer.c b/pango/pango-ot-buffer.c
index 533c310..f5a6851 100644
--- a/pango/pango-ot-buffer.c
+++ b/pango/pango-ot-buffer.c
@@ -207,6 +207,9 @@ pango_ot_buffer_get_glyphs (const PangoOTBuffer  *buffer,
 static void
 apply_gpos_ltr (PangoGlyphString    *glyphs,
 		hb_glyph_position_t *positions,
+		gboolean             scale,
+		double               xscale,
+		double               yscale,
 		gboolean             is_hinted)
 {
   int i;
@@ -224,6 +227,8 @@ apply_gpos_ltr (PangoGlyphString    *glyphs,
 
       if (is_hinted)
 	adjustment = PANGO_UNITS_ROUND (adjustment);
+      if (G_UNLIKELY (scale))
+	adjustment *= xscale;
 
       if (positions[i].new_advance)
 	glyphs->glyphs[i].geometry.width  = adjustment;
@@ -241,14 +246,25 @@ apply_gpos_ltr (PangoGlyphString    *glyphs,
       for (j = back; j < i; j++)
 	glyphs->glyphs[i].geometry.x_offset -= glyphs->glyphs[j].geometry.width;
 
-      glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
-      glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
+      if (G_UNLIKELY (scale))
+        {
+	  glyphs->glyphs[i].geometry.x_offset += xscale * PANGO_UNITS_26_6(x_pos);
+	  glyphs->glyphs[i].geometry.y_offset -= yscale * PANGO_UNITS_26_6(y_pos);
+	}
+      else
+        {
+	  glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
+	  glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
+	}
     }
 }
 
 static void
 apply_gpos_rtl (PangoGlyphString    *glyphs,
 		hb_glyph_position_t *positions,
+		gboolean             scale,
+		double               xscale,
+		double               yscale,
 		gboolean             is_hinted)
 {
   int i;
@@ -268,6 +284,8 @@ apply_gpos_rtl (PangoGlyphString    *glyphs,
 
       if (is_hinted)
 	adjustment = PANGO_UNITS_ROUND (adjustment);
+      if (G_UNLIKELY (scale))
+	adjustment *= xscale;
 
       if (positions[i_rev].new_advance)
 	glyphs->glyphs[i].geometry.width  = adjustment;
@@ -287,8 +305,16 @@ apply_gpos_rtl (PangoGlyphString    *glyphs,
       for (j = i; j < back; j++)
 	glyphs->glyphs[i].geometry.x_offset += glyphs->glyphs[j].geometry.width;
 
-      glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
-      glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
+      if (G_UNLIKELY (scale))
+        {
+	  glyphs->glyphs[i].geometry.x_offset += xscale * PANGO_UNITS_26_6(x_pos);
+	  glyphs->glyphs[i].geometry.y_offset -= yscale * PANGO_UNITS_26_6(y_pos);
+	}
+      else
+        {
+	  glyphs->glyphs[i].geometry.x_offset += PANGO_UNITS_26_6(x_pos);
+	  glyphs->glyphs[i].geometry.y_offset -= PANGO_UNITS_26_6(y_pos);
+	}
     }
 }
 
@@ -376,10 +402,28 @@ pango_ot_buffer_output (const PangoOTBuffer *buffer,
   positions = hb_buffer_get_glyph_positions (buffer->buffer);
   if (buffer->applied_gpos)
     {
+      gboolean scale = FALSE;
+      double xscale = 1, yscale = 1;
+      PangoFcFontKey *key = _pango_fc_font_get_font_key (buffer->font);
+
+      /* This is a kludge, and dupped in pango_fc_font_kern_glyphs().
+       * Should move the scale factor to PangoFcFont layer. */
+      if (key) {
+	const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
+	PangoMatrix identity = PANGO_MATRIX_INIT;
+	if (G_UNLIKELY (matrix && 0 != memcmp (&identity, matrix, 4 * sizeof (double))))
+	  {
+	    scale = TRUE;
+	    pango_matrix_get_font_scale_factors (matrix, &xscale, &yscale);
+	    if (xscale) xscale = 1 / xscale;
+	    if (yscale) yscale = 1 / yscale;
+	  }
+      }
+
       if (buffer->rtl)
-	apply_gpos_rtl (glyphs, positions, buffer->font->is_hinted);
+	apply_gpos_rtl (glyphs, positions, scale, xscale, yscale, buffer->font->is_hinted);
       else
-	apply_gpos_ltr (glyphs, positions, buffer->font->is_hinted);
+	apply_gpos_ltr (glyphs, positions, scale, xscale, yscale, buffer->font->is_hinted);
     }
   else
     {
diff --git a/pango/pangofc-font.c b/pango/pangofc-font.c
index 8fc5a57..ad234be 100644
--- a/pango/pangofc-font.c
+++ b/pango/pangofc-font.c
@@ -807,6 +807,9 @@ pango_fc_font_kern_glyphs (PangoFcFont      *font,
   FT_Vector kerning;
   int i;
   gboolean hinting = font->is_hinted;
+  gboolean scale = FALSE;
+  double xscale = 1;
+  PangoFcFontKey *key;
 
   g_return_if_fail (PANGO_IS_FC_FONT (font));
   g_return_if_fail (glyphs != NULL);
@@ -821,6 +824,20 @@ pango_fc_font_kern_glyphs (PangoFcFont      *font,
       return;
     }
 
+  /* This is a kludge, and dupped in pango_ot_buffer_output().
+   * Should move the scale factor to PangoFcFont layer. */
+  key = _pango_fc_font_get_font_key (font);
+  if (key) {
+    const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
+    PangoMatrix identity = PANGO_MATRIX_INIT;
+    if (G_UNLIKELY (matrix && 0 != memcmp (&identity, matrix, 2 * sizeof (double))))
+      {
+	scale = TRUE;
+	pango_matrix_get_font_scale_factors (matrix, &xscale, NULL);
+	if (xscale) xscale = 1 / xscale;
+      }
+  }
+
   for (i = 1; i < glyphs->num_glyphs; ++i)
     {
       error = FT_Get_Kerning (face,
@@ -834,6 +851,8 @@ pango_fc_font_kern_glyphs (PangoFcFont      *font,
 
 	if (hinting)
 	  adjustment = PANGO_UNITS_ROUND (adjustment);
+	if (G_UNLIKELY (scale))
+	  adjustment *= xscale;
 
 	glyphs->glyphs[i-1].geometry.width += adjustment;
       }
diff --git a/pango/pangofc-private.h b/pango/pangofc-private.h
index 0612a69..e7c08bf 100644
--- a/pango/pangofc-private.h
+++ b/pango/pangofc-private.h
@@ -93,6 +93,50 @@ void            pango_fc_font_get_raw_extents    (PangoFcFont    *font,
 PangoFontMetrics *pango_fc_font_create_metrics_for_context (PangoFcFont   *font,
 							    PangoContext  *context);
 
+
+
+/* To be made public at some point */
+
+#include <math.h>
+
+static G_GNUC_UNUSED void
+pango_matrix_get_font_scale_factors (const PangoMatrix *matrix,
+				     double *xscale, double *yscale)
+{
+/*
+ * Based on cairo-matrix.c:_cairo_matrix_compute_scale_factors()
+ *
+ * Copyright 2005, Keith Packard
+ */
+  double major = 0, minor = 0;
+
+  if (matrix) {
+    double det = matrix->xx * matrix->yy - matrix->yx * matrix->xy;
+
+    if (det)
+      {
+	double x = matrix->xx;
+	double y = matrix->yx;
+
+	major = sqrt (x*x + y*y);
+
+	/*
+	 * ignore mirroring
+	 */
+	if (det < 0)
+	  det = - det;
+
+	if (major)
+	  minor = det / major;
+      }
+  }
+
+  if (xscale)
+    *xscale = major;
+  if (yscale)
+    *yscale = minor;
+}
+
 G_END_DECLS
 
 #endif /* __PANGOFC_PRIVATE_H__ */



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