xref: /aosp_15_r20/external/pdfium/fxjs/xfa/cjx_object.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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(CFXJSE_Engine * pScriptContext,const WideString & func,const std::vector<v8::Local<v8::Value>> & params)161 CJS_Result CJX_Object::RunMethod(
162     CFXJSE_Engine* pScriptContext,
163     const WideString& func,
164     const std::vector<v8::Local<v8::Value>>& params) {
165   auto it = method_specs_.find(func.ToUTF8());
166   if (it == method_specs_.end())
167     return CJS_Result::Failure(JSMessage::kUnknownMethod);
168 
169   return it->second(this, pScriptContext, 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   }
245 }
246 
SetAttributeByString(WideStringView wsAttr,const WideString & wsValue)247 void CJX_Object::SetAttributeByString(WideStringView wsAttr,
248                                       const WideString& wsValue) {
249   absl::optional<XFA_ATTRIBUTEINFO> attr = XFA_GetAttributeByName(wsAttr);
250   if (attr.has_value()) {
251     SetAttributeByEnum(attr.value().attribute, wsValue, true);
252     return;
253   }
254   uint32_t key = GetMapKey_Custom(wsAttr);
255   SetMapModuleString(key, wsValue);
256 }
257 
GetAttributeByString(WideStringView attr) const258 WideString CJX_Object::GetAttributeByString(WideStringView attr) const {
259   absl::optional<WideString> result;
260   absl::optional<XFA_ATTRIBUTEINFO> enum_attr = XFA_GetAttributeByName(attr);
261   if (enum_attr.has_value())
262     result = TryAttribute(enum_attr.value().attribute, true);
263   else
264     result = GetMapModuleStringFollowingChain(GetMapKey_Custom(attr));
265   return result.value_or(WideString());
266 }
267 
GetAttributeByEnum(XFA_Attribute attr) const268 WideString CJX_Object::GetAttributeByEnum(XFA_Attribute attr) const {
269   return TryAttribute(attr, true).value_or(WideString());
270 }
271 
TryAttribute(XFA_Attribute eAttr,bool bUseDefault) const272 absl::optional<WideString> CJX_Object::TryAttribute(XFA_Attribute eAttr,
273                                                     bool bUseDefault) const {
274   switch (GetXFANode()->GetAttributeType(eAttr)) {
275     case XFA_AttributeType::Enum: {
276       absl::optional<XFA_AttributeValue> value = TryEnum(eAttr, bUseDefault);
277       if (!value.has_value())
278         return absl::nullopt;
279       return WideString::FromASCII(XFA_AttributeValueToName(value.value()));
280     }
281     case XFA_AttributeType::CData:
282       return TryCData(eAttr, bUseDefault);
283 
284     case XFA_AttributeType::Boolean: {
285       absl::optional<bool> value = TryBoolean(eAttr, bUseDefault);
286       if (!value.has_value())
287         return absl::nullopt;
288       return WideString(value.value() ? L"1" : L"0");
289     }
290     case XFA_AttributeType::Integer: {
291       absl::optional<int32_t> iValue = TryInteger(eAttr, bUseDefault);
292       if (!iValue.has_value())
293         return absl::nullopt;
294       return WideString::FormatInteger(iValue.value());
295     }
296     case XFA_AttributeType::Measure: {
297       absl::optional<CXFA_Measurement> value = TryMeasure(eAttr, bUseDefault);
298       if (!value.has_value())
299         return absl::nullopt;
300       return value->ToString();
301     }
302   }
303   return absl::nullopt;
304 }
305 
RemoveAttribute(WideStringView wsAttr)306 void CJX_Object::RemoveAttribute(WideStringView wsAttr) {
307   RemoveMapModuleKey(GetMapKey_Custom(wsAttr));
308 }
309 
TryBoolean(XFA_Attribute eAttr,bool bUseDefault) const310 absl::optional<bool> CJX_Object::TryBoolean(XFA_Attribute eAttr,
311                                             bool bUseDefault) const {
312   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
313   absl::optional<int32_t> value = GetMapModuleValueFollowingChain(key);
314   if (value.has_value())
315     return !!value.value();
316   if (!bUseDefault)
317     return absl::nullopt;
318   return GetXFANode()->GetDefaultBoolean(eAttr);
319 }
320 
SetBoolean(XFA_Attribute eAttr,bool bValue,bool bNotify)321 void CJX_Object::SetBoolean(XFA_Attribute eAttr, bool bValue, bool bNotify) {
322   CFX_XMLElement* elem = SetValue(eAttr, static_cast<int32_t>(bValue), bNotify);
323   if (elem) {
324     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
325                        bValue ? L"1" : L"0");
326   }
327 }
328 
GetBoolean(XFA_Attribute eAttr) const329 bool CJX_Object::GetBoolean(XFA_Attribute eAttr) const {
330   return TryBoolean(eAttr, true).value_or(false);
331 }
332 
SetInteger(XFA_Attribute eAttr,int32_t iValue,bool bNotify)333 void CJX_Object::SetInteger(XFA_Attribute eAttr, int32_t iValue, bool bNotify) {
334   CFX_XMLElement* elem = SetValue(eAttr, iValue, bNotify);
335   if (elem) {
336     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
337                        WideString::FormatInteger(iValue));
338   }
339 }
340 
GetInteger(XFA_Attribute eAttr) const341 int32_t CJX_Object::GetInteger(XFA_Attribute eAttr) const {
342   return TryInteger(eAttr, true).value_or(0);
343 }
344 
TryInteger(XFA_Attribute eAttr,bool bUseDefault) const345 absl::optional<int32_t> CJX_Object::TryInteger(XFA_Attribute eAttr,
346                                                bool bUseDefault) const {
347   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
348   absl::optional<int32_t> value = GetMapModuleValueFollowingChain(key);
349   if (value.has_value())
350     return value.value();
351   if (!bUseDefault)
352     return absl::nullopt;
353   return GetXFANode()->GetDefaultInteger(eAttr);
354 }
355 
TryEnum(XFA_Attribute eAttr,bool bUseDefault) const356 absl::optional<XFA_AttributeValue> CJX_Object::TryEnum(XFA_Attribute eAttr,
357                                                        bool bUseDefault) const {
358   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
359   absl::optional<int32_t> value = GetMapModuleValueFollowingChain(key);
360   if (value.has_value())
361     return static_cast<XFA_AttributeValue>(value.value());
362   if (!bUseDefault)
363     return absl::nullopt;
364   return GetXFANode()->GetDefaultEnum(eAttr);
365 }
366 
SetEnum(XFA_Attribute eAttr,XFA_AttributeValue eValue,bool bNotify)367 void CJX_Object::SetEnum(XFA_Attribute eAttr,
368                          XFA_AttributeValue eValue,
369                          bool bNotify) {
370   CFX_XMLElement* elem = SetValue(eAttr, static_cast<int32_t>(eValue), bNotify);
371   if (elem) {
372     elem->SetAttribute(WideString::FromASCII(XFA_AttributeToName(eAttr)),
373                        WideString::FromASCII(XFA_AttributeValueToName(eValue)));
374   }
375 }
376 
GetEnum(XFA_Attribute eAttr) const377 XFA_AttributeValue CJX_Object::GetEnum(XFA_Attribute eAttr) const {
378   return TryEnum(eAttr, true).value_or(XFA_AttributeValue::Unknown);
379 }
380 
SetMeasure(XFA_Attribute eAttr,const CXFA_Measurement & mValue,bool bNotify)381 void CJX_Object::SetMeasure(XFA_Attribute eAttr,
382                             const CXFA_Measurement& mValue,
383                             bool bNotify) {
384   // Can't short-circuit update here when the value is the same since it
385   // might have come from further up the chain from where we are setting it.
386   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
387   if (bNotify)
388     OnChanging(eAttr);
389   SetMapModuleMeasurement(key, mValue);
390   if (bNotify)
391     OnChanged(eAttr, false);
392 }
393 
TryMeasure(XFA_Attribute eAttr,bool bUseDefault) const394 absl::optional<CXFA_Measurement> CJX_Object::TryMeasure(
395     XFA_Attribute eAttr,
396     bool bUseDefault) const {
397   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
398   absl::optional<CXFA_Measurement> result =
399       GetMapModuleMeasurementFollowingChain(key);
400   if (result.has_value())
401     return result.value();
402   if (!bUseDefault)
403     return absl::nullopt;
404   return GetXFANode()->GetDefaultMeasurement(eAttr);
405 }
406 
TryMeasureAsFloat(XFA_Attribute attr) const407 absl::optional<float> CJX_Object::TryMeasureAsFloat(XFA_Attribute attr) const {
408   absl::optional<CXFA_Measurement> measure = TryMeasure(attr, false);
409   if (!measure.has_value())
410     return absl::nullopt;
411   return measure->ToUnit(XFA_Unit::Pt);
412 }
413 
GetMeasure(XFA_Attribute eAttr) const414 CXFA_Measurement CJX_Object::GetMeasure(XFA_Attribute eAttr) const {
415   return TryMeasure(eAttr, true).value_or(CXFA_Measurement());
416 }
417 
GetMeasureInUnit(XFA_Attribute eAttr,XFA_Unit unit) const418 float CJX_Object::GetMeasureInUnit(XFA_Attribute eAttr, XFA_Unit unit) const {
419   return GetMeasure(eAttr).ToUnit(unit);
420 }
421 
GetCData(XFA_Attribute eAttr) const422 WideString CJX_Object::GetCData(XFA_Attribute eAttr) const {
423   return TryCData(eAttr, true).value_or(WideString());
424 }
425 
SetCData(XFA_Attribute eAttr,const WideString & wsValue)426 void CJX_Object::SetCData(XFA_Attribute eAttr, const WideString& wsValue) {
427   return SetCDataImpl(eAttr, wsValue, false, false);
428 }
429 
SetCDataImpl(XFA_Attribute eAttr,const WideString & wsValue,bool bNotify,bool bScriptModify)430 void CJX_Object::SetCDataImpl(XFA_Attribute eAttr,
431                               const WideString& wsValue,
432                               bool bNotify,
433                               bool bScriptModify) {
434   CXFA_Node* xfaObj = GetXFANode();
435   uint32_t key = GetMapKey_Element(xfaObj->GetElementType(), eAttr);
436   absl::optional<WideString> old_value = GetMapModuleString(key);
437   if (!old_value.has_value() || old_value.value() != wsValue) {
438     if (bNotify)
439       OnChanging(eAttr);
440     SetMapModuleString(key, wsValue);
441     if (eAttr == XFA_Attribute::Name)
442       xfaObj->UpdateNameHash();
443     if (bNotify)
444       OnChanged(eAttr, bScriptModify);
445   }
446 
447   if (!xfaObj->IsNeedSavingXMLNode() || eAttr == XFA_Attribute::QualifiedName ||
448       eAttr == XFA_Attribute::BindingNode) {
449     return;
450   }
451 
452   if (eAttr == XFA_Attribute::Name &&
453       (xfaObj->GetElementType() == XFA_Element::DataValue ||
454        xfaObj->GetElementType() == XFA_Element::DataGroup)) {
455     return;
456   }
457 
458   if (eAttr == XFA_Attribute::Value) {
459     xfaObj->SetToXML(wsValue);
460     return;
461   }
462 
463   CFX_XMLElement* elem = ToXMLElement(xfaObj->GetXMLMappingNode());
464   if (!elem) {
465     return;
466   }
467 
468   WideString wsAttrName = WideString::FromASCII(XFA_AttributeToName(eAttr));
469   if (eAttr == XFA_Attribute::ContentType)
470     wsAttrName = L"xfa:" + wsAttrName;
471   elem->SetAttribute(wsAttrName, wsValue);
472 }
473 
SetAttributeValue(const WideString & wsValue,const WideString & wsXMLValue)474 void CJX_Object::SetAttributeValue(const WideString& wsValue,
475                                    const WideString& wsXMLValue) {
476   SetAttributeValueImpl(wsValue, wsXMLValue, false, false);
477 }
478 
SetAttributeValueImpl(const WideString & wsValue,const WideString & wsXMLValue,bool bNotify,bool bScriptModify)479 void CJX_Object::SetAttributeValueImpl(const WideString& wsValue,
480                                        const WideString& wsXMLValue,
481                                        bool bNotify,
482                                        bool bScriptModify) {
483   auto* xfaObj = GetXFANode();
484   uint32_t key =
485       GetMapKey_Element(xfaObj->GetElementType(), XFA_Attribute::Value);
486   absl::optional<WideString> old_value = GetMapModuleString(key);
487   if (!old_value.has_value() || old_value.value() != wsValue) {
488     if (bNotify)
489       OnChanging(XFA_Attribute::Value);
490     SetMapModuleString(key, wsValue);
491     if (bNotify)
492       OnChanged(XFA_Attribute::Value, bScriptModify);
493     if (xfaObj->IsNeedSavingXMLNode())
494       xfaObj->SetToXML(wsXMLValue);
495   }
496 }
497 
TryCData(XFA_Attribute eAttr,bool bUseDefault) const498 absl::optional<WideString> CJX_Object::TryCData(XFA_Attribute eAttr,
499                                                 bool bUseDefault) const {
500   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
501   absl::optional<WideString> value = GetMapModuleStringFollowingChain(key);
502   if (value.has_value())
503     return value;
504 
505   if (!bUseDefault)
506     return absl::nullopt;
507 
508   return GetXFANode()->GetDefaultCData(eAttr);
509 }
510 
SetValue(XFA_Attribute eAttr,int32_t value,bool bNotify)511 CFX_XMLElement* CJX_Object::SetValue(XFA_Attribute eAttr,
512                                      int32_t value,
513                                      bool bNotify) {
514   uint32_t key = GetMapKey_Element(GetXFAObject()->GetElementType(), eAttr);
515   absl::optional<int32_t> old_value = GetMapModuleValue(key);
516   if (!old_value.has_value() || old_value.value() != value) {
517     if (bNotify)
518       OnChanging(eAttr);
519     SetMapModuleValue(key, value);
520     if (bNotify)
521       OnChanged(eAttr, false);
522   }
523   CXFA_Node* pNode = GetXFANode();
524   return pNode->IsNeedSavingXMLNode() ? ToXMLElement(pNode->GetXMLMappingNode())
525                                       : nullptr;
526 }
527 
SetContent(const WideString & wsContent,const WideString & wsXMLValue,bool bNotify,bool bScriptModify,bool bSyncData)528 void CJX_Object::SetContent(const WideString& wsContent,
529                             const WideString& wsXMLValue,
530                             bool bNotify,
531                             bool bScriptModify,
532                             bool bSyncData) {
533   CXFA_Node* pNode = nullptr;
534   CXFA_Node* pBindNode = nullptr;
535   switch (GetXFANode()->GetObjectType()) {
536     case XFA_ObjectType::ContainerNode: {
537       if (XFA_FieldIsMultiListBox(GetXFANode())) {
538         CXFA_Value* pValue =
539             GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
540         if (!pValue)
541           break;
542 
543         CXFA_Node* pChildValue = pValue->GetFirstChild();
544         pChildValue->JSObject()->SetCData(XFA_Attribute::ContentType,
545                                           L"text/xml");
546         pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
547                                             bScriptModify, false);
548 
549         CXFA_Node* pBind = GetXFANode()->GetBindData();
550         if (bSyncData && pBind) {
551           std::vector<WideString> wsSaveTextArray =
552               fxcrt::Split(wsContent, L'\n');
553           std::vector<CXFA_Node*> valueNodes =
554               pBind->GetNodeListForType(XFA_Element::DataValue);
555 
556           // Adusting node count might have side effects, do not trust that
557           // we'll ever actually get there.
558           size_t tries = 0;
559           while (valueNodes.size() != wsSaveTextArray.size()) {
560             if (++tries > 4)
561               return;
562             if (valueNodes.size() < wsSaveTextArray.size()) {
563               size_t iAddNodes = wsSaveTextArray.size() - valueNodes.size();
564               while (iAddNodes-- > 0) {
565                 CXFA_Node* pValueNodes =
566                     pBind->CreateSamePacketNode(XFA_Element::DataValue);
567                 pValueNodes->JSObject()->SetCData(XFA_Attribute::Name,
568                                                   L"value");
569                 pValueNodes->CreateXMLMappingNode();
570                 pBind->InsertChildAndNotify(pValueNodes, nullptr);
571               }
572             } else {
573               size_t iDelNodes = valueNodes.size() - wsSaveTextArray.size();
574               for (size_t i = 0; i < iDelNodes; ++i)
575                 pBind->RemoveChildAndNotify(valueNodes[i], true);
576             }
577             valueNodes = pBind->GetNodeListForType(XFA_Element::DataValue);
578           }
579           DCHECK_EQ(valueNodes.size(), wsSaveTextArray.size());
580           size_t i = 0;
581           for (CXFA_Node* pValueNode : valueNodes) {
582             pValueNode->JSObject()->SetAttributeValue(wsSaveTextArray[i],
583                                                       wsSaveTextArray[i]);
584             i++;
585           }
586           for (auto* pArrayNode : pBind->GetBindItemsCopy()) {
587             if (pArrayNode != GetXFANode()) {
588               pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
589                                                  bScriptModify, false);
590             }
591           }
592         }
593         break;
594       }
595       if (GetXFANode()->GetElementType() == XFA_Element::ExclGroup) {
596         pNode = GetXFANode();
597       } else {
598         CXFA_Value* pValue =
599             GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
600         if (!pValue)
601           break;
602 
603         CXFA_Node* pChildValue = pValue->GetFirstChild();
604         if (pChildValue) {
605           pChildValue->JSObject()->SetContent(wsContent, wsContent, bNotify,
606                                               bScriptModify, false);
607         }
608       }
609       pBindNode = GetXFANode()->GetBindData();
610       if (pBindNode && bSyncData) {
611         pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
612                                           bScriptModify, false);
613         for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
614           if (pArrayNode != GetXFANode()) {
615             pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
616                                                true, false);
617           }
618         }
619       }
620       pBindNode = nullptr;
621       break;
622     }
623     case XFA_ObjectType::ContentNode: {
624       WideString wsContentType;
625       if (GetXFANode()->GetElementType() == XFA_Element::ExData) {
626         absl::optional<WideString> ret =
627             TryAttribute(XFA_Attribute::ContentType, false);
628         if (ret.has_value())
629           wsContentType = ret.value();
630         if (wsContentType.EqualsASCII("text/html")) {
631           wsContentType.clear();
632           SetAttributeByEnum(XFA_Attribute::ContentType, wsContentType, false);
633         }
634       }
635 
636       CXFA_Node* pContentRawDataNode = GetXFANode()->GetFirstChild();
637       if (!pContentRawDataNode) {
638         pContentRawDataNode = GetXFANode()->CreateSamePacketNode(
639             wsContentType.EqualsASCII("text/xml") ? XFA_Element::Sharpxml
640                                                   : XFA_Element::Sharptext);
641         GetXFANode()->InsertChildAndNotify(pContentRawDataNode, nullptr);
642       }
643       pContentRawDataNode->JSObject()->SetContent(
644           wsContent, wsXMLValue, bNotify, bScriptModify, bSyncData);
645       return;
646     }
647     case XFA_ObjectType::NodeC:
648     case XFA_ObjectType::TextNode:
649       pNode = GetXFANode();
650       break;
651     case XFA_ObjectType::NodeV:
652       pNode = GetXFANode();
653       if (bSyncData && GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
654         CXFA_Node* pParent = GetXFANode()->GetParent();
655         if (pParent) {
656           pParent = pParent->GetParent();
657         }
658         if (pParent && pParent->GetElementType() == XFA_Element::Value) {
659           pParent = pParent->GetParent();
660           if (pParent && pParent->IsContainerNode()) {
661             pBindNode = pParent->GetBindData();
662             if (pBindNode) {
663               pBindNode->JSObject()->SetContent(wsContent, wsXMLValue, bNotify,
664                                                 bScriptModify, false);
665             }
666           }
667         }
668       }
669       break;
670     default:
671       if (GetXFANode()->GetElementType() == XFA_Element::DataValue) {
672         pNode = GetXFANode();
673         pBindNode = GetXFANode();
674       }
675       break;
676   }
677   if (!pNode)
678     return;
679 
680   SetAttributeValueImpl(wsContent, wsXMLValue, bNotify, bScriptModify);
681   if (pBindNode && bSyncData) {
682     for (auto* pArrayNode : pBindNode->GetBindItemsCopy()) {
683       pArrayNode->JSObject()->SetContent(wsContent, wsContent, bNotify,
684                                          bScriptModify, false);
685     }
686   }
687 }
688 
GetContent(bool bScriptModify) const689 WideString CJX_Object::GetContent(bool bScriptModify) const {
690   return TryContent(bScriptModify, true).value_or(WideString());
691 }
692 
TryContent(bool bScriptModify,bool bProto) const693 absl::optional<WideString> CJX_Object::TryContent(bool bScriptModify,
694                                                   bool bProto) const {
695   CXFA_Node* pNode = nullptr;
696   switch (GetXFANode()->GetObjectType()) {
697     case XFA_ObjectType::ContainerNode:
698       if (GetXFANode()->GetElementType() == XFA_Element::ExclGroup) {
699         pNode = GetXFANode();
700       } else {
701         CXFA_Value* pValue =
702             GetXFANode()->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
703         if (!pValue)
704           return absl::nullopt;
705 
706         CXFA_Node* pChildValue = pValue->GetFirstChild();
707         if (pChildValue && XFA_FieldIsMultiListBox(GetXFANode())) {
708           pChildValue->JSObject()->SetAttributeByEnum(
709               XFA_Attribute::ContentType, L"text/xml", false);
710         }
711         if (!pChildValue)
712           return absl::nullopt;
713         return pChildValue->JSObject()->TryContent(bScriptModify, bProto);
714       }
715       break;
716     case XFA_ObjectType::ContentNode: {
717       CXFA_Node* pContentRawDataNode = GetXFANode()->GetFirstChild();
718       if (!pContentRawDataNode) {
719         XFA_Element element = XFA_Element::Sharptext;
720         if (GetXFANode()->GetElementType() == XFA_Element::ExData) {
721           absl::optional<WideString> contentType =
722               TryAttribute(XFA_Attribute::ContentType, false);
723           if (contentType.has_value()) {
724             if (contentType.value().EqualsASCII("text/html"))
725               element = XFA_Element::SharpxHTML;
726             else if (contentType.value().EqualsASCII("text/xml"))
727               element = XFA_Element::Sharpxml;
728           }
729         }
730         pContentRawDataNode = GetXFANode()->CreateSamePacketNode(element);
731         GetXFANode()->InsertChildAndNotify(pContentRawDataNode, nullptr);
732       }
733       return pContentRawDataNode->JSObject()->TryContent(bScriptModify, true);
734     }
735     case XFA_ObjectType::NodeC:
736     case XFA_ObjectType::NodeV:
737     case XFA_ObjectType::TextNode:
738       pNode = GetXFANode();
739       [[fallthrough]];
740     default:
741       if (GetXFANode()->GetElementType() == XFA_Element::DataValue)
742         pNode = GetXFANode();
743       break;
744   }
745   if (pNode) {
746     if (bScriptModify) {
747       CFXJSE_Engine* pScriptContext = GetDocument()->GetScriptContext();
748       pScriptContext->AddNodesOfRunScript(GetXFANode());
749     }
750     return TryCData(XFA_Attribute::Value, false);
751   }
752   return absl::nullopt;
753 }
754 
TryNamespace() const755 absl::optional<WideString> CJX_Object::TryNamespace() const {
756   if (GetXFANode()->IsModelNode() ||
757       GetXFANode()->GetElementType() == XFA_Element::Packet) {
758     CFX_XMLNode* pXMLNode = GetXFANode()->GetXMLMappingNode();
759     CFX_XMLElement* element = ToXMLElement(pXMLNode);
760     if (!element)
761       return absl::nullopt;
762 
763     return element->GetNamespaceURI();
764   }
765 
766   if (GetXFANode()->GetPacketType() != XFA_PacketType::Datasets)
767     return GetXFANode()->GetModelNode()->JSObject()->TryNamespace();
768 
769   CFX_XMLNode* pXMLNode = GetXFANode()->GetXMLMappingNode();
770   CFX_XMLElement* element = ToXMLElement(pXMLNode);
771   if (!element)
772     return absl::nullopt;
773 
774   if (GetXFANode()->GetElementType() == XFA_Element::DataValue &&
775       GetEnum(XFA_Attribute::Contains) == XFA_AttributeValue::MetaData) {
776     WideString wsNamespace;
777     if (!XFA_FDEExtension_ResolveNamespaceQualifier(
778             element, GetCData(XFA_Attribute::QualifiedName), &wsNamespace)) {
779       return absl::nullopt;
780     }
781     return wsNamespace;
782   }
783   return element->GetNamespaceURI();
784 }
785 
GetPropertyInternal(int32_t index,XFA_Element eProperty) const786 CXFA_Node* CJX_Object::GetPropertyInternal(int32_t index,
787                                            XFA_Element eProperty) const {
788   return GetXFANode()->GetProperty(index, eProperty).first;
789 }
790 
GetOrCreatePropertyInternal(int32_t index,XFA_Element eProperty)791 CXFA_Node* CJX_Object::GetOrCreatePropertyInternal(int32_t index,
792                                                    XFA_Element eProperty) {
793   return GetXFANode()->GetOrCreateProperty(index, eProperty);
794 }
795 
CreateMapModule()796 CFXJSE_MapModule* CJX_Object::CreateMapModule() {
797   if (!map_module_)
798     map_module_ = std::make_unique<CFXJSE_MapModule>();
799   return map_module_.get();
800 }
801 
GetMapModule() const802 CFXJSE_MapModule* CJX_Object::GetMapModule() const {
803   return map_module_.get();
804 }
805 
SetMapModuleValue(uint32_t key,int32_t value)806 void CJX_Object::SetMapModuleValue(uint32_t key, int32_t value) {
807   CreateMapModule()->SetValue(key, value);
808 }
809 
SetMapModuleString(uint32_t key,const WideString & wsValue)810 void CJX_Object::SetMapModuleString(uint32_t key, const WideString& wsValue) {
811   CreateMapModule()->SetString(key, wsValue);
812 }
813 
SetMapModuleMeasurement(uint32_t key,const CXFA_Measurement & value)814 void CJX_Object::SetMapModuleMeasurement(uint32_t key,
815                                          const CXFA_Measurement& value) {
816   CreateMapModule()->SetMeasurement(key, value);
817 }
818 
GetMapModuleValue(uint32_t key) const819 absl::optional<int32_t> CJX_Object::GetMapModuleValue(uint32_t key) const {
820   CFXJSE_MapModule* pModule = GetMapModule();
821   if (!pModule)
822     return absl::nullopt;
823   return pModule->GetValue(key);
824 }
825 
GetMapModuleString(uint32_t key) const826 absl::optional<WideString> CJX_Object::GetMapModuleString(uint32_t key) const {
827   CFXJSE_MapModule* pModule = GetMapModule();
828   if (!pModule)
829     return absl::nullopt;
830   return pModule->GetString(key);
831 }
832 
GetMapModuleMeasurement(uint32_t key) const833 absl::optional<CXFA_Measurement> CJX_Object::GetMapModuleMeasurement(
834     uint32_t key) const {
835   CFXJSE_MapModule* pModule = GetMapModule();
836   if (!pModule)
837     return absl::nullopt;
838   return pModule->GetMeasurement(key);
839 }
840 
GetMapModuleValueFollowingChain(uint32_t key) const841 absl::optional<int32_t> CJX_Object::GetMapModuleValueFollowingChain(
842     uint32_t key) const {
843   std::set<const CXFA_Node*> visited;
844   for (const CXFA_Node* pNode = GetXFANode(); pNode;
845        pNode = pNode->GetTemplateNodeIfExists()) {
846     if (!visited.insert(pNode).second)
847       break;
848 
849     absl::optional<int32_t> result = pNode->JSObject()->GetMapModuleValue(key);
850     if (result.has_value())
851       return result;
852 
853     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
854       break;
855   }
856   return absl::nullopt;
857 }
858 
GetMapModuleStringFollowingChain(uint32_t key) const859 absl::optional<WideString> CJX_Object::GetMapModuleStringFollowingChain(
860     uint32_t key) const {
861   std::set<const CXFA_Node*> visited;
862   for (const CXFA_Node* pNode = GetXFANode(); pNode;
863        pNode = pNode->GetTemplateNodeIfExists()) {
864     if (!visited.insert(pNode).second)
865       break;
866 
867     absl::optional<WideString> result =
868         pNode->JSObject()->GetMapModuleString(key);
869     if (result.has_value())
870       return result;
871 
872     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
873       break;
874   }
875   return absl::nullopt;
876 }
877 
878 absl::optional<CXFA_Measurement>
GetMapModuleMeasurementFollowingChain(uint32_t key) const879 CJX_Object::GetMapModuleMeasurementFollowingChain(uint32_t key) const {
880   std::set<const CXFA_Node*> visited;
881   for (const CXFA_Node* pNode = GetXFANode(); pNode;
882        pNode = pNode->GetTemplateNodeIfExists()) {
883     if (!visited.insert(pNode).second)
884       break;
885 
886     absl::optional<CXFA_Measurement> result =
887         pNode->JSObject()->GetMapModuleMeasurement(key);
888     if (result.has_value())
889       return result;
890 
891     if (pNode->GetPacketType() == XFA_PacketType::Datasets)
892       break;
893   }
894   return absl::nullopt;
895 }
896 
HasMapModuleKey(uint32_t key) const897 bool CJX_Object::HasMapModuleKey(uint32_t key) const {
898   CFXJSE_MapModule* pModule = GetMapModule();
899   return pModule && pModule->HasKey(key);
900 }
901 
RemoveMapModuleKey(uint32_t key)902 void CJX_Object::RemoveMapModuleKey(uint32_t key) {
903   CFXJSE_MapModule* pModule = GetMapModule();
904   if (pModule)
905     pModule->RemoveKey(key);
906 }
907 
MergeAllData(CXFA_Object * pDstObj)908 void CJX_Object::MergeAllData(CXFA_Object* pDstObj) {
909   CFXJSE_MapModule* pDstModule = ToNode(pDstObj)->JSObject()->CreateMapModule();
910   CFXJSE_MapModule* pSrcModule = GetMapModule();
911   if (!pSrcModule)
912     return;
913 
914   pDstModule->MergeDataFrom(pSrcModule);
915 }
916 
MoveBufferMapData(CXFA_Object * pDstObj)917 void CJX_Object::MoveBufferMapData(CXFA_Object* pDstObj) {
918   if (!pDstObj)
919     return;
920 
921   if (pDstObj->GetElementType() == GetXFAObject()->GetElementType())
922     ToNode(pDstObj)->JSObject()->TakeCalcDataFrom(this);
923 
924   if (!pDstObj->IsNodeV())
925     return;
926 
927   WideString wsValue = ToNode(pDstObj)->JSObject()->GetContent(false);
928   WideString wsFormatValue(wsValue);
929   CXFA_Node* pNode = ToNode(pDstObj)->GetContainerNode();
930   if (pNode)
931     wsFormatValue = pNode->GetFormatDataValue(wsValue);
932 
933   ToNode(pDstObj)->JSObject()->SetContent(wsValue, wsFormatValue, true, true,
934                                           true);
935 }
936 
MoveBufferMapData(CXFA_Object * pSrcObj,CXFA_Object * pDstObj)937 void CJX_Object::MoveBufferMapData(CXFA_Object* pSrcObj, CXFA_Object* pDstObj) {
938   if (!pSrcObj || !pDstObj)
939     return;
940 
941   CXFA_Node* pSrcChild = ToNode(pSrcObj)->GetFirstChild();
942   CXFA_Node* pDstChild = ToNode(pDstObj)->GetFirstChild();
943   while (pSrcChild && pDstChild) {
944     MoveBufferMapData(pSrcChild, pDstChild);
945     pSrcChild = pSrcChild->GetNextSibling();
946     pDstChild = pDstChild->GetNextSibling();
947   }
948   ToNode(pSrcObj)->JSObject()->MoveBufferMapData(pDstObj);
949 }
950 
OnChanging(XFA_Attribute eAttr)951 void CJX_Object::OnChanging(XFA_Attribute eAttr) {
952   if (!GetXFANode()->IsInitialized())
953     return;
954 
955   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
956   if (!pNotify)
957     return;
958 
959   pNotify->OnValueChanging(GetXFANode(), eAttr);
960 }
961 
OnChanged(XFA_Attribute eAttr,bool bScriptModify)962 void CJX_Object::OnChanged(XFA_Attribute eAttr, bool bScriptModify) {
963   if (!GetXFANode()->IsInitialized())
964     return;
965 
966   GetXFANode()->SendAttributeChangeMessage(eAttr, bScriptModify);
967 }
968 
GetOrCreateCalcData(cppgc::Heap * heap)969 CJX_Object::CalcData* CJX_Object::GetOrCreateCalcData(cppgc::Heap* heap) {
970   if (!calc_data_) {
971     calc_data_ =
972         cppgc::MakeGarbageCollected<CalcData>(heap->GetAllocationHandle());
973   }
974   return calc_data_;
975 }
976 
TakeCalcDataFrom(CJX_Object * that)977 void CJX_Object::TakeCalcDataFrom(CJX_Object* that) {
978   calc_data_ = that->calc_data_;
979   that->calc_data_ = nullptr;
980 }
981 
ScriptAttributeString(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)982 void CJX_Object::ScriptAttributeString(v8::Isolate* pIsolate,
983                                        v8::Local<v8::Value>* pValue,
984                                        bool bSetting,
985                                        XFA_Attribute eAttribute) {
986   if (!bSetting) {
987     *pValue = fxv8::NewStringHelper(
988         pIsolate, GetAttributeByEnum(eAttribute).ToUTF8().AsStringView());
989     return;
990   }
991 
992   WideString wsValue = fxv8::ReentrantToWideStringHelper(pIsolate, *pValue);
993   SetAttributeByEnum(eAttribute, wsValue, true);
994   if (eAttribute != XFA_Attribute::Use ||
995       GetXFAObject()->GetElementType() != XFA_Element::Desc) {
996     return;
997   }
998 
999   CXFA_Node* pTemplateNode =
1000       ToNode(GetDocument()->GetXFAObject(XFA_HASHCODE_Template));
1001   CXFA_Subform* pSubForm =
1002       pTemplateNode->GetFirstChildByClass<CXFA_Subform>(XFA_Element::Subform);
1003   CXFA_Proto* pProtoRoot =
1004       pSubForm ? pSubForm->GetFirstChildByClass<CXFA_Proto>(XFA_Element::Proto)
1005                : nullptr;
1006 
1007   WideString wsID;
1008   WideString wsSOM;
1009   if (!wsValue.IsEmpty()) {
1010     if (wsValue[0] == '#')
1011       wsID = wsValue.Substr(1);
1012     else
1013       wsSOM = std::move(wsValue);
1014   }
1015 
1016   CXFA_Node* pProtoNode = nullptr;
1017   if (!wsSOM.IsEmpty()) {
1018     absl::optional<CFXJSE_Engine::ResolveResult> maybeResult =
1019         GetDocument()->GetScriptContext()->ResolveObjects(
1020             pProtoRoot, wsSOM.AsStringView(),
1021             Mask<XFA_ResolveFlag>{
1022                 XFA_ResolveFlag::kChildren, XFA_ResolveFlag::kAttributes,
1023                 XFA_ResolveFlag::kProperties, XFA_ResolveFlag::kParent,
1024                 XFA_ResolveFlag::kSiblings});
1025     if (maybeResult.has_value() &&
1026         maybeResult.value().objects.front()->IsNode()) {
1027       pProtoNode = maybeResult.value().objects.front()->AsNode();
1028     }
1029   } else if (!wsID.IsEmpty()) {
1030     pProtoNode = GetDocument()->GetNodeByID(pProtoRoot, wsID.AsStringView());
1031   }
1032   if (!pProtoNode || pProtoNode->GetPacketType() != XFA_PacketType::Template)
1033     return;
1034 
1035   CXFA_Node* pHeadChild = GetXFANode()->GetFirstChild();
1036   while (pHeadChild) {
1037     CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1038     GetXFANode()->RemoveChildAndNotify(pHeadChild, true);
1039     pHeadChild = pSibling;
1040   }
1041 
1042   CXFA_Node* pProtoForm = pProtoNode->CloneTemplateToForm(true);
1043   pHeadChild = pProtoForm->GetFirstChild();
1044   while (pHeadChild) {
1045     CXFA_Node* pSibling = pHeadChild->GetNextSibling();
1046     pProtoForm->RemoveChildAndNotify(pHeadChild, true);
1047     GetXFANode()->InsertChildAndNotify(pHeadChild, nullptr);
1048     pHeadChild = pSibling;
1049   }
1050 }
1051 
ScriptAttributeBool(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1052 void CJX_Object::ScriptAttributeBool(v8::Isolate* pIsolate,
1053                                      v8::Local<v8::Value>* pValue,
1054                                      bool bSetting,
1055                                      XFA_Attribute eAttribute) {
1056   if (bSetting) {
1057     SetBoolean(eAttribute, fxv8::ReentrantToBooleanHelper(pIsolate, *pValue),
1058                true);
1059     return;
1060   }
1061   *pValue = fxv8::NewStringHelper(pIsolate, GetBoolean(eAttribute) ? "1" : "0");
1062 }
1063 
ScriptAttributeInteger(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1064 void CJX_Object::ScriptAttributeInteger(v8::Isolate* pIsolate,
1065                                         v8::Local<v8::Value>* pValue,
1066                                         bool bSetting,
1067                                         XFA_Attribute eAttribute) {
1068   if (bSetting) {
1069     SetInteger(eAttribute, fxv8::ReentrantToInt32Helper(pIsolate, *pValue),
1070                true);
1071     return;
1072   }
1073   *pValue = fxv8::NewNumberHelper(pIsolate, GetInteger(eAttribute));
1074 }
1075 
ScriptSomFontColor(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1076 void CJX_Object::ScriptSomFontColor(v8::Isolate* pIsolate,
1077                                     v8::Local<v8::Value>* pValue,
1078                                     bool bSetting,
1079                                     XFA_Attribute eAttribute) {
1080   CXFA_Font* font = ToNode(object_.Get())->GetOrCreateFontIfPossible();
1081   if (!font)
1082     return;
1083 
1084   if (bSetting) {
1085     int32_t r;
1086     int32_t g;
1087     int32_t b;
1088     std::tie(r, g, b) =
1089         StrToRGB(fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1090     FX_ARGB color = ArgbEncode(0xff, r, g, b);
1091     font->SetColor(color);
1092     return;
1093   }
1094 
1095   int32_t a;
1096   int32_t r;
1097   int32_t g;
1098   int32_t b;
1099   std::tie(a, r, g, b) = ArgbDecode(font->GetColor());
1100   *pValue = fxv8::NewStringHelper(
1101       pIsolate, ByteString::Format("%d,%d,%d", r, g, b).AsStringView());
1102 }
1103 
ScriptSomFillColor(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1104 void CJX_Object::ScriptSomFillColor(v8::Isolate* pIsolate,
1105                                     v8::Local<v8::Value>* pValue,
1106                                     bool bSetting,
1107                                     XFA_Attribute eAttribute) {
1108   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1109   CXFA_Fill* borderfill = border->GetOrCreateFillIfPossible();
1110   if (!borderfill)
1111     return;
1112 
1113   if (bSetting) {
1114     int32_t r;
1115     int32_t g;
1116     int32_t b;
1117     std::tie(r, g, b) =
1118         StrToRGB(fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1119     FX_ARGB color = ArgbEncode(0xff, r, g, b);
1120     borderfill->SetColor(color);
1121     return;
1122   }
1123 
1124   FX_ARGB color = borderfill->GetFillColor();
1125   int32_t a;
1126   int32_t r;
1127   int32_t g;
1128   int32_t b;
1129   std::tie(a, r, g, b) = ArgbDecode(color);
1130   *pValue = fxv8::NewStringHelper(
1131       pIsolate, ByteString::Format("%d,%d,%d", r, g, b).AsStringView());
1132 }
1133 
ScriptSomBorderColor(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1134 void CJX_Object::ScriptSomBorderColor(v8::Isolate* pIsolate,
1135                                       v8::Local<v8::Value>* pValue,
1136                                       bool bSetting,
1137                                       XFA_Attribute eAttribute) {
1138   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1139   int32_t iSize = border->CountEdges();
1140   if (bSetting) {
1141     int32_t r = 0;
1142     int32_t g = 0;
1143     int32_t b = 0;
1144     std::tie(r, g, b) =
1145         StrToRGB(fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1146     FX_ARGB rgb = ArgbEncode(100, r, g, b);
1147     for (int32_t i = 0; i < iSize; ++i) {
1148       CXFA_Edge* edge = border->GetEdgeIfExists(i);
1149       if (edge)
1150         edge->SetColor(rgb);
1151     }
1152 
1153     return;
1154   }
1155 
1156   CXFA_Edge* edge = border->GetEdgeIfExists(0);
1157   FX_ARGB color = edge ? edge->GetColor() : CXFA_Edge::kDefaultColor;
1158   int32_t a;
1159   int32_t r;
1160   int32_t g;
1161   int32_t b;
1162   std::tie(a, r, g, b) = ArgbDecode(color);
1163   *pValue = fxv8::NewStringHelper(
1164       pIsolate, ByteString::Format("%d,%d,%d", r, g, b).AsStringView());
1165 }
1166 
ScriptSomBorderWidth(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1167 void CJX_Object::ScriptSomBorderWidth(v8::Isolate* pIsolate,
1168                                       v8::Local<v8::Value>* pValue,
1169                                       bool bSetting,
1170                                       XFA_Attribute eAttribute) {
1171   CXFA_Border* border = ToNode(object_.Get())->GetOrCreateBorderIfPossible();
1172   if (bSetting) {
1173     CXFA_Edge* edge = border->GetEdgeIfExists(0);
1174     CXFA_Measurement thickness =
1175         edge ? edge->GetMSThickness() : CXFA_Measurement(0.5, XFA_Unit::Pt);
1176     *pValue = fxv8::NewStringHelper(
1177         pIsolate, thickness.ToString().ToUTF8().AsStringView());
1178     return;
1179   }
1180 
1181   if (pValue->IsEmpty())
1182     return;
1183 
1184   WideString wsThickness = fxv8::ReentrantToWideStringHelper(pIsolate, *pValue);
1185   for (size_t i = 0; i < border->CountEdges(); ++i) {
1186     CXFA_Edge* edge = border->GetEdgeIfExists(i);
1187     if (edge)
1188       edge->SetMSThickness(CXFA_Measurement(wsThickness.AsStringView()));
1189   }
1190 }
1191 
ScriptSomMessage(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,SOMMessageType iMessageType)1192 void CJX_Object::ScriptSomMessage(v8::Isolate* pIsolate,
1193                                   v8::Local<v8::Value>* pValue,
1194                                   bool bSetting,
1195                                   SOMMessageType iMessageType) {
1196   bool bNew = false;
1197   CXFA_Validate* validate = ToNode(object_.Get())->GetValidateIfExists();
1198   if (!validate) {
1199     validate = ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1200     bNew = true;
1201   }
1202 
1203   if (bSetting) {
1204     if (validate) {
1205       switch (iMessageType) {
1206         case SOMMessageType::kValidationMessage:
1207           validate->SetScriptMessageText(
1208               fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1209           break;
1210         case SOMMessageType::kFormatMessage:
1211           validate->SetFormatMessageText(
1212               fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1213           break;
1214         case SOMMessageType::kMandatoryMessage:
1215           validate->SetNullMessageText(
1216               fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1217           break;
1218       }
1219     }
1220 
1221     if (!bNew) {
1222       CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1223       if (!pNotify)
1224         return;
1225 
1226       pNotify->AddCalcValidate(GetXFANode());
1227     }
1228     return;
1229   }
1230 
1231   if (!validate) {
1232     // TODO(dsinclair): Better error message?
1233     ThrowInvalidPropertyException(pIsolate);
1234     return;
1235   }
1236 
1237   WideString wsMessage;
1238   switch (iMessageType) {
1239     case SOMMessageType::kValidationMessage:
1240       wsMessage = validate->GetScriptMessageText();
1241       break;
1242     case SOMMessageType::kFormatMessage:
1243       wsMessage = validate->GetFormatMessageText();
1244       break;
1245     case SOMMessageType::kMandatoryMessage:
1246       wsMessage = validate->GetNullMessageText();
1247       break;
1248   }
1249   *pValue = fxv8::NewStringHelper(pIsolate, wsMessage.ToUTF8().AsStringView());
1250 }
1251 
ScriptSomValidationMessage(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1252 void CJX_Object::ScriptSomValidationMessage(v8::Isolate* pIsolate,
1253                                             v8::Local<v8::Value>* pValue,
1254                                             bool bSetting,
1255                                             XFA_Attribute eAttribute) {
1256   ScriptSomMessage(pIsolate, pValue, bSetting,
1257                    SOMMessageType::kValidationMessage);
1258 }
1259 
ScriptSomMandatoryMessage(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1260 void CJX_Object::ScriptSomMandatoryMessage(v8::Isolate* pIsolate,
1261                                            v8::Local<v8::Value>* pValue,
1262                                            bool bSetting,
1263                                            XFA_Attribute eAttribute) {
1264   ScriptSomMessage(pIsolate, pValue, bSetting,
1265                    SOMMessageType::kMandatoryMessage);
1266 }
1267 
ScriptSomDefaultValue(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute)1268 void CJX_Object::ScriptSomDefaultValue(v8::Isolate* pIsolate,
1269                                        v8::Local<v8::Value>* pValue,
1270                                        bool bSetting,
1271                                        XFA_Attribute /* unused */) {
1272   XFA_Element eType = GetXFANode()->GetElementType();
1273 
1274   // TODO(dsinclair): This should look through the properties on the node to see
1275   // if defaultValue is defined and, if so, call that one. Just have to make
1276   // sure that those defaultValue calls don't call back to this one ....
1277   if (eType == XFA_Element::Field) {
1278     static_cast<CJX_Field*>(this)->defaultValue(pIsolate, pValue, bSetting,
1279                                                 XFA_Attribute::Unknown);
1280     return;
1281   }
1282   if (eType == XFA_Element::Draw) {
1283     static_cast<CJX_Draw*>(this)->defaultValue(pIsolate, pValue, bSetting,
1284                                                XFA_Attribute::Unknown);
1285     return;
1286   }
1287   if (eType == XFA_Element::Boolean) {
1288     static_cast<CJX_Boolean*>(this)->defaultValue(pIsolate, pValue, bSetting,
1289                                                   XFA_Attribute::Unknown);
1290     return;
1291   }
1292 
1293   if (bSetting) {
1294     WideString wsNewValue;
1295     if (pValue && !(pValue->IsEmpty() || fxv8::IsNull(*pValue) ||
1296                     fxv8::IsUndefined(*pValue))) {
1297       wsNewValue = fxv8::ReentrantToWideStringHelper(pIsolate, *pValue);
1298     }
1299 
1300     WideString wsFormatValue = wsNewValue;
1301     CXFA_Node* pContainerNode = nullptr;
1302     if (GetXFANode()->GetPacketType() == XFA_PacketType::Datasets) {
1303       WideString wsPicture;
1304       for (auto* pFormNode : GetXFANode()->GetBindItemsCopy()) {
1305         if (!pFormNode || pFormNode->HasRemovedChildren())
1306           continue;
1307 
1308         pContainerNode = pFormNode->GetContainerNode();
1309         if (pContainerNode) {
1310           wsPicture =
1311               pContainerNode->GetPictureContent(XFA_ValuePicture::kDataBind);
1312         }
1313         if (!wsPicture.IsEmpty())
1314           break;
1315 
1316         pContainerNode = nullptr;
1317       }
1318     } else if (GetXFANode()->GetPacketType() == XFA_PacketType::Form) {
1319       pContainerNode = GetXFANode()->GetContainerNode();
1320     }
1321 
1322     if (pContainerNode)
1323       wsFormatValue = pContainerNode->GetFormatDataValue(wsNewValue);
1324 
1325     SetContent(wsNewValue, wsFormatValue, true, true, true);
1326     return;
1327   }
1328 
1329   WideString content = GetContent(true);
1330   if (content.IsEmpty() && eType != XFA_Element::Text &&
1331       eType != XFA_Element::SubmitUrl) {
1332     *pValue = fxv8::NewNullHelper(pIsolate);
1333   } else if (eType == XFA_Element::Integer) {
1334     *pValue = fxv8::NewNumberHelper(pIsolate, FXSYS_wtoi(content.c_str()));
1335   } else if (eType == XFA_Element::Float || eType == XFA_Element::Decimal) {
1336     CFGAS_Decimal decimal(content.AsStringView());
1337     *pValue = fxv8::NewNumberHelper(pIsolate, decimal.ToFloat());
1338   } else {
1339     *pValue = fxv8::NewStringHelper(pIsolate, content.ToUTF8().AsStringView());
1340   }
1341 }
1342 
ScriptSomDefaultValue_Read(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1343 void CJX_Object::ScriptSomDefaultValue_Read(v8::Isolate* pIsolate,
1344                                             v8::Local<v8::Value>* pValue,
1345                                             bool bSetting,
1346                                             XFA_Attribute eAttribute) {
1347   if (bSetting) {
1348     ThrowInvalidPropertyException(pIsolate);
1349     return;
1350   }
1351 
1352   WideString content = GetContent(true);
1353   if (content.IsEmpty()) {
1354     *pValue = fxv8::NewNullHelper(pIsolate);
1355     return;
1356   }
1357   *pValue = fxv8::NewStringHelper(pIsolate, content.ToUTF8().AsStringView());
1358 }
1359 
ScriptSomDataNode(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1360 void CJX_Object::ScriptSomDataNode(v8::Isolate* pIsolate,
1361                                    v8::Local<v8::Value>* pValue,
1362                                    bool bSetting,
1363                                    XFA_Attribute eAttribute) {
1364   if (bSetting) {
1365     ThrowInvalidPropertyException(pIsolate);
1366     return;
1367   }
1368 
1369   CXFA_Node* pDataNode = GetXFANode()->GetBindData();
1370   if (!pDataNode) {
1371     *pValue = fxv8::NewNullHelper(pIsolate);
1372     return;
1373   }
1374 
1375   *pValue =
1376       GetDocument()->GetScriptContext()->GetOrCreateJSBindingFromMap(pDataNode);
1377 }
1378 
ScriptSomMandatory(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1379 void CJX_Object::ScriptSomMandatory(v8::Isolate* pIsolate,
1380                                     v8::Local<v8::Value>* pValue,
1381                                     bool bSetting,
1382                                     XFA_Attribute eAttribute) {
1383   CXFA_Validate* validate =
1384       ToNode(object_.Get())->GetOrCreateValidateIfPossible();
1385   if (!validate)
1386     return;
1387 
1388   if (bSetting) {
1389     validate->SetNullTest(fxv8::ReentrantToWideStringHelper(pIsolate, *pValue));
1390     return;
1391   }
1392 
1393   *pValue = fxv8::NewStringHelper(
1394       pIsolate, XFA_AttributeValueToName(validate->GetNullTest()));
1395 }
1396 
ScriptSomInstanceIndex(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1397 void CJX_Object::ScriptSomInstanceIndex(v8::Isolate* pIsolate,
1398                                         v8::Local<v8::Value>* pValue,
1399                                         bool bSetting,
1400                                         XFA_Attribute eAttribute) {
1401   if (!bSetting) {
1402     *pValue =
1403         fxv8::NewNumberHelper(pIsolate, Subform_and_SubformSet_InstanceIndex());
1404     return;
1405   }
1406 
1407   int32_t iTo = fxv8::ReentrantToInt32Helper(pIsolate, *pValue);
1408   int32_t iFrom = Subform_and_SubformSet_InstanceIndex();
1409   CXFA_Node* pManagerNode = nullptr;
1410   for (CXFA_Node* pNode = GetXFANode()->GetPrevSibling(); pNode;
1411        pNode = pNode->GetPrevSibling()) {
1412     if (pNode->GetElementType() == XFA_Element::InstanceManager) {
1413       pManagerNode = pNode;
1414       break;
1415     }
1416   }
1417   if (!pManagerNode)
1418     return;
1419 
1420   auto* mgr = static_cast<CJX_InstanceManager*>(pManagerNode->JSObject());
1421   mgr->MoveInstance(pIsolate, iTo, iFrom);
1422   CXFA_FFNotify* pNotify = GetDocument()->GetNotify();
1423   if (!pNotify)
1424     return;
1425 
1426   auto* pToInstance =
1427       CXFA_Subform::FromNode(pManagerNode->GetItemIfExists(iTo));
1428   if (pToInstance)
1429     pNotify->RunSubformIndexChange(pToInstance);
1430 
1431   auto* pFromInstance =
1432       CXFA_Subform::FromNode(pManagerNode->GetItemIfExists(iFrom));
1433   if (pFromInstance)
1434     pNotify->RunSubformIndexChange(pFromInstance);
1435 }
1436 
ScriptSubmitFormatMode(v8::Isolate * pIsolate,v8::Local<v8::Value> * pValue,bool bSetting,XFA_Attribute eAttribute)1437 void CJX_Object::ScriptSubmitFormatMode(v8::Isolate* pIsolate,
1438                                         v8::Local<v8::Value>* pValue,
1439                                         bool bSetting,
1440                                         XFA_Attribute eAttribute) {}
1441 
1442 CJX_Object::CalcData::CalcData() = default;
1443 
1444 CJX_Object::CalcData::~CalcData() = default;
1445 
Trace(cppgc::Visitor * visitor) const1446 void CJX_Object::CalcData::Trace(cppgc::Visitor* visitor) const {
1447   ContainerTrace(visitor, m_Globals);
1448 }
1449