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