summaryrefslogtreecommitdiffstats
path: root/gfx/ots
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-12 05:35:29 +0000
commit59203c63bb777a3bacec32fb8830fba33540e809 (patch)
tree58298e711c0ff0575818c30485b44a2f21bf28a0 /gfx/ots
parentAdding upstream version 126.0.1. (diff)
downloadfirefox-59203c63bb777a3bacec32fb8830fba33540e809.tar.xz
firefox-59203c63bb777a3bacec32fb8830fba33540e809.zip
Adding upstream version 127.0.upstream/127.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/ots')
-rw-r--r--gfx/ots/include/ots-memory-stream.h4
-rw-r--r--gfx/ots/moz.yaml5
-rw-r--r--gfx/ots/ots-1850314.patch177
-rw-r--r--gfx/ots/src/cff.cc140
-rw-r--r--gfx/ots/src/colr.cc13
-rw-r--r--gfx/ots/src/glyf.cc8
-rw-r--r--gfx/ots/src/glyf.h8
-rw-r--r--gfx/ots/src/maxp.cc76
-rw-r--r--gfx/ots/src/ots.cc10
9 files changed, 153 insertions, 288 deletions
diff --git a/gfx/ots/include/ots-memory-stream.h b/gfx/ots/include/ots-memory-stream.h
index cb844709c2..ec0b362fea 100644
--- a/gfx/ots/include/ots-memory-stream.h
+++ b/gfx/ots/include/ots-memory-stream.h
@@ -26,7 +26,7 @@ class MemoryStream : public OTSStream {
return false;
}
std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
- off_ += length;
+ off_ += static_cast<off_t>(length);
return true;
}
@@ -82,7 +82,7 @@ class ExpandingMemoryStream : public OTSStream {
return WriteRaw(data, length);
}
std::memcpy(static_cast<char*>(ptr_) + off_, data, length);
- off_ += length;
+ off_ += static_cast<off_t>(length);
return true;
}
diff --git a/gfx/ots/moz.yaml b/gfx/ots/moz.yaml
index 50ce2b4e8f..bff78ff44b 100644
--- a/gfx/ots/moz.yaml
+++ b/gfx/ots/moz.yaml
@@ -10,8 +10,8 @@ origin:
url: https://github.com/khaledhosny/ots
- release: 6ba665aa307ea360283191736814863ca398398d (2023-08-16T17:30:00Z).
- revision: 6ba665aa307ea360283191736814863ca398398d
+ release: d51fceea592507b78cf6c5fd90ba9ef6b969ffd1 (2024-03-26T11:28:30Z).
+ revision: d51fceea592507b78cf6c5fd90ba9ef6b969ffd1
license: BSD-3-Clause
license-file: LICENSE
@@ -39,4 +39,3 @@ vendoring:
- ots-lz4.patch
- ots-rlbox.patch
- ots-visibility.patch
- - ots-1850314.patch
diff --git a/gfx/ots/ots-1850314.patch b/gfx/ots/ots-1850314.patch
deleted file mode 100644
index 88088f5064..0000000000
--- a/gfx/ots/ots-1850314.patch
+++ /dev/null
@@ -1,177 +0,0 @@
-commit 362a59be47f9e187eec43df0938def661be6c972
-Author: Jonathan Kew <jkew@mozilla.com>
-Date: Wed Aug 30 12:55:02 2023 +0000
-
- Bug 1850314 - Don't do glyph bounding-box fixup for "tricky" fonts, because it may disrupt glyph rendering on macOS. r=gfx-reviewers,lsalzman
-
- Differential Revision: https://phabricator.services.mozilla.com/D187096
-
-diff --git a/src/glyf.cc b/src/glyf.cc
-index 0ed9515ef16d6..31487957bf99b 100644
---- a/src/glyf.cc
-+++ b/src/glyf.cc
-@@ -10,6 +10,7 @@
- #include "head.h"
- #include "loca.h"
- #include "maxp.h"
-+#include "name.h"
-
- // glyf - Glyph Data
- // http://www.microsoft.com/typography/otspec/glyf.htm
-@@ -97,7 +98,8 @@ bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
- int16_t& xmin,
- int16_t& ymin,
- int16_t& xmax,
-- int16_t& ymax) {
-+ int16_t& ymax,
-+ bool is_tricky_font) {
- // read the end-points array
- uint16_t num_flags = 0;
- for (int i = 0; i < num_contours; ++i) {
-@@ -219,27 +221,32 @@ bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
- }
-
- if (adjusted_bbox) {
-- Warning("Glyph bbox was incorrect; adjusting (glyph %u)", gid);
-- // copy the numberOfContours field
-- this->iov.push_back(std::make_pair(glyph.buffer(), 2));
-- // output a fixed-up version of the bounding box
-- uint8_t* fixed_bbox = new uint8_t[8];
-- fixed_bboxes.push_back(fixed_bbox);
-- xmin = ots_htons(xmin);
-- std::memcpy(fixed_bbox, &xmin, 2);
-- ymin = ots_htons(ymin);
-- std::memcpy(fixed_bbox + 2, &ymin, 2);
-- xmax = ots_htons(xmax);
-- std::memcpy(fixed_bbox + 4, &xmax, 2);
-- ymax = ots_htons(ymax);
-- std::memcpy(fixed_bbox + 6, &ymax, 2);
-- this->iov.push_back(std::make_pair(fixed_bbox, 8));
-- // copy the remainder of the glyph data
-- this->iov.push_back(std::make_pair(glyph.buffer() + 10, glyph.offset() - 10));
-- } else {
-- this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));
-+ if (is_tricky_font) {
-+ Warning("Glyph bbox was incorrect; NOT adjusting tricky font (glyph %u)", gid);
-+ } else {
-+ Warning("Glyph bbox was incorrect; adjusting (glyph %u)", gid);
-+ // copy the numberOfContours field
-+ this->iov.push_back(std::make_pair(glyph.buffer(), 2));
-+ // output a fixed-up version of the bounding box
-+ uint8_t* fixed_bbox = new uint8_t[8];
-+ fixed_bboxes.push_back(fixed_bbox);
-+ xmin = ots_htons(xmin);
-+ std::memcpy(fixed_bbox, &xmin, 2);
-+ ymin = ots_htons(ymin);
-+ std::memcpy(fixed_bbox + 2, &ymin, 2);
-+ xmax = ots_htons(xmax);
-+ std::memcpy(fixed_bbox + 4, &xmax, 2);
-+ ymax = ots_htons(ymax);
-+ std::memcpy(fixed_bbox + 6, &ymax, 2);
-+ this->iov.push_back(std::make_pair(fixed_bbox, 8));
-+ // copy the remainder of the glyph data
-+ this->iov.push_back(std::make_pair(glyph.buffer() + 10, glyph.offset() - 10));
-+ return true;
-+ }
- }
-
-+ this->iov.push_back(std::make_pair(glyph.buffer(), glyph.offset()));
-+
- return true;
- }
-
-@@ -342,6 +349,10 @@ bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) {
- return Error("Missing maxp or loca or head table needed by glyf table");
- }
-
-+ OpenTypeNAME *name = static_cast<OpenTypeNAME*>(
-+ GetFont()->GetTypedTable(OTS_TAG_NAME));
-+ bool is_tricky = name->IsTrickyFont();
-+
- this->maxp = maxp;
-
- const unsigned num_glyphs = maxp->num_glyphs;
-@@ -397,7 +408,7 @@ bool OpenTypeGLYF::Parse(const uint8_t *data, size_t length) {
- // does we will simply ignore it.
- glyph.set_offset(0);
- } else if (num_contours > 0) {
-- if (!ParseSimpleGlyph(glyph, i, num_contours, xmin, ymin, xmax, ymax)) {
-+ if (!ParseSimpleGlyph(glyph, i, num_contours, xmin, ymin, xmax, ymax, is_tricky)) {
- return Error("Failed to parse glyph %d", i);
- }
- } else {
-diff --git a/src/glyf.h b/src/glyf.h
-index 05e846f1cb6e8..f85fdc4652fcf 100644
---- a/src/glyf.h
-+++ b/src/glyf.h
-@@ -51,7 +51,8 @@ class OpenTypeGLYF : public Table {
- int16_t& xmin,
- int16_t& ymin,
- int16_t& xmax,
-- int16_t& ymax);
-+ int16_t& ymax,
-+ bool is_tricky_font);
- bool ParseCompositeGlyph(
- Buffer &glyph,
- ComponentPointCount* component_point_count);
-diff --git a/src/name.cc b/src/name.cc
-index fc5074b0587a3..7526e1f72b9ea 100644
---- a/src/name.cc
-+++ b/src/name.cc
-@@ -366,4 +366,44 @@ bool OpenTypeNAME::IsValidNameId(uint16_t nameID, bool addIfMissing) {
- return this->name_ids.count(nameID);
- }
-
-+// List of font names considered "tricky" (dependent on applying original TrueType instructions) by FreeType, see
-+// https://gitlab.freedesktop.org/freetype/freetype/-/blob/2d9fce53d4ce89f36075168282fcdd7289e082f9/src/truetype/ttobjs.c#L170-241
-+static const char* tricky_font_names[] = {
-+ "cpop",
-+ "DFGirl-W6-WIN-BF",
-+ "DFGothic-EB",
-+ "DFGyoSho-Lt",
-+ "DFHei",
-+ "DFHSGothic-W5",
-+ "DFHSMincho-W3",
-+ "DFHSMincho-W7",
-+ "DFKaiSho-SB",
-+ "DFKaiShu",
-+ "DFKai-SB",
-+ "DFMing",
-+ "DLC",
-+ "HuaTianKaiTi?",
-+ "HuaTianSongTi?",
-+ "Ming(for ISO10646)",
-+ "MingLiU",
-+ "MingMedium",
-+ "PMingLiU",
-+ "MingLi43"
-+};
-+
-+bool OpenTypeNAME::IsTrickyFont() const {
-+ for (const auto& name : this->names) {
-+ const uint16_t id = name.name_id;
-+ if (id != 1) {
-+ continue;
-+ }
-+ for (const auto* p : tricky_font_names) {
-+ if (name.text.find(p) != std::string::npos) {
-+ return true;
-+ }
-+ }
-+ }
-+ return false;
-+}
-+
- } // namespace
-diff --git a/src/name.h b/src/name.h
-index 68c7ac096d3f8..a241e77ee26bb 100644
---- a/src/name.h
-+++ b/src/name.h
-@@ -52,6 +52,7 @@ class OpenTypeNAME : public Table {
- bool Parse(const uint8_t *data, size_t length);
- bool Serialize(OTSStream *out);
- bool IsValidNameId(uint16_t nameID, bool addIfMissing = false);
-+ bool IsTrickyFont() const;
-
- private:
- std::vector<NameRecord> names;
diff --git a/gfx/ots/src/cff.cc b/gfx/ots/src/cff.cc
index af54a4a16c..95ff7f744b 100644
--- a/gfx/ots/src/cff.cc
+++ b/gfx/ots/src/cff.cc
@@ -41,7 +41,7 @@ enum FONT_FORMAT {
// see Appendix. A
const size_t kNStdString = 390;
-typedef std::pair<uint32_t, DICT_OPERAND_TYPE> Operand;
+typedef std::pair<int32_t, DICT_OPERAND_TYPE> Operand;
bool ReadOffset(ots::Buffer &table, uint8_t off_size, uint32_t *offset) {
if (off_size > 4) {
@@ -172,7 +172,7 @@ bool CheckOffset(const Operand& operand, size_t table_length) {
if (operand.second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- if (operand.first >= table_length) {
+ if (operand.first >= static_cast<int32_t>(table_length) || operand.first < 0) {
return OTS_FAILURE();
}
return true;
@@ -182,7 +182,7 @@ bool CheckSid(const Operand& operand, size_t sid_max) {
if (operand.second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- if (operand.first > sid_max) {
+ if (operand.first > static_cast<int32_t>(sid_max) || operand.first < 0) {
return OTS_FAILURE();
}
return true;
@@ -202,15 +202,13 @@ bool ParseDictDataBcd(ots::Buffer &table, std::vector<Operand> &operands) {
if ((nibble & 0xf) == 0xf) {
// TODO(yusukes): would be better to store actual double value,
// rather than the dummy integer.
- operands.push_back(std::make_pair(static_cast<uint32_t>(0),
- DICT_OPERAND_REAL));
+ operands.push_back(std::make_pair(0, DICT_OPERAND_REAL));
return true;
}
return OTS_FAILURE();
}
if ((nibble & 0x0f) == 0x0f) {
- operands.push_back(std::make_pair(static_cast<uint32_t>(0),
- DICT_OPERAND_REAL));
+ operands.push_back(std::make_pair(0, DICT_OPERAND_REAL));
return true;
}
@@ -256,7 +254,7 @@ bool ParseDictDataEscapedOperator(ots::Buffer &table,
if ((op <= 14) ||
(op >= 17 && op <= 23) ||
(op >= 30 && op <= 38)) {
- operands.push_back(std::make_pair((12U << 8) + op, DICT_OPERATOR));
+ operands.push_back(std::make_pair((12 << 8) + op, DICT_OPERATOR));
return true;
}
@@ -277,8 +275,9 @@ bool ParseDictDataNumber(ots::Buffer &table, uint8_t b0,
!table.ReadU8(&b2)) {
return OTS_FAILURE();
}
+ //the two-byte value needs to be casted to int16_t in order to get the right sign
operands.push_back(std::make_pair(
- static_cast<uint32_t>((b1 << 8) + b2), DICT_OPERAND_INTEGER));
+ static_cast<int16_t>((b1 << 8) + b2), DICT_OPERAND_INTEGER));
return true;
case 29: // longint
@@ -289,7 +288,7 @@ bool ParseDictDataNumber(ots::Buffer &table, uint8_t b0,
return OTS_FAILURE();
}
operands.push_back(std::make_pair(
- static_cast<uint32_t>((b1 << 24) + (b2 << 16) + (b3 << 8) + b4),
+ (b1 << 24) + (b2 << 16) + (b3 << 8) + b4,
DICT_OPERAND_INTEGER));
return true;
@@ -300,7 +299,7 @@ bool ParseDictDataNumber(ots::Buffer &table, uint8_t b0,
break;
}
- uint32_t result;
+ int32_t result;
if (b0 >=32 && b0 <=246) {
result = b0 - 139;
} else if (b0 >=247 && b0 <= 250) {
@@ -332,7 +331,7 @@ bool ParseDictDataReadNext(ots::Buffer &table,
return ParseDictDataEscapedOperator(table, operands);
}
operands.push_back(std::make_pair(
- static_cast<uint32_t>(op), DICT_OPERATOR));
+ static_cast<int32_t>(op), DICT_OPERATOR));
return true;
} else if (op <= 27 || op == 31 || op == 255) {
// reserved area.
@@ -367,13 +366,13 @@ bool ParseDictDataReadOperands(ots::Buffer& dict,
return true;
}
-bool ValidCFF2DictOp(uint32_t op, DICT_DATA_TYPE type) {
+bool ValidCFF2DictOp(int32_t op, DICT_DATA_TYPE type) {
if (type == DICT_DATA_TOPLEVEL) {
switch (op) {
- case (12U << 8) + 7: // FontMatrix
+ case (12 << 8) + 7: // FontMatrix
case 17: // CharStrings
- case (12U << 8) + 36: // FDArray
- case (12U << 8) + 37: // FDSelect
+ case (12 << 8) + 36: // FDArray
+ case (12 << 8) + 37: // FDSelect
case 24: // vstore
return true;
default:
@@ -384,8 +383,8 @@ bool ValidCFF2DictOp(uint32_t op, DICT_DATA_TYPE type) {
return true;
} else if (type == DICT_DATA_PRIVATE) {
switch (op) {
- case (12U << 8) + 14: // ForceBold
- case (12U << 8) + 19: // initialRandomSeed
+ case (12 << 8) + 14: // ForceBold
+ case (12 << 8) + 19: // initialRandomSeed
case 20: // defaultWidthX
case 21: // nominalWidthX
return false;
@@ -426,7 +425,7 @@ bool ParsePrivateDictData(
}
// got operator
- const uint32_t op = operands.back().first;
+ const int32_t op = operands.back().first;
operands.pop_back();
if (cff2 && !ValidCFF2DictOp(op, DICT_DATA_PRIVATE)) {
@@ -446,8 +445,8 @@ bool ParsePrivateDictData(
break;
// array
- case (12U << 8) + 12: // StemSnapH (delta)
- case (12U << 8) + 13: // StemSnapV (delta)
+ case (12 << 8) + 12: // StemSnapH (delta)
+ case (12 << 8) + 13: // StemSnapV (delta)
if (operands.empty()) {
return OTS_FAILURE();
}
@@ -458,12 +457,12 @@ bool ParsePrivateDictData(
case 11: // StdVW
case 20: // defaultWidthX
case 21: // nominalWidthX
- case (12U << 8) + 9: // BlueScale
- case (12U << 8) + 10: // BlueShift
- case (12U << 8) + 11: // BlueFuzz
- case (12U << 8) + 17: // LanguageGroup
- case (12U << 8) + 18: // ExpansionFactor
- case (12U << 8) + 19: // initialRandomSeed
+ case (12 << 8) + 9: // BlueScale
+ case (12 << 8) + 10: // BlueShift
+ case (12 << 8) + 11: // BlueFuzz
+ case (12 << 8) + 17: // LanguageGroup
+ case (12 << 8) + 18: // ExpansionFactor
+ case (12 << 8) + 19: // initialRandomSeed
if (operands.size() != 1) {
return OTS_FAILURE();
}
@@ -477,7 +476,14 @@ bool ParsePrivateDictData(
if (operands.back().second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- if (operands.back().first >= 1024 * 1024 * 1024) {
+ // In theory a negative operand could occur here, if the Local Subrs
+ // were stored before the Private dict, but this does not seem to be
+ // well supported by implementations, and mishandling of a negative
+ // offset (e.g. by using unsigned offset arithmetic) might become a
+ // vector for exploitation. AFAIK no major font creation tool will
+ // generate such an offset, so to be on the safe side, we don't allow
+ // it here.
+ if (operands.back().first >= 1024 * 1024 * 1024 || operands.back().first < 0) {
return OTS_FAILURE();
}
if (operands.back().first + offset >= table.length()) {
@@ -505,14 +511,14 @@ bool ParsePrivateDictData(
}
// boolean
- case (12U << 8) + 14: // ForceBold
+ case (12 << 8) + 14: // ForceBold
if (operands.size() != 1) {
return OTS_FAILURE();
}
if (operands.back().second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- if (operands.back().first >= 2) {
+ if (operands.back().first >= 2 || operands.back().first < 0) {
return OTS_FAILURE();
}
break;
@@ -532,7 +538,7 @@ bool ParsePrivateDictData(
}
vsindex = operands.back().first;
if (vsindex < 0 ||
- vsindex >= (int32_t)out_cff->region_index_count.size()) {
+ vsindex >= static_cast<int32_t>(out_cff->region_index_count.size())) {
return OTS_FAILURE();
}
out_cff->vsindex_per_font.back() = vsindex;
@@ -546,11 +552,15 @@ bool ParsePrivateDictData(
if (operands.size() < 1) {
return OTS_FAILURE();
}
- if (vsindex >= (int32_t)out_cff->region_index_count.size()) {
+ if (vsindex >= static_cast<int32_t>(out_cff->region_index_count.size())) {
return OTS_FAILURE();
}
uint16_t k = out_cff->region_index_count.at(vsindex);
- uint16_t n = operands.back().first;
+
+ if (operands.back().first > static_cast<uint16_t>(0xffff) || operands.back().first < 0){
+ return OTS_FAILURE();
+ }
+ uint16_t n = static_cast<uint16_t>(operands.back().first);
if (operands.size() < n * (k + 1) + 1) {
return OTS_FAILURE();
}
@@ -644,7 +654,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
if (operands.back().second != DICT_OPERATOR) continue;
// got operator
- const uint32_t op = operands.back().first;
+ const int32_t op = operands.back().first;
operands.pop_back();
if (op == 18 && type == DICT_DATA_FDARRAY) {
@@ -686,7 +696,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
if (operands.back().second != DICT_OPERATOR) continue;
// got operator
- const uint32_t op = operands.back().first;
+ const int32_t op = operands.back().first;
operands.pop_back();
if (cff2 && !ValidCFF2DictOp(op, type)) {
@@ -700,10 +710,10 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
case 2: // Copyright
case 3: // FullName
case 4: // FamilyName
- case (12U << 8) + 0: // Copyright
- case (12U << 8) + 21: // PostScript
- case (12U << 8) + 22: // BaseFontName
- case (12U << 8) + 38: // FontName
+ case (12 << 8) + 0: // Copyright
+ case (12 << 8) + 21: // PostScript
+ case (12 << 8) + 22: // BaseFontName
+ case (12 << 8) + 38: // FontName
if (operands.size() != 1) {
return OTS_FAILURE();
}
@@ -715,8 +725,8 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
// array
case 5: // FontBBox
case 14: // XUID
- case (12U << 8) + 7: // FontMatrix
- case (12U << 8) + 23: // BaseFontBlend (delta)
+ case (12 << 8) + 7: // FontMatrix
+ case (12 << 8) + 23: // BaseFontBlend (delta)
if (operands.empty()) {
return OTS_FAILURE();
}
@@ -724,21 +734,21 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
// number
case 13: // UniqueID
- case (12U << 8) + 2: // ItalicAngle
- case (12U << 8) + 3: // UnderlinePosition
- case (12U << 8) + 4: // UnderlineThickness
- case (12U << 8) + 5: // PaintType
- case (12U << 8) + 8: // StrokeWidth
- case (12U << 8) + 20: // SyntheticBase
+ case (12 << 8) + 2: // ItalicAngle
+ case (12 << 8) + 3: // UnderlinePosition
+ case (12 << 8) + 4: // UnderlineThickness
+ case (12 << 8) + 5: // PaintType
+ case (12 << 8) + 8: // StrokeWidth
+ case (12 << 8) + 20: // SyntheticBase
if (operands.size() != 1) {
return OTS_FAILURE();
}
break;
- case (12U << 8) + 31: // CIDFontVersion
- case (12U << 8) + 32: // CIDFontRevision
- case (12U << 8) + 33: // CIDFontType
- case (12U << 8) + 34: // CIDCount
- case (12U << 8) + 35: // UIDBase
+ case (12 << 8) + 31: // CIDFontVersion
+ case (12 << 8) + 32: // CIDFontRevision
+ case (12 << 8) + 33: // CIDFontType
+ case (12 << 8) + 34: // CIDCount
+ case (12 << 8) + 35: // UIDBase
if (operands.size() != 1) {
return OTS_FAILURE();
}
@@ -746,7 +756,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
return OTS_FAILURE();
}
break;
- case (12U << 8) + 6: // CharstringType
+ case (12 << 8) + 6: // CharstringType
if (operands.size() != 1) {
return OTS_FAILURE();
}
@@ -761,14 +771,14 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
break;
// boolean
- case (12U << 8) + 1: // isFixedPitch
+ case (12 << 8) + 1: // isFixedPitch
if (operands.size() != 1) {
return OTS_FAILURE();
}
if (operands.back().second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- if (operands.back().first >= 2) {
+ if (operands.back().first >= 2 || operands.back().first < 0) {
return OTS_FAILURE();
}
break;
@@ -778,7 +788,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
if (operands.size() != 1) {
return OTS_FAILURE();
}
- if (operands.back().first <= 2) {
+ if (operands.back().first <= 2 && operands.back().first >= 0) {
// predefined charset, ISOAdobe, Expert or ExpertSubset, is used.
break;
}
@@ -795,7 +805,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
if (operands.size() != 1) {
return OTS_FAILURE();
}
- if (operands.back().first <= 1) {
+ if (operands.back().first <= 1 && operands.back().first >= 0) {
break; // predefined encoding, "Standard" or "Expert", is used.
}
if (!CheckOffset(operands.back(), table.length())) {
@@ -856,7 +866,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
break;
}
- case (12U << 8) + 36: { // FDArray
+ case (12 << 8) + 36: { // FDArray
if (type != DICT_DATA_TOPLEVEL) {
return OTS_FAILURE();
}
@@ -885,7 +895,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
break;
}
- case (12U << 8) + 37: { // FDSelect
+ case (12 << 8) + 37: { // FDSelect
if (type != DICT_DATA_TOPLEVEL) {
return OTS_FAILURE();
}
@@ -1043,19 +1053,19 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
if (operands.back().second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- const uint32_t private_offset = operands.back().first;
+ const int32_t private_offset = operands.back().first;
operands.pop_back();
if (operands.back().second != DICT_OPERAND_INTEGER) {
return OTS_FAILURE();
}
- const uint32_t private_length = operands.back().first;
- if (private_offset > table.length()) {
+ const int32_t private_length = operands.back().first;
+ if (private_offset > static_cast<int32_t>(table.length())) {
return OTS_FAILURE();
}
- if (private_length >= table.length()) {
+ if (private_length >= static_cast<int32_t>(table.length()) || private_length < 0) {
return OTS_FAILURE();
}
- if (private_length + private_offset > table.length()) {
+ if (private_length + private_offset > static_cast<int32_t>(table.length()) || private_length + private_offset < 0) {
return OTS_FAILURE();
}
// parse "15. Private DICT data"
@@ -1067,7 +1077,7 @@ bool ParseDictData(ots::Buffer& table, ots::Buffer& dict,
}
// ROS
- case (12U << 8) + 30:
+ case (12 << 8) + 30:
if (font_format != FORMAT_UNKNOWN) {
return OTS_FAILURE();
}
diff --git a/gfx/ots/src/colr.cc b/gfx/ots/src/colr.cc
index 8931c77c32..a09d3ab3a4 100644
--- a/gfx/ots/src/colr.cc
+++ b/gfx/ots/src/colr.cc
@@ -193,7 +193,15 @@ bool ParsePaintColrLayers(const ots::Font* font,
colrState& state)
{
if (setContains(state.visited, data)) {
+#ifdef OTS_COLR_CYCLE_CHECK
+ // A cycle would imply an infinite loop during painting, unless the renderer
+ // detects and breaks it. To be safe, reject the table.
return OTS_FAILURE_MSG("Cycle detected in PaintColrLayers");
+#else
+ // Just issue a warning and return (as we've already checked this subgraph).
+ OTS_WARNING("Cycle detected in COLRv1 glyph paint graph (PaintColrLayers)\n");
+ return true;
+#endif
}
state.visited.insert(data);
@@ -393,7 +401,12 @@ bool ParsePaintColrGlyph(const ots::Font* font,
colrState& state)
{
if (setContains(state.visited, data)) {
+#ifdef OTS_COLR_CYCLE_CHECK
return OTS_FAILURE_MSG("Cycle detected in PaintColrGlyph");
+#else
+ OTS_WARNING("Cycle detected in COLRv1 glyph paint graph (PaintColrGlyph)\n");
+ return true;
+#endif
}
state.visited.insert(data);
diff --git a/gfx/ots/src/glyf.cc b/gfx/ots/src/glyf.cc
index 31487957bf..12c0537f64 100644
--- a/gfx/ots/src/glyf.cc
+++ b/gfx/ots/src/glyf.cc
@@ -95,10 +95,10 @@ bool OpenTypeGLYF::ParseFlagsForSimpleGlyph(Buffer &glyph,
bool OpenTypeGLYF::ParseSimpleGlyph(Buffer &glyph,
unsigned gid,
int16_t num_contours,
- int16_t& xmin,
- int16_t& ymin,
- int16_t& xmax,
- int16_t& ymax,
+ int16_t xmin,
+ int16_t ymin,
+ int16_t xmax,
+ int16_t ymax,
bool is_tricky_font) {
// read the end-points array
uint16_t num_flags = 0;
diff --git a/gfx/ots/src/glyf.h b/gfx/ots/src/glyf.h
index f85fdc4652..c0d5871edf 100644
--- a/gfx/ots/src/glyf.h
+++ b/gfx/ots/src/glyf.h
@@ -48,10 +48,10 @@ class OpenTypeGLYF : public Table {
bool ParseSimpleGlyph(Buffer &glyph,
unsigned gid,
int16_t num_contours,
- int16_t& xmin,
- int16_t& ymin,
- int16_t& xmax,
- int16_t& ymax,
+ int16_t xmin,
+ int16_t ymin,
+ int16_t xmax,
+ int16_t ymax,
bool is_tricky_font);
bool ParseCompositeGlyph(
Buffer &glyph,
diff --git a/gfx/ots/src/maxp.cc b/gfx/ots/src/maxp.cc
index 232e4a9889..90f53b0e39 100644
--- a/gfx/ots/src/maxp.cc
+++ b/gfx/ots/src/maxp.cc
@@ -29,39 +29,49 @@ bool OpenTypeMAXP::Parse(const uint8_t *data, size_t length) {
return Error("numGlyphs is 0");
}
- if (version >> 16 == 1) {
- this->version_1 = true;
- if (!table.ReadU16(&this->max_points) ||
- !table.ReadU16(&this->max_contours) ||
- !table.ReadU16(&this->max_c_points) ||
- !table.ReadU16(&this->max_c_contours) ||
- !table.ReadU16(&this->max_zones) ||
- !table.ReadU16(&this->max_t_points) ||
- !table.ReadU16(&this->max_storage) ||
- !table.ReadU16(&this->max_fdefs) ||
- !table.ReadU16(&this->max_idefs) ||
- !table.ReadU16(&this->max_stack) ||
- !table.ReadU16(&this->max_size_glyf_instructions) ||
- !table.ReadU16(&this->max_c_components) ||
- !table.ReadU16(&this->max_c_depth)) {
- return Error("Failed to read version 1 table data");
- }
-
- if (this->max_zones == 0) {
- // 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.
- 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;
+ this->version_1 = false;
+
+ // 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 it's version 0.5, there is nothing more to read.
+ if (version == 0x00005000) {
+ return true;
+ }
+
+ if (version != 0x00010000) {
+ Warning("Unexpected version 0x%08x; attempting to read as version 1.0",
+ version);
+ }
+
+ // Otherwise, try to read the version 1.0 fields:
+ if (!table.ReadU16(&this->max_points) ||
+ !table.ReadU16(&this->max_contours) ||
+ !table.ReadU16(&this->max_c_points) ||
+ !table.ReadU16(&this->max_c_contours) ||
+ !table.ReadU16(&this->max_zones) ||
+ !table.ReadU16(&this->max_t_points) ||
+ !table.ReadU16(&this->max_storage) ||
+ !table.ReadU16(&this->max_fdefs) ||
+ !table.ReadU16(&this->max_idefs) ||
+ !table.ReadU16(&this->max_stack) ||
+ !table.ReadU16(&this->max_size_glyf_instructions) ||
+ !table.ReadU16(&this->max_c_components) ||
+ !table.ReadU16(&this->max_c_depth)) {
+ Warning("Failed to read version 1.0 fields, downgrading to version 0.5");
+ return true;
+ }
+
+ this->version_1 = true;
+
+ 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 > 2) {
+ // workaround for Ecolier-*.ttf fonts and bad fonts in some PDFs
+ Warning("Bad maxZones: %u", this->max_zones);
+ this->max_zones = 2;
}
return true;
diff --git a/gfx/ots/src/ots.cc b/gfx/ots/src/ots.cc
index 73b1d235cf..1ee4498363 100644
--- a/gfx/ots/src/ots.cc
+++ b/gfx/ots/src/ots.cc
@@ -728,12 +728,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)
@@ -747,6 +753,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