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