From 16b3f69d1c3260b8bdeb8c5058eaf4b6f4f2060a Mon Sep 17 00:00:00 2001 From: Adrian Johnson Date: Tue, 7 Feb 2012 16:03:45 +1030 Subject: [PATCH] cairo: adjust subtitute font width using first character in each string instead of the letter 'm'. Bug 36536 has a PDF where the non embedded font has bad widths for unused characters included the letter 'm'. --- poppler/CairoFontEngine.cc | 19 ++++++++----------- poppler/CairoFontEngine.h | 2 +- poppler/CairoOutputDev.cc | 35 ++++++++++++++++++++++++++++------- 3 files changed, 37 insertions(+), 19 deletions(-) diff --git a/poppler/CairoFontEngine.cc b/poppler/CairoFontEngine.cc index c9d2d0c..7e8ba91 100644 --- a/poppler/CairoFontEngine.cc +++ b/poppler/CairoFontEngine.cc @@ -104,21 +104,13 @@ CairoFont::getGlyph(CharCode code, } double -CairoFont::getSubstitutionCorrection(GfxFont *gfxFont) +CairoFont::getSubstitutionCorrection(GfxFont *gfxFont, CharCode code) { double w1, w2; - CharCode code; - char *name; // for substituted fonts: adjust the font matrix -- compare the - // width of 'm' in the original font and the substituted font + // width of the character in the original font and the substituted font if (isSubstitute() && !gfxFont->isCIDFont()) { - for (code = 0; code < 256; ++code) { - if ((name = ((Gfx8BitFont *)gfxFont)->getCharName(code)) && - name[0] == 'm' && name[1] == '\0') { - break; - } - } if (code < 256) { w1 = ((Gfx8BitFont *)gfxFont)->getWidth(code); { @@ -129,8 +121,13 @@ CairoFont::getSubstitutionCorrection(GfxFont *gfxFont) cairo_font_options_set_hint_metrics(options, CAIRO_HINT_METRICS_OFF); cairo_scaled_font_t *scaled_font = cairo_scaled_font_create(cairo_font_face, &m, &m, options); + cairo_glyph_t glyph; + glyph.index = getGlyph(code, NULL, 0); + glyph.x = 0; + glyph.y = 0; + cairo_text_extents_t extents; - cairo_scaled_font_text_extents(scaled_font, "m", &extents); + cairo_scaled_font_glyph_extents(scaled_font, &glyph, 1, &extents); cairo_scaled_font_destroy(scaled_font); cairo_font_options_destroy(options); diff --git a/poppler/CairoFontEngine.h b/poppler/CairoFontEngine.h index 6335348..5a1a5ca 100644 --- a/poppler/CairoFontEngine.h +++ b/poppler/CairoFontEngine.h @@ -53,7 +53,7 @@ public: virtual GBool matches(Ref &other, GBool printing); cairo_font_face_t *getFontFace(void); unsigned long getGlyph(CharCode code, Unicode *u, int uLen); - double getSubstitutionCorrection(GfxFont *gfxFont); + double getSubstitutionCorrection(GfxFont *gfxFont, CharCode code); GBool isSubstitute() { return substitute; } protected: diff --git a/poppler/CairoOutputDev.cc b/poppler/CairoOutputDev.cc index dab1e47..8ae448a 100644 --- a/poppler/CairoOutputDev.cc +++ b/poppler/CairoOutputDev.cc @@ -607,15 +607,11 @@ void CairoOutputDev::updateFont(GfxState *state) { use_show_text_glyphs = state->getFont()->hasToUnicodeCMap() && cairo_surface_has_show_text_glyphs (cairo_get_target (cairo)); - + double fontSize = state->getFontSize(); double *m = state->getTextMat(); - /* NOTE: adjusting by a constant is hack. The correct solution - * is probably to use user-fonts and compute the scale on a per - * glyph basis instead of for the entire font */ - double w = currentFont->getSubstitutionCorrection(state->getFont()); - matrix.xx = m[0] * fontSize * state->getHorizScaling() * w; - matrix.yx = m[1] * fontSize * state->getHorizScaling() * w; + matrix.xx = m[0] * fontSize * state->getHorizScaling(); + matrix.yx = m[1] * fontSize * state->getHorizScaling(); matrix.xy = -m[2] * fontSize; matrix.yy = -m[3] * fontSize; matrix.x0 = 0; @@ -1123,6 +1119,31 @@ void CairoOutputDev::drawChar(GfxState *state, double x, double y, CharCode code, int nBytes, Unicode *u, int uLen) { if (currentFont) { + + /* Adjust width of substitute fonts to match the width of the + * first character in the string. (Bug 36536) */ + if (glyphCount == 0 && currentFont->isSubstitute()) { + double w = currentFont->getSubstitutionCorrection(state->getFont(), code); + if (w != 1.0) { + /* NOTE: adjusting by a constant is hack. The correct solution + * is probably to use user-fonts and compute the scale on a per + * glyph basis instead of for the entire font */ + double fontSize = state->getFontSize(); + double *m = state->getTextMat(); + cairo_matrix_t matrix; + matrix.xx = m[0] * fontSize * state->getHorizScaling() * w; + matrix.yx = m[1] * fontSize * state->getHorizScaling() * w; + matrix.xy = -m[2] * fontSize; + matrix.yy = -m[3] * fontSize; + matrix.x0 = 0; + matrix.y0 = 0; + + LOG(printf ("substitute font matrix: %f %f %f %f\n", matrix.xx, matrix.yx, matrix.xy, matrix.yy)); + + cairo_set_font_matrix (cairo, &matrix); + } + } + glyphs[glyphCount].index = currentFont->getGlyph (code, u, uLen); glyphs[glyphCount].x = x - originX; glyphs[glyphCount].y = y - originY; -- 1.7.5.4