• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 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 "fxjs/xfa/cjx_field.h"
8 
9 #include "core/fxcrt/numerics/safe_conversions.h"
10 #include "core/fxcrt/span.h"
11 #include "fxjs/cfx_v8.h"
12 #include "fxjs/fxv8.h"
13 #include "fxjs/js_resources.h"
14 #include "v8/include/v8-primitive.h"
15 #include "xfa/fgas/crt/cfgas_decimal.h"
16 #include "xfa/fxfa/cxfa_eventparam.h"
17 #include "xfa/fxfa/cxfa_ffnotify.h"
18 #include "xfa/fxfa/fxfa.h"
19 #include "xfa/fxfa/parser/cxfa_document.h"
20 #include "xfa/fxfa/parser/cxfa_field.h"
21 #include "xfa/fxfa/parser/cxfa_value.h"
22 
23 const CJX_MethodSpec CJX_Field::MethodSpecs[] = {
24     {"addItem", addItem_static},
25     {"boundItem", boundItem_static},
26     {"clearItems", clearItems_static},
27     {"deleteItem", deleteItem_static},
28     {"execCalculate", execCalculate_static},
29     {"execEvent", execEvent_static},
30     {"execInitialize", execInitialize_static},
31     {"execValidate", execValidate_static},
32     {"getDisplayItem", getDisplayItem_static},
33     {"getItemState", getItemState_static},
34     {"getSaveItem", getSaveItem_static},
35     {"setItemState", setItemState_static}};
36 
CJX_Field(CXFA_Field * field)37 CJX_Field::CJX_Field(CXFA_Field* field) : CJX_Container(field) {
38   DefineMethods(MethodSpecs);
39 }
40 
41 CJX_Field::~CJX_Field() = default;
42 
DynamicTypeIs(TypeTag eType) const43 bool CJX_Field::DynamicTypeIs(TypeTag eType) const {
44   return eType == static_type__ || ParentType__::DynamicTypeIs(eType);
45 }
46 
clearItems(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)47 CJS_Result CJX_Field::clearItems(CFXJSE_Engine* runtime,
48                                  pdfium::span<v8::Local<v8::Value>> params) {
49   CXFA_Node* node = GetXFANode();
50   if (node->IsWidgetReady())
51     node->DeleteItem(-1, true, false);
52   return CJS_Result::Success();
53 }
54 
execEvent(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)55 CJS_Result CJX_Field::execEvent(CFXJSE_Engine* runtime,
56                                 pdfium::span<v8::Local<v8::Value>> params) {
57   if (params.size() != 1)
58     return CJS_Result::Failure(JSMessage::kParamError);
59 
60   WideString eventString = runtime->ToWideString(params[0]);
61   XFA_EventError iRet =
62       execSingleEventByName(eventString.AsStringView(), XFA_Element::Field);
63   if (!eventString.EqualsASCII("validate"))
64     return CJS_Result::Success();
65 
66   return CJS_Result::Success(
67       runtime->NewBoolean(iRet != XFA_EventError::kError));
68 }
69 
execInitialize(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)70 CJS_Result CJX_Field::execInitialize(
71     CFXJSE_Engine* runtime,
72     pdfium::span<v8::Local<v8::Value>> params) {
73   if (!params.empty())
74     return CJS_Result::Failure(JSMessage::kParamError);
75 
76   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
77   if (pNotify) {
78     pNotify->ExecEventByDeepFirst(GetXFANode(), XFA_EVENT_Initialize, false,
79                                   false);
80   }
81   return CJS_Result::Success();
82 }
83 
deleteItem(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)84 CJS_Result CJX_Field::deleteItem(CFXJSE_Engine* runtime,
85                                  pdfium::span<v8::Local<v8::Value>> params) {
86   if (params.size() != 1)
87     return CJS_Result::Failure(JSMessage::kParamError);
88 
89   CXFA_Node* node = GetXFANode();
90   if (!node->IsWidgetReady())
91     return CJS_Result::Success();
92 
93   bool bValue = node->DeleteItem(runtime->ToInt32(params[0]), true, true);
94   return CJS_Result::Success(runtime->NewBoolean(bValue));
95 }
96 
getSaveItem(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)97 CJS_Result CJX_Field::getSaveItem(CFXJSE_Engine* runtime,
98                                   pdfium::span<v8::Local<v8::Value>> params) {
99   if (params.size() != 1)
100     return CJS_Result::Failure(JSMessage::kParamError);
101 
102   int32_t iIndex = runtime->ToInt32(params[0]);
103   if (iIndex < 0)
104     return CJS_Result::Success(runtime->NewNull());
105 
106   CXFA_Node* node = GetXFANode();
107   if (!node->IsWidgetReady())
108     return CJS_Result::Success(runtime->NewNull());
109 
110   std::optional<WideString> value = node->GetChoiceListItem(iIndex, true);
111   if (!value.has_value())
112     return CJS_Result::Success(runtime->NewNull());
113 
114   return CJS_Result::Success(
115       runtime->NewString(value->ToUTF8().AsStringView()));
116 }
117 
boundItem(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)118 CJS_Result CJX_Field::boundItem(CFXJSE_Engine* runtime,
119                                 pdfium::span<v8::Local<v8::Value>> params) {
120   if (params.size() != 1)
121     return CJS_Result::Failure(JSMessage::kParamError);
122 
123   CXFA_Node* node = GetXFANode();
124   if (!node->IsWidgetReady())
125     return CJS_Result::Success();
126 
127   WideString value = runtime->ToWideString(params[0]);
128   WideString boundValue = node->GetItemValue(value.AsStringView());
129   return CJS_Result::Success(
130       runtime->NewString(boundValue.ToUTF8().AsStringView()));
131 }
132 
getItemState(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)133 CJS_Result CJX_Field::getItemState(CFXJSE_Engine* runtime,
134                                    pdfium::span<v8::Local<v8::Value>> params) {
135   if (params.size() != 1)
136     return CJS_Result::Failure(JSMessage::kParamError);
137 
138   CXFA_Node* node = GetXFANode();
139   if (!node->IsWidgetReady())
140     return CJS_Result::Success();
141 
142   int32_t state = node->GetItemState(runtime->ToInt32(params[0]));
143   return CJS_Result::Success(runtime->NewBoolean(state != 0));
144 }
145 
execCalculate(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)146 CJS_Result CJX_Field::execCalculate(CFXJSE_Engine* runtime,
147                                     pdfium::span<v8::Local<v8::Value>> params) {
148   if (!params.empty())
149     return CJS_Result::Failure(JSMessage::kParamError);
150 
151   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
152   if (pNotify) {
153     pNotify->ExecEventByDeepFirst(GetXFANode(), XFA_EVENT_Calculate, false,
154                                   false);
155   }
156   return CJS_Result::Success();
157 }
158 
getDisplayItem(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)159 CJS_Result CJX_Field::getDisplayItem(
160     CFXJSE_Engine* runtime,
161     pdfium::span<v8::Local<v8::Value>> params) {
162   if (params.size() != 1)
163     return CJS_Result::Failure(JSMessage::kParamError);
164 
165   int32_t iIndex = runtime->ToInt32(params[0]);
166   if (iIndex < 0)
167     return CJS_Result::Success(runtime->NewNull());
168 
169   CXFA_Node* node = GetXFANode();
170   if (!node->IsWidgetReady())
171     return CJS_Result::Success(runtime->NewNull());
172 
173   std::optional<WideString> value = node->GetChoiceListItem(iIndex, false);
174   if (!value.has_value())
175     return CJS_Result::Success(runtime->NewNull());
176 
177   return CJS_Result::Success(
178       runtime->NewString(value->ToUTF8().AsStringView()));
179 }
180 
setItemState(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)181 CJS_Result CJX_Field::setItemState(CFXJSE_Engine* runtime,
182                                    pdfium::span<v8::Local<v8::Value>> params) {
183   if (params.size() != 2)
184     return CJS_Result::Failure(JSMessage::kParamError);
185 
186   CXFA_Node* node = GetXFANode();
187   if (!node->IsWidgetReady())
188     return CJS_Result::Success();
189 
190   int32_t iIndex = runtime->ToInt32(params[0]);
191   if (runtime->ToInt32(params[1]) != 0) {
192     node->SetItemState(iIndex, true, true, true);
193     return CJS_Result::Success();
194   }
195   if (node->GetItemState(iIndex))
196     node->SetItemState(iIndex, false, true, true);
197 
198   return CJS_Result::Success();
199 }
200 
addItem(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)201 CJS_Result CJX_Field::addItem(CFXJSE_Engine* runtime,
202                               pdfium::span<v8::Local<v8::Value>> params) {
203   if (params.size() != 1 && params.size() != 2)
204     return CJS_Result::Failure(JSMessage::kParamError);
205 
206   CXFA_Node* node = GetXFANode();
207   if (!node->IsWidgetReady())
208     return CJS_Result::Success();
209 
210   WideString label;
211   if (params.size() >= 1)
212     label = runtime->ToWideString(params[0]);
213 
214   WideString value;
215   if (params.size() >= 2)
216     value = runtime->ToWideString(params[1]);
217 
218   node->InsertItem(label, value, true);
219   return CJS_Result::Success();
220 }
221 
execValidate(CFXJSE_Engine * runtime,pdfium::span<v8::Local<v8::Value>> params)222 CJS_Result CJX_Field::execValidate(CFXJSE_Engine* runtime,
223                                    pdfium::span<v8::Local<v8::Value>> params) {
224   if (!params.empty())
225     return CJS_Result::Failure(JSMessage::kParamError);
226 
227   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
228   if (!pNotify)
229     return CJS_Result::Success(runtime->NewBoolean(false));
230 
231   XFA_EventError iRet = pNotify->ExecEventByDeepFirst(
232       GetXFANode(), XFA_EVENT_Validate, false, false);
233   return CJS_Result::Success(
234       runtime->NewBoolean(iRet != XFA_EventError::kError));
235 }
236 
defaultValue(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)237 void CJX_Field::defaultValue(v8::Isolate* pIsolate,
238                              v8::Local<v8::Value>* pValue,
239                              bool bSetting,
240                              XFA_Attribute eAttribute) {
241   CXFA_Node* xfaNode = GetXFANode();
242   if (!xfaNode->IsWidgetReady())
243     return;
244 
245   if (bSetting) {
246     if (pValue) {
247       xfaNode->SetPreNull(xfaNode->IsNull());
248       xfaNode->SetIsNull(fxv8::IsNull(*pValue));
249     }
250 
251     WideString wsNewText;
252     if (pValue && !(fxv8::IsNull(*pValue) || fxv8::IsUndefined(*pValue)))
253       wsNewText = fxv8::ReentrantToWideStringHelper(pIsolate, *pValue);
254     if (xfaNode->GetUIChildNode()->GetElementType() == XFA_Element::NumericEdit)
255       wsNewText = xfaNode->NumericLimit(wsNewText);
256 
257     CXFA_Node* pContainerNode = xfaNode->GetContainerNode();
258     WideString wsFormatText(wsNewText);
259     if (pContainerNode)
260       wsFormatText = pContainerNode->GetFormatDataValue(wsNewText);
261 
262     SetContent(wsNewText, wsFormatText, true, true, true);
263     return;
264   }
265 
266   WideString content = GetContent(true);
267   if (content.IsEmpty()) {
268     *pValue = fxv8::NewNullHelper(pIsolate);
269     return;
270   }
271 
272   CXFA_Node* formValue = xfaNode->GetFormValueIfExists();
273   CXFA_Node* pNode = formValue ? formValue->GetFirstChild() : nullptr;
274   if (pNode && pNode->GetElementType() == XFA_Element::Decimal) {
275     if (xfaNode->GetUIChildNode()->GetElementType() ==
276             XFA_Element::NumericEdit &&
277         (pNode->JSObject()->GetInteger(XFA_Attribute::FracDigits) == -1)) {
278       *pValue =
279           fxv8::NewStringHelper(pIsolate, content.ToUTF8().AsStringView());
280     } else {
281       CFGAS_Decimal decimal(content.AsStringView());
282       *pValue = fxv8::NewNumberHelper(pIsolate, decimal.ToFloat());
283     }
284   } else if (pNode && pNode->GetElementType() == XFA_Element::Integer) {
285     *pValue = fxv8::NewNumberHelper(pIsolate, FXSYS_wtoi(content.c_str()));
286   } else if (pNode && pNode->GetElementType() == XFA_Element::Boolean) {
287     *pValue =
288         fxv8::NewBooleanHelper(pIsolate, FXSYS_wtoi(content.c_str()) != 0);
289   } else if (pNode && pNode->GetElementType() == XFA_Element::Float) {
290     CFGAS_Decimal decimal(content.AsStringView());
291     *pValue = fxv8::NewNumberHelper(pIsolate, decimal.ToFloat());
292   } else {
293     *pValue = fxv8::NewStringHelper(pIsolate, content.ToUTF8().AsStringView());
294   }
295 }
296 
editValue(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)297 void CJX_Field::editValue(v8::Isolate* pIsolate,
298                           v8::Local<v8::Value>* pValue,
299                           bool bSetting,
300                           XFA_Attribute eAttribute) {
301   CXFA_Node* node = GetXFANode();
302   if (!node->IsWidgetReady())
303     return;
304 
305   if (bSetting) {
306     node->SetValue(XFA_ValuePicture::kEdit,
307                    fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
308     return;
309   }
310   *pValue = fxv8::NewStringHelper(
311       pIsolate,
312       node->GetValue(XFA_ValuePicture::kEdit).ToUTF8().AsStringView());
313 }
314 
formatMessage(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)315 void CJX_Field::formatMessage(v8::Isolate* pIsolate,
316                               v8::Local<v8::Value>* pValue,
317                               bool bSetting,
318                               XFA_Attribute eAttribute) {
319   ScriptSomMessage(pIsolate, pValue, bSetting, SOMMessageType::kFormatMessage);
320 }
321 
formattedValue(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)322 void CJX_Field::formattedValue(v8::Isolate* pIsolate,
323                                v8::Local<v8::Value>* pValue,
324                                bool bSetting,
325                                XFA_Attribute eAttribute) {
326   CXFA_Node* node = GetXFANode();
327   if (!node->IsWidgetReady())
328     return;
329 
330   if (bSetting) {
331     node->SetValue(XFA_ValuePicture::kDisplay,
332                    fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
333     return;
334   }
335   *pValue = fxv8::NewStringHelper(
336       pIsolate,
337       node->GetValue(XFA_ValuePicture::kDisplay).ToUTF8().AsStringView());
338 }
339 
length(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)340 void CJX_Field::length(v8::Isolate* pIsolate,
341                        v8::Local<v8::Value>* pValue,
342                        bool bSetting,
343                        XFA_Attribute eAttribute) {
344   if (bSetting) {
345     ThrowInvalidPropertyException(pIsolate);
346     return;
347   }
348 
349   CXFA_Node* node = GetXFANode();
350   *pValue = fxv8::NewNumberHelper(
351       pIsolate, node->IsWidgetReady() ? pdfium::checked_cast<int>(
352                                             node->CountChoiceListItems(true))
353                                       : 0);
354 }
355 
parentSubform(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)356 void CJX_Field::parentSubform(v8::Isolate* pIsolate,
357                               v8::Local<v8::Value>* pValue,
358                               bool bSetting,
359                               XFA_Attribute eAttribute) {
360   if (bSetting) {
361     ThrowInvalidPropertyException(pIsolate);
362     return;
363   }
364   *pValue = fxv8::NewNullHelper(pIsolate);
365 }
366 
selectedIndex(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)367 void CJX_Field::selectedIndex(v8::Isolate* pIsolate,
368                               v8::Local<v8::Value>* pValue,
369                               bool bSetting,
370                               XFA_Attribute eAttribute) {
371   CXFA_Node* node = GetXFANode();
372   if (!node->IsWidgetReady())
373     return;
374 
375   if (!bSetting) {
376     *pValue = fxv8::NewNumberHelper(pIsolate, node->GetSelectedItem(0));
377     return;
378   }
379 
380   int32_t iIndex = fxv8::ReentrantToInt32Helper(pIsolate, *pValue);
381   if (iIndex == -1) {
382     node->ClearAllSelections();
383     return;
384   }
385 
386   node->SetItemState(iIndex, true, true, true);
387 }
388 
rawValue(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)389 void CJX_Field::rawValue(v8::Isolate* pIsolate,
390                          v8::Local<v8::Value>* pValue,
391                          bool bSetting,
392                          XFA_Attribute eAttribute) {
393   defaultValue(pIsolate, pValue, bSetting, eAttribute);
394 }
395