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