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_ffcheckbutton.h"
8
9 #include "third_party/base/check.h"
10 #include "v8/include/cppgc/visitor.h"
11 #include "xfa/fwl/cfwl_checkbox.h"
12 #include "xfa/fwl/cfwl_messagemouse.h"
13 #include "xfa/fwl/cfwl_notedriver.h"
14 #include "xfa/fwl/cfwl_widgetmgr.h"
15 #include "xfa/fxfa/cxfa_ffapp.h"
16 #include "xfa/fxfa/cxfa_ffdoc.h"
17 #include "xfa/fxfa/cxfa_ffdocview.h"
18 #include "xfa/fxfa/cxfa_ffexclgroup.h"
19 #include "xfa/fxfa/cxfa_fffield.h"
20 #include "xfa/fxfa/cxfa_ffpageview.h"
21 #include "xfa/fxfa/cxfa_ffwidget.h"
22 #include "xfa/fxfa/parser/cxfa_border.h"
23 #include "xfa/fxfa/parser/cxfa_caption.h"
24 #include "xfa/fxfa/parser/cxfa_checkbutton.h"
25 #include "xfa/fxfa/parser/cxfa_para.h"
26
CXFA_FFCheckButton(CXFA_Node * pNode,CXFA_CheckButton * button)27 CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode,
28 CXFA_CheckButton* button)
29 : CXFA_FFField(pNode), button_(button) {}
30
31 CXFA_FFCheckButton::~CXFA_FFCheckButton() = default;
32
Trace(cppgc::Visitor * visitor) const33 void CXFA_FFCheckButton::Trace(cppgc::Visitor* visitor) const {
34 CXFA_FFField::Trace(visitor);
35 visitor->Trace(m_pOldDelegate);
36 visitor->Trace(button_);
37 }
38
LoadWidget()39 bool CXFA_FFCheckButton::LoadWidget() {
40 DCHECK(!IsLoaded());
41
42 CFWL_CheckBox* pCheckBox = cppgc::MakeGarbageCollected<CFWL_CheckBox>(
43 GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp());
44 SetNormalWidget(pCheckBox);
45 pCheckBox->SetAdapterIface(this);
46
47 CFWL_NoteDriver* pNoteDriver = pCheckBox->GetFWLApp()->GetNoteDriver();
48 pNoteDriver->RegisterEventTarget(pCheckBox, pCheckBox);
49 m_pOldDelegate = pCheckBox->GetDelegate();
50 pCheckBox->SetDelegate(this);
51 if (m_pNode->IsRadioButton())
52 pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF);
53
54 {
55 CFWL_Widget::ScopedUpdateLock update_lock(pCheckBox);
56 UpdateWidgetProperty();
57 SetFWLCheckState(m_pNode->GetCheckState());
58 }
59
60 return CXFA_FFField::LoadWidget();
61 }
62
UpdateWidgetProperty()63 void CXFA_FFCheckButton::UpdateWidgetProperty() {
64 auto* pCheckBox = static_cast<CFWL_CheckBox*>(GetNormalWidget());
65 if (!pCheckBox)
66 return;
67
68 pCheckBox->SetBoxSize(m_pNode->GetCheckButtonSize());
69 uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross;
70 switch (button_->GetMark()) {
71 case XFA_AttributeValue::Check:
72 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck;
73 break;
74 case XFA_AttributeValue::Circle:
75 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
76 break;
77 case XFA_AttributeValue::Cross:
78 break;
79 case XFA_AttributeValue::Diamond:
80 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond;
81 break;
82 case XFA_AttributeValue::Square:
83 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare;
84 break;
85 case XFA_AttributeValue::Star:
86 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar;
87 break;
88 default: {
89 if (button_->IsRound())
90 dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle;
91 } break;
92 }
93 if (button_->IsAllowNeutral())
94 dwStyleEx |= FWL_STYLEEXT_CKB_3State;
95
96 pCheckBox->ModifyStylesEx(
97 dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State);
98 }
99
PerformLayout()100 bool CXFA_FFCheckButton::PerformLayout() {
101 CXFA_FFWidget::PerformLayout();
102
103 float fCheckSize = m_pNode->GetCheckButtonSize();
104 CXFA_Margin* margin = m_pNode->GetMarginIfExists();
105 CFX_RectF rtWidget = GetRectWithoutRotate();
106 XFA_RectWithoutMargin(&rtWidget, margin);
107
108 XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown;
109 float fCapReserve = 0;
110 CXFA_Caption* caption = m_pNode->GetCaptionIfExists();
111 if (caption && caption->IsVisible()) {
112 m_CaptionRect = rtWidget;
113 iCapPlacement = caption->GetPlacementType();
114 fCapReserve = caption->GetReserve();
115 if (fCapReserve <= 0) {
116 if (iCapPlacement == XFA_AttributeValue::Top ||
117 iCapPlacement == XFA_AttributeValue::Bottom) {
118 fCapReserve = rtWidget.height - fCheckSize;
119 } else {
120 fCapReserve = rtWidget.width - fCheckSize;
121 }
122 }
123 }
124
125 XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left;
126 XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top;
127 CXFA_Para* para = m_pNode->GetParaIfExists();
128 if (para) {
129 iHorzAlign = para->GetHorizontalAlign();
130 iVertAlign = para->GetVerticalAlign();
131 }
132
133 m_UIRect = rtWidget;
134 CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr;
135 switch (iCapPlacement) {
136 case XFA_AttributeValue::Left: {
137 m_CaptionRect.width = fCapReserve;
138 CapLeftRightPlacement(captionMargin);
139 m_UIRect.width -= fCapReserve;
140 m_UIRect.left += fCapReserve;
141 break;
142 }
143 case XFA_AttributeValue::Top: {
144 m_CaptionRect.height = fCapReserve;
145 XFA_RectWithoutMargin(&m_CaptionRect, captionMargin);
146 m_UIRect.height -= fCapReserve;
147 m_UIRect.top += fCapReserve;
148 break;
149 }
150 case XFA_AttributeValue::Right: {
151 m_CaptionRect.left = m_CaptionRect.right() - fCapReserve;
152 m_CaptionRect.width = fCapReserve;
153 CapLeftRightPlacement(captionMargin);
154 m_UIRect.width -= fCapReserve;
155 break;
156 }
157 case XFA_AttributeValue::Bottom: {
158 m_CaptionRect.top = m_CaptionRect.bottom() - fCapReserve;
159 m_CaptionRect.height = fCapReserve;
160 XFA_RectWithoutMargin(&m_CaptionRect, captionMargin);
161 m_UIRect.height -= fCapReserve;
162 break;
163 }
164 case XFA_AttributeValue::Inline:
165 break;
166 default:
167 iHorzAlign = XFA_AttributeValue::Right;
168 break;
169 }
170
171 if (iHorzAlign == XFA_AttributeValue::Center)
172 m_UIRect.left += (m_UIRect.width - fCheckSize) / 2;
173 else if (iHorzAlign == XFA_AttributeValue::Right)
174 m_UIRect.left = m_UIRect.right() - fCheckSize;
175
176 if (iVertAlign == XFA_AttributeValue::Middle)
177 m_UIRect.top += (m_UIRect.height - fCheckSize) / 2;
178 else if (iVertAlign == XFA_AttributeValue::Bottom)
179 m_UIRect.top = m_UIRect.bottom() - fCheckSize;
180
181 m_UIRect.width = fCheckSize;
182 m_UIRect.height = fCheckSize;
183 AddUIMargin(iCapPlacement);
184 m_CheckBoxRect = m_UIRect;
185 CXFA_Border* borderUI = m_pNode->GetUIBorder();
186 if (borderUI) {
187 CXFA_Margin* borderMargin = borderUI->GetMarginIfExists();
188 XFA_RectWithoutMargin(&m_UIRect, borderMargin);
189 }
190
191 m_UIRect.Normalize();
192 LayoutCaption();
193 SetFWLRect();
194 if (GetNormalWidget())
195 GetNormalWidget()->Update();
196
197 return true;
198 }
199
CapLeftRightPlacement(const CXFA_Margin * captionMargin)200 void CXFA_FFCheckButton::CapLeftRightPlacement(
201 const CXFA_Margin* captionMargin) {
202 XFA_RectWithoutMargin(&m_CaptionRect, captionMargin);
203 if (m_CaptionRect.height < 0)
204 m_CaptionRect.top += m_CaptionRect.height;
205 if (m_CaptionRect.width < 0) {
206 m_CaptionRect.left += m_CaptionRect.width;
207 m_CaptionRect.width = -m_CaptionRect.width;
208 }
209 }
210
AddUIMargin(XFA_AttributeValue iCapPlacement)211 void CXFA_FFCheckButton::AddUIMargin(XFA_AttributeValue iCapPlacement) {
212 CFX_RectF rtUIMargin = m_pNode->GetUIMargin();
213 m_UIRect.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2;
214
215 float fLeftAddRight = rtUIMargin.left + rtUIMargin.width;
216 float fTopAddBottom = rtUIMargin.top + rtUIMargin.height;
217 if (m_UIRect.width < fLeftAddRight) {
218 if (iCapPlacement == XFA_AttributeValue::Right ||
219 iCapPlacement == XFA_AttributeValue::Left) {
220 m_UIRect.left -= fLeftAddRight - m_UIRect.width;
221 } else {
222 m_UIRect.left -= 2 * (fLeftAddRight - m_UIRect.width);
223 }
224 m_UIRect.width += 2 * (fLeftAddRight - m_UIRect.width);
225 }
226 if (m_UIRect.height < fTopAddBottom) {
227 if (iCapPlacement == XFA_AttributeValue::Right)
228 m_UIRect.left -= fTopAddBottom - m_UIRect.height;
229
230 m_UIRect.top -= fTopAddBottom - m_UIRect.height;
231 m_UIRect.height += 2 * (fTopAddBottom - m_UIRect.height);
232 }
233 }
234
RenderWidget(CFGAS_GEGraphics * pGS,const CFX_Matrix & matrix,HighlightOption highlight)235 void CXFA_FFCheckButton::RenderWidget(CFGAS_GEGraphics* pGS,
236 const CFX_Matrix& matrix,
237 HighlightOption highlight) {
238 if (!HasVisibleStatus())
239 return;
240
241 CFX_Matrix mtRotate = GetRotateMatrix();
242 mtRotate.Concat(matrix);
243
244 CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight);
245 DrawBorderWithFlag(pGS, m_pNode->GetUIBorder(), m_UIRect, mtRotate,
246 button_->IsRound());
247 RenderCaption(pGS, &mtRotate);
248 DrawHighlight(pGS, &mtRotate, highlight,
249 button_->IsRound() ? kRoundShape : kSquareShape);
250 CFX_Matrix mt(1, 0, 0, 1, m_CheckBoxRect.left, m_CheckBoxRect.top);
251 mt.Concat(mtRotate);
252 GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt);
253 }
254
OnLButtonUp(uint32_t dwFlags,const CFX_PointF & point)255 bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags,
256 const CFX_PointF& point) {
257 if (!GetNormalWidget() || !IsButtonDown())
258 return false;
259
260 SetButtonDown(false);
261 CFWL_MessageMouse msg(GetNormalWidget(), FWL_MouseCommand::LeftButtonUp,
262 dwFlags, FWLToClient(point));
263 SendMessageToFWLWidget(&msg);
264 return true;
265 }
266
FWLState2XFAState()267 XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() {
268 uint32_t dwState = GetNormalWidget()->GetStates();
269 if (dwState & FWL_STATE_CKB_Checked)
270 return XFA_CHECKSTATE_On;
271 if (dwState & FWL_STATE_CKB_Neutral)
272 return XFA_CHECKSTATE_Neutral;
273 return XFA_CHECKSTATE_Off;
274 }
275
CommitData()276 bool CXFA_FFCheckButton::CommitData() {
277 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
278 m_pNode->SetCheckState(eCheckState, true);
279 return true;
280 }
281
IsDataChanged()282 bool CXFA_FFCheckButton::IsDataChanged() {
283 XFA_CHECKSTATE eCheckState = FWLState2XFAState();
284 return m_pNode->GetCheckState() != eCheckState;
285 }
286
SetFWLCheckState(XFA_CHECKSTATE eCheckState)287 void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) {
288 if (eCheckState == XFA_CHECKSTATE_Neutral)
289 GetNormalWidget()->SetStates(FWL_STATE_CKB_Neutral);
290 else if (eCheckState == XFA_CHECKSTATE_On)
291 GetNormalWidget()->SetStates(FWL_STATE_CKB_Checked);
292 else
293 GetNormalWidget()->RemoveStates(FWL_STATE_CKB_Checked);
294 }
295
UpdateFWLData()296 bool CXFA_FFCheckButton::UpdateFWLData() {
297 if (!GetNormalWidget())
298 return false;
299
300 SetFWLCheckState(m_pNode->GetCheckState());
301 GetNormalWidget()->Update();
302 return true;
303 }
304
OnProcessMessage(CFWL_Message * pMessage)305 void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) {
306 m_pOldDelegate->OnProcessMessage(pMessage);
307 }
308
OnProcessEvent(CFWL_Event * pEvent)309 void CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) {
310 CXFA_FFField::OnProcessEvent(pEvent);
311 switch (pEvent->GetType()) {
312 case CFWL_Event::Type::CheckStateChanged: {
313 CXFA_EventParam eParam;
314 eParam.m_eType = XFA_EVENT_Change;
315 eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw);
316
317 CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists();
318 if (ProcessCommittedData()) {
319 eParam.m_pTarget = exclNode;
320 if (exclNode) {
321 m_pDocView->AddValidateNode(exclNode);
322 m_pDocView->AddCalculateNode(exclNode);
323 exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change,
324 &eParam);
325 }
326 eParam.m_pTarget = m_pNode.Get();
327 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change,
328 &eParam);
329 } else {
330 SetFWLCheckState(m_pNode->GetCheckState());
331 }
332 if (exclNode) {
333 eParam.m_pTarget = exclNode;
334 exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click,
335 &eParam);
336 }
337 eParam.m_pTarget = m_pNode.Get();
338 m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click, &eParam);
339 break;
340 }
341 default:
342 break;
343 }
344 m_pOldDelegate->OnProcessEvent(pEvent);
345 }
346
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)347 void CXFA_FFCheckButton::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
348 const CFX_Matrix& matrix) {
349 m_pOldDelegate->OnDrawWidget(pGraphics, matrix);
350 }
351
GetFormFieldType()352 FormFieldType CXFA_FFCheckButton::GetFormFieldType() {
353 return FormFieldType::kXFA_CheckBox;
354 }
355