Fix overlapping annot rendering with focused annot. The reason CPDFSDK_AnnotReverseIteration existed was to put the focused annotation at the end of the list, so it will draw on top of other annotations. When https://pdfium-review.googlesource.com/98870 fixed the drawing order for overlapping annotations, it broke this use case. Add CPDFSDK_AnnotIteration::CreateForDrawing() as a factory function to create CPDFSDK_AnnotIteration objects that iterate correctly for the drawing use case. Use it in CPDFSDK_PageView::PageView_OnDraw() to fix annotation drawing. Make sure it works as expected with a new test case. Bug: chromium:1372651 Change-Id: I0bf673e9af9eb59773f7ef933fc363aab9f22abc Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/99110 Commit-Queue: Lei Zhang <thestig@chromium.org> Reviewed-by: Tom Sepez <tsepez@chromium.org>
diff --git a/fpdfsdk/cpdfsdk_annotiteration.cpp b/fpdfsdk/cpdfsdk_annotiteration.cpp index aa736bb..e32946f 100644 --- a/fpdfsdk/cpdfsdk_annotiteration.cpp +++ b/fpdfsdk/cpdfsdk_annotiteration.cpp
@@ -11,26 +11,39 @@ #include "fpdfsdk/cpdfsdk_annot.h" #include "fpdfsdk/cpdfsdk_pageview.h" -CPDFSDK_AnnotIteration::CPDFSDK_AnnotIteration(CPDFSDK_PageView* pPageView) { +// static +CPDFSDK_AnnotIteration CPDFSDK_AnnotIteration::CreateForDrawing( + CPDFSDK_PageView* page_view) { + CPDFSDK_AnnotIteration result(page_view); + return CPDFSDK_AnnotIteration(page_view, /*put_focused_annot_at_end=*/true); +} + +CPDFSDK_AnnotIteration::CPDFSDK_AnnotIteration(CPDFSDK_PageView* page_view) + : CPDFSDK_AnnotIteration(page_view, /*put_focused_annot_at_end=*/false) {} + +CPDFSDK_AnnotIteration::CPDFSDK_AnnotIteration(CPDFSDK_PageView* page_view, + bool put_focused_annot_at_end) { // Copying ObservedPtrs is expensive, so do it once at the end. - std::vector<CPDFSDK_Annot*> copied_list = pPageView->GetAnnotList(); + std::vector<CPDFSDK_Annot*> copied_list = page_view->GetAnnotList(); std::stable_sort(copied_list.begin(), copied_list.end(), [](const CPDFSDK_Annot* p1, const CPDFSDK_Annot* p2) { return p1->GetLayoutOrder() < p2->GetLayoutOrder(); }); - CPDFSDK_Annot* pTopMostAnnot = pPageView->GetFocusAnnot(); + CPDFSDK_Annot* pTopMostAnnot = page_view->GetFocusAnnot(); if (pTopMostAnnot) { auto it = std::find(copied_list.begin(), copied_list.end(), pTopMostAnnot); if (it != copied_list.end()) { copied_list.erase(it); - copied_list.insert(copied_list.begin(), pTopMostAnnot); + auto insert_it = + put_focused_annot_at_end ? copied_list.end() : copied_list.begin(); + copied_list.insert(insert_it, pTopMostAnnot); } } - m_List.reserve(copied_list.size()); + list_.reserve(copied_list.size()); for (auto* pAnnot : copied_list) - m_List.emplace_back(pAnnot); + list_.emplace_back(pAnnot); } CPDFSDK_AnnotIteration::~CPDFSDK_AnnotIteration() = default;
diff --git a/fpdfsdk/cpdfsdk_annotiteration.h b/fpdfsdk/cpdfsdk_annotiteration.h index a222877..ff5b99a 100644 --- a/fpdfsdk/cpdfsdk_annotiteration.h +++ b/fpdfsdk/cpdfsdk_annotiteration.h
@@ -18,14 +18,21 @@ using const_iterator = std::vector<ObservedPtr<CPDFSDK_Annot>>::const_iterator; - explicit CPDFSDK_AnnotIteration(CPDFSDK_PageView* pPageView); + static CPDFSDK_AnnotIteration CreateForDrawing(CPDFSDK_PageView* page_view); + + explicit CPDFSDK_AnnotIteration(CPDFSDK_PageView* page_view); + CPDFSDK_AnnotIteration(const CPDFSDK_AnnotIteration&) = delete; + CPDFSDK_AnnotIteration& operator=(const CPDFSDK_AnnotIteration&) = delete; ~CPDFSDK_AnnotIteration(); - const_iterator begin() const { return m_List.begin(); } - const_iterator end() const { return m_List.end(); } + const_iterator begin() const { return list_.begin(); } + const_iterator end() const { return list_.end(); } private: - std::vector<ObservedPtr<CPDFSDK_Annot>> m_List; + CPDFSDK_AnnotIteration(CPDFSDK_PageView* page_view, + bool put_focused_annot_at_end); + + std::vector<ObservedPtr<CPDFSDK_Annot>> list_; }; #endif // FPDFSDK_CPDFSDK_ANNOTITERATION_H_
diff --git a/fpdfsdk/cpdfsdk_pageview.cpp b/fpdfsdk/cpdfsdk_pageview.cpp index 66ed4cf..2f35101 100644 --- a/fpdfsdk/cpdfsdk_pageview.cpp +++ b/fpdfsdk/cpdfsdk_pageview.cpp
@@ -86,7 +86,7 @@ #endif // PDF_ENABLE_XFA // for pdf/static xfa. - CPDFSDK_AnnotIteration annot_iteration(this); + auto annot_iteration = CPDFSDK_AnnotIteration::CreateForDrawing(this); for (const auto& pSDKAnnot : annot_iteration) { pSDKAnnot->OnDraw(pDevice, mtUser2Device, pOptions->GetDrawAnnots()); }
diff --git a/testing/resources/pixel/bug_1372651.evt b/testing/resources/pixel/bug_1372651.evt new file mode 100644 index 0000000..eb762eb --- /dev/null +++ b/testing/resources/pixel/bug_1372651.evt
@@ -0,0 +1,4 @@ +# Open the dropdown +mousemove,140,145 +mousedown,left,140,145 +mouseup,left,140,145
diff --git a/testing/resources/pixel/bug_1372651.in b/testing/resources/pixel/bug_1372651.in new file mode 100644 index 0000000..95b1948 --- /dev/null +++ b/testing/resources/pixel/bug_1372651.in
@@ -0,0 +1,71 @@ +{{header}} +{{object 1 0}} << + /Type /Catalog + /AcroForm << + /DA (/Helv 0 Tf 0 g) + /DR << + /Font << + /Helv 4 0 R + >> + >> + /Fields [5 0 R 6 0 R] + >> + /Pages 2 0 R +>> +endobj +{{object 2 0}} << + /Type /Pages + /Count 1 + /Kids [3 0 R] +>> +endobj +{{object 3 0}} << + /Type /Page + /Parent 2 0 R + /Annots [5 0 R 6 0 R] + /MediaBox [0 0 200 200] +>> +endobj +{{object 4 0}} << + /Type /Font + /Subtype /Type1 + /BaseFont /Helvetica +>> +endobj +{{object 5 0}} << + /Type /Annot + /Subtype /Widget + /FT /Ch + /DV (Item3) + /F 4 + /Ff 131072 + /I [2] + /MK << + /BG [1.0] + >> + /Opt [(Item1) (Item2) (Item3)] + /P 3 0 R + /Rect [70 135 150 155] + /T (Dropdown) + /V (Item3) +>> +endobj +{{object 6 0}} << + /Type /Annot + /Subtype /Widget + /FT /Btn + /F 4 + /Ff 65536 + /MK << + /BG [0.5] + >> + /P 3 0 R + /Rect [50 90 150 110] + /T (Button) + /TU (Button Tooltip) +>> +endobj +{{xref}} +{{trailer}} +{{startxref}} +%%EOF
diff --git a/testing/resources/pixel/bug_1372651_expected.pdf.0.png b/testing/resources/pixel/bug_1372651_expected.pdf.0.png new file mode 100644 index 0000000..c7386a1 --- /dev/null +++ b/testing/resources/pixel/bug_1372651_expected.pdf.0.png Binary files differ
diff --git a/testing/resources/pixel/bug_1372651_expected_mac.pdf.0.png b/testing/resources/pixel/bug_1372651_expected_mac.pdf.0.png new file mode 100644 index 0000000..a749d63 --- /dev/null +++ b/testing/resources/pixel/bug_1372651_expected_mac.pdf.0.png Binary files differ
diff --git a/testing/resources/pixel/bug_1372651_expected_skia.pdf.0.png b/testing/resources/pixel/bug_1372651_expected_skia.pdf.0.png new file mode 100644 index 0000000..00cc13c --- /dev/null +++ b/testing/resources/pixel/bug_1372651_expected_skia.pdf.0.png Binary files differ
diff --git a/testing/resources/pixel/bug_1372651_expected_skiapaths.pdf.0.png b/testing/resources/pixel/bug_1372651_expected_skiapaths.pdf.0.png new file mode 100644 index 0000000..f33a4a7 --- /dev/null +++ b/testing/resources/pixel/bug_1372651_expected_skiapaths.pdf.0.png Binary files differ