Przeglądaj źródła

LibGfx: Tweak semantics of some SkipTables enum values

It turns out that hmtx and OS/2 table values _are_ used when
rendering OpenType for PDFs: hmtx is used for the left-side bearing
value (which is read in `Painter::draw_glyph()`), and OS/2 is used
for the ascender, which Type0's CIDFontType2::draw_glyph()
and TrueTypeFont::draw_glyph() read.

So instead of not trying to read these tables, instead try to read
them but tolerate them failing to read and ignore them then.

Follow-up to #23276.

(I've seen weird glyph positioning from not reading the hmtx table.
I haven't seen any problems caused by not reading the OS/2 table yet,
but since the PDF code does use the ascender value, let's read that
too.)
Nico Weber 1 rok temu
rodzic
commit
78b3c552c2

+ 15 - 7
Userland/Libraries/LibGfx/Font/OpenType/Font.cpp

@@ -271,11 +271,16 @@ ErrorOr<NonnullRefPtr<Font>> Font::try_load_from_offset(ReadonlyBytes buffer, u3
         return Error::from_string_literal("Font is missing Maxp");
     auto maxp = TRY(Maxp::from_slice(opt_maxp_slice.value()));
 
+    bool can_omit_hmtx = (options.skip_tables & Options::SkipTables::Hmtx);
     Optional<Hmtx> hmtx;
-    if (!(options.skip_tables & Options::SkipTables::Hmtx)) {
-        if (!opt_hmtx_slice.has_value())
-            return Error::from_string_literal("Font is missing Hmtx");
-        hmtx = TRY(Hmtx::from_slice(opt_hmtx_slice.value(), maxp.num_glyphs(), hhea.number_of_h_metrics()));
+    if (opt_hmtx_slice.has_value()) {
+        auto hmtx_or_error = Hmtx::from_slice(opt_hmtx_slice.value(), maxp.num_glyphs(), hhea.number_of_h_metrics());
+        if (!hmtx_or_error.is_error())
+            hmtx = hmtx_or_error.release_value();
+        else if (!can_omit_hmtx)
+            return hmtx_or_error.release_error();
+    } else if (!can_omit_hmtx) {
+        return Error::from_string_literal("Font is missing Hmtx");
     }
 
     if (!options.external_cmap && !opt_cmap_slice.has_value())
@@ -292,9 +297,12 @@ ErrorOr<NonnullRefPtr<Font>> Font::try_load_from_offset(ReadonlyBytes buffer, u3
     }
 
     Optional<OS2> os2;
-    if (!(options.skip_tables & Options::SkipTables::OS2)) {
-        if (opt_os2_slice.has_value())
-            os2 = TRY(OS2::from_slice(opt_os2_slice.value()));
+    if (opt_os2_slice.has_value()) {
+        auto os2_or_error = OS2::from_slice(opt_os2_slice.value());
+        if (!os2_or_error.is_error())
+            os2 = os2_or_error.release_value();
+        else if (!(options.skip_tables & Options::SkipTables::OS2))
+            return os2_or_error.release_error();
     }
 
     Optional<Kern> kern {};

+ 2 - 2
Userland/Libraries/LibGfx/Font/OpenType/Font.h

@@ -35,10 +35,10 @@ struct FontOptions {
         // If set, do not try to read the 'name' table. family() and variant() will return empty strings.
         Name = 1 << 0,
 
-        // If set, do not try to read the 'hmtx' table. This will make glyph_metrics() return 0 for everyting and is_fixed_width() return true.
+        // If set, tolerate a missing or broken 'hmtx' table. This will make glyph_metrics() return 0 for everyting and is_fixed_width() return true.
         Hmtx = 1 << 1,
 
-        // If set, do not try to read the 'OS/2' table. metrics(), resolve_ascender_and_descender(), weight(), width(), and slope() will return different values.
+        // If set, tolerate a missing or broken 'OS/2' table. metrics(), resolve_ascender_and_descender(), weight(), width(), and slope() will return different values.
         OS2 = 1 << 2,
     };
     u32 skip_tables { 0 };