summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBehdad Esfahbod <behdad@behdad.org>2009-11-17 19:31:23 -0500
committerBehdad Esfahbod <behdad@behdad.org>2009-11-17 19:31:23 -0500
commitd9abcaf566e9cd7f702c98958f99f90fd53b4c0b (patch)
tree56795cbfc1a72f0c4b76fb456b97b1ac86e3bb7f
parent4ccabeffc20f899163bf610356871afb197e9bf8 (diff)
downloadpango-d9abcaf566e9cd7f702c98958f99f90fd53b4c0b.tar.gz
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.
-rw-r--r--pango/pango-ot-buffer.c56
-rw-r--r--pango/pangofc-font.c19
-rw-r--r--pango/pangofc-private.h44
3 files changed, 113 insertions, 6 deletions
diff --git a/pango/pango-ot-buffer.c b/pango/pango-ot-buffer.c
index 533c3102..f5a68512 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 8fc5a579..ad234beb 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 0612a692..e7c08bff 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__ */