[poppler] poppler/Form.cc poppler/Form.h poppler/PDFDoc.cc qt5/src qt6/src

GitLab Mirror gitlab-mirror at kemper.freedesktop.org
Sat May 21 21:55:09 UTC 2022


 poppler/Form.cc               |   52 +++++++++++++++++++++++++++++++-----------
 poppler/Form.h                |   16 +++++++++---
 poppler/PDFDoc.cc             |    2 -
 qt5/src/poppler-annotation.cc |    2 -
 qt6/src/poppler-annotation.cc |    2 -
 5 files changed, 54 insertions(+), 20 deletions(-)

New commits:
commit b700e0b254ed35b672b85bb86d6a81877fe30e10
Author: Albert Astals Cid <aacid at kde.org>
Date:   Tue May 17 00:52:04 2022 +0200

    Forms: Fix crash in forms with their own DR
    
    When adding potentially missing fonts to the PDF file because we have
    written a letter like ħ that is not available on the form font, if the
    form has their own DR, we also need to add the font to that DR Font dict
    and not only to the global Form one (in theory we would only have to add
    it to the particular form one and not to the global, but it's easier
    this way and it's not like we're adding the data twice, we're just
    adding the Ref to two dicts)

diff --git a/poppler/Form.cc b/poppler/Form.cc
index 5ee1e221..acd52014 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -697,7 +697,7 @@ bool FormWidgetSignature::signDocumentWithAppearance(const char *saveFilename, c
     Form *form = doc->getCatalog()->getForm();
     std::string pdfFontName = form->findFontInDefaultResources("Helvetica", "");
     if (pdfFontName.empty()) {
-        pdfFontName = form->addFontToDefaultResources("Helvetica", "");
+        pdfFontName = form->addFontToDefaultResources("Helvetica", "").fontName;
     }
 
     const DefaultAppearance da { { objName, pdfFontName.c_str() }, fontSize, std::move(fontColor) };
@@ -1668,7 +1668,19 @@ void FormFieldText::setContentCopy(const GooString *new_content)
             if (da.getFontName().isName()) {
                 const std::string fontName = da.getFontName().getName();
                 if (!fontName.empty()) {
-                    form->ensureFontsForAllCharacters(new_content, fontName);
+                    // Use the field resource dictionary if it exists
+                    Object fieldResourcesDictObj = obj.dictLookup("DR");
+                    if (fieldResourcesDictObj.isDict()) {
+                        GfxResources fieldResources(doc->getXRef(), fieldResourcesDictObj.getDict(), form->getDefaultResources());
+                        const std::vector<Form::AddFontResult> newFonts = form->ensureFontsForAllCharacters(new_content, fontName, &fieldResources);
+                        // If we added new fonts to the Form object default resuources we also need to add them (we only add the ref so this is cheap)
+                        // to the field DR dictionary
+                        for (const Form::AddFontResult &afr : newFonts) {
+                            fieldResourcesDictObj.dictLookup("Font").dictAdd(afr.fontName.c_str(), Object(afr.ref));
+                        }
+                    } else {
+                        form->ensureFontsForAllCharacters(new_content, fontName);
+                    }
                 }
             } else {
                 // This is wrong, there has to be a Tf in DA
@@ -2707,14 +2719,14 @@ std::string Form::findFontInDefaultResources(const std::string &fontFamily, cons
     return {};
 }
 
-std::string Form::addFontToDefaultResources(const std::string &fontFamily, const std::string &fontStyle)
+Form::AddFontResult Form::addFontToDefaultResources(const std::string &fontFamily, const std::string &fontStyle)
 {
     const FamilyStyleFontSearchResult res = globalParams->findSystemFontFileForFamilyAndStyle(fontFamily, fontStyle);
 
     return addFontToDefaultResources(res.filepath, res.faceIndex, fontFamily, fontStyle);
 }
 
-std::string Form::addFontToDefaultResources(const std::string &filepath, int faceIndex, const std::string &fontFamily, const std::string &fontStyle)
+Form::AddFontResult Form::addFontToDefaultResources(const std::string &filepath, int faceIndex, const std::string &fontFamily, const std::string &fontStyle)
 {
     if (!GooString::endsWith(filepath, ".ttf") && !GooString::endsWith(filepath, ".ttc") && !GooString::endsWith(filepath, ".otf")) {
         error(errIO, -1, "We only support embedding ttf/ttc/otf fonts for now. The font file for %s %s was %s", fontFamily.c_str(), fontStyle.c_str(), filepath.c_str());
@@ -2924,7 +2936,7 @@ std::string Form::addFontToDefaultResources(const std::string &filepath, int fac
         doc->getCatalog()->setAcroFormModified();
     }
 
-    return dictFontName;
+    return { dictFontName, fontDictRef };
 }
 
 std::string Form::getFallbackFontForChar(Unicode uChar, const GfxFont &fontToEmulate) const
@@ -2934,45 +2946,59 @@ std::string Form::getFallbackFontForChar(Unicode uChar, const GfxFont &fontToEmu
     return findFontInDefaultResources(res.family, res.style);
 }
 
-void Form::ensureFontsForAllCharacters(const GooString *unicodeText, const std::string &pdfFontNameToEmulate)
+std::vector<Form::AddFontResult> Form::ensureFontsForAllCharacters(const GooString *unicodeText, const std::string &pdfFontNameToEmulate, GfxResources *fieldResources)
 {
-    std::shared_ptr<GfxFont> f = defaultResources->lookupFont(pdfFontNameToEmulate.c_str());
+    GfxResources *resources = fieldResources ? fieldResources : defaultResources;
+    std::shared_ptr<GfxFont> f = resources->lookupFont(pdfFontNameToEmulate.c_str());
     const CharCodeToUnicode *ccToUnicode = f->getToUnicode();
     if (!ccToUnicode) {
-        return; // will never happen with current code
+        error(errInternal, -1, "Form::ensureFontsForAllCharacters: No ccToUnicode, this should not happen\n");
+        return {}; // will never happen with current code
     }
 
+    std::vector<AddFontResult> newFonts;
+
     // If the text has some characters that are not available in the font, try adding a font for those
     for (int i = 2; i < unicodeText->getLength(); i += 2) {
         Unicode uChar = (unsigned char)(unicodeText->getChar(i)) << 8;
         uChar += (unsigned char)(unicodeText->getChar(i + 1));
 
         CharCode c;
+        bool addFont = false;
         if (ccToUnicode->mapToCharCode(&uChar, &c, 1)) {
             if (f->isCIDFont()) {
                 auto cidFont = static_cast<const GfxCIDFont *>(f.get());
                 if (c < cidFont->getCIDToGIDLen() && c != 0 && c != '\r' && c != '\n') {
                     const int glyph = cidFont->getCIDToGID()[c];
                     if (glyph == 0) {
-                        doGetAddFontToDefaultResources(uChar, *f);
+                        addFont = true;
                     }
                 }
             }
         } else {
-            doGetAddFontToDefaultResources(uChar, *f);
+            addFont = true;
+        }
+
+        if (addFont) {
+            Form::AddFontResult res = doGetAddFontToDefaultResources(uChar, *f);
+            if (res.ref != Ref::INVALID()) {
+                newFonts.emplace_back(res);
+            }
         }
     }
+
+    return newFonts;
 }
 
-std::string Form::doGetAddFontToDefaultResources(Unicode uChar, const GfxFont &fontToEmulate)
+Form::AddFontResult Form::doGetAddFontToDefaultResources(Unicode uChar, const GfxFont &fontToEmulate)
 {
     const UCharFontSearchResult res = globalParams->findSystemFontFileForUChar(uChar, fontToEmulate);
 
     std::string pdfFontName = findFontInDefaultResources(res.family, res.style);
     if (pdfFontName.empty()) {
-        pdfFontName = addFontToDefaultResources(res.filepath, res.faceIndex, res.family, res.style);
+        return addFontToDefaultResources(res.filepath, res.faceIndex, res.family, res.style);
     }
-    return pdfFontName;
+    return { pdfFontName, Ref::INVALID() };
 }
 
 void Form::postWidgetsLoad()
diff --git a/poppler/Form.h b/poppler/Form.h
index 9017bd42..248dcb2e 100644
--- a/poppler/Form.h
+++ b/poppler/Form.h
@@ -682,9 +682,15 @@ public:
     // has the given fontFamily and fontStyle. This makes us relatively sure that we added that font ourselves
     std::string findFontInDefaultResources(const std::string &fontFamily, const std::string &fontStyle) const;
 
+    struct AddFontResult
+    {
+        std::string fontName;
+        Ref ref;
+    };
+
     // Finds in the system a font name matching the given fontFamily and fontStyle
     // And adds it to the default resources dictionary, font name there will be popplerfontXXX
-    std::string addFontToDefaultResources(const std::string &fontFamily, const std::string &fontStyle);
+    AddFontResult addFontToDefaultResources(const std::string &fontFamily, const std::string &fontStyle);
 
     // Finds in the default resources dictionary a font named popplerfontXXX that
     // emulates fontToEmulate and can draw the given char
@@ -692,7 +698,9 @@ public:
 
     // Makes sure the default resources has fonts to draw all the given chars and as close as possible to the given pdfFontNameToEmulate
     // If needed adds fonts to the default resources dictionary, font names will be popplerfontXXX
-    void ensureFontsForAllCharacters(const GooString *unicodeText, const std::string &pdfFontNameToEmulate);
+    // If fieldResources is not nullptr, it is used instead of the to query the font to emulate instead of the default resources
+    // Returns a list of all the added fonts (if any)
+    std::vector<AddFontResult> ensureFontsForAllCharacters(const GooString *unicodeText, const std::string &pdfFontNameToEmulate, GfxResources *fieldResources = nullptr);
 
     bool getNeedAppearances() const { return needAppearances; }
     int getNumFields() const { return numFields; }
@@ -715,9 +723,9 @@ public:
 private:
     // Finds in the system a font name matching the given fontFamily and fontStyle
     // And adds it to the default resources dictionary, font name there will be popplerfontXXX
-    std::string addFontToDefaultResources(const std::string &filepath, int faceIndex, const std::string &fontFamily, const std::string &fontStyle);
+    AddFontResult addFontToDefaultResources(const std::string &filepath, int faceIndex, const std::string &fontFamily, const std::string &fontStyle);
 
-    std::string doGetAddFontToDefaultResources(Unicode uChar, const GfxFont &fontToEmulate);
+    AddFontResult doGetAddFontToDefaultResources(Unicode uChar, const GfxFont &fontToEmulate);
 
     FormField **rootFields;
     int numFields;
diff --git a/poppler/PDFDoc.cc b/poppler/PDFDoc.cc
index 25d0b56a..351140af 100644
--- a/poppler/PDFDoc.cc
+++ b/poppler/PDFDoc.cc
@@ -2126,7 +2126,7 @@ bool PDFDoc::sign(const char *saveFilename, const char *certNickname, const char
     Form *form = catalog->getCreateForm();
     std::string pdfFontName = form->findFontInDefaultResources("Helvetica", "");
     if (pdfFontName.empty()) {
-        pdfFontName = form->addFontToDefaultResources("Helvetica", "");
+        pdfFontName = form->addFontToDefaultResources("Helvetica", "").fontName;
     }
 
     const DefaultAppearance da { { objName, pdfFontName.c_str() }, fontSize, std::move(fontColor) };
diff --git a/qt5/src/poppler-annotation.cc b/qt5/src/poppler-annotation.cc
index a1804cb5..8378ea69 100644
--- a/qt5/src/poppler-annotation.cc
+++ b/qt5/src/poppler-annotation.cc
@@ -1991,7 +1991,7 @@ void TextAnnotationPrivate::setDefaultAppearanceToNative()
             if (form) {
                 fontName = form->findFontInDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString());
                 if (fontName.empty()) {
-                    fontName = form->addFontToDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString());
+                    fontName = form->addFontToDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString()).fontName;
                 }
 
                 if (!fontName.empty()) {
diff --git a/qt6/src/poppler-annotation.cc b/qt6/src/poppler-annotation.cc
index 4232fe8a..940ea12d 100644
--- a/qt6/src/poppler-annotation.cc
+++ b/qt6/src/poppler-annotation.cc
@@ -1629,7 +1629,7 @@ void TextAnnotationPrivate::setDefaultAppearanceToNative()
             if (form) {
                 fontName = form->findFontInDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString());
                 if (fontName.empty()) {
-                    fontName = form->addFontToDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString());
+                    fontName = form->addFontToDefaultResources(textFont->family().toStdString(), textFont->styleName().toStdString()).fontName;
                 }
 
                 if (!fontName.empty()) {


More information about the poppler mailing list