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