• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/fpdfxfa/cpdfxfa_page.h"
8 
9 #include <memory>
10 
11 #include "core/fpdfapi/page/cpdf_page.h"
12 #include "core/fpdfapi/parser/cpdf_document.h"
13 #include "core/fpdfapi/render/cpdf_pagerendercache.h"
14 #include "fpdfsdk/cpdfsdk_pageview.h"
15 #include "fpdfsdk/fpdfxfa/cpdfxfa_context.h"
16 #include "fpdfsdk/fpdfxfa/cpdfxfa_widget.h"
17 #include "third_party/base/ptr_util.h"
18 #include "xfa/fxfa/cxfa_ffdocview.h"
19 #include "xfa/fxfa/cxfa_ffpageview.h"
20 #include "xfa/fxfa/cxfa_ffwidget.h"
21 #include "xfa/fxfa/cxfa_ffwidgethandler.h"
22 #include "xfa/fxfa/cxfa_rendercontext.h"
23 #include "xfa/fxgraphics/cxfa_graphics.h"
24 
CPDFXFA_Page(CPDF_Document * pDocument,int page_index)25 CPDFXFA_Page::CPDFXFA_Page(CPDF_Document* pDocument, int page_index)
26     : m_pDocument(pDocument), m_iPageIndex(page_index) {
27   ASSERT(m_pDocument->GetExtension());
28   ASSERT(m_iPageIndex >= 0);
29 }
30 
31 CPDFXFA_Page::~CPDFXFA_Page() = default;
32 
AsPDFPage()33 CPDF_Page* CPDFXFA_Page::AsPDFPage() {
34   return m_pPDFPage.Get();
35 }
36 
AsXFAPage()37 CPDFXFA_Page* CPDFXFA_Page::AsXFAPage() {
38   return this;
39 }
40 
GetDocument() const41 CPDF_Document* CPDFXFA_Page::GetDocument() const {
42   return m_pDocument.Get();
43 }
44 
LoadPDFPage()45 bool CPDFXFA_Page::LoadPDFPage() {
46   CPDF_Document* pPDFDoc = GetDocument();
47   CPDF_Dictionary* pDict = pPDFDoc->GetPageDictionary(m_iPageIndex);
48   if (!pDict)
49     return false;
50 
51   if (!m_pPDFPage || m_pPDFPage->GetDict() != pDict)
52     LoadPDFPageFromDict(pDict);
53 
54   return true;
55 }
56 
GetXFAPageView() const57 CXFA_FFPageView* CPDFXFA_Page::GetXFAPageView() const {
58   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
59   CXFA_FFDocView* pXFADocView = pContext->GetXFADocView();
60   return pXFADocView ? pXFADocView->GetPageView(m_iPageIndex) : nullptr;
61 }
62 
LoadPage()63 bool CPDFXFA_Page::LoadPage() {
64   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
65   switch (pContext->GetFormType()) {
66     case FormType::kNone:
67     case FormType::kAcroForm:
68     case FormType::kXFAForeground:
69       return LoadPDFPage();
70     case FormType::kXFAFull:
71       return !!GetXFAPageView();
72   }
73   NOTREACHED();
74   return false;
75 }
76 
LoadPDFPageFromDict(CPDF_Dictionary * pPageDict)77 void CPDFXFA_Page::LoadPDFPageFromDict(CPDF_Dictionary* pPageDict) {
78   ASSERT(pPageDict);
79   m_pPDFPage = pdfium::MakeRetain<CPDF_Page>(GetDocument(), pPageDict);
80   m_pPDFPage->SetRenderCache(
81       pdfium::MakeUnique<CPDF_PageRenderCache>(m_pPDFPage.Get()));
82   m_pPDFPage->ParseContent();
83 }
84 
GetPageWidth() const85 float CPDFXFA_Page::GetPageWidth() const {
86   CXFA_FFPageView* pPageView = GetXFAPageView();
87   if (!m_pPDFPage && !pPageView)
88     return 0.0f;
89 
90   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
91   switch (pContext->GetFormType()) {
92     case FormType::kNone:
93     case FormType::kAcroForm:
94     case FormType::kXFAForeground:
95       if (m_pPDFPage)
96         return m_pPDFPage->GetPageWidth();
97       FALLTHROUGH;
98     case FormType::kXFAFull:
99       if (pPageView)
100         return pPageView->GetPageViewRect().width;
101       break;
102   }
103 
104   return 0.0f;
105 }
106 
GetPageHeight() const107 float CPDFXFA_Page::GetPageHeight() const {
108   CXFA_FFPageView* pPageView = GetXFAPageView();
109   if (!m_pPDFPage && !pPageView)
110     return 0.0f;
111 
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       if (m_pPDFPage)
118         return m_pPDFPage->GetPageHeight();
119       FALLTHROUGH;
120     case FormType::kXFAFull:
121       if (pPageView)
122         return pPageView->GetPageViewRect().height;
123       break;
124   }
125 
126   return 0.0f;
127 }
128 
DeviceToPage(const FX_RECT & rect,int rotate,const CFX_PointF & device_point) const129 Optional<CFX_PointF> CPDFXFA_Page::DeviceToPage(
130     const FX_RECT& rect,
131     int rotate,
132     const CFX_PointF& device_point) const {
133   CXFA_FFPageView* pPageView = GetXFAPageView();
134   if (!m_pPDFPage && !pPageView)
135     return {};
136 
137   CFX_PointF pos =
138       GetDisplayMatrix(rect, rotate).GetInverse().Transform(device_point);
139   return pos;
140 }
141 
PageToDevice(const FX_RECT & rect,int rotate,const CFX_PointF & page_point) const142 Optional<CFX_PointF> CPDFXFA_Page::PageToDevice(
143     const FX_RECT& rect,
144     int rotate,
145     const CFX_PointF& page_point) const {
146   CXFA_FFPageView* pPageView = GetXFAPageView();
147   if (!m_pPDFPage && !pPageView)
148     return {};
149 
150   CFX_Matrix page2device = GetDisplayMatrix(rect, rotate);
151   return page2device.Transform(page_point);
152 }
153 
GetDisplayMatrix(const FX_RECT & rect,int iRotate) const154 CFX_Matrix CPDFXFA_Page::GetDisplayMatrix(const FX_RECT& rect,
155                                           int iRotate) const {
156   CXFA_FFPageView* pPageView = GetXFAPageView();
157   if (!m_pPDFPage && !pPageView)
158     return CFX_Matrix();
159 
160   auto* pContext = static_cast<CPDFXFA_Context*>(m_pDocument->GetExtension());
161   switch (pContext->GetFormType()) {
162     case FormType::kNone:
163     case FormType::kAcroForm:
164     case FormType::kXFAForeground:
165       if (m_pPDFPage)
166         return m_pPDFPage->GetDisplayMatrix(rect, iRotate);
167       FALLTHROUGH;
168     case FormType::kXFAFull:
169       if (pPageView)
170         return pPageView->GetDisplayMatrix(rect, iRotate);
171       break;
172   }
173 
174   return CFX_Matrix();
175 }
176 
GetNextXFAAnnot(CPDFSDK_Annot * pSDKAnnot,bool bNext)177 CPDFSDK_Annot* CPDFXFA_Page::GetNextXFAAnnot(CPDFSDK_Annot* pSDKAnnot,
178                                              bool bNext) {
179   CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pSDKAnnot);
180   if (!pXFAWidget)
181     return nullptr;
182 
183   ObservedPtr<CPDFSDK_Annot> pObservedAnnot(pSDKAnnot);
184   CPDFSDK_PageView* pPageView = pSDKAnnot->GetPageView();
185   std::unique_ptr<IXFA_WidgetIterator> pWidgetIterator =
186       GetXFAPageView()->CreateTraverseWidgetIterator(XFA_WidgetStatus_Visible |
187                                                      XFA_WidgetStatus_Viewable |
188                                                      XFA_WidgetStatus_Focused);
189 
190   // Check |pSDKAnnot| again because JS may have destroyed it
191   if (!pObservedAnnot)
192     return nullptr;
193 
194   if (pWidgetIterator->GetCurrentWidget() != pXFAWidget->GetXFAFFWidget())
195     pWidgetIterator->SetCurrentWidget(pXFAWidget->GetXFAFFWidget());
196 
197   CXFA_FFWidget* hNextFocus =
198       bNext ? pWidgetIterator->MoveToNext() : pWidgetIterator->MoveToPrevious();
199   if (!hNextFocus && pSDKAnnot)
200     hNextFocus = pWidgetIterator->MoveToFirst();
201 
202   return pPageView->GetAnnotByXFAWidget(hNextFocus);
203 }
204 
HasFormFieldAtPoint(const CFX_PointF & point) const205 int CPDFXFA_Page::HasFormFieldAtPoint(const CFX_PointF& point) const {
206   CXFA_FFPageView* pPageView = GetXFAPageView();
207   if (!pPageView)
208     return -1;
209 
210   CXFA_FFDocView* pDocView = pPageView->GetDocView();
211   if (!pDocView)
212     return -1;
213 
214   CXFA_FFWidgetHandler* pWidgetHandler = pDocView->GetWidgetHandler();
215   if (!pWidgetHandler)
216     return -1;
217 
218   std::unique_ptr<IXFA_WidgetIterator> pWidgetIterator =
219       pPageView->CreateFormWidgetIterator(XFA_WidgetStatus_Viewable);
220 
221   CXFA_FFWidget* pXFAAnnot;
222   while ((pXFAAnnot = pWidgetIterator->MoveToNext()) != nullptr) {
223     if (pXFAAnnot->GetFormFieldType() == FormFieldType::kXFA)
224       continue;
225 
226     CFX_FloatRect rcWidget = pXFAAnnot->GetWidgetRect().ToFloatRect();
227     rcWidget.Inflate(1.0f, 1.0f);
228     if (rcWidget.Contains(point))
229       return static_cast<int>(pXFAAnnot->GetFormFieldType());
230   }
231 
232   return -1;
233 }
234 
DrawFocusAnnot(CFX_RenderDevice * pDevice,CPDFSDK_Annot * pAnnot,const CFX_Matrix & mtUser2Device,const FX_RECT & rtClip)235 void CPDFXFA_Page::DrawFocusAnnot(CFX_RenderDevice* pDevice,
236                                   CPDFSDK_Annot* pAnnot,
237                                   const CFX_Matrix& mtUser2Device,
238                                   const FX_RECT& rtClip) {
239   CFX_RectF rectClip(rtClip);
240   CXFA_Graphics gs(pDevice);
241   gs.SetClipRect(rectClip);
242 
243   CXFA_FFPageView* xfaView = GetXFAPageView();
244   CXFA_RenderContext renderContext(xfaView, rectClip, mtUser2Device);
245   renderContext.DoRender(&gs);
246 
247   CPDFXFA_Widget* pXFAWidget = ToXFAWidget(pAnnot);
248   if (!pXFAWidget)
249     return;
250 
251   CXFA_FFDocView* docView = xfaView->GetDocView();
252   if (!docView)
253     return;
254 
255   docView->GetWidgetHandler()->RenderWidget(pXFAWidget->GetXFAFFWidget(), &gs,
256                                             mtUser2Device, false);
257 }
258