Commit 4489c4bcc59af95f88f88776134bd1bbfd98fd1e

Authored by m-holger
1 parent f9287c41

Refactor `QPDFAcroFormDocumentHelper`: replace `std::list<QPDFObjectHandle>` wit…

…h `std::list<Dictionary>`, simplify `/Kids` handling, and update method calls for consistency.
libqpdf/QPDFAcroFormDocumentHelper.cc
@@ -480,6 +480,9 @@ QPDFAcroFormDocumentHelper::adjustInheritedFields( @@ -480,6 +480,9 @@ QPDFAcroFormDocumentHelper::adjustInheritedFields(
480 bool override_q, 480 bool override_q,
481 int from_default_q) 481 int from_default_q)
482 { 482 {
  483 + if (!(override_da || override_q)) {
  484 + return;
  485 + }
483 // Override /Q or /DA if needed. If this object has a field type, directly or inherited, it is a 486 // Override /Q or /DA if needed. If this object has a field type, directly or inherited, it is a
484 // field and not just an annotation. In that case, we need to override if we are getting a value 487 // field and not just an annotation. In that case, we need to override if we are getting a value
485 // from the document that is different from the value we would have gotten from the old 488 // from the document that is different from the value we would have gotten from the old
@@ -892,65 +895,60 @@ QPDFAcroFormDocumentHelper::transformAnnotations( @@ -892,65 +895,60 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
892 } 895 }
893 896
894 // Traverse the field, copying kids, and preserving integrity. 897 // Traverse the field, copying kids, and preserving integrity.
895 - std::list<QPDFObjectHandle> queue;  
896 - QPDFObjGen::set seen;  
897 if (maybe_copy_object(top_field)) { 898 if (maybe_copy_object(top_field)) {
  899 + std::list<Dictionary> queue;
  900 + QPDFObjGen::set seen;
898 queue.emplace_back(top_field); 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 if (maybe_copy_object(kid)) { 921 if (maybe_copy_object(kid)) {
921 - kids.setArrayItem(i, kid); 922 + Kids.set(i, kid);
922 queue.emplace_back(kid); 923 queue.emplace_back(kid);
923 } 924 }
  925 + ++i;
924 } 926 }
925 - }  
926 -  
927 - if (override_da || override_q) {  
928 adjustInheritedFields( 927 adjustInheritedFields(
929 obj, override_da, from_default_da, override_q, from_default_q); 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 // Now switch to copies. We already switched for top_field 950 // Now switch to copies. We already switched for top_field
952 maybe_copy_object(ffield_oh); 951 maybe_copy_object(ffield_oh);
953 - ffield = QPDFFormFieldObjectHelper(ffield_oh);  
954 return {top_field, true, have_parent}; 952 return {top_field, true, have_parent};
955 }; 953 };
956 954