Commit 6ad83cfde47c8a523351f79d22b2ad6bcd317705

Authored by m-holger
1 parent d33e5a9c

Refactor QPDFFormFieldObjectHelper: extract logic into `impl::FormField`, clean …

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