Use the built-in widths to calculate glyphs metrics
This commit is contained in:
parent
f759e56a02
commit
d4fb9c786c
47
fonts.js
47
fonts.js
@ -140,11 +140,25 @@ var FontMeasure = (function FontMeasure() {
|
|||||||
ctx.font = rule;
|
ctx.font = rule;
|
||||||
current = font;
|
current = font;
|
||||||
},
|
},
|
||||||
measureText: function fonts_measureText(text) {
|
measureText: function fonts_measureText(text, font, size) {
|
||||||
var width;
|
var width;
|
||||||
if (measureCache && (width = measureCache[text]))
|
if (measureCache && (width = measureCache[text]))
|
||||||
return width;
|
return width;
|
||||||
|
|
||||||
|
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;
|
width = ctx.measureText(text).width / kScalePrecision;
|
||||||
|
}
|
||||||
if (measureCache)
|
if (measureCache)
|
||||||
measureCache[text] = width;
|
measureCache[text] = width;
|
||||||
return width;
|
return width;
|
||||||
@ -444,7 +458,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 +482,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];
|
||||||
@ -1019,7 +1031,9 @@ var Font = (function Font() {
|
|||||||
var index = firstCode;
|
var index = firstCode;
|
||||||
for (var j = start; j <= end; j++) {
|
for (var j = start; j <= end; j++) {
|
||||||
var code = j - firstCode - 1;
|
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);
|
return cmap.data = createCMapTable(glyphs);
|
||||||
}
|
}
|
||||||
@ -1126,8 +1140,13 @@ var Font = (function Font() {
|
|||||||
if (!encoding[0]) {
|
if (!encoding[0]) {
|
||||||
// the font is directly characters to glyphs with no encoding
|
// the font is directly characters to glyphs with no encoding
|
||||||
// so create an identity encoding
|
// so create an identity encoding
|
||||||
for (i = 0; i < numGlyphs; i++)
|
var widths = properties.widths;
|
||||||
encoding[i] = { unicode: i + kCmapGlyphOffset };
|
for (i = 0; i < numGlyphs; i++) {
|
||||||
|
encoding[i] = {
|
||||||
|
unicode: i + kCmapGlyphOffset,
|
||||||
|
width: widths[i] || properties.defaultWidth
|
||||||
|
};
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
for (var code in encoding)
|
for (var code in encoding)
|
||||||
encoding[code].unicode += kCmapGlyphOffset;
|
encoding[code].unicode += kCmapGlyphOffset;
|
||||||
@ -1368,10 +1387,6 @@ var Font = (function Font() {
|
|||||||
unicode = charcode;
|
unicode = charcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the glyph has already been converted
|
|
||||||
if (!IsNum(unicode))
|
|
||||||
unicode = encoding[charcode].unicode = this.glyphs[unicode].unicode;
|
|
||||||
|
|
||||||
// Handle surrogate pairs
|
// Handle surrogate pairs
|
||||||
if (unicode > 0xFFFF) {
|
if (unicode > 0xFFFF) {
|
||||||
str += String.fromCharCode(unicode & 0xFFFF);
|
str += String.fromCharCode(unicode & 0xFFFF);
|
||||||
@ -1824,7 +1839,8 @@ var Type1Parser = function() {
|
|||||||
var glyph = getToken();
|
var glyph = getToken();
|
||||||
|
|
||||||
if ('undefined' == typeof(properties.differences[index])) {
|
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;
|
properties.glyphs[glyph] = properties.encoding[index] = mapping;
|
||||||
}
|
}
|
||||||
getToken(); // read the in 'put'
|
getToken(); // read the in 'put'
|
||||||
@ -2315,8 +2331,6 @@ var Type2CFF = (function() {
|
|||||||
|
|
||||||
getCharStrings: function cff_charstrings(charsets, charStrings,
|
getCharStrings: function cff_charstrings(charsets, charStrings,
|
||||||
privDict, properties) {
|
privDict, properties) {
|
||||||
var widths = properties.widths;
|
|
||||||
|
|
||||||
var defaultWidth = privDict['defaultWidthX'];
|
var defaultWidth = privDict['defaultWidthX'];
|
||||||
var nominalWidth = privDict['nominalWidthX'];
|
var nominalWidth = privDict['nominalWidthX'];
|
||||||
|
|
||||||
@ -2334,12 +2348,11 @@ var Type2CFF = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (code == -1) {
|
|
||||||
var mapping = properties.glyphs[glyph] || {};
|
var mapping = properties.glyphs[glyph] || {};
|
||||||
|
if (code == -1)
|
||||||
index = code = mapping.unicode || 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;
|
||||||
|
|
||||||
|
2938
metrics.js
Normal file
2938
metrics.js
Normal file
File diff suppressed because it is too large
Load Diff
90
pdf.js
90
pdf.js
@ -4197,8 +4197,31 @@ var PartialEvaluator = (function() {
|
|||||||
extractEncoding: function(dict, xref, properties) {
|
extractEncoding: function(dict, xref, properties) {
|
||||||
var type = properties.type;
|
var type = properties.type;
|
||||||
if (properties.composite) {
|
if (properties.composite) {
|
||||||
// XXX only CIDFontType2 supported for now
|
|
||||||
if (type == 'CIDFontType2') {
|
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');
|
var cidToGidMap = dict.get('CIDToGIDMap');
|
||||||
if (!cidToGidMap || !IsRef(cidToGidMap))
|
if (!cidToGidMap || !IsRef(cidToGidMap))
|
||||||
return GlyphsUnicode;
|
return GlyphsUnicode;
|
||||||
@ -4211,15 +4234,16 @@ var PartialEvaluator = (function() {
|
|||||||
var encoding = properties.encoding;
|
var encoding = properties.encoding;
|
||||||
|
|
||||||
// Set encoding 0 to later verify the font has an 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++) {
|
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)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
encoding[j >> 1] = {
|
var code = j >> 1;
|
||||||
|
encoding[code] = {
|
||||||
unicode: glyphID,
|
unicode: glyphID,
|
||||||
width: 0
|
width: glyphsWidths[code] || defaultWidth
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
} else if (type == 'CIDFontType0') {
|
} else if (type == 'CIDFontType0') {
|
||||||
@ -4287,13 +4311,16 @@ 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;
|
||||||
glyphs[glyph] = map[i] = {
|
var width = properties.widths[i] || properties.widths[glyph];
|
||||||
|
map[i] = {
|
||||||
unicode: index,
|
unicode: index,
|
||||||
width: properties.widths[i - firstChar] || properties.defaultWidth
|
width: width || properties.defaultWidth
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (glyph)
|
||||||
|
glyphs[glyph] = map[i];
|
||||||
|
|
||||||
// If there is no file, the character mapping can't be modified
|
// If there is no file, the character mapping can't be modified
|
||||||
// but this is unlikely that there is any standard encoding with
|
// but this is unlikely that there is any standard encoding with
|
||||||
// chars below 0x1f, so that's fine.
|
// chars below 0x1f, so that's fine.
|
||||||
@ -4303,7 +4330,6 @@ var PartialEvaluator = (function() {
|
|||||||
if (index <= 0x1f || (index >= 127 && index <= 255))
|
if (index <= 0x1f || (index >= 127 && index <= 255))
|
||||||
map[i].unicode += kCmapGlyphOffset;
|
map[i].unicode += kCmapGlyphOffset;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
|
if (type == 'TrueType' && dict.has('ToUnicode') && differences) {
|
||||||
var cmapObj = xref.fetchIfRef(dict.get('ToUnicode'));
|
var cmapObj = xref.fetchIfRef(dict.get('ToUnicode'));
|
||||||
@ -4339,10 +4365,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] = {
|
var mapping = map[startRange] || {};
|
||||||
unicode: code++,
|
mapping.unicode = code++;
|
||||||
width: 0
|
map[startRange] = mapping;
|
||||||
}
|
|
||||||
++startRange;
|
++startRange;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4353,10 +4378,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] = {
|
var mapping = map[index] || {};
|
||||||
unicode: code,
|
mapping.unicode = code;
|
||||||
width: 0
|
map[index] = mapping;
|
||||||
};
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -4425,7 +4449,8 @@ var PartialEvaluator = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Before PDF 1.5 if the font was one of the base 14 fonts, having a
|
// 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'));
|
var descriptor = xref.fetchIfRef(dict.get('FontDescriptor'));
|
||||||
if (!descriptor) {
|
if (!descriptor) {
|
||||||
var baseFontName = dict.get('BaseFont');
|
var baseFontName = dict.get('BaseFont');
|
||||||
@ -4445,11 +4470,18 @@ var PartialEvaluator = (function() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var defaultWidth = 0;
|
||||||
|
var widths = Metrics[stdFontMap[baseFontName] || baseFontName];
|
||||||
|
if (IsNum(widths)) {
|
||||||
|
defaultWidth = widths;
|
||||||
|
widths = null;
|
||||||
|
}
|
||||||
var properties = {
|
var properties = {
|
||||||
type: type.name,
|
type: type.name,
|
||||||
encoding: map,
|
encoding: map,
|
||||||
differences: [],
|
differences: [],
|
||||||
widths: {},
|
widths: widths,
|
||||||
|
defaultWidth: defaultWidth,
|
||||||
firstChar: 0,
|
firstChar: 0,
|
||||||
lastChar: 256
|
lastChar: 256
|
||||||
};
|
};
|
||||||
@ -4508,13 +4540,13 @@ 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: descriptor.get('MissingWidth') || 0,
|
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: (function() {
|
widths: (function() {
|
||||||
var glyphWidths = {};
|
var glyphWidths = {};
|
||||||
for (var i = 0; i <= widths.length; i++)
|
for (var i = 0; i < widths.length; i++)
|
||||||
glyphWidths[firstChar++] = widths[i];
|
glyphWidths[firstChar++] = widths[i];
|
||||||
return glyphWidths;
|
return glyphWidths;
|
||||||
})(),
|
})(),
|
||||||
@ -4903,6 +4935,7 @@ var CanvasGraphics = (function() {
|
|||||||
showText: function(text) {
|
showText: function(text) {
|
||||||
var ctx = this.ctx;
|
var ctx = this.ctx;
|
||||||
var current = this.current;
|
var current = this.current;
|
||||||
|
var originalText = text;
|
||||||
|
|
||||||
ctx.save();
|
ctx.save();
|
||||||
ctx.transform.apply(ctx, current.textMatrix);
|
ctx.transform.apply(ctx, current.textMatrix);
|
||||||
@ -4921,26 +4954,21 @@ var CanvasGraphics = (function() {
|
|||||||
text = font.charsToUnicode(text);
|
text = font.charsToUnicode(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
ctx.fillText(text.charAt(i), 0, 0);
|
||||||
ctx.fillText(c, 0, 0);
|
var c = originalText.charAt(i);
|
||||||
var charWidth = FontMeasure.measureText(c) + charSpacing;
|
var charWidth = FontMeasure.measureText(c, font, 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);
|
||||||
@ -4949,7 +4977,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(originalText, font, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.ctx.restore();
|
this.ctx.restore();
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
<script type="text/javascript" src="../fonts.js"></script>
|
<script type="text/javascript" src="../fonts.js"></script>
|
||||||
<script type="text/javascript" src="../crypto.js"></script>
|
<script type="text/javascript" src="../crypto.js"></script>
|
||||||
<script type="text/javascript" src="../glyphlist.js"></script>
|
<script type="text/javascript" src="../glyphlist.js"></script>
|
||||||
|
<script type="text/javascript" src="../metrics.js"></script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
|
Loading…
Reference in New Issue
Block a user