Rename s2a, s16, s32 and do some dance inside the bind() code

This commit is contained in:
Vivien Nicolas 2011-06-21 04:30:28 +02:00
parent 8787e7cbe9
commit 8523896023
2 changed files with 116 additions and 109 deletions

217
fonts.js
View File

@ -43,38 +43,39 @@ var Fonts = {
this._active = this[aName]; this._active = this[aName];
}, },
chars2Unicode: function(chars) { charsToUnicode: function fonts_chars2Unicode(chars) {
var active = this._active; var active = this._active;
if (!active) if (!active)
return chars; return chars;
// if we translated this string before, just grab it from the cache // if we translated this string before, just grab it from the cache
var ret = active.cache[chars]; var str = active.cache[chars] || "";
if (ret) if (str)
return ret; return str;
// translate the string using the font's encoding // translate the string using the font's encoding
var encoding = active.properties.encoding; var encoding = active.properties.encoding;
if (!encoding) if (!encoding)
return chars; return chars;
var ret = "";
for (var i = 0; i < chars.length; ++i) { for (var i = 0; i < chars.length; ++i) {
var ch = chars.charCodeAt(i); var charcode = chars.charCodeAt(i);
var uc = encoding[ch]; var unicode = encoding[charcode];
if (uc instanceof Name) // we didn't convert the glyph yet
uc = encoding[ch] = GlyphsUnicode[uc.name]; // Check if the glyph has already been converted
if (uc > 0xffff) { // handle surrogate pairs if (unicode instanceof Name)
ret += String.fromCharCode(uc & 0xffff); unicode = encoding[unicode] = GlyphsUnicode[unicode.name];
uc >>= 16;
// Handle surrogate pairs
if (unicode > 0xFFFF) {
str += String.fromCharCode(unicode & 0xFFFF);
unicode >>= 16;
} }
ret += String.fromCharCode(uc); str += String.fromCharCode(unicode);
} }
// enter the translated string into the cache // Enter the translated string into the cache
active.cache[chars] = ret; return active.cache[chars] = str;
return ret;
} }
}; };
@ -99,6 +100,8 @@ var Font = (function () {
fontCount++; fontCount++;
fontName = aName; fontName = aName;
// If the font is to be ignored, register it like an already loaded font
// to avoid the cost of waiting for it be be loaded by the platform.
if (aProperties.ignore || kDisableFonts) { if (aProperties.ignore || kDisableFonts) {
Fonts[aName] = { Fonts[aName] = {
data: aFile, data: aFile,
@ -168,31 +171,12 @@ var Font = (function () {
bind: function font_bind() { bind: function font_bind() {
var data = this.font; var data = this.font;
// Get the base64 encoding of the binary font data
var str = "";
var length = data.length;
for (var i = 0; i < length; ++i)
str += String.fromCharCode(data[i]);
var dataBase64 = window.btoa(str);
var fontName = this.name; var fontName = this.name;
/** Hack begin */ /** Hack begin */
// Actually there is not event when a font has finished downloading so // Actually there is not event when a font has finished downloading so
// the following tons of code are a dirty hack to 'guess' when a font is // the following code are a dirty hack to 'guess' when a font is ready
// ready
var debug = false;
if (debug) {
var name = document.createElement("font");
name.setAttribute("style", "position: absolute; left: 20px; top: " +
(100 * fontCount + 60) + "px");
name.innerHTML = fontName;
document.body.appendChild(name);
}
var canvas = document.createElement("canvas"); var canvas = document.createElement("canvas");
var style = "border: 1px solid black; position:absolute; top: " + var style = "border: 1px solid black; position:absolute; top: " +
(debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px"; (debug ? (100 * fontCount) : "-200") + "px; left: 2px; width: 340px; height: 100px";
@ -201,6 +185,21 @@ var Font = (function () {
canvas.setAttribute("heigth", 100); canvas.setAttribute("heigth", 100);
document.body.appendChild(canvas); document.body.appendChild(canvas);
// Get the font size canvas think it will be for 'spaces'
var ctx = canvas.getContext("2d");
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
var testString = " ";
// When debugging use the characters provided by the charsets to visually
// see what's happening instead of 'spaces'
var debug = false;
if (debug) {
var name = document.createElement("font");
name.setAttribute("style", "position: absolute; left: 20px; top: " +
(100 * fontCount + 60) + "px");
name.innerHTML = fontName;
document.body.appendChild(name);
// Retrieve font charset // Retrieve font charset
var charset = Fonts[fontName].properties.charset || []; var charset = Fonts[fontName].properties.charset || [];
@ -209,25 +208,19 @@ var Font = (function () {
while (count-- && charset.length <= 30) while (count-- && charset.length <= 30)
charset = charset.concat(charset.slice()); charset = charset.concat(charset.slice());
// Get the font size canvas think it will be for 'spaces'
var ctx = canvas.getContext("2d");
var testString = " ";
// When debugging use the characters provided by the charsets to visually
// see what's happening
if (debug) {
for (var i = 0; i < charset.length; i++) { for (var i = 0; i < charset.length; i++) {
var unicode = GlyphsUnicode[charset[i]]; var unicode = GlyphsUnicode[charset[i]];
if (!unicode) if (!unicode)
continue; continue;
testString += String.fromCharCode(unicode); testString += String.fromCharCode(unicode);
} }
}
ctx.font = "bold italic 20px " + fontName + ", Symbol, Arial";
var textWidth = ctx.measureText(testString).width;
if (debug)
ctx.fillText(testString, 20, 20); ctx.fillText(testString, 20, 20);
}
// Periodicaly check for the width of the testString, it will be
// different once the real font has loaded
var textWidth = ctx.measureText(testString).width;
var interval = window.setInterval(function canvasInterval(self) { var interval = window.setInterval(function canvasInterval(self) {
this.start = this.start || Date.now(); this.start = this.start || Date.now();
@ -248,12 +241,20 @@ var Font = (function () {
if (debug) if (debug)
ctx.fillText(testString, 20, 50); ctx.fillText(testString, 20, 50);
}, 50, this); }, 30, this);
/** Hack end */ /** Hack end */
// Get the base64 encoding of the binary font data
var str = "";
var length = data.length;
for (var i = 0; i < length; ++i)
str += String.fromCharCode(data[i]);
var base64 = window.btoa(str);
// Add the @font-face rule to the document // Add the @font-face rule to the document
var url = "url(data:" + this.mimetype + ";base64," + dataBase64 + ");"; var url = "url(data:" + this.mimetype + ";base64," + base64 + ");";
var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}"; var rule = "@font-face { font-family:'" + fontName + "';src:" + url + "}";
var styleSheet = document.styleSheets[0]; var styleSheet = document.styleSheets[0];
styleSheet.insertRule(rule, styleSheet.length); styleSheet.insertRule(rule, styleSheet.length);
@ -262,20 +263,23 @@ var Font = (function () {
cover: function font_cover(aName, aFont, aProperties) { cover: function font_cover(aName, aFont, aProperties) {
var otf = Uint8Array(kMaxFontFileSize); var otf = Uint8Array(kMaxFontFileSize);
function s2a(s) { function stringToArray(str) {
var a = []; var array = [];
for (var i = 0; i < s.length; ++i) for (var i = 0; i < str.length; ++i)
a[i] = s.charCodeAt(i); array[i] = str.charCodeAt(i);
return a; return array;
} }
function s16(value) { function string16(value) {
return String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); return String.fromCharCode((value >> 8) & 0xff) +
String.fromCharCode(value & 0xff);
} }
function s32(value) { function string32(value) {
return String.fromCharCode((value >> 24) & 0xff) + String.fromCharCode((value >> 16) & 0xff) + return String.fromCharCode((value >> 24) & 0xff) +
String.fromCharCode((value >> 8) & 0xff) + String.fromCharCode(value & 0xff); String.fromCharCode((value >> 16) & 0xff) +
String.fromCharCode((value >> 8) & 0xff) +
String.fromCharCode(value & 0xff);
} }
function createOpenTypeHeader(aFile, aOffsets, numTables) { function createOpenTypeHeader(aFile, aOffsets, numTables) {
@ -285,20 +289,20 @@ var Font = (function () {
header += "\x4F\x54\x54\x4F"; header += "\x4F\x54\x54\x4F";
// numTables (2 bytes) // numTables (2 bytes)
header += s16(numTables); header += string16(numTables);
// searchRange (2 bytes) // searchRange (2 bytes)
var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables); var tablesMaxPower2 = FontsUtils.getMaxPower2(numTables);
var searchRange = tablesMaxPower2 * 16; var searchRange = tablesMaxPower2 * 16;
header += s16(searchRange); header += string16(searchRange);
// entrySelector (2 bytes) // entrySelector (2 bytes)
header += s16(Math.log(tablesMaxPower2) / Math.log(2)); header += string16(Math.log(tablesMaxPower2) / Math.log(2));
// rangeShift (2 bytes) // rangeShift (2 bytes)
header += s16(numTables * 16 - searchRange); header += string16(numTables * 16 - searchRange);
aFile.set(s2a(header), aOffsets.currentOffset); aFile.set(stringToArray(header), aOffsets.currentOffset);
aOffsets.currentOffset += header.length; aOffsets.currentOffset += header.length;
aOffsets.virtualOffset += header.length; aOffsets.virtualOffset += header.length;
} }
@ -322,25 +326,27 @@ var Font = (function () {
offset + offset +
length; length;
var tableEntry = aTag + s32(checksum) + s32(offset) + s32(length); var tableEntry = aTag + string32(checksum) + string32(offset) + string32(length);
tableEntry = s2a(tableEntry); tableEntry = stringToArray(tableEntry);
aFile.set(tableEntry, aOffsets.currentOffset); aFile.set(tableEntry, aOffsets.currentOffset);
aOffsets.currentOffset += tableEntry.length; aOffsets.currentOffset += tableEntry.length;
aOffsets.virtualOffset += aData.length; aOffsets.virtualOffset += aData.length;
} }
function createNameTable(aName) { function createNameTable(aName) {
var names = var names = [
"See original licence" + // Copyright "See original licence", // Copyright
aName + // Font family aName, // Font family
"undefined" + // Font subfamily (font weight) "undefined", // Font subfamily (font weight)
"uniqueID" + // Unique ID "uniqueID", // Unique ID
aName + // Full font name aName, // Full font name
"0.1" + // Version "0.1", // Version
"undefined" + // Postscript name "undefined", // Postscript name
"undefined" + // Trademark "undefined", // Trademark
"undefined" + // Manufacturer "undefined", // Manufacturer
"undefined"; // Designer "undefined" // Designer
];
var name = var name =
"\x00\x00" + // format "\x00\x00" + // format
@ -357,14 +363,14 @@ var Font = (function () {
"\x00\x00" + // encoding ID "\x00\x00" + // encoding ID
"\x00\x00" + // language ID "\x00\x00" + // language ID
"\x00\x00" + // name ID "\x00\x00" + // name ID
s16(str.length) + string16(str.length) +
s16(strOffset); string16(strOffset);
name += nameRecord; name += nameRecord;
strOffset += str.length; strOffset += str.length;
} }
name += names; name += names.join("");
return name; return name;
} }
@ -407,12 +413,12 @@ var Font = (function () {
"\x00\x01" + // encodingID "\x00\x01" + // encodingID
"\x00\x00\x00\x0C" + // start of the table record "\x00\x00\x00\x0C" + // start of the table record
"\x00\x04" + // format "\x00\x04" + // format
s16(headerSize) + // length string16(headerSize) + // length
"\x00\x00" + // languages "\x00\x00" + // languages
s16(segCount2) + string16(segCount2) +
s16(searchRange) + string16(searchRange) +
s16(searchEntry) + string16(searchEntry) +
s16(rangeShift); string16(rangeShift);
// Fill up the 4 parallel arrays describing the segments. // Fill up the 4 parallel arrays describing the segments.
var startCount = ""; var startCount = "";
@ -428,10 +434,10 @@ var Font = (function () {
var delta = (((start - 1) - bias) ^ 0xffff) + 1; var delta = (((start - 1) - bias) ^ 0xffff) + 1;
bias += (end - start + 1); bias += (end - start + 1);
startCount += s16(start); startCount += string16(start);
endCount += s16(end); endCount += string16(end);
idDeltas += s16(delta); idDeltas += string16(delta);
idRangeOffsets += s16(0); idRangeOffsets += string16(0);
for (var j = start; j <= end; j++) for (var j = start; j <= end; j++)
glyphsIds += String.fromCharCode(j); glyphsIds += String.fromCharCode(j);
@ -442,7 +448,7 @@ var Font = (function () {
idDeltas += "\x00\x01"; idDeltas += "\x00\x01";
idRangeOffsets += "\x00\x00"; idRangeOffsets += "\x00\x00";
return s2a(cmap + endCount + "\x00\x00" + startCount + return stringToArray(cmap + endCount + "\x00\x00" + startCount +
idDeltas + idRangeOffsets + glyphsIds); idDeltas + idRangeOffsets + glyphsIds);
} }
@ -477,7 +483,7 @@ var Font = (function () {
createTableEntry(otf, offsets, "CFF ", CFF); createTableEntry(otf, offsets, "CFF ", CFF);
/** OS/2 */ /** OS/2 */
OS2 = s2a( OS2 = stringToArray(
"\x00\x03" + // version "\x00\x03" + // version
"\x02\x24" + // xAvgCharWidth "\x02\x24" + // xAvgCharWidth
"\x01\xF4" + // usWeightClass "\x01\xF4" + // usWeightClass
@ -526,7 +532,7 @@ var Font = (function () {
createTableEntry(otf, offsets, "cmap", cmap); createTableEntry(otf, offsets, "cmap", cmap);
/** HEAD */ /** HEAD */
head = s2a( head = stringToArray(
"\x00\x01\x00\x00" + // Version number "\x00\x01\x00\x00" + // Version number
"\x00\x00\x50\x00" + // fontRevision "\x00\x00\x50\x00" + // fontRevision
"\x00\x00\x00\x00" + // checksumAdjustement "\x00\x00\x00\x00" + // checksumAdjustement
@ -548,7 +554,7 @@ var Font = (function () {
createTableEntry(otf, offsets, "head", head); createTableEntry(otf, offsets, "head", head);
/** HHEA */ /** HHEA */
hhea = s2a( hhea = stringToArray(
"\x00\x01\x00\x00" + // Version number "\x00\x01\x00\x00" + // Version number
"\x00\x00" + // Typographic Ascent "\x00\x00" + // Typographic Ascent
"\x00\x00" + // Typographic Descent "\x00\x00" + // Typographic Descent
@ -565,7 +571,7 @@ var Font = (function () {
"\x00\x00" + // -reserved- "\x00\x00" + // -reserved-
"\x00\x00" + // -reserved- "\x00\x00" + // -reserved-
"\x00\x00" + // metricDataFormat "\x00\x00" + // metricDataFormat
s16(charstrings.length) string16(charstrings.length)
); );
createTableEntry(otf, offsets, "hhea", hhea); createTableEntry(otf, offsets, "hhea", hhea);
@ -575,19 +581,19 @@ var Font = (function () {
var charstring = charstrings[i].charstring; var charstring = charstrings[i].charstring;
var width = charstring[1]; var width = charstring[1];
var lsb = charstring[0]; var lsb = charstring[0];
hmtx += s16(width) + s16(lsb); hmtx += string16(width) + string16(lsb);
} }
hmtx = s2a(hmtx); hmtx = stringToArray(hmtx);
createTableEntry(otf, offsets, "hmtx", hmtx); createTableEntry(otf, offsets, "hmtx", hmtx);
/** MAXP */ /** MAXP */
maxp = "\x00\x00\x50\x00" + // Version number maxp = "\x00\x00\x50\x00" + // Version number
s16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...) string16(charstrings.length + 1); // Num of glyphs (+1 to pass the sanitizer...)
maxp = s2a(maxp); maxp = stringToArray(maxp);
createTableEntry(otf, offsets, "maxp", maxp); createTableEntry(otf, offsets, "maxp", maxp);
/** NAME */ /** NAME */
name = s2a(createNameTable(aName)); name = stringToArray(createNameTable(aName));
createTableEntry(otf, offsets, "name", name); createTableEntry(otf, offsets, "name", name);
/** POST */ /** POST */
@ -601,7 +607,7 @@ var Font = (function () {
"\x00\x00\x00\x00" + // maxMemType42 "\x00\x00\x00\x00" + // maxMemType42
"\x00\x00\x00\x00" + // minMemType1 "\x00\x00\x00\x00" + // minMemType1
"\x00\x00\x00\x00"; // maxMemType1 "\x00\x00\x00\x00"; // maxMemType1
post = s2a(post); post = stringToArray(post);
createTableEntry(otf, offsets, "post", post); createTableEntry(otf, offsets, "post", post);
// Once all the table entries header are written, dump the data! // Once all the table entries header are written, dump the data!
@ -622,6 +628,7 @@ var Font = (function () {
return constructor; return constructor;
})(); })();
/** /**
* FontsUtils is a static class dedicated to hold codes that are not related * FontsUtils is a static class dedicated to hold codes that are not related
* to fonts in particular and needs to be share between them. * to fonts in particular and needs to be share between them.
@ -1300,6 +1307,10 @@ var Type1Parser = function() {
} }
}; };
/**
* The CFF class takes a Type1 file and wrap it into a 'Compact Font Format',
* which itself embed Type2 charstrings.
*/
const CFFStrings = [ const CFFStrings = [
".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand", ".notdef","space","exclam","quotedbl","numbersign","dollar","percent","ampersand",
"quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period", "quoteright","parenleft","parenright","asterisk","plus","comma","hyphen","period",
@ -1358,10 +1369,6 @@ const CFFStrings = [
"001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold" "001.003","Black","Bold","Book","Light","Medium","Regular","Roman","Semibold"
]; ];
/**
* Take a Type1 file as input and wrap it into a Compact Font Format (CFF)
* wrapping Type2 charstrings.
*/
var CFF = function(aName, aFile, aProperties) { var CFF = function(aName, aFile, aProperties) {
// Get the data block containing glyphs and subrs informations // Get the data block containing glyphs and subrs informations
var length1 = aFile.dict.get("Length1"); var length1 = aFile.dict.get("Length1");

2
pdf.js
View File

@ -2561,7 +2561,7 @@ var CanvasGraphics = (function() {
this.ctx.transform.apply(this.ctx, this.current.textMatrix); this.ctx.transform.apply(this.ctx, this.current.textMatrix);
this.ctx.scale(1, -1); this.ctx.scale(1, -1);
this.ctx.translate(0, -2 * this.current.y); this.ctx.translate(0, -2 * this.current.y);
this.ctx.fillText(Fonts.chars2Unicode(text), this.current.x, this.current.y); this.ctx.fillText(Fonts.charsToUnicode(text), this.current.x, this.current.y);
this.current.x += this.ctx.measureText(text).width; this.current.x += this.ctx.measureText(text).width;
this.ctx.restore(); this.ctx.restore();