Bug 1791017 - Update OTS to 9.0.0. r=RyanVM

Differential Revision: https://phabricator.services.mozilla.com/D157474
This commit is contained in:
Jonathan Kew 2022-09-22 19:11:33 +00:00
Родитель c73876ca6c
Коммит 3ac18db1ff
9 изменённых файлов: 1473 добавлений и 4 удалений

Просмотреть файл

@ -2,7 +2,7 @@ This is the Sanitiser for OpenType project, from http://code.google.com/p/ots/.
Our reference repository is https://github.com/khaledhosny/ots/.
Current revision: dd99d9a451d070048b73b7c385c19c8dfb28c24d (8.2.2)
Current revision: 35643038c4904538aa74c2c691f8d792efdbd6c0 (9.0.0)
Upstream files included: LICENSE, src/, include/, tests/*.cc

1092
gfx/ots/src/colr.cc Normal file

Разница между файлами не показана из-за своего большого размера Загрузить разницу

31
gfx/ots/src/colr.h Normal file
Просмотреть файл

@ -0,0 +1,31 @@
// Copyright (c) 2022 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OTS_COLR_H_
#define OTS_COLR_H_
#include "ots.h"
namespace ots {
class OpenTypeCOLR : public Table {
public:
explicit OpenTypeCOLR(Font *font, uint32_t tag)
: Table(font, tag, tag),
m_data(NULL),
m_length(0) {
}
bool Parse(const uint8_t *data, size_t length);
bool Serialize(OTSStream *out);
private:
const uint8_t *m_data;
size_t m_length;
};
} // namespace ots
#endif // OTS_COLR_H_

283
gfx/ots/src/cpal.cc Normal file
Просмотреть файл

@ -0,0 +1,283 @@
// Copyright (c) 2022 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cpal.h"
#include "name.h"
// CPAL - Color Palette Table
// http://www.microsoft.com/typography/otspec/cpal.htm
#define TABLE_NAME "CPAL"
namespace {
// Caller has sized the colorRecords array, so we know how much to try and read.
bool ParseColorRecordsArray(const ots::Font* font,
const uint8_t* data, size_t length,
std::vector<uint32_t>* colorRecords)
{
ots::Buffer subtable(data, length);
for (auto& color : *colorRecords) {
if (!subtable.ReadU32(&color)) {
return OTS_FAILURE_MSG("Failed to read color record");
}
}
return true;
}
// Caller has sized the paletteTypes array, so we know how much to try and read.
bool ParsePaletteTypesArray(const ots::Font* font,
const uint8_t* data, size_t length,
std::vector<uint32_t>* paletteTypes)
{
ots::Buffer subtable(data, length);
constexpr uint32_t USABLE_WITH_LIGHT_BACKGROUND = 0x0001;
constexpr uint32_t USABLE_WITH_DARK_BACKGROUND = 0x0002;
constexpr uint32_t RESERVED = ~(USABLE_WITH_LIGHT_BACKGROUND | USABLE_WITH_DARK_BACKGROUND);
for (auto& type : *paletteTypes) {
if (!subtable.ReadU32(&type)) {
return OTS_FAILURE_MSG("Failed to read palette type");
}
if (type & RESERVED) {
// Should we treat this as failure? For now, just a warning; seems unlikely
// to be dangerous.
OTS_WARNING("Invalid (reserved) palette type flags %08x", type);
type &= ~RESERVED;
}
}
return true;
}
// Caller has sized the labels array, so we know how much to try and read.
bool ParseLabelsArray(const ots::Font* font,
const uint8_t* data, size_t length,
std::vector<uint16_t>* labels,
const char* labelType)
{
ots::Buffer subtable(data, length);
auto* name = static_cast<ots::OpenTypeNAME*>(font->GetTypedTable(OTS_TAG_NAME));
if (!name) {
return OTS_FAILURE_MSG("Required name table missing");
}
for (auto& nameID : *labels) {
if (!subtable.ReadU16(&nameID)) {
return OTS_FAILURE_MSG("Failed to read %s label ID", labelType);
}
if (nameID != 0xffff) {
if (!name->IsValidNameId(nameID)) {
OTS_WARNING("Label ID %u for %s missing from name table", nameID, labelType);
nameID = 0xffff;
}
}
}
return true;
}
} // namespace
namespace ots {
bool OpenTypeCPAL::Parse(const uint8_t *data, size_t length) {
Font *font = GetFont();
Buffer table(data, length);
// Header fields common to versions 0 and 1. These are recomputed
// from the array sizes during serialization.
uint16_t numPalettes;
uint16_t numColorRecords;
uint32_t colorRecordsArrayOffset;
if (!table.ReadU16(&this->version) ||
!table.ReadU16(&this->num_palette_entries) ||
!table.ReadU16(&numPalettes) ||
!table.ReadU16(&numColorRecords) ||
!table.ReadU32(&colorRecordsArrayOffset)) {
return Error("Failed to read CPAL table header");
}
if (this->version > 1) {
return Error("Unknown CPAL table version %u", this->version);
}
if (!this->num_palette_entries || !numPalettes || !numColorRecords) {
return Error("Empty CPAL is not valid");
}
if (this->num_palette_entries > numColorRecords) {
return Error("Not enough color records for a complete palette");
}
uint32_t headerSize = 4 * sizeof(uint16_t) + sizeof(uint32_t) +
numPalettes * sizeof(uint16_t);
// uint16_t colorRecordIndices[numPalettes]
this->colorRecordIndices.resize(numPalettes);
for (auto& colorRecordIndex : this->colorRecordIndices) {
if (!table.ReadU16(&colorRecordIndex)) {
return Error("Failed to read color record index");
}
if (colorRecordIndex > numColorRecords - this->num_palette_entries) {
return Error("Palette overflows color records array");
}
}
uint32_t paletteTypesArrayOffset = 0;
uint32_t paletteLabelsArrayOffset = 0;
uint32_t paletteEntryLabelsArrayOffset = 0;
if (this->version == 1) {
if (!table.ReadU32(&paletteTypesArrayOffset) ||
!table.ReadU32(&paletteLabelsArrayOffset) ||
!table.ReadU32(&paletteEntryLabelsArrayOffset)) {
return Error("Failed to read CPAL v.1 table header");
}
headerSize += 3 * sizeof(uint32_t);
}
// The following arrays may occur in any order, as they're independently referenced
// by offsets in the header.
if (colorRecordsArrayOffset < headerSize || colorRecordsArrayOffset >= length) {
return Error("Bad color records array offset in table header");
}
this->colorRecords.resize(numColorRecords);
if (!ParseColorRecordsArray(font, data + colorRecordsArrayOffset, length - colorRecordsArrayOffset,
&this->colorRecords)) {
return Error("Failed to parse color records array");
}
if (paletteTypesArrayOffset) {
if (paletteTypesArrayOffset < headerSize || paletteTypesArrayOffset >= length) {
return Error("Bad palette types array offset in table header");
}
this->paletteTypes.resize(numPalettes);
if (!ParsePaletteTypesArray(font, data + paletteTypesArrayOffset, length - paletteTypesArrayOffset,
&this->paletteTypes)) {
return Error("Failed to parse palette types array");
}
}
if (paletteLabelsArrayOffset) {
if (paletteLabelsArrayOffset < headerSize || paletteLabelsArrayOffset >= length) {
return Error("Bad palette labels array offset in table header");
}
this->paletteLabels.resize(numPalettes);
if (!ParseLabelsArray(font, data + paletteLabelsArrayOffset, length - paletteLabelsArrayOffset,
&this->paletteLabels, "palette")) {
return Error("Failed to parse palette labels array");
}
}
if (paletteEntryLabelsArrayOffset) {
if (paletteEntryLabelsArrayOffset < headerSize || paletteEntryLabelsArrayOffset >= length) {
return Error("Bad palette entry labels array offset in table header");
}
this->paletteEntryLabels.resize(this->num_palette_entries);
if (!ParseLabelsArray(font, data + paletteEntryLabelsArrayOffset, length - paletteEntryLabelsArrayOffset,
&this->paletteEntryLabels, "palette entry")) {
return Error("Failed to parse palette entry labels array");
}
}
return true;
}
bool OpenTypeCPAL::Serialize(OTSStream *out) {
uint16_t numPalettes = this->colorRecordIndices.size();
uint16_t numColorRecords = this->colorRecords.size();
off_t start = out->Tell();
size_t colorRecordsArrayOffset = 4 * sizeof(uint16_t) + sizeof(uint32_t) +
numPalettes * sizeof(uint16_t);
if (this->version == 1) {
colorRecordsArrayOffset += 3 * sizeof(uint32_t);
}
size_t totalLen = colorRecordsArrayOffset + numColorRecords * sizeof(uint32_t);
if (!out->WriteU16(this->version) ||
!out->WriteU16(this->num_palette_entries) ||
!out->WriteU16(numPalettes) ||
!out->WriteU16(numColorRecords) ||
!out->WriteU32(colorRecordsArrayOffset)) {
return Error("Failed to write CPAL header");
}
for (auto i : this->colorRecordIndices) {
if (!out->WriteU16(i)) {
return Error("Failed to write color record indices");
}
}
if (this->version == 1) {
size_t paletteTypesArrayOffset = 0;
if (!this->paletteTypes.empty()) {
assert(paletteTypes.size() == numPalettes);
paletteTypesArrayOffset = totalLen;
totalLen += numPalettes * sizeof(uint32_t);
}
size_t paletteLabelsArrayOffset = 0;
if (!this->paletteLabels.empty()) {
assert(paletteLabels.size() == numPalettes);
paletteLabelsArrayOffset = totalLen;
totalLen += numPalettes * sizeof(uint16_t);
}
size_t paletteEntryLabelsArrayOffset = 0;
if (!this->paletteEntryLabels.empty()) {
assert(paletteEntryLabels.size() == this->num_palette_entries);
paletteEntryLabelsArrayOffset = totalLen;
totalLen += this->num_palette_entries * sizeof(uint16_t);
}
if (!out->WriteU32(paletteTypesArrayOffset) ||
!out->WriteU32(paletteLabelsArrayOffset) ||
!out->WriteU32(paletteEntryLabelsArrayOffset)) {
return Error("Failed to write CPAL v.1 header");
}
}
for (auto i : this->colorRecords) {
if (!out->WriteU32(i)) {
return Error("Failed to write color records");
}
}
if (this->version == 1) {
for (auto i : this->paletteTypes) {
if (!out->WriteU32(i)) {
return Error("Failed to write palette types");
}
}
for (auto i : this->paletteLabels) {
if (!out->WriteU16(i)) {
return Error("Failed to write palette labels");
}
}
for (auto i : this->paletteEntryLabels) {
if (!out->WriteU16(i)) {
return Error("Failed to write palette entry labels");
}
}
}
assert(size_t(out->Tell() - start) == totalLen);
return true;
}
} // namespace ots
#undef TABLE_NAME

40
gfx/ots/src/cpal.h Normal file
Просмотреть файл

@ -0,0 +1,40 @@
// Copyright (c) 2022 The OTS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef OTS_CPAL_H_
#define OTS_CPAL_H_
#include "ots.h"
#include <vector>
namespace ots {
class OpenTypeCPAL : public Table {
public:
explicit OpenTypeCPAL(Font *font, uint32_t tag)
: Table(font, tag, tag) {
}
bool Parse(const uint8_t *data, size_t length);
bool Serialize(OTSStream *out);
// This is public so that COLR can access it.
uint16_t num_palette_entries;
private:
uint16_t version;
std::vector<uint16_t> colorRecordIndices;
std::vector<uint32_t> colorRecords;
// Arrays present only if version == 1.
std::vector<uint32_t> paletteTypes;
std::vector<uint16_t> paletteLabels;
std::vector<uint16_t> paletteEntryLabels;
};
} // namespace ots
#endif // OTS_CPAL_H_

Просмотреть файл

@ -19,6 +19,8 @@ UNIFIED_SOURCES += [
'cff.cc',
'cff_charstring.cc',
'cmap.cc',
'colr.cc',
'cpal.cc',
'cvar.cc',
'cvt.cc',
'feat.cc',

Просмотреть файл

@ -22,6 +22,8 @@
#include "avar.h"
#include "cff.h"
#include "cmap.h"
#include "colr.h"
#include "cpal.h"
#include "cvar.h"
#include "cvt.h"
#include "fpgm.h"
@ -144,6 +146,11 @@ const struct {
{ OTS_TAG_STAT, false },
{ OTS_TAG_VVAR, false },
{ OTS_TAG_CFF2, false },
// Color font tables.
// We need to parse CPAL before COLR so that the number of palette entries
// is known; and these tables follow fvar because COLR may use variations.
{ OTS_TAG_CPAL, false },
{ OTS_TAG_COLR, false },
// We need to parse GDEF table in advance of parsing GSUB/GPOS tables
// because they could refer GDEF table.
{ OTS_TAG_GDEF, false },
@ -884,6 +891,8 @@ bool Font::ParseTable(const TableEntry& table_entry, const uint8_t* data,
case OTS_TAG_CFF: table = new OpenTypeCFF(this, tag); break;
case OTS_TAG_CFF2: table = new OpenTypeCFF2(this, tag); break;
case OTS_TAG_CMAP: table = new OpenTypeCMAP(this, tag); break;
case OTS_TAG_COLR: table = new OpenTypeCOLR(this, tag); break;
case OTS_TAG_CPAL: table = new OpenTypeCPAL(this, tag); break;
case OTS_TAG_CVAR: table = new OpenTypeCVAR(this, tag); break;
case OTS_TAG_CVT: table = new OpenTypeCVT(this, tag); break;
case OTS_TAG_FPGM: table = new OpenTypeFPGM(this, tag); break;

Просмотреть файл

@ -190,6 +190,8 @@ bool CheckTag(uint32_t tag_value);
#define OTS_TAG_CFF OTS_TAG('C','F','F',' ')
#define OTS_TAG_CFF2 OTS_TAG('C','F','F','2')
#define OTS_TAG_CMAP OTS_TAG('c','m','a','p')
#define OTS_TAG_COLR OTS_TAG('C','O','L','R')
#define OTS_TAG_CPAL OTS_TAG('C','P','A','L')
#define OTS_TAG_CVT OTS_TAG('c','v','t',' ')
#define OTS_TAG_FEAT OTS_TAG('F','e','a','t')
#define OTS_TAG_FPGM OTS_TAG('f','p','g','m')

Просмотреть файл

@ -67,14 +67,24 @@ ParseVariationDataSubtable(const ots::Font* font, const uint8_t* data, const siz
ots::Buffer subtable(data, length);
uint16_t itemCount;
uint16_t shortDeltaCount;
uint16_t wordDeltaCount;
const uint16_t LONG_WORDS = 0x8000u;
const uint16_t WORD_DELTA_COUNT_MASK = 0x7FFF;
if (!subtable.ReadU16(&itemCount) ||
!subtable.ReadU16(&shortDeltaCount) ||
!subtable.ReadU16(&wordDeltaCount) ||
!subtable.ReadU16(regionIndexCount)) {
return OTS_FAILURE_MSG("Failed to read variation data subtable header");
}
size_t valueSize = (wordDeltaCount & LONG_WORDS) ? 2 : 1;
wordDeltaCount &= WORD_DELTA_COUNT_MASK;
if (wordDeltaCount > *regionIndexCount) {
return OTS_FAILURE_MSG("Bad word delta count");
}
for (unsigned i = 0; i < *regionIndexCount; i++) {
uint16_t regionIndex;
if (!subtable.ReadU16(&regionIndex) || regionIndex >= regionCount) {
@ -82,7 +92,7 @@ ParseVariationDataSubtable(const ots::Font* font, const uint8_t* data, const siz
}
}
if (!subtable.Skip(size_t(itemCount) * (size_t(shortDeltaCount) + size_t(*regionIndexCount)))) {
if (!subtable.Skip(valueSize * size_t(itemCount) * (size_t(wordDeltaCount) + size_t(*regionIndexCount)))) {
return OTS_FAILURE_MSG("Failed to read delta data");
}