Attempt to recover valid format 3
FDSelect data from broken CFF fonts (bug 1146106)
According to the CFF specification, see http://partners.adobe.com/public/developer/en/font/5176.CFF.pdf#G3.46884, for `format 3` FDSelect data: "The first range must have a ‘first’ GID of 0". Since the PDF file (attached in the bug) violates that part of the specification, this patch tries to recover valid FDSelect data to prevent OTS from rejecting the font. Fixes https://bugzilla.mozilla.org/show_bug.cgi?id=1146106.
This commit is contained in:
parent
bd47440e79
commit
6260fc09a3
@ -856,8 +856,8 @@ var CFFParser = (function CFFParserClosure() {
|
|||||||
var start = pos;
|
var start = pos;
|
||||||
var bytes = this.bytes;
|
var bytes = this.bytes;
|
||||||
var format = bytes[pos++];
|
var format = bytes[pos++];
|
||||||
var fdSelect = [];
|
var fdSelect = [], rawBytes;
|
||||||
var i;
|
var i, invalidFirstGID = false;
|
||||||
|
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case 0:
|
case 0:
|
||||||
@ -865,11 +865,18 @@ var CFFParser = (function CFFParserClosure() {
|
|||||||
var id = bytes[pos++];
|
var id = bytes[pos++];
|
||||||
fdSelect.push(id);
|
fdSelect.push(id);
|
||||||
}
|
}
|
||||||
|
rawBytes = bytes.subarray(start, pos);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
|
var rangesCount = (bytes[pos++] << 8) | bytes[pos++];
|
||||||
for (i = 0; i < rangesCount; ++i) {
|
for (i = 0; i < rangesCount; ++i) {
|
||||||
var first = (bytes[pos++] << 8) | bytes[pos++];
|
var first = (bytes[pos++] << 8) | bytes[pos++];
|
||||||
|
if (i === 0 && first !== 0) {
|
||||||
|
warn('parseFDSelect: The first range must have a first GID of 0' +
|
||||||
|
' -- trying to recover.');
|
||||||
|
invalidFirstGID = true;
|
||||||
|
first = 0;
|
||||||
|
}
|
||||||
var fdIndex = bytes[pos++];
|
var fdIndex = bytes[pos++];
|
||||||
var next = (bytes[pos] << 8) | bytes[pos + 1];
|
var next = (bytes[pos] << 8) | bytes[pos + 1];
|
||||||
for (var j = first; j < next; ++j) {
|
for (var j = first; j < next; ++j) {
|
||||||
@ -878,13 +885,19 @@ var CFFParser = (function CFFParserClosure() {
|
|||||||
}
|
}
|
||||||
// Advance past the sentinel(next).
|
// Advance past the sentinel(next).
|
||||||
pos += 2;
|
pos += 2;
|
||||||
|
rawBytes = bytes.subarray(start, pos);
|
||||||
|
|
||||||
|
if (invalidFirstGID) {
|
||||||
|
rawBytes[3] = rawBytes[4] = 0; // Adjust the first range, first GID.
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
error('Unknown fdselect format ' + format);
|
error('parseFDSelect: Unknown format "' + format + '".');
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
var end = pos;
|
assert(fdSelect.length === length, 'parseFDSelect: Invalid font data.');
|
||||||
return new CFFFDSelect(fdSelect, bytes.subarray(start, end));
|
|
||||||
|
return new CFFFDSelect(fdSelect, rawBytes);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return CFFParser;
|
return CFFParser;
|
||||||
|
1
test/pdfs/.gitignore
vendored
1
test/pdfs/.gitignore
vendored
@ -37,6 +37,7 @@
|
|||||||
!bug1050040.pdf
|
!bug1050040.pdf
|
||||||
!bug1200096.pdf
|
!bug1200096.pdf
|
||||||
!bug1068432.pdf
|
!bug1068432.pdf
|
||||||
|
!bug1146106.pdf
|
||||||
!issue5564_reduced.pdf
|
!issue5564_reduced.pdf
|
||||||
!canvas.pdf
|
!canvas.pdf
|
||||||
!bug1132849.pdf
|
!bug1132849.pdf
|
||||||
|
BIN
test/pdfs/bug1146106.pdf
Normal file
BIN
test/pdfs/bug1146106.pdf
Normal file
Binary file not shown.
@ -210,6 +210,13 @@
|
|||||||
"link": false,
|
"link": false,
|
||||||
"type": "eq"
|
"type": "eq"
|
||||||
},
|
},
|
||||||
|
{ "id": "bug1146106",
|
||||||
|
"file": "pdfs/bug1146106.pdf",
|
||||||
|
"md5": "a323d3766da49ee40f7d5dff0aeb0cc1",
|
||||||
|
"rounds": 1,
|
||||||
|
"link": false,
|
||||||
|
"type": "eq"
|
||||||
|
},
|
||||||
{ "id": "issue1512",
|
{ "id": "issue1512",
|
||||||
"file": "pdfs/issue1512r.pdf",
|
"file": "pdfs/issue1512r.pdf",
|
||||||
"md5": "af48ede2658d99cca423147085c6609b",
|
"md5": "af48ede2658d99cca423147085c6609b",
|
||||||
|
@ -263,9 +263,11 @@ describe('CFFParser', function() {
|
|||||||
0x00, // gid: 0 fd: 0
|
0x00, // gid: 0 fd: 0
|
||||||
0x01 // gid: 1 fd: 1
|
0x01 // gid: 1 fd: 1
|
||||||
]);
|
]);
|
||||||
parser.bytes = bytes;
|
parser.bytes = bytes.slice();
|
||||||
var fdSelect = parser.parseFDSelect(0, 2);
|
var fdSelect = parser.parseFDSelect(0, 2);
|
||||||
|
|
||||||
expect(fdSelect.fdSelect).toEqual([0, 1]);
|
expect(fdSelect.fdSelect).toEqual([0, 1]);
|
||||||
|
expect(fdSelect.raw).toEqual(bytes);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('parses fdselect format 3', function() {
|
it('parses fdselect format 3', function() {
|
||||||
@ -273,13 +275,32 @@ describe('CFFParser', function() {
|
|||||||
0x00, 0x02, // range count
|
0x00, 0x02, // range count
|
||||||
0x00, 0x00, // first gid
|
0x00, 0x00, // first gid
|
||||||
0x09, // font dict 1 id
|
0x09, // font dict 1 id
|
||||||
0x00, 0x02, // nex gid
|
0x00, 0x02, // next gid
|
||||||
0x0a, // font dict 2 gid
|
0x0a, // font dict 2 id
|
||||||
0x00, 0x04 // sentinel (last gid)
|
0x00, 0x04 // sentinel (last gid)
|
||||||
]);
|
]);
|
||||||
parser.bytes = bytes;
|
parser.bytes = bytes.slice();
|
||||||
var fdSelect = parser.parseFDSelect(0, 2);
|
var fdSelect = parser.parseFDSelect(0, 4);
|
||||||
|
|
||||||
expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]);
|
expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]);
|
||||||
|
expect(fdSelect.raw).toEqual(bytes);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('parses invalid fdselect format 3 (bug 1146106)', function() {
|
||||||
|
var bytes = new Uint8Array([0x03, // format
|
||||||
|
0x00, 0x02, // range count
|
||||||
|
0x00, 0x01, // first gid (invalid)
|
||||||
|
0x09, // font dict 1 id
|
||||||
|
0x00, 0x02, // next gid
|
||||||
|
0x0a, // font dict 2 id
|
||||||
|
0x00, 0x04 // sentinel (last gid)
|
||||||
|
]);
|
||||||
|
parser.bytes = bytes.slice();
|
||||||
|
var fdSelect = parser.parseFDSelect(0, 4);
|
||||||
|
|
||||||
|
expect(fdSelect.fdSelect).toEqual([9, 9, 0xa, 0xa]);
|
||||||
|
bytes[3] = bytes[4] = 0x00; // The adjusted first range, first gid.
|
||||||
|
expect(fdSelect.raw).toEqual(bytes);
|
||||||
});
|
});
|
||||||
|
|
||||||
// TODO fdArray
|
// TODO fdArray
|
||||||
|
Loading…
x
Reference in New Issue
Block a user