diff --git a/CHANGELOG.md b/CHANGELOG.md index ea9db8210..8a2af59db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,9 @@ The release run heads these entries with the version and opens a fresh ## Unreleased +- **Fix**: a pdf CFF font with no glyph but `.notdef` is no longer embedded, + because browsers reject it. Its text uses a substitute font. + - **Fix**: a pdf whose zlib streams declare a smaller window than they use failed to open with "Inflator: error in compressed block". It opens now. diff --git a/src/odr/internal/font/cff_transform.cpp b/src/odr/internal/font/cff_transform.cpp index 7dfa79618..b06f9f458 100644 --- a/src/odr/internal/font/cff_transform.cpp +++ b/src/odr/internal/font/cff_transform.cpp @@ -136,6 +136,10 @@ namespace odr::internal::font { std::string cff::wrap_to_otf(const CffFont &font, const std::map &extra) { const std::uint16_t glyphs = font.glyph_count(); + if (glyphs < 2) { + // OTS rejects a `CFF ` table whose CharStrings hold only `.notdef`. + throw std::runtime_error("cff: no glyph besides .notdef"); + } // Glyphs past the 6400-slot BMP PUA overflow into Supplementary PUA-A, which // serialize_cmap covers with a format-12 subtable. diff --git a/src/odr/internal/font/cff_transform.hpp b/src/odr/internal/font/cff_transform.hpp index 838e5d04a..b835e4e07 100644 --- a/src/odr/internal/font/cff_transform.hpp +++ b/src/odr/internal/font/cff_transform.hpp @@ -18,7 +18,7 @@ class CffFont; /// /// The `cmap` is `pua_cmap(glyph_count, extra)`, so the font renders every /// glyph — including charset-unreachable ones — at the PUA code points the PDF -/// HTML layer emits. +/// HTML layer emits. Throws for a font with no glyph besides `.notdef`. [[nodiscard]] std::string wrap_to_otf(const CffFont &font, const std::map &extra = {}); diff --git a/test/data.cmake b/test/data.cmake index c8dbf66e6..68bbf75a6 100644 --- a/test/data.cmake +++ b/test/data.cmake @@ -17,9 +17,9 @@ odr_test_data( odr_test_data( PATH "reference-output/odr-public" URL "https://github.com/opendocument-app/OpenDocument.test.output.git" - REVISION "542037eec472235ed0ada025fb41de76f082ea6e") + REVISION "055e7ec00193112b0759c1189463ef17ca892201") odr_test_data( PATH "reference-output/odr-private" URL "https://github.com/opendocument-app/OpenDocument.test-private.output.git" - REVISION "78502f22a1c2631825476daa3351843f9f6c60ae") + REVISION "509b8191ac4ef3be1d5e14c0f69647d586dbe6c5") diff --git a/test/src/internal/font/cff_font.cpp b/test/src/internal/font/cff_font.cpp index d3d0c445c..bf1650b50 100644 --- a/test/src/internal/font/cff_font.cpp +++ b/test/src/internal/font/cff_font.cpp @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -491,6 +492,16 @@ TEST(CffFontTest, WrapSanitizesTheFontName) { EXPECT_EQ(patched.advance_width(1), cff.advance_width(1)); } +TEST(CffFontTest, WrapRejectsAFontOfOnlyNotdef) { + using namespace odr::internal::font; + const std::vector glyphs = { + {".notdef", std::string("\x0e", 1)}}; + const cff::CffFont font{ + cff::build_cff("Hidden", glyphs, 0, 0, FontBBox{0, 0, 1000, 1000})}; + ASSERT_EQ(font.glyph_count(), 1); + EXPECT_THROW((void)cff::wrap_to_otf(font), std::runtime_error); +} + TEST(CffFontTest, WrapDropsExtraEntriesPastGlyphCount) { using namespace odr::internal::font; const CffFont cff{build_cff()}; // 2 glyphs: valid ids 0..1