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 <aa...@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()) {

Reply via email to