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