• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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