Merge branch 'refactor'

This commit is contained in:
Vivien Nicolas 2011-09-09 01:32:45 +02:00
commit 59af13e09f
2 changed files with 100 additions and 83 deletions

102
fonts.js
View File

@ -140,11 +140,21 @@ var FontMeasure = (function FontMeasure() {
ctx.font = rule; ctx.font = rule;
current = font; current = font;
}, },
measureText: function fonts_measureText(text) { measureText: function fonts_measureText(text, encoding, size) {
var width; var width;
if (measureCache && (width = measureCache[text])) if (measureCache && (width = measureCache[text]))
return width; return width;
width = ctx.measureText(text).width / kScalePrecision;
try {
width = 0.0;
for (var i = 0; i < text.length; i++) {
var charWidth = encoding[text.charCodeAt(i)].width;
width += parseFloat(charWidth);
}
width = width * size / 1000;
} catch(e) {
width = ctx.measureText(text).width / kScalePrecision;
}
if (measureCache) if (measureCache)
measureCache[text] = width; measureCache[text] = width;
return width; return width;
@ -444,7 +454,6 @@ 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 = [];
var names = name.split("+"); var names = name.split("+");
@ -469,8 +478,7 @@ var Font = (function Font() {
(fontName.indexOf('Italic') != -1); (fontName.indexOf('Italic') != -1);
// Use 'name' instead of 'fontName' here because the original // Use 'name' instead of 'fontName' here because the original
// name ArialNarrow for example will be replaced by Helvetica. // name ArialBlack for example will be replaced by Helvetica.
this.narrow = (name.indexOf("Narrow") != -1)
this.black = (name.indexOf("Black") != -1) this.black = (name.indexOf("Black") != -1)
this.loadedName = fontName.split('-')[0]; this.loadedName = fontName.split('-')[0];
@ -711,7 +719,7 @@ var Font = (function Font() {
var encoding = properties.encoding; var encoding = properties.encoding;
for (var index in encoding) { for (var index in encoding) {
var code = encoding[index]; var code = encoding[index].unicode;
if (firstCharIndex > code || !firstCharIndex) if (firstCharIndex > code || !firstCharIndex)
firstCharIndex = code; firstCharIndex = code;
if (lastCharIndex < code) if (lastCharIndex < code)
@ -970,15 +978,9 @@ var Font = (function Font() {
if (index) { if (index) {
deltas.push(index); deltas.push(index);
var code = encoding[index];
for (var glyph in properties.glyphs) {
if (properties.glyphs[glyph] == code)
break;
}
var unicode = j + kCmapGlyphOffset; var unicode = j + kCmapGlyphOffset;
properties.glyphs[glyph] = encoding[j] = unicode; encoding[j].unicode = unicode;
glyphs.push({ glyph: glyph, unicode: unicode }); glyphs.push({ unicode: unicode });
} }
} }
@ -1023,8 +1025,12 @@ var Font = (function Font() {
var start = denseRange[0]; var start = denseRange[0];
var end = denseRange[1]; var end = denseRange[1];
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; var code = j - firstCode - 1;
var mapping = encoding[index + 1] || {};
mapping.unicode = glyphs[code].unicode;
encoding[index++] = mapping;
}
return cmap.data = createCMapTable(glyphs); return cmap.data = createCMapTable(glyphs);
} }
} }
@ -1118,23 +1124,6 @@ var Font = (function Font() {
// U+00AD (soft hyphen) is not drawn. // U+00AD (soft hyphen) is not drawn.
// So, offset all the glyphs by 0xFF to avoid these cases and use // So, offset all the glyphs by 0xFF to avoid these cases and use
// the encoding to map incoming characters to the new glyph positions // the encoding to map incoming characters to the new glyph positions
var glyphs = [];
var encoding = properties.encoding;
for (var i = 1; i < numGlyphs; i++)
glyphs.push({ unicode: i + kCmapGlyphOffset });
if ('undefined' == typeof(encoding[0])) {
// the font is directly characters to glyphs with no encoding
// so create an identity encoding
for (i = 0; i < numGlyphs; i++)
encoding[i] = i + kCmapGlyphOffset;
} else {
for (var code in encoding)
encoding[code] += kCmapGlyphOffset;
}
if (!cmap) { if (!cmap) {
cmap = { cmap = {
tag: 'cmap', tag: 'cmap',
@ -1142,6 +1131,21 @@ var Font = (function Font() {
}; };
tables.push(cmap); tables.push(cmap);
} }
var encoding = properties.encoding;
if (!encoding[0]) {
// the font is directly characters to glyphs with no encoding
// so create an identity encoding
for (i = 0; i < numGlyphs; i++)
encoding[i] = { unicode: i + kCmapGlyphOffset };
} else {
for (var code in encoding)
encoding[code].unicode += kCmapGlyphOffset;
}
var glyphs = [];
for (var i = 1; i < numGlyphs; i++)
glyphs.push({ unicode: i + kCmapGlyphOffset });
cmap.data = createCMapTable(glyphs); cmap.data = createCMapTable(glyphs);
} else { } else {
replaceCMapTable(cmap, font, properties); replaceCMapTable(cmap, font, properties);
@ -1361,23 +1365,19 @@ var Font = (function Font() {
// loop should never end on the last byte // loop should never end on the last byte
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]); var charcode = int16([chars.charCodeAt(i++), chars.charCodeAt(i)]);
var unicode = encoding[charcode]; var unicode = encoding[charcode].unicode;
str += String.fromCharCode(unicode); str += String.fromCharCode(unicode);
} }
} }
else { else {
for (var i = 0; i < chars.length; ++i) { for (var i = 0; i < chars.length; ++i) {
var charcode = chars.charCodeAt(i); var charcode = chars.charCodeAt(i);
var unicode = encoding[charcode]; var unicode = encoding[charcode].unicode;
if ('undefined' == typeof(unicode)) { if ('undefined' == typeof(unicode)) {
warn('Unencoded charcode ' + charcode); warn('Unencoded charcode ' + charcode);
unicode = charcode; unicode = charcode;
} }
// Check if the glyph has already been converted
if (!IsNum(unicode))
unicode = encoding[charcode] = this.glyphs[unicode];
// Handle surrogate pairs // Handle surrogate pairs
if (unicode > 0xFFFF) { if (unicode > 0xFFFF) {
str += String.fromCharCode(unicode & 0xFFFF); str += String.fromCharCode(unicode & 0xFFFF);
@ -1830,8 +1830,8 @@ var Type1Parser = function() {
var glyph = getToken(); var glyph = getToken();
if ('undefined' == typeof(properties.differences[index])) { if ('undefined' == typeof(properties.differences[index])) {
properties.encoding[index] = glyph; var mapping = { unicode: GlyphsUnicode[glyph] || j };
properties.glyphs[glyph] = GlyphsUnicode[glyph] || index; properties.glyphs[glyph] = properties.encoding[index] = mapping;
} }
getToken(); // read the in 'put' getToken(); // read the in 'put'
} }
@ -2000,14 +2000,14 @@ CFF.prototype = {
for (var i = 0; i < glyphs.length; i++) { for (var i = 0; i < glyphs.length; i++) {
var glyph = glyphs[i]; var glyph = glyphs[i];
var unicode = properties.glyphs[glyph.glyph]; var mapping = properties.glyphs[glyph.glyph];
if (!unicode) { if (!mapping) {
if (glyph.glyph != '.notdef') if (glyph.glyph != '.notdef')
missings.push(glyph.glyph); missings.push(glyph.glyph);
} else { } else {
charstrings.push({ charstrings.push({
glyph: glyph.glyph, glyph: glyph.glyph,
unicode: unicode, unicode: mapping.unicode,
charstring: glyph.data, charstring: glyph.data,
width: glyph.width, width: glyph.width,
lsb: glyph.lsb lsb: glyph.lsb
@ -2340,17 +2340,23 @@ var Type2CFF = (function() {
} }
} }
var mapping = properties.glyphs[glyph] || {};
if (code == -1) if (code == -1)
index = code = properties.glyphs[glyph] || index; index = code = mapping.unicode || index;
var width = widths[code] || defaultWidth; var width = mapping.width || defaultWidth;
if (code <= 0x1f || (code >= 127 && code <= 255)) if (code <= 0x1f || (code >= 127 && code <= 255))
code += kCmapGlyphOffset; code += kCmapGlyphOffset;
properties.encoding[index] = code; properties.glyphs[glyph] = properties.encoding[index] = {
unicode: code,
width: width
};
charstrings.push({ charstrings.push({
unicode: code, unicode: code,
width: width, gid: i width: width,
gid: i
}); });
index++; index++;
} }

81
pdf.js
View File

@ -4208,13 +4208,19 @@ var PartialEvaluator = (function() {
var glyphsData = glyphsStream.getBytes(0); var glyphsData = glyphsStream.getBytes(0);
// Glyph ids are big-endian 2-byte values // Glyph ids are big-endian 2-byte values
// Set this to 0 to verify the font has an encoding.
var encoding = properties.encoding; var encoding = properties.encoding;
encoding[0] = 0;
// Set encoding 0 to later verify the font has an encoding
encoding[0] = { unicode: 0 };
for (var j = 0; j < glyphsData.length; j++) { for (var j = 0; j < glyphsData.length; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j]; var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
if (glyphID != 0) if (glyphID == 0)
encoding[j >> 1] = glyphID; continue;
encoding[j >> 1] = {
unicode: glyphID,
width: 0
};
} }
} else if (type == 'CIDFontType0') { } else if (type == 'CIDFontType0') {
var encoding = xref.fetchIfRef(dict.get('Encoding')); var encoding = xref.fetchIfRef(dict.get('Encoding'));
@ -4281,19 +4287,23 @@ var PartialEvaluator = (function() {
var glyphs = {}; var glyphs = {};
for (var i = firstChar; i <= lastChar; i++) { for (var i = firstChar; i <= lastChar; i++) {
var glyph = differences[i] || baseEncoding[i]; var glyph = differences[i] || baseEncoding[i];
if (glyph) { var index = GlyphsUnicode[glyph] || i;
var index = GlyphsUnicode[glyph] || i; map[i] = {
glyphs[glyph] = map[i] = index; unicode: index,
width: properties.widths[i] || properties.defaultWidth
};
// If there is no file, the character mapping can't be modified if (glyph)
// but this is unlikely that there is any standard encoding with glyphs[glyph] = map[i];
// chars below 0x1f, so that's fine.
if (!properties.file)
continue;
if (index <= 0x1f || (index >= 127 && index <= 255)) // If there is no file, the character mapping can't be modified
glyphs[glyph] = map[i] += kCmapGlyphOffset; // but this is unlikely that there is any standard encoding with
} // chars below 0x1f, so that's fine.
if (!properties.file)
continue;
if (index <= 0x1f || (index >= 127 && index <= 255))
map[i].unicode += kCmapGlyphOffset;
} }
if (type == 'TrueType' && dict.has('ToUnicode') && differences) { if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
@ -4330,7 +4340,9 @@ var PartialEvaluator = (function() {
var endRange = tokens[j + 1]; var endRange = tokens[j + 1];
var code = tokens[j + 2]; var code = tokens[j + 2];
while (startRange < endRange) { while (startRange < endRange) {
map[startRange] = code++; var mapping = map[startRange] || {};
mapping.unicode = code++;
map[startRange] = mapping;
++startRange; ++startRange;
} }
} }
@ -4341,7 +4353,9 @@ var PartialEvaluator = (function() {
for (var j = 0; j < tokens.length; j += 2) { for (var j = 0; j < tokens.length; j += 2) {
var index = tokens[j]; var index = tokens[j];
var code = tokens[j + 1]; var code = tokens[j + 1];
map[index] = code; var mapping = map[index] || {};
mapping.unicode = code;
map[index] = mapping;
} }
break; break;
@ -4434,6 +4448,7 @@ var PartialEvaluator = (function() {
type: type.name, type: type.name,
encoding: map, encoding: map,
differences: [], differences: [],
widths: {},
firstChar: 0, firstChar: 0,
lastChar: 256 lastChar: 256
}; };
@ -4492,19 +4507,18 @@ var PartialEvaluator = (function() {
descent: descriptor.get('Descent'), descent: descriptor.get('Descent'),
xHeight: descriptor.get('XHeight'), xHeight: descriptor.get('XHeight'),
capHeight: descriptor.get('CapHeight'), capHeight: descriptor.get('CapHeight'),
defaultWidth: parseFloat(descriptor.get('MissingWidth')) || 0,
flags: descriptor.get('Flags'), flags: descriptor.get('Flags'),
italicAngle: descriptor.get('ItalicAngle'), italicAngle: descriptor.get('ItalicAngle'),
differences: [], differences: [],
widths: [], widths: (function() {
var glyphWidths = {};
for (var i = 0; i < widths.length; i++)
glyphWidths[firstChar++] = widths[i];
return glyphWidths;
})(),
encoding: {} encoding: {}
}; };
// XXX Encoding and Glyphs should point to the same object so it will
// be hard to be out of sync. The object could contains the unicode and
// the width of the glyph.
for (var i = 0; i <= widths.length; i++)
properties.widths[firstChar++] = widths[i];
properties.glyphs = this.extractEncoding(dict, xref, properties); properties.glyphs = this.extractEncoding(dict, xref, properties);
return { return {
@ -4897,6 +4911,7 @@ var CanvasGraphics = (function() {
var scaleFactorX = 1, scaleFactorY = 1; var scaleFactorX = 1, scaleFactorY = 1;
var font = current.font; var font = current.font;
var baseText= text;
if (font) { if (font) {
if (current.fontSize <= kRasterizerMin) { if (current.fontSize <= kRasterizerMin) {
scaleFactorX = scaleFactorY = kScalePrecision; scaleFactorX = scaleFactorY = kScalePrecision;
@ -4906,26 +4921,22 @@ var CanvasGraphics = (function() {
text = font.charsToUnicode(text); text = font.charsToUnicode(text);
} }
var encoding = current.font.encoding;
var size = current.fontSize;
var charSpacing = current.charSpacing; var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing; var wordSpacing = current.wordSpacing;
var textHScale = current.textHScale; var textHScale = current.textHScale;
// This is a poor simulation for Arial Narrow while font-stretch
// is not implemented (bug 3512)
if (current.font.narrow) {
textHScale += 0.2;
charSpacing -= (0.09 * current.fontSize);
}
if (charSpacing != 0 || wordSpacing != 0 || textHScale != 1) { if (charSpacing != 0 || wordSpacing != 0 || textHScale != 1) {
scaleFactorX *= textHScale; scaleFactorX *= textHScale;
ctx.scale(1 / textHScale, 1); ctx.scale(1 / textHScale, 1);
var width = 0; var width = 0;
for (var i = 0, ii = text.length; i < ii; ++i) { for (var i = 0, ii = text.length; i < ii; ++i) {
var c = text.charAt(i); var c = baseText.charAt(i);
ctx.fillText(c, 0, 0); ctx.fillText(c, 0, 0);
var charWidth = FontMeasure.measureText(c) + charSpacing; var charWidth = FontMeasure.measureText(c, encoding, size);
charWidth += charSpacing;
if (c.charCodeAt(0) == 32) if (c.charCodeAt(0) == 32)
charWidth += wordSpacing; charWidth += wordSpacing;
ctx.translate(charWidth * scaleFactorX, 0); ctx.translate(charWidth * scaleFactorX, 0);
@ -4934,7 +4945,7 @@ var CanvasGraphics = (function() {
current.x += width; current.x += width;
} else { } else {
ctx.fillText(text, 0, 0); ctx.fillText(text, 0, 0);
current.x += FontMeasure.measureText(text); current.x += FontMeasure.measureText(baseText, encoding, size);
} }
this.ctx.restore(); this.ctx.restore();