Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 165 additions & 0 deletions src/libs/ttffont.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ jsPDF.API.TTFFont = (function() {
this.os2 = new OS2Table(this);
this.loca = new LocaTable(this);
this.glyf = new GlyfTable(this);
this.gsub = new GsubTable(this);
this.ascender =
(this.os2.exists && this.os2.ascender) || this.hhea.ascender;
this.decender =
Expand Down Expand Up @@ -135,6 +136,16 @@ jsPDF.API.TTFFont = (function() {
0
);
};
TTFFont.prototype.applyFeaturesToGlyph = function(glyphId) {
if (
this.gsub &&
this.gsub.smcpSubstitutions &&
this.gsub.smcpSubstitutions[glyphId] !== undefined
) {
return this.gsub.smcpSubstitutions[glyphId];
}
return glyphId;
};
TTFFont.prototype.widthOfGlyph = function(glyph) {
var scale;
scale = 1000.0 / this.head.unitsPerEm;
Expand Down Expand Up @@ -1678,6 +1689,160 @@ var LocaTable = (function(_super) {
return LocaTable;
})(Table);

var GsubTable = (function(_super) {
__extends(GsubTable, _super);

function GsubTable() {
return GsubTable.__super__.constructor.apply(this, arguments);
}
GsubTable.prototype.tag = "GSUB";
GsubTable.prototype.parse = function(data) {
var i,
j,
tableOffset,
featureListOffset,
lookupListOffset,
featureCount,
tag,
featureOffset,
savedPos,
lookupIndexCount,
smcpLookupIndices,
lookupCount,
lookupOffsets,
lookupIndex,
lookupOffset,
lookupType,
subTableCount,
subTableOffsets,
self;

this.smcpSubstitutions = {};
tableOffset = this.offset;
data.pos = tableOffset;
data.pos += 4; // skip MajorVersion + MinorVersion
data.readUInt16(); // scriptListOffset (unused)
featureListOffset = data.readUInt16();
lookupListOffset = data.readUInt16();

data.pos = tableOffset + featureListOffset;
featureCount = data.readUInt16();
smcpLookupIndices = [];

for (i = 0; i < featureCount; i++) {
tag = data.readString(4);
featureOffset = data.readUInt16();
if (tag === "smcp") {
savedPos = data.pos;
data.pos = tableOffset + featureListOffset + featureOffset;
data.readUInt16(); // featureParamsOffset
lookupIndexCount = data.readUInt16();
for (j = 0; j < lookupIndexCount; j++) {
smcpLookupIndices.push(data.readUInt16());
}
data.pos = savedPos;
}
}

if (smcpLookupIndices.length === 0) return;

data.pos = tableOffset + lookupListOffset;
lookupCount = data.readUInt16();
lookupOffsets = [];
for (i = 0; i < lookupCount; i++) {
lookupOffsets.push(data.readUInt16());
}

self = this;
for (i = 0; i < smcpLookupIndices.length; i++) {
lookupIndex = smcpLookupIndices[i];
if (lookupIndex >= lookupCount) continue;
lookupOffset =
tableOffset + lookupListOffset + lookupOffsets[lookupIndex];
data.pos = lookupOffset;
lookupType = data.readUInt16();
data.readUInt16(); // lookupFlag
subTableCount = data.readUInt16();
subTableOffsets = [];
for (j = 0; j < subTableCount; j++) {
subTableOffsets.push(lookupOffset + data.readUInt16());
}
if (lookupType === 1) {
for (j = 0; j < subTableOffsets.length; j++) {
self.parseSingleSubst(data, subTableOffsets[j]);
}
}
}
};
GsubTable.prototype.parseSingleSubst = function(data, offset) {
var substFormat,
coverageRelOffset,
coverageOffset,
deltaGlyphID,
glyphCount,
substituteGlyphs,
glyphs,
i;
data.pos = offset;
substFormat = data.readUInt16();
coverageRelOffset = data.readUInt16();
coverageOffset = offset + coverageRelOffset;

if (substFormat === 1) {
deltaGlyphID = data.readInt16();
glyphs = this.parseCoverage(data, coverageOffset);
for (i = 0; i < glyphs.length; i++) {
this.smcpSubstitutions[glyphs[i]] = (glyphs[i] + deltaGlyphID) & 0xffff;
}
} else if (substFormat === 2) {
glyphCount = data.readUInt16();
substituteGlyphs = [];
for (i = 0; i < glyphCount; i++) {
substituteGlyphs.push(data.readUInt16());
}
glyphs = this.parseCoverage(data, coverageOffset);
for (i = 0; i < glyphs.length; i++) {
if (i < substituteGlyphs.length) {
this.smcpSubstitutions[glyphs[i]] = substituteGlyphs[i];
}
}
}
};
GsubTable.prototype.parseCoverage = function(data, offset) {
var coverageFormat,
glyphCount,
rangeCount,
startGlyphID,
endGlyphID,
glyphs,
i,
g;
data.pos = offset;
coverageFormat = data.readUInt16();
glyphs = [];

if (coverageFormat === 1) {
glyphCount = data.readUInt16();
for (i = 0; i < glyphCount; i++) {
glyphs.push(data.readUInt16());
}
} else if (coverageFormat === 2) {
rangeCount = data.readUInt16();
for (i = 0; i < rangeCount; i++) {
startGlyphID = data.readUInt16();
endGlyphID = data.readUInt16();
data.readUInt16(); // startCoverageIndex
for (g = startGlyphID; g <= endGlyphID; g++) {
glyphs.push(g);
}
}
}

return glyphs;
};
return GsubTable;
})(Table);

/************************************************************************************/
/* function : invert */
/* comment : Change the object's (key: value) to create an object with (value: key).*/
Expand Down
8 changes: 6 additions & 2 deletions src/modules/utf8.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,13 @@ import { toPDFName } from "../libs/pdfname.js";
var padz = ["", "0", "00", "000", "0000"];
var ar = [""];
for (var i = 0, l = text.length, t; i < l; ++i) {
t = font.metadata.characterToGlyph(text.charCodeAt(i));
var charCode = text.charCodeAt(i);
t = font.metadata.characterToGlyph(charCode);
if (font.metadata.applyFeaturesToGlyph) {
t = font.metadata.applyFeaturesToGlyph(t);
}
font.metadata.glyIdsUsed.push(t);
font.metadata.toUnicode[t] = text.charCodeAt(i);
font.metadata.toUnicode[t] = charCode;
if (widths.indexOf(t) == -1) {
widths.push(t);
widths.push([parseInt(font.metadata.widthOfGlyph(t), 10)]);
Expand Down