Home | History | Annotate | Download | only in fxfa
      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_fffield.h"
      8 
      9 #include "xfa/fwl/cfwl_edit.h"
     10 #include "xfa/fwl/cfwl_eventmouse.h"
     11 #include "xfa/fwl/cfwl_messagekey.h"
     12 #include "xfa/fwl/cfwl_messagekillfocus.h"
     13 #include "xfa/fwl/cfwl_messagemouse.h"
     14 #include "xfa/fwl/cfwl_messagemousewheel.h"
     15 #include "xfa/fwl/cfwl_messagesetfocus.h"
     16 #include "xfa/fwl/cfwl_picturebox.h"
     17 #include "xfa/fwl/cfwl_widgetmgr.h"
     18 #include "xfa/fxfa/cxfa_ffapp.h"
     19 #include "xfa/fxfa/cxfa_ffdoc.h"
     20 #include "xfa/fxfa/cxfa_ffdocview.h"
     21 #include "xfa/fxfa/cxfa_ffpageview.h"
     22 #include "xfa/fxfa/cxfa_ffwidget.h"
     23 #include "xfa/fxfa/cxfa_fwltheme.h"
     24 #include "xfa/fxfa/cxfa_textlayout.h"
     25 #include "xfa/fxfa/parser/cxfa_border.h"
     26 #include "xfa/fxfa/parser/cxfa_calculate.h"
     27 #include "xfa/fxfa/parser/cxfa_caption.h"
     28 #include "xfa/fxfa/parser/cxfa_margin.h"
     29 #include "xfa/fxfa/parser/cxfa_node.h"
     30 #include "xfa/fxfa/parser/cxfa_script.h"
     31 #include "xfa/fxgraphics/cxfa_gecolor.h"
     32 #include "xfa/fxgraphics/cxfa_gepath.h"
     33 
     34 namespace {
     35 
     36 CXFA_FFField* ToField(CXFA_LayoutItem* widget) {
     37   return static_cast<CXFA_FFField*>(widget);
     38 }
     39 
     40 }  // namespace
     41 
     42 CXFA_FFField::CXFA_FFField(CXFA_Node* pNode) : CXFA_FFWidget(pNode) {}
     43 
     44 CXFA_FFField::~CXFA_FFField() {
     45   CXFA_FFField::UnloadWidget();
     46 }
     47 
     48 CFX_RectF CXFA_FFField::GetBBox(uint32_t dwStatus, bool bDrawFocus) {
     49   if (!bDrawFocus)
     50     return CXFA_FFWidget::GetBBox(dwStatus);
     51 
     52   XFA_Element type = m_pNode->GetWidgetAcc()->GetUIType();
     53   if (type != XFA_Element::Button && type != XFA_Element::CheckButton &&
     54       type != XFA_Element::ImageEdit && type != XFA_Element::Signature &&
     55       type != XFA_Element::ChoiceList) {
     56     return CFX_RectF();
     57   }
     58 
     59   return GetRotateMatrix().TransformRect(m_rtUI);
     60 }
     61 
     62 void CXFA_FFField::RenderWidget(CXFA_Graphics* pGS,
     63                                 const CFX_Matrix& matrix,
     64                                 uint32_t dwStatus) {
     65   if (!IsMatchVisibleStatus(dwStatus))
     66     return;
     67 
     68   CFX_Matrix mtRotate = GetRotateMatrix();
     69   mtRotate.Concat(matrix);
     70 
     71   CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus);
     72   DrawBorder(pGS, m_pNode->GetWidgetAcc()->GetUIBorder(), m_rtUI, mtRotate);
     73   RenderCaption(pGS, &mtRotate);
     74   DrawHighlight(pGS, &mtRotate, dwStatus, false);
     75 
     76   CFX_RectF rtWidget = m_pNormalWidget->GetWidgetRect();
     77   CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top);
     78   mt.Concat(mtRotate);
     79   GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt);
     80 }
     81 
     82 void CXFA_FFField::DrawHighlight(CXFA_Graphics* pGS,
     83                                  CFX_Matrix* pMatrix,
     84                                  uint32_t dwStatus,
     85                                  bool bEllipse) {
     86   if (m_rtUI.IsEmpty() || !GetDoc()->GetXFADoc()->IsInteractive())
     87     return;
     88   if (!(dwStatus & XFA_WidgetStatus_Highlight) || !m_pNode->IsOpenAccess())
     89     return;
     90 
     91   CXFA_FFDoc* pDoc = GetDoc();
     92   pGS->SetFillColor(
     93       CXFA_GEColor(pDoc->GetDocEnvironment()->GetHighlightColor(pDoc)));
     94   CXFA_GEPath path;
     95   if (bEllipse)
     96     path.AddEllipse(m_rtUI);
     97   else
     98     path.AddRectangle(m_rtUI.left, m_rtUI.top, m_rtUI.width, m_rtUI.height);
     99 
    100   pGS->FillPath(&path, FXFILL_WINDING, pMatrix);
    101 }
    102 
    103 void CXFA_FFField::DrawFocus(CXFA_Graphics* pGS, CFX_Matrix* pMatrix) {
    104   if (!(m_dwStatus & XFA_WidgetStatus_Focused))
    105     return;
    106 
    107   pGS->SetStrokeColor(CXFA_GEColor(0xFF000000));
    108 
    109   float DashPattern[2] = {1, 1};
    110   pGS->SetLineDash(0.0f, DashPattern, 2);
    111   pGS->SetLineWidth(0);
    112 
    113   CXFA_GEPath path;
    114   path.AddRectangle(m_rtUI.left, m_rtUI.top, m_rtUI.width, m_rtUI.height);
    115   pGS->StrokePath(&path, pMatrix);
    116 }
    117 
    118 void CXFA_FFField::SetFWLThemeProvider() {
    119   if (m_pNormalWidget)
    120     m_pNormalWidget->SetThemeProvider(GetApp()->GetFWLTheme());
    121 }
    122 
    123 bool CXFA_FFField::IsLoaded() {
    124   return m_pNormalWidget && CXFA_FFWidget::IsLoaded();
    125 }
    126 
    127 bool CXFA_FFField::LoadWidget() {
    128   SetFWLThemeProvider();
    129   m_pNode->GetWidgetAcc()->LoadCaption(GetDoc());
    130   PerformLayout();
    131   return true;
    132 }
    133 
    134 void CXFA_FFField::UnloadWidget() {
    135   m_pNormalWidget.reset();
    136 }
    137 
    138 void CXFA_FFField::SetEditScrollOffset() {
    139   XFA_Element eType = m_pNode->GetWidgetAcc()->GetUIType();
    140   if (eType != XFA_Element::TextEdit && eType != XFA_Element::NumericEdit &&
    141       eType != XFA_Element::PasswordEdit) {
    142     return;
    143   }
    144 
    145   float fScrollOffset = 0;
    146   CXFA_FFField* pPrev = ToField(GetPrev());
    147   if (pPrev) {
    148     CFX_RectF rtMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
    149     fScrollOffset = -rtMargin.top;
    150   }
    151 
    152   while (pPrev) {
    153     fScrollOffset += pPrev->m_rtUI.height;
    154     pPrev = ToField(pPrev->GetPrev());
    155   }
    156   static_cast<CFWL_Edit*>(m_pNormalWidget.get())
    157       ->SetScrollOffset(fScrollOffset);
    158 }
    159 
    160 bool CXFA_FFField::PerformLayout() {
    161   CXFA_FFWidget::PerformLayout();
    162   CapPlacement();
    163   LayoutCaption();
    164   SetFWLRect();
    165   SetEditScrollOffset();
    166   if (m_pNormalWidget)
    167     m_pNormalWidget->Update();
    168   return true;
    169 }
    170 
    171 void CXFA_FFField::CapPlacement() {
    172   CFX_RectF rtWidget = GetRectWithoutRotate();
    173   CXFA_Margin* margin = m_pNode->GetMarginIfExists();
    174   if (margin) {
    175     CXFA_LayoutItem* pItem = this;
    176     float fLeftInset = margin->GetLeftInset();
    177     float fRightInset = margin->GetRightInset();
    178     float fTopInset = margin->GetTopInset();
    179     float fBottomInset = margin->GetBottomInset();
    180     if (!pItem->GetPrev() && !pItem->GetNext()) {
    181       rtWidget.Deflate(fLeftInset, fTopInset, fRightInset, fBottomInset);
    182     } else {
    183       if (!pItem->GetPrev())
    184         rtWidget.Deflate(fLeftInset, fTopInset, fRightInset, 0);
    185       else if (!pItem->GetNext())
    186         rtWidget.Deflate(fLeftInset, 0, fRightInset, fBottomInset);
    187       else
    188         rtWidget.Deflate(fLeftInset, 0, fRightInset, 0);
    189     }
    190   }
    191 
    192   XFA_AttributeEnum iCapPlacement = XFA_AttributeEnum::Unknown;
    193   float fCapReserve = 0;
    194   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
    195   if (caption && !caption->IsHidden()) {
    196     iCapPlacement = caption->GetPlacementType();
    197     if (iCapPlacement == XFA_AttributeEnum::Top && GetPrev()) {
    198       m_rtCaption.Reset();
    199     } else if (iCapPlacement == XFA_AttributeEnum::Bottom && GetNext()) {
    200       m_rtCaption.Reset();
    201     } else {
    202       fCapReserve = caption->GetReserve();
    203       CXFA_LayoutItem* pItem = this;
    204       if (!pItem->GetPrev() && !pItem->GetNext()) {
    205         m_rtCaption = rtWidget;
    206       } else {
    207         pItem = pItem->GetFirst();
    208         m_rtCaption = pItem->GetRect(false);
    209         pItem = pItem->GetNext();
    210         while (pItem) {
    211           m_rtCaption.height += pItem->GetRect(false).Height();
    212           pItem = pItem->GetNext();
    213         }
    214         XFA_RectWithoutMargin(m_rtCaption, margin);
    215       }
    216 
    217       CXFA_TextLayout* pCapTextLayout =
    218           m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
    219       if (fCapReserve <= 0 && pCapTextLayout) {
    220         CFX_SizeF minSize;
    221         CFX_SizeF maxSize;
    222         CFX_SizeF size = pCapTextLayout->CalcSize(minSize, maxSize);
    223         if (iCapPlacement == XFA_AttributeEnum::Top ||
    224             iCapPlacement == XFA_AttributeEnum::Bottom) {
    225           fCapReserve = size.height;
    226         } else {
    227           fCapReserve = size.width;
    228         }
    229       }
    230     }
    231   }
    232 
    233   m_rtUI = rtWidget;
    234   CXFA_Margin* capMargin = caption ? caption->GetMarginIfExists() : nullptr;
    235   switch (iCapPlacement) {
    236     case XFA_AttributeEnum::Left: {
    237       m_rtCaption.width = fCapReserve;
    238       CapLeftRightPlacement(capMargin, rtWidget, iCapPlacement);
    239       m_rtUI.width -= fCapReserve;
    240       m_rtUI.left += fCapReserve;
    241       break;
    242     }
    243     case XFA_AttributeEnum::Top: {
    244       m_rtCaption.height = fCapReserve;
    245       CapTopBottomPlacement(capMargin, rtWidget, iCapPlacement);
    246       m_rtUI.top += fCapReserve;
    247       m_rtUI.height -= fCapReserve;
    248       break;
    249     }
    250     case XFA_AttributeEnum::Right: {
    251       m_rtCaption.left = m_rtCaption.right() - fCapReserve;
    252       m_rtCaption.width = fCapReserve;
    253       CapLeftRightPlacement(capMargin, rtWidget, iCapPlacement);
    254       m_rtUI.width -= fCapReserve;
    255       break;
    256     }
    257     case XFA_AttributeEnum::Bottom: {
    258       m_rtCaption.top = m_rtCaption.bottom() - fCapReserve;
    259       m_rtCaption.height = fCapReserve;
    260       CapTopBottomPlacement(capMargin, rtWidget, iCapPlacement);
    261       m_rtUI.height -= fCapReserve;
    262       break;
    263     }
    264     case XFA_AttributeEnum::Inline:
    265       break;
    266     default:
    267       break;
    268   }
    269 
    270   CXFA_Border* borderUI = m_pNode->GetWidgetAcc()->GetUIBorder();
    271   if (borderUI) {
    272     CXFA_Margin* borderMargin = borderUI->GetMarginIfExists();
    273     if (borderMargin)
    274       XFA_RectWithoutMargin(m_rtUI, borderMargin);
    275   }
    276   m_rtUI.Normalize();
    277 }
    278 
    279 void CXFA_FFField::CapTopBottomPlacement(const CXFA_Margin* margin,
    280                                          const CFX_RectF& rtWidget,
    281                                          XFA_AttributeEnum iCapPlacement) {
    282   CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
    283   m_rtCaption.left += rtUIMargin.left;
    284   if (margin) {
    285     XFA_RectWithoutMargin(m_rtCaption, margin);
    286     if (m_rtCaption.height < 0)
    287       m_rtCaption.top += m_rtCaption.height;
    288   }
    289 
    290   float fWidth = rtUIMargin.left + rtUIMargin.width;
    291   float fHeight = m_rtCaption.height + rtUIMargin.top + rtUIMargin.height;
    292   if (fWidth > rtWidget.width)
    293     m_rtUI.width += fWidth - rtWidget.width;
    294 
    295   if (fHeight == XFA_DEFAULTUI_HEIGHT && m_rtUI.height < XFA_MINUI_HEIGHT) {
    296     m_rtUI.height = XFA_MINUI_HEIGHT;
    297     m_rtCaption.top += rtUIMargin.top + rtUIMargin.height;
    298   } else if (fHeight > rtWidget.height) {
    299     m_rtUI.height += fHeight - rtWidget.height;
    300     if (iCapPlacement == XFA_AttributeEnum::Bottom)
    301       m_rtCaption.top += fHeight - rtWidget.height;
    302   }
    303 }
    304 
    305 void CXFA_FFField::CapLeftRightPlacement(const CXFA_Margin* margin,
    306                                          const CFX_RectF& rtWidget,
    307                                          XFA_AttributeEnum iCapPlacement) {
    308   CFX_RectF rtUIMargin = m_pNode->GetWidgetAcc()->GetUIMargin();
    309   m_rtCaption.top += rtUIMargin.top;
    310   m_rtCaption.height -= rtUIMargin.top;
    311   if (margin) {
    312     XFA_RectWithoutMargin(m_rtCaption, margin);
    313     if (m_rtCaption.height < 0)
    314       m_rtCaption.top += m_rtCaption.height;
    315   }
    316 
    317   float fWidth = m_rtCaption.width + rtUIMargin.left + rtUIMargin.width;
    318   float fHeight = rtUIMargin.top + rtUIMargin.height;
    319   if (fWidth > rtWidget.width) {
    320     m_rtUI.width += fWidth - rtWidget.width;
    321     if (iCapPlacement == XFA_AttributeEnum::Right)
    322       m_rtCaption.left += fWidth - rtWidget.width;
    323   }
    324 
    325   if (fHeight == XFA_DEFAULTUI_HEIGHT && m_rtUI.height < XFA_MINUI_HEIGHT) {
    326     m_rtUI.height = XFA_MINUI_HEIGHT;
    327     m_rtCaption.top += rtUIMargin.top + rtUIMargin.height;
    328   } else if (fHeight > rtWidget.height) {
    329     m_rtUI.height += fHeight - rtWidget.height;
    330   }
    331 }
    332 
    333 void CXFA_FFField::UpdateFWL() {
    334   if (m_pNormalWidget)
    335     m_pNormalWidget->Update();
    336 }
    337 
    338 uint32_t CXFA_FFField::UpdateUIProperty() {
    339   CXFA_Node* pUiNode = m_pNode->GetWidgetAcc()->GetUIChild();
    340   if (pUiNode && pUiNode->GetElementType() == XFA_Element::DefaultUi)
    341     return FWL_STYLEEXT_EDT_ReadOnly;
    342   return 0;
    343 }
    344 
    345 void CXFA_FFField::SetFWLRect() {
    346   if (!m_pNormalWidget)
    347     return;
    348 
    349   CFX_RectF rtUi = m_rtUI;
    350   if (rtUi.width < 1.0)
    351     rtUi.width = 1.0;
    352   if (!GetDoc()->GetXFADoc()->IsInteractive()) {
    353     float fFontSize = m_pNode->GetFontSize();
    354     if (rtUi.height < fFontSize)
    355       rtUi.height = fFontSize;
    356   }
    357   m_pNormalWidget->SetWidgetRect(rtUi);
    358 }
    359 
    360 bool CXFA_FFField::OnMouseEnter() {
    361   if (!m_pNormalWidget)
    362     return false;
    363 
    364   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    365   ms.m_dwCmd = FWL_MouseCommand::Enter;
    366   TranslateFWLMessage(&ms);
    367   return true;
    368 }
    369 
    370 bool CXFA_FFField::OnMouseExit() {
    371   if (!m_pNormalWidget)
    372     return false;
    373 
    374   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    375   ms.m_dwCmd = FWL_MouseCommand::Leave;
    376   TranslateFWLMessage(&ms);
    377   return true;
    378 }
    379 
    380 CFX_PointF CXFA_FFField::FWLToClient(const CFX_PointF& point) {
    381   return m_pNormalWidget ? point - m_pNormalWidget->GetWidgetRect().TopLeft()
    382                          : point;
    383 }
    384 
    385 bool CXFA_FFField::OnLButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    386   if (!m_pNormalWidget)
    387     return false;
    388   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
    389     return false;
    390   if (!PtInActiveRect(point))
    391     return false;
    392 
    393   SetButtonDown(true);
    394   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    395   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDown;
    396   ms.m_dwFlags = dwFlags;
    397   ms.m_pos = FWLToClient(point);
    398   TranslateFWLMessage(&ms);
    399   return true;
    400 }
    401 
    402 bool CXFA_FFField::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    403   if (!m_pNormalWidget)
    404     return false;
    405   if (!IsButtonDown())
    406     return false;
    407 
    408   SetButtonDown(false);
    409   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    410   ms.m_dwCmd = FWL_MouseCommand::LeftButtonUp;
    411   ms.m_dwFlags = dwFlags;
    412   ms.m_pos = FWLToClient(point);
    413   TranslateFWLMessage(&ms);
    414   return true;
    415 }
    416 
    417 bool CXFA_FFField::OnLButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
    418   if (!m_pNormalWidget)
    419     return false;
    420 
    421   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    422   ms.m_dwCmd = FWL_MouseCommand::LeftButtonDblClk;
    423   ms.m_dwFlags = dwFlags;
    424   ms.m_pos = FWLToClient(point);
    425   TranslateFWLMessage(&ms);
    426   return true;
    427 }
    428 
    429 bool CXFA_FFField::OnMouseMove(uint32_t dwFlags, const CFX_PointF& point) {
    430   if (!m_pNormalWidget)
    431     return false;
    432 
    433   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    434   ms.m_dwCmd = FWL_MouseCommand::Move;
    435   ms.m_dwFlags = dwFlags;
    436   ms.m_pos = FWLToClient(point);
    437   TranslateFWLMessage(&ms);
    438   return true;
    439 }
    440 
    441 bool CXFA_FFField::OnMouseWheel(uint32_t dwFlags,
    442                                 int16_t zDelta,
    443                                 const CFX_PointF& point) {
    444   if (!m_pNormalWidget)
    445     return false;
    446 
    447   CFWL_MessageMouseWheel ms(nullptr, m_pNormalWidget.get());
    448   ms.m_dwFlags = dwFlags;
    449   ms.m_pos = FWLToClient(point);
    450   ms.m_delta = CFX_PointF(zDelta, 0);
    451   TranslateFWLMessage(&ms);
    452   return true;
    453 }
    454 
    455 bool CXFA_FFField::OnRButtonDown(uint32_t dwFlags, const CFX_PointF& point) {
    456   if (!m_pNormalWidget)
    457     return false;
    458   if (!m_pNode->IsOpenAccess() || !GetDoc()->GetXFADoc()->IsInteractive())
    459     return false;
    460   if (!PtInActiveRect(point))
    461     return false;
    462 
    463   SetButtonDown(true);
    464 
    465   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    466   ms.m_dwCmd = FWL_MouseCommand::RightButtonDown;
    467   ms.m_dwFlags = dwFlags;
    468   ms.m_pos = FWLToClient(point);
    469   TranslateFWLMessage(&ms);
    470   return true;
    471 }
    472 
    473 bool CXFA_FFField::OnRButtonUp(uint32_t dwFlags, const CFX_PointF& point) {
    474   if (!m_pNormalWidget)
    475     return false;
    476   if (!IsButtonDown())
    477     return false;
    478 
    479   SetButtonDown(false);
    480   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    481   ms.m_dwCmd = FWL_MouseCommand::RightButtonUp;
    482   ms.m_dwFlags = dwFlags;
    483   ms.m_pos = FWLToClient(point);
    484   TranslateFWLMessage(&ms);
    485   return true;
    486 }
    487 
    488 bool CXFA_FFField::OnRButtonDblClk(uint32_t dwFlags, const CFX_PointF& point) {
    489   if (!m_pNormalWidget)
    490     return false;
    491 
    492   CFWL_MessageMouse ms(nullptr, m_pNormalWidget.get());
    493   ms.m_dwCmd = FWL_MouseCommand::RightButtonDblClk;
    494   ms.m_dwFlags = dwFlags;
    495   ms.m_pos = FWLToClient(point);
    496   TranslateFWLMessage(&ms);
    497   return true;
    498 }
    499 
    500 bool CXFA_FFField::OnSetFocus(CXFA_FFWidget* pOldWidget) {
    501   CXFA_FFWidget::OnSetFocus(pOldWidget);
    502   if (!m_pNormalWidget)
    503     return false;
    504 
    505   CFWL_MessageSetFocus ms(nullptr, m_pNormalWidget.get());
    506   TranslateFWLMessage(&ms);
    507   m_dwStatus |= XFA_WidgetStatus_Focused;
    508   AddInvalidateRect();
    509   return true;
    510 }
    511 
    512 bool CXFA_FFField::OnKillFocus(CXFA_FFWidget* pNewWidget) {
    513   if (!m_pNormalWidget)
    514     return CXFA_FFWidget::OnKillFocus(pNewWidget);
    515 
    516   CFWL_MessageKillFocus ms(nullptr, m_pNormalWidget.get());
    517   TranslateFWLMessage(&ms);
    518   m_dwStatus &= ~XFA_WidgetStatus_Focused;
    519   AddInvalidateRect();
    520   CXFA_FFWidget::OnKillFocus(pNewWidget);
    521   return true;
    522 }
    523 
    524 bool CXFA_FFField::OnKeyDown(uint32_t dwKeyCode, uint32_t dwFlags) {
    525   if (!m_pNormalWidget || !GetDoc()->GetXFADoc()->IsInteractive())
    526     return false;
    527 
    528   CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
    529   ms.m_dwCmd = FWL_KeyCommand::KeyDown;
    530   ms.m_dwFlags = dwFlags;
    531   ms.m_dwKeyCode = dwKeyCode;
    532   TranslateFWLMessage(&ms);
    533   return true;
    534 }
    535 
    536 bool CXFA_FFField::OnKeyUp(uint32_t dwKeyCode, uint32_t dwFlags) {
    537   if (!m_pNormalWidget || !GetDoc()->GetXFADoc()->IsInteractive())
    538     return false;
    539 
    540   CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
    541   ms.m_dwCmd = FWL_KeyCommand::KeyUp;
    542   ms.m_dwFlags = dwFlags;
    543   ms.m_dwKeyCode = dwKeyCode;
    544   TranslateFWLMessage(&ms);
    545   return true;
    546 }
    547 
    548 bool CXFA_FFField::OnChar(uint32_t dwChar, uint32_t dwFlags) {
    549   if (!GetDoc()->GetXFADoc()->IsInteractive())
    550     return false;
    551   if (dwChar == FWL_VKEY_Tab)
    552     return true;
    553   if (!m_pNormalWidget)
    554     return false;
    555   if (!m_pNode->IsOpenAccess())
    556     return false;
    557 
    558   CFWL_MessageKey ms(nullptr, m_pNormalWidget.get());
    559   ms.m_dwCmd = FWL_KeyCommand::Char;
    560   ms.m_dwFlags = dwFlags;
    561   ms.m_dwKeyCode = dwChar;
    562   TranslateFWLMessage(&ms);
    563   return true;
    564 }
    565 
    566 FWL_WidgetHit CXFA_FFField::OnHitTest(const CFX_PointF& point) {
    567   if (m_pNormalWidget &&
    568       m_pNormalWidget->HitTest(FWLToClient(point)) != FWL_WidgetHit::Unknown) {
    569     return FWL_WidgetHit::Client;
    570   }
    571 
    572   if (!GetRectWithoutRotate().Contains(point))
    573     return FWL_WidgetHit::Unknown;
    574   if (m_rtCaption.Contains(point))
    575     return FWL_WidgetHit::Titlebar;
    576   return FWL_WidgetHit::Border;
    577 }
    578 
    579 bool CXFA_FFField::OnSetCursor(const CFX_PointF& point) {
    580   return true;
    581 }
    582 
    583 bool CXFA_FFField::PtInActiveRect(const CFX_PointF& point) {
    584   return m_pNormalWidget && m_pNormalWidget->GetWidgetRect().Contains(point);
    585 }
    586 
    587 void CXFA_FFField::LayoutCaption() {
    588   CXFA_TextLayout* pCapTextLayout =
    589       m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
    590   if (!pCapTextLayout)
    591     return;
    592 
    593   float fHeight =
    594       pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
    595   if (m_rtCaption.height < fHeight)
    596     m_rtCaption.height = fHeight;
    597 }
    598 
    599 void CXFA_FFField::RenderCaption(CXFA_Graphics* pGS, CFX_Matrix* pMatrix) {
    600   CXFA_TextLayout* pCapTextLayout =
    601       m_pNode->GetWidgetAcc()->GetCaptionTextLayout();
    602   if (!pCapTextLayout)
    603     return;
    604 
    605   CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
    606   if (!caption || !caption->IsVisible())
    607     return;
    608 
    609   if (!pCapTextLayout->IsLoaded())
    610     pCapTextLayout->Layout(CFX_SizeF(m_rtCaption.width, m_rtCaption.height));
    611 
    612   CFX_RectF rtClip = m_rtCaption;
    613   rtClip.Intersect(GetRectWithoutRotate());
    614   CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice();
    615   CFX_Matrix mt(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top);
    616   if (pMatrix) {
    617     rtClip = pMatrix->TransformRect(rtClip);
    618     mt.Concat(*pMatrix);
    619   }
    620   pCapTextLayout->DrawString(pRenderDevice, mt, rtClip, 0);
    621 }
    622 
    623 bool CXFA_FFField::ProcessCommittedData() {
    624   if (!m_pNode->IsOpenAccess())
    625     return false;
    626   if (!IsDataChanged())
    627     return false;
    628   if (CalculateOverride() != 1)
    629     return false;
    630   if (!CommitData())
    631     return false;
    632 
    633   m_pDocView->SetChangeMark();
    634   m_pDocView->AddValidateWidget(m_pNode->GetWidgetAcc());
    635   return true;
    636 }
    637 
    638 int32_t CXFA_FFField::CalculateOverride() {
    639   CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists();
    640   if (!exclNode)
    641     return CalculateWidgetAcc(m_pNode->GetWidgetAcc());
    642 
    643   CXFA_WidgetAcc* pAcc = exclNode->GetWidgetAcc();
    644   if (!pAcc)
    645     return CalculateWidgetAcc(m_pNode->GetWidgetAcc());
    646   if (CalculateWidgetAcc(pAcc) == 0)
    647     return 0;
    648 
    649   CXFA_Node* pNode = pAcc->GetExclGroupFirstMember();
    650   if (!pNode)
    651     return 1;
    652 
    653   CXFA_WidgetAcc* pWidgetAcc = nullptr;
    654   while (pNode) {
    655     pWidgetAcc = pNode->GetWidgetAcc();
    656     if (!pWidgetAcc)
    657       return 1;
    658     if (CalculateWidgetAcc(pWidgetAcc) == 0)
    659       return 0;
    660 
    661     pNode = pWidgetAcc->GetExclGroupNextMember(pNode);
    662   }
    663   return 1;
    664 }
    665 
    666 int32_t CXFA_FFField::CalculateWidgetAcc(CXFA_WidgetAcc* pAcc) {
    667   CXFA_Calculate* calc = pAcc->GetNode()->GetCalculateIfExists();
    668   if (!calc)
    669     return 1;
    670 
    671   XFA_VERSION version = GetDoc()->GetXFADoc()->GetCurVersionMode();
    672   switch (calc->GetOverride()) {
    673     case XFA_AttributeEnum::Error: {
    674       if (version <= XFA_VERSION_204)
    675         return 1;
    676 
    677       IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
    678       if (pAppProvider) {
    679         pAppProvider->MsgBox(L"You are not allowed to modify this field.",
    680                              L"Calculate Override", XFA_MBICON_Warning,
    681                              XFA_MB_OK);
    682       }
    683       return 0;
    684     }
    685     case XFA_AttributeEnum::Warning: {
    686       if (version <= XFA_VERSION_204) {
    687         CXFA_Script* script = calc->GetScriptIfExists();
    688         if (!script)
    689           return 1;
    690         if (script->GetExpression().IsEmpty())
    691           return 1;
    692       }
    693 
    694       if (pAcc->GetNode()->IsUserInteractive())
    695         return 1;
    696 
    697       IXFA_AppProvider* pAppProvider = GetApp()->GetAppProvider();
    698       if (!pAppProvider)
    699         return 0;
    700 
    701       WideString wsMessage = calc->GetMessageText();
    702       if (!wsMessage.IsEmpty())
    703         wsMessage += L"\r\n";
    704 
    705       wsMessage += L"Are you sure you want to modify this field?";
    706       if (pAppProvider->MsgBox(wsMessage, L"Calculate Override",
    707                                XFA_MBICON_Warning, XFA_MB_YesNo) == XFA_IDYes) {
    708         pAcc->GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
    709         return 1;
    710       }
    711       return 0;
    712     }
    713     case XFA_AttributeEnum::Ignore:
    714       return 0;
    715     case XFA_AttributeEnum::Disabled:
    716       pAcc->GetNode()->SetFlag(XFA_NodeFlag_UserInteractive, false);
    717       return 1;
    718     default:
    719       return 1;
    720   }
    721 }
    722 
    723 bool CXFA_FFField::CommitData() {
    724   return false;
    725 }
    726 
    727 bool CXFA_FFField::IsDataChanged() {
    728   return false;
    729 }
    730 
    731 void CXFA_FFField::TranslateFWLMessage(CFWL_Message* pMessage) {
    732   GetApp()->GetFWLWidgetMgr()->OnProcessMessageToForm(pMessage);
    733 }
    734 
    735 void CXFA_FFField::OnProcessMessage(CFWL_Message* pMessage) {}
    736 
    737 void CXFA_FFField::OnProcessEvent(CFWL_Event* pEvent) {
    738   switch (pEvent->GetType()) {
    739     case CFWL_Event::Type::Mouse: {
    740       CFWL_EventMouse* event = static_cast<CFWL_EventMouse*>(pEvent);
    741       if (event->m_dwCmd == FWL_MouseCommand::Enter) {
    742         CXFA_EventParam eParam;
    743         eParam.m_eType = XFA_EVENT_MouseEnter;
    744         eParam.m_pTarget = m_pNode->GetWidgetAcc();
    745         m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseEnter,
    746                               &eParam);
    747       } else if (event->m_dwCmd == FWL_MouseCommand::Leave) {
    748         CXFA_EventParam eParam;
    749         eParam.m_eType = XFA_EVENT_MouseExit;
    750         eParam.m_pTarget = m_pNode->GetWidgetAcc();
    751         m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseExit,
    752                               &eParam);
    753       } else if (event->m_dwCmd == FWL_MouseCommand::LeftButtonDown) {
    754         CXFA_EventParam eParam;
    755         eParam.m_eType = XFA_EVENT_MouseDown;
    756         eParam.m_pTarget = m_pNode->GetWidgetAcc();
    757         m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseDown,
    758                               &eParam);
    759       } else if (event->m_dwCmd == FWL_MouseCommand::LeftButtonUp) {
    760         CXFA_EventParam eParam;
    761         eParam.m_eType = XFA_EVENT_MouseUp;
    762         eParam.m_pTarget = m_pNode->GetWidgetAcc();
    763         m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::MouseUp,
    764                               &eParam);
    765       }
    766       break;
    767     }
    768     case CFWL_Event::Type::Click: {
    769       CXFA_EventParam eParam;
    770       eParam.m_eType = XFA_EVENT_Click;
    771       eParam.m_pTarget = m_pNode->GetWidgetAcc();
    772       m_pNode->ProcessEvent(GetDocView(), XFA_AttributeEnum::Click, &eParam);
    773       break;
    774     }
    775     default:
    776       break;
    777   }
    778 }
    779 
    780 void CXFA_FFField::OnDrawWidget(CXFA_Graphics* pGraphics,
    781                                 const CFX_Matrix& matrix) {}
    782