ctx.font = rule;
current = font;
},
- measureText: function fonts_measureText(text) {
+ measureText: function fonts_measureText(text, font, size) {
var width;
if (measureCache && (width = measureCache[text]))
return width;
- width = ctx.measureText(text).width / kScalePrecision;
+
+ try {
+ width = 0.0;
+ var composite = font.composite;
+ for (var i = 0; i < text.length; i++) {
+ var charcode = composite ?
+ ((text.charCodeAt(i++) << 8) + text.charCodeAt(i)) :
+ text.charCodeAt(i);
+ var charWidth = parseFloat(font.encoding[charcode].width);
+ width += charWidth;
+ }
+ width = width * size / 1000;
+ } catch(e) {
+ width = ctx.measureText(text).width / kScalePrecision;
+ }
if (measureCache)
measureCache[text] = width;
return width;
var constructor = function font_constructor(name, file, properties) {
this.name = name;
this.encoding = properties.encoding;
- this.glyphs = properties.glyphs;
this.sizes = [];
var names = name.split("+");
(fontName.indexOf('Italic') != -1);
// Use 'name' instead of 'fontName' here because the original
- // name ArialNarrow for example will be replaced by Helvetica.
- this.narrow = (name.indexOf("Narrow") != -1)
+ // name ArialBlack for example will be replaced by Helvetica.
this.black = (name.indexOf("Black") != -1)
this.loadedName = fontName.split('-')[0];
var index = firstCode;
for (var j = start; j <= end; j++) {
var code = j - firstCode - 1;
- encoding[index++] = { unicode: glyphs[code].unicode };
+ var mapping = encoding[index + 1] || {};
+ mapping.unicode = glyphs[code].unicode;
+ encoding[index++] = mapping;
}
return cmap.data = createCMapTable(glyphs);
}
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 };
+ var widths = properties.widths;
+ for (i = 0; i < numGlyphs; i++) {
+ encoding[i] = {
+ unicode: i + kCmapGlyphOffset,
+ width: widths[i] || properties.defaultWidth
+ };
+ }
} else {
for (var code in encoding)
encoding[code].unicode += kCmapGlyphOffset;
unicode = charcode;
}
- // Check if the glyph has already been converted
- if (!IsNum(unicode))
- unicode = encoding[charcode].unicode = this.glyphs[unicode].unicode;
-
// Handle surrogate pairs
if (unicode > 0xFFFF) {
str += String.fromCharCode(unicode & 0xFFFF);
var glyph = getToken();
if ('undefined' == typeof(properties.differences[index])) {
- var mapping = { unicode: GlyphsUnicode[glyph] || j };
+ var mapping = properties.encoding[index] || {};
+ mapping.unicode = GlyphsUnicode[glyph] || j;
properties.glyphs[glyph] = properties.encoding[index] = mapping;
}
getToken(); // read the in 'put'
getCharStrings: function cff_charstrings(charsets, charStrings,
privDict, properties) {
- var widths = properties.widths;
-
var defaultWidth = privDict['defaultWidthX'];
var nominalWidth = privDict['nominalWidthX'];
}
}
- if (code == -1) {
- var mapping = properties.glyphs[glyph] || {};
+ var mapping = properties.glyphs[glyph] || {};
+ if (code == -1)
index = code = mapping.unicode || index;
- }
- var width = widths[code] || defaultWidth;
+ var width = mapping.width || defaultWidth;
if (code <= 0x1f || (code >= 127 && code <= 255))
code += kCmapGlyphOffset;
extractEncoding: function(dict, xref, properties) {
var type = properties.type;
if (properties.composite) {
- // XXX only CIDFontType2 supported for now
if (type == 'CIDFontType2') {
+ var defaultWidth = xref.fetchIfRef(dict.get('DW')) || 1000;
+ properties.defaultWidth = defaultWidth;
+
+ var glyphsWidths = {};
+ var widths = xref.fetchIfRef(dict.get('W'));
+ if (widths) {
+ var start = 0, end = 0;
+ for (var i = 0; i < widths.length; i++) {
+ var code = widths[i];
+ if (IsArray(code)) {
+ for (var j = 0; j < code.length; j++)
+ glyphsWidths[start++] = code[j];
+ start = 0;
+ } else if (start) {
+ for (var j = start; j <= code; j++)
+ glyphsWidths[j] = widths[++i];
+ start = 0;
+ } else {
+ start = code;
+ }
+ }
+ }
+ properties.widths = glyphsWidths;
+
var cidToGidMap = dict.get('CIDToGIDMap');
if (!cidToGidMap || !IsRef(cidToGidMap))
return GlyphsUnicode;
var encoding = properties.encoding;
// Set encoding 0 to later verify the font has an encoding
- encoding[0] = { unicode: 0 };
+ encoding[0] = { unicode: 0, width: 0 };
for (var j = 0; j < glyphsData.length; j++) {
var glyphID = (glyphsData[j++] << 8) | glyphsData[j];
if (glyphID == 0)
continue;
- encoding[j >> 1] = {
+ var code = j >> 1;
+ encoding[code] = {
unicode: glyphID,
- width: 0
+ width: glyphsWidths[code] || defaultWidth
};
}
} else if (type == 'CIDFontType0') {
var glyphs = {};
for (var i = firstChar; i <= lastChar; i++) {
var glyph = differences[i] || baseEncoding[i];
- if (glyph) {
- var index = GlyphsUnicode[glyph] || i;
- glyphs[glyph] = map[i] = {
- unicode: index,
- width: properties.widths[i - firstChar] || properties.defaultWidth
- };
-
- // If there is no file, the character mapping can't be modified
- // but this is unlikely that there is any standard encoding with
- // chars below 0x1f, so that's fine.
- if (!properties.file)
- continue;
+ var index = GlyphsUnicode[glyph] || i;
+ var width = properties.widths[i] || properties.widths[glyph];
+ map[i] = {
+ unicode: index,
+ width: width || properties.defaultWidth
+ };
- if (index <= 0x1f || (index >= 127 && index <= 255))
- map[i].unicode += kCmapGlyphOffset;
- }
+ if (glyph)
+ glyphs[glyph] = map[i];
+
+ // If there is no file, the character mapping can't be modified
+ // 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) {
var endRange = tokens[j + 1];
var code = tokens[j + 2];
while (startRange < endRange) {
- map[startRange] = {
- unicode: code++,
- width: 0
- }
+ var mapping = map[startRange] || {};
+ mapping.unicode = code++;
+ map[startRange] = mapping;
++startRange;
}
}
for (var j = 0; j < tokens.length; j += 2) {
var index = tokens[j];
var code = tokens[j + 1];
- map[index] = {
- unicode: code,
- width: 0
- };
+ var mapping = map[index] || {};
+ mapping.unicode = code;
+ map[index] = mapping;
}
break;
}
// Before PDF 1.5 if the font was one of the base 14 fonts, having a
- // FontDescriptor was not required. This case is here for compatibility.
+ // FontDescriptor was not required.
+ // This case is here for compatibility.
var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
if (!descriptor) {
var baseFontName = dict.get('BaseFont');
}
}
+ var defaultWidth = 0;
+ var widths = Metrics[stdFontMap[baseFontName] || baseFontName];
+ if (IsNum(widths)) {
+ defaultWidth = widths;
+ widths = null;
+ }
var properties = {
type: type.name,
encoding: map,
differences: [],
- widths: {},
+ widths: widths,
+ defaultWidth: defaultWidth,
firstChar: 0,
lastChar: 256
};
descent: descriptor.get('Descent'),
xHeight: descriptor.get('XHeight'),
capHeight: descriptor.get('CapHeight'),
- defaultWidth: descriptor.get('MissingWidth') || 0,
+ defaultWidth: parseFloat(descriptor.get('MissingWidth')) || 0,
flags: descriptor.get('Flags'),
italicAngle: descriptor.get('ItalicAngle'),
differences: [],
widths: (function() {
var glyphWidths = {};
- for (var i = 0; i <= widths.length; i++)
+ for (var i = 0; i < widths.length; i++)
glyphWidths[firstChar++] = widths[i];
return glyphWidths;
})(),
showText: function(text) {
var ctx = this.ctx;
var current = this.current;
+ var originalText = text;
ctx.save();
ctx.transform.apply(ctx, current.textMatrix);
text = font.charsToUnicode(text);
}
+ var size = current.fontSize;
var charSpacing = current.charSpacing;
var wordSpacing = current.wordSpacing;
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) {
scaleFactorX *= textHScale;
ctx.scale(1 / textHScale, 1);
var width = 0;
for (var i = 0, ii = text.length; i < ii; ++i) {
- var c = text.charAt(i);
- ctx.fillText(c, 0, 0);
- var charWidth = FontMeasure.measureText(c) + charSpacing;
+ ctx.fillText(text.charAt(i), 0, 0);
+ var c = originalText.charAt(i);
+ var charWidth = FontMeasure.measureText(c, font, size);
+ charWidth += charSpacing;
if (c.charCodeAt(0) == 32)
charWidth += wordSpacing;
ctx.translate(charWidth * scaleFactorX, 0);
current.x += width;
} else {
ctx.fillText(text, 0, 0);
- current.x += FontMeasure.measureText(text);
+ current.x += FontMeasure.measureText(originalText, font, size);
}
this.ctx.restore();