Merge pull request #409 from vingtetun/master

Allow bypassing the sanitizer for Type1C font with encoding supplement
This commit is contained in:
Andreas Gal 2011-08-31 08:39:00 -07:00
commit ca17f3e75b
4 changed files with 207 additions and 176 deletions

View File

@ -569,6 +569,7 @@ var CipherTransformFactory = (function() {
}; };
} }
error('Unknown crypto method'); error('Unknown crypto method');
return null;
} }
constructor.prototype = { constructor.prototype = {

264
fonts.js
View File

@ -57,7 +57,7 @@ var stdFontMap = {
}; };
var FontMeasure = (function FontMeasure() { var FontMeasure = (function FontMeasure() {
var kScalePrecision = 50; var kScalePrecision = 30;
var ctx = document.createElement('canvas').getContext('2d'); var ctx = document.createElement('canvas').getContext('2d');
ctx.scale(1 / kScalePrecision, 1); ctx.scale(1 / kScalePrecision, 1);
@ -66,7 +66,7 @@ var FontMeasure = (function FontMeasure() {
return { return {
setActive: function fonts_setActive(font, size) { setActive: function fonts_setActive(font, size) {
if (current = font) { if (current == font) {
var sizes = current.sizes; var sizes = current.sizes;
if (!(measureCache = sizes[size])) if (!(measureCache = sizes[size]))
measureCache = sizes[size] = Object.create(null); measureCache = sizes[size] = Object.create(null);
@ -80,6 +80,7 @@ var FontMeasure = (function FontMeasure() {
size *= kScalePrecision; size *= kScalePrecision;
var rule = italic + ' ' + bold + ' ' + size + 'px "' + name + '"'; var rule = italic + ' ' + bold + ' ' + size + 'px "' + name + '"';
ctx.font = rule; ctx.font = rule;
current = font;
}, },
measureText: function fonts_measureText(text) { measureText: function fonts_measureText(text) {
var width; var width;
@ -385,6 +386,7 @@ var Font = (function Font() {
var constructor = function font_constructor(name, file, properties) { var constructor = function font_constructor(name, file, properties) {
this.name = name; this.name = name;
this.encoding = properties.encoding; this.encoding = properties.encoding;
this.glyphs = properties.glyphs;
this.sizes = []; this.sizes = [];
// If the font is to be ignored, register it like an already loaded font // If the font is to be ignored, register it like an already loaded font
@ -414,11 +416,8 @@ var Font = (function Font() {
this.mimetype = 'font/opentype'; this.mimetype = 'font/opentype';
var subtype = properties.subtype; var subtype = properties.subtype;
if (subtype === 'Type1C') { var cff = (subtype === 'Type1C') ? new Type2CFF(file, properties)
var cff = new Type2CFF(file, properties); : new CFF(name, file, properties);
} else {
var cff = new CFF(name, file, properties);
}
// Wrap the CFF data inside an OTF font file // Wrap the CFF data inside an OTF font file
data = this.convert(name, cff, properties); data = this.convert(name, cff, properties);
@ -638,30 +637,28 @@ var Font = (function Font() {
var ulUnicodeRange3 = 0; var ulUnicodeRange3 = 0;
var ulUnicodeRange4 = 0; var ulUnicodeRange4 = 0;
var charset = properties.charset; var firstCharIndex = null;
if (charset && charset.length) { var lastCharIndex = 0;
var firstCharIndex = null;
var lastCharIndex = 0;
for (var i = 0; i < charset.length; i++) { var encoding = properties.encoding;
var code = GlyphsUnicode[charset[i]]; for (var index in encoding) {
if (firstCharIndex > code || !firstCharIndex) var code = encoding[index];
firstCharIndex = code; if (firstCharIndex > code || !firstCharIndex)
if (lastCharIndex < code) firstCharIndex = code;
lastCharIndex = code; if (lastCharIndex < code)
lastCharIndex = code;
var position = getUnicodeRangeFor(code); var position = getUnicodeRangeFor(code);
if (position < 32) { if (position < 32) {
ulUnicodeRange1 |= 1 << position; ulUnicodeRange1 |= 1 << position;
} else if (position < 64) { } else if (position < 64) {
ulUnicodeRange2 |= 1 << position - 32; ulUnicodeRange2 |= 1 << position - 32;
} else if (position < 96) { } else if (position < 96) {
ulUnicodeRange3 |= 1 << position - 64; ulUnicodeRange3 |= 1 << position - 64;
} else if (position < 123) { } else if (position < 123) {
ulUnicodeRange4 |= 1 << position - 96; ulUnicodeRange4 |= 1 << position - 96;
} else { } else {
error('Unicode ranges Bits > 123 are reserved for internal usage'); error('Unicode ranges Bits > 123 are reserved for internal usage');
}
} }
} }
@ -847,7 +844,6 @@ var Font = (function Font() {
} }
var encoding = properties.encoding; var encoding = properties.encoding;
var charset = properties.charset;
for (var i = 0; i < numRecords; i++) { for (var i = 0; i < numRecords; i++) {
var table = records[i]; var table = records[i];
font.pos = start + table.offset; font.pos = start + table.offset;
@ -856,7 +852,9 @@ var Font = (function Font() {
var length = int16(font.getBytes(2)); var length = int16(font.getBytes(2));
var language = int16(font.getBytes(2)); var language = int16(font.getBytes(2));
if (format == 0) { if (format == 4) {
return cmap.data;
} else if (format == 0) {
// Characters below 0x20 are controls characters that are hardcoded // Characters below 0x20 are controls characters that are hardcoded
// into the platform so if some characters in the font are assigned // into the platform so if some characters in the font are assigned
// under this limit they will not be displayed so let's rewrite the // under this limit they will not be displayed so let's rewrite the
@ -871,35 +869,17 @@ var Font = (function Font() {
} }
} }
var rewrite = false; if (properties.firstChar < 0x20) {
for (var code in encoding) { var code = 0;
if (code < 0x20 && encoding[code])
rewrite = true;
if (rewrite)
encoding[code] = parseInt(code) + 0x1F;
}
if (rewrite) {
for (var j = 0; j < glyphs.length; j++) { for (var j = 0; j < glyphs.length; j++) {
var glyph = glyphs[j];
glyphs[j].unicode += 0x1F; glyphs[j].unicode += 0x1F;
properties.glyphs[glyph.glyph] = encoding[++code] = glyph.unicode;
} }
} }
cmap.data = createCMapTable(glyphs, deltas);
} else if (format == 6 && numRecords == 1 && !encoding.empty) { return cmap.data = createCMapTable(glyphs, deltas);
// Format 0 alone is not allowed by the sanitizer so let's rewrite } else if (format == 6) {
// that to a 3-1-4 Unicode BMP table
TODO('Use an other source of informations than ' +
'charset here, it is not reliable');
var glyphs = [];
for (var j = 0; j < charset.length; j++) {
glyphs.push({
unicode: GlyphsUnicode[charset[j]] || 0
});
}
cmap.data = createCMapTable(glyphs);
} else if (format == 6 && numRecords == 1) {
// Format 6 is a 2-bytes dense mapping, which means the font data // Format 6 is a 2-bytes dense mapping, which means the font data
// lives glue together even if they are pretty far in the unicode // lives glue together even if they are pretty far in the unicode
// table. (This looks weird, so I can have missed something), this // table. (This looks weird, so I can have missed something), this
@ -912,6 +892,8 @@ var Font = (function Font() {
var min = 0xffff, max = 0; var min = 0xffff, max = 0;
for (var j = 0; j < entryCount; j++) { for (var j = 0; j < entryCount; j++) {
var charcode = int16(font.getBytes(2)); var charcode = int16(font.getBytes(2));
if (!charcode)
continue;
glyphs.push(charcode); glyphs.push(charcode);
if (charcode < min) if (charcode < min)
@ -939,9 +921,10 @@ var Font = (function Font() {
var index = firstCode; var index = firstCode;
for (var j = start; j <= end; j++) for (var j = start; j <= end; j++)
encoding[index++] = glyphs[j - firstCode - 1].unicode; encoding[index++] = glyphs[j - firstCode - 1].unicode;
cmap.data = createCMapTable(glyphs); return cmap.data = createCMapTable(glyphs);
} }
} }
return cmap.data;
}; };
// Check that required tables are present // Check that required tables are present
@ -1035,9 +1018,8 @@ var Font = (function Font() {
var glyphs = []; var glyphs = [];
var encoding = properties.encoding; var encoding = properties.encoding;
for (var i = 1; i < numGlyphs; i++) { for (var i = 1; i < numGlyphs; i++)
glyphs.push({ unicode: i + kCmapGlyphOffset }); glyphs.push({ unicode: i + kCmapGlyphOffset });
}
if ('undefined' == typeof(encoding[0])) { if ('undefined' == typeof(encoding[0])) {
// the font is directly characters to glyphs with no encoding // the font is directly characters to glyphs with no encoding
@ -1290,7 +1272,7 @@ var Font = (function Font() {
// Check if the glyph has already been converted // Check if the glyph has already been converted
if (!IsNum(unicode)) if (!IsNum(unicode))
unicode = encoding[unicode] = GlyphsUnicode[unicode.name]; unicode = encoding[charcode] = this.glyphs[unicode];
// Handle surrogate pairs // Handle surrogate pairs
if (unicode > 0xFFFF) { if (unicode > 0xFFFF) {
@ -1715,9 +1697,6 @@ var Type1Parser = function() {
properties.textMatrix = matrix; properties.textMatrix = matrix;
break; break;
case '/Encoding': case '/Encoding':
if (!properties.builtInEncoding)
break;
var size = parseInt(getToken()); var size = parseInt(getToken());
getToken(); // read in 'array' getToken(); // read in 'array'
@ -1726,9 +1705,12 @@ var Type1Parser = function() {
if (token == 'dup') { if (token == 'dup') {
var index = parseInt(getToken()); var index = parseInt(getToken());
var glyph = getToken(); var glyph = getToken();
properties.encoding[index] = GlyphsUnicode[glyph];
if ('undefined' == typeof(properties.differences[index])) {
properties.encoding[index] = glyph;
properties.glyphs[glyph] = GlyphsUnicode[glyph];
}
getToken(); // read the in 'put' getToken(); // read the in 'put'
j = index;
} }
} }
break; break;
@ -1904,7 +1886,7 @@ CFF.prototype = {
missings.push(glyph.glyph); missings.push(glyph.glyph);
} else { } else {
charstrings.push({ charstrings.push({
glyph: glyph, glyph: glyph.glyph,
unicode: unicode, unicode: unicode,
charstring: glyph.data, charstring: glyph.data,
width: glyph.width, width: glyph.width,
@ -2080,7 +2062,7 @@ CFF.prototype = {
var count = glyphs.length; var count = glyphs.length;
for (var i = 0; i < count; i++) { for (var i = 0; i < count; i++) {
var index = CFFStrings.indexOf(charstrings[i].glyph.glyph); var index = CFFStrings.indexOf(charstrings[i].glyph);
// Some characters like asterikmath && circlecopyrt are // Some characters like asterikmath && circlecopyrt are
// missing from the original strings, for the moment let's // missing from the original strings, for the moment let's
// map them to .notdef and see later if it cause any // map them to .notdef and see later if it cause any
@ -2149,35 +2131,28 @@ CFF.prototype = {
}; };
var Type2CFF = (function() { var Type2CFF = (function() {
// TODO: replace parsing code with the Type2Parser in font_utils.js // TODO: replace parsing code with the Type2Parser in font_utils.js
function constructor(file, properties) { function constructor(file, properties) {
var bytes = file.getBytes(); var bytes = file.getBytes();
this.bytes = bytes; this.bytes = bytes;
this.properties = properties; this.properties = properties;
// Other classes expect this.data to be a Javascript array this.data = this.parse();
var data = [];
for (var i = 0, ii = bytes.length; i < ii; ++i)
data.push(bytes[i]);
this.data = data;
this.parse();
}; };
constructor.prototype = { constructor.prototype = {
parse: function cff_parse() { parse: function cff_parse() {
var header = this.parseHeader(); var header = this.parseHeader();
var properties = this.properties;
var nameIndex = this.parseIndex(header.endPos); var nameIndex = this.parseIndex(header.endPos);
var dictIndex = this.parseIndex(nameIndex.endPos); var dictIndex = this.parseIndex(nameIndex.endPos);
if (dictIndex.length != 1) if (dictIndex.length != 1)
error('More than 1 font'); error('CFF contains more than 1 font');
var stringIndex = this.parseIndex(dictIndex.endPos); var stringIndex = this.parseIndex(dictIndex.endPos);
var gsubrIndex = this.parseIndex(stringIndex.endPos); var gsubrIndex = this.parseIndex(stringIndex.endPos);
var strings = this.getStrings(stringIndex); var strings = this.getStrings(stringIndex);
var baseDict = this.parseDict(dictIndex.get(0)); var baseDict = this.parseDict(dictIndex.get(0));
@ -2185,31 +2160,45 @@ var Type2CFF = (function() {
var bytes = this.bytes; var bytes = this.bytes;
var privInfo = topDict['Private']; var privateInfo = topDict.Private;
var privOffset = privInfo[1], privLength = privInfo[0]; var privOffset = privateInfo[1], privLength = privateInfo[0];
var privBytes = bytes.subarray(privOffset, privOffset + privLength); var privBytes = bytes.subarray(privOffset, privOffset + privLength);
baseDict = this.parseDict(privBytes); baseDict = this.parseDict(privBytes);
var privDict = this.getPrivDict(baseDict, strings); var privDict = this.getPrivDict(baseDict, strings);
TODO('Parse encoding'); var charStrings = this.parseIndex(topDict.CharStrings);
var charStrings = this.parseIndex(topDict['CharStrings']); var charset = this.parseCharsets(topDict.charset,
var charset = this.parseCharsets(topDict['charset'], charStrings.length, charStrings.length, strings);
strings); var hasSupplement = this.parseEncoding(topDict.Encoding, properties,
strings, charset);
// The font sanitizer does not support CFF encoding with a
// supplement, since the encoding is not really use to map
// between gid to glyph, let's overwrite what is declared in
// the top dictionary to let the sanitizer think the font use
// StandardEncoding, that's a lie but that's ok.
if (hasSupplement)
bytes[topDict.Encoding] = 0;
// charstrings contains info about glyphs (one element per glyph // charstrings contains info about glyphs (one element per glyph
// containing mappings for {unicode, width}) // containing mappings for {unicode, width})
var charstrings = this.getCharStrings(charset, charStrings, var charstrings = this.getCharStrings(charset, charStrings,
privDict, this.properties); privDict, this.properties);
// create the mapping between charstring and glyph id // create the mapping between charstring and glyph id
var glyphIds = []; var glyphIds = [];
for (var i = 0, ii = charstrings.length; i < ii; ++i) { for (var i = 0; i < charstrings.length; i++)
glyphIds.push(charstrings[i].gid); glyphIds.push(charstrings[i].gid);
}
this.charstrings = charstrings; this.charstrings = charstrings;
this.glyphIds = glyphIds; this.glyphIds = glyphIds;
var data = [];
for (var i = 0, ii = bytes.length; i < ii; ++i)
data.push(bytes[i]);
return data;
}, },
getCharStrings: function cff_charstrings(charsets, charStrings, getCharStrings: function cff_charstrings(charsets, charStrings,
privDict, properties) { privDict, properties) {
var widths = properties.widths; var widths = properties.widths;
@ -2218,31 +2207,93 @@ var Type2CFF = (function() {
var nominalWidth = privDict['nominalWidthX']; var nominalWidth = privDict['nominalWidthX'];
var charstrings = []; var charstrings = [];
for (var i = 0, ii = charsets.length; i < ii; ++i) { var differences = properties.differences;
var charName = charsets[i]; var index = 0;
var charCode = GlyphsUnicode[charName]; var kCmapGlyphOffset = 0xE000;
if (charCode) { for (var i = 1; i < charsets.length; i++) {
var width = widths[charCode] || defaultWidth; var glyph = charsets[i];
charstrings.push({unicode: charCode, width: width, gid: i}); for (var j = index; j < differences.length; j++) {
} else { if (differences[j]) {
if (charName !== '.notdef') index = j;
warn('Cannot find unicode for glyph ' + charName); break;
}
} }
var code = differences.indexOf(glyph);
if (code == -1)
code = properties.glyphs[glyph] || index;
var width = widths[code] || defaultWidth;
properties.encoding[index] = index + kCmapGlyphOffset;
charstrings.push({unicode: code + kCmapGlyphOffset, width: width, gid: i});
index++;
} }
// sort the arry by the unicode value // sort the array by the unicode value
charstrings.sort(function(a, b) {return a.unicode - b.unicode}); charstrings.sort(function(a, b) {return a.unicode - b.unicode});
return charstrings; return charstrings;
}, },
parseEncoding: function cff_parseencoding(pos) {
if (pos == 0) { parseEncoding: function cff_parseencoding(pos, properties, strings, charset) {
return Encodings.StandardEncoding; var encoding = {};
} else if (pos == 1) { var bytes = this.bytes;
return Encodings.ExpertEncoding;
function readSupplement() {
var supplementsCount = bytes[pos++];
for (var i = 0; i < supplementsCount; i++) {
var code = bytes[pos++];
var sid = (bytes[pos++] << 8) + (bytes[pos++] & 0xff);
encoding[code] = properties.differences.indexOf(strings[sid]);
}
} }
error('not implemented encodings'); if (pos == 0 || pos == 1) {
var gid = 1;
var baseEncoding = pos ? Encodings.ExpertEncoding
: Encodings.StandardEncoding;
for (var i = 0; i < charset.length; i++) {
var index = baseEncoding.indexOf(charset[i]);
if (index != -1)
encoding[index] = gid++;
}
} else {
var format = bytes[pos++];
switch (format & 0x7f) {
case 0:
var glyphsCount = bytes[pos++];
for (var i = 1; i <= glyphsCount; i++)
encoding[bytes[pos++]] = i;
if (format & 0x80) {
readSupplement();
return true;
}
break;
case 1:
var rangesCount = bytes[pos++];
var gid = 1;
for (var i = 0; i < rangesCount; i++) {
var start = bytes[pos++];
var count = bytes[pos++];
for (var j = start; j <= start + count; j++)
encoding[j] = gid++;
}
if (format & 0x80) {
readSupplement();
return true;
}
break;
default:
error('Unknow encoding format: ' + format + " in CFF");
break;
}
}
return false;
}, },
parseCharsets: function cff_parsecharsets(pos, length, strings) { parseCharsets: function cff_parsecharsets(pos, length, strings) {
var bytes = this.bytes; var bytes = this.bytes;
var format = bytes[pos++]; var format = bytes[pos++];
@ -2257,7 +2308,7 @@ var Type2CFF = (function() {
id = (id << 8) | bytes[pos++]; id = (id << 8) | bytes[pos++];
charset.push(strings[id]); charset.push(strings[id]);
} }
return charset; break;
case 1: case 1:
while (charset.length <= length) { while (charset.length <= length) {
var first = bytes[pos++]; var first = bytes[pos++];
@ -2266,7 +2317,7 @@ var Type2CFF = (function() {
for (var i = 0; i <= numLeft; ++i) for (var i = 0; i <= numLeft; ++i)
charset.push(strings[first++]); charset.push(strings[first++]);
} }
return charset; break;
case 2: case 2:
while (charset.length <= length) { while (charset.length <= length) {
var first = bytes[pos++]; var first = bytes[pos++];
@ -2276,11 +2327,11 @@ var Type2CFF = (function() {
for (var i = 0; i <= numLeft; ++i) for (var i = 0; i <= numLeft; ++i)
charset.push(strings[first++]); charset.push(strings[first++]);
} }
return charset; break;
default: default:
error('Unknown charset format'); error('Unknown charset format');
} }
return charset;
}, },
getPrivDict: function cff_getprivdict(baseDict, strings) { getPrivDict: function cff_getprivdict(baseDict, strings) {
var dict = {}; var dict = {};
@ -2410,6 +2461,7 @@ var Type2CFF = (function() {
} else { } else {
error('Incorrect byte'); error('Incorrect byte');
} }
return -1;
}; };
function parseFloatOperand() { function parseFloatOperand() {

97
pdf.js
View File

@ -2093,7 +2093,7 @@ var LZWStream = (function() {
var c = this.str.getByte(); var c = this.str.getByte();
if (c == null) { if (c == null) {
this.eof = true; this.eof = true;
return; return null;
} }
cachedData = (cachedData << 8) | c; cachedData = (cachedData << 8) | c;
bitsCached += 8; bitsCached += 8;
@ -4204,8 +4204,6 @@ var PartialEvaluator = (function() {
var builtInEncoding = false; var builtInEncoding = false;
var encodingMap = {}; var encodingMap = {};
var glyphMap = {};
var charset = [];
if (compositeFont) { if (compositeFont) {
// Special CIDFont support // Special CIDFont support
// XXX only CIDFontType2 supported for now // XXX only CIDFontType2 supported for now
@ -4247,69 +4245,64 @@ var PartialEvaluator = (function() {
if (fontDict.has('Encoding')) { if (fontDict.has('Encoding')) {
var encoding = xref.fetchIfRef(fontDict.get('Encoding')); var encoding = xref.fetchIfRef(fontDict.get('Encoding'));
if (IsDict(encoding)) { if (IsDict(encoding)) {
// Build a map of between codes and glyphs
// Load the base encoding
var baseName = encoding.get('BaseEncoding'); var baseName = encoding.get('BaseEncoding');
if (baseName) { if (baseName)
baseEncoding = Encodings[baseName.name].slice(); baseEncoding = Encodings[baseName.name].slice();
}
// Load the differences between the base and original // Load the differences between the base and original
var differences = encoding.get('Differences'); var differences = encoding.get('Differences');
var index = 0; var index = 0;
for (var j = 0; j < differences.length; j++) { for (var j = 0; j < differences.length; j++) {
var data = differences[j]; var data = differences[j];
if (IsNum(data)) { if (IsNum(data))
index = data; index = data;
} else { else
diffEncoding[index++] = data.name; diffEncoding[index++] = data.name;
}
} }
} else if (IsName(encoding)) { } else if (IsName(encoding)) {
baseEncoding = Encodings[encoding.name].slice(); baseEncoding = Encodings[encoding.name].slice();
} else {
error("Encoding is not a Name nor a Dict");
} }
} }
var fontType = subType.name;
if (!baseEncoding) { if (!baseEncoding) {
var type = subType.name; switch (fontType) {
if (type == 'TrueType') { case 'TrueType':
baseEncoding = Encodings.WinAnsiEncoding.slice(); baseEncoding = Encodings.WinAnsiEncoding.slice();
} else if (type == 'Type1') { break;
baseEncoding = Encodings.StandardEncoding.slice(); case 'Type1':
if (!diffEncoding.length) baseEncoding = Encodings.StandardEncoding.slice();
builtInEncoding = true; break;
} else { default:
error('Unknown type of font'); warn('Unknown type of font: ' + fontType);
break;
} }
} }
// firstChar and width are required
// (except for 14 standard fonts)
var firstChar = xref.fetchIfRef(fontDict.get('FirstChar')) || 0;
var widths = xref.fetchIfRef(fontDict.get('Widths')) || [];
var lastChar = xref.fetchIfRef(fontDict.get('LastChar'));
if (!lastChar)
lastChar = diffEncoding.length || baseEncoding.length;
// merge in the differences // merge in the differences
var length = baseEncoding.length > diffEncoding.length ? var glyphsMap = {};
baseEncoding.length : diffEncoding.length; for (var i = firstChar; i <= lastChar; i++) {
for (var i = 0, ii = length; i < ii; ++i) { var glyph = diffEncoding[i] || baseEncoding[i];
var diffGlyph = diffEncoding[i]; if (glyph)
var baseGlyph = baseEncoding[i]; glyphsMap[glyph] = encodingMap[i] = GlyphsUnicode[glyph] || i;
if (diffGlyph) {
glyphMap[i] = diffGlyph;
encodingMap[i] = GlyphsUnicode[diffGlyph];
} else if (baseGlyph) {
glyphMap[i] = baseGlyph;
encodingMap[i] = GlyphsUnicode[baseGlyph];
}
} }
if (fontDict.has('ToUnicode')) { if (fontType == 'TrueType' && fontDict.has('ToUnicode') && differences) {
encodingMap['empty'] = true;
var glyphsMap = {};
for (var p in glyphMap)
glyphsMap[glyphMap[p]] = encodingMap[p];
var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode')); var cmapObj = xref.fetchIfRef(fontDict.get('ToUnicode'));
if (IsName(cmapObj)) { if (IsName(cmapObj)) {
error('ToUnicode file cmap translation not implemented'); error('ToUnicode file cmap translation not implemented');
} else if (IsStream(cmapObj)) { } else if (IsStream(cmapObj)) {
var firstChar = xref.fetchIfRef(fontDict.get('FirstChar'));
var tokens = []; var tokens = [];
var token = ''; var token = '';
var beginArrayToken = {}; var beginArrayToken = {};
@ -4390,21 +4383,13 @@ var PartialEvaluator = (function() {
} }
} }
} }
// firstChar and width are required
// (except for 14 standard fonts)
var firstChar = xref.fetchIfRef(fontDict.get('FirstChar'));
var widths = xref.fetchIfRef(fontDict.get('Widths')) || [];
for (var j = 0; j < widths.length; j++) {
if (widths[j])
charset.push(glyphMap[j + firstChar]);
}
} }
if (!fd) { if (!fd) {
var baseFontName = fontDict.get('BaseFont'); var baseFontName = fontDict.get('BaseFont');
if (!IsName(baseFontName)) if (!IsName(baseFontName))
return null; return null;
// Using base font name as a font name. // Using base font name as a font name.
baseFontName = baseFontName.name.replace(/[\+,\-]/g, '_'); baseFontName = baseFontName.name.replace(/[\+,\-]/g, '_');
if (/^Symbol(_?(Bold|Italic))*$/.test(baseFontName)) { if (/^Symbol(_?(Bold|Italic))*$/.test(baseFontName)) {
@ -4426,7 +4411,6 @@ var PartialEvaluator = (function() {
} }
var descriptor = xref.fetch(fd); var descriptor = xref.fetch(fd);
var fontName = fontDict.get('Name'); var fontName = fontDict.get('Name');
if (!fontName) if (!fontName)
fontName = xref.fetchIfRef(descriptor.get('FontName')); fontName = xref.fetchIfRef(descriptor.get('FontName'));
@ -4444,14 +4428,6 @@ var PartialEvaluator = (function() {
} }
} }
if (descriptor.has('CharSet')) {
// Get the font charset if any (meaningful only in Type 1)
charset = descriptor.get('CharSet');
assertWellFormed(IsString(charset), 'invalid charset');
charset = charset.split('/');
charset.shift();
}
var widths = fontDict.get('Widths'); var widths = fontDict.get('Widths');
if (widths) { if (widths) {
var glyphWidths = {}; var glyphWidths = {};
@ -4465,9 +4441,8 @@ var PartialEvaluator = (function() {
subtype: fileType, subtype: fileType,
widths: glyphWidths, widths: glyphWidths,
encoding: encodingMap, encoding: encodingMap,
differences: diffEncoding,
glyphs: glyphsMap || GlyphsUnicode, glyphs: glyphsMap || GlyphsUnicode,
builtInEncoding: builtInEncoding,
charset: charset,
firstChar: fontDict.get('FirstChar'), firstChar: fontDict.get('FirstChar'),
lastChar: fontDict.get('LastChar'), lastChar: fontDict.get('LastChar'),
bbox: descriptor.get('FontBBox'), bbox: descriptor.get('FontBBox'),
@ -5236,7 +5211,7 @@ var Util = (function() {
return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
}; };
constructor.makeCssCmyk = function makecmyk(c, m, y, k) { constructor.makeCssCmyk = function makecmyk(c, m, y, k) {
var c = (new DeviceCmykCS()).getRgb([c, m, y, k]); c = (new DeviceCmykCS()).getRgb([c, m, y, k]);
var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0; var ri = (255 * c[0]) | 0, gi = (255 * c[1]) | 0, bi = (255 * c[2]) | 0;
return 'rgb(' + ri + ',' + gi + ',' + bi + ')'; return 'rgb(' + ri + ',' + gi + ',' + bi + ')';
}; };
@ -5363,6 +5338,7 @@ var ColorSpace = (function() {
} else { } else {
error('unrecognized color space object: "' + cs + '"'); error('unrecognized color space object: "' + cs + '"');
} }
return null;
}; };
return constructor; return constructor;
@ -5661,6 +5637,7 @@ var Pattern = (function() {
default: default:
error('Unknown type of pattern: ' + typeNum); error('Unknown type of pattern: ' + typeNum);
} }
return null;
}; };
constructor.parseShading = function pattern_shading(shading, matrix, constructor.parseShading = function pattern_shading(shading, matrix,

View File

@ -218,11 +218,10 @@ var PageView = function(container, content, id, width, height,
function setupLinks(canvas, content, scale) { function setupLinks(canvas, content, scale) {
function bindLink(link, dest) { function bindLink(link, dest) {
if (dest) { link.onclick = function() {
link.onclick = function() { if (dest)
PDFView.navigateTo(dest); PDFView.navigateTo(dest);
return false; return false;
};
} }
} }
var links = content.getLinks(); var links = content.getLinks();
@ -233,7 +232,7 @@ var PageView = function(container, content, id, width, height,
link.style.width = Math.ceil(links[i].width * scale) + 'px'; link.style.width = Math.ceil(links[i].width * scale) + 'px';
link.style.height = Math.ceil(links[i].height * scale) + 'px'; link.style.height = Math.ceil(links[i].height * scale) + 'px';
link.href = links[i].url || ''; link.href = links[i].url || '';
bindLink(link, links[i].dest); bindLink(link, ('dest' in links[i]) ? links[i].dest : null);
div.appendChild(link); div.appendChild(link);
} }
} }
@ -423,16 +422,18 @@ window.addEventListener('transitionend', function(evt) {
var pagesCount = PDFView.pages.length; var pagesCount = PDFView.pages.length;
var container = document.getElementById('sidebarView'); var container = document.getElementById('sidebarView');
container._interval = window.setInterval(function() { container._interval = window.setInterval(function interval() {
if (pageIndex >= pagesCount) if (pageIndex >= pagesCount) {
return window.clearInterval(container._interval); window.clearInterval(container._interval);
return;
}
PDFView.thumbnails[pageIndex++].draw(); PDFView.thumbnails[pageIndex++].draw();
}, 500); }, 500);
}, true); }, true);
window.addEventListener('scalechange', function(evt) { window.addEventListener('scalechange', function scalechange(evt) {
var options = document.getElementById('scaleSelect').options; var options = document.getElementById('scaleSelect').options;
for (var i = 0; i < options.length; i++) { for (var i = 0; i < options.length; i++) {
var option = options[i]; var option = options[i];
@ -440,7 +441,7 @@ window.addEventListener('scalechange', function(evt) {
} }
}, true); }, true);
window.addEventListener('pagechange', function(evt) { window.addEventListener('pagechange', function pagechange(evt) {
var page = evt.detail; var page = evt.detail;
document.location.hash = page; document.location.hash = page;
document.getElementById('pageNumber').value = page; document.getElementById('pageNumber').value = page;