[prev in list] [next in list] [prev in thread] [next in thread]
List: freedesktop-poppler
Subject: [poppler] poppler/Annot.cc poppler/Annot.h poppler/Form.cc
From: GitLab Mirror <gitlab-mirror () kemper ! freedesktop ! org>
Date: 2022-04-06 12:23:01
Message-ID: 20220406122301.3E448760BC () kemper ! freedesktop ! org
[Download RAW message or body]
poppler/Annot.cc | 433 +++++++++++++++++++++++++++++++------------------------
poppler/Annot.h | 8 -
poppler/Form.cc | 33 ++--
3 files changed, 275 insertions(+), 199 deletions(-)
New commits:
commit 0b474ffb990a8285a6d3c2bf157b32b2264fb140
Author: Albert Astals Cid <aacid@kde.org>
Date: Wed Mar 23 13:35:01 2022 +0100
Forms: Make sure we embedd fonts as needed
And a bit of refactoring :)
diff --git a/poppler/Annot.cc b/poppler/Annot.cc
index 5959a993..db84027f 100644
--- a/poppler/Annot.cc
+++ b/poppler/Annot.cc
@@ -3046,141 +3046,190 @@ static std::unique_ptr<GfxFont> createAnnotDrawFont(XRef \
*xref, Dict *fontParent class HorizontalTextLayouter
{
public:
- void add(const std::string &text, const std::string &fontName, const double \
width) { data.emplace_back(text, fontName, width); } + HorizontalTextLayouter() = \
default;
- std::string layout(const VariableTextQuadding quadding, const double \
availableWidth, const double fontSize, double &xposPrev) const + \
HorizontalTextLayouter(const GooString *text, const Form *form, const GfxFont *font, \
std::optional<double> availableWidth, const bool noReencode) {
- double totalWidth = 0;
- for (const Data &d : data) {
- totalWidth += d.width;
- }
+ int i = 0;
+ double blockWidth;
+ bool newFontNeeded = false;
+ GooString outputText;
+ const bool isUnicode = text->hasUnicodeMarker();
+ int charCount;
- double newXpos;
- switch (quadding) {
- case VariableTextQuadding::centered:
- newXpos = (availableWidth - totalWidth) / 2;
- break;
- case VariableTextQuadding::rightJustified:
- newXpos = availableWidth - totalWidth;
- break;
- default: // VariableTextQuadding::lLeftJustified:
- newXpos = 0;
- break;
+ Annot::layoutText(text, &outputText, &i, *font, &blockWidth, availableWidth \
? *availableWidth : 0.0, &charCount, noReencode, !noReencode ? &newFontNeeded : \
nullptr); + data.emplace_back(outputText.toStr(), std::string(), blockWidth, \
charCount); + if (availableWidth) {
+ *availableWidth -= blockWidth;
}
- AnnotAppearanceBuilder builder;
- bool first = true;
- double prevBlockWidth = 0;
- for (const Data &d : data) {
- builder.appendf("/{0:s} {1:.2f} Tf\n", d.fontName.c_str(), fontSize);
+ while (newFontNeeded && (!availableWidth || *availableWidth > 0)) {
+ if (!form) {
+ // There's no fonts to look for, so just skip the characters
+ i += isUnicode ? 2 : 1;
+ error(errSyntaxError, -1, "HorizontalTextLayouter, found character \
that the font can't represent"); + newFontNeeded = false;
+ } else {
+ Unicode uChar;
+ if (isUnicode) {
+ uChar = (unsigned char)(text->getChar(i)) << 8;
+ uChar += (unsigned char)(text->getChar(i + 1));
+ } else {
+ uChar = pdfDocEncoding[text->getChar(i) & 0xff];
+ }
+ const std::string auxFontName = form->getFallbackFontForChar(uChar, \
*font); + if (!auxFontName.empty()) {
+ std::shared_ptr<GfxFont> auxFont = \
form->getDefaultResources()->lookupFont(auxFontName.c_str());
- const double yDiff = first ? -fontSize : 0;
- const double xDiff = first ? newXpos - xposPrev : prevBlockWidth;
+ // Here we just layout one char, we don't know if the one \
afterwards can be layouted with the original font + GooString \
auxContents = GooString(text->toStr().substr(i, isUnicode ? 2 : 1)); + \
if (isUnicode) { + auxContents.prependUnicodeMarker();
+ }
+ int auxI = 0;
+ Annot::layoutText(&auxContents, &outputText, &auxI, *auxFont, \
&blockWidth, availableWidth ? *availableWidth : 0.0, &charCount, false, \
&newFontNeeded); + assert(!newFontNeeded);
+ if (availableWidth) {
+ *availableWidth -= blockWidth;
+ }
+ // layoutText will always at least layout one character even if \
it doesn't fit in + // the given space which makes sense (except \
in the case of switching fonts, so we control if we ran out of space here manually) + \
if (!availableWidth || *availableWidth > 0) { + i += isUnicode \
? 2 : 1; + data.emplace_back(outputText.toStr(), auxFontName, \
blockWidth, charCount); + }
+ } else {
+ error(errSyntaxError, -1, "HorizontalTextLayouter, couldn't find \
a font for character U+{0:04uX}", uChar); + newFontNeeded = false;
+ i += isUnicode ? 2 : 1;
+ }
+ }
+ // Now layout the rest of the text with the original font
+ if (!availableWidth || *availableWidth > 0) {
+ Annot::layoutText(text, &outputText, &i, *font, &blockWidth, \
availableWidth ? *availableWidth : 0.0, &charCount, false, &newFontNeeded); + \
if (availableWidth) { + *availableWidth -= blockWidth;
+ }
+ // layoutText will always at least layout one character even if it \
doesn't fit in + // the given space which makes sense (except in the \
case of switching fonts, so we control if we ran out of space here manually) + \
if (!availableWidth || *availableWidth > 0) { + \
data.emplace_back(outputText.toStr(), std::string(), blockWidth, charCount); + \
} else { + i -= isUnicode ? 2 : 1;
+ }
+ }
+ }
+ consumedText = i;
+ }
- builder.appendf("{0:.2f} {1:.2f} Td\n", xDiff, yDiff);
- builder.writeString(d.text);
- builder.append("Tj\n");
- first = false;
- prevBlockWidth = d.width;
+ HorizontalTextLayouter(const HorizontalTextLayouter &) = delete;
+ HorizontalTextLayouter &operator=(const HorizontalTextLayouter &) = delete;
+
+ double totalWidth() const
+ {
+ double totalWidth = 0;
+ for (const Data &d : data) {
+ totalWidth += d.width;
}
- xposPrev = newXpos + totalWidth - prevBlockWidth;
+ return totalWidth;
+ }
- return builder.buffer()->toStr();
+ int totalCharCount() const
+ {
+ int total = 0;
+ for (const Data &d : data) {
+ total += d.charCount;
+ }
+ return total;
}
-private:
struct Data
{
- Data(const std::string &t, const std::string &fName, double w) : text(t), \
fontName(fName), width(w) { } + Data(const std::string &t, const std::string \
&fName, double w, int cc) : text(t), fontName(fName), width(w), charCount(cc) { }
const std::string text;
const std::string fontName;
const double width;
+ const int charCount;
};
std::vector<Data> data;
+ int consumedText;
};
-struct DrawFreeTextResult
+struct DrawMultiLineTextResult
{
std::string text;
int nLines = 0;
};
-static DrawFreeTextResult drawFreeTextText(const GooString &text, double \
availableWidth, const Form *form, const GfxFont &font, const std::string &fontName, \
double fontSize, VariableTextQuadding quadding) +// if fontName is empty it is \
assumed it is sent from the outside +// so for text that is in font no Tf is added \
and for text that is in the aux fonts +// a pair of q/Q is added
+static DrawMultiLineTextResult drawMultiLineText(const GooString &text, double \
availableWidth, const Form *form, const GfxFont &font, const std::string &fontName, \
double fontSize, VariableTextQuadding quadding, double borderWidth) {
- DrawFreeTextResult result;
+ DrawMultiLineTextResult result;
int i = 0;
- double xposPrev = 0;
- const bool isUnicode = text.hasUnicodeMarker();
+ double xPosPrev = 0;
+ const double availableTextWidthInFontPtSize = availableWidth / fontSize;
while (i < text.getLength()) {
- HorizontalTextLayouter textLayouter;
-
- GooString out;
- double availableTextWidthInFontPtSize = availableWidth / fontSize;
- double blockWidth;
- bool newFontNeeded;
- Annot::layoutText(&text, &out, &i, font, &blockWidth, \
availableTextWidthInFontPtSize, nullptr, false, &newFontNeeded);
- availableTextWidthInFontPtSize -= blockWidth;
- textLayouter.add(out.toStr(), fontName, blockWidth * fontSize);
+ GooString lineText(text.toStr().substr(i));
+ if (!lineText.hasUnicodeMarker() && text.hasUnicodeMarker()) {
+ lineText.prependUnicodeMarker();
+ }
+ const HorizontalTextLayouter textLayouter(&lineText, form, &font, \
availableTextWidthInFontPtSize, false);
- while (availableTextWidthInFontPtSize >= 0 && newFontNeeded) {
- if (!form) {
- // There's no fonts to look for, so just skip the characters
- i += isUnicode ? 2 : 1;
- error(errSyntaxError, -1, \
"AnnotFreeText::generateFreeTextAppearance, found character that the font can't \
represent");
- newFontNeeded = false;
- } else {
- Unicode uChar;
- if (isUnicode) {
- uChar = (unsigned char)(text.getChar(i)) << 8;
- uChar += (unsigned char)(text.getChar(i + 1));
- } else {
- uChar = pdfDocEncoding[text.getChar(i) & 0xff];
- }
- const std::string auxFontName = form->getFallbackFontForChar(uChar, \
font);
- if (!auxFontName.empty()) {
- std::shared_ptr<GfxFont> auxFont = \
form->getDefaultResources()->lookupFont(auxFontName.c_str()); + const double \
totalWidth = textLayouter.totalWidth() * fontSize;
- // Here we just layout one char, we don't know if the one \
afterwards can be layouted with the original font
- GooString auxContents = GooString(text.toStr().substr(i, \
isUnicode ? 2 : 1));
- if (isUnicode) {
- auxContents.prependUnicodeMarker();
- }
- int auxI = 0;
- Annot::layoutText(&auxContents, &out, &auxI, *auxFont, \
&blockWidth, availableTextWidthInFontPtSize, nullptr, false, \
&newFontNeeded);
- assert(!newFontNeeded);
- // layoutText will always at least layout one character even if \
it doesn't fit in
- // the given space which makes sense (except in the case of \
switching fonts, so we control if we ran out of space here manually)
- availableTextWidthInFontPtSize -= blockWidth;
- if (availableTextWidthInFontPtSize >= 0) {
- i += auxI - (isUnicode ? 2 : 0); // the second term is the \
unicode marker
- textLayouter.add(out.toStr(), auxFontName, blockWidth * \
fontSize);
- }
+ auto calculateX = [quadding, availableWidth, totalWidth, borderWidth] {
+ switch (quadding) {
+ case VariableTextQuadding::centered:
+ return (availableWidth - totalWidth) / 2;
+ break;
+ case VariableTextQuadding::rightJustified:
+ return availableWidth - totalWidth - borderWidth;
+ break;
+ default: // VariableTextQuadding::lLeftJustified:
+ return borderWidth;
+ break;
+ }
+ };
+ const double xPos = calculateX();
- } else {
- error(errSyntaxError, -1, \
"AnnotFreeText::generateFreeTextAppearance, couldn't find a font for character \
U+{0:04uX}", uChar);
- newFontNeeded = false;
- i += text.hasUnicodeMarker() ? 2 : 1;
+ AnnotAppearanceBuilder builder;
+ bool first = true;
+ double prevBlockWidth = 0;
+ for (const HorizontalTextLayouter::Data &d : textLayouter.data) {
+ const std::string &fName = d.fontName.empty() ? fontName : d.fontName;
+ if (!fName.empty()) {
+ if (fontName.empty()) {
+ builder.append(" q\n");
}
+ builder.appendf("/{0:s} {1:.2f} Tf\n", fName.c_str(), fontSize);
}
- // Now layout the rest of the text with the original font if we still \
have space
- if (availableTextWidthInFontPtSize >= 0) {
- Annot::layoutText(&text, &out, &i, font, &blockWidth, \
availableTextWidthInFontPtSize, nullptr, false, &newFontNeeded);
- availableTextWidthInFontPtSize -= blockWidth;
- // layoutText will always at least layout one character even if it \
doesn't fit in
- // the given space which makes sense (except in the case of \
switching fonts, so we control if we ran out of space here manually)
- if (availableTextWidthInFontPtSize >= 0) {
- textLayouter.add(out.toStr(), fontName, blockWidth * fontSize);
- } else {
- i -= isUnicode ? 2 : 1;
- }
+ const double yDiff = first ? -fontSize : 0;
+ const double xDiff = first ? xPos - xPosPrev : prevBlockWidth;
+
+ builder.appendf("{0:.2f} {1:.2f} Td\n", xDiff, yDiff);
+ builder.writeString(d.text);
+ builder.append(" Tj\n");
+ first = false;
+ prevBlockWidth = d.width * fontSize;
+
+ if (!fName.empty() && fontName.empty()) {
+ builder.append(" Q\n");
}
}
+ xPosPrev = xPos + totalWidth - prevBlockWidth;
- result.text += textLayouter.layout(quadding, availableWidth, fontSize, \
xposPrev); + result.text += builder.buffer()->toStr();
result.nLines += 1;
+ if (i == 0) {
+ i += textLayouter.consumedText;
+ } else {
+ i += textLayouter.consumedText - (text.hasUnicodeMarker() ? 2 : 0);
+ }
}
return result;
}
@@ -3276,7 +3325,7 @@ void AnnotFreeText::generateFreeTextAppearance()
// Set font state
appearBuilder.setDrawColor(da.getFontColor(), true);
appearBuilder.appendf("BT 1 0 0 1 {0:.2f} {1:.2f} Tm\n", textmargin, height - \
textmargin - da.getFontPtSize() * font->getDescent());
- const DrawFreeTextResult textCommands = drawFreeTextText(*contents, textwidth, \
form, *font, da.getFontName().getName(), da.getFontPtSize(), quadding); + const \
DrawMultiLineTextResult textCommands = drawMultiLineText(*contents, textwidth, form, \
*font, da.getFontName().getName(), da.getFontPtSize(), quadding, 0 /*borderWidth*/); \
appearBuilder.append(textCommands.text.c_str()); appearBuilder.append("ET Q\n");
@@ -4330,7 +4379,13 @@ void Annot::layoutText(const GooString *text, GooString \
*outBuf, int *i, const G outBuf->append(c);
}
} else {
- error(errSyntaxError, -1, "AnnotWidget::layoutText, cannot convert \
U+{0:04uX}", uChar); + if (newFontNeeded) {
+ *newFontNeeded = true;
+ *i -= unicode ? 2 : 1;
+ break;
+ } else {
+ error(errSyntaxError, -1, "AnnotWidget::layoutText, cannot \
convert U+{0:04uX}", uChar); + }
}
}
@@ -4449,13 +4504,12 @@ void AnnotAppearanceBuilder::writeString(const std::string \
&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 \
AnnotAppearanceBuilder::drawText(const GooString *text, const Form *form, const \
GooString *da, const GfxResources *resources, const AnnotBorder *border, const \
AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect,
const VariableTextQuadding quadding, XRef \
*xref, Dict *resourcesDict, const int flags, const int nCombs) {
const bool forceZapfDingbats = flags & ForceZapfDingbatsDrawTextFlag;
std::vector<std::string> daToks;
- GooString convertedText;
const GfxFont *font;
double dx, dy;
double fontSize;
@@ -4575,15 +4629,26 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da
// note: comb is ignored in multiline mode as mentioned in the spec
const double wMax = dx - 2 * borderWidth - 4;
+ const bool isUnicode = text->hasUnicodeMarker();
// compute font autosize
if (fontSize == 0) {
for (fontSize = 20; fontSize > 1; --fontSize) {
+ const double availableWidthInFontSize = wMax / fontSize;
double y = dy - 3;
int i = 0;
while (i < text->getLength()) {
- Annot::layoutText(text, &convertedText, &i, *font, nullptr, wMax \
/ fontSize, nullptr, forceZapfDingbats); + GooString \
lineText(text->toStr().substr(i)); + if \
(!lineText.hasUnicodeMarker() && isUnicode) { + \
lineText.prependUnicodeMarker(); + }
+ const HorizontalTextLayouter textLayouter(&lineText, form, font, \
availableWidthInFontSize, forceZapfDingbats); y -= fontSize;
+ if (i == 0) {
+ i += textLayouter.consumedText;
+ } else {
+ i += textLayouter.consumedText - (isUnicode ? 2 : 0);
+ }
}
// approximate the descender for the last line
if (y >= 0.33 * fontSize) {
@@ -4607,36 +4672,8 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da appearBuf->append(daTok)->append(' ');
}
- // write a series of lines of text
- int i = 0;
- double xPrev = 0;
- while (i < text->getLength()) {
- double w;
- Annot::layoutText(text, &convertedText, &i, *font, &w, wMax / fontSize, \
nullptr, forceZapfDingbats);
- w *= fontSize;
-
- // compute text start position
- auto calculateX = [quadding, borderWidth, dx, w] {
- switch (quadding) {
- case VariableTextQuadding::leftJustified:
- default:
- return borderWidth + 2;
- case VariableTextQuadding::centered:
- return (dx - w) / 2;
- case VariableTextQuadding::rightJustified:
- return dx - borderWidth - 2 - w;
- }
- };
- const double x = calculateX();
-
- // draw the line
- appearBuf->appendf("{0:.2f} {1:.2f} Td\n", x - xPrev, -fontSize);
- writeString(convertedText.toStr());
- appearBuf->append(" Tj\n");
-
- // next line
- xPrev = x;
- }
+ const DrawMultiLineTextResult textCommands = drawMultiLineText(*text, dx, \
form, *font, std::string(), fontSize, quadding, borderWidth + 2); + \
appearBuf->append(textCommands.text);
// single-line text
} else {
@@ -4644,8 +4681,6 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da
// comb formatting
if (nCombs > 0) {
- int charCount;
-
// compute comb spacing
const double w = (dx - 2 * borderWidth) / nCombs;
@@ -4659,11 +4694,9 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da
daToks[tfPos + 1] = GooString().appendf("{0:.2f}", \
fontSize)->toStr(); }
- int dummy = 0;
- Annot::layoutText(text, &convertedText, &dummy, *font, nullptr, 0.0, \
&charCount, forceZapfDingbats);
- if (charCount > nCombs) {
- charCount = nCombs;
- }
+ const HorizontalTextLayouter textLayouter(text, form, font, {}, \
forceZapfDingbats); +
+ const int charCount = std::min(textLayouter.totalCharCount(), nCombs);
// compute starting text cell
auto calculateX = [quadding, borderWidth, nCombs, charCount, w] {
@@ -4690,47 +4723,60 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da }
// write the text string
- const char *s = convertedText.c_str();
- int len = convertedText.getLength();
int i = 0;
double xPrev = w; // so that first character is placed properly
- while (i < nCombs && len > 0) {
- CharCode code;
- const Unicode *uAux;
- int uLen, n;
- double char_dx, char_dy, ox, oy;
-
- char_dx = 0.0;
- n = font->getNextChar(s, len, &code, &uAux, &uLen, &char_dx, \
&char_dy, &ox, &oy);
- char_dx *= fontSize;
-
- // center each character within its cell, by advancing the text
- // position the appropriate amount relative to the start of the
- // previous character
- const double combX = 0.5 * (w - char_dx);
- appearBuf->appendf("{0:.2f} 0 Td\n", combX - xPrev + w);
-
- GooString charBuf(s, n);
- writeString(charBuf.toStr());
- appearBuf->append(" Tj\n");
+ for (const HorizontalTextLayouter::Data &d : textLayouter.data) {
+ const char *s = d.text.c_str();
+ int len = d.text.size();
+ while (i < nCombs && len > 0) {
+ CharCode code;
+ const Unicode *uAux;
+ int uLen, n;
+ double char_dx, char_dy, ox, oy;
+
+ const GfxFont *currentFont = font;
+ if (!d.fontName.empty()) {
+ appearBuf->append(" q\n");
+ appearBuf->appendf("/{0:s} {1:.2f} Tf\n", \
d.fontName.c_str(), fontSize); + currentFont = \
form->getDefaultResources()->lookupFont(d.fontName.c_str()).get(); + \
} +
+ char_dx = 0.0;
+ n = currentFont->getNextChar(s, len, &code, &uAux, &uLen, \
&char_dx, &char_dy, &ox, &oy); + char_dx *= fontSize;
+
+ // center each character within its cell, by advancing the text
+ // position the appropriate amount relative to the start of the
+ // previous character
+ const double combX = 0.5 * (w - char_dx);
+ appearBuf->appendf("{0:.2f} 0 Td\n", combX - xPrev + w);
+
+ GooString charBuf(s, n);
+ writeString(charBuf.toStr());
+ appearBuf->append(" Tj\n");
+
+ if (!d.fontName.empty()) {
+ appearBuf->append(" Q\n");
+ }
- i++;
- s += n;
- len -= n;
- xPrev = combX;
+ i++;
+ s += n;
+ len -= n;
+ xPrev = combX;
+ }
}
// regular (non-comb) formatting
} else {
- int ii = 0;
- double w;
- Annot::layoutText(text, &convertedText, &ii, *font, &w, 0.0, nullptr, \
forceZapfDingbats); + const HorizontalTextLayouter textLayouter(text, \
form, font, {}, forceZapfDingbats); +
+ const double usedWidthUnscaled = textLayouter.totalWidth();
// compute font autosize
if (fontSize == 0) {
fontSize = dy - 2 * borderWidth;
- if (w > 0) {
- const double fontSize2 = (dx - 4 - 2 * borderWidth) / w;
+ if (usedWidthUnscaled > 0) {
+ const double fontSize2 = (dx - 4 - 2 * borderWidth) / \
usedWidthUnscaled; if (fontSize2 < fontSize) {
fontSize = fontSize2;
}
@@ -4740,16 +4786,16 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da }
// compute text start position
- w *= fontSize;
- auto calculateX = [quadding, borderWidth, dx, w] {
+ const double usedWidth = usedWidthUnscaled * fontSize;
+ auto calculateX = [quadding, borderWidth, dx, usedWidth] {
switch (quadding) {
case VariableTextQuadding::leftJustified:
default:
return borderWidth + 2;
case VariableTextQuadding::centered:
- return (dx - w) / 2;
+ return (dx - usedWidth) / 2;
case VariableTextQuadding::rightJustified:
- return dx - borderWidth - 2 - w;
+ return dx - borderWidth - 2 - usedWidth;
}
};
const double x = calculateX();
@@ -4767,9 +4813,18 @@ bool AnnotAppearanceBuilder::drawText(const GooString *text, \
const GooString *da
// and our auto tests "wrongly" assume it will be there, so add it \
anyway appearBuf->append("\n");
- // write the text string
- writeString(convertedText.toStr());
- appearBuf->append(" Tj\n");
+ // write the text strings
+ for (const HorizontalTextLayouter::Data &d : textLayouter.data) {
+ if (!d.fontName.empty()) {
+ appearBuf->append(" q\n");
+ appearBuf->appendf("/{0:s} {1:.2f} Tf\n", d.fontName.c_str(), \
fontSize); + }
+ writeString(d.text);
+ appearBuf->append(" Tj\n");
+ if (!d.fontName.empty()) {
+ appearBuf->append(" Q\n");
+ }
+ }
}
}
// cleanup
@@ -5080,7 +5135,7 @@ bool AnnotAppearanceBuilder::drawFormField(const FormField \
*field, const Form *f // draw the field contents
switch (field->getType()) {
case formButton:
- return drawFormFieldButton(static_cast<const FormFieldButton *>(field), \
resources, da, border, appearCharacs, rect, appearState, xref, resourcesDict); + \
return drawFormFieldButton(static_cast<const FormFieldButton *>(field), form, \
resources, da, border, appearCharacs, rect, appearState, xref, resourcesDict); \
break; case formText:
return drawFormFieldText(static_cast<const FormFieldText *>(field), form, \
resources, da, border, appearCharacs, rect, xref, resourcesDict); @@ -5098,8 +5153,8 \
@@ bool AnnotAppearanceBuilder::drawFormField(const FormField *field, const Form *f \
return false; }
-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, Dict *resourcesDict) +bool AnnotAppearanceBuilder::drawFormFieldButton(const \
FormFieldButton *field, const Form *form, const GfxResources *resources, const \
GooString *da, const AnnotBorder *border, const AnnotAppearanceCharacs \
*appearCharacs, + const PDFRectangle \
*rect, const GooString *appearState, XRef *xref, Dict *resourcesDict) {
const GooString *caption = nullptr;
if (appearCharacs) {
@@ -5111,7 +5166,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, \
VariableTextQuadding::centered, xref, resourcesDict, ForceZapfDingbatsDrawTextFlag); \
+ return drawText(caption, form, da, resources, border, appearCharacs, \
rect, VariableTextQuadding::centered, xref, resourcesDict, \
ForceZapfDingbatsDrawTextFlag); } else if (appearCharacs) {
const AnnotColor *aColor = appearCharacs->getBorderColor();
if (aColor) {
@@ -5126,16 +5181,16 @@ bool AnnotAppearanceBuilder::drawFormFieldButton(const \
FormFieldButton *field, c } break;
case formButtonPush:
if (caption) {
- return drawText(caption, da, resources, border, appearCharacs, rect, \
VariableTextQuadding::centered, xref, resourcesDict); + return \
drawText(caption, form, da, resources, border, appearCharacs, rect, \
VariableTextQuadding::centered, xref, resourcesDict); }
break;
case formButtonCheck:
if (appearState && appearState->cmp("Off") != 0) {
if (!caption) {
GooString checkMark("3");
- return drawText(&checkMark, da, resources, border, appearCharacs, \
rect, VariableTextQuadding::centered, xref, resourcesDict, \
ForceZapfDingbatsDrawTextFlag); + return drawText(&checkMark, form, \
da, resources, border, appearCharacs, rect, VariableTextQuadding::centered, xref, \
resourcesDict, ForceZapfDingbatsDrawTextFlag); } else {
- return drawText(caption, da, resources, border, appearCharacs, rect, \
VariableTextQuadding::centered, xref, resourcesDict, ForceZapfDingbatsDrawTextFlag); \
+ return drawText(caption, form, da, resources, border, appearCharacs, \
rect, VariableTextQuadding::centered, xref, resourcesDict, \
ForceZapfDingbatsDrawTextFlag); }
}
break;
@@ -5169,7 +5224,7 @@ bool AnnotAppearanceBuilder::drawFormFieldText(const \
FormFieldText *fieldText, c if (fieldText->isPassword()) {
flags = flags | TurnTextToStarsDrawTextFlag;
}
- return drawText(contents, da, resources, border, appearCharacs, rect, \
quadding, xref, resourcesDict, flags, nCombs); + return drawText(contents, \
form, da, resources, border, appearCharacs, rect, quadding, xref, resourcesDict, \
flags, nCombs); }
return true;
@@ -5250,7 +5305,8 @@ void AnnotAppearanceBuilder::drawSignatureFieldText(const \
GooString &text, const // Setup text clipping
appendf("{0:.2f} {1:.2f} {2:.2f} {3:.2f} re W n\n", leftMargin + textmargin, \
textmargin, textwidth, height - 2 * textmargin); setDrawColor(da.getFontColor(), \
true);
- const DrawFreeTextResult textCommands = drawFreeTextText(text, textwidth, form, \
*font, da.getFontName().getName(), da.getFontPtSize(), centerHorizontally ? \
VariableTextQuadding::centered : VariableTextQuadding::leftJustified); + const \
DrawMultiLineTextResult textCommands = + drawMultiLineText(text, \
textwidth, form, *font, da.getFontName().getName(), da.getFontPtSize(), \
centerHorizontally ? VariableTextQuadding::centered : \
VariableTextQuadding::leftJustified, 0 /*borderWidth*/);
double yDelta = height - textmargin - da.getFontPtSize() * font->getDescent();
if (centerVertically) {
@@ -5281,7 +5337,7 @@ bool AnnotAppearanceBuilder::drawFormFieldChoice(const \
FormFieldChoice *fieldCho if (fieldChoice->isCombo()) {
selected = fieldChoice->getSelectedChoice();
if (selected) {
- return drawText(selected, da, resources, border, appearCharacs, rect, \
quadding, xref, resourcesDict, EmitMarkedContentDrawTextFlag); + return \
drawText(selected, form, da, resources, border, appearCharacs, rect, quadding, xref, \
resourcesDict, EmitMarkedContentDrawTextFlag); //~ Acrobat draws a popup icon on the \
right side }
// list box
@@ -5369,7 +5425,14 @@ void AnnotWidget::generateFieldAppearance()
// build the appearance stream
Stream *appearStream = new AutoFreeMemStream(copyString(appearBuf->c_str()), 0, \
appearBuf->getLength(), Object(appearDict));
- appearance = Object(appearStream);
+ if (hasBeenUpdated) {
+ // We should technically do this for all annots but AnnotFreeText
+ // forms are particularly special since we're potentially embeddeing a font \
so we really need + // to set the AP and not let other renderers guess it from \
the contents + setNewAppearance(Object(appearStream));
+ } else {
+ appearance = Object(appearStream);
+ }
if (resourcesToFree) {
delete resourcesToFree;
diff --git a/poppler/Annot.h b/poppler/Annot.h
index f9c7816c..15dbfe81 100644
--- a/poppler/Annot.h
+++ b/poppler/Annot.h
@@ -615,8 +615,8 @@ private:
};
bool drawListBox(const FormFieldChoice *fieldChoice, const AnnotBorder *border, \
const PDFRectangle *rect, const GooString *da, const GfxResources *resources, \
VariableTextQuadding 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, Dict *resourcesDict);
+ bool drawFormFieldButton(const FormFieldButton *field, const Form *form, const \
GfxResources *resources, const GooString *da, const AnnotBorder *border, const \
AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, + \
const GooString *appearState, 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, @@ \
-625,8 +625,8 @@ private: XRef *xref, Dict *resourcesDict);
void drawSignatureFieldText(const GooString &text, const Form *form, 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, const VariableTextQuadding quadding, XRef \
*xref,
- Dict *resourcesDict, const int flags = NoDrawTextFlags, const int \
nCombs = 0); + bool drawText(const GooString *text, const Form *form, const \
GooString *da, const GfxResources *resources, const AnnotBorder *border, const \
AnnotAppearanceCharacs *appearCharacs, const PDFRectangle *rect, + \
const VariableTextQuadding quadding, XRef *xref, Dict *resourcesDict, const int flags \
= NoDrawTextFlags, const int nCombs = 0);
void drawArrowPath(double x, double y, const Matrix &m, int orientation = 1);
GooString *appearBuf;
diff --git a/poppler/Form.cc b/poppler/Form.cc
index 41f823dc..a7bf9aba 100644
--- a/poppler/Form.cc
+++ b/poppler/Form.cc
@@ -1660,6 +1660,18 @@ void FormFieldText::setContentCopy(const GooString \
*new_content) if (!content->hasUnicodeMarker()) {
content->prependUnicodeMarker();
}
+ Form *form = doc->getCatalog()->getForm();
+ if (form) {
+ DefaultAppearance da(defaultAppearance);
+ if (da.getFontName().isName()) {
+ const std::string fontName = da.getFontName().getName();
+ if (!fontName.empty()) {
+ form->ensureFontsForAllCharacters(new_content, fontName);
+ }
+ } else {
+ // This is wrong, there has to be a Tf in DA
+ }
+ }
}
obj.getDict()->set("V", Object(content ? content->copy() : new GooString("")));
@@ -2922,24 +2934,25 @@ void Form::ensureFontsForAllCharacters(const GooString \
*unicodeText, const std:: if (!ccToUnicode) {
return; // will never happen with current code
}
- if (!f->isCIDFont()) {
- return; // will never happen with current code
- }
- auto cidFont = static_cast<const GfxCIDFont *>(f.get());
// 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;
- ccToUnicode->mapToCharCode(&uChar, &c, 1);
-
- if (c < cidFont->getCIDToGIDLen() && c != 0 && c != '\r' && c != '\n') {
- const int glyph = cidFont->getCIDToGID()[c];
- if (glyph == 0) {
- doGetAddFontToDefaultResources(uChar, *f);
+ 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);
+ }
+ }
}
+ } else {
+ doGetAddFontToDefaultResources(uChar, *f);
}
}
}
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic