1 // Copyright 2017 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 "fxjs/xfa/cjx_object.h"
8 
9 #include <set>
10 #include <tuple>
11 
12 #include "core/fxcrt/fx_extension.h"
13 #include "core/fxcrt/fx_memory.h"
14 #include "core/fxcrt/xml/cfx_xmlelement.h"
15 #include "core/fxcrt/xml/cfx_xmltext.h"
16 #include "fxjs/cjs_result.h"
17 #include "fxjs/gc/container_trace.h"
18 #include "fxjs/xfa/cfxjse_engine.h"
19 #include "fxjs/xfa/cfxjse_mapmodule.h"
20 #include "fxjs/xfa/cfxjse_value.h"
21 #include "fxjs/xfa/cjx_boolean.h"
22 #include "fxjs/xfa/cjx_draw.h"
23 #include "fxjs/xfa/cjx_field.h"
24 #include "fxjs/xfa/cjx_instancemanager.h"
25 #include "third_party/base/compiler_specific.h"
26 #include "third_party/base/stl_util.h"
27 #include "xfa/fgas/crt/cfgas_decimal.h"
28 #include "xfa/fxfa/cxfa_ffnotify.h"
29 #include "xfa/fxfa/cxfa_ffwidget.h"
30 #include "xfa/fxfa/parser/cxfa_border.h"
31 #include "xfa/fxfa/parser/cxfa_datavalue.h"
32 #include "xfa/fxfa/parser/cxfa_document.h"
33 #include "xfa/fxfa/parser/cxfa_edge.h"
34 #include "xfa/fxfa/parser/cxfa_fill.h"
35 #include "xfa/fxfa/parser/cxfa_font.h"
36 #include "xfa/fxfa/parser/cxfa_measurement.h"
37 #include "xfa/fxfa/parser/cxfa_node.h"
38 #include "xfa/fxfa/parser/cxfa_object.h"
39 #include "xfa/fxfa/parser/cxfa_occur.h"
40 #include "xfa/fxfa/parser/cxfa_proto.h"
41 #include "xfa/fxfa/parser/cxfa_subform.h"
42 #include "xfa/fxfa/parser/cxfa_validate.h"
43 #include "xfa/fxfa/parser/cxfa_value.h"
44 #include "xfa/fxfa/parser/xfa_basic_data.h"
45 #include "xfa/fxfa/parser/xfa_utils.h"
46 
47 namespace {
48 
49 enum XFA_KEYTYPE {
50   XFA_KEYTYPE_Custom,
51   XFA_KEYTYPE_Element,
52 };
53 
GetMapKey_Custom(WideStringView wsKey)54 uint32_t GetMapKey_Custom(WideStringView wsKey) {
55   uint32_t dwKey = FX_HashCode_GetW(wsKey, false);
56   return ((dwKey << 1) | XFA_KEYTYPE_Custom);
57 }
58 
GetMapKey_Element(XFA_Element eType,XFA_Attribute eAttribute)59 uint32_t GetMapKey_Element(XFA_Element eType, XFA_Attribute eAttribute) {
60   return ((static_cast<uint32_t>(eType) << 16) |
61           (static_cast<uint32_t>(eAttribute) << 8) | XFA_KEYTYPE_Element);
62 }
63 
StrToRGB(const WideString & strRGB)64 std::tuple<int32_t, int32_t, int32_t> StrToRGB(const WideString& strRGB) {
65   int32_t r = 0;
66   int32_t g = 0;
67   int32_t b = 0;
68 
69   size_t iIndex = 0;
70   for (size_t i = 0; i < strRGB.GetLength(); ++i) {
71     wchar_t ch = strRGB[i];
72     if (ch == L',')
73       ++iIndex;
74     if (iIndex > 2)
75       break;
76 
77     int32_t iValue = ch - L'0';
78     if (iValue >= 0 && iValue <= 9) {
79       switch (iIndex) {
80         case 0:
81           r = r * 10 + iValue;
82           break;
83         case 1:
84           g = g * 10 + iValue;
85           break;
86         default:
87           b = b * 10 + iValue;
88           break;
89       }
90     }
91   }
92   return {r, g, b};
93 }
94 
95 }  // namespace
96 
CJX_Object(CXFA_Object * obj)97 CJX_Object::CJX_Object(CXFA_Object* obj) : object_(obj) {}
98 
99 CJX_Object::~CJX_Object() = default;
100 
AsCJXObject()101 CJX_Object* CJX_Object::AsCJXObject() {
102   return this;
103 }
104 
Trace(cppgc::Visitor * visitor) const105 void CJX_Object::Trace(cppgc::Visitor* visitor) const {
106   visitor->Trace(object_);
107   visitor->Trace(layout_item_);
108   visitor->Trace(calc_data_);
109 }
110 
DynamicTypeIs(TypeTag eType) const111 bool CJX_Object::DynamicTypeIs(TypeTag eType) const {
112   return eType == static_type__;
113 }
114 
DefineMethods(pdfium::span<const CJX_MethodSpec> methods)115 void CJX_Object::DefineMethods(pdfium::span<const CJX_MethodSpec> methods) {
116   for (const auto& item : methods)
117     method_specs_[item.pName] = item.pMethodCall;
118 }
119 
GetDocument() const120 CXFA_Document* CJX_Object::GetDocument() const {
121   return object_->GetDocument();
122 }
123 
GetXFANode() const124 CXFA_Node* CJX_Object::GetXFANode() const {
125   return ToNode(GetXFAObject());
126 }
127 
className(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)128 void CJX_Object::className(v8::Isolate* pIsolate,
129                            CFXJSE_Value* pValue,
130                            bool bSetting,
131                            XFA_Attribute eAttribute) {
132   if (bSetting) {
133     ThrowInvalidPropertyException();
134     return;
135   }
136   pValue->SetString(pIsolate, GetXFAObject()->GetClassName());
137 }
138 
Subform_and_SubformSet_InstanceIndex()139 int32_t CJX_Object::Subform_and_SubformSet_InstanceIndex() {
140   int32_t index = 0;
141   for (CXFA_Node* pNode = GetXFANode()->GetPrevSibling(); pNode;
142        pNode = pNode->GetPrevSibling()) {
143     if ((pNode->GetElementType() != XFA_Element::Subform) &&
144         (pNode->GetElementType() != XFA_Element::SubformSet)) {
145       break;
146     }
147     index++;
148   }
149   return index;
150 }
151 
HasMethod(const WideString & func) const152 bool CJX_Object::HasMethod(const WideString& func) const {
153   return pdfium::Contains(method_specs_, func.ToUTF8());
154 }
155 
RunMethod(const WideString & func,const std::vector<v8::Local<v8::Value>> & params)156 CJS_Result CJX_Object::RunMethod(
157     const WideString& func,
158     const std::vector<v8::Local<v8::Value>>& params) {
159   auto it = method_specs_.find(func.ToUTF8());
160   if (it == method_specs_.end())
161     return CJS_Result::Failure(JSMessage::kUnknownMethod);
162 
163   return it->second(this, GetXFAObject()->GetDocument()->GetScriptContext(),
164                     params);
165 }
166 
ThrowTooManyOccurancesException(const WideString & obj) const167 void CJX_Object::ThrowTooManyOccurancesException(const WideString& obj) const {
168   ThrowException(WideString::FromASCII("The element [") + obj +
169                  WideString::FromASCII(
170                      "] has violated its allowable number of occurrences."));
171 }
172 
ThrowInvalidPropertyException() const173 void CJX_Object::ThrowInvalidPropertyException() const {
174   ThrowException(WideString::FromASCII("Invalid property set operation."));
175 }
176 
ThrowIndexOutOfBoundsException() const177 void CJX_Object::ThrowIndexOutOfBoundsException() const {
178   ThrowException(WideString::FromASCII("Index value is out of bounds."));
179 }
180 
ThrowParamCountMismatchException(const WideString & method) const181 void CJX_Object::ThrowParamCountMismatchException(
182     const WideString& method) const {
183   ThrowException(
184       WideString::FromASCII("Incorrect number of parameters calling method '") +
185       method + WideString::FromASCII("'."));
186 }
187 
ThrowArgumentMismatchException() const188 void CJX_Object::ThrowArgumentMismatchException() const {
189   ThrowException(WideString::FromASCII(
190       "Argument mismatch in property or function argument."));
191 }
192 
ThrowException(const WideString & str) const193 void CJX_Object::ThrowException(const WideString& str) const {
194   ASSERT(!str.IsEmpty());
195   FXJSE_ThrowMessage(str.ToUTF8().AsStringView());
196 }
197 
HasAttribute(XFA_Attribute eAttr)198 bool CJX_Object::HasAttribute(XFA_Attribute eAttr) {
199   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
200   return HasMapModuleKey(key);
201 }
202 
SetAttributeByEnum(XFA_Attribute eAttr,const WideString & wsValue,bool bNotify)203 void CJX_Object::SetAttributeByEnum(XFA_Attribute eAttr,
204                                     const WideString& wsValue,
205                                     bool bNotify) {
206   switch (GetXFANode()->GetAttributeType(eAttr)) {
207     case XFA_AttributeType::Enum: {
208       Optional<XFA_AttributeValue> item =
209           XFA_GetAttributeValueByName(wsValue.AsStringView());
210       SetEnum(eAttr, item ? *item : *(GetXFANode()->GetDefaultEnum(eAttr)),
211               bNotify);
212       break;
213     }
214     case XFA_AttributeType::CData:
215       SetCDataImpl(eAttr, WideString(wsValue), bNotify, false);
216       break;
217     case XFA_AttributeType::Boolean:
218       SetBoolean(eAttr, !wsValue.EqualsASCII("0"), bNotify);
219       break;
220     case XFA_AttributeType::Integer:
221       SetInteger(eAttr,
222                  FXSYS_roundf(FXSYS_wcstof(wsValue.c_str(), wsValue.GetLength(),
223                                            nullptr)),
224                  bNotify);
225       break;
226     case XFA_AttributeType::Measure:
227       SetMeasure(eAttr, CXFA_Measurement(wsValue.AsStringView()), bNotify);
228       break;
229     default:
230       break;
231   }
232 }
233 
SetAttributeByString(WideStringView wsAttr,const WideString & wsValue)234 void CJX_Object::SetAttributeByString(WideStringView wsAttr,
235                                       const WideString& wsValue) {
236   Optional<XFA_ATTRIBUTEINFO> attr = XFA_GetAttributeByName(wsAttr);
237   if (attr.has_value()) {
238     SetAttributeByEnum(attr.value().attribute, wsValue, true);
239     return;
240   }
241   uint32_t key = GetMapKey_Custom(wsAttr);
242   SetMapModuleString(key, wsValue);
243 }
244 
GetAttributeByString(WideStringView attr)245 WideString CJX_Object::GetAttributeByString(WideStringView attr) {
246   Optional<WideString> result;
247   Optional<XFA_ATTRIBUTEINFO> enum_attr = XFA_GetAttributeByName(attr);
248   if (enum_attr.has_value())
249     result = TryAttribute(enum_attr.value().attribute, true);
250   else
251     result = GetMapModuleStringFollowingChain(GetMapKey_Custom(attr));
252   return result.value_or(WideString());
253 }
254 
GetAttributeByEnum(XFA_Attribute attr)255 WideString CJX_Object::GetAttributeByEnum(XFA_Attribute attr) {
256   return TryAttribute(attr, true).value_or(WideString());
257 }
258 
TryAttribute(XFA_Attribute eAttr,bool bUseDefault)259 Optional<WideString> CJX_Object::TryAttribute(XFA_Attribute eAttr,
260                                               bool bUseDefault) {
261   switch (GetXFANode()->GetAttributeType(eAttr)) {
262     case XFA_AttributeType::Enum: {
263       Optional<XFA_AttributeValue> value = TryEnum(eAttr, bUseDefault);
264       if (!value)
265         return {};
266       return WideString::FromASCII(XFA_AttributeValueToName(*value));
267     }
268     case XFA_AttributeType::CData:
269       return TryCData(eAttr, bUseDefault);
270 
271     case XFA_AttributeType::Boolean: {
272       Optional<bool> value = TryBoolean(eAttr, bUseDefault);
273       if (!value)
274         return {};
275       return WideString(*value ? L"1" : L"0");
276     }
277     case XFA_AttributeType::Integer: {
278       Optional<int32_t> iValue = TryInteger(eAttr, bUseDefault);
279       if (!iValue)
280         return {};
281       return WideString::Format(L"%d", *iValue);
282     }
283     case XFA_AttributeType::Measure: {
284       Optional<CXFA_Measurement> value = TryMeasure(eAttr, bUseDefault);
285       if (!value)
286         return {};
287 
288       return value->ToString();
289     }
290     default:
291       break;
292   }
293   return {};
294 }
295 
RemoveAttribute(WideStringView wsAttr)296 void CJX_Object::RemoveAttribute(WideStringView wsAttr) {
297   RemoveMapModuleKey(GetMapKey_Custom(wsAttr));
298 }
299 
TryBoolean(XFA_Attribute eAttr,bool bUseDefault)300 Optional<bool> CJX_Object::TryBoolean(XFA_Attribute eAttr, bool bUseDefault) {
301   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
302   Optional<int32_t> value = GetMapModuleValueFollowingChain(key);
303   if (value.has_value())
304     return !!value.value();
305   if (!bUseDefault)
306     return pdfium::nullopt;
307   return GetXFANode()->GetDefaultBoolean(eAttr);
308 }
309 
SetBoolean(XFA_Attribute eAttr,bool bValue,bool bNotify)310 void CJX_Object::SetBoolean(XFA_Attribute eAttr, bool bValue, bool bNotify) {
311   CFX_XMLElement* elem = SetValue(eAttr, static_cast<int32_t>(bValue), bNotify);
312   if (elem) {
313     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
314                        bValue ? L"1" : L"0");
315   }
316 }
317 
GetBoolean(XFA_Attribute eAttr)318 bool CJX_Object::GetBoolean(XFA_Attribute eAttr) {
319   return TryBoolean(eAttr, true).value_or(false);
320 }
321 
SetInteger(XFA_Attribute eAttr,int32_t iValue,bool bNotify)322 void CJX_Object::SetInteger(XFA_Attribute eAttr, int32_t iValue, bool bNotify) {
323   CFX_XMLElement* elem = SetValue(eAttr, iValue, bNotify);
324   if (elem) {
325     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
326                        WideString::Format(L"%d", iValue));
327   }
328 }
329 
GetInteger(XFA_Attribute eAttr) const330 int32_t CJX_Object::GetInteger(XFA_Attribute eAttr) const {
331   return TryInteger(eAttr, true).value_or(0);
332 }
333 
TryInteger(XFA_Attribute eAttr,bool bUseDefault) const334 Optional<int32_t> CJX_Object::TryInteger(XFA_Attribute eAttr,
335                                          bool bUseDefault) const {
336   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
337   Optional<int32_t> value = GetMapModuleValueFollowingChain(key);
338   if (value.has_value())
339     return value.value();
340   if (!bUseDefault)
341     return pdfium::nullopt;
342   return GetXFANode()->GetDefaultInteger(eAttr);
343 }
344 
TryEnum(XFA_Attribute eAttr,bool bUseDefault) const345 Optional<XFA_AttributeValue> CJX_Object::TryEnum(XFA_Attribute eAttr,
346                                                  bool bUseDefault) const {
347   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
348   Optional<int32_t> value = GetMapModuleValueFollowingChain(key);
349   if (value.has_value())
350     return static_cast<XFA_AttributeValue>(value.value());
351   if (!bUseDefault)
352     return pdfium::nullopt;
353   return GetXFANode()->GetDefaultEnum(eAttr);
354 }
355 
SetEnum(XFA_Attribute eAttr,XFA_AttributeValue eValue,bool bNotify)356 void CJX_Object::SetEnum(XFA_Attribute eAttr,
357                          XFA_AttributeValue eValue,
358                          bool bNotify) {
359   CFX_XMLElement* elem = SetValue(eAttr, static_cast<int32_t>(eValue), bNotify);
360   if (elem) {
361     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
362                        WideString::FromASCII(XFA_AttributeValueToName(eValue)));
363   }
364 }
365 
GetEnum(XFA_Attribute eAttr) const366 XFA_AttributeValue CJX_Object::GetEnum(XFA_Attribute eAttr) const {
367   return TryEnum(eAttr, true).value_or(XFA_AttributeValue::Unknown);
368 }
369 
SetMeasure(XFA_Attribute eAttr,const CXFA_Measurement & mValue,bool bNotify)370 void CJX_Object::SetMeasure(XFA_Attribute eAttr,
371                             const CXFA_Measurement& mValue,
372                             bool bNotify) {
373   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
374   OnChanging(eAttr, bNotify);
375   SetMapModuleMeasurement(key, mValue);
376   OnChanged(eAttr, bNotify, false);
377 }
378 
TryMeasure(XFA_Attribute eAttr,bool bUseDefault) const379 Optional<CXFA_Measurement> CJX_Object::TryMeasure(XFA_Attribute eAttr,
380                                                   bool bUseDefault) const {
381   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
382   Optional<CXFA_Measurement> result =
383       GetMapModuleMeasurementFollowingChain(key);
384   if (result.has_value())
385     return result.value();
386   if (!bUseDefault)
387     return pdfium::nullopt;
388   return GetXFANode()->GetDefaultMeasurement(eAttr);
389 }
390 
TryMeasureAsFloat(XFA_Attribute attr) const391 Optional<float> CJX_Object::TryMeasureAsFloat(XFA_Attribute attr) const {
392   Optional<CXFA_Measurement> measure = TryMeasure(attr, false);
393   if (!measure)
394     return pdfium::nullopt;
395   return measure->ToUnit(XFA_Unit::Pt);
396 }
397 
GetMeasure(XFA_Attribute eAttr) const398 CXFA_Measurement CJX_Object::GetMeasure(XFA_Attribute eAttr) const {
399   return TryMeasure(eAttr, true).value_or(CXFA_Measurement());
400 }
401 
GetMeasureInUnit(XFA_Attribute eAttr,XFA_Unit unit) const402 float CJX_Object::GetMeasureInUnit(XFA_Attribute eAttr, XFA_Unit unit) const {
403   return GetMeasure(eAttr).ToUnit(unit);
404 }
405 
GetCData(XFA_Attribute eAttr) const406 WideString CJX_Object::GetCData(XFA_Attribute eAttr) const {
407   return TryCData(eAttr, true).value_or(WideString());
408 }
409 
SetCData(XFA_Attribute eAttr,const WideString & wsValue)410 void CJX_Object::SetCData(XFA_Attribute eAttr, const WideString& wsValue) {
411   return SetCDataImpl(eAttr, wsValue, false, false);
412 }
413 
SetCDataImpl(XFA_Attribute eAttr,const WideString & wsValue,bool bNotify,bool bScriptModify)414 void CJX_Object::SetCDataImpl(XFA_Attribute eAttr,
415                               const WideString& wsValue,
416                               bool bNotify,
417                               bool bScriptModify) {
418   CXFA_Node* xfaObj = GetXFANode();
419   uint32_t key = GetMapKey_Element(xfaObj->GetElementType(), eAttr);
420   OnChanging(eAttr, bNotify);
421   SetMapModuleString(key, wsValue);
422   if (eAttr == XFA_Attribute::Name)
423     xfaObj->UpdateNameHash();
424   OnChanged(eAttr, bNotify, bScriptModify);
425 
426   if (!xfaObj->IsNeedSavingXMLNode() || eAttr == XFA_Attribute::QualifiedName ||
427       eAttr == XFA_Attribute::BindingNode) {
428     return;
429   }
430 
431   if (eAttr == XFA_Attribute::Name &&
432       (xfaObj->GetElementType() == XFA_Element::DataValue ||
433        xfaObj->GetElementType() == XFA_Element::DataGroup)) {
434     return;
435   }
436 
437   if (eAttr == XFA_Attribute::Value) {
438     xfaObj->SetToXML(wsValue);
439     return;
440   }
441 
442   WideString wsAttrName = WideString::FromASCII(XFA_AttributeToName(eAttr));
443   if (eAttr == XFA_Attribute::ContentType)
444     wsAttrName = L"xfa:" + wsAttrName;
445 
446   CFX_XMLElement* elem = ToXMLElement(xfaObj->GetXMLMappingNode());
447   elem->SetAttribute(wsAttrName, wsValue);
448   return;
449 }
450 
SetAttributeValue(const WideString & wsValue,const WideString & wsXMLValue)451 void CJX_Object::SetAttributeValue(const WideString& wsValue,
452                                    const WideString& wsXMLValue) {
453   SetAttributeValueImpl(wsValue, wsXMLValue, false, false);
454 }
455 
SetAttributeValueImpl(const WideString & wsValue,const WideString & wsXMLValue,bool bNotify,bool bScriptModify)456 void CJX_Object::SetAttributeValueImpl(const WideString& wsValue,
457                                        const WideString& wsXMLValue,
458                                        bool bNotify,
459                                        bool bScriptModify) {
460   auto* xfaObj = GetXFANode();
461   uint32_t key =
462       GetMapKey_Element(xfaObj->GetElementType(), XFA_Attribute::Value);
463 
464   OnChanging(XFA_Attribute::Value, bNotify);
465   SetMapModuleString(key, wsValue);
466   OnChanged(XFA_Attribute::Value, bNotify, bScriptModify);
467   if (xfaObj->IsNeedSavingXMLNode())
468     xfaObj->SetToXML(wsXMLValue);
469 }
470 
TryCData(XFA_Attribute eAttr,bool bUseDefault) const471 Optional<WideString> CJX_Object::TryCData(XFA_Attribute eAttr,
472                                           bool bUseDefault) const {
473   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
474   Optional<WideString> value = GetMapModuleStringFollowingChain(key);
475   if (value.has_value())
476     return value;
477 
478   if (!bUseDefault)
479     return pdfium::nullopt;
480   return GetXFANode()->GetDefaultCData(eAttr);
481 }
482 
SetValue(XFA_Attribute eAttr,int32_t value,bool bNotify)483 CFX_XMLElement* CJX_Object::SetValue(XFA_Attribute eAttr,
484                                      int32_t value,
485                                      bool bNotify) {
486   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
487   OnChanging(eAttr, bNotify);
488   SetMapModuleValue(key, value);
489   OnChanged(eAttr, bNotify, false);
490 
491   CXFA_Node* pNode = GetXFANode();
492   return pNode->IsNeedSavingXMLNode() ? ToXMLElement(pNode->GetXMLMappingNode())
493                                       : nullptr;
494 }
495 
SetContent(const WideString & wsContent,const WideString & wsXMLValue,bool bNotify,bool bScriptModify,bool bSyncData)496 void CJX_Object::SetContent(const WideString& wsContent,
497                             const WideString& wsXMLValue,
498                             bool bNotify,
499                             bool bScriptModify,
500                             bool bSyncData) {
501   CXFA_Node* pNode = nullptr;
502   CXFA_Node* pBindNode = nullptr;
503   switch (GetXFANode()->GetObjectType()) {
504     case XFA_ObjectType::ContainerNode: {
505       if (XFA_FieldIsMultiListBox(GetXFANode())) {
506         CXFA_Value* pValue =
507             GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
508         if (!pValue)
509           break;
510 
511         CXFA_Node* pChildValue = pValue->GetFirstChild();
512         pChildValue->JSObject()->SetCData(XFA_Attribute::ContentType,
513                                           L"text/xml");
514         pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
515                                             bScriptModify, false);
516 
517         CXFA_Node* pBind = GetXFANode()->GetBindData();
518         if (bSyncData && pBind) {
519           std::vector<WideString> wsSaveTextArray =
520               fxcrt::Split(wsContent, L'\n');
521           std::vector<CXFA_Node*> valueNodes =
522               pBind->GetNodeListForType(XFA_Element::DataValue);
523 
524           // Adusting node count might have side effects, do not trust that
525           // we'll ever actually get there.
526           size_t tries = 0;
527           while (valueNodes.size() != wsSaveTextArray.size()) {
528             if (++tries > 4)
529               return;
530             if (valueNodes.size() < wsSaveTextArray.size()) {
531               size_t iAddNodes = wsSaveTextArray.size() - valueNodes.size();
532               while (iAddNodes-- > 0) {
533                 CXFA_Node* pValueNodes =
534                     pBind->CreateSamePacketNode(XFA_Element::DataValue);
535                 pValueNodes->JSObject()->SetCData(XFA_Attribute::Name,
536                                                   L"value");
537                 pValueNodes->CreateXMLMappingNode();
538                 pBind->InsertChildAndNotify(pValueNodes, nullptr);
539               }
540             } else {
541               size_t iDelNodes = valueNodes.size() - wsSaveTextArray.size();
542               for (size_t i = 0; i < iDelNodes; ++i)
543                 pBind->RemoveChildAndNotify(valueNodes[i], true);
544             }
545             valueNodes = pBind->GetNodeListForType(XFA_Element::DataValue);
546           }
547           ASSERT(valueNodes.size() == wsSaveTextArray.size());
548           size_t i = 0;
549           for (CXFA_Node* pValueNode : valueNodes) {
550             pValueNode->JSObject()->SetAttributeValue(wsSaveTextArray[i],
551                                                       wsSaveTextArray[i]);
552             i++;
553           }
554           for (auto* pArrayNode : pBind->GetBindItemsCopy()) {
555             if (pArrayNode != GetXFANode()) {
556               pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
557                                                  bScriptModify, false);
558             }
559           }
560         }
561         break;
562       }
563       if (GetXFANode()->GetElementType() == XFA_Element::ExclGroup) {
564         pNode = GetXFANode();
565       } else {
566         CXFA_Value* pValue =
567             GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
568         if (!pValue)
569           break;
570 
571         CXFA_Node* pChildValue = pValue->GetFirstChild();
572         ASSERT(pChildValue);
573         pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
574                                             bScriptModify, false);
575       }
576       pBindNode = GetXFANode()->GetBindData();
577       if (pBindNode && bSyncData) {
578         pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
579                                           bScriptModify, false);
580         for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
581           if (pArrayNode != GetXFANode()) {
582             pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
583                                                true, false);
584           }
585         }
586       }
587       pBindNode = nullptr;
588       break;
589     }
590     case XFA_ObjectType::ContentNode: {
591       WideString wsContentType;
592       if (GetXFANode()->GetElementType() == XFA_Element::ExData) {
593         Optional<WideString> ret =
594             TryAttribute(XFA_Attribute::ContentType, false);
595         if (ret)
596           wsContentType = *ret;
597         if (wsContentType.EqualsASCII("text/html")) {
598           wsContentType.clear();
599           SetAttributeByEnum(XFA_Attribute::ContentType, wsContentType, false);
600         }
601       }
602 
603       CXFA_Node* pContentRawDataNode = GetXFANode()->GetFirstChild();
604       if (!pContentRawDataNode) {
605         pContentRawDataNode = GetXFANode()->CreateSamePacketNode(
606             wsContentType.EqualsASCII("text/xml") ? XFA_Element::Sharpxml
607                                                   : XFA_Element::Sharptext);
608         GetXFANode()->InsertChildAndNotify(pContentRawDataNode, nullptr);
609       }
610       pContentRawDataNode->JSObject()->SetContent(
611           wsContent, wsXMLValue, bNotify, bScriptModify, bSyncData);
612       return;
613     }
614     case XFA_ObjectType::NodeC:
615     case XFA_ObjectType::TextNode:
616       pNode = GetXFANode();
617       break;
618     case XFA_ObjectType::NodeV:
619       pNode = GetXFANode();
620       if (bSyncData && GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
621         CXFA_Node* pParent = GetXFANode()->GetParent();
622         if (pParent) {
623           pParent = pParent->GetParent();
624         }
625         if (pParent && pParent->GetElementType() == XFA_Element::Value) {
626           pParent = pParent->GetParent();
627           if (pParent && pParent->IsContainerNode()) {
628             pBindNode = pParent->GetBindData();
629             if (pBindNode) {
630               pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
631                                                 bScriptModify, false);
632             }
633           }
634         }
635       }
636       break;
637     default:
638       if (GetXFANode()->GetElementType() == XFA_Element::DataValue) {
639         pNode = GetXFANode();
640         pBindNode = GetXFANode();
641       }
642       break;
643   }
644   if (!pNode)
645     return;
646 
647   SetAttributeValueImpl(wsContent, wsXMLValue, bNotify, bScriptModify);
648   if (pBindNode && bSyncData) {
649     for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
650       pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
651                                          bScriptModify, false);
652     }
653   }
654 }
655 
GetContent(bool bScriptModify)656 WideString CJX_Object::GetContent(bool bScriptModify) {
657   return TryContent(bScriptModify, true).value_or(WideString());
658 }
659 
TryContent(bool bScriptModify,bool bProto)660 Optional<WideString> CJX_Object::TryContent(bool bScriptModify, bool bProto) {
661   CXFA_Node* pNode = nullptr;
662   switch (GetXFANode()->GetObjectType()) {
663     case XFA_ObjectType::ContainerNode:
664       if (GetXFANode()->GetElementType() == XFA_Element::ExclGroup) {
665         pNode = GetXFANode();
666       } else {
667         CXFA_Value* pValue =
668             GetXFANode()->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
669         if (!pValue)
670           return {};
671 
672         CXFA_Node* pChildValue = pValue->GetFirstChild();
673         if (pChildValue && XFA_FieldIsMultiListBox(GetXFANode())) {
674           pChildValue->JSObject()->SetAttributeByEnum(
675               XFA_Attribute::ContentType, L"text/xml", false);
676         }
677         if (pChildValue)
678           return pChildValue->JSObject()->TryContent(bScriptModify, bProto);
679         return {};
680       }
681       break;
682     case XFA_ObjectType::ContentNode: {
683       CXFA_Node* pContentRawDataNode = GetXFANode()->GetFirstChild();
684       if (!pContentRawDataNode) {
685         XFA_Element element = XFA_Element::Sharptext;
686         if (GetXFANode()->GetElementType() == XFA_Element::ExData) {
687           Optional<WideString> contentType =
688               TryAttribute(XFA_Attribute::ContentType, false);
689           if (contentType.has_value()) {
690             if (contentType.value().EqualsASCII("text/html"))
691               element = XFA_Element::SharpxHTML;
692             else if (contentType.value().EqualsASCII("text/xml"))
693               element = XFA_Element::Sharpxml;
694           }
695         }
696         pContentRawDataNode = GetXFANode()->CreateSamePacketNode(element);
697         GetXFANode()->InsertChildAndNotify(pContentRawDataNode, nullptr);
698       }
699       return pContentRawDataNode->JSObject()->TryContent(bScriptModify, true);
700     }
701     case XFA_ObjectType::NodeC:
702     case XFA_ObjectType::NodeV:
703     case XFA_ObjectType::TextNode:
704       pNode = GetXFANode();
705       FALLTHROUGH;
706     default:
707       if (GetXFANode()->GetElementType() == XFA_Element::DataValue)
708         pNode = GetXFANode();
709       break;
710   }
711   if (pNode) {
712     if (bScriptModify) {
713       CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
714       pScriptContext->AddNodesOfRunScript(GetXFANode());
715     }
716     return TryCData(XFA_Attribute::Value, false);
717   }
718   return {};
719 }
720 
TryNamespace()721 Optional<WideString> CJX_Object::TryNamespace() {
722   if (GetXFANode()->IsModelNode() ||
723       GetXFANode()->GetElementType() == XFA_Element::Packet) {
724     CFX_XMLNode* pXMLNode = GetXFANode()->GetXMLMappingNode();
725     CFX_XMLElement* element = ToXMLElement(pXMLNode);
726     if (!element)
727       return {};
728 
729     return element->GetNamespaceURI();
730   }
731 
732   if (GetXFANode()->GetPacketType() != XFA_PacketType::Datasets)
733     return GetXFANode()->GetModelNode()->JSObject()->TryNamespace();
734 
735   CFX_XMLNode* pXMLNode = GetXFANode()->GetXMLMappingNode();
736   CFX_XMLElement* element = ToXMLElement(pXMLNode);
737   if (!element)
738     return {};
739 
740   if (GetXFANode()->GetElementType() == XFA_Element::DataValue &&
741       GetEnum(XFA_Attribute::Contains) == XFA_AttributeValue::MetaData) {
742     WideString wsNamespace;
743     if (!XFA_FDEExtension_ResolveNamespaceQualifier(
744             element, GetCData(XFA_Attribute::QualifiedName), &wsNamespace)) {
745       return {};
746     }
747     return wsNamespace;
748   }
749   return element->GetNamespaceURI();
750 }
751 
GetPropertyInternal(int32_t index,XFA_Element eProperty) const752 std::pair<CXFA_Node*, int32_t> CJX_Object::GetPropertyInternal(
753     int32_t index,
754     XFA_Element eProperty) const {
755   return GetXFANode()->GetProperty(index, eProperty);
756 }
757 
GetOrCreatePropertyInternal(int32_t index,XFA_Element eProperty)758 CXFA_Node* CJX_Object::GetOrCreatePropertyInternal(int32_t index,
759                                                    XFA_Element eProperty) {
760   return GetXFANode()->GetOrCreateProperty(index, eProperty);
761 }
762 
CreateMapModule()763 CFXJSE_MapModule* CJX_Object::CreateMapModule() {
764   if (!map_module_)
765     map_module_ = std::make_unique<CFXJSE_MapModule>();
766   return map_module_.get();
767 }
768 
GetMapModule() const769 CFXJSE_MapModule* CJX_Object::GetMapModule() const {
770   return map_module_.get();
771 }
772 
SetMapModuleValue(uint32_t key,int32_t value)773 void CJX_Object::SetMapModuleValue(uint32_t key, int32_t value) {
774   CreateMapModule()->SetValue(key, value);
775 }
776 
SetMapModuleString(uint32_t key,const WideString & wsValue)777 void CJX_Object::SetMapModuleString(uint32_t key, const WideString& wsValue) {
778   CreateMapModule()->SetString(key, wsValue);
779 }
780 
SetMapModuleMeasurement(uint32_t key,const CXFA_Measurement & value)781 void CJX_Object::SetMapModuleMeasurement(uint32_t key,
782                                          const CXFA_Measurement& value) {
783   CreateMapModule()->SetMeasurement(key, value);
784 }
785 
GetMapModuleValue(uint32_t key) const786 Optional<int32_t> CJX_Object::GetMapModuleValue(uint32_t key) const {
787   CFXJSE_MapModule* pModule = GetMapModule();
788   if (!pModule)
789     return pdfium::nullopt;
790   return pModule->GetValue(key);
791 }
792 
GetMapModuleString(uint32_t key) const793 Optional<WideString> CJX_Object::GetMapModuleString(uint32_t key) const {
794   CFXJSE_MapModule* pModule = GetMapModule();
795   if (!pModule)
796     return pdfium::nullopt;
797   return pModule->GetString(key);
798 }
799 
GetMapModuleMeasurement(uint32_t key) const800 Optional<CXFA_Measurement> CJX_Object::GetMapModuleMeasurement(
801     uint32_t key) const {
802   CFXJSE_MapModule* pModule = GetMapModule();
803   if (!pModule)
804     return pdfium::nullopt;
805   return pModule->GetMeasurement(key);
806 }
807 
GetMapModuleValueFollowingChain(uint32_t key) const808 Optional<int32_t> CJX_Object::GetMapModuleValueFollowingChain(
809     uint32_t key) const {
810   std::set<const CXFA_Node*> visited;
811   for (const CXFA_Node* pNode = GetXFANode(); pNode;
812        pNode = pNode->GetTemplateNodeIfExists()) {
813     if (!visited.insert(pNode).second)
814       break;
815 
816     Optional<int32_t> result = pNode->JSObject()->GetMapModuleValue(key);
817     if (result.has_value())
818       return result;
819 
820     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
821       break;
822   }
823   return pdfium::nullopt;
824 }
825 
GetMapModuleStringFollowingChain(uint32_t key) const826 Optional<WideString> CJX_Object::GetMapModuleStringFollowingChain(
827     uint32_t key) const {
828   std::set<const CXFA_Node*> visited;
829   for (const CXFA_Node* pNode = GetXFANode(); pNode;
830        pNode = pNode->GetTemplateNodeIfExists()) {
831     if (!visited.insert(pNode).second)
832       break;
833 
834     Optional<WideString> result = pNode->JSObject()->GetMapModuleString(key);
835     if (result.has_value())
836       return result;
837 
838     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
839       break;
840   }
841   return pdfium::nullopt;
842 }
843 
GetMapModuleMeasurementFollowingChain(uint32_t key) const844 Optional<CXFA_Measurement> CJX_Object::GetMapModuleMeasurementFollowingChain(
845     uint32_t key) const {
846   std::set<const CXFA_Node*> visited;
847   for (const CXFA_Node* pNode = GetXFANode(); pNode;
848        pNode = pNode->GetTemplateNodeIfExists()) {
849     if (!visited.insert(pNode).second)
850       break;
851 
852     Optional<CXFA_Measurement> result =
853         pNode->JSObject()->GetMapModuleMeasurement(key);
854     if (result.has_value())
855       return result;
856 
857     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
858       break;
859   }
860   return pdfium::nullopt;
861 }
862 
HasMapModuleKey(uint32_t key)863 bool CJX_Object::HasMapModuleKey(uint32_t key) {
864   CFXJSE_MapModule* pModule = GetMapModule();
865   return pModule && pModule->HasKey(key);
866 }
867 
RemoveMapModuleKey(uint32_t key)868 void CJX_Object::RemoveMapModuleKey(uint32_t key) {
869   CFXJSE_MapModule* pModule = GetMapModule();
870   if (pModule)
871     pModule->RemoveKey(key);
872 }
873 
MergeAllData(CXFA_Object * pDstObj)874 void CJX_Object::MergeAllData(CXFA_Object* pDstObj) {
875   CFXJSE_MapModule* pDstModule = ToNode(pDstObj)->JSObject()->CreateMapModule();
876   CFXJSE_MapModule* pSrcModule = GetMapModule();
877   if (!pSrcModule)
878     return;
879 
880   pDstModule->MergeDataFrom(pSrcModule);
881 }
882 
MoveBufferMapData(CXFA_Object * pDstObj)883 void CJX_Object::MoveBufferMapData(CXFA_Object* pDstObj) {
884   if (!pDstObj)
885     return;
886 
887   if (pDstObj->GetElementType() == GetXFAObject()->GetElementType())
888     ToNode(pDstObj)->JSObject()->TakeCalcDataFrom(this);
889 
890   if (!pDstObj->IsNodeV())
891     return;
892 
893   WideString wsValue = ToNode(pDstObj)->JSObject()->GetContent(false);
894   WideString wsFormatValue(wsValue);
895   CXFA_Node* pNode = ToNode(pDstObj)->GetContainerNode();
896   if (pNode)
897     wsFormatValue = pNode->GetFormatDataValue(wsValue);
898 
899   ToNode(pDstObj)->JSObject()->SetContent(wsValue, wsFormatValue, true, true,
900                                           true);
901 }
902 
MoveBufferMapData(CXFA_Object * pSrcObj,CXFA_Object * pDstObj)903 void CJX_Object::MoveBufferMapData(CXFA_Object* pSrcObj, CXFA_Object* pDstObj) {
904   if (!pSrcObj || !pDstObj)
905     return;
906 
907   CXFA_Node* pSrcChild = ToNode(pSrcObj)->GetFirstChild();
908   CXFA_Node* pDstChild = ToNode(pDstObj)->GetFirstChild();
909   while (pSrcChild && pDstChild) {
910     MoveBufferMapData(pSrcChild, pDstChild);
911     pSrcChild = pSrcChild->GetNextSibling();
912     pDstChild = pDstChild->GetNextSibling();
913   }
914   ToNode(pSrcObj)->JSObject()->MoveBufferMapData(pDstObj);
915 }
916 
OnChanging(XFA_Attribute eAttr,bool bNotify)917 void CJX_Object::OnChanging(XFA_Attribute eAttr, bool bNotify) {
918   if (!bNotify || !GetXFANode()->IsInitialized())
919     return;
920 
921   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
922   if (pNotify)
923     pNotify->OnValueChanging(GetXFANode(), eAttr);
924 }
925 
OnChanged(XFA_Attribute eAttr,bool bNotify,bool bScriptModify)926 void CJX_Object::OnChanged(XFA_Attribute eAttr,
927                            bool bNotify,
928                            bool bScriptModify) {
929   if (bNotify && GetXFANode()->IsInitialized())
930     GetXFANode()->SendAttributeChangeMessage(eAttr, bScriptModify);
931 }
932 
GetOrCreateCalcData(cppgc::Heap * heap)933 CJX_Object::CalcData* CJX_Object::GetOrCreateCalcData(cppgc::Heap* heap) {
934   if (!calc_data_) {
935     calc_data_ =
936         cppgc::MakeGarbageCollected<CalcData>(heap->GetAllocationHandle());
937   }
938   return calc_data_;
939 }
940 
TakeCalcDataFrom(CJX_Object * that)941 void CJX_Object::TakeCalcDataFrom(CJX_Object* that) {
942   calc_data_ = that->calc_data_;
943   that->calc_data_ = nullptr;
944 }
945 
ScriptAttributeString(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)946 void CJX_Object::ScriptAttributeString(v8::Isolate* pIsolate,
947                                        CFXJSE_Value* pValue,
948                                        bool bSetting,
949                                        XFA_Attribute eAttribute) {
950   if (!bSetting) {
951     pValue->SetString(pIsolate,
952                       GetAttributeByEnum(eAttribute).ToUTF8().AsStringView());
953     return;
954   }
955 
956   WideString wsValue = pValue->ToWideString(pIsolate);
957   SetAttributeByEnum(eAttribute, wsValue, true);
958   if (eAttribute != XFA_Attribute::Use ||
959       GetXFAObject()->GetElementType() != XFA_Element::Desc) {
960     return;
961   }
962 
963   CXFA_Node* pTemplateNode =
964       ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Template));
965   CXFA_Subform* pSubForm =
966       pTemplateNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
967   CXFA_Proto* pProtoRoot =
968       pSubForm ? pSubForm->GetFirstChildByClass<CXFA_Proto>(XFA_Element::Proto)
969                : nullptr;
970 
971   WideString wsID;
972   WideString wsSOM;
973   if (!wsValue.IsEmpty()) {
974     if (wsValue[0] == '#')
975       wsID = wsValue.Substr(1, wsValue.GetLength() - 1);
976     else
977       wsSOM = std::move(wsValue);
978   }
979 
980   CXFA_Node* pProtoNode = nullptr;
981   if (!wsSOM.IsEmpty()) {
982     XFA_ResolveNodeRS resolveNodeRS;
983     bool bRet = GetDocument()->GetScriptContext()->ResolveObjects(
984         pProtoRoot, wsSOM.AsStringView(), &resolveNodeRS,
985         XFA_RESOLVENODE_Children | XFA_RESOLVENODE_Attributes |
986             XFA_RESOLVENODE_Properties | XFA_RESOLVENODE_Parent |
987             XFA_RESOLVENODE_Siblings,
988         nullptr);
989     if (bRet && resolveNodeRS.objects.front()->IsNode())
990       pProtoNode = resolveNodeRS.objects.front()->AsNode();
991 
992   } else if (!wsID.IsEmpty()) {
993     pProtoNode = GetDocument()->GetNodeByID(pProtoRoot, wsID.AsStringView());
994   }
995   if (!pProtoNode)
996     return;
997 
998   CXFA_Node* pHeadChild = GetXFANode()->GetFirstChild();
999   while (pHeadChild) {
1000     CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1001     GetXFANode()->RemoveChildAndNotify(pHeadChild, true);
1002     pHeadChild = pSibling;
1003   }
1004 
1005   CXFA_Node* pProtoForm = pProtoNode->CloneTemplateToForm(true);
1006   pHeadChild = pProtoForm->GetFirstChild();
1007   while (pHeadChild) {
1008     CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1009     pProtoForm->RemoveChildAndNotify(pHeadChild, true);
1010     GetXFANode()->InsertChildAndNotify(pHeadChild, nullptr);
1011     pHeadChild = pSibling;
1012   }
1013 }
1014 
ScriptAttributeBool(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1015 void CJX_Object::ScriptAttributeBool(v8::Isolate* pIsolate,
1016                                      CFXJSE_Value* pValue,
1017                                      bool bSetting,
1018                                      XFA_Attribute eAttribute) {
1019   if (bSetting) {
1020     SetBoolean(eAttribute, pValue->ToBoolean(pIsolate), true);
1021     return;
1022   }
1023   pValue->SetString(pIsolate, GetBoolean(eAttribute) ? "1" : "0");
1024 }
1025 
ScriptAttributeInteger(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1026 void CJX_Object::ScriptAttributeInteger(v8::Isolate* pIsolate,
1027                                         CFXJSE_Value* pValue,
1028                                         bool bSetting,
1029                                         XFA_Attribute eAttribute) {
1030   if (bSetting) {
1031     SetInteger(eAttribute, pValue->ToInteger(pIsolate), true);
1032     return;
1033   }
1034   pValue->SetInteger(pIsolate, GetInteger(eAttribute));
1035 }
1036 
ScriptSomFontColor(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1037 void CJX_Object::ScriptSomFontColor(v8::Isolate* pIsolate,
1038                                     CFXJSE_Value* pValue,
1039                                     bool bSetting,
1040                                     XFA_Attribute eAttribute) {
1041   CXFA_Font* font = ToNode(object_.Get())->GetOrCreateFontIfPossible();
1042   if (!font)
1043     return;
1044 
1045   if (bSetting) {
1046     int32_t r;
1047     int32_t g;
1048     int32_t b;
1049     std::tie(r, g, b) = StrToRGB(pValue->ToWideString(pIsolate));
1050     FX_ARGB color = ArgbEncode(0xff, r, g, b);
1051     font->SetColor(color);
1052     return;
1053   }
1054 
1055   int32_t a;
1056   int32_t r;
1057   int32_t g;
1058   int32_t b;
1059   std::tie(a, r, g, b) = ArgbDecode(font->GetColor());
1060   pValue->SetString(pIsolate,
1061                     ByteString::Format("%d,%d,%d", r, g, b).AsStringView());
1062 }
1063 
ScriptSomFillColor(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1064 void CJX_Object::ScriptSomFillColor(v8::Isolate* pIsolate,
1065                                     CFXJSE_Value* pValue,
1066                                     bool bSetting,
1067                                     XFA_Attribute eAttribute) {
1068   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1069   CXFA_Fill* borderfill = border->GetOrCreateFillIfPossible();
1070   if (!borderfill)
1071     return;
1072 
1073   if (bSetting) {
1074     int32_t r;
1075     int32_t g;
1076     int32_t b;
1077     std::tie(r, g, b) = StrToRGB(pValue->ToWideString(pIsolate));
1078     FX_ARGB color = ArgbEncode(0xff, r, g, b);
1079     borderfill->SetColor(color);
1080     return;
1081   }
1082 
1083   FX_ARGB color = borderfill->GetColor(false);
1084   int32_t a;
1085   int32_t r;
1086   int32_t g;
1087   int32_t b;
1088   std::tie(a, r, g, b) = ArgbDecode(color);
1089   pValue->SetString(
1090       pIsolate,
1091       WideString::Format(L"%d,%d,%d", r, g, b).ToUTF8().AsStringView());
1092 }
1093 
ScriptSomBorderColor(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1094 void CJX_Object::ScriptSomBorderColor(v8::Isolate* pIsolate,
1095                                       CFXJSE_Value* pValue,
1096                                       bool bSetting,
1097                                       XFA_Attribute eAttribute) {
1098   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1099   int32_t iSize = border->CountEdges();
1100   if (bSetting) {
1101     int32_t r = 0;
1102     int32_t g = 0;
1103     int32_t b = 0;
1104     std::tie(r, g, b) = StrToRGB(pValue->ToWideString(pIsolate));
1105     FX_ARGB rgb = ArgbEncode(100, r, g, b);
1106     for (int32_t i = 0; i < iSize; ++i) {
1107       CXFA_Edge* edge = border->GetEdgeIfExists(i);
1108       if (edge)
1109         edge->SetColor(rgb);
1110     }
1111 
1112     return;
1113   }
1114 
1115   CXFA_Edge* edge = border->GetEdgeIfExists(0);
1116   FX_ARGB color = edge ? edge->GetColor() : CXFA_Edge::kDefaultColor;
1117   int32_t a;
1118   int32_t r;
1119   int32_t g;
1120   int32_t b;
1121   std::tie(a, r, g, b) = ArgbDecode(color);
1122   pValue->SetString(
1123       pIsolate,
1124       WideString::Format(L"%d,%d,%d", r, g, b).ToUTF8().AsStringView());
1125 }
1126 
ScriptSomBorderWidth(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1127 void CJX_Object::ScriptSomBorderWidth(v8::Isolate* pIsolate,
1128                                       CFXJSE_Value* pValue,
1129                                       bool bSetting,
1130                                       XFA_Attribute eAttribute) {
1131   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1132   if (bSetting) {
1133     CXFA_Edge* edge = border->GetEdgeIfExists(0);
1134     CXFA_Measurement thickness =
1135         edge ? edge->GetMSThickness() : CXFA_Measurement(0.5, XFA_Unit::Pt);
1136     pValue->SetString(pIsolate, thickness.ToString().ToUTF8().AsStringView());
1137     return;
1138   }
1139 
1140   if (pValue->IsEmpty())
1141     return;
1142 
1143   WideString wsThickness = pValue->ToWideString(pIsolate);
1144   for (int32_t i = 0; i < border->CountEdges(); ++i) {
1145     CXFA_Edge* edge = border->GetEdgeIfExists(i);
1146     if (edge)
1147       edge->SetMSThickness(CXFA_Measurement(wsThickness.AsStringView()));
1148   }
1149 }
1150 
ScriptSomMessage(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_SOM_MESSAGETYPE iMessageType)1151 void CJX_Object::ScriptSomMessage(v8::Isolate* pIsolate,
1152                                   CFXJSE_Value* pValue,
1153                                   bool bSetting,
1154                                   XFA_SOM_MESSAGETYPE iMessageType) {
1155   bool bNew = false;
1156   CXFA_Validate* validate = ToNode(object_.Get())->GetValidateIfExists();
1157   if (!validate) {
1158     validate = ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1159     bNew = true;
1160   }
1161 
1162   if (bSetting) {
1163     if (validate) {
1164       switch (iMessageType) {
1165         case XFA_SOM_ValidationMessage:
1166           validate->SetScriptMessageText(pValue->ToWideString(pIsolate));
1167           break;
1168         case XFA_SOM_FormatMessage:
1169           validate->SetFormatMessageText(pValue->ToWideString(pIsolate));
1170           break;
1171         case XFA_SOM_MandatoryMessage:
1172           validate->SetNullMessageText(pValue->ToWideString(pIsolate));
1173           break;
1174         default:
1175           break;
1176       }
1177     }
1178 
1179     if (!bNew) {
1180       CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1181       if (!pNotify)
1182         return;
1183 
1184       pNotify->AddCalcValidate(GetXFANode());
1185     }
1186     return;
1187   }
1188 
1189   if (!validate) {
1190     // TODO(dsinclair): Better error message?
1191     ThrowInvalidPropertyException();
1192     return;
1193   }
1194 
1195   WideString wsMessage;
1196   switch (iMessageType) {
1197     case XFA_SOM_ValidationMessage:
1198       wsMessage = validate->GetScriptMessageText();
1199       break;
1200     case XFA_SOM_FormatMessage:
1201       wsMessage = validate->GetFormatMessageText();
1202       break;
1203     case XFA_SOM_MandatoryMessage:
1204       wsMessage = validate->GetNullMessageText();
1205       break;
1206     default:
1207       break;
1208   }
1209   pValue->SetString(pIsolate, wsMessage.ToUTF8().AsStringView());
1210 }
1211 
ScriptSomValidationMessage(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1212 void CJX_Object::ScriptSomValidationMessage(v8::Isolate* pIsolate,
1213                                             CFXJSE_Value* pValue,
1214                                             bool bSetting,
1215                                             XFA_Attribute eAttribute) {
1216   ScriptSomMessage(pIsolate, pValue, bSetting, XFA_SOM_ValidationMessage);
1217 }
1218 
ScriptSomMandatoryMessage(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1219 void CJX_Object::ScriptSomMandatoryMessage(v8::Isolate* pIsolate,
1220                                            CFXJSE_Value* pValue,
1221                                            bool bSetting,
1222                                            XFA_Attribute eAttribute) {
1223   ScriptSomMessage(pIsolate, pValue, bSetting, XFA_SOM_MandatoryMessage);
1224 }
1225 
ScriptSomDefaultValue(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute)1226 void CJX_Object::ScriptSomDefaultValue(v8::Isolate* pIsolate,
1227                                        CFXJSE_Value* pValue,
1228                                        bool bSetting,
1229                                        XFA_Attribute /* unused */) {
1230   XFA_Element eType = GetXFANode()->GetElementType();
1231 
1232   // TODO(dsinclair): This should look through the properties on the node to see
1233   // if defaultValue is defined and, if so, call that one. Just have to make
1234   // sure that those defaultValue calls don't call back to this one ....
1235   if (eType == XFA_Element::Field) {
1236     static_cast<CJX_Field*>(this)->defaultValue(pIsolate, pValue, bSetting,
1237                                                 XFA_Attribute::Unknown);
1238     return;
1239   }
1240   if (eType == XFA_Element::Draw) {
1241     static_cast<CJX_Draw*>(this)->defaultValue(pIsolate, pValue, bSetting,
1242                                                XFA_Attribute::Unknown);
1243     return;
1244   }
1245   if (eType == XFA_Element::Boolean) {
1246     static_cast<CJX_Boolean*>(this)->defaultValue(pIsolate, pValue, bSetting,
1247                                                   XFA_Attribute::Unknown);
1248     return;
1249   }
1250 
1251   if (bSetting) {
1252     WideString wsNewValue;
1253     if (pValue && !(pValue->IsEmpty() || pValue->IsNull(pIsolate) ||
1254                     pValue->IsUndefined(pIsolate))) {
1255       wsNewValue = pValue->ToWideString(pIsolate);
1256     }
1257 
1258     WideString wsFormatValue(wsNewValue);
1259     CXFA_Node* pContainerNode = nullptr;
1260     if (GetXFANode()->GetPacketType() == XFA_PacketType::Datasets) {
1261       WideString wsPicture;
1262       for (auto* pFormNode : GetXFANode()->GetBindItemsCopy()) {
1263         if (!pFormNode || pFormNode->HasRemovedChildren())
1264           continue;
1265 
1266         pContainerNode = pFormNode->GetContainerNode();
1267         if (pContainerNode) {
1268           wsPicture =
1269               pContainerNode->GetPictureContent(XFA_VALUEPICTURE_DataBind);
1270         }
1271         if (!wsPicture.IsEmpty())
1272           break;
1273 
1274         pContainerNode = nullptr;
1275       }
1276     } else if (GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
1277       pContainerNode = GetXFANode()->GetContainerNode();
1278     }
1279 
1280     if (pContainerNode)
1281       wsFormatValue = pContainerNode->GetFormatDataValue(wsNewValue);
1282 
1283     SetContent(wsNewValue, wsFormatValue, true, true, true);
1284     return;
1285   }
1286 
1287   WideString content = GetContent(true);
1288   if (content.IsEmpty() && eType != XFA_Element::Text &&
1289       eType != XFA_Element::SubmitUrl) {
1290     pValue->SetNull(pIsolate);
1291   } else if (eType == XFA_Element::Integer) {
1292     pValue->SetInteger(pIsolate, FXSYS_wtoi(content.c_str()));
1293   } else if (eType == XFA_Element::Float || eType == XFA_Element::Decimal) {
1294     CFGAS_Decimal decimal(content.AsStringView());
1295     pValue->SetFloat(pIsolate, decimal.ToFloat());
1296   } else {
1297     pValue->SetString(pIsolate, content.ToUTF8().AsStringView());
1298   }
1299 }
1300 
ScriptSomDefaultValue_Read(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1301 void CJX_Object::ScriptSomDefaultValue_Read(v8::Isolate* pIsolate,
1302                                             CFXJSE_Value* pValue,
1303                                             bool bSetting,
1304                                             XFA_Attribute eAttribute) {
1305   if (bSetting) {
1306     ThrowInvalidPropertyException();
1307     return;
1308   }
1309 
1310   WideString content = GetContent(true);
1311   if (content.IsEmpty()) {
1312     pValue->SetNull(pIsolate);
1313     return;
1314   }
1315   pValue->SetString(pIsolate, content.ToUTF8().AsStringView());
1316 }
1317 
ScriptSomDataNode(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1318 void CJX_Object::ScriptSomDataNode(v8::Isolate* pIsolate,
1319                                    CFXJSE_Value* pValue,
1320                                    bool bSetting,
1321                                    XFA_Attribute eAttribute) {
1322   if (bSetting) {
1323     ThrowInvalidPropertyException();
1324     return;
1325   }
1326 
1327   CXFA_Node* pDataNode = GetXFANode()->GetBindData();
1328   if (!pDataNode) {
1329     pValue->SetNull(pIsolate);
1330     return;
1331   }
1332 
1333   pValue->ForceSetValue(
1334       pIsolate, GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(
1335                     pDataNode));
1336 }
1337 
ScriptSomMandatory(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1338 void CJX_Object::ScriptSomMandatory(v8::Isolate* pIsolate,
1339                                     CFXJSE_Value* pValue,
1340                                     bool bSetting,
1341                                     XFA_Attribute eAttribute) {
1342   CXFA_Validate* validate =
1343       ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1344   if (!validate)
1345     return;
1346 
1347   if (bSetting) {
1348     validate->SetNullTest(pValue->ToWideString(pIsolate));
1349     return;
1350   }
1351 
1352   pValue->SetString(pIsolate,
1353                     XFA_AttributeValueToName(validate->GetNullTest()));
1354 }
1355 
ScriptSomInstanceIndex(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1356 void CJX_Object::ScriptSomInstanceIndex(v8::Isolate* pIsolate,
1357                                         CFXJSE_Value* pValue,
1358                                         bool bSetting,
1359                                         XFA_Attribute eAttribute) {
1360   if (!bSetting) {
1361     pValue->SetInteger(pIsolate, Subform_and_SubformSet_InstanceIndex());
1362     return;
1363   }
1364 
1365   int32_t iTo = pValue->ToInteger(pIsolate);
1366   int32_t iFrom = Subform_and_SubformSet_InstanceIndex();
1367   CXFA_Node* pManagerNode = nullptr;
1368   for (CXFA_Node* pNode = GetXFANode()->GetPrevSibling(); pNode;
1369        pNode = pNode->GetPrevSibling()) {
1370     if (pNode->GetElementType() == XFA_Element::InstanceManager) {
1371       pManagerNode = pNode;
1372       break;
1373     }
1374   }
1375   if (!pManagerNode)
1376     return;
1377 
1378   auto* mgr = static_cast<CJX_InstanceManager*>(pManagerNode->JSObject());
1379   mgr->MoveInstance(iTo, iFrom);
1380   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1381   if (!pNotify)
1382     return;
1383 
1384   CXFA_Node* pToInstance = pManagerNode->GetItemIfExists(iTo);
1385   if (pToInstance && pToInstance->GetElementType() == XFA_Element::Subform) {
1386     pNotify->RunSubformIndexChange(pToInstance);
1387   }
1388 
1389   CXFA_Node* pFromInstance = pManagerNode->GetItemIfExists(iFrom);
1390   if (pFromInstance &&
1391       pFromInstance->GetElementType() == XFA_Element::Subform) {
1392     pNotify->RunSubformIndexChange(pFromInstance);
1393   }
1394 }
1395 
ScriptSubmitFormatMode(v8::Isolate * pIsolate,CFXJSE_Value * pValue,bool bSetting,XFA_Attribute eAttribute)1396 void CJX_Object::ScriptSubmitFormatMode(v8::Isolate* pIsolate,
1397                                         CFXJSE_Value* pValue,
1398                                         bool bSetting,
1399                                         XFA_Attribute eAttribute) {}
1400 
1401 CJX_Object::CalcData::CalcData() = default;
1402 
1403 CJX_Object::CalcData::~CalcData() = default;
1404 
Trace(cppgc::Visitor * visitor) const1405 void CJX_Object::CalcData::Trace(cppgc::Visitor* visitor) const {
1406   ContainerTrace(visitor, m_Globals);
1407 }
1408