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