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