From 28d4e326f8b682d4c8e27be20565994e5549f891 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Thu, 6 Jun 2024 11:10:01 +0200 Subject: [PATCH] LibGfx: Use the woff2 library to decode WOFF2 font files This saves us the trouble of maintaining our own implementation, and instantly brings us to full WOFF2 feature parity with others. Co-Authored-By: Andrew Kaster --- Meta/CMake/woff2.cmake | 11 + Userland/Libraries/LibGfx/CMakeLists.txt | 7 + Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp | 1048 +---------------- Userland/Libraries/LibGfx/Font/WOFF2/Font.h | 2 - vcpkg-configuration.json | 5 - vcpkg.json | 8 +- 6 files changed, 63 insertions(+), 1018 deletions(-) create mode 100644 Meta/CMake/woff2.cmake diff --git a/Meta/CMake/woff2.cmake b/Meta/CMake/woff2.cmake new file mode 100644 index 00000000000..577c8628e3a --- /dev/null +++ b/Meta/CMake/woff2.cmake @@ -0,0 +1,11 @@ +find_package(PkgConfig) +pkg_check_modules(WOFF2 REQUIRED IMPORTED_TARGET libwoff2dec) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args( + WOFF2 + REQUIRED_VARS + WOFF2_INCLUDE_DIRS + WOFF2_LIBRARY_DIRS + WOFF2_LIBRARIES +) diff --git a/Userland/Libraries/LibGfx/CMakeLists.txt b/Userland/Libraries/LibGfx/CMakeLists.txt index fb814b74724..67ac9941486 100644 --- a/Userland/Libraries/LibGfx/CMakeLists.txt +++ b/Userland/Libraries/LibGfx/CMakeLists.txt @@ -1,3 +1,5 @@ +include(woff2) + set(SOURCES AffineTransform.cpp AntiAliasingPainter.cpp @@ -89,6 +91,11 @@ set(SOURCES serenity_lib(LibGfx gfx) target_link_libraries(LibGfx PRIVATE LibCompress LibCore LibCrypto LibFileSystem LibRIFF LibTextCodec LibIPC LibUnicode LibURL) +# Third-party +target_include_directories(LibGfx PRIVATE ${WOFF2_INCLUDE_DIRS}) +target_link_libraries(LibGfx PRIVATE ${WOFF2_LIBRARIES}) +target_link_directories(LibGfx PRIVATE ${WOFF2_LIBRARY_DIRS}) + set(generated_sources TIFFMetadata.h TIFFTagHandler.cpp) list(TRANSFORM generated_sources PREPEND "ImageFormats/") diff --git a/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp b/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp index f125ac78fd8..c8f7edce0a0 100644 --- a/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/WOFF2/Font.cpp @@ -1,1041 +1,69 @@ /* - * Copyright (c) 2022, Luke Wilde - * Copyright (c) 2023, Andreas Kling - * Copyright (c) 2023, Sam Atkins + * Copyright (c) 2024, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include -#include -#include -#include +#define AK_DONT_REPLACE_STD #include #include - -// The following is an implementation of the WOFF2 specification. -// https://www.w3.org/TR/WOFF2/ +#include namespace WOFF2 { -// https://www.w3.org/TR/WOFF2/#woff20Header -struct [[gnu::packed]] Header { - BigEndian signature; // 0x774F4632 'wOF2' - BigEndian flavor; // The "sfnt version" of the input font. - BigEndian length; // Total size of the WOFF file. - BigEndian num_tables; // Number of entries in directory of font tables. - BigEndian reserved; // Reserved; set to 0. - BigEndian total_sfnt_size; // Total size needed for the uncompressed font data, including the sfnt header, - // directory, and font tables (including padding). - BigEndian total_compressed_size; // Total length of the compressed data block. - BigEndian major_version; // Major version of the WOFF file. - BigEndian minor_version; // Minor version of the WOFF file. - BigEndian meta_offset; // Offset to metadata block, from beginning of WOFF file. - BigEndian meta_length; // Length of compressed metadata block. - BigEndian meta_orig_length; // Uncompressed size of metadata block. - BigEndian priv_offset; // Offset to private data block, from beginning of WOFF file. - BigEndian priv_length; // Length of private data block. -}; -static_assert(AssertSize()); - -} - -template<> -class AK::Traits : public DefaultTraits { +class WOFF2ByteBufferOut final : public woff2::WOFF2Out { public: - static constexpr bool is_trivially_serializable() { return true; } -}; - -namespace WOFF2 { - -static constexpr u32 WOFF2_SIGNATURE = 0x774F4632; -static constexpr u32 TTCF_SIGNAURE = 0x74746366; -static constexpr size_t SFNT_HEADER_SIZE = 12; -static constexpr size_t SFNT_TABLE_SIZE = 16; - -[[maybe_unused]] static ErrorOr read_255_u_short(FixedMemoryStream& stream) -{ - constexpr u8 one_more_byte_code_1 = 255; - constexpr u8 one_more_byte_code_2 = 254; - constexpr u8 word_code = 253; - constexpr u8 lowest_u_code = 253; - constexpr u16 lowest_u_code_multiplied_by_2 = lowest_u_code * 2; - - auto code = TRY(stream.read_value()); - - if (code == word_code) { - return TRY(stream.read_value>()); - } - - if (code == one_more_byte_code_1) { - u16 final_value = TRY(stream.read_value()); - final_value += lowest_u_code; - return final_value; - } - - if (code == one_more_byte_code_2) { - u16 final_value = TRY(stream.read_value()); - final_value += lowest_u_code_multiplied_by_2; - return final_value; - } - return code; -} - -static ErrorOr read_uint_base_128(SeekableStream& stream) -{ - u32 accumulator = 0; - - for (u8 i = 0; i < 5; ++i) { - u8 const next_byte = TRY(stream.read_value()); - - if (i == 0 && next_byte == 0x80) - return Error::from_string_literal("UIntBase128 type contains a leading zero"); - - if (accumulator & 0xfe000000) - return Error::from_string_literal("UIntBase128 type exceeds the length of a u32"); - - accumulator = (accumulator << 7) | (next_byte & 0x7F); - - if ((next_byte & 0x80) == 0) - return accumulator; - } - - return Error::from_string_literal("UIntBase128 type is larger than 5 bytes"); -} - -static i16 be_i16(u8 const* ptr) -{ - return (((i16)ptr[0]) << 8) | ((i16)ptr[1]); -} - -static u16 pow_2_less_than_or_equal(u16 x) -{ - VERIFY(x > 0); - VERIFY(x < 32769); - return 1 << (sizeof(u16) * 8 - count_leading_zeroes_safe(x - 1)); -} - -enum class TransformationVersion { - Version0, - Version1, - Version2, - Version3, -}; - -struct TableDirectoryEntry { - TransformationVersion transformation_version { TransformationVersion::Version0 }; - OpenType::Tag tag; - u32 original_length { 0 }; - Optional transform_length; - - bool has_transformation() const + explicit WOFF2ByteBufferOut(ByteBuffer& buffer) + : m_buffer(buffer) { - return transform_length.has_value(); } -}; -// NOTE: Any tags less than 4 characters long are padded with spaces at the end. -static constexpr Array known_tag_names = { - OpenType::Tag("cmap"), - OpenType::Tag("head"), - OpenType::Tag("hhea"), - OpenType::Tag("hmtx"), - OpenType::Tag("maxp"), - OpenType::Tag("name"), - OpenType::Tag("OS/2"), - OpenType::Tag("post"), - OpenType::Tag("cvt "), - OpenType::Tag("fpgm"), - OpenType::Tag("glyf"), - OpenType::Tag("loca"), - OpenType::Tag("prep"), - OpenType::Tag("CFF "), - OpenType::Tag("VORG"), - OpenType::Tag("EBDT"), - OpenType::Tag("EBLC"), - OpenType::Tag("gasp"), - OpenType::Tag("hdmx"), - OpenType::Tag("kern"), - OpenType::Tag("LTSH"), - OpenType::Tag("PCLT"), - OpenType::Tag("VDMX"), - OpenType::Tag("vhea"), - OpenType::Tag("vmtx"), - OpenType::Tag("BASE"), - OpenType::Tag("GDEF"), - OpenType::Tag("GPOS"), - OpenType::Tag("GSUB"), - OpenType::Tag("EBSC"), - OpenType::Tag("JSTF"), - OpenType::Tag("MATH"), - OpenType::Tag("CBDT"), - OpenType::Tag("CBLC"), - OpenType::Tag("COLR"), - OpenType::Tag("CPAL"), - OpenType::Tag("SVG "), - OpenType::Tag("sbix"), - OpenType::Tag("acnt"), - OpenType::Tag("avar"), - OpenType::Tag("bdat"), - OpenType::Tag("bloc"), - OpenType::Tag("bsln"), - OpenType::Tag("cvar"), - OpenType::Tag("fdsc"), - OpenType::Tag("feat"), - OpenType::Tag("fmtx"), - OpenType::Tag("fvar"), - OpenType::Tag("gvar"), - OpenType::Tag("hsty"), - OpenType::Tag("just"), - OpenType::Tag("lcar"), - OpenType::Tag("mort"), - OpenType::Tag("morx"), - OpenType::Tag("opbd"), - OpenType::Tag("prop"), - OpenType::Tag("trak"), - OpenType::Tag("Zapf"), - OpenType::Tag("Silf"), - OpenType::Tag("Glat"), - OpenType::Tag("Gloc"), - OpenType::Tag("Feat"), - OpenType::Tag("Sill"), -}; - -struct CoordinateTripletEncoding { - u8 byte_count { 0 }; - u8 x_bits { 0 }; - u8 y_bits { 0 }; - Optional delta_x; - Optional delta_y; - Optional positive_x; - Optional positive_y; -}; - -// https://www.w3.org/TR/WOFF2/#triplet_decoding -// 5.2. Decoding of variable-length X and Y coordinates -static CoordinateTripletEncoding const coordinate_triplet_encodings[128] = { - { 2, 0, 8, {}, 0, {}, false }, // 0 - { 2, 0, 8, {}, 0, {}, true }, // 1 - { 2, 0, 8, {}, 256, {}, false }, // 2 - { 2, 0, 8, {}, 256, {}, true }, // 3 - { 2, 0, 8, {}, 512, {}, false }, // 4 - { 2, 0, 8, {}, 512, {}, true }, // 5 - { 2, 0, 8, {}, 768, {}, false }, // 6 - { 2, 0, 8, {}, 768, {}, true }, // 7 - { 2, 0, 8, {}, 1024, {}, false }, // 8 - { 2, 0, 8, {}, 1024, {}, true }, // 9 - { 2, 8, 0, 0, {}, false, {} }, // 10 - { 2, 8, 0, 0, {}, true, {} }, // 11 - { 2, 8, 0, 256, {}, false, {} }, // 12 - { 2, 8, 0, 256, {}, true, {} }, // 13 - { 2, 8, 0, 512, {}, false, {} }, // 14 - { 2, 8, 0, 512, {}, true, {} }, // 15 - { 2, 8, 0, 768, {}, false, {} }, // 16 - { 2, 8, 0, 768, {}, true, {} }, // 17 - { 2, 8, 0, 1024, {}, false, {} }, // 18 - { 2, 8, 0, 1024, {}, true, {} }, // 19 - { 2, 4, 4, 1, 1, false, false }, // 20 - { 2, 4, 4, 1, 1, true, false }, // 21 - { 2, 4, 4, 1, 1, false, true }, // 22 - { 2, 4, 4, 1, 1, true, true }, // 23 - { 2, 4, 4, 1, 17, false, false }, // 24 - { 2, 4, 4, 1, 17, true, false }, // 25 - { 2, 4, 4, 1, 17, false, true }, // 26 - { 2, 4, 4, 1, 17, true, true }, // 27 - { 2, 4, 4, 1, 33, false, false }, // 28 - { 2, 4, 4, 1, 33, true, false }, // 29 - { 2, 4, 4, 1, 33, false, true }, // 30 - { 2, 4, 4, 1, 33, true, true }, // 31 - { 2, 4, 4, 1, 49, false, false }, // 32 - { 2, 4, 4, 1, 49, true, false }, // 33 - { 2, 4, 4, 1, 49, false, true }, // 34 - { 2, 4, 4, 1, 49, true, true }, // 35 - { 2, 4, 4, 17, 1, false, false }, // 36 - { 2, 4, 4, 17, 1, true, false }, // 37 - { 2, 4, 4, 17, 1, false, true }, // 38 - { 2, 4, 4, 17, 1, true, true }, // 39 - { 2, 4, 4, 17, 17, false, false }, // 40 - { 2, 4, 4, 17, 17, true, false }, // 41 - { 2, 4, 4, 17, 17, false, true }, // 42 - { 2, 4, 4, 17, 17, true, true }, // 43 - { 2, 4, 4, 17, 33, false, false }, // 44 - { 2, 4, 4, 17, 33, true, false }, // 45 - { 2, 4, 4, 17, 33, false, true }, // 46 - { 2, 4, 4, 17, 33, true, true }, // 47 - { 2, 4, 4, 17, 49, false, false }, // 48 - { 2, 4, 4, 17, 49, true, false }, // 49 - { 2, 4, 4, 17, 49, false, true }, // 50 - { 2, 4, 4, 17, 49, true, true }, // 51 - { 2, 4, 4, 33, 1, false, false }, // 52 - { 2, 4, 4, 33, 1, true, false }, // 53 - { 2, 4, 4, 33, 1, false, true }, // 54 - { 2, 4, 4, 33, 1, true, true }, // 55 - { 2, 4, 4, 33, 17, false, false }, // 56 - { 2, 4, 4, 33, 17, true, false }, // 57 - { 2, 4, 4, 33, 17, false, true }, // 58 - { 2, 4, 4, 33, 17, true, true }, // 59 - { 2, 4, 4, 33, 33, false, false }, // 60 - { 2, 4, 4, 33, 33, true, false }, // 61 - { 2, 4, 4, 33, 33, false, true }, // 62 - { 2, 4, 4, 33, 33, true, true }, // 63 - { 2, 4, 4, 33, 49, false, false }, // 64 - { 2, 4, 4, 33, 49, true, false }, // 65 - { 2, 4, 4, 33, 49, false, true }, // 66 - { 2, 4, 4, 33, 49, true, true }, // 67 - { 2, 4, 4, 49, 1, false, false }, // 68 - { 2, 4, 4, 49, 1, true, false }, // 69 - { 2, 4, 4, 49, 1, false, true }, // 70 - { 2, 4, 4, 49, 1, true, true }, // 71 - { 2, 4, 4, 49, 17, false, false }, // 72 - { 2, 4, 4, 49, 17, true, false }, // 73 - { 2, 4, 4, 49, 17, false, true }, // 74 - { 2, 4, 4, 49, 17, true, true }, // 75 - { 2, 4, 4, 49, 33, false, false }, // 76 - { 2, 4, 4, 49, 33, true, false }, // 77 - { 2, 4, 4, 49, 33, false, true }, // 78 - { 2, 4, 4, 49, 33, true, true }, // 79 - { 2, 4, 4, 49, 49, false, false }, // 80 - { 2, 4, 4, 49, 49, true, false }, // 81 - { 2, 4, 4, 49, 49, false, true }, // 82 - { 2, 4, 4, 49, 49, true, true }, // 83 - { 3, 8, 8, 1, 1, false, false }, // 84 - { 3, 8, 8, 1, 1, true, false }, // 85 - { 3, 8, 8, 1, 1, false, true }, // 86 - { 3, 8, 8, 1, 1, true, true }, // 87 - { 3, 8, 8, 1, 257, false, false }, // 88 - { 3, 8, 8, 1, 257, true, false }, // 89 - { 3, 8, 8, 1, 257, false, true }, // 90 - { 3, 8, 8, 1, 257, true, true }, // 91 - { 3, 8, 8, 1, 513, false, false }, // 92 - { 3, 8, 8, 1, 513, true, false }, // 93 - { 3, 8, 8, 1, 513, false, true }, // 94 - { 3, 8, 8, 1, 513, true, true }, // 95 - { 3, 8, 8, 257, 1, false, false }, // 96 - { 3, 8, 8, 257, 1, true, false }, // 97 - { 3, 8, 8, 257, 1, false, true }, // 98 - { 3, 8, 8, 257, 1, true, true }, // 99 - { 3, 8, 8, 257, 257, false, false }, // 100 - { 3, 8, 8, 257, 257, true, false }, // 101 - { 3, 8, 8, 257, 257, false, true }, // 102 - { 3, 8, 8, 257, 257, true, true }, // 103 - { 3, 8, 8, 257, 513, false, false }, // 104 - { 3, 8, 8, 257, 513, true, false }, // 105 - { 3, 8, 8, 257, 513, false, true }, // 106 - { 3, 8, 8, 257, 513, true, true }, // 107 - { 3, 8, 8, 513, 1, false, false }, // 108 - { 3, 8, 8, 513, 1, true, false }, // 109 - { 3, 8, 8, 513, 1, false, true }, // 110 - { 3, 8, 8, 513, 1, true, true }, // 111 - { 3, 8, 8, 513, 257, false, false }, // 112 - { 3, 8, 8, 513, 257, true, false }, // 113 - { 3, 8, 8, 513, 257, false, true }, // 114 - { 3, 8, 8, 513, 257, true, true }, // 115 - { 3, 8, 8, 513, 513, false, false }, // 116 - { 3, 8, 8, 513, 513, true, false }, // 117 - { 3, 8, 8, 513, 513, false, true }, // 118 - { 3, 8, 8, 513, 513, true, true }, // 119 - { 4, 12, 12, 0, 0, false, false }, // 120 - { 4, 12, 12, 0, 0, true, false }, // 121 - { 4, 12, 12, 0, 0, false, true }, // 122 - { 4, 12, 12, 0, 0, true, true }, // 123 - { 5, 16, 16, 0, 0, false, false }, // 124 - { 5, 16, 16, 0, 0, true, false }, // 125 - { 5, 16, 16, 0, 0, false, true }, // 126 - { 5, 16, 16, 0, 0, true, true }, // 127 -}; - -struct FontPoint { - i16 x { 0 }; - i16 y { 0 }; - bool on_curve { false }; -}; - -static ErrorOr> retrieve_points_of_simple_glyph(FixedMemoryStream& flags_stream, FixedMemoryStream& glyph_stream, u16 number_of_points) -{ - Vector points; - TRY(points.try_ensure_capacity(number_of_points)); - - i16 x = 0; - i16 y = 0; - - for (u32 point = 0; point < number_of_points; ++point) { - u8 flags = TRY(flags_stream.read_value()); - bool on_curve = (flags & 0x80) == 0; - u8 coordinate_triplet_index = flags & 0x7F; - - auto const& coordinate_triplet_encoding = coordinate_triplet_encodings[coordinate_triplet_index]; - - // The byte_count in the array accounts for the flags, but we already read them in from a different stream. - u8 const byte_count_not_including_flags = coordinate_triplet_encoding.byte_count - 1; - - u8 point_coordinates_buffer[4]; - Bytes point_coordinates { point_coordinates_buffer, byte_count_not_including_flags }; - TRY(glyph_stream.read_until_filled(point_coordinates)); - - int delta_x = 0; - int delta_y = 0; - - switch (coordinate_triplet_encoding.x_bits) { - case 0: - break; - case 4: - delta_x = static_cast(point_coordinates[0] >> 4); - break; - case 8: - delta_x = static_cast(point_coordinates[0]); - break; - case 12: - delta_x = (static_cast(point_coordinates[0]) << 4) | (static_cast(point_coordinates[1]) >> 4); - break; - case 16: - delta_x = be_i16(point_coordinates.data()); - break; - default: + // Append n bytes of data from buf. + // Return true if all written, false otherwise. + virtual bool Write(void const* data, size_t size) override + { + auto result = m_buffer.try_append(static_cast(data), size); + if (result.is_error()) { VERIFY_NOT_REACHED(); } - - switch (coordinate_triplet_encoding.y_bits) { - case 0: - break; - case 4: - delta_y = static_cast(point_coordinates[0] & 0x0f); - break; - case 8: - delta_y = byte_count_not_including_flags == 2 ? static_cast(point_coordinates[1]) : static_cast(point_coordinates[0]); - break; - case 12: - delta_y = (static_cast(point_coordinates[1] & 0x0f) << 8) | static_cast(point_coordinates[2]); - break; - case 16: - delta_y = be_i16(point_coordinates.offset(2)); - break; - default: - VERIFY_NOT_REACHED(); - } - - if (coordinate_triplet_encoding.delta_x.has_value()) { - if (Checked::addition_would_overflow(delta_x, coordinate_triplet_encoding.delta_x.value())) - return Error::from_string_literal("EOVERFLOW 3"); - - delta_x += coordinate_triplet_encoding.delta_x.value(); - } - - if (coordinate_triplet_encoding.delta_y.has_value()) { - if (Checked::addition_would_overflow(delta_y, coordinate_triplet_encoding.delta_y.value())) - return Error::from_string_literal("EOVERFLOW 4"); - - delta_y += coordinate_triplet_encoding.delta_y.value(); - } - - if (coordinate_triplet_encoding.positive_x.has_value() && !coordinate_triplet_encoding.positive_x.value()) - delta_x = -delta_x; - - if (coordinate_triplet_encoding.positive_y.has_value() && !coordinate_triplet_encoding.positive_y.value()) - delta_y = -delta_y; - - if (Checked::addition_would_overflow(x, delta_x)) - return Error::from_string_literal("EOVERFLOW 5"); - - if (Checked::addition_would_overflow(y, delta_y)) - return Error::from_string_literal("EOVERFLOW 6"); - - x += delta_x; - y += delta_y; - - points.unchecked_append(FontPoint { .x = x, .y = y, .on_curve = on_curve }); + return true; } - return points; -} - -// https://www.w3.org/TR/WOFF2/#glyf_table_format -struct [[gnu::packed]] TransformedGlyfTable { - BigEndian reserved; // = 0x0000 - BigEndian option_flags; // Bit 0: if set, indicates the presence of the overlapSimpleBitmap[] bit array. - // Bits 1-15: Reserved. - BigEndian num_glyphs; // Number of glyphs - BigEndian index_format; // Offset format for loca table, should be consistent with indexToLocFormat of the - // original head table (see [OFF] specification) - BigEndian n_contour_stream_size; // Size of nContour stream in bytes - BigEndian n_points_stream_size; // Size of nPoints stream in bytes - BigEndian flag_stream_size; // Size of flag stream in bytes - BigEndian glyph_stream_size; // Size of glyph stream in bytes (a stream of variable-length encoded values, see - // description below) - BigEndian composite_stream_size; // Size of composite stream in bytes (a stream of variable-length encoded values, - // see description below) - BigEndian bbox_stream_size; // Size of bbox data in bytes representing combined length of bboxBitmap - // (a packed bit array) and bboxStream (a stream of Int16 values) - BigEndian instruction_stream_size; // Size of instruction stream (a stream of UInt8 values) - - // Other fields are variable-length, and so are not represented in this struct: - // Int16 nContourStream[] Stream of Int16 values representing number of contours for each glyph record - // 255UInt16 nPointsStream[] Stream of values representing number of outline points for each contour in glyph records - // UInt8 flagStream[] Stream of UInt8 values representing flag values for each outline point. - // Vary glyphStream[] Stream of bytes representing point coordinate values using variable length encoding - // format (defined in subclause 5.2) - // Vary compositeStream[] Stream of bytes representing component flag values and associated composite glyph data - // UInt8 bboxBitmap[] Bitmap (a numGlyphs-long bit array) indicating explicit bounding boxes - // Int16 bboxStream[] Stream of Int16 values representing glyph bounding box data - // UInt8 instructionStream[] Stream of UInt8 values representing a set of instructions for each corresponding glyph - // UInt8 overlapSimpleBitmap[] A numGlyphs-long bit array that provides values for the overlap flag [bit 6] for each - // simple glyph. (Flag values for composite glyphs are already encoded as part of the - // compositeStream[]). -}; -static_assert(AssertSize()); - -} - -template<> -class AK::Traits : public DefaultTraits { -public: - static constexpr bool is_trivially_serializable() { return true; } -}; - -namespace WOFF2 { - -enum class LocaElementSize { - TwoBytes, - FourBytes, -}; - -struct GlyfAndLocaTableBuffers { - ByteBuffer glyf_table; - ByteBuffer loca_table; -}; - -enum SimpleGlyphFlags : u8 { - OnCurve = 0x01, - XShortVector = 0x02, - YShortVector = 0x04, - RepeatFlag = 0x08, - XIsSameOrPositiveXShortVector = 0x10, - YIsSameOrPositiveYShortVector = 0x20, -}; - -static ErrorOr create_glyf_and_loca_tables_from_transformed_glyf_table(FixedMemoryStream& table_stream) -{ - auto header = TRY(table_stream.read_value()); - - auto loca_element_size = header.index_format == 0 ? LocaElementSize::TwoBytes : LocaElementSize::FourBytes; - - size_t table_size = TRY(table_stream.size()); - u64 total_size_of_streams = header.n_contour_stream_size; - total_size_of_streams += header.n_points_stream_size; - total_size_of_streams += header.flag_stream_size; - total_size_of_streams += header.glyph_stream_size; - total_size_of_streams += header.composite_stream_size; - total_size_of_streams += header.bbox_stream_size; - total_size_of_streams += header.instruction_stream_size; - - if (table_size < total_size_of_streams) - return Error::from_string_literal("Not enough data to read in streams of transformed glyf table"); - - auto number_of_contours_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.n_contour_stream_size))); - auto number_of_points_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.n_points_stream_size))); - auto flag_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.flag_stream_size))); - auto glyph_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.glyph_stream_size))); - auto composite_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.composite_stream_size))); - - size_t bounding_box_bitmap_length = ((header.num_glyphs + 31) >> 5) << 2; - auto bounding_box_bitmap_memory_stream = FixedMemoryStream(TRY(table_stream.read_in_place(bounding_box_bitmap_length))); - auto bounding_box_bitmap_bit_stream = BigEndianInputBitStream { MaybeOwned(bounding_box_bitmap_memory_stream) }; - - if (header.bbox_stream_size < bounding_box_bitmap_length) - return Error::from_string_literal("Not enough data to read bounding box stream of transformed glyf table"); - auto bounding_box_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.bbox_stream_size - bounding_box_bitmap_length))); - - auto instruction_stream = FixedMemoryStream(TRY(table_stream.read_in_place(header.instruction_stream_size))); - - ByteBuffer reconstructed_glyf_table; - Vector loca_indexes; - - auto append_u16 = [&](BigEndian value) -> ErrorOr { - return reconstructed_glyf_table.try_append(&value, sizeof(value)); - }; - - auto append_i16 = [&](BigEndian value) -> ErrorOr { - return reconstructed_glyf_table.try_append(&value, sizeof(value)); - }; - - auto append_bytes = [&](ReadonlyBytes bytes) -> ErrorOr { - return reconstructed_glyf_table.try_append(bytes); - }; - - for (size_t glyph_index = 0; glyph_index < header.num_glyphs; ++glyph_index) { - size_t starting_glyf_table_size = reconstructed_glyf_table.size(); - - bool has_bounding_box = TRY(bounding_box_bitmap_bit_stream.read_bit()); - - auto number_of_contours = TRY(number_of_contours_stream.read_value>()); - - if (number_of_contours == 0) { - // Empty glyph - - // Reconstruction of an empty glyph (when nContour = 0) is a simple step - // that involves incrementing the glyph record count and creating a new entry in the loca table - // where loca[n] = loca[n-1]. - - // If the bboxBitmap flag indicates that the bounding box values are explicitly encoded in the bboxStream - // the decoder MUST reject WOFF2 file as invalid. - if (has_bounding_box) - return Error::from_string_literal("Empty glyphs cannot have an explicit bounding box"); - } else if (number_of_contours < 0) { - // Decoding of Composite Glyphs - - [[maybe_unused]] i16 bounding_box_x_min = 0; - [[maybe_unused]] i16 bounding_box_y_min = 0; - [[maybe_unused]] i16 bounding_box_x_max = 0; - [[maybe_unused]] i16 bounding_box_y_max = 0; - - if (has_bounding_box) { - bounding_box_x_min = TRY(bounding_box_stream.read_value>()); - bounding_box_y_min = TRY(bounding_box_stream.read_value>()); - bounding_box_x_max = TRY(bounding_box_stream.read_value>()); - bounding_box_y_max = TRY(bounding_box_stream.read_value>()); - } - - TRY(append_i16(number_of_contours)); - TRY(append_i16(bounding_box_x_min)); - TRY(append_i16(bounding_box_y_min)); - TRY(append_i16(bounding_box_x_max)); - TRY(append_i16(bounding_box_y_max)); - - bool have_instructions = false; - u16 flags = to_underlying(OpenType::Glyf::CompositeFlags::MoreComponents); - while (flags & to_underlying(OpenType::Glyf::CompositeFlags::MoreComponents)) { - // 1a. Read a UInt16 from compositeStream. This is interpreted as a component flag word as in the TrueType spec. - // Based on the flag values, there are between 4 and 14 additional argument bytes, - // interpreted as glyph index, arg1, arg2, and optional scale or affine matrix. - - flags = TRY(composite_stream.read_value>()); - - if (flags & to_underlying(OpenType::Glyf::CompositeFlags::WeHaveInstructions)) { - have_instructions = true; - } - - // 2a. Read the number of argument bytes as determined in step 1a from the composite stream, - // and store these in the reconstructed glyph. - // If the flag word read in step 1a has the FLAG_MORE_COMPONENTS bit (bit 5) set, go back to step 1a. - - size_t argument_byte_count = 2; - - if (flags & to_underlying(OpenType::Glyf::CompositeFlags::Arg1AndArg2AreWords)) { - argument_byte_count += 4; - } else { - argument_byte_count += 2; - } - - if (flags & to_underlying(OpenType::Glyf::CompositeFlags::WeHaveAScale)) { - argument_byte_count += 2; - } else if (flags & to_underlying(OpenType::Glyf::CompositeFlags::WeHaveAnXAndYScale)) { - argument_byte_count += 4; - } else if (flags & to_underlying(OpenType::Glyf::CompositeFlags::WeHaveATwoByTwo)) { - argument_byte_count += 8; - } - - TRY(append_u16(flags)); - TRY(reconstructed_glyf_table.try_append(TRY(composite_stream.read_in_place(argument_byte_count)))); - } - - if (have_instructions) { - auto number_of_instructions = TRY(read_255_u_short(glyph_stream)); - TRY(append_u16(number_of_instructions)); - - if (number_of_instructions) - TRY(reconstructed_glyf_table.try_append(TRY(instruction_stream.read_in_place(number_of_instructions)))); - } - } else if (number_of_contours > 0) { - // Decoding of Simple Glyphs - - // For a simple glyph (when nContour > 0), the process continues as follows: - // Each of these is the number of points of that contour. - // Convert this into the endPtsOfContours[] array by computing the cumulative sum, then subtracting one. - - Vector end_points_of_contours; - size_t number_of_points = 0; - - for (size_t contour_index = 0; contour_index < static_cast(number_of_contours); ++contour_index) { - size_t number_of_points_for_this_contour = TRY(read_255_u_short(number_of_points_stream)); - if (Checked::addition_would_overflow(number_of_points, number_of_points_for_this_contour)) - return Error::from_string_literal("EOVERFLOW 1"); - - number_of_points += number_of_points_for_this_contour; - if (number_of_points == 0) - return Error::from_string_literal("EOVERFLOW 2"); - - TRY(end_points_of_contours.try_append(number_of_points - 1)); - } - - auto points = TRY(retrieve_points_of_simple_glyph(flag_stream, glyph_stream, number_of_points)); - - auto instruction_size = TRY(read_255_u_short(glyph_stream)); - auto instructions_buffer = TRY(ByteBuffer::create_zeroed(instruction_size)); - if (instruction_size != 0) - TRY(instruction_stream.read_until_filled(instructions_buffer)); - - i16 bounding_box_x_min = 0; - i16 bounding_box_y_min = 0; - i16 bounding_box_x_max = 0; - i16 bounding_box_y_max = 0; - - if (has_bounding_box) { - bounding_box_x_min = TRY(bounding_box_stream.read_value>()); - bounding_box_y_min = TRY(bounding_box_stream.read_value>()); - bounding_box_x_max = TRY(bounding_box_stream.read_value>()); - bounding_box_y_max = TRY(bounding_box_stream.read_value>()); - } else { - for (size_t point_index = 0; point_index < points.size(); ++point_index) { - auto& point = points.at(point_index); - - if (point_index == 0) { - bounding_box_x_min = bounding_box_x_max = point.x; - bounding_box_y_min = bounding_box_y_max = point.y; - continue; - } - - bounding_box_x_min = min(bounding_box_x_min, point.x); - bounding_box_x_max = max(bounding_box_x_max, point.x); - bounding_box_y_min = min(bounding_box_y_min, point.y); - bounding_box_y_max = max(bounding_box_y_max, point.y); - } - } - - TRY(append_i16(number_of_contours)); - TRY(append_i16(bounding_box_x_min)); - TRY(append_i16(bounding_box_y_min)); - TRY(append_i16(bounding_box_x_max)); - TRY(append_i16(bounding_box_y_max)); - - for (auto end_point : end_points_of_contours) - TRY(append_u16(end_point)); - - TRY(append_u16(instruction_size)); - if (instruction_size != 0) - TRY(append_bytes(instructions_buffer)); - - Vector relative_points; - TRY(relative_points.try_ensure_capacity(points.size())); - - { - i16 previous_point_x = 0; - i16 previous_point_y = 0; - for (auto& point : points) { - i16 x = point.x - previous_point_x; - i16 y = point.y - previous_point_y; - relative_points.unchecked_append({ x, y, point.on_curve }); - previous_point_x = point.x; - previous_point_y = point.y; - } - } - - Optional last_flags; - u8 repeat_count = 0; - - for (auto& point : relative_points) { - u8 flags = 0; - - if (point.on_curve) - flags |= SimpleGlyphFlags::OnCurve; - - if (point.x == 0) { - flags |= SimpleGlyphFlags::XIsSameOrPositiveXShortVector; - } else if (point.x > -256 && point.x < 256) { - flags |= SimpleGlyphFlags::XShortVector; - - if (point.x > 0) - flags |= SimpleGlyphFlags::XIsSameOrPositiveXShortVector; - } - - if (point.y == 0) { - flags |= SimpleGlyphFlags::YIsSameOrPositiveYShortVector; - } else if (point.y > -256 && point.y < 256) { - flags |= SimpleGlyphFlags::YShortVector; - - if (point.y > 0) - flags |= SimpleGlyphFlags::YIsSameOrPositiveYShortVector; - } - - if (last_flags.has_value() && flags == last_flags.value() && repeat_count != 0xff) { - // NOTE: Update the previous entry to say it's repeating. - reconstructed_glyf_table[reconstructed_glyf_table.size() - 1] |= SimpleGlyphFlags::RepeatFlag; - ++repeat_count; - } else { - if (repeat_count != 0) { - TRY(reconstructed_glyf_table.try_append(repeat_count)); - repeat_count = 0; - } - TRY(reconstructed_glyf_table.try_append(flags)); - } - last_flags = flags; - } - if (repeat_count != 0) { - TRY(reconstructed_glyf_table.try_append(repeat_count)); - } - - for (auto& point : relative_points) { - if (point.x == 0) { - // No need to write to the table. - } else if (point.x > -256 && point.x < 256) { - TRY(reconstructed_glyf_table.try_append(abs(point.x))); - } else { - TRY(append_i16(point.x)); - } - } - - for (auto& point : relative_points) { - if (point.y == 0) { - // No need to write to the table. - } else if (point.y > -256 && point.y < 256) { - TRY(reconstructed_glyf_table.try_append(abs(point.y))); - } else { - TRY(append_i16(point.y)); - } + // Write n bytes of data from buf at offset. + // Return true if all written, false otherwise. + virtual bool Write(void const* data, size_t offset, size_t n) override + { + if (Checked::addition_would_overflow(offset, n)) { + return false; + } + if (offset + n > m_buffer.size()) { + if (m_buffer.try_resize(offset + n).is_error()) { + return false; } } - - // NOTE: Make sure each glyph starts on a 4-byte boundary. - // I haven't found the spec text for this, but it matches other implementations. - while (reconstructed_glyf_table.size() % 4 != 0) { - TRY(reconstructed_glyf_table.try_append(0)); - } - - TRY(loca_indexes.try_append(starting_glyf_table_size)); + memcpy(m_buffer.offset_pointer(offset), data, n); + return true; } - TRY(loca_indexes.try_append(reconstructed_glyf_table.size())); - - size_t loca_element_size_in_bytes = loca_element_size == LocaElementSize::TwoBytes ? sizeof(u16) : sizeof(u32); - size_t loca_table_buffer_size = loca_indexes.size() * loca_element_size_in_bytes; - ByteBuffer loca_table_buffer; - TRY(loca_table_buffer.try_ensure_capacity(loca_table_buffer_size)); - for (auto loca_index : loca_indexes) { - if (loca_element_size == LocaElementSize::TwoBytes) { - auto value = BigEndian(loca_index >> 1); - loca_table_buffer.append({ &value, sizeof(value) }); - } else { - auto value = BigEndian(loca_index); - loca_table_buffer.append({ &value, sizeof(value) }); - } + virtual size_t Size() override + { + return m_buffer.size(); } - return GlyfAndLocaTableBuffers { .glyf_table = move(reconstructed_glyf_table), .loca_table = move(loca_table_buffer) }; -} - -ErrorOr> Font::try_load_from_resource(Core::Resource const& resource) -{ - return try_load_from_externally_owned_memory(resource.data()); -} +private: + ByteBuffer& m_buffer; +}; ErrorOr> Font::try_load_from_externally_owned_memory(ReadonlyBytes bytes) { - FixedMemoryStream stream(bytes); - return try_load_from_externally_owned_memory(stream); -} - -ErrorOr> Font::try_load_from_externally_owned_memory(SeekableStream& stream) -{ - auto header = TRY(stream.read_value
()); - - // The signature field in the WOFF2 header MUST contain the value of 0x774F4632 ('wOF2'), which distinguishes it from WOFF 1.0 files. - // If the field does not contain this value, user agents MUST reject the file as invalid. - if (header.signature != WOFF2_SIGNATURE) - return Error::from_string_literal("Invalid WOFF2 signature"); - - // The interpretation of the WOFF2 Header is the same as the WOFF Header in [WOFF1], with the addition of one new totalCompressedSize field. - // NOTE: See WOFF/Font.cpp for more comments about this. - - static constexpr size_t MAX_BUFFER_SIZE = 10 * MiB; - if (header.length > TRY(stream.size())) - return Error::from_string_literal("Invalid WOFF length"); - if (header.num_tables == 0 || header.num_tables > NumericLimits::max() / 16) - return Error::from_string_literal("Invalid WOFF numTables"); - if (header.total_compressed_size > MAX_BUFFER_SIZE) - return Error::from_string_literal("Compressed font is more than 10 MiB"); - if (header.meta_length == 0 && header.meta_offset != 0) - return Error::from_string_literal("Invalid WOFF meta block offset"); - if (header.priv_length == 0 && header.priv_offset != 0) - return Error::from_string_literal("Invalid WOFF private block offset"); - if (header.flavor == TTCF_SIGNAURE) - return Error::from_string_literal("Font collections not yet supported"); - - // NOTE: "The "totalSfntSize" value in the WOFF2 Header is intended to be used for reference purposes only. It may represent the size of the uncompressed input font file, - // but if the transformed 'glyf' and 'loca' tables are present, the uncompressed size of the reconstructed tables and the total decompressed font size may differ - // substantially from the original total size specified in the WOFF2 Header." - // We use it as an initial size of the font buffer and extend it as necessary. - auto font_buffer_size = clamp(header.total_sfnt_size, sizeof(OpenType::TableDirectory) + header.num_tables * sizeof(TableDirectoryEntry), MAX_BUFFER_SIZE); - auto font_buffer = TRY(ByteBuffer::create_zeroed(font_buffer_size)); - - u16 search_range = pow_2_less_than_or_equal(header.num_tables); - OpenType::TableDirectory table_directory { - .sfnt_version = header.flavor, - .num_tables = header.num_tables, - .search_range = search_range * 16, - .entry_selector = log2(search_range), - .range_shift = header.num_tables * 16 - search_range * 16, - }; - font_buffer.overwrite(0, &table_directory, sizeof(table_directory)); - - Vector table_entries; - TRY(table_entries.try_ensure_capacity(header.num_tables)); - - u64 total_length_of_all_tables = 0; - - for (size_t table_entry_index = 0; table_entry_index < header.num_tables; ++table_entry_index) { - TableDirectoryEntry table_directory_entry; - u8 const flags_byte = TRY(stream.read_value()); - - switch ((flags_byte & 0xC0) >> 6) { - case 0: - table_directory_entry.transformation_version = TransformationVersion::Version0; - break; - case 1: - table_directory_entry.transformation_version = TransformationVersion::Version1; - break; - case 2: - table_directory_entry.transformation_version = TransformationVersion::Version2; - break; - case 3: - table_directory_entry.transformation_version = TransformationVersion::Version3; - break; - default: - VERIFY_NOT_REACHED(); - } - - u8 tag_number = flags_byte & 0x3F; - - if (tag_number != 0x3F) { - table_directory_entry.tag = known_tag_names[tag_number]; - } else { - table_directory_entry.tag = TRY(stream.read_value()); - } - - table_directory_entry.original_length = TRY(read_uint_base_128(stream)); - - bool needs_to_read_transform_length = false; - if (table_directory_entry.tag == OpenType::Tag("glyf") || table_directory_entry.tag == OpenType::Tag("loca")) - needs_to_read_transform_length = table_directory_entry.transformation_version == TransformationVersion::Version0; - else - needs_to_read_transform_length = table_directory_entry.transformation_version != TransformationVersion::Version0; - - if (needs_to_read_transform_length) { - u32 transform_length = TRY(read_uint_base_128(stream)); - table_directory_entry.transform_length = transform_length; - total_length_of_all_tables += transform_length; - } else { - total_length_of_all_tables += table_directory_entry.original_length; - } - - table_entries.unchecked_append(move(table_directory_entry)); + auto ttf_buffer = TRY(ByteBuffer::create_uninitialized(0)); + auto output = WOFF2ByteBufferOut { ttf_buffer }; + auto result = woff2::ConvertWOFF2ToTTF(bytes.data(), bytes.size(), &output); + if (!result) { + return Error::from_string_literal("Failed to convert the WOFF2 font to TTF"); } - - // FIXME: Read in collection header and entries. - - auto glyf_table = table_entries.find_if([](TableDirectoryEntry const& entry) { - return entry.tag == OpenType::Tag("glyf"); - }); - - auto loca_table = table_entries.find_if([](TableDirectoryEntry const& entry) { - return entry.tag == OpenType::Tag("loca"); - }); - - // "In other words, both glyf and loca tables must either be present in their transformed format or with null transform applied to both tables." - if (glyf_table.is_end() != loca_table.is_end()) - return Error::from_string_literal("Must have both 'loca' and 'glyf' tables if one of them is present"); - - if (!glyf_table.is_end() && !loca_table.is_end()) { - if (glyf_table->transformation_version != loca_table->transformation_version) - return Error::from_string_literal("The 'loca' and 'glyf' tables must have the same transformation version"); - } - - if (!loca_table.is_end()) { - if (loca_table->has_transformation() && loca_table->transform_length.value() != 0) - return Error::from_string_literal("Transformed 'loca' table must have a transform length of 0"); - } - - auto compressed_bytes_read_buffer = TRY(ByteBuffer::create_zeroed(header.total_compressed_size)); - auto compressed_bytes = TRY(stream.read_some(compressed_bytes_read_buffer)); - if (compressed_bytes.size() != header.total_compressed_size) - return Error::from_string_literal("Not enough data to read in the reported size of the compressed data"); - - auto compressed_stream = FixedMemoryStream(compressed_bytes); - auto brotli_stream = Compress::BrotliDecompressionStream { MaybeOwned(compressed_stream) }; - auto decompressed_table_data = TRY(brotli_stream.read_until_eof()); - if (decompressed_table_data.size() != total_length_of_all_tables) - return Error::from_string_literal("Size of the decompressed data is not equal to the total of the reported lengths of each table"); - - auto decompressed_data_stream = FixedMemoryStream(decompressed_table_data.bytes()); - size_t font_buffer_offset = SFNT_HEADER_SIZE + header.num_tables * SFNT_TABLE_SIZE; - Optional glyf_and_loca_buffer; - for (size_t table_entry_index = 0; table_entry_index < header.num_tables; ++table_entry_index) { - auto& table_entry = table_entries.at(table_entry_index); - u32 length_to_read = table_entry.has_transformation() ? table_entry.transform_length.value() : table_entry.original_length; - - auto table_buffer = TRY(ByteBuffer::create_zeroed(length_to_read)); - auto table_bytes = TRY(decompressed_data_stream.read_some(table_buffer)); - if (table_bytes.size() != length_to_read) - return Error::from_string_literal("Not enough data to read decompressed table"); - - size_t table_directory_offset = SFNT_HEADER_SIZE + table_entry_index * SFNT_TABLE_SIZE; - - if (table_entry.has_transformation()) { - if (table_entry.tag == OpenType::Tag("glyf")) { - auto table_stream = FixedMemoryStream(table_bytes); - glyf_and_loca_buffer = TRY(create_glyf_and_loca_tables_from_transformed_glyf_table(table_stream)); - - if (font_buffer.size() < (font_buffer_offset + glyf_and_loca_buffer->glyf_table.size())) - TRY(font_buffer.try_resize(font_buffer_offset + glyf_and_loca_buffer->glyf_table.size())); - - OpenType::TableRecord table_record { - .table_tag = table_entry.tag, - .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. - .offset = font_buffer_offset, - .length = glyf_and_loca_buffer->glyf_table.size(), - }; - font_buffer.overwrite(table_directory_offset, &table_record, sizeof(table_record)); - - font_buffer.overwrite(font_buffer_offset, glyf_and_loca_buffer->glyf_table.data(), glyf_and_loca_buffer->glyf_table.size()); - font_buffer_offset += glyf_and_loca_buffer->glyf_table.size(); - } else if (table_entry.tag == OpenType::Tag("loca")) { - // FIXME: Handle loca table coming before glyf table in input? - VERIFY(glyf_and_loca_buffer.has_value()); - if (font_buffer.size() < (font_buffer_offset + glyf_and_loca_buffer->loca_table.size())) - TRY(font_buffer.try_resize(font_buffer_offset + glyf_and_loca_buffer->loca_table.size())); - - OpenType::TableRecord table_record { - .table_tag = table_entry.tag, - .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. - .offset = font_buffer_offset, - .length = glyf_and_loca_buffer->loca_table.size(), - }; - font_buffer.overwrite(table_directory_offset, &table_record, sizeof(table_record)); - - font_buffer.overwrite(font_buffer_offset, glyf_and_loca_buffer->loca_table.data(), glyf_and_loca_buffer->loca_table.size()); - font_buffer_offset += glyf_and_loca_buffer->loca_table.size(); - } else if (table_entry.tag == OpenType::Tag("hmtx")) { - return Error::from_string_literal("Decoding transformed hmtx table not yet supported"); - } else { - return Error::from_string_literal("Unknown transformation"); - } - } else { - OpenType::TableRecord table_record { - .table_tag = table_entry.tag, - .checksum = 0, // FIXME: WOFF2 does not give us the original checksum. - .offset = font_buffer_offset, - .length = length_to_read, - }; - font_buffer.overwrite(table_directory_offset, &table_record, sizeof(table_record)); - - if (font_buffer.size() < (font_buffer_offset + length_to_read)) - TRY(font_buffer.try_resize(font_buffer_offset + length_to_read)); - font_buffer.overwrite(font_buffer_offset, table_buffer.data(), length_to_read); - - font_buffer_offset += length_to_read; - } - } - - auto input_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_buffer.bytes())); - return adopt_ref(*new Font(input_font, move(font_buffer))); + auto input_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(ttf_buffer.bytes())); + return adopt_ref(*new Font(input_font, move(ttf_buffer))); } } diff --git a/Userland/Libraries/LibGfx/Font/WOFF2/Font.h b/Userland/Libraries/LibGfx/Font/WOFF2/Font.h index 36ea4acc5bd..ad08eb7cd04 100644 --- a/Userland/Libraries/LibGfx/Font/WOFF2/Font.h +++ b/Userland/Libraries/LibGfx/Font/WOFF2/Font.h @@ -21,8 +21,6 @@ class Font : public Gfx::VectorFont { AK_MAKE_NONCOPYABLE(Font); public: - static ErrorOr> try_load_from_resource(Core::Resource const&); - static ErrorOr> try_load_from_externally_owned_memory(SeekableStream&); static ErrorOr> try_load_from_externally_owned_memory(ReadonlyBytes); virtual Gfx::ScaledFontMetrics metrics(float x_scale, float y_scale) const override { return m_input_font->metrics(x_scale, y_scale); } diff --git a/vcpkg-configuration.json b/vcpkg-configuration.json index 4bca4e6cb57..5274e2d59e6 100644 --- a/vcpkg-configuration.json +++ b/vcpkg-configuration.json @@ -1,9 +1,4 @@ { - "default-registry": { - "kind": "git", - "baseline": "01f602195983451bc83e72f4214af2cbc495aa94", - "repository": "https://github.com/microsoft/vcpkg" - }, "registries": [ { "kind": "artifact", diff --git a/vcpkg.json b/vcpkg.json index a91bca6ca84..dfe14428e60 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,11 +1,17 @@ { + "builtin-baseline": "01f602195983451bc83e72f4214af2cbc495aa94", "dependencies": [ - "sqlite3" + "sqlite3", + "woff2" ], "overrides": [ { "name": "sqlite3", "version": "3.45.3" + }, + { + "name": "woff2", + "version": "1.0.2#4" } ] }