|
|
|
@ -1568,16 +1568,21 @@ var Font = (function FontClosure() {
@@ -1568,16 +1568,21 @@ var Font = (function FontClosure() {
|
|
|
|
|
|
|
|
|
|
function sanitizeGlyph(source, sourceStart, sourceEnd, dest, destStart, |
|
|
|
|
hintsValid) { |
|
|
|
|
var glyphProfile = { |
|
|
|
|
length: 0, |
|
|
|
|
sizeOfInstructions: 0, |
|
|
|
|
}; |
|
|
|
|
if (sourceEnd - sourceStart <= 12) { |
|
|
|
|
// glyph with data less than 12 is invalid one
|
|
|
|
|
return 0; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
glyphProfile.length = glyf.length; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var i, j = 10, flagsCount = 0; |
|
|
|
@ -1589,6 +1594,7 @@ var Font = (function FontClosure() {
@@ -1589,6 +1594,7 @@ var Font = (function FontClosure() {
|
|
|
|
|
// skipping instructions
|
|
|
|
|
var instructionsStart = j; |
|
|
|
|
var instructionsLength = (glyf[j] << 8) | glyf[j + 1]; |
|
|
|
|
glyphProfile.sizeOfInstructions = instructionsLength; |
|
|
|
|
j += 2 + instructionsLength; |
|
|
|
|
var instructionsEnd = j; |
|
|
|
|
// validating flags
|
|
|
|
@ -1610,12 +1616,12 @@ var Font = (function FontClosure() {
@@ -1610,12 +1616,12 @@ var Font = (function FontClosure() {
|
|
|
|
|
} |
|
|
|
|
// glyph without coordinates will be rejected
|
|
|
|
|
if (coordinatesLength === 0) { |
|
|
|
|
return 0; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
var glyphDataLength = j + coordinatesLength; |
|
|
|
|
if (glyphDataLength > glyf.length) { |
|
|
|
|
// not enough data for coordinates
|
|
|
|
|
return 0; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
if (!hintsValid && instructionsLength > 0) { |
|
|
|
|
dest.set(glyf.subarray(0, instructionsStart), destStart); |
|
|
|
@ -1626,17 +1632,20 @@ var Font = (function FontClosure() {
@@ -1626,17 +1632,20 @@ var Font = (function FontClosure() {
|
|
|
|
|
if (glyf.length - glyphDataLength > 3) { |
|
|
|
|
glyphDataLength = (glyphDataLength + 3) & ~3; |
|
|
|
|
} |
|
|
|
|
return glyphDataLength; |
|
|
|
|
glyphProfile.length = glyphDataLength; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
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; |
|
|
|
|
glyphProfile.length = glyphDataLength; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
// glyph data is fine
|
|
|
|
|
dest.set(glyf, destStart); |
|
|
|
|
return glyf.length; |
|
|
|
|
glyphProfile.length = glyf.length; |
|
|
|
|
return glyphProfile; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function sanitizeHead(head, numGlyphs, locaLength) { |
|
|
|
@ -1686,7 +1695,7 @@ var Font = (function FontClosure() {
@@ -1686,7 +1695,7 @@ var Font = (function FontClosure() {
|
|
|
|
|
|
|
|
|
|
function sanitizeGlyphLocations(loca, glyf, numGlyphs, |
|
|
|
|
isGlyphLocationsLong, hintsValid, |
|
|
|
|
dupFirstEntry) { |
|
|
|
|
dupFirstEntry, maxSizeOfInstructions) { |
|
|
|
|
var itemSize, itemDecode, itemEncode; |
|
|
|
|
if (isGlyphLocationsLong) { |
|
|
|
|
itemSize = 4; |
|
|
|
@ -1724,7 +1733,7 @@ var Font = (function FontClosure() {
@@ -1724,7 +1733,7 @@ var Font = (function FontClosure() {
|
|
|
|
|
var newGlyfData = new Uint8Array(oldGlyfDataLength); |
|
|
|
|
var startOffset = itemDecode(locaData, 0); |
|
|
|
|
var writeOffset = 0; |
|
|
|
|
var missingGlyphData = Object.create(null); |
|
|
|
|
var missingGlyphs = Object.create(null); |
|
|
|
|
itemEncode(locaData, 0, writeOffset); |
|
|
|
|
var i, j; |
|
|
|
|
// When called with dupFirstEntry the number of glyphs has already been
|
|
|
|
@ -1743,10 +1752,15 @@ var Font = (function FontClosure() {
@@ -1743,10 +1752,15 @@ var Font = (function FontClosure() {
|
|
|
|
|
startOffset = endOffset; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var newLength = sanitizeGlyph(oldGlyfData, startOffset, endOffset, |
|
|
|
|
newGlyfData, writeOffset, hintsValid); |
|
|
|
|
var glyphProfile = sanitizeGlyph(oldGlyfData, startOffset, endOffset, |
|
|
|
|
newGlyfData, writeOffset, |
|
|
|
|
hintsValid); |
|
|
|
|
var newLength = glyphProfile.length; |
|
|
|
|
if (newLength === 0) { |
|
|
|
|
missingGlyphData[i] = true; |
|
|
|
|
missingGlyphs[i] = true; |
|
|
|
|
} |
|
|
|
|
if (glyphProfile.sizeOfInstructions > maxSizeOfInstructions) { |
|
|
|
|
maxSizeOfInstructions = glyphProfile.sizeOfInstructions; |
|
|
|
|
} |
|
|
|
|
writeOffset += newLength; |
|
|
|
|
itemEncode(locaData, j, writeOffset); |
|
|
|
@ -1762,10 +1776,7 @@ var Font = (function FontClosure() {
@@ -1762,10 +1776,7 @@ var Font = (function FontClosure() {
|
|
|
|
|
itemEncode(locaData, j, simpleGlyph.length); |
|
|
|
|
} |
|
|
|
|
glyf.data = simpleGlyph; |
|
|
|
|
return missingGlyphData; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (dupFirstEntry) { |
|
|
|
|
} else if (dupFirstEntry) { |
|
|
|
|
var firstEntryLength = itemDecode(locaData, itemSize); |
|
|
|
|
if (newGlyfData.length > firstEntryLength + writeOffset) { |
|
|
|
|
glyf.data = newGlyfData.subarray(0, firstEntryLength + writeOffset); |
|
|
|
@ -1779,7 +1790,10 @@ var Font = (function FontClosure() {
@@ -1779,7 +1790,10 @@ var Font = (function FontClosure() {
|
|
|
|
|
} else { |
|
|
|
|
glyf.data = newGlyfData.subarray(0, writeOffset); |
|
|
|
|
} |
|
|
|
|
return missingGlyphData; |
|
|
|
|
return { |
|
|
|
|
missingGlyphs, |
|
|
|
|
maxSizeOfInstructions, |
|
|
|
|
}; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function readPostScriptTable(post, properties, maxpNumGlyphs) { |
|
|
|
@ -2226,6 +2240,7 @@ var Font = (function FontClosure() {
@@ -2226,6 +2240,7 @@ var Font = (function FontClosure() {
|
|
|
|
|
var version = font.getInt32(); |
|
|
|
|
var numGlyphs = font.getUint16(); |
|
|
|
|
var maxFunctionDefs = 0; |
|
|
|
|
var maxSizeOfInstructions = 0; |
|
|
|
|
if (version >= 0x00010000 && tables['maxp'].length >= 22) { |
|
|
|
|
// maxZones can be invalid
|
|
|
|
|
font.pos += 8; |
|
|
|
@ -2236,6 +2251,8 @@ var Font = (function FontClosure() {
@@ -2236,6 +2251,8 @@ var Font = (function FontClosure() {
|
|
|
|
|
} |
|
|
|
|
font.pos += 4; |
|
|
|
|
maxFunctionDefs = font.getUint16(); |
|
|
|
|
font.pos += 6; |
|
|
|
|
maxSizeOfInstructions = font.getUint16(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
var dupFirstEntry = false; |
|
|
|
@ -2271,11 +2288,19 @@ var Font = (function FontClosure() {
@@ -2271,11 +2288,19 @@ var Font = (function FontClosure() {
|
|
|
|
|
if (isTrueType) { |
|
|
|
|
var isGlyphLocationsLong = int16(tables['head'].data[50], |
|
|
|
|
tables['head'].data[51]); |
|
|
|
|
missingGlyphs = sanitizeGlyphLocations(tables['loca'], tables['glyf'], |
|
|
|
|
numGlyphs, isGlyphLocationsLong, |
|
|
|
|
hintsValid, dupFirstEntry); |
|
|
|
|
} |
|
|
|
|
var glyphsInfo = sanitizeGlyphLocations(tables['loca'], tables['glyf'], |
|
|
|
|
numGlyphs, isGlyphLocationsLong, |
|
|
|
|
hintsValid, dupFirstEntry, |
|
|
|
|
maxSizeOfInstructions); |
|
|
|
|
missingGlyphs = glyphsInfo.missingGlyphs; |
|
|
|
|
|
|
|
|
|
// Some fonts have incorrect maxSizeOfInstructions values, so we use
|
|
|
|
|
// the computed value instead.
|
|
|
|
|
if (version >= 0x00010000 && tables['maxp'].length >= 22) { |
|
|
|
|
tables['maxp'].data[26] = glyphsInfo.maxSizeOfInstructions >> 8; |
|
|
|
|
tables['maxp'].data[27] = glyphsInfo.maxSizeOfInstructions & 255; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
if (!tables['hhea']) { |
|
|
|
|
throw new FormatError('Required "hhea" table is not found'); |
|
|
|
|
} |
|
|
|
|