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