Commit 0fa8fbbcc76027a4318f1fe2f3754d0436969cd7
1 parent
f4589458
Refactor `QPDFAcroFormDocumentHelper::transformAnnotation`: replace `getKey` wit…
…h operator[], update type handling for clarity and consistency, and streamline resource merging.
Showing
1 changed file
with
45 additions
and
50 deletions
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 | } | ... | ... |