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 "xfa/fxfa/cxfa_widgetacc.h"
8
9 #include <algorithm>
10 #include <tuple>
11 #include <vector>
12
13 #include "core/fxcrt/cfx_decimal.h"
14 #include "core/fxcrt/cfx_memorystream.h"
15 #include "core/fxcrt/fx_extension.h"
16 #include "core/fxcrt/xml/cfx_xmlelement.h"
17 #include "core/fxcrt/xml/cfx_xmlnode.h"
18 #include "fxjs/cfxjse_engine.h"
19 #include "fxjs/xfa/cjx_object.h"
20 #include "third_party/base/stl_util.h"
21 #include "xfa/fde/cfde_textout.h"
22 #include "xfa/fxfa/cxfa_ffapp.h"
23 #include "xfa/fxfa/cxfa_ffdoc.h"
24 #include "xfa/fxfa/cxfa_ffdocview.h"
25 #include "xfa/fxfa/cxfa_ffnotify.h"
26 #include "xfa/fxfa/cxfa_ffwidget.h"
27 #include "xfa/fxfa/cxfa_fontmgr.h"
28 #include "xfa/fxfa/cxfa_textlayout.h"
29 #include "xfa/fxfa/cxfa_textprovider.h"
30 #include "xfa/fxfa/parser/cxfa_bind.h"
31 #include "xfa/fxfa/parser/cxfa_border.h"
32 #include "xfa/fxfa/parser/cxfa_calculate.h"
33 #include "xfa/fxfa/parser/cxfa_caption.h"
34 #include "xfa/fxfa/parser/cxfa_comb.h"
35 #include "xfa/fxfa/parser/cxfa_decimal.h"
36 #include "xfa/fxfa/parser/cxfa_document.h"
37 #include "xfa/fxfa/parser/cxfa_event.h"
38 #include "xfa/fxfa/parser/cxfa_font.h"
39 #include "xfa/fxfa/parser/cxfa_format.h"
40 #include "xfa/fxfa/parser/cxfa_image.h"
41 #include "xfa/fxfa/parser/cxfa_items.h"
42 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h"
43 #include "xfa/fxfa/parser/cxfa_localevalue.h"
44 #include "xfa/fxfa/parser/cxfa_margin.h"
45 #include "xfa/fxfa/parser/cxfa_measurement.h"
46 #include "xfa/fxfa/parser/cxfa_node.h"
47 #include "xfa/fxfa/parser/cxfa_para.h"
48 #include "xfa/fxfa/parser/cxfa_picture.h"
49 #include "xfa/fxfa/parser/cxfa_script.h"
50 #include "xfa/fxfa/parser/cxfa_stroke.h"
51 #include "xfa/fxfa/parser/cxfa_ui.h"
52 #include "xfa/fxfa/parser/cxfa_validate.h"
53 #include "xfa/fxfa/parser/cxfa_value.h"
54 #include "xfa/fxfa/parser/xfa_utils.h"
55
56 class CXFA_WidgetLayoutData {
57 public:
CXFA_WidgetLayoutData()58 CXFA_WidgetLayoutData() : m_fWidgetHeight(-1) {}
~CXFA_WidgetLayoutData()59 virtual ~CXFA_WidgetLayoutData() {}
60
61 float m_fWidgetHeight;
62 };
63
64 namespace {
65
66 constexpr uint8_t g_inv_base64[128] = {
67 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
68 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
69 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255,
70 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255,
71 255, 255, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
72 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
73 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33,
74 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
75 49, 50, 51, 255, 255, 255, 255, 255,
76 };
77
XFA_RemoveBase64Whitespace(const uint8_t * pStr,int32_t iLen)78 uint8_t* XFA_RemoveBase64Whitespace(const uint8_t* pStr, int32_t iLen) {
79 uint8_t* pCP;
80 int32_t i = 0, j = 0;
81 if (iLen == 0) {
82 iLen = strlen((char*)pStr);
83 }
84 pCP = FX_Alloc(uint8_t, iLen + 1);
85 for (; i < iLen; i++) {
86 if ((pStr[i] & 128) == 0) {
87 if (g_inv_base64[pStr[i]] != 0xFF || pStr[i] == '=') {
88 pCP[j++] = pStr[i];
89 }
90 }
91 }
92 pCP[j] = '\0';
93 return pCP;
94 }
95
XFA_Base64Decode(const char * pStr,uint8_t * pOutBuffer)96 int32_t XFA_Base64Decode(const char* pStr, uint8_t* pOutBuffer) {
97 if (!pStr) {
98 return 0;
99 }
100 uint8_t* pBuffer =
101 XFA_RemoveBase64Whitespace((uint8_t*)pStr, strlen((char*)pStr));
102 if (!pBuffer) {
103 return 0;
104 }
105 int32_t iLen = strlen((char*)pBuffer);
106 int32_t i = 0, j = 0;
107 uint32_t dwLimb = 0;
108 for (; i + 3 < iLen; i += 4) {
109 if (pBuffer[i] == '=' || pBuffer[i + 1] == '=' || pBuffer[i + 2] == '=' ||
110 pBuffer[i + 3] == '=') {
111 if (pBuffer[i] == '=' || pBuffer[i + 1] == '=') {
112 break;
113 }
114 if (pBuffer[i + 2] == '=') {
115 dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 6) |
116 ((uint32_t)g_inv_base64[pBuffer[i + 1]]);
117 pOutBuffer[j] = (uint8_t)(dwLimb >> 4) & 0xFF;
118 j++;
119 } else {
120 dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 12) |
121 ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 6) |
122 ((uint32_t)g_inv_base64[pBuffer[i + 2]]);
123 pOutBuffer[j] = (uint8_t)(dwLimb >> 10) & 0xFF;
124 pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 2) & 0xFF;
125 j += 2;
126 }
127 } else {
128 dwLimb = ((uint32_t)g_inv_base64[pBuffer[i]] << 18) |
129 ((uint32_t)g_inv_base64[pBuffer[i + 1]] << 12) |
130 ((uint32_t)g_inv_base64[pBuffer[i + 2]] << 6) |
131 ((uint32_t)g_inv_base64[pBuffer[i + 3]]);
132 pOutBuffer[j] = (uint8_t)(dwLimb >> 16) & 0xff;
133 pOutBuffer[j + 1] = (uint8_t)(dwLimb >> 8) & 0xff;
134 pOutBuffer[j + 2] = (uint8_t)(dwLimb)&0xff;
135 j += 3;
136 }
137 }
138 FX_Free(pBuffer);
139 return j;
140 }
141
XFA_GetImageType(const WideString & wsType)142 FXCODEC_IMAGE_TYPE XFA_GetImageType(const WideString& wsType) {
143 WideString wsContentType(wsType);
144 wsContentType.MakeLower();
145 if (wsContentType == L"image/jpg")
146 return FXCODEC_IMAGE_JPG;
147 if (wsContentType == L"image/png")
148 return FXCODEC_IMAGE_PNG;
149 if (wsContentType == L"image/gif")
150 return FXCODEC_IMAGE_GIF;
151 if (wsContentType == L"image/bmp")
152 return FXCODEC_IMAGE_BMP;
153 if (wsContentType == L"image/tif")
154 return FXCODEC_IMAGE_TIF;
155 return FXCODEC_IMAGE_UNKNOWN;
156 }
157
XFA_LoadImageData(CXFA_FFDoc * pDoc,CXFA_Image * pImage,bool & bNameImage,int32_t & iImageXDpi,int32_t & iImageYDpi)158 RetainPtr<CFX_DIBitmap> XFA_LoadImageData(CXFA_FFDoc* pDoc,
159 CXFA_Image* pImage,
160 bool& bNameImage,
161 int32_t& iImageXDpi,
162 int32_t& iImageYDpi) {
163 WideString wsHref = pImage->GetHref();
164 WideString wsImage = pImage->GetContent();
165 if (wsHref.IsEmpty() && wsImage.IsEmpty())
166 return nullptr;
167
168 FXCODEC_IMAGE_TYPE type = XFA_GetImageType(pImage->GetContentType());
169 ByteString bsContent;
170 uint8_t* pImageBuffer = nullptr;
171 RetainPtr<IFX_SeekableReadStream> pImageFileRead;
172 if (wsImage.GetLength() > 0) {
173 XFA_AttributeEnum iEncoding = pImage->GetTransferEncoding();
174 if (iEncoding == XFA_AttributeEnum::Base64) {
175 ByteString bsData = wsImage.UTF8Encode();
176 int32_t iLength = bsData.GetLength();
177 pImageBuffer = FX_Alloc(uint8_t, iLength);
178 int32_t iRead = XFA_Base64Decode(bsData.c_str(), pImageBuffer);
179 if (iRead > 0) {
180 pImageFileRead =
181 pdfium::MakeRetain<CFX_MemoryStream>(pImageBuffer, iRead, false);
182 }
183 } else {
184 bsContent = ByteString::FromUnicode(wsImage);
185 pImageFileRead = pdfium::MakeRetain<CFX_MemoryStream>(
186 const_cast<uint8_t*>(bsContent.raw_str()), bsContent.GetLength(),
187 false);
188 }
189 } else {
190 WideString wsURL = wsHref;
191 if (wsURL.Left(7) != L"http://" && wsURL.Left(6) != L"ftp://") {
192 RetainPtr<CFX_DIBitmap> pBitmap =
193 pDoc->GetPDFNamedImage(wsURL.AsStringView(), iImageXDpi, iImageYDpi);
194 if (pBitmap) {
195 bNameImage = true;
196 return pBitmap;
197 }
198 }
199 pImageFileRead = pDoc->GetDocEnvironment()->OpenLinkedFile(pDoc, wsURL);
200 }
201 if (!pImageFileRead) {
202 FX_Free(pImageBuffer);
203 return nullptr;
204 }
205 bNameImage = false;
206 RetainPtr<CFX_DIBitmap> pBitmap =
207 XFA_LoadImageFromBuffer(pImageFileRead, type, iImageXDpi, iImageYDpi);
208 FX_Free(pImageBuffer);
209 return pBitmap;
210 }
211
212 class CXFA_TextLayoutData : public CXFA_WidgetLayoutData {
213 public:
CXFA_TextLayoutData()214 CXFA_TextLayoutData() {}
~CXFA_TextLayoutData()215 ~CXFA_TextLayoutData() override {}
216
GetTextLayout() const217 CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
GetTextProvider() const218 CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
219
LoadText(CXFA_FFDoc * doc,CXFA_WidgetAcc * pAcc)220 void LoadText(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
221 if (m_pTextLayout)
222 return;
223
224 m_pTextProvider =
225 pdfium::MakeUnique<CXFA_TextProvider>(pAcc, XFA_TEXTPROVIDERTYPE_Text);
226 m_pTextLayout =
227 pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pTextProvider.get());
228 }
229
230 private:
231 std::unique_ptr<CXFA_TextLayout> m_pTextLayout;
232 std::unique_ptr<CXFA_TextProvider> m_pTextProvider;
233 };
234
235 class CXFA_ImageLayoutData : public CXFA_WidgetLayoutData {
236 public:
CXFA_ImageLayoutData()237 CXFA_ImageLayoutData()
238 : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
239
~CXFA_ImageLayoutData()240 ~CXFA_ImageLayoutData() override {}
241
LoadImageData(CXFA_FFDoc * doc,CXFA_WidgetAcc * pAcc)242 bool LoadImageData(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
243 if (m_pDIBitmap)
244 return true;
245
246 CXFA_Value* value = pAcc->GetNode()->GetFormValueIfExists();
247 if (!value)
248 return false;
249
250 CXFA_Image* image = value->GetImageIfExists();
251 if (!image)
252 return false;
253
254 pAcc->SetImageImage(XFA_LoadImageData(doc, image, m_bNamedImage,
255 m_iImageXDpi, m_iImageYDpi));
256 return !!m_pDIBitmap;
257 }
258
259 RetainPtr<CFX_DIBitmap> m_pDIBitmap;
260 bool m_bNamedImage;
261 int32_t m_iImageXDpi;
262 int32_t m_iImageYDpi;
263 };
264
265 class CXFA_FieldLayoutData : public CXFA_WidgetLayoutData {
266 public:
CXFA_FieldLayoutData()267 CXFA_FieldLayoutData() {}
~CXFA_FieldLayoutData()268 ~CXFA_FieldLayoutData() override {}
269
LoadCaption(CXFA_FFDoc * doc,CXFA_WidgetAcc * pAcc)270 bool LoadCaption(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
271 if (m_pCapTextLayout)
272 return true;
273 CXFA_Caption* caption = pAcc->GetNode()->GetCaptionIfExists();
274 if (!caption || caption->IsHidden())
275 return false;
276
277 m_pCapTextProvider = pdfium::MakeUnique<CXFA_TextProvider>(
278 pAcc, XFA_TEXTPROVIDERTYPE_Caption);
279 m_pCapTextLayout =
280 pdfium::MakeUnique<CXFA_TextLayout>(doc, m_pCapTextProvider.get());
281 return true;
282 }
283
284 std::unique_ptr<CXFA_TextLayout> m_pCapTextLayout;
285 std::unique_ptr<CXFA_TextProvider> m_pCapTextProvider;
286 std::unique_ptr<CFDE_TextOut> m_pTextOut;
287 std::vector<float> m_FieldSplitArray;
288 };
289
290 class CXFA_TextEditData : public CXFA_FieldLayoutData {};
291
292 class CXFA_ImageEditData : public CXFA_FieldLayoutData {
293 public:
CXFA_ImageEditData()294 CXFA_ImageEditData()
295 : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
296
~CXFA_ImageEditData()297 ~CXFA_ImageEditData() override {}
298
LoadImageData(CXFA_FFDoc * doc,CXFA_WidgetAcc * pAcc)299 bool LoadImageData(CXFA_FFDoc* doc, CXFA_WidgetAcc* pAcc) {
300 if (m_pDIBitmap)
301 return true;
302
303 CXFA_Value* value = pAcc->GetNode()->GetFormValueIfExists();
304 if (!value)
305 return false;
306
307 CXFA_Image* image = value->GetImageIfExists();
308 if (!image)
309 return false;
310
311 pAcc->SetImageEditImage(XFA_LoadImageData(doc, image, m_bNamedImage,
312 m_iImageXDpi, m_iImageYDpi));
313 return !!m_pDIBitmap;
314 }
315
316 RetainPtr<CFX_DIBitmap> m_pDIBitmap;
317 bool m_bNamedImage;
318 int32_t m_iImageXDpi;
319 int32_t m_iImageYDpi;
320 };
321
GetEdgeThickness(const std::vector<CXFA_Stroke * > & strokes,bool b3DStyle,int32_t nIndex)322 float GetEdgeThickness(const std::vector<CXFA_Stroke*>& strokes,
323 bool b3DStyle,
324 int32_t nIndex) {
325 float fThickness = 0;
326
327 CXFA_Stroke* stroke = strokes[nIndex * 2 + 1];
328 if (stroke->IsVisible()) {
329 if (nIndex == 0)
330 fThickness += 2.5f;
331
332 fThickness += stroke->GetThickness() * (b3DStyle ? 4 : 2);
333 }
334 return fThickness;
335 }
336
SplitDateTime(const WideString & wsDateTime,WideString & wsDate,WideString & wsTime)337 bool SplitDateTime(const WideString& wsDateTime,
338 WideString& wsDate,
339 WideString& wsTime) {
340 wsDate = L"";
341 wsTime = L"";
342 if (wsDateTime.IsEmpty())
343 return false;
344
345 auto nSplitIndex = wsDateTime.Find('T');
346 if (!nSplitIndex.has_value())
347 nSplitIndex = wsDateTime.Find(' ');
348 if (!nSplitIndex.has_value())
349 return false;
350
351 wsDate = wsDateTime.Left(nSplitIndex.value());
352 if (!wsDate.IsEmpty()) {
353 if (!std::any_of(wsDate.begin(), wsDate.end(), std::iswdigit))
354 return false;
355 }
356 wsTime = wsDateTime.Right(wsDateTime.GetLength() - nSplitIndex.value() - 1);
357 if (!wsTime.IsEmpty()) {
358 if (!std::any_of(wsTime.begin(), wsTime.end(), std::iswdigit))
359 return false;
360 }
361 return true;
362 }
363
CreateUIChild(CXFA_Node * pNode)364 std::pair<XFA_Element, CXFA_Node*> CreateUIChild(CXFA_Node* pNode) {
365 XFA_Element eType = pNode->GetElementType();
366 XFA_Element eWidgetType = eType;
367 if (eType != XFA_Element::Field && eType != XFA_Element::Draw)
368 return {eWidgetType, nullptr};
369
370 eWidgetType = XFA_Element::Unknown;
371 XFA_Element eUIType = XFA_Element::Unknown;
372 auto* defValue =
373 pNode->JSObject()->GetOrCreateProperty<CXFA_Value>(0, XFA_Element::Value);
374 XFA_Element eValueType =
375 defValue ? defValue->GetChildValueClassID() : XFA_Element::Unknown;
376 switch (eValueType) {
377 case XFA_Element::Boolean:
378 eUIType = XFA_Element::CheckButton;
379 break;
380 case XFA_Element::Integer:
381 case XFA_Element::Decimal:
382 case XFA_Element::Float:
383 eUIType = XFA_Element::NumericEdit;
384 break;
385 case XFA_Element::ExData:
386 case XFA_Element::Text:
387 eUIType = XFA_Element::TextEdit;
388 eWidgetType = XFA_Element::Text;
389 break;
390 case XFA_Element::Date:
391 case XFA_Element::Time:
392 case XFA_Element::DateTime:
393 eUIType = XFA_Element::DateTimeEdit;
394 break;
395 case XFA_Element::Image:
396 eUIType = XFA_Element::ImageEdit;
397 eWidgetType = XFA_Element::Image;
398 break;
399 case XFA_Element::Arc:
400 case XFA_Element::Line:
401 case XFA_Element::Rectangle:
402 eUIType = XFA_Element::DefaultUi;
403 eWidgetType = eValueType;
404 break;
405 default:
406 break;
407 }
408
409 CXFA_Node* pUIChild = nullptr;
410 CXFA_Ui* pUI =
411 pNode->JSObject()->GetOrCreateProperty<CXFA_Ui>(0, XFA_Element::Ui);
412 CXFA_Node* pChild = pUI ? pUI->GetFirstChild() : nullptr;
413 for (; pChild; pChild = pChild->GetNextSibling()) {
414 XFA_Element eChildType = pChild->GetElementType();
415 if (eChildType == XFA_Element::Extras ||
416 eChildType == XFA_Element::Picture) {
417 continue;
418 }
419
420 auto node = CXFA_Node::Create(pChild->GetDocument(), XFA_Element::Ui,
421 XFA_PacketType::Form);
422 if (node && node->HasPropertyFlags(eChildType, XFA_PROPERTYFLAG_OneOf)) {
423 pUIChild = pChild;
424 break;
425 }
426 }
427
428 if (eType == XFA_Element::Draw) {
429 XFA_Element eDraw =
430 pUIChild ? pUIChild->GetElementType() : XFA_Element::Unknown;
431 switch (eDraw) {
432 case XFA_Element::TextEdit:
433 eWidgetType = XFA_Element::Text;
434 break;
435 case XFA_Element::ImageEdit:
436 eWidgetType = XFA_Element::Image;
437 break;
438 default:
439 eWidgetType = eWidgetType == XFA_Element::Unknown ? XFA_Element::Text
440 : eWidgetType;
441 break;
442 }
443 } else {
444 if (pUIChild && pUIChild->GetElementType() == XFA_Element::DefaultUi) {
445 eWidgetType = XFA_Element::TextEdit;
446 } else {
447 eWidgetType =
448 pUIChild ? pUIChild->GetElementType()
449 : (eUIType == XFA_Element::Unknown ? XFA_Element::TextEdit
450 : eUIType);
451 }
452 }
453
454 if (!pUIChild) {
455 if (eUIType == XFA_Element::Unknown) {
456 eUIType = XFA_Element::TextEdit;
457 if (defValue) {
458 defValue->JSObject()->GetOrCreateProperty<CXFA_Text>(0,
459 XFA_Element::Text);
460 }
461 }
462 return {eWidgetType,
463 pUI ? pUI->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eUIType)
464 : nullptr};
465 }
466
467 if (eUIType != XFA_Element::Unknown)
468 return {eWidgetType, pUIChild};
469
470 switch (pUIChild->GetElementType()) {
471 case XFA_Element::CheckButton: {
472 eValueType = XFA_Element::Text;
473 if (CXFA_Items* pItems =
474 pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false)) {
475 if (CXFA_Node* pItem =
476 pItems->GetChild<CXFA_Node>(0, XFA_Element::Unknown, false)) {
477 eValueType = pItem->GetElementType();
478 }
479 }
480 break;
481 }
482 case XFA_Element::DateTimeEdit:
483 eValueType = XFA_Element::DateTime;
484 break;
485 case XFA_Element::ImageEdit:
486 eValueType = XFA_Element::Image;
487 break;
488 case XFA_Element::NumericEdit:
489 eValueType = XFA_Element::Float;
490 break;
491 case XFA_Element::ChoiceList: {
492 eValueType = (pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
493 XFA_AttributeEnum::MultiSelect)
494 ? XFA_Element::ExData
495 : XFA_Element::Text;
496 break;
497 }
498 case XFA_Element::Barcode:
499 case XFA_Element::Button:
500 case XFA_Element::PasswordEdit:
501 case XFA_Element::Signature:
502 case XFA_Element::TextEdit:
503 default:
504 eValueType = XFA_Element::Text;
505 break;
506 }
507 if (defValue)
508 defValue->JSObject()->GetOrCreateProperty<CXFA_Node>(0, eValueType);
509
510 return {eWidgetType, pUIChild};
511 }
512
513 } // namespace
514
CXFA_WidgetAcc(CXFA_Node * pNode)515 CXFA_WidgetAcc::CXFA_WidgetAcc(CXFA_Node* pNode)
516 : m_bIsNull(true),
517 m_bPreNull(true),
518 m_pUiChildNode(nullptr),
519 m_eUIType(XFA_Element::Unknown),
520 m_pNode(pNode) {}
521
522 CXFA_WidgetAcc::~CXFA_WidgetAcc() = default;
523
ResetData()524 void CXFA_WidgetAcc::ResetData() {
525 WideString wsValue;
526 XFA_Element eUIType = GetUIType();
527 switch (eUIType) {
528 case XFA_Element::ImageEdit: {
529 CXFA_Value* imageValue = m_pNode->GetDefaultValueIfExists();
530 CXFA_Image* image = imageValue ? imageValue->GetImageIfExists() : nullptr;
531 WideString wsContentType, wsHref;
532 if (image) {
533 wsValue = image->GetContent();
534 wsContentType = image->GetContentType();
535 wsHref = image->GetHref();
536 }
537 SetImageEdit(wsContentType, wsHref, wsValue);
538 break;
539 }
540 case XFA_Element::ExclGroup: {
541 CXFA_Node* pNextChild = m_pNode->GetFirstContainerChild();
542 while (pNextChild) {
543 CXFA_Node* pChild = pNextChild;
544 CXFA_WidgetAcc* pAcc = pChild->GetWidgetAcc();
545 if (!pAcc)
546 continue;
547
548 bool done = false;
549 if (wsValue.IsEmpty()) {
550 CXFA_Value* defValue = pAcc->GetNode()->GetDefaultValueIfExists();
551 if (defValue) {
552 wsValue = defValue->GetChildValueContent();
553 SetValue(XFA_VALUEPICTURE_Raw, wsValue);
554 pAcc->SetValue(XFA_VALUEPICTURE_Raw, wsValue);
555 done = true;
556 }
557 }
558 if (!done) {
559 CXFA_Items* pItems =
560 pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
561 if (!pItems)
562 continue;
563
564 WideString itemText;
565 if (pItems->CountChildren(XFA_Element::Unknown, false) > 1) {
566 itemText =
567 pItems->GetChild<CXFA_Node>(1, XFA_Element::Unknown, false)
568 ->JSObject()
569 ->GetContent(false);
570 }
571 pAcc->SetValue(XFA_VALUEPICTURE_Raw, itemText);
572 }
573 pNextChild = pChild->GetNextContainerSibling();
574 }
575 break;
576 }
577 case XFA_Element::ChoiceList:
578 ClearAllSelections();
579 default: {
580 CXFA_Value* defValue = m_pNode->GetDefaultValueIfExists();
581 if (defValue)
582 wsValue = defValue->GetChildValueContent();
583
584 SetValue(XFA_VALUEPICTURE_Raw, wsValue);
585 break;
586 }
587 }
588 }
589
SetImageEdit(const WideString & wsContentType,const WideString & wsHref,const WideString & wsData)590 void CXFA_WidgetAcc::SetImageEdit(const WideString& wsContentType,
591 const WideString& wsHref,
592 const WideString& wsData) {
593 CXFA_Value* formValue = m_pNode->GetFormValueIfExists();
594 CXFA_Image* image = formValue ? formValue->GetImageIfExists() : nullptr;
595 if (image) {
596 image->SetContentType(WideString(wsContentType));
597 image->SetHref(wsHref);
598 }
599
600 m_pNode->JSObject()->SetContent(wsData, GetFormatDataValue(wsData), true,
601 false, true);
602
603 CXFA_Node* pBind = m_pNode->GetBindData();
604 if (!pBind) {
605 if (image)
606 image->SetTransferEncoding(XFA_AttributeEnum::Base64);
607 return;
608 }
609 pBind->JSObject()->SetCData(XFA_Attribute::ContentType, wsContentType, false,
610 false);
611 CXFA_Node* pHrefNode = pBind->GetFirstChild();
612 if (pHrefNode) {
613 pHrefNode->JSObject()->SetCData(XFA_Attribute::Value, wsHref, false, false);
614 } else {
615 CFX_XMLNode* pXMLNode = pBind->GetXMLMappingNode();
616 ASSERT(pXMLNode && pXMLNode->GetType() == FX_XMLNODE_Element);
617 static_cast<CFX_XMLElement*>(pXMLNode)->SetString(L"href", wsHref);
618 }
619 }
620
GetNextWidget(CXFA_FFWidget * pWidget)621 CXFA_FFWidget* CXFA_WidgetAcc::GetNextWidget(CXFA_FFWidget* pWidget) {
622 return static_cast<CXFA_FFWidget*>(pWidget->GetNext());
623 }
624
UpdateUIDisplay(CXFA_FFDocView * docView,CXFA_FFWidget * pExcept)625 void CXFA_WidgetAcc::UpdateUIDisplay(CXFA_FFDocView* docView,
626 CXFA_FFWidget* pExcept) {
627 CXFA_FFWidget* pWidget = docView->GetWidgetForNode(m_pNode);
628 for (; pWidget; pWidget = GetNextWidget(pWidget)) {
629 if (pWidget == pExcept || !pWidget->IsLoaded() ||
630 (GetUIType() != XFA_Element::CheckButton && pWidget->IsFocused())) {
631 continue;
632 }
633 pWidget->UpdateFWLData();
634 pWidget->AddInvalidateRect();
635 }
636 }
637
CalcCaptionSize(CXFA_FFDoc * doc,CFX_SizeF & szCap)638 void CXFA_WidgetAcc::CalcCaptionSize(CXFA_FFDoc* doc, CFX_SizeF& szCap) {
639 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
640 if (!caption || !caption->IsVisible())
641 return;
642
643 LoadCaption(doc);
644
645 XFA_Element eUIType = GetUIType();
646 XFA_AttributeEnum iCapPlacement = caption->GetPlacementType();
647 float fCapReserve = caption->GetReserve();
648 const bool bVert = iCapPlacement == XFA_AttributeEnum::Top ||
649 iCapPlacement == XFA_AttributeEnum::Bottom;
650 const bool bReserveExit = fCapReserve > 0.01;
651 CXFA_TextLayout* pCapTextLayout =
652 static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
653 ->m_pCapTextLayout.get();
654 if (pCapTextLayout) {
655 if (!bVert && eUIType != XFA_Element::Button)
656 szCap.width = fCapReserve;
657
658 CFX_SizeF minSize;
659 szCap = pCapTextLayout->CalcSize(minSize, szCap);
660 if (bReserveExit)
661 bVert ? szCap.height = fCapReserve : szCap.width = fCapReserve;
662 } else {
663 float fFontSize = 10.0f;
664 CXFA_Font* font = caption->GetFontIfExists();
665 if (font) {
666 fFontSize = font->GetFontSize();
667 } else {
668 CXFA_Font* widgetfont = m_pNode->GetFontIfExists();
669 if (widgetfont)
670 fFontSize = widgetfont->GetFontSize();
671 }
672
673 if (bVert) {
674 szCap.height = fCapReserve > 0 ? fCapReserve : fFontSize;
675 } else {
676 szCap.width = fCapReserve > 0 ? fCapReserve : 0;
677 szCap.height = fFontSize;
678 }
679 }
680
681 CXFA_Margin* captionMargin = caption->GetMarginIfExists();
682 if (!captionMargin)
683 return;
684
685 float fLeftInset = captionMargin->GetLeftInset();
686 float fTopInset = captionMargin->GetTopInset();
687 float fRightInset = captionMargin->GetRightInset();
688 float fBottomInset = captionMargin->GetBottomInset();
689 if (bReserveExit) {
690 bVert ? (szCap.width += fLeftInset + fRightInset)
691 : (szCap.height += fTopInset + fBottomInset);
692 } else {
693 szCap.width += fLeftInset + fRightInset;
694 szCap.height += fTopInset + fBottomInset;
695 }
696 }
697
CalculateFieldAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)698 bool CXFA_WidgetAcc::CalculateFieldAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size) {
699 CFX_SizeF szCap;
700 CalcCaptionSize(doc, szCap);
701
702 CFX_RectF rtUIMargin = GetUIMargin();
703 size.width += rtUIMargin.left + rtUIMargin.width;
704 size.height += rtUIMargin.top + rtUIMargin.height;
705 if (szCap.width > 0 && szCap.height > 0) {
706 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
707 XFA_AttributeEnum placement = caption ? caption->GetPlacementType()
708 : CXFA_Caption::kDefaultPlacementType;
709 switch (placement) {
710 case XFA_AttributeEnum::Left:
711 case XFA_AttributeEnum::Right:
712 case XFA_AttributeEnum::Inline: {
713 size.width += szCap.width;
714 size.height = std::max(size.height, szCap.height);
715 } break;
716 case XFA_AttributeEnum::Top:
717 case XFA_AttributeEnum::Bottom: {
718 size.height += szCap.height;
719 size.width = std::max(size.width, szCap.width);
720 }
721 default:
722 break;
723 }
724 }
725 return CalculateWidgetAutoSize(size);
726 }
727
CalculateWidgetAutoSize(CFX_SizeF & size)728 bool CXFA_WidgetAcc::CalculateWidgetAutoSize(CFX_SizeF& size) {
729 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
730 if (margin) {
731 size.width += margin->GetLeftInset() + margin->GetRightInset();
732 size.height += margin->GetTopInset() + margin->GetBottomInset();
733 }
734
735 CXFA_Para* para = m_pNode->GetParaIfExists();
736 if (para)
737 size.width += para->GetMarginLeft() + para->GetTextIndent();
738
739 Optional<float> width = m_pNode->TryWidth();
740 if (width) {
741 size.width = *width;
742 } else {
743 Optional<float> min = m_pNode->TryMinWidth();
744 if (min)
745 size.width = std::max(size.width, *min);
746
747 Optional<float> max = m_pNode->TryMaxWidth();
748 if (max && *max > 0)
749 size.width = std::min(size.width, *max);
750 }
751
752 Optional<float> height = m_pNode->TryHeight();
753 if (height) {
754 size.height = *height;
755 } else {
756 Optional<float> min = m_pNode->TryMinHeight();
757 if (min)
758 size.height = std::max(size.height, *min);
759
760 Optional<float> max = m_pNode->TryMaxHeight();
761 if (max && *max > 0)
762 size.height = std::min(size.height, *max);
763 }
764 return true;
765 }
766
CalculateTextContentSize(CXFA_FFDoc * doc,CFX_SizeF & size)767 void CXFA_WidgetAcc::CalculateTextContentSize(CXFA_FFDoc* doc,
768 CFX_SizeF& size) {
769 float fFontSize = m_pNode->GetFontSize();
770 WideString wsText = GetValue(XFA_VALUEPICTURE_Display);
771 if (wsText.IsEmpty()) {
772 size.height += fFontSize;
773 return;
774 }
775
776 wchar_t wcEnter = '\n';
777 wchar_t wsLast = wsText[wsText.GetLength() - 1];
778 if (wsLast == wcEnter)
779 wsText = wsText + wcEnter;
780
781 CXFA_FieldLayoutData* layoutData =
782 static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
783 if (!layoutData->m_pTextOut) {
784 layoutData->m_pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
785 CFDE_TextOut* pTextOut = layoutData->m_pTextOut.get();
786 pTextOut->SetFont(GetFDEFont(doc));
787 pTextOut->SetFontSize(fFontSize);
788 pTextOut->SetLineBreakTolerance(fFontSize * 0.2f);
789 pTextOut->SetLineSpace(m_pNode->GetLineHeight());
790
791 FDE_TextStyle dwStyles;
792 dwStyles.last_line_height_ = true;
793 if (GetUIType() == XFA_Element::TextEdit && IsMultiLine())
794 dwStyles.line_wrap_ = true;
795
796 pTextOut->SetStyles(dwStyles);
797 }
798 layoutData->m_pTextOut->CalcLogicSize(wsText, size);
799 }
800
CalculateTextEditAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)801 bool CXFA_WidgetAcc::CalculateTextEditAutoSize(CXFA_FFDoc* doc,
802 CFX_SizeF& size) {
803 if (size.width > 0) {
804 CFX_SizeF szOrz = size;
805 CFX_SizeF szCap;
806 CalcCaptionSize(doc, szCap);
807 bool bCapExit = szCap.width > 0.01 && szCap.height > 0.01;
808 XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
809 if (bCapExit) {
810 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
811 iCapPlacement = caption ? caption->GetPlacementType()
812 : CXFA_Caption::kDefaultPlacementType;
813 switch (iCapPlacement) {
814 case XFA_AttributeEnum::Left:
815 case XFA_AttributeEnum::Right:
816 case XFA_AttributeEnum::Inline: {
817 size.width -= szCap.width;
818 }
819 default:
820 break;
821 }
822 }
823 CFX_RectF rtUIMargin = GetUIMargin();
824 size.width -= rtUIMargin.left + rtUIMargin.width;
825 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
826 if (margin)
827 size.width -= margin->GetLeftInset() + margin->GetRightInset();
828
829 CalculateTextContentSize(doc, size);
830 size.height += rtUIMargin.top + rtUIMargin.height;
831 if (bCapExit) {
832 switch (iCapPlacement) {
833 case XFA_AttributeEnum::Left:
834 case XFA_AttributeEnum::Right:
835 case XFA_AttributeEnum::Inline: {
836 size.height = std::max(size.height, szCap.height);
837 } break;
838 case XFA_AttributeEnum::Top:
839 case XFA_AttributeEnum::Bottom: {
840 size.height += szCap.height;
841 }
842 default:
843 break;
844 }
845 }
846 size.width = szOrz.width;
847 return CalculateWidgetAutoSize(size);
848 }
849 CalculateTextContentSize(doc, size);
850 return CalculateFieldAutoSize(doc, size);
851 }
852
CalculateCheckButtonAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)853 bool CXFA_WidgetAcc::CalculateCheckButtonAutoSize(CXFA_FFDoc* doc,
854 CFX_SizeF& size) {
855 float fCheckSize = GetCheckButtonSize();
856 size = CFX_SizeF(fCheckSize, fCheckSize);
857 return CalculateFieldAutoSize(doc, size);
858 }
859
CalculatePushButtonAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)860 bool CXFA_WidgetAcc::CalculatePushButtonAutoSize(CXFA_FFDoc* doc,
861 CFX_SizeF& size) {
862 CalcCaptionSize(doc, size);
863 return CalculateWidgetAutoSize(size);
864 }
865
CalculateImageSize(float img_width,float img_height,float dpi_x,float dpi_y)866 CFX_SizeF CXFA_WidgetAcc::CalculateImageSize(float img_width,
867 float img_height,
868 float dpi_x,
869 float dpi_y) {
870 CFX_RectF rtImage(0, 0, XFA_UnitPx2Pt(img_width, dpi_x),
871 XFA_UnitPx2Pt(img_height, dpi_y));
872
873 CFX_RectF rtFit;
874 Optional<float> width = m_pNode->TryWidth();
875 if (width) {
876 rtFit.width = *width;
877 GetWidthWithoutMargin(rtFit.width);
878 } else {
879 rtFit.width = rtImage.width;
880 }
881
882 Optional<float> height = m_pNode->TryHeight();
883 if (height) {
884 rtFit.height = *height;
885 GetHeightWithoutMargin(rtFit.height);
886 } else {
887 rtFit.height = rtImage.height;
888 }
889
890 return rtFit.Size();
891 }
892
CalculateImageAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)893 bool CXFA_WidgetAcc::CalculateImageAutoSize(CXFA_FFDoc* doc, CFX_SizeF& size) {
894 if (!GetImageImage())
895 LoadImageImage(doc);
896
897 size.clear();
898 RetainPtr<CFX_DIBitmap> pBitmap = GetImageImage();
899 if (!pBitmap)
900 return CalculateWidgetAutoSize(size);
901
902 int32_t iImageXDpi = 0;
903 int32_t iImageYDpi = 0;
904 GetImageDpi(iImageXDpi, iImageYDpi);
905
906 size = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
907 iImageXDpi, iImageYDpi);
908 return CalculateWidgetAutoSize(size);
909 }
910
CalculateImageEditAutoSize(CXFA_FFDoc * doc,CFX_SizeF & size)911 bool CXFA_WidgetAcc::CalculateImageEditAutoSize(CXFA_FFDoc* doc,
912 CFX_SizeF& size) {
913 if (!GetImageEditImage())
914 LoadImageEditImage(doc);
915
916 size.clear();
917 RetainPtr<CFX_DIBitmap> pBitmap = GetImageEditImage();
918 if (!pBitmap)
919 return CalculateFieldAutoSize(doc, size);
920
921 int32_t iImageXDpi = 0;
922 int32_t iImageYDpi = 0;
923 GetImageEditDpi(iImageXDpi, iImageYDpi);
924
925 size = CalculateImageSize(pBitmap->GetWidth(), pBitmap->GetHeight(),
926 iImageXDpi, iImageYDpi);
927 return CalculateFieldAutoSize(doc, size);
928 }
929
LoadImageImage(CXFA_FFDoc * doc)930 bool CXFA_WidgetAcc::LoadImageImage(CXFA_FFDoc* doc) {
931 InitLayoutData();
932 return static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
933 ->LoadImageData(doc, this);
934 }
935
LoadImageEditImage(CXFA_FFDoc * doc)936 bool CXFA_WidgetAcc::LoadImageEditImage(CXFA_FFDoc* doc) {
937 InitLayoutData();
938 return static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
939 ->LoadImageData(doc, this);
940 }
941
GetImageDpi(int32_t & iImageXDpi,int32_t & iImageYDpi)942 void CXFA_WidgetAcc::GetImageDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
943 CXFA_ImageLayoutData* pData =
944 static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
945 iImageXDpi = pData->m_iImageXDpi;
946 iImageYDpi = pData->m_iImageYDpi;
947 }
948
GetImageEditDpi(int32_t & iImageXDpi,int32_t & iImageYDpi)949 void CXFA_WidgetAcc::GetImageEditDpi(int32_t& iImageXDpi, int32_t& iImageYDpi) {
950 CXFA_ImageEditData* pData =
951 static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
952 iImageXDpi = pData->m_iImageXDpi;
953 iImageYDpi = pData->m_iImageYDpi;
954 }
955
LoadText(CXFA_FFDoc * doc)956 void CXFA_WidgetAcc::LoadText(CXFA_FFDoc* doc) {
957 InitLayoutData();
958 static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->LoadText(doc, this);
959 }
960
CalculateWidgetAutoWidth(float fWidthCalc)961 float CXFA_WidgetAcc::CalculateWidgetAutoWidth(float fWidthCalc) {
962 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
963 if (margin)
964 fWidthCalc += margin->GetLeftInset() + margin->GetRightInset();
965
966 Optional<float> min = m_pNode->TryMinWidth();
967 if (min)
968 fWidthCalc = std::max(fWidthCalc, *min);
969
970 Optional<float> max = m_pNode->TryMaxWidth();
971 if (max && *max > 0)
972 fWidthCalc = std::min(fWidthCalc, *max);
973
974 return fWidthCalc;
975 }
976
GetWidthWithoutMargin(float fWidthCalc)977 float CXFA_WidgetAcc::GetWidthWithoutMargin(float fWidthCalc) {
978 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
979 if (margin)
980 fWidthCalc -= margin->GetLeftInset() + margin->GetRightInset();
981 return fWidthCalc;
982 }
983
CalculateWidgetAutoHeight(float fHeightCalc)984 float CXFA_WidgetAcc::CalculateWidgetAutoHeight(float fHeightCalc) {
985 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
986 if (margin)
987 fHeightCalc += margin->GetTopInset() + margin->GetBottomInset();
988
989 Optional<float> min = m_pNode->TryMinHeight();
990 if (min)
991 fHeightCalc = std::max(fHeightCalc, *min);
992
993 Optional<float> max = m_pNode->TryMaxHeight();
994 if (max && *max > 0)
995 fHeightCalc = std::min(fHeightCalc, *max);
996
997 return fHeightCalc;
998 }
999
GetHeightWithoutMargin(float fHeightCalc)1000 float CXFA_WidgetAcc::GetHeightWithoutMargin(float fHeightCalc) {
1001 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
1002 if (margin)
1003 fHeightCalc -= margin->GetTopInset() + margin->GetBottomInset();
1004 return fHeightCalc;
1005 }
1006
StartWidgetLayout(CXFA_FFDoc * doc,float & fCalcWidth,float & fCalcHeight)1007 void CXFA_WidgetAcc::StartWidgetLayout(CXFA_FFDoc* doc,
1008 float& fCalcWidth,
1009 float& fCalcHeight) {
1010 InitLayoutData();
1011
1012 XFA_Element eUIType = GetUIType();
1013 if (eUIType == XFA_Element::Text) {
1014 m_pLayoutData->m_fWidgetHeight = m_pNode->TryHeight().value_or(-1);
1015 StartTextLayout(doc, fCalcWidth, fCalcHeight);
1016 return;
1017 }
1018 if (fCalcWidth > 0 && fCalcHeight > 0)
1019 return;
1020
1021 m_pLayoutData->m_fWidgetHeight = -1;
1022 float fWidth = 0;
1023 if (fCalcWidth > 0 && fCalcHeight < 0) {
1024 Optional<float> height = m_pNode->TryHeight();
1025 if (height)
1026 fCalcHeight = *height;
1027 else
1028 CalculateAccWidthAndHeight(doc, eUIType, fCalcWidth, fCalcHeight);
1029
1030 m_pLayoutData->m_fWidgetHeight = fCalcHeight;
1031 return;
1032 }
1033 if (fCalcWidth < 0 && fCalcHeight < 0) {
1034 Optional<float> height;
1035 Optional<float> width = m_pNode->TryWidth();
1036 if (width) {
1037 fWidth = *width;
1038
1039 height = m_pNode->TryHeight();
1040 if (height)
1041 fCalcHeight = *height;
1042 }
1043 if (!width || !height)
1044 CalculateAccWidthAndHeight(doc, eUIType, fWidth, fCalcHeight);
1045
1046 fCalcWidth = fWidth;
1047 }
1048 m_pLayoutData->m_fWidgetHeight = fCalcHeight;
1049 }
1050
CalculateAccWidthAndHeight(CXFA_FFDoc * doc,XFA_Element eUIType,float & fWidth,float & fCalcHeight)1051 void CXFA_WidgetAcc::CalculateAccWidthAndHeight(CXFA_FFDoc* doc,
1052 XFA_Element eUIType,
1053 float& fWidth,
1054 float& fCalcHeight) {
1055 CFX_SizeF sz(fWidth, m_pLayoutData->m_fWidgetHeight);
1056 switch (eUIType) {
1057 case XFA_Element::Barcode:
1058 case XFA_Element::ChoiceList:
1059 case XFA_Element::Signature:
1060 CalculateFieldAutoSize(doc, sz);
1061 break;
1062 case XFA_Element::ImageEdit:
1063 CalculateImageEditAutoSize(doc, sz);
1064 break;
1065 case XFA_Element::Button:
1066 CalculatePushButtonAutoSize(doc, sz);
1067 break;
1068 case XFA_Element::CheckButton:
1069 CalculateCheckButtonAutoSize(doc, sz);
1070 break;
1071 case XFA_Element::DateTimeEdit:
1072 case XFA_Element::NumericEdit:
1073 case XFA_Element::PasswordEdit:
1074 case XFA_Element::TextEdit:
1075 CalculateTextEditAutoSize(doc, sz);
1076 break;
1077 case XFA_Element::Image:
1078 CalculateImageAutoSize(doc, sz);
1079 break;
1080 case XFA_Element::Arc:
1081 case XFA_Element::Line:
1082 case XFA_Element::Rectangle:
1083 case XFA_Element::Subform:
1084 case XFA_Element::ExclGroup:
1085 CalculateWidgetAutoSize(sz);
1086 break;
1087 default:
1088 break;
1089 }
1090 fWidth = sz.width;
1091 m_pLayoutData->m_fWidgetHeight = sz.height;
1092 fCalcHeight = sz.height;
1093 }
1094
FindSplitPos(CXFA_FFDocView * docView,int32_t iBlockIndex,float & fCalcHeight)1095 bool CXFA_WidgetAcc::FindSplitPos(CXFA_FFDocView* docView,
1096 int32_t iBlockIndex,
1097 float& fCalcHeight) {
1098 XFA_Element eUIType = GetUIType();
1099 if (eUIType == XFA_Element::Subform)
1100 return false;
1101
1102 if (eUIType != XFA_Element::Text && eUIType != XFA_Element::TextEdit &&
1103 eUIType != XFA_Element::NumericEdit &&
1104 eUIType != XFA_Element::PasswordEdit) {
1105 fCalcHeight = 0;
1106 return true;
1107 }
1108
1109 float fTopInset = 0;
1110 float fBottomInset = 0;
1111 if (iBlockIndex == 0) {
1112 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
1113 if (margin) {
1114 fTopInset = margin->GetTopInset();
1115 fBottomInset = margin->GetBottomInset();
1116 }
1117
1118 CFX_RectF rtUIMargin = GetUIMargin();
1119 fTopInset += rtUIMargin.top;
1120 fBottomInset += rtUIMargin.width;
1121 }
1122 if (eUIType == XFA_Element::Text) {
1123 float fHeight = fCalcHeight;
1124 if (iBlockIndex == 0) {
1125 fCalcHeight = fCalcHeight - fTopInset;
1126 if (fCalcHeight < 0)
1127 fCalcHeight = 0;
1128 }
1129
1130 CXFA_TextLayout* pTextLayout =
1131 static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
1132 fCalcHeight =
1133 pTextLayout->DoLayout(iBlockIndex, fCalcHeight, fCalcHeight,
1134 m_pLayoutData->m_fWidgetHeight - fTopInset);
1135 if (fCalcHeight != 0) {
1136 if (iBlockIndex == 0)
1137 fCalcHeight = fCalcHeight + fTopInset;
1138 if (fabs(fHeight - fCalcHeight) < XFA_FLOAT_PERCISION)
1139 return false;
1140 }
1141 return true;
1142 }
1143 XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
1144 float fCapReserve = 0;
1145 if (iBlockIndex == 0) {
1146 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
1147 if (caption && !caption->IsHidden()) {
1148 iCapPlacement = caption->GetPlacementType();
1149 fCapReserve = caption->GetReserve();
1150 }
1151 if (iCapPlacement == XFA_AttributeEnum::Top &&
1152 fCalcHeight < fCapReserve + fTopInset) {
1153 fCalcHeight = 0;
1154 return true;
1155 }
1156 if (iCapPlacement == XFA_AttributeEnum::Bottom &&
1157 m_pLayoutData->m_fWidgetHeight - fCapReserve - fBottomInset) {
1158 fCalcHeight = 0;
1159 return true;
1160 }
1161 if (iCapPlacement != XFA_AttributeEnum::Top)
1162 fCapReserve = 0;
1163 }
1164 CXFA_FieldLayoutData* pFieldData =
1165 static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get());
1166 int32_t iLinesCount = 0;
1167 float fHeight = m_pLayoutData->m_fWidgetHeight;
1168 if (GetValue(XFA_VALUEPICTURE_Display).IsEmpty()) {
1169 iLinesCount = 1;
1170 } else {
1171 if (!pFieldData->m_pTextOut) {
1172 // TODO(dsinclair): Inline fWidth when the 2nd param of
1173 // CalculateAccWidthAndHeight isn't a ref-param.
1174 float fWidth = m_pNode->TryWidth().value_or(0);
1175 CalculateAccWidthAndHeight(docView->GetDoc(), eUIType, fWidth, fHeight);
1176 }
1177 iLinesCount = pFieldData->m_pTextOut->GetTotalLines();
1178 }
1179 std::vector<float>* pFieldArray = &pFieldData->m_FieldSplitArray;
1180 int32_t iFieldSplitCount = pdfium::CollectionSize<int32_t>(*pFieldArray);
1181 for (int32_t i = 0; i < iBlockIndex * 3; i += 3) {
1182 iLinesCount -= (int32_t)(*pFieldArray)[i + 1];
1183 fHeight -= (*pFieldArray)[i + 2];
1184 }
1185 if (iLinesCount == 0)
1186 return false;
1187
1188 float fLineHeight = m_pNode->GetLineHeight();
1189 float fFontSize = m_pNode->GetFontSize();
1190 float fTextHeight = iLinesCount * fLineHeight - fLineHeight + fFontSize;
1191 float fSpaceAbove = 0;
1192 float fStartOffset = 0;
1193 if (fHeight > 0.1f && iBlockIndex == 0) {
1194 fStartOffset = fTopInset;
1195 fHeight -= (fTopInset + fBottomInset);
1196 CXFA_Para* para = m_pNode->GetParaIfExists();
1197 if (para) {
1198 fSpaceAbove = para->GetSpaceAbove();
1199 float fSpaceBelow = para->GetSpaceBelow();
1200 fHeight -= (fSpaceAbove + fSpaceBelow);
1201 switch (para->GetVerticalAlign()) {
1202 case XFA_AttributeEnum::Top:
1203 fStartOffset += fSpaceAbove;
1204 break;
1205 case XFA_AttributeEnum::Middle:
1206 fStartOffset += ((fHeight - fTextHeight) / 2 + fSpaceAbove);
1207 break;
1208 case XFA_AttributeEnum::Bottom:
1209 fStartOffset += (fHeight - fTextHeight + fSpaceAbove);
1210 break;
1211 default:
1212 NOTREACHED();
1213 break;
1214 }
1215 }
1216 if (fStartOffset < 0.1f)
1217 fStartOffset = 0;
1218 }
1219 for (int32_t i = iBlockIndex - 1; iBlockIndex > 0 && i < iBlockIndex; i++) {
1220 fStartOffset = (*pFieldArray)[i * 3] - (*pFieldArray)[i * 3 + 2];
1221 if (fStartOffset < 0.1f)
1222 fStartOffset = 0;
1223 }
1224 if (iFieldSplitCount / 3 == (iBlockIndex + 1))
1225 (*pFieldArray)[0] = fStartOffset;
1226 else
1227 pFieldArray->push_back(fStartOffset);
1228
1229 XFA_VERSION version = docView->GetDoc()->GetXFADoc()->GetCurVersionMode();
1230 bool bCanSplitNoContent = false;
1231 XFA_AttributeEnum eLayoutMode = GetNode()
1232 ->GetParent()
1233 ->JSObject()
1234 ->TryEnum(XFA_Attribute::Layout, true)
1235 .value_or(XFA_AttributeEnum::Position);
1236 if ((eLayoutMode == XFA_AttributeEnum::Position ||
1237 eLayoutMode == XFA_AttributeEnum::Tb ||
1238 eLayoutMode == XFA_AttributeEnum::Row ||
1239 eLayoutMode == XFA_AttributeEnum::Table) &&
1240 version > XFA_VERSION_208) {
1241 bCanSplitNoContent = true;
1242 }
1243 if ((eLayoutMode == XFA_AttributeEnum::Tb ||
1244 eLayoutMode == XFA_AttributeEnum::Row ||
1245 eLayoutMode == XFA_AttributeEnum::Table) &&
1246 version <= XFA_VERSION_208) {
1247 if (fStartOffset < fCalcHeight) {
1248 bCanSplitNoContent = true;
1249 } else {
1250 fCalcHeight = 0;
1251 return true;
1252 }
1253 }
1254 if (bCanSplitNoContent) {
1255 if ((fCalcHeight - fTopInset - fSpaceAbove < fLineHeight)) {
1256 fCalcHeight = 0;
1257 return true;
1258 }
1259 if (fStartOffset + XFA_FLOAT_PERCISION >= fCalcHeight) {
1260 if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
1261 (*pFieldArray)[iBlockIndex * 3 + 1] = 0;
1262 (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
1263 } else {
1264 pFieldArray->push_back(0);
1265 pFieldArray->push_back(fCalcHeight);
1266 }
1267 return false;
1268 }
1269 if (fCalcHeight - fStartOffset < fLineHeight) {
1270 fCalcHeight = fStartOffset;
1271 if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
1272 (*pFieldArray)[iBlockIndex * 3 + 1] = 0;
1273 (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
1274 } else {
1275 pFieldArray->push_back(0);
1276 pFieldArray->push_back(fCalcHeight);
1277 }
1278 return true;
1279 }
1280 float fTextNum =
1281 fCalcHeight + XFA_FLOAT_PERCISION - fCapReserve - fStartOffset;
1282 int32_t iLineNum =
1283 (int32_t)((fTextNum + (fLineHeight - fFontSize)) / fLineHeight);
1284 if (iLineNum >= iLinesCount) {
1285 if (fCalcHeight - fStartOffset - fTextHeight >= fFontSize) {
1286 if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
1287 (*pFieldArray)[iBlockIndex * 3 + 1] = (float)iLinesCount;
1288 (*pFieldArray)[iBlockIndex * 3 + 2] = fCalcHeight;
1289 } else {
1290 pFieldArray->push_back((float)iLinesCount);
1291 pFieldArray->push_back(fCalcHeight);
1292 }
1293 return false;
1294 }
1295 if (fHeight - fStartOffset - fTextHeight < fFontSize) {
1296 iLineNum -= 1;
1297 if (iLineNum == 0) {
1298 fCalcHeight = 0;
1299 return true;
1300 }
1301 } else {
1302 iLineNum = (int32_t)(fTextNum / fLineHeight);
1303 }
1304 }
1305 if (iLineNum > 0) {
1306 float fSplitHeight = iLineNum * fLineHeight + fCapReserve + fStartOffset;
1307 if (iFieldSplitCount / 3 == (iBlockIndex + 1)) {
1308 (*pFieldArray)[iBlockIndex * 3 + 1] = (float)iLineNum;
1309 (*pFieldArray)[iBlockIndex * 3 + 2] = fSplitHeight;
1310 } else {
1311 pFieldArray->push_back((float)iLineNum);
1312 pFieldArray->push_back(fSplitHeight);
1313 }
1314 if (fabs(fSplitHeight - fCalcHeight) < XFA_FLOAT_PERCISION)
1315 return false;
1316
1317 fCalcHeight = fSplitHeight;
1318 return true;
1319 }
1320 }
1321 fCalcHeight = 0;
1322 return true;
1323 }
1324
InitLayoutData()1325 void CXFA_WidgetAcc::InitLayoutData() {
1326 if (m_pLayoutData)
1327 return;
1328
1329 switch (GetUIType()) {
1330 case XFA_Element::Text:
1331 m_pLayoutData = pdfium::MakeUnique<CXFA_TextLayoutData>();
1332 return;
1333 case XFA_Element::TextEdit:
1334 m_pLayoutData = pdfium::MakeUnique<CXFA_TextEditData>();
1335 return;
1336 case XFA_Element::Image:
1337 m_pLayoutData = pdfium::MakeUnique<CXFA_ImageLayoutData>();
1338 return;
1339 case XFA_Element::ImageEdit:
1340 m_pLayoutData = pdfium::MakeUnique<CXFA_ImageEditData>();
1341 return;
1342 default:
1343 break;
1344 }
1345 if (m_pNode && m_pNode->GetElementType() == XFA_Element::Field) {
1346 m_pLayoutData = pdfium::MakeUnique<CXFA_FieldLayoutData>();
1347 return;
1348 }
1349 m_pLayoutData = pdfium::MakeUnique<CXFA_WidgetLayoutData>();
1350 }
1351
StartTextLayout(CXFA_FFDoc * doc,float & fCalcWidth,float & fCalcHeight)1352 void CXFA_WidgetAcc::StartTextLayout(CXFA_FFDoc* doc,
1353 float& fCalcWidth,
1354 float& fCalcHeight) {
1355 LoadText(doc);
1356
1357 CXFA_TextLayout* pTextLayout =
1358 static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->GetTextLayout();
1359 float fTextHeight = 0;
1360 if (fCalcWidth > 0 && fCalcHeight > 0) {
1361 float fWidth = GetWidthWithoutMargin(fCalcWidth);
1362 pTextLayout->StartLayout(fWidth);
1363 fTextHeight = fCalcHeight;
1364 fTextHeight = GetHeightWithoutMargin(fTextHeight);
1365 pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
1366 return;
1367 }
1368 if (fCalcWidth > 0 && fCalcHeight < 0) {
1369 float fWidth = GetWidthWithoutMargin(fCalcWidth);
1370 pTextLayout->StartLayout(fWidth);
1371 }
1372
1373 if (fCalcWidth < 0 && fCalcHeight < 0) {
1374 Optional<float> width = m_pNode->TryWidth();
1375 if (width) {
1376 pTextLayout->StartLayout(GetWidthWithoutMargin(*width));
1377 fCalcWidth = *width;
1378 } else {
1379 float fMaxWidth = CalculateWidgetAutoWidth(pTextLayout->StartLayout(-1));
1380 pTextLayout->StartLayout(GetWidthWithoutMargin(fMaxWidth));
1381 fCalcWidth = fMaxWidth;
1382 }
1383 }
1384
1385 if (m_pLayoutData->m_fWidgetHeight < 0) {
1386 m_pLayoutData->m_fWidgetHeight = pTextLayout->GetLayoutHeight();
1387 m_pLayoutData->m_fWidgetHeight =
1388 CalculateWidgetAutoHeight(m_pLayoutData->m_fWidgetHeight);
1389 }
1390 fTextHeight = m_pLayoutData->m_fWidgetHeight;
1391 fTextHeight = GetHeightWithoutMargin(fTextHeight);
1392 pTextLayout->DoLayout(0, fTextHeight, -1, fTextHeight);
1393 fCalcHeight = m_pLayoutData->m_fWidgetHeight;
1394 }
1395
LoadCaption(CXFA_FFDoc * doc)1396 bool CXFA_WidgetAcc::LoadCaption(CXFA_FFDoc* doc) {
1397 InitLayoutData();
1398 return static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
1399 ->LoadCaption(doc, this);
1400 }
1401
GetCaptionTextLayout()1402 CXFA_TextLayout* CXFA_WidgetAcc::GetCaptionTextLayout() {
1403 return m_pLayoutData
1404 ? static_cast<CXFA_FieldLayoutData*>(m_pLayoutData.get())
1405 ->m_pCapTextLayout.get()
1406 : nullptr;
1407 }
1408
GetTextLayout()1409 CXFA_TextLayout* CXFA_WidgetAcc::GetTextLayout() {
1410 return m_pLayoutData
1411 ? static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())
1412 ->GetTextLayout()
1413 : nullptr;
1414 }
1415
GetImageImage()1416 RetainPtr<CFX_DIBitmap> CXFA_WidgetAcc::GetImageImage() {
1417 return m_pLayoutData
1418 ? static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get())
1419 ->m_pDIBitmap
1420 : nullptr;
1421 }
1422
GetImageEditImage()1423 RetainPtr<CFX_DIBitmap> CXFA_WidgetAcc::GetImageEditImage() {
1424 return m_pLayoutData
1425 ? static_cast<CXFA_ImageEditData*>(m_pLayoutData.get())
1426 ->m_pDIBitmap
1427 : nullptr;
1428 }
1429
SetImageImage(const RetainPtr<CFX_DIBitmap> & newImage)1430 void CXFA_WidgetAcc::SetImageImage(const RetainPtr<CFX_DIBitmap>& newImage) {
1431 CXFA_ImageLayoutData* pData =
1432 static_cast<CXFA_ImageLayoutData*>(m_pLayoutData.get());
1433 if (pData->m_pDIBitmap != newImage)
1434 pData->m_pDIBitmap = newImage;
1435 }
1436
SetImageEditImage(const RetainPtr<CFX_DIBitmap> & newImage)1437 void CXFA_WidgetAcc::SetImageEditImage(
1438 const RetainPtr<CFX_DIBitmap>& newImage) {
1439 CXFA_ImageEditData* pData =
1440 static_cast<CXFA_ImageEditData*>(m_pLayoutData.get());
1441 if (pData->m_pDIBitmap != newImage)
1442 pData->m_pDIBitmap = newImage;
1443 }
1444
GetFDEFont(CXFA_FFDoc * doc)1445 RetainPtr<CFGAS_GEFont> CXFA_WidgetAcc::GetFDEFont(CXFA_FFDoc* doc) {
1446 WideString wsFontName = L"Courier";
1447 uint32_t dwFontStyle = 0;
1448 CXFA_Font* font = m_pNode->GetFontIfExists();
1449 if (font) {
1450 if (font->IsBold())
1451 dwFontStyle |= FXFONT_BOLD;
1452 if (font->IsItalic())
1453 dwFontStyle |= FXFONT_ITALIC;
1454
1455 wsFontName = font->GetTypeface();
1456 }
1457 return doc->GetApp()->GetXFAFontMgr()->GetFont(doc, wsFontName.AsStringView(),
1458 dwFontStyle);
1459 }
1460
GetUIChild()1461 CXFA_Node* CXFA_WidgetAcc::GetUIChild() {
1462 if (m_eUIType == XFA_Element::Unknown)
1463 std::tie(m_eUIType, m_pUiChildNode) = CreateUIChild(m_pNode);
1464 return m_pUiChildNode;
1465 }
1466
GetUIType()1467 XFA_Element CXFA_WidgetAcc::GetUIType() {
1468 GetUIChild();
1469 return m_eUIType;
1470 }
1471
IsOpenAccess() const1472 bool CXFA_WidgetAcc::IsOpenAccess() const {
1473 return m_pNode && m_pNode->IsOpenAccess();
1474 }
1475
GetEventByActivity(XFA_AttributeEnum iActivity,bool bIsFormReady)1476 std::vector<CXFA_Event*> CXFA_WidgetAcc::GetEventByActivity(
1477 XFA_AttributeEnum iActivity,
1478 bool bIsFormReady) {
1479 std::vector<CXFA_Event*> events;
1480 for (CXFA_Node* node : m_pNode->GetNodeList(0, XFA_Element::Event)) {
1481 auto* event = static_cast<CXFA_Event*>(node);
1482 if (event->GetActivity() == iActivity) {
1483 if (iActivity == XFA_AttributeEnum::Ready) {
1484 WideString wsRef = event->GetRef();
1485 if (bIsFormReady) {
1486 if (wsRef == WideStringView(L"$form"))
1487 events.push_back(event);
1488 } else {
1489 if (wsRef == WideStringView(L"$layout"))
1490 events.push_back(event);
1491 }
1492 } else {
1493 events.push_back(event);
1494 }
1495 }
1496 }
1497 return events;
1498 }
1499
GetUIBorder()1500 CXFA_Border* CXFA_WidgetAcc::GetUIBorder() {
1501 CXFA_Node* pUIChild = GetUIChild();
1502 return pUIChild ? pUIChild->JSObject()->GetProperty<CXFA_Border>(
1503 0, XFA_Element::Border)
1504 : nullptr;
1505 }
1506
GetUIMargin()1507 CFX_RectF CXFA_WidgetAcc::GetUIMargin() {
1508 CXFA_Node* pUIChild = GetUIChild();
1509 CXFA_Margin* mgUI = nullptr;
1510 if (pUIChild) {
1511 mgUI =
1512 pUIChild->JSObject()->GetProperty<CXFA_Margin>(0, XFA_Element::Margin);
1513 }
1514
1515 if (!mgUI)
1516 return CFX_RectF();
1517
1518 CXFA_Border* border = GetUIBorder();
1519 if (border && border->GetPresence() != XFA_AttributeEnum::Visible)
1520 return CFX_RectF();
1521
1522 Optional<float> left = mgUI->TryLeftInset();
1523 Optional<float> top = mgUI->TryTopInset();
1524 Optional<float> right = mgUI->TryRightInset();
1525 Optional<float> bottom = mgUI->TryBottomInset();
1526 if (border) {
1527 bool bVisible = false;
1528 float fThickness = 0;
1529 XFA_AttributeEnum iType = XFA_AttributeEnum::Unknown;
1530 std::tie(iType, bVisible, fThickness) = border->Get3DStyle();
1531 if (!left || !top || !right || !bottom) {
1532 std::vector<CXFA_Stroke*> strokes = border->GetStrokes();
1533 if (!top)
1534 top = GetEdgeThickness(strokes, bVisible, 0);
1535 if (!right)
1536 right = GetEdgeThickness(strokes, bVisible, 1);
1537 if (!bottom)
1538 bottom = GetEdgeThickness(strokes, bVisible, 2);
1539 if (!left)
1540 left = GetEdgeThickness(strokes, bVisible, 3);
1541 }
1542 }
1543 return CFX_RectF(left.value_or(0.0), top.value_or(0.0), right.value_or(0.0),
1544 bottom.value_or(0.0));
1545 }
1546
GetButtonHighlight()1547 XFA_AttributeEnum CXFA_WidgetAcc::GetButtonHighlight() {
1548 CXFA_Node* pUIChild = GetUIChild();
1549 if (pUIChild)
1550 return pUIChild->JSObject()->GetEnum(XFA_Attribute::Highlight);
1551 return XFA_AttributeEnum::Inverted;
1552 }
1553
HasButtonRollover() const1554 bool CXFA_WidgetAcc::HasButtonRollover() const {
1555 CXFA_Items* pItems =
1556 m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1557 if (!pItems)
1558 return false;
1559
1560 for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
1561 pText = pText->GetNextSibling()) {
1562 if (pText->JSObject()->GetCData(XFA_Attribute::Name) == L"rollover")
1563 return !pText->JSObject()->GetContent(false).IsEmpty();
1564 }
1565 return false;
1566 }
1567
HasButtonDown() const1568 bool CXFA_WidgetAcc::HasButtonDown() const {
1569 CXFA_Items* pItems =
1570 m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1571 if (!pItems)
1572 return false;
1573
1574 for (CXFA_Node* pText = pItems->GetFirstChild(); pText;
1575 pText = pText->GetNextSibling()) {
1576 if (pText->JSObject()->GetCData(XFA_Attribute::Name) == L"down")
1577 return !pText->JSObject()->GetContent(false).IsEmpty();
1578 }
1579 return false;
1580 }
1581
IsCheckButtonRound()1582 bool CXFA_WidgetAcc::IsCheckButtonRound() {
1583 CXFA_Node* pUIChild = GetUIChild();
1584 if (pUIChild)
1585 return pUIChild->JSObject()->GetEnum(XFA_Attribute::Shape) ==
1586 XFA_AttributeEnum::Round;
1587 return false;
1588 }
1589
GetCheckButtonMark()1590 XFA_AttributeEnum CXFA_WidgetAcc::GetCheckButtonMark() {
1591 CXFA_Node* pUIChild = GetUIChild();
1592 if (pUIChild)
1593 return pUIChild->JSObject()->GetEnum(XFA_Attribute::Mark);
1594 return XFA_AttributeEnum::Default;
1595 }
1596
IsRadioButton()1597 bool CXFA_WidgetAcc::IsRadioButton() {
1598 CXFA_Node* pParent = m_pNode->GetParent();
1599 return pParent && pParent->GetElementType() == XFA_Element::ExclGroup;
1600 }
1601
GetCheckButtonSize()1602 float CXFA_WidgetAcc::GetCheckButtonSize() {
1603 CXFA_Node* pUIChild = GetUIChild();
1604 if (pUIChild) {
1605 return pUIChild->JSObject()
1606 ->GetMeasure(XFA_Attribute::Size)
1607 .ToUnit(XFA_Unit::Pt);
1608 }
1609 return CXFA_Measurement(10, XFA_Unit::Pt).ToUnit(XFA_Unit::Pt);
1610 }
1611
IsAllowNeutral()1612 bool CXFA_WidgetAcc::IsAllowNeutral() {
1613 CXFA_Node* pUIChild = GetUIChild();
1614 return pUIChild &&
1615 pUIChild->JSObject()->GetBoolean(XFA_Attribute::AllowNeutral);
1616 }
1617
GetCheckState()1618 XFA_CHECKSTATE CXFA_WidgetAcc::GetCheckState() {
1619 WideString wsValue = m_pNode->GetRawValue();
1620 if (wsValue.IsEmpty())
1621 return XFA_CHECKSTATE_Off;
1622
1623 auto* pItems = m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1624 if (!pItems)
1625 return XFA_CHECKSTATE_Off;
1626
1627 CXFA_Node* pText = pItems->GetFirstChild();
1628 int32_t i = 0;
1629 while (pText) {
1630 Optional<WideString> wsContent = pText->JSObject()->TryContent(false, true);
1631 if (wsContent && *wsContent == wsValue)
1632 return static_cast<XFA_CHECKSTATE>(i);
1633
1634 i++;
1635 pText = pText->GetNextSibling();
1636 }
1637 return XFA_CHECKSTATE_Off;
1638 }
1639
SetCheckState(XFA_CHECKSTATE eCheckState,bool bNotify)1640 void CXFA_WidgetAcc::SetCheckState(XFA_CHECKSTATE eCheckState, bool bNotify) {
1641 CXFA_Node* node = m_pNode->GetExclGroupIfExists();
1642 if (!node) {
1643 CXFA_Items* pItems =
1644 m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1645 if (!pItems)
1646 return;
1647
1648 int32_t i = -1;
1649 CXFA_Node* pText = pItems->GetFirstChild();
1650 WideString wsContent;
1651 while (pText) {
1652 i++;
1653 if (i == eCheckState) {
1654 wsContent = pText->JSObject()->GetContent(false);
1655 break;
1656 }
1657 pText = pText->GetNextSibling();
1658 }
1659 if (m_pNode)
1660 m_pNode->SyncValue(wsContent, bNotify);
1661
1662 return;
1663 }
1664
1665 WideString wsValue;
1666 if (eCheckState != XFA_CHECKSTATE_Off) {
1667 if (CXFA_Items* pItems =
1668 m_pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false)) {
1669 CXFA_Node* pText = pItems->GetFirstChild();
1670 if (pText)
1671 wsValue = pText->JSObject()->GetContent(false);
1672 }
1673 }
1674 CXFA_Node* pChild = node->GetFirstChild();
1675 for (; pChild; pChild = pChild->GetNextSibling()) {
1676 if (pChild->GetElementType() != XFA_Element::Field)
1677 continue;
1678
1679 CXFA_Items* pItem =
1680 pChild->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1681 if (!pItem)
1682 continue;
1683
1684 CXFA_Node* pItemchild = pItem->GetFirstChild();
1685 if (!pItemchild)
1686 continue;
1687
1688 WideString text = pItemchild->JSObject()->GetContent(false);
1689 WideString wsChildValue = text;
1690 if (wsValue != text) {
1691 pItemchild = pItemchild->GetNextSibling();
1692 if (pItemchild)
1693 wsChildValue = pItemchild->JSObject()->GetContent(false);
1694 else
1695 wsChildValue.clear();
1696 }
1697 pChild->SyncValue(wsChildValue, bNotify);
1698 }
1699 node->SyncValue(wsValue, bNotify);
1700 }
1701
GetSelectedMember()1702 CXFA_Node* CXFA_WidgetAcc::GetSelectedMember() {
1703 CXFA_Node* pSelectedMember = nullptr;
1704 WideString wsState = m_pNode->GetRawValue();
1705 if (wsState.IsEmpty())
1706 return pSelectedMember;
1707
1708 for (CXFA_Node* pNode = ToNode(m_pNode->GetFirstChild()); pNode;
1709 pNode = pNode->GetNextSibling()) {
1710 CXFA_WidgetAcc widgetData(pNode);
1711 if (widgetData.GetCheckState() == XFA_CHECKSTATE_On) {
1712 pSelectedMember = pNode;
1713 break;
1714 }
1715 }
1716 return pSelectedMember;
1717 }
1718
SetSelectedMember(const WideStringView & wsName,bool bNotify)1719 CXFA_Node* CXFA_WidgetAcc::SetSelectedMember(const WideStringView& wsName,
1720 bool bNotify) {
1721 uint32_t nameHash = FX_HashCode_GetW(wsName, false);
1722 for (CXFA_Node* pNode = ToNode(m_pNode->GetFirstChild()); pNode;
1723 pNode = pNode->GetNextSibling()) {
1724 if (pNode->GetNameHash() == nameHash) {
1725 CXFA_WidgetAcc widgetData(pNode);
1726 widgetData.SetCheckState(XFA_CHECKSTATE_On, bNotify);
1727 return pNode;
1728 }
1729 }
1730 return nullptr;
1731 }
1732
SetSelectedMemberByValue(const WideStringView & wsValue,bool bNotify,bool bScriptModify,bool bSyncData)1733 void CXFA_WidgetAcc::SetSelectedMemberByValue(const WideStringView& wsValue,
1734 bool bNotify,
1735 bool bScriptModify,
1736 bool bSyncData) {
1737 WideString wsExclGroup;
1738 for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
1739 pNode = pNode->GetNextSibling()) {
1740 if (pNode->GetElementType() != XFA_Element::Field)
1741 continue;
1742
1743 CXFA_Items* pItem =
1744 pNode->GetChild<CXFA_Items>(0, XFA_Element::Items, false);
1745 if (!pItem)
1746 continue;
1747
1748 CXFA_Node* pItemchild = pItem->GetFirstChild();
1749 if (!pItemchild)
1750 continue;
1751
1752 WideString wsChildValue = pItemchild->JSObject()->GetContent(false);
1753 if (wsValue != wsChildValue) {
1754 pItemchild = pItemchild->GetNextSibling();
1755 if (pItemchild)
1756 wsChildValue = pItemchild->JSObject()->GetContent(false);
1757 else
1758 wsChildValue.clear();
1759 } else {
1760 wsExclGroup = wsValue;
1761 }
1762 pNode->JSObject()->SetContent(wsChildValue, wsChildValue, bNotify,
1763 bScriptModify, false);
1764 }
1765 if (m_pNode) {
1766 m_pNode->JSObject()->SetContent(wsExclGroup, wsExclGroup, bNotify,
1767 bScriptModify, bSyncData);
1768 }
1769 }
1770
GetExclGroupFirstMember()1771 CXFA_Node* CXFA_WidgetAcc::GetExclGroupFirstMember() {
1772 CXFA_Node* pExcl = GetNode();
1773 if (!pExcl)
1774 return nullptr;
1775
1776 CXFA_Node* pNode = pExcl->GetFirstChild();
1777 while (pNode) {
1778 if (pNode->GetElementType() == XFA_Element::Field)
1779 return pNode;
1780
1781 pNode = pNode->GetNextSibling();
1782 }
1783 return nullptr;
1784 }
GetExclGroupNextMember(CXFA_Node * pNode)1785 CXFA_Node* CXFA_WidgetAcc::GetExclGroupNextMember(CXFA_Node* pNode) {
1786 if (!pNode)
1787 return nullptr;
1788
1789 CXFA_Node* pNodeField = pNode->GetNextSibling();
1790 while (pNodeField) {
1791 if (pNodeField->GetElementType() == XFA_Element::Field)
1792 return pNodeField;
1793
1794 pNodeField = pNodeField->GetNextSibling();
1795 }
1796 return nullptr;
1797 }
1798
IsChoiceListCommitOnSelect()1799 bool CXFA_WidgetAcc::IsChoiceListCommitOnSelect() {
1800 CXFA_Node* pUIChild = GetUIChild();
1801 if (pUIChild) {
1802 return pUIChild->JSObject()->GetEnum(XFA_Attribute::CommitOn) ==
1803 XFA_AttributeEnum::Select;
1804 }
1805 return true;
1806 }
1807
IsChoiceListAllowTextEntry()1808 bool CXFA_WidgetAcc::IsChoiceListAllowTextEntry() {
1809 CXFA_Node* pUIChild = GetUIChild();
1810 return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::TextEntry);
1811 }
1812
IsChoiceListMultiSelect()1813 bool CXFA_WidgetAcc::IsChoiceListMultiSelect() {
1814 CXFA_Node* pUIChild = GetUIChild();
1815 if (pUIChild) {
1816 return pUIChild->JSObject()->GetEnum(XFA_Attribute::Open) ==
1817 XFA_AttributeEnum::MultiSelect;
1818 }
1819 return false;
1820 }
1821
IsListBox()1822 bool CXFA_WidgetAcc::IsListBox() {
1823 CXFA_Node* pUIChild = GetUIChild();
1824 if (!pUIChild)
1825 return false;
1826
1827 XFA_AttributeEnum attr = pUIChild->JSObject()->GetEnum(XFA_Attribute::Open);
1828 return attr == XFA_AttributeEnum::Always ||
1829 attr == XFA_AttributeEnum::MultiSelect;
1830 }
1831
CountChoiceListItems(bool bSaveValue)1832 int32_t CXFA_WidgetAcc::CountChoiceListItems(bool bSaveValue) {
1833 std::vector<CXFA_Node*> pItems;
1834 int32_t iCount = 0;
1835 for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
1836 pNode = pNode->GetNextSibling()) {
1837 if (pNode->GetElementType() != XFA_Element::Items)
1838 continue;
1839 iCount++;
1840 pItems.push_back(pNode);
1841 if (iCount == 2)
1842 break;
1843 }
1844 if (iCount == 0)
1845 return 0;
1846
1847 CXFA_Node* pItem = pItems[0];
1848 if (iCount > 1) {
1849 bool bItemOneHasSave =
1850 pItems[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
1851 bool bItemTwoHasSave =
1852 pItems[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
1853 if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
1854 pItem = pItems[1];
1855 }
1856 return pItem->CountChildren(XFA_Element::Unknown, false);
1857 }
1858
GetChoiceListItem(int32_t nIndex,bool bSaveValue)1859 Optional<WideString> CXFA_WidgetAcc::GetChoiceListItem(int32_t nIndex,
1860 bool bSaveValue) {
1861 std::vector<CXFA_Node*> pItemsArray;
1862 int32_t iCount = 0;
1863 for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode;
1864 pNode = pNode->GetNextSibling()) {
1865 if (pNode->GetElementType() != XFA_Element::Items)
1866 continue;
1867
1868 ++iCount;
1869 pItemsArray.push_back(pNode);
1870 if (iCount == 2)
1871 break;
1872 }
1873 if (iCount == 0)
1874 return {};
1875
1876 CXFA_Node* pItems = pItemsArray[0];
1877 if (iCount > 1) {
1878 bool bItemOneHasSave =
1879 pItemsArray[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
1880 bool bItemTwoHasSave =
1881 pItemsArray[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
1882 if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
1883 pItems = pItemsArray[1];
1884 }
1885 if (!pItems)
1886 return {};
1887
1888 CXFA_Node* pItem =
1889 pItems->GetChild<CXFA_Node>(nIndex, XFA_Element::Unknown, false);
1890 if (pItem)
1891 return {pItem->JSObject()->GetContent(false)};
1892 return {};
1893 }
1894
GetChoiceListItems(bool bSaveValue)1895 std::vector<WideString> CXFA_WidgetAcc::GetChoiceListItems(bool bSaveValue) {
1896 std::vector<CXFA_Node*> items;
1897 for (CXFA_Node* pNode = m_pNode->GetFirstChild(); pNode && items.size() < 2;
1898 pNode = pNode->GetNextSibling()) {
1899 if (pNode->GetElementType() == XFA_Element::Items)
1900 items.push_back(pNode);
1901 }
1902 if (items.empty())
1903 return std::vector<WideString>();
1904
1905 CXFA_Node* pItem = items.front();
1906 if (items.size() > 1) {
1907 bool bItemOneHasSave =
1908 items[0]->JSObject()->GetBoolean(XFA_Attribute::Save);
1909 bool bItemTwoHasSave =
1910 items[1]->JSObject()->GetBoolean(XFA_Attribute::Save);
1911 if (bItemOneHasSave != bItemTwoHasSave && bSaveValue == bItemTwoHasSave)
1912 pItem = items[1];
1913 }
1914
1915 std::vector<WideString> wsTextArray;
1916 for (CXFA_Node* pNode = pItem->GetFirstChild(); pNode;
1917 pNode = pNode->GetNextSibling()) {
1918 wsTextArray.emplace_back(pNode->JSObject()->GetContent(false));
1919 }
1920 return wsTextArray;
1921 }
1922
CountSelectedItems()1923 int32_t CXFA_WidgetAcc::CountSelectedItems() {
1924 std::vector<WideString> wsValueArray = GetSelectedItemsValue();
1925 if (IsListBox() || !IsChoiceListAllowTextEntry())
1926 return pdfium::CollectionSize<int32_t>(wsValueArray);
1927
1928 int32_t iSelected = 0;
1929 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
1930 for (const auto& value : wsValueArray) {
1931 if (pdfium::ContainsValue(wsSaveTextArray, value))
1932 iSelected++;
1933 }
1934 return iSelected;
1935 }
1936
GetSelectedItem(int32_t nIndex)1937 int32_t CXFA_WidgetAcc::GetSelectedItem(int32_t nIndex) {
1938 std::vector<WideString> wsValueArray = GetSelectedItemsValue();
1939 if (!pdfium::IndexInBounds(wsValueArray, nIndex))
1940 return -1;
1941
1942 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
1943 auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(),
1944 wsValueArray[nIndex]);
1945 return it != wsSaveTextArray.end() ? it - wsSaveTextArray.begin() : -1;
1946 }
1947
GetSelectedItems()1948 std::vector<int32_t> CXFA_WidgetAcc::GetSelectedItems() {
1949 std::vector<int32_t> iSelArray;
1950 std::vector<WideString> wsValueArray = GetSelectedItemsValue();
1951 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
1952 for (const auto& value : wsValueArray) {
1953 auto it = std::find(wsSaveTextArray.begin(), wsSaveTextArray.end(), value);
1954 if (it != wsSaveTextArray.end())
1955 iSelArray.push_back(it - wsSaveTextArray.begin());
1956 }
1957 return iSelArray;
1958 }
1959
GetSelectedItemsValue()1960 std::vector<WideString> CXFA_WidgetAcc::GetSelectedItemsValue() {
1961 std::vector<WideString> wsSelTextArray;
1962 WideString wsValue = m_pNode->GetRawValue();
1963 if (IsChoiceListMultiSelect()) {
1964 if (!wsValue.IsEmpty()) {
1965 size_t iStart = 0;
1966 size_t iLength = wsValue.GetLength();
1967 auto iEnd = wsValue.Find(L'\n', iStart);
1968 iEnd = (!iEnd.has_value()) ? iLength : iEnd;
1969 while (iEnd >= iStart) {
1970 wsSelTextArray.push_back(wsValue.Mid(iStart, iEnd.value() - iStart));
1971 iStart = iEnd.value() + 1;
1972 if (iStart >= iLength)
1973 break;
1974 iEnd = wsValue.Find(L'\n', iStart);
1975 if (!iEnd.has_value())
1976 wsSelTextArray.push_back(wsValue.Mid(iStart, iLength - iStart));
1977 }
1978 }
1979 } else {
1980 wsSelTextArray.push_back(wsValue);
1981 }
1982 return wsSelTextArray;
1983 }
1984
GetItemState(int32_t nIndex)1985 bool CXFA_WidgetAcc::GetItemState(int32_t nIndex) {
1986 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
1987 return pdfium::IndexInBounds(wsSaveTextArray, nIndex) &&
1988 pdfium::ContainsValue(GetSelectedItemsValue(),
1989 wsSaveTextArray[nIndex]);
1990 }
1991
SetItemState(int32_t nIndex,bool bSelected,bool bNotify,bool bScriptModify,bool bSyncData)1992 void CXFA_WidgetAcc::SetItemState(int32_t nIndex,
1993 bool bSelected,
1994 bool bNotify,
1995 bool bScriptModify,
1996 bool bSyncData) {
1997 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
1998 if (!pdfium::IndexInBounds(wsSaveTextArray, nIndex))
1999 return;
2000
2001 int32_t iSel = -1;
2002 std::vector<WideString> wsValueArray = GetSelectedItemsValue();
2003 auto it = std::find(wsValueArray.begin(), wsValueArray.end(),
2004 wsSaveTextArray[nIndex]);
2005 if (it != wsValueArray.end())
2006 iSel = it - wsValueArray.begin();
2007
2008 if (IsChoiceListMultiSelect()) {
2009 if (bSelected) {
2010 if (iSel < 0) {
2011 WideString wsValue = m_pNode->GetRawValue();
2012 if (!wsValue.IsEmpty()) {
2013 wsValue += L"\n";
2014 }
2015 wsValue += wsSaveTextArray[nIndex];
2016 m_pNode->JSObject()->SetContent(wsValue, wsValue, bNotify,
2017 bScriptModify, bSyncData);
2018 }
2019 } else if (iSel >= 0) {
2020 std::vector<int32_t> iSelArray = GetSelectedItems();
2021 auto it = std::find(iSelArray.begin(), iSelArray.end(), nIndex);
2022 if (it != iSelArray.end())
2023 iSelArray.erase(it);
2024 SetSelectedItems(iSelArray, bNotify, bScriptModify, bSyncData);
2025 }
2026 } else {
2027 if (bSelected) {
2028 if (iSel < 0) {
2029 WideString wsSaveText = wsSaveTextArray[nIndex];
2030 m_pNode->JSObject()->SetContent(wsSaveText,
2031 GetFormatDataValue(wsSaveText), bNotify,
2032 bScriptModify, bSyncData);
2033 }
2034 } else if (iSel >= 0) {
2035 m_pNode->JSObject()->SetContent(WideString(), WideString(), bNotify,
2036 bScriptModify, bSyncData);
2037 }
2038 }
2039 }
2040
SetSelectedItems(const std::vector<int32_t> & iSelArray,bool bNotify,bool bScriptModify,bool bSyncData)2041 void CXFA_WidgetAcc::SetSelectedItems(const std::vector<int32_t>& iSelArray,
2042 bool bNotify,
2043 bool bScriptModify,
2044 bool bSyncData) {
2045 WideString wsValue;
2046 int32_t iSize = pdfium::CollectionSize<int32_t>(iSelArray);
2047 if (iSize >= 1) {
2048 std::vector<WideString> wsSaveTextArray = GetChoiceListItems(true);
2049 WideString wsItemValue;
2050 for (int32_t i = 0; i < iSize; i++) {
2051 wsItemValue = (iSize == 1) ? wsSaveTextArray[iSelArray[i]]
2052 : wsSaveTextArray[iSelArray[i]] + L"\n";
2053 wsValue += wsItemValue;
2054 }
2055 }
2056 WideString wsFormat(wsValue);
2057 if (!IsChoiceListMultiSelect())
2058 wsFormat = GetFormatDataValue(wsValue);
2059
2060 m_pNode->JSObject()->SetContent(wsValue, wsFormat, bNotify, bScriptModify,
2061 bSyncData);
2062 }
2063
ClearAllSelections()2064 void CXFA_WidgetAcc::ClearAllSelections() {
2065 CXFA_Node* pBind = m_pNode->GetBindData();
2066 if (!pBind || !IsChoiceListMultiSelect()) {
2067 m_pNode->SyncValue(WideString(), false);
2068 return;
2069 }
2070
2071 while (CXFA_Node* pChildNode = pBind->GetFirstChild())
2072 pBind->RemoveChild(pChildNode, true);
2073 }
2074
InsertItem(const WideString & wsLabel,const WideString & wsValue,bool bNotify)2075 void CXFA_WidgetAcc::InsertItem(const WideString& wsLabel,
2076 const WideString& wsValue,
2077 bool bNotify) {
2078 int32_t nIndex = -1;
2079 WideString wsNewValue(wsValue);
2080 if (wsNewValue.IsEmpty())
2081 wsNewValue = wsLabel;
2082
2083 std::vector<CXFA_Node*> listitems;
2084 for (CXFA_Node* pItem = m_pNode->GetFirstChild(); pItem;
2085 pItem = pItem->GetNextSibling()) {
2086 if (pItem->GetElementType() == XFA_Element::Items)
2087 listitems.push_back(pItem);
2088 }
2089 if (listitems.empty()) {
2090 CXFA_Node* pItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
2091 m_pNode->InsertChild(-1, pItems);
2092 InsertListTextItem(pItems, wsLabel, nIndex);
2093 CXFA_Node* pSaveItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
2094 m_pNode->InsertChild(-1, pSaveItems);
2095 pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
2096 InsertListTextItem(pSaveItems, wsNewValue, nIndex);
2097 } else if (listitems.size() > 1) {
2098 for (int32_t i = 0; i < 2; i++) {
2099 CXFA_Node* pNode = listitems[i];
2100 bool bHasSave = pNode->JSObject()->GetBoolean(XFA_Attribute::Save);
2101 if (bHasSave)
2102 InsertListTextItem(pNode, wsNewValue, nIndex);
2103 else
2104 InsertListTextItem(pNode, wsLabel, nIndex);
2105 }
2106 } else {
2107 CXFA_Node* pNode = listitems[0];
2108 pNode->JSObject()->SetBoolean(XFA_Attribute::Save, false, false);
2109 pNode->JSObject()->SetEnum(XFA_Attribute::Presence,
2110 XFA_AttributeEnum::Visible, false);
2111 CXFA_Node* pSaveItems = m_pNode->CreateSamePacketNode(XFA_Element::Items);
2112 m_pNode->InsertChild(-1, pSaveItems);
2113 pSaveItems->JSObject()->SetBoolean(XFA_Attribute::Save, true, false);
2114 pSaveItems->JSObject()->SetEnum(XFA_Attribute::Presence,
2115 XFA_AttributeEnum::Hidden, false);
2116 CXFA_Node* pListNode = pNode->GetFirstChild();
2117 int32_t i = 0;
2118 while (pListNode) {
2119 InsertListTextItem(pSaveItems, pListNode->JSObject()->GetContent(false),
2120 i);
2121 ++i;
2122
2123 pListNode = pListNode->GetNextSibling();
2124 }
2125 InsertListTextItem(pNode, wsLabel, nIndex);
2126 InsertListTextItem(pSaveItems, wsNewValue, nIndex);
2127 }
2128 if (!bNotify)
2129 return;
2130
2131 m_pNode->GetDocument()->GetNotify()->OnWidgetListItemAdded(
2132 this, wsLabel.c_str(), wsValue.c_str(), nIndex);
2133 }
2134
GetItemLabel(const WideStringView & wsValue,WideString & wsLabel)2135 void CXFA_WidgetAcc::GetItemLabel(const WideStringView& wsValue,
2136 WideString& wsLabel) {
2137 int32_t iCount = 0;
2138 std::vector<CXFA_Node*> listitems;
2139 CXFA_Node* pItems = m_pNode->GetFirstChild();
2140 for (; pItems; pItems = pItems->GetNextSibling()) {
2141 if (pItems->GetElementType() != XFA_Element::Items)
2142 continue;
2143 iCount++;
2144 listitems.push_back(pItems);
2145 }
2146
2147 if (iCount <= 1) {
2148 wsLabel = wsValue;
2149 return;
2150 }
2151
2152 CXFA_Node* pLabelItems = listitems[0];
2153 bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
2154 CXFA_Node* pSaveItems = nullptr;
2155 if (bSave) {
2156 pSaveItems = pLabelItems;
2157 pLabelItems = listitems[1];
2158 } else {
2159 pSaveItems = listitems[1];
2160 }
2161 iCount = 0;
2162
2163 int32_t iSearch = -1;
2164 for (CXFA_Node* pChildItem = pSaveItems->GetFirstChild(); pChildItem;
2165 pChildItem = pChildItem->GetNextSibling()) {
2166 if (pChildItem->JSObject()->GetContent(false) == wsValue) {
2167 iSearch = iCount;
2168 break;
2169 }
2170 iCount++;
2171 }
2172 if (iSearch < 0)
2173 return;
2174
2175 CXFA_Node* pText =
2176 pLabelItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
2177 if (pText)
2178 wsLabel = pText->JSObject()->GetContent(false);
2179 }
2180
GetItemValue(const WideStringView & wsLabel)2181 WideString CXFA_WidgetAcc::GetItemValue(const WideStringView& wsLabel) {
2182 int32_t iCount = 0;
2183 std::vector<CXFA_Node*> listitems;
2184 for (CXFA_Node* pItems = m_pNode->GetFirstChild(); pItems;
2185 pItems = pItems->GetNextSibling()) {
2186 if (pItems->GetElementType() != XFA_Element::Items)
2187 continue;
2188 iCount++;
2189 listitems.push_back(pItems);
2190 }
2191 if (iCount <= 1)
2192 return WideString(wsLabel);
2193
2194 CXFA_Node* pLabelItems = listitems[0];
2195 bool bSave = pLabelItems->JSObject()->GetBoolean(XFA_Attribute::Save);
2196 CXFA_Node* pSaveItems = nullptr;
2197 if (bSave) {
2198 pSaveItems = pLabelItems;
2199 pLabelItems = listitems[1];
2200 } else {
2201 pSaveItems = listitems[1];
2202 }
2203 iCount = 0;
2204
2205 int32_t iSearch = -1;
2206 WideString wsContent;
2207 CXFA_Node* pChildItem = pLabelItems->GetFirstChild();
2208 for (; pChildItem; pChildItem = pChildItem->GetNextSibling()) {
2209 if (pChildItem->JSObject()->GetContent(false) == wsLabel) {
2210 iSearch = iCount;
2211 break;
2212 }
2213 iCount++;
2214 }
2215 if (iSearch < 0)
2216 return L"";
2217
2218 CXFA_Node* pText =
2219 pSaveItems->GetChild<CXFA_Node>(iSearch, XFA_Element::Unknown, false);
2220 return pText ? pText->JSObject()->GetContent(false) : L"";
2221 }
2222
DeleteItem(int32_t nIndex,bool bNotify,bool bScriptModify)2223 bool CXFA_WidgetAcc::DeleteItem(int32_t nIndex,
2224 bool bNotify,
2225 bool bScriptModify) {
2226 bool bSetValue = false;
2227 CXFA_Node* pItems = m_pNode->GetFirstChild();
2228 for (; pItems; pItems = pItems->GetNextSibling()) {
2229 if (pItems->GetElementType() != XFA_Element::Items)
2230 continue;
2231
2232 if (nIndex < 0) {
2233 while (CXFA_Node* pNode = pItems->GetFirstChild()) {
2234 pItems->RemoveChild(pNode, true);
2235 }
2236 } else {
2237 if (!bSetValue && pItems->JSObject()->GetBoolean(XFA_Attribute::Save)) {
2238 SetItemState(nIndex, false, true, bScriptModify, true);
2239 bSetValue = true;
2240 }
2241 int32_t i = 0;
2242 CXFA_Node* pNode = pItems->GetFirstChild();
2243 while (pNode) {
2244 if (i == nIndex) {
2245 pItems->RemoveChild(pNode, true);
2246 break;
2247 }
2248 i++;
2249 pNode = pNode->GetNextSibling();
2250 }
2251 }
2252 }
2253 if (bNotify)
2254 m_pNode->GetDocument()->GetNotify()->OnWidgetListItemRemoved(this, nIndex);
2255 return true;
2256 }
2257
IsHorizontalScrollPolicyOff()2258 bool CXFA_WidgetAcc::IsHorizontalScrollPolicyOff() {
2259 CXFA_Node* pUIChild = GetUIChild();
2260 if (pUIChild) {
2261 return pUIChild->JSObject()->GetEnum(XFA_Attribute::HScrollPolicy) ==
2262 XFA_AttributeEnum::Off;
2263 }
2264 return false;
2265 }
2266
IsVerticalScrollPolicyOff()2267 bool CXFA_WidgetAcc::IsVerticalScrollPolicyOff() {
2268 CXFA_Node* pUIChild = GetUIChild();
2269 if (pUIChild) {
2270 return pUIChild->JSObject()->GetEnum(XFA_Attribute::VScrollPolicy) ==
2271 XFA_AttributeEnum::Off;
2272 }
2273 return false;
2274 }
2275
GetNumberOfCells()2276 Optional<int32_t> CXFA_WidgetAcc::GetNumberOfCells() {
2277 CXFA_Node* pUIChild = GetUIChild();
2278 if (!pUIChild)
2279 return {};
2280 if (CXFA_Comb* pNode =
2281 pUIChild->GetChild<CXFA_Comb>(0, XFA_Element::Comb, false))
2282 return {pNode->JSObject()->GetInteger(XFA_Attribute::NumberOfCells)};
2283 return {};
2284 }
2285
GetPasswordChar()2286 WideString CXFA_WidgetAcc::GetPasswordChar() {
2287 CXFA_Node* pUIChild = GetUIChild();
2288 return pUIChild ? pUIChild->JSObject()->GetCData(XFA_Attribute::PasswordChar)
2289 : L"*";
2290 }
2291
IsMultiLine()2292 bool CXFA_WidgetAcc::IsMultiLine() {
2293 CXFA_Node* pUIChild = GetUIChild();
2294 return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::MultiLine);
2295 }
2296
GetMaxChars()2297 std::pair<XFA_Element, int32_t> CXFA_WidgetAcc::GetMaxChars() {
2298 if (CXFA_Value* pNode =
2299 m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false)) {
2300 if (CXFA_Node* pChild = pNode->GetFirstChild()) {
2301 switch (pChild->GetElementType()) {
2302 case XFA_Element::Text:
2303 return {XFA_Element::Text,
2304 pChild->JSObject()->GetInteger(XFA_Attribute::MaxChars)};
2305 case XFA_Element::ExData: {
2306 int32_t iMax =
2307 pChild->JSObject()->GetInteger(XFA_Attribute::MaxLength);
2308 return {XFA_Element::ExData, iMax < 0 ? 0 : iMax};
2309 }
2310 default:
2311 break;
2312 }
2313 }
2314 }
2315 return {XFA_Element::Unknown, 0};
2316 }
2317
GetFracDigits()2318 int32_t CXFA_WidgetAcc::GetFracDigits() {
2319 CXFA_Value* pNode =
2320 m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
2321 if (!pNode)
2322 return -1;
2323
2324 CXFA_Decimal* pChild =
2325 pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
2326 if (!pChild)
2327 return -1;
2328
2329 return pChild->JSObject()
2330 ->TryInteger(XFA_Attribute::FracDigits, true)
2331 .value_or(-1);
2332 }
2333
GetLeadDigits()2334 int32_t CXFA_WidgetAcc::GetLeadDigits() {
2335 CXFA_Value* pNode =
2336 m_pNode->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
2337 if (!pNode)
2338 return -1;
2339
2340 CXFA_Decimal* pChild =
2341 pNode->GetChild<CXFA_Decimal>(0, XFA_Element::Decimal, false);
2342 if (!pChild)
2343 return -1;
2344
2345 return pChild->JSObject()
2346 ->TryInteger(XFA_Attribute::LeadDigits, true)
2347 .value_or(-1);
2348 }
2349
SetValue(XFA_VALUEPICTURE eValueType,const WideString & wsValue)2350 bool CXFA_WidgetAcc::SetValue(XFA_VALUEPICTURE eValueType,
2351 const WideString& wsValue) {
2352 if (wsValue.IsEmpty()) {
2353 if (m_pNode)
2354 m_pNode->SyncValue(wsValue, true);
2355 return true;
2356 }
2357
2358 m_bPreNull = m_bIsNull;
2359 m_bIsNull = false;
2360 WideString wsNewText(wsValue);
2361 WideString wsPicture = GetPictureContent(eValueType);
2362 bool bValidate = true;
2363 bool bSyncData = false;
2364 CXFA_Node* pNode = GetUIChild();
2365 if (!pNode)
2366 return true;
2367
2368 XFA_Element eType = pNode->GetElementType();
2369 if (!wsPicture.IsEmpty()) {
2370 CXFA_LocaleMgr* pLocalMgr = m_pNode->GetDocument()->GetLocalMgr();
2371 IFX_Locale* pLocale = GetLocale();
2372 CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
2373 bValidate =
2374 widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture);
2375 if (bValidate) {
2376 widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsNewText,
2377 wsPicture, pLocale, pLocalMgr);
2378 wsNewText = widgetValue.GetValue();
2379 if (eType == XFA_Element::NumericEdit)
2380 wsNewText = NumericLimit(wsNewText, GetLeadDigits(), GetFracDigits());
2381
2382 bSyncData = true;
2383 }
2384 } else {
2385 if (eType == XFA_Element::NumericEdit) {
2386 if (wsNewText != L"0")
2387 wsNewText = NumericLimit(wsNewText, GetLeadDigits(), GetFracDigits());
2388
2389 bSyncData = true;
2390 }
2391 }
2392 if (eType != XFA_Element::NumericEdit || bSyncData) {
2393 if (m_pNode)
2394 m_pNode->SyncValue(wsNewText, true);
2395 }
2396
2397 return bValidate;
2398 }
2399
GetPictureContent(XFA_VALUEPICTURE ePicture)2400 WideString CXFA_WidgetAcc::GetPictureContent(XFA_VALUEPICTURE ePicture) {
2401 if (ePicture == XFA_VALUEPICTURE_Raw)
2402 return L"";
2403
2404 CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
2405 switch (ePicture) {
2406 case XFA_VALUEPICTURE_Display: {
2407 if (CXFA_Format* pFormat =
2408 m_pNode->GetChild<CXFA_Format>(0, XFA_Element::Format, false)) {
2409 if (CXFA_Picture* pPicture = pFormat->GetChild<CXFA_Picture>(
2410 0, XFA_Element::Picture, false)) {
2411 Optional<WideString> picture =
2412 pPicture->JSObject()->TryContent(false, true);
2413 if (picture)
2414 return *picture;
2415 }
2416 }
2417
2418 IFX_Locale* pLocale = GetLocale();
2419 if (!pLocale)
2420 return L"";
2421
2422 uint32_t dwType = widgetValue.GetType();
2423 switch (dwType) {
2424 case XFA_VT_DATE:
2425 return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
2426 case XFA_VT_TIME:
2427 return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
2428 case XFA_VT_DATETIME:
2429 return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium) +
2430 L"T" +
2431 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Medium);
2432 case XFA_VT_DECIMAL:
2433 case XFA_VT_FLOAT:
2434 default:
2435 return L"";
2436 }
2437 }
2438 case XFA_VALUEPICTURE_Edit: {
2439 CXFA_Ui* pUI = m_pNode->GetChild<CXFA_Ui>(0, XFA_Element::Ui, false);
2440 if (pUI) {
2441 if (CXFA_Picture* pPicture =
2442 pUI->GetChild<CXFA_Picture>(0, XFA_Element::Picture, false)) {
2443 Optional<WideString> picture =
2444 pPicture->JSObject()->TryContent(false, true);
2445 if (picture)
2446 return *picture;
2447 }
2448 }
2449
2450 IFX_Locale* pLocale = GetLocale();
2451 if (!pLocale)
2452 return L"";
2453
2454 uint32_t dwType = widgetValue.GetType();
2455 switch (dwType) {
2456 case XFA_VT_DATE:
2457 return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
2458 case XFA_VT_TIME:
2459 return pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
2460 case XFA_VT_DATETIME:
2461 return pLocale->GetDatePattern(FX_LOCALEDATETIMESUBCATEGORY_Short) +
2462 L"T" +
2463 pLocale->GetTimePattern(FX_LOCALEDATETIMESUBCATEGORY_Short);
2464 default:
2465 return L"";
2466 }
2467 }
2468 case XFA_VALUEPICTURE_DataBind: {
2469 CXFA_Bind* bind = m_pNode->GetBindIfExists();
2470 if (bind)
2471 return bind->GetPicture();
2472 break;
2473 }
2474 default:
2475 break;
2476 }
2477 return L"";
2478 }
2479
GetLocale()2480 IFX_Locale* CXFA_WidgetAcc::GetLocale() {
2481 return m_pNode ? m_pNode->GetLocale() : nullptr;
2482 }
2483
GetValue(XFA_VALUEPICTURE eValueType)2484 WideString CXFA_WidgetAcc::GetValue(XFA_VALUEPICTURE eValueType) {
2485 WideString wsValue = m_pNode->JSObject()->GetContent(false);
2486
2487 if (eValueType == XFA_VALUEPICTURE_Display)
2488 GetItemLabel(wsValue.AsStringView(), wsValue);
2489
2490 WideString wsPicture = GetPictureContent(eValueType);
2491 CXFA_Node* pNode = GetUIChild();
2492 if (!pNode)
2493 return wsValue;
2494
2495 switch (GetUIChild()->GetElementType()) {
2496 case XFA_Element::ChoiceList: {
2497 if (eValueType == XFA_VALUEPICTURE_Display) {
2498 int32_t iSelItemIndex = GetSelectedItem(0);
2499 if (iSelItemIndex >= 0) {
2500 wsValue = GetChoiceListItem(iSelItemIndex, false).value_or(L"");
2501 wsPicture.clear();
2502 }
2503 }
2504 } break;
2505 case XFA_Element::NumericEdit:
2506 if (eValueType != XFA_VALUEPICTURE_Raw && wsPicture.IsEmpty()) {
2507 IFX_Locale* pLocale = GetLocale();
2508 if (eValueType == XFA_VALUEPICTURE_Display && pLocale)
2509 wsValue = FormatNumStr(NormalizeNumStr(wsValue), pLocale);
2510 }
2511 break;
2512 default:
2513 break;
2514 }
2515 if (wsPicture.IsEmpty())
2516 return wsValue;
2517
2518 if (IFX_Locale* pLocale = GetLocale()) {
2519 CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
2520 CXFA_LocaleMgr* pLocalMgr = m_pNode->GetDocument()->GetLocalMgr();
2521 switch (widgetValue.GetType()) {
2522 case XFA_VT_DATE: {
2523 WideString wsDate, wsTime;
2524 if (SplitDateTime(wsValue, wsDate, wsTime)) {
2525 CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocalMgr);
2526 if (date.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
2527 return wsValue;
2528 }
2529 break;
2530 }
2531 case XFA_VT_TIME: {
2532 WideString wsDate, wsTime;
2533 if (SplitDateTime(wsValue, wsDate, wsTime)) {
2534 CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocalMgr);
2535 if (time.FormatPatterns(wsValue, wsPicture, pLocale, eValueType))
2536 return wsValue;
2537 }
2538 break;
2539 }
2540 default:
2541 break;
2542 }
2543 widgetValue.FormatPatterns(wsValue, wsPicture, pLocale, eValueType);
2544 }
2545 return wsValue;
2546 }
2547
GetNormalizeDataValue(const WideString & wsValue)2548 WideString CXFA_WidgetAcc::GetNormalizeDataValue(const WideString& wsValue) {
2549 if (wsValue.IsEmpty())
2550 return L"";
2551
2552 WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
2553 if (wsPicture.IsEmpty())
2554 return wsValue;
2555
2556 ASSERT(GetNode());
2557 CXFA_LocaleMgr* pLocalMgr = GetNode()->GetDocument()->GetLocalMgr();
2558 IFX_Locale* pLocale = GetLocale();
2559 CXFA_LocaleValue widgetValue = XFA_GetLocaleValue(GetNode());
2560 if (widgetValue.ValidateValue(wsValue, wsPicture, pLocale, &wsPicture)) {
2561 widgetValue = CXFA_LocaleValue(widgetValue.GetType(), wsValue, wsPicture,
2562 pLocale, pLocalMgr);
2563 return widgetValue.GetValue();
2564 }
2565 return wsValue;
2566 }
2567
GetFormatDataValue(const WideString & wsValue)2568 WideString CXFA_WidgetAcc::GetFormatDataValue(const WideString& wsValue) {
2569 if (wsValue.IsEmpty())
2570 return L"";
2571
2572 WideString wsPicture = GetPictureContent(XFA_VALUEPICTURE_DataBind);
2573 if (wsPicture.IsEmpty())
2574 return wsValue;
2575
2576 WideString wsFormattedValue = wsValue;
2577 if (IFX_Locale* pLocale = GetLocale()) {
2578 ASSERT(GetNode());
2579 CXFA_Value* pNodeValue =
2580 GetNode()->GetChild<CXFA_Value>(0, XFA_Element::Value, false);
2581 if (!pNodeValue)
2582 return wsValue;
2583
2584 CXFA_Node* pValueChild = pNodeValue->GetFirstChild();
2585 if (!pValueChild)
2586 return wsValue;
2587
2588 int32_t iVTType = XFA_VT_NULL;
2589 switch (pValueChild->GetElementType()) {
2590 case XFA_Element::Decimal:
2591 iVTType = XFA_VT_DECIMAL;
2592 break;
2593 case XFA_Element::Float:
2594 iVTType = XFA_VT_FLOAT;
2595 break;
2596 case XFA_Element::Date:
2597 iVTType = XFA_VT_DATE;
2598 break;
2599 case XFA_Element::Time:
2600 iVTType = XFA_VT_TIME;
2601 break;
2602 case XFA_Element::DateTime:
2603 iVTType = XFA_VT_DATETIME;
2604 break;
2605 case XFA_Element::Boolean:
2606 iVTType = XFA_VT_BOOLEAN;
2607 break;
2608 case XFA_Element::Integer:
2609 iVTType = XFA_VT_INTEGER;
2610 break;
2611 case XFA_Element::Text:
2612 iVTType = XFA_VT_TEXT;
2613 break;
2614 default:
2615 iVTType = XFA_VT_NULL;
2616 break;
2617 }
2618 CXFA_LocaleMgr* pLocalMgr = GetNode()->GetDocument()->GetLocalMgr();
2619 CXFA_LocaleValue widgetValue(iVTType, wsValue, pLocalMgr);
2620 switch (widgetValue.GetType()) {
2621 case XFA_VT_DATE: {
2622 WideString wsDate, wsTime;
2623 if (SplitDateTime(wsValue, wsDate, wsTime)) {
2624 CXFA_LocaleValue date(XFA_VT_DATE, wsDate, pLocalMgr);
2625 if (date.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
2626 XFA_VALUEPICTURE_DataBind)) {
2627 return wsFormattedValue;
2628 }
2629 }
2630 break;
2631 }
2632 case XFA_VT_TIME: {
2633 WideString wsDate, wsTime;
2634 if (SplitDateTime(wsValue, wsDate, wsTime)) {
2635 CXFA_LocaleValue time(XFA_VT_TIME, wsTime, pLocalMgr);
2636 if (time.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
2637 XFA_VALUEPICTURE_DataBind)) {
2638 return wsFormattedValue;
2639 }
2640 }
2641 break;
2642 }
2643 default:
2644 break;
2645 }
2646 widgetValue.FormatPatterns(wsFormattedValue, wsPicture, pLocale,
2647 XFA_VALUEPICTURE_DataBind);
2648 }
2649 return wsFormattedValue;
2650 }
2651
NormalizeNumStr(const WideString & wsValue)2652 WideString CXFA_WidgetAcc::NormalizeNumStr(const WideString& wsValue) {
2653 if (wsValue.IsEmpty())
2654 return L"";
2655
2656 WideString wsOutput = wsValue;
2657 wsOutput.TrimLeft('0');
2658
2659 if (!wsOutput.IsEmpty() && wsOutput.Contains('.') && GetFracDigits() != -1) {
2660 wsOutput.TrimRight(L"0");
2661 wsOutput.TrimRight(L".");
2662 }
2663 if (wsOutput.IsEmpty() || wsOutput[0] == '.')
2664 wsOutput.InsertAtFront('0');
2665
2666 return wsOutput;
2667 }
2668
FormatNumStr(const WideString & wsValue,IFX_Locale * pLocale)2669 WideString CXFA_WidgetAcc::FormatNumStr(const WideString& wsValue,
2670 IFX_Locale* pLocale) {
2671 if (wsValue.IsEmpty())
2672 return L"";
2673
2674 WideString wsSrcNum = wsValue;
2675 WideString wsGroupSymbol =
2676 pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Grouping);
2677 bool bNeg = false;
2678 if (wsSrcNum[0] == '-') {
2679 bNeg = true;
2680 wsSrcNum.Delete(0, 1);
2681 }
2682
2683 auto dot_index = wsSrcNum.Find('.');
2684 dot_index = !dot_index.has_value() ? wsSrcNum.GetLength() : dot_index;
2685
2686 if (dot_index.value() < 1)
2687 return L"";
2688
2689 size_t nPos = dot_index.value() % 3;
2690 WideString wsOutput;
2691 for (size_t i = 0; i < dot_index.value(); i++) {
2692 if (i % 3 == nPos && i != 0)
2693 wsOutput += wsGroupSymbol;
2694
2695 wsOutput += wsSrcNum[i];
2696 }
2697 if (dot_index.value() < wsSrcNum.GetLength()) {
2698 wsOutput += pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Decimal);
2699 wsOutput += wsSrcNum.Right(wsSrcNum.GetLength() - dot_index.value() - 1);
2700 }
2701 if (bNeg)
2702 return pLocale->GetNumbericSymbol(FX_LOCALENUMSYMBOL_Minus) + wsOutput;
2703
2704 return wsOutput;
2705 }
2706
InsertListTextItem(CXFA_Node * pItems,const WideString & wsText,int32_t nIndex)2707 void CXFA_WidgetAcc::InsertListTextItem(CXFA_Node* pItems,
2708 const WideString& wsText,
2709 int32_t nIndex) {
2710 CXFA_Node* pText = pItems->CreateSamePacketNode(XFA_Element::Text);
2711 pItems->InsertChild(nIndex, pText);
2712 pText->JSObject()->SetContent(wsText, wsText, false, false, false);
2713 }
2714
NumericLimit(const WideString & wsValue,int32_t iLead,int32_t iTread) const2715 WideString CXFA_WidgetAcc::NumericLimit(const WideString& wsValue,
2716 int32_t iLead,
2717 int32_t iTread) const {
2718 if ((iLead == -1) && (iTread == -1))
2719 return wsValue;
2720
2721 WideString wsRet;
2722 int32_t iLead_ = 0, iTread_ = -1;
2723 int32_t iCount = wsValue.GetLength();
2724 if (iCount == 0)
2725 return wsValue;
2726
2727 int32_t i = 0;
2728 if (wsValue[i] == L'-') {
2729 wsRet += L'-';
2730 i++;
2731 }
2732 for (; i < iCount; i++) {
2733 wchar_t wc = wsValue[i];
2734 if (FXSYS_isDecimalDigit(wc)) {
2735 if (iLead >= 0) {
2736 iLead_++;
2737 if (iLead_ > iLead)
2738 return L"0";
2739 } else if (iTread_ >= 0) {
2740 iTread_++;
2741 if (iTread_ > iTread) {
2742 if (iTread != -1) {
2743 CFX_Decimal wsDeci = CFX_Decimal(wsValue.AsStringView());
2744 wsDeci.SetScale(iTread);
2745 wsRet = wsDeci;
2746 }
2747 return wsRet;
2748 }
2749 }
2750 } else if (wc == L'.') {
2751 iTread_ = 0;
2752 iLead = -1;
2753 }
2754 wsRet += wc;
2755 }
2756 return wsRet;
2757 }
2758