From 3082d05f8014ef60c40171527ef502b848e9cf64 Mon Sep 17 00:00:00 2001 From: Jon Meow <46229924+jonmeow@users.noreply.github.com> Date: Fri, 9 Jul 2021 11:29:38 -0700 Subject: [PATCH] Handle var initialization. (#628) --- migrate_cpp/cpp_refactoring/var_decl.cpp | 16 +- migrate_cpp/cpp_refactoring/var_decl_test.cpp | 71 +++- .../woff2/carbon/include/woff2/output.carbon | 2 +- .../src/convert_woff2ttf_fuzzer.impl.carbon | 2 +- ...vert_woff2ttf_fuzzer_new_entry.impl.carbon | 5 +- .../examples/woff2/carbon/src/file.carbon | 4 +- .../woff2/carbon/src/font.impl.carbon | 81 +++-- .../woff2/carbon/src/glyph.impl.carbon | 102 +++--- .../woff2/carbon/src/normalize.impl.carbon | 71 ++-- .../woff2/carbon/src/table_tags.carbon | 16 +- .../woff2/carbon/src/table_tags.impl.carbon | 66 +++- .../woff2/carbon/src/transform.impl.carbon | 94 ++--- .../carbon/src/variable_length.impl.carbon | 32 +- .../woff2/carbon/src/woff2_common.carbon | 10 +- .../woff2/carbon/src/woff2_common.impl.carbon | 14 +- .../carbon/src/woff2_compress.impl.carbon | 14 +- .../woff2/carbon/src/woff2_dec.impl.carbon | 341 +++++++++--------- .../carbon/src/woff2_decompress.impl.carbon | 15 +- .../woff2/carbon/src/woff2_enc.impl.carbon | 91 ++--- .../woff2/carbon/src/woff2_info.impl.carbon | 26 +- 20 files changed, 605 insertions(+), 468 deletions(-) diff --git a/migrate_cpp/cpp_refactoring/var_decl.cpp b/migrate_cpp/cpp_refactoring/var_decl.cpp index f0d9d802c287..5911c2a2a9ea 100644 --- a/migrate_cpp/cpp_refactoring/var_decl.cpp +++ b/migrate_cpp/cpp_refactoring/var_decl.cpp @@ -116,11 +116,19 @@ void VarDecl::Run() { type_loc.getEndLoc(), 0, GetSourceManager(), GetLangOpts()); llvm::StringRef comma_source_text = GetSourceText( clang::CharSourceRange::getCharRange(after_type_loc, decl.getLocation())); - bool has_comma = !comma_source_text.trim().empty(); - clang::CharSourceRange replace_range = clang::CharSourceRange::getTokenRange( - has_comma ? decl.getLocation() : decl.getBeginLoc(), decl.getEndLoc()); + clang::SourceLocation replace_start = !comma_source_text.trim().empty() + ? decl.getLocation() + : decl.getBeginLoc(); - AddReplacement(replace_range, after); + // Figure out where the replacement ends and initialization begins. For + // example, `int i` the end is the identifier, `int i[4]` the end is the `[4]` + // type qualifier. + clang::SourceLocation identifier_end = clang::Lexer::getLocForEndOfToken( + decl.getLocation(), 0, GetSourceManager(), GetLangOpts()); + clang::SourceLocation replace_end = std::max(identifier_end, after_type_loc); + + AddReplacement( + clang::CharSourceRange::getCharRange(replace_start, replace_end), after); } auto VarDeclFactory::GetAstMatcher() -> cam::DeclarationMatcher { diff --git a/migrate_cpp/cpp_refactoring/var_decl_test.cpp b/migrate_cpp/cpp_refactoring/var_decl_test.cpp index a40091c36743..8482cc2e1dad 100644 --- a/migrate_cpp/cpp_refactoring/var_decl_test.cpp +++ b/migrate_cpp/cpp_refactoring/var_decl_test.cpp @@ -25,12 +25,11 @@ TEST_F(VarDeclTest, DeclarationArray) { TEST_F(VarDeclTest, DeclarationConstArray) { constexpr char Before[] = "const int i[] = {0, 1};"; - constexpr char After[] = "let i: const int[];"; + constexpr char After[] = "let i: const int[] = {0, 1};"; ExpectReplacement(Before, After); } TEST_F(VarDeclTest, DeclarationConstPointer) { - // TODO: Include init. // TODO: Fix j replacement location. constexpr char Before[] = R"cpp( int i = 0; @@ -38,9 +37,9 @@ TEST_F(VarDeclTest, DeclarationConstPointer) { const int* k = &i; )cpp"; constexpr char After[] = R"( - var i: int; - int* const let j: int* const; - var k: const int*; + var i: int = 0; + int* const let j: int* const = &i; + var k: const int* = &i; )"; ExpectReplacement(Before, After); } @@ -52,6 +51,13 @@ TEST_F(VarDeclTest, DeclarationComma) { ExpectReplacement(Before, After); } +TEST_F(VarDeclTest, DeclarationCommaAssignment) { + // TODO: Maybe replace the comma with a `;`. + constexpr char Before[] = "int i = 0, j = 0;"; + constexpr char After[] = "var i: int = 0, var j: int = 0;"; + ExpectReplacement(Before, After); +} + TEST_F(VarDeclTest, DeclarationCommaArray) { // TODO: Maybe replace the comma with a `;`. // TODO: Need to handle j's array. @@ -60,6 +66,14 @@ TEST_F(VarDeclTest, DeclarationCommaArray) { ExpectReplacement(Before, After); } +TEST_F(VarDeclTest, DeclarationCommaArrayAssignment) { + // TODO: Maybe replace the comma with a `;`. + // TODO: Need to handle j's array. + constexpr char Before[] = "int i[] = {0}, j[] = {1};"; + constexpr char After[] = "var i: int[] = {0}, j[] = {1};"; + ExpectReplacement(Before, After); +} + TEST_F(VarDeclTest, DeclarationCommaPointers) { // TODO: Maybe replace the comma with a `;`. // TODO: Need to handle j's pointer. @@ -69,36 +83,42 @@ TEST_F(VarDeclTest, DeclarationCommaPointers) { ExpectReplacement(Before, After); } +TEST_F(VarDeclTest, DeclarationCommaPointersAssignment) { + // TODO: Maybe replace the comma with a `;`. + // TODO: Need to handle j's pointer. + // constexpr char After[] = "var i: int *, var j: int *;"; + constexpr char Before[] = "int *i = nullptr, *j = i;"; + constexpr char After[] = "var i: int* = nullptr, *j = i;"; + ExpectReplacement(Before, After); +} + TEST_F(VarDeclTest, Assignment) { constexpr char Before[] = "int i = 0;"; - // TODO: Include init. - constexpr char After[] = "var i: int;"; + constexpr char After[] = "var i: int = 0;"; ExpectReplacement(Before, After); } TEST_F(VarDeclTest, Auto) { constexpr char Before[] = "auto i = 0;"; - constexpr char After[] = "var i: auto;"; + constexpr char After[] = "var i: auto = 0;"; ExpectReplacement(Before, After); } TEST_F(VarDeclTest, AutoRef) { - // TODO: Include init. constexpr char Before[] = R"cpp( auto i = 0; const auto& j = i; )cpp"; constexpr char After[] = R"( - var i: auto; - var j: const auto&; + var i: auto = 0; + var j: const auto& = i; )"; ExpectReplacement(Before, After); } TEST_F(VarDeclTest, Const) { - // TODO: Include init. constexpr char Before[] = "const int i = 0;"; - constexpr char After[] = "let i: const int;"; + constexpr char After[] = "let i: const int = 0;"; ExpectReplacement(Before, After); } @@ -132,9 +152,8 @@ TEST_F(VarDeclTest, Params) { } TEST_F(VarDeclTest, ParamsDefault) { - // TODO: Include init. constexpr char Before[] = "auto Foo(int i = 0) -> int;"; - constexpr char After[] = "auto Foo(i: int) -> int;"; + constexpr char After[] = "auto Foo(i: int = 0) -> int;"; ExpectReplacement(Before, After); } @@ -172,6 +191,26 @@ TEST_F(VarDeclTest, Member) { ExpectReplacement(Before, Before); } +TEST_F(VarDeclTest, Constructor) { + constexpr char Before[] = R"cpp( + struct Index { + Index(int i) : i(i) {} + + int i; + }; + Index x(0); + )cpp"; + constexpr char After[] = R"( + struct Index { + Index(i: int) : i(i) {} + + int i; + }; + var x: Index(0); + )"; + ExpectReplacement(Before, After); +} + TEST_F(VarDeclTest, RangeFor) { constexpr char Before[] = R"cpp( void Foo() { @@ -183,7 +222,7 @@ TEST_F(VarDeclTest, RangeFor) { )cpp"; constexpr char After[] = R"( void Foo() { - var items: int[]; + var items: int[] = {1}; for (int i : items) { var j: int; } diff --git a/third_party/examples/woff2/carbon/include/woff2/output.carbon b/third_party/examples/woff2/carbon/include/woff2/output.carbon index f83fdcc6541a..b2852d667e31 100644 --- a/third_party/examples/woff2/carbon/include/woff2/output.carbon +++ b/third_party/examples/woff2/carbon/include/woff2/output.carbon @@ -17,7 +17,7 @@ namespace woff2 { // Suggested max size for output. -let kDefaultMaxSize: const size_t; +let kDefaultMaxSize: const size_t = 30 * 1024 * 1024; /** * Output interface for the woff2 decoding. diff --git a/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer.impl.carbon b/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer.impl.carbon index 93f80ec0cc1d..696edf9f407a 100644 --- a/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer.impl.carbon +++ b/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer.impl.carbon @@ -6,7 +6,7 @@ // Entry point for LibFuzzer. extern "C" fn LLVMFuzzerTestOneInput(data: const uint8_t*, size: size_t) -> int { var buf: std::string; - var out: woff2::WOFF2StringOut; + var out: woff2::WOFF2StringOut(&buf); out.SetMaxSize(30 * 1024 * 1024); woff2::ConvertWOFF2ToTTF(data, size, &out); return 0; diff --git a/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer_new_entry.impl.carbon b/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer_new_entry.impl.carbon index 01ac2c97683d..65114d0bf20c 100644 --- a/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer_new_entry.impl.carbon +++ b/third_party/examples/woff2/carbon/src/convert_woff2ttf_fuzzer_new_entry.impl.carbon @@ -4,8 +4,9 @@ extern "C" fn LLVMFuzzerTestOneInput(data: const uint8_t*, data_size: size_t) -> int { // Decode using newer entry pattern. // Same pattern as woff2_decompress. - var output: std::string; - var out: woff2::WOFF2StringOut; + var output: std::string(std::min(woff2::ComputeWOFF2FinalSize(data, data_size), + woff2::kDefaultMaxSize), 0); + var out: woff2::WOFF2StringOut(&output); woff2::ConvertWOFF2ToTTF(data, data_size, &out); return 0; } diff --git a/third_party/examples/woff2/carbon/src/file.carbon b/third_party/examples/woff2/carbon/src/file.carbon index cffe1e8cf347..bebf76b2b493 100644 --- a/third_party/examples/woff2/carbon/src/file.carbon +++ b/third_party/examples/woff2/carbon/src/file.carbon @@ -18,7 +18,7 @@ using std::string; fn inline GetFileContent(filename: const string&) -> string { - var ifs: std::ifstream; + var ifs: std::ifstream(filename.c_str(), std::ios::binary); return string( std::istreambuf_iterator(ifs.rdbuf()), std::istreambuf_iterator()); @@ -26,7 +26,7 @@ fn inline GetFileContent(filename: const string&) -> string { fn inline SetFileContents(filename: const string&, start: string::iterator, end: string::iterator) { - var ofs: std::ofstream; + var ofs: std::ofstream(filename.c_str(), std::ios::binary); std::copy(start, end, std::ostream_iterator(ofs)); } diff --git a/third_party/examples/woff2/carbon/src/font.impl.carbon b/third_party/examples/woff2/carbon/src/font.impl.carbon index fbe15c0c5cfd..6f89d54b1363 100644 --- a/third_party/examples/woff2/carbon/src/font.impl.carbon +++ b/third_party/examples/woff2/carbon/src/font.impl.carbon @@ -19,12 +19,12 @@ namespace woff2 { fn Font::FindTable(tag: uint32_t) -> Font::Table* { - var it: auto; + var it: auto = tables.find(tag); return it == tables.end() ? nullptr : &it->second; } fn Font::FindTable(tag: uint32_t) const -> const Font::Table* { - var it: auto; + var it: auto = tables.find(tag); return it == tables.end() ? nullptr : &it->second; } @@ -32,7 +32,7 @@ fn Font::OutputOrderedTags() const -> std::vector { var output_order: std::vector; for (const auto& i : tables) { - var table: const Font::Table&; + var table: const Font::Table& = i.second; // This is a transformed table, we will write it together with the // original version. if (table.tag & 0x80808080) { @@ -42,8 +42,10 @@ fn Font::OutputOrderedTags() const -> std::vector { } // Alphabetize then put loca immediately after glyf - var glyf_loc: auto; - var loca_loc: auto; + var glyf_loc: auto = std::find(output_order.begin(), output_order.end(), + kGlyfTableTag); + var loca_loc: auto = std::find(output_order.begin(), output_order.end(), + kLocaTableTag); if (glyf_loc != output_order.end() && loca_loc != output_order.end()) { output_order.erase(loca_loc); output_order.insert(std::find(output_order.begin(), output_order.end(), @@ -63,7 +65,7 @@ fn ReadTrueTypeFont(file: Buffer*, data: const uint8_t*, len: size_t, } var intervals: std::map; - for (var i: uint16_t; i < font->num_tables; ++i) { + for (var i: uint16_t = 0; i < font->num_tables; ++i) { var table: Font::Table; table.flag_byte = 0; table.reuse_of = nullptr; @@ -87,7 +89,7 @@ fn ReadTrueTypeFont(file: Buffer*, data: const uint8_t*, len: size_t, } // Check that tables are non-overlapping. - var last_offset: uint32_t; + var last_offset: uint32_t = 12UL + 16UL * font->num_tables; for (const auto& i : intervals) { if (i.first < last_offset || i.first + i.second < i.first) { return FONT_COMPRESSION_FAILURE(); @@ -96,7 +98,7 @@ fn ReadTrueTypeFont(file: Buffer*, data: const uint8_t*, len: size_t, } // Sanity check key tables - var head_table: const Font::Table*; + var head_table: const Font::Table* = font->FindTable(kHeadTableTag); if (head_table != nullptr && head_table->length < 52) { return FONT_COMPRESSION_FAILURE(); } @@ -115,7 +117,7 @@ fn ReadCollectionFont(file: Buffer*, data: const uint8_t*, len: size_t, } for (auto& entry : font->tables) { - var table: Font::Table&; + var table: Font::Table& = entry.second; if (all_tables->find(table.offset) == all_tables->end()) { (*all_tables)[table.offset] = font->FindTable(table.tag); @@ -140,7 +142,7 @@ fn ReadTrueTypeCollection(file: Buffer*, data: const uint8_t*, len: size_t, } var offsets: std::vector; - for (var i: size_t; i < num_fonts; i++) { + for (var i: size_t = 0; i < num_fonts; i++) { var offset: uint32_t; if (!file->ReadU32(&offset)) { return FONT_COMPRESSION_FAILURE(); @@ -149,12 +151,12 @@ fn ReadTrueTypeCollection(file: Buffer*, data: const uint8_t*, len: size_t, } font_collection->fonts.resize(offsets.size()); - var font_it: auto; + var font_it: auto = font_collection->fonts.begin(); var all_tables: std::map; for (const auto offset : offsets) { file->set_offset(offset); - var font: Font&; + var font: Font& = *font_it++; if (!ReadCollectionFont(file, data, len, &font, &all_tables)) { return FONT_COMPRESSION_FAILURE(); } @@ -164,7 +166,7 @@ fn ReadTrueTypeCollection(file: Buffer*, data: const uint8_t*, len: size_t, } fn ReadFont(data: const uint8_t*, len: size_t, font: Font*) -> bool { - var file: Buffer; + var file: Buffer(data, len); if (!file.ReadU32(&font->flavor)) { return FONT_COMPRESSION_FAILURE(); @@ -178,7 +180,7 @@ fn ReadFont(data: const uint8_t*, len: size_t, font: Font*) -> bool { fn ReadFontCollection(data: const uint8_t*, len: size_t, font_collection: FontCollection*) -> bool { - var file: Buffer; + var file: Buffer(data, len); if (!file.ReadU32(&font_collection->flavor)) { return FONT_COMPRESSION_FAILURE(); @@ -186,7 +188,7 @@ fn ReadFontCollection(data: const uint8_t*, len: size_t, if (font_collection->flavor != kTtcFontFlavor) { font_collection->fonts.resize(1); - var font: Font&; + var font: Font& = font_collection->fonts[0]; font.flavor = font_collection->flavor; return ReadTrueTypeFont(&file, data, len, &font); } @@ -194,18 +196,18 @@ fn ReadFontCollection(data: const uint8_t*, len: size_t, } fn FontFileSize(font: const Font&) -> size_t { - var max_offset: size_t; + var max_offset: size_t = 12ULL + 16ULL * font.num_tables; for (const auto& i : font.tables) { - var table: const Font::Table&; - var padding_size: size_t; - var end_offset: size_t; + var table: const Font::Table& = i.second; + var padding_size: size_t = (4 - (table.length & 3)) & 3; + var end_offset: size_t = (padding_size + table.offset) + table.length; max_offset = std::max(max_offset, end_offset); } return max_offset; } fn FontCollectionFileSize(font_collection: const FontCollection&) -> size_t { - var max_offset: size_t; + var max_offset: size_t = 0; for (auto& font : font_collection.fonts) { // font file size actually just finds max offset max_offset = std::max(max_offset, FontFileSize(font)); @@ -214,7 +216,7 @@ fn FontCollectionFileSize(font_collection: const FontCollection&) -> size_t { } fn WriteFont(font: const Font&, dst: uint8_t*, dst_size: size_t) -> bool { - var offset: size_t; + var offset: size_t = 0; return WriteFont(font, &offset, dst, dst_size); } @@ -246,7 +248,7 @@ fn WriteTable(table: const Font::Table&, offset: size_t*, dst: uint8_t*, return FONT_COMPRESSION_FAILURE(); } memcpy(dst + table.offset, table.data, table.length); - var padding_size: size_t; + var padding_size: size_t = (4 - (table.length & 3)) & 3; if (table.offset + table.length + padding_size < padding_size || dst_size < table.offset + table.length + padding_size) { return FONT_COMPRESSION_FAILURE(); @@ -263,9 +265,9 @@ fn WriteFont(font: const Font&, offset: size_t*, dst: uint8_t*, } StoreU32(font.flavor, offset, dst); Store16(font.num_tables, offset, dst); - var max_pow2: uint16_t; - var search_range: uint16_t; - var range_shift: uint16_t; + var max_pow2: uint16_t = font.num_tables ? Log2Floor(font.num_tables) : 0; + var search_range: uint16_t = max_pow2 ? 1 << (max_pow2 + 4) : 0; + var range_shift: uint16_t = (font.num_tables << 4) - search_range; Store16(search_range, offset, dst); Store16(max_pow2, offset, dst); Store16(range_shift, offset, dst); @@ -281,7 +283,7 @@ fn WriteFont(font: const Font&, offset: size_t*, dst: uint8_t*, fn WriteFontCollection(font_collection: const FontCollection&, dst: uint8_t*, dst_size: size_t) -> bool { - var offset: size_t; + var offset: size_t = 0; // It's simpler if this just a simple sfnt if (font_collection.flavor != kTtcFontFlavor) { @@ -294,8 +296,8 @@ fn WriteFontCollection(font_collection: const FontCollection&, dst: uint8_t*, StoreU32(font_collection.fonts.size(), &offset, dst); // Offset Table, zeroed for now - var offset_table: size_t; // where to write offsets later - for (var i: size_t; i < font_collection.fonts.size(); i++) { + var offset_table: size_t = offset; // where to write offsets later + for (var i: size_t = 0; i < font_collection.fonts.size(); i++) { StoreU32(0, &offset, dst); } @@ -317,13 +319,13 @@ fn WriteFontCollection(font_collection: const FontCollection&, dst: uint8_t*, } fn NumGlyphs(font: const Font&) -> int { - var head_table: const Font::Table*; - var loca_table: const Font::Table*; + var head_table: const Font::Table* = font.FindTable(kHeadTableTag); + var loca_table: const Font::Table* = font.FindTable(kLocaTableTag); if (head_table == nullptr || loca_table == nullptr || head_table->length < 52) { return 0; } - var index_fmt: int; - var loca_record_size: int; + var index_fmt: int = IndexFormat(font); + var loca_record_size: int = (index_fmt == 0 ? 2 : 4); if (loca_table->length < loca_record_size) { return 0; } @@ -331,7 +333,7 @@ fn NumGlyphs(font: const Font&) -> int { } fn IndexFormat(font: const Font&) -> int { - var head_table: const Font::Table*; + var head_table: const Font::Table* = font.FindTable(kHeadTableTag); if (head_table == nullptr) { return 0; } @@ -347,17 +349,17 @@ fn GetGlyphData(font: const Font&, glyph_index: int, if (glyph_index < 0) { return FONT_COMPRESSION_FAILURE(); } - var head_table: const Font::Table*; - var loca_table: const Font::Table*; - var glyf_table: const Font::Table*; + var head_table: const Font::Table* = font.FindTable(kHeadTableTag); + var loca_table: const Font::Table* = font.FindTable(kLocaTableTag); + var glyf_table: const Font::Table* = font.FindTable(kGlyfTableTag); if (head_table == nullptr || loca_table == nullptr || glyf_table == nullptr || head_table->length < 52) { return FONT_COMPRESSION_FAILURE(); } - var index_fmt: int; + var index_fmt: int = IndexFormat(font); - var loca_buf: Buffer; + var loca_buf: Buffer(loca_table->data, loca_table->length); if (index_fmt == 0) { var offset1: uint16_t, var offset2: uint16_t; if (!loca_buf.Skip(2 * glyph_index) || @@ -385,7 +387,8 @@ fn GetGlyphData(font: const Font&, glyph_index: int, } fn RemoveDigitalSignature(font: Font*) -> bool { - var it: auto; + var it: auto = + font->tables.find(kDsigTableTag); if (it != font->tables.end()) { font->tables.erase(it); font->num_tables = font->tables.size(); diff --git a/third_party/examples/woff2/carbon/src/glyph.impl.carbon b/third_party/examples/woff2/carbon/src/glyph.impl.carbon index 7ceda640b569..17bf3eb0a08b 100644 --- a/third_party/examples/woff2/carbon/src/glyph.impl.carbon +++ b/third_party/examples/woff2/carbon/src/glyph.impl.carbon @@ -15,30 +15,30 @@ namespace woff2 { -let kFLAG_ONCURVE: const int32_t; -let kFLAG_XSHORT: const int32_t; -let kFLAG_YSHORT: const int32_t; -let kFLAG_REPEAT: const int32_t; -let kFLAG_XREPEATSIGN: const int32_t; -let kFLAG_YREPEATSIGN: const int32_t; -let kFLAG_ARG_1_AND_2_ARE_WORDS: const int32_t; -let kFLAG_WE_HAVE_A_SCALE: const int32_t; -let kFLAG_MORE_COMPONENTS: const int32_t; -let kFLAG_WE_HAVE_AN_X_AND_Y_SCALE: const int32_t; -let kFLAG_WE_HAVE_A_TWO_BY_TWO: const int32_t; -let kFLAG_WE_HAVE_INSTRUCTIONS: const int32_t; +let kFLAG_ONCURVE: const int32_t = 1; +let kFLAG_XSHORT: const int32_t = 1 << 1; +let kFLAG_YSHORT: const int32_t = 1 << 2; +let kFLAG_REPEAT: const int32_t = 1 << 3; +let kFLAG_XREPEATSIGN: const int32_t = 1 << 4; +let kFLAG_YREPEATSIGN: const int32_t = 1 << 5; +let kFLAG_ARG_1_AND_2_ARE_WORDS: const int32_t = 1 << 0; +let kFLAG_WE_HAVE_A_SCALE: const int32_t = 1 << 3; +let kFLAG_MORE_COMPONENTS: const int32_t = 1 << 5; +let kFLAG_WE_HAVE_AN_X_AND_Y_SCALE: const int32_t = 1 << 6; +let kFLAG_WE_HAVE_A_TWO_BY_TWO: const int32_t = 1 << 7; +let kFLAG_WE_HAVE_INSTRUCTIONS: const int32_t = 1 << 8; fn ReadCompositeGlyphData(buffer: Buffer*, glyph: Glyph*) -> bool { glyph->have_instructions = false; glyph->composite_data = buffer->buffer() + buffer->offset(); - var start_offset: size_t; - var flags: uint16_t; + var start_offset: size_t = buffer->offset(); + var flags: uint16_t = kFLAG_MORE_COMPONENTS; while (flags & kFLAG_MORE_COMPONENTS) { if (!buffer->ReadU16(&flags)) { return FONT_COMPRESSION_FAILURE(); } glyph->have_instructions |= (flags & kFLAG_WE_HAVE_INSTRUCTIONS) != 0; - var arg_size: size_t; // glyph index + var arg_size: size_t = 2; // glyph index if (flags & kFLAG_ARG_1_AND_2_ARE_WORDS) { arg_size += 4; } else { @@ -63,7 +63,7 @@ fn ReadCompositeGlyphData(buffer: Buffer*, glyph: Glyph*) -> bool { } fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool { - var buffer: Buffer; + var buffer: Buffer(data, len); var num_contours: int16_t; if (!buffer.ReadS16(&num_contours)) { @@ -88,13 +88,13 @@ fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool { glyph->contours.resize(num_contours); // Read the number of points per contour. - var last_point_index: uint16_t; - for (var i: int; i < num_contours; ++i) { + var last_point_index: uint16_t = 0; + for (var i: int = 0; i < num_contours; ++i) { var point_index: uint16_t; if (!buffer.ReadU16(&point_index)) { return FONT_COMPRESSION_FAILURE(); } - var num_points: uint16_t; + var num_points: uint16_t = point_index - last_point_index + (i == 0 ? 1 : 0); glyph->contours[i].resize(num_points); last_point_index = point_index; } @@ -109,13 +109,13 @@ fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool { } // Read the run-length coded flags. - var flags: std::vector >; + var flags: std::vector >(num_contours); { - var flag: uint8_t; - var flag_repeat: uint8_t; - for (var i: int; i < num_contours; ++i) { + var flag: uint8_t = 0; + var flag_repeat: uint8_t = 0; + for (var i: int = 0; i < num_contours; ++i) { flags[i].resize(glyph->contours[i].size()); - for (var j: size_t; j < glyph->contours[i].size(); ++j) { + for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) { if (flag_repeat == 0) { if (!buffer.ReadU8(&flag)) { return FONT_COMPRESSION_FAILURE(); @@ -135,21 +135,21 @@ fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool { } // Read the x coordinates. - var prev_x: int; - for (var i: int; i < num_contours; ++i) { - for (var j: size_t; j < glyph->contours[i].size(); ++j) { - var flag: uint8_t; + var prev_x: int = 0; + for (var i: int = 0; i < num_contours; ++i) { + for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) { + var flag: uint8_t = flags[i][j]; if (flag & kFLAG_XSHORT) { // single byte x-delta coord value var x_delta: uint8_t; if (!buffer.ReadU8(&x_delta)) { return FONT_COMPRESSION_FAILURE(); } - var sign: int; + var sign: int = (flag & kFLAG_XREPEATSIGN) ? 1 : -1; glyph->contours[i][j].x = prev_x + sign * x_delta; } else { // double byte x-delta coord value - var x_delta: int16_t; + var x_delta: int16_t = 0; if (!(flag & kFLAG_XREPEATSIGN)) { if (!buffer.ReadS16(&x_delta)) { return FONT_COMPRESSION_FAILURE(); @@ -162,21 +162,21 @@ fn ReadGlyph(data: const uint8_t*, len: size_t, glyph: Glyph*) -> bool { } // Read the y coordinates. - var prev_y: int; - for (var i: int; i < num_contours; ++i) { - for (var j: size_t; j < glyph->contours[i].size(); ++j) { - var flag: uint8_t; + var prev_y: int = 0; + for (var i: int = 0; i < num_contours; ++i) { + for (var j: size_t = 0; j < glyph->contours[i].size(); ++j) { + var flag: uint8_t = flags[i][j]; if (flag & kFLAG_YSHORT) { // single byte y-delta coord value var y_delta: uint8_t; if (!buffer.ReadU8(&y_delta)) { return FONT_COMPRESSION_FAILURE(); } - var sign: int; + var sign: int = (flag & kFLAG_YREPEATSIGN) ? 1 : -1; glyph->contours[i][j].y = prev_y + sign * y_delta; } else { // double byte y-delta coord value - var y_delta: int16_t; + var y_delta: int16_t = 0; if (!(flag & kFLAG_YREPEATSIGN)) { if (!buffer.ReadS16(&y_delta)) { return FONT_COMPRESSION_FAILURE(); @@ -225,7 +225,7 @@ fn StoreInstructions(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) { } fn StoreEndPtsOfContours(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) -> bool { - var end_point: int; + var end_point: int = -1; for (const auto& contour : glyph.contours) { end_point += contour.size(); if (contour.size() > std::numeric_limits::max() || @@ -239,19 +239,19 @@ fn StoreEndPtsOfContours(glyph: const Glyph&, offset: size_t*, dst: uint8_t*) -> fn StorePoints(glyph: const Glyph&, offset: size_t*, dst: uint8_t*, dst_size: size_t) -> bool { - var last_flag: int; - var repeat_count: int; - var last_x: int; - var last_y: int; - var x_bytes: size_t; - var y_bytes: size_t; + var last_flag: int = -1; + var repeat_count: int = 0; + var last_x: int = 0; + var last_y: int = 0; + var x_bytes: size_t = 0; + var y_bytes: size_t = 0; // Store the flags and calculate the total size of the x and y coordinates. for (const auto& contour : glyph.contours) { for (const auto& point : contour) { - var flag: int; - var dx: int; - var dy: int; + var flag: int = point.on_curve ? kFLAG_ONCURVE : 0; + var dx: int = point.x - last_x; + var dy: int = point.y - last_y; if (dx == 0) { flag |= kFLAG_XREPEATSIGN; } else if (dx > -256 && dx < 256) { @@ -301,14 +301,14 @@ fn StorePoints(glyph: const Glyph&, offset: size_t*, } // Store the x and y coordinates. - var x_offset: size_t; - var y_offset: size_t; + var x_offset: size_t = *offset; + var y_offset: size_t = *offset + x_bytes; last_x = 0; last_y = 0; for (const auto& contour : glyph.contours) { for (const auto& point : contour) { - var dx: int; - var dy: int; + var dx: int = point.x - last_x; + var dy: int = point.y - last_y; if (dx == 0) { // pass } else if (dx > -256 && dx < 256) { @@ -334,7 +334,7 @@ fn StorePoints(glyph: const Glyph&, offset: size_t*, } // namespace fn StoreGlyph(glyph: const Glyph&, dst: uint8_t*, dst_size: size_t*) -> bool { - var offset: size_t; + var offset: size_t = 0; if (glyph.composite_data_size > 0) { // Composite glyph. if (*dst_size < ((10ULL + glyph.composite_data_size) + diff --git a/third_party/examples/woff2/carbon/src/normalize.impl.carbon b/third_party/examples/woff2/carbon/src/normalize.impl.carbon index b0a88bd4dfe4..8ff5cd01d45e 100644 --- a/third_party/examples/woff2/carbon/src/normalize.impl.carbon +++ b/third_party/examples/woff2/carbon/src/normalize.impl.carbon @@ -37,19 +37,19 @@ fn StoreLoca(index_fmt: int, value: uint32_t, offset: size_t*, dst: uint8_t*) { namespace { fn WriteNormalizedLoca(index_fmt: int, num_glyphs: int, font: Font*) -> bool { - var glyf_table: Font::Table*; - var loca_table: Font::Table*; + var glyf_table: Font::Table* = font->FindTable(kGlyfTableTag); + var loca_table: Font::Table* = font->FindTable(kLocaTableTag); - var glyph_sz: int; + var glyph_sz: int = index_fmt == 0 ? 2 : 4; loca_table->buffer.resize(Round4(num_glyphs + 1) * glyph_sz); loca_table->length = (num_glyphs + 1) * glyph_sz; - var glyf_dst: uint8_t*; - var loca_dst: uint8_t*; - var glyf_offset: uint32_t; - var loca_offset: size_t; + var glyf_dst: uint8_t* = num_glyphs ? &glyf_table->buffer[0] : nullptr; + var loca_dst: uint8_t* = &loca_table->buffer[0]; + var glyf_offset: uint32_t = 0; + var loca_offset: size_t = 0; - for (var i: int; i < num_glyphs; ++i) { + for (var i: int = 0; i < num_glyphs; ++i) { StoreLoca(index_fmt, glyf_offset, &loca_offset, loca_dst); var glyph: Glyph; var glyph_data: const uint8_t*; @@ -58,7 +58,7 @@ fn WriteNormalizedLoca(index_fmt: int, num_glyphs: int, font: Font*) -> bool { (glyph_size > 0 && !ReadGlyph(glyph_data, glyph_size, &glyph))) { return FONT_COMPRESSION_FAILURE(); } - var glyf_dst_size: size_t; + var glyf_dst_size: size_t = glyf_table->buffer.size() - glyf_offset; if (!StoreGlyph(glyph, glyf_dst + glyf_offset, &glyf_dst_size)) { return FONT_COMPRESSION_FAILURE(); } @@ -86,16 +86,16 @@ fn WriteNormalizedLoca(index_fmt: int, num_glyphs: int, font: Font*) -> bool { namespace { fn MakeEditableBuffer(font: Font*, tableTag: int) -> bool { - var table: Font::Table*; + var table: Font::Table* = font->FindTable(tableTag); if (table == nullptr) { return FONT_COMPRESSION_FAILURE(); } if (table->IsReused()) { return true; } - var sz: int; + var sz: int = Round4(table->length); table->buffer.resize(sz); - var buf: uint8_t*; + var buf: uint8_t* = &table->buffer[0]; memcpy(buf, table->data, table->length); if (PREDICT_FALSE(sz > table->length)) { memset(buf + table->length, 0, sz - table->length); @@ -107,9 +107,9 @@ fn MakeEditableBuffer(font: Font*, tableTag: int) -> bool { } // namespace fn NormalizeGlyphs(font: Font*) -> bool { - var head_table: Font::Table*; - var glyf_table: Font::Table*; - var loca_table: Font::Table*; + var head_table: Font::Table* = font->FindTable(kHeadTableTag); + var glyf_table: Font::Table* = font->FindTable(kGlyfTableTag); + var loca_table: Font::Table* = font->FindTable(kLocaTableTag); if (head_table == nullptr) { return FONT_COMPRESSION_FAILURE(); } @@ -129,8 +129,8 @@ fn NormalizeGlyphs(font: Font*) -> bool { return true; } - var index_fmt: int; - var num_glyphs: int; + var index_fmt: int = head_table->data[51]; + var num_glyphs: int = NumGlyphs(*font); // We need to allocate a bit more than its original length for the normalized // glyf table, since it can happen that the glyphs in the original table are @@ -141,7 +141,7 @@ fn NormalizeGlyphs(font: Font*) -> bool { // some general overhead. // TODO(user) Figure out some more precise upper bound on the size of // the overhead. - var max_normalized_glyf_size: size_t; + var max_normalized_glyf_size: size_t = 1.1 * glyf_table->length + 2 * num_glyphs; glyf_table->buffer.resize(max_normalized_glyf_size); @@ -164,9 +164,9 @@ fn NormalizeGlyphs(font: Font*) -> bool { } fn NormalizeOffsets(font: Font*) -> bool { - var offset: uint32_t; + var offset: uint32_t = 12 + 16 * font->num_tables; for (auto tag : font->OutputOrderedTags()) { - var table: auto&; + var table: auto& = font->tables[tag]; table.offset = offset; offset += Round4(table.length); } @@ -176,14 +176,14 @@ fn NormalizeOffsets(font: Font*) -> bool { namespace { fn ComputeHeaderChecksum(font: const Font&) -> uint32_t { - var checksum: uint32_t; - var max_pow2: uint16_t; - var search_range: uint16_t; - var range_shift: uint16_t; + var checksum: uint32_t = font.flavor; + var max_pow2: uint16_t = font.num_tables ? Log2Floor(font.num_tables) : 0; + var search_range: uint16_t = max_pow2 ? 1 << (max_pow2 + 4) : 0; + var range_shift: uint16_t = (font.num_tables << 4) - search_range; checksum += (font.num_tables << 16 | search_range); checksum += (max_pow2 << 16 | range_shift); for (const auto& i : font.tables) { - var table: const Font::Table*; + var table: const Font::Table* = &i.second; if (table->IsReused()) { table = table->reuse_of; } @@ -198,7 +198,7 @@ fn ComputeHeaderChecksum(font: const Font&) -> uint32_t { } // namespace fn FixChecksums(font: Font*) -> bool { - var head_table: Font::Table*; + var head_table: Font::Table* = font->FindTable(kHeadTableTag); if (head_table == nullptr) { return FONT_COMPRESSION_FAILURE(); } @@ -209,13 +209,13 @@ fn FixChecksums(font: Font*) -> bool { return FONT_COMPRESSION_FAILURE(); } - var head_buf: uint8_t*; - var offset: size_t; + var head_buf: uint8_t* = &head_table->buffer[0]; + var offset: size_t = 8; StoreU32(0, &offset, head_buf); - var file_checksum: uint32_t; - var head_checksum: uint32_t; + var file_checksum: uint32_t = 0; + var head_checksum: uint32_t = 0; for (auto& i : font->tables) { - var table: Font::Table*; + var table: Font::Table* = &i.second; if (table->IsReused()) { table = table->reuse_of; } @@ -236,7 +236,7 @@ fn FixChecksums(font: Font*) -> bool { namespace { fn MarkTransformed(font: Font*) -> bool { - var head_table: Font::Table*; + var head_table: Font::Table* = font->FindTable(kHeadTableTag); if (head_table == nullptr) { return FONT_COMPRESSION_FAILURE(); } @@ -248,7 +248,7 @@ fn MarkTransformed(font: Font*) -> bool { } // set bit 11 of head table 'flags' to indicate that font has undergone // lossless modifying transform - var head_flags: int; + var head_flags: int = head_table->data[16]; head_table->buffer[16] = head_flags | 0x08; return true; } @@ -273,7 +273,8 @@ fn NormalizeFontCollection(font_collection: FontCollection*) -> bool { return NormalizeFont(&font_collection->fonts[0]); } - var offset: uint32_t; + var offset: uint32_t = CollectionHeaderSize(font_collection->header_version, + font_collection->fonts.size()); for (auto& font : font_collection->fonts) { if (!NormalizeWithoutFixingChecksums(&font)) { #ifdef FONT_COMPRESSION_BIN @@ -287,7 +288,7 @@ fn NormalizeFontCollection(font_collection: FontCollection*) -> bool { // Start table offsets after TTC Header and Sfnt Headers for (auto& font : font_collection->fonts) { for (auto tag : font.OutputOrderedTags()) { - var table: Font::Table&; + var table: Font::Table& = font.tables[tag]; if (table.IsReused()) { table.offset = table.reuse_of->offset; } else { diff --git a/third_party/examples/woff2/carbon/src/table_tags.carbon b/third_party/examples/woff2/carbon/src/table_tags.carbon index b23d7edc42c9..9740aa7791df 100644 --- a/third_party/examples/woff2/carbon/src/table_tags.carbon +++ b/third_party/examples/woff2/carbon/src/table_tags.carbon @@ -14,14 +14,14 @@ namespace woff2 { // Tags of popular tables. -let kGlyfTableTag: const uint32_t; -let kHeadTableTag: const uint32_t; -let kLocaTableTag: const uint32_t; -let kDsigTableTag: const uint32_t; -let kCffTableTag: const uint32_t; -let kHmtxTableTag: const uint32_t; -let kHheaTableTag: const uint32_t; -let kMaxpTableTag: const uint32_t; +let kGlyfTableTag: const uint32_t = 0x676c7966; +let kHeadTableTag: const uint32_t = 0x68656164; +let kLocaTableTag: const uint32_t = 0x6c6f6361; +let kDsigTableTag: const uint32_t = 0x44534947; +let kCffTableTag: const uint32_t = 0x43464620; +let kHmtxTableTag: const uint32_t = 0x686d7478; +let kHheaTableTag: const uint32_t = 0x68686561; +let kMaxpTableTag: const uint32_t = 0x6d617870; let kKnownTags: const uint32_t[]; diff --git a/third_party/examples/woff2/carbon/src/table_tags.impl.carbon b/third_party/examples/woff2/carbon/src/table_tags.impl.carbon index 54ca0c128d8a..54f0accc4dd8 100644 --- a/third_party/examples/woff2/carbon/src/table_tags.impl.carbon +++ b/third_party/examples/woff2/carbon/src/table_tags.impl.carbon @@ -13,6 +13,70 @@ namespace woff2 { // Note that the byte order is big-endian, not the same as ots.cc #define TAG(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) -let kKnownTags: const uint32_t[63]; +let kKnownTags: const uint32_t[63] = { + TAG('c', 'm', 'a', 'p'), // 0 + TAG('h', 'e', 'a', 'd'), // 1 + TAG('h', 'h', 'e', 'a'), // 2 + TAG('h', 'm', 't', 'x'), // 3 + TAG('m', 'a', 'x', 'p'), // 4 + TAG('n', 'a', 'm', 'e'), // 5 + TAG('O', 'S', '/', '2'), // 6 + TAG('p', 'o', 's', 't'), // 7 + TAG('c', 'v', 't', ' '), // 8 + TAG('f', 'p', 'g', 'm'), // 9 + TAG('g', 'l', 'y', 'f'), // 10 + TAG('l', 'o', 'c', 'a'), // 11 + TAG('p', 'r', 'e', 'p'), // 12 + TAG('C', 'F', 'F', ' '), // 13 + TAG('V', 'O', 'R', 'G'), // 14 + TAG('E', 'B', 'D', 'T'), // 15 + TAG('E', 'B', 'L', 'C'), // 16 + TAG('g', 'a', 's', 'p'), // 17 + TAG('h', 'd', 'm', 'x'), // 18 + TAG('k', 'e', 'r', 'n'), // 19 + TAG('L', 'T', 'S', 'H'), // 20 + TAG('P', 'C', 'L', 'T'), // 21 + TAG('V', 'D', 'M', 'X'), // 22 + TAG('v', 'h', 'e', 'a'), // 23 + TAG('v', 'm', 't', 'x'), // 24 + TAG('B', 'A', 'S', 'E'), // 25 + TAG('G', 'D', 'E', 'F'), // 26 + TAG('G', 'P', 'O', 'S'), // 27 + TAG('G', 'S', 'U', 'B'), // 28 + TAG('E', 'B', 'S', 'C'), // 29 + TAG('J', 'S', 'T', 'F'), // 30 + TAG('M', 'A', 'T', 'H'), // 31 + TAG('C', 'B', 'D', 'T'), // 32 + TAG('C', 'B', 'L', 'C'), // 33 + TAG('C', 'O', 'L', 'R'), // 34 + TAG('C', 'P', 'A', 'L'), // 35 + TAG('S', 'V', 'G', ' '), // 36 + TAG('s', 'b', 'i', 'x'), // 37 + TAG('a', 'c', 'n', 't'), // 38 + TAG('a', 'v', 'a', 'r'), // 39 + TAG('b', 'd', 'a', 't'), // 40 + TAG('b', 'l', 'o', 'c'), // 41 + TAG('b', 's', 'l', 'n'), // 42 + TAG('c', 'v', 'a', 'r'), // 43 + TAG('f', 'd', 's', 'c'), // 44 + TAG('f', 'e', 'a', 't'), // 45 + TAG('f', 'm', 't', 'x'), // 46 + TAG('f', 'v', 'a', 'r'), // 47 + TAG('g', 'v', 'a', 'r'), // 48 + TAG('h', 's', 't', 'y'), // 49 + TAG('j', 'u', 's', 't'), // 50 + TAG('l', 'c', 'a', 'r'), // 51 + TAG('m', 'o', 'r', 't'), // 52 + TAG('m', 'o', 'r', 'x'), // 53 + TAG('o', 'p', 'b', 'd'), // 54 + TAG('p', 'r', 'o', 'p'), // 55 + TAG('t', 'r', 'a', 'k'), // 56 + TAG('Z', 'a', 'p', 'f'), // 57 + TAG('S', 'i', 'l', 'f'), // 58 + TAG('G', 'l', 'a', 't'), // 59 + TAG('G', 'l', 'o', 'c'), // 60 + TAG('F', 'e', 'a', 't'), // 61 + TAG('S', 'i', 'l', 'l'), // 62 +}; } // namespace woff2 diff --git a/third_party/examples/woff2/carbon/src/transform.impl.carbon b/third_party/examples/woff2/carbon/src/transform.impl.carbon index b38669e9ee9f..dca7cfbe7d45 100644 --- a/third_party/examples/woff2/carbon/src/transform.impl.carbon +++ b/third_party/examples/woff2/carbon/src/transform.impl.carbon @@ -20,13 +20,13 @@ namespace woff2 { namespace { -let FLAG_ARG_1_AND_2_ARE_WORDS: const int; -let FLAG_WE_HAVE_INSTRUCTIONS: const int; +let FLAG_ARG_1_AND_2_ARE_WORDS: const int = 1 << 0; +let FLAG_WE_HAVE_INSTRUCTIONS: const int = 1 << 8; fn WriteBytes(out: std::vector*, data: const uint8_t*, len: size_t) { if (len == 0) { return; } - var offset: size_t; + var offset: size_t = out->size(); out->resize(offset + len); memcpy(&(*out)[offset], data, len); } @@ -102,10 +102,10 @@ class GlyfEncoder { return glyph.x_min || glyph.y_min || glyph.x_max || glyph.y_max; } - var x_min: int16_t; - var y_min: int16_t; - var x_max: int16_t; - var y_max: int16_t; + var x_min: int16_t = glyph.contours[0][0].x; + var y_min: int16_t = glyph.contours[0][0].y; + var x_max: int16_t = x_min; + var y_max: int16_t = y_min; for (const auto& contour : glyph.contours) { for (const auto& point : contour) { if (point.x < x_min) { x_min = point.x; @@ -136,23 +136,23 @@ class GlyfEncoder { } fn WriteSimpleGlyph(glyph_id: int, glyph: const Glyph&) { - var num_contours: int; + var num_contours: int = glyph.contours.size(); WriteUShort(&n_contour_stream_, num_contours); if (ShouldWriteSimpleGlyphBbox(glyph)) { WriteBbox(glyph_id, glyph); } - for (var i: int; i < num_contours; i++) { + for (var i: int = 0; i < num_contours; i++) { Write255UShort(&n_points_stream_, glyph.contours[i].size()); } - var lastX: int; - var lastY: int; - for (var i: int; i < num_contours; i++) { - var num_points: int; - for (var j: int; j < num_points; j++) { - var x: int; - var y: int; - var dx: int; - var dy: int; + var lastX: int = 0; + var lastY: int = 0; + for (var i: int = 0; i < num_contours; i++) { + var num_points: int = glyph.contours[i].size(); + for (var j: int = 0; j < num_points; j++) { + var x: int = glyph.contours[i][j].x; + var y: int = glyph.contours[i][j].y; + var dx: int = x - lastX; + var dy: int = y - lastY; WriteTriplet(glyph.contours[i][j].on_curve, dx, dy); lastX = x; lastY = y; @@ -183,12 +183,12 @@ class GlyfEncoder { } fn WriteTriplet(on_curve: bool, x: int, y: int) { - var abs_x: int; - var abs_y: int; - var on_curve_bit: int; - var x_sign_bit: int; - var y_sign_bit: int; - var xy_sign_bits: int; + var abs_x: int = std::abs(x); + var abs_y: int = std::abs(y); + var on_curve_bit: int = on_curve ? 0 : 128; + var x_sign_bit: int = (x < 0) ? 0 : 1; + var y_sign_bit: int = (y < 0) ? 0 : 1; + var xy_sign_bits: int = x_sign_bit + 2 * y_sign_bit; if (x == 0 && abs_y < 1280) { flag_byte_stream_.push_back(on_curve_bit + ((abs_y & 0xf00) >> 7) + y_sign_bit); @@ -238,8 +238,8 @@ class GlyfEncoder { fn TransformGlyfAndLocaTables(font: Font*) -> bool { // no transform for CFF - var glyf_table: const Font::Table*; - var loca_table: const Font::Table*; + var glyf_table: const Font::Table* = font->FindTable(kGlyfTableTag); + var loca_table: const Font::Table* = font->FindTable(kLocaTableTag); // If you don't have glyf/loca this transform isn't very interesting if (loca_table == nullptr && glyf_table == nullptr) { @@ -257,12 +257,12 @@ fn TransformGlyfAndLocaTables(font: Font*) -> bool { return true; } - var transformed_glyf: Font::Table*; - var transformed_loca: Font::Table*; + var transformed_glyf: Font::Table* = &font->tables[kGlyfTableTag ^ 0x80808080]; + var transformed_loca: Font::Table* = &font->tables[kLocaTableTag ^ 0x80808080]; - var num_glyphs: int; - var encoder: GlyfEncoder; - for (var i: int; i < num_glyphs; ++i) { + var num_glyphs: int = NumGlyphs(*font); + var encoder: GlyfEncoder(num_glyphs); + for (var i: int = 0; i < num_glyphs; ++i) { var glyph: Glyph; var glyph_data: const uint8_t*; var glyph_size: size_t; @@ -274,7 +274,7 @@ fn TransformGlyfAndLocaTables(font: Font*) -> bool { } encoder.GetTransformedGlyfBytes(&transformed_glyf->buffer); - var head_table: const Font::Table*; + var head_table: const Font::Table* = font->FindTable(kHeadTableTag); if (head_table == nullptr || head_table->length < 52) { return FONT_COMPRESSION_FAILURE(); } @@ -294,9 +294,9 @@ fn TransformGlyfAndLocaTables(font: Font*) -> bool { // See https://www.microsoft.com/typography/otspec/hmtx.htm // See WOFF2 spec, 5.4. Transformed hmtx table format fn TransformHmtxTable(font: Font*) -> bool { - var glyf_table: const Font::Table*; - var hmtx_table: const Font::Table*; - var hhea_table: const Font::Table*; + var glyf_table: const Font::Table* = font->FindTable(kGlyfTableTag); + var hmtx_table: const Font::Table* = font->FindTable(kHmtxTableTag); + var hhea_table: const Font::Table* = font->FindTable(kHheaTableTag); // If you don't have hmtx or a glyf not much is going to happen here if (hmtx_table == nullptr || glyf_table == nullptr) { @@ -309,7 +309,7 @@ fn TransformHmtxTable(font: Font*) -> bool { } // Skip 34 to reach 'hhea' numberOfHMetrics - var hhea_buf: Buffer; + var hhea_buf: Buffer(hhea_table->data, hhea_table->length); var num_hmetrics: uint16_t; if (!hhea_buf.Skip(34) || !hhea_buf.ReadU16(&num_hmetrics)) { return FONT_COMPRESSION_FAILURE(); @@ -320,18 +320,18 @@ fn TransformHmtxTable(font: Font*) -> bool { return FONT_COMPRESSION_FAILURE(); } - var num_glyphs: int; + var num_glyphs: int = NumGlyphs(*font); // Most fonts can be transformed; assume it's a go until proven otherwise var advance_widths: std::vector; var proportional_lsbs: std::vector; var monospace_lsbs: std::vector; - var remove_proportional_lsb: bool; - var remove_monospace_lsb: bool; + var remove_proportional_lsb: bool = true; + var remove_monospace_lsb: bool = (num_glyphs - num_hmetrics) > 0; - var hmtx_buf: Buffer; - for (var i: int; i < num_glyphs; i++) { + var hmtx_buf: Buffer(hmtx_table->data, hmtx_table->length); + for (var i: int = 0; i < num_glyphs; i++) { var glyph: Glyph; var glyph_data: const uint8_t*; var glyph_size: size_t; @@ -340,8 +340,8 @@ fn TransformHmtxTable(font: Font*) -> bool { return FONT_COMPRESSION_FAILURE(); } - var advance_width: uint16_t; - var lsb: int16_t; + var advance_width: uint16_t = 0; + var lsb: int16_t = 0; if (i < num_hmetrics) { // [0, num_hmetrics) are proportional hMetrics @@ -376,10 +376,10 @@ fn TransformHmtxTable(font: Font*) -> bool { } } - var transformed_hmtx: Font::Table*; + var transformed_hmtx: Font::Table* = &font->tables[kHmtxTableTag ^ 0x80808080]; - var flags: uint8_t; - var transformed_size: size_t; + var flags: uint8_t = 0; + var transformed_size: size_t = 1 + 2 * advance_widths.size(); if (remove_proportional_lsb) { flags |= 1; } else { @@ -392,7 +392,7 @@ fn TransformHmtxTable(font: Font*) -> bool { } transformed_hmtx->buffer.reserve(transformed_size); - var out: std::vector*; + var out: std::vector* = &transformed_hmtx->buffer; WriteBytes(out, &flags, 1); for (uint16_t advance_width : advance_widths) { WriteUShort(out, advance_width); diff --git a/third_party/examples/woff2/carbon/src/variable_length.impl.carbon b/third_party/examples/woff2/carbon/src/variable_length.impl.carbon index 64bafbcf7018..4d49398acb2c 100644 --- a/third_party/examples/woff2/carbon/src/variable_length.impl.carbon +++ b/third_party/examples/woff2/carbon/src/variable_length.impl.carbon @@ -11,7 +11,7 @@ namespace woff2 { fn Size255UShort(value: uint16_t) -> size_t { - var result: size_t; + var result: size_t = 3; if (value < 253) { result = 1; } else if (value < 762) { @@ -48,30 +48,30 @@ fn Store255UShort(val: int, offset: size_t*, dst: uint8_t*) { // Based on section 6.1.1 of MicroType Express draft spec fn Read255UShort(buf: Buffer*, value: unsigned int*) -> bool { - let kWordCode: const int; - let kOneMoreByteCode2: const int; - let kOneMoreByteCode1: const int; - let kLowestUCode: const int; - var code: uint8_t; + let kWordCode: const int = 253; + let kOneMoreByteCode2: const int = 254; + let kOneMoreByteCode1: const int = 255; + let kLowestUCode: const int = 253; + var code: uint8_t = 0; if (!buf->ReadU8(&code)) { return FONT_COMPRESSION_FAILURE(); } if (code == kWordCode) { - var result: uint16_t; + var result: uint16_t = 0; if (!buf->ReadU16(&result)) { return FONT_COMPRESSION_FAILURE(); } *value = result; return true; } else if (code == kOneMoreByteCode1) { - var result: uint8_t; + var result: uint8_t = 0; if (!buf->ReadU8(&result)) { return FONT_COMPRESSION_FAILURE(); } *value = result + kLowestUCode; return true; } else if (code == kOneMoreByteCode2) { - var result: uint8_t; + var result: uint8_t = 0; if (!buf->ReadU8(&result)) { return FONT_COMPRESSION_FAILURE(); } @@ -84,9 +84,9 @@ fn Read255UShort(buf: Buffer*, value: unsigned int*) -> bool { } fn ReadBase128(buf: Buffer*, value: uint32_t*) -> bool { - var result: uint32_t; - for (var i: size_t; i < 5; ++i) { - var code: uint8_t; + var result: uint32_t = 0; + for (var i: size_t = 0; i < 5; ++i) { + var code: uint8_t = 0; if (!buf->ReadU8(&code)) { return FONT_COMPRESSION_FAILURE(); } @@ -109,16 +109,16 @@ fn ReadBase128(buf: Buffer*, value: uint32_t*) -> bool { } fn Base128Size(n: size_t) -> size_t { - var size: size_t; + var size: size_t = 1; for (; n >= 128; n >>= 7) { ++size; } return size; } fn StoreBase128(len: size_t, offset: size_t*, dst: uint8_t*) { - var size: size_t; - for (var i: size_t; i < size; ++i) { - var b: int; + var size: size_t = Base128Size(len); + for (var i: size_t = 0; i < size; ++i) { + var b: int = static_cast((len >> (7 * (size - i - 1))) & 0x7f); if (i < size - 1) { b |= 0x80; } diff --git a/third_party/examples/woff2/carbon/src/woff2_common.carbon b/third_party/examples/woff2/carbon/src/woff2_common.carbon index 9fef80afc977..af7f59ad48ef 100644 --- a/third_party/examples/woff2/carbon/src/woff2_common.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_common.carbon @@ -16,16 +16,16 @@ namespace woff2 { -let kWoff2Signature: const uint32_t; // "wOF2" +let kWoff2Signature: const uint32_t = 0x774f4632; // "wOF2" // Leave the first byte open to store flag_byte -let kWoff2FlagsTransform: const unsigned int; +let kWoff2FlagsTransform: const unsigned int = 1 << 8; // TrueType Collection ID string: 'ttcf' -let kTtcFontFlavor: const uint32_t; +let kTtcFontFlavor: const uint32_t = 0x74746366; -let kSfntHeaderSize: const size_t; -let kSfntEntrySize: const size_t; +let kSfntHeaderSize: const size_t = 12; +let kSfntEntrySize: const size_t = 16; struct Point { int x; diff --git a/third_party/examples/woff2/carbon/src/woff2_common.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_common.impl.carbon index c7984fefc9e1..3aeb6527bedc 100644 --- a/third_party/examples/woff2/carbon/src/woff2_common.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_common.impl.carbon @@ -16,11 +16,11 @@ namespace woff2 { fn ComputeULongSum(buf: const uint8_t*, size: size_t) -> uint32_t { - var checksum: uint32_t; - var aligned_size: size_t; - for (var i: size_t; i < aligned_size; i += 4) { + var checksum: uint32_t = 0; + var aligned_size: size_t = size & ~3; + for (var i: size_t = 0; i < aligned_size; i += 4) { #if defined(WOFF_LITTLE_ENDIAN) - var v: uint32_t; + var v: uint32_t = *reinterpret_cast(buf + i); checksum += (((v & 0xFF) << 24) | ((v & 0xFF00) << 8) | ((v & 0xFF0000) >> 8) | ((v & 0xFF000000) >> 24)); #elif defined(WOFF_BIG_ENDIAN) @@ -33,8 +33,8 @@ fn ComputeULongSum(buf: const uint8_t*, size: size_t) -> uint32_t { // treat size not aligned on 4 as if it were padded to 4 with 0's if (size != aligned_size) { - var v: uint32_t; - for (var i: size_t; i < size; ++i) { + var v: uint32_t = 0; + for (var i: size_t = aligned_size; i < size; ++i) { v |= buf[i] << (24 - 8 * (i & 3)); } checksum += v; @@ -44,7 +44,7 @@ fn ComputeULongSum(buf: const uint8_t*, size: size_t) -> uint32_t { } fn CollectionHeaderSize(header_version: uint32_t, num_fonts: uint32_t) -> size_t { - var size: size_t; + var size: size_t = 0; if (header_version == 0x00020000) { size += 12; // ulDsig{Tag,Length,Offset} } diff --git a/third_party/examples/woff2/carbon/src/woff2_compress.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_compress.impl.carbon index bb6fa9bd709d..e9cd7a4f3fcb 100644 --- a/third_party/examples/woff2/carbon/src/woff2_compress.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_compress.impl.carbon @@ -20,16 +20,16 @@ fn main(argc: int, argv: char**) -> int { return 1; } - var filename: string; - var outfilename: string; + var filename: string(argv[1]); + var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".woff2"; fprintf(stdout, "Processing %s => %s\n", filename.c_str(), outfilename.c_str()); - var input: string; + var input: string = woff2::GetFileContent(filename); - var input_data: const auto*; - var output_size: size_t; - var output: string; - var output_data: auto*; + var input_data: const auto* = reinterpret_cast(input.data()); + var output_size: size_t = woff2::MaxWOFF2CompressedSize(input_data, input.size()); + var output: string(output_size, 0); + var output_data: auto* = reinterpret_cast(&output[0]); var params: woff2::WOFF2Params; if (!woff2::ConvertTTFToWOFF2(input_data, input.size(), diff --git a/third_party/examples/woff2/carbon/src/woff2_dec.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_dec.impl.carbon index 2cb588610ef0..a452ceb8ef44 100644 --- a/third_party/examples/woff2/carbon/src/woff2_dec.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_dec.impl.carbon @@ -38,34 +38,34 @@ using std::vector; // simple glyph flags -let kGlyfOnCurve: const int; -let kGlyfXShort: const int; -let kGlyfYShort: const int; -let kGlyfRepeat: const int; -let kGlyfThisXIsSame: const int; -let kGlyfThisYIsSame: const int; +let kGlyfOnCurve: const int = 1 << 0; +let kGlyfXShort: const int = 1 << 1; +let kGlyfYShort: const int = 1 << 2; +let kGlyfRepeat: const int = 1 << 3; +let kGlyfThisXIsSame: const int = 1 << 4; +let kGlyfThisYIsSame: const int = 1 << 5; // composite glyph flags // See CompositeGlyph.java in sfntly for full definitions -let FLAG_ARG_1_AND_2_ARE_WORDS: const int; -let FLAG_WE_HAVE_A_SCALE: const int; -let FLAG_MORE_COMPONENTS: const int; -let FLAG_WE_HAVE_AN_X_AND_Y_SCALE: const int; -let FLAG_WE_HAVE_A_TWO_BY_TWO: const int; -let FLAG_WE_HAVE_INSTRUCTIONS: const int; +let FLAG_ARG_1_AND_2_ARE_WORDS: const int = 1 << 0; +let FLAG_WE_HAVE_A_SCALE: const int = 1 << 3; +let FLAG_MORE_COMPONENTS: const int = 1 << 5; +let FLAG_WE_HAVE_AN_X_AND_Y_SCALE: const int = 1 << 6; +let FLAG_WE_HAVE_A_TWO_BY_TWO: const int = 1 << 7; +let FLAG_WE_HAVE_INSTRUCTIONS: const int = 1 << 8; -let kCheckSumAdjustmentOffset: const size_t; +let kCheckSumAdjustmentOffset: const size_t = 8; -let kEndPtsOfContoursOffset: const size_t; -let kCompositeGlyphBegin: const size_t; +let kEndPtsOfContoursOffset: const size_t = 10; +let kCompositeGlyphBegin: const size_t = 10; // 98% of Google Fonts have no glyph above 5k bytes // Largest glyph ever observed was 72k bytes -let kDefaultGlyphBuf: const size_t; +let kDefaultGlyphBuf: const size_t = 5120; // Over 14k test fonts the max compression ratio seen to date was ~20. // >100 suggests you wrote a bad uncompressed size. -let kMaxPlausibleCompressionRatio: const float; +let kMaxPlausibleCompressionRatio: const float = 100.0; // metadata for a TTC font entry struct TtcFont { @@ -124,17 +124,17 @@ fn _SafeIntAddition(a: int, b: int, result: int*) -> bool { fn TripletDecode(flags_in: const uint8_t*, in: const uint8_t*, in_size: size_t, n_points: unsigned int, result: Point*, in_bytes_consumed: size_t*) -> bool { - var x: int; - var y: int; + var x: int = 0; + var y: int = 0; if (PREDICT_FALSE(n_points > in_size)) { return FONT_COMPRESSION_FAILURE(); } - var triplet_index: unsigned int; + var triplet_index: unsigned int = 0; - for (var i: unsigned int; i < n_points; ++i) { - var flag: uint8_t; - var on_curve: bool; + for (var i: unsigned int = 0; i < n_points; ++i) { + var flag: uint8_t = flags_in[i]; + var on_curve: bool = !(flag >> 7); flag &= 0x7f; var n_data_bytes: unsigned int; if (flag < 84) { @@ -158,17 +158,17 @@ fn TripletDecode(flags_in: const uint8_t*, in: const uint8_t*, in_size: size_t, dx = WithSign(flag, (((flag - 10) & 14) << 7) + in[triplet_index]); dy = 0; } else if (flag < 84) { - var b0: int; - var b1: int; + var b0: int = flag - 20; + var b1: int = in[triplet_index]; dx = WithSign(flag, 1 + (b0 & 0x30) + (b1 >> 4)); dy = WithSign(flag >> 1, 1 + ((b0 & 0x0c) << 2) + (b1 & 0x0f)); } else if (flag < 120) { - var b0: int; + var b0: int = flag - 84; dx = WithSign(flag, 1 + ((b0 / 12) << 8) + in[triplet_index]); dy = WithSign(flag >> 1, 1 + (((b0 % 12) >> 2) << 8) + in[triplet_index + 1]); } else if (flag < 124) { - var b2: int; + var b2: int = in[triplet_index + 1]; dx = WithSign(flag, (in[triplet_index] << 4) + (b2 >> 4)); dy = WithSign(flag >> 1, ((b2 & 0x0f) << 8) + in[triplet_index + 2]); } else { @@ -196,19 +196,20 @@ fn StorePoints(n_points: unsigned int, points: const Point*, dst: uint8_t*, dst_size: size_t, glyph_size: size_t*) -> bool { // I believe that n_contours < 65536, in which case this is safe. However, a // comment and/or an assert would be good. - var flag_offset: unsigned int; - var last_flag: int; - var repeat_count: int; - var last_x: int; - var last_y: int; - var x_bytes: unsigned int; - var y_bytes: unsigned int; + var flag_offset: unsigned int = kEndPtsOfContoursOffset + 2 * n_contours + 2 + + instruction_length; + var last_flag: int = -1; + var repeat_count: int = 0; + var last_x: int = 0; + var last_y: int = 0; + var x_bytes: unsigned int = 0; + var y_bytes: unsigned int = 0; - for (var i: unsigned int; i < n_points; ++i) { - var point: const Point&; - var flag: int; - var dx: int; - var dy: int; + for (var i: unsigned int = 0; i < n_points; ++i) { + var point: const Point& = points[i]; + var flag: int = point.on_curve ? kGlyfOnCurve : 0; + var dx: int = point.x - last_x; + var dy: int = point.y - last_y; if (dx == 0) { flag |= kGlyfThisXIsSame; } else if (dx > -256 && dx < 256) { @@ -253,19 +254,19 @@ fn StorePoints(n_points: unsigned int, points: const Point*, } dst[flag_offset++] = repeat_count; } - var xy_bytes: unsigned int; + var xy_bytes: unsigned int = x_bytes + y_bytes; if (PREDICT_FALSE(xy_bytes < x_bytes || flag_offset + xy_bytes < flag_offset || flag_offset + xy_bytes > dst_size)) { return FONT_COMPRESSION_FAILURE(); } - var x_offset: int; - var y_offset: int; + var x_offset: int = flag_offset; + var y_offset: int = flag_offset + x_bytes; last_x = 0; last_y = 0; - for (var i: unsigned int; i < n_points; ++i) { - var dx: int; + for (var i: unsigned int = 0; i < n_points; ++i) { + var dx: int = points[i].x - last_x; if (dx == 0) { // pass } else if (dx > -256 && dx < 256) { @@ -275,7 +276,7 @@ fn StorePoints(n_points: unsigned int, points: const Point*, x_offset = Store16(dst, x_offset, dx); } last_x += dx; - var dy: int; + var dy: int = points[i].y - last_y; if (dy == 0) { // pass } else if (dy > -256 && dy < 256) { @@ -293,10 +294,10 @@ fn StorePoints(n_points: unsigned int, points: const Point*, // A precondition is that there are at least 10 bytes available. // dst should point to the beginning of a 'glyf' record. fn ComputeBbox(n_points: unsigned int, points: const Point*, dst: uint8_t*) { - var x_min: int; - var y_min: int; - var x_max: int; - var y_max: int; + var x_min: int = 0; + var y_min: int = 0; + var x_max: int = 0; + var y_max: int = 0; if (n_points > 0) { x_min = points[0].x; @@ -304,15 +305,15 @@ fn ComputeBbox(n_points: unsigned int, points: const Point*, dst: uint8_t*) { y_min = points[0].y; y_max = points[0].y; } - for (var i: unsigned int; i < n_points; ++i) { - var x: int; - var y: int; + for (var i: unsigned int = 1; i < n_points; ++i) { + var x: int = points[i].x; + var y: int = points[i].y; x_min = std::min(x, x_min); x_max = std::max(x, x_max); y_min = std::min(y, y_min); y_max = std::max(y, y_max); } - var offset: size_t; + var offset: size_t = 2; offset = Store16(dst, offset, x_min); offset = Store16(dst, offset, y_min); offset = Store16(dst, offset, x_max); @@ -322,16 +323,16 @@ fn ComputeBbox(n_points: unsigned int, points: const Point*, dst: uint8_t*) { fn SizeOfComposite(composite_stream: Buffer, size: size_t*, have_instructions: bool*) -> bool { - var start_offset: size_t; - var we_have_instructions: bool; + var start_offset: size_t = composite_stream.offset(); + var we_have_instructions: bool = false; - var flags: uint16_t; + var flags: uint16_t = FLAG_MORE_COMPONENTS; while (flags & FLAG_MORE_COMPONENTS) { if (PREDICT_FALSE(!composite_stream.ReadU16(&flags))) { return FONT_COMPRESSION_FAILURE(); } we_have_instructions |= (flags & FLAG_WE_HAVE_INSTRUCTIONS) != 0; - var arg_size: size_t; // glyph index + var arg_size: size_t = 2; // glyph index if (flags & FLAG_ARG_1_AND_2_ARE_WORDS) { arg_size += 4; } else { @@ -356,11 +357,11 @@ fn SizeOfComposite(composite_stream: Buffer, size: size_t*, } fn Pad4(out: WOFF2Out*) -> bool { - var zeroes: uint8_t[]; + var zeroes: uint8_t[] = {0, 0, 0}; if (PREDICT_FALSE(out->Size() + 3 < out->Size())) { return FONT_COMPRESSION_FAILURE(); } - var pad_bytes: uint32_t; + var pad_bytes: uint32_t = Round4(out->Size()) - out->Size(); if (pad_bytes > 0) { if (PREDICT_FALSE(!out->Write(&zeroes, pad_bytes))) { return FONT_COMPRESSION_FAILURE(); @@ -374,14 +375,14 @@ fn StoreLoca(loca_values: const std::vector&, index_format: int, checksum: uint32_t*, out: WOFF2Out*) -> bool { // TODO(user) figure out what index format to use based on whether max // offset fits into uint16_t or not - let loca_size: const uint64_t; - let offset_size: const uint64_t; + let loca_size: const uint64_t = loca_values.size(); + let offset_size: const uint64_t = index_format ? 4 : 2; if (PREDICT_FALSE((loca_size << 2) >> 2 != loca_size)) { return FONT_COMPRESSION_FAILURE(); } - var loca_content: std::vector; - var dst: uint8_t*; - var offset: size_t; + var loca_content: std::vector(loca_size * offset_size); + var dst: uint8_t* = &loca_content[0]; + var offset: size_t = 0; for (unsigned int value : loca_values) { if (index_format) { offset = StoreU32(dst, offset, value); @@ -401,11 +402,11 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, glyf_checksum: uint32_t*, loca_table: Table*, loca_checksum: uint32_t*, info: WOFF2FontInfo*, out: WOFF2Out*) -> bool { - let kNumSubStreams: const int; - var file: Buffer; + let kNumSubStreams: const int = 7; + var file: Buffer(data, glyf_table->transform_length); var version: uint32_t; - var substreams: std::vector >; - let glyf_start: const size_t; + var substreams: std::vector >(kNumSubStreams); + let glyf_start: const size_t = out->Size(); if (PREDICT_FALSE(!file.ReadU32(&version))) { return FONT_COMPRESSION_FAILURE(); @@ -417,17 +418,18 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, // https://dev.w3.org/webfonts/WOFF2/spec/#conform-mustRejectLoca // dst_length here is origLength in the spec - var expected_loca_dst_length: uint32_t; + var expected_loca_dst_length: uint32_t = (info->index_format ? 4 : 2) + * (static_cast(info->num_glyphs) + 1); if (PREDICT_FALSE(loca_table->dst_length != expected_loca_dst_length)) { return FONT_COMPRESSION_FAILURE(); } - var offset: unsigned int; + var offset: unsigned int = (2 + kNumSubStreams) * 4; if (PREDICT_FALSE(offset > glyf_table->transform_length)) { return FONT_COMPRESSION_FAILURE(); } // Invariant from here on: data_size >= offset - for (var i: int; i < kNumSubStreams; ++i) { + for (var i: int = 0; i < kNumSubStreams; ++i) { var substream_size: uint32_t; if (PREDICT_FALSE(!file.ReadU32(&substream_size))) { return FONT_COMPRESSION_FAILURE(); @@ -438,34 +440,34 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, substreams[i] = std::make_pair(data + offset, substream_size); offset += substream_size; } - var n_contour_stream: Buffer; - var n_points_stream: Buffer; - var flag_stream: Buffer; - var glyph_stream: Buffer; - var composite_stream: Buffer; - var bbox_stream: Buffer; - var instruction_stream: Buffer; + var n_contour_stream: Buffer(substreams[0].first, substreams[0].second); + var n_points_stream: Buffer(substreams[1].first, substreams[1].second); + var flag_stream: Buffer(substreams[2].first, substreams[2].second); + var glyph_stream: Buffer(substreams[3].first, substreams[3].second); + var composite_stream: Buffer(substreams[4].first, substreams[4].second); + var bbox_stream: Buffer(substreams[5].first, substreams[5].second); + var instruction_stream: Buffer(substreams[6].first, substreams[6].second); - var loca_values: std::vector; + var loca_values: std::vector(info->num_glyphs + 1); var n_points_vec: std::vector; var points: std::unique_ptr; - var points_size: size_t; - var bbox_bitmap: const uint8_t*; + var points_size: size_t = 0; + var bbox_bitmap: const uint8_t* = bbox_stream.buffer(); // Safe because num_glyphs is bounded - var bitmap_length: unsigned int; + var bitmap_length: unsigned int = ((info->num_glyphs + 31) >> 5) << 2; if (!bbox_stream.Skip(bitmap_length)) { return FONT_COMPRESSION_FAILURE(); } // Temp buffer for glyph's. - var glyph_buf_size: size_t; - var glyph_buf: std::unique_ptr; + var glyph_buf_size: size_t = kDefaultGlyphBuf; + var glyph_buf: std::unique_ptr(new uint8_t[glyph_buf_size]); info->x_mins.resize(info->num_glyphs); - for (var i: unsigned int; i < info->num_glyphs; ++i) { - var glyph_size: size_t; - var n_contours: uint16_t; - var have_bbox: bool; + for (var i: unsigned int = 0; i < info->num_glyphs; ++i) { + var glyph_size: size_t = 0; + var n_contours: uint16_t = 0; + var have_bbox: bool = false; if (bbox_bitmap[i >> 3] & (0x80 >> (i & 7))) { have_bbox = true; } @@ -475,8 +477,8 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, if (n_contours == 0xffff) { // composite glyph - var have_instructions: bool; - var instruction_size: unsigned int; + var have_instructions: bool = false; + var instruction_size: unsigned int = 0; if (PREDICT_FALSE(!have_bbox)) { // composite glyphs must have an explicit bbox return FONT_COMPRESSION_FAILURE(); @@ -493,7 +495,7 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, } } - var size_needed: size_t; + var size_needed: size_t = 12 + composite_size + instruction_size; if (PREDICT_FALSE(glyph_buf_size < size_needed)) { glyph_buf.reset(new uint8_t[size_needed]); glyph_buf_size = size_needed; @@ -521,9 +523,9 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, } else if (n_contours > 0) { // simple glyph n_points_vec.clear(); - var total_n_points: unsigned int; + var total_n_points: unsigned int = 0; var n_points_contour: unsigned int; - for (var j: unsigned int; j < n_contours; ++j) { + for (var j: unsigned int = 0; j < n_contours; ++j) { if (PREDICT_FALSE( !Read255UShort(&n_points_stream, &n_points_contour))) { return FONT_COMPRESSION_FAILURE(); @@ -534,15 +536,16 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, } total_n_points += n_points_contour; } - var flag_size: unsigned int; + var flag_size: unsigned int = total_n_points; if (PREDICT_FALSE( flag_size > flag_stream.length() - flag_stream.offset())) { return FONT_COMPRESSION_FAILURE(); } - var flags_buf: const uint8_t*; - var triplet_buf: const uint8_t*; - var triplet_size: size_t; - var triplet_bytes_consumed: size_t; + var flags_buf: const uint8_t* = flag_stream.buffer() + flag_stream.offset(); + var triplet_buf: const uint8_t* = glyph_stream.buffer() + + glyph_stream.offset(); + var triplet_size: size_t = glyph_stream.length() - glyph_stream.offset(); + var triplet_bytes_consumed: size_t = 0; if (points_size < total_n_points) { points_size = total_n_points; points = std::make_unique(points_size); @@ -566,7 +569,8 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, || instruction_size >= (1 << 30))) { return FONT_COMPRESSION_FAILURE(); } - var size_needed: size_t; + var size_needed: size_t = 12 + 2 * n_contours + 5 * total_n_points + + instruction_size; if (PREDICT_FALSE(glyph_buf_size < size_needed)) { glyph_buf.reset(new uint8_t[size_needed]); glyph_buf_size = size_needed; @@ -581,8 +585,8 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, ComputeBbox(total_n_points, points.get(), glyph_buf.get()); } glyph_size = kEndPtsOfContoursOffset; - var end_point: int; - for (var contour_ix: unsigned int; contour_ix < n_contours; ++contour_ix) { + var end_point: int = -1; + for (var contour_ix: unsigned int = 0; contour_ix < n_contours; ++contour_ix) { end_point += n_points_vec[contour_ix]; if (PREDICT_FALSE(end_point >= 65536)) { return FONT_COMPRESSION_FAILURE(); @@ -625,7 +629,7 @@ fn ReconstructGlyf(data: const uint8_t*, glyf_table: Table*, // We may need x_min to reconstruct 'hmtx' if (n_contours > 0) { - var x_min_buf: Buffer; + var x_min_buf: Buffer(glyph_buf.get() + 2, 2); if (PREDICT_FALSE(!x_min_buf.ReadS16(&info->x_mins[i]))) { return FONT_COMPRESSION_FAILURE(); } @@ -659,7 +663,7 @@ fn FindTable(tables: std::vector*, tag: uint32_t) -> Table* { fn ReadNumHMetrics(data: const uint8_t*, data_size: size_t, num_hmetrics: uint16_t*) -> bool { // Skip 34 to reach 'hhea' numberOfHMetrics - var buffer: Buffer; + var buffer: Buffer(data, data_size); if (PREDICT_FALSE(!buffer.Skip(34) || !buffer.ReadU16(num_hmetrics))) { return FONT_COMPRESSION_FAILURE(); } @@ -674,7 +678,7 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, x_mins: const std::vector&, checksum: uint32_t*, out: WOFF2Out*) -> bool { - var hmtx_buff_in: Buffer; + var hmtx_buff_in: Buffer(transformed_buf, transformed_size); var hmtx_flags: uint8_t; if (PREDICT_FALSE(!hmtx_buff_in.ReadU8(&hmtx_flags))) { @@ -683,8 +687,8 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, var advance_widths: std::vector; var lsbs: std::vector; - var has_proportional_lsbs: bool; - var has_monospace_lsbs: bool; + var has_proportional_lsbs: bool = (hmtx_flags & 1) == 0; + var has_monospace_lsbs: bool = (hmtx_flags & 2) == 0; // Bits 2-7 are reserved and MUST be zero. if ((hmtx_flags & 0xFC) != 0) { @@ -712,7 +716,7 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, return FONT_COMPRESSION_FAILURE(); } - for (var i: uint16_t; i < num_hmetrics; i++) { + for (var i: uint16_t = 0; i < num_hmetrics; i++) { var advance_width: uint16_t; if (PREDICT_FALSE(!hmtx_buff_in.ReadU16(&advance_width))) { return FONT_COMPRESSION_FAILURE(); @@ -720,7 +724,7 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, advance_widths.push_back(advance_width); } - for (var i: uint16_t; i < num_hmetrics; i++) { + for (var i: uint16_t = 0; i < num_hmetrics; i++) { var lsb: int16_t; if (has_proportional_lsbs) { if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) { @@ -732,7 +736,7 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, lsbs.push_back(lsb); } - for (var i: uint16_t; i < num_glyphs; i++) { + for (var i: uint16_t = num_hmetrics; i < num_glyphs; i++) { var lsb: int16_t; if (has_monospace_lsbs) { if (PREDICT_FALSE(!hmtx_buff_in.ReadS16(&lsb))) { @@ -745,11 +749,11 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, } // bake me a shiny new hmtx table - var hmtx_output_size: uint32_t; - var hmtx_table: std::vector; - var dst: uint8_t*; - var dst_offset: size_t; - for (var i: uint32_t; i < num_glyphs; i++) { + var hmtx_output_size: uint32_t = 2 * num_glyphs + 2 * num_hmetrics; + var hmtx_table: std::vector(hmtx_output_size); + var dst: uint8_t* = &hmtx_table[0]; + var dst_offset: size_t = 0; + for (var i: uint32_t = 0; i < num_glyphs; i++) { if (i < num_hmetrics) { Store16(advance_widths[i], &dst_offset, dst); } @@ -766,8 +770,9 @@ fn ReconstructTransformedHmtx(transformed_buf: const uint8_t*, fn Woff2Uncompress(dst_buf: uint8_t*, dst_size: size_t, src_buf: const uint8_t*, src_size: size_t) -> bool { - var uncompressed_size: size_t; - var result: BrotliDecoderResult; + var uncompressed_size: size_t = dst_size; + var result: BrotliDecoderResult = BrotliDecoderDecompress( + src_size, src_buf, &uncompressed_size, dst_buf); if (PREDICT_FALSE(result != BROTLI_DECODER_RESULT_SUCCESS || uncompressed_size != dst_size)) { return FONT_COMPRESSION_FAILURE(); @@ -777,9 +782,9 @@ fn Woff2Uncompress(dst_buf: uint8_t*, dst_size: size_t, fn ReadTableDirectory(file: Buffer*, tables: std::vector*, num_tables: size_t) -> bool { - var src_offset: uint32_t; - for (var i: size_t; i < num_tables; ++i) { - var table: Table*; + var src_offset: uint32_t = 0; + for (var i: size_t = 0; i < num_tables; ++i) { + var table: Table* = &(*tables)[i]; var flag_byte: uint8_t; if (PREDICT_FALSE(!file->ReadU8(&flag_byte))) { return FONT_COMPRESSION_FAILURE(); @@ -792,8 +797,8 @@ fn ReadTableDirectory(file: Buffer*, tables: std::vector
*, } else { tag = kKnownTags[flag_byte & 0x3f]; } - var flags: uint32_t; - var xform_version: uint8_t; + var flags: uint32_t = 0; + var xform_version: uint8_t = (flag_byte >> 6) & 0x03; // 0 means xform for glyph/loca, non-0 for others if (tag == kGlyfTableTag || tag == kLocaTableTag) { @@ -809,7 +814,7 @@ fn ReadTableDirectory(file: Buffer*, tables: std::vector
*, if (PREDICT_FALSE(!ReadBase128(file, &dst_length))) { return FONT_COMPRESSION_FAILURE(); } - var transform_length: uint32_t; + var transform_length: uint32_t = dst_length; if ((flags & kWoff2FlagsTransform) != 0) { if (PREDICT_FALSE(!ReadBase128(file, &transform_length))) { return FONT_COMPRESSION_FAILURE(); @@ -838,11 +843,11 @@ fn StoreOffsetTable(result: uint8_t*, offset: size_t, flavor: uint32_t, num_tables: uint16_t) -> size_t { offset = StoreU32(result, offset, flavor); // sfnt version offset = Store16(result, offset, num_tables); // num_tables - var max_pow2: unsigned; + var max_pow2: unsigned = 0; while (1u << (max_pow2 + 1) <= num_tables) { max_pow2++; } - let output_search_range: const uint16_t; + let output_search_range: const uint16_t = (1u << max_pow2) << 4; offset = Store16(result, offset, output_search_range); // searchRange offset = Store16(result, offset, max_pow2); // entrySelector // rangeShift @@ -860,7 +865,8 @@ fn StoreTableEntry(result: uint8_t*, offset: uint32_t, tag: uint32_t) -> size_t // First table goes after all the headers, table directory, etc fn ComputeOffsetToFirstTable(hdr: const WOFF2Header&) -> uint64_t { - var offset: uint64_t; + var offset: uint64_t = kSfntHeaderSize + + kSfntEntrySize * static_cast(hdr.num_tables); if (hdr.header_version) { offset = CollectionHeaderSize(hdr.header_version, hdr.ttc_fonts.size()) + kSfntHeaderSize * hdr.ttc_fonts.size(); @@ -893,14 +899,14 @@ fn ReconstructFont(transformed_buf: uint8_t*, hdr: WOFF2Header*, font_index: size_t, out: WOFF2Out*) -> bool { - var dest_offset: size_t; + var dest_offset: size_t = out->Size(); var table_entry: uint8_t[12]; - var info: WOFF2FontInfo*; - var tables: std::vector; + var info: WOFF2FontInfo* = &metadata->font_infos[font_index]; + var tables: std::vector = Tables(hdr, font_index); // 'glyf' without 'loca' doesn't make sense - var glyf_table: const Table*; - var loca_table: const Table*; + var glyf_table: const Table* = FindTable(&tables, kGlyfTableTag); + var loca_table: const Table* = FindTable(&tables, kLocaTableTag); if (PREDICT_FALSE(static_cast(glyf_table) != static_cast(loca_table))) { #ifdef FONT_COMPRESSION_BIN @@ -919,17 +925,18 @@ fn ReconstructFont(transformed_buf: uint8_t*, } } - var font_checksum: uint32_t; + var font_checksum: uint32_t = metadata->header_checksum; if (hdr->header_version) { font_checksum = hdr->ttc_fonts[font_index].header_checksum; } - var loca_checksum: uint32_t; - for (var i: size_t; i < tables.size(); i++) { - var table: Table&; + var loca_checksum: uint32_t = 0; + for (var i: size_t = 0; i < tables.size(); i++) { + var table: Table& = *tables[i]; - var checksum_key: std::pair; - var reused: bool; + var checksum_key: std::pair = {table.tag, table.src_offset}; + var reused: bool = metadata->checksums.find(checksum_key) + != metadata->checksums.end(); if (PREDICT_FALSE(font_index == 0 && reused)) { return FONT_COMPRESSION_FAILURE(); } @@ -948,7 +955,7 @@ fn ReconstructFont(transformed_buf: uint8_t*, } } - var checksum: uint32_t; + var checksum: uint32_t = 0; if (!reused) { if ((table.flags & kWoff2FlagsTransform) != kWoff2FlagsTransform) { if (table.tag == kHeadTableTag) { @@ -969,7 +976,7 @@ fn ReconstructFont(transformed_buf: uint8_t*, if (table.tag == kGlyfTableTag) { table.dst_offset = dest_offset; - var loca_table: Table*; + var loca_table: Table* = FindTable(&tables, kLocaTableTag); if (PREDICT_FALSE(!ReconstructGlyf(transformed_buf + table.src_offset, &table, &checksum, loca_table, &loca_checksum, info, out))) { return FONT_COMPRESSION_FAILURE(); @@ -1020,7 +1027,7 @@ fn ReconstructFont(transformed_buf: uint8_t*, } // Update 'head' checkSumAdjustment. We already set it to 0 and summed font. - var head_table: Table*; + var head_table: Table* = FindTable(&tables, kHeadTableTag); if (head_table) { if (PREDICT_FALSE(head_table->dst_length < 12)) { return FONT_COMPRESSION_FAILURE(); @@ -1037,7 +1044,7 @@ fn ReconstructFont(transformed_buf: uint8_t*, } fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> bool { - var file: Buffer; + var file: Buffer(data, length); var signature: uint32_t; if (PREDICT_FALSE(!file.ReadU32(&signature) || signature != kWoff2Signature || @@ -1103,7 +1110,7 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b } // Before we sort for output the last table end is the uncompressed size. - var last_table: Table&; + var last_table: Table& = hdr->tables.back(); hdr->uncompressed_size = last_table.src_offset + last_table.src_length; if (PREDICT_FALSE(hdr->uncompressed_size < last_table.src_offset)) { return FONT_COMPRESSION_FAILURE(); @@ -1125,8 +1132,8 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b } hdr->ttc_fonts.resize(num_fonts); - for (var i: uint32_t; i < num_fonts; i++) { - var ttc_font: TtcFont&; + for (var i: uint32_t = 0; i < num_fonts; i++) { + var ttc_font: TtcFont& = hdr->ttc_fonts[i]; var num_tables: uint32_t; if (PREDICT_FALSE(!Read255UShort(&file, &num_tables) || !num_tables)) { return FONT_COMPRESSION_FAILURE(); @@ -1138,10 +1145,10 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b ttc_font.table_indices.resize(num_tables); - var glyf_idx: unsigned int; - var loca_idx: unsigned int; + var glyf_idx: unsigned int = 0; + var loca_idx: unsigned int = 0; - for (var j: uint32_t; j < num_tables; j++) { + for (var j: uint32_t = 0; j < num_tables; j++) { var table_idx: unsigned int; if (PREDICT_FALSE(!Read255UShort(&file, &table_idx)) || table_idx >= hdr->tables.size()) { @@ -1149,7 +1156,7 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b } ttc_font.table_indices[j] = table_idx; - var table: const Table&; + var table: const Table& = hdr->tables[table_idx]; if (table.tag == kLocaTableTag) { loca_idx = table_idx; } @@ -1172,15 +1179,15 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b } } - let first_table_offset: const uint64_t; + let first_table_offset: const uint64_t = ComputeOffsetToFirstTable(*hdr); hdr->compressed_offset = file.offset(); if (PREDICT_FALSE(hdr->compressed_offset > std::numeric_limits::max())) { return FONT_COMPRESSION_FAILURE(); } - var src_offset: uint64_t; - var dst_offset: uint64_t; + var src_offset: uint64_t = Round4(hdr->compressed_offset + hdr->compressed_length); + var dst_offset: uint64_t = first_table_offset; if (PREDICT_FALSE(src_offset > length)) { @@ -1221,10 +1228,10 @@ fn ReadWOFF2Header(data: const uint8_t*, length: size_t, hdr: WOFF2Header*) -> b // Write everything before the actual table data fn WriteHeaders(metadata: RebuildMetadata*, hdr: WOFF2Header*, out: WOFF2Out*) -> bool { - var output: std::vector; + var output: std::vector(ComputeOffsetToFirstTable(*hdr), 0); // Re-order tables in output (OTSpec) order - var sorted_tables: std::vector
; + var sorted_tables: std::vector
(hdr->tables); if (hdr->header_version) { // collection; we have to sort the table offset vector in each font for (auto& ttc_font : hdr->ttc_fonts) { @@ -1232,7 +1239,7 @@ fn WriteHeaders(metadata: RebuildMetadata*, for (auto table_index : ttc_font.table_indices) { sorted_index_by_tag[hdr->tables[table_index].tag] = table_index; } - var index: uint16_t; + var index: uint16_t = 0; for (auto& i : sorted_index_by_tag) { ttc_font.table_indices[index++] = i.second; } @@ -1243,16 +1250,16 @@ fn WriteHeaders(metadata: RebuildMetadata*, } // Start building the font - var result: uint8_t*; - var offset: size_t; + var result: uint8_t* = &output[0]; + var offset: size_t = 0; if (hdr->header_version) { // TTC header offset = StoreU32(result, offset, hdr->flavor); // TAG TTCTag offset = StoreU32(result, offset, hdr->header_version); // FIXED Version offset = StoreU32(result, offset, hdr->ttc_fonts.size()); // ULONG numFonts // Space for ULONG OffsetTable[numFonts] (zeroed initially) - var offset_table: size_t; // keep start of offset table for later - for (var i: size_t; i < hdr->ttc_fonts.size(); i++) { + var offset_table: size_t = offset; // keep start of offset table for later + for (var i: size_t = 0; i < hdr->ttc_fonts.size(); i++) { offset = StoreU32(result, offset, 0); // will fill real values in later } // space for DSIG fields for header v2 @@ -1264,8 +1271,8 @@ fn WriteHeaders(metadata: RebuildMetadata*, // write Offset Tables and store the location of each in TTC Header metadata->font_infos.resize(hdr->ttc_fonts.size()); - for (var i: size_t; i < hdr->ttc_fonts.size(); i++) { - var ttc_font: TtcFont&; + for (var i: size_t = 0; i < hdr->ttc_fonts.size(); i++) { + var ttc_font: TtcFont& = hdr->ttc_fonts[i]; // write Offset Table location into TTC Header offset_table = StoreU32(result, offset_table, offset); @@ -1276,7 +1283,7 @@ fn WriteHeaders(metadata: RebuildMetadata*, ttc_font.table_indices.size()); for (const auto table_index : ttc_font.table_indices) { - var tag: uint32_t; + var tag: uint32_t = hdr->tables[table_index].tag; metadata->font_infos[i].table_entry_by_tag[tag] = offset; offset = StoreTableEntry(result, offset, tag); } @@ -1287,7 +1294,7 @@ fn WriteHeaders(metadata: RebuildMetadata*, } else { metadata->font_infos.resize(1); offset = StoreOffsetTable(result, offset, hdr->flavor, hdr->num_tables); - for (var i: uint16_t; i < hdr->num_tables; ++i) { + for (var i: uint16_t = 0; i < hdr->num_tables; ++i) { metadata->font_infos[0].table_entry_by_tag[sorted_tables[i].tag] = offset; offset = StoreTableEntry(result, offset, sorted_tables[i].tag); } @@ -1303,7 +1310,7 @@ fn WriteHeaders(metadata: RebuildMetadata*, } // namespace fn ComputeWOFF2FinalSize(data: const uint8_t*, length: size_t) -> size_t { - var file: Buffer; + var file: Buffer(data, length); var total_length: uint32_t; if (!file.Skip(16) || @@ -1315,7 +1322,7 @@ fn ComputeWOFF2FinalSize(data: const uint8_t*, length: size_t) -> size_t { fn ConvertWOFF2ToTTF(result: uint8_t*, result_length: size_t, data: const uint8_t*, length: size_t) -> bool { - var out: WOFF2MemoryOut; + var out: WOFF2MemoryOut(result, result_length); return ConvertWOFF2ToTTF(data, length, &out); } @@ -1331,7 +1338,7 @@ fn ConvertWOFF2ToTTF(data: const uint8_t*, length: size_t, return FONT_COMPRESSION_FAILURE(); } - let compression_ratio: const float; + let compression_ratio: const float = static_cast(hdr.uncompressed_size) / length; if (compression_ratio > kMaxPlausibleCompressionRatio) { #ifdef FONT_COMPRESSION_BIN fprintf(stderr, "Implausible compression ratio %.01f\n", compression_ratio); @@ -1339,8 +1346,8 @@ fn ConvertWOFF2ToTTF(data: const uint8_t*, length: size_t, return FONT_COMPRESSION_FAILURE(); } - var src_buf: const uint8_t*; - var uncompressed_buf: std::vector; + var src_buf: const uint8_t* = data + hdr.compressed_offset; + var uncompressed_buf: std::vector(hdr.uncompressed_size); if (PREDICT_FALSE(hdr.uncompressed_size < 1)) { return FONT_COMPRESSION_FAILURE(); } @@ -1350,7 +1357,7 @@ fn ConvertWOFF2ToTTF(data: const uint8_t*, length: size_t, return FONT_COMPRESSION_FAILURE(); } - for (var i: size_t; i < metadata.font_infos.size(); i++) { + for (var i: size_t = 0; i < metadata.font_infos.size(); i++) { if (PREDICT_FALSE(!ReconstructFont(&uncompressed_buf[0], hdr.uncompressed_size, &metadata, &hdr, i, out))) { diff --git a/third_party/examples/woff2/carbon/src/woff2_decompress.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_decompress.impl.carbon index 83da899db9d6..2898d37992f1 100644 --- a/third_party/examples/woff2/carbon/src/woff2_decompress.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_decompress.impl.carbon @@ -21,16 +21,17 @@ fn main(argc: int, argv: char**) -> int { return 1; } - var filename: string; - var outfilename: string; + var filename: string(argv[1]); + var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".ttf"; // Note: update woff2_dec_fuzzer_new_entry.cc if this pattern changes. - var input: string; - var raw_input: const auto*; - var output: string; - var out: woff2::WOFF2StringOut; + var input: string = woff2::GetFileContent(filename); + var raw_input: const auto* = reinterpret_cast(input.data()); + var output: string(std::min(woff2::ComputeWOFF2FinalSize(raw_input, input.size()), + woff2::kDefaultMaxSize), 0); + var out: woff2::WOFF2StringOut(&output); - let ok: const bool; + let ok: const bool = woff2::ConvertWOFF2ToTTF(raw_input, input.size(), &out); if (ok) { woff2::SetFileContents(outfilename, output.begin(), diff --git a/third_party/examples/woff2/carbon/src/woff2_enc.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_enc.impl.carbon index d4caceea553f..182e154f2812 100644 --- a/third_party/examples/woff2/carbon/src/woff2_enc.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_enc.impl.carbon @@ -35,12 +35,12 @@ using std::string; using std::vector; -let kWoff2HeaderSize: const size_t; -let kWoff2EntrySize: const size_t; +let kWoff2HeaderSize: const size_t = 48; +let kWoff2EntrySize: const size_t = 20; fn Compress(data: const uint8_t*, let len: const size_t, result: uint8_t*, result_len: uint32_t*, mode: BrotliEncoderMode, quality: int) -> bool { - var compressed_len: size_t; + var compressed_len: size_t = *result_len; if (BrotliEncoderCompress(quality, BROTLI_DEFAULT_WINDOW, mode, len, data, &compressed_len, result) == 0) { return false; @@ -64,7 +64,7 @@ fn TextCompress(data: const uint8_t*, let len: const size_t, } fn KnownTableIndex(tag: uint32_t) -> int { - for (var i: int; i < 63; ++i) { + for (var i: int = 0; i < 63; ++i) { if (tag == kKnownTags[i]) { return i; } } @@ -72,7 +72,7 @@ fn KnownTableIndex(tag: uint32_t) -> int { } fn StoreTableEntry(table: const Table&, offset: size_t*, dst: uint8_t*) { - var flag_byte: uint8_t; + var flag_byte: uint8_t = (table.flags & 0xC0) | KnownTableIndex(table.tag); dst[(*offset)++] = flag_byte; // The index here is treated as a set of flag bytes because // bits 6 and 7 of the byte are reserved for future use as flags. @@ -87,8 +87,8 @@ fn StoreTableEntry(table: const Table&, offset: size_t*, dst: uint8_t*) { } fn TableEntrySize(table: const Table&) -> size_t { - var flag_byte: uint8_t; - var size: size_t; + var flag_byte: uint8_t = KnownTableIndex(table.tag); + var size: size_t = ((flag_byte & 0x3f) != 0x3f) ? 1 : 5; size += Base128Size(table.src_length); if ((table.flags & kWoff2FlagsTransform) != 0) { size += Base128Size(table.transform_length); @@ -101,7 +101,7 @@ fn ComputeWoff2Length(font_collection: const FontCollection&, index_by_tag_offset: std::map, uint16_t>, compressed_data_length: size_t, extended_metadata_length: size_t) -> size_t { - var size: size_t; + var size: size_t = kWoff2HeaderSize; for (const auto& table : tables) { size += TableEntrySize(table); @@ -117,13 +117,13 @@ fn ComputeWoff2Length(font_collection: const FontCollection&, for (const auto& font : font_collection.fonts) { size += Size255UShort(font.tables.size()); // 255UInt16 numTables for (const auto& entry : font.tables) { - var table: const Font::Table&; + var table: const Font::Table& = entry.second; // no collection entry for xform table if (table.tag & 0x80808080) { continue; } - var tag_offset: std::pair; - var table_index: uint16_t; + var tag_offset: std::pair(table.tag, table.offset); + var table_index: uint16_t = index_by_tag_offset[tag_offset]; size += Size255UShort(table_index); // 255UInt16 index entry } } @@ -139,9 +139,9 @@ fn ComputeWoff2Length(font_collection: const FontCollection&, fn ComputeUncompressedLength(font: const Font&) -> size_t { // sfnt header + offset table - var size: size_t; + var size: size_t = 12 + 16 * font.num_tables; for (const auto& entry : font.tables) { - var table: const Font::Table&; + var table: const Font::Table& = entry.second; if (table.tag & 0x80808080) { continue; // xform tables don't stay } if (table.IsReused()) { continue; // don't have to pay twice @@ -155,7 +155,8 @@ fn ComputeUncompressedLength(font_collection: const FontCollection&) -> size_t { if (font_collection.flavor != kTtcFontFlavor) { return ComputeUncompressedLength(font_collection.fonts[0]); } - var size: size_t; + var size: size_t = CollectionHeaderSize(font_collection.header_version, + font_collection.fonts.size()); for (const auto& font : font_collection.fonts) { size += ComputeUncompressedLength(font); } @@ -163,9 +164,9 @@ fn ComputeUncompressedLength(font_collection: const FontCollection&) -> size_t { } fn ComputeTotalTransformLength(font: const Font&) -> size_t { - var total: size_t; + var total: size_t = 0; for (const auto& i : font.tables) { - var table: const Font::Table&; + var table: const Font::Table& = i.second; if (table.IsReused()) { continue; } @@ -184,7 +185,7 @@ fn MaxWOFF2CompressedSize(data: const uint8_t*, length: size_t) -> size_t { return MaxWOFF2CompressedSize(data, length, ""); } -fn MaxWOFF2CompressedSize(const uint8_t* /*data*/: const uint8_t* /*data*/, length: size_t, +fn MaxWOFF2CompressedSize(const uint8_t* /*data*/: const uint8_t* length: size_t, extended_metadata: const string&) -> size_t { // Except for the header size, which is 32 bytes larger in woff2 format, // all other parts should be smaller (table header in short format, @@ -237,8 +238,8 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, } else { // glyf/loca use 11 to flag "not transformed" for (auto& font : font_collection.fonts) { - var glyf_table: Font::Table*; - var loca_table: Font::Table*; + var glyf_table: Font::Table* = font.FindTable(kGlyfTableTag); + var loca_table: Font::Table* = font.FindTable(kLocaTableTag); if (glyf_table) { glyf_table->flag_byte |= 0xc0; } @@ -254,25 +255,25 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, // the size. If the compressor overflows this, it should return false and // then this function will also return false. - var total_transform_length: size_t; + var total_transform_length: size_t = 0; for (const auto& font : font_collection.fonts) { total_transform_length += ComputeTotalTransformLength(font); } - var compression_buffer_size: size_t; - var compression_buf: std::vector; - var total_compressed_length: uint32_t; + var compression_buffer_size: size_t = CompressedBufferSize(total_transform_length); + var compression_buf: std::vector(compression_buffer_size); + var total_compressed_length: uint32_t = compression_buffer_size; // Collect all transformed data into one place in output order. - var transform_buf: std::vector; - var transform_offset: size_t; + var transform_buf: std::vector(total_transform_length); + var transform_offset: size_t = 0; for (const auto& font : font_collection.fonts) { for (const auto tag : font.OutputOrderedTags()) { - var original: const Font::Table&; + var original: const Font::Table& = font.tables.at(tag); if (original.IsReused()) { continue; } if (tag & 0x80808080) { continue; } - var table_to_store: const Font::Table*; + var table_to_store: const Font::Table* = font.FindTable(tag ^ 0x80808080); if (table_to_store == nullptr) { table_to_store = &original; } @@ -299,8 +300,9 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, // Compress the extended metadata // TODO(user): how does this apply to collections - var compressed_metadata_buf_length: uint32_t; - var compressed_metadata_buf: std::vector; + var compressed_metadata_buf_length: uint32_t = + CompressedBufferSize(params.extended_metadata.length()); + var compressed_metadata_buf: std::vector(compressed_metadata_buf_length); if (params.extended_metadata.length() > 0) { if (!TextCompress(reinterpret_cast(params.extended_metadata.data()), @@ -323,12 +325,12 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, for (const auto& font : font_collection.fonts) { for (const auto tag : font.OutputOrderedTags()) { - var src_table: const Font::Table&; + var src_table: const Font::Table& = font.tables.at(tag); if (src_table.IsReused()) { continue; } - var tag_offset: std::pair; + var tag_offset: std::pair(src_table.tag, src_table.offset); if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) { index_by_tag_offset[tag_offset] = tables.size(); } else { @@ -340,8 +342,9 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, table.flags = src_table.flag_byte; table.src_length = src_table.length; table.transform_length = src_table.length; - var transformed_data: const uint8_t*; - var transformed_table: const Font::Table*; + var transformed_data: const uint8_t* = src_table.data; + var transformed_table: const Font::Table* = + font.FindTable(src_table.tag ^ 0x80808080); if (transformed_table != nullptr) { table.flags = transformed_table->flag_byte; table.flags |= kWoff2FlagsTransform; @@ -353,7 +356,9 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, } } - var woff2_length: size_t; + var woff2_length: size_t = ComputeWoff2Length(font_collection, tables, + index_by_tag_offset, total_compressed_length, + compressed_metadata_buf_length); if (woff2_length > *result_length) { #ifdef FONT_COMPRESSION_BIN fprintf(stderr, "Result allocation was too small (%zd vs %zd bytes).\n", @@ -363,7 +368,7 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, } *result_length = woff2_length; - var offset: size_t; + var offset: size_t = 0; // start of woff2 header (http://www.w3.org/TR/WOFF2/#woff20Header) StoreU32(kWoff2Signature, &offset, result); @@ -408,9 +413,9 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, Store255UShort(font_collection.fonts.size(), &offset, result); for (const Font& font : font_collection.fonts) { - var num_tables: uint16_t; + var num_tables: uint16_t = 0; for (const auto& entry : font.tables) { - var table: const Font::Table&; + var table: const Font::Table& = entry.second; if (table.tag & 0x80808080) { continue; // don't write xform tables } num_tables++; @@ -419,14 +424,16 @@ fn ConvertTTFToWOFF2(data: const uint8_t*, length: size_t, StoreU32(font.flavor, &offset, result); for (const auto& entry : font.tables) { - var table: const Font::Table&; + var table: const Font::Table& = entry.second; if (table.tag & 0x80808080) { continue; // don't write xform tables } // for reused tables, only the original has an updated offset - var table_offset: uint32_t; - var table_length: uint32_t; - var tag_offset: std::pair; + var table_offset: uint32_t = + table.IsReused() ? table.reuse_of->offset : table.offset; + var table_length: uint32_t = + table.IsReused() ? table.reuse_of->length : table.length; + var tag_offset: std::pair(table.tag, table_offset); if (index_by_tag_offset.find(tag_offset) == index_by_tag_offset.end()) { #ifdef FONT_COMPRESSION_BIN fprintf(stderr, "Missing table index for offset 0x%08x\n", @@ -434,7 +441,7 @@ fprintf(stderr, "Missing table index for offset 0x%08x\n", #endif return FONT_COMPRESSION_FAILURE(); } - var index: uint16_t; + var index: uint16_t = index_by_tag_offset[tag_offset]; Store255UShort(index, &offset, result); } diff --git a/third_party/examples/woff2/carbon/src/woff2_info.impl.carbon b/third_party/examples/woff2/carbon/src/woff2_info.impl.carbon index 0563cb32fe99..8e46f7eab5ff 100644 --- a/third_party/examples/woff2/carbon/src/woff2_info.impl.carbon +++ b/third_party/examples/woff2/carbon/src/woff2_info.impl.carbon @@ -19,7 +19,12 @@ fn PrintTag(tag: int) -> std::string { if (tag & 0x80808080) { return std::string("_xfm"); // print _xfm for xform tables (else garbage) } - var printable: char[]; + var printable: char[] = { + static_cast((tag >> 24) & 0xFF), + static_cast((tag >> 16) & 0xFF), + static_cast((tag >> 8) & 0xFF), + static_cast(tag & 0xFF) + }; return std::string(printable, 4); } @@ -31,13 +36,14 @@ fn main(argc: int, argv: char**) -> int { return 1; } - var filename: string; - var outfilename: string; + var filename: string(argv[1]); + var outfilename: string = filename.substr(0, filename.find_last_of('.')) + ".woff2"; fprintf(stdout, "Processing %s => %s\n", filename.c_str(), outfilename.c_str()); - var input: string; + var input: string = woff2::GetFileContent(filename); - var file: woff2::Buffer; + var file: woff2::Buffer(reinterpret_cast(input.data()), + input.size()); printf("WOFF2Header\n"); var signature: uint32_t, var flavor: uint32_t, var length: uint32_t, var totalSfntSize: uint32_t, var totalCompressedSize: uint32_t; @@ -94,8 +100,8 @@ fn main(argc: int, argv: char**) -> int { var table_tags: std::vector; printf("TableDirectory starts at +%zu\n", file.offset()); printf("Entry offset flags tag origLength txLength\n"); - for (var i: auto; i < num_tables; i++) { - var offset: size_t; + for (var i: auto = 0; i < num_tables; i++) { + var offset: size_t = file.offset(); var flags: uint8_t; var tag: uint32_t, var origLength: uint32_t, var transformLength: uint32_t; if (!file.ReadU8(&flags)) { return 1; @@ -113,7 +119,7 @@ fn main(argc: int, argv: char**) -> int { printf("%5d %6zu 0x%02x %s %10d", i, offset, flags, PrintTag(tag).c_str(), origLength); - var xform_version: uint8_t; + var xform_version: uint8_t = (flags >> 6) & 0x3; if (tag == woff2::kGlyfTableTag || tag == woff2::kLocaTableTag) { if (xform_version == 0) { if (!ReadBase128(&file, &transformLength)) { return 1; @@ -137,7 +143,7 @@ fn main(argc: int, argv: char**) -> int { } printf("CollectionHeader 0x%08x %d fonts\n", version, numFonts); - for (var i: auto; i < numFonts; i++) { + for (var i: auto = 0; i < numFonts; i++) { var numTables: uint32_t, var flavor: uint32_t; if (!woff2::Read255UShort(&file, &numTables)) { return 1; } @@ -145,7 +151,7 @@ fn main(argc: int, argv: char**) -> int { } printf("CollectionFontEntry %d flavor 0x%08x %d tables\n", i, flavor, numTables); - for (var j: auto; j < numTables; j++) { + for (var j: auto = 0; j < numTables; j++) { var table_idx: uint32_t; if (!woff2::Read255UShort(&file, &table_idx)) { return 1; }