xref: /aosp_15_r20/external/pdfium/xfa/fwl/cfwl_edit.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
1*3ac0a46fSAndroid Build Coastguard Worker // Copyright 2014 The PDFium Authors
2*3ac0a46fSAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*3ac0a46fSAndroid Build Coastguard Worker // found in the LICENSE file.
4*3ac0a46fSAndroid Build Coastguard Worker 
5*3ac0a46fSAndroid Build Coastguard Worker // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6*3ac0a46fSAndroid Build Coastguard Worker 
7*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_edit.h"
8*3ac0a46fSAndroid Build Coastguard Worker 
9*3ac0a46fSAndroid Build Coastguard Worker #include <algorithm>
10*3ac0a46fSAndroid Build Coastguard Worker #include <memory>
11*3ac0a46fSAndroid Build Coastguard Worker #include <utility>
12*3ac0a46fSAndroid Build Coastguard Worker #include <vector>
13*3ac0a46fSAndroid Build Coastguard Worker 
14*3ac0a46fSAndroid Build Coastguard Worker #include "build/build_config.h"
15*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/cfx_renderdevice.h"
16*3ac0a46fSAndroid Build Coastguard Worker #include "core/fxge/text_char_pos.h"
17*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/check.h"
18*3ac0a46fSAndroid Build Coastguard Worker #include "third_party/base/numerics/safe_conversions.h"
19*3ac0a46fSAndroid Build Coastguard Worker #include "v8/include/cppgc/visitor.h"
20*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fde/cfde_textout.h"
21*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/font/cfgas_gefont.h"
22*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gegraphics.h"
23*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fgas/graphics/cfgas_gepath.h"
24*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_app.h"
25*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_caret.h"
26*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_event.h"
27*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_eventtextwillchange.h"
28*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_eventvalidate.h"
29*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_messagekey.h"
30*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_messagemouse.h"
31*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_themebackground.h"
32*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_themepart.h"
33*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/cfwl_widgetmgr.h"
34*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/fwl_widgetdef.h"
35*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/ifwl_themeprovider.h"
36*3ac0a46fSAndroid Build Coastguard Worker #include "xfa/fwl/theme/cfwl_utils.h"
37*3ac0a46fSAndroid Build Coastguard Worker 
38*3ac0a46fSAndroid Build Coastguard Worker namespace {
39*3ac0a46fSAndroid Build Coastguard Worker 
40*3ac0a46fSAndroid Build Coastguard Worker constexpr int kEditMargin = 3;
41*3ac0a46fSAndroid Build Coastguard Worker 
42*3ac0a46fSAndroid Build Coastguard Worker #if BUILDFLAG(IS_APPLE)
43*3ac0a46fSAndroid Build Coastguard Worker constexpr XFA_FWL_KeyFlag kEditingModifier = XFA_FWL_KeyFlag::kCommand;
44*3ac0a46fSAndroid Build Coastguard Worker #else
45*3ac0a46fSAndroid Build Coastguard Worker constexpr XFA_FWL_KeyFlag kEditingModifier = XFA_FWL_KeyFlag::kCtrl;
46*3ac0a46fSAndroid Build Coastguard Worker #endif
47*3ac0a46fSAndroid Build Coastguard Worker 
48*3ac0a46fSAndroid Build Coastguard Worker }  // namespace
49*3ac0a46fSAndroid Build Coastguard Worker 
CFWL_Edit(CFWL_App * app,const Properties & properties,CFWL_Widget * pOuter)50*3ac0a46fSAndroid Build Coastguard Worker CFWL_Edit::CFWL_Edit(CFWL_App* app,
51*3ac0a46fSAndroid Build Coastguard Worker                      const Properties& properties,
52*3ac0a46fSAndroid Build Coastguard Worker                      CFWL_Widget* pOuter)
53*3ac0a46fSAndroid Build Coastguard Worker     : CFWL_Widget(app, properties, pOuter),
54*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine(std::make_unique<CFDE_TextEditEngine>()) {
55*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetDelegate(this);
56*3ac0a46fSAndroid Build Coastguard Worker }
57*3ac0a46fSAndroid Build Coastguard Worker 
58*3ac0a46fSAndroid Build Coastguard Worker CFWL_Edit::~CFWL_Edit() = default;
59*3ac0a46fSAndroid Build Coastguard Worker 
PreFinalize()60*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::PreFinalize() {
61*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetDelegate(nullptr);
62*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused)
63*3ac0a46fSAndroid Build Coastguard Worker     HideCaret(nullptr);
64*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget::PreFinalize();
65*3ac0a46fSAndroid Build Coastguard Worker }
66*3ac0a46fSAndroid Build Coastguard Worker 
Trace(cppgc::Visitor * visitor) const67*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::Trace(cppgc::Visitor* visitor) const {
68*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget::Trace(visitor);
69*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pVertScrollBar);
70*3ac0a46fSAndroid Build Coastguard Worker   visitor->Trace(m_pCaret);
71*3ac0a46fSAndroid Build Coastguard Worker }
72*3ac0a46fSAndroid Build Coastguard Worker 
GetClassID() const73*3ac0a46fSAndroid Build Coastguard Worker FWL_Type CFWL_Edit::GetClassID() const {
74*3ac0a46fSAndroid Build Coastguard Worker   return FWL_Type::Edit;
75*3ac0a46fSAndroid Build Coastguard Worker }
76*3ac0a46fSAndroid Build Coastguard Worker 
GetWidgetRect()77*3ac0a46fSAndroid Build Coastguard Worker CFX_RectF CFWL_Edit::GetWidgetRect() {
78*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rect = m_WidgetRect;
79*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_OuterScrollbar) {
80*3ac0a46fSAndroid Build Coastguard Worker     float scrollbarWidth = GetThemeProvider()->GetScrollBarWidth();
81*3ac0a46fSAndroid Build Coastguard Worker     if (IsShowVertScrollBar()) {
82*3ac0a46fSAndroid Build Coastguard Worker       rect.width += scrollbarWidth;
83*3ac0a46fSAndroid Build Coastguard Worker       rect.width += kEditMargin;
84*3ac0a46fSAndroid Build Coastguard Worker     }
85*3ac0a46fSAndroid Build Coastguard Worker   }
86*3ac0a46fSAndroid Build Coastguard Worker   return rect;
87*3ac0a46fSAndroid Build Coastguard Worker }
88*3ac0a46fSAndroid Build Coastguard Worker 
GetAutosizedWidgetRect()89*3ac0a46fSAndroid Build Coastguard Worker CFX_RectF CFWL_Edit::GetAutosizedWidgetRect() {
90*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rect;
91*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->GetLength() > 0) {
92*3ac0a46fSAndroid Build Coastguard Worker     CFX_SizeF size = CalcTextSize(
93*3ac0a46fSAndroid Build Coastguard Worker         m_pEditEngine->GetText(),
94*3ac0a46fSAndroid Build Coastguard Worker         !!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_MultiLine));
95*3ac0a46fSAndroid Build Coastguard Worker     rect = CFX_RectF(0, 0, size);
96*3ac0a46fSAndroid Build Coastguard Worker   }
97*3ac0a46fSAndroid Build Coastguard Worker   InflateWidgetRect(rect);
98*3ac0a46fSAndroid Build Coastguard Worker   return rect;
99*3ac0a46fSAndroid Build Coastguard Worker }
100*3ac0a46fSAndroid Build Coastguard Worker 
SetStates(uint32_t dwStates)101*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetStates(uint32_t dwStates) {
102*3ac0a46fSAndroid Build Coastguard Worker   if ((m_Properties.m_dwStates & FWL_STATE_WGT_Invisible) ||
103*3ac0a46fSAndroid Build Coastguard Worker       (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)) {
104*3ac0a46fSAndroid Build Coastguard Worker     HideCaret(nullptr);
105*3ac0a46fSAndroid Build Coastguard Worker   }
106*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget::SetStates(dwStates);
107*3ac0a46fSAndroid Build Coastguard Worker }
108*3ac0a46fSAndroid Build Coastguard Worker 
Update()109*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::Update() {
110*3ac0a46fSAndroid Build Coastguard Worker   if (IsLocked())
111*3ac0a46fSAndroid Build Coastguard Worker     return;
112*3ac0a46fSAndroid Build Coastguard Worker 
113*3ac0a46fSAndroid Build Coastguard Worker   Layout();
114*3ac0a46fSAndroid Build Coastguard Worker   if (m_ClientRect.IsEmpty())
115*3ac0a46fSAndroid Build Coastguard Worker     return;
116*3ac0a46fSAndroid Build Coastguard Worker 
117*3ac0a46fSAndroid Build Coastguard Worker   UpdateEditEngine();
118*3ac0a46fSAndroid Build Coastguard Worker   UpdateVAlignment();
119*3ac0a46fSAndroid Build Coastguard Worker   UpdateScroll();
120*3ac0a46fSAndroid Build Coastguard Worker   InitCaret();
121*3ac0a46fSAndroid Build Coastguard Worker }
122*3ac0a46fSAndroid Build Coastguard Worker 
HitTest(const CFX_PointF & point)123*3ac0a46fSAndroid Build Coastguard Worker FWL_WidgetHit CFWL_Edit::HitTest(const CFX_PointF& point) {
124*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_OuterScrollbar) {
125*3ac0a46fSAndroid Build Coastguard Worker     if (IsShowVertScrollBar()) {
126*3ac0a46fSAndroid Build Coastguard Worker       if (m_pVertScrollBar->GetWidgetRect().Contains(point))
127*3ac0a46fSAndroid Build Coastguard Worker         return FWL_WidgetHit::VScrollBar;
128*3ac0a46fSAndroid Build Coastguard Worker     }
129*3ac0a46fSAndroid Build Coastguard Worker   }
130*3ac0a46fSAndroid Build Coastguard Worker   if (m_ClientRect.Contains(point))
131*3ac0a46fSAndroid Build Coastguard Worker     return FWL_WidgetHit::Edit;
132*3ac0a46fSAndroid Build Coastguard Worker   return FWL_WidgetHit::Unknown;
133*3ac0a46fSAndroid Build Coastguard Worker }
134*3ac0a46fSAndroid Build Coastguard Worker 
DrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)135*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::DrawWidget(CFGAS_GEGraphics* pGraphics,
136*3ac0a46fSAndroid Build Coastguard Worker                            const CFX_Matrix& matrix) {
137*3ac0a46fSAndroid Build Coastguard Worker   if (!pGraphics)
138*3ac0a46fSAndroid Build Coastguard Worker     return;
139*3ac0a46fSAndroid Build Coastguard Worker 
140*3ac0a46fSAndroid Build Coastguard Worker   if (m_ClientRect.IsEmpty())
141*3ac0a46fSAndroid Build Coastguard Worker     return;
142*3ac0a46fSAndroid Build Coastguard Worker 
143*3ac0a46fSAndroid Build Coastguard Worker   DrawContent(pGraphics, matrix);
144*3ac0a46fSAndroid Build Coastguard Worker   if (HasBorder())
145*3ac0a46fSAndroid Build Coastguard Worker     DrawBorder(pGraphics, CFWL_ThemePart::Part::kBorder, matrix);
146*3ac0a46fSAndroid Build Coastguard Worker }
147*3ac0a46fSAndroid Build Coastguard Worker 
SetText(const WideString & wsText)148*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetText(const WideString& wsText) {
149*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Clear();
150*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Insert(0, wsText,
151*3ac0a46fSAndroid Build Coastguard Worker                         CFDE_TextEditEngine::RecordOperation::kInsertRecord);
152*3ac0a46fSAndroid Build Coastguard Worker }
153*3ac0a46fSAndroid Build Coastguard Worker 
SetTextSkipNotify(const WideString & wsText)154*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetTextSkipNotify(const WideString& wsText) {
155*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Clear();
156*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Insert(0, wsText,
157*3ac0a46fSAndroid Build Coastguard Worker                         CFDE_TextEditEngine::RecordOperation::kSkipNotify);
158*3ac0a46fSAndroid Build Coastguard Worker }
159*3ac0a46fSAndroid Build Coastguard Worker 
GetTextLength() const160*3ac0a46fSAndroid Build Coastguard Worker size_t CFWL_Edit::GetTextLength() const {
161*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->GetLength();
162*3ac0a46fSAndroid Build Coastguard Worker }
163*3ac0a46fSAndroid Build Coastguard Worker 
GetText() const164*3ac0a46fSAndroid Build Coastguard Worker WideString CFWL_Edit::GetText() const {
165*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->GetText();
166*3ac0a46fSAndroid Build Coastguard Worker }
167*3ac0a46fSAndroid Build Coastguard Worker 
ClearText()168*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::ClearText() {
169*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Clear();
170*3ac0a46fSAndroid Build Coastguard Worker }
171*3ac0a46fSAndroid Build Coastguard Worker 
SelectAll()172*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SelectAll() {
173*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SelectAll();
174*3ac0a46fSAndroid Build Coastguard Worker }
175*3ac0a46fSAndroid Build Coastguard Worker 
HasSelection() const176*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::HasSelection() const {
177*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->HasSelection();
178*3ac0a46fSAndroid Build Coastguard Worker }
179*3ac0a46fSAndroid Build Coastguard Worker 
GetSelection() const180*3ac0a46fSAndroid Build Coastguard Worker std::pair<size_t, size_t> CFWL_Edit::GetSelection() const {
181*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->GetSelection();
182*3ac0a46fSAndroid Build Coastguard Worker }
183*3ac0a46fSAndroid Build Coastguard Worker 
ClearSelection()184*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::ClearSelection() {
185*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->ClearSelection();
186*3ac0a46fSAndroid Build Coastguard Worker }
187*3ac0a46fSAndroid Build Coastguard Worker 
GetLimit() const188*3ac0a46fSAndroid Build Coastguard Worker int32_t CFWL_Edit::GetLimit() const {
189*3ac0a46fSAndroid Build Coastguard Worker   return m_nLimit;
190*3ac0a46fSAndroid Build Coastguard Worker }
191*3ac0a46fSAndroid Build Coastguard Worker 
SetLimit(int32_t nLimit)192*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetLimit(int32_t nLimit) {
193*3ac0a46fSAndroid Build Coastguard Worker   m_nLimit = nLimit;
194*3ac0a46fSAndroid Build Coastguard Worker 
195*3ac0a46fSAndroid Build Coastguard Worker   if (m_nLimit > 0) {
196*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->SetHasCharacterLimit(true);
197*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->SetCharacterLimit(nLimit);
198*3ac0a46fSAndroid Build Coastguard Worker   } else {
199*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->SetHasCharacterLimit(false);
200*3ac0a46fSAndroid Build Coastguard Worker   }
201*3ac0a46fSAndroid Build Coastguard Worker }
202*3ac0a46fSAndroid Build Coastguard Worker 
SetAliasChar(wchar_t wAlias)203*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetAliasChar(wchar_t wAlias) {
204*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetAliasChar(wAlias);
205*3ac0a46fSAndroid Build Coastguard Worker }
206*3ac0a46fSAndroid Build Coastguard Worker 
Copy()207*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> CFWL_Edit::Copy() {
208*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pEditEngine->HasSelection())
209*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
210*3ac0a46fSAndroid Build Coastguard Worker 
211*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->GetSelectedText();
212*3ac0a46fSAndroid Build Coastguard Worker }
213*3ac0a46fSAndroid Build Coastguard Worker 
Cut()214*3ac0a46fSAndroid Build Coastguard Worker absl::optional<WideString> CFWL_Edit::Cut() {
215*3ac0a46fSAndroid Build Coastguard Worker   if (!m_pEditEngine->HasSelection())
216*3ac0a46fSAndroid Build Coastguard Worker     return absl::nullopt;
217*3ac0a46fSAndroid Build Coastguard Worker 
218*3ac0a46fSAndroid Build Coastguard Worker   WideString cut_text = m_pEditEngine->DeleteSelectedText();
219*3ac0a46fSAndroid Build Coastguard Worker   UpdateCaret();
220*3ac0a46fSAndroid Build Coastguard Worker   return cut_text;
221*3ac0a46fSAndroid Build Coastguard Worker }
222*3ac0a46fSAndroid Build Coastguard Worker 
Paste(const WideString & wsPaste)223*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::Paste(const WideString& wsPaste) {
224*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->HasSelection())
225*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->ReplaceSelectedText(wsPaste);
226*3ac0a46fSAndroid Build Coastguard Worker   else
227*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->Insert(m_CursorPosition, wsPaste);
228*3ac0a46fSAndroid Build Coastguard Worker 
229*3ac0a46fSAndroid Build Coastguard Worker   return true;
230*3ac0a46fSAndroid Build Coastguard Worker }
231*3ac0a46fSAndroid Build Coastguard Worker 
Undo()232*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::Undo() {
233*3ac0a46fSAndroid Build Coastguard Worker   return CanUndo() && m_pEditEngine->Undo();
234*3ac0a46fSAndroid Build Coastguard Worker }
235*3ac0a46fSAndroid Build Coastguard Worker 
Redo()236*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::Redo() {
237*3ac0a46fSAndroid Build Coastguard Worker   return CanRedo() && m_pEditEngine->Redo();
238*3ac0a46fSAndroid Build Coastguard Worker }
239*3ac0a46fSAndroid Build Coastguard Worker 
CanUndo()240*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::CanUndo() {
241*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->CanUndo();
242*3ac0a46fSAndroid Build Coastguard Worker }
243*3ac0a46fSAndroid Build Coastguard Worker 
CanRedo()244*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::CanRedo() {
245*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->CanRedo();
246*3ac0a46fSAndroid Build Coastguard Worker }
247*3ac0a46fSAndroid Build Coastguard Worker 
NotifyTextFull()248*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::NotifyTextFull() {
249*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Event evt(CFWL_Event::Type::TextFull, this);
250*3ac0a46fSAndroid Build Coastguard Worker   DispatchEvent(&evt);
251*3ac0a46fSAndroid Build Coastguard Worker }
252*3ac0a46fSAndroid Build Coastguard Worker 
OnCaretChanged()253*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnCaretChanged() {
254*3ac0a46fSAndroid Build Coastguard Worker   if (m_EngineRect.IsEmpty())
255*3ac0a46fSAndroid Build Coastguard Worker     return;
256*3ac0a46fSAndroid Build Coastguard Worker   if ((m_Properties.m_dwStates & FWL_STATE_WGT_Focused) == 0)
257*3ac0a46fSAndroid Build Coastguard Worker     return;
258*3ac0a46fSAndroid Build Coastguard Worker 
259*3ac0a46fSAndroid Build Coastguard Worker   bool bRepaintContent = UpdateOffset();
260*3ac0a46fSAndroid Build Coastguard Worker   UpdateCaret();
261*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtInvalid;
262*3ac0a46fSAndroid Build Coastguard Worker   bool bRepaintScroll = false;
263*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_MultiLine) {
264*3ac0a46fSAndroid Build Coastguard Worker     CFWL_ScrollBar* pScroll = UpdateScroll();
265*3ac0a46fSAndroid Build Coastguard Worker     if (pScroll) {
266*3ac0a46fSAndroid Build Coastguard Worker       rtInvalid = pScroll->GetWidgetRect();
267*3ac0a46fSAndroid Build Coastguard Worker       bRepaintScroll = true;
268*3ac0a46fSAndroid Build Coastguard Worker     }
269*3ac0a46fSAndroid Build Coastguard Worker   }
270*3ac0a46fSAndroid Build Coastguard Worker   if (bRepaintContent || bRepaintScroll) {
271*3ac0a46fSAndroid Build Coastguard Worker     if (bRepaintContent)
272*3ac0a46fSAndroid Build Coastguard Worker       rtInvalid.Union(m_EngineRect);
273*3ac0a46fSAndroid Build Coastguard Worker     RepaintRect(rtInvalid);
274*3ac0a46fSAndroid Build Coastguard Worker   }
275*3ac0a46fSAndroid Build Coastguard Worker }
276*3ac0a46fSAndroid Build Coastguard Worker 
OnTextWillChange(CFDE_TextEditEngine::TextChange * change)277*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnTextWillChange(CFDE_TextEditEngine::TextChange* change) {
278*3ac0a46fSAndroid Build Coastguard Worker   CFWL_EventTextWillChange event(this, change->text, change->previous_text,
279*3ac0a46fSAndroid Build Coastguard Worker                                  change->selection_start,
280*3ac0a46fSAndroid Build Coastguard Worker                                  change->selection_end);
281*3ac0a46fSAndroid Build Coastguard Worker   DispatchEvent(&event);
282*3ac0a46fSAndroid Build Coastguard Worker 
283*3ac0a46fSAndroid Build Coastguard Worker   change->text = event.GetChangeText();
284*3ac0a46fSAndroid Build Coastguard Worker   change->selection_start = event.GetSelectionStart();
285*3ac0a46fSAndroid Build Coastguard Worker   change->selection_end = event.GetSelectionEnd();
286*3ac0a46fSAndroid Build Coastguard Worker   change->cancelled = event.GetCancelled();
287*3ac0a46fSAndroid Build Coastguard Worker }
288*3ac0a46fSAndroid Build Coastguard Worker 
OnTextChanged()289*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnTextChanged() {
290*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_VAlignMask)
291*3ac0a46fSAndroid Build Coastguard Worker     UpdateVAlignment();
292*3ac0a46fSAndroid Build Coastguard Worker 
293*3ac0a46fSAndroid Build Coastguard Worker   LayoutScrollBar();
294*3ac0a46fSAndroid Build Coastguard Worker   RepaintRect(GetClientRect());
295*3ac0a46fSAndroid Build Coastguard Worker }
296*3ac0a46fSAndroid Build Coastguard Worker 
OnSelChanged()297*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnSelChanged() {
298*3ac0a46fSAndroid Build Coastguard Worker   RepaintRect(GetClientRect());
299*3ac0a46fSAndroid Build Coastguard Worker }
300*3ac0a46fSAndroid Build Coastguard Worker 
OnValidate(const WideString & wsText)301*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::OnValidate(const WideString& wsText) {
302*3ac0a46fSAndroid Build Coastguard Worker   CFWL_EventValidate event(this, wsText);
303*3ac0a46fSAndroid Build Coastguard Worker   DispatchEvent(&event);
304*3ac0a46fSAndroid Build Coastguard Worker   return event.GetValidate();
305*3ac0a46fSAndroid Build Coastguard Worker }
306*3ac0a46fSAndroid Build Coastguard Worker 
SetScrollOffset(float fScrollOffset)307*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetScrollOffset(float fScrollOffset) {
308*3ac0a46fSAndroid Build Coastguard Worker   m_fScrollOffsetY = fScrollOffset;
309*3ac0a46fSAndroid Build Coastguard Worker }
310*3ac0a46fSAndroid Build Coastguard Worker 
DrawContent(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & mtMatrix)311*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::DrawContent(CFGAS_GEGraphics* pGraphics,
312*3ac0a46fSAndroid Build Coastguard Worker                             const CFX_Matrix& mtMatrix) {
313*3ac0a46fSAndroid Build Coastguard Worker   DrawContentNonComb(pGraphics, mtMatrix);
314*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_CombText) {
315*3ac0a46fSAndroid Build Coastguard Worker     CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
316*3ac0a46fSAndroid Build Coastguard Worker     CFGAS_GEPath path;
317*3ac0a46fSAndroid Build Coastguard Worker     const int32_t iLimit = m_nLimit > 0 ? m_nLimit : 1;
318*3ac0a46fSAndroid Build Coastguard Worker     const float fStep = m_EngineRect.width / iLimit;
319*3ac0a46fSAndroid Build Coastguard Worker     float fLeft = m_EngineRect.left + 1;
320*3ac0a46fSAndroid Build Coastguard Worker     for (int32_t i = 1; i < iLimit; i++) {
321*3ac0a46fSAndroid Build Coastguard Worker       fLeft += fStep;
322*3ac0a46fSAndroid Build Coastguard Worker       path.AddLine(CFX_PointF(fLeft, m_ClientRect.top),
323*3ac0a46fSAndroid Build Coastguard Worker                    CFX_PointF(fLeft, m_ClientRect.bottom()));
324*3ac0a46fSAndroid Build Coastguard Worker     }
325*3ac0a46fSAndroid Build Coastguard Worker     CFWL_ThemeBackground param(CFWL_ThemePart::Part::kCombTextLine, this,
326*3ac0a46fSAndroid Build Coastguard Worker                                pGraphics);
327*3ac0a46fSAndroid Build Coastguard Worker     param.m_matrix = mtMatrix;
328*3ac0a46fSAndroid Build Coastguard Worker     param.SetPath(&path);
329*3ac0a46fSAndroid Build Coastguard Worker     GetThemeProvider()->DrawBackground(param);
330*3ac0a46fSAndroid Build Coastguard Worker   }
331*3ac0a46fSAndroid Build Coastguard Worker }
332*3ac0a46fSAndroid Build Coastguard Worker 
DrawContentNonComb(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & mtMatrix)333*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::DrawContentNonComb(CFGAS_GEGraphics* pGraphics,
334*3ac0a46fSAndroid Build Coastguard Worker                                    const CFX_Matrix& mtMatrix) {
335*3ac0a46fSAndroid Build Coastguard Worker   CFGAS_GEGraphics::StateRestorer restorer(pGraphics);
336*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtClip = m_EngineRect;
337*3ac0a46fSAndroid Build Coastguard Worker   float fOffSetX = m_EngineRect.left - m_fScrollOffsetX;
338*3ac0a46fSAndroid Build Coastguard Worker   float fOffSetY = m_EngineRect.top - m_fScrollOffsetY + m_fVAlignOffset;
339*3ac0a46fSAndroid Build Coastguard Worker   CFX_Matrix mt(1, 0, 0, 1, fOffSetX, fOffSetY);
340*3ac0a46fSAndroid Build Coastguard Worker   rtClip = mtMatrix.TransformRect(rtClip);
341*3ac0a46fSAndroid Build Coastguard Worker   mt.Concat(mtMatrix);
342*3ac0a46fSAndroid Build Coastguard Worker 
343*3ac0a46fSAndroid Build Coastguard Worker   bool bShowSel = !!(m_Properties.m_dwStates & FWL_STATE_WGT_Focused);
344*3ac0a46fSAndroid Build Coastguard Worker   if (bShowSel && m_pEditEngine->HasSelection()) {
345*3ac0a46fSAndroid Build Coastguard Worker     size_t sel_start;
346*3ac0a46fSAndroid Build Coastguard Worker     size_t count;
347*3ac0a46fSAndroid Build Coastguard Worker     std::tie(sel_start, count) = m_pEditEngine->GetSelection();
348*3ac0a46fSAndroid Build Coastguard Worker     std::vector<CFX_RectF> rects = m_pEditEngine->GetCharacterRectsInRange(
349*3ac0a46fSAndroid Build Coastguard Worker         pdfium::base::checked_cast<int32_t>(sel_start),
350*3ac0a46fSAndroid Build Coastguard Worker         pdfium::base::checked_cast<int32_t>(count));
351*3ac0a46fSAndroid Build Coastguard Worker 
352*3ac0a46fSAndroid Build Coastguard Worker     CFGAS_GEPath path;
353*3ac0a46fSAndroid Build Coastguard Worker     for (auto& rect : rects) {
354*3ac0a46fSAndroid Build Coastguard Worker       rect.left += fOffSetX;
355*3ac0a46fSAndroid Build Coastguard Worker       rect.top += fOffSetY;
356*3ac0a46fSAndroid Build Coastguard Worker       path.AddRectangle(rect.left, rect.top, rect.width, rect.height);
357*3ac0a46fSAndroid Build Coastguard Worker     }
358*3ac0a46fSAndroid Build Coastguard Worker     pGraphics->SetClipRect(rtClip);
359*3ac0a46fSAndroid Build Coastguard Worker 
360*3ac0a46fSAndroid Build Coastguard Worker     CFWL_ThemeBackground param(CFWL_ThemePart::Part::kBackground, this,
361*3ac0a46fSAndroid Build Coastguard Worker                                pGraphics);
362*3ac0a46fSAndroid Build Coastguard Worker     param.m_matrix = mtMatrix;
363*3ac0a46fSAndroid Build Coastguard Worker     param.SetPath(&path);
364*3ac0a46fSAndroid Build Coastguard Worker     GetThemeProvider()->DrawBackground(param);
365*3ac0a46fSAndroid Build Coastguard Worker   }
366*3ac0a46fSAndroid Build Coastguard Worker 
367*3ac0a46fSAndroid Build Coastguard Worker   CFX_RenderDevice* pRenderDev = pGraphics->GetRenderDevice();
368*3ac0a46fSAndroid Build Coastguard Worker   RenderText(pRenderDev, rtClip, mt);
369*3ac0a46fSAndroid Build Coastguard Worker }
370*3ac0a46fSAndroid Build Coastguard Worker 
RenderText(CFX_RenderDevice * pRenderDev,const CFX_RectF & clipRect,const CFX_Matrix & mt)371*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::RenderText(CFX_RenderDevice* pRenderDev,
372*3ac0a46fSAndroid Build Coastguard Worker                            const CFX_RectF& clipRect,
373*3ac0a46fSAndroid Build Coastguard Worker                            const CFX_Matrix& mt) {
374*3ac0a46fSAndroid Build Coastguard Worker   DCHECK(pRenderDev);
375*3ac0a46fSAndroid Build Coastguard Worker 
376*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CFGAS_GEFont> font = m_pEditEngine->GetFont();
377*3ac0a46fSAndroid Build Coastguard Worker   if (!font)
378*3ac0a46fSAndroid Build Coastguard Worker     return;
379*3ac0a46fSAndroid Build Coastguard Worker 
380*3ac0a46fSAndroid Build Coastguard Worker   pRenderDev->SetClip_Rect(clipRect.GetOuterRect());
381*3ac0a46fSAndroid Build Coastguard Worker 
382*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtDocClip = clipRect;
383*3ac0a46fSAndroid Build Coastguard Worker   if (rtDocClip.IsEmpty()) {
384*3ac0a46fSAndroid Build Coastguard Worker     rtDocClip.left = 0;
385*3ac0a46fSAndroid Build Coastguard Worker     rtDocClip.top = 0;
386*3ac0a46fSAndroid Build Coastguard Worker     rtDocClip.width = static_cast<float>(pRenderDev->GetWidth());
387*3ac0a46fSAndroid Build Coastguard Worker     rtDocClip.height = static_cast<float>(pRenderDev->GetHeight());
388*3ac0a46fSAndroid Build Coastguard Worker   }
389*3ac0a46fSAndroid Build Coastguard Worker   rtDocClip = mt.GetInverse().TransformRect(rtDocClip);
390*3ac0a46fSAndroid Build Coastguard Worker 
391*3ac0a46fSAndroid Build Coastguard Worker   for (const FDE_TEXTEDITPIECE& info : m_pEditEngine->GetTextPieces()) {
392*3ac0a46fSAndroid Build Coastguard Worker     // If this character is outside the clip, skip it.
393*3ac0a46fSAndroid Build Coastguard Worker     if (!rtDocClip.IntersectWith(info.rtPiece))
394*3ac0a46fSAndroid Build Coastguard Worker       continue;
395*3ac0a46fSAndroid Build Coastguard Worker 
396*3ac0a46fSAndroid Build Coastguard Worker     std::vector<TextCharPos> char_pos = m_pEditEngine->GetDisplayPos(info);
397*3ac0a46fSAndroid Build Coastguard Worker     if (char_pos.empty())
398*3ac0a46fSAndroid Build Coastguard Worker       continue;
399*3ac0a46fSAndroid Build Coastguard Worker 
400*3ac0a46fSAndroid Build Coastguard Worker     CFDE_TextOut::DrawString(pRenderDev, m_pEditEngine->GetFontColor(), font,
401*3ac0a46fSAndroid Build Coastguard Worker                              char_pos, m_pEditEngine->GetFontSize(), mt);
402*3ac0a46fSAndroid Build Coastguard Worker   }
403*3ac0a46fSAndroid Build Coastguard Worker }
404*3ac0a46fSAndroid Build Coastguard Worker 
UpdateEditEngine()405*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateEditEngine() {
406*3ac0a46fSAndroid Build Coastguard Worker   UpdateEditParams();
407*3ac0a46fSAndroid Build Coastguard Worker   UpdateEditLayout();
408*3ac0a46fSAndroid Build Coastguard Worker }
409*3ac0a46fSAndroid Build Coastguard Worker 
UpdateEditParams()410*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateEditParams() {
411*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetAvailableWidth(m_EngineRect.width);
412*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetCombText(
413*3ac0a46fSAndroid Build Coastguard Worker       !!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_CombText));
414*3ac0a46fSAndroid Build Coastguard Worker 
415*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->EnableValidation(
416*3ac0a46fSAndroid Build Coastguard Worker       !!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_Validate));
417*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->EnablePasswordMode(
418*3ac0a46fSAndroid Build Coastguard Worker       !!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_Password));
419*3ac0a46fSAndroid Build Coastguard Worker 
420*3ac0a46fSAndroid Build Coastguard Worker   uint32_t alignment = 0;
421*3ac0a46fSAndroid Build Coastguard Worker   switch (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_HAlignMask) {
422*3ac0a46fSAndroid Build Coastguard Worker     case FWL_STYLEEXT_EDT_HNear: {
423*3ac0a46fSAndroid Build Coastguard Worker       alignment |= CFX_TxtLineAlignment_Left;
424*3ac0a46fSAndroid Build Coastguard Worker       break;
425*3ac0a46fSAndroid Build Coastguard Worker     }
426*3ac0a46fSAndroid Build Coastguard Worker     case FWL_STYLEEXT_EDT_HCenter: {
427*3ac0a46fSAndroid Build Coastguard Worker       alignment |= CFX_TxtLineAlignment_Center;
428*3ac0a46fSAndroid Build Coastguard Worker       break;
429*3ac0a46fSAndroid Build Coastguard Worker     }
430*3ac0a46fSAndroid Build Coastguard Worker     case FWL_STYLEEXT_EDT_HFar: {
431*3ac0a46fSAndroid Build Coastguard Worker       alignment |= CFX_TxtLineAlignment_Right;
432*3ac0a46fSAndroid Build Coastguard Worker       break;
433*3ac0a46fSAndroid Build Coastguard Worker     }
434*3ac0a46fSAndroid Build Coastguard Worker     default:
435*3ac0a46fSAndroid Build Coastguard Worker       break;
436*3ac0a46fSAndroid Build Coastguard Worker   }
437*3ac0a46fSAndroid Build Coastguard Worker   switch (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_HAlignModeMask) {
438*3ac0a46fSAndroid Build Coastguard Worker     case FWL_STYLEEXT_EDT_Justified: {
439*3ac0a46fSAndroid Build Coastguard Worker       alignment |= CFX_TxtLineAlignment_Justified;
440*3ac0a46fSAndroid Build Coastguard Worker       break;
441*3ac0a46fSAndroid Build Coastguard Worker     }
442*3ac0a46fSAndroid Build Coastguard Worker     default:
443*3ac0a46fSAndroid Build Coastguard Worker       break;
444*3ac0a46fSAndroid Build Coastguard Worker   }
445*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetAlignment(alignment);
446*3ac0a46fSAndroid Build Coastguard Worker 
447*3ac0a46fSAndroid Build Coastguard Worker   bool auto_hscroll =
448*3ac0a46fSAndroid Build Coastguard Worker       !!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_AutoHScroll);
449*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_MultiLine) {
450*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->EnableMultiLine(true);
451*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->EnableLineWrap(!auto_hscroll);
452*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->LimitVerticalScroll(
453*3ac0a46fSAndroid Build Coastguard Worker         (m_Properties.m_dwStyles & FWL_STYLE_WGT_VScroll) == 0 &&
454*3ac0a46fSAndroid Build Coastguard Worker         (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_AutoVScroll) == 0);
455*3ac0a46fSAndroid Build Coastguard Worker   } else {
456*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->EnableMultiLine(false);
457*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->EnableLineWrap(false);
458*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->LimitVerticalScroll(false);
459*3ac0a46fSAndroid Build Coastguard Worker   }
460*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->LimitHorizontalScroll(!auto_hscroll);
461*3ac0a46fSAndroid Build Coastguard Worker 
462*3ac0a46fSAndroid Build Coastguard Worker   IFWL_ThemeProvider* theme = GetThemeProvider();
463*3ac0a46fSAndroid Build Coastguard Worker   CFWL_ThemePart part(CFWL_ThemePart::Part::kNone, this);
464*3ac0a46fSAndroid Build Coastguard Worker   m_fFontSize = theme->GetFontSize(part);
465*3ac0a46fSAndroid Build Coastguard Worker 
466*3ac0a46fSAndroid Build Coastguard Worker   RetainPtr<CFGAS_GEFont> pFont = theme->GetFont(part);
467*3ac0a46fSAndroid Build Coastguard Worker   if (!pFont)
468*3ac0a46fSAndroid Build Coastguard Worker     return;
469*3ac0a46fSAndroid Build Coastguard Worker 
470*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetFont(pFont);
471*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetFontColor(theme->GetTextColor(part));
472*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetFontSize(m_fFontSize);
473*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetLineSpace(theme->GetLineHeight(part));
474*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetTabWidth(m_fFontSize);
475*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetVisibleLineCount(m_EngineRect.height /
476*3ac0a46fSAndroid Build Coastguard Worker                                      theme->GetLineHeight(part));
477*3ac0a46fSAndroid Build Coastguard Worker }
478*3ac0a46fSAndroid Build Coastguard Worker 
UpdateEditLayout()479*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateEditLayout() {
480*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->Layout();
481*3ac0a46fSAndroid Build Coastguard Worker }
482*3ac0a46fSAndroid Build Coastguard Worker 
UpdateOffset()483*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::UpdateOffset() {
484*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtCaret = m_CaretRect;
485*3ac0a46fSAndroid Build Coastguard Worker 
486*3ac0a46fSAndroid Build Coastguard Worker   float fOffSetX = m_EngineRect.left - m_fScrollOffsetX;
487*3ac0a46fSAndroid Build Coastguard Worker   float fOffSetY = m_EngineRect.top - m_fScrollOffsetY + m_fVAlignOffset;
488*3ac0a46fSAndroid Build Coastguard Worker   rtCaret.Offset(fOffSetX, fOffSetY);
489*3ac0a46fSAndroid Build Coastguard Worker 
490*3ac0a46fSAndroid Build Coastguard Worker   const CFX_RectF& edit_bounds = m_EngineRect;
491*3ac0a46fSAndroid Build Coastguard Worker   if (edit_bounds.Contains(rtCaret)) {
492*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
493*3ac0a46fSAndroid Build Coastguard Worker     contents_bounds.Offset(fOffSetX, fOffSetY);
494*3ac0a46fSAndroid Build Coastguard Worker     if (contents_bounds.right() < edit_bounds.right() && m_fScrollOffsetX > 0) {
495*3ac0a46fSAndroid Build Coastguard Worker       m_fScrollOffsetX += contents_bounds.right() - edit_bounds.right();
496*3ac0a46fSAndroid Build Coastguard Worker       m_fScrollOffsetX = std::max(m_fScrollOffsetX, 0.0f);
497*3ac0a46fSAndroid Build Coastguard Worker     }
498*3ac0a46fSAndroid Build Coastguard Worker     if (contents_bounds.bottom() < edit_bounds.bottom() &&
499*3ac0a46fSAndroid Build Coastguard Worker         m_fScrollOffsetY > 0) {
500*3ac0a46fSAndroid Build Coastguard Worker       m_fScrollOffsetY += contents_bounds.bottom() - edit_bounds.bottom();
501*3ac0a46fSAndroid Build Coastguard Worker       m_fScrollOffsetY = std::max(m_fScrollOffsetY, 0.0f);
502*3ac0a46fSAndroid Build Coastguard Worker     }
503*3ac0a46fSAndroid Build Coastguard Worker     return false;
504*3ac0a46fSAndroid Build Coastguard Worker   }
505*3ac0a46fSAndroid Build Coastguard Worker 
506*3ac0a46fSAndroid Build Coastguard Worker   float offsetX = 0.0;
507*3ac0a46fSAndroid Build Coastguard Worker   float offsetY = 0.0;
508*3ac0a46fSAndroid Build Coastguard Worker   if (rtCaret.left < edit_bounds.left)
509*3ac0a46fSAndroid Build Coastguard Worker     offsetX = rtCaret.left - edit_bounds.left;
510*3ac0a46fSAndroid Build Coastguard Worker   if (rtCaret.right() > edit_bounds.right())
511*3ac0a46fSAndroid Build Coastguard Worker     offsetX = rtCaret.right() - edit_bounds.right();
512*3ac0a46fSAndroid Build Coastguard Worker   if (rtCaret.top < edit_bounds.top)
513*3ac0a46fSAndroid Build Coastguard Worker     offsetY = rtCaret.top - edit_bounds.top;
514*3ac0a46fSAndroid Build Coastguard Worker   if (rtCaret.bottom() > edit_bounds.bottom())
515*3ac0a46fSAndroid Build Coastguard Worker     offsetY = rtCaret.bottom() - edit_bounds.bottom();
516*3ac0a46fSAndroid Build Coastguard Worker 
517*3ac0a46fSAndroid Build Coastguard Worker   m_fScrollOffsetX += offsetX;
518*3ac0a46fSAndroid Build Coastguard Worker   m_fScrollOffsetY += offsetY;
519*3ac0a46fSAndroid Build Coastguard Worker   if (m_fFontSize > m_EngineRect.height)
520*3ac0a46fSAndroid Build Coastguard Worker     m_fScrollOffsetY = 0;
521*3ac0a46fSAndroid Build Coastguard Worker 
522*3ac0a46fSAndroid Build Coastguard Worker   return true;
523*3ac0a46fSAndroid Build Coastguard Worker }
524*3ac0a46fSAndroid Build Coastguard Worker 
UpdateOffset(CFWL_ScrollBar * pScrollBar,float fPosChanged)525*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::UpdateOffset(CFWL_ScrollBar* pScrollBar, float fPosChanged) {
526*3ac0a46fSAndroid Build Coastguard Worker   m_fScrollOffsetY += fPosChanged;
527*3ac0a46fSAndroid Build Coastguard Worker   return true;
528*3ac0a46fSAndroid Build Coastguard Worker }
529*3ac0a46fSAndroid Build Coastguard Worker 
UpdateVAlignment()530*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateVAlignment() {
531*3ac0a46fSAndroid Build Coastguard Worker   IFWL_ThemeProvider* theme = GetThemeProvider();
532*3ac0a46fSAndroid Build Coastguard Worker   CFWL_ThemePart part(CFWL_ThemePart::Part::kNone, this);
533*3ac0a46fSAndroid Build Coastguard Worker   const CFX_SizeF pSpace = theme->GetSpaceAboveBelow(part);
534*3ac0a46fSAndroid Build Coastguard Worker   const float fSpaceAbove = pSpace.width >= 0.1f ? pSpace.width : 0.0f;
535*3ac0a46fSAndroid Build Coastguard Worker   const float fSpaceBelow = pSpace.height >= 0.1f ? pSpace.height : 0.0f;
536*3ac0a46fSAndroid Build Coastguard Worker   float fOffsetY = 0.0f;
537*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
538*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_VCenter) {
539*3ac0a46fSAndroid Build Coastguard Worker     fOffsetY = (m_EngineRect.height - contents_bounds.height) / 2.0f;
540*3ac0a46fSAndroid Build Coastguard Worker     if (fOffsetY < (fSpaceAbove + fSpaceBelow) / 2.0f &&
541*3ac0a46fSAndroid Build Coastguard Worker         fSpaceAbove < fSpaceBelow) {
542*3ac0a46fSAndroid Build Coastguard Worker       return;
543*3ac0a46fSAndroid Build Coastguard Worker     }
544*3ac0a46fSAndroid Build Coastguard Worker     fOffsetY += (fSpaceAbove - fSpaceBelow) / 2.0f;
545*3ac0a46fSAndroid Build Coastguard Worker   } else if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_VFar) {
546*3ac0a46fSAndroid Build Coastguard Worker     fOffsetY = (m_EngineRect.height - contents_bounds.height);
547*3ac0a46fSAndroid Build Coastguard Worker     fOffsetY -= fSpaceBelow;
548*3ac0a46fSAndroid Build Coastguard Worker   } else {
549*3ac0a46fSAndroid Build Coastguard Worker     fOffsetY += fSpaceAbove;
550*3ac0a46fSAndroid Build Coastguard Worker   }
551*3ac0a46fSAndroid Build Coastguard Worker   m_fVAlignOffset = std::max(fOffsetY, 0.0f);
552*3ac0a46fSAndroid Build Coastguard Worker }
553*3ac0a46fSAndroid Build Coastguard Worker 
UpdateCaret()554*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateCaret() {
555*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtCaret = m_CaretRect;
556*3ac0a46fSAndroid Build Coastguard Worker   rtCaret.Offset(m_EngineRect.left - m_fScrollOffsetX,
557*3ac0a46fSAndroid Build Coastguard Worker                  m_EngineRect.top - m_fScrollOffsetY + m_fVAlignOffset);
558*3ac0a46fSAndroid Build Coastguard Worker 
559*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtClient = GetClientRect();
560*3ac0a46fSAndroid Build Coastguard Worker   rtCaret.Intersect(rtClient);
561*3ac0a46fSAndroid Build Coastguard Worker   if (rtCaret.left > rtClient.right()) {
562*3ac0a46fSAndroid Build Coastguard Worker     float right = rtCaret.right();
563*3ac0a46fSAndroid Build Coastguard Worker     rtCaret.left = rtClient.right() - 1;
564*3ac0a46fSAndroid Build Coastguard Worker     rtCaret.width = right - rtCaret.left;
565*3ac0a46fSAndroid Build Coastguard Worker   }
566*3ac0a46fSAndroid Build Coastguard Worker 
567*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused && !rtCaret.IsEmpty())
568*3ac0a46fSAndroid Build Coastguard Worker     ShowCaret(&rtCaret);
569*3ac0a46fSAndroid Build Coastguard Worker   else
570*3ac0a46fSAndroid Build Coastguard Worker     HideCaret(&rtCaret);
571*3ac0a46fSAndroid Build Coastguard Worker }
572*3ac0a46fSAndroid Build Coastguard Worker 
UpdateScroll()573*3ac0a46fSAndroid Build Coastguard Worker CFWL_ScrollBar* CFWL_Edit::UpdateScroll() {
574*3ac0a46fSAndroid Build Coastguard Worker   bool bShowVert = m_pVertScrollBar && m_pVertScrollBar->IsVisible();
575*3ac0a46fSAndroid Build Coastguard Worker   if (!bShowVert)
576*3ac0a46fSAndroid Build Coastguard Worker     return nullptr;
577*3ac0a46fSAndroid Build Coastguard Worker 
578*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF contents_bounds = m_pEditEngine->GetContentsBoundingBox();
579*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rtScroll = m_pVertScrollBar->GetWidgetRect();
580*3ac0a46fSAndroid Build Coastguard Worker   if (rtScroll.height < contents_bounds.height) {
581*3ac0a46fSAndroid Build Coastguard Worker     float fStep = m_pEditEngine->GetLineSpace();
582*3ac0a46fSAndroid Build Coastguard Worker     float fRange =
583*3ac0a46fSAndroid Build Coastguard Worker         std::max(contents_bounds.height - m_EngineRect.height, fStep);
584*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetRange(0.0f, fRange);
585*3ac0a46fSAndroid Build Coastguard Worker     float fPos = std::clamp(m_fScrollOffsetY, 0.0f, fRange);
586*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetPos(fPos);
587*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetTrackPos(fPos);
588*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetPageSize(rtScroll.height);
589*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetStepSize(fStep);
590*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->RemoveStates(FWL_STATE_WGT_Disabled);
591*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->Update();
592*3ac0a46fSAndroid Build Coastguard Worker     return m_pVertScrollBar;
593*3ac0a46fSAndroid Build Coastguard Worker   }
594*3ac0a46fSAndroid Build Coastguard Worker   if ((m_pVertScrollBar->GetStates() & FWL_STATE_WGT_Disabled) == 0) {
595*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetRange(0, -1);
596*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetStates(FWL_STATE_WGT_Disabled);
597*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->Update();
598*3ac0a46fSAndroid Build Coastguard Worker     return m_pVertScrollBar;
599*3ac0a46fSAndroid Build Coastguard Worker   }
600*3ac0a46fSAndroid Build Coastguard Worker   return nullptr;
601*3ac0a46fSAndroid Build Coastguard Worker }
602*3ac0a46fSAndroid Build Coastguard Worker 
IsShowVertScrollBar() const603*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::IsShowVertScrollBar() const {
604*3ac0a46fSAndroid Build Coastguard Worker   const bool bShow =
605*3ac0a46fSAndroid Build Coastguard Worker       !(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_ShowScrollbarFocus) ||
606*3ac0a46fSAndroid Build Coastguard Worker       (m_Properties.m_dwStates & FWL_STATE_WGT_Focused);
607*3ac0a46fSAndroid Build Coastguard Worker   return bShow && (m_Properties.m_dwStyles & FWL_STYLE_WGT_VScroll) &&
608*3ac0a46fSAndroid Build Coastguard Worker          (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_MultiLine) &&
609*3ac0a46fSAndroid Build Coastguard Worker          IsContentHeightOverflow();
610*3ac0a46fSAndroid Build Coastguard Worker }
611*3ac0a46fSAndroid Build Coastguard Worker 
IsContentHeightOverflow() const612*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::IsContentHeightOverflow() const {
613*3ac0a46fSAndroid Build Coastguard Worker   return m_pEditEngine->GetContentsBoundingBox().height >
614*3ac0a46fSAndroid Build Coastguard Worker          m_EngineRect.height + 1.0f;
615*3ac0a46fSAndroid Build Coastguard Worker }
616*3ac0a46fSAndroid Build Coastguard Worker 
Layout()617*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::Layout() {
618*3ac0a46fSAndroid Build Coastguard Worker   m_ClientRect = GetClientRect();
619*3ac0a46fSAndroid Build Coastguard Worker   m_EngineRect = m_ClientRect;
620*3ac0a46fSAndroid Build Coastguard Worker 
621*3ac0a46fSAndroid Build Coastguard Worker   IFWL_ThemeProvider* theme = GetThemeProvider();
622*3ac0a46fSAndroid Build Coastguard Worker   float fWidth = theme->GetScrollBarWidth();
623*3ac0a46fSAndroid Build Coastguard Worker   if (!GetOuter()) {
624*3ac0a46fSAndroid Build Coastguard Worker     CFWL_ThemePart part(CFWL_ThemePart::Part::kNone, this);
625*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF pUIMargin = theme->GetUIMargin(part);
626*3ac0a46fSAndroid Build Coastguard Worker     m_EngineRect.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
627*3ac0a46fSAndroid Build Coastguard Worker                          pUIMargin.height);
628*3ac0a46fSAndroid Build Coastguard Worker   } else if (GetOuter()->GetClassID() == FWL_Type::DateTimePicker) {
629*3ac0a46fSAndroid Build Coastguard Worker     CFWL_ThemePart part(CFWL_ThemePart::Part::kNone, GetOuter());
630*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF pUIMargin = theme->GetUIMargin(part);
631*3ac0a46fSAndroid Build Coastguard Worker     m_EngineRect.Deflate(pUIMargin.left, pUIMargin.top, pUIMargin.width,
632*3ac0a46fSAndroid Build Coastguard Worker                          pUIMargin.height);
633*3ac0a46fSAndroid Build Coastguard Worker   }
634*3ac0a46fSAndroid Build Coastguard Worker 
635*3ac0a46fSAndroid Build Coastguard Worker   bool bShowVertScrollbar = IsShowVertScrollBar();
636*3ac0a46fSAndroid Build Coastguard Worker   if (bShowVertScrollbar) {
637*3ac0a46fSAndroid Build Coastguard Worker     InitVerticalScrollBar();
638*3ac0a46fSAndroid Build Coastguard Worker 
639*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF rtVertScr;
640*3ac0a46fSAndroid Build Coastguard Worker     if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_OuterScrollbar) {
641*3ac0a46fSAndroid Build Coastguard Worker       rtVertScr = CFX_RectF(m_ClientRect.right() + kEditMargin,
642*3ac0a46fSAndroid Build Coastguard Worker                             m_ClientRect.top, fWidth, m_ClientRect.height);
643*3ac0a46fSAndroid Build Coastguard Worker     } else {
644*3ac0a46fSAndroid Build Coastguard Worker       rtVertScr = CFX_RectF(m_ClientRect.right() - fWidth, m_ClientRect.top,
645*3ac0a46fSAndroid Build Coastguard Worker                             fWidth, m_ClientRect.height);
646*3ac0a46fSAndroid Build Coastguard Worker       m_EngineRect.width -= fWidth;
647*3ac0a46fSAndroid Build Coastguard Worker     }
648*3ac0a46fSAndroid Build Coastguard Worker 
649*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetWidgetRect(rtVertScr);
650*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->RemoveStates(FWL_STATE_WGT_Invisible);
651*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->Update();
652*3ac0a46fSAndroid Build Coastguard Worker   } else if (m_pVertScrollBar) {
653*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetStates(FWL_STATE_WGT_Invisible);
654*3ac0a46fSAndroid Build Coastguard Worker   }
655*3ac0a46fSAndroid Build Coastguard Worker }
656*3ac0a46fSAndroid Build Coastguard Worker 
LayoutScrollBar()657*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::LayoutScrollBar() {
658*3ac0a46fSAndroid Build Coastguard Worker   if (!(m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_ShowScrollbarFocus))
659*3ac0a46fSAndroid Build Coastguard Worker     return;
660*3ac0a46fSAndroid Build Coastguard Worker 
661*3ac0a46fSAndroid Build Coastguard Worker   bool bShowVertScrollbar = IsShowVertScrollBar();
662*3ac0a46fSAndroid Build Coastguard Worker   IFWL_ThemeProvider* theme = GetThemeProvider();
663*3ac0a46fSAndroid Build Coastguard Worker   float fWidth = theme->GetScrollBarWidth();
664*3ac0a46fSAndroid Build Coastguard Worker   if (bShowVertScrollbar) {
665*3ac0a46fSAndroid Build Coastguard Worker     if (!m_pVertScrollBar) {
666*3ac0a46fSAndroid Build Coastguard Worker       InitVerticalScrollBar();
667*3ac0a46fSAndroid Build Coastguard Worker       CFX_RectF rtVertScr;
668*3ac0a46fSAndroid Build Coastguard Worker       if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_OuterScrollbar) {
669*3ac0a46fSAndroid Build Coastguard Worker         rtVertScr = CFX_RectF(m_ClientRect.right() + kEditMargin,
670*3ac0a46fSAndroid Build Coastguard Worker                               m_ClientRect.top, fWidth, m_ClientRect.height);
671*3ac0a46fSAndroid Build Coastguard Worker       } else {
672*3ac0a46fSAndroid Build Coastguard Worker         rtVertScr = CFX_RectF(m_ClientRect.right() - fWidth, m_ClientRect.top,
673*3ac0a46fSAndroid Build Coastguard Worker                               fWidth, m_ClientRect.height);
674*3ac0a46fSAndroid Build Coastguard Worker       }
675*3ac0a46fSAndroid Build Coastguard Worker       m_pVertScrollBar->SetWidgetRect(rtVertScr);
676*3ac0a46fSAndroid Build Coastguard Worker       m_pVertScrollBar->Update();
677*3ac0a46fSAndroid Build Coastguard Worker     }
678*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->RemoveStates(FWL_STATE_WGT_Invisible);
679*3ac0a46fSAndroid Build Coastguard Worker   } else if (m_pVertScrollBar) {
680*3ac0a46fSAndroid Build Coastguard Worker     m_pVertScrollBar->SetStates(FWL_STATE_WGT_Invisible);
681*3ac0a46fSAndroid Build Coastguard Worker   }
682*3ac0a46fSAndroid Build Coastguard Worker   if (bShowVertScrollbar)
683*3ac0a46fSAndroid Build Coastguard Worker     UpdateScroll();
684*3ac0a46fSAndroid Build Coastguard Worker }
685*3ac0a46fSAndroid Build Coastguard Worker 
DeviceToEngine(const CFX_PointF & pt)686*3ac0a46fSAndroid Build Coastguard Worker CFX_PointF CFWL_Edit::DeviceToEngine(const CFX_PointF& pt) {
687*3ac0a46fSAndroid Build Coastguard Worker   return pt + CFX_PointF(m_fScrollOffsetX - m_EngineRect.left,
688*3ac0a46fSAndroid Build Coastguard Worker                          m_fScrollOffsetY - m_EngineRect.top - m_fVAlignOffset);
689*3ac0a46fSAndroid Build Coastguard Worker }
690*3ac0a46fSAndroid Build Coastguard Worker 
InitVerticalScrollBar()691*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::InitVerticalScrollBar() {
692*3ac0a46fSAndroid Build Coastguard Worker   if (m_pVertScrollBar)
693*3ac0a46fSAndroid Build Coastguard Worker     return;
694*3ac0a46fSAndroid Build Coastguard Worker 
695*3ac0a46fSAndroid Build Coastguard Worker   m_pVertScrollBar = cppgc::MakeGarbageCollected<CFWL_ScrollBar>(
696*3ac0a46fSAndroid Build Coastguard Worker       GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp(),
697*3ac0a46fSAndroid Build Coastguard Worker       Properties{0, FWL_STYLEEXT_SCB_Vert,
698*3ac0a46fSAndroid Build Coastguard Worker                  FWL_STATE_WGT_Disabled | FWL_STATE_WGT_Invisible},
699*3ac0a46fSAndroid Build Coastguard Worker       this);
700*3ac0a46fSAndroid Build Coastguard Worker }
701*3ac0a46fSAndroid Build Coastguard Worker 
ShowCaret(CFX_RectF * pRect)702*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::ShowCaret(CFX_RectF* pRect) {
703*3ac0a46fSAndroid Build Coastguard Worker   if (m_pCaret) {
704*3ac0a46fSAndroid Build Coastguard Worker     m_pCaret->ShowCaret();
705*3ac0a46fSAndroid Build Coastguard Worker     if (!pRect->IsEmpty())
706*3ac0a46fSAndroid Build Coastguard Worker       m_pCaret->SetWidgetRect(*pRect);
707*3ac0a46fSAndroid Build Coastguard Worker     RepaintRect(m_EngineRect);
708*3ac0a46fSAndroid Build Coastguard Worker     return;
709*3ac0a46fSAndroid Build Coastguard Worker   }
710*3ac0a46fSAndroid Build Coastguard Worker 
711*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget* pOuter = this;
712*3ac0a46fSAndroid Build Coastguard Worker   pRect->Offset(m_WidgetRect.left, m_WidgetRect.top);
713*3ac0a46fSAndroid Build Coastguard Worker   while (pOuter->GetOuter()) {
714*3ac0a46fSAndroid Build Coastguard Worker     pOuter = pOuter->GetOuter();
715*3ac0a46fSAndroid Build Coastguard Worker     CFX_RectF rtOuter = pOuter->GetWidgetRect();
716*3ac0a46fSAndroid Build Coastguard Worker     pRect->Offset(rtOuter.left, rtOuter.top);
717*3ac0a46fSAndroid Build Coastguard Worker   }
718*3ac0a46fSAndroid Build Coastguard Worker 
719*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget::AdapterIface* pXFAWidget = pOuter->GetAdapterIface();
720*3ac0a46fSAndroid Build Coastguard Worker   if (!pXFAWidget)
721*3ac0a46fSAndroid Build Coastguard Worker     return;
722*3ac0a46fSAndroid Build Coastguard Worker 
723*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rt = pXFAWidget->GetRotateMatrix().TransformRect(*pRect);
724*3ac0a46fSAndroid Build Coastguard Worker   pXFAWidget->DisplayCaret(true, &rt);
725*3ac0a46fSAndroid Build Coastguard Worker }
726*3ac0a46fSAndroid Build Coastguard Worker 
HideCaret(CFX_RectF * pRect)727*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::HideCaret(CFX_RectF* pRect) {
728*3ac0a46fSAndroid Build Coastguard Worker   if (m_pCaret) {
729*3ac0a46fSAndroid Build Coastguard Worker     m_pCaret->HideCaret();
730*3ac0a46fSAndroid Build Coastguard Worker     RepaintRect(m_EngineRect);
731*3ac0a46fSAndroid Build Coastguard Worker     return;
732*3ac0a46fSAndroid Build Coastguard Worker   }
733*3ac0a46fSAndroid Build Coastguard Worker 
734*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget* pOuter = this;
735*3ac0a46fSAndroid Build Coastguard Worker   while (pOuter->GetOuter())
736*3ac0a46fSAndroid Build Coastguard Worker     pOuter = pOuter->GetOuter();
737*3ac0a46fSAndroid Build Coastguard Worker 
738*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget::AdapterIface* pXFAWidget = pOuter->GetAdapterIface();
739*3ac0a46fSAndroid Build Coastguard Worker   if (!pXFAWidget)
740*3ac0a46fSAndroid Build Coastguard Worker     return;
741*3ac0a46fSAndroid Build Coastguard Worker 
742*3ac0a46fSAndroid Build Coastguard Worker   pXFAWidget->DisplayCaret(false, pRect);
743*3ac0a46fSAndroid Build Coastguard Worker }
744*3ac0a46fSAndroid Build Coastguard Worker 
InitCaret()745*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::InitCaret() {
746*3ac0a46fSAndroid Build Coastguard Worker   if (m_pCaret)
747*3ac0a46fSAndroid Build Coastguard Worker     return;
748*3ac0a46fSAndroid Build Coastguard Worker 
749*3ac0a46fSAndroid Build Coastguard Worker   m_pCaret = cppgc::MakeGarbageCollected<CFWL_Caret>(
750*3ac0a46fSAndroid Build Coastguard Worker       GetFWLApp()->GetHeap()->GetAllocationHandle(), GetFWLApp(), Properties(),
751*3ac0a46fSAndroid Build Coastguard Worker       this);
752*3ac0a46fSAndroid Build Coastguard Worker   m_pCaret->SetStates(m_Properties.m_dwStates);
753*3ac0a46fSAndroid Build Coastguard Worker   UpdateCursorRect();
754*3ac0a46fSAndroid Build Coastguard Worker }
755*3ac0a46fSAndroid Build Coastguard Worker 
UpdateCursorRect()756*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::UpdateCursorRect() {
757*3ac0a46fSAndroid Build Coastguard Worker   int32_t bidi_level;
758*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->CanGenerateCharacterInfo()) {
759*3ac0a46fSAndroid Build Coastguard Worker     std::tie(bidi_level, m_CaretRect) = m_pEditEngine->GetCharacterInfo(
760*3ac0a46fSAndroid Build Coastguard Worker         pdfium::base::checked_cast<int32_t>(m_CursorPosition));
761*3ac0a46fSAndroid Build Coastguard Worker   } else {
762*3ac0a46fSAndroid Build Coastguard Worker     bidi_level = 0;
763*3ac0a46fSAndroid Build Coastguard Worker     m_CaretRect = CFX_RectF();
764*3ac0a46fSAndroid Build Coastguard Worker   }
765*3ac0a46fSAndroid Build Coastguard Worker 
766*3ac0a46fSAndroid Build Coastguard Worker   // TODO(dsinclair): This should handle bidi level  ...
767*3ac0a46fSAndroid Build Coastguard Worker 
768*3ac0a46fSAndroid Build Coastguard Worker   m_CaretRect.width = 1.0f;
769*3ac0a46fSAndroid Build Coastguard Worker 
770*3ac0a46fSAndroid Build Coastguard Worker   // TODO(hnakashima): Handle correctly edits with empty text instead of using
771*3ac0a46fSAndroid Build Coastguard Worker   // these defaults.
772*3ac0a46fSAndroid Build Coastguard Worker   if (m_CaretRect.height == 0)
773*3ac0a46fSAndroid Build Coastguard Worker     m_CaretRect.height = 8.0f;
774*3ac0a46fSAndroid Build Coastguard Worker }
775*3ac0a46fSAndroid Build Coastguard Worker 
SetCursorPosition(size_t position)776*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::SetCursorPosition(size_t position) {
777*3ac0a46fSAndroid Build Coastguard Worker   if (m_CursorPosition == position)
778*3ac0a46fSAndroid Build Coastguard Worker     return;
779*3ac0a46fSAndroid Build Coastguard Worker 
780*3ac0a46fSAndroid Build Coastguard Worker   m_CursorPosition = std::min(position, m_pEditEngine->GetLength());
781*3ac0a46fSAndroid Build Coastguard Worker   UpdateCursorRect();
782*3ac0a46fSAndroid Build Coastguard Worker   OnCaretChanged();
783*3ac0a46fSAndroid Build Coastguard Worker }
784*3ac0a46fSAndroid Build Coastguard Worker 
OnProcessMessage(CFWL_Message * pMessage)785*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnProcessMessage(CFWL_Message* pMessage) {
786*3ac0a46fSAndroid Build Coastguard Worker   switch (pMessage->GetType()) {
787*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_Message::Type::kSetFocus:
788*3ac0a46fSAndroid Build Coastguard Worker       OnFocusGained();
789*3ac0a46fSAndroid Build Coastguard Worker       break;
790*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_Message::Type::kKillFocus:
791*3ac0a46fSAndroid Build Coastguard Worker       OnFocusLost();
792*3ac0a46fSAndroid Build Coastguard Worker       break;
793*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_Message::Type::kMouse: {
794*3ac0a46fSAndroid Build Coastguard Worker       CFWL_MessageMouse* pMsg = static_cast<CFWL_MessageMouse*>(pMessage);
795*3ac0a46fSAndroid Build Coastguard Worker       switch (pMsg->m_dwCmd) {
796*3ac0a46fSAndroid Build Coastguard Worker         case CFWL_MessageMouse::MouseCommand::kLeftButtonDown:
797*3ac0a46fSAndroid Build Coastguard Worker           OnLButtonDown(pMsg);
798*3ac0a46fSAndroid Build Coastguard Worker           break;
799*3ac0a46fSAndroid Build Coastguard Worker         case CFWL_MessageMouse::MouseCommand::kLeftButtonUp:
800*3ac0a46fSAndroid Build Coastguard Worker           OnLButtonUp(pMsg);
801*3ac0a46fSAndroid Build Coastguard Worker           break;
802*3ac0a46fSAndroid Build Coastguard Worker         case CFWL_MessageMouse::MouseCommand::kLeftButtonDblClk:
803*3ac0a46fSAndroid Build Coastguard Worker           OnButtonDoubleClick(pMsg);
804*3ac0a46fSAndroid Build Coastguard Worker           break;
805*3ac0a46fSAndroid Build Coastguard Worker         case CFWL_MessageMouse::MouseCommand::kMove:
806*3ac0a46fSAndroid Build Coastguard Worker           OnMouseMove(pMsg);
807*3ac0a46fSAndroid Build Coastguard Worker           break;
808*3ac0a46fSAndroid Build Coastguard Worker         case CFWL_MessageMouse::MouseCommand::kRightButtonDown:
809*3ac0a46fSAndroid Build Coastguard Worker           DoRButtonDown(pMsg);
810*3ac0a46fSAndroid Build Coastguard Worker           break;
811*3ac0a46fSAndroid Build Coastguard Worker         default:
812*3ac0a46fSAndroid Build Coastguard Worker           break;
813*3ac0a46fSAndroid Build Coastguard Worker       }
814*3ac0a46fSAndroid Build Coastguard Worker       break;
815*3ac0a46fSAndroid Build Coastguard Worker     }
816*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_Message::Type::kKey: {
817*3ac0a46fSAndroid Build Coastguard Worker       CFWL_MessageKey* pKey = static_cast<CFWL_MessageKey*>(pMessage);
818*3ac0a46fSAndroid Build Coastguard Worker       if (pKey->m_dwCmd == CFWL_MessageKey::KeyCommand::kKeyDown)
819*3ac0a46fSAndroid Build Coastguard Worker         OnKeyDown(pKey);
820*3ac0a46fSAndroid Build Coastguard Worker       else if (pKey->m_dwCmd == CFWL_MessageKey::KeyCommand::kChar)
821*3ac0a46fSAndroid Build Coastguard Worker         OnChar(pKey);
822*3ac0a46fSAndroid Build Coastguard Worker       break;
823*3ac0a46fSAndroid Build Coastguard Worker     }
824*3ac0a46fSAndroid Build Coastguard Worker     default:
825*3ac0a46fSAndroid Build Coastguard Worker       break;
826*3ac0a46fSAndroid Build Coastguard Worker   }
827*3ac0a46fSAndroid Build Coastguard Worker   // Dst target could be |this|, continue only if not destroyed by above.
828*3ac0a46fSAndroid Build Coastguard Worker   if (pMessage->GetDstTarget())
829*3ac0a46fSAndroid Build Coastguard Worker     CFWL_Widget::OnProcessMessage(pMessage);
830*3ac0a46fSAndroid Build Coastguard Worker }
831*3ac0a46fSAndroid Build Coastguard Worker 
OnProcessEvent(CFWL_Event * pEvent)832*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnProcessEvent(CFWL_Event* pEvent) {
833*3ac0a46fSAndroid Build Coastguard Worker   if (!pEvent || pEvent->GetType() != CFWL_Event::Type::Scroll)
834*3ac0a46fSAndroid Build Coastguard Worker     return;
835*3ac0a46fSAndroid Build Coastguard Worker 
836*3ac0a46fSAndroid Build Coastguard Worker   CFWL_Widget* pSrcTarget = pEvent->GetSrcTarget();
837*3ac0a46fSAndroid Build Coastguard Worker   if ((pSrcTarget == m_pVertScrollBar && m_pVertScrollBar)) {
838*3ac0a46fSAndroid Build Coastguard Worker     CFWL_EventScroll* pScrollEvent = static_cast<CFWL_EventScroll*>(pEvent);
839*3ac0a46fSAndroid Build Coastguard Worker     OnScroll(static_cast<CFWL_ScrollBar*>(pSrcTarget),
840*3ac0a46fSAndroid Build Coastguard Worker              pScrollEvent->GetScrollCode(), pScrollEvent->GetPos());
841*3ac0a46fSAndroid Build Coastguard Worker   }
842*3ac0a46fSAndroid Build Coastguard Worker }
843*3ac0a46fSAndroid Build Coastguard Worker 
OnDrawWidget(CFGAS_GEGraphics * pGraphics,const CFX_Matrix & matrix)844*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnDrawWidget(CFGAS_GEGraphics* pGraphics,
845*3ac0a46fSAndroid Build Coastguard Worker                              const CFX_Matrix& matrix) {
846*3ac0a46fSAndroid Build Coastguard Worker   DrawWidget(pGraphics, matrix);
847*3ac0a46fSAndroid Build Coastguard Worker }
848*3ac0a46fSAndroid Build Coastguard Worker 
DoRButtonDown(CFWL_MessageMouse * pMsg)849*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::DoRButtonDown(CFWL_MessageMouse* pMsg) {
850*3ac0a46fSAndroid Build Coastguard Worker   SetCursorPosition(
851*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
852*3ac0a46fSAndroid Build Coastguard Worker }
853*3ac0a46fSAndroid Build Coastguard Worker 
OnFocusGained()854*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnFocusGained() {
855*3ac0a46fSAndroid Build Coastguard Worker   m_Properties.m_dwStates |= FWL_STATE_WGT_Focused;
856*3ac0a46fSAndroid Build Coastguard Worker   UpdateVAlignment();
857*3ac0a46fSAndroid Build Coastguard Worker   UpdateOffset();
858*3ac0a46fSAndroid Build Coastguard Worker   UpdateCaret();
859*3ac0a46fSAndroid Build Coastguard Worker   LayoutScrollBar();
860*3ac0a46fSAndroid Build Coastguard Worker }
861*3ac0a46fSAndroid Build Coastguard Worker 
OnFocusLost()862*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnFocusLost() {
863*3ac0a46fSAndroid Build Coastguard Worker   bool bRepaint = false;
864*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStates & FWL_STATE_WGT_Focused) {
865*3ac0a46fSAndroid Build Coastguard Worker     m_Properties.m_dwStates &= ~FWL_STATE_WGT_Focused;
866*3ac0a46fSAndroid Build Coastguard Worker     HideCaret(nullptr);
867*3ac0a46fSAndroid Build Coastguard Worker     if (HasSelection()) {
868*3ac0a46fSAndroid Build Coastguard Worker       ClearSelection();
869*3ac0a46fSAndroid Build Coastguard Worker       bRepaint = true;
870*3ac0a46fSAndroid Build Coastguard Worker     }
871*3ac0a46fSAndroid Build Coastguard Worker     UpdateOffset();
872*3ac0a46fSAndroid Build Coastguard Worker   }
873*3ac0a46fSAndroid Build Coastguard Worker   LayoutScrollBar();
874*3ac0a46fSAndroid Build Coastguard Worker   if (!bRepaint)
875*3ac0a46fSAndroid Build Coastguard Worker     return;
876*3ac0a46fSAndroid Build Coastguard Worker 
877*3ac0a46fSAndroid Build Coastguard Worker   RepaintRect(CFX_RectF(0, 0, m_WidgetRect.width, m_WidgetRect.height));
878*3ac0a46fSAndroid Build Coastguard Worker }
879*3ac0a46fSAndroid Build Coastguard Worker 
OnLButtonDown(CFWL_MessageMouse * pMsg)880*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnLButtonDown(CFWL_MessageMouse* pMsg) {
881*3ac0a46fSAndroid Build Coastguard Worker   if (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)
882*3ac0a46fSAndroid Build Coastguard Worker     return;
883*3ac0a46fSAndroid Build Coastguard Worker 
884*3ac0a46fSAndroid Build Coastguard Worker   m_bLButtonDown = true;
885*3ac0a46fSAndroid Build Coastguard Worker   SetGrab(true);
886*3ac0a46fSAndroid Build Coastguard Worker 
887*3ac0a46fSAndroid Build Coastguard Worker   bool bRepaint = false;
888*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->HasSelection()) {
889*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->ClearSelection();
890*3ac0a46fSAndroid Build Coastguard Worker     bRepaint = true;
891*3ac0a46fSAndroid Build Coastguard Worker   }
892*3ac0a46fSAndroid Build Coastguard Worker 
893*3ac0a46fSAndroid Build Coastguard Worker   size_t index_at_click =
894*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
895*3ac0a46fSAndroid Build Coastguard Worker 
896*3ac0a46fSAndroid Build Coastguard Worker   if (index_at_click != m_CursorPosition &&
897*3ac0a46fSAndroid Build Coastguard Worker       !!(pMsg->m_dwFlags & XFA_FWL_KeyFlag::kShift)) {
898*3ac0a46fSAndroid Build Coastguard Worker     size_t start = std::min(m_CursorPosition, index_at_click);
899*3ac0a46fSAndroid Build Coastguard Worker     size_t end = std::max(m_CursorPosition, index_at_click);
900*3ac0a46fSAndroid Build Coastguard Worker 
901*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->SetSelection(start, end - start);
902*3ac0a46fSAndroid Build Coastguard Worker     bRepaint = true;
903*3ac0a46fSAndroid Build Coastguard Worker   } else {
904*3ac0a46fSAndroid Build Coastguard Worker     SetCursorPosition(index_at_click);
905*3ac0a46fSAndroid Build Coastguard Worker   }
906*3ac0a46fSAndroid Build Coastguard Worker 
907*3ac0a46fSAndroid Build Coastguard Worker   if (bRepaint)
908*3ac0a46fSAndroid Build Coastguard Worker     RepaintRect(m_EngineRect);
909*3ac0a46fSAndroid Build Coastguard Worker }
910*3ac0a46fSAndroid Build Coastguard Worker 
OnLButtonUp(CFWL_MessageMouse * pMsg)911*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnLButtonUp(CFWL_MessageMouse* pMsg) {
912*3ac0a46fSAndroid Build Coastguard Worker   m_bLButtonDown = false;
913*3ac0a46fSAndroid Build Coastguard Worker   SetGrab(false);
914*3ac0a46fSAndroid Build Coastguard Worker }
915*3ac0a46fSAndroid Build Coastguard Worker 
OnButtonDoubleClick(CFWL_MessageMouse * pMsg)916*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnButtonDoubleClick(CFWL_MessageMouse* pMsg) {
917*3ac0a46fSAndroid Build Coastguard Worker   size_t click_idx =
918*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos));
919*3ac0a46fSAndroid Build Coastguard Worker   size_t start_idx;
920*3ac0a46fSAndroid Build Coastguard Worker   size_t count;
921*3ac0a46fSAndroid Build Coastguard Worker   std::tie(start_idx, count) = m_pEditEngine->BoundsForWordAt(click_idx);
922*3ac0a46fSAndroid Build Coastguard Worker 
923*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetSelection(start_idx, count);
924*3ac0a46fSAndroid Build Coastguard Worker   m_CursorPosition = start_idx + count;
925*3ac0a46fSAndroid Build Coastguard Worker   RepaintRect(m_EngineRect);
926*3ac0a46fSAndroid Build Coastguard Worker }
927*3ac0a46fSAndroid Build Coastguard Worker 
OnMouseMove(CFWL_MessageMouse * pMsg)928*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnMouseMove(CFWL_MessageMouse* pMsg) {
929*3ac0a46fSAndroid Build Coastguard Worker   bool shift = !!(pMsg->m_dwFlags & XFA_FWL_KeyFlag::kShift);
930*3ac0a46fSAndroid Build Coastguard Worker   if (!m_bLButtonDown || !shift)
931*3ac0a46fSAndroid Build Coastguard Worker     return;
932*3ac0a46fSAndroid Build Coastguard Worker 
933*3ac0a46fSAndroid Build Coastguard Worker   size_t old_cursor_pos = m_CursorPosition;
934*3ac0a46fSAndroid Build Coastguard Worker   SetCursorPosition(
935*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->GetIndexForPoint(DeviceToEngine(pMsg->m_pos)));
936*3ac0a46fSAndroid Build Coastguard Worker   if (old_cursor_pos == m_CursorPosition)
937*3ac0a46fSAndroid Build Coastguard Worker     return;
938*3ac0a46fSAndroid Build Coastguard Worker 
939*3ac0a46fSAndroid Build Coastguard Worker   size_t length = m_pEditEngine->GetLength();
940*3ac0a46fSAndroid Build Coastguard Worker   if (m_CursorPosition > length)
941*3ac0a46fSAndroid Build Coastguard Worker     SetCursorPosition(length);
942*3ac0a46fSAndroid Build Coastguard Worker 
943*3ac0a46fSAndroid Build Coastguard Worker   size_t sel_start = 0;
944*3ac0a46fSAndroid Build Coastguard Worker   size_t count = 0;
945*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->HasSelection())
946*3ac0a46fSAndroid Build Coastguard Worker     std::tie(sel_start, count) = m_pEditEngine->GetSelection();
947*3ac0a46fSAndroid Build Coastguard Worker   else
948*3ac0a46fSAndroid Build Coastguard Worker     sel_start = old_cursor_pos;
949*3ac0a46fSAndroid Build Coastguard Worker 
950*3ac0a46fSAndroid Build Coastguard Worker   size_t start_pos = std::min(sel_start, m_CursorPosition);
951*3ac0a46fSAndroid Build Coastguard Worker   size_t end_pos = std::max(sel_start, m_CursorPosition);
952*3ac0a46fSAndroid Build Coastguard Worker   m_pEditEngine->SetSelection(start_pos, end_pos - start_pos);
953*3ac0a46fSAndroid Build Coastguard Worker }
954*3ac0a46fSAndroid Build Coastguard Worker 
OnKeyDown(CFWL_MessageKey * pMsg)955*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnKeyDown(CFWL_MessageKey* pMsg) {
956*3ac0a46fSAndroid Build Coastguard Worker   bool bShift = !!(pMsg->m_dwFlags & XFA_FWL_KeyFlag::kShift);
957*3ac0a46fSAndroid Build Coastguard Worker   bool bCtrl = !!(pMsg->m_dwFlags & XFA_FWL_KeyFlag::kCtrl);
958*3ac0a46fSAndroid Build Coastguard Worker 
959*3ac0a46fSAndroid Build Coastguard Worker   size_t sel_start = m_CursorPosition;
960*3ac0a46fSAndroid Build Coastguard Worker   if (m_pEditEngine->HasSelection()) {
961*3ac0a46fSAndroid Build Coastguard Worker     size_t start_idx;
962*3ac0a46fSAndroid Build Coastguard Worker     size_t count;
963*3ac0a46fSAndroid Build Coastguard Worker     std::tie(start_idx, count) = m_pEditEngine->GetSelection();
964*3ac0a46fSAndroid Build Coastguard Worker     sel_start = start_idx;
965*3ac0a46fSAndroid Build Coastguard Worker   }
966*3ac0a46fSAndroid Build Coastguard Worker 
967*3ac0a46fSAndroid Build Coastguard Worker   switch (pMsg->m_dwKeyCodeOrChar) {
968*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Left:
969*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_pEditEngine->GetIndexLeft(m_CursorPosition));
970*3ac0a46fSAndroid Build Coastguard Worker       break;
971*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Right:
972*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_pEditEngine->GetIndexRight(m_CursorPosition));
973*3ac0a46fSAndroid Build Coastguard Worker       break;
974*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Up:
975*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_pEditEngine->GetIndexUp(m_CursorPosition));
976*3ac0a46fSAndroid Build Coastguard Worker       break;
977*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Down:
978*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_pEditEngine->GetIndexDown(m_CursorPosition));
979*3ac0a46fSAndroid Build Coastguard Worker       break;
980*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Home:
981*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(
982*3ac0a46fSAndroid Build Coastguard Worker           bCtrl ? 0 : m_pEditEngine->GetIndexAtStartOfLine(m_CursorPosition));
983*3ac0a46fSAndroid Build Coastguard Worker       break;
984*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_End:
985*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(
986*3ac0a46fSAndroid Build Coastguard Worker           bCtrl ? m_pEditEngine->GetLength()
987*3ac0a46fSAndroid Build Coastguard Worker                 : m_pEditEngine->GetIndexAtEndOfLine(m_CursorPosition));
988*3ac0a46fSAndroid Build Coastguard Worker       break;
989*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Delete: {
990*3ac0a46fSAndroid Build Coastguard Worker       if ((m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_ReadOnly) ||
991*3ac0a46fSAndroid Build Coastguard Worker           (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)) {
992*3ac0a46fSAndroid Build Coastguard Worker         break;
993*3ac0a46fSAndroid Build Coastguard Worker       }
994*3ac0a46fSAndroid Build Coastguard Worker 
995*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->Delete(m_CursorPosition, 1);
996*3ac0a46fSAndroid Build Coastguard Worker       UpdateCaret();
997*3ac0a46fSAndroid Build Coastguard Worker       break;
998*3ac0a46fSAndroid Build Coastguard Worker     }
999*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Insert:
1000*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_F2:
1001*3ac0a46fSAndroid Build Coastguard Worker     case XFA_FWL_VKEY_Tab:
1002*3ac0a46fSAndroid Build Coastguard Worker     default:
1003*3ac0a46fSAndroid Build Coastguard Worker       break;
1004*3ac0a46fSAndroid Build Coastguard Worker   }
1005*3ac0a46fSAndroid Build Coastguard Worker 
1006*3ac0a46fSAndroid Build Coastguard Worker   // Update the selection.
1007*3ac0a46fSAndroid Build Coastguard Worker   if (bShift && sel_start != m_CursorPosition) {
1008*3ac0a46fSAndroid Build Coastguard Worker     m_pEditEngine->SetSelection(std::min(sel_start, m_CursorPosition),
1009*3ac0a46fSAndroid Build Coastguard Worker                                 std::max(sel_start, m_CursorPosition));
1010*3ac0a46fSAndroid Build Coastguard Worker     RepaintRect(m_EngineRect);
1011*3ac0a46fSAndroid Build Coastguard Worker   }
1012*3ac0a46fSAndroid Build Coastguard Worker }
1013*3ac0a46fSAndroid Build Coastguard Worker 
OnChar(CFWL_MessageKey * pMsg)1014*3ac0a46fSAndroid Build Coastguard Worker void CFWL_Edit::OnChar(CFWL_MessageKey* pMsg) {
1015*3ac0a46fSAndroid Build Coastguard Worker   if ((m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_ReadOnly) ||
1016*3ac0a46fSAndroid Build Coastguard Worker       (m_Properties.m_dwStates & FWL_STATE_WGT_Disabled)) {
1017*3ac0a46fSAndroid Build Coastguard Worker     return;
1018*3ac0a46fSAndroid Build Coastguard Worker   }
1019*3ac0a46fSAndroid Build Coastguard Worker 
1020*3ac0a46fSAndroid Build Coastguard Worker   wchar_t c = static_cast<wchar_t>(pMsg->m_dwKeyCodeOrChar);
1021*3ac0a46fSAndroid Build Coastguard Worker   switch (c) {
1022*3ac0a46fSAndroid Build Coastguard Worker     case L'\b':
1023*3ac0a46fSAndroid Build Coastguard Worker       if (m_CursorPosition > 0) {
1024*3ac0a46fSAndroid Build Coastguard Worker         SetCursorPosition(m_CursorPosition - 1);
1025*3ac0a46fSAndroid Build Coastguard Worker         m_pEditEngine->Delete(m_CursorPosition, 1);
1026*3ac0a46fSAndroid Build Coastguard Worker         UpdateCaret();
1027*3ac0a46fSAndroid Build Coastguard Worker       }
1028*3ac0a46fSAndroid Build Coastguard Worker       break;
1029*3ac0a46fSAndroid Build Coastguard Worker     case L'\n':
1030*3ac0a46fSAndroid Build Coastguard Worker     case 27:   // Esc
1031*3ac0a46fSAndroid Build Coastguard Worker     case 127:  // Delete
1032*3ac0a46fSAndroid Build Coastguard Worker       break;
1033*3ac0a46fSAndroid Build Coastguard Worker     case L'\t':
1034*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->Insert(m_CursorPosition, L"\t");
1035*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_CursorPosition + 1);
1036*3ac0a46fSAndroid Build Coastguard Worker       break;
1037*3ac0a46fSAndroid Build Coastguard Worker     case L'\r':
1038*3ac0a46fSAndroid Build Coastguard Worker       if (m_Properties.m_dwStyleExts & FWL_STYLEEXT_EDT_WantReturn) {
1039*3ac0a46fSAndroid Build Coastguard Worker         m_pEditEngine->Insert(m_CursorPosition, L"\n");
1040*3ac0a46fSAndroid Build Coastguard Worker         SetCursorPosition(m_CursorPosition + 1);
1041*3ac0a46fSAndroid Build Coastguard Worker       }
1042*3ac0a46fSAndroid Build Coastguard Worker       break;
1043*3ac0a46fSAndroid Build Coastguard Worker     default: {
1044*3ac0a46fSAndroid Build Coastguard Worker       if (pMsg->m_dwFlags & kEditingModifier)
1045*3ac0a46fSAndroid Build Coastguard Worker         break;
1046*3ac0a46fSAndroid Build Coastguard Worker 
1047*3ac0a46fSAndroid Build Coastguard Worker       m_pEditEngine->Insert(m_CursorPosition, WideString(c));
1048*3ac0a46fSAndroid Build Coastguard Worker       SetCursorPosition(m_CursorPosition + 1);
1049*3ac0a46fSAndroid Build Coastguard Worker       break;
1050*3ac0a46fSAndroid Build Coastguard Worker     }
1051*3ac0a46fSAndroid Build Coastguard Worker   }
1052*3ac0a46fSAndroid Build Coastguard Worker }
1053*3ac0a46fSAndroid Build Coastguard Worker 
OnScroll(CFWL_ScrollBar * pScrollBar,CFWL_EventScroll::Code dwCode,float fPos)1054*3ac0a46fSAndroid Build Coastguard Worker bool CFWL_Edit::OnScroll(CFWL_ScrollBar* pScrollBar,
1055*3ac0a46fSAndroid Build Coastguard Worker                          CFWL_EventScroll::Code dwCode,
1056*3ac0a46fSAndroid Build Coastguard Worker                          float fPos) {
1057*3ac0a46fSAndroid Build Coastguard Worker   float fMin;
1058*3ac0a46fSAndroid Build Coastguard Worker   float fMax;
1059*3ac0a46fSAndroid Build Coastguard Worker   pScrollBar->GetRange(&fMin, &fMax);
1060*3ac0a46fSAndroid Build Coastguard Worker   float iCurPos = pScrollBar->GetPos();
1061*3ac0a46fSAndroid Build Coastguard Worker   float fStep = pScrollBar->GetStepSize();
1062*3ac0a46fSAndroid Build Coastguard Worker   switch (dwCode) {
1063*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::Min: {
1064*3ac0a46fSAndroid Build Coastguard Worker       fPos = fMin;
1065*3ac0a46fSAndroid Build Coastguard Worker       break;
1066*3ac0a46fSAndroid Build Coastguard Worker     }
1067*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::Max: {
1068*3ac0a46fSAndroid Build Coastguard Worker       fPos = fMax;
1069*3ac0a46fSAndroid Build Coastguard Worker       break;
1070*3ac0a46fSAndroid Build Coastguard Worker     }
1071*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::StepBackward: {
1072*3ac0a46fSAndroid Build Coastguard Worker       fPos -= fStep;
1073*3ac0a46fSAndroid Build Coastguard Worker       if (fPos < fMin + fStep / 2) {
1074*3ac0a46fSAndroid Build Coastguard Worker         fPos = fMin;
1075*3ac0a46fSAndroid Build Coastguard Worker       }
1076*3ac0a46fSAndroid Build Coastguard Worker       break;
1077*3ac0a46fSAndroid Build Coastguard Worker     }
1078*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::StepForward: {
1079*3ac0a46fSAndroid Build Coastguard Worker       fPos += fStep;
1080*3ac0a46fSAndroid Build Coastguard Worker       if (fPos > fMax - fStep / 2) {
1081*3ac0a46fSAndroid Build Coastguard Worker         fPos = fMax;
1082*3ac0a46fSAndroid Build Coastguard Worker       }
1083*3ac0a46fSAndroid Build Coastguard Worker       break;
1084*3ac0a46fSAndroid Build Coastguard Worker     }
1085*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::PageBackward: {
1086*3ac0a46fSAndroid Build Coastguard Worker       fPos -= pScrollBar->GetPageSize();
1087*3ac0a46fSAndroid Build Coastguard Worker       if (fPos < fMin) {
1088*3ac0a46fSAndroid Build Coastguard Worker         fPos = fMin;
1089*3ac0a46fSAndroid Build Coastguard Worker       }
1090*3ac0a46fSAndroid Build Coastguard Worker       break;
1091*3ac0a46fSAndroid Build Coastguard Worker     }
1092*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::PageForward: {
1093*3ac0a46fSAndroid Build Coastguard Worker       fPos += pScrollBar->GetPageSize();
1094*3ac0a46fSAndroid Build Coastguard Worker       if (fPos > fMax) {
1095*3ac0a46fSAndroid Build Coastguard Worker         fPos = fMax;
1096*3ac0a46fSAndroid Build Coastguard Worker       }
1097*3ac0a46fSAndroid Build Coastguard Worker       break;
1098*3ac0a46fSAndroid Build Coastguard Worker     }
1099*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::Pos:
1100*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::TrackPos:
1101*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::None:
1102*3ac0a46fSAndroid Build Coastguard Worker       break;
1103*3ac0a46fSAndroid Build Coastguard Worker     case CFWL_EventScroll::Code::EndScroll:
1104*3ac0a46fSAndroid Build Coastguard Worker       return false;
1105*3ac0a46fSAndroid Build Coastguard Worker   }
1106*3ac0a46fSAndroid Build Coastguard Worker   if (iCurPos == fPos)
1107*3ac0a46fSAndroid Build Coastguard Worker     return true;
1108*3ac0a46fSAndroid Build Coastguard Worker 
1109*3ac0a46fSAndroid Build Coastguard Worker   pScrollBar->SetPos(fPos);
1110*3ac0a46fSAndroid Build Coastguard Worker   pScrollBar->SetTrackPos(fPos);
1111*3ac0a46fSAndroid Build Coastguard Worker   UpdateOffset(pScrollBar, fPos - iCurPos);
1112*3ac0a46fSAndroid Build Coastguard Worker   UpdateCaret();
1113*3ac0a46fSAndroid Build Coastguard Worker 
1114*3ac0a46fSAndroid Build Coastguard Worker   CFX_RectF rect = GetWidgetRect();
1115*3ac0a46fSAndroid Build Coastguard Worker   RepaintRect(CFX_RectF(0, 0, rect.width + 2, rect.height + 2));
1116*3ac0a46fSAndroid Build Coastguard Worker   return true;
1117*3ac0a46fSAndroid Build Coastguard Worker }
1118