• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
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/fpdfxfa/cpdfxfa_page.h"
8 
9 #include <memory>
10 #include <utility>
11 
12 #include "core/fpdfapi/page/cpdf_page.h"
13 #include "core/fpdfapi/page/cpdf_pageimagecache.h"
14 #include "core/fpdfapi/parser/cpdf_document.h"
15 #include "fpdfsdk/cpdfsdk_pageview.h"
16 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
17 #include "fpdfsdk/fpdfxfa/cpdfxfa_widget.h"
18 #include "third_party/base/check.h"
19 #include "xfa/fgas/graphics/cfgas_gegraphics.h"
20 #include "xfa/fxfa/cxfa_ffdocview.h"
21 #include "xfa/fxfa/cxfa_ffpageview.h"
22 #include "xfa/fxfa/cxfa_ffwidget.h"
23 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
24 
25 namespace {
26 
27 constexpr Mask<XFA_WidgetStatus> kIteratorFilter = {
28     XFA_WidgetStatus::kVisible,
29     XFA_WidgetStatus::kViewable,
30     XFA_WidgetStatus::kFocused,
31 };
32 
GCedWidgetIteratorForPage(CXFA_FFPageView * pFFPageView,CPDFSDK_PageView * pPageView)33 CXFA_FFWidget::IteratorIface* GCedWidgetIteratorForPage(
34     CXFA_FFPageView* pFFPageView,
35     CPDFSDK_PageView* pPageView) {
36   if (!pFFPageView)
37     return nullptr;
38 
39   ObservedPtr<CPDFSDK_PageView> pWatchedPageView(pPageView);
40   CXFA_FFWidget::IteratorIface* pIterator =
41       pFFPageView->CreateGCedTraverseWidgetIterator(kIteratorFilter);
42 
43   // Check |pPageView| again because JS may have destroyed it.
44   return pWatchedPageView ? pIterator : nullptr;
45 }
46 
GCedWidgetIteratorForAnnot(CXFA_FFPageView * pFFPageView,CPDFSDK_Annot * pSDKAnnot)47 CXFA_FFWidget::IteratorIface* GCedWidgetIteratorForAnnot(
48     CXFA_FFPageView* pFFPageView,
49     CPDFSDK_Annot* pSDKAnnot) {
50   if (!pFFPageView)
51     return nullptr;
52 
53   CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pSDKAnnot);
54   if (!pXFAWidget)
55     return nullptr;
56 
57   ObservedPtr<CPDFSDK_Annot> pObservedAnnot(pSDKAnnot);
58   CXFA_FFWidget::IteratorIface* pWidgetIterator =
59       pFFPageView->CreateGCedTraverseWidgetIterator(kIteratorFilter);
60 
61   // Check |pSDKAnnot| again because JS may have destroyed it.
62   if (!pObservedAnnot)
63     return nullptr;
64 
65   if (pWidgetIterator->GetCurrentWidget() != pXFAWidget->GetXFAFFWidget())
66     pWidgetIterator->SetCurrentWidget(pXFAWidget->GetXFAFFWidget());
67 
68   return pWidgetIterator;
69 }
70 
71 }  // namespace
72 
CPDFXFA_Page(CPDF_Document * pDocument,int page_index)73 CPDFXFA_Page::CPDFXFA_Page(CPDF_Document* pDocument, int page_index)
74     : m_pDocument(pDocument), m_iPageIndex(page_index) {
75   DCHECK(m_pDocument->GetExtension());
76   DCHECK(m_iPageIndex >= 0);
77 }
78 
79 CPDFXFA_Page::~CPDFXFA_Page() = default;
80 
AsPDFPage()81 CPDF_Page* CPDFXFA_Page::AsPDFPage() {
82   return m_pPDFPage.Get();
83 }
84 
AsXFAPage()85 CPDFXFA_Page* CPDFXFA_Page::AsXFAPage() {
86   return this;
87 }
88 
GetDocument() const89 CPDF_Document* CPDFXFA_Page::GetDocument() const {
90   return m_pDocument;
91 }
92 
LoadPDFPage()93 bool CPDFXFA_Page::LoadPDFPage() {
94   RetainPtr<CPDF_Dictionary> pDict =
95       GetDocument()->GetMutablePageDictionary(m_iPageIndex);
96   if (!pDict)
97     return false;
98 
99   if (!m_pPDFPage || m_pPDFPage->GetDict() != pDict)
100     LoadPDFPageFromDict(std::move(pDict));
101 
102   return true;
103 }
104 
GetXFAPageView() const105 CXFA_FFPageView* CPDFXFA_Page::GetXFAPageView() const {
106   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
107   CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
108   return pXFADocView ? pXFADocView->GetPageView(m_iPageIndex) : nullptr;
109 }
110 
LoadPage()111 bool CPDFXFA_Page::LoadPage() {
112   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
113   switch (pContext->GetFormType()) {
114     case FormType::kNone:
115     case FormType::kAcroForm:
116     case FormType::kXFAForeground:
117       return LoadPDFPage();
118     case FormType::kXFAFull:
119       return !!GetXFAPageView();
120   }
121 }
122 
LoadPDFPageFromDict(RetainPtr<CPDF_Dictionary> pPageDict)123 void CPDFXFA_Page::LoadPDFPageFromDict(RetainPtr<CPDF_Dictionary> pPageDict) {
124   DCHECK(pPageDict);
125   m_pPDFPage =
126       pdfium::MakeRetain<CPDF_Page>(GetDocument(), std::move(pPageDict));
127   m_pPDFPage->AddPageImageCache();
128   m_pPDFPage->ParseContent();
129 }
130 
GetPageWidth() const131 float CPDFXFA_Page::GetPageWidth() const {
132   CXFA_FFPageView* pPageView = GetXFAPageView();
133   if (!m_pPDFPage && !pPageView)
134     return 0.0f;
135 
136   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
137   switch (pContext->GetFormType()) {
138     case FormType::kNone:
139     case FormType::kAcroForm:
140     case FormType::kXFAForeground:
141       if (m_pPDFPage)
142         return m_pPDFPage->GetPageWidth();
143       [[fallthrough]];
144     case FormType::kXFAFull:
145       if (pPageView)
146         return pPageView->GetPageViewRect().width;
147       break;
148   }
149 
150   return 0.0f;
151 }
152 
GetPageHeight() const153 float CPDFXFA_Page::GetPageHeight() const {
154   CXFA_FFPageView* pPageView = GetXFAPageView();
155   if (!m_pPDFPage && !pPageView)
156     return 0.0f;
157 
158   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
159   switch (pContext->GetFormType()) {
160     case FormType::kNone:
161     case FormType::kAcroForm:
162     case FormType::kXFAForeground:
163       if (m_pPDFPage)
164         return m_pPDFPage->GetPageHeight();
165       [[fallthrough]];
166     case FormType::kXFAFull:
167       if (pPageView)
168         return pPageView->GetPageViewRect().height;
169       break;
170   }
171 
172   return 0.0f;
173 }
174 
DeviceToPage(const FX_RECT & rect,int rotate,const CFX_PointF & device_point) const175 absl::optional<CFX_PointF> CPDFXFA_Page::DeviceToPage(
176     const FX_RECT& rect,
177     int rotate,
178     const CFX_PointF& device_point) const {
179   CXFA_FFPageView* pPageView = GetXFAPageView();
180   if (!m_pPDFPage && !pPageView)
181     return absl::nullopt;
182 
183   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
184   return page2device.GetInverse().Transform(device_point);
185 }
186 
PageToDevice(const FX_RECT & rect,int rotate,const CFX_PointF & page_point) const187 absl::optional<CFX_PointF> CPDFXFA_Page::PageToDevice(
188     const FX_RECT& rect,
189     int rotate,
190     const CFX_PointF& page_point) const {
191   CXFA_FFPageView* pPageView = GetXFAPageView();
192   if (!m_pPDFPage && !pPageView)
193     return absl::nullopt;
194 
195   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
196   return page2device.Transform(page_point);
197 }
198 
GetDisplayMatrix(const FX_RECT & rect,int iRotate) const199 CFX_Matrix CPDFXFA_Page::GetDisplayMatrix(const FX_RECT& rect,
200                                           int iRotate) const {
201   CXFA_FFPageView* pPageView = GetXFAPageView();
202   if (!m_pPDFPage && !pPageView)
203     return CFX_Matrix();
204 
205   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
206   switch (pContext->GetFormType()) {
207     case FormType::kNone:
208     case FormType::kAcroForm:
209     case FormType::kXFAForeground:
210       if (m_pPDFPage)
211         return m_pPDFPage->GetDisplayMatrix(rect, iRotate);
212       [[fallthrough]];
213     case FormType::kXFAFull:
214       if (pPageView)
215         return pPageView->GetDisplayMatrix(rect, iRotate);
216       break;
217   }
218 
219   return CFX_Matrix();
220 }
221 
GetNextXFAAnnot(CPDFSDK_Annot * pSDKAnnot) const222 CPDFSDK_Annot* CPDFXFA_Page::GetNextXFAAnnot(CPDFSDK_Annot* pSDKAnnot) const {
223   CXFA_FFWidget::IteratorIface* pWidgetIterator =
224       GCedWidgetIteratorForAnnot(GetXFAPageView(), pSDKAnnot);
225   if (!pWidgetIterator)
226     return nullptr;
227 
228   return pSDKAnnot->GetPageView()->GetAnnotForFFWidget(
229       pWidgetIterator->MoveToNext());
230 }
231 
GetPrevXFAAnnot(CPDFSDK_Annot * pSDKAnnot) const232 CPDFSDK_Annot* CPDFXFA_Page::GetPrevXFAAnnot(CPDFSDK_Annot* pSDKAnnot) const {
233   CXFA_FFWidget::IteratorIface* pWidgetIterator =
234       GCedWidgetIteratorForAnnot(GetXFAPageView(), pSDKAnnot);
235   if (!pWidgetIterator)
236     return nullptr;
237 
238   return pSDKAnnot->GetPageView()->GetAnnotForFFWidget(
239       pWidgetIterator->MoveToPrevious());
240 }
241 
GetFirstXFAAnnot(CPDFSDK_PageView * page_view) const242 CPDFSDK_Annot* CPDFXFA_Page::GetFirstXFAAnnot(
243     CPDFSDK_PageView* page_view) const {
244   CXFA_FFWidget::IteratorIface* pWidgetIterator =
245       GCedWidgetIteratorForPage(GetXFAPageView(), page_view);
246   if (!pWidgetIterator)
247     return nullptr;
248 
249   return page_view->GetAnnotForFFWidget(pWidgetIterator->MoveToFirst());
250 }
251 
GetLastXFAAnnot(CPDFSDK_PageView * page_view) const252 CPDFSDK_Annot* CPDFXFA_Page::GetLastXFAAnnot(
253     CPDFSDK_PageView* page_view) const {
254   CXFA_FFWidget::IteratorIface* pWidgetIterator =
255       GCedWidgetIteratorForPage(GetXFAPageView(), page_view);
256   if (!pWidgetIterator)
257     return nullptr;
258 
259   return page_view->GetAnnotForFFWidget(pWidgetIterator->MoveToLast());
260 }
261 
HasFormFieldAtPoint(const CFX_PointF & point) const262 int CPDFXFA_Page::HasFormFieldAtPoint(const CFX_PointF& point) const {
263   CXFA_FFPageView* pPageView = GetXFAPageView();
264   if (!pPageView)
265     return -1;
266 
267   CXFA_FFDocView* pDocView = pPageView->GetDocView();
268   if (!pDocView)
269     return -1;
270 
271   CXFA_FFWidgetHandler* pWidgetHandler = pDocView->GetWidgetHandler();
272   if (!pWidgetHandler)
273     return -1;
274   CXFA_FFPageWidgetIterator pWidgetIterator(pPageView,
275                                             XFA_WidgetStatus::kViewable);
276 
277   CXFA_FFWidget* pXFAAnnot;
278   while ((pXFAAnnot = pWidgetIterator.MoveToNext()) != nullptr) {
279     if (pXFAAnnot->GetFormFieldType() == FormFieldType::kXFA)
280       continue;
281 
282     CFX_FloatRect rcWidget = pXFAAnnot->GetWidgetRect().ToFloatRect();
283     rcWidget.Inflate(1.0f, 1.0f);
284     if (rcWidget.Contains(point))
285       return static_cast<int>(pXFAAnnot->GetFormFieldType());
286   }
287 
288   return -1;
289 }
290 
DrawFocusAnnot(CFX_RenderDevice * pDevice,CPDFSDK_Annot * pAnnot,const CFX_Matrix & mtUser2Device,const FX_RECT & rtClip)291 void CPDFXFA_Page::DrawFocusAnnot(CFX_RenderDevice* pDevice,
292                                   CPDFSDK_Annot* pAnnot,
293                                   const CFX_Matrix& mtUser2Device,
294                                   const FX_RECT& rtClip) {
295   CFX_RectF rectClip(rtClip);
296   CFGAS_GEGraphics gs(pDevice);
297   gs.SetClipRect(rectClip);
298 
299   CXFA_FFPageView* xfaView = GetXFAPageView();
300   CXFA_FFPageWidgetIterator pWidgetIterator(
301       xfaView, Mask<XFA_WidgetStatus>{XFA_WidgetStatus::kVisible,
302                                       XFA_WidgetStatus::kViewable});
303 
304   while (true) {
305     CXFA_FFWidget* pWidget = pWidgetIterator.MoveToNext();
306     if (!pWidget)
307       break;
308 
309     CFX_RectF rtWidgetBox = pWidget->GetBBox(CXFA_FFWidget::kDoNotDrawFocus);
310     ++rtWidgetBox.width;
311     ++rtWidgetBox.height;
312     if (rtWidgetBox.IntersectWith(rectClip))
313       pWidget->RenderWidget(&gs, mtUser2Device, CXFA_FFWidget::kHighlight);
314   }
315 
316   CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pAnnot);
317   if (!pXFAWidget)
318     return;
319 
320   CXFA_FFDocView* docView = xfaView->GetDocView();
321   if (!docView)
322     return;
323 
324   docView->GetWidgetHandler()->RenderWidget(pXFAWidget->GetXFAFFWidget(), &gs,
325                                             mtUser2Device, false);
326 }
327