Skip to content

Commit

Permalink
[maxp] Attempt to improve fixup of bad 'maxp' version numbers.
Browse files Browse the repository at this point in the history
If the version number is less than 0x00010000 (e.g. an example reported at
mozilla/pdf.js#16839 apparently has 0x0100),
it will be treated as version 0.5 and only the num_glyphs field is kept.

However, this can prevent the font working on Windows, which apparently
requires the full maxp table for truetype fonts.

So if the version number was bad, but there is in fact enough data to
parse as version 1.0, let's try correcting it to 1.0 rather than 0.5.

Also make the max_zones fixup more general, as the example font from the
above issue has max_zones=512(!). Correcting it to 2 should be harmless.
  • Loading branch information
jfkthame committed Nov 10, 2023
1 parent c9b38cf commit 9353793
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 7 deletions.
27 changes: 20 additions & 7 deletions src/maxp.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,23 @@ bool OpenTypeMAXP::Parse(const uint8_t *data, size_t length) {
return Error("numGlyphs is 0");
}

// Per https://learn.microsoft.com/en-gb/typography/opentype/spec/maxp,
// the only two 'maxp' version numbers are 0.5 (for CFF/CFF2) and 1.0
// (for TrueType).
if (version == 0x00005000) {
this->version_1 = false;
return true;
}

if (version != 0x00010000) {
Warning("Unrecognized version %08x, attempting to fix", version);
// If there's at least enough data to read as a version 1.0 table,
// we'll try that.
if (length >= 32) {
version = 0x00010000;
}
}

if (version >> 16 == 1) {
this->version_1 = true;
if (!table.ReadU16(&this->max_points) ||
Expand All @@ -47,19 +64,15 @@ bool OpenTypeMAXP::Parse(const uint8_t *data, size_t length) {
return Error("Failed to read version 1 table data");
}

if (this->max_zones == 0) {
if (this->max_zones < 1) {
// workaround for ipa*.ttf Japanese fonts.
Warning("Bad maxZones: %u", this->max_zones);
this->max_zones = 1;
} else if (this->max_zones == 3) {
// workaround for Ecolier-*.ttf fonts.
} else if (this->max_zones > 2) {
// workaround for Ecolier-*.ttf fonts and bad fonts in some PDFs
Warning("Bad maxZones: %u", this->max_zones);
this->max_zones = 2;
}

if ((this->max_zones != 1) && (this->max_zones != 2)) {
return Error("Bad maxZones: %u", this->max_zones);
}
} else {
this->version_1 = false;
}
Expand Down
10 changes: 10 additions & 0 deletions src/ots.cc
Original file line number Diff line number Diff line change
Expand Up @@ -762,12 +762,18 @@ bool ProcessGeneric(ots::FontFile *header,
ots::Table *loca = font->GetTable(OTS_TAG_LOCA);
ots::Table *cff = font->GetTable(OTS_TAG_CFF);
ots::Table *cff2 = font->GetTable(OTS_TAG_CFF2);
ots::OpenTypeMAXP *maxp = static_cast<ots::OpenTypeMAXP*>(
font->GetTypedTable(OTS_TAG_MAXP));

if (glyf && loca) {
if (font->version != 0x000010000) {
OTS_WARNING_MSG_HDR("wrong sfntVersion for glyph data");
font->version = 0x000010000;
}
if (!maxp->version_1) {
return OTS_FAILURE_MSG_TAG("wrong maxp version for glyph data",
OTS_TAG_MAXP);
}
if (cff)
cff->Drop("font contains both CFF and glyf/loca tables");
if (cff2)
Expand All @@ -781,6 +787,10 @@ bool ProcessGeneric(ots::FontFile *header,
glyf->Drop("font contains both CFF and glyf tables");
if (loca)
loca->Drop("font contains both CFF and loca tables");
if (maxp->version_1) {
OTS_WARNING_MSG_HDR("fixing incorrect maxp version for CFF font");
maxp->version_1 = false;
}
} else if (font->GetTable(OTS_TAG('C','B','D','T')) &&
font->GetTable(OTS_TAG('C','B','L','C'))) {
// We don't sanitize bitmap tables, but don’t reject bitmap-only fonts if
Expand Down

0 comments on commit 9353793

Please sign in to comment.