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 "fpdfsdk/pwl/cpwl_edit_ctrl.h"
8
9 #include <utility>
10
11 #include "core/fpdfdoc/cpvt_word.h"
12 #include "core/fxge/fx_font.h"
13 #include "fpdfsdk/pwl/cpwl_caret.h"
14 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
15 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
16 #include "fpdfsdk/pwl/cpwl_wnd.h"
17 #include "public/fpdf_fwlevent.h"
18
CPWL_EditCtrl(const CreateParams & cp,std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)19 CPWL_EditCtrl::CPWL_EditCtrl(
20 const CreateParams& cp,
21 std::unique_ptr<IPWL_SystemHandler::PerWindowData> pAttachedData)
22 : CPWL_Wnd(cp, std::move(pAttachedData)),
23 m_pEdit(std::make_unique<CPWL_EditImpl>()) {
24 GetCreationParams()->eCursorType = FXCT_VBEAM;
25 }
26
27 CPWL_EditCtrl::~CPWL_EditCtrl() = default;
28
OnCreated()29 void CPWL_EditCtrl::OnCreated() {
30 SetFontSize(GetCreationParams()->fFontSize);
31 m_pEdit->SetFontMap(GetFontMap());
32 m_pEdit->SetNotify(this);
33 m_pEdit->Initialize();
34 }
35
IsWndHorV() const36 bool CPWL_EditCtrl::IsWndHorV() const {
37 CFX_Matrix mt = GetWindowMatrix();
38 return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
39 }
40
SetCursor()41 void CPWL_EditCtrl::SetCursor() {
42 if (IsValid())
43 GetSystemHandler()->SetCursor(IsWndHorV() ? FXCT_VBEAM : FXCT_HBEAM);
44 }
45
GetSelectedText()46 WideString CPWL_EditCtrl::GetSelectedText() {
47 return m_pEdit->GetSelectedText();
48 }
49
ReplaceSelection(const WideString & text)50 void CPWL_EditCtrl::ReplaceSelection(const WideString& text) {
51 m_pEdit->ReplaceSelection(text);
52 }
53
SelectAllText()54 bool CPWL_EditCtrl::SelectAllText() {
55 m_pEdit->SelectAll();
56 return true;
57 }
58
RePosChildWnd()59 bool CPWL_EditCtrl::RePosChildWnd() {
60 m_pEdit->SetPlateRect(GetClientRect());
61 return true;
62 }
63
SetScrollInfo(const PWL_SCROLL_INFO & info)64 void CPWL_EditCtrl::SetScrollInfo(const PWL_SCROLL_INFO& info) {
65 if (CPWL_Wnd* pChild = GetVScrollBar())
66 pChild->SetScrollInfo(info);
67 }
68
SetScrollPosition(float pos)69 void CPWL_EditCtrl::SetScrollPosition(float pos) {
70 if (CPWL_Wnd* pChild = GetVScrollBar())
71 pChild->SetScrollPosition(pos);
72 }
73
ScrollWindowVertically(float pos)74 void CPWL_EditCtrl::ScrollWindowVertically(float pos) {
75 m_pEdit->SetScrollPos(CFX_PointF(m_pEdit->GetScrollPos().x, pos));
76 }
77
CreateChildWnd(const CreateParams & cp)78 void CPWL_EditCtrl::CreateChildWnd(const CreateParams& cp) {
79 if (!IsReadOnly())
80 CreateEditCaret(cp);
81 }
82
CreateEditCaret(const CreateParams & cp)83 void CPWL_EditCtrl::CreateEditCaret(const CreateParams& cp) {
84 if (m_pEditCaret)
85 return;
86
87 CreateParams ecp = cp;
88 ecp.dwFlags = PWS_CHILD | PWS_NOREFRESHCLIP;
89 ecp.dwBorderWidth = 0;
90 ecp.nBorderStyle = BorderStyle::kSolid;
91 ecp.rcRectWnd = CFX_FloatRect();
92
93 auto pCaret = std::make_unique<CPWL_Caret>(ecp, CloneAttachedData());
94 m_pEditCaret = pCaret.get();
95 m_pEditCaret->SetInvalidRect(GetClientRect());
96 AddChild(std::move(pCaret));
97 m_pEditCaret->Realize();
98 }
99
SetFontSize(float fFontSize)100 void CPWL_EditCtrl::SetFontSize(float fFontSize) {
101 m_pEdit->SetFontSize(fFontSize);
102 }
103
GetFontSize() const104 float CPWL_EditCtrl::GetFontSize() const {
105 return m_pEdit->GetFontSize();
106 }
107
OnKeyDown(uint16_t nChar,uint32_t nFlag)108 bool CPWL_EditCtrl::OnKeyDown(uint16_t nChar, uint32_t nFlag) {
109 if (m_bMouseDown)
110 return true;
111
112 bool bRet = CPWL_Wnd::OnKeyDown(nChar, nFlag);
113
114 // FILTER
115 switch (nChar) {
116 default:
117 return false;
118 case FWL_VKEY_Delete:
119 case FWL_VKEY_Up:
120 case FWL_VKEY_Down:
121 case FWL_VKEY_Left:
122 case FWL_VKEY_Right:
123 case FWL_VKEY_Home:
124 case FWL_VKEY_End:
125 case FWL_VKEY_Insert:
126 case 'C':
127 case 'V':
128 case 'X':
129 case 'A':
130 case 'Z':
131 case 'c':
132 case 'v':
133 case 'x':
134 case 'a':
135 case 'z':
136 break;
137 }
138
139 if (nChar == FWL_VKEY_Delete && m_pEdit->IsSelected())
140 nChar = FWL_VKEY_Unknown;
141
142 switch (nChar) {
143 case FWL_VKEY_Delete:
144 Delete();
145 return true;
146 case FWL_VKEY_Insert:
147 if (IsSHIFTpressed(nFlag))
148 PasteText();
149 return true;
150 case FWL_VKEY_Up:
151 m_pEdit->OnVK_UP(IsSHIFTpressed(nFlag), false);
152 return true;
153 case FWL_VKEY_Down:
154 m_pEdit->OnVK_DOWN(IsSHIFTpressed(nFlag), false);
155 return true;
156 case FWL_VKEY_Left:
157 m_pEdit->OnVK_LEFT(IsSHIFTpressed(nFlag), false);
158 return true;
159 case FWL_VKEY_Right:
160 m_pEdit->OnVK_RIGHT(IsSHIFTpressed(nFlag), false);
161 return true;
162 case FWL_VKEY_Home:
163 m_pEdit->OnVK_HOME(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
164 return true;
165 case FWL_VKEY_End:
166 m_pEdit->OnVK_END(IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
167 return true;
168 case FWL_VKEY_Unknown:
169 if (!IsSHIFTpressed(nFlag))
170 ClearSelection();
171 else
172 CutText();
173 return true;
174 default:
175 break;
176 }
177
178 return bRet;
179 }
180
OnChar(uint16_t nChar,uint32_t nFlag)181 bool CPWL_EditCtrl::OnChar(uint16_t nChar, uint32_t nFlag) {
182 if (m_bMouseDown)
183 return true;
184
185 CPWL_Wnd::OnChar(nChar, nFlag);
186
187 // FILTER
188 switch (nChar) {
189 case 0x0A:
190 case 0x1B:
191 return false;
192 default:
193 break;
194 }
195
196 bool bCtrl = IsCTRLpressed(nFlag);
197 bool bAlt = IsALTpressed(nFlag);
198 bool bShift = IsSHIFTpressed(nFlag);
199
200 uint16_t word = nChar;
201
202 if (bCtrl && !bAlt) {
203 switch (nChar) {
204 case 'C' - 'A' + 1:
205 CopyText();
206 return true;
207 case 'V' - 'A' + 1:
208 PasteText();
209 return true;
210 case 'X' - 'A' + 1:
211 CutText();
212 return true;
213 case 'A' - 'A' + 1:
214 SelectAllText();
215 return true;
216 case 'Z' - 'A' + 1:
217 if (bShift)
218 Redo();
219 else
220 Undo();
221 return true;
222 default:
223 if (nChar < 32)
224 return false;
225 }
226 }
227
228 if (IsReadOnly())
229 return true;
230
231 if (m_pEdit->IsSelected() && word == FWL_VKEY_Back)
232 word = FWL_VKEY_Unknown;
233
234 ClearSelection();
235
236 switch (word) {
237 case FWL_VKEY_Back:
238 Backspace();
239 break;
240 case FWL_VKEY_Return:
241 InsertReturn();
242 break;
243 case FWL_VKEY_Unknown:
244 break;
245 default:
246 InsertWord(word, GetCharSet());
247 break;
248 }
249
250 return true;
251 }
252
OnLButtonDown(uint32_t nFlag,const CFX_PointF & point)253 bool CPWL_EditCtrl::OnLButtonDown(uint32_t nFlag, const CFX_PointF& point) {
254 CPWL_Wnd::OnLButtonDown(nFlag, point);
255
256 if (ClientHitTest(point)) {
257 if (m_bMouseDown && !InvalidateRect(nullptr))
258 return true;
259
260 m_bMouseDown = true;
261 SetCapture();
262
263 m_pEdit->OnMouseDown(point, IsSHIFTpressed(nFlag), IsCTRLpressed(nFlag));
264 }
265
266 return true;
267 }
268
OnLButtonUp(uint32_t nFlag,const CFX_PointF & point)269 bool CPWL_EditCtrl::OnLButtonUp(uint32_t nFlag, const CFX_PointF& point) {
270 CPWL_Wnd::OnLButtonUp(nFlag, point);
271
272 if (m_bMouseDown) {
273 // can receive keybord message
274 if (ClientHitTest(point) && !IsFocused())
275 SetFocus();
276
277 ReleaseCapture();
278 m_bMouseDown = false;
279 }
280
281 return true;
282 }
283
OnMouseMove(uint32_t nFlag,const CFX_PointF & point)284 bool CPWL_EditCtrl::OnMouseMove(uint32_t nFlag, const CFX_PointF& point) {
285 CPWL_Wnd::OnMouseMove(nFlag, point);
286
287 if (m_bMouseDown)
288 m_pEdit->OnMouseMove(point, false, false);
289
290 return true;
291 }
292
SetEditCaret(bool bVisible)293 void CPWL_EditCtrl::SetEditCaret(bool bVisible) {
294 CFX_PointF ptHead;
295 CFX_PointF ptFoot;
296 if (bVisible)
297 GetCaretInfo(&ptHead, &ptFoot);
298
299 SetCaret(bVisible, ptHead, ptFoot);
300 // Note, |this| may no longer be viable at this point. If more work needs to
301 // be done, check the return value of SetCaret().
302 }
303
GetCaretInfo(CFX_PointF * ptHead,CFX_PointF * ptFoot) const304 void CPWL_EditCtrl::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const {
305 CPWL_EditImpl_Iterator* pIterator = m_pEdit->GetIterator();
306 pIterator->SetAt(m_pEdit->GetCaret());
307 CPVT_Word word;
308 CPVT_Line line;
309 if (pIterator->GetWord(word)) {
310 ptHead->x = word.ptWord.x + word.fWidth;
311 ptHead->y = word.ptWord.y + word.fAscent;
312 ptFoot->x = word.ptWord.x + word.fWidth;
313 ptFoot->y = word.ptWord.y + word.fDescent;
314 } else if (pIterator->GetLine(line)) {
315 ptHead->x = line.ptLine.x;
316 ptHead->y = line.ptLine.y + line.fLineAscent;
317 ptFoot->x = line.ptLine.x;
318 ptFoot->y = line.ptLine.y + line.fLineDescent;
319 }
320 }
321
SetCaret(bool bVisible,const CFX_PointF & ptHead,const CFX_PointF & ptFoot)322 bool CPWL_EditCtrl::SetCaret(bool bVisible,
323 const CFX_PointF& ptHead,
324 const CFX_PointF& ptFoot) {
325 if (!m_pEditCaret)
326 return true;
327
328 if (!IsFocused() || m_pEdit->IsSelected())
329 bVisible = false;
330
331 ObservedPtr<CPWL_EditCtrl> thisObserved(this);
332 m_pEditCaret->SetCaret(bVisible, ptHead, ptFoot);
333 if (!thisObserved)
334 return false;
335
336 return true;
337 }
338
GetText()339 WideString CPWL_EditCtrl::GetText() {
340 return m_pEdit->GetText();
341 }
342
SetSelection(int32_t nStartChar,int32_t nEndChar)343 void CPWL_EditCtrl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
344 m_pEdit->SetSelection(nStartChar, nEndChar);
345 }
346
GetSelection() const347 std::pair<int32_t, int32_t> CPWL_EditCtrl::GetSelection() const {
348 return m_pEdit->GetSelection();
349 }
350
ClearSelection()351 void CPWL_EditCtrl::ClearSelection() {
352 if (!IsReadOnly())
353 m_pEdit->ClearSelection();
354 }
355
SetScrollPos(const CFX_PointF & point)356 void CPWL_EditCtrl::SetScrollPos(const CFX_PointF& point) {
357 m_pEdit->SetScrollPos(point);
358 }
359
GetScrollPos() const360 CFX_PointF CPWL_EditCtrl::GetScrollPos() const {
361 return m_pEdit->GetScrollPos();
362 }
363
CopyText()364 void CPWL_EditCtrl::CopyText() {}
365
PasteText()366 void CPWL_EditCtrl::PasteText() {}
367
CutText()368 void CPWL_EditCtrl::CutText() {}
369
InsertWord(uint16_t word,int32_t nCharset)370 void CPWL_EditCtrl::InsertWord(uint16_t word, int32_t nCharset) {
371 if (!IsReadOnly())
372 m_pEdit->InsertWord(word, nCharset);
373 }
374
InsertReturn()375 void CPWL_EditCtrl::InsertReturn() {
376 if (!IsReadOnly())
377 m_pEdit->InsertReturn();
378 }
379
Delete()380 void CPWL_EditCtrl::Delete() {
381 if (!IsReadOnly())
382 m_pEdit->Delete();
383 }
384
Backspace()385 void CPWL_EditCtrl::Backspace() {
386 if (!IsReadOnly())
387 m_pEdit->Backspace();
388 }
389
CanUndo()390 bool CPWL_EditCtrl::CanUndo() {
391 return !IsReadOnly() && m_pEdit->CanUndo();
392 }
393
CanRedo()394 bool CPWL_EditCtrl::CanRedo() {
395 return !IsReadOnly() && m_pEdit->CanRedo();
396 }
397
Undo()398 bool CPWL_EditCtrl::Undo() {
399 return CanUndo() && m_pEdit->Undo();
400 }
401
Redo()402 bool CPWL_EditCtrl::Redo() {
403 return CanRedo() && m_pEdit->Redo();
404 }
405
GetCharSet() const406 int32_t CPWL_EditCtrl::GetCharSet() const {
407 return m_nCharSet < 0 ? FX_CHARSET_Default : m_nCharSet;
408 }
409
SetReadyToInput()410 void CPWL_EditCtrl::SetReadyToInput() {
411 if (m_bMouseDown) {
412 ReleaseCapture();
413 m_bMouseDown = false;
414 }
415 }
416