Commit 0ea709d427760b8007372eeefead66e373d94e93
1 parent
6923f0d4
Refactor `FormNode::setRadioButtonValue`
Fix identification of radio button widgets by relying on the absence of `Kids` arrays. Fix the exclusion of RadioButtonFields with parents. Fixes #1449
Showing
2 changed files
with
22 additions
and
16 deletions
libqpdf/QPDFFormFieldObjectHelper.cc
| ... | ... | @@ -446,8 +446,8 @@ QPDFFormFieldObjectHelper::setV(QPDFObjectHandle value, bool need_appearances) |
| 446 | 446 | void |
| 447 | 447 | FormNode::setV(QPDFObjectHandle value, bool need_appearances) |
| 448 | 448 | { |
| 449 | - Name name = value; | |
| 450 | 449 | if (FT() == "/Btn") { |
| 450 | + Name name = value; | |
| 451 | 451 | if (isCheckbox()) { |
| 452 | 452 | if (!name) { |
| 453 | 453 | warn("ignoring attempt to set a checkbox field to a value whose type is not name"); |
| ... | ... | @@ -498,31 +498,30 @@ FormNode::setV(std::string const& utf8_value, bool need_appearances) |
| 498 | 498 | } |
| 499 | 499 | |
| 500 | 500 | void |
| 501 | -FormNode::setRadioButtonValue(QPDFObjectHandle name) | |
| 501 | +FormNode::setRadioButtonValue(Name const& name) | |
| 502 | 502 | { |
| 503 | + qpdf_expect(name); | |
| 503 | 504 | // Set the value of a radio button field. This has the following specific behavior: |
| 504 | - // * If this is a radio button field that has a parent that is also a radio button field and has | |
| 505 | - // no explicit /V, call itself on the parent | |
| 505 | + // * If this is a node without /Kids, assume this is a individual radio button widget and call | |
| 506 | + // itself on the parent | |
| 506 | 507 | // * If this is a radio button field with children, set /V to the given value. Then, for each |
| 507 | 508 | // child, if the child has the specified value as one of its keys in the /N subdictionary of |
| 508 | 509 | // its /AP (i.e. its normal appearance stream dictionary), set /AS to name; otherwise, if /Off |
| 509 | 510 | // is a member, set /AS to /Off. |
| 510 | - // Note that we never turn on /NeedAppearances when setting a radio button field. | |
| 511 | - QPDFObjectHandle parent = oh().getKey("/Parent"); | |
| 512 | - if (parent.isDictionary() && parent.getKey("/Parent").null()) { | |
| 513 | - FormNode ph(parent); | |
| 514 | - if (ph.isRadioButton()) { | |
| 515 | - // This is most likely one of the individual buttons. Try calling on the parent. | |
| 516 | - ph.setRadioButtonValue(name); | |
| 511 | + auto kids = Kids(); | |
| 512 | + if (!kids) { | |
| 513 | + // This is most likely one of the individual buttons. Try calling on the parent. | |
| 514 | + auto parent = Parent(); | |
| 515 | + if (parent.Kids()) { | |
| 516 | + parent.setRadioButtonValue(name); | |
| 517 | 517 | return; |
| 518 | 518 | } |
| 519 | 519 | } |
| 520 | - auto kids = Kids(); | |
| 521 | - if (!(isRadioButton() && parent.null() && kids)) { | |
| 520 | + if (!isRadioButton() || !kids) { | |
| 522 | 521 | warn("don't know how to set the value of this field as a radio button"); |
| 523 | 522 | return; |
| 524 | 523 | } |
| 525 | - setFieldAttribute("/V", name); | |
| 524 | + replace("/V", name); | |
| 526 | 525 | for (FormNode kid: kids) { |
| 527 | 526 | auto ap = kid.AP(); |
| 528 | 527 | QPDFObjectHandle annot; |
| ... | ... | @@ -542,7 +541,7 @@ FormNode::setRadioButtonValue(QPDFObjectHandle name) |
| 542 | 541 | warn("unable to set the value of this radio button"); |
| 543 | 542 | continue; |
| 544 | 543 | } |
| 545 | - if (ap["/N"].contains(name.getName())) { | |
| 544 | + if (ap["/N"].contains(name.value())) { | |
| 546 | 545 | annot.replace("/AS", name); |
| 547 | 546 | } else { |
| 548 | 547 | annot.replace("/AS", Name("/Off")); | ... | ... |
libqpdf/qpdf/AcroForm.hh
| ... | ... | @@ -767,7 +767,14 @@ namespace qpdf::impl |
| 767 | 767 | return {qpdf() ? qpdf()->getRoot()["/AcroForm"][name] : null_oh}; |
| 768 | 768 | } |
| 769 | 769 | |
| 770 | - void setRadioButtonValue(QPDFObjectHandle name); | |
| 770 | + /// @brief Sets the value of a radio button field. | |
| 771 | + /// | |
| 772 | + /// This method updates the value of a radio button field to the specified name. | |
| 773 | + /// It ensures that the radio button's state is consistent with the provided value. | |
| 774 | + /// | |
| 775 | + /// @param name The name of the radio button value to set. This corresponds to the | |
| 776 | + /// appearance state name of the selected radio button. | |
| 777 | + void setRadioButtonValue(Name const& name); | |
| 771 | 778 | void setCheckBoxValue(bool value); |
| 772 | 779 | void generateTextAppearance(QPDFAnnotationObjectHelper&); |
| 773 | 780 | ... | ... |