Commit 4489c4bcc59af95f88f88776134bd1bbfd98fd1e
1 parent
f9287c41
Refactor `QPDFAcroFormDocumentHelper`: replace `std::list<QPDFObjectHandle>` wit…
…h `std::list<Dictionary>`, simplify `/Kids` handling, and update method calls for consistency.
Showing
1 changed file
with
41 additions
and
43 deletions
libqpdf/QPDFAcroFormDocumentHelper.cc
| ... | ... | @@ -480,6 +480,9 @@ QPDFAcroFormDocumentHelper::adjustInheritedFields( |
| 480 | 480 | bool override_q, |
| 481 | 481 | int from_default_q) |
| 482 | 482 | { |
| 483 | + if (!(override_da || override_q)) { | |
| 484 | + return; | |
| 485 | + } | |
| 483 | 486 | // Override /Q or /DA if needed. If this object has a field type, directly or inherited, it is a |
| 484 | 487 | // field and not just an annotation. In that case, we need to override if we are getting a value |
| 485 | 488 | // from the document that is different from the value we would have gotten from the old |
| ... | ... | @@ -892,65 +895,60 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 892 | 895 | } |
| 893 | 896 | |
| 894 | 897 | // Traverse the field, copying kids, and preserving integrity. |
| 895 | - std::list<QPDFObjectHandle> queue; | |
| 896 | - QPDFObjGen::set seen; | |
| 897 | 898 | if (maybe_copy_object(top_field)) { |
| 899 | + std::list<Dictionary> queue; | |
| 900 | + QPDFObjGen::set seen; | |
| 898 | 901 | queue.emplace_back(top_field); |
| 899 | - } | |
| 900 | - for (; !queue.empty(); queue.pop_front()) { | |
| 901 | - auto& obj = queue.front(); | |
| 902 | - if (seen.add(obj)) { | |
| 903 | - auto parent = obj["/Parent"]; | |
| 904 | - if (parent.isIndirect()) { | |
| 905 | - auto parent_og = parent.getObjGen(); | |
| 906 | - if (orig_to_copy.contains(parent_og)) { | |
| 907 | - obj.replaceKey("/Parent", orig_to_copy[parent_og]); | |
| 908 | - } else { | |
| 909 | - parent.warn( | |
| 910 | - "while traversing field " + obj.getObjGen().unparse(',') + | |
| 911 | - ", found parent (" + parent_og.unparse(',') + | |
| 912 | - ") that had not been seen, indicating likely invalid field structure"); | |
| 902 | + for (; !queue.empty(); queue.pop_front()) { | |
| 903 | + auto& obj = queue.front(); | |
| 904 | + if (seen.add(obj)) { | |
| 905 | + auto parent = obj["/Parent"]; | |
| 906 | + if (parent.isIndirect()) { | |
| 907 | + auto parent_og = parent.id_gen(); | |
| 908 | + if (orig_to_copy.contains(parent_og)) { | |
| 909 | + obj.replaceKey("/Parent", orig_to_copy[parent_og]); | |
| 910 | + } else { | |
| 911 | + parent.warn( | |
| 912 | + "while traversing field " + obj.id_gen().unparse(',') + | |
| 913 | + ", found parent (" + parent_og.unparse(',') + | |
| 914 | + ") that had not been seen, indicating likely invalid field " | |
| 915 | + "structure"); | |
| 916 | + } | |
| 913 | 917 | } |
| 914 | - } | |
| 915 | - auto kids = obj["/Kids"]; | |
| 916 | - int sz = static_cast<int>(kids.size()); | |
| 917 | - if (sz != 1 || kids.isArray()) { | |
| 918 | - for (int i = 0; i < sz; ++i) { | |
| 919 | - auto kid = kids.getArrayItem(i); | |
| 918 | + size_t i = 0; | |
| 919 | + Array Kids = obj["/Kids"]; | |
| 920 | + for (auto& kid: Kids) { | |
| 920 | 921 | if (maybe_copy_object(kid)) { |
| 921 | - kids.setArrayItem(i, kid); | |
| 922 | + Kids.set(i, kid); | |
| 922 | 923 | queue.emplace_back(kid); |
| 923 | 924 | } |
| 925 | + ++i; | |
| 924 | 926 | } |
| 925 | - } | |
| 926 | - | |
| 927 | - if (override_da || override_q) { | |
| 928 | 927 | adjustInheritedFields( |
| 929 | 928 | obj, override_da, from_default_da, override_q, from_default_q); |
| 930 | - } | |
| 931 | - if (foreign) { | |
| 932 | - // Lazily initialize our /DR and the conflict map. | |
| 933 | - init_dr_map(); | |
| 934 | - // The spec doesn't say anything about /DR on the field, but lots of writers | |
| 935 | - // put one there, and it is frequently the same as the document-level /DR. | |
| 936 | - // To avoid having the field's /DR point to information that we are not | |
| 937 | - // maintaining, just reset it to that if it exists. Empirical evidence | |
| 938 | - // suggests that many readers, including Acrobat, Adobe Acrobat Reader, | |
| 939 | - // chrome, firefox, the mac Preview application, and several of the free | |
| 940 | - // readers on Linux all ignore /DR at the field level. | |
| 941 | - if (obj.hasKey("/DR")) { | |
| 942 | - obj.replaceKey("/DR", dr); | |
| 929 | + if (foreign) { | |
| 930 | + // Lazily initialize our /DR and the conflict map. | |
| 931 | + init_dr_map(); | |
| 932 | + // The spec doesn't say anything about /DR on the field, but lots of writers | |
| 933 | + // put one there, and it is frequently the same as the document-level /DR. | |
| 934 | + // To avoid having the field's /DR point to information that we are not | |
| 935 | + // maintaining, just reset it to that if it exists. Empirical evidence | |
| 936 | + // suggests that many readers, including Acrobat, Adobe Acrobat Reader, | |
| 937 | + // chrome, firefox, the mac Preview application, and several of the free | |
| 938 | + // readers on Linux all ignore /DR at the field level. | |
| 939 | + if (obj.contains("/DR")) { | |
| 940 | + obj.replaceKey("/DR", dr); | |
| 941 | + } | |
| 942 | + if (obj["/DA"].isString() && !dr_map.empty()) { | |
| 943 | + adjustDefaultAppearances(obj, dr_map); | |
| 944 | + } | |
| 943 | 945 | } |
| 944 | 946 | } |
| 945 | - if (foreign && obj["/DA"].isString() && !dr_map.empty()) { | |
| 946 | - adjustDefaultAppearances(obj, dr_map); | |
| 947 | - } | |
| 948 | 947 | } |
| 949 | 948 | } |
| 950 | 949 | |
| 951 | 950 | // Now switch to copies. We already switched for top_field |
| 952 | 951 | maybe_copy_object(ffield_oh); |
| 953 | - ffield = QPDFFormFieldObjectHelper(ffield_oh); | |
| 954 | 952 | return {top_field, true, have_parent}; |
| 955 | 953 | }; |
| 956 | 954 | ... | ... |