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