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