Commit 0421e2ae26a8ca0655a09c5bb36199a52bfe53fe

Authored by m-holger
1 parent 4489c4bc

Refactor `QPDFAcroFormDocumentHelper::transformAnnotations`: extract `traverse_f…

…ield` function to increase code clarity.
libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -834,6 +834,58 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -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 auto transform_annotation = 889 auto transform_annotation =
838 [&](QPDFObjectHandle& annot) -> std::tuple<QPDFObjectHandle, bool, bool> { 890 [&](QPDFObjectHandle& annot) -> std::tuple<QPDFObjectHandle, bool, bool> {
839 // Make copies of annotations and fields down to the appearance streams, preserving all 891 // Make copies of annotations and fields down to the appearance streams, preserving all
@@ -896,55 +948,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -896,55 +948,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
896 948
897 // Traverse the field, copying kids, and preserving integrity. 949 // Traverse the field, copying kids, and preserving integrity.
898 if (maybe_copy_object(top_field)) { 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 // Now switch to copies. We already switched for top_field 954 // Now switch to copies. We already switched for top_field