浏览代码

LibPDF: Implement stream CIDToGIDMaps for Type0 CIDFontType2 fonts

Of my 1000 test files, 73 have stream Type0 truetype fonts with stream
CIDToGIDMaps. This makes that work.

(With this patch, the number of files in my 1000 test files complaining
"Font is missing Name" increases from 41 to 75, so a bit under half of
the fonts using stream CIDToGIDMaps also have no 'name' table. So that's
next.)

Increases files without issues from 652 to 681.
Nico Weber 1 年之前
父节点
当前提交
012f6d46e7
共有 1 个文件被更改,包括 42 次插入13 次删除
  1. 42 13
      Userland/Libraries/LibPDF/Fonts/Type0Font.cpp

+ 42 - 13
Userland/Libraries/LibPDF/Fonts/Type0Font.cpp

@@ -129,32 +129,61 @@ private:
     RefPtr<Gfx::Font> m_font;
 };
 
-PDFErrorOr<NonnullOwnPtr<CIDFontType2>> CIDFontType2::create(Document* document, NonnullRefPtr<DictObject> const& descendant, float font_size)
+static PDFErrorOr<NonnullOwnPtr<OpenType::CharCodeToGlyphIndex>> create_cid_to_gid_map(Document* document, NonnullRefPtr<DictObject> const& dict)
 {
-    auto descriptor = TRY(descendant->get_dict(document, CommonNames::FontDescriptor));
-
-    if (descendant->contains(CommonNames::CIDToGIDMap)) {
-        auto value = TRY(descendant->get_object(document, CommonNames::CIDToGIDMap));
-        if (value->is<StreamObject>()) {
-            return Error::rendering_unsupported_error("Type0 font subtype 2: support for stream cid maps not yet implemented");
-        } else if (value->cast<NameObject>()->name() != "Identity") {
-            return Error::rendering_unsupported_error("Type0 font: support for non-Identity named cid maps not yet implemented");
-        }
-    }
+    // "If the value is a stream, the bytes in the stream contain the mapping from CIDs to glyph indices:
+    //  the glyph index for a particular CID value c is a 2-byte value stored in bytes 2×c and 2×c+1, where the first byte is the high-order byte.
+    //  If the value of CIDToGIDMap is a name, it must be Identity, indicating that the mapping between CIDs and glyph indices is the identity mapping.
+    //  Default value: Identity."
 
     class IdentityCIDToGIDMap : public OpenType::CharCodeToGlyphIndex {
     public:
+        virtual u32 glyph_id_for_code_point(u32 char_code) const override { return char_code; }
+    };
+
+    class StreamCIDToGIDMap : public OpenType::CharCodeToGlyphIndex {
+    public:
+        StreamCIDToGIDMap(ReadonlyBytes bytes)
+            : m_bytes(move(bytes))
+        {
+        }
         virtual u32 glyph_id_for_code_point(u32 char_code) const override
         {
-            return char_code;
+            u32 index = char_code * 2;
+            if (index + 1 >= m_bytes.size()) {
+                // This can happen because Font::populate_glyph_page() with CIDs not used on the page and hence not in the font.
+                return 0;
+            }
+            return (m_bytes[index] << 8) | m_bytes[index + 1];
         }
+
+    private:
+        ReadonlyBytes m_bytes;
     };
 
+    if (!dict->contains(CommonNames::CIDToGIDMap))
+        return make<IdentityCIDToGIDMap>();
+
+    auto value = TRY(dict->get_object(document, CommonNames::CIDToGIDMap));
+    if (value->is<StreamObject>())
+        return make<StreamCIDToGIDMap>(value->cast<StreamObject>()->bytes());
+
+    if (value->cast<NameObject>()->name() != "Identity")
+        return Error::rendering_unsupported_error("Type0 font: The only valid CIDToGIDMap name is 'Identity'");
+    return make<IdentityCIDToGIDMap>();
+}
+
+PDFErrorOr<NonnullOwnPtr<CIDFontType2>> CIDFontType2::create(Document* document, NonnullRefPtr<DictObject> const& descendant, float font_size)
+{
+    auto descriptor = TRY(descendant->get_dict(document, CommonNames::FontDescriptor));
+
+    auto cid_to_gid_map = TRY(create_cid_to_gid_map(document, descendant));
+
     RefPtr<Gfx::Font> font;
     if (descriptor->contains(CommonNames::FontFile2)) {
         auto font_file_stream = TRY(descriptor->get_stream(document, CommonNames::FontFile2));
         float point_size = (font_size * POINTS_PER_INCH) / DEFAULT_DPI;
-        auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), 0, make<IdentityCIDToGIDMap>()));
+        auto ttf_font = TRY(OpenType::Font::try_load_from_externally_owned_memory(font_file_stream->bytes(), 0, move(cid_to_gid_map)));
         font = adopt_ref(*new Gfx::ScaledFont(*ttf_font, point_size, point_size));
     }