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