xref: /aosp_15_r20/external/pdfium/fpdfsdk/pwl/cpwl_edit_impl.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_impl.h"
8 
9 #include <algorithm>
10 #include <memory>
11 #include <utility>
12 
13 #include "core/fpdfapi/font/cpdf_font.h"
14 #include "core/fpdfapi/render/cpdf_renderoptions.h"
15 #include "core/fpdfapi/render/cpdf_textrenderer.h"
16 #include "core/fpdfdoc/cpvt_word.h"
17 #include "core/fpdfdoc/ipvt_fontmap.h"
18 #include "core/fxcrt/autorestorer.h"
19 #include "core/fxcrt/fx_codepage.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 "fpdfsdk/pwl/cpwl_edit.h"
25 #include "fpdfsdk/pwl/cpwl_scroll_bar.h"
26 #include "fpdfsdk/pwl/ipwl_fillernotify.h"
27 #include "third_party/base/check.h"
28 #include "third_party/base/check_op.h"
29 
30 namespace {
31 
32 const int kEditUndoMaxItems = 10000;
33 
DrawTextString(CFX_RenderDevice * pDevice,const CFX_PointF & pt,CPDF_Font * pFont,float fFontSize,const CFX_Matrix & mtUser2Device,const ByteString & str,FX_ARGB crTextFill)34 void DrawTextString(CFX_RenderDevice* pDevice,
35                     const CFX_PointF& pt,
36                     CPDF_Font* pFont,
37                     float fFontSize,
38                     const CFX_Matrix& mtUser2Device,
39                     const ByteString& str,
40                     FX_ARGB crTextFill) {
41   if (!pFont)
42     return;
43 
44   CFX_PointF pos = mtUser2Device.Transform(pt);
45   CPDF_RenderOptions ro;
46   DCHECK(ro.GetOptions().bClearType);
47   ro.SetColorMode(CPDF_RenderOptions::kNormal);
48   CPDF_TextRenderer::DrawTextString(pDevice, pos.x, pos.y, pFont, fFontSize,
49                                     mtUser2Device, str, crTextFill, ro);
50 }
51 
52 }  // namespace
53 
Iterator(CPWL_EditImpl * pEdit,CPVT_VariableText::Iterator * pVTIterator)54 CPWL_EditImpl::Iterator::Iterator(CPWL_EditImpl* pEdit,
55                                   CPVT_VariableText::Iterator* pVTIterator)
56     : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
57 
58 CPWL_EditImpl::Iterator::~Iterator() = default;
59 
NextWord()60 bool CPWL_EditImpl::Iterator::NextWord() {
61   return m_pVTIterator->NextWord();
62 }
63 
GetWord(CPVT_Word & word) const64 bool CPWL_EditImpl::Iterator::GetWord(CPVT_Word& word) const {
65   DCHECK(m_pEdit);
66 
67   if (m_pVTIterator->GetWord(word)) {
68     word.ptWord = m_pEdit->VTToEdit(word.ptWord);
69     return true;
70   }
71   return false;
72 }
73 
GetLine(CPVT_Line & line) const74 bool CPWL_EditImpl::Iterator::GetLine(CPVT_Line& line) const {
75   DCHECK(m_pEdit);
76 
77   if (m_pVTIterator->GetLine(line)) {
78     line.ptLine = m_pEdit->VTToEdit(line.ptLine);
79     return true;
80   }
81   return false;
82 }
83 
SetAt(int32_t nWordIndex)84 void CPWL_EditImpl::Iterator::SetAt(int32_t nWordIndex) {
85   m_pVTIterator->SetAt(nWordIndex);
86 }
87 
SetAt(const CPVT_WordPlace & place)88 void CPWL_EditImpl::Iterator::SetAt(const CPVT_WordPlace& place) {
89   m_pVTIterator->SetAt(place);
90 }
91 
GetAt() const92 const CPVT_WordPlace& CPWL_EditImpl::Iterator::GetAt() const {
93   return m_pVTIterator->GetWordPlace();
94 }
95 
96 class CPWL_EditImpl::Provider final : public CPVT_VariableText::Provider {
97  public:
98   explicit Provider(IPVT_FontMap* pFontMap);
99   ~Provider() override;
100 
101   // CPVT_VariableText::Provider:
102   int GetCharWidth(int32_t nFontIndex, uint16_t word) override;
103   int32_t GetWordFontIndex(uint16_t word,
104                            FX_Charset charset,
105                            int32_t nFontIndex) override;
106 };
107 
Provider(IPVT_FontMap * pFontMap)108 CPWL_EditImpl::Provider::Provider(IPVT_FontMap* pFontMap)
109     : CPVT_VariableText::Provider(pFontMap) {}
110 
111 CPWL_EditImpl::Provider::~Provider() = default;
112 
GetCharWidth(int32_t nFontIndex,uint16_t word)113 int CPWL_EditImpl::Provider::GetCharWidth(int32_t nFontIndex, uint16_t word) {
114   RetainPtr<CPDF_Font> pPDFFont = GetFontMap()->GetPDFFont(nFontIndex);
115   if (!pPDFFont)
116     return 0;
117 
118   uint32_t charcode = pPDFFont->IsUnicodeCompatible()
119                           ? pPDFFont->CharCodeFromUnicode(word)
120                           : GetFontMap()->CharCodeFromUnicode(nFontIndex, word);
121   if (charcode == CPDF_Font::kInvalidCharCode)
122     return 0;
123 
124   return pPDFFont->GetCharWidthF(charcode);
125 }
126 
GetWordFontIndex(uint16_t word,FX_Charset charset,int32_t nFontIndex)127 int32_t CPWL_EditImpl::Provider::GetWordFontIndex(uint16_t word,
128                                                   FX_Charset charset,
129                                                   int32_t nFontIndex) {
130   return GetFontMap()->GetWordFontIndex(word, charset, nFontIndex);
131 }
132 
133 CPWL_EditImpl::RefreshState::RefreshState() = default;
134 
135 CPWL_EditImpl::RefreshState::~RefreshState() = default;
136 
BeginRefresh()137 void CPWL_EditImpl::RefreshState::BeginRefresh() {
138   m_OldLineRects = std::move(m_NewLineRects);
139   m_NewLineRects.clear();
140   m_RefreshRects.clear();
141 }
142 
Push(const CPVT_WordRange & linerange,const CFX_FloatRect & rect)143 void CPWL_EditImpl::RefreshState::Push(const CPVT_WordRange& linerange,
144                                        const CFX_FloatRect& rect) {
145   m_NewLineRects.emplace_back(LineRect(linerange, rect));
146 }
147 
NoAnalyse()148 void CPWL_EditImpl::RefreshState::NoAnalyse() {
149   for (const auto& lineRect : m_OldLineRects)
150     Add(lineRect.m_rcLine);
151 
152   for (const auto& lineRect : m_NewLineRects)
153     Add(lineRect.m_rcLine);
154 }
155 
GetRefreshRects()156 std::vector<CFX_FloatRect>* CPWL_EditImpl::RefreshState::GetRefreshRects() {
157   return &m_RefreshRects;
158 }
159 
EndRefresh()160 void CPWL_EditImpl::RefreshState::EndRefresh() {
161   m_RefreshRects.clear();
162 }
163 
Add(const CFX_FloatRect & new_rect)164 void CPWL_EditImpl::RefreshState::Add(const CFX_FloatRect& new_rect) {
165   // Check for overlapped area.
166   for (const auto& rect : m_RefreshRects) {
167     if (rect.Contains(new_rect))
168       return;
169   }
170   m_RefreshRects.emplace_back(CFX_FloatRect(new_rect));
171 }
172 
173 CPWL_EditImpl::UndoStack::UndoStack() = default;
174 
175 CPWL_EditImpl::UndoStack::~UndoStack() = default;
176 
CanUndo() const177 bool CPWL_EditImpl::UndoStack::CanUndo() const {
178   return m_nCurUndoPos > 0;
179 }
180 
Undo()181 void CPWL_EditImpl::UndoStack::Undo() {
182   DCHECK(!m_bWorking);
183   m_bWorking = true;
184   int nUndoRemain = 1;
185   while (CanUndo() && nUndoRemain > 0) {
186     nUndoRemain += m_UndoItemStack[m_nCurUndoPos - 1]->Undo();
187     m_nCurUndoPos--;
188     nUndoRemain--;
189   }
190   DCHECK_EQ(nUndoRemain, 0);
191   DCHECK(m_bWorking);
192   m_bWorking = false;
193 }
194 
CanRedo() const195 bool CPWL_EditImpl::UndoStack::CanRedo() const {
196   return m_nCurUndoPos < m_UndoItemStack.size();
197 }
198 
Redo()199 void CPWL_EditImpl::UndoStack::Redo() {
200   DCHECK(!m_bWorking);
201   m_bWorking = true;
202   int nRedoRemain = 1;
203   while (CanRedo() && nRedoRemain > 0) {
204     nRedoRemain += m_UndoItemStack[m_nCurUndoPos]->Redo();
205     m_nCurUndoPos++;
206     nRedoRemain--;
207   }
208   DCHECK_EQ(nRedoRemain, 0);
209   DCHECK(m_bWorking);
210   m_bWorking = false;
211 }
212 
AddItem(std::unique_ptr<UndoItemIface> pItem)213 void CPWL_EditImpl::UndoStack::AddItem(std::unique_ptr<UndoItemIface> pItem) {
214   DCHECK(!m_bWorking);
215   DCHECK(pItem);
216   if (CanRedo())
217     RemoveTails();
218 
219   if (m_UndoItemStack.size() >= kEditUndoMaxItems)
220     RemoveHeads();
221 
222   m_UndoItemStack.push_back(std::move(pItem));
223   m_nCurUndoPos = m_UndoItemStack.size();
224 }
225 
RemoveHeads()226 void CPWL_EditImpl::UndoStack::RemoveHeads() {
227   DCHECK(m_UndoItemStack.size() > 1);
228   m_UndoItemStack.pop_front();
229 }
230 
RemoveTails()231 void CPWL_EditImpl::UndoStack::RemoveTails() {
232   while (CanRedo())
233     m_UndoItemStack.pop_back();
234 }
235 
236 class CPWL_EditImpl::UndoInsertWord final
237     : public CPWL_EditImpl::UndoItemIface {
238  public:
239   UndoInsertWord(CPWL_EditImpl* pEdit,
240                  const CPVT_WordPlace& wpOldPlace,
241                  const CPVT_WordPlace& wpNewPlace,
242                  uint16_t word,
243                  FX_Charset charset);
244   ~UndoInsertWord() override;
245 
246   // UndoItemIface:
247   int Redo() override;
248   int Undo() override;
249 
250  private:
251   UnownedPtr<CPWL_EditImpl> m_pEdit;
252 
253   CPVT_WordPlace m_wpOld;
254   CPVT_WordPlace m_wpNew;
255   uint16_t m_Word;
256   FX_Charset m_nCharset;
257 };
258 
UndoInsertWord(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,FX_Charset charset)259 CPWL_EditImpl::UndoInsertWord::UndoInsertWord(CPWL_EditImpl* pEdit,
260                                               const CPVT_WordPlace& wpOldPlace,
261                                               const CPVT_WordPlace& wpNewPlace,
262                                               uint16_t word,
263                                               FX_Charset charset)
264     : m_pEdit(pEdit),
265       m_wpOld(wpOldPlace),
266       m_wpNew(wpNewPlace),
267       m_Word(word),
268       m_nCharset(charset) {
269   DCHECK(m_pEdit);
270 }
271 
272 CPWL_EditImpl::UndoInsertWord::~UndoInsertWord() = default;
273 
Redo()274 int CPWL_EditImpl::UndoInsertWord::Redo() {
275   m_pEdit->SelectNone();
276   m_pEdit->SetCaret(m_wpOld);
277   m_pEdit->InsertWord(m_Word, m_nCharset, false);
278   return 0;
279 }
280 
Undo()281 int CPWL_EditImpl::UndoInsertWord::Undo() {
282   m_pEdit->SelectNone();
283   m_pEdit->SetCaret(m_wpNew);
284   m_pEdit->Backspace(false);
285   return 0;
286 }
287 
288 class CPWL_EditImpl::UndoInsertReturn final
289     : public CPWL_EditImpl::UndoItemIface {
290  public:
291   UndoInsertReturn(CPWL_EditImpl* pEdit,
292                    const CPVT_WordPlace& wpOldPlace,
293                    const CPVT_WordPlace& wpNewPlace);
294   ~UndoInsertReturn() override;
295 
296   // UndoItemIface:
297   int Redo() override;
298   int Undo() override;
299 
300  private:
301   UnownedPtr<CPWL_EditImpl> m_pEdit;
302 
303   CPVT_WordPlace m_wpOld;
304   CPVT_WordPlace m_wpNew;
305 };
306 
UndoInsertReturn(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace)307 CPWL_EditImpl::UndoInsertReturn::UndoInsertReturn(
308     CPWL_EditImpl* pEdit,
309     const CPVT_WordPlace& wpOldPlace,
310     const CPVT_WordPlace& wpNewPlace)
311     : m_pEdit(pEdit), m_wpOld(wpOldPlace), m_wpNew(wpNewPlace) {
312   DCHECK(m_pEdit);
313 }
314 
315 CPWL_EditImpl::UndoInsertReturn::~UndoInsertReturn() = default;
316 
Redo()317 int CPWL_EditImpl::UndoInsertReturn::Redo() {
318   m_pEdit->SelectNone();
319   m_pEdit->SetCaret(m_wpOld);
320   m_pEdit->InsertReturn(false);
321   return 0;
322 }
323 
Undo()324 int CPWL_EditImpl::UndoInsertReturn::Undo() {
325   m_pEdit->SelectNone();
326   m_pEdit->SetCaret(m_wpNew);
327   m_pEdit->Backspace(false);
328   return 0;
329 }
330 
331 class CPWL_EditImpl::UndoReplaceSelection final
332     : public CPWL_EditImpl::UndoItemIface {
333  public:
334   UndoReplaceSelection(CPWL_EditImpl* pEdit, bool bIsEnd);
335   ~UndoReplaceSelection() override;
336 
337   // UndoItemIface:
338   int Redo() override;
339   int Undo() override;
340 
341  private:
IsEnd() const342   bool IsEnd() const { return m_bEnd; }
343 
344   UnownedPtr<CPWL_EditImpl> m_pEdit;
345   const bool m_bEnd;  // indicate whether this is the end of replace action
346 };
347 
UndoReplaceSelection(CPWL_EditImpl * pEdit,bool bIsEnd)348 CPWL_EditImpl::UndoReplaceSelection::UndoReplaceSelection(CPWL_EditImpl* pEdit,
349                                                           bool bIsEnd)
350     : m_pEdit(pEdit), m_bEnd(bIsEnd) {
351   DCHECK(m_pEdit);
352 }
353 
354 CPWL_EditImpl::UndoReplaceSelection::~UndoReplaceSelection() = default;
355 
Redo()356 int CPWL_EditImpl::UndoReplaceSelection::Redo() {
357   m_pEdit->SelectNone();
358   if (IsEnd())
359     return 0;
360   // Redo ClearSelection, InsertText and ReplaceSelection's end marker
361   return 3;
362 }
363 
Undo()364 int CPWL_EditImpl::UndoReplaceSelection::Undo() {
365   m_pEdit->SelectNone();
366   if (!IsEnd())
367     return 0;
368   // Undo InsertText, ClearSelection and ReplaceSelection's beginning
369   // marker
370   return 3;
371 }
372 
373 class CPWL_EditImpl::UndoBackspace final : public CPWL_EditImpl::UndoItemIface {
374  public:
375   UndoBackspace(CPWL_EditImpl* pEdit,
376                 const CPVT_WordPlace& wpOldPlace,
377                 const CPVT_WordPlace& wpNewPlace,
378                 uint16_t word,
379                 FX_Charset charset);
380   ~UndoBackspace() override;
381 
382   // UndoItemIface:
383   int Redo() override;
384   int Undo() override;
385 
386  private:
387   UnownedPtr<CPWL_EditImpl> m_pEdit;
388 
389   CPVT_WordPlace m_wpOld;
390   CPVT_WordPlace m_wpNew;
391   uint16_t m_Word;
392   FX_Charset m_nCharset;
393 };
394 
UndoBackspace(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,FX_Charset charset)395 CPWL_EditImpl::UndoBackspace::UndoBackspace(CPWL_EditImpl* pEdit,
396                                             const CPVT_WordPlace& wpOldPlace,
397                                             const CPVT_WordPlace& wpNewPlace,
398                                             uint16_t word,
399                                             FX_Charset charset)
400     : m_pEdit(pEdit),
401       m_wpOld(wpOldPlace),
402       m_wpNew(wpNewPlace),
403       m_Word(word),
404       m_nCharset(charset) {
405   DCHECK(m_pEdit);
406 }
407 
408 CPWL_EditImpl::UndoBackspace::~UndoBackspace() = default;
409 
Redo()410 int CPWL_EditImpl::UndoBackspace::Redo() {
411   m_pEdit->SelectNone();
412   m_pEdit->SetCaret(m_wpOld);
413   m_pEdit->Backspace(false);
414   return 0;
415 }
416 
Undo()417 int CPWL_EditImpl::UndoBackspace::Undo() {
418   m_pEdit->SelectNone();
419   m_pEdit->SetCaret(m_wpNew);
420   if (m_wpNew.nSecIndex != m_wpOld.nSecIndex)
421     m_pEdit->InsertReturn(false);
422   else
423     m_pEdit->InsertWord(m_Word, m_nCharset, false);
424   return 0;
425 }
426 
427 class CPWL_EditImpl::UndoDelete final : public CPWL_EditImpl::UndoItemIface {
428  public:
429   UndoDelete(CPWL_EditImpl* pEdit,
430              const CPVT_WordPlace& wpOldPlace,
431              const CPVT_WordPlace& wpNewPlace,
432              uint16_t word,
433              FX_Charset charset,
434              bool bSecEnd);
435   ~UndoDelete() override;
436 
437   // UndoItemIface:
438   int Redo() override;
439   int Undo() override;
440 
441  private:
442   UnownedPtr<CPWL_EditImpl> m_pEdit;
443 
444   CPVT_WordPlace m_wpOld;
445   CPVT_WordPlace m_wpNew;
446   uint16_t m_Word;
447   FX_Charset m_nCharset;
448   bool m_bSecEnd;
449 };
450 
UndoDelete(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,uint16_t word,FX_Charset charset,bool bSecEnd)451 CPWL_EditImpl::UndoDelete::UndoDelete(CPWL_EditImpl* pEdit,
452                                       const CPVT_WordPlace& wpOldPlace,
453                                       const CPVT_WordPlace& wpNewPlace,
454                                       uint16_t word,
455                                       FX_Charset charset,
456                                       bool bSecEnd)
457     : m_pEdit(pEdit),
458       m_wpOld(wpOldPlace),
459       m_wpNew(wpNewPlace),
460       m_Word(word),
461       m_nCharset(charset),
462       m_bSecEnd(bSecEnd) {
463   DCHECK(m_pEdit);
464 }
465 
466 CPWL_EditImpl::UndoDelete::~UndoDelete() = default;
467 
Redo()468 int CPWL_EditImpl::UndoDelete::Redo() {
469   m_pEdit->SelectNone();
470   m_pEdit->SetCaret(m_wpOld);
471   m_pEdit->Delete(false);
472   return 0;
473 }
474 
Undo()475 int CPWL_EditImpl::UndoDelete::Undo() {
476   m_pEdit->SelectNone();
477   m_pEdit->SetCaret(m_wpNew);
478   if (m_bSecEnd)
479     m_pEdit->InsertReturn(false);
480   else
481     m_pEdit->InsertWord(m_Word, m_nCharset, false);
482   return 0;
483 }
484 
485 class CPWL_EditImpl::UndoClear final : public CPWL_EditImpl::UndoItemIface {
486  public:
487   UndoClear(CPWL_EditImpl* pEdit,
488             const CPVT_WordRange& wrSel,
489             const WideString& swText);
490   ~UndoClear() override;
491 
492   // UndoItemIface:
493   int Redo() override;
494   int Undo() override;
495 
496  private:
497   UnownedPtr<CPWL_EditImpl> m_pEdit;
498 
499   CPVT_WordRange m_wrSel;
500   WideString m_swText;
501 };
502 
UndoClear(CPWL_EditImpl * pEdit,const CPVT_WordRange & wrSel,const WideString & swText)503 CPWL_EditImpl::UndoClear::UndoClear(CPWL_EditImpl* pEdit,
504                                     const CPVT_WordRange& wrSel,
505                                     const WideString& swText)
506     : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {
507   DCHECK(m_pEdit);
508 }
509 
510 CPWL_EditImpl::UndoClear::~UndoClear() = default;
511 
Redo()512 int CPWL_EditImpl::UndoClear::Redo() {
513   m_pEdit->SelectNone();
514   m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
515   m_pEdit->Clear(false);
516   return 0;
517 }
518 
Undo()519 int CPWL_EditImpl::UndoClear::Undo() {
520   m_pEdit->SelectNone();
521   m_pEdit->SetCaret(m_wrSel.BeginPos);
522   m_pEdit->InsertText(m_swText, FX_Charset::kDefault, false);
523   m_pEdit->SetSelection(m_wrSel.BeginPos, m_wrSel.EndPos);
524   return 0;
525 }
526 
527 class CPWL_EditImpl::UndoInsertText final
528     : public CPWL_EditImpl::UndoItemIface {
529  public:
530   UndoInsertText(CPWL_EditImpl* pEdit,
531                  const CPVT_WordPlace& wpOldPlace,
532                  const CPVT_WordPlace& wpNewPlace,
533                  const WideString& swText,
534                  FX_Charset charset);
535   ~UndoInsertText() override;
536 
537   // UndoItemIface:
538   int Redo() override;
539   int Undo() override;
540 
541  private:
542   UnownedPtr<CPWL_EditImpl> m_pEdit;
543 
544   CPVT_WordPlace m_wpOld;
545   CPVT_WordPlace m_wpNew;
546   WideString m_swText;
547   FX_Charset m_nCharset;
548 };
549 
UndoInsertText(CPWL_EditImpl * pEdit,const CPVT_WordPlace & wpOldPlace,const CPVT_WordPlace & wpNewPlace,const WideString & swText,FX_Charset charset)550 CPWL_EditImpl::UndoInsertText::UndoInsertText(CPWL_EditImpl* pEdit,
551                                               const CPVT_WordPlace& wpOldPlace,
552                                               const CPVT_WordPlace& wpNewPlace,
553                                               const WideString& swText,
554                                               FX_Charset charset)
555     : m_pEdit(pEdit),
556       m_wpOld(wpOldPlace),
557       m_wpNew(wpNewPlace),
558       m_swText(swText),
559       m_nCharset(charset) {
560   DCHECK(m_pEdit);
561 }
562 
563 CPWL_EditImpl::UndoInsertText::~UndoInsertText() = default;
564 
Redo()565 int CPWL_EditImpl::UndoInsertText::Redo() {
566   m_pEdit->SelectNone();
567   m_pEdit->SetCaret(m_wpOld);
568   m_pEdit->InsertText(m_swText, m_nCharset, false);
569   return 0;
570 }
571 
Undo()572 int CPWL_EditImpl::UndoInsertText::Undo() {
573   m_pEdit->SelectNone();
574   m_pEdit->SetSelection(m_wpOld, m_wpNew);
575   m_pEdit->Clear(false);
576   return 0;
577 }
578 
DrawEdit(CFX_RenderDevice * pDevice,const CFX_Matrix & mtUser2Device,FX_COLORREF crTextFill,const CFX_FloatRect & rcClip,const CFX_PointF & ptOffset,const CPVT_WordRange * pRange,IPWL_FillerNotify * pFillerNotify,IPWL_FillerNotify::PerWindowData * pSystemData)579 void CPWL_EditImpl::DrawEdit(CFX_RenderDevice* pDevice,
580                              const CFX_Matrix& mtUser2Device,
581                              FX_COLORREF crTextFill,
582                              const CFX_FloatRect& rcClip,
583                              const CFX_PointF& ptOffset,
584                              const CPVT_WordRange* pRange,
585                              IPWL_FillerNotify* pFillerNotify,
586                              IPWL_FillerNotify::PerWindowData* pSystemData) {
587   const bool bContinuous = GetCharArray() == 0;
588   uint16_t SubWord = GetPasswordChar();
589   float fFontSize = GetFontSize();
590   CPVT_WordRange wrSelect = GetSelectWordRange();
591   FX_COLORREF crCurFill = crTextFill;
592   FX_COLORREF crOldFill = crCurFill;
593   bool bSelect = false;
594   const FX_COLORREF crWhite = ArgbEncode(255, 255, 255, 255);
595   const FX_COLORREF crSelBK = ArgbEncode(255, 0, 51, 113);
596 
597   int32_t nFontIndex = -1;
598   CFX_PointF ptBT;
599   CFX_RenderDevice::StateRestorer restorer(pDevice);
600   if (!rcClip.IsEmpty())
601     pDevice->SetClip_Rect(mtUser2Device.TransformRect(rcClip).ToFxRect());
602 
603   Iterator* pIterator = GetIterator();
604   IPVT_FontMap* pFontMap = GetFontMap();
605   if (!pFontMap)
606     return;
607 
608   if (pRange)
609     pIterator->SetAt(pRange->BeginPos);
610   else
611     pIterator->SetAt(0);
612 
613   ByteString sTextBuf;
614   CPVT_WordPlace oldplace;
615   while (pIterator->NextWord()) {
616     CPVT_WordPlace place = pIterator->GetAt();
617     if (pRange && place > pRange->EndPos)
618       break;
619 
620     if (!wrSelect.IsEmpty()) {
621       bSelect = place > wrSelect.BeginPos && place <= wrSelect.EndPos;
622       crCurFill = bSelect ? crWhite : crTextFill;
623     }
624     if (pFillerNotify->IsSelectionImplemented()) {
625       crCurFill = crTextFill;
626       crOldFill = crCurFill;
627     }
628     CPVT_Word word;
629     if (pIterator->GetWord(word)) {
630       if (bSelect) {
631         CPVT_Line line;
632         pIterator->GetLine(line);
633         if (pFillerNotify->IsSelectionImplemented()) {
634           CFX_FloatRect rc(word.ptWord.x, line.ptLine.y + line.fLineDescent,
635                            word.ptWord.x + word.fWidth,
636                            line.ptLine.y + line.fLineAscent);
637           rc.Intersect(rcClip);
638           pFillerNotify->OutputSelectedRect(pSystemData, rc);
639         } else {
640           CFX_Path pathSelBK;
641           pathSelBK.AppendRect(word.ptWord.x, line.ptLine.y + line.fLineDescent,
642                                word.ptWord.x + word.fWidth,
643                                line.ptLine.y + line.fLineAscent);
644 
645           pDevice->DrawPath(pathSelBK, &mtUser2Device, nullptr, crSelBK, 0,
646                             CFX_FillRenderOptions::WindingOptions());
647         }
648       }
649       if (bContinuous) {
650         if (place.LineCmp(oldplace) != 0 || word.nFontIndex != nFontIndex ||
651             crOldFill != crCurFill) {
652           if (!sTextBuf.IsEmpty()) {
653             DrawTextString(pDevice,
654                            CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
655                            pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
656                            mtUser2Device, sTextBuf, crOldFill);
657             sTextBuf.clear();
658           }
659           nFontIndex = word.nFontIndex;
660           ptBT = word.ptWord;
661           crOldFill = crCurFill;
662         }
663         sTextBuf += GetPDFWordString(word.nFontIndex, word.Word, SubWord);
664       } else {
665         DrawTextString(
666             pDevice,
667             CFX_PointF(word.ptWord.x + ptOffset.x, word.ptWord.y + ptOffset.y),
668             pFontMap->GetPDFFont(word.nFontIndex).Get(), fFontSize,
669             mtUser2Device,
670             GetPDFWordString(word.nFontIndex, word.Word, SubWord), crCurFill);
671       }
672       oldplace = place;
673     }
674   }
675   if (!sTextBuf.IsEmpty()) {
676     DrawTextString(pDevice,
677                    CFX_PointF(ptBT.x + ptOffset.x, ptBT.y + ptOffset.y),
678                    pFontMap->GetPDFFont(nFontIndex).Get(), fFontSize,
679                    mtUser2Device, sTextBuf, crOldFill);
680   }
681 }
682 
CPWL_EditImpl()683 CPWL_EditImpl::CPWL_EditImpl()
684     : m_pVT(std::make_unique<CPVT_VariableText>(nullptr)) {}
685 
686 CPWL_EditImpl::~CPWL_EditImpl() = default;
687 
Initialize()688 void CPWL_EditImpl::Initialize() {
689   m_pVT->Initialize();
690   SetCaret(m_pVT->GetBeginWordPlace());
691   SetCaretOrigin();
692 }
693 
SetFontMap(IPVT_FontMap * pFontMap)694 void CPWL_EditImpl::SetFontMap(IPVT_FontMap* pFontMap) {
695   m_pVTProvider = std::make_unique<Provider>(pFontMap);
696   m_pVT->SetProvider(m_pVTProvider.get());
697 }
698 
SetNotify(CPWL_Edit * pNotify)699 void CPWL_EditImpl::SetNotify(CPWL_Edit* pNotify) {
700   m_pNotify = pNotify;
701 }
702 
GetIterator()703 CPWL_EditImpl::Iterator* CPWL_EditImpl::GetIterator() {
704   if (!m_pIterator)
705     m_pIterator = std::make_unique<Iterator>(this, m_pVT->GetIterator());
706   return m_pIterator.get();
707 }
708 
GetFontMap()709 IPVT_FontMap* CPWL_EditImpl::GetFontMap() {
710   return m_pVTProvider ? m_pVTProvider->GetFontMap() : nullptr;
711 }
712 
SetPlateRect(const CFX_FloatRect & rect)713 void CPWL_EditImpl::SetPlateRect(const CFX_FloatRect& rect) {
714   m_pVT->SetPlateRect(rect);
715   m_ptScrollPos = CFX_PointF(rect.left, rect.top);
716 }
717 
SetAlignmentH(int32_t nFormat)718 void CPWL_EditImpl::SetAlignmentH(int32_t nFormat) {
719   m_pVT->SetAlignment(nFormat);
720 }
721 
SetAlignmentV(int32_t nFormat)722 void CPWL_EditImpl::SetAlignmentV(int32_t nFormat) {
723   m_nAlignment = nFormat;
724 }
725 
SetPasswordChar(uint16_t wSubWord)726 void CPWL_EditImpl::SetPasswordChar(uint16_t wSubWord) {
727   m_pVT->SetPasswordChar(wSubWord);
728 }
729 
SetLimitChar(int32_t nLimitChar)730 void CPWL_EditImpl::SetLimitChar(int32_t nLimitChar) {
731   m_pVT->SetLimitChar(nLimitChar);
732 }
733 
SetCharArray(int32_t nCharArray)734 void CPWL_EditImpl::SetCharArray(int32_t nCharArray) {
735   m_pVT->SetCharArray(nCharArray);
736 }
737 
SetMultiLine(bool bMultiLine)738 void CPWL_EditImpl::SetMultiLine(bool bMultiLine) {
739   m_pVT->SetMultiLine(bMultiLine);
740 }
741 
SetAutoReturn(bool bAuto)742 void CPWL_EditImpl::SetAutoReturn(bool bAuto) {
743   m_pVT->SetAutoReturn(bAuto);
744 }
745 
SetAutoFontSize(bool bAuto)746 void CPWL_EditImpl::SetAutoFontSize(bool bAuto) {
747   m_pVT->SetAutoFontSize(bAuto);
748 }
749 
SetFontSize(float fFontSize)750 void CPWL_EditImpl::SetFontSize(float fFontSize) {
751   m_pVT->SetFontSize(fFontSize);
752 }
753 
SetAutoScroll(bool bAuto)754 void CPWL_EditImpl::SetAutoScroll(bool bAuto) {
755   m_bEnableScroll = bAuto;
756 }
757 
SetTextOverflow(bool bAllowed)758 void CPWL_EditImpl::SetTextOverflow(bool bAllowed) {
759   m_bEnableOverflow = bAllowed;
760 }
761 
SetSelection(int32_t nStartChar,int32_t nEndChar)762 void CPWL_EditImpl::SetSelection(int32_t nStartChar, int32_t nEndChar) {
763   if (m_pVT->IsValid()) {
764     if (nStartChar == 0 && nEndChar < 0) {
765       SelectAll();
766     } else if (nStartChar < 0) {
767       SelectNone();
768     } else {
769       if (nStartChar < nEndChar) {
770         SetSelection(m_pVT->WordIndexToWordPlace(nStartChar),
771                      m_pVT->WordIndexToWordPlace(nEndChar));
772       } else {
773         SetSelection(m_pVT->WordIndexToWordPlace(nEndChar),
774                      m_pVT->WordIndexToWordPlace(nStartChar));
775       }
776     }
777   }
778 }
779 
SetSelection(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)780 void CPWL_EditImpl::SetSelection(const CPVT_WordPlace& begin,
781                                  const CPVT_WordPlace& end) {
782   if (!m_pVT->IsValid())
783     return;
784 
785   SelectNone();
786   m_SelState.Set(begin, end);
787   SetCaret(m_SelState.EndPos);
788   ScrollToCaret();
789   if (!m_SelState.IsEmpty())
790     Refresh();
791   SetCaretInfo();
792 }
793 
GetSelection() const794 std::pair<int32_t, int32_t> CPWL_EditImpl::GetSelection() const {
795   if (!m_pVT->IsValid())
796     return std::make_pair(-1, -1);
797 
798   if (m_SelState.IsEmpty()) {
799     return std::make_pair(m_pVT->WordPlaceToWordIndex(m_wpCaret),
800                           m_pVT->WordPlaceToWordIndex(m_wpCaret));
801   }
802   if (m_SelState.BeginPos < m_SelState.EndPos) {
803     return std::make_pair(m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos),
804                           m_pVT->WordPlaceToWordIndex(m_SelState.EndPos));
805   }
806   return std::make_pair(m_pVT->WordPlaceToWordIndex(m_SelState.EndPos),
807                         m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos));
808 }
809 
GetCaret() const810 int32_t CPWL_EditImpl::GetCaret() const {
811   if (m_pVT->IsValid())
812     return m_pVT->WordPlaceToWordIndex(m_wpCaret);
813 
814   return -1;
815 }
816 
GetCaretWordPlace() const817 CPVT_WordPlace CPWL_EditImpl::GetCaretWordPlace() const {
818   return m_wpCaret;
819 }
820 
GetText() const821 WideString CPWL_EditImpl::GetText() const {
822   WideString swRet;
823   if (!m_pVT->IsValid())
824     return swRet;
825 
826   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
827   pIterator->SetAt(0);
828 
829   CPVT_Word wordinfo;
830   CPVT_WordPlace oldplace = pIterator->GetWordPlace();
831   while (pIterator->NextWord()) {
832     CPVT_WordPlace place = pIterator->GetWordPlace();
833     if (pIterator->GetWord(wordinfo))
834       swRet += wordinfo.Word;
835     if (oldplace.nSecIndex != place.nSecIndex)
836       swRet += L"\r\n";
837     oldplace = place;
838   }
839   return swRet;
840 }
841 
GetRangeText(const CPVT_WordRange & range) const842 WideString CPWL_EditImpl::GetRangeText(const CPVT_WordRange& range) const {
843   WideString swRet;
844   if (!m_pVT->IsValid())
845     return swRet;
846 
847   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
848   CPVT_WordRange wrTemp = range;
849   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
850   m_pVT->UpdateWordPlace(wrTemp.EndPos);
851   pIterator->SetAt(wrTemp.BeginPos);
852 
853   CPVT_Word wordinfo;
854   CPVT_WordPlace oldplace = wrTemp.BeginPos;
855   while (pIterator->NextWord()) {
856     CPVT_WordPlace place = pIterator->GetWordPlace();
857     if (place > wrTemp.EndPos)
858       break;
859     if (pIterator->GetWord(wordinfo))
860       swRet += wordinfo.Word;
861     if (oldplace.nSecIndex != place.nSecIndex)
862       swRet += L"\r\n";
863     oldplace = place;
864   }
865   return swRet;
866 }
867 
GetSelectedText() const868 WideString CPWL_EditImpl::GetSelectedText() const {
869   return GetRangeText(m_SelState.ConvertToWordRange());
870 }
871 
GetTotalLines() const872 int32_t CPWL_EditImpl::GetTotalLines() const {
873   int32_t nLines = 1;
874 
875   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
876   pIterator->SetAt(0);
877   while (pIterator->NextLine())
878     ++nLines;
879 
880   return nLines;
881 }
882 
GetSelectWordRange() const883 CPVT_WordRange CPWL_EditImpl::GetSelectWordRange() const {
884   return m_SelState.ConvertToWordRange();
885 }
886 
SetText(const WideString & sText)887 void CPWL_EditImpl::SetText(const WideString& sText) {
888   Clear();
889   DoInsertText(CPVT_WordPlace(0, 0, -1), sText, FX_Charset::kDefault);
890 }
891 
InsertWord(uint16_t word,FX_Charset charset)892 bool CPWL_EditImpl::InsertWord(uint16_t word, FX_Charset charset) {
893   return InsertWord(word, charset, true);
894 }
895 
InsertReturn()896 bool CPWL_EditImpl::InsertReturn() {
897   return InsertReturn(true);
898 }
899 
Backspace()900 bool CPWL_EditImpl::Backspace() {
901   return Backspace(true);
902 }
903 
Delete()904 bool CPWL_EditImpl::Delete() {
905   return Delete(true);
906 }
907 
ClearSelection()908 bool CPWL_EditImpl::ClearSelection() {
909   return Clear(true);
910 }
911 
InsertText(const WideString & sText,FX_Charset charset)912 bool CPWL_EditImpl::InsertText(const WideString& sText, FX_Charset charset) {
913   return InsertText(sText, charset, true);
914 }
915 
GetFontSize() const916 float CPWL_EditImpl::GetFontSize() const {
917   return m_pVT->GetFontSize();
918 }
919 
GetPasswordChar() const920 uint16_t CPWL_EditImpl::GetPasswordChar() const {
921   return m_pVT->GetPasswordChar();
922 }
923 
GetCharArray() const924 int32_t CPWL_EditImpl::GetCharArray() const {
925   return m_pVT->GetCharArray();
926 }
927 
GetContentRect() const928 CFX_FloatRect CPWL_EditImpl::GetContentRect() const {
929   return VTToEdit(m_pVT->GetContentRect());
930 }
931 
GetWholeWordRange() const932 CPVT_WordRange CPWL_EditImpl::GetWholeWordRange() const {
933   if (m_pVT->IsValid())
934     return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
935 
936   return CPVT_WordRange();
937 }
938 
GetVisibleWordRange() const939 CPVT_WordRange CPWL_EditImpl::GetVisibleWordRange() const {
940   if (m_bEnableOverflow)
941     return GetWholeWordRange();
942 
943   if (m_pVT->IsValid()) {
944     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
945 
946     CPVT_WordPlace place1 =
947         m_pVT->SearchWordPlace(EditToVT(CFX_PointF(rcPlate.left, rcPlate.top)));
948     CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
949         EditToVT(CFX_PointF(rcPlate.right, rcPlate.bottom)));
950 
951     return CPVT_WordRange(place1, place2);
952   }
953 
954   return CPVT_WordRange();
955 }
956 
SearchWordPlace(const CFX_PointF & point) const957 CPVT_WordPlace CPWL_EditImpl::SearchWordPlace(const CFX_PointF& point) const {
958   if (m_pVT->IsValid()) {
959     return m_pVT->SearchWordPlace(EditToVT(point));
960   }
961 
962   return CPVT_WordPlace();
963 }
964 
Paint()965 void CPWL_EditImpl::Paint() {
966   if (m_pVT->IsValid()) {
967     RearrangeAll();
968     ScrollToCaret();
969     Refresh();
970     SetCaretOrigin();
971     SetCaretInfo();
972   }
973 }
974 
RearrangeAll()975 void CPWL_EditImpl::RearrangeAll() {
976   if (m_pVT->IsValid()) {
977     m_pVT->UpdateWordPlace(m_wpCaret);
978     m_pVT->RearrangeAll();
979     m_pVT->UpdateWordPlace(m_wpCaret);
980     SetScrollInfo();
981     SetContentChanged();
982   }
983 }
984 
RearrangePart(const CPVT_WordRange & range)985 void CPWL_EditImpl::RearrangePart(const CPVT_WordRange& range) {
986   if (m_pVT->IsValid()) {
987     m_pVT->UpdateWordPlace(m_wpCaret);
988     m_pVT->RearrangePart(range);
989     m_pVT->UpdateWordPlace(m_wpCaret);
990     SetScrollInfo();
991     SetContentChanged();
992   }
993 }
994 
SetContentChanged()995 void CPWL_EditImpl::SetContentChanged() {
996   if (m_pNotify) {
997     CFX_FloatRect rcContent = m_pVT->GetContentRect();
998     if (rcContent.Width() != m_rcOldContent.Width() ||
999         rcContent.Height() != m_rcOldContent.Height()) {
1000       m_rcOldContent = rcContent;
1001     }
1002   }
1003 }
1004 
SelectAll()1005 void CPWL_EditImpl::SelectAll() {
1006   if (!m_pVT->IsValid())
1007     return;
1008   m_SelState = SelectState(GetWholeWordRange());
1009   SetCaret(m_SelState.EndPos);
1010   ScrollToCaret();
1011   Refresh();
1012   SetCaretInfo();
1013 }
1014 
SelectNone()1015 void CPWL_EditImpl::SelectNone() {
1016   if (!m_pVT->IsValid() || m_SelState.IsEmpty())
1017     return;
1018 
1019   m_SelState.Reset();
1020   Refresh();
1021 }
1022 
IsSelected() const1023 bool CPWL_EditImpl::IsSelected() const {
1024   return !m_SelState.IsEmpty();
1025 }
1026 
VTToEdit(const CFX_PointF & point) const1027 CFX_PointF CPWL_EditImpl::VTToEdit(const CFX_PointF& point) const {
1028   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1029   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1030 
1031   float fPadding = 0.0f;
1032 
1033   switch (m_nAlignment) {
1034     case 0:
1035       fPadding = 0.0f;
1036       break;
1037     case 1:
1038       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1039       break;
1040     case 2:
1041       fPadding = rcPlate.Height() - rcContent.Height();
1042       break;
1043   }
1044 
1045   return CFX_PointF(point.x - (m_ptScrollPos.x - rcPlate.left),
1046                     point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
1047 }
1048 
EditToVT(const CFX_PointF & point) const1049 CFX_PointF CPWL_EditImpl::EditToVT(const CFX_PointF& point) const {
1050   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1051   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1052 
1053   float fPadding = 0.0f;
1054 
1055   switch (m_nAlignment) {
1056     case 0:
1057       fPadding = 0.0f;
1058       break;
1059     case 1:
1060       fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1061       break;
1062     case 2:
1063       fPadding = rcPlate.Height() - rcContent.Height();
1064       break;
1065   }
1066 
1067   return CFX_PointF(point.x + (m_ptScrollPos.x - rcPlate.left),
1068                     point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
1069 }
1070 
VTToEdit(const CFX_FloatRect & rect) const1071 CFX_FloatRect CPWL_EditImpl::VTToEdit(const CFX_FloatRect& rect) const {
1072   CFX_PointF ptLeftBottom = VTToEdit(CFX_PointF(rect.left, rect.bottom));
1073   CFX_PointF ptRightTop = VTToEdit(CFX_PointF(rect.right, rect.top));
1074 
1075   return CFX_FloatRect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x,
1076                        ptRightTop.y);
1077 }
1078 
SetScrollInfo()1079 void CPWL_EditImpl::SetScrollInfo() {
1080   if (!m_pNotify)
1081     return;
1082 
1083   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1084   CFX_FloatRect rcContent = m_pVT->GetContentRect();
1085   if (m_bNotifyFlag)
1086     return;
1087 
1088   AutoRestorer<bool> restorer(&m_bNotifyFlag);
1089   m_bNotifyFlag = true;
1090 
1091   PWL_SCROLL_INFO Info;
1092   Info.fPlateWidth = rcPlate.top - rcPlate.bottom;
1093   Info.fContentMin = rcContent.bottom;
1094   Info.fContentMax = rcContent.top;
1095   Info.fSmallStep = rcPlate.Height() / 3;
1096   Info.fBigStep = rcPlate.Height();
1097   m_pNotify->SetScrollInfo(Info);
1098 }
1099 
SetScrollPosX(float fx)1100 void CPWL_EditImpl::SetScrollPosX(float fx) {
1101   if (!m_bEnableScroll)
1102     return;
1103 
1104   if (m_pVT->IsValid()) {
1105     if (!FXSYS_IsFloatEqual(m_ptScrollPos.x, fx)) {
1106       m_ptScrollPos.x = fx;
1107       Refresh();
1108     }
1109   }
1110 }
1111 
SetScrollPosY(float fy)1112 void CPWL_EditImpl::SetScrollPosY(float fy) {
1113   if (!m_bEnableScroll)
1114     return;
1115 
1116   if (m_pVT->IsValid()) {
1117     if (!FXSYS_IsFloatEqual(m_ptScrollPos.y, fy)) {
1118       m_ptScrollPos.y = fy;
1119       Refresh();
1120 
1121       if (m_pNotify) {
1122         if (!m_bNotifyFlag) {
1123           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1124           m_bNotifyFlag = true;
1125           m_pNotify->SetScrollPosition(fy);
1126         }
1127       }
1128     }
1129   }
1130 }
1131 
SetScrollPos(const CFX_PointF & point)1132 void CPWL_EditImpl::SetScrollPos(const CFX_PointF& point) {
1133   SetScrollPosX(point.x);
1134   SetScrollPosY(point.y);
1135   SetScrollLimit();
1136   SetCaretInfo();
1137 }
1138 
GetScrollPos() const1139 CFX_PointF CPWL_EditImpl::GetScrollPos() const {
1140   return m_ptScrollPos;
1141 }
1142 
SetScrollLimit()1143 void CPWL_EditImpl::SetScrollLimit() {
1144   if (m_pVT->IsValid()) {
1145     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1146     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1147 
1148     if (rcPlate.Width() > rcContent.Width()) {
1149       SetScrollPosX(rcPlate.left);
1150     } else {
1151       if (FXSYS_IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
1152         SetScrollPosX(rcContent.left);
1153       } else if (FXSYS_IsFloatBigger(m_ptScrollPos.x,
1154                                      rcContent.right - rcPlate.Width())) {
1155         SetScrollPosX(rcContent.right - rcPlate.Width());
1156       }
1157     }
1158 
1159     if (rcPlate.Height() > rcContent.Height()) {
1160       SetScrollPosY(rcPlate.top);
1161     } else {
1162       if (FXSYS_IsFloatSmaller(m_ptScrollPos.y,
1163                                rcContent.bottom + rcPlate.Height())) {
1164         SetScrollPosY(rcContent.bottom + rcPlate.Height());
1165       } else if (FXSYS_IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
1166         SetScrollPosY(rcContent.top);
1167       }
1168     }
1169   }
1170 }
1171 
ScrollToCaret()1172 void CPWL_EditImpl::ScrollToCaret() {
1173   SetScrollLimit();
1174 
1175   if (!m_pVT->IsValid())
1176     return;
1177 
1178   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1179   pIterator->SetAt(m_wpCaret);
1180 
1181   CFX_PointF ptHead;
1182   CFX_PointF ptFoot;
1183   CPVT_Word word;
1184   CPVT_Line line;
1185   if (pIterator->GetWord(word)) {
1186     ptHead.x = word.ptWord.x + word.fWidth;
1187     ptHead.y = word.ptWord.y + word.fAscent;
1188     ptFoot.x = word.ptWord.x + word.fWidth;
1189     ptFoot.y = word.ptWord.y + word.fDescent;
1190   } else if (pIterator->GetLine(line)) {
1191     ptHead.x = line.ptLine.x;
1192     ptHead.y = line.ptLine.y + line.fLineAscent;
1193     ptFoot.x = line.ptLine.x;
1194     ptFoot.y = line.ptLine.y + line.fLineDescent;
1195   }
1196 
1197   CFX_PointF ptHeadEdit = VTToEdit(ptHead);
1198   CFX_PointF ptFootEdit = VTToEdit(ptFoot);
1199   CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1200   if (!FXSYS_IsFloatEqual(rcPlate.left, rcPlate.right)) {
1201     if (FXSYS_IsFloatSmaller(ptHeadEdit.x, rcPlate.left) ||
1202         FXSYS_IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
1203       SetScrollPosX(ptHead.x);
1204     } else if (FXSYS_IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
1205       SetScrollPosX(ptHead.x - rcPlate.Width());
1206     }
1207   }
1208 
1209   if (!FXSYS_IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
1210     if (FXSYS_IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
1211         FXSYS_IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
1212       if (FXSYS_IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
1213         SetScrollPosY(ptFoot.y + rcPlate.Height());
1214       }
1215     } else if (FXSYS_IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
1216       if (FXSYS_IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
1217         SetScrollPosY(ptHead.y);
1218       }
1219     }
1220   }
1221 }
1222 
Refresh()1223 void CPWL_EditImpl::Refresh() {
1224   if (m_bEnableRefresh && m_pVT->IsValid()) {
1225     m_Refresh.BeginRefresh();
1226     RefreshPushLineRects(GetVisibleWordRange());
1227 
1228     m_Refresh.NoAnalyse();
1229     m_ptRefreshScrollPos = m_ptScrollPos;
1230 
1231     if (m_pNotify) {
1232       if (!m_bNotifyFlag) {
1233         AutoRestorer<bool> restorer(&m_bNotifyFlag);
1234         m_bNotifyFlag = true;
1235         std::vector<CFX_FloatRect>* pRects = m_Refresh.GetRefreshRects();
1236         for (auto& rect : *pRects) {
1237           if (!m_pNotify->InvalidateRect(&rect)) {
1238             m_pNotify = nullptr;  // Gone, dangling even.
1239             break;
1240           }
1241         }
1242       }
1243     }
1244 
1245     m_Refresh.EndRefresh();
1246   }
1247 }
1248 
RefreshPushLineRects(const CPVT_WordRange & wr)1249 void CPWL_EditImpl::RefreshPushLineRects(const CPVT_WordRange& wr) {
1250   if (!m_pVT->IsValid())
1251     return;
1252 
1253   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1254   CPVT_WordPlace wpBegin = wr.BeginPos;
1255   m_pVT->UpdateWordPlace(wpBegin);
1256   CPVT_WordPlace wpEnd = wr.EndPos;
1257   m_pVT->UpdateWordPlace(wpEnd);
1258   pIterator->SetAt(wpBegin);
1259 
1260   CPVT_Line lineinfo;
1261   do {
1262     if (!pIterator->GetLine(lineinfo))
1263       break;
1264     if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
1265       break;
1266 
1267     CFX_FloatRect rcLine(lineinfo.ptLine.x,
1268                          lineinfo.ptLine.y + lineinfo.fLineDescent,
1269                          lineinfo.ptLine.x + lineinfo.fLineWidth,
1270                          lineinfo.ptLine.y + lineinfo.fLineAscent);
1271 
1272     m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
1273                    VTToEdit(rcLine));
1274   } while (pIterator->NextLine());
1275 }
1276 
RefreshWordRange(const CPVT_WordRange & wr)1277 void CPWL_EditImpl::RefreshWordRange(const CPVT_WordRange& wr) {
1278   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1279   CPVT_WordRange wrTemp = wr;
1280 
1281   m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1282   m_pVT->UpdateWordPlace(wrTemp.EndPos);
1283   pIterator->SetAt(wrTemp.BeginPos);
1284 
1285   CPVT_Word wordinfo;
1286   CPVT_Line lineinfo;
1287   CPVT_WordPlace place;
1288 
1289   while (pIterator->NextWord()) {
1290     place = pIterator->GetWordPlace();
1291     if (place > wrTemp.EndPos)
1292       break;
1293 
1294     pIterator->GetWord(wordinfo);
1295     pIterator->GetLine(lineinfo);
1296     if (place.LineCmp(wrTemp.BeginPos) == 0 ||
1297         place.LineCmp(wrTemp.EndPos) == 0) {
1298       CFX_FloatRect rcWord(wordinfo.ptWord.x,
1299                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1300                            wordinfo.ptWord.x + wordinfo.fWidth,
1301                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1302 
1303       if (m_pNotify) {
1304         if (!m_bNotifyFlag) {
1305           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1306           m_bNotifyFlag = true;
1307           CFX_FloatRect rcRefresh = VTToEdit(rcWord);
1308           if (!m_pNotify->InvalidateRect(&rcRefresh)) {
1309             m_pNotify = nullptr;  // Gone, dangling even.
1310           }
1311         }
1312       }
1313     } else {
1314       CFX_FloatRect rcLine(lineinfo.ptLine.x,
1315                            lineinfo.ptLine.y + lineinfo.fLineDescent,
1316                            lineinfo.ptLine.x + lineinfo.fLineWidth,
1317                            lineinfo.ptLine.y + lineinfo.fLineAscent);
1318 
1319       if (m_pNotify) {
1320         if (!m_bNotifyFlag) {
1321           AutoRestorer<bool> restorer(&m_bNotifyFlag);
1322           m_bNotifyFlag = true;
1323           CFX_FloatRect rcRefresh = VTToEdit(rcLine);
1324           if (!m_pNotify->InvalidateRect(&rcRefresh)) {
1325             m_pNotify = nullptr;  // Gone, dangling even.
1326           }
1327         }
1328       }
1329 
1330       pIterator->NextLine();
1331     }
1332   }
1333 }
1334 
SetCaret(const CPVT_WordPlace & place)1335 void CPWL_EditImpl::SetCaret(const CPVT_WordPlace& place) {
1336   m_wpOldCaret = m_wpCaret;
1337   m_wpCaret = place;
1338 }
1339 
SetCaretInfo()1340 void CPWL_EditImpl::SetCaretInfo() {
1341   if (m_pNotify) {
1342     if (!m_bNotifyFlag) {
1343       CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1344       pIterator->SetAt(m_wpCaret);
1345 
1346       CFX_PointF ptHead;
1347       CFX_PointF ptFoot;
1348       CPVT_Word word;
1349       CPVT_Line line;
1350       if (pIterator->GetWord(word)) {
1351         ptHead.x = word.ptWord.x + word.fWidth;
1352         ptHead.y = word.ptWord.y + word.fAscent;
1353         ptFoot.x = word.ptWord.x + word.fWidth;
1354         ptFoot.y = word.ptWord.y + word.fDescent;
1355       } else if (pIterator->GetLine(line)) {
1356         ptHead.x = line.ptLine.x;
1357         ptHead.y = line.ptLine.y + line.fLineAscent;
1358         ptFoot.x = line.ptLine.x;
1359         ptFoot.y = line.ptLine.y + line.fLineDescent;
1360       }
1361 
1362       AutoRestorer<bool> restorer(&m_bNotifyFlag);
1363       m_bNotifyFlag = true;
1364       m_pNotify->SetCaret(m_SelState.IsEmpty(), VTToEdit(ptHead),
1365                           VTToEdit(ptFoot));
1366     }
1367   }
1368 }
1369 
OnMouseDown(const CFX_PointF & point,bool bShift,bool bCtrl)1370 void CPWL_EditImpl::OnMouseDown(const CFX_PointF& point,
1371                                 bool bShift,
1372                                 bool bCtrl) {
1373   if (!m_pVT->IsValid())
1374     return;
1375 
1376   SelectNone();
1377   SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1378   m_SelState.Set(m_wpCaret, m_wpCaret);
1379   ScrollToCaret();
1380   SetCaretOrigin();
1381   SetCaretInfo();
1382 }
1383 
OnMouseMove(const CFX_PointF & point,bool bShift,bool bCtrl)1384 void CPWL_EditImpl::OnMouseMove(const CFX_PointF& point,
1385                                 bool bShift,
1386                                 bool bCtrl) {
1387   if (!m_pVT->IsValid())
1388     return;
1389 
1390   SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
1391   if (m_wpCaret == m_wpOldCaret)
1392     return;
1393 
1394   m_SelState.SetEndPos(m_wpCaret);
1395   ScrollToCaret();
1396   Refresh();
1397   SetCaretOrigin();
1398   SetCaretInfo();
1399 }
1400 
OnVK_UP(bool bShift)1401 void CPWL_EditImpl::OnVK_UP(bool bShift) {
1402   if (!m_pVT->IsValid())
1403     return;
1404 
1405   SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
1406   if (bShift) {
1407     if (m_SelState.IsEmpty())
1408       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1409     else
1410       m_SelState.SetEndPos(m_wpCaret);
1411 
1412     if (m_wpOldCaret != m_wpCaret) {
1413       ScrollToCaret();
1414       Refresh();
1415       SetCaretInfo();
1416     }
1417   } else {
1418     SelectNone();
1419     ScrollToCaret();
1420     SetCaretInfo();
1421   }
1422 }
1423 
OnVK_DOWN(bool bShift)1424 void CPWL_EditImpl::OnVK_DOWN(bool bShift) {
1425   if (!m_pVT->IsValid())
1426     return;
1427 
1428   SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
1429   if (bShift) {
1430     if (m_SelState.IsEmpty())
1431       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1432     else
1433       m_SelState.SetEndPos(m_wpCaret);
1434 
1435     if (m_wpOldCaret != m_wpCaret) {
1436       ScrollToCaret();
1437       Refresh();
1438       SetCaretInfo();
1439     }
1440   } else {
1441     SelectNone();
1442     ScrollToCaret();
1443     SetCaretInfo();
1444   }
1445 }
1446 
OnVK_LEFT(bool bShift)1447 void CPWL_EditImpl::OnVK_LEFT(bool bShift) {
1448   if (!m_pVT->IsValid())
1449     return;
1450 
1451   if (bShift) {
1452     if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1453         m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
1454       SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1455     }
1456     SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1457     if (m_SelState.IsEmpty())
1458       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1459     else
1460       m_SelState.SetEndPos(m_wpCaret);
1461 
1462     if (m_wpOldCaret != m_wpCaret) {
1463       ScrollToCaret();
1464       Refresh();
1465       SetCaretInfo();
1466     }
1467   } else {
1468     if (!m_SelState.IsEmpty()) {
1469       if (m_SelState.BeginPos < m_SelState.EndPos)
1470         SetCaret(m_SelState.BeginPos);
1471       else
1472         SetCaret(m_SelState.EndPos);
1473 
1474       SelectNone();
1475       ScrollToCaret();
1476       SetCaretInfo();
1477     } else {
1478       if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
1479           m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret)) {
1480         SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1481       }
1482       SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
1483       ScrollToCaret();
1484       SetCaretOrigin();
1485       SetCaretInfo();
1486     }
1487   }
1488 }
1489 
OnVK_RIGHT(bool bShift)1490 void CPWL_EditImpl::OnVK_RIGHT(bool bShift) {
1491   if (!m_pVT->IsValid())
1492     return;
1493 
1494   if (bShift) {
1495     SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1496     if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1497         m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
1498       SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1499 
1500     if (m_SelState.IsEmpty())
1501       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1502     else
1503       m_SelState.SetEndPos(m_wpCaret);
1504 
1505     if (m_wpOldCaret != m_wpCaret) {
1506       ScrollToCaret();
1507       Refresh();
1508       SetCaretInfo();
1509     }
1510   } else {
1511     if (!m_SelState.IsEmpty()) {
1512       if (m_SelState.BeginPos > m_SelState.EndPos)
1513         SetCaret(m_SelState.BeginPos);
1514       else
1515         SetCaret(m_SelState.EndPos);
1516 
1517       SelectNone();
1518       ScrollToCaret();
1519       SetCaretInfo();
1520     } else {
1521       SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1522       if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
1523           m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret)) {
1524         SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
1525       }
1526       ScrollToCaret();
1527       SetCaretOrigin();
1528       SetCaretInfo();
1529     }
1530   }
1531 }
1532 
OnVK_HOME(bool bShift,bool bCtrl)1533 void CPWL_EditImpl::OnVK_HOME(bool bShift, bool bCtrl) {
1534   if (!m_pVT->IsValid())
1535     return;
1536 
1537   if (bShift) {
1538     if (bCtrl)
1539       SetCaret(m_pVT->GetBeginWordPlace());
1540     else
1541       SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1542 
1543     if (m_SelState.IsEmpty())
1544       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1545     else
1546       m_SelState.SetEndPos(m_wpCaret);
1547 
1548     ScrollToCaret();
1549     Refresh();
1550     SetCaretInfo();
1551   } else {
1552     if (!m_SelState.IsEmpty()) {
1553       SetCaret(std::min(m_SelState.BeginPos, m_SelState.EndPos));
1554       SelectNone();
1555       ScrollToCaret();
1556       SetCaretInfo();
1557     } else {
1558       if (bCtrl)
1559         SetCaret(m_pVT->GetBeginWordPlace());
1560       else
1561         SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
1562 
1563       ScrollToCaret();
1564       SetCaretOrigin();
1565       SetCaretInfo();
1566     }
1567   }
1568 }
1569 
OnVK_END(bool bShift,bool bCtrl)1570 void CPWL_EditImpl::OnVK_END(bool bShift, bool bCtrl) {
1571   if (!m_pVT->IsValid())
1572     return;
1573 
1574   if (bShift) {
1575     if (bCtrl)
1576       SetCaret(m_pVT->GetEndWordPlace());
1577     else
1578       SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1579 
1580     if (m_SelState.IsEmpty())
1581       m_SelState.Set(m_wpOldCaret, m_wpCaret);
1582     else
1583       m_SelState.SetEndPos(m_wpCaret);
1584 
1585     ScrollToCaret();
1586     Refresh();
1587     SetCaretInfo();
1588   } else {
1589     if (!m_SelState.IsEmpty()) {
1590       SetCaret(std::max(m_SelState.BeginPos, m_SelState.EndPos));
1591       SelectNone();
1592       ScrollToCaret();
1593       SetCaretInfo();
1594     } else {
1595       if (bCtrl)
1596         SetCaret(m_pVT->GetEndWordPlace());
1597       else
1598         SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
1599 
1600       ScrollToCaret();
1601       SetCaretOrigin();
1602       SetCaretInfo();
1603     }
1604   }
1605 }
1606 
InsertWord(uint16_t word,FX_Charset charset,bool bAddUndo)1607 bool CPWL_EditImpl::InsertWord(uint16_t word,
1608                                FX_Charset charset,
1609                                bool bAddUndo) {
1610   if (IsTextOverflow() || !m_pVT->IsValid())
1611     return false;
1612 
1613   m_pVT->UpdateWordPlace(m_wpCaret);
1614   SetCaret(
1615       m_pVT->InsertWord(m_wpCaret, word, GetCharSetFromUnicode(word, charset)));
1616   m_SelState.Set(m_wpCaret, m_wpCaret);
1617   if (m_wpCaret == m_wpOldCaret)
1618     return false;
1619 
1620   if (bAddUndo && m_bEnableUndo) {
1621     AddEditUndoItem(std::make_unique<UndoInsertWord>(this, m_wpOldCaret,
1622                                                      m_wpCaret, word, charset));
1623   }
1624   PaintInsertText(m_wpOldCaret, m_wpCaret);
1625   return true;
1626 }
1627 
InsertReturn(bool bAddUndo)1628 bool CPWL_EditImpl::InsertReturn(bool bAddUndo) {
1629   if (IsTextOverflow() || !m_pVT->IsValid())
1630     return false;
1631 
1632   m_pVT->UpdateWordPlace(m_wpCaret);
1633   SetCaret(m_pVT->InsertSection(m_wpCaret));
1634   m_SelState.Set(m_wpCaret, m_wpCaret);
1635   if (m_wpCaret == m_wpOldCaret)
1636     return false;
1637 
1638   if (bAddUndo && m_bEnableUndo) {
1639     AddEditUndoItem(
1640         std::make_unique<UndoInsertReturn>(this, m_wpOldCaret, m_wpCaret));
1641   }
1642   RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1643   ScrollToCaret();
1644   Refresh();
1645   SetCaretOrigin();
1646   SetCaretInfo();
1647   return true;
1648 }
1649 
Backspace(bool bAddUndo)1650 bool CPWL_EditImpl::Backspace(bool bAddUndo) {
1651   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetBeginWordPlace())
1652     return false;
1653 
1654   CPVT_Word word;
1655   if (bAddUndo) {
1656     CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1657     pIterator->SetAt(m_wpCaret);
1658     pIterator->GetWord(word);
1659   }
1660   m_pVT->UpdateWordPlace(m_wpCaret);
1661   SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
1662   m_SelState.Set(m_wpCaret, m_wpCaret);
1663   if (m_wpCaret == m_wpOldCaret)
1664     return false;
1665 
1666   if (bAddUndo && m_bEnableUndo) {
1667     AddEditUndoItem(std::make_unique<UndoBackspace>(
1668         this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset));
1669   }
1670   RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
1671   ScrollToCaret();
1672   Refresh();
1673   SetCaretOrigin();
1674   SetCaretInfo();
1675   return true;
1676 }
1677 
Delete(bool bAddUndo)1678 bool CPWL_EditImpl::Delete(bool bAddUndo) {
1679   if (!m_pVT->IsValid() || m_wpCaret == m_pVT->GetEndWordPlace())
1680     return false;
1681 
1682   CPVT_Word word;
1683   if (bAddUndo) {
1684     CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1685     pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
1686     pIterator->GetWord(word);
1687   }
1688   m_pVT->UpdateWordPlace(m_wpCaret);
1689   bool bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
1690   SetCaret(m_pVT->DeleteWord(m_wpCaret));
1691   m_SelState.Set(m_wpCaret, m_wpCaret);
1692   if (bAddUndo && m_bEnableUndo) {
1693     if (bSecEnd) {
1694       AddEditUndoItem(std::make_unique<UndoDelete>(
1695           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, bSecEnd));
1696     } else {
1697       AddEditUndoItem(std::make_unique<UndoDelete>(
1698           this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset, bSecEnd));
1699     }
1700   }
1701   RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
1702   ScrollToCaret();
1703   Refresh();
1704   SetCaretOrigin();
1705   SetCaretInfo();
1706   return true;
1707 }
1708 
Clear()1709 bool CPWL_EditImpl::Clear() {
1710   if (m_pVT->IsValid()) {
1711     m_pVT->DeleteWords(GetWholeWordRange());
1712     SetCaret(m_pVT->GetBeginWordPlace());
1713 
1714     return true;
1715   }
1716 
1717   return false;
1718 }
1719 
Clear(bool bAddUndo)1720 bool CPWL_EditImpl::Clear(bool bAddUndo) {
1721   if (!m_pVT->IsValid() || m_SelState.IsEmpty())
1722     return false;
1723 
1724   CPVT_WordRange range = m_SelState.ConvertToWordRange();
1725   if (bAddUndo && m_bEnableUndo) {
1726     AddEditUndoItem(
1727         std::make_unique<UndoClear>(this, range, GetSelectedText()));
1728   }
1729   SelectNone();
1730   SetCaret(m_pVT->DeleteWords(range));
1731   m_SelState.Set(m_wpCaret, m_wpCaret);
1732   RearrangePart(range);
1733   ScrollToCaret();
1734   Refresh();
1735   SetCaretOrigin();
1736   SetCaretInfo();
1737   return true;
1738 }
1739 
InsertText(const WideString & sText,FX_Charset charset,bool bAddUndo)1740 bool CPWL_EditImpl::InsertText(const WideString& sText,
1741                                FX_Charset charset,
1742                                bool bAddUndo) {
1743   if (IsTextOverflow())
1744     return false;
1745 
1746   m_pVT->UpdateWordPlace(m_wpCaret);
1747   SetCaret(DoInsertText(m_wpCaret, sText, charset));
1748   m_SelState.Set(m_wpCaret, m_wpCaret);
1749   if (m_wpCaret == m_wpOldCaret)
1750     return false;
1751 
1752   if (bAddUndo && m_bEnableUndo) {
1753     AddEditUndoItem(std::make_unique<UndoInsertText>(
1754         this, m_wpOldCaret, m_wpCaret, sText, charset));
1755   }
1756   PaintInsertText(m_wpOldCaret, m_wpCaret);
1757   return true;
1758 }
1759 
PaintInsertText(const CPVT_WordPlace & wpOld,const CPVT_WordPlace & wpNew)1760 void CPWL_EditImpl::PaintInsertText(const CPVT_WordPlace& wpOld,
1761                                     const CPVT_WordPlace& wpNew) {
1762   if (m_pVT->IsValid()) {
1763     RearrangePart(CPVT_WordRange(wpOld, wpNew));
1764     ScrollToCaret();
1765     Refresh();
1766     SetCaretOrigin();
1767     SetCaretInfo();
1768   }
1769 }
1770 
ReplaceAndKeepSelection(const WideString & text)1771 void CPWL_EditImpl::ReplaceAndKeepSelection(const WideString& text) {
1772   AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, false));
1773   ClearSelection();
1774 
1775   // Select the inserted text.
1776   CPVT_WordPlace caret_before_insert = m_wpCaret;
1777   InsertText(text, FX_Charset::kDefault);
1778   CPVT_WordPlace caret_after_insert = m_wpCaret;
1779   m_SelState.Set(caret_before_insert, caret_after_insert);
1780 
1781   AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, true));
1782 }
1783 
ReplaceSelection(const WideString & text)1784 void CPWL_EditImpl::ReplaceSelection(const WideString& text) {
1785   AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, false));
1786   ClearSelection();
1787   InsertText(text, FX_Charset::kDefault);
1788   AddEditUndoItem(std::make_unique<UndoReplaceSelection>(this, true));
1789 }
1790 
Redo()1791 bool CPWL_EditImpl::Redo() {
1792   if (m_bEnableUndo) {
1793     if (m_Undo.CanRedo()) {
1794       m_Undo.Redo();
1795       return true;
1796     }
1797   }
1798 
1799   return false;
1800 }
1801 
Undo()1802 bool CPWL_EditImpl::Undo() {
1803   if (m_bEnableUndo) {
1804     if (m_Undo.CanUndo()) {
1805       m_Undo.Undo();
1806       return true;
1807     }
1808   }
1809 
1810   return false;
1811 }
1812 
SetCaretOrigin()1813 void CPWL_EditImpl::SetCaretOrigin() {
1814   if (!m_pVT->IsValid())
1815     return;
1816 
1817   CPVT_VariableText::Iterator* pIterator = m_pVT->GetIterator();
1818   pIterator->SetAt(m_wpCaret);
1819   CPVT_Word word;
1820   CPVT_Line line;
1821   if (pIterator->GetWord(word)) {
1822     m_ptCaret.x = word.ptWord.x + word.fWidth;
1823     m_ptCaret.y = word.ptWord.y;
1824   } else if (pIterator->GetLine(line)) {
1825     m_ptCaret.x = line.ptLine.x;
1826     m_ptCaret.y = line.ptLine.y;
1827   }
1828 }
1829 
WordIndexToWordPlace(int32_t index) const1830 CPVT_WordPlace CPWL_EditImpl::WordIndexToWordPlace(int32_t index) const {
1831   if (m_pVT->IsValid())
1832     return m_pVT->WordIndexToWordPlace(index);
1833 
1834   return CPVT_WordPlace();
1835 }
1836 
IsTextFull() const1837 bool CPWL_EditImpl::IsTextFull() const {
1838   int32_t nTotalWords = m_pVT->GetTotalWords();
1839   int32_t nLimitChar = m_pVT->GetLimitChar();
1840   int32_t nCharArray = m_pVT->GetCharArray();
1841 
1842   return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
1843          (nCharArray > 0 && nTotalWords >= nCharArray);
1844 }
1845 
IsTextOverflow() const1846 bool CPWL_EditImpl::IsTextOverflow() const {
1847   if (!m_bEnableScroll && !m_bEnableOverflow) {
1848     CFX_FloatRect rcPlate = m_pVT->GetPlateRect();
1849     CFX_FloatRect rcContent = m_pVT->GetContentRect();
1850 
1851     if (m_pVT->IsMultiLine() && GetTotalLines() > 1 &&
1852         FXSYS_IsFloatBigger(rcContent.Height(), rcPlate.Height())) {
1853       return true;
1854     }
1855 
1856     if (FXSYS_IsFloatBigger(rcContent.Width(), rcPlate.Width()))
1857       return true;
1858   }
1859 
1860   return false;
1861 }
1862 
CanUndo() const1863 bool CPWL_EditImpl::CanUndo() const {
1864   if (m_bEnableUndo) {
1865     return m_Undo.CanUndo();
1866   }
1867 
1868   return false;
1869 }
1870 
CanRedo() const1871 bool CPWL_EditImpl::CanRedo() const {
1872   if (m_bEnableUndo) {
1873     return m_Undo.CanRedo();
1874   }
1875 
1876   return false;
1877 }
1878 
EnableRefresh(bool bRefresh)1879 void CPWL_EditImpl::EnableRefresh(bool bRefresh) {
1880   m_bEnableRefresh = bRefresh;
1881 }
1882 
EnableUndo(bool bUndo)1883 void CPWL_EditImpl::EnableUndo(bool bUndo) {
1884   m_bEnableUndo = bUndo;
1885 }
1886 
DoInsertText(const CPVT_WordPlace & place,const WideString & sText,FX_Charset charset)1887 CPVT_WordPlace CPWL_EditImpl::DoInsertText(const CPVT_WordPlace& place,
1888                                            const WideString& sText,
1889                                            FX_Charset charset) {
1890   if (!m_pVT->IsValid())
1891     return place;
1892 
1893   CPVT_WordPlace wp = place;
1894   for (size_t i = 0; i < sText.GetLength(); ++i) {
1895     uint16_t word = sText[i];
1896     switch (word) {
1897       case '\r':
1898         wp = m_pVT->InsertSection(wp);
1899         if (i + 1 < sText.GetLength() && sText[i + 1] == '\n')
1900           i++;
1901         break;
1902       case '\n':
1903         wp = m_pVT->InsertSection(wp);
1904         break;
1905       case '\t':
1906         word = ' ';
1907         [[fallthrough]];
1908       default:
1909         wp = m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset));
1910         break;
1911     }
1912   }
1913   return wp;
1914 }
1915 
GetCharSetFromUnicode(uint16_t word,FX_Charset nOldCharset)1916 FX_Charset CPWL_EditImpl::GetCharSetFromUnicode(uint16_t word,
1917                                                 FX_Charset nOldCharset) {
1918   if (IPVT_FontMap* pFontMap = GetFontMap())
1919     return pFontMap->CharSetFromUnicode(word, nOldCharset);
1920   return nOldCharset;
1921 }
1922 
AddEditUndoItem(std::unique_ptr<UndoItemIface> pEditUndoItem)1923 void CPWL_EditImpl::AddEditUndoItem(
1924     std::unique_ptr<UndoItemIface> pEditUndoItem) {
1925   m_Undo.AddItem(std::move(pEditUndoItem));
1926 }
1927 
GetPDFWordString(int32_t nFontIndex,uint16_t Word,uint16_t SubWord)1928 ByteString CPWL_EditImpl::GetPDFWordString(int32_t nFontIndex,
1929                                            uint16_t Word,
1930                                            uint16_t SubWord) {
1931   IPVT_FontMap* pFontMap = GetFontMap();
1932   RetainPtr<CPDF_Font> pPDFFont = pFontMap->GetPDFFont(nFontIndex);
1933   if (!pPDFFont)
1934     return ByteString();
1935 
1936   ByteString sWord;
1937   if (SubWord > 0) {
1938     Word = SubWord;
1939   } else {
1940     uint32_t dwCharCode = pPDFFont->IsUnicodeCompatible()
1941                               ? pPDFFont->CharCodeFromUnicode(Word)
1942                               : pFontMap->CharCodeFromUnicode(nFontIndex, Word);
1943     if (dwCharCode > 0) {
1944       pPDFFont->AppendChar(&sWord, dwCharCode);
1945       return sWord;
1946     }
1947   }
1948   pPDFFont->AppendChar(&sWord, Word);
1949   return sWord;
1950 }
1951 
1952 CPWL_EditImpl::SelectState::SelectState() = default;
1953 
SelectState(const CPVT_WordRange & range)1954 CPWL_EditImpl::SelectState::SelectState(const CPVT_WordRange& range) {
1955   Set(range.BeginPos, range.EndPos);
1956 }
1957 
ConvertToWordRange() const1958 CPVT_WordRange CPWL_EditImpl::SelectState::ConvertToWordRange() const {
1959   return CPVT_WordRange(BeginPos, EndPos);
1960 }
1961 
Reset()1962 void CPWL_EditImpl::SelectState::Reset() {
1963   BeginPos.Reset();
1964   EndPos.Reset();
1965 }
1966 
Set(const CPVT_WordPlace & begin,const CPVT_WordPlace & end)1967 void CPWL_EditImpl::SelectState::Set(const CPVT_WordPlace& begin,
1968                                      const CPVT_WordPlace& end) {
1969   BeginPos = begin;
1970   EndPos = end;
1971 }
1972 
SetEndPos(const CPVT_WordPlace & end)1973 void CPWL_EditImpl::SelectState::SetEndPos(const CPVT_WordPlace& end) {
1974   EndPos = end;
1975 }
1976 
IsEmpty() const1977 bool CPWL_EditImpl::SelectState::IsEmpty() const {
1978   return BeginPos == EndPos;
1979 }
1980