Commit c290a82fcc236a739465b8387d91ae009e8fafcb

Authored by m-holger
Committed by GitHub
2 parents 9a6cfda2 3f43b187

Merge pull request #1584 from m-holger/ffoh

Remove implementation detail from QPDFFormFieldObjectHelper.hh
include/qpdf/QPDFFormFieldObjectHelper.hh
... ... @@ -187,23 +187,7 @@ class QPDFFormFieldObjectHelper: public QPDFObjectHelper
187 187 void generateAppearance(QPDFAnnotationObjectHelper&);
188 188  
189 189 private:
190   - QPDFObjectHandle getFieldFromAcroForm(std::string const& name);
191   - void setRadioButtonValue(QPDFObjectHandle name);
192   - void setCheckBoxValue(bool value);
193   - void generateTextAppearance(QPDFAnnotationObjectHelper&);
194   - QPDFObjectHandle getFontFromResource(QPDFObjectHandle resources, std::string const& font_name);
195   -
196   - class Members
197   - {
198   - friend class QPDFFormFieldObjectHelper;
199   -
200   - public:
201   - ~Members() = default;
202   -
203   - private:
204   - Members() = default;
205   - Members(Members const&) = delete;
206   - };
  190 + class Members;
207 191  
208 192 std::shared_ptr<Members> m;
209 193 };
... ...
libqpdf/QPDFFormFieldObjectHelper.cc
1 1 #include <qpdf/QPDFFormFieldObjectHelper.hh>
2 2  
  3 +#include <qpdf/FormField.hh>
  4 +
3 5 #include <qpdf/Pl_QPDFTokenizer.hh>
4 6 #include <qpdf/QIntC.hh>
5 7 #include <qpdf/QPDFAcroFormDocumentHelper.hh>
... ... @@ -10,35 +12,63 @@
10 12 #include <qpdf/QUtil.hh>
11 13 #include <cstdlib>
12 14  
  15 +#include <memory>
  16 +
13 17 using namespace qpdf;
14 18  
15   -QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper(QPDFObjectHandle oh) :
16   - QPDFObjectHelper(oh),
17   - m(new Members())
  19 +using FormField = qpdf::impl::FormField;
  20 +
  21 +class QPDFFormFieldObjectHelper::Members: public FormField
  22 +{
  23 + public:
  24 + Members(QPDFObjectHandle const& oh) :
  25 + FormField(oh)
  26 + {
  27 + }
  28 +};
  29 +
  30 +QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper(QPDFObjectHandle o) :
  31 + QPDFObjectHelper(o),
  32 + m(std::make_shared<Members>(oh()))
18 33 {
19 34 }
20 35  
21 36 QPDFFormFieldObjectHelper::QPDFFormFieldObjectHelper() :
22   - QPDFObjectHelper(QPDFObjectHandle::newNull()),
23   - m(new Members())
  37 + QPDFObjectHelper(Null::temp()),
  38 + m(std::make_shared<Members>(QPDFObjectHandle()))
24 39 {
25 40 }
26 41  
27 42 bool
28 43 QPDFFormFieldObjectHelper::isNull()
29 44 {
30   - return oh().null();
  45 + return m->null();
31 46 }
32 47  
33 48 QPDFFormFieldObjectHelper
34 49 QPDFFormFieldObjectHelper::getParent()
35 50 {
36   - return oh().getKey("/Parent"); // may be null
  51 + return {Null::if_null(m->getParent().oh())};
  52 +}
  53 +
  54 +FormField
  55 +FormField::getParent()
  56 +{
  57 + return {oh()["/Parent"]}; // maybe null
37 58 }
38 59  
39 60 QPDFFormFieldObjectHelper
40 61 QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different)
41 62 {
  63 + return Null::if_null(m->getTopLevelField(is_different).oh());
  64 +}
  65 +
  66 +FormField
  67 +FormField::getTopLevelField(bool* is_different)
  68 +{
  69 + if (!obj) {
  70 + return {};
  71 + }
42 72 auto top_field = oh();
43 73 QPDFObjGen::set seen;
44 74 while (seen.add(top_field) && !top_field.getKeyIfDict("/Parent").null()) {
... ... @@ -51,7 +81,7 @@ QPDFFormFieldObjectHelper::getTopLevelField(bool* is_different)
51 81 }
52 82  
53 83 QPDFObjectHandle
54   -QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const& name)
  84 +FormField::getFieldFromAcroForm(std::string const& name)
55 85 {
56 86 QPDFObjectHandle result = QPDFObjectHandle::newNull();
57 87 // Fields are supposed to be indirect, so this should work.
... ... @@ -69,6 +99,12 @@ QPDFFormFieldObjectHelper::getFieldFromAcroForm(std::string const&amp; name)
69 99 QPDFObjectHandle
70 100 QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const& name)
71 101 {
  102 + return m->getInheritableFieldValue(name);
  103 +}
  104 +
  105 +QPDFObjectHandle
  106 +FormField::getInheritableFieldValue(std::string const& name)
  107 +{
72 108 QPDFObjectHandle node = oh();
73 109 if (!node.isDictionary()) {
74 110 return QPDFObjectHandle::newNull();
... ... @@ -90,6 +126,12 @@ QPDFFormFieldObjectHelper::getInheritableFieldValue(std::string const&amp; name)
90 126 std::string
91 127 QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const& name)
92 128 {
  129 + return m->getInheritableFieldValueAsString(name);
  130 +}
  131 +
  132 +std::string
  133 +FormField::getInheritableFieldValueAsString(std::string const& name)
  134 +{
93 135 auto fv = getInheritableFieldValue(name);
94 136 if (fv.isString()) {
95 137 return fv.getUTF8Value();
... ... @@ -100,6 +142,12 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsString(std::string const&amp; n
100 142 std::string
101 143 QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const& name)
102 144 {
  145 + return m->getInheritableFieldValueAsName(name);
  146 +}
  147 +
  148 +std::string
  149 +FormField::getInheritableFieldValueAsName(std::string const& name)
  150 +{
103 151 if (Name fv = getInheritableFieldValue(name)) {
104 152 return fv;
105 153 }
... ... @@ -109,12 +157,24 @@ QPDFFormFieldObjectHelper::getInheritableFieldValueAsName(std::string const&amp; nam
109 157 std::string
110 158 QPDFFormFieldObjectHelper::getFieldType()
111 159 {
  160 + return m->getFieldType();
  161 +}
  162 +
  163 +std::string
  164 +FormField::getFieldType()
  165 +{
112 166 return getInheritableFieldValueAsName("/FT");
113 167 }
114 168  
115 169 std::string
116 170 QPDFFormFieldObjectHelper::getFullyQualifiedName()
117 171 {
  172 + return m->getFullyQualifiedName();
  173 +}
  174 +
  175 +std::string
  176 +FormField::getFullyQualifiedName()
  177 +{
118 178 std::string result;
119 179 QPDFObjectHandle node = oh();
120 180 QPDFObjGen::set seen;
... ... @@ -133,6 +193,12 @@ QPDFFormFieldObjectHelper::getFullyQualifiedName()
133 193 std::string
134 194 QPDFFormFieldObjectHelper::getPartialName()
135 195 {
  196 + return m->getPartialName();
  197 +}
  198 +
  199 +std::string
  200 +FormField::getPartialName()
  201 +{
136 202 std::string result;
137 203 if (oh().getKey("/T").isString()) {
138 204 result = oh().getKey("/T").getUTF8Value();
... ... @@ -143,6 +209,12 @@ QPDFFormFieldObjectHelper::getPartialName()
143 209 std::string
144 210 QPDFFormFieldObjectHelper::getAlternativeName()
145 211 {
  212 + return m->getAlternativeName();
  213 +}
  214 +
  215 +std::string
  216 +FormField::getAlternativeName()
  217 +{
146 218 if (oh().getKey("/TU").isString()) {
147 219 QTC::TC("qpdf", "QPDFFormFieldObjectHelper TU present");
148 220 return oh().getKey("/TU").getUTF8Value();
... ... @@ -154,6 +226,12 @@ QPDFFormFieldObjectHelper::getAlternativeName()
154 226 std::string
155 227 QPDFFormFieldObjectHelper::getMappingName()
156 228 {
  229 + return m->getMappingName();
  230 +}
  231 +
  232 +std::string
  233 +FormField::getMappingName()
  234 +{
157 235 if (oh().getKey("/TM").isString()) {
158 236 QTC::TC("qpdf", "QPDFFormFieldObjectHelper TM present");
159 237 return oh().getKey("/TM").getUTF8Value();
... ... @@ -165,6 +243,12 @@ QPDFFormFieldObjectHelper::getMappingName()
165 243 QPDFObjectHandle
166 244 QPDFFormFieldObjectHelper::getValue()
167 245 {
  246 + return m->getValue();
  247 +}
  248 +
  249 +QPDFObjectHandle
  250 +FormField::getValue()
  251 +{
168 252 return getInheritableFieldValue("/V");
169 253 }
170 254  
... ... @@ -174,27 +258,57 @@ QPDFFormFieldObjectHelper::getValueAsString()
174 258 return getInheritableFieldValueAsString("/V");
175 259 }
176 260  
  261 +std::string
  262 +FormField::getValueAsString()
  263 +{
  264 + return getInheritableFieldValueAsString("/V");
  265 +}
  266 +
177 267 QPDFObjectHandle
178 268 QPDFFormFieldObjectHelper::getDefaultValue()
179 269 {
  270 + return m->getDefaultValue();
  271 +}
  272 +
  273 +QPDFObjectHandle
  274 +FormField::getDefaultValue()
  275 +{
180 276 return getInheritableFieldValue("/DV");
181 277 }
182 278  
183 279 std::string
184 280 QPDFFormFieldObjectHelper::getDefaultValueAsString()
185 281 {
  282 + return m->getDefaultValueAsString();
  283 +}
  284 +
  285 +std::string
  286 +FormField::getDefaultValueAsString()
  287 +{
186 288 return getInheritableFieldValueAsString("/DV");
187 289 }
188 290  
189 291 QPDFObjectHandle
190 292 QPDFFormFieldObjectHelper::getDefaultResources()
191 293 {
  294 + return m->getDefaultResources();
  295 +}
  296 +
  297 +QPDFObjectHandle
  298 +FormField::getDefaultResources()
  299 +{
192 300 return getFieldFromAcroForm("/DR");
193 301 }
194 302  
195 303 std::string
196 304 QPDFFormFieldObjectHelper::getDefaultAppearance()
197 305 {
  306 + return m->getDefaultAppearance();
  307 +}
  308 +
  309 +std::string
  310 +FormField::getDefaultAppearance()
  311 +{
198 312 auto value = getInheritableFieldValue("/DA");
199 313 bool looked_in_acroform = false;
200 314 if (!value.isString()) {
... ... @@ -211,6 +325,12 @@ QPDFFormFieldObjectHelper::getDefaultAppearance()
211 325 int
212 326 QPDFFormFieldObjectHelper::getQuadding()
213 327 {
  328 + return m->getQuadding();
  329 +}
  330 +
  331 +int
  332 +FormField::getQuadding()
  333 +{
214 334 QPDFObjectHandle fv = getInheritableFieldValue("/Q");
215 335 bool looked_in_acroform = false;
216 336 if (!fv.isInteger()) {
... ... @@ -227,6 +347,12 @@ QPDFFormFieldObjectHelper::getQuadding()
227 347 int
228 348 QPDFFormFieldObjectHelper::getFlags()
229 349 {
  350 + return m->getFlags();
  351 +}
  352 +
  353 +int
  354 +FormField::getFlags()
  355 +{
230 356 QPDFObjectHandle f = getInheritableFieldValue("/Ff");
231 357 return f.isInteger() ? f.getIntValueAsInt() : 0;
232 358 }
... ... @@ -234,42 +360,84 @@ QPDFFormFieldObjectHelper::getFlags()
234 360 bool
235 361 QPDFFormFieldObjectHelper::isText()
236 362 {
  363 + return m->isText();
  364 +}
  365 +
  366 +bool
  367 +FormField::isText()
  368 +{
237 369 return getFieldType() == "/Tx";
238 370 }
239 371  
240 372 bool
241 373 QPDFFormFieldObjectHelper::isCheckbox()
242 374 {
  375 + return m->isCheckbox();
  376 +}
  377 +
  378 +bool
  379 +FormField::isCheckbox()
  380 +{
243 381 return getFieldType() == "/Btn" && (getFlags() & (ff_btn_radio | ff_btn_pushbutton)) == 0;
244 382 }
245 383  
246 384 bool
247 385 QPDFFormFieldObjectHelper::isChecked()
248 386 {
  387 + return m->isChecked();
  388 +}
  389 +
  390 +bool
  391 +FormField::isChecked()
  392 +{
249 393 return isCheckbox() && Name(getValue()) != "/Off";
250 394 }
251 395  
252 396 bool
253 397 QPDFFormFieldObjectHelper::isRadioButton()
254 398 {
  399 + return m->isRadioButton();
  400 +}
  401 +
  402 +bool
  403 +FormField::isRadioButton()
  404 +{
255 405 return getFieldType() == "/Btn" && (getFlags() & ff_btn_radio) == ff_btn_radio;
256 406 }
257 407  
258 408 bool
259 409 QPDFFormFieldObjectHelper::isPushbutton()
260 410 {
  411 + return m->isPushbutton();
  412 +}
  413 +
  414 +bool
  415 +FormField::isPushbutton()
  416 +{
261 417 return getFieldType() == "/Btn" && (getFlags() & ff_btn_pushbutton) == ff_btn_pushbutton;
262 418 }
263 419  
264 420 bool
265 421 QPDFFormFieldObjectHelper::isChoice()
266 422 {
  423 + return m->isChoice();
  424 +}
  425 +
  426 +bool
  427 +FormField::isChoice()
  428 +{
267 429 return getFieldType() == "/Ch";
268 430 }
269 431  
270 432 std::vector<std::string>
271 433 QPDFFormFieldObjectHelper::getChoices()
272 434 {
  435 + return m->getChoices();
  436 +}
  437 +
  438 +std::vector<std::string>
  439 +FormField::getChoices()
  440 +{
273 441 if (!isChoice()) {
274 442 return {};
275 443 }
... ... @@ -290,18 +458,36 @@ QPDFFormFieldObjectHelper::getChoices()
290 458 void
291 459 QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, QPDFObjectHandle value)
292 460 {
  461 + m->setFieldAttribute(key, value);
  462 +}
  463 +
  464 +void
  465 +FormField::setFieldAttribute(std::string const& key, QPDFObjectHandle value)
  466 +{
293 467 oh().replaceKey(key, value);
294 468 }
295 469  
296 470 void
297 471 QPDFFormFieldObjectHelper::setFieldAttribute(std::string const& key, std::string const& utf8_value)
298 472 {
  473 + m->setFieldAttribute(key, utf8_value);
  474 +}
  475 +
  476 +void
  477 +FormField::setFieldAttribute(std::string const& key, std::string const& utf8_value)
  478 +{
299 479 oh().replaceKey(key, QPDFObjectHandle::newUnicodeString(utf8_value));
300 480 }
301 481  
302 482 void
303 483 QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
304 484 {
  485 + m->setV(value, need_appearances);
  486 +}
  487 +
  488 +void
  489 +FormField::setV(QPDFObjectHandle value, bool need_appearances)
  490 +{
305 491 Name name = value;
306 492 if (getFieldType() == "/Btn") {
307 493 if (isCheckbox()) {
... ... @@ -344,11 +530,17 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances)
344 530 void
345 531 QPDFFormFieldObjectHelper::setV(std::string const& utf8_value, bool need_appearances)
346 532 {
  533 + m->setV(utf8_value, need_appearances);
  534 +}
  535 +
  536 +void
  537 +FormField::setV(std::string const& utf8_value, bool need_appearances)
  538 +{
347 539 setV(QPDFObjectHandle::newUnicodeString(utf8_value), need_appearances);
348 540 }
349 541  
350 542 void
351   -QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
  543 +FormField::setRadioButtonValue(QPDFObjectHandle name)
352 544 {
353 545 // Set the value of a radio button field. This has the following specific behavior:
354 546 // * If this is a radio button field that has a parent that is also a radio button field and has
... ... @@ -360,7 +552,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
360 552 // Note that we never turn on /NeedAppearances when setting a radio button field.
361 553 QPDFObjectHandle parent = oh().getKey("/Parent");
362 554 if (parent.isDictionary() && parent.getKey("/Parent").null()) {
363   - QPDFFormFieldObjectHelper ph(parent);
  555 + FormField ph(parent);
364 556 if (ph.isRadioButton()) {
365 557 // This is most likely one of the individual buttons. Try calling on the parent.
366 558 ph.setRadioButtonValue(name);
... ... @@ -403,7 +595,7 @@ QPDFFormFieldObjectHelper::setRadioButtonValue(QPDFObjectHandle name)
403 595 }
404 596  
405 597 void
406   -QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
  598 +FormField::setCheckBoxValue(bool value)
407 599 {
408 600 QPDFObjectHandle AP = oh().getKey("/AP");
409 601 QPDFObjectHandle annot;
... ... @@ -454,6 +646,12 @@ QPDFFormFieldObjectHelper::setCheckBoxValue(bool value)
454 646 void
455 647 QPDFFormFieldObjectHelper::generateAppearance(QPDFAnnotationObjectHelper& aoh)
456 648 {
  649 + m->generateAppearance(aoh);
  650 +}
  651 +
  652 +void
  653 +FormField::generateAppearance(QPDFAnnotationObjectHelper& aoh)
  654 +{
457 655 std::string ft = getFieldType();
458 656 // Ignore field types we don't know how to generate appearances for. Button fields don't really
459 657 // need them -- see code in QPDFAcroFormDocumentHelper::generateAppearancesIfNeeded.
... ... @@ -729,7 +927,7 @@ namespace
729 927 } // namespace
730 928  
731 929 QPDFObjectHandle
732   -QPDFFormFieldObjectHelper::getFontFromResource(QPDFObjectHandle resources, std::string const& name)
  930 +FormField::getFontFromResource(QPDFObjectHandle resources, std::string const& name)
733 931 {
734 932 QPDFObjectHandle result;
735 933 if (resources.isDictionary() && resources.getKey("/Font").isDictionary() &&
... ... @@ -740,7 +938,7 @@ QPDFFormFieldObjectHelper::getFontFromResource(QPDFObjectHandle resources, std::
740 938 }
741 939  
742 940 void
743   -QPDFFormFieldObjectHelper::generateTextAppearance(QPDFAnnotationObjectHelper& aoh)
  941 +FormField::generateTextAppearance(QPDFAnnotationObjectHelper& aoh)
744 942 {
745 943 QPDFObjectHandle AS = aoh.getAppearanceStream("/N");
746 944 if (AS.null()) {
... ...
libqpdf/qpdf/FormField.hh 0 โ†’ 100644
  1 +#ifndef FORMFIELD_HH
  2 +#define FORMFIELD_HH
  3 +
  4 +#include <qpdf/QPDFObjectHandle_private.hh>
  5 +#include <qpdf/QPDFObjectHelper.hh>
  6 +
  7 +#include <vector>
  8 +
  9 +class QPDFAnnotationObjectHelper;
  10 +
  11 +namespace qpdf::impl
  12 +{
  13 + // This object helper helps with form fields for interactive forms. Please see comments in
  14 + // QPDFAcroFormDocumentHelper.hh for additional details.
  15 + class FormField: public qpdf::BaseDictionary
  16 + {
  17 + public:
  18 + FormField() = default;
  19 + FormField(FormField const&) = default;
  20 + FormField& operator=(FormField const&) = default;
  21 + FormField(FormField&&) = default;
  22 + FormField& operator=(FormField&&) = default;
  23 + ~FormField() = default;
  24 +
  25 + FormField(QPDFObjectHandle const& oh) :
  26 + BaseDictionary(oh)
  27 + {
  28 + }
  29 +
  30 + FormField(QPDFObjectHandle&& oh) :
  31 + BaseDictionary(std::move(oh))
  32 + {
  33 + }
  34 +
  35 + // Return the field's parent. A form field object helper whose underlying object is null is
  36 + // returned if there is no parent. This condition may be tested by calling isNull().
  37 + FormField getParent();
  38 +
  39 + // Return the top-level field for this field. Typically this will be the field itself or its
  40 + // parent. If is_different is provided, it is set to true if the top-level field is
  41 + // different from the field itself; otherwise it is set to false.
  42 + FormField getTopLevelField(bool* is_different = nullptr);
  43 +
  44 + // Get a field value, possibly inheriting the value from an ancestor node.
  45 + QPDFObjectHandle getInheritableFieldValue(std::string const& name);
  46 +
  47 + // Get an inherited field value as a string. If it is not a string, silently return the
  48 + // empty string.
  49 + std::string getInheritableFieldValueAsString(std::string const& name);
  50 +
  51 + // Get an inherited field value of type name as a string representing the name. If it is not
  52 + // a name, silently return the empty string.
  53 + std::string getInheritableFieldValueAsName(std::string const& name);
  54 +
  55 + // Returns the value of /FT if present, otherwise returns the empty string.
  56 + std::string getFieldType();
  57 +
  58 + std::string getFullyQualifiedName();
  59 +
  60 + std::string getPartialName();
  61 +
  62 + // Return the alternative field name (/TU), which is the field name intended to be presented
  63 + // to users. If not present, fall back to the fully qualified name.
  64 + std::string getAlternativeName();
  65 +
  66 + // Return the mapping field name (/TM). If not present, fall back to the alternative name,
  67 + // then to the partial name.
  68 + std::string getMappingName();
  69 +
  70 + QPDFObjectHandle getValue();
  71 +
  72 + // Return the field's value as a string. If this is called with a field whose value is not a
  73 + std::string getValueAsString();
  74 +
  75 + QPDFObjectHandle getDefaultValue();
  76 +
  77 + // Return the field's default value as a string. If this is called with a field whose value
  78 + // is not a string, the empty string will be silently returned.
  79 + std::string getDefaultValueAsString();
  80 +
  81 + // Return the default appearance string, taking inheritance from the field tree into
  82 + // account. Returns the empty string if the default appearance string is not available
  83 + // (because it's erroneously absent or because this is not a variable text field). If not
  84 + // found in the field hierarchy, look in /AcroForm.
  85 + std::string getDefaultAppearance();
  86 +
  87 + // Return the default resource dictionary for the field. This comes not from the field but
  88 + // from the document-level /AcroForm dictionary. While several PDF generates put a /DR key
  89 + // in the form field's dictionary, experimentation suggests that many popular readers,
  90 + // including Adobe Acrobat and Acrobat Reader, ignore any /DR item on the field.
  91 + QPDFObjectHandle getDefaultResources();
  92 +
  93 + // Return the quadding value, taking inheritance from the field tree into account. Returns 0
  94 + // if quadding is not specified. Look in /AcroForm if not found in the field hierarchy.
  95 + int getQuadding();
  96 +
  97 + // Return field flags from /Ff. The value is a logical or of pdf_form_field_flag_e as
  98 + // defined in qpdf/Constants.h//
  99 + int getFlags();
  100 +
  101 + // Methods for testing for particular types of form fields
  102 +
  103 + // Returns true if field is of type /Tx
  104 + bool isText();
  105 + // Returns true if field is of type /Btn and flags do not indicate some other type of
  106 + // button.
  107 + bool isCheckbox();
  108 +
  109 + // Returns true if field is a checkbox and is checked.
  110 + bool isChecked();
  111 +
  112 + // Returns true if field is of type /Btn and flags indicate that it is a radio button
  113 + bool isRadioButton();
  114 +
  115 + // Returns true if field is of type /Btn and flags indicate that it is a pushbutton
  116 + bool isPushbutton();
  117 +
  118 + // Returns true if fields if of type /Ch
  119 + bool isChoice();
  120 +
  121 + // Returns choices display values as UTF-8 strings
  122 + std::vector<std::string> getChoices();
  123 +
  124 + // Set an attribute to the given value. If you have a QPDFAcroFormDocumentHelper and you
  125 + // want to set the name of a field, use QPDFAcroFormDocumentHelper::setFormFieldName
  126 + // instead.
  127 + void setFieldAttribute(std::string const& key, QPDFObjectHandle value);
  128 +
  129 + // Set an attribute to the given value as a Unicode string (UTF-16 BE encoded). The input
  130 + // string should be UTF-8 encoded. If you have a QPDFAcroFormDocumentHelper and you want to
  131 + // set the name of a field, use QPDFAcroFormDocumentHelper::setFormFieldName instead.
  132 + void setFieldAttribute(std::string const& key, std::string const& utf8_value);
  133 +
  134 + // Set /V (field value) to the given value. If need_appearances is true and the field type
  135 + // is either /Tx (text) or /Ch (choice), set /NeedAppearances to true. You can explicitly
  136 + // tell this method not to set /NeedAppearances if you are going to generate an appearance
  137 + // stream yourself. Starting with qpdf 8.3.0, this method handles fields of type /Btn
  138 + // (checkboxes, radio buttons, pushbuttons) specially. When setting a checkbox value, any
  139 + // value other than /Off will be treated as on, and the actual value set will be based on
  140 + // the appearance stream's /N dictionary, so the value that ends up in /V may not exactly
  141 + // match the value you pass in.
  142 + void setV(QPDFObjectHandle value, bool need_appearances = true);
  143 +
  144 + // Set /V (field value) to the given string value encoded as a Unicode string. The input
  145 + // value should be UTF-8 encoded. See comments above about /NeedAppearances.
  146 + void setV(std::string const& utf8_value, bool need_appearances = true);
  147 +
  148 + // Update the appearance stream for this field. Note that qpdf's ability to generate
  149 + // appearance streams is limited. We only generate appearance streams for streams of type
  150 + // text or choice. The appearance uses the default parameters provided in the file, and it
  151 + // only supports ASCII characters. Quadding is currently ignored. While this functionality
  152 + // is limited, it should do a decent job on properly constructed PDF files when field values
  153 + // are restricted to ASCII characters.
  154 + void generateAppearance(QPDFAnnotationObjectHelper&);
  155 +
  156 + private:
  157 + QPDFObjectHandle getFieldFromAcroForm(std::string const& name);
  158 + void setRadioButtonValue(QPDFObjectHandle name);
  159 + void setCheckBoxValue(bool value);
  160 + void generateTextAppearance(QPDFAnnotationObjectHelper&);
  161 + QPDFObjectHandle
  162 + getFontFromResource(QPDFObjectHandle resources, std::string const& font_name);
  163 + };
  164 +} // namespace qpdf::impl
  165 +
  166 +#endif // FORMFIELD_HH
... ...