cannot use OpenType fonts if they are installed locally on Windows and same font is loaded via WOFF #1620
Comments
Can you post your HTML/CSS as a gist? |
Pick your flavor. https://www.google.com/fonts#UsePlace:use/Collection:Roboto The only variable that makes any difference is whether the same font (literally, the .ttfs provided by Google from the same site) exists in c:\Windows\Fonts\ or not. I've confirmed this on Windows 8.1 Enterprise and Server 2012 R2. |
Woff from google fonts does not work due to css hacks (wkhtmltopdf does not load fallback urls) so I'd prefer a simpler test case. |
I would have to disagree because that's ALL I use (and so far, JUST Roboto) and it works fine (though still with SOME kerning issues) unless i also have the .ttf installed in c:\windows\fonts. In fact, it works better than fine. I HAD to do it because of the letter-spacing bug in wkhtmltopdf. My output was otherwise unreadable and the only reason I am using custom fonts was a desperate idea to find a solution to: https://code.google.com/p/wkhtmltopdf/issues/detail?id=72 |
Here's full test case with code that demonstrates that WKHTMLPDF 1.12 can and will use Google-hosted .woff files just fine: https://gist.github.com/rainabba/9996443 it includes a link to the following PDF which was created with WKHTMLTOPDF: http://goo.gl/qoc47N |
@ashkulz , hi friend, i have a grand problem, i am need to convert a file for pdf, but i have a page in PHP that i would like to convert in PDF, whiout the necessary to create at hand because are 60 pages. |
@brmartins: please post on StackOverflow or the mailing list if you need help on how to use wkhtmltopdf. |
@rainabba: when the font is installed on your Windows machine, is it an OpenType font? |
It is installed as an OpenType font and I'm seeing at least 2 of those 3 |
Looks like the patch attached to QTBUG-11387 does not help, I tried using diff --git a/src/gui/text/qfontengine_win.cpp b/src/gui/text/qfontengine_win.cpp
index 66a741c..2381241 100644
--- a/src/gui/text/qfontengine_win.cpp
+++ b/src/gui/text/qfontengine_win.cpp
@@ -196,12 +196,14 @@ void QFontEngineWin::getCMap()
HDC hdc = shared_dc();
SelectObject(hdc, hfont);
bool symb = false;
- if (ttf) {
- cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
- int size = 0;
- cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
- cmapTable.size(), &symb, &size);
- }
+
+ // Need to retrieve cmap table for OpenType PS as well as TTF fonts - these share the sfnt format.
+ // This should fail safely if the font doesn't have a cmap.
+ cmapTable = getSfntTable(qbswap<quint32>(MAKE_TAG('c', 'm', 'a', 'p')));
+ int size = 0;
+ cmap = QFontEngine::getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()),
+ cmapTable.size(), &symb, &size);
+
if (!cmap) {
ttf = false;
symb = false;
@@ -243,14 +245,14 @@ int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout
#if defined(Q_WS_WINCE)
{
#else
- if (symbol) {
+ if (symbol && cmap) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
if (!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
}
- } else if (ttf) {
+ } else if (cmap) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, QChar::mirroredChar(uc));
@@ -276,14 +278,14 @@ int QFontEngineWin::getGlyphIndexes(const QChar *str, int numChars, QGlyphLayout
#if defined(Q_WS_WINCE)
{
#else
- if (symbol) {
+ if (symbol && cmap) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
}
- } else if (ttf) {
+ } else if (cmap) {
for (; i < numChars; ++i, ++glyph_pos) {
unsigned int uc = getChar(str, i, numChars);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
@@ -407,7 +409,7 @@ void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla
{
HGDIOBJ oldFont = 0;
HDC hdc = shared_dc();
- if (ttf && (flags & QTextEngine::DesignMetrics)) {
+ if (cmap && (flags & QTextEngine::DesignMetrics)) {
for(int i = 0; i < glyphs->numGlyphs; i++) {
unsigned int glyph = glyphs->glyphs[i];
if(int(glyph) >= designAdvancesSize) {
@@ -451,7 +453,7 @@ void QFontEngineWin::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFla
if (!oldFont)
oldFont = SelectObject(hdc, hfont);
- if (!ttf) {
+ if (!cmap) {
QChar ch[2] = { ushort(glyph), 0 };
int chrLen = 1;
if (glyph > 0xffff) {
@@ -486,7 +488,7 @@ glyph_metrics_t QFontEngineWin::boundingBox(const QGlyphLayout &glyphs)
for (int i = 0; i < glyphs.numGlyphs; ++i)
w += glyphs.effectiveAdvance(i);
- return glyph_metrics_t(0, -tm.tmAscent, w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
+ return glyph_metrics_t(0, -ascent(), w - lastRightBearing(glyphs), tm.tmHeight, w, 0);
}
#ifndef Q_WS_WINCE
@@ -521,7 +523,7 @@ bool QFontEngineWin::getOutlineMetrics(glyph_t glyph, const QTransform &t, glyph
}
uint format = GGO_METRICS;
- if (ttf)
+ if (cmap)
format |= GGO_GLYPH_INDEX;
res = GetGlyphOutline(hdc, glyph, format, &gm, 0, 0, &mat);
@@ -559,7 +561,7 @@ glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
GetCharABCWidthsFloat(hdc, ch, ch, &abc);
int width = qRound(abc.abcfB);
- return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -tm.tmAscent, width, tm.tmHeight, width, 0).transformed(t);
+ return glyph_metrics_t(QFixed::fromReal(abc.abcfA), -ascent(), width, tm.tmHeight, width, 0).transformed(t);
}
return glyphMetrics;
@@ -589,7 +591,7 @@ glyph_metrics_t QFontEngineWin::boundingBox(glyph_t glyph, const QTransform &t)
}
SelectObject(hdc, oldFont);
- return glyph_metrics_t(0, -tm.tmAscent, width, tm.tmHeight, advance, 0).transformed(t);
+ return glyph_metrics_t(0, -ascent(), width, tm.tmHeight, advance, 0).transformed(t);
#endif
}
@@ -802,7 +804,7 @@ bool QFontEngineWin::canRender(const QChar *string, int len)
}
}
}
- } else if (ttf) {
+ } else if (cmap) {
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(string, i, len);
if (getTrueTypeGlyphIndex(cmap, uc) == 0)
@@ -835,7 +837,7 @@ static inline QPointF qt_to_qpointf(const POINTFX &pt, qreal scale) {
#endif
static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
- QPainterPath *path, bool ttf, glyph_metrics_t *metric = 0, qreal scale = 1)
+ QPainterPath *path, bool cmap, glyph_metrics_t *metric = 0, qreal scale = 1)
{
#if defined(Q_WS_WINCE)
Q_UNUSED(glyph);
@@ -848,7 +850,7 @@ static bool addGlyphToPath(glyph_t glyph, const QFixedPoint &position, HDC hdc,
mat.eM21.fract = mat.eM12.fract = 0;
uint glyphFormat = GGO_NATIVE;
- if (ttf)
+ if (cmap)
glyphFormat |= GGO_GLYPH_INDEX;
GLYPHMETRICS gMetric;
@@ -956,7 +958,7 @@ void QFontEngineWin::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, in
HGDIOBJ oldfont = SelectObject(hdc, hf);
for(int i = 0; i < nglyphs; ++i) {
- if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, ttf, /*metric*/0,
+ if (!addGlyphToPath(glyphs[i], positions[i], hdc, path, cmap, /*metric*/0,
qreal(fontDef.pixelSize) / unitsPerEm)) {
// Some windows fonts, like "Modern", are vector stroke
// fonts, which are reported as TMPF_VECTOR but do not
@@ -1000,7 +1002,7 @@ int QFontEngineWin::synthesized() const
{
if(synthesized_flags == -1) {
synthesized_flags = 0;
- if(ttf) {
+ if(cmap) {
const DWORD HEAD = MAKE_TAG('h', 'e', 'a', 'd');
HDC hdc = shared_dc();
SelectObject(hdc, hfont);
@@ -1009,7 +1011,7 @@ int QFontEngineWin::synthesized() const
USHORT macStyle = getUShort(data);
if (tm.tmItalic && !(macStyle & 2))
synthesized_flags = SynthesizedItalic;
- if (fontDef.stretch != 100 && ttf)
+ if (fontDef.stretch != 100)
synthesized_flags |= SynthesizedStretch;
if (tm.tmWeight >= 500 && !(macStyle & 1))
synthesized_flags |= SynthesizedBold;
@@ -1066,14 +1068,14 @@ void QFontEngineWin::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_m
QFixedPoint p;
p.x = 0;
p.y = 0;
- addGlyphToPath(glyph, p, hdc, path, ttf, metrics);
+ addGlyphToPath(glyph, p, hdc, path, cmap, metrics);
DeleteObject(SelectObject(hdc, oldfont));
}
bool QFontEngineWin::getSfntTableData(uint tag, uchar *buffer, uint *length) const
{
- if (!ttf)
- return false;
+ // Need to retrieve tables for OpenType as well as TTF fonts - these share the sfnt format.
+ // This should fail safely if the font isn't hin sfnt format.
HDC hdc = shared_dc();
SelectObject(hdc, hfont);
DWORD t = qbswap<quint32>(tag);
@@ -1106,7 +1108,7 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin
bool has_transformation = t.type() > QTransform::TxTranslate;
#ifndef Q_WS_WINCE
- unsigned int options = ttf ? ETO_GLYPH_INDEX : 0;
+ unsigned int options = cmap ? ETO_GLYPH_INDEX : 0;
XFORM xform;
if (has_transformation) {
@@ -1124,7 +1126,7 @@ QNativeImage *QFontEngineWin::drawGDIGlyph(HFONT font, glyph_t glyph, int margin
SetWorldTransform(hdc, &xform);
HGDIOBJ old_font = SelectObject(hdc, font);
- int ggo_options = GGO_METRICS | (ttf ? GGO_GLYPH_INDEX : 0);
+ int ggo_options = GGO_METRICS | (cmap ? GGO_GLYPH_INDEX : 0);
GLYPHMETRICS tgm;
MAT2 mat;
memset(&mat, 0, sizeof(mat)); So it looks like an issue with Qt itself. I'll investigate a bit further, but I don't think that I'll be able to come up with a solution on my own. |
@rainabba: can you show screenshots of the kerning bug, so that I can figure out if a patch fixes the issue? For the and with the font installed it comes out as: |
A very similar, (if not the same) issue happens on linux, if a font is installed locally: Trying the same template with 0.12.1 and patched qt the bold or expaneded fonts won't get loaded. Even if using font-face and loading the font with url(path/to/font). But after deinstalling the font from global font-directory, everything works as expected. |
Can you verify if the output is better with |
The following screenshot show the same test code in Chrome 41 dev-m (looks as I'd expect) and a PDF generated with alpha-13.0 (note the highlighted areas). It looks like there has been some improvement from the previous version, but there are still some issues in both Arial and Roboto. I also undid my "rename-font.ttf" trick and reinstalled the Roboto fonts locally and I'm not getting blank pages now so I think the original bug has been resolved in 0.13, but not the kerning one that came up later in this discussion. Now that I look back at my last screenshot ( http://goo.gl/qoc47N ), it looks like overall, the kerning has just been spaced out more on pretty much everything so the things that were too close in Arial are now decent, the things that where decent are too spaced and on Roboto, things appear too spaced, but the culprit may just be the 'o' which appears frequently in my example. Here is the newer pdf: http://goo.gl/og4CTd |
Kerning issue is tracked in #1527, marking this issue closed for 0.13.x |
My development environment was working great but when I ran the EXACT same Node.js app using wkhtmltox-win64_0.12.0-03c001d.exe to generate PDFs on my production machine, the PDFs I got were effectively blank. There were hints of structure though so I suspected it was a font issue.
In the end, I found that my workstation started doing the exact same thing right after I installed the fonts locally (c:\windows\fonts) so I uninstalled the fonts locally and the issue went away. When I uninstalled on the production machine (Windows Server 2012 R2), the issue also resolved itself there.
My pages are using .woff (built from the same .ttf files that were installed using the same name) included through CSS. It didn't matter if the declaration was made on the page in the critical rendering path or if it was a linked CSS file. It also didn't matter if I used externally hosted files or local to my site (I tested all this in the hopes something would resolve the issue).
I'm going to test further to see if I can name the local fonts differently without an issue but I can't imagine why this would create a problem. If anything, I'd think that having the fonts installed locally should be better and if such a thing is problematic, why isn't it for default fonts like Arial?
If I can provide any more info to help, please let me know what.
The following sound EXACTLY like my issue though they're all unresolved so I wonder if it is related or not:
https://code.google.com/p/wkhtmltopdf/issues/detail?id=688
The text was updated successfully, but these errors were encountered: