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 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
... ...