Commit 0fa8fbbcc76027a4318f1fe2f3754d0436969cd7

Authored by m-holger
1 parent f4589458

Refactor `QPDFAcroFormDocumentHelper::transformAnnotation`: replace `getKey` wit…

…h operator[], update type handling for clarity and consistency, and streamline resource merging.
libqpdf/QPDFAcroFormDocumentHelper.cc
... ... @@ -719,7 +719,7 @@ QPDFAcroFormDocumentHelper::adjustAppearanceStream(
719 719  
720 720 void
721 721 QPDFAcroFormDocumentHelper::transformAnnotations(
722   - QPDFObjectHandle old_annots,
  722 + QPDFObjectHandle a_old_annots,
723 723 std::vector<QPDFObjectHandle>& new_annots,
724 724 std::vector<QPDFObjectHandle>& new_fields,
725 725 std::set<QPDFObjGen>& old_fields,
... ... @@ -727,94 +727,89 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
727 727 QPDF* from_qpdf,
728 728 QPDFAcroFormDocumentHelper* from_afdh)
729 729 {
730   - std::shared_ptr<QPDFAcroFormDocumentHelper> afdhph;
  730 + Array old_annots = std::move(a_old_annots);
731 731 if (!from_qpdf) {
732 732 // Assume these are from the same QPDF.
733 733 from_qpdf = &qpdf;
734 734 from_afdh = this;
735   - } else if ((from_qpdf != &qpdf) && (!from_afdh)) {
736   - afdhph = std::make_shared<QPDFAcroFormDocumentHelper>(*from_qpdf);
737   - from_afdh = afdhph.get();
  735 + } else if (from_qpdf != &qpdf && !from_afdh) {
  736 + from_afdh = &QPDFAcroFormDocumentHelper::get(*from_qpdf);
738 737 }
739   - bool foreign = (from_qpdf != &qpdf);
  738 + const bool foreign = from_qpdf != &qpdf;
740 739  
741 740 // It's possible that we will transform annotations that don't include any form fields. This
742 741 // code takes care not to muck around with /AcroForm unless we have to.
743 742  
744   - QPDFObjectHandle acroform = qpdf.getRoot().getKey("/AcroForm");
745   - QPDFObjectHandle from_acroform = from_qpdf->getRoot().getKey("/AcroForm");
  743 + Dictionary acroform = qpdf.getRoot()["/AcroForm"];
  744 + Dictionary from_acroform = from_qpdf->getRoot()["/AcroForm"];
746 745  
747 746 // /DA and /Q may be inherited from the document-level /AcroForm dictionary. If we are copying a
748 747 // foreign stream and the stream is getting one of these values from its document's /AcroForm,
749 748 // we will need to copy the value explicitly so that it doesn't start getting its default from
750 749 // the destination document.
751   - bool override_da = false;
752   - bool override_q = false;
753 750 std::string from_default_da;
754 751 int from_default_q = 0;
755 752 // If we copy any form fields, we will need to merge the source document's /DR into this
756 753 // document's /DR.
757   - QPDFObjectHandle from_dr = QPDFObjectHandle::newNull();
  754 + Dictionary from_dr;
  755 + std::string default_da;
  756 + int default_q = 0;
758 757 if (foreign) {
759   - std::string default_da;
760   - int default_q = 0;
761   - if (acroform.isDictionary()) {
762   - if (acroform.getKey("/DA").isString()) {
763   - default_da = acroform.getKey("/DA").getUTF8Value();
  758 + if (acroform) {
  759 + if (acroform["/DA"].isString()) {
  760 + default_da = acroform["/DA"].getUTF8Value();
764 761 }
765   - if (acroform.getKey("/Q").isInteger()) {
766   - default_q = acroform.getKey("/Q").getIntValueAsInt();
  762 + if (Integer Q = acroform["/Q"]) {
  763 + default_q = Q;
767 764 }
768 765 }
769   - if (from_acroform.isDictionary()) {
770   - if (from_acroform.getKey("/DR").isDictionary()) {
771   - from_dr = from_acroform.getKey("/DR");
772   - if (!from_dr.isIndirect()) {
  766 + if (from_acroform) {
  767 + from_dr = from_acroform["/DR"];
  768 + if (from_dr) {
  769 + if (!from_dr.indirect()) {
773 770 from_dr = from_qpdf->makeIndirectObject(from_dr);
774 771 }
775 772 from_dr = qpdf.copyForeignObject(from_dr);
776 773 }
777   - if (from_acroform.getKey("/DA").isString()) {
778   - from_default_da = from_acroform.getKey("/DA").getUTF8Value();
  774 + if (from_acroform["/DA"].isString()) {
  775 + from_default_da = from_acroform["/DA"].getUTF8Value();
779 776 }
780   - if (from_acroform.getKey("/Q").isInteger()) {
781   - from_default_q = from_acroform.getKey("/Q").getIntValueAsInt();
  777 + if (Integer Q = from_acroform["/Q"]) {
  778 + from_default_q = Q;
782 779 }
783 780 }
784   - if (from_default_da != default_da) {
785   - override_da = true;
786   - }
787   - if (from_default_q != default_q) {
788   - override_q = true;
789   - }
790 781 }
  782 + const bool override_da = from_acroform ? from_default_da != default_da : false;
  783 + const bool override_q = from_acroform ? from_default_q != default_q : false;
791 784  
792 785 // If we have to merge /DR, we will need a mapping of conflicting keys for rewriting /DA. Set
793 786 // this up for lazy initialization in case we encounter any form fields.
794 787 std::map<std::string, std::map<std::string, std::string>> dr_map;
795 788 bool initialized_dr_map = false;
796   - QPDFObjectHandle dr = QPDFObjectHandle::newNull();
  789 + Dictionary dr;
  790 +
797 791 auto init_dr_map = [&]() {
798 792 if (!initialized_dr_map) {
799 793 initialized_dr_map = true;
800 794 // Ensure that we have a /DR that is an indirect
801 795 // dictionary object.
802   - if (!acroform.isDictionary()) {
  796 + if (!acroform) {
803 797 acroform = getOrCreateAcroForm();
804 798 }
805   - dr = acroform.getKey("/DR");
806   - if (!dr.isDictionary()) {
807   - dr = QPDFObjectHandle::newDictionary();
  799 + dr = acroform["/DR"];
  800 + if (!dr) {
  801 + dr = Dictionary::empty();
808 802 }
809   - dr.makeResourcesIndirect(qpdf);
810   - if (!dr.isIndirect()) {
811   - dr = acroform.replaceKeyAndGetNew("/DR", qpdf.makeIndirectObject(dr));
  803 + QPDFObjectHandle(dr).makeResourcesIndirect(qpdf);
  804 + if (!dr.indirect()) {
  805 + acroform.replaceKey("/DR", qpdf.makeIndirectObject(dr));
  806 + dr = acroform["/DR"];
812 807 }
813 808 // Merge the other document's /DR, creating a conflict map. mergeResources checks to
814 809 // make sure both objects are dictionaries. By this point, if this is foreign, from_dr
815 810 // has been copied, so we use the target qpdf as the owning qpdf.
816   - from_dr.makeResourcesIndirect(qpdf);
817   - dr.mergeResources(from_dr, &dr_map);
  811 + QPDFObjectHandle(from_dr).makeResourcesIndirect(qpdf);
  812 + QPDFObjectHandle(dr).mergeResources(from_dr, &dr_map);
818 813  
819 814 if (from_afdh->getNeedAppearances()) {
820 815 setNeedAppearances(true);
... ... @@ -839,7 +834,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
839 834 // Now do the actual copies.
840 835  
841 836 QPDFObjGen::set added_new_fields;
842   - for (auto annot: old_annots.aitems()) {
  837 + for (auto annot: old_annots) {
843 838 if (annot.isStream()) {
844 839 annot.warn("ignoring annotation that's a stream");
845 840 continue;
... ... @@ -904,12 +899,12 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
904 899 std::list<QPDFObjectHandle> queue;
905 900 QPDFObjGen::set seen;
906 901 if (maybe_copy_object(top_field)) {
907   - queue.push_back(top_field);
  902 + queue.emplace_back(top_field);
908 903 }
909 904 for (; !queue.empty(); queue.pop_front()) {
910 905 auto& obj = queue.front();
911 906 if (seen.add(obj)) {
912   - auto parent = obj.getKey("/Parent");
  907 + auto parent = obj["/Parent"];
913 908 if (parent.isIndirect()) {
914 909 auto parent_og = parent.getObjGen();
915 910 if (orig_to_copy.contains(parent_og)) {
... ... @@ -922,7 +917,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
922 917 "structure");
923 918 }
924 919 }
925   - auto kids = obj.getKey("/Kids");
  920 + auto kids = obj["/Kids"];
926 921 int sz = static_cast<int>(kids.size());
927 922 if (sz != 1 || kids.isArray()) {
928 923 for (int i = 0; i < sz; ++i) {
... ... @@ -952,7 +947,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
952 947 obj.replaceKey("/DR", dr);
953 948 }
954 949 }
955   - if (foreign && obj.getKey("/DA").isString() && (!dr_map.empty())) {
  950 + if (foreign && obj["/DA"].isString() && !dr_map.empty()) {
956 951 adjustDefaultAppearances(obj, dr_map);
957 952 }
958 953 }
... ... @@ -1011,7 +1006,7 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
1011 1006 // Now we can safely mutate the annotation and its appearance streams.
1012 1007 for (auto& stream: streams) {
1013 1008 auto dict = stream.getDict();
1014   - auto omatrix = dict.getKey("/Matrix");
  1009 + auto omatrix = dict["/Matrix"];
1015 1010 QPDFMatrix apcm;
1016 1011 if (omatrix.isArray()) {
1017 1012 QTC::TC("qpdf", "QPDFAcroFormDocumentHelper modify ap matrix");
... ... @@ -1023,12 +1018,12 @@ QPDFAcroFormDocumentHelper::transformAnnotations(
1023 1018 if (omatrix.isArray() || (apcm != QPDFMatrix())) {
1024 1019 dict.replaceKey("/Matrix", new_matrix);
1025 1020 }
1026   - auto resources = dict.getKey("/Resources");
  1021 + auto resources = dict["/Resources"];
1027 1022 if ((!dr_map.empty()) && resources.isDictionary()) {
1028 1023 adjustAppearanceStream(stream, dr_map);
1029 1024 }
1030 1025 }
1031   - auto rect = cm.transformRectangle(annot.getKey("/Rect").getArrayAsRectangle());
  1026 + auto rect = cm.transformRectangle(annot["/Rect"].getArrayAsRectangle());
1032 1027 annot.replaceKey("/Rect", QPDFObjectHandle::newFromRectangle(rect));
1033 1028 }
1034 1029 }
... ...