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