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