1 // Copyright 2016 PDFium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fpdfsdk/cpdfsdk_pageview.h"
8
9 #include <memory>
10 #include <vector>
11
12 #include "core/fpdfapi/parser/cpdf_document.h"
13 #include "core/fpdfapi/render/cpdf_renderoptions.h"
14 #include "core/fpdfdoc/cpdf_annotlist.h"
15 #include "core/fpdfdoc/cpdf_interform.h"
16 #include "fpdfsdk/cpdfsdk_annot.h"
17 #include "fpdfsdk/cpdfsdk_annothandlermgr.h"
18 #include "fpdfsdk/cpdfsdk_annotiteration.h"
19 #include "fpdfsdk/cpdfsdk_formfillenvironment.h"
20 #include "fpdfsdk/cpdfsdk_interform.h"
21 #include "third_party/base/ptr_util.h"
22
23 #ifdef PDF_ENABLE_XFA
24 #include "fpdfsdk/fpdfxfa/cpdfxfa_page.h"
25 #include "xfa/fxfa/xfa_ffdocview.h"
26 #include "xfa/fxfa/xfa_ffpageview.h"
27 #include "xfa/fxfa/xfa_ffwidgethandler.h"
28 #include "xfa/fxfa/xfa_rendercontext.h"
29 #include "xfa/fxgraphics/cfx_graphics.h"
30 #endif // PDF_ENABLE_XFA
31
CPDFSDK_PageView(CPDFSDK_FormFillEnvironment * pFormFillEnv,UnderlyingPageType * page)32 CPDFSDK_PageView::CPDFSDK_PageView(CPDFSDK_FormFillEnvironment* pFormFillEnv,
33 UnderlyingPageType* page)
34 : m_page(page),
35 m_pFormFillEnv(pFormFillEnv),
36 #ifndef PDF_ENABLE_XFA
37 m_bOwnsPage(false),
38 #endif // PDF_ENABLE_XFA
39 m_bEnterWidget(false),
40 m_bExitWidget(false),
41 m_bOnWidget(false),
42 m_bValid(false),
43 m_bLocked(false),
44 m_bBeingDestroyed(false) {
45 CPDFSDK_InterForm* pInterForm = pFormFillEnv->GetInterForm();
46 if (pInterForm) {
47 CPDF_InterForm* pPDFInterForm = pInterForm->GetInterForm();
48 #ifdef PDF_ENABLE_XFA
49 if (page->GetPDFPage())
50 pPDFInterForm->FixPageFields(page->GetPDFPage());
51 #else // PDF_ENABLE_XFA
52 pPDFInterForm->FixPageFields(page);
53 #endif // PDF_ENABLE_XFA
54 }
55 #ifndef PDF_ENABLE_XFA
56 m_page->SetView(this);
57 #endif // PDF_ENABLE_XFA
58 }
59
~CPDFSDK_PageView()60 CPDFSDK_PageView::~CPDFSDK_PageView() {
61 #ifndef PDF_ENABLE_XFA
62 // The call to |ReleaseAnnot| can cause the page pointed to by |m_page| to
63 // be freed, which will cause issues if we try to cleanup the pageview pointer
64 // in |m_page|. So, reset the pageview pointer before doing anything else.
65 m_page->SetView(nullptr);
66 #endif // PDF_ENABLE_XFA
67
68 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
69 m_pFormFillEnv->GetAnnotHandlerMgr();
70 for (CPDFSDK_Annot* pAnnot : m_SDKAnnotArray)
71 pAnnotHandlerMgr->ReleaseAnnot(pAnnot);
72
73 m_SDKAnnotArray.clear();
74 m_pAnnotList.reset();
75
76 #ifndef PDF_ENABLE_XFA
77 if (m_bOwnsPage)
78 delete m_page;
79 #endif // PDF_ENABLE_XFA
80 }
81
PageView_OnDraw(CFX_RenderDevice * pDevice,CFX_Matrix * pUser2Device,CPDF_RenderOptions * pOptions,const FX_RECT & pClip)82 void CPDFSDK_PageView::PageView_OnDraw(CFX_RenderDevice* pDevice,
83 CFX_Matrix* pUser2Device,
84 #ifdef PDF_ENABLE_XFA
85 CPDF_RenderOptions* pOptions,
86 const FX_RECT& pClip) {
87 #else
88 CPDF_RenderOptions* pOptions) {
89 #endif // PDF_ENABLE_XFA
90 m_curMatrix = *pUser2Device;
91
92 #ifdef PDF_ENABLE_XFA
93 CPDFXFA_Page* pPage = GetPDFXFAPage();
94 if (!pPage)
95 return;
96
97 if (pPage->GetContext()->GetDocType() == DOCTYPE_DYNAMIC_XFA) {
98 CFX_Graphics gs(pDevice);
99 CFX_RectF rectClip(static_cast<FX_FLOAT>(pClip.left),
100 static_cast<FX_FLOAT>(pClip.top),
101 static_cast<FX_FLOAT>(pClip.Width()),
102 static_cast<FX_FLOAT>(pClip.Height()));
103 gs.SetClipRect(rectClip);
104 std::unique_ptr<CXFA_RenderContext> pRenderContext(new CXFA_RenderContext);
105 CXFA_RenderOptions renderOptions;
106 renderOptions.m_bHighlight = true;
107 CXFA_FFPageView* xfaView = pPage->GetXFAPageView();
108 pRenderContext->StartRender(xfaView, &gs, *pUser2Device, renderOptions);
109 pRenderContext->DoRender();
110 pRenderContext->StopRender();
111 CXFA_FFDocView* docView = xfaView->GetDocView();
112 if (!docView)
113 return;
114 CPDFSDK_Annot* annot = GetFocusAnnot();
115 if (!annot)
116 return;
117 // Render the focus widget
118 docView->GetWidgetHandler()->RenderWidget(annot->GetXFAWidget(), &gs,
119 pUser2Device, false);
120 return;
121 }
122 #endif // PDF_ENABLE_XFA
123
124 // for pdf/static xfa.
125 CPDFSDK_AnnotIteration annotIteration(this, true);
126 for (const auto& pSDKAnnot : annotIteration) {
127 m_pFormFillEnv->GetAnnotHandlerMgr()->Annot_OnDraw(
128 this, pSDKAnnot.Get(), pDevice, pUser2Device, pOptions->m_bDrawAnnots);
129 }
130 }
131
132 CPDFSDK_Annot* CPDFSDK_PageView::GetFXAnnotAtPoint(const CFX_PointF& point) {
133 CPDFSDK_AnnotHandlerMgr* pAnnotMgr = m_pFormFillEnv->GetAnnotHandlerMgr();
134 CPDFSDK_AnnotIteration annotIteration(this, false);
135 for (const auto& pSDKAnnot : annotIteration) {
136 CFX_FloatRect rc = pAnnotMgr->Annot_OnGetViewBBox(this, pSDKAnnot.Get());
137 if (pSDKAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::POPUP)
138 continue;
139 if (rc.Contains(point))
140 return pSDKAnnot.Get();
141 }
142 return nullptr;
143 }
144
145 CPDFSDK_Annot* CPDFSDK_PageView::GetFXWidgetAtPoint(const CFX_PointF& point) {
146 CPDFSDK_AnnotHandlerMgr* pAnnotMgr = m_pFormFillEnv->GetAnnotHandlerMgr();
147 CPDFSDK_AnnotIteration annotIteration(this, false);
148 for (const auto& pSDKAnnot : annotIteration) {
149 bool bHitTest = pSDKAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::WIDGET;
150 #ifdef PDF_ENABLE_XFA
151 bHitTest = bHitTest ||
152 pSDKAnnot->GetAnnotSubtype() == CPDF_Annot::Subtype::XFAWIDGET;
153 #endif // PDF_ENABLE_XFA
154 if (bHitTest) {
155 pAnnotMgr->Annot_OnGetViewBBox(this, pSDKAnnot.Get());
156 if (pAnnotMgr->Annot_OnHitTest(this, pSDKAnnot.Get(), point))
157 return pSDKAnnot.Get();
158 }
159 }
160 return nullptr;
161 }
162
163 #ifdef PDF_ENABLE_XFA
164 CPDFSDK_Annot* CPDFSDK_PageView::AddAnnot(CXFA_FFWidget* pPDFAnnot) {
165 if (!pPDFAnnot)
166 return nullptr;
167
168 CPDFSDK_Annot* pSDKAnnot = GetAnnotByXFAWidget(pPDFAnnot);
169 if (pSDKAnnot)
170 return pSDKAnnot;
171
172 CPDFSDK_AnnotHandlerMgr* pAnnotHandler = m_pFormFillEnv->GetAnnotHandlerMgr();
173 pSDKAnnot = pAnnotHandler->NewAnnot(pPDFAnnot, this);
174 if (!pSDKAnnot)
175 return nullptr;
176
177 m_SDKAnnotArray.push_back(pSDKAnnot);
178 return pSDKAnnot;
179 }
180
181 bool CPDFSDK_PageView::DeleteAnnot(CPDFSDK_Annot* pAnnot) {
182 if (!pAnnot)
183 return false;
184 CPDFXFA_Page* pPage = pAnnot->GetPDFXFAPage();
185 if (!pPage || (pPage->GetContext()->GetDocType() != DOCTYPE_STATIC_XFA &&
186 pPage->GetContext()->GetDocType() != DOCTYPE_DYNAMIC_XFA))
187 return false;
188
189 if (GetFocusAnnot() == pAnnot)
190 m_pFormFillEnv->KillFocusAnnot(0);
191 CPDFSDK_AnnotHandlerMgr* pAnnotHandler = m_pFormFillEnv->GetAnnotHandlerMgr();
192 if (pAnnotHandler)
193 pAnnotHandler->ReleaseAnnot(pAnnot);
194
195 auto it = std::find(m_SDKAnnotArray.begin(), m_SDKAnnotArray.end(), pAnnot);
196 if (it != m_SDKAnnotArray.end())
197 m_SDKAnnotArray.erase(it);
198 if (m_pCaptureWidget.Get() == pAnnot)
199 m_pCaptureWidget.Reset();
200
201 return true;
202 }
203 #endif // PDF_ENABLE_XFA
204
205 CPDF_Document* CPDFSDK_PageView::GetPDFDocument() {
206 if (m_page) {
207 #ifdef PDF_ENABLE_XFA
208 return m_page->GetContext()->GetPDFDoc();
209 #else // PDF_ENABLE_XFA
210 return m_page->m_pDocument;
211 #endif // PDF_ENABLE_XFA
212 }
213 return nullptr;
214 }
215
216 CPDF_Page* CPDFSDK_PageView::GetPDFPage() const {
217 #ifdef PDF_ENABLE_XFA
218 return m_page ? m_page->GetPDFPage() : nullptr;
219 #else // PDF_ENABLE_XFA
220 return m_page;
221 #endif // PDF_ENABLE_XFA
222 }
223
224 CPDFSDK_Annot* CPDFSDK_PageView::GetAnnotByDict(CPDF_Dictionary* pDict) {
225 for (CPDFSDK_Annot* pAnnot : m_SDKAnnotArray) {
226 if (pAnnot->GetPDFAnnot()->GetAnnotDict() == pDict)
227 return pAnnot;
228 }
229 return nullptr;
230 }
231
232 #ifdef PDF_ENABLE_XFA
233 CPDFSDK_Annot* CPDFSDK_PageView::GetAnnotByXFAWidget(CXFA_FFWidget* hWidget) {
234 if (!hWidget)
235 return nullptr;
236
237 for (CPDFSDK_Annot* pAnnot : m_SDKAnnotArray) {
238 if (pAnnot->GetXFAWidget() == hWidget)
239 return pAnnot;
240 }
241 return nullptr;
242 }
243 #endif // PDF_ENABLE_XFA
244
245 bool CPDFSDK_PageView::OnLButtonDown(const CFX_PointF& point, uint32_t nFlag) {
246 CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
247 if (!pAnnot) {
248 m_pFormFillEnv->KillFocusAnnot(nFlag);
249 return false;
250 }
251
252 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
253 m_pFormFillEnv->GetAnnotHandlerMgr();
254 if (!pAnnotHandlerMgr->Annot_OnLButtonDown(this, &pAnnot, nFlag, point))
255 return false;
256
257 if (!pAnnot)
258 return false;
259
260 m_pFormFillEnv->SetFocusAnnot(&pAnnot);
261 return true;
262 }
263
264 #ifdef PDF_ENABLE_XFA
265 bool CPDFSDK_PageView::OnRButtonDown(const CFX_PointF& point, uint32_t nFlag) {
266 CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
267 if (!pAnnot)
268 return false;
269
270 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
271 m_pFormFillEnv->GetAnnotHandlerMgr();
272 bool ok = pAnnotHandlerMgr->Annot_OnRButtonDown(this, &pAnnot, nFlag, point);
273 if (!pAnnot)
274 return false;
275
276 if (ok)
277 m_pFormFillEnv->SetFocusAnnot(&pAnnot);
278
279 return true;
280 }
281
282 bool CPDFSDK_PageView::OnRButtonUp(const CFX_PointF& point, uint32_t nFlag) {
283 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
284 m_pFormFillEnv->GetAnnotHandlerMgr();
285 CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point));
286 if (!pFXAnnot)
287 return false;
288
289 if (pAnnotHandlerMgr->Annot_OnRButtonUp(this, &pFXAnnot, nFlag, point))
290 m_pFormFillEnv->SetFocusAnnot(&pFXAnnot);
291
292 return true;
293 }
294 #endif // PDF_ENABLE_XFA
295
296 bool CPDFSDK_PageView::OnLButtonUp(const CFX_PointF& point, uint32_t nFlag) {
297 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
298 m_pFormFillEnv->GetAnnotHandlerMgr();
299 CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXWidgetAtPoint(point));
300 CPDFSDK_Annot::ObservedPtr pFocusAnnot(GetFocusAnnot());
301 if (pFocusAnnot && pFocusAnnot != pFXAnnot) {
302 // Last focus Annot gets a chance to handle the event.
303 if (pAnnotHandlerMgr->Annot_OnLButtonUp(this, &pFocusAnnot, nFlag, point))
304 return true;
305 }
306 return pFXAnnot &&
307 pAnnotHandlerMgr->Annot_OnLButtonUp(this, &pFXAnnot, nFlag, point);
308 }
309
310 bool CPDFSDK_PageView::OnMouseMove(const CFX_PointF& point, int nFlag) {
311 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
312 m_pFormFillEnv->GetAnnotHandlerMgr();
313 CPDFSDK_Annot::ObservedPtr pFXAnnot(GetFXAnnotAtPoint(point));
314 if (pFXAnnot) {
315 if (m_pCaptureWidget && m_pCaptureWidget != pFXAnnot) {
316 m_bExitWidget = true;
317 m_bEnterWidget = false;
318 pAnnotHandlerMgr->Annot_OnMouseExit(this, &m_pCaptureWidget, nFlag);
319 }
320 m_pCaptureWidget.Reset(pFXAnnot.Get());
321 m_bOnWidget = true;
322 if (!m_bEnterWidget) {
323 m_bEnterWidget = true;
324 m_bExitWidget = false;
325 pAnnotHandlerMgr->Annot_OnMouseEnter(this, &pFXAnnot, nFlag);
326 }
327 pAnnotHandlerMgr->Annot_OnMouseMove(this, &pFXAnnot, nFlag, point);
328 return true;
329 }
330 if (m_bOnWidget) {
331 m_bOnWidget = false;
332 m_bExitWidget = true;
333 m_bEnterWidget = false;
334 if (m_pCaptureWidget) {
335 pAnnotHandlerMgr->Annot_OnMouseExit(this, &m_pCaptureWidget, nFlag);
336 m_pCaptureWidget.Reset();
337 }
338 }
339 return false;
340 }
341
342 bool CPDFSDK_PageView::OnMouseWheel(double deltaX,
343 double deltaY,
344 const CFX_PointF& point,
345 int nFlag) {
346 CPDFSDK_Annot::ObservedPtr pAnnot(GetFXWidgetAtPoint(point));
347 if (!pAnnot)
348 return false;
349
350 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
351 m_pFormFillEnv->GetAnnotHandlerMgr();
352 return pAnnotHandlerMgr->Annot_OnMouseWheel(this, &pAnnot, nFlag, (int)deltaY,
353 point);
354 }
355
356 bool CPDFSDK_PageView::OnChar(int nChar, uint32_t nFlag) {
357 if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
358 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
359 m_pFormFillEnv->GetAnnotHandlerMgr();
360 return pAnnotHandlerMgr->Annot_OnChar(pAnnot, nChar, nFlag);
361 }
362
363 return false;
364 }
365
366 bool CPDFSDK_PageView::OnKeyDown(int nKeyCode, int nFlag) {
367 if (CPDFSDK_Annot* pAnnot = GetFocusAnnot()) {
368 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
369 m_pFormFillEnv->GetAnnotHandlerMgr();
370 return pAnnotHandlerMgr->Annot_OnKeyDown(pAnnot, nKeyCode, nFlag);
371 }
372 return false;
373 }
374
375 bool CPDFSDK_PageView::OnKeyUp(int nKeyCode, int nFlag) {
376 return false;
377 }
378
379 void CPDFSDK_PageView::LoadFXAnnots() {
380 CPDFSDK_AnnotHandlerMgr* pAnnotHandlerMgr =
381 m_pFormFillEnv->GetAnnotHandlerMgr();
382
383 SetLock(true);
384
385 #ifdef PDF_ENABLE_XFA
386 CFX_RetainPtr<CPDFXFA_Page> protector(m_page);
387 if (m_pFormFillEnv->GetXFAContext()->GetDocType() == DOCTYPE_DYNAMIC_XFA) {
388 CXFA_FFPageView* pageView = m_page->GetXFAPageView();
389 std::unique_ptr<IXFA_WidgetIterator> pWidgetHander(
390 pageView->CreateWidgetIterator(
391 XFA_TRAVERSEWAY_Form,
392 XFA_WidgetStatus_Visible | XFA_WidgetStatus_Viewable));
393 if (!pWidgetHander) {
394 SetLock(false);
395 return;
396 }
397
398 while (CXFA_FFWidget* pXFAAnnot = pWidgetHander->MoveToNext()) {
399 CPDFSDK_Annot* pAnnot = pAnnotHandlerMgr->NewAnnot(pXFAAnnot, this);
400 if (!pAnnot)
401 continue;
402 m_SDKAnnotArray.push_back(pAnnot);
403 pAnnotHandlerMgr->Annot_OnLoad(pAnnot);
404 }
405
406 SetLock(false);
407 return;
408 }
409 #endif // PDF_ENABLE_XFA
410
411 CPDF_Page* pPage = GetPDFPage();
412 ASSERT(pPage);
413 bool bUpdateAP = CPDF_InterForm::IsUpdateAPEnabled();
414 // Disable the default AP construction.
415 CPDF_InterForm::SetUpdateAP(false);
416 m_pAnnotList = pdfium::MakeUnique<CPDF_AnnotList>(pPage);
417 CPDF_InterForm::SetUpdateAP(bUpdateAP);
418
419 const size_t nCount = m_pAnnotList->Count();
420 for (size_t i = 0; i < nCount; ++i) {
421 CPDF_Annot* pPDFAnnot = m_pAnnotList->GetAt(i);
422 CheckUnSupportAnnot(GetPDFDocument(), pPDFAnnot);
423 CPDFSDK_Annot* pAnnot = pAnnotHandlerMgr->NewAnnot(pPDFAnnot, this);
424 if (!pAnnot)
425 continue;
426 m_SDKAnnotArray.push_back(pAnnot);
427 pAnnotHandlerMgr->Annot_OnLoad(pAnnot);
428 }
429
430 SetLock(false);
431 }
432
433 void CPDFSDK_PageView::UpdateRects(const std::vector<CFX_FloatRect>& rects) {
434 for (const auto& rc : rects)
435 m_pFormFillEnv->Invalidate(m_page, rc.ToFxRect());
436 }
437
438 void CPDFSDK_PageView::UpdateView(CPDFSDK_Annot* pAnnot) {
439 CFX_FloatRect rcWindow = pAnnot->GetRect();
440 m_pFormFillEnv->Invalidate(m_page, rcWindow.ToFxRect());
441 }
442
443 int CPDFSDK_PageView::GetPageIndex() const {
444 if (!m_page)
445 return -1;
446
447 #ifdef PDF_ENABLE_XFA
448 int nDocType = m_page->GetContext()->GetDocType();
449 switch (nDocType) {
450 case DOCTYPE_DYNAMIC_XFA: {
451 CXFA_FFPageView* pPageView = m_page->GetXFAPageView();
452 return pPageView ? pPageView->GetPageIndex() : -1;
453 }
454 case DOCTYPE_STATIC_XFA:
455 case DOCTYPE_PDF:
456 return GetPageIndexForStaticPDF();
457 default:
458 return -1;
459 }
460 #else // PDF_ENABLE_XFA
461 return GetPageIndexForStaticPDF();
462 #endif // PDF_ENABLE_XFA
463 }
464
465 bool CPDFSDK_PageView::IsValidAnnot(const CPDF_Annot* p) const {
466 if (!p)
467 return false;
468
469 const auto& annots = m_pAnnotList->All();
470 auto it = std::find_if(annots.begin(), annots.end(),
471 [p](const std::unique_ptr<CPDF_Annot>& annot) {
472 return annot.get() == p;
473 });
474 return it != annots.end();
475 }
476
477 bool CPDFSDK_PageView::IsValidSDKAnnot(const CPDFSDK_Annot* p) const {
478 if (!p)
479 return false;
480 return pdfium::ContainsValue(m_SDKAnnotArray, p);
481 }
482
483 CPDFSDK_Annot* CPDFSDK_PageView::GetFocusAnnot() {
484 CPDFSDK_Annot* pFocusAnnot = m_pFormFillEnv->GetFocusAnnot();
485 return IsValidSDKAnnot(pFocusAnnot) ? pFocusAnnot : nullptr;
486 }
487
488 int CPDFSDK_PageView::GetPageIndexForStaticPDF() const {
489 CPDF_Dictionary* pDict = GetPDFPage()->m_pFormDict;
490 CPDF_Document* pDoc = m_pFormFillEnv->GetPDFDocument();
491 return (pDoc && pDict) ? pDoc->GetPageIndex(pDict->GetObjNum()) : -1;
492 }
493