• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 The PDFium Authors
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.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <sstream>
12 #include <utility>
13 
14 #include "constants/ascii.h"
15 #include "core/fpdfapi/font/cpdf_font.h"
16 #include "core/fpdfdoc/cpvt_word.h"
17 #include "core/fpdfdoc/ipvt_fontmap.h"
18 #include "core/fxcrt/check.h"
19 #include "core/fxcrt/fx_safe_types.h"
20 #include "core/fxge/cfx_fillrenderoptions.h"
21 #include "core/fxge/cfx_graphstatedata.h"
22 #include "core/fxge/cfx_path.h"
23 #include "core/fxge/cfx_renderdevice.h"
24 #include "core/fxge/fx_font.h"
25 #include "fpdfsdk/pwl/cpwl_caret.h"
26 #include "fpdfsdk/pwl/cpwl_edit_impl.h"
27 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
28 #include "fpdfsdk/pwl/cpwl_wnd.h"
29 #include "fpdfsdk/pwl/ipwl_fillernotify.h"
30 #include "public/fpdf_fwlevent.h"
31 
CPWL_Edit(const CreateParams & cp,std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)32 CPWL_Edit::CPWL_Edit(
33     const CreateParams& cp,
34     std::unique_ptr<IPWL_FillerNotify::PerWindowData> pAttachedData)
35     : CPWL_Wnd(cp, std::move(pAttachedData)),
36       m_pEditImpl(std::make_unique<CPWL_EditImpl>()) {
37   GetCreationParams()->eCursorType = IPWL_FillerNotify::CursorStyle::kVBeam;
38 }
39 
~CPWL_Edit()40 CPWL_Edit::~CPWL_Edit() {
41   DCHECK(!m_bFocus);
42 }
43 
SetText(const WideString & csText)44 void CPWL_Edit::SetText(const WideString& csText) {
45   m_pEditImpl->SetText(csText);
46   m_pEditImpl->Paint();
47 }
48 
RepositionChildWnd()49 bool CPWL_Edit::RepositionChildWnd() {
50   ObservedPtr<CPWL_Edit> this_observed(this);
51   if (CPWL_ScrollBar* pVSB = this_observed->GetVScrollBar()) {
52     CFX_FloatRect rcWindow = this_observed->m_rcOldWindow;
53     CFX_FloatRect rcVScroll =
54         CFX_FloatRect(rcWindow.right, rcWindow.bottom,
55                       rcWindow.right + CPWL_ScrollBar::kWidth, rcWindow.top);
56     pVSB->Move(rcVScroll, true, false);
57     if (!this_observed) {
58       return false;
59     }
60   }
61   if (this_observed->m_pCaret && !HasFlag(PES_TEXTOVERFLOW)) {
62     CFX_FloatRect rect = this_observed->GetClientRect();
63     if (!rect.IsEmpty()) {
64       // +1 for caret beside border
65       rect.Inflate(1.0f, 1.0f);
66       rect.Normalize();
67     }
68     this_observed->m_pCaret->SetClipRect(rect);
69   }
70   this_observed->m_pEditImpl->SetPlateRect(GetClientRect());
71   this_observed->m_pEditImpl->Paint();
72   return true;
73 }
74 
GetClientRect() const75 CFX_FloatRect CPWL_Edit::GetClientRect() const {
76   float width = static_cast<float>(GetBorderWidth() + GetInnerBorderWidth());
77   CFX_FloatRect rcClient = GetWindowRect().GetDeflated(width, width);
78   CPWL_ScrollBar* pVSB = GetVScrollBar();
79   if (pVSB && pVSB->IsVisible())
80     rcClient.right -= CPWL_ScrollBar::kWidth;
81   return rcClient;
82 }
83 
SetAlignFormatVerticalCenter()84 void CPWL_Edit::SetAlignFormatVerticalCenter() {
85   m_pEditImpl->SetAlignmentV(static_cast<int32_t>(PEAV_CENTER));
86   m_pEditImpl->Paint();
87 }
88 
CanSelectAll() const89 bool CPWL_Edit::CanSelectAll() const {
90   return GetSelectWordRange() != m_pEditImpl->GetWholeWordRange();
91 }
92 
CanCopy() const93 bool CPWL_Edit::CanCopy() const {
94   return !HasFlag(PES_PASSWORD) && m_pEditImpl->IsSelected();
95 }
96 
CanCut() const97 bool CPWL_Edit::CanCut() const {
98   return CanCopy() && !IsReadOnly();
99 }
100 
CutText()101 void CPWL_Edit::CutText() {
102   if (!CanCut())
103     return;
104   m_pEditImpl->ClearSelection();
105 }
106 
OnCreated()107 void CPWL_Edit::OnCreated() {
108   SetFontSize(GetCreationParams()->fFontSize);
109   m_pEditImpl->SetFontMap(GetFontMap());
110   m_pEditImpl->SetNotify(this);
111   m_pEditImpl->Initialize();
112 
113   if (CPWL_ScrollBar* pScroll = GetVScrollBar()) {
114     pScroll->RemoveFlag(PWS_AUTOTRANSPARENT);
115     pScroll->SetTransparency(255);
116   }
117 
118   SetParamByFlag();
119   m_rcOldWindow = GetWindowRect();
120 }
121 
SetParamByFlag()122 void CPWL_Edit::SetParamByFlag() {
123   if (HasFlag(PES_RIGHT)) {
124     m_pEditImpl->SetAlignmentH(2);
125   } else if (HasFlag(PES_MIDDLE)) {
126     m_pEditImpl->SetAlignmentH(1);
127   } else {
128     m_pEditImpl->SetAlignmentH(0);
129   }
130 
131   if (HasFlag(PES_CENTER)) {
132     m_pEditImpl->SetAlignmentV(1);
133   } else {
134     m_pEditImpl->SetAlignmentV(0);
135   }
136 
137   if (HasFlag(PES_PASSWORD)) {
138     m_pEditImpl->SetPasswordChar('*');
139   }
140 
141   m_pEditImpl->SetMultiLine(HasFlag(PES_MULTILINE));
142   m_pEditImpl->SetAutoReturn(HasFlag(PES_AUTORETURN));
143   m_pEditImpl->SetAutoFontSize(HasFlag(PWS_AUTOFONTSIZE));
144   m_pEditImpl->SetAutoScroll(HasFlag(PES_AUTOSCROLL));
145   m_pEditImpl->EnableUndo(HasFlag(PES_UNDO));
146 
147   if (HasFlag(PES_TEXTOVERFLOW)) {
148     SetClipRect(CFX_FloatRect());
149     m_pEditImpl->SetTextOverflow(true);
150   } else {
151     if (m_pCaret) {
152       CFX_FloatRect rect = GetClientRect();
153       if (!rect.IsEmpty()) {
154         // +1 for caret beside border
155         rect.Inflate(1.0f, 1.0f);
156         rect.Normalize();
157       }
158       m_pCaret->SetClipRect(rect);
159     }
160   }
161 }
162 
DrawThisAppearance(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device)163 void CPWL_Edit::DrawThisAppearance(CFX_RenderDevice* pDevice,
164                                    const CFX_Matrix& mtUser2Device) {
165   CPWL_Wnd::DrawThisAppearance(pDevice, mtUser2Device);
166 
167   const CFX_FloatRect rcClient = GetClientRect();
168   const BorderStyle border_style = GetBorderStyle();
169   const int32_t nCharArray = m_pEditImpl->GetCharArray();
170   bool draw_border = nCharArray > 0 && (border_style == BorderStyle::kSolid ||
171                                         border_style == BorderStyle::kDash);
172   if (draw_border) {
173     FX_SAFE_INT32 nCharArraySafe = nCharArray;
174     nCharArraySafe -= 1;
175     nCharArraySafe *= 2;
176     draw_border = nCharArraySafe.IsValid();
177   }
178 
179   if (draw_border) {
180     CFX_GraphStateData gsd;
181     gsd.set_line_width(GetBorderWidth());
182     if (border_style == BorderStyle::kDash) {
183       gsd.set_dash_array({static_cast<float>(GetBorderDash().nDash),
184                           static_cast<float>(GetBorderDash().nGap)});
185       gsd.set_dash_phase(GetBorderDash().nPhase);
186     }
187 
188     const float width = (rcClient.right - rcClient.left) / nCharArray;
189     CFX_Path path;
190     CFX_PointF bottom(0, rcClient.bottom);
191     CFX_PointF top(0, rcClient.top);
192     for (int32_t i = 0; i < nCharArray - 1; ++i) {
193       bottom.x = rcClient.left + width * (i + 1);
194       top.x = bottom.x;
195       path.AppendPoint(bottom, CFX_Path::Point::Type::kMove);
196       path.AppendPoint(top, CFX_Path::Point::Type::kLine);
197     }
198     if (!path.GetPoints().empty()) {
199       pDevice->DrawPath(path, &mtUser2Device, &gsd, 0,
200                         GetBorderColor().ToFXColor(255),
201                         CFX_FillRenderOptions::EvenOddOptions());
202     }
203   }
204 
205   CFX_FloatRect rcClip;
206   CPVT_WordRange wrRange = m_pEditImpl->GetVisibleWordRange();
207   CPVT_WordRange* pRange = nullptr;
208   if (!HasFlag(PES_TEXTOVERFLOW)) {
209     rcClip = GetClientRect();
210     pRange = &wrRange;
211   }
212   m_pEditImpl->DrawEdit(
213       pDevice, mtUser2Device, GetTextColor().ToFXColor(GetTransparency()),
214       rcClip, CFX_PointF(), pRange, GetFillerNotify(), GetAttachedData());
215 }
216 
OnSetFocus()217 void CPWL_Edit::OnSetFocus() {
218   ObservedPtr<CPWL_Edit> this_observed(this);
219   this_observed->SetEditCaret(true);
220   if (!this_observed) {
221     return;
222   }
223   if (!this_observed->IsReadOnly()) {
224     CPWL_Wnd::ProviderIface* pProvider = this_observed->GetProvider();
225     if (pProvider) {
226       pProvider->OnSetFocusForEdit(this);
227       if (!this_observed) {
228         return;
229       }
230     }
231   }
232   this_observed->m_bFocus = true;
233 }
234 
OnKillFocus()235 void CPWL_Edit::OnKillFocus() {
236   ObservedPtr<CPWL_Edit> this_observed(this);
237   CPWL_ScrollBar* pScroll = this_observed->GetVScrollBar();
238   if (pScroll && pScroll->IsVisible()) {
239     if (!pScroll->SetVisible(false)) {
240       return;
241     }
242     if (!this_observed) {
243       return;
244     }
245     if (!this_observed->Move(this_observed->m_rcOldWindow, true, true)) {
246       return;
247     }
248   }
249   this_observed->m_pEditImpl->SelectNone();
250   if (!this_observed) {
251     return;
252   }
253   if (!this_observed->SetCaret(false, CFX_PointF(), CFX_PointF())) {
254     return;
255   }
256   this_observed->SetCharSet(FX_Charset::kANSI);
257   this_observed->m_bFocus = false;
258 }
259 
GetSelectWordRange() const260 CPVT_WordRange CPWL_Edit::GetSelectWordRange() const {
261   if (!m_pEditImpl->IsSelected())
262     return CPVT_WordRange();
263 
264   auto [nStart, nEnd] = m_pEditImpl->GetSelection();
265 
266   CPVT_WordPlace wpStart = m_pEditImpl->WordIndexToWordPlace(nStart);
267   CPVT_WordPlace wpEnd = m_pEditImpl->WordIndexToWordPlace(nEnd);
268   return CPVT_WordRange(wpStart, wpEnd);
269 }
270 
IsTextFull() const271 bool CPWL_Edit::IsTextFull() const {
272   return m_pEditImpl->IsTextFull();
273 }
274 
GetCharArrayAutoFontSize(const CPDF_Font * pFont,const CFX_FloatRect & rcPlate,int32_t nCharArray)275 float CPWL_Edit::GetCharArrayAutoFontSize(const CPDF_Font* pFont,
276                                           const CFX_FloatRect& rcPlate,
277                                           int32_t nCharArray) {
278   if (!pFont || pFont->IsStandardFont())
279     return 0.0f;
280 
281   const FX_RECT& rcBBox = pFont->GetFontBBox();
282 
283   CFX_FloatRect rcCell = rcPlate;
284   float xdiv = rcCell.Width() / nCharArray * 1000.0f / rcBBox.Width();
285   float ydiv = -rcCell.Height() * 1000.0f / rcBBox.Height();
286 
287   return xdiv < ydiv ? xdiv : ydiv;
288 }
289 
SetCharArray(int32_t nCharArray)290 void CPWL_Edit::SetCharArray(int32_t nCharArray) {
291   if (!HasFlag(PES_CHARARRAY) || nCharArray <= 0)
292     return;
293 
294   m_pEditImpl->SetCharArray(nCharArray);
295   m_pEditImpl->SetTextOverflow(true);
296   m_pEditImpl->Paint();
297 
298   if (!HasFlag(PWS_AUTOFONTSIZE))
299     return;
300 
301   IPVT_FontMap* pFontMap = GetFontMap();
302   if (!pFontMap)
303     return;
304 
305   float fFontSize = GetCharArrayAutoFontSize(pFontMap->GetPDFFont(0).Get(),
306                                              GetClientRect(), nCharArray);
307   if (fFontSize <= 0.0f)
308     return;
309 
310   m_pEditImpl->SetAutoFontSize(false);
311   m_pEditImpl->SetFontSize(fFontSize);
312   m_pEditImpl->Paint();
313 }
314 
SetLimitChar(int32_t nLimitChar)315 void CPWL_Edit::SetLimitChar(int32_t nLimitChar) {
316   m_pEditImpl->SetLimitChar(nLimitChar);
317   m_pEditImpl->Paint();
318 }
319 
GetFocusRect() const320 CFX_FloatRect CPWL_Edit::GetFocusRect() const {
321   return CFX_FloatRect();
322 }
323 
IsVScrollBarVisible() const324 bool CPWL_Edit::IsVScrollBarVisible() const {
325   CPWL_ScrollBar* pScroll = GetVScrollBar();
326   return pScroll && pScroll->IsVisible();
327 }
328 
OnKeyDown(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlag)329 bool CPWL_Edit::OnKeyDown(FWL_VKEYCODE nKeyCode, Mask<FWL_EVENTFLAG> nFlag) {
330   ObservedPtr<CPWL_Edit> this_observed(this);
331   if (this_observed->m_bMouseDown) {
332     return true;
333   }
334   if (nKeyCode == FWL_VKEY_Delete) {
335     WideString strChange;
336     WideString strChangeEx;
337     auto [nSelStart, nSelEnd] = this_observed->GetSelection();
338     if (nSelStart == nSelEnd) {
339       nSelEnd = nSelStart + 1;
340     }
341     IPWL_FillerNotify::BeforeKeystrokeResult result =
342         this_observed->GetFillerNotify()->OnBeforeKeyStroke(
343             this_observed->GetAttachedData(), strChange, strChangeEx, nSelStart,
344             nSelEnd, true, nFlag);
345 
346     if (!this_observed) {
347       return false;
348     }
349     if (!result.rc) {
350       return false;
351     }
352     if (result.exit) {
353       return false;
354     }
355   }
356 
357   bool bRet = this_observed->OnKeyDownInternal(nKeyCode, nFlag);
358 
359   // In case of implementation swallow the OnKeyDown event.
360   if (this_observed->IsProceedtoOnChar(nKeyCode, nFlag)) {
361     return true;
362   }
363   return bRet;
364 }
365 
366 // static
IsProceedtoOnChar(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlag)367 bool CPWL_Edit::IsProceedtoOnChar(FWL_VKEYCODE nKeyCode,
368                                   Mask<FWL_EVENTFLAG> nFlag) {
369   bool bCtrl = IsPlatformShortcutKey(nFlag);
370   bool bAlt = IsALTKeyDown(nFlag);
371   if (bCtrl && !bAlt) {
372     // hot keys for edit control.
373     switch (nKeyCode) {
374       case FWL_VKEY_A:
375       case FWL_VKEY_C:
376       case FWL_VKEY_V:
377       case FWL_VKEY_X:
378       case FWL_VKEY_Z:
379         return true;
380       default:
381         break;
382     }
383   }
384   // control characters.
385   switch (nKeyCode) {
386     case FWL_VKEY_Escape:
387     case FWL_VKEY_Back:
388     case FWL_VKEY_Return:
389     case FWL_VKEY_Space:
390       return true;
391     default:
392       return false;
393   }
394 }
395 
OnChar(uint16_t nChar,Mask<FWL_EVENTFLAG> nFlag)396 bool CPWL_Edit::OnChar(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
397   ObservedPtr<CPWL_Edit> this_observed(this);
398   if (this_observed->m_bMouseDown) {
399     return true;
400   }
401   if (!this_observed->IsCTRLKeyDown(nFlag)) {
402     WideString swChange;
403     auto [nSelStart, nSelEnd] = this_observed->GetSelection();
404     switch (nChar) {
405       case pdfium::ascii::kBackspace:
406         if (nSelStart == nSelEnd)
407           nSelStart = nSelEnd - 1;
408         break;
409       case pdfium::ascii::kReturn:
410         break;
411       default:
412         swChange += nChar;
413         break;
414     }
415     WideString strChangeEx;
416     IPWL_FillerNotify::BeforeKeystrokeResult result =
417         this_observed->GetFillerNotify()->OnBeforeKeyStroke(
418             this_observed->GetAttachedData(), swChange, strChangeEx, nSelStart,
419             nSelEnd, true, nFlag);
420 
421     if (!this_observed) {
422       return false;
423     }
424     if (!result.rc) {
425       return true;
426     }
427     if (result.exit) {
428       return false;
429     }
430   }
431   if (IPVT_FontMap* pFontMap = this_observed->GetFontMap()) {
432     FX_Charset nOldCharSet = this_observed->GetCharSet();
433     FX_Charset nNewCharSet =
434         pFontMap->CharSetFromUnicode(nChar, FX_Charset::kDefault);
435     if (nOldCharSet != nNewCharSet) {
436       this_observed->SetCharSet(nNewCharSet);
437     }
438   }
439   return this_observed->OnCharInternal(nChar, nFlag);
440 }
441 
OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point,const CFX_Vector & delta)442 bool CPWL_Edit::OnMouseWheel(Mask<FWL_EVENTFLAG> nFlag,
443                              const CFX_PointF& point,
444                              const CFX_Vector& delta) {
445   if (!HasFlag(PES_MULTILINE))
446     return false;
447 
448   CFX_PointF ptScroll = GetScrollPos();
449   if (delta.y > 0)
450     ptScroll.y += GetFontSize();
451   else
452     ptScroll.y -= GetFontSize();
453   SetScrollPos(ptScroll);
454   return true;
455 }
456 
OnDestroy()457 void CPWL_Edit::OnDestroy() {
458   m_pCaret.ExtractAsDangling();
459 }
460 
IsWndHorV() const461 bool CPWL_Edit::IsWndHorV() const {
462   CFX_Matrix mt = GetWindowMatrix();
463   return mt.Transform(CFX_PointF(1, 1)).y == mt.Transform(CFX_PointF(0, 1)).y;
464 }
465 
SetCursor()466 void CPWL_Edit::SetCursor() {
467   if (IsValid()) {
468     GetFillerNotify()->SetCursor(IsWndHorV()
469                                      ? IPWL_FillerNotify::CursorStyle::kVBeam
470                                      : IPWL_FillerNotify::CursorStyle::kHBeam);
471   }
472 }
473 
GetSelectedText()474 WideString CPWL_Edit::GetSelectedText() {
475   return m_pEditImpl->GetSelectedText();
476 }
477 
ReplaceAndKeepSelection(const WideString & text)478 void CPWL_Edit::ReplaceAndKeepSelection(const WideString& text) {
479   m_pEditImpl->ReplaceAndKeepSelection(text);
480 }
481 
ReplaceSelection(const WideString & text)482 void CPWL_Edit::ReplaceSelection(const WideString& text) {
483   m_pEditImpl->ReplaceSelection(text);
484 }
485 
SelectAllText()486 bool CPWL_Edit::SelectAllText() {
487   m_pEditImpl->SelectAll();
488   return true;
489 }
490 
SetScrollInfo(const PWL_SCROLL_INFO & info)491 void CPWL_Edit::SetScrollInfo(const PWL_SCROLL_INFO& info) {
492   if (CPWL_Wnd* pChild = GetVScrollBar())
493     pChild->SetScrollInfo(info);
494 }
495 
SetScrollPosition(float pos)496 void CPWL_Edit::SetScrollPosition(float pos) {
497   if (CPWL_Wnd* pChild = GetVScrollBar())
498     pChild->SetScrollPosition(pos);
499 }
500 
ScrollWindowVertically(float pos)501 void CPWL_Edit::ScrollWindowVertically(float pos) {
502   m_pEditImpl->SetScrollPos(CFX_PointF(m_pEditImpl->GetScrollPos().x, pos));
503 }
504 
CreateChildWnd(const CreateParams & cp)505 void CPWL_Edit::CreateChildWnd(const CreateParams& cp) {
506   if (!IsReadOnly())
507     CreateEditCaret(cp);
508 }
509 
CreateEditCaret(const CreateParams & cp)510 void CPWL_Edit::CreateEditCaret(const CreateParams& cp) {
511   if (m_pCaret)
512     return;
513 
514   CreateParams ecp = cp;
515   ecp.dwFlags = PWS_NOREFRESHCLIP;
516   ecp.dwBorderWidth = 0;
517   ecp.nBorderStyle = BorderStyle::kSolid;
518   ecp.rcRectWnd = CFX_FloatRect();
519 
520   auto pCaret = std::make_unique<CPWL_Caret>(ecp, CloneAttachedData());
521   m_pCaret = pCaret.get();
522   m_pCaret->SetInvalidRect(GetClientRect());
523   AddChild(std::move(pCaret));
524   m_pCaret->Realize();
525 }
526 
SetFontSize(float fFontSize)527 void CPWL_Edit::SetFontSize(float fFontSize) {
528   m_pEditImpl->SetFontSize(fFontSize);
529   m_pEditImpl->Paint();
530 }
531 
GetFontSize() const532 float CPWL_Edit::GetFontSize() const {
533   return m_pEditImpl->GetFontSize();
534 }
535 
OnKeyDownInternal(FWL_VKEYCODE nKeyCode,Mask<FWL_EVENTFLAG> nFlag)536 bool CPWL_Edit::OnKeyDownInternal(FWL_VKEYCODE nKeyCode,
537                                   Mask<FWL_EVENTFLAG> nFlag) {
538   if (m_bMouseDown)
539     return true;
540 
541   bool bRet = CPWL_Wnd::OnKeyDown(nKeyCode, nFlag);
542 
543   // FILTER
544   switch (nKeyCode) {
545     default:
546       return false;
547     case FWL_VKEY_Delete:
548     case FWL_VKEY_Up:
549     case FWL_VKEY_Down:
550     case FWL_VKEY_Left:
551     case FWL_VKEY_Right:
552     case FWL_VKEY_Home:
553     case FWL_VKEY_End:
554     case FWL_VKEY_Insert:
555     case FWL_VKEY_A:
556     case FWL_VKEY_C:
557     case FWL_VKEY_V:
558     case FWL_VKEY_X:
559     case FWL_VKEY_Z:
560       break;
561   }
562 
563   if (nKeyCode == FWL_VKEY_Delete && m_pEditImpl->IsSelected())
564     nKeyCode = FWL_VKEY_Unknown;
565 
566   switch (nKeyCode) {
567     case FWL_VKEY_Delete:
568       Delete();
569       return true;
570     case FWL_VKEY_Insert:
571       if (IsSHIFTKeyDown(nFlag))
572         PasteText();
573       return true;
574     case FWL_VKEY_Up:
575       m_pEditImpl->OnVK_UP(IsSHIFTKeyDown(nFlag));
576       return true;
577     case FWL_VKEY_Down:
578       m_pEditImpl->OnVK_DOWN(IsSHIFTKeyDown(nFlag));
579       return true;
580     case FWL_VKEY_Left:
581       m_pEditImpl->OnVK_LEFT(IsSHIFTKeyDown(nFlag));
582       return true;
583     case FWL_VKEY_Right:
584       m_pEditImpl->OnVK_RIGHT(IsSHIFTKeyDown(nFlag));
585       return true;
586     case FWL_VKEY_Home:
587       m_pEditImpl->OnVK_HOME(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
588       return true;
589     case FWL_VKEY_End:
590       m_pEditImpl->OnVK_END(IsSHIFTKeyDown(nFlag), IsCTRLKeyDown(nFlag));
591       return true;
592     case FWL_VKEY_Unknown:
593       if (!IsSHIFTKeyDown(nFlag))
594         ClearSelection();
595       else
596         CutText();
597       return true;
598     default:
599       break;
600   }
601 
602   return bRet;
603 }
604 
OnCharInternal(uint16_t nChar,Mask<FWL_EVENTFLAG> nFlag)605 bool CPWL_Edit::OnCharInternal(uint16_t nChar, Mask<FWL_EVENTFLAG> nFlag) {
606   if (m_bMouseDown)
607     return true;
608 
609   CPWL_Wnd::OnChar(nChar, nFlag);
610 
611   // FILTER
612   switch (nChar) {
613     case pdfium::ascii::kNewline:
614     case pdfium::ascii::kEscape:
615       return false;
616     default:
617       break;
618   }
619 
620   bool bCtrl = IsPlatformShortcutKey(nFlag);
621   bool bAlt = IsALTKeyDown(nFlag);
622   bool bShift = IsSHIFTKeyDown(nFlag);
623 
624   uint16_t word = nChar;
625 
626   if (bCtrl && !bAlt) {
627     switch (nChar) {
628       case pdfium::ascii::kControlC:
629         CopyText();
630         return true;
631       case pdfium::ascii::kControlV:
632         PasteText();
633         return true;
634       case pdfium::ascii::kControlX:
635         CutText();
636         return true;
637       case pdfium::ascii::kControlA:
638         SelectAllText();
639         return true;
640       case pdfium::ascii::kControlZ:
641         if (bShift)
642           Redo();
643         else
644           Undo();
645         return true;
646       default:
647         if (nChar < 32)
648           return false;
649     }
650   }
651 
652   if (IsReadOnly())
653     return true;
654 
655   if (m_pEditImpl->IsSelected() && word == pdfium::ascii::kBackspace)
656     word = pdfium::ascii::kNul;
657 
658   ClearSelection();
659 
660   switch (word) {
661     case pdfium::ascii::kBackspace:
662       Backspace();
663       break;
664     case pdfium::ascii::kReturn:
665       InsertReturn();
666       break;
667     case pdfium::ascii::kNul:
668       break;
669     default:
670       InsertWord(word, GetCharSet());
671       break;
672   }
673 
674   return true;
675 }
676 
OnLButtonDown(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)677 bool CPWL_Edit::OnLButtonDown(Mask<FWL_EVENTFLAG> nFlag,
678                               const CFX_PointF& point) {
679   CPWL_Wnd::OnLButtonDown(nFlag, point);
680   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point)) {
681     if (m_bMouseDown && !InvalidateRect(nullptr))
682       return true;
683 
684     m_bMouseDown = true;
685     SetCapture();
686     m_pEditImpl->OnMouseDown(point, IsSHIFTKeyDown(nFlag),
687                              IsCTRLKeyDown(nFlag));
688   }
689   return true;
690 }
691 
OnLButtonUp(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)692 bool CPWL_Edit::OnLButtonUp(Mask<FWL_EVENTFLAG> nFlag,
693                             const CFX_PointF& point) {
694   CPWL_Wnd::OnLButtonUp(nFlag, point);
695   if (m_bMouseDown) {
696     // can receive keybord message
697     if (ClientHitTest(point) && !IsFocused())
698       SetFocus();
699 
700     ReleaseCapture();
701     m_bMouseDown = false;
702   }
703   return true;
704 }
705 
OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)706 bool CPWL_Edit::OnLButtonDblClk(Mask<FWL_EVENTFLAG> nFlag,
707                                 const CFX_PointF& point) {
708   CPWL_Wnd::OnLButtonDblClk(nFlag, point);
709   if (HasFlag(PES_TEXTOVERFLOW) || ClientHitTest(point))
710     m_pEditImpl->SelectAll();
711 
712   return true;
713 }
714 
OnRButtonUp(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)715 bool CPWL_Edit::OnRButtonUp(Mask<FWL_EVENTFLAG> nFlag,
716                             const CFX_PointF& point) {
717   if (m_bMouseDown)
718     return false;
719 
720   CPWL_Wnd::OnRButtonUp(nFlag, point);
721   if (!HasFlag(PES_TEXTOVERFLOW) && !ClientHitTest(point))
722     return true;
723 
724   SetFocus();
725   return false;
726 }
727 
OnMouseMove(Mask<FWL_EVENTFLAG> nFlag,const CFX_PointF & point)728 bool CPWL_Edit::OnMouseMove(Mask<FWL_EVENTFLAG> nFlag,
729                             const CFX_PointF& point) {
730   CPWL_Wnd::OnMouseMove(nFlag, point);
731 
732   if (m_bMouseDown)
733     m_pEditImpl->OnMouseMove(point, false, false);
734 
735   return true;
736 }
737 
SetEditCaret(bool bVisible)738 void CPWL_Edit::SetEditCaret(bool bVisible) {
739   CFX_PointF ptHead;
740   CFX_PointF ptFoot;
741   if (bVisible)
742     GetCaretInfo(&ptHead, &ptFoot);
743 
744   SetCaret(bVisible, ptHead, ptFoot);
745   // Note, |this| may no longer be viable at this point. If more work needs to
746   // be done, check the return value of SetCaret().
747 }
748 
GetCaretInfo(CFX_PointF * ptHead,CFX_PointF * ptFoot) const749 void CPWL_Edit::GetCaretInfo(CFX_PointF* ptHead, CFX_PointF* ptFoot) const {
750   CPWL_EditImpl::Iterator* pIterator = m_pEditImpl->GetIterator();
751   pIterator->SetAt(m_pEditImpl->GetCaret());
752   CPVT_Word word;
753   CPVT_Line line;
754   if (pIterator->GetWord(word)) {
755     ptHead->x = word.ptWord.x + word.fWidth;
756     ptHead->y = word.ptWord.y + word.fAscent;
757     ptFoot->x = word.ptWord.x + word.fWidth;
758     ptFoot->y = word.ptWord.y + word.fDescent;
759   } else if (pIterator->GetLine(line)) {
760     ptHead->x = line.ptLine.x;
761     ptHead->y = line.ptLine.y + line.fLineAscent;
762     ptFoot->x = line.ptLine.x;
763     ptFoot->y = line.ptLine.y + line.fLineDescent;
764   }
765 }
766 
SetCaret(bool bVisible,const CFX_PointF & ptHead,const CFX_PointF & ptFoot)767 bool CPWL_Edit::SetCaret(bool bVisible,
768                          const CFX_PointF& ptHead,
769                          const CFX_PointF& ptFoot) {
770   ObservedPtr<CPWL_Edit> this_observed(this);
771   if (!this_observed->m_pCaret) {
772     return true;
773   }
774   if (!this_observed->IsFocused() || this_observed->m_pEditImpl->IsSelected()) {
775     bVisible = false;
776   }
777   this_observed->m_pCaret->SetCaret(bVisible, ptHead, ptFoot);
778   return !!this_observed;
779 }
780 
GetText()781 WideString CPWL_Edit::GetText() {
782   return m_pEditImpl->GetText();
783 }
784 
SetSelection(int32_t nStartChar,int32_t nEndChar)785 void CPWL_Edit::SetSelection(int32_t nStartChar, int32_t nEndChar) {
786   m_pEditImpl->SetSelection(nStartChar, nEndChar);
787 }
788 
GetSelection() const789 std::pair<int32_t, int32_t> CPWL_Edit::GetSelection() const {
790   return m_pEditImpl->GetSelection();
791 }
792 
ClearSelection()793 void CPWL_Edit::ClearSelection() {
794   if (!IsReadOnly())
795     m_pEditImpl->ClearSelection();
796 }
797 
SetScrollPos(const CFX_PointF & point)798 void CPWL_Edit::SetScrollPos(const CFX_PointF& point) {
799   m_pEditImpl->SetScrollPos(point);
800 }
801 
GetScrollPos() const802 CFX_PointF CPWL_Edit::GetScrollPos() const {
803   return m_pEditImpl->GetScrollPos();
804 }
805 
CopyText()806 void CPWL_Edit::CopyText() {}
807 
PasteText()808 void CPWL_Edit::PasteText() {}
809 
InsertWord(uint16_t word,FX_Charset nCharset)810 void CPWL_Edit::InsertWord(uint16_t word, FX_Charset nCharset) {
811   if (!IsReadOnly())
812     m_pEditImpl->InsertWord(word, nCharset);
813 }
814 
InsertReturn()815 void CPWL_Edit::InsertReturn() {
816   if (!IsReadOnly())
817     m_pEditImpl->InsertReturn();
818 }
819 
Delete()820 void CPWL_Edit::Delete() {
821   if (!IsReadOnly())
822     m_pEditImpl->Delete();
823 }
824 
Backspace()825 void CPWL_Edit::Backspace() {
826   if (!IsReadOnly())
827     m_pEditImpl->Backspace();
828 }
829 
CanUndo()830 bool CPWL_Edit::CanUndo() {
831   return !IsReadOnly() && m_pEditImpl->CanUndo();
832 }
833 
CanRedo()834 bool CPWL_Edit::CanRedo() {
835   return !IsReadOnly() && m_pEditImpl->CanRedo();
836 }
837 
Undo()838 bool CPWL_Edit::Undo() {
839   return CanUndo() && m_pEditImpl->Undo();
840 }
841 
Redo()842 bool CPWL_Edit::Redo() {
843   return CanRedo() && m_pEditImpl->Redo();
844 }
845 
SetReadyToInput()846 void CPWL_Edit::SetReadyToInput() {
847   if (m_bMouseDown) {
848     ReleaseCapture();
849     m_bMouseDown = false;
850   }
851 }
852