• 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 "xfa/fxfa/parser/cscript_layoutpseudomodel.h"
8 
9 #include <set>
10 
11 #include "fxjs/cfxjse_arguments.h"
12 #include "third_party/base/stl_util.h"
13 #include "xfa/fxfa/app/xfa_ffnotify.h"
14 #include "xfa/fxfa/parser/cxfa_containerlayoutitem.h"
15 #include "xfa/fxfa/parser/cxfa_contentlayoutitem.h"
16 #include "xfa/fxfa/parser/cxfa_document.h"
17 #include "xfa/fxfa/parser/cxfa_layoutitem.h"
18 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
19 #include "xfa/fxfa/parser/cxfa_measurement.h"
20 #include "xfa/fxfa/parser/cxfa_scriptcontext.h"
21 #include "xfa/fxfa/parser/cxfa_traversestrategy_contentlayoutitem.h"
22 #include "xfa/fxfa/parser/xfa_localemgr.h"
23 #include "xfa/fxfa/parser/xfa_object.h"
24 #include "xfa/fxfa/parser/xfa_utils.h"
25 
CScript_LayoutPseudoModel(CXFA_Document * pDocument)26 CScript_LayoutPseudoModel::CScript_LayoutPseudoModel(CXFA_Document* pDocument)
27     : CXFA_Object(pDocument,
28                   XFA_ObjectType::Object,
29                   XFA_Element::LayoutPseudoModel,
30                   CFX_WideStringC(L"layoutPseudoModel")) {}
31 
~CScript_LayoutPseudoModel()32 CScript_LayoutPseudoModel::~CScript_LayoutPseudoModel() {}
33 
Ready(CFXJSE_Value * pValue,bool bSetting,XFA_ATTRIBUTE eAttribute)34 void CScript_LayoutPseudoModel::Ready(CFXJSE_Value* pValue,
35                                       bool bSetting,
36                                       XFA_ATTRIBUTE eAttribute) {
37   CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
38   if (!pNotify) {
39     return;
40   }
41   if (bSetting) {
42     ThrowSetReadyException();
43     return;
44   }
45   int32_t iStatus = pNotify->GetLayoutStatus();
46   pValue->SetBoolean(iStatus >= 2);
47 }
48 
HWXY(CFXJSE_Arguments * pArguments,XFA_LAYOUTMODEL_HWXY layoutModel)49 void CScript_LayoutPseudoModel::HWXY(CFXJSE_Arguments* pArguments,
50                                      XFA_LAYOUTMODEL_HWXY layoutModel) {
51   int32_t iLength = pArguments->GetLength();
52   if (iLength < 1 || iLength > 3) {
53     const FX_WCHAR* methodName = nullptr;
54     switch (layoutModel) {
55       case XFA_LAYOUTMODEL_H:
56         methodName = L"h";
57         break;
58       case XFA_LAYOUTMODEL_W:
59         methodName = L"w";
60         break;
61       case XFA_LAYOUTMODEL_X:
62         methodName = L"x";
63         break;
64       case XFA_LAYOUTMODEL_Y:
65         methodName = L"y";
66         break;
67     }
68     ThrowParamCountMismatchException(methodName);
69     return;
70   }
71   CXFA_Node* pNode = nullptr;
72   CFX_WideString wsUnit(L"pt");
73   int32_t iIndex = 0;
74   if (iLength >= 1) {
75     pNode = static_cast<CXFA_Node*>(pArguments->GetObject(0));
76   }
77   if (iLength >= 2) {
78     CFX_ByteString bsUnit = pArguments->GetUTF8String(1);
79     if (!bsUnit.IsEmpty()) {
80       wsUnit = CFX_WideString::FromUTF8(bsUnit.AsStringC());
81     }
82   }
83   if (iLength >= 3) {
84     iIndex = pArguments->GetInt32(2);
85   }
86   if (!pNode) {
87     return;
88   }
89   CXFA_LayoutProcessor* pDocLayout = m_pDocument->GetDocLayout();
90   if (!pDocLayout) {
91     return;
92   }
93 
94   CXFA_Measurement measure;
95   CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
96   if (!pLayoutItem) {
97     return;
98   }
99   while (iIndex > 0 && pLayoutItem) {
100     pLayoutItem = pLayoutItem->GetNext();
101     iIndex--;
102   }
103   CFXJSE_Value* pValue = pArguments->GetReturnValue();
104   if (!pLayoutItem) {
105     pValue->SetFloat(0);
106     return;
107   }
108 
109   CFX_RectF rtRect = pLayoutItem->GetRect(true);
110   switch (layoutModel) {
111     case XFA_LAYOUTMODEL_H:
112       measure.Set(rtRect.height, XFA_UNIT_Pt);
113       break;
114     case XFA_LAYOUTMODEL_W:
115       measure.Set(rtRect.width, XFA_UNIT_Pt);
116       break;
117     case XFA_LAYOUTMODEL_X:
118       measure.Set(rtRect.left, XFA_UNIT_Pt);
119       break;
120     case XFA_LAYOUTMODEL_Y:
121       measure.Set(rtRect.top, XFA_UNIT_Pt);
122       break;
123   }
124   XFA_UNIT unit = measure.GetUnit(wsUnit.AsStringC());
125   FX_FLOAT fValue = measure.ToUnit(unit);
126   fValue = FXSYS_round(fValue * 1000) / 1000.0f;
127   if (pValue)
128     pValue->SetFloat(fValue);
129 }
130 
H(CFXJSE_Arguments * pArguments)131 void CScript_LayoutPseudoModel::H(CFXJSE_Arguments* pArguments) {
132   HWXY(pArguments, XFA_LAYOUTMODEL_H);
133 }
134 
W(CFXJSE_Arguments * pArguments)135 void CScript_LayoutPseudoModel::W(CFXJSE_Arguments* pArguments) {
136   HWXY(pArguments, XFA_LAYOUTMODEL_W);
137 }
138 
X(CFXJSE_Arguments * pArguments)139 void CScript_LayoutPseudoModel::X(CFXJSE_Arguments* pArguments) {
140   HWXY(pArguments, XFA_LAYOUTMODEL_X);
141 }
142 
Y(CFXJSE_Arguments * pArguments)143 void CScript_LayoutPseudoModel::Y(CFXJSE_Arguments* pArguments) {
144   HWXY(pArguments, XFA_LAYOUTMODEL_Y);
145 }
146 
NumberedPageCount(CFXJSE_Arguments * pArguments,bool bNumbered)147 void CScript_LayoutPseudoModel::NumberedPageCount(CFXJSE_Arguments* pArguments,
148                                                   bool bNumbered) {
149   CXFA_LayoutProcessor* pDocLayout = m_pDocument->GetDocLayout();
150   if (!pDocLayout) {
151     return;
152   }
153   int32_t iPageCount = 0;
154   int32_t iPageNum = pDocLayout->CountPages();
155   if (bNumbered) {
156     for (int32_t i = 0; i < iPageNum; i++) {
157       CXFA_ContainerLayoutItem* pLayoutPage = pDocLayout->GetPage(i);
158       if (!pLayoutPage) {
159         continue;
160       }
161       CXFA_Node* pMasterPage = pLayoutPage->GetMasterPage();
162       if (pMasterPage->GetInteger(XFA_ATTRIBUTE_Numbered)) {
163         iPageCount++;
164       }
165     }
166   } else {
167     iPageCount = iPageNum;
168   }
169   CFXJSE_Value* pValue = pArguments->GetReturnValue();
170   if (pValue)
171     pValue->SetInteger(iPageCount);
172 }
173 
PageCount(CFXJSE_Arguments * pArguments)174 void CScript_LayoutPseudoModel::PageCount(CFXJSE_Arguments* pArguments) {
175   NumberedPageCount(pArguments, true);
176 }
177 
PageSpan(CFXJSE_Arguments * pArguments)178 void CScript_LayoutPseudoModel::PageSpan(CFXJSE_Arguments* pArguments) {
179   int32_t iLength = pArguments->GetLength();
180   if (iLength != 1) {
181     ThrowParamCountMismatchException(L"pageSpan");
182     return;
183   }
184   CXFA_Node* pNode = nullptr;
185   if (iLength >= 1) {
186     pNode = static_cast<CXFA_Node*>(pArguments->GetObject(0));
187   }
188   if (!pNode) {
189     return;
190   }
191   CXFA_LayoutProcessor* pDocLayout = m_pDocument->GetDocLayout();
192   if (!pDocLayout) {
193     return;
194   }
195   CFXJSE_Value* pValue = pArguments->GetReturnValue();
196   CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
197   if (!pLayoutItem) {
198     pValue->SetInteger(-1);
199     return;
200   }
201   int32_t iLast = pLayoutItem->GetLast()->GetPage()->GetPageIndex();
202   int32_t iFirst = pLayoutItem->GetFirst()->GetPage()->GetPageIndex();
203   int32_t iPageSpan = iLast - iFirst + 1;
204   if (pValue)
205     pValue->SetInteger(iPageSpan);
206 }
207 
Page(CFXJSE_Arguments * pArguments)208 void CScript_LayoutPseudoModel::Page(CFXJSE_Arguments* pArguments) {
209   PageImp(pArguments, false);
210 }
211 
GetObjArray(CXFA_LayoutProcessor * pDocLayout,int32_t iPageNo,const CFX_WideString & wsType,bool bOnPageArea,CXFA_NodeArray & retArray)212 void CScript_LayoutPseudoModel::GetObjArray(CXFA_LayoutProcessor* pDocLayout,
213                                             int32_t iPageNo,
214                                             const CFX_WideString& wsType,
215                                             bool bOnPageArea,
216                                             CXFA_NodeArray& retArray) {
217   CXFA_ContainerLayoutItem* pLayoutPage = pDocLayout->GetPage(iPageNo);
218   if (!pLayoutPage) {
219     return;
220   }
221   if (wsType == L"pageArea") {
222     if (CXFA_Node* pMasterPage = pLayoutPage->m_pFormNode) {
223       retArray.Add(pMasterPage);
224     }
225     return;
226   }
227   if (wsType == L"contentArea") {
228     for (CXFA_LayoutItem* pItem = pLayoutPage->m_pFirstChild; pItem;
229          pItem = pItem->m_pNextSibling) {
230       if (pItem->m_pFormNode->GetElementType() == XFA_Element::ContentArea) {
231         retArray.Add(pItem->m_pFormNode);
232       }
233     }
234     return;
235   }
236   std::set<CXFA_Node*> formItems;
237   if (wsType.IsEmpty()) {
238     if (CXFA_Node* pMasterPage = pLayoutPage->m_pFormNode) {
239       retArray.Add(pMasterPage);
240     }
241     for (CXFA_LayoutItem* pItem = pLayoutPage->m_pFirstChild; pItem;
242          pItem = pItem->m_pNextSibling) {
243       if (pItem->m_pFormNode->GetElementType() == XFA_Element::ContentArea) {
244         retArray.Add(pItem->m_pFormNode);
245         if (!bOnPageArea) {
246           CXFA_NodeIteratorTemplate<CXFA_ContentLayoutItem,
247                                     CXFA_TraverseStrategy_ContentLayoutItem>
248           iterator(static_cast<CXFA_ContentLayoutItem*>(pItem->m_pFirstChild));
249           for (CXFA_ContentLayoutItem* pItemChild = iterator.GetCurrent();
250                pItemChild; pItemChild = iterator.MoveToNext()) {
251             if (!pItemChild->IsContentLayoutItem()) {
252               continue;
253             }
254             XFA_Element eType = pItemChild->m_pFormNode->GetElementType();
255             if (eType != XFA_Element::Field && eType != XFA_Element::Draw &&
256                 eType != XFA_Element::Subform && eType != XFA_Element::Area) {
257               continue;
258             }
259             if (pdfium::ContainsValue(formItems, pItemChild->m_pFormNode))
260               continue;
261 
262             formItems.insert(pItemChild->m_pFormNode);
263             retArray.Add(pItemChild->m_pFormNode);
264           }
265         }
266       } else {
267         if (bOnPageArea) {
268           CXFA_NodeIteratorTemplate<CXFA_ContentLayoutItem,
269                                     CXFA_TraverseStrategy_ContentLayoutItem>
270           iterator(static_cast<CXFA_ContentLayoutItem*>(pItem));
271           for (CXFA_ContentLayoutItem* pItemChild = iterator.GetCurrent();
272                pItemChild; pItemChild = iterator.MoveToNext()) {
273             if (!pItemChild->IsContentLayoutItem()) {
274               continue;
275             }
276             XFA_Element eType = pItemChild->m_pFormNode->GetElementType();
277             if (eType != XFA_Element::Field && eType != XFA_Element::Draw &&
278                 eType != XFA_Element::Subform && eType != XFA_Element::Area) {
279               continue;
280             }
281             if (pdfium::ContainsValue(formItems, pItemChild->m_pFormNode))
282               continue;
283             formItems.insert(pItemChild->m_pFormNode);
284             retArray.Add(pItemChild->m_pFormNode);
285           }
286         }
287       }
288     }
289     return;
290   }
291   XFA_Element eType = XFA_Element::Unknown;
292   if (wsType == L"field") {
293     eType = XFA_Element::Field;
294   } else if (wsType == L"draw") {
295     eType = XFA_Element::Draw;
296   } else if (wsType == L"subform") {
297     eType = XFA_Element::Subform;
298   } else if (wsType == L"area") {
299     eType = XFA_Element::Area;
300   }
301   if (eType != XFA_Element::Unknown) {
302     for (CXFA_LayoutItem* pItem = pLayoutPage->m_pFirstChild; pItem;
303          pItem = pItem->m_pNextSibling) {
304       if (pItem->m_pFormNode->GetElementType() == XFA_Element::ContentArea) {
305         if (!bOnPageArea) {
306           CXFA_NodeIteratorTemplate<CXFA_ContentLayoutItem,
307                                     CXFA_TraverseStrategy_ContentLayoutItem>
308           iterator(static_cast<CXFA_ContentLayoutItem*>(pItem->m_pFirstChild));
309           for (CXFA_ContentLayoutItem* pItemChild = iterator.GetCurrent();
310                pItemChild; pItemChild = iterator.MoveToNext()) {
311             if (!pItemChild->IsContentLayoutItem())
312               continue;
313             if (pItemChild->m_pFormNode->GetElementType() != eType)
314               continue;
315             if (pdfium::ContainsValue(formItems, pItemChild->m_pFormNode))
316               continue;
317             formItems.insert(pItemChild->m_pFormNode);
318             retArray.Add(pItemChild->m_pFormNode);
319           }
320         }
321       } else {
322         if (bOnPageArea) {
323           CXFA_NodeIteratorTemplate<CXFA_ContentLayoutItem,
324                                     CXFA_TraverseStrategy_ContentLayoutItem>
325           iterator(static_cast<CXFA_ContentLayoutItem*>(pItem));
326           for (CXFA_ContentLayoutItem* pItemChild = iterator.GetCurrent();
327                pItemChild; pItemChild = iterator.MoveToNext()) {
328             if (!pItemChild->IsContentLayoutItem())
329               continue;
330             if (pItemChild->m_pFormNode->GetElementType() != eType)
331               continue;
332             if (pdfium::ContainsValue(formItems, pItemChild->m_pFormNode))
333               continue;
334             formItems.insert(pItemChild->m_pFormNode);
335             retArray.Add(pItemChild->m_pFormNode);
336           }
337         }
338       }
339     }
340     return;
341   }
342 }
343 
PageContent(CFXJSE_Arguments * pArguments)344 void CScript_LayoutPseudoModel::PageContent(CFXJSE_Arguments* pArguments) {
345   int32_t iLength = pArguments->GetLength();
346   if (iLength < 1 || iLength > 3) {
347     ThrowParamCountMismatchException(L"pageContent");
348     return;
349   }
350   int32_t iIndex = 0;
351   CFX_WideString wsType;
352   bool bOnPageArea = false;
353   if (iLength >= 1) {
354     iIndex = pArguments->GetInt32(0);
355   }
356   if (iLength >= 2) {
357     CFX_ByteString bsType = pArguments->GetUTF8String(1);
358     wsType = CFX_WideString::FromUTF8(bsType.AsStringC());
359   }
360   if (iLength >= 3) {
361     bOnPageArea = pArguments->GetInt32(2) == 0 ? false : true;
362   }
363   CXFA_FFNotify* pNotify = m_pDocument->GetNotify();
364   if (!pNotify) {
365     return;
366   }
367   CXFA_LayoutProcessor* pDocLayout = m_pDocument->GetDocLayout();
368   if (!pDocLayout) {
369     return;
370   }
371   CXFA_NodeArray retArray;
372   GetObjArray(pDocLayout, iIndex, wsType, bOnPageArea, retArray);
373   CXFA_ArrayNodeList* pArrayNodeList = new CXFA_ArrayNodeList(m_pDocument);
374   pArrayNodeList->SetArrayNodeList(retArray);
375   pArguments->GetReturnValue()->SetObject(
376       pArrayNodeList, m_pDocument->GetScriptContext()->GetJseNormalClass());
377 }
378 
AbsPageCount(CFXJSE_Arguments * pArguments)379 void CScript_LayoutPseudoModel::AbsPageCount(CFXJSE_Arguments* pArguments) {
380   NumberedPageCount(pArguments, false);
381 }
382 
AbsPageCountInBatch(CFXJSE_Arguments * pArguments)383 void CScript_LayoutPseudoModel::AbsPageCountInBatch(
384     CFXJSE_Arguments* pArguments) {
385   CFXJSE_Value* pValue = pArguments->GetReturnValue();
386   if (pValue)
387     pValue->SetInteger(0);
388 }
389 
SheetCountInBatch(CFXJSE_Arguments * pArguments)390 void CScript_LayoutPseudoModel::SheetCountInBatch(
391     CFXJSE_Arguments* pArguments) {
392   CFXJSE_Value* pValue = pArguments->GetReturnValue();
393   if (pValue)
394     pValue->SetInteger(0);
395 }
396 
Relayout(CFXJSE_Arguments * pArguments)397 void CScript_LayoutPseudoModel::Relayout(CFXJSE_Arguments* pArguments) {
398   CXFA_Node* pRootNode = m_pDocument->GetRoot();
399   CXFA_Node* pFormRoot = pRootNode->GetFirstChildByClass(XFA_Element::Form);
400   ASSERT(pFormRoot);
401   CXFA_Node* pContentRootNode = pFormRoot->GetNodeItem(XFA_NODEITEM_FirstChild);
402   CXFA_LayoutProcessor* pLayoutProcessor = m_pDocument->GetLayoutProcessor();
403   if (pContentRootNode) {
404     pLayoutProcessor->AddChangedContainer(pContentRootNode);
405   }
406   pLayoutProcessor->SetForceReLayout(true);
407 }
408 
AbsPageSpan(CFXJSE_Arguments * pArguments)409 void CScript_LayoutPseudoModel::AbsPageSpan(CFXJSE_Arguments* pArguments) {
410   PageSpan(pArguments);
411 }
412 
AbsPageInBatch(CFXJSE_Arguments * pArguments)413 void CScript_LayoutPseudoModel::AbsPageInBatch(CFXJSE_Arguments* pArguments) {
414   if (pArguments->GetLength() != 1) {
415     ThrowParamCountMismatchException(L"absPageInBatch");
416     return;
417   }
418 
419   CFXJSE_Value* pValue = pArguments->GetReturnValue();
420   if (pValue)
421     pValue->SetInteger(0);
422 }
423 
SheetInBatch(CFXJSE_Arguments * pArguments)424 void CScript_LayoutPseudoModel::SheetInBatch(CFXJSE_Arguments* pArguments) {
425   if (pArguments->GetLength() != 1) {
426     ThrowParamCountMismatchException(L"sheetInBatch");
427     return;
428   }
429 
430   CFXJSE_Value* pValue = pArguments->GetReturnValue();
431   if (pValue)
432     pValue->SetInteger(0);
433 }
434 
Sheet(CFXJSE_Arguments * pArguments)435 void CScript_LayoutPseudoModel::Sheet(CFXJSE_Arguments* pArguments) {
436   PageImp(pArguments, true);
437 }
438 
RelayoutPageArea(CFXJSE_Arguments * pArguments)439 void CScript_LayoutPseudoModel::RelayoutPageArea(CFXJSE_Arguments* pArguments) {
440 }
441 
SheetCount(CFXJSE_Arguments * pArguments)442 void CScript_LayoutPseudoModel::SheetCount(CFXJSE_Arguments* pArguments) {
443   NumberedPageCount(pArguments, false);
444 }
445 
AbsPage(CFXJSE_Arguments * pArguments)446 void CScript_LayoutPseudoModel::AbsPage(CFXJSE_Arguments* pArguments) {
447   PageImp(pArguments, true);
448 }
449 
PageImp(CFXJSE_Arguments * pArguments,bool bAbsPage)450 void CScript_LayoutPseudoModel::PageImp(CFXJSE_Arguments* pArguments,
451                                         bool bAbsPage) {
452   int32_t iLength = pArguments->GetLength();
453   if (iLength != 1) {
454     const FX_WCHAR* methodName;
455     if (bAbsPage) {
456       methodName = L"absPage";
457     } else {
458       methodName = L"page";
459     }
460     ThrowParamCountMismatchException(methodName);
461     return;
462   }
463   CXFA_Node* pNode = nullptr;
464   if (iLength >= 1) {
465     pNode = static_cast<CXFA_Node*>(pArguments->GetObject(0));
466   }
467   int32_t iPage = 0;
468   CFXJSE_Value* pValue = pArguments->GetReturnValue();
469   if (!pNode && pValue)
470     pValue->SetInteger(iPage);
471 
472   CXFA_LayoutProcessor* pDocLayout = m_pDocument->GetDocLayout();
473   if (!pDocLayout) {
474     return;
475   }
476   CXFA_LayoutItem* pLayoutItem = pDocLayout->GetLayoutItem(pNode);
477   if (!pLayoutItem) {
478     pValue->SetInteger(-1);
479     return;
480   }
481   iPage = pLayoutItem->GetFirst()->GetPage()->GetPageIndex();
482   if (pValue)
483     pValue->SetInteger(bAbsPage ? iPage : iPage + 1);
484 }
485 
ThrowSetReadyException() const486 void CScript_LayoutPseudoModel::ThrowSetReadyException() const {
487   ThrowException(L"Unable to set ready value.");
488 }
489