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