Merge pull request from notmasteryet/glyf-sanitize

Sanitizing the font glyphs to avoid OTS rejections
This commit is contained in:
Brendan Dahl 2012-02-15 12:08:05 -08:00
commit c440dfeee0
3 changed files with 77 additions and 13 deletions

@ -1553,6 +1553,61 @@ var Font = (function FontClosure() {
} }
}; };
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart) {
if (sourceEnd - sourceStart <= 12) {
// glyph with data less than 12 is invalid one
return 0;
}
var glyf = source.subarray(sourceStart, sourceEnd);
var contoursCount = (glyf[0] << 8) | glyf[1];
if (contoursCount & 0x8000) {
// complex glyph, writing as is
dest.set(glyf, destStart);
return glyf.length;
}
var j = 10, flagsCount = 0;
for (var i = 0; i < contoursCount; i++) {
var endPoint = (glyf[j] << 8) | glyf[j + 1];
flagsCount = endPoint + 1;
j += 2;
}
// skipping instructions
var instructionsLength = (glyf[j] << 8) | glyf[j + 1];
j += 2 + instructionsLength;
// validating flags
var coordinatesLength = 0;
for (var i = 0; i < flagsCount; i++) {
var flag = glyf[j++];
if (flag & 0xC0) {
// reserved flags must be zero, rejecting
return 0;
}
var xyLength = ((flag & 2) ? 1 : (flag & 16) ? 0 : 2) +
((flag & 4) ? 1 : (flag & 32) ? 0 : 2);
coordinatesLength += xyLength;
if (flag & 8) {
var repeat = glyf[j++];
i += repeat;
coordinatesLength += repeat * xyLength;
}
}
var glyphDataLength = j + coordinatesLength;
if (glyphDataLength > glyf.length) {
// not enough data for coordinates
return 0;
}
if (glyf.length - glyphDataLength > 3) {
// truncating and aligning to 4 bytes the long glyph data
glyphDataLength = (glyphDataLength + 3) & ~3;
dest.set(glyf.subarray(0, glyphDataLength), destStart);
return glyphDataLength;
}
// glyph data is fine
dest.set(glyf, destStart);
return glyf.length;
}
function sanitizeGlyphLocations(loca, glyf, numGlyphs, function sanitizeGlyphLocations(loca, glyf, numGlyphs,
isGlyphLocationsLong) { isGlyphLocationsLong) {
var itemSize, itemDecode, itemEncode; var itemSize, itemDecode, itemEncode;
@ -1579,21 +1634,21 @@ var Font = (function FontClosure() {
}; };
} }
var locaData = loca.data; var locaData = loca.data;
// removing the invalid glyphs
var oldGlyfData = glyf.data;
var newGlyfData = new Uint8Array(oldGlyfData.length);
var startOffset = itemDecode(locaData, 0); var startOffset = itemDecode(locaData, 0);
var firstOffset = itemDecode(locaData, itemSize); var writeOffset = 0;
if (firstOffset - startOffset < 12 || startOffset > 0) { itemEncode(locaData, 0, writeOffset);
// removing first glyph for (var i = 0, j = itemSize; i < numGlyphs; i++, j += itemSize) {
glyf.data = glyf.data.subarray(firstOffset); var endOffset = itemDecode(locaData, j);
glyf.length -= firstOffset; var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset,
newGlyfData, writeOffset);
itemEncode(locaData, 0, 0); writeOffset += newLength;
var i, pos = itemSize; itemEncode(locaData, j, writeOffset);
for (i = 1; i <= numGlyphs; ++i) { startOffset = endOffset;
itemEncode(locaData, pos,
itemDecode(locaData, pos) - firstOffset);
pos += itemSize;
}
} }
glyf.data = newGlyfData.subarray(0, writeOffset);
} }
function readGlyphNameMap(post, properties) { function readGlyphNameMap(post, properties) {

@ -0,0 +1 @@
http://hsivonen.iki.fi/thesis/html5-conformance-checker.pdf

@ -452,6 +452,14 @@
"link": false, "link": false,
"type": "eq" "type": "eq"
}, },
{ "id": "html5checker",
"file": "pdfs/html5checker.pdf",
"md5": "74bbd80d1e7eb5f2951582233ef9ebab",
"rounds": 1,
"pageLimit": 7,
"link": true,
"type": "eq"
},
{ "id": "issue1133", { "id": "issue1133",
"file": "pdfs/issue1133.pdf", "file": "pdfs/issue1133.pdf",
"md5": "d1b61580cb100e3df93d33703af1773a", "md5": "d1b61580cb100e3df93d33703af1773a",