// Copyright 2014 PDFium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com #include "xfa/fxfa/cxfa_ffcheckbutton.h" #include "third_party/base/check.h" #include "v8/include/cppgc/visitor.h" #include "xfa/fwl/cfwl_checkbox.h" #include "xfa/fwl/cfwl_messagemouse.h" #include "xfa/fwl/cfwl_notedriver.h" #include "xfa/fwl/cfwl_widgetmgr.h" #include "xfa/fxfa/cxfa_ffapp.h" #include "xfa/fxfa/cxfa_ffdoc.h" #include "xfa/fxfa/cxfa_ffdocview.h" #include "xfa/fxfa/cxfa_ffexclgroup.h" #include "xfa/fxfa/cxfa_fffield.h" #include "xfa/fxfa/cxfa_ffpageview.h" #include "xfa/fxfa/cxfa_ffwidget.h" #include "xfa/fxfa/parser/cxfa_border.h" #include "xfa/fxfa/parser/cxfa_caption.h" #include "xfa/fxfa/parser/cxfa_checkbutton.h" #include "xfa/fxfa/parser/cxfa_para.h" CXFA_FFCheckButton::CXFA_FFCheckButton(CXFA_Node* pNode, CXFA_CheckButton* button) : CXFA_FFField(pNode), button_(button) {} CXFA_FFCheckButton::~CXFA_FFCheckButton() = default; void CXFA_FFCheckButton::Trace(cppgc::Visitor* visitor) const { CXFA_FFField::Trace(visitor); visitor->Trace(m_pOldDelegate); visitor->Trace(button_); } bool CXFA_FFCheckButton::LoadWidget() { DCHECK(!IsLoaded()); CFWL_CheckBox* pCheckBox = cppgc::MakeGarbageCollected( GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp()); SetNormalWidget(pCheckBox); pCheckBox->SetAdapterIface(this); CFWL_NoteDriver* pNoteDriver = pCheckBox->GetFWLApp()->GetNoteDriver(); pNoteDriver->RegisterEventTarget(pCheckBox, pCheckBox); m_pOldDelegate = pCheckBox->GetDelegate(); pCheckBox->SetDelegate(this); if (m_pNode->IsRadioButton()) pCheckBox->ModifyStylesEx(FWL_STYLEEXT_CKB_RadioButton, 0xFFFFFFFF); { CFWL_Widget::ScopedUpdateLock update_lock(pCheckBox); UpdateWidgetProperty(); SetFWLCheckState(m_pNode->GetCheckState()); } return CXFA_FFField::LoadWidget(); } void CXFA_FFCheckButton::UpdateWidgetProperty() { auto* pCheckBox = static_cast(GetNormalWidget()); if (!pCheckBox) return; pCheckBox->SetBoxSize(m_pNode->GetCheckButtonSize()); uint32_t dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCross; switch (button_->GetMark()) { case XFA_AttributeValue::Check: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCheck; break; case XFA_AttributeValue::Circle: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle; break; case XFA_AttributeValue::Cross: break; case XFA_AttributeValue::Diamond: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeDiamond; break; case XFA_AttributeValue::Square: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeSquare; break; case XFA_AttributeValue::Star: dwStyleEx = FWL_STYLEEXT_CKB_SignShapeStar; break; default: { if (button_->IsRound()) dwStyleEx = FWL_STYLEEXT_CKB_SignShapeCircle; } break; } if (button_->IsAllowNeutral()) dwStyleEx |= FWL_STYLEEXT_CKB_3State; pCheckBox->ModifyStylesEx( dwStyleEx, FWL_STYLEEXT_CKB_SignShapeMask | FWL_STYLEEXT_CKB_3State); } bool CXFA_FFCheckButton::PerformLayout() { CXFA_FFWidget::PerformLayout(); float fCheckSize = m_pNode->GetCheckButtonSize(); CXFA_Margin* margin = m_pNode->GetMarginIfExists(); CFX_RectF rtWidget = GetRectWithoutRotate(); XFA_RectWithoutMargin(&rtWidget, margin); XFA_AttributeValue iCapPlacement = XFA_AttributeValue::Unknown; float fCapReserve = 0; CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); if (caption && caption->IsVisible()) { m_CaptionRect = rtWidget; iCapPlacement = caption->GetPlacementType(); fCapReserve = caption->GetReserve(); if (fCapReserve <= 0) { if (iCapPlacement == XFA_AttributeValue::Top || iCapPlacement == XFA_AttributeValue::Bottom) { fCapReserve = rtWidget.height - fCheckSize; } else { fCapReserve = rtWidget.width - fCheckSize; } } } XFA_AttributeValue iHorzAlign = XFA_AttributeValue::Left; XFA_AttributeValue iVertAlign = XFA_AttributeValue::Top; CXFA_Para* para = m_pNode->GetParaIfExists(); if (para) { iHorzAlign = para->GetHorizontalAlign(); iVertAlign = para->GetVerticalAlign(); } m_UIRect = rtWidget; CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr; switch (iCapPlacement) { case XFA_AttributeValue::Left: { m_CaptionRect.width = fCapReserve; CapLeftRightPlacement(captionMargin); m_UIRect.width -= fCapReserve; m_UIRect.left += fCapReserve; break; } case XFA_AttributeValue::Top: { m_CaptionRect.height = fCapReserve; XFA_RectWithoutMargin(&m_CaptionRect, captionMargin); m_UIRect.height -= fCapReserve; m_UIRect.top += fCapReserve; break; } case XFA_AttributeValue::Right: { m_CaptionRect.left = m_CaptionRect.right() - fCapReserve; m_CaptionRect.width = fCapReserve; CapLeftRightPlacement(captionMargin); m_UIRect.width -= fCapReserve; break; } case XFA_AttributeValue::Bottom: { m_CaptionRect.top = m_CaptionRect.bottom() - fCapReserve; m_CaptionRect.height = fCapReserve; XFA_RectWithoutMargin(&m_CaptionRect, captionMargin); m_UIRect.height -= fCapReserve; break; } case XFA_AttributeValue::Inline: break; default: iHorzAlign = XFA_AttributeValue::Right; break; } if (iHorzAlign == XFA_AttributeValue::Center) m_UIRect.left += (m_UIRect.width - fCheckSize) / 2; else if (iHorzAlign == XFA_AttributeValue::Right) m_UIRect.left = m_UIRect.right() - fCheckSize; if (iVertAlign == XFA_AttributeValue::Middle) m_UIRect.top += (m_UIRect.height - fCheckSize) / 2; else if (iVertAlign == XFA_AttributeValue::Bottom) m_UIRect.top = m_UIRect.bottom() - fCheckSize; m_UIRect.width = fCheckSize; m_UIRect.height = fCheckSize; AddUIMargin(iCapPlacement); m_CheckBoxRect = m_UIRect; CXFA_Border* borderUI = m_pNode->GetUIBorder(); if (borderUI) { CXFA_Margin* borderMargin = borderUI->GetMarginIfExists(); XFA_RectWithoutMargin(&m_UIRect, borderMargin); } m_UIRect.Normalize(); LayoutCaption(); SetFWLRect(); if (GetNormalWidget()) GetNormalWidget()->Update(); return true; } void CXFA_FFCheckButton::CapLeftRightPlacement( const CXFA_Margin* captionMargin) { XFA_RectWithoutMargin(&m_CaptionRect, captionMargin); if (m_CaptionRect.height < 0) m_CaptionRect.top += m_CaptionRect.height; if (m_CaptionRect.width < 0) { m_CaptionRect.left += m_CaptionRect.width; m_CaptionRect.width = -m_CaptionRect.width; } } void CXFA_FFCheckButton::AddUIMargin(XFA_AttributeValue iCapPlacement) { CFX_RectF rtUIMargin = m_pNode->GetUIMargin(); m_UIRect.top -= rtUIMargin.top / 2 - rtUIMargin.height / 2; float fLeftAddRight = rtUIMargin.left + rtUIMargin.width; float fTopAddBottom = rtUIMargin.top + rtUIMargin.height; if (m_UIRect.width < fLeftAddRight) { if (iCapPlacement == XFA_AttributeValue::Right || iCapPlacement == XFA_AttributeValue::Left) { m_UIRect.left -= fLeftAddRight - m_UIRect.width; } else { m_UIRect.left -= 2 * (fLeftAddRight - m_UIRect.width); } m_UIRect.width += 2 * (fLeftAddRight - m_UIRect.width); } if (m_UIRect.height < fTopAddBottom) { if (iCapPlacement == XFA_AttributeValue::Right) m_UIRect.left -= fTopAddBottom - m_UIRect.height; m_UIRect.top -= fTopAddBottom - m_UIRect.height; m_UIRect.height += 2 * (fTopAddBottom - m_UIRect.height); } } void CXFA_FFCheckButton::RenderWidget(CFGAS_GEGraphics* pGS, const CFX_Matrix& matrix, HighlightOption highlight) { if (!HasVisibleStatus()) return; CFX_Matrix mtRotate = GetRotateMatrix(); mtRotate.Concat(matrix); CXFA_FFWidget::RenderWidget(pGS, mtRotate, highlight); DrawBorderWithFlag(pGS, m_pNode->GetUIBorder(), m_UIRect, mtRotate, button_->IsRound()); RenderCaption(pGS, &mtRotate); DrawHighlight(pGS, &mtRotate, highlight, button_->IsRound() ? kRoundShape : kSquareShape); CFX_Matrix mt(1, 0, 0, 1, m_CheckBoxRect.left, m_CheckBoxRect.top); mt.Concat(mtRotate); GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt); } bool CXFA_FFCheckButton::OnLButtonUp(uint32_t dwFlags, const CFX_PointF& point) { if (!GetNormalWidget() || !IsButtonDown()) return false; SetButtonDown(false); CFWL_MessageMouse msg(GetNormalWidget(), FWL_MouseCommand::LeftButtonUp, dwFlags, FWLToClient(point)); SendMessageToFWLWidget(&msg); return true; } XFA_CHECKSTATE CXFA_FFCheckButton::FWLState2XFAState() { uint32_t dwState = GetNormalWidget()->GetStates(); if (dwState & FWL_STATE_CKB_Checked) return XFA_CHECKSTATE_On; if (dwState & FWL_STATE_CKB_Neutral) return XFA_CHECKSTATE_Neutral; return XFA_CHECKSTATE_Off; } bool CXFA_FFCheckButton::CommitData() { XFA_CHECKSTATE eCheckState = FWLState2XFAState(); m_pNode->SetCheckState(eCheckState, true); return true; } bool CXFA_FFCheckButton::IsDataChanged() { XFA_CHECKSTATE eCheckState = FWLState2XFAState(); return m_pNode->GetCheckState() != eCheckState; } void CXFA_FFCheckButton::SetFWLCheckState(XFA_CHECKSTATE eCheckState) { if (eCheckState == XFA_CHECKSTATE_Neutral) GetNormalWidget()->SetStates(FWL_STATE_CKB_Neutral); else if (eCheckState == XFA_CHECKSTATE_On) GetNormalWidget()->SetStates(FWL_STATE_CKB_Checked); else GetNormalWidget()->RemoveStates(FWL_STATE_CKB_Checked); } bool CXFA_FFCheckButton::UpdateFWLData() { if (!GetNormalWidget()) return false; SetFWLCheckState(m_pNode->GetCheckState()); GetNormalWidget()->Update(); return true; } void CXFA_FFCheckButton::OnProcessMessage(CFWL_Message* pMessage) { m_pOldDelegate->OnProcessMessage(pMessage); } void CXFA_FFCheckButton::OnProcessEvent(CFWL_Event* pEvent) { CXFA_FFField::OnProcessEvent(pEvent); switch (pEvent->GetType()) { case CFWL_Event::Type::CheckStateChanged: { CXFA_EventParam eParam; eParam.m_eType = XFA_EVENT_Change; eParam.m_wsPrevText = m_pNode->GetValue(XFA_VALUEPICTURE_Raw); CXFA_Node* exclNode = m_pNode->GetExclGroupIfExists(); if (ProcessCommittedData()) { eParam.m_pTarget = exclNode; if (exclNode) { m_pDocView->AddValidateNode(exclNode); m_pDocView->AddCalculateNode(exclNode); exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam); } eParam.m_pTarget = m_pNode.Get(); m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Change, &eParam); } else { SetFWLCheckState(m_pNode->GetCheckState()); } if (exclNode) { eParam.m_pTarget = exclNode; exclNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click, &eParam); } eParam.m_pTarget = m_pNode.Get(); m_pNode->ProcessEvent(GetDocView(), XFA_AttributeValue::Click, &eParam); break; } default: break; } m_pOldDelegate->OnProcessEvent(pEvent); } void CXFA_FFCheckButton::OnDrawWidget(CFGAS_GEGraphics* pGraphics, const CFX_Matrix& matrix) { m_pOldDelegate->OnDrawWidget(pGraphics, matrix); } FormFieldType CXFA_FFCheckButton::GetFormFieldType() { return FormFieldType::kXFA_CheckBox; }