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