[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