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