|  | // 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_ffpushbutton.h" | 
|  |  | 
|  | #include "third_party/base/check.h" | 
|  | #include "v8/include/cppgc/visitor.h" | 
|  | #include "xfa/fgas/graphics/cfgas_gecolor.h" | 
|  | #include "xfa/fgas/graphics/cfgas_gepath.h" | 
|  | #include "xfa/fwl/cfwl_notedriver.h" | 
|  | #include "xfa/fwl/cfwl_pushbutton.h" | 
|  | #include "xfa/fwl/cfwl_widgetmgr.h" | 
|  | #include "xfa/fxfa/cxfa_ffapp.h" | 
|  | #include "xfa/fxfa/cxfa_ffdoc.h" | 
|  | #include "xfa/fxfa/cxfa_fffield.h" | 
|  | #include "xfa/fxfa/cxfa_ffpageview.h" | 
|  | #include "xfa/fxfa/cxfa_ffwidget.h" | 
|  | #include "xfa/fxfa/cxfa_textlayout.h" | 
|  | #include "xfa/fxfa/cxfa_textprovider.h" | 
|  | #include "xfa/fxfa/parser/cxfa_border.h" | 
|  | #include "xfa/fxfa/parser/cxfa_button.h" | 
|  | #include "xfa/fxfa/parser/cxfa_caption.h" | 
|  | #include "xfa/fxfa/parser/cxfa_edge.h" | 
|  |  | 
|  | CXFA_FFPushButton::CXFA_FFPushButton(CXFA_Node* pNode, CXFA_Button* button) | 
|  | : CXFA_FFField(pNode), button_(button) {} | 
|  |  | 
|  | CXFA_FFPushButton::~CXFA_FFPushButton() = default; | 
|  |  | 
|  | void CXFA_FFPushButton::Trace(cppgc::Visitor* visitor) const { | 
|  | CXFA_FFField::Trace(visitor); | 
|  | visitor->Trace(m_pRolloverTextLayout); | 
|  | visitor->Trace(m_pDownTextLayout); | 
|  | visitor->Trace(m_pRollProvider); | 
|  | visitor->Trace(m_pDownProvider); | 
|  | visitor->Trace(m_pOldDelegate); | 
|  | visitor->Trace(button_); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::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); | 
|  | RenderHighlightCaption(pGS, &mtRotate); | 
|  |  | 
|  | CFX_RectF rtWidget = GetRectWithoutRotate(); | 
|  | CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top); | 
|  | mt.Concat(mtRotate); | 
|  | GetApp()->GetFWLWidgetMgr()->OnDrawWidget(GetNormalWidget(), pGS, mt); | 
|  | } | 
|  |  | 
|  | bool CXFA_FFPushButton::LoadWidget() { | 
|  | DCHECK(!IsLoaded()); | 
|  |  | 
|  | CFWL_PushButton* pPushButton = cppgc::MakeGarbageCollected<CFWL_PushButton>( | 
|  | GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp()); | 
|  | m_pOldDelegate = pPushButton->GetDelegate(); | 
|  | pPushButton->SetDelegate(this); | 
|  | SetNormalWidget(pPushButton); | 
|  | pPushButton->SetAdapterIface(this); | 
|  |  | 
|  | CFWL_NoteDriver* pNoteDriver = pPushButton->GetFWLApp()->GetNoteDriver(); | 
|  | pNoteDriver->RegisterEventTarget(pPushButton, pPushButton); | 
|  |  | 
|  | { | 
|  | CFWL_Widget::ScopedUpdateLock update_lock(pPushButton); | 
|  | UpdateWidgetProperty(); | 
|  | LoadHighlightCaption(); | 
|  | } | 
|  |  | 
|  | return CXFA_FFField::LoadWidget(); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::UpdateWidgetProperty() { | 
|  | uint32_t dwStyleEx = 0; | 
|  | switch (button_->GetHighlight()) { | 
|  | case XFA_AttributeValue::Inverted: | 
|  | dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteInverted; | 
|  | break; | 
|  | case XFA_AttributeValue::Outline: | 
|  | dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteOutLine; | 
|  | break; | 
|  | case XFA_AttributeValue::Push: | 
|  | dwStyleEx = XFA_FWL_PSBSTYLEEXT_HilitePush; | 
|  | break; | 
|  | default: | 
|  | break; | 
|  | } | 
|  | GetNormalWidget()->ModifyStyleExts(dwStyleEx, 0xFFFFFFFF); | 
|  | } | 
|  |  | 
|  | bool CXFA_FFPushButton::PerformLayout() { | 
|  | CXFA_FFWidget::PerformLayout(); | 
|  | CFX_RectF rtWidget = GetRectWithoutRotate(); | 
|  |  | 
|  | m_UIRect = rtWidget; | 
|  | CXFA_Margin* margin = m_pNode->GetMarginIfExists(); | 
|  | XFA_RectWithoutMargin(&rtWidget, margin); | 
|  |  | 
|  | m_CaptionRect = rtWidget; | 
|  |  | 
|  | CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); | 
|  | CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr; | 
|  | XFA_RectWithoutMargin(&m_CaptionRect, captionMargin); | 
|  |  | 
|  | LayoutHighlightCaption(); | 
|  | SetFWLRect(); | 
|  | if (GetNormalWidget()) | 
|  | GetNormalWidget()->Update(); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | float CXFA_FFPushButton::GetLineWidth() { | 
|  | CXFA_Border* border = m_pNode->GetBorderIfExists(); | 
|  | if (border && border->GetPresence() == XFA_AttributeValue::Visible) { | 
|  | CXFA_Edge* edge = border->GetEdgeIfExists(0); | 
|  | return edge ? edge->GetThickness() : 0; | 
|  | } | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | FX_ARGB CXFA_FFPushButton::GetLineColor() { | 
|  | return 0xFF000000; | 
|  | } | 
|  |  | 
|  | FX_ARGB CXFA_FFPushButton::GetFillColor() { | 
|  | return 0xFFFFFFFF; | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::LoadHighlightCaption() { | 
|  | CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); | 
|  | if (!caption || caption->IsHidden()) | 
|  | return; | 
|  |  | 
|  | if (m_pNode->HasButtonRollover()) { | 
|  | if (!m_pRollProvider) { | 
|  | m_pRollProvider = cppgc::MakeGarbageCollected<CXFA_TextProvider>( | 
|  | GetDoc()->GetHeap()->GetAllocationHandle(), m_pNode.Get(), | 
|  | XFA_TEXTPROVIDERTYPE_Rollover); | 
|  | } | 
|  | m_pRolloverTextLayout = cppgc::MakeGarbageCollected<CXFA_TextLayout>( | 
|  | GetDoc()->GetHeap()->GetAllocationHandle(), GetDoc(), m_pRollProvider); | 
|  | } | 
|  | if (m_pNode->HasButtonDown()) { | 
|  | if (!m_pDownProvider) { | 
|  | m_pDownProvider = cppgc::MakeGarbageCollected<CXFA_TextProvider>( | 
|  | GetDoc()->GetHeap()->GetAllocationHandle(), m_pNode.Get(), | 
|  | XFA_TEXTPROVIDERTYPE_Down); | 
|  | } | 
|  | m_pDownTextLayout = cppgc::MakeGarbageCollected<CXFA_TextLayout>( | 
|  | GetDoc()->GetHeap()->GetAllocationHandle(), GetDoc(), m_pDownProvider); | 
|  | } | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::LayoutHighlightCaption() { | 
|  | CFX_SizeF sz(m_CaptionRect.width, m_CaptionRect.height); | 
|  | LayoutCaption(); | 
|  | if (m_pRolloverTextLayout) | 
|  | m_pRolloverTextLayout->Layout(sz); | 
|  | if (m_pDownTextLayout) | 
|  | m_pDownTextLayout->Layout(sz); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::RenderHighlightCaption(CFGAS_GEGraphics* pGS, | 
|  | CFX_Matrix* pMatrix) { | 
|  | CXFA_TextLayout* pCapTextLayout = m_pNode->GetCaptionTextLayout(); | 
|  | CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); | 
|  | if (!caption || !caption->IsVisible()) | 
|  | return; | 
|  |  | 
|  | CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); | 
|  | CFX_RectF rtClip = m_CaptionRect; | 
|  | rtClip.Intersect(GetRectWithoutRotate()); | 
|  | CFX_Matrix mt(1, 0, 0, 1, m_CaptionRect.left, m_CaptionRect.top); | 
|  | if (pMatrix) { | 
|  | rtClip = pMatrix->TransformRect(rtClip); | 
|  | mt.Concat(*pMatrix); | 
|  | } | 
|  |  | 
|  | uint32_t dwState = GetNormalWidget()->GetStates(); | 
|  | if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) && | 
|  | (dwState & FWL_STATE_PSB_Hovered)) { | 
|  | if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip, 0)) | 
|  | return; | 
|  | } else if (m_pRolloverTextLayout && (dwState & FWL_STATE_PSB_Hovered)) { | 
|  | if (m_pRolloverTextLayout->DrawString(pRenderDevice, mt, rtClip, 0)) | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (pCapTextLayout) | 
|  | pCapTextLayout->DrawString(pRenderDevice, mt, rtClip, 0); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::OnProcessMessage(CFWL_Message* pMessage) { | 
|  | m_pOldDelegate->OnProcessMessage(pMessage); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::OnProcessEvent(CFWL_Event* pEvent) { | 
|  | m_pOldDelegate->OnProcessEvent(pEvent); | 
|  | CXFA_FFField::OnProcessEvent(pEvent); | 
|  | } | 
|  |  | 
|  | void CXFA_FFPushButton::OnDrawWidget(CFGAS_GEGraphics* pGraphics, | 
|  | const CFX_Matrix& matrix) { | 
|  | auto* pWidget = GetNormalWidget(); | 
|  | if (pWidget->GetStyleExts() & XFA_FWL_PSBSTYLEEXT_HiliteInverted) { | 
|  | if ((pWidget->GetStates() & FWL_STATE_PSB_Pressed) && | 
|  | (pWidget->GetStates() & FWL_STATE_PSB_Hovered)) { | 
|  | CFX_RectF rtFill(0, 0, pWidget->GetWidgetRect().Size()); | 
|  | float fLineWith = GetLineWidth(); | 
|  | rtFill.Deflate(fLineWith, fLineWith); | 
|  | CFGAS_GEPath path; | 
|  | path.AddRectangle(rtFill.left, rtFill.top, rtFill.width, rtFill.height); | 
|  | pGraphics->SetFillColor(CFGAS_GEColor(ArgbEncode(128, 128, 255, 255))); | 
|  | pGraphics->FillPath(path, CFX_FillRenderOptions::FillType::kWinding, | 
|  | matrix); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | if (pWidget->GetStyleExts() & XFA_FWL_PSBSTYLEEXT_HiliteOutLine) { | 
|  | if ((pWidget->GetStates() & FWL_STATE_PSB_Pressed) && | 
|  | (pWidget->GetStates() & FWL_STATE_PSB_Hovered)) { | 
|  | float fLineWidth = GetLineWidth(); | 
|  | pGraphics->SetStrokeColor(CFGAS_GEColor(ArgbEncode(255, 128, 255, 255))); | 
|  | pGraphics->SetLineWidth(fLineWidth); | 
|  |  | 
|  | CFGAS_GEPath path; | 
|  | CFX_RectF rect = pWidget->GetWidgetRect(); | 
|  | path.AddRectangle(0, 0, rect.width, rect.height); | 
|  | pGraphics->StrokePath(path, matrix); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | FormFieldType CXFA_FFPushButton::GetFormFieldType() { | 
|  | return FormFieldType::kXFA_PushButton; | 
|  | } |