[poppler] poppler/Annot.cc poppler/Annot.h qt5/src qt6/src
GitLab Mirror
gitlab-mirror at kemper.freedesktop.org
Tue Jul 6 22:53:25 UTC 2021
poppler/Annot.cc | 126 ++++++++++++++++++---------------------
poppler/Annot.h | 17 ++---
qt5/src/poppler-pdf-converter.cc | 4 -
qt6/src/poppler-pdf-converter.cc | 4 -
4 files changed, 71 insertions(+), 80 deletions(-)
New commits:
commit e674ca6453f3f20c4bf0cb463222a97c99221dd6
Author: Zachary Travis <ztravis at everlaw.com>
Date: Tue Jul 6 22:53:22 2021 +0000
Create fallback fonts as needed.
If a PDF form field value uses a font that is not in the resources dictionary, a warning is logged and the field value is ignored/not displayed. It's unclear whether this behavior is strictly valid based on the PDF spec (since typically font references, even to base fonts, require a corresponding font dictionary) but Acrobat seems to display the content anyway.
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 0e36b209..66db4a32 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -245,6 +245,21 @@ static const char *getFormAdditionalActionKey(Annot::FormAdditionalActionsType t
return (type == Annot::actionFieldModified ? "K" : type == Annot::actionFormatField ? "F" : type == Annot::actionValidateField ? "V" : type == Annot::actionCalculateField ? "C" : nullptr);
}
+static const char *determineFallbackFont(GooString *tok, const char *defaultFallback)
+{
+ // TODO: adjust these based on other example PDFs.
+ if (!tok->cmp("/ZaDb")) {
+ return "ZapfDingbats";
+ } else if (!tok->cmp("/Cour")) {
+ return "Courier";
+ } else if (!tok->cmp("/TiRo")) {
+ return "TimesNewRoman";
+ } else if (!tok->cmp("/Helvetica-Bold")) {
+ return "Helvetica-Bold";
+ }
+ return defaultFallback;
+}
+
//------------------------------------------------------------------------
// AnnotBorderEffect
//------------------------------------------------------------------------
@@ -2852,7 +2867,9 @@ static GfxFont *createAnnotDrawFont(XRef *xref, Dict *fontParentDict, const char
Dict *fontDict = new Dict(xref);
fontDict->add("BaseFont", Object(objName, fontname));
fontDict->add("Subtype", Object(objName, "Type1"));
- fontDict->add("Encoding", Object(objName, "WinAnsiEncoding"));
+ if (strcmp(fontname, "ZapfDingbats") && strcmp(fontname, "Symbol")) {
+ fontDict->add("Encoding", Object(objName, "WinAnsiEncoding"));
+ }
Object fontsDictObj = fontParentDict->lookup("Font");
if (!fontsDictObj.isDict()) {
@@ -4110,7 +4127,7 @@ void AnnotAppearanceBuilder::writeString(const GooString &str)
// Draw the variable text or caption for a field.
bool AnnotAppearanceBuilder::drawText(const GooString *text, const GooString *da, const GfxResources *resources, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, bool multiline, int comb,
- int quadding, bool txField, bool forceZapfDingbats, XRef *xref, bool *addedDingbatsResource, bool password)
+ int quadding, bool txField, bool forceZapfDingbats, XRef *xref, bool password, Dict *resourcesDict, const char *defaultFallback)
{
std::vector<GooString *> *daToks;
GooString *tok;
@@ -4154,36 +4171,24 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, const GooString *da
daToks = nullptr;
}
- // force ZapfDingbats
- if (forceZapfDingbats) {
- assert(xref != nullptr);
- assert(addedDingbatsResource != nullptr);
- *addedDingbatsResource = false;
-
- if (tfPos >= 0) {
- tok = (*daToks)[tfPos];
- if (tok->cmp("/ZaDb")) {
- tok->clear();
- tok->append("/ZaDb");
- }
- }
- }
// get the font and font size
font = nullptr;
fontSize = 0;
if (tfPos >= 0) {
tok = (*daToks)[tfPos];
+ if (forceZapfDingbats) {
+ assert(xref != nullptr);
+ if (tok->cmp("/ZaDb")) {
+ tok->clear();
+ tok->append("/ZaDb");
+ }
+ }
if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
if (!resources || !(font = resources->lookupFont(tok->c_str() + 1))) {
- if (forceZapfDingbats) {
- // We are forcing ZaDb but the font does not exist
- // so create a fake one
- Ref r = Ref::INVALID(); // dummy Ref, it's not used at all in this codepath
- Dict *d = new Dict(xref);
- fontToFree = new Gfx8BitFont(xref, "ZaDb", r, new GooString("ZapfDingbats"), fontType1, r, d);
- delete d;
+ if (xref != nullptr && resourcesDict != nullptr) {
+ const char *fallback = determineFallbackFont(tok, defaultFallback);
+ fontToFree = createAnnotDrawFont(xref, resourcesDict, tok->c_str() + 1, fallback);
font = fontToFree;
- *addedDingbatsResource = true;
} else {
error(errSyntaxError, -1, "Unknown font in field's DA string");
}
@@ -4522,7 +4527,7 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, const GooString *da
}
// Draw the variable text or caption for a field.
-bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect, const GooString *da, const GfxResources *resources, int quadding)
+bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect, const GooString *da, const GfxResources *resources, int quadding, XRef *xref, Dict *resourcesDict)
{
std::vector<GooString *> *daToks;
GooString *tok;
@@ -4530,6 +4535,7 @@ bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, con
const GfxFont *font;
double fontSize, borderWidth, x, y, w, wMax;
int tfPos, tmPos, i, j;
+ GfxFont *fontToFree = nullptr;
//~ if there is no MK entry, this should use the existing content stream,
//~ and only replace the marked content portion of it
@@ -4569,7 +4575,13 @@ bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, con
tok = (*daToks)[tfPos];
if (tok->getLength() >= 1 && tok->getChar(0) == '/') {
if (!resources || !(font = resources->lookupFont(tok->c_str() + 1))) {
- error(errSyntaxError, -1, "Unknown font in field's DA string");
+ if (xref != nullptr && resourcesDict != nullptr) {
+ const char *fallback = determineFallbackFont(tok, "Helvetica");
+ fontToFree = createAnnotDrawFont(xref, resourcesDict, tok->c_str() + 1, fallback);
+ font = fontToFree;
+ } else {
+ error(errSyntaxError, -1, "Unknown font in field's DA string");
+ }
}
} else {
error(errSyntaxError, -1, "Invalid font name in 'Tf' operator in field's DA string");
@@ -4701,6 +4713,9 @@ bool AnnotAppearanceBuilder::drawListBox(const FormFieldChoice *fieldChoice, con
}
delete daToks;
}
+ if (fontToFree) {
+ fontToFree->decRefCnt();
+ }
return true;
}
@@ -4808,17 +4823,17 @@ void AnnotAppearanceBuilder::drawFieldBorder(const FormField *field, const Annot
}
bool AnnotAppearanceBuilder::drawFormField(const FormField *field, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
- const GooString *appearState, XRef *xref, bool *addedDingbatsResource, Dict *resourcesDict)
+ const GooString *appearState, XRef *xref, Dict *resourcesDict)
{
// draw the field contents
switch (field->getType()) {
case formButton:
- return drawFormFieldButton(static_cast<const FormFieldButton *>(field), resources, da, border, appearCharacs, rect, appearState, xref, addedDingbatsResource);
+ return drawFormFieldButton(static_cast<const FormFieldButton *>(field), resources, da, border, appearCharacs, rect, appearState, xref, resourcesDict);
break;
case formText:
- return drawFormFieldText(static_cast<const FormFieldText *>(field), form, resources, da, border, appearCharacs, rect);
+ return drawFormFieldText(static_cast<const FormFieldText *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
case formChoice:
- return drawFormFieldChoice(static_cast<const FormFieldChoice *>(field), form, resources, da, border, appearCharacs, rect);
+ return drawFormFieldChoice(static_cast<const FormFieldChoice *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
break;
case formSignature:
return drawSignatureFieldText(static_cast<const FormFieldSignature *>(field), form, resources, da, border, appearCharacs, rect, xref, resourcesDict);
@@ -4832,7 +4847,7 @@ bool AnnotAppearanceBuilder::drawFormField(const FormField *field, const Form *f
}
bool AnnotAppearanceBuilder::drawFormFieldButton(const FormFieldButton *field, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
- const GooString *appearState, XRef *xref, bool *addedDingbatsResource)
+ const GooString *appearState, XRef *xref, Dict *resourcesDict)
{
const GooString *caption = nullptr;
if (appearCharacs)
@@ -4843,7 +4858,7 @@ bool AnnotAppearanceBuilder::drawFormFieldButton(const FormFieldButton *field, c
//~ Acrobat doesn't draw a caption if there is no AP dict (?)
if (appearState && appearState->cmp("Off") != 0 && field->getState(appearState->c_str())) {
if (caption) {
- return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, addedDingbatsResource, false);
+ return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
} else if (appearCharacs) {
const AnnotColor *aColor = appearCharacs->getBorderColor();
if (aColor) {
@@ -4858,15 +4873,15 @@ bool AnnotAppearanceBuilder::drawFormFieldButton(const FormFieldButton *field, c
} break;
case formButtonPush:
if (caption)
- return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, false, xref, addedDingbatsResource, false);
+ return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, false, xref, false, resourcesDict);
break;
case formButtonCheck:
if (appearState && appearState->cmp("Off") != 0) {
if (!caption) {
GooString checkMark("3");
- return drawText(&checkMark, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, addedDingbatsResource, false);
+ return drawText(&checkMark, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
} else {
- return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, addedDingbatsResource, false);
+ return drawText(caption, da, resources, border, appearCharacs, rect, false, 0, fieldQuadCenter, false, true, xref, false, resourcesDict, "ZapfDingbats");
}
}
break;
@@ -4876,7 +4891,7 @@ bool AnnotAppearanceBuilder::drawFormFieldButton(const FormFieldButton *field, c
}
bool AnnotAppearanceBuilder::drawFormFieldText(const FormFieldText *fieldText, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs,
- const PDFRectangle *rect)
+ const PDFRectangle *rect, XRef *xref, Dict *resourcesDict)
{
VariableTextQuadding quadding;
const GooString *contents;
@@ -4895,7 +4910,7 @@ bool AnnotAppearanceBuilder::drawFormFieldText(const FormFieldText *fieldText, c
if (fieldText->isComb())
comb = fieldText->getMaxLen();
- return drawText(contents, da, resources, border, appearCharacs, rect, fieldText->isMultiline(), comb, quadding, true, false, nullptr, nullptr, fieldText->isPassword());
+ return drawText(contents, da, resources, border, appearCharacs, rect, fieldText->isMultiline(), comb, quadding, true, false, xref, fieldText->isPassword(), resourcesDict);
}
return true;
@@ -4995,7 +5010,7 @@ void AnnotAppearanceBuilder::drawSignatureFieldText(const GooString &text, const
}
bool AnnotAppearanceBuilder::drawFormFieldChoice(const FormFieldChoice *fieldChoice, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs,
- const PDFRectangle *rect)
+ const PDFRectangle *rect, XRef *xref, Dict *resourcesDict)
{
const GooString *selected;
VariableTextQuadding quadding;
@@ -5011,18 +5026,18 @@ bool AnnotAppearanceBuilder::drawFormFieldChoice(const FormFieldChoice *fieldCho
if (fieldChoice->isCombo()) {
selected = fieldChoice->getSelectedChoice();
if (selected) {
- return drawText(selected, da, resources, border, appearCharacs, rect, false, 0, quadding, true, false, nullptr, nullptr, false);
+ return drawText(selected, da, resources, border, appearCharacs, rect, false, 0, quadding, true, false, xref, false, resourcesDict);
//~ Acrobat draws a popup icon on the right side
}
// list box
} else {
- return drawListBox(fieldChoice, border, rect, da, resources, quadding);
+ return drawListBox(fieldChoice, border, rect, da, resources, quadding, xref, resourcesDict);
}
return true;
}
-void AnnotWidget::generateFieldAppearance(bool *addedDingbatsResource)
+void AnnotWidget::generateFieldAppearance()
{
const GooString *da;
@@ -5055,10 +5070,10 @@ void AnnotWidget::generateFieldAppearance(bool *addedDingbatsResource)
resourcesDictObj = Object(new Dict(doc->getXRef()));
}
- const bool success = appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), addedDingbatsResource, resourcesDictObj.getDict());
+ const bool success = appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), resourcesDictObj.getDict());
if (!success && form && da != form->getDefaultAppearance()) {
da = form->getDefaultAppearance();
- appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), addedDingbatsResource, resourcesDictObj.getDict());
+ appearBuilder.drawFormField(field, form, resources, da, border.get(), appearCharacs.get(), rect.get(), appearState.get(), doc->getXRef(), resourcesDictObj.getDict());
}
const GooString *appearBuf = appearBuilder.buffer();
@@ -5096,9 +5111,7 @@ void AnnotWidget::updateAppearanceStream()
return;
// Create the new appearance
- bool dummyAddDingbatsResource = false; // This is only update so if we didn't need to add
- // the dingbats resource we should not need it now
- generateFieldAppearance(&dummyAddDingbatsResource);
+ generateFieldAppearance();
// Fetch the appearance stream we've just created
Object obj1 = appearance.fetch(doc->getXRef());
@@ -5130,38 +5143,19 @@ void AnnotWidget::draw(Gfx *gfx, bool printing)
return;
annotLocker();
- bool addDingbatsResource = false;
// Only construct the appearance stream when
// - annot doesn't have an AP or
// - NeedAppearances is true
if (field) {
if (appearance.isNull() || (form && form->getNeedAppearances())) {
- generateFieldAppearance(&addDingbatsResource);
+ generateFieldAppearance();
}
}
// draw the appearance stream
Object obj = appearance.fetch(gfx->getXRef());
- if (addDingbatsResource) {
- // We are forcing ZaDb but the font does not exist
- // so create a fake one
- Dict *fontDict = new Dict(gfx->getXRef());
- fontDict->add("BaseFont", Object(objName, "ZapfDingbats"));
- fontDict->add("Subtype", Object(objName, "Type1"));
-
- Dict *fontsDict = new Dict(gfx->getXRef());
- fontsDict->add("ZaDb", Object(fontDict));
-
- Dict *dict = new Dict(gfx->getXRef());
- dict->add("Font", Object(fontsDict));
- gfx->pushResources(dict);
- delete dict;
- }
gfx->drawAnnot(&obj, nullptr, color.get(), rect->x1, rect->y1, rect->x2, rect->y2, getRotation());
- if (addDingbatsResource) {
- gfx->popResources();
- }
}
void AnnotWidget::invalidateAppearance()
diff --git a/poppler/Annot.h b/poppler/Annot.h
index afafc775..de4ce74c 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -574,7 +574,7 @@ public:
void drawLineEndSlash(double x, double y, double size, const Matrix &m);
void drawFieldBorder(const FormField *field, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
bool drawFormField(const FormField *field, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
- const GooString *appearState, XRef *xref, bool *addedDingbatsResource, Dict *resourcesDict);
+ const GooString *appearState, XRef *xref, Dict *resourcesDict);
static double lineEndingXShorten(AnnotLineEndingStyle endingStyle, double size);
static double lineEndingXExtendBBox(AnnotLineEndingStyle endingStyle, double size);
void writeString(const GooString &str);
@@ -585,17 +585,18 @@ public:
const GooString *buffer() const;
private:
- bool drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect, const GooString *da, const GfxResources *resources, int quadding);
+ bool drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, const PDFRectangle *rect, const GooString *da, const GfxResources *resources, int quadding, XRef *xref, Dict *resourcesDict);
bool drawFormFieldButton(const FormFieldButton *field, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, const GooString *appearState,
- XRef *xref, bool *addedDingbatsResource);
- bool drawFormFieldText(const FormFieldText *fieldText, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
- bool drawFormFieldChoice(const FormFieldChoice *fieldChoice, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect);
+ XRef *xref, Dict *resourcesDict);
+ bool drawFormFieldText(const FormFieldText *fieldText, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, XRef *xref,
+ Dict *resourcesDict);
+ bool drawFormFieldChoice(const FormFieldChoice *fieldChoice, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
+ XRef *xref, Dict *resourcesDict);
bool drawSignatureFieldText(const FormFieldSignature *field, const Form *form, const GfxResources *resources, const GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
XRef *xref, Dict *resourcesDict);
void drawSignatureFieldText(const GooString &text, const DefaultAppearance &da, const AnnotBorder *border, const PDFRectangle *rect, XRef *xref, Dict *resourcesDict, double leftMargin, bool centerVertically, bool centerHorizontally);
bool drawText(const GooString *text, const GooString *da, const GfxResources *resources, const AnnotBorder *border, const AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, bool multiline, int comb, int quadding,
- bool txField, bool forceZapfDingbats, XRef *xref, bool *addedDingbatsResource, // xref and addedDingbatsResource both must not be null if forceZapfDingbats is passed
- bool password);
+ bool txField, bool forceZapfDingbats, XRef *xref, bool password, Dict *resourcesDict, const char *defaultFallback = "Helvetica");
void drawArrowPath(double x, double y, const Matrix &m, int orientation = 1);
GooString *appearBuf;
@@ -1424,7 +1425,7 @@ public:
void draw(Gfx *gfx, bool printing) override;
void invalidateAppearance() override;
- void generateFieldAppearance(bool *addedDingbatsResource);
+ void generateFieldAppearance();
void updateAppearanceStream();
AnnotWidgetHighlightMode getMode() { return mode; }
diff --git a/qt5/src/poppler-pdf-converter.cc b/qt5/src/poppler-pdf-converter.cc
index 5606b6e5..379312f6 100644
--- a/qt5/src/poppler-pdf-converter.cc
+++ b/qt5/src/poppler-pdf-converter.cc
@@ -168,9 +168,7 @@ bool PDFConverter::sign(const NewSignatureData &data)
appearCharacs->setBackColor(std::unique_ptr<AnnotColor> { convertQColor(data.backgroundColor()) });
signatureAnnot->setAppearCharacs(std::move(appearCharacs));
- bool dummyAddDingbatsResource = false; // This is only update so if we didn't need to add
- // the dingbats resource we should not need it now
- signatureAnnot->generateFieldAppearance(&dummyAddDingbatsResource);
+ signatureAnnot->generateFieldAppearance();
signatureAnnot->updateAppearanceStream();
FormWidget *formWidget = field->getWidget(field->getNumWidgets() - 1);
diff --git a/qt6/src/poppler-pdf-converter.cc b/qt6/src/poppler-pdf-converter.cc
index 04ee5761..19933c41 100644
--- a/qt6/src/poppler-pdf-converter.cc
+++ b/qt6/src/poppler-pdf-converter.cc
@@ -168,9 +168,7 @@ bool PDFConverter::sign(const NewSignatureData &data)
appearCharacs->setBackColor(std::unique_ptr<AnnotColor> { convertQColor(data.backgroundColor()) });
signatureAnnot->setAppearCharacs(std::move(appearCharacs));
- bool dummyAddDingbatsResource = false; // This is only update so if we didn't need to add
- // the dingbats resource we should not need it now
- signatureAnnot->generateFieldAppearance(&dummyAddDingbatsResource);
+ signatureAnnot->generateFieldAppearance();
signatureAnnot->updateAppearanceStream();
FormWidget *formWidget = field->getWidget(field->getNumWidgets() - 1);
More information about the poppler
mailing list