The wrong bounding box causes Chrome to refuse to render
Closed this issue · 10 comments
Here is a simple example to help us improve the bounding box of the generated font.
- Demo: https://at.alicdn.com/t/project/2575312/a0bdfc53-838a-4de8-b7cd-2196167f06da.html
- iconfont bug: thx/iconfont-plus#2009
SVG file:
<svg viewBox="0 0 62464 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200"><path d="M62464 0H0v1024h62464V0z" fill="#FF0000"></path></svg>
OpenType Sanitizer error prompt:
ERROR: head: Bad x dimension in the font bounding box (0, -3072)
ERROR: head: Failed to parse table
Failed to sanitize file!
Font Table
<head>
<!-- Most of this table will be recalculated by the compiler -->
<tableVersion value="1.0"/>
<fontRevision value="1.0"/>
<checkSumAdjustment value="0xd63f6d33"/>
<magicNumber value="0x5f0f3cf5"/>
<flags value="00000000 00001011"/>
<unitsPerEm value="1024"/>
<created value="Mon Jun 21 11:04:19 2021"/>
<modified value="Mon Jun 21 11:04:19 2021"/>
<xMin value="0"/>
<yMin value="-128"/>
<xMax value="-3072"/>
<yMax value="896"/>
<macStyle value="00000000 00000000"/>
<lowestRecPPEM value="8"/>
<fontDirectionHint value="2"/>
<indexToLocFormat value="0"/>
<glyphDataFormat value="0"/>
</head>
<OS_2>
<!-- The fields 'usFirstCharIndex' and 'usLastCharIndex'
will be recalculated by the compiler -->
<version value="4"/>
<xAvgCharWidth value="31744"/>
<usWeightClass value="500"/>
<usWidthClass value="5"/>
<fsType value="00000000 00000000"/>
<ySubscriptXSize value="649"/>
<ySubscriptYSize value="716"/>
<ySubscriptXOffset value="0"/>
<ySubscriptYOffset value="143"/>
<ySuperscriptXSize value="649"/>
<ySuperscriptYSize value="716"/>
<ySuperscriptXOffset value="0"/>
<ySuperscriptYOffset value="491"/>
<yStrikeoutSize value="50"/>
<yStrikeoutPosition value="264"/>
<sFamilyClass value="0"/>
<panose>
<bFamilyType value="2"/>
<bSerifStyle value="0"/>
<bWeight value="5"/>
<bProportion value="3"/>
<bContrast value="0"/>
<bStrokeVariation value="0"/>
<bArmStyle value="0"/>
<bLetterForm value="0"/>
<bMidline value="0"/>
<bXHeight value="0"/>
</panose>
<ulUnicodeRange1 value="00000000 00000000 00000000 00000000"/>
<ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
<ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
<ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
<achVendID value="PfEd"/>
<fsSelection value="00000000 11000000"/>
<usFirstCharIndex value="59053"/>
<usLastCharIndex value="59053"/>
<sTypoAscender value="896"/>
<sTypoDescender value="-128"/>
<sTypoLineGap value="92"/>
<usWinAscent value="988"/>
<usWinDescent value="128"/>
<ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
<ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
<sxHeight value="0"/>
<sCapHeight value="0"/>
<usDefaultChar value="0"/>
<usBreakChar value="0"/>
<usMaxContext value="2"/>
</OS_2>
AFAIK term "wrong" is not precise:
- Bbox is calculated from real data and can not be wrong (after last fixes).
- BUT (!) too high values are "highly likely" caused by bad input.
Questions:
- We need concrete criteria of issue resolve
- Probably "throw error on too big bbox values"
- We need concrete bounds for bbox
- Probably, use ones from Chrome/FF (need to extract somehow)
Chrome and Firefox use OpenType Sanitizer to detect fonts, the code is here:
https://github.com/khaledhosny/ots/blob/ff09cd0b6b0dd210a4c1bafd61fcbbba21738751/src/head.cc#L66-L73
if (this->xmin > this->xmax) {
return Error("Bad x dimension in the font bounding box (%d, %d)",
this->xmin, this->xmax);
}
if (this->ymin > this->ymax) {
return Error("Bad y dimension in the font bounding box (%d, %d)",
this->ymin, this->ymax);
}
Glyf table also has related checks:
https://github.com/khaledhosny/ots/blob/f2c7b32198080b6cce338a72beef8f0ebbc2db96/src/glyf.cc#L282-L293
// workaround for fonts in http://www.princexml.com/fonts/
if ((xmin == 32767) &&
(xmax == -32767) &&
(ymin == 32767) &&
(ymax == -32767)) {
Warning("bad xmin/xmax/ymin/ymax values");
xmin = xmax = ymin = ymax = 0;
}
if (xmin > xmax || ymin > ymax) {
return Error("Bad bounding box values bl=(%d, %d), tr=(%d, %d) in glyph %d", xmin, ymin, xmax, ymax, i);
}
At first glance, those checks are not actual for svg2ttf. I mean, load errors happened due different checks. Or, probably i miss something.
I mean, condition xmin > xmax
can not happen.
In the txt dump above xmin is 0 and xmax is negative, so xmin is greater than xmax.
Hm... strange, i will check. Thanks for clarification.
Yes, it is precisely because the font generated by svg2ttf has xMin> xMax
that it will trigger OpenType Sanitizer to report an error.
<xMin value="0"/>
<xMax value="-3072"/>
The very first instruction in the svg path is M62464
, which is exactly what xMax is calculated to be.
The field type allocated to it is: signed int16. We write 62464 there, which is the same as -3072 (62464+3072=65536).
So we have two issues here:
- invalid glyph (or at least a glyph we can't safely convert to ttf)
- no boundary checks
What do you expect svg2ttf to do here? Would an error (if glyph boundaries fall outside of ±32767) be enough?
Fixed, now this font should output an error.
Looks good, thanks!
Published 6.0.2