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