1 // Copyright 2014 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_ffwidget.h" 8 9 #include <algorithm> 10 #include <cmath> 11 #include <memory> 12 #include <utility> 13 #include <vector> 14 15 #include "core/fpdfapi/cpdf_modulemgr.h" 16 #include "core/fxcodec/codec/ccodec_progressivedecoder.h" 17 #include "core/fxcodec/fx_codec.h" 18 #include "core/fxcrt/cfx_memorystream.h" 19 #include "core/fxcrt/maybe_owned.h" 20 #include "core/fxge/cfx_pathdata.h" 21 #include "xfa/fwl/fwl_widgethit.h" 22 #include "xfa/fxfa/cxfa_eventparam.h" 23 #include "xfa/fxfa/cxfa_ffapp.h" 24 #include "xfa/fxfa/cxfa_ffdoc.h" 25 #include "xfa/fxfa/cxfa_ffdocview.h" 26 #include "xfa/fxfa/cxfa_ffpageview.h" 27 #include "xfa/fxfa/cxfa_imagerenderer.h" 28 #include "xfa/fxfa/cxfa_widgetacc.h" 29 #include "xfa/fxfa/parser/cxfa_border.h" 30 #include "xfa/fxfa/parser/cxfa_box.h" 31 #include "xfa/fxfa/parser/cxfa_image.h" 32 #include "xfa/fxfa/parser/cxfa_layoutprocessor.h" 33 #include "xfa/fxfa/parser/cxfa_margin.h" 34 #include "xfa/fxfa/parser/cxfa_node.h" 35 #include "xfa/fxgraphics/cxfa_graphics.h" 36 37 namespace { 38 39 FXDIB_Format XFA_GetDIBFormat(FXCODEC_IMAGE_TYPE type, 40 int32_t iComponents, 41 int32_t iBitsPerComponent) { 42 FXDIB_Format dibFormat = FXDIB_Argb; 43 switch (type) { 44 case FXCODEC_IMAGE_BMP: 45 case FXCODEC_IMAGE_JPG: 46 case FXCODEC_IMAGE_TIF: { 47 dibFormat = FXDIB_Rgb32; 48 int32_t bpp = iComponents * iBitsPerComponent; 49 if (bpp <= 24) { 50 dibFormat = FXDIB_Rgb; 51 } 52 } break; 53 case FXCODEC_IMAGE_PNG: 54 default: 55 break; 56 } 57 return dibFormat; 58 } 59 60 bool IsFXCodecErrorStatus(FXCODEC_STATUS status) { 61 return (status == FXCODEC_STATUS_ERROR || 62 #ifdef PDF_ENABLE_XFA 63 status == FXCODEC_STATUS_ERR_MEMORY || 64 #endif // PDF_ENABLE_XFA 65 status == FXCODEC_STATUS_ERR_READ || 66 status == FXCODEC_STATUS_ERR_FLUSH || 67 status == FXCODEC_STATUS_ERR_FORMAT || 68 status == FXCODEC_STATUS_ERR_PARAMS); 69 } 70 71 } // namespace 72 73 void XFA_DrawImage(CXFA_Graphics* pGS, 74 const CFX_RectF& rtImage, 75 const CFX_Matrix& matrix, 76 const RetainPtr<CFX_DIBitmap>& pDIBitmap, 77 XFA_AttributeEnum iAspect, 78 int32_t iImageXDpi, 79 int32_t iImageYDpi, 80 XFA_AttributeEnum iHorzAlign, 81 XFA_AttributeEnum iVertAlign) { 82 if (rtImage.IsEmpty()) 83 return; 84 if (!pDIBitmap || !pDIBitmap->GetBuffer()) 85 return; 86 87 CFX_RectF rtFit( 88 rtImage.TopLeft(), 89 XFA_UnitPx2Pt((float)pDIBitmap->GetWidth(), (float)iImageXDpi), 90 XFA_UnitPx2Pt((float)pDIBitmap->GetHeight(), (float)iImageYDpi)); 91 switch (iAspect) { 92 case XFA_AttributeEnum::Fit: { 93 float f1 = rtImage.height / rtFit.height; 94 float f2 = rtImage.width / rtFit.width; 95 f1 = std::min(f1, f2); 96 rtFit.height = rtFit.height * f1; 97 rtFit.width = rtFit.width * f1; 98 break; 99 } 100 case XFA_AttributeEnum::Height: { 101 float f1 = rtImage.height / rtFit.height; 102 rtFit.height = rtImage.height; 103 rtFit.width = f1 * rtFit.width; 104 break; 105 } 106 case XFA_AttributeEnum::None: 107 rtFit.height = rtImage.height; 108 rtFit.width = rtImage.width; 109 break; 110 case XFA_AttributeEnum::Width: { 111 float f1 = rtImage.width / rtFit.width; 112 rtFit.width = rtImage.width; 113 rtFit.height = rtFit.height * f1; 114 break; 115 } 116 case XFA_AttributeEnum::Actual: 117 default: 118 break; 119 } 120 121 if (iHorzAlign == XFA_AttributeEnum::Center) 122 rtFit.left += (rtImage.width - rtFit.width) / 2; 123 else if (iHorzAlign == XFA_AttributeEnum::Right) 124 rtFit.left = rtImage.right() - rtFit.width; 125 126 if (iVertAlign == XFA_AttributeEnum::Middle) 127 rtFit.top += (rtImage.height - rtFit.height) / 2; 128 else if (iVertAlign == XFA_AttributeEnum::Bottom) 129 rtFit.top = rtImage.bottom() - rtImage.height; 130 131 CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); 132 CFX_RenderDevice::StateRestorer restorer(pRenderDevice); 133 CFX_PathData path; 134 path.AppendRect(rtImage.left, rtImage.bottom(), rtImage.right(), rtImage.top); 135 pRenderDevice->SetClip_PathFill(&path, &matrix, FXFILL_WINDING); 136 137 CFX_Matrix mtImage(1, 0, 0, -1, 0, 1); 138 mtImage.Concat( 139 CFX_Matrix(rtFit.width, 0, 0, rtFit.height, rtFit.left, rtFit.top)); 140 mtImage.Concat(matrix); 141 142 CXFA_ImageRenderer imageRender(pRenderDevice, pDIBitmap, &mtImage); 143 if (!imageRender.Start()) { 144 return; 145 } 146 while (imageRender.Continue()) 147 continue; 148 } 149 150 RetainPtr<CFX_DIBitmap> XFA_LoadImageFromBuffer( 151 const RetainPtr<IFX_SeekableReadStream>& pImageFileRead, 152 FXCODEC_IMAGE_TYPE type, 153 int32_t& iImageXDpi, 154 int32_t& iImageYDpi) { 155 CCodec_ModuleMgr* pCodecMgr = CPDF_ModuleMgr::Get()->GetCodecModule(); 156 std::unique_ptr<CCodec_ProgressiveDecoder> pProgressiveDecoder = 157 pCodecMgr->CreateProgressiveDecoder(); 158 159 CFX_DIBAttribute dibAttr; 160 pProgressiveDecoder->LoadImageInfo(pImageFileRead, type, &dibAttr, false); 161 switch (dibAttr.m_wDPIUnit) { 162 case FXCODEC_RESUNIT_CENTIMETER: 163 dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI * 2.54f); 164 dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI * 2.54f); 165 break; 166 case FXCODEC_RESUNIT_METER: 167 dibAttr.m_nXDPI = (int32_t)(dibAttr.m_nXDPI / (float)100 * 2.54f); 168 dibAttr.m_nYDPI = (int32_t)(dibAttr.m_nYDPI / (float)100 * 2.54f); 169 break; 170 default: 171 break; 172 } 173 iImageXDpi = dibAttr.m_nXDPI > 1 ? dibAttr.m_nXDPI : (96); 174 iImageYDpi = dibAttr.m_nYDPI > 1 ? dibAttr.m_nYDPI : (96); 175 if (pProgressiveDecoder->GetWidth() <= 0 || 176 pProgressiveDecoder->GetHeight() <= 0) { 177 return nullptr; 178 } 179 180 type = pProgressiveDecoder->GetType(); 181 int32_t iComponents = pProgressiveDecoder->GetNumComponents(); 182 int32_t iBpc = pProgressiveDecoder->GetBPC(); 183 FXDIB_Format dibFormat = XFA_GetDIBFormat(type, iComponents, iBpc); 184 RetainPtr<CFX_DIBitmap> pBitmap = pdfium::MakeRetain<CFX_DIBitmap>(); 185 pBitmap->Create(pProgressiveDecoder->GetWidth(), 186 pProgressiveDecoder->GetHeight(), dibFormat); 187 pBitmap->Clear(0xffffffff); 188 189 size_t nFrames; 190 FXCODEC_STATUS status; 191 std::tie(status, nFrames) = pProgressiveDecoder->GetFrames(); 192 if (status != FXCODEC_STATUS_DECODE_READY || nFrames == 0) { 193 pBitmap = nullptr; 194 return pBitmap; 195 } 196 197 status = pProgressiveDecoder->StartDecode(pBitmap, 0, 0, pBitmap->GetWidth(), 198 pBitmap->GetHeight()); 199 if (IsFXCodecErrorStatus(status)) { 200 pBitmap = nullptr; 201 return pBitmap; 202 } 203 204 while (status == FXCODEC_STATUS_DECODE_TOBECONTINUE) { 205 status = pProgressiveDecoder->ContinueDecode(); 206 if (IsFXCodecErrorStatus(status)) { 207 pBitmap = nullptr; 208 return pBitmap; 209 } 210 } 211 212 return pBitmap; 213 } 214 215 void XFA_RectWithoutMargin(CFX_RectF& rt, const CXFA_Margin* margin, bool bUI) { 216 if (!margin) 217 return; 218 219 rt.Deflate(margin->GetLeftInset(), margin->GetTopInset(), 220 margin->GetRightInset(), margin->GetBottomInset()); 221 } 222 223 CXFA_FFWidget* XFA_GetWidgetFromLayoutItem(CXFA_LayoutItem* pLayoutItem) { 224 if (pLayoutItem->GetFormNode()->HasCreatedUIWidget()) 225 return static_cast<CXFA_FFWidget*>(pLayoutItem); 226 return nullptr; 227 } 228 229 CXFA_CalcData::CXFA_CalcData() : m_iRefCount(0) {} 230 231 CXFA_CalcData::~CXFA_CalcData() {} 232 233 CXFA_FFWidget::CXFA_FFWidget(CXFA_Node* node) 234 : CXFA_ContentLayoutItem(node), m_pNode(node) {} 235 236 CXFA_FFWidget::~CXFA_FFWidget() {} 237 238 const CFWL_App* CXFA_FFWidget::GetFWLApp() { 239 return GetPageView()->GetDocView()->GetDoc()->GetApp()->GetFWLApp(); 240 } 241 242 const CFX_RectF& CXFA_FFWidget::GetWidgetRect() const { 243 if ((m_dwStatus & XFA_WidgetStatus_RectCached) == 0) 244 RecacheWidgetRect(); 245 return m_rtWidget; 246 } 247 248 const CFX_RectF& CXFA_FFWidget::RecacheWidgetRect() const { 249 m_dwStatus |= XFA_WidgetStatus_RectCached; 250 m_rtWidget = GetRect(false); 251 return m_rtWidget; 252 } 253 254 CFX_RectF CXFA_FFWidget::GetRectWithoutRotate() { 255 CFX_RectF rtWidget = GetWidgetRect(); 256 float fValue = 0; 257 switch (m_pNode->GetRotate()) { 258 case 90: 259 rtWidget.top = rtWidget.bottom(); 260 fValue = rtWidget.width; 261 rtWidget.width = rtWidget.height; 262 rtWidget.height = fValue; 263 break; 264 case 180: 265 rtWidget.left = rtWidget.right(); 266 rtWidget.top = rtWidget.bottom(); 267 break; 268 case 270: 269 rtWidget.left = rtWidget.right(); 270 fValue = rtWidget.width; 271 rtWidget.width = rtWidget.height; 272 rtWidget.height = fValue; 273 break; 274 } 275 return rtWidget; 276 } 277 278 uint32_t CXFA_FFWidget::GetStatus() { 279 return m_dwStatus; 280 } 281 282 void CXFA_FFWidget::ModifyStatus(uint32_t dwAdded, uint32_t dwRemoved) { 283 m_dwStatus = (m_dwStatus & ~dwRemoved) | dwAdded; 284 } 285 286 CFX_RectF CXFA_FFWidget::GetBBox(uint32_t dwStatus, bool bDrawFocus) { 287 if (bDrawFocus || !m_pPageView) 288 return CFX_RectF(); 289 return m_pPageView->GetPageViewRect(); 290 } 291 292 void CXFA_FFWidget::RenderWidget(CXFA_Graphics* pGS, 293 const CFX_Matrix& matrix, 294 uint32_t dwStatus) { 295 if (!IsMatchVisibleStatus(dwStatus)) 296 return; 297 298 CXFA_Border* border = m_pNode->GetBorderIfExists(); 299 if (!border) 300 return; 301 302 CFX_RectF rtBorder = GetRectWithoutRotate(); 303 CXFA_Margin* margin = border->GetMarginIfExists(); 304 if (margin) 305 XFA_RectWithoutMargin(rtBorder, margin); 306 307 rtBorder.Normalize(); 308 DrawBorder(pGS, border, rtBorder, matrix); 309 } 310 311 bool CXFA_FFWidget::IsLoaded() { 312 return !!m_pPageView; 313 } 314 315 bool CXFA_FFWidget::LoadWidget() { 316 PerformLayout(); 317 return true; 318 } 319 320 void CXFA_FFWidget::UnloadWidget() {} 321 322 bool CXFA_FFWidget::PerformLayout() { 323 RecacheWidgetRect(); 324 return true; 325 } 326 327 bool CXFA_FFWidget::UpdateFWLData() { 328 return false; 329 } 330 331 void CXFA_FFWidget::UpdateWidgetProperty() {} 332 333 void CXFA_FFWidget::DrawBorder(CXFA_Graphics* pGS, 334 CXFA_Box* box, 335 const CFX_RectF& rtBorder, 336 const CFX_Matrix& matrix) { 337 if (box) 338 box->Draw(pGS, rtBorder, matrix, false); 339 } 340 341 void CXFA_FFWidget::DrawBorderWithFlag(CXFA_Graphics* pGS, 342 CXFA_Box* box, 343 const CFX_RectF& rtBorder, 344 const CFX_Matrix& matrix, 345 bool forceRound) { 346 if (box) 347 box->Draw(pGS, rtBorder, matrix, forceRound); 348 } 349 350 void CXFA_FFWidget::AddInvalidateRect() { 351 CFX_RectF rtWidget = GetBBox(XFA_WidgetStatus_Focused); 352 rtWidget.Inflate(2, 2); 353 m_pDocView->AddInvalidateRect(m_pPageView, rtWidget); 354 } 355 356 bool CXFA_FFWidget::OnMouseEnter() { 357 return false; 358 } 359 360 bool CXFA_FFWidget::OnMouseExit() { 361 return false; 362 } 363 364 bool CXFA_FFWidget::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) { 365 return false; 366 } 367 368 bool CXFA_FFWidget::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) { 369 return false; 370 } 371 372 bool CXFA_FFWidget::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) { 373 return false; 374 } 375 376 bool CXFA_FFWidget::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) { 377 return false; 378 } 379 380 bool CXFA_FFWidget::OnMouseWheel(uint32_t dwFlags, 381 int16_t zDelta, 382 const CFX_PointF& point) { 383 return false; 384 } 385 386 bool CXFA_FFWidget::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) { 387 return false; 388 } 389 390 bool CXFA_FFWidget::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) { 391 return false; 392 } 393 394 bool CXFA_FFWidget::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) { 395 return false; 396 } 397 398 bool CXFA_FFWidget::OnSetFocus(CXFA_FFWidget* pOldWidget) { 399 CXFA_FFWidget* pParent = GetParent(); 400 if (pParent && !pParent->IsAncestorOf(pOldWidget)) { 401 pParent->OnSetFocus(pOldWidget); 402 } 403 m_dwStatus |= XFA_WidgetStatus_Focused; 404 CXFA_EventParam eParam; 405 eParam.m_eType = XFA_EVENT_Enter; 406 eParam.m_pTarget = m_pNode->GetWidgetAcc(); 407 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Enter, &eParam); 408 return true; 409 } 410 411 bool CXFA_FFWidget::OnKillFocus(CXFA_FFWidget* pNewWidget) { 412 m_dwStatus &= ~XFA_WidgetStatus_Focused; 413 EventKillFocus(); 414 if (pNewWidget) { 415 CXFA_FFWidget* pParent = GetParent(); 416 if (pParent && !pParent->IsAncestorOf(pNewWidget)) { 417 pParent->OnKillFocus(pNewWidget); 418 } 419 } 420 return true; 421 } 422 423 bool CXFA_FFWidget::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) { 424 return false; 425 } 426 427 bool CXFA_FFWidget::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) { 428 return false; 429 } 430 431 bool CXFA_FFWidget::OnChar(uint32_t dwChar, uint32_t dwFlags) { 432 return false; 433 } 434 435 FWL_WidgetHit CXFA_FFWidget::OnHitTest(const CFX_PointF& point) { 436 return FWL_WidgetHit::Unknown; 437 } 438 439 bool CXFA_FFWidget::OnSetCursor(const CFX_PointF& point) { 440 return false; 441 } 442 443 bool CXFA_FFWidget::CanUndo() { 444 return false; 445 } 446 447 bool CXFA_FFWidget::CanRedo() { 448 return false; 449 } 450 451 bool CXFA_FFWidget::Undo() { 452 return false; 453 } 454 455 bool CXFA_FFWidget::Redo() { 456 return false; 457 } 458 459 bool CXFA_FFWidget::CanCopy() { 460 return false; 461 } 462 463 bool CXFA_FFWidget::CanCut() { 464 return false; 465 } 466 467 bool CXFA_FFWidget::CanPaste() { 468 return false; 469 } 470 471 bool CXFA_FFWidget::CanSelectAll() { 472 return false; 473 } 474 475 bool CXFA_FFWidget::CanDelete() { 476 return CanCut(); 477 } 478 479 bool CXFA_FFWidget::CanDeSelect() { 480 return CanCopy(); 481 } 482 483 Optional<WideString> CXFA_FFWidget::Copy() { 484 return {}; 485 } 486 487 Optional<WideString> CXFA_FFWidget::Cut() { 488 return {}; 489 } 490 491 bool CXFA_FFWidget::Paste(const WideString& wsPaste) { 492 return false; 493 } 494 495 void CXFA_FFWidget::SelectAll() {} 496 497 void CXFA_FFWidget::Delete() {} 498 499 void CXFA_FFWidget::DeSelect() {} 500 501 FormFieldType CXFA_FFWidget::GetFormFieldType() { 502 return FormFieldType::kXFA; 503 } 504 505 void CXFA_FFWidget::GetSuggestWords(CFX_PointF pointf, 506 std::vector<ByteString>* pWords) { 507 pWords->clear(); 508 } 509 510 bool CXFA_FFWidget::ReplaceSpellCheckWord(CFX_PointF pointf, 511 const ByteStringView& bsReplace) { 512 return false; 513 } 514 515 CFX_PointF CXFA_FFWidget::Rotate2Normal(const CFX_PointF& point) { 516 CFX_Matrix mt = GetRotateMatrix(); 517 if (mt.IsIdentity()) 518 return point; 519 520 return mt.GetInverse().Transform(point); 521 } 522 523 CFX_Matrix CXFA_FFWidget::GetRotateMatrix() { 524 int32_t iRotate = m_pNode->GetRotate(); 525 if (!iRotate) 526 return CFX_Matrix(); 527 528 CFX_RectF rcWidget = GetRectWithoutRotate(); 529 CFX_Matrix mt; 530 switch (iRotate) { 531 case 90: 532 mt.a = 0; 533 mt.b = -1; 534 mt.c = 1; 535 mt.d = 0; 536 mt.e = rcWidget.left - rcWidget.top; 537 mt.f = rcWidget.left + rcWidget.top; 538 break; 539 case 180: 540 mt.a = -1; 541 mt.b = 0; 542 mt.c = 0; 543 mt.d = -1; 544 mt.e = rcWidget.left * 2; 545 mt.f = rcWidget.top * 2; 546 break; 547 case 270: 548 mt.a = 0; 549 mt.b = 1; 550 mt.c = -1; 551 mt.d = 0; 552 mt.e = rcWidget.left + rcWidget.top; 553 mt.f = rcWidget.top - rcWidget.left; 554 break; 555 } 556 return mt; 557 } 558 559 bool CXFA_FFWidget::IsLayoutRectEmpty() { 560 CFX_RectF rtLayout = GetRectWithoutRotate(); 561 return rtLayout.width < 0.1f && rtLayout.height < 0.1f; 562 } 563 564 CXFA_FFWidget* CXFA_FFWidget::GetParent() { 565 CXFA_Node* pParentNode = m_pNode->GetParent(); 566 if (pParentNode) { 567 CXFA_WidgetAcc* pParentWidgetAcc = 568 static_cast<CXFA_WidgetAcc*>(pParentNode->GetWidgetAcc()); 569 if (pParentWidgetAcc) { 570 CXFA_LayoutProcessor* layout = GetDocView()->GetXFALayout(); 571 return static_cast<CXFA_FFWidget*>( 572 layout->GetLayoutItem(pParentWidgetAcc->GetNode())); 573 } 574 } 575 return nullptr; 576 } 577 578 bool CXFA_FFWidget::IsAncestorOf(CXFA_FFWidget* pWidget) { 579 if (!pWidget) 580 return false; 581 582 CXFA_Node* pChildNode = pWidget->GetNode(); 583 while (pChildNode) { 584 if (pChildNode == m_pNode) 585 return true; 586 587 pChildNode = pChildNode->GetParent(); 588 } 589 return false; 590 } 591 592 bool CXFA_FFWidget::PtInActiveRect(const CFX_PointF& point) { 593 return GetWidgetRect().Contains(point); 594 } 595 596 CXFA_FFDocView* CXFA_FFWidget::GetDocView() { 597 return m_pDocView; 598 } 599 600 void CXFA_FFWidget::SetDocView(CXFA_FFDocView* pDocView) { 601 m_pDocView = pDocView; 602 } 603 604 CXFA_FFDoc* CXFA_FFWidget::GetDoc() { 605 return m_pDocView->GetDoc(); 606 } 607 608 CXFA_FFApp* CXFA_FFWidget::GetApp() { 609 return GetDoc()->GetApp(); 610 } 611 612 IXFA_AppProvider* CXFA_FFWidget::GetAppProvider() { 613 return GetApp()->GetAppProvider(); 614 } 615 616 bool CXFA_FFWidget::IsMatchVisibleStatus(uint32_t dwStatus) { 617 return !!(m_dwStatus & XFA_WidgetStatus_Visible); 618 } 619 620 void CXFA_FFWidget::EventKillFocus() { 621 if (m_dwStatus & XFA_WidgetStatus_Access) { 622 m_dwStatus &= ~XFA_WidgetStatus_Access; 623 return; 624 } 625 CXFA_EventParam eParam; 626 eParam.m_eType = XFA_EVENT_Exit; 627 eParam.m_pTarget = m_pNode->GetWidgetAcc(); 628 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Exit, &eParam); 629 } 630 631 bool CXFA_FFWidget::IsButtonDown() { 632 return (m_dwStatus & XFA_WidgetStatus_ButtonDown) != 0; 633 } 634 635 void CXFA_FFWidget::SetButtonDown(bool bSet) { 636 bSet ? m_dwStatus |= XFA_WidgetStatus_ButtonDown 637 : m_dwStatus &= ~XFA_WidgetStatus_ButtonDown; 638 } 639