ec591adb72b1757a19fc786e203e5547b2ee9946
[pdfium.git] / xfa / src / fxfa / src / app / xfa_ffpageview.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../foxitlib.h"\r
8 #include "../common/xfa_common.h"\r
9 #include "xfa_fwladapter.h"\r
10 #include "xfa_ffpageview.h"\r
11 #include "xfa_ffwidget.h"\r
12 #include "xfa_ffdoc.h"\r
13 #include "xfa_ffdocview.h"\r
14 #include "xfa_fffield.h"\r
15 #include "xfa_ffpushbutton.h"\r
16 #include "xfa_ffcheckbutton.h"\r
17 #include "xfa_ffchoicelist.h"\r
18 #include "xfa_ffimageedit.h"\r
19 #include "xfa_fftextedit.h"\r
20 CXFA_FFPageView::CXFA_FFPageView(CXFA_FFDocView* pDocView, CXFA_Node* pPageArea)\r
21     : CXFA_ContainerLayoutItemImpl(pPageArea)\r
22     , m_pDocView(pDocView)\r
23     , m_bLoaded(FALSE)\r
24 {\r
25 }\r
26 CXFA_FFPageView::~CXFA_FFPageView()\r
27 {\r
28 }\r
29 IXFA_DocView* CXFA_FFPageView::GetDocView()\r
30 {\r
31     return m_pDocView;\r
32 }\r
33 FX_INT32 CXFA_FFPageView::GetPageViewIndex()\r
34 {\r
35     return GetLayoutPage()->GetPageIndex();\r
36 }\r
37 void CXFA_FFPageView::GetPageViewRect(CFX_RectF &rtPage)\r
38 {\r
39     CFX_SizeF sz;\r
40     GetLayoutPage()->GetPageSize(sz);\r
41     rtPage.Set(0, 0, sz);\r
42 }\r
43 void CXFA_FFPageView::GetDisplayMatrix(CFX_Matrix &mt, const CFX_Rect &rtDisp, FX_INT32 iRotate)\r
44 {\r
45     CFX_SizeF sz;\r
46     GetLayoutPage()->GetPageSize(sz);\r
47     CFX_RectF fdePage;\r
48     fdePage.Set(0, 0, sz.x, sz.y);\r
49     FDE_GetPageMatrix(mt, fdePage, rtDisp, iRotate, 0);\r
50 }\r
51 FX_INT32 CXFA_FFPageView::LoadPageView(IFX_Pause *pPause )\r
52 {\r
53     if (m_bLoaded) {\r
54         return 100;\r
55     }\r
56     m_bLoaded = TRUE;\r
57     return 100;\r
58 }\r
59 void CXFA_FFPageView::UnloadPageView()\r
60 {\r
61     if (!m_bLoaded) {\r
62         return;\r
63     }\r
64 }\r
65 FX_BOOL CXFA_FFPageView::IsPageViewLoaded()\r
66 {\r
67     return m_bLoaded;\r
68 }\r
69 XFA_HWIDGET CXFA_FFPageView::GetWidgetByPos(FX_FLOAT fx, FX_FLOAT fy)\r
70 {\r
71     if (!m_bLoaded) {\r
72         return NULL;\r
73     }\r
74     IXFA_WidgetIterator* pIterator = CreateWidgetIterator();\r
75     while (CXFA_FFWidget* pWidget = (CXFA_FFWidget*)pIterator->MoveToNext()) {\r
76         if (!(pWidget->GetStatus() & XFA_WIDGETSTATUS_Visible)) {\r
77             continue;\r
78         }\r
79         CXFA_WidgetAcc* pAcc = pWidget->GetDataAcc();\r
80         FX_INT32 type = pAcc->GetClassID();\r
81         if (type != XFA_ELEMENT_Field && type != XFA_ELEMENT_Draw) {\r
82             continue;\r
83         }\r
84         FX_FLOAT fWidgetx = fx, fWidgety = fy;\r
85         pWidget->Rotate2Normal(fWidgetx, fWidgety);\r
86         FX_DWORD dwFlag = pWidget->OnHitTest(fWidgetx, fWidgety);\r
87         if (( FWL_WGTHITTEST_Client == dwFlag\r
88                 ||  FWL_WGTHITTEST_Transparent == dwFlag)) {\r
89             pIterator->Release();\r
90             return (XFA_HWIDGET)pWidget;\r
91         }\r
92     }\r
93     pIterator->Release();\r
94     return NULL;\r
95 }\r
96 IXFA_WidgetIterator* CXFA_FFPageView::CreateWidgetIterator(FX_DWORD dwTraverseWay ,\r
97         FX_DWORD dwWidgetFilter )\r
98 {\r
99     switch (dwTraverseWay) {\r
100         case XFA_TRAVERSEWAY_Tranvalse:\r
101             return FX_NEW CXFA_FFTabOrderPageWidgetIterator(this, dwWidgetFilter);\r
102         case XFA_TRAVERSEWAY_Form:\r
103             return FX_NEW CXFA_FFPageWidgetIterator(this, dwWidgetFilter);\r
104     }\r
105     return NULL;\r
106 }\r
107 static FX_BOOL XFA_PageWidgetFilter(CXFA_FFWidget* pWidget, FX_DWORD dwFilter, FX_BOOL bTraversal, FX_BOOL bIgnorerelevant)\r
108 {\r
109     CXFA_WidgetAcc* pWidgetAcc = pWidget->GetDataAcc();\r
110     FX_DWORD dwType = dwFilter & XFA_WIDGETFILTER_AllType;\r
111     if ((dwType == XFA_WIDGETFILTER_Field) && (pWidgetAcc->GetClassID() != XFA_ELEMENT_Field)) {\r
112         return FALSE;\r
113     }\r
114     FX_DWORD dwStatus = pWidget->GetStatus();\r
115     if (bTraversal && (dwStatus & XFA_WIDGETSTATUS_Disabled)) {\r
116         return FALSE;\r
117     }\r
118     if (bIgnorerelevant) {\r
119         return (dwStatus & XFA_WIDGETFILTER_Visible) != 0;\r
120     }\r
121     dwFilter &= (XFA_WIDGETFILTER_Visible | XFA_WIDGETFILTER_Viewable | XFA_WIDGETFILTER_Printable);\r
122     return (dwFilter & dwStatus) == dwFilter;\r
123 }\r
124 CXFA_FFPageWidgetIterator::CXFA_FFPageWidgetIterator(CXFA_FFPageView* pPageView, FX_DWORD dwFilter)\r
125 {\r
126     m_pPageView = pPageView;\r
127     m_dwFilter = dwFilter;\r
128     m_sIterator.Init((CXFA_LayoutItem*)pPageView->GetLayoutPage());\r
129     m_bIgnorerelevant = ((CXFA_FFDoc*)m_pPageView->GetDocView()->GetDoc())->GetXFADoc()->GetCurVersionMode() < XFA_VERSION_205;\r
130 }\r
131 CXFA_FFPageWidgetIterator::~CXFA_FFPageWidgetIterator()\r
132 {\r
133 }\r
134 void CXFA_FFPageWidgetIterator::Reset()\r
135 {\r
136     m_sIterator.Reset();\r
137 }\r
138 XFA_HWIDGET CXFA_FFPageWidgetIterator::MoveToFirst()\r
139 {\r
140     m_sIterator.Reset();\r
141     for(CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent(); pLayoutItem; pLayoutItem = m_sIterator.MoveToNext()) {\r
142         if (XFA_HWIDGET hWidget = GetWidget(pLayoutItem)) {\r
143             return hWidget;\r
144         }\r
145     }\r
146     return NULL;\r
147 }\r
148 XFA_HWIDGET CXFA_FFPageWidgetIterator::MoveToLast()\r
149 {\r
150     m_sIterator.SetCurrent(NULL);\r
151     return MoveToPrevious();\r
152 }\r
153 XFA_HWIDGET CXFA_FFPageWidgetIterator::MoveToNext()\r
154 {\r
155     for(CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToNext(); pLayoutItem; pLayoutItem = m_sIterator.MoveToNext()) {\r
156         if (XFA_HWIDGET hWidget = GetWidget(pLayoutItem)) {\r
157             return hWidget;\r
158         }\r
159     }\r
160     return NULL;\r
161 }\r
162 XFA_HWIDGET CXFA_FFPageWidgetIterator::MoveToPrevious()\r
163 {\r
164     for(CXFA_LayoutItem* pLayoutItem = m_sIterator.MoveToPrev(); pLayoutItem; pLayoutItem = m_sIterator.MoveToPrev()) {\r
165         if (XFA_HWIDGET hWidget = GetWidget(pLayoutItem)) {\r
166             return hWidget;\r
167         }\r
168     }\r
169     return NULL;\r
170 }\r
171 XFA_HWIDGET CXFA_FFPageWidgetIterator::GetCurrentWidget()\r
172 {\r
173     CXFA_LayoutItem* pLayoutItem = m_sIterator.GetCurrent();\r
174     return pLayoutItem ? (XFA_HWIDGET)XFA_GetWidgetFromLayoutItem(pLayoutItem) : NULL;\r
175 }\r
176 FX_BOOL CXFA_FFPageWidgetIterator::SetCurrentWidget(XFA_HWIDGET hWidget)\r
177 {\r
178     if(hWidget && m_sIterator.SetCurrent(((CXFA_FFWidget*)hWidget)->GetLayoutItem())) {\r
179         return TRUE;\r
180     }\r
181     return FALSE;\r
182 }\r
183 XFA_HWIDGET CXFA_FFPageWidgetIterator::GetWidget(CXFA_LayoutItem* pLayoutItem)\r
184 {\r
185     if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) {\r
186         if (!XFA_PageWidgetFilter(pWidget, m_dwFilter, FALSE, m_bIgnorerelevant)) {\r
187             return NULL;\r
188         }\r
189         if (!pWidget->IsLoaded() && (pWidget->GetStatus() & XFA_WIDGETSTATUS_Visible) != 0) {\r
190             pWidget->LoadWidget();\r
191         }\r
192         return (XFA_HWIDGET)pWidget;\r
193     }\r
194     return NULL;\r
195 }\r
196 CXFA_FFTabOrderPageWidgetIterator::CXFA_FFTabOrderPageWidgetIterator(CXFA_FFPageView* pPageView, FX_DWORD dwFilter)\r
197     : m_pPageView(pPageView)\r
198     , m_dwFilter(dwFilter)\r
199     , m_iCurWidget(-1)\r
200 {\r
201     m_bIgnorerelevant = ((CXFA_FFDoc*)m_pPageView->GetDocView()->GetDoc())->GetXFADoc()->GetCurVersionMode() < XFA_VERSION_205;\r
202     Reset();\r
203 }\r
204 CXFA_FFTabOrderPageWidgetIterator::~CXFA_FFTabOrderPageWidgetIterator()\r
205 {\r
206 }\r
207 void CXFA_FFTabOrderPageWidgetIterator::Release()\r
208 {\r
209     delete this;\r
210 }\r
211 void CXFA_FFTabOrderPageWidgetIterator::Reset()\r
212 {\r
213     CreateTabOrderWidgetArray();\r
214     m_iCurWidget = -1;\r
215 }\r
216 XFA_HWIDGET CXFA_FFTabOrderPageWidgetIterator::MoveToFirst()\r
217 {\r
218     if (m_TabOrderWidgetArray.GetSize() > 0) {\r
219         for (FX_INT32 i = 0; i < m_TabOrderWidgetArray.GetSize(); i++) {\r
220             if (XFA_PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, TRUE, m_bIgnorerelevant)) {\r
221                 m_iCurWidget = i;\r
222                 return (XFA_HWIDGET)m_TabOrderWidgetArray[m_iCurWidget];\r
223             }\r
224         }\r
225     }\r
226     return NULL;\r
227 }\r
228 XFA_HWIDGET CXFA_FFTabOrderPageWidgetIterator::MoveToLast()\r
229 {\r
230     if (m_TabOrderWidgetArray.GetSize() > 0) {\r
231         for (FX_INT32 i = m_TabOrderWidgetArray.GetSize() - 1; i >= 0; i--) {\r
232             if (XFA_PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, TRUE, m_bIgnorerelevant)) {\r
233                 m_iCurWidget = i;\r
234                 return (XFA_HWIDGET)m_TabOrderWidgetArray[m_iCurWidget];\r
235             }\r
236         }\r
237     }\r
238     return NULL;\r
239 }\r
240 XFA_HWIDGET CXFA_FFTabOrderPageWidgetIterator::MoveToNext()\r
241 {\r
242     for (FX_INT32 i = m_iCurWidget + 1; i < m_TabOrderWidgetArray.GetSize(); i++) {\r
243         if (XFA_PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, TRUE, m_bIgnorerelevant)) {\r
244             m_iCurWidget = i;\r
245             return (XFA_HWIDGET)m_TabOrderWidgetArray[m_iCurWidget];\r
246         }\r
247     }\r
248     m_iCurWidget = -1;\r
249     return NULL;\r
250 }\r
251 XFA_HWIDGET CXFA_FFTabOrderPageWidgetIterator::MoveToPrevious()\r
252 {\r
253     for (FX_INT32 i = m_iCurWidget - 1; i >= 0; i--) {\r
254         if (XFA_PageWidgetFilter(m_TabOrderWidgetArray[i], m_dwFilter, TRUE, m_bIgnorerelevant)) {\r
255             m_iCurWidget = i;\r
256             return (XFA_HWIDGET)m_TabOrderWidgetArray[m_iCurWidget];\r
257         }\r
258     }\r
259     m_iCurWidget = -1;\r
260     return NULL;\r
261 }\r
262 XFA_HWIDGET CXFA_FFTabOrderPageWidgetIterator::GetCurrentWidget()\r
263 {\r
264     if (m_iCurWidget >= 0) {\r
265         return (XFA_HWIDGET)m_TabOrderWidgetArray[m_iCurWidget];\r
266     }\r
267     return NULL;\r
268 }\r
269 FX_BOOL CXFA_FFTabOrderPageWidgetIterator::SetCurrentWidget(XFA_HWIDGET hWidget)\r
270 {\r
271     FX_INT32 iWidgetIndex = m_TabOrderWidgetArray.Find((CXFA_FFWidget*)hWidget);\r
272     if (iWidgetIndex >= 0) {\r
273         m_iCurWidget = iWidgetIndex;\r
274         return TRUE;\r
275     }\r
276     return FALSE;\r
277 }\r
278 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetTraverseWidget(CXFA_FFWidget* pWidget)\r
279 {\r
280     CXFA_WidgetAcc* pAcc = pWidget->GetDataAcc();\r
281     CXFA_Node* pTraversal = pAcc->GetNode()->GetChild(0, XFA_ELEMENT_Traversal);\r
282     if (pTraversal != NULL) {\r
283         CXFA_Node* pTraverse = pTraversal->GetChild(0, XFA_ELEMENT_Traverse);\r
284         if (pTraverse != NULL) {\r
285             CFX_WideString wsTraverseWidgetName;\r
286             if (pTraverse->GetAttribute(XFA_ATTRIBUTE_Ref, wsTraverseWidgetName)) {\r
287                 return FindWidgetByName(wsTraverseWidgetName, pWidget);\r
288             }\r
289         }\r
290     }\r
291     return NULL;\r
292 }\r
293 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::FindWidgetByName(FX_WSTR wsWidgetName, CXFA_FFWidget* pRefWidget)\r
294 {\r
295     return pRefWidget->GetDocView()->GetWidgetByName(wsWidgetName, pRefWidget);\r
296 }\r
297 void CXFA_FFTabOrderPageWidgetIterator::CreateTabOrderWidgetArray()\r
298 {\r
299     m_TabOrderWidgetArray.RemoveAll();\r
300     CXFA_WidgetArray SpaceOrderWidgetArray;\r
301     CreateSpaceOrderWidgetArray(SpaceOrderWidgetArray);\r
302     FX_INT32 nWidgetCount = SpaceOrderWidgetArray.GetSize();\r
303     if (nWidgetCount < 1) {\r
304         return;\r
305     }\r
306     CXFA_FFWidget* hWidget = SpaceOrderWidgetArray[0];\r
307     for (; m_TabOrderWidgetArray.GetSize() < nWidgetCount; ) {\r
308         if (m_TabOrderWidgetArray.Find(hWidget) < 0) {\r
309             m_TabOrderWidgetArray.Add(hWidget);\r
310             CXFA_WidgetAcc* pWidgetAcc = hWidget->GetDataAcc();\r
311             if (pWidgetAcc->GetUIType() == XFA_ELEMENT_ExclGroup) {\r
312                 FX_INT32 iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget) + 1;\r
313                 while (TRUE) {\r
314                     CXFA_FFWidget* pRadio = SpaceOrderWidgetArray[(iWidgetIndex) % nWidgetCount];\r
315                     if (pRadio->GetDataAcc()->GetExclGroup() != pWidgetAcc) {\r
316                         break;\r
317                     }\r
318                     if (m_TabOrderWidgetArray.Find(hWidget) < 0) {\r
319                         m_TabOrderWidgetArray.Add(pRadio);\r
320                     }\r
321                     iWidgetIndex++;\r
322                 }\r
323             }\r
324             if (CXFA_FFWidget* hTraverseWidget = GetTraverseWidget(hWidget)) {\r
325                 hWidget = hTraverseWidget;\r
326                 continue;\r
327             }\r
328         }\r
329         FX_INT32 iWidgetIndex = SpaceOrderWidgetArray.Find(hWidget);\r
330         hWidget = SpaceOrderWidgetArray[(iWidgetIndex + 1) % nWidgetCount];\r
331     }\r
332 }\r
333 static FX_INT32 XFA_TabOrderWidgetComparator(const void* phWidget1, const void* phWidget2)\r
334 {\r
335     CXFA_FFWidget* pWidget1 = (*(CXFA_TabParam**)phWidget1)->m_pWidget;\r
336     CXFA_FFWidget* pWidget2 = (*(CXFA_TabParam**)phWidget2)->m_pWidget;\r
337     CFX_RectF rt1, rt2;\r
338     pWidget1->GetWidgetRect(rt1);\r
339     pWidget2->GetWidgetRect(rt2);\r
340     FX_FLOAT x1 = rt1.left, y1 = rt1.top, x2 = rt2.left, y2 = rt2.top;\r
341     if (y1 < y2 || (y1 - y2 < XFA_FLOAT_PERCISION && x1 < x2)) {\r
342         return -1;\r
343     }\r
344     return 1;\r
345 }\r
346 void CXFA_FFTabOrderPageWidgetIterator::OrderContainer(CXFA_LayoutItemIterator* sIterator, CXFA_LayoutItem* pContainerItem, CXFA_TabParam* pContainer, FX_BOOL &bCurrentItem, FX_BOOL& bContentArea, FX_BOOL bMarsterPage)\r
347 {\r
348     CFX_PtrArray tabParams;\r
349     CXFA_LayoutItem* pSearchItem = sIterator->MoveToNext();\r
350     while(pSearchItem) {\r
351         FX_BOOL bIsContentLayoutItem = ((CXFA_LayoutItemImpl*)pSearchItem)->IsContentLayoutItem();\r
352         if(!bIsContentLayoutItem) {\r
353             bContentArea = TRUE;\r
354             pSearchItem = sIterator->MoveToNext();\r
355             continue;\r
356         }\r
357         if (bMarsterPage && bContentArea) {\r
358             break;\r
359         }\r
360         if (bMarsterPage || bContentArea) {\r
361             CXFA_FFWidget* hWidget = GetWidget(pSearchItem);\r
362             if (!hWidget) {\r
363                 pSearchItem = sIterator->MoveToNext();\r
364                 continue;\r
365             }\r
366             if (pContainerItem && (pSearchItem->GetParent() != pContainerItem)) {\r
367                 bCurrentItem = TRUE;\r
368                 break;\r
369             }\r
370             CXFA_TabParam* pParam = FX_NEW CXFA_TabParam;\r
371             pParam->m_pWidget = hWidget;\r
372             tabParams.Add(pParam);\r
373             if (XFA_IsLayoutElement(pSearchItem->GetFormNode()->GetClassID(), TRUE)) {\r
374                 OrderContainer(sIterator, pSearchItem, pParam, bCurrentItem, bContentArea, bMarsterPage);\r
375             }\r
376         }\r
377         if (bCurrentItem) {\r
378             pSearchItem = sIterator->GetCurrent();\r
379             bCurrentItem = FALSE;\r
380         } else {\r
381             pSearchItem = sIterator->MoveToNext();\r
382         }\r
383     }\r
384     FX_INT32 iChildren = tabParams.GetSize();\r
385     if (iChildren > 1) {\r
386         FXSYS_qsort(tabParams.GetData(), iChildren, sizeof(FX_LPVOID), XFA_TabOrderWidgetComparator);\r
387     }\r
388     for (FX_INT32 iStart = 0; iStart < iChildren; iStart++) {\r
389         CXFA_TabParam* pParam = (CXFA_TabParam*)tabParams[iStart];\r
390         pContainer->m_Children.Add(pParam->m_pWidget);\r
391         if (pParam->m_Children.GetSize() > 0) {\r
392             pContainer->m_Children.Append(pParam->m_Children);\r
393         }\r
394         delete pParam;\r
395     }\r
396     tabParams.RemoveAll();\r
397 }\r
398 void CXFA_FFTabOrderPageWidgetIterator::CreateSpaceOrderWidgetArray(CXFA_WidgetArray& WidgetArray)\r
399 {\r
400     CXFA_LayoutItemIterator sIterator;\r
401     sIterator.Init((CXFA_LayoutItem*)m_pPageView->GetLayoutPage());\r
402     CXFA_TabParam* pParam = FX_NEW CXFA_TabParam;\r
403     FX_BOOL bCurrentItem = FALSE;\r
404     FX_BOOL bContentArea = FALSE;\r
405     OrderContainer(&sIterator, NULL, pParam, bCurrentItem, bContentArea);\r
406     if (pParam->m_Children.GetSize() > 0) {\r
407         WidgetArray.Append(pParam->m_Children);\r
408     }\r
409     sIterator.Reset();\r
410     bCurrentItem = FALSE;\r
411     bContentArea = FALSE;\r
412     pParam->m_Children.RemoveAll();\r
413     OrderContainer(&sIterator, NULL, pParam, bCurrentItem, bContentArea, TRUE);\r
414     if (pParam->m_Children.GetSize() > 0) {\r
415         WidgetArray.Append(pParam->m_Children);\r
416     }\r
417     delete pParam;\r
418 }\r
419 CXFA_FFWidget* CXFA_FFTabOrderPageWidgetIterator::GetWidget(CXFA_LayoutItem* pLayoutItem)\r
420 {\r
421     if (CXFA_FFWidget* pWidget = XFA_GetWidgetFromLayoutItem(pLayoutItem)) {\r
422         if (!pWidget->IsLoaded() && (pWidget->GetStatus() & XFA_WIDGETSTATUS_Visible)) {\r
423             pWidget->LoadWidget();\r
424         }\r
425         return pWidget;\r
426     }\r
427     return NULL;\r
428 }\r