[pango] Fix PangoFc with non-identity scale matrix (again!)



commit 061633100aa120262db2acf9486bb590b2e0862e
Author: Behdad Esfahbod <behdad behdad org>
Date:   Mon May 11 17:16:40 2015 -0700

    Fix PangoFc with non-identity scale matrix (again!)
    
    https://bugzilla.gnome.org/show_bug.cgi?id=700592

 examples/cairosimple.c |   31 +++++++++++----
 pango/pangofc-shape.c  |   98 +++++++++++++++++++++++++++++++++--------------
 2 files changed, 91 insertions(+), 38 deletions(-)
---
diff --git a/examples/cairosimple.c b/examples/cairosimple.c
index faef326..881bac5 100644
--- a/examples/cairosimple.c
+++ b/examples/cairosimple.c
@@ -6,9 +6,16 @@
 static void
 draw_text (cairo_t *cr)
 {
-#define RADIUS 150
-#define N_WORDS 10
-#define FONT "Sans Bold 27"
+#define RADIUS 200
+#define N_WORDS 8
+#define FONT_WITH_MANUAL_SIZE "Times new roman,Sans"
+#define FONT_SIZE 36
+#define DEVICE_DPI 72
+
+/* The following number applies a cairo CTM.  Tests for
+ * https://bugzilla.gnome.org/show_bug.cgi?id=700592
+ */
+#define TWEAKABLE_SCALE ((double) 0.1)
 
   PangoLayout *layout;
   PangoFontDescription *desc;
@@ -16,13 +23,18 @@ draw_text (cairo_t *cr)
 
   /* Center coordinates on the middle of the region we are drawing
    */
-  cairo_translate (cr, RADIUS, RADIUS);
+  cairo_translate (cr, RADIUS / TWEAKABLE_SCALE, RADIUS / TWEAKABLE_SCALE);
 
   /* Create a PangoLayout, set the font and text */
   layout = pango_cairo_create_layout (cr);
 
-  pango_layout_set_text (layout, "Text", -1);
-  desc = pango_font_description_from_string (FONT);
+  pango_layout_set_text (layout, "Test\nسَلام", -1);
+
+  desc = pango_font_description_from_string (FONT_WITH_MANUAL_SIZE);
+  pango_font_description_set_absolute_size(desc, FONT_SIZE * DEVICE_DPI * PANGO_SCALE / (72.0 * 
TWEAKABLE_SCALE));
+  //pango_font_description_set_size(desc, 27 * PANGO_SCALE / TWEAKABLE_SCALE);
+
+  printf("PANGO_SCALE = %d\n", PANGO_SCALE);
   pango_layout_set_font_description (layout, desc);
   pango_font_description_free (desc);
 
@@ -45,7 +57,7 @@ draw_text (cairo_t *cr)
       pango_cairo_update_layout (cr, layout);
 
       pango_layout_get_size (layout, &width, &height);
-      cairo_move_to (cr, - ((double)width / PANGO_SCALE) / 2, - RADIUS);
+      cairo_move_to (cr,( - (((double)width) / PANGO_SCALE) / 2.0) , (- RADIUS)  / TWEAKABLE_SCALE);
       pango_cairo_show_layout (cr, layout);
 
       cairo_restore (cr);
@@ -68,12 +80,13 @@ int main (int argc, char **argv)
       return 1;
     }
 
-  filename = argv[1];
+     filename = argv[1];
 
   surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                       2 * RADIUS, 2 * RADIUS);
+                                        2 * RADIUS, 2 * RADIUS);
   cr = cairo_create (surface);
 
+  cairo_scale(cr, 1 * TWEAKABLE_SCALE, 1 * TWEAKABLE_SCALE);
 
   cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
   cairo_paint (cr);
diff --git a/pango/pangofc-shape.c b/pango/pangofc-shape.c
index f0ea784..2f6c7cc 100644
--- a/pango/pangofc-shape.c
+++ b/pango/pangofc-shape.c
@@ -24,8 +24,7 @@
 
 #include "config.h"
 #include <string.h>
-
-#define PANGO_ENABLE_BACKEND 1 /* XXX */
+#include <math.h>
 
 #include "pangofc-private.h"
 #include <hb-ft.h>
@@ -84,7 +83,7 @@ typedef struct _PangoFcHbContext {
   FT_Face ft_face;
   PangoFcFont *fc_font;
   gboolean vertical;
-  int improper_sign;
+  double x_scale, y_scale; /* CTM scales. */
 } PangoFcHbContext;
 
 static hb_bool_t
@@ -218,6 +217,7 @@ pango_fc_hb_font_get_glyph_v_origin (hb_font_t *font, void *font_data,
   FT_Face ft_face = context->ft_face;
   int load_flags = FT_LOAD_DEFAULT;
 
+  /* pangocairo-fc configures font in vertical origin for vertical writing. */
   if (context->vertical) return TRUE;
 
   if (FT_Load_Glyph (ft_face, glyph, load_flags))
@@ -246,7 +246,7 @@ pango_fc_hb_font_get_h_kerning (hb_font_t *font, void *font_data,
   if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerning))
     return 0;
 
-  return PANGO_UNITS_26_6 (kerning.x);
+  return PANGO_UNITS_26_6 (kerning.x * context->x_scale);
 }
 
 static hb_font_funcs_t *
@@ -283,13 +283,13 @@ _pango_fc_shape (PangoFont           *font,
 {
   PangoFcHbContext context;
   PangoFcFont *fc_font;
+  PangoFcFontKey *key;
   FT_Face ft_face;
   hb_face_t *hb_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;
   hb_glyph_position_t *hb_position;
   int last_cluster;
@@ -297,6 +297,8 @@ _pango_fc_shape (PangoFont           *font,
   unsigned int item_offset = item_text - paragraph_text;
   hb_feature_t features[32];
   unsigned int num_features = 0;
+  double x_scale_inv, y_scale_inv;
+  PangoGlyphInfo *infos;
 
   g_return_if_fail (font != NULL);
   g_return_if_fail (analysis != NULL);
@@ -307,10 +309,24 @@ _pango_fc_shape (PangoFont           *font,
     return;
 
   /* TODO: Cache hb_font? */
+
+  x_scale_inv = y_scale_inv = 1.0;
+  key = _pango_fc_font_get_font_key (fc_font);
+  if (key)
+  {
+    const PangoMatrix *matrix = pango_fc_font_key_get_matrix (key);
+    pango_matrix_get_font_scale_factors (matrix, &x_scale_inv, &y_scale_inv);
+  }
+  if (PANGO_GRAVITY_IS_IMPROPER (analysis->gravity))
+  {
+    x_scale_inv = -x_scale_inv;
+    y_scale_inv = -y_scale_inv;
+  }
+  context.x_scale = 1. / x_scale_inv;
+  context.y_scale = 1. / y_scale_inv;
   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_face = hb_ft_face_create_cached (ft_face);
   hb_font = hb_font_create (hb_face);
   hb_font_set_funcs (hb_font,
@@ -318,15 +334,11 @@ _pango_fc_shape (PangoFont           *font,
                     &context,
                     NULL);
   hb_font_set_scale (hb_font,
-                    /* XXX CTM */
-                    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;
+                    +(((gint64) ft_face->size->metrics.x_scale * ft_face->units_per_EM) >> 12) * 
context.x_scale,
+                    -(((gint64) ft_face->size->metrics.y_scale * ft_face->units_per_EM) >> 12) * 
context.y_scale);
   hb_font_set_ppem (hb_font,
-                   is_hinted ? ft_face->size->metrics.x_ppem : 0,
-                   is_hinted ? ft_face->size->metrics.y_ppem : 0);
+                   fc_font->is_hinted ? ft_face->size->metrics.x_ppem : 0,
+                   fc_font->is_hinted ? ft_face->size->metrics.y_ppem : 0);
 
   hb_buffer = acquire_buffer (&free_buffer);
 
@@ -374,12 +386,13 @@ _pango_fc_shape (PangoFont           *font,
   num_glyphs = hb_buffer_get_length (hb_buffer);
   hb_glyph = hb_buffer_get_glyph_infos (hb_buffer, NULL);
   pango_glyph_string_set_size (glyphs, num_glyphs);
+  infos = glyphs->glyphs;
   last_cluster = -1;
   for (i = 0; i < num_glyphs; i++)
     {
-      glyphs->glyphs[i].glyph = hb_glyph->codepoint;
+      infos[i].glyph = hb_glyph->codepoint;
       glyphs->log_clusters[i] = hb_glyph->cluster - item_offset;
-      glyphs->glyphs[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
+      infos[i].attr.is_cluster_start = glyphs->log_clusters[i] != last_cluster;
       hb_glyph++;
       last_cluster = glyphs->log_clusters[i];
     }
@@ -388,27 +401,54 @@ _pango_fc_shape (PangoFont           *font,
   if (context.vertical)
     for (i = 0; i < num_glyphs; i++)
       {
-        unsigned int advance = hb_position->y_advance;
-       if (is_hinted)
-         advance = PANGO_UNITS_ROUND (advance);
-       glyphs->glyphs[i].geometry.width    = advance;
-       /* XXX */
-       glyphs->glyphs[i].geometry.x_offset = hb_position->y_offset;
-       glyphs->glyphs[i].geometry.y_offset = -hb_position->x_offset;
+        /* 90 degrees rotation counter-clockwise. */
+       infos[i].geometry.width    =  hb_position->y_advance;
+       infos[i].geometry.x_offset =  hb_position->y_offset;
+       infos[i].geometry.y_offset = -hb_position->x_offset;
        hb_position++;
       }
   else /* horizontal */
     for (i = 0; i < num_glyphs; i++)
       {
-        unsigned int advance = hb_position->x_advance;
-       if (is_hinted)
-         advance = PANGO_UNITS_ROUND (advance);
-       glyphs->glyphs[i].geometry.width    = advance;
-       glyphs->glyphs[i].geometry.x_offset = hb_position->x_offset;
-       glyphs->glyphs[i].geometry.y_offset = hb_position->y_offset;
+       infos[i].geometry.width    = hb_position->x_advance;
+       infos[i].geometry.x_offset = hb_position->x_offset;
+       infos[i].geometry.y_offset = hb_position->y_offset;
        hb_position++;
       }
 
+  if (fc_font->is_hinted)
+  {
+    if (context.x_scale == 1.0 && context.y_scale == 1.0)
+      {
+       for (i = 0; i < num_glyphs; i++)
+         infos[i].geometry.width = PANGO_UNITS_ROUND (infos[i].geometry.width);
+      }
+    else
+      {
+#if 0
+       if (context.vertical)
+         {
+           /* XXX */
+           double tmp = x_scale;
+           x_scale = y_scale;
+           y_scale = -tmp;
+         }
+#endif
+#define HINT(value, scale_inv, scale) (PANGO_UNITS_ROUND ((int) ((value) * scale)) * scale_inv)
+#define HINT_X(value) HINT ((value), context.x_scale, x_scale_inv)
+#define HINT_Y(value) HINT ((value), context.y_scale, y_scale_inv)
+       for (i = 0; i < num_glyphs; i++)
+         {
+           infos[i].geometry.width    = HINT_X (infos[i].geometry.width);
+           infos[i].geometry.x_offset = HINT_X (infos[i].geometry.x_offset);
+           infos[i].geometry.y_offset = HINT_Y (infos[i].geometry.y_offset);
+         }
+#undef HINT_Y
+#undef HINT_X
+#undef HINT
+      }
+  }
+
   release_buffer (hb_buffer, free_buffer);
   hb_font_destroy (hb_font);
   hb_face_destroy (hb_face);


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