Commit 0421e2ae26a8ca0655a09c5bb36199a52bfe53fe
1 parent
4489c4bc
Refactor `QPDFAcroFormDocumentHelper::transformAnnotations`: extract `traverse_f…
…ield` function to increase code clarity.
Showing
1 changed file
with
53 additions
and
49 deletions
libqpdf/QPDFAcroFormDocumentHelper.cc
| ... | ... | @@ -834,6 +834,58 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 834 | 834 | } |
| 835 | 835 | }; |
| 836 | 836 | |
| 837 | + auto traverse_field = [&](QPDFObjectHandle& top_field) -> void { | |
| 838 | + std::list<Dictionary> queue; | |
| 839 | + QPDFObjGen::set seen; | |
| 840 | + queue.emplace_back(top_field); | |
| 841 | + for (; !queue.empty(); queue.pop_front()) { | |
| 842 | + auto& obj = queue.front(); | |
| 843 | + if (seen.add(obj)) { | |
| 844 | + auto parent = obj["/Parent"]; | |
| 845 | + if (parent.isIndirect()) { | |
| 846 | + auto parent_og = parent.id_gen(); | |
| 847 | + if (orig_to_copy.contains(parent_og)) { | |
| 848 | + obj.replaceKey("/Parent", orig_to_copy[parent_og]); | |
| 849 | + } else { | |
| 850 | + parent.warn( | |
| 851 | + "while traversing field " + obj.id_gen().unparse(',') + | |
| 852 | + ", found parent (" + parent_og.unparse(',') + | |
| 853 | + ") that had not been seen, indicating likely invalid field " | |
| 854 | + "structure"); | |
| 855 | + } | |
| 856 | + } | |
| 857 | + size_t i = 0; | |
| 858 | + Array Kids = obj["/Kids"]; | |
| 859 | + for (auto& kid: Kids) { | |
| 860 | + if (maybe_copy_object(kid)) { | |
| 861 | + Kids.set(i, kid); | |
| 862 | + queue.emplace_back(kid); | |
| 863 | + } | |
| 864 | + ++i; | |
| 865 | + } | |
| 866 | + adjustInheritedFields( | |
| 867 | + obj, override_da, from_default_da, override_q, from_default_q); | |
| 868 | + if (foreign) { | |
| 869 | + // Lazily initialize our /DR and the conflict map. | |
| 870 | + init_dr_map(); | |
| 871 | + // The spec doesn't say anything about /DR on the field, but lots of writers | |
| 872 | + // put one there, and it is frequently the same as the document-level /DR. | |
| 873 | + // To avoid having the field's /DR point to information that we are not | |
| 874 | + // maintaining, just reset it to that if it exists. Empirical evidence | |
| 875 | + // suggests that many readers, including Acrobat, Adobe Acrobat Reader, | |
| 876 | + // chrome, firefox, the mac Preview application, and several of the free | |
| 877 | + // readers on Linux all ignore /DR at the field level. | |
| 878 | + if (obj.contains("/DR")) { | |
| 879 | + obj.replaceKey("/DR", dr); | |
| 880 | + } | |
| 881 | + if (obj["/DA"].isString() && !dr_map.empty()) { | |
| 882 | + adjustDefaultAppearances(obj, dr_map); | |
| 883 | + } | |
| 884 | + } | |
| 885 | + } | |
| 886 | + } | |
| 887 | + }; | |
| 888 | + | |
| 837 | 889 | auto transform_annotation = |
| 838 | 890 | [&](QPDFObjectHandle& annot) -> std::tuple<QPDFObjectHandle, bool, bool> { |
| 839 | 891 | // Make copies of annotations and fields down to the appearance streams, preserving all |
| ... | ... | @@ -896,55 +948,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( |
| 896 | 948 | |
| 897 | 949 | // Traverse the field, copying kids, and preserving integrity. |
| 898 | 950 | if (maybe_copy_object(top_field)) { |
| 899 | - std::list<Dictionary> queue; | |
| 900 | - QPDFObjGen::set seen; | |
| 901 | - queue.emplace_back(top_field); | |
| 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 | - } | |
| 917 | - } | |
| 918 | - size_t i = 0; | |
| 919 | - Array Kids = obj["/Kids"]; | |
| 920 | - for (auto& kid: Kids) { | |
| 921 | - if (maybe_copy_object(kid)) { | |
| 922 | - Kids.set(i, kid); | |
| 923 | - queue.emplace_back(kid); | |
| 924 | - } | |
| 925 | - ++i; | |
| 926 | - } | |
| 927 | - adjustInheritedFields( | |
| 928 | - obj, override_da, from_default_da, override_q, from_default_q); | |
| 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 | - } | |
| 945 | - } | |
| 946 | - } | |
| 947 | - } | |
| 951 | + traverse_field(top_field); | |
| 948 | 952 | } |
| 949 | 953 | |
| 950 | 954 | // Now switch to copies. We already switched for top_field | ... | ... |