Skip to content
This repository was archived by the owner on Oct 30, 2022. It is now read-only.

Commit 4721483

Browse files
authored
Merge pull request google#149 from garretrieger/overlap_bit
Add woff2 encoder/decoder support for overlapSimpleBitmap.
2 parents a0d0ed7 + 62ae7a4 commit 4721483

File tree

12 files changed

+105
-59
lines changed

12 files changed

+105
-59
lines changed

include/woff2/encode.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ struct WOFF2Params {
2626

2727
// Returns an upper bound on the size of the compressed file.
2828
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length);
29-
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length,
30-
const std::string& extended_metadata);
29+
size_t MaxWOFF2CompressedSize(const uint8_t *data, size_t length,
30+
const std::string &extended_metadata);
3131

3232
// Compresses the font into the target buffer. *result_length should be at least
3333
// the value returned by MaxWOFF2CompressedSize(), upon return, it is set to the

include/woff2/output.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,15 @@ class WOFF2StringOut : public WOFF2Out {
5151
// Create a writer that writes its data to buf.
5252
// buf->size() will grow to at most max_size
5353
// buf may be sized (e.g. using EstimateWOFF2FinalSize) or empty.
54-
explicit WOFF2StringOut(std::string* buf);
54+
explicit WOFF2StringOut(std::string *buf);
5555

5656
bool Write(const void *buf, size_t n) override;
5757
bool Write(const void *buf, size_t offset, size_t n) override;
5858
size_t Size() override { return offset_; }
5959
size_t MaxSize() { return max_size_; }
6060
void SetMaxSize(size_t max_size);
6161
private:
62-
std::string* buf_;
62+
std::string *buf_;
6363
size_t max_size_;
6464
size_t offset_;
6565
};

src/file.h

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,18 +14,14 @@
1414

1515
namespace woff2 {
1616

17-
using std::string;
18-
19-
20-
inline string GetFileContent(string filename) {
17+
inline std::string GetFileContent(std::string filename) {
2118
std::ifstream ifs(filename.c_str(), std::ios::binary);
22-
return string(
23-
std::istreambuf_iterator<char>(ifs.rdbuf()),
24-
std::istreambuf_iterator<char>());
19+
return std::string(std::istreambuf_iterator<char>(ifs.rdbuf()),
20+
std::istreambuf_iterator<char>());
2521
}
2622

27-
inline void SetFileContents(string filename, string::iterator start,
28-
string::iterator end) {
23+
inline void SetFileContents(std::string filename, std::string::iterator start,
24+
std::string::iterator end) {
2925
std::ofstream ofs(filename.c_str(), std::ios::binary);
3026
std::copy(start, end, std::ostream_iterator<char>(ofs));
3127
}

src/glyph.cc

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ static const int32_t kFLAG_YSHORT = 1 << 2;
2121
static const int32_t kFLAG_REPEAT = 1 << 3;
2222
static const int32_t kFLAG_XREPEATSIGN = 1 << 4;
2323
static const int32_t kFLAG_YREPEATSIGN = 1 << 5;
24+
static const int32_t kFLAG_OVERLAP_SIMPLE = 1 << 6;
2425
static const int32_t kFLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
2526
static const int32_t kFLAG_WE_HAVE_A_SCALE = 1 << 3;
2627
static const int32_t kFLAG_MORE_COMPONENTS = 1 << 5;
@@ -134,6 +135,10 @@ bool ReadGlyph(const uint8_t* data, size_t len, Glyph* glyph) {
134135
}
135136
}
136137

138+
if (!flags.empty() && !flags[0].empty()) {
139+
glyph->overlap_simple_flag_set = (flags[0][0] & kFLAG_OVERLAP_SIMPLE);
140+
}
141+
137142
// Read the x coordinates.
138143
int prev_x = 0;
139144
for (int i = 0; i < num_contours; ++i) {
@@ -239,7 +244,7 @@ bool StoreEndPtsOfContours(const Glyph& glyph, size_t* offset, uint8_t* dst) {
239244

240245
bool StorePoints(const Glyph& glyph, size_t* offset,
241246
uint8_t* dst, size_t dst_size) {
242-
int last_flag = -1;
247+
int previous_flag = -1;
243248
int repeat_count = 0;
244249
int last_x = 0;
245250
int last_y = 0;
@@ -250,6 +255,10 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
250255
for (const auto& contour : glyph.contours) {
251256
for (const auto& point : contour) {
252257
int flag = point.on_curve ? kFLAG_ONCURVE : 0;
258+
if (previous_flag == -1 && glyph.overlap_simple_flag_set) {
259+
// First flag needs to have overlap simple bit set.
260+
flag = flag | kFLAG_OVERLAP_SIMPLE;
261+
}
253262
int dx = point.x - last_x;
254263
int dy = point.y - last_y;
255264
if (dx == 0) {
@@ -268,7 +277,7 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
268277
} else {
269278
y_bytes += 2;
270279
}
271-
if (flag == last_flag && repeat_count != 255) {
280+
if (flag == previous_flag && repeat_count != 255) {
272281
dst[*offset - 1] |= kFLAG_REPEAT;
273282
repeat_count++;
274283
} else {
@@ -286,7 +295,7 @@ bool StorePoints(const Glyph& glyph, size_t* offset,
286295
}
287296
last_x = point.x;
288297
last_y = point.y;
289-
last_flag = flag;
298+
previous_flag = flag;
290299
}
291300
}
292301
if (repeat_count != 0) {

src/glyph.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@
1010
#ifndef WOFF2_GLYPH_H_
1111
#define WOFF2_GLYPH_H_
1212

13-
#include <stddef.h>
1413
#include <inttypes.h>
14+
#include <stddef.h>
15+
16+
#include <cstdint>
1517
#include <vector>
1618

1719
namespace woff2 {
@@ -22,7 +24,10 @@ namespace woff2 {
2224
// is around.
2325
class Glyph {
2426
public:
25-
Glyph() : instructions_size(0), composite_data_size(0) {}
27+
Glyph()
28+
: instructions_size(0),
29+
overlap_simple_flag_set(false),
30+
composite_data_size(0) {}
2631

2732
// Bounding box.
2833
int16_t x_min;
@@ -34,6 +39,9 @@ class Glyph {
3439
uint16_t instructions_size;
3540
const uint8_t* instructions_data;
3641

42+
// Flags.
43+
bool overlap_simple_flag_set;
44+
3745
// Data model for simple glyphs.
3846
struct Point {
3947
int x;

src/transform.cc

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ namespace {
2222

2323
const int FLAG_ARG_1_AND_2_ARE_WORDS = 1 << 0;
2424
const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
25+
const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0;
2526

2627
void WriteBytes(std::vector<uint8_t>* out, const uint8_t* data, size_t len) {
2728
if (len == 0) return;
@@ -69,7 +70,10 @@ class GlyfEncoder {
6970
}
7071

7172
void GetTransformedGlyfBytes(std::vector<uint8_t>* result) {
72-
WriteLong(result, 0); // version
73+
WriteUShort(result, 0); // Version
74+
WriteUShort(result, overlap_bitmap_.empty()
75+
? 0x00
76+
: FLAG_OVERLAP_SIMPLE_BITMAP); // Flags
7377
WriteUShort(result, n_glyphs_);
7478
WriteUShort(result, 0); // index_format, will be set later
7579
WriteLong(result, n_contour_stream_.size());
@@ -87,6 +91,9 @@ class GlyfEncoder {
8791
WriteBytes(result, bbox_bitmap_);
8892
WriteBytes(result, bbox_stream_);
8993
WriteBytes(result, instruction_stream_);
94+
if (!overlap_bitmap_.empty()) {
95+
WriteBytes(result, overlap_bitmap_);
96+
}
9097
}
9198

9299
private:
@@ -127,6 +134,10 @@ class GlyfEncoder {
127134
}
128135

129136
void WriteSimpleGlyph(int glyph_id, const Glyph& glyph) {
137+
if (glyph.overlap_simple_flag_set) {
138+
EnsureOverlapBitmap();
139+
overlap_bitmap_[glyph_id >> 3] |= 0x80 >> (glyph_id & 7);
140+
}
130141
int num_contours = glyph.contours.size();
131142
WriteUShort(&n_contour_stream_, num_contours);
132143
if (ShouldWriteSimpleGlyphBbox(glyph)) {
@@ -214,6 +225,12 @@ class GlyfEncoder {
214225
}
215226
}
216227

228+
void EnsureOverlapBitmap() {
229+
if (overlap_bitmap_.empty()) {
230+
overlap_bitmap_.resize((n_glyphs_ + 7) >> 3);
231+
}
232+
}
233+
217234
std::vector<uint8_t> n_contour_stream_;
218235
std::vector<uint8_t> n_points_stream_;
219236
std::vector<uint8_t> flag_byte_stream_;
@@ -222,6 +239,7 @@ class GlyfEncoder {
222239
std::vector<uint8_t> bbox_stream_;
223240
std::vector<uint8_t> glyph_stream_;
224241
std::vector<uint8_t> instruction_stream_;
242+
std::vector<uint8_t> overlap_bitmap_;
225243
int n_glyphs_;
226244
};
227245

src/woff2_compress.cc

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,20 @@
1313

1414

1515
int main(int argc, char **argv) {
16-
using std::string;
17-
1816
if (argc != 2) {
1917
fprintf(stderr, "One argument, the input filename, must be provided.\n");
2018
return 1;
2119
}
2220

23-
string filename(argv[1]);
24-
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
21+
std::string filename(argv[1]);
22+
std::string outfilename = filename.substr(0, filename.find_last_of(".")) + ".woff2";
2523
fprintf(stdout, "Processing %s => %s\n",
2624
filename.c_str(), outfilename.c_str());
27-
string input = woff2::GetFileContent(filename);
25+
std::string input = woff2::GetFileContent(filename);
2826

2927
const uint8_t* input_data = reinterpret_cast<const uint8_t*>(input.data());
3028
size_t output_size = woff2::MaxWOFF2CompressedSize(input_data, input.size());
31-
string output(output_size, 0);
29+
std::string output(output_size, 0);
3230
uint8_t* output_data = reinterpret_cast<uint8_t*>(&output[0]);
3331

3432
woff2::WOFF2Params params;

src/woff2_dec.cc

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -32,17 +32,14 @@ namespace woff2 {
3232

3333
namespace {
3434

35-
using std::string;
36-
using std::vector;
37-
38-
3935
// simple glyph flags
4036
const int kGlyfOnCurve = 1 << 0;
4137
const int kGlyfXShort = 1 << 1;
4238
const int kGlyfYShort = 1 << 2;
4339
const int kGlyfRepeat = 1 << 3;
4440
const int kGlyfThisXIsSame = 1 << 4;
4541
const int kGlyfThisYIsSame = 1 << 5;
42+
const int kOverlapSimple = 1 << 6;
4643

4744
// composite glyph flags
4845
// See CompositeGlyph.java in sfntly for full definitions
@@ -53,6 +50,9 @@ const int FLAG_WE_HAVE_AN_X_AND_Y_SCALE = 1 << 6;
5350
const int FLAG_WE_HAVE_A_TWO_BY_TWO = 1 << 7;
5451
const int FLAG_WE_HAVE_INSTRUCTIONS = 1 << 8;
5552

53+
// glyf flags
54+
const int FLAG_OVERLAP_SIMPLE_BITMAP = 1 << 0;
55+
5656
const size_t kCheckSumAdjustmentOffset = 8;
5757

5858
const size_t kEndPtsOfContoursOffset = 10;
@@ -191,8 +191,9 @@ bool TripletDecode(const uint8_t* flags_in, const uint8_t* in, size_t in_size,
191191
// This function stores just the point data. On entry, dst points to the
192192
// beginning of a simple glyph. Returns true on success.
193193
bool StorePoints(unsigned int n_points, const Point* points,
194-
unsigned int n_contours, unsigned int instruction_length,
195-
uint8_t* dst, size_t dst_size, size_t* glyph_size) {
194+
unsigned int n_contours, unsigned int instruction_length,
195+
bool has_overlap_bit, uint8_t* dst, size_t dst_size,
196+
size_t* glyph_size) {
196197
// I believe that n_contours < 65536, in which case this is safe. However, a
197198
// comment and/or an assert would be good.
198199
unsigned int flag_offset = kEndPtsOfContoursOffset + 2 * n_contours + 2 +
@@ -207,6 +208,10 @@ bool StorePoints(unsigned int n_points, const Point* points,
207208
for (unsigned int i = 0; i < n_points; ++i) {
208209
const Point& point = points[i];
209210
int flag = point.on_curve ? kGlyfOnCurve : 0;
211+
if (has_overlap_bit && i == 0) {
212+
flag |= kOverlapSimple;
213+
}
214+
210215
int dx = point.x - last_x;
211216
int dy = point.y - last_y;
212217
if (dx == 0) {
@@ -404,13 +409,20 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
404409
WOFF2Out* out) {
405410
static const int kNumSubStreams = 7;
406411
Buffer file(data, glyf_table->transform_length);
407-
uint32_t version;
412+
uint16_t version;
408413
std::vector<std::pair<const uint8_t*, size_t> > substreams(kNumSubStreams);
409414
const size_t glyf_start = out->Size();
410415

411-
if (PREDICT_FALSE(!file.ReadU32(&version))) {
416+
if (PREDICT_FALSE(!file.ReadU16(&version))) {
417+
return FONT_COMPRESSION_FAILURE();
418+
}
419+
420+
uint16_t flags;
421+
if (PREDICT_FALSE(!file.ReadU16(&flags))) {
412422
return FONT_COMPRESSION_FAILURE();
413423
}
424+
bool has_overlap_bitmap = (flags & FLAG_OVERLAP_SIMPLE_BITMAP);
425+
414426
if (PREDICT_FALSE(!file.ReadU16(&info->num_glyphs) ||
415427
!file.ReadU16(&info->index_format))) {
416428
return FONT_COMPRESSION_FAILURE();
@@ -448,6 +460,17 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
448460
Buffer bbox_stream(substreams[5].first, substreams[5].second);
449461
Buffer instruction_stream(substreams[6].first, substreams[6].second);
450462

463+
const uint8_t* overlap_bitmap = nullptr;
464+
unsigned int overlap_bitmap_length = 0;
465+
if (has_overlap_bitmap) {
466+
overlap_bitmap_length = (info->num_glyphs + 7) >> 3;
467+
overlap_bitmap = data + offset;
468+
if (PREDICT_FALSE(overlap_bitmap_length >
469+
glyf_table->transform_length - offset)) {
470+
return FONT_COMPRESSION_FAILURE();
471+
}
472+
}
473+
451474
std::vector<uint32_t> loca_values(info->num_glyphs + 1);
452475
std::vector<unsigned int> n_points_vec;
453476
std::unique_ptr<Point[]> points;
@@ -601,8 +624,12 @@ bool ReconstructGlyf(const uint8_t* data, Table* glyf_table,
601624
}
602625
glyph_size += instruction_size;
603626

604-
if (PREDICT_FALSE(!StorePoints(total_n_points, points.get(), n_contours,
605-
instruction_size, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
627+
bool has_overlap_bit =
628+
has_overlap_bitmap && overlap_bitmap[i >> 3] & (0x80 >> (i & 7));
629+
630+
if (PREDICT_FALSE(!StorePoints(
631+
total_n_points, points.get(), n_contours, instruction_size,
632+
has_overlap_bit, glyph_buf.get(), glyph_buf_size, &glyph_size))) {
606633
return FONT_COMPRESSION_FAILURE();
607634
}
608635
} else {

src/woff2_decompress.cc

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -14,21 +14,21 @@
1414

1515

1616
int main(int argc, char **argv) {
17-
using std::string;
18-
1917
if (argc != 2) {
2018
fprintf(stderr, "One argument, the input filename, must be provided.\n");
2119
return 1;
2220
}
2321

24-
string filename(argv[1]);
25-
string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
22+
std::string filename(argv[1]);
23+
std::string outfilename = filename.substr(0, filename.find_last_of(".")) + ".ttf";
2624

2725
// Note: update woff2_dec_fuzzer_new_entry.cc if this pattern changes.
28-
string input = woff2::GetFileContent(filename);
26+
std::string input = woff2::GetFileContent(filename);
2927
const uint8_t* raw_input = reinterpret_cast<const uint8_t*>(input.data());
30-
string output(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
31-
woff2::kDefaultMaxSize), 0);
28+
std::string output(
29+
std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()),
30+
woff2::kDefaultMaxSize),
31+
0);
3232
woff2::WOFF2StringOut out(&output);
3333

3434
const bool ok = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out);

src/woff2_enc.cc

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,8 @@
2828

2929
namespace woff2 {
3030

31-
namespace {
32-
33-
34-
using std::string;
35-
using std::vector;
3631

32+
namespace {
3733

3834
const size_t kWoff2HeaderSize = 48;
3935
const size_t kWoff2EntrySize = 20;
@@ -183,7 +179,7 @@ size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length) {
183179
}
184180

185181
size_t MaxWOFF2CompressedSize(const uint8_t* data, size_t length,
186-
const string& extended_metadata) {
182+
const std::string& extended_metadata) {
187183
// Except for the header size, which is 32 bytes larger in woff2 format,
188184
// all other parts should be smaller (table header in short format,
189185
// transformations and compression). Just to be sure, we will give some

0 commit comments

Comments
 (0)