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