Home | History | Annotate | Download | only in fxfa
      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:
     58   CXFA_WidgetLayoutData() : m_fWidgetHeight(-1) {}
     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 
     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 
     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 
    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 
    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:
    214   CXFA_TextLayoutData() {}
    215   ~CXFA_TextLayoutData() override {}
    216 
    217   CXFA_TextLayout* GetTextLayout() const { return m_pTextLayout.get(); }
    218   CXFA_TextProvider* GetTextProvider() const { return m_pTextProvider.get(); }
    219 
    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:
    237   CXFA_ImageLayoutData()
    238       : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
    239 
    240   ~CXFA_ImageLayoutData() override {}
    241 
    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:
    267   CXFA_FieldLayoutData() {}
    268   ~CXFA_FieldLayoutData() override {}
    269 
    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:
    294   CXFA_ImageEditData()
    295       : m_bNamedImage(false), m_iImageXDpi(0), m_iImageYDpi(0) {}
    296 
    297   ~CXFA_ImageEditData() override {}
    298 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    621 CXFA_FFWidget* CXFA_WidgetAcc::GetNextWidget(CXFA_FFWidget* pWidget) {
    622   return static_cast<CXFA_FFWidget*>(pWidget->GetNext());
    623 }
    624 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    860 bool CXFA_WidgetAcc::CalculatePushButtonAutoSize(CXFA_FFDoc* doc,
    861                                                  CFX_SizeF& size) {
    862   CalcCaptionSize(doc, size);
    863   return CalculateWidgetAutoSize(size);
    864 }
    865 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    956 void CXFA_WidgetAcc::LoadText(CXFA_FFDoc* doc) {
    957   InitLayoutData();
    958   static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())->LoadText(doc, this);
    959 }
    960 
    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 
    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 
    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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   1409 CXFA_TextLayout* CXFA_WidgetAcc::GetTextLayout() {
   1410   return m_pLayoutData
   1411              ? static_cast<CXFA_TextLayoutData*>(m_pLayoutData.get())
   1412                    ->GetTextLayout()
   1413              : nullptr;
   1414 }
   1415 
   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 
   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 
   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 
   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 
   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 
   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 
   1467 XFA_Element CXFA_WidgetAcc::GetUIType() {
   1468   GetUIChild();
   1469   return m_eUIType;
   1470 }
   1471 
   1472 bool CXFA_WidgetAcc::IsOpenAccess() const {
   1473   return m_pNode && m_pNode->IsOpenAccess();
   1474 }
   1475 
   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 
   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 
   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 
   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 
   1554 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 
   1568 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 
   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 
   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 
   1597 bool CXFA_WidgetAcc::IsRadioButton() {
   1598   CXFA_Node* pParent = m_pNode->GetParent();
   1599   return pParent && pParent->GetElementType() == XFA_Element::ExclGroup;
   1600 }
   1601 
   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 
   1612 bool CXFA_WidgetAcc::IsAllowNeutral() {
   1613   CXFA_Node* pUIChild = GetUIChild();
   1614   return pUIChild &&
   1615          pUIChild->JSObject()->GetBoolean(XFA_Attribute::AllowNeutral);
   1616 }
   1617 
   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 
   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 
   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 
   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 
   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 
   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 }
   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 
   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 
   1808 bool CXFA_WidgetAcc::IsChoiceListAllowTextEntry() {
   1809   CXFA_Node* pUIChild = GetUIChild();
   1810   return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::TextEntry);
   1811 }
   1812 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   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 
   2286 WideString CXFA_WidgetAcc::GetPasswordChar() {
   2287   CXFA_Node* pUIChild = GetUIChild();
   2288   return pUIChild ? pUIChild->JSObject()->GetCData(XFA_Attribute::PasswordChar)
   2289                   : L"*";
   2290 }
   2291 
   2292 bool CXFA_WidgetAcc::IsMultiLine() {
   2293   CXFA_Node* pUIChild = GetUIChild();
   2294   return pUIChild && pUIChild->JSObject()->GetBoolean(XFA_Attribute::MultiLine);
   2295 }
   2296 
   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 
   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 
   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 
   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 
   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 
   2480 IFX_Locale* CXFA_WidgetAcc::GetLocale() {
   2481   return m_pNode ? m_pNode->GetLocale() : nullptr;
   2482 }
   2483 
   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 
   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 
   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 
   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 
   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 
   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 
   2715 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