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_ffpushbutton.h" 8 9 #include <utility> 10 11 #include "third_party/base/ptr_util.h" 12 #include "xfa/fwl/cfwl_notedriver.h" 13 #include "xfa/fwl/cfwl_pushbutton.h" 14 #include "xfa/fwl/cfwl_widgetmgr.h" 15 #include "xfa/fxfa/cxfa_ffapp.h" 16 #include "xfa/fxfa/cxfa_fffield.h" 17 #include "xfa/fxfa/cxfa_ffpageview.h" 18 #include "xfa/fxfa/cxfa_ffwidget.h" 19 #include "xfa/fxfa/cxfa_textlayout.h" 20 #include "xfa/fxfa/cxfa_textprovider.h" 21 #include "xfa/fxfa/parser/cxfa_border.h" 22 #include "xfa/fxfa/parser/cxfa_caption.h" 23 #include "xfa/fxfa/parser/cxfa_edge.h" 24 #include "xfa/fxgraphics/cxfa_gecolor.h" 25 #include "xfa/fxgraphics/cxfa_gepath.h" 26 27 CXFA_FFPushButton::CXFA_FFPushButton(CXFA_Node* pNode) 28 : CXFA_FFField(pNode), m_pOldDelegate(nullptr) {} 29 30 CXFA_FFPushButton::~CXFA_FFPushButton() { 31 CXFA_FFPushButton::UnloadWidget(); 32 } 33 34 void CXFA_FFPushButton::RenderWidget(CXFA_Graphics* pGS, 35 const CFX_Matrix& matrix, 36 uint32_t dwStatus) { 37 if (!IsMatchVisibleStatus(dwStatus)) 38 return; 39 40 CFX_Matrix mtRotate = GetRotateMatrix(); 41 mtRotate.Concat(matrix); 42 43 CXFA_FFWidget::RenderWidget(pGS, mtRotate, dwStatus); 44 RenderHighlightCaption(pGS, &mtRotate); 45 46 CFX_RectF rtWidget = GetRectWithoutRotate(); 47 CFX_Matrix mt(1, 0, 0, 1, rtWidget.left, rtWidget.top); 48 mt.Concat(mtRotate); 49 GetApp()->GetFWLWidgetMgr()->OnDrawWidget(m_pNormalWidget.get(), pGS, mt); 50 } 51 52 bool CXFA_FFPushButton::LoadWidget() { 53 ASSERT(!m_pNormalWidget); 54 auto pNew = pdfium::MakeUnique<CFWL_PushButton>(GetFWLApp()); 55 CFWL_PushButton* pPushButton = pNew.get(); 56 m_pOldDelegate = pPushButton->GetDelegate(); 57 pPushButton->SetDelegate(this); 58 m_pNormalWidget = std::move(pNew); 59 m_pNormalWidget->SetLayoutItem(this); 60 61 CFWL_NoteDriver* pNoteDriver = 62 m_pNormalWidget->GetOwnerApp()->GetNoteDriver(); 63 pNoteDriver->RegisterEventTarget(m_pNormalWidget.get(), 64 m_pNormalWidget.get()); 65 m_pNormalWidget->LockUpdate(); 66 UpdateWidgetProperty(); 67 LoadHighlightCaption(); 68 m_pNormalWidget->UnlockUpdate(); 69 return CXFA_FFField::LoadWidget(); 70 } 71 72 void CXFA_FFPushButton::UpdateWidgetProperty() { 73 uint32_t dwStyleEx = 0; 74 switch (m_pNode->GetWidgetAcc()->GetButtonHighlight()) { 75 case XFA_AttributeEnum::Inverted: 76 dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteInverted; 77 break; 78 case XFA_AttributeEnum::Outline: 79 dwStyleEx = XFA_FWL_PSBSTYLEEXT_HiliteOutLine; 80 break; 81 case XFA_AttributeEnum::Push: 82 dwStyleEx = XFA_FWL_PSBSTYLEEXT_HilitePush; 83 break; 84 default: 85 break; 86 } 87 m_pNormalWidget->ModifyStylesEx(dwStyleEx, 0xFFFFFFFF); 88 } 89 90 void CXFA_FFPushButton::UnloadWidget() { 91 m_pRolloverTextLayout.reset(); 92 m_pDownTextLayout.reset(); 93 m_pRollProvider.reset(); 94 m_pDownProvider.reset(); 95 CXFA_FFField::UnloadWidget(); 96 } 97 98 bool CXFA_FFPushButton::PerformLayout() { 99 CXFA_FFWidget::PerformLayout(); 100 CFX_RectF rtWidget = GetRectWithoutRotate(); 101 102 m_rtUI = rtWidget; 103 CXFA_Margin* margin = m_pNode->GetMarginIfExists(); 104 if (margin) 105 XFA_RectWithoutMargin(rtWidget, margin); 106 107 m_rtCaption = rtWidget; 108 109 CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); 110 CXFA_Margin* captionMargin = caption ? caption->GetMarginIfExists() : nullptr; 111 if (captionMargin) 112 XFA_RectWithoutMargin(m_rtCaption, captionMargin); 113 114 LayoutHighlightCaption(); 115 SetFWLRect(); 116 if (m_pNormalWidget) 117 m_pNormalWidget->Update(); 118 119 return true; 120 } 121 122 float CXFA_FFPushButton::GetLineWidth() { 123 CXFA_Border* border = m_pNode->GetBorderIfExists(); 124 if (border && border->GetPresence() == XFA_AttributeEnum::Visible) { 125 CXFA_Edge* edge = border->GetEdgeIfExists(0); 126 return edge ? edge->GetThickness() : 0; 127 } 128 return 0; 129 } 130 131 FX_ARGB CXFA_FFPushButton::GetLineColor() { 132 return 0xFF000000; 133 } 134 135 FX_ARGB CXFA_FFPushButton::GetFillColor() { 136 return 0xFFFFFFFF; 137 } 138 139 void CXFA_FFPushButton::LoadHighlightCaption() { 140 CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); 141 if (!caption || caption->IsHidden()) 142 return; 143 144 if (m_pNode->GetWidgetAcc()->HasButtonRollover()) { 145 if (!m_pRollProvider) { 146 m_pRollProvider = pdfium::MakeUnique<CXFA_TextProvider>( 147 m_pNode->GetWidgetAcc(), XFA_TEXTPROVIDERTYPE_Rollover); 148 } 149 m_pRolloverTextLayout = 150 pdfium::MakeUnique<CXFA_TextLayout>(GetDoc(), m_pRollProvider.get()); 151 } 152 153 if (m_pNode->GetWidgetAcc()->HasButtonDown()) { 154 if (!m_pDownProvider) { 155 m_pDownProvider = pdfium::MakeUnique<CXFA_TextProvider>( 156 m_pNode->GetWidgetAcc(), XFA_TEXTPROVIDERTYPE_Down); 157 } 158 m_pDownTextLayout = 159 pdfium::MakeUnique<CXFA_TextLayout>(GetDoc(), m_pDownProvider.get()); 160 } 161 } 162 163 void CXFA_FFPushButton::LayoutHighlightCaption() { 164 CFX_SizeF sz(m_rtCaption.width, m_rtCaption.height); 165 LayoutCaption(); 166 if (m_pRolloverTextLayout) 167 m_pRolloverTextLayout->Layout(sz); 168 if (m_pDownTextLayout) 169 m_pDownTextLayout->Layout(sz); 170 } 171 172 void CXFA_FFPushButton::RenderHighlightCaption(CXFA_Graphics* pGS, 173 CFX_Matrix* pMatrix) { 174 CXFA_TextLayout* pCapTextLayout = 175 m_pNode->GetWidgetAcc()->GetCaptionTextLayout(); 176 CXFA_Caption* caption = m_pNode->GetCaptionIfExists(); 177 if (!caption || !caption->IsVisible()) 178 return; 179 180 CFX_RenderDevice* pRenderDevice = pGS->GetRenderDevice(); 181 CFX_RectF rtClip = m_rtCaption; 182 rtClip.Intersect(GetRectWithoutRotate()); 183 CFX_Matrix mt(1, 0, 0, 1, m_rtCaption.left, m_rtCaption.top); 184 if (pMatrix) { 185 rtClip = pMatrix->TransformRect(rtClip); 186 mt.Concat(*pMatrix); 187 } 188 189 uint32_t dwState = m_pNormalWidget->GetStates(); 190 if (m_pDownTextLayout && (dwState & FWL_STATE_PSB_Pressed) && 191 (dwState & FWL_STATE_PSB_Hovered)) { 192 if (m_pDownTextLayout->DrawString(pRenderDevice, mt, rtClip, 0)) 193 return; 194 } else if (m_pRolloverTextLayout && (dwState & FWL_STATE_PSB_Hovered)) { 195 if (m_pRolloverTextLayout->DrawString(pRenderDevice, mt, rtClip, 0)) 196 return; 197 } 198 199 if (pCapTextLayout) 200 pCapTextLayout->DrawString(pRenderDevice, mt, rtClip, 0); 201 } 202 203 void CXFA_FFPushButton::OnProcessMessage(CFWL_Message* pMessage) { 204 m_pOldDelegate->OnProcessMessage(pMessage); 205 } 206 207 void CXFA_FFPushButton::OnProcessEvent(CFWL_Event* pEvent) { 208 m_pOldDelegate->OnProcessEvent(pEvent); 209 CXFA_FFField::OnProcessEvent(pEvent); 210 } 211 212 void CXFA_FFPushButton::OnDrawWidget(CXFA_Graphics* pGraphics, 213 const CFX_Matrix& matrix) { 214 if (m_pNormalWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteInverted) { 215 if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) && 216 (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) { 217 CFX_RectF rtFill(0, 0, m_pNormalWidget->GetWidgetRect().Size()); 218 float fLineWith = GetLineWidth(); 219 rtFill.Deflate(fLineWith, fLineWith); 220 CXFA_GEPath path; 221 path.AddRectangle(rtFill.left, rtFill.top, rtFill.width, rtFill.height); 222 pGraphics->SetFillColor(CXFA_GEColor(FXARGB_MAKE(128, 128, 255, 255))); 223 pGraphics->FillPath(&path, FXFILL_WINDING, &matrix); 224 } 225 return; 226 } 227 228 if (m_pNormalWidget->GetStylesEx() & XFA_FWL_PSBSTYLEEXT_HiliteOutLine) { 229 if ((m_pNormalWidget->GetStates() & FWL_STATE_PSB_Pressed) && 230 (m_pNormalWidget->GetStates() & FWL_STATE_PSB_Hovered)) { 231 float fLineWidth = GetLineWidth(); 232 pGraphics->SetStrokeColor(CXFA_GEColor(FXARGB_MAKE(255, 128, 255, 255))); 233 pGraphics->SetLineWidth(fLineWidth); 234 235 CXFA_GEPath path; 236 CFX_RectF rect = m_pNormalWidget->GetWidgetRect(); 237 path.AddRectangle(0, 0, rect.width, rect.height); 238 pGraphics->StrokePath(&path, &matrix); 239 } 240 } 241 } 242 243 FormFieldType CXFA_FFPushButton::GetFormFieldType() { 244 return FormFieldType::kXFA_PushButton; 245 } 246