Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add unique glyph names for CFF fonts. #10591

Merged
merged 1 commit into from
Mar 1, 2019
Merged
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
65 changes: 55 additions & 10 deletions src/core/cff_parser.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ var CFFStandardStrings = [
'Black', 'Bold', 'Book', 'Light', 'Medium', 'Regular', 'Roman', 'Semibold'
];

const NUM_STANDARD_CFF_STRINGS = 391;

var CFFParser = (function CFFParserClosure() {
var CharstringValidationData = [
null,
Expand Down Expand Up @@ -931,16 +933,27 @@ var CFFStrings = (function CFFStringsClosure() {
}
CFFStrings.prototype = {
get: function CFFStrings_get(index) {
if (index >= 0 && index <= 390) {
if (index >= 0 && index <= (NUM_STANDARD_CFF_STRINGS - 1)) {
return CFFStandardStrings[index];
}
if (index - 391 <= this.strings.length) {
return this.strings[index - 391];
if (index - NUM_STANDARD_CFF_STRINGS <= this.strings.length) {
return this.strings[index - NUM_STANDARD_CFF_STRINGS];
}
return CFFStandardStrings[0];
},
getSID: function CFFStrings_getSID(str) {
let index = CFFStandardStrings.indexOf(str);
if (index !== -1) {
return index;
}
index = this.strings.indexOf(str);
if (index !== -1) {
return index + NUM_STANDARD_CFF_STRINGS;
}
return -1;
},
add: function CFFStrings_add(value) {
this.strings.push(value);
return this.strings.push(value) + NUM_STANDARD_CFF_STRINGS - 1;
},
get count() {
return this.strings.length;
Expand Down Expand Up @@ -1312,7 +1325,8 @@ var CFFCompiler = (function CFFCompilerClosure() {
output.add(encoding);
}
}
var charset = this.compileCharset(cff.charset);
var charset = this.compileCharset(cff.charset, cff.charStrings.count,
cff.strings, cff.isCIDFont);
topDictTracker.setEntryLocation('charset', [output.length], output);
output.add(charset);

Expand Down Expand Up @@ -1580,11 +1594,42 @@ var CFFCompiler = (function CFFCompilerClosure() {
}
return this.compileIndex(charStringsIndex);
},
compileCharset: function CFFCompiler_compileCharset(charset) {
let length = 1 + (this.cff.charStrings.count - 1) * 2;
// The contents of the charset doesn't matter, it's just there to make
// freetype happy.
let out = new Uint8Array(length);
compileCharset: function CFFCompiler_compileCharset(charset, numGlyphs,
strings, isCIDFont) {
// Freetype requires the number of charset strings be correct and MacOS
// requires a valid mapping for printing.
let out;
let numGlyphsLessNotDef = numGlyphs - 1;
if (isCIDFont) {
// In a CID font, the charset is a mapping of CIDs not SIDs so just
// create an identity mapping.
out = new Uint8Array([
2, // format
0, // first CID upper byte
0, // first CID lower byte
(numGlyphsLessNotDef >> 8) & 0xFF,
numGlyphsLessNotDef & 0xFF,
]);
} else {
let length = 1 + numGlyphsLessNotDef * 2;
out = new Uint8Array(length);
out[0] = 0; // format 0
let charsetIndex = 0;
let numCharsets = charset.charset.length;
for (let i = 1; i < out.length; i += 2) {
let sid = 0;
if (charsetIndex < numCharsets) {
let name = charset.charset[charsetIndex++];
sid = strings.getSID(name);
if (sid === -1) {
sid = 0;
warn(`Couldn't find ${name} in CFF strings`);
Copy link
Collaborator

@Snuffleupagus Snuffleupagus Mar 1, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@brendandahl This seem to have caused a lot of warning "spam" in the console even for something as simple as e.g. the default tracemonkey.pdf file.
From a cursory look it appears that charset.charset only contains numbers, and not strings, for many PDF files.

}
}
out[i] = (sid >> 8) & 0xFF;
out[i + 1] = sid & 0xFF;
}
}
return this.compileTypedArray(out);
},
compileEncoding: function CFFCompiler_compileEncoding(encoding) {
Expand Down
10 changes: 3 additions & 7 deletions src/core/fonts.js
Original file line number Diff line number Diff line change
Expand Up @@ -3333,16 +3333,12 @@ var Type1Font = (function Type1FontClosure() {
var i, ii;
for (i = 0; i < count; i++) {
var index = CFFStandardStrings.indexOf(charstrings[i].glyphName);
// TODO: Insert the string and correctly map it. Previously it was
// thought mapping names that aren't in the standard strings to .notdef
// was fine, however in issue818 when mapping them all to .notdef the
// adieresis glyph no longer worked.
if (index === -1) {
index = 0;
index = strings.add(charstrings[i].glyphName);
}
charsetArray.push((index >> 8) & 0xff, index & 0xff);
charsetArray.push(index);
}
cff.charset = new CFFCharset(false, 0, [], charsetArray);
cff.charset = new CFFCharset(false, 0, charsetArray);

var charStringsIndex = new CFFIndex();
charStringsIndex.add([0x8B, 0x0E]); // .notdef
Expand Down
32 changes: 31 additions & 1 deletion test/unit/cff_parser_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/

import {
CFFCompiler, CFFFDSelect, CFFParser, CFFStrings
CFFCharset, CFFCompiler, CFFFDSelect, CFFParser, CFFStrings
} from '../../src/core/cff_parser';
import { SEAC_ANALYSIS_ENABLED } from '../../src/core/fonts';
import { Stream } from '../../src/core/stream';
Expand Down Expand Up @@ -446,5 +446,35 @@ describe('CFFCompiler', function() {
]);
});

it('compiles charset of CID font', function() {
var charset = new CFFCharset();
var c = new CFFCompiler();
var numGlyphs = 7;
var out = c.compileCharset(charset, numGlyphs, new CFFStrings(), true);
// All CID charsets get turned into a simple format 2.
expect(out).toEqual([
2, // format
0, // cid (high)
0, // cid (low)
0, // nLeft (high)
numGlyphs - 1, // nLeft (low)
]);
});

it('compiles charset of non CID font', function() {
var charset = new CFFCharset(false, 0, ['space', 'exclam']);
var c = new CFFCompiler();
var numGlyphs = 3;
var out = c.compileCharset(charset, numGlyphs, new CFFStrings(), false);
// All non-CID fonts use a format 0 charset.
expect(out).toEqual([
0, // format
0, // sid of 'space' (high)
1, // sid of 'space' (low)
0, // sid of 'exclam' (high)
2, // sid of 'exclam' (low)
]);
});

// TODO a lot more compiler tests
});