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