зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1466443 - Update WOFF2 library to upstream tip, to pick up overlapSimpleBitmap support. r=gfx-reviewers,lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D164324
This commit is contained in:
Родитель
3821ab942f
Коммит
ab2c050f10
|
@ -11,6 +11,6 @@ The in-tree copy is updated by running
|
|||
sh update.sh
|
||||
from within the modules/woff2 directory.
|
||||
|
||||
Current version: [commit 1bccf208bca986e53a647dfe4811322adb06ecf8].
|
||||
Current version: [commit 4721483ad780ee2b63cb787bfee4aa64b61a0446].
|
||||
|
||||
Additional patch: woff2-rlbox.patch (bug 1732201).
|
||||
|
|
|
@ -26,8 +26,8 @@ struct WOFF2Params {
|
|||
|
||||
// Returns an upper bound on the size of the compressed file.
|
||||
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length);
|
||||
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length,
|
||||
const std::string& extended_metadata);
|
||||
size_t MaxWOFF2CompressedSize(const uint8_t *data, size_t length,
|
||||
const std::string &extended_metadata);
|
||||
|
||||
// Compresses the font into the target buffer. *result_length should be at least
|
||||
// the value returned by MaxWOFF2CompressedSize(), upon return, it is set to the
|
||||
|
|
|
@ -51,7 +51,7 @@ class WOFF2StringOut : public WOFF2Out {
|
|||
// Create a writer that writes its data to buf.
|
||||
// buf->size() will grow to at most max_size
|
||||
// buf may be sized (e.g. using EstimateWOFF2FinalSize) or empty.
|
||||
explicit WOFF2StringOut(std::string* buf);
|
||||
explicit WOFF2StringOut(std::string *buf);
|
||||
|
||||
bool Write(const void *buf, size_t n) override;
|
||||
bool Write(const void *buf, size_t offset, size_t n) override;
|
||||
|
@ -59,7 +59,7 @@ class WOFF2StringOut : public WOFF2Out {
|
|||
size_t MaxSize() { return max_size_; }
|
||||
void SetMaxSize(size_t max_size);
|
||||
private:
|
||||
std::string* buf_;
|
||||
std::string *buf_;
|
||||
size_t max_size_;
|
||||
size_t offset_;
|
||||
};
|
||||
|
|
|
@ -14,18 +14,14 @@
|
|||
|
||||
namespace woff2 {
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
inline string GetFileContent(string filename) {
|
||||
inline std::string GetFileContent(std::string filename) {
|
||||
std::ifstream ifs(filename.c_str(), std::ios::binary);
|
||||
return string(
|
||||
std::istreambuf_iterator<char>(ifs.rdbuf()),
|
||||
std::istreambuf_iterator<char>());
|
||||
return std::string(std::istreambuf_iterator<char>(ifs.rdbuf()),
|
||||
std::istreambuf_iterator<char>());
|
||||
}
|
||||
|
||||
inline void SetFileContents(string filename, string::iterator start,
|
||||
string::iterator end) {
|
||||
inline void SetFileContents(std::string filename, std::string::iterator start,
|
||||
std::string::iterator end) {
|
||||
std::ofstream ofs(filename.c_str(), std::ios::binary);
|
||||
std::copy(start, end, std::ostream_iterator<char>(ofs));
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ static const int32_t kFLAG_YSHORT = 1 << 2;
|
|||
static const int32_t kFLAG_REPEAT = 1 << 3;
|
||||
static const int32_t kFLAG_XREPEATSIGN = 1 << 4;
|
||||
static const int32_t kFLAG_YREPEATSIGN = 1 << 5;
|
||||
static const int32_t kFLAG_OVERLAP_SIMPLE = 1 << 6;
|
||||
static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
|
||||
static const int32_t kFLAG_WE_HAVE_A_SCALE = 1 << 3;
|
||||
static const int32_t kFLAG_MORE_COMPONENTS = 1 << 5;
|
||||
|
@ -134,6 +135,10 @@ bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
|
|||
}
|
||||
}
|
||||
|
||||
if (!flags.empty() && !flags[0].empty()) {
|
||||
glyph->overlap_simple_flag_set = (flags[0][0] & kFLAG_OVERLAP_SIMPLE);
|
||||
}
|
||||
|
||||
// Read the x coordinates.
|
||||
int prev_x = 0;
|
||||
for (int i = 0; i < num_contours; ++i) {
|
||||
|
@ -239,7 +244,7 @@ bool StoreEndPtsOfContours(const Glyph& glyph, size_t* offset, uint8_t* dst) {
|
|||
|
||||
bool StorePoints(const Glyph& glyph, size_t* offset,
|
||||
uint8_t* dst, size_t dst_size) {
|
||||
int last_flag = -1;
|
||||
int previous_flag = -1;
|
||||
int repeat_count = 0;
|
||||
int last_x = 0;
|
||||
int last_y = 0;
|
||||
|
@ -250,6 +255,10 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
|
|||
for (const auto& contour : glyph.contours) {
|
||||
for (const auto& point : contour) {
|
||||
int flag = point.on_curve ? kFLAG_ONCURVE : 0;
|
||||
if (previous_flag == -1 && glyph.overlap_simple_flag_set) {
|
||||
// First flag needs to have overlap simple bit set.
|
||||
flag = flag | kFLAG_OVERLAP_SIMPLE;
|
||||
}
|
||||
int dx = point.x - last_x;
|
||||
int dy = point.y - last_y;
|
||||
if (dx == 0) {
|
||||
|
@ -268,7 +277,7 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
|
|||
} else {
|
||||
y_bytes += 2;
|
||||
}
|
||||
if (flag == last_flag && repeat_count != 255) {
|
||||
if (flag == previous_flag && repeat_count != 255) {
|
||||
dst[*offset - 1] |= kFLAG_REPEAT;
|
||||
repeat_count++;
|
||||
} else {
|
||||
|
@ -286,7 +295,7 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
|
|||
}
|
||||
last_x = point.x;
|
||||
last_y = point.y;
|
||||
last_flag = flag;
|
||||
previous_flag = flag;
|
||||
}
|
||||
}
|
||||
if (repeat_count != 0) {
|
||||
|
|
|
@ -10,8 +10,10 @@
|
|||
#ifndef WOFF2_GLYPH_H_
|
||||
#define WOFF2_GLYPH_H_
|
||||
|
||||
#include <stddef.h>
|
||||
#include <inttypes.h>
|
||||
#include <stddef.h>
|
||||
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
namespace woff2 {
|
||||
|
@ -22,7 +24,10 @@ namespace woff2 {
|
|||
// is around.
|
||||
class Glyph {
|
||||
public:
|
||||
Glyph() : instructions_size(0), composite_data_size(0) {}
|
||||
Glyph()
|
||||
: instructions_size(0),
|
||||
overlap_simple_flag_set(false),
|
||||
composite_data_size(0) {}
|
||||
|
||||
// Bounding box.
|
||||
int16_t x_min;
|
||||
|
@ -34,6 +39,9 @@ class Glyph {
|
|||
uint16_t instructions_size;
|
||||
const uint8_t* instructions_data;
|
||||
|
||||
// Flags.
|
||||
bool overlap_simple_flag_set;
|
||||
|
||||
// Data model for simple glyphs.
|
||||
struct Point {
|
||||
int x;
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace {
|
|||
|
||||
const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
|
||||
const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
|
||||
const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0;
|
||||
|
||||
void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
|
||||
if (len == 0) return;
|
||||
|
@ -69,7 +70,10 @@ class GlyfEncoder {
|
|||
}
|
||||
|
||||
void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
|
||||
WriteLong(result, 0); // version
|
||||
WriteUShort(result, 0); // Version
|
||||
WriteUShort(result, overlap_bitmap_.empty()
|
||||
? 0x00
|
||||
: FLAG_OVERLAP_SIMPLE_BITMAP); // Flags
|
||||
WriteUShort(result, n_glyphs_);
|
||||
WriteUShort(result, 0); // index_format, will be set later
|
||||
WriteLong(result, n_contour_stream_.size());
|
||||
|
@ -87,6 +91,9 @@ class GlyfEncoder {
|
|||
WriteBytes(result, bbox_bitmap_);
|
||||
WriteBytes(result, bbox_stream_);
|
||||
WriteBytes(result, instruction_stream_);
|
||||
if (!overlap_bitmap_.empty()) {
|
||||
WriteBytes(result, overlap_bitmap_);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
@ -127,6 +134,10 @@ class GlyfEncoder {
|
|||
}
|
||||
|
||||
void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
|
||||
if (glyph.overlap_simple_flag_set) {
|
||||
EnsureOverlapBitmap();
|
||||
overlap_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
|
||||
}
|
||||
int num_contours = glyph.contours.size();
|
||||
WriteUShort(&n_contour_stream_, num_contours);
|
||||
if (ShouldWriteSimpleGlyphBbox(glyph)) {
|
||||
|
@ -214,6 +225,12 @@ class GlyfEncoder {
|
|||
}
|
||||
}
|
||||
|
||||
void EnsureOverlapBitmap() {
|
||||
if (overlap_bitmap_.empty()) {
|
||||
overlap_bitmap_.resize((n_glyphs_ + 7) >> 3);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint8_t> n_contour_stream_;
|
||||
std::vector<uint8_t> n_points_stream_;
|
||||
std::vector<uint8_t> flag_byte_stream_;
|
||||
|
@ -222,6 +239,7 @@ class GlyfEncoder {
|
|||
std::vector<uint8_t> bbox_stream_;
|
||||
std::vector<uint8_t> glyph_stream_;
|
||||
std::vector<uint8_t> instruction_stream_;
|
||||
std::vector<uint8_t> overlap_bitmap_;
|
||||
int n_glyphs_;
|
||||
};
|
||||
|
||||
|
|
|
@ -13,22 +13,20 @@
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::string;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "One argument, the input filename, must be provided.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
string filename(argv[1]);
|
||||
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
|
||||
std::string filename(argv[1]);
|
||||
std::string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
|
||||
fprintf(stdout, "Processing %s => %s\n",
|
||||
filename.c_str(), outfilename.c_str());
|
||||
string input = woff2::GetFileContent(filename);
|
||||
std::string input = woff2::GetFileContent(filename);
|
||||
|
||||
const uint8_t* input_data = reinterpret_cast<const uint8_t*>(input.data());
|
||||
size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, input.size());
|
||||
string output(output_size, 0);
|
||||
std::string output(output_size, 0);
|
||||
uint8_t* output_data = reinterpret_cast<uint8_t*>(&output[0]);
|
||||
|
||||
woff2::WOFF2Params params;
|
||||
|
|
|
@ -33,10 +33,6 @@ namespace woff2 {
|
|||
|
||||
namespace {
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
||||
// simple glyph flags
|
||||
const int kGlyfOnCurve = 1 << 0;
|
||||
const int kGlyfXShort = 1 << 1;
|
||||
|
@ -44,6 +40,7 @@ const int kGlyfYShort = 1 << 2;
|
|||
const int kGlyfRepeat = 1 << 3;
|
||||
const int kGlyfThisXIsSame = 1 << 4;
|
||||
const int kGlyfThisYIsSame = 1 << 5;
|
||||
const int kOverlapSimple = 1 << 6;
|
||||
|
||||
// composite glyph flags
|
||||
// See CompositeGlyph.java in sfntly for full definitions
|
||||
|
@ -54,6 +51,9 @@ const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
|
|||
const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
|
||||
const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
|
||||
|
||||
// glyf flags
|
||||
const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0;
|
||||
|
||||
const size_t kCheckSumAdjustmentOffset = 8;
|
||||
|
||||
const size_t kEndPtsOfContoursOffset = 10;
|
||||
|
@ -112,6 +112,16 @@ int WithSign(int flag, int baseval) {
|
|||
return (flag & 1) ? baseval : -baseval;
|
||||
}
|
||||
|
||||
bool _SafeIntAddition(int a, int b, int* result) {
|
||||
if (PREDICT_FALSE(
|
||||
((a > 0) && (b > std::numeric_limits<int>::max() - a)) ||
|
||||
((a < 0) && (b < std::numeric_limits<int>::min() - a)))) {
|
||||
return false;
|
||||
}
|
||||
*result = a + b;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
||||
unsigned int n_points, Point* result, size_t* in_bytes_consumed) {
|
||||
int x = 0;
|
||||
|
@ -167,9 +177,12 @@ bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
|||
(in[triplet_index + 2] << 8) + in[triplet_index + 3]);
|
||||
}
|
||||
triplet_index += n_data_bytes;
|
||||
// Possible overflow but coordinate values are not security sensitive
|
||||
x += dx;
|
||||
y += dy;
|
||||
if (!_SafeIntAddition(x, dx, &x)) {
|
||||
return false;
|
||||
}
|
||||
if (!_SafeIntAddition(y, dy, &y)) {
|
||||
return false;
|
||||
}
|
||||
*result++ = {x, y, on_curve};
|
||||
}
|
||||
*in_bytes_consumed = triplet_index;
|
||||
|
@ -179,8 +192,9 @@ bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
|
|||
// This function stores just the point data. On entry, dst points to the
|
||||
// beginning of a simple glyph. Returns true on success.
|
||||
bool StorePoints(unsigned int n_points, const Point* points,
|
||||
unsigned int n_contours, unsigned int instruction_length,
|
||||
uint8_t* dst, size_t dst_size, size_t* glyph_size) {
|
||||
unsigned int n_contours, unsigned int instruction_length,
|
||||
bool has_overlap_bit, uint8_t* dst, size_t dst_size,
|
||||
size_t* glyph_size) {
|
||||
// I believe that n_contours < 65536, in which case this is safe. However, a
|
||||
// comment and/or an assert would be good.
|
||||
unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
|
||||
|
@ -195,6 +209,10 @@ bool StorePoints(unsigned int n_points, const Point* points,
|
|||
for (unsigned int i = 0; i < n_points; ++i) {
|
||||
const Point& point = points[i];
|
||||
int flag = point.on_curve ? kGlyfOnCurve : 0;
|
||||
if (has_overlap_bit && i == 0) {
|
||||
flag |= kOverlapSimple;
|
||||
}
|
||||
|
||||
int dx = point.x - last_x;
|
||||
int dy = point.y - last_y;
|
||||
if (dx == 0) {
|
||||
|
@ -392,13 +410,20 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
|
|||
WOFF2Out* out) {
|
||||
static const int kNumSubStreams = 7;
|
||||
Buffer file(data, glyf_table->transform_length);
|
||||
uint32_t version;
|
||||
uint16_t version;
|
||||
std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
|
||||
const size_t glyf_start = out->Size();
|
||||
|
||||
if (PREDICT_FALSE(!file.ReadU32(&version))) {
|
||||
if (PREDICT_FALSE(!file.ReadU16(&version))) {
|
||||
return FONT_COMPRESSION_FAILURE();
|
||||
}
|
||||
|
||||
uint16_t flags;
|
||||
if (PREDICT_FALSE(!file.ReadU16(&flags))) {
|
||||
return FONT_COMPRESSION_FAILURE();
|
||||
}
|
||||
bool has_overlap_bitmap = (flags & FLAG_OVERLAP_SIMPLE_BITMAP);
|
||||
|
||||
if (PREDICT_FALSE(!file.ReadU16(&info->num_glyphs) ||
|
||||
!file.ReadU16(&info->index_format))) {
|
||||
return FONT_COMPRESSION_FAILURE();
|
||||
|
@ -436,6 +461,17 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
|
|||
Buffer bbox_stream(substreams[5].first, substreams[5].second);
|
||||
Buffer instruction_stream(substreams[6].first, substreams[6].second);
|
||||
|
||||
const uint8_t* overlap_bitmap = nullptr;
|
||||
unsigned int overlap_bitmap_length = 0;
|
||||
if (has_overlap_bitmap) {
|
||||
overlap_bitmap_length = (info->num_glyphs + 7) >> 3;
|
||||
overlap_bitmap = data + offset;
|
||||
if (PREDICT_FALSE(overlap_bitmap_length >
|
||||
glyf_table->transform_length - offset)) {
|
||||
return FONT_COMPRESSION_FAILURE();
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<uint32_t> loca_values(info->num_glyphs + 1);
|
||||
std::vector<unsigned int> n_points_vec;
|
||||
std::unique_ptr<Point[]> points;
|
||||
|
@ -589,8 +625,12 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
|
|||
}
|
||||
glyph_size += instruction_size;
|
||||
|
||||
if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
|
||||
instruction_size, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
|
||||
bool has_overlap_bit =
|
||||
has_overlap_bitmap && overlap_bitmap[i >> 3] & (0x80 >> (i & 7));
|
||||
|
||||
if (PREDICT_FALSE(!StorePoints(
|
||||
total_n_points, points.get(), n_contours, instruction_size,
|
||||
has_overlap_bit, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
|
||||
return FONT_COMPRESSION_FAILURE();
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -14,21 +14,21 @@
|
|||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::string;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "One argument, the input filename, must be provided.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
string filename(argv[1]);
|
||||
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
|
||||
std::string filename(argv[1]);
|
||||
std::string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
|
||||
|
||||
// Note: update woff2_dec_fuzzer_new_entry.cc if this pattern changes.
|
||||
string input = woff2::GetFileContent(filename);
|
||||
std::string input = woff2::GetFileContent(filename);
|
||||
const uint8_t* raw_input = reinterpret_cast<const uint8_t*>(input.data());
|
||||
string output(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
|
||||
woff2::kDefaultMaxSize), 0);
|
||||
std::string output(
|
||||
std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
|
||||
woff2::kDefaultMaxSize),
|
||||
0);
|
||||
woff2::WOFF2StringOut out(&output);
|
||||
|
||||
const bool ok = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out);
|
||||
|
|
|
@ -28,13 +28,9 @@
|
|||
|
||||
namespace woff2 {
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
|
||||
const size_t kWoff2HeaderSize = 48;
|
||||
const size_t kWoff2EntrySize = 20;
|
||||
|
||||
|
@ -183,7 +179,7 @@ size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length) {
|
|||
}
|
||||
|
||||
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length,
|
||||
const string& extended_metadata) {
|
||||
const std::string& extended_metadata) {
|
||||
// Except for the header size, which is 32 bytes larger in woff2 format,
|
||||
// all other parts should be smaller (table header in short format,
|
||||
// transformations and compression). Just to be sure, we will give some
|
||||
|
|
|
@ -29,18 +29,16 @@ std::string PrintTag(int tag) {
|
|||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
using std::string;
|
||||
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "One argument, the input filename, must be provided.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
string filename(argv[1]);
|
||||
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
|
||||
std::string filename(argv[1]);
|
||||
std::string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
|
||||
fprintf(stdout, "Processing %s => %s\n",
|
||||
filename.c_str(), outfilename.c_str());
|
||||
string input = woff2::GetFileContent(filename);
|
||||
std::string input = woff2::GetFileContent(filename);
|
||||
|
||||
woff2::Buffer file(reinterpret_cast<const uint8_t*>(input.data()),
|
||||
input.size());
|
||||
|
|
|
@ -8,14 +8,10 @@
|
|||
|
||||
#include <woff2/output.h>
|
||||
|
||||
using std::string;
|
||||
|
||||
namespace woff2 {
|
||||
|
||||
WOFF2StringOut::WOFF2StringOut(string* buf)
|
||||
: buf_(buf),
|
||||
max_size_(kDefaultMaxSize),
|
||||
offset_(0) {}
|
||||
WOFF2StringOut::WOFF2StringOut(std::string *buf)
|
||||
: buf_(buf), max_size_(kDefaultMaxSize), offset_(0) {}
|
||||
|
||||
bool WOFF2StringOut::Write(const void *buf, size_t n) {
|
||||
return Write(buf, offset_, n);
|
||||
|
|
Загрузка…
Ссылка в новой задаче