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