1// Copyright 2014 PDFium Authors. All rights reserved.
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/include/fxedit/fxet_edit.h"
8
9#include <algorithm>
10
11#include "core/include/fpdfapi/fpdf_resource.h"
12
13#define FX_EDIT_UNDO_MAXITEM 10000
14
15CFX_Edit_Iterator::CFX_Edit_Iterator(CFX_Edit* pEdit,
16                                     IPDF_VariableText_Iterator* pVTIterator)
17    : m_pEdit(pEdit), m_pVTIterator(pVTIterator) {}
18
19CFX_Edit_Iterator::~CFX_Edit_Iterator() {}
20
21FX_BOOL CFX_Edit_Iterator::NextWord() {
22  return m_pVTIterator->NextWord();
23}
24
25FX_BOOL CFX_Edit_Iterator::NextLine() {
26  return m_pVTIterator->NextLine();
27}
28
29FX_BOOL CFX_Edit_Iterator::NextSection() {
30  return m_pVTIterator->NextSection();
31}
32
33FX_BOOL CFX_Edit_Iterator::PrevWord() {
34  return m_pVTIterator->PrevWord();
35}
36
37FX_BOOL CFX_Edit_Iterator::PrevLine() {
38  return m_pVTIterator->PrevLine();
39}
40
41FX_BOOL CFX_Edit_Iterator::PrevSection() {
42  return m_pVTIterator->PrevSection();
43}
44
45FX_BOOL CFX_Edit_Iterator::GetWord(CPVT_Word& word) const {
46  ASSERT(m_pEdit);
47
48  if (m_pVTIterator->GetWord(word)) {
49    word.ptWord = m_pEdit->VTToEdit(word.ptWord);
50    return TRUE;
51  }
52  return FALSE;
53}
54
55FX_BOOL CFX_Edit_Iterator::GetLine(CPVT_Line& line) const {
56  ASSERT(m_pEdit);
57
58  if (m_pVTIterator->GetLine(line)) {
59    line.ptLine = m_pEdit->VTToEdit(line.ptLine);
60    return TRUE;
61  }
62  return FALSE;
63}
64
65FX_BOOL CFX_Edit_Iterator::GetSection(CPVT_Section& section) const {
66  ASSERT(m_pEdit);
67
68  if (m_pVTIterator->GetSection(section)) {
69    section.rcSection = m_pEdit->VTToEdit(section.rcSection);
70    return TRUE;
71  }
72  return FALSE;
73}
74
75void CFX_Edit_Iterator::SetAt(int32_t nWordIndex) {
76  m_pVTIterator->SetAt(nWordIndex);
77}
78
79void CFX_Edit_Iterator::SetAt(const CPVT_WordPlace& place) {
80  m_pVTIterator->SetAt(place);
81}
82
83const CPVT_WordPlace& CFX_Edit_Iterator::GetAt() const {
84  return m_pVTIterator->GetAt();
85}
86
87IFX_Edit* CFX_Edit_Iterator::GetEdit() const {
88  return m_pEdit;
89}
90
91CFX_Edit_Provider::CFX_Edit_Provider(IFX_Edit_FontMap* pFontMap)
92    : m_pFontMap(pFontMap) {
93  ASSERT(m_pFontMap);
94}
95
96CFX_Edit_Provider::~CFX_Edit_Provider() {}
97
98IFX_Edit_FontMap* CFX_Edit_Provider::GetFontMap() {
99  return m_pFontMap;
100}
101
102int32_t CFX_Edit_Provider::GetCharWidth(int32_t nFontIndex,
103                                        FX_WORD word,
104                                        int32_t nWordStyle) {
105  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex)) {
106    FX_DWORD charcode = word;
107
108    if (pPDFFont->IsUnicodeCompatible())
109      charcode = pPDFFont->CharCodeFromUnicode(word);
110    else
111      charcode = m_pFontMap->CharCodeFromUnicode(nFontIndex, word);
112
113    if (charcode != -1)
114      return pPDFFont->GetCharWidthF(charcode);
115  }
116
117  return 0;
118}
119
120int32_t CFX_Edit_Provider::GetTypeAscent(int32_t nFontIndex) {
121  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
122    return pPDFFont->GetTypeAscent();
123
124  return 0;
125}
126
127int32_t CFX_Edit_Provider::GetTypeDescent(int32_t nFontIndex) {
128  if (CPDF_Font* pPDFFont = m_pFontMap->GetPDFFont(nFontIndex))
129    return pPDFFont->GetTypeDescent();
130
131  return 0;
132}
133
134int32_t CFX_Edit_Provider::GetWordFontIndex(FX_WORD word,
135                                            int32_t charset,
136                                            int32_t nFontIndex) {
137  return m_pFontMap->GetWordFontIndex(word, charset, nFontIndex);
138}
139
140int32_t CFX_Edit_Provider::GetDefaultFontIndex() {
141  return 0;
142}
143
144FX_BOOL CFX_Edit_Provider::IsLatinWord(FX_WORD word) {
145  return FX_EDIT_ISLATINWORD(word);
146}
147
148CFX_Edit_Refresh::CFX_Edit_Refresh() {}
149
150CFX_Edit_Refresh::~CFX_Edit_Refresh() {}
151
152void CFX_Edit_Refresh::BeginRefresh() {
153  m_RefreshRects.Empty();
154  m_OldLineRects = m_NewLineRects;
155}
156
157void CFX_Edit_Refresh::Push(const CPVT_WordRange& linerange,
158                            const CPDF_Rect& rect) {
159  m_NewLineRects.Add(linerange, rect);
160}
161
162void CFX_Edit_Refresh::NoAnalyse() {
163  {
164    for (int32_t i = 0, sz = m_OldLineRects.GetSize(); i < sz; i++)
165      if (CFX_Edit_LineRect* pOldRect = m_OldLineRects.GetAt(i))
166        m_RefreshRects.Add(pOldRect->m_rcLine);
167  }
168
169  {
170    for (int32_t i = 0, sz = m_NewLineRects.GetSize(); i < sz; i++)
171      if (CFX_Edit_LineRect* pNewRect = m_NewLineRects.GetAt(i))
172        m_RefreshRects.Add(pNewRect->m_rcLine);
173  }
174}
175
176void CFX_Edit_Refresh::Analyse(int32_t nAlignment) {
177  FX_BOOL bLineTopChanged = FALSE;
178  CPDF_Rect rcResult;
179  FX_FLOAT fWidthDiff;
180
181  int32_t szMax = std::max(m_OldLineRects.GetSize(), m_NewLineRects.GetSize());
182  int32_t i = 0;
183
184  while (i < szMax) {
185    CFX_Edit_LineRect* pOldRect = m_OldLineRects.GetAt(i);
186    CFX_Edit_LineRect* pNewRect = m_NewLineRects.GetAt(i);
187
188    if (pOldRect) {
189      if (pNewRect) {
190        if (bLineTopChanged) {
191          rcResult = pOldRect->m_rcLine;
192          rcResult.Union(pNewRect->m_rcLine);
193          m_RefreshRects.Add(rcResult);
194        } else {
195          if (*pNewRect != *pOldRect) {
196            if (!pNewRect->IsSameTop(*pOldRect) ||
197                !pNewRect->IsSameHeight(*pOldRect)) {
198              bLineTopChanged = TRUE;
199              continue;
200            }
201
202            if (nAlignment == 0) {
203              if (pNewRect->m_wrLine.BeginPos != pOldRect->m_wrLine.BeginPos) {
204                rcResult = pOldRect->m_rcLine;
205                rcResult.Union(pNewRect->m_rcLine);
206                m_RefreshRects.Add(rcResult);
207              } else {
208                if (!pNewRect->IsSameLeft(*pOldRect)) {
209                  rcResult = pOldRect->m_rcLine;
210                  rcResult.Union(pNewRect->m_rcLine);
211                } else {
212                  fWidthDiff =
213                      pNewRect->m_rcLine.Width() - pOldRect->m_rcLine.Width();
214                  rcResult = pNewRect->m_rcLine;
215                  if (fWidthDiff > 0.0f) {
216                    rcResult.left = rcResult.right - fWidthDiff;
217                  } else {
218                    rcResult.left = rcResult.right;
219                    rcResult.right += (-fWidthDiff);
220                  }
221                }
222                m_RefreshRects.Add(rcResult);
223              }
224            } else {
225              rcResult = pOldRect->m_rcLine;
226              rcResult.Union(pNewRect->m_rcLine);
227              m_RefreshRects.Add(rcResult);
228            }
229          }
230        }
231      } else {
232        m_RefreshRects.Add(pOldRect->m_rcLine);
233      }
234    } else {
235      if (pNewRect) {
236        m_RefreshRects.Add(pNewRect->m_rcLine);
237      }
238    }
239    i++;
240  }
241}
242
243void CFX_Edit_Refresh::AddRefresh(const CPDF_Rect& rect) {
244  m_RefreshRects.Add(rect);
245}
246
247const CFX_Edit_RectArray* CFX_Edit_Refresh::GetRefreshRects() const {
248  return &m_RefreshRects;
249}
250
251void CFX_Edit_Refresh::EndRefresh() {
252  m_RefreshRects.Empty();
253}
254
255CFX_Edit_Undo::CFX_Edit_Undo(int32_t nBufsize)
256    : m_nCurUndoPos(0),
257      m_nBufSize(nBufsize),
258      m_bModified(FALSE),
259      m_bVirgin(TRUE),
260      m_bWorking(FALSE) {}
261
262CFX_Edit_Undo::~CFX_Edit_Undo() {
263  Reset();
264}
265
266FX_BOOL CFX_Edit_Undo::CanUndo() const {
267  return m_nCurUndoPos > 0;
268}
269
270void CFX_Edit_Undo::Undo() {
271  m_bWorking = TRUE;
272
273  if (m_nCurUndoPos > 0) {
274    IFX_Edit_UndoItem* pItem = m_UndoItemStack.GetAt(m_nCurUndoPos - 1);
275    pItem->Undo();
276
277    m_nCurUndoPos--;
278    m_bModified = (m_nCurUndoPos != 0);
279  }
280
281  m_bWorking = FALSE;
282}
283
284FX_BOOL CFX_Edit_Undo::CanRedo() const {
285  return m_nCurUndoPos < m_UndoItemStack.GetSize();
286}
287
288void CFX_Edit_Undo::Redo() {
289  m_bWorking = TRUE;
290
291  int32_t nStackSize = m_UndoItemStack.GetSize();
292
293  if (m_nCurUndoPos < nStackSize) {
294    IFX_Edit_UndoItem* pItem = m_UndoItemStack.GetAt(m_nCurUndoPos);
295    pItem->Redo();
296
297    m_nCurUndoPos++;
298    m_bModified = (m_nCurUndoPos != 0);
299  }
300
301  m_bWorking = FALSE;
302}
303
304FX_BOOL CFX_Edit_Undo::IsWorking() const {
305  return m_bWorking;
306}
307
308void CFX_Edit_Undo::AddItem(IFX_Edit_UndoItem* pItem) {
309  ASSERT(!m_bWorking);
310  ASSERT(pItem);
311  ASSERT(m_nBufSize > 1);
312
313  if (m_nCurUndoPos < m_UndoItemStack.GetSize())
314    RemoveTails();
315
316  if (m_UndoItemStack.GetSize() >= m_nBufSize) {
317    RemoveHeads();
318    m_bVirgin = FALSE;
319  }
320
321  m_UndoItemStack.Add(pItem);
322  m_nCurUndoPos = m_UndoItemStack.GetSize();
323
324  m_bModified = (m_nCurUndoPos != 0);
325}
326
327FX_BOOL CFX_Edit_Undo::IsModified() const {
328  return m_bVirgin ? m_bModified : TRUE;
329}
330
331IFX_Edit_UndoItem* CFX_Edit_Undo::GetItem(int32_t nIndex) {
332  if (nIndex >= 0 && nIndex < m_UndoItemStack.GetSize())
333    return m_UndoItemStack.GetAt(nIndex);
334
335  return NULL;
336}
337
338void CFX_Edit_Undo::RemoveHeads() {
339  ASSERT(m_UndoItemStack.GetSize() > 1);
340
341  delete m_UndoItemStack.GetAt(0);
342  m_UndoItemStack.RemoveAt(0);
343}
344
345void CFX_Edit_Undo::RemoveTails() {
346  for (int32_t i = m_UndoItemStack.GetSize() - 1; i >= m_nCurUndoPos; i--) {
347    delete m_UndoItemStack.GetAt(i);
348    m_UndoItemStack.RemoveAt(i);
349  }
350}
351
352void CFX_Edit_Undo::Reset() {
353  for (int32_t i = 0, sz = m_UndoItemStack.GetSize(); i < sz; i++) {
354    delete m_UndoItemStack.GetAt(i);
355  }
356  m_nCurUndoPos = 0;
357  m_UndoItemStack.RemoveAll();
358}
359
360CFX_Edit_GroupUndoItem::CFX_Edit_GroupUndoItem(const CFX_WideString& sTitle)
361    : m_sTitle(sTitle) {}
362
363CFX_Edit_GroupUndoItem::~CFX_Edit_GroupUndoItem() {
364  for (int i = 0, sz = m_Items.GetSize(); i < sz; i++) {
365    delete m_Items[i];
366  }
367
368  m_Items.RemoveAll();
369}
370
371void CFX_Edit_GroupUndoItem::AddUndoItem(CFX_Edit_UndoItem* pUndoItem) {
372  pUndoItem->SetFirst(FALSE);
373  pUndoItem->SetLast(FALSE);
374
375  m_Items.Add(pUndoItem);
376
377  if (m_sTitle.IsEmpty())
378    m_sTitle = pUndoItem->GetUndoTitle();
379}
380
381void CFX_Edit_GroupUndoItem::UpdateItems() {
382  if (m_Items.GetSize() > 0) {
383    CFX_Edit_UndoItem* pFirstItem = m_Items[0];
384    pFirstItem->SetFirst(TRUE);
385
386    CFX_Edit_UndoItem* pLastItem = m_Items[m_Items.GetSize() - 1];
387    pLastItem->SetLast(TRUE);
388  }
389}
390
391void CFX_Edit_GroupUndoItem::Undo() {
392  for (int i = m_Items.GetSize() - 1; i >= 0; i--) {
393    CFX_Edit_UndoItem* pUndoItem = m_Items[i];
394    pUndoItem->Undo();
395  }
396}
397
398void CFX_Edit_GroupUndoItem::Redo() {
399  for (int i = 0, sz = m_Items.GetSize(); i < sz; i++) {
400    CFX_Edit_UndoItem* pUndoItem = m_Items[i];
401    pUndoItem->Redo();
402  }
403}
404
405CFX_WideString CFX_Edit_GroupUndoItem::GetUndoTitle() {
406  return m_sTitle;
407}
408
409CFXEU_InsertWord::CFXEU_InsertWord(CFX_Edit* pEdit,
410                                   const CPVT_WordPlace& wpOldPlace,
411                                   const CPVT_WordPlace& wpNewPlace,
412                                   FX_WORD word,
413                                   int32_t charset,
414                                   const CPVT_WordProps* pWordProps)
415    : m_pEdit(pEdit),
416      m_wpOld(wpOldPlace),
417      m_wpNew(wpNewPlace),
418      m_Word(word),
419      m_nCharset(charset),
420      m_WordProps() {
421  if (pWordProps)
422    m_WordProps = *pWordProps;
423}
424
425CFXEU_InsertWord::~CFXEU_InsertWord() {}
426
427void CFXEU_InsertWord::Redo() {
428  if (m_pEdit) {
429    m_pEdit->SelectNone();
430    m_pEdit->SetCaret(m_wpOld);
431    m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, FALSE, TRUE);
432  }
433}
434
435void CFXEU_InsertWord::Undo() {
436  if (m_pEdit) {
437    m_pEdit->SelectNone();
438    m_pEdit->SetCaret(m_wpNew);
439    m_pEdit->Backspace(FALSE, TRUE);
440  }
441}
442
443CFXEU_InsertReturn::CFXEU_InsertReturn(CFX_Edit* pEdit,
444                                       const CPVT_WordPlace& wpOldPlace,
445                                       const CPVT_WordPlace& wpNewPlace,
446                                       const CPVT_SecProps* pSecProps,
447                                       const CPVT_WordProps* pWordProps)
448    : m_pEdit(pEdit),
449      m_wpOld(wpOldPlace),
450      m_wpNew(wpNewPlace),
451      m_SecProps(),
452      m_WordProps() {
453  if (pSecProps)
454    m_SecProps = *pSecProps;
455  if (pWordProps)
456    m_WordProps = *pWordProps;
457}
458
459CFXEU_InsertReturn::~CFXEU_InsertReturn() {}
460
461void CFXEU_InsertReturn::Redo() {
462  if (m_pEdit) {
463    m_pEdit->SelectNone();
464    m_pEdit->SetCaret(m_wpOld);
465    m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, FALSE, TRUE);
466  }
467}
468
469void CFXEU_InsertReturn::Undo() {
470  if (m_pEdit) {
471    m_pEdit->SelectNone();
472    m_pEdit->SetCaret(m_wpNew);
473    m_pEdit->Backspace(FALSE, TRUE);
474  }
475}
476
477CFXEU_Backspace::CFXEU_Backspace(CFX_Edit* pEdit,
478                                 const CPVT_WordPlace& wpOldPlace,
479                                 const CPVT_WordPlace& wpNewPlace,
480                                 FX_WORD word,
481                                 int32_t charset,
482                                 const CPVT_SecProps& SecProps,
483                                 const CPVT_WordProps& WordProps)
484    : m_pEdit(pEdit),
485      m_wpOld(wpOldPlace),
486      m_wpNew(wpNewPlace),
487      m_Word(word),
488      m_nCharset(charset),
489      m_SecProps(SecProps),
490      m_WordProps(WordProps) {}
491
492CFXEU_Backspace::~CFXEU_Backspace() {}
493
494void CFXEU_Backspace::Redo() {
495  if (m_pEdit) {
496    m_pEdit->SelectNone();
497    m_pEdit->SetCaret(m_wpOld);
498    m_pEdit->Backspace(FALSE, TRUE);
499  }
500}
501
502void CFXEU_Backspace::Undo() {
503  if (m_pEdit) {
504    m_pEdit->SelectNone();
505    m_pEdit->SetCaret(m_wpNew);
506    if (m_wpNew.SecCmp(m_wpOld) != 0) {
507      m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, FALSE, TRUE);
508    } else {
509      m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, FALSE, TRUE);
510    }
511  }
512}
513
514CFXEU_Delete::CFXEU_Delete(CFX_Edit* pEdit,
515                           const CPVT_WordPlace& wpOldPlace,
516                           const CPVT_WordPlace& wpNewPlace,
517                           FX_WORD word,
518                           int32_t charset,
519                           const CPVT_SecProps& SecProps,
520                           const CPVT_WordProps& WordProps,
521                           FX_BOOL bSecEnd)
522    : m_pEdit(pEdit),
523      m_wpOld(wpOldPlace),
524      m_wpNew(wpNewPlace),
525      m_Word(word),
526      m_nCharset(charset),
527      m_SecProps(SecProps),
528      m_WordProps(WordProps),
529      m_bSecEnd(bSecEnd) {}
530
531CFXEU_Delete::~CFXEU_Delete() {}
532
533void CFXEU_Delete::Redo() {
534  if (m_pEdit) {
535    m_pEdit->SelectNone();
536    m_pEdit->SetCaret(m_wpOld);
537    m_pEdit->Delete(FALSE, TRUE);
538  }
539}
540
541void CFXEU_Delete::Undo() {
542  if (m_pEdit) {
543    m_pEdit->SelectNone();
544    m_pEdit->SetCaret(m_wpNew);
545    if (m_bSecEnd) {
546      m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, FALSE, TRUE);
547    } else {
548      m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, FALSE, TRUE);
549    }
550  }
551}
552
553CFXEU_Clear::CFXEU_Clear(CFX_Edit* pEdit,
554                         const CPVT_WordRange& wrSel,
555                         const CFX_WideString& swText)
556    : m_pEdit(pEdit), m_wrSel(wrSel), m_swText(swText) {}
557
558CFXEU_Clear::~CFXEU_Clear() {}
559
560void CFXEU_Clear::Redo() {
561  if (m_pEdit) {
562    m_pEdit->SelectNone();
563    m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
564    m_pEdit->Clear(FALSE, TRUE);
565  }
566}
567
568void CFXEU_Clear::Undo() {
569  if (m_pEdit) {
570    m_pEdit->SelectNone();
571    m_pEdit->SetCaret(m_wrSel.BeginPos);
572    m_pEdit->InsertText(m_swText.c_str(), DEFAULT_CHARSET, NULL, NULL, FALSE,
573                        TRUE);
574    m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
575  }
576}
577
578CFXEU_ClearRich::CFXEU_ClearRich(CFX_Edit* pEdit,
579                                 const CPVT_WordPlace& wpOldPlace,
580                                 const CPVT_WordPlace& wpNewPlace,
581                                 const CPVT_WordRange& wrSel,
582                                 FX_WORD word,
583                                 int32_t charset,
584                                 const CPVT_SecProps& SecProps,
585                                 const CPVT_WordProps& WordProps)
586    : m_pEdit(pEdit),
587      m_wpOld(wpOldPlace),
588      m_wpNew(wpNewPlace),
589      m_wrSel(wrSel),
590      m_Word(word),
591      m_nCharset(charset),
592      m_SecProps(SecProps),
593      m_WordProps(WordProps) {}
594
595CFXEU_ClearRich::~CFXEU_ClearRich() {}
596
597void CFXEU_ClearRich::Redo() {
598  if (m_pEdit && IsLast()) {
599    m_pEdit->SelectNone();
600    m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
601    m_pEdit->Clear(FALSE, TRUE);
602  }
603}
604
605void CFXEU_ClearRich::Undo() {
606  if (m_pEdit) {
607    m_pEdit->SelectNone();
608    m_pEdit->SetCaret(m_wpOld);
609    if (m_wpNew.SecCmp(m_wpOld) != 0) {
610      m_pEdit->InsertReturn(&m_SecProps, &m_WordProps, FALSE, FALSE);
611    } else {
612      m_pEdit->InsertWord(m_Word, m_nCharset, &m_WordProps, FALSE, FALSE);
613    }
614
615    if (IsFirst()) {
616      m_pEdit->PaintInsertText(m_wrSel.BeginPos, m_wrSel.EndPos);
617      m_pEdit->SetSel(m_wrSel.BeginPos, m_wrSel.EndPos);
618    }
619  }
620}
621CFXEU_InsertText::CFXEU_InsertText(CFX_Edit* pEdit,
622                                   const CPVT_WordPlace& wpOldPlace,
623                                   const CPVT_WordPlace& wpNewPlace,
624                                   const CFX_WideString& swText,
625                                   int32_t charset,
626                                   const CPVT_SecProps* pSecProps,
627                                   const CPVT_WordProps* pWordProps)
628    : m_pEdit(pEdit),
629      m_wpOld(wpOldPlace),
630      m_wpNew(wpNewPlace),
631      m_swText(swText),
632      m_nCharset(charset),
633      m_SecProps(),
634      m_WordProps() {
635  if (pSecProps)
636    m_SecProps = *pSecProps;
637  if (pWordProps)
638    m_WordProps = *pWordProps;
639}
640
641CFXEU_InsertText::~CFXEU_InsertText() {}
642
643void CFXEU_InsertText::Redo() {
644  if (m_pEdit && IsLast()) {
645    m_pEdit->SelectNone();
646    m_pEdit->SetCaret(m_wpOld);
647    m_pEdit->InsertText(m_swText.c_str(), m_nCharset, &m_SecProps, &m_WordProps,
648                        FALSE, TRUE);
649  }
650}
651
652void CFXEU_InsertText::Undo() {
653  if (m_pEdit) {
654    m_pEdit->SelectNone();
655    m_pEdit->SetSel(m_wpOld, m_wpNew);
656    m_pEdit->Clear(FALSE, TRUE);
657  }
658}
659
660CFXEU_SetSecProps::CFXEU_SetSecProps(CFX_Edit* pEdit,
661                                     const CPVT_WordPlace& place,
662                                     EDIT_PROPS_E ep,
663                                     const CPVT_SecProps& oldsecprops,
664                                     const CPVT_WordProps& oldwordprops,
665                                     const CPVT_SecProps& newsecprops,
666                                     const CPVT_WordProps& newwordprops,
667                                     const CPVT_WordRange& range)
668    : m_pEdit(pEdit),
669      m_wpPlace(place),
670      m_wrPlace(range),
671      m_eProps(ep),
672      m_OldSecProps(oldsecprops),
673      m_NewSecProps(newsecprops),
674      m_OldWordProps(oldwordprops),
675      m_NewWordProps(newwordprops) {}
676
677CFXEU_SetSecProps::~CFXEU_SetSecProps() {}
678
679void CFXEU_SetSecProps::Redo() {
680  if (m_pEdit) {
681    m_pEdit->SetSecProps(m_eProps, m_wpPlace, &m_NewSecProps, &m_NewWordProps,
682                         m_wrPlace, FALSE);
683    if (IsLast()) {
684      m_pEdit->SelectNone();
685      m_pEdit->PaintSetProps(m_eProps, m_wrPlace);
686      m_pEdit->SetSel(m_wrPlace.BeginPos, m_wrPlace.EndPos);
687    }
688  }
689}
690
691void CFXEU_SetSecProps::Undo() {
692  if (m_pEdit) {
693    m_pEdit->SetSecProps(m_eProps, m_wpPlace, &m_OldSecProps, &m_OldWordProps,
694                         m_wrPlace, FALSE);
695    if (IsFirst()) {
696      m_pEdit->SelectNone();
697      m_pEdit->PaintSetProps(m_eProps, m_wrPlace);
698      m_pEdit->SetSel(m_wrPlace.BeginPos, m_wrPlace.EndPos);
699    }
700  }
701}
702
703CFXEU_SetWordProps::CFXEU_SetWordProps(CFX_Edit* pEdit,
704                                       const CPVT_WordPlace& place,
705                                       EDIT_PROPS_E ep,
706                                       const CPVT_WordProps& oldprops,
707                                       const CPVT_WordProps& newprops,
708                                       const CPVT_WordRange& range)
709    : m_pEdit(pEdit),
710      m_wpPlace(place),
711      m_wrPlace(range),
712      m_eProps(ep),
713      m_OldWordProps(oldprops),
714      m_NewWordProps(newprops) {}
715
716CFXEU_SetWordProps::~CFXEU_SetWordProps() {}
717
718void CFXEU_SetWordProps::Redo() {
719  if (m_pEdit) {
720    m_pEdit->SetWordProps(m_eProps, m_wpPlace, &m_NewWordProps, m_wrPlace,
721                          FALSE);
722    if (IsLast()) {
723      m_pEdit->SelectNone();
724      m_pEdit->PaintSetProps(m_eProps, m_wrPlace);
725      m_pEdit->SetSel(m_wrPlace.BeginPos, m_wrPlace.EndPos);
726    }
727  }
728}
729
730void CFXEU_SetWordProps::Undo() {
731  if (m_pEdit) {
732    m_pEdit->SetWordProps(m_eProps, m_wpPlace, &m_OldWordProps, m_wrPlace,
733                          FALSE);
734    if (IsFirst()) {
735      m_pEdit->SelectNone();
736      m_pEdit->PaintSetProps(m_eProps, m_wrPlace);
737      m_pEdit->SetSel(m_wrPlace.BeginPos, m_wrPlace.EndPos);
738    }
739  }
740}
741
742CFX_Edit::CFX_Edit(IPDF_VariableText* pVT)
743    : m_pVT(pVT),
744      m_pNotify(NULL),
745      m_pOprNotify(NULL),
746      m_pVTProvide(NULL),
747      m_wpCaret(-1, -1, -1),
748      m_wpOldCaret(-1, -1, -1),
749      m_SelState(),
750      m_ptScrollPos(0, 0),
751      m_ptRefreshScrollPos(0, 0),
752      m_bEnableScroll(FALSE),
753      m_pIterator(NULL),
754      m_ptCaret(0.0f, 0.0f),
755      m_Undo(FX_EDIT_UNDO_MAXITEM),
756      m_nAlignment(0),
757      m_bNotifyFlag(FALSE),
758      m_bEnableOverflow(FALSE),
759      m_bEnableRefresh(TRUE),
760      m_rcOldContent(0.0f, 0.0f, 0.0f, 0.0f),
761      m_bEnableUndo(TRUE),
762      m_bNotify(TRUE),
763      m_bOprNotify(FALSE),
764      m_pGroupUndoItem(NULL) {
765  ASSERT(pVT);
766}
767
768CFX_Edit::~CFX_Edit() {
769  delete m_pVTProvide;
770  m_pVTProvide = NULL;
771  delete m_pIterator;
772  m_pIterator = NULL;
773  ASSERT(!m_pGroupUndoItem);
774}
775
776void CFX_Edit::Initialize() {
777  m_pVT->Initialize();
778  SetCaret(m_pVT->GetBeginWordPlace());
779  SetCaretOrigin();
780}
781
782void CFX_Edit::SetFontMap(IFX_Edit_FontMap* pFontMap) {
783  delete m_pVTProvide;
784  m_pVT->SetProvider(m_pVTProvide = new CFX_Edit_Provider(pFontMap));
785}
786
787void CFX_Edit::SetVTProvider(IPDF_VariableText_Provider* pProvider) {
788  m_pVT->SetProvider(pProvider);
789}
790
791void CFX_Edit::SetNotify(IFX_Edit_Notify* pNotify) {
792  m_pNotify = pNotify;
793}
794
795void CFX_Edit::SetOprNotify(IFX_Edit_OprNotify* pOprNotify) {
796  m_pOprNotify = pOprNotify;
797}
798
799IFX_Edit_Iterator* CFX_Edit::GetIterator() {
800  if (!m_pIterator)
801    m_pIterator = new CFX_Edit_Iterator(this, m_pVT->GetIterator());
802
803  return m_pIterator;
804}
805
806IPDF_VariableText* CFX_Edit::GetVariableText() {
807  return m_pVT;
808}
809
810IFX_Edit_FontMap* CFX_Edit::GetFontMap() {
811  if (m_pVTProvide)
812    return m_pVTProvide->GetFontMap();
813
814  return NULL;
815}
816
817void CFX_Edit::SetPlateRect(const CPDF_Rect& rect, FX_BOOL bPaint) {
818  m_pVT->SetPlateRect(rect);
819  m_ptScrollPos = CPDF_Point(rect.left, rect.top);
820  if (bPaint)
821    Paint();
822}
823
824void CFX_Edit::SetAlignmentH(int32_t nFormat, FX_BOOL bPaint) {
825  m_pVT->SetAlignment(nFormat);
826  if (bPaint)
827    Paint();
828}
829
830void CFX_Edit::SetAlignmentV(int32_t nFormat, FX_BOOL bPaint) {
831  m_nAlignment = nFormat;
832  if (bPaint)
833    Paint();
834}
835
836void CFX_Edit::SetPasswordChar(FX_WORD wSubWord, FX_BOOL bPaint) {
837  m_pVT->SetPasswordChar(wSubWord);
838  if (bPaint)
839    Paint();
840}
841
842void CFX_Edit::SetLimitChar(int32_t nLimitChar, FX_BOOL bPaint) {
843  m_pVT->SetLimitChar(nLimitChar);
844  if (bPaint)
845    Paint();
846}
847
848void CFX_Edit::SetCharArray(int32_t nCharArray, FX_BOOL bPaint) {
849  m_pVT->SetCharArray(nCharArray);
850  if (bPaint)
851    Paint();
852}
853
854void CFX_Edit::SetCharSpace(FX_FLOAT fCharSpace, FX_BOOL bPaint) {
855  m_pVT->SetCharSpace(fCharSpace);
856  if (bPaint)
857    Paint();
858}
859
860void CFX_Edit::SetHorzScale(int32_t nHorzScale, FX_BOOL bPaint) {
861  m_pVT->SetHorzScale(nHorzScale);
862  if (bPaint)
863    Paint();
864}
865
866void CFX_Edit::SetMultiLine(FX_BOOL bMultiLine, FX_BOOL bPaint) {
867  m_pVT->SetMultiLine(bMultiLine);
868  if (bPaint)
869    Paint();
870}
871
872void CFX_Edit::SetAutoReturn(FX_BOOL bAuto, FX_BOOL bPaint) {
873  m_pVT->SetAutoReturn(bAuto);
874  if (bPaint)
875    Paint();
876}
877
878void CFX_Edit::SetLineLeading(FX_FLOAT fLineLeading, FX_BOOL bPaint) {
879  m_pVT->SetLineLeading(fLineLeading);
880  if (bPaint)
881    Paint();
882}
883
884void CFX_Edit::SetAutoFontSize(FX_BOOL bAuto, FX_BOOL bPaint) {
885  m_pVT->SetAutoFontSize(bAuto);
886  if (bPaint)
887    Paint();
888}
889
890void CFX_Edit::SetFontSize(FX_FLOAT fFontSize, FX_BOOL bPaint) {
891  m_pVT->SetFontSize(fFontSize);
892  if (bPaint)
893    Paint();
894}
895
896void CFX_Edit::SetAutoScroll(FX_BOOL bAuto, FX_BOOL bPaint) {
897  m_bEnableScroll = bAuto;
898  if (bPaint)
899    Paint();
900}
901
902void CFX_Edit::SetTextOverflow(FX_BOOL bAllowed, FX_BOOL bPaint) {
903  m_bEnableOverflow = bAllowed;
904  if (bPaint)
905    Paint();
906}
907
908void CFX_Edit::SetSel(int32_t nStartChar, int32_t nEndChar) {
909  if (m_pVT->IsValid()) {
910    if (nStartChar == 0 && nEndChar < 0) {
911      SelectAll();
912    } else if (nStartChar < 0) {
913      SelectNone();
914    } else {
915      if (nStartChar < nEndChar) {
916        SetSel(m_pVT->WordIndexToWordPlace(nStartChar),
917               m_pVT->WordIndexToWordPlace(nEndChar));
918      } else {
919        SetSel(m_pVT->WordIndexToWordPlace(nEndChar),
920               m_pVT->WordIndexToWordPlace(nStartChar));
921      }
922    }
923  }
924}
925
926void CFX_Edit::SetSel(const CPVT_WordPlace& begin, const CPVT_WordPlace& end) {
927  if (m_pVT->IsValid()) {
928    SelectNone();
929
930    m_SelState.Set(begin, end);
931
932    SetCaret(m_SelState.EndPos);
933
934    if (m_SelState.IsExist()) {
935      ScrollToCaret();
936      CPVT_WordRange wr(m_SelState.BeginPos, m_SelState.EndPos);
937      Refresh(RP_OPTIONAL, &wr);
938      SetCaretInfo();
939    } else {
940      ScrollToCaret();
941      SetCaretInfo();
942    }
943  }
944}
945
946void CFX_Edit::GetSel(int32_t& nStartChar, int32_t& nEndChar) const {
947  nStartChar = -1;
948  nEndChar = -1;
949
950  if (m_pVT->IsValid()) {
951    if (m_SelState.IsExist()) {
952      if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0) {
953        nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
954        nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
955      } else {
956        nStartChar = m_pVT->WordPlaceToWordIndex(m_SelState.EndPos);
957        nEndChar = m_pVT->WordPlaceToWordIndex(m_SelState.BeginPos);
958      }
959    } else {
960      nStartChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
961      nEndChar = m_pVT->WordPlaceToWordIndex(m_wpCaret);
962    }
963  }
964}
965
966int32_t CFX_Edit::GetCaret() const {
967  if (m_pVT->IsValid())
968    return m_pVT->WordPlaceToWordIndex(m_wpCaret);
969
970  return -1;
971}
972
973CPVT_WordPlace CFX_Edit::GetCaretWordPlace() const {
974  return m_wpCaret;
975}
976
977CFX_WideString CFX_Edit::GetText() const {
978  CFX_WideString swRet;
979
980  if (m_pVT->IsValid()) {
981    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
982      FX_BOOL bRich = m_pVT->IsRichText();
983
984      pIterator->SetAt(0);
985
986      CPVT_Word wordinfo;
987      CPVT_WordPlace oldplace = pIterator->GetAt();
988      while (pIterator->NextWord()) {
989        CPVT_WordPlace place = pIterator->GetAt();
990
991        if (pIterator->GetWord(wordinfo)) {
992          if (bRich) {
993            swRet += wordinfo.Word;
994          } else {
995            swRet += wordinfo.Word;
996          }
997        }
998
999        if (oldplace.SecCmp(place) != 0) {
1000          swRet += 0x0D;
1001          swRet += 0x0A;
1002        }
1003
1004        oldplace = place;
1005      }
1006    }
1007  }
1008
1009  return swRet;
1010}
1011
1012CFX_WideString CFX_Edit::GetRangeText(const CPVT_WordRange& range) const {
1013  CFX_WideString swRet;
1014
1015  if (m_pVT->IsValid()) {
1016    FX_BOOL bRich = m_pVT->IsRichText();
1017
1018    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1019      CPVT_WordRange wrTemp = range;
1020      m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1021      m_pVT->UpdateWordPlace(wrTemp.EndPos);
1022      pIterator->SetAt(wrTemp.BeginPos);
1023
1024      CPVT_Word wordinfo;
1025      CPVT_WordPlace oldplace = wrTemp.BeginPos;
1026      while (pIterator->NextWord()) {
1027        CPVT_WordPlace place = pIterator->GetAt();
1028        if (place.WordCmp(wrTemp.EndPos) > 0)
1029          break;
1030
1031        if (pIterator->GetWord(wordinfo)) {
1032          if (bRich) {
1033            swRet += wordinfo.Word;
1034          } else {
1035            swRet += wordinfo.Word;
1036          }
1037        }
1038
1039        if (oldplace.SecCmp(place) != 0) {
1040          swRet += 0x0D;
1041          swRet += 0x0A;
1042        }
1043
1044        oldplace = place;
1045      }
1046    }
1047  }
1048
1049  return swRet;
1050}
1051
1052CFX_WideString CFX_Edit::GetSelText() const {
1053  return GetRangeText(m_SelState.ConvertToWordRange());
1054}
1055
1056int32_t CFX_Edit::GetTotalWords() const {
1057  return m_pVT->GetTotalWords();
1058}
1059
1060int32_t CFX_Edit::GetTotalLines() const {
1061  int32_t nLines = 0;
1062
1063  if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1064    pIterator->SetAt(0);
1065    while (pIterator->NextLine())
1066      nLines++;
1067  }
1068
1069  return nLines + 1;
1070}
1071
1072CPVT_WordRange CFX_Edit::GetSelectWordRange() const {
1073  return m_SelState.ConvertToWordRange();
1074}
1075
1076CPVT_WordRange CFX_Edit::CombineWordRange(const CPVT_WordRange& wr1,
1077                                          const CPVT_WordRange& wr2) {
1078  CPVT_WordRange wrRet;
1079
1080  if (wr1.BeginPos.WordCmp(wr2.BeginPos) < 0) {
1081    wrRet.BeginPos = wr1.BeginPos;
1082  } else {
1083    wrRet.BeginPos = wr2.BeginPos;
1084  }
1085
1086  if (wr1.EndPos.WordCmp(wr2.EndPos) < 0) {
1087    wrRet.EndPos = wr2.EndPos;
1088  } else {
1089    wrRet.EndPos = wr1.EndPos;
1090  }
1091
1092  return wrRet;
1093}
1094
1095FX_BOOL CFX_Edit::IsRichText() const {
1096  return m_pVT->IsRichText();
1097}
1098
1099void CFX_Edit::SetRichText(FX_BOOL bRichText, FX_BOOL bPaint) {
1100  m_pVT->SetRichText(bRichText);
1101  if (bPaint)
1102    Paint();
1103}
1104
1105FX_BOOL CFX_Edit::SetRichFontIndex(int32_t nFontIndex) {
1106  CPVT_WordProps WordProps;
1107  WordProps.nFontIndex = nFontIndex;
1108  return SetRichTextProps(EP_FONTINDEX, NULL, &WordProps);
1109}
1110
1111FX_BOOL CFX_Edit::SetRichFontSize(FX_FLOAT fFontSize) {
1112  CPVT_WordProps WordProps;
1113  WordProps.fFontSize = fFontSize;
1114  return SetRichTextProps(EP_FONTSIZE, NULL, &WordProps);
1115}
1116
1117FX_BOOL CFX_Edit::SetRichTextColor(FX_COLORREF dwColor) {
1118  CPVT_WordProps WordProps;
1119  WordProps.dwWordColor = dwColor;
1120  return SetRichTextProps(EP_WORDCOLOR, NULL, &WordProps);
1121}
1122
1123FX_BOOL CFX_Edit::SetRichTextScript(int32_t nScriptType) {
1124  CPVT_WordProps WordProps;
1125  WordProps.nScriptType = nScriptType;
1126  return SetRichTextProps(EP_SCRIPTTYPE, NULL, &WordProps);
1127}
1128
1129FX_BOOL CFX_Edit::SetRichTextBold(FX_BOOL bBold) {
1130  CPVT_WordProps WordProps;
1131  if (bBold)
1132    WordProps.nWordStyle |= PVTWORD_STYLE_BOLD;
1133  return SetRichTextProps(EP_BOLD, NULL, &WordProps);
1134}
1135
1136FX_BOOL CFX_Edit::SetRichTextItalic(FX_BOOL bItalic) {
1137  CPVT_WordProps WordProps;
1138  if (bItalic)
1139    WordProps.nWordStyle |= PVTWORD_STYLE_ITALIC;
1140  return SetRichTextProps(EP_ITALIC, NULL, &WordProps);
1141}
1142
1143FX_BOOL CFX_Edit::SetRichTextUnderline(FX_BOOL bUnderline) {
1144  CPVT_WordProps WordProps;
1145  if (bUnderline)
1146    WordProps.nWordStyle |= PVTWORD_STYLE_UNDERLINE;
1147  return SetRichTextProps(EP_UNDERLINE, NULL, &WordProps);
1148}
1149
1150FX_BOOL CFX_Edit::SetRichTextCrossout(FX_BOOL bCrossout) {
1151  CPVT_WordProps WordProps;
1152  if (bCrossout)
1153    WordProps.nWordStyle |= PVTWORD_STYLE_CROSSOUT;
1154  return SetRichTextProps(EP_CROSSOUT, NULL, &WordProps);
1155}
1156
1157FX_BOOL CFX_Edit::SetRichTextCharSpace(FX_FLOAT fCharSpace) {
1158  CPVT_WordProps WordProps;
1159  WordProps.fCharSpace = fCharSpace;
1160  return SetRichTextProps(EP_CHARSPACE, NULL, &WordProps);
1161}
1162
1163FX_BOOL CFX_Edit::SetRichTextHorzScale(int32_t nHorzScale) {
1164  CPVT_WordProps WordProps;
1165  WordProps.nHorzScale = nHorzScale;
1166  return SetRichTextProps(EP_HORZSCALE, NULL, &WordProps);
1167}
1168
1169FX_BOOL CFX_Edit::SetRichTextLineLeading(FX_FLOAT fLineLeading) {
1170  CPVT_SecProps SecProps;
1171  SecProps.fLineLeading = fLineLeading;
1172  return SetRichTextProps(EP_LINELEADING, &SecProps, NULL);
1173}
1174
1175FX_BOOL CFX_Edit::SetRichTextLineIndent(FX_FLOAT fLineIndent) {
1176  CPVT_SecProps SecProps;
1177  SecProps.fLineIndent = fLineIndent;
1178  return SetRichTextProps(EP_LINEINDENT, &SecProps, NULL);
1179}
1180
1181FX_BOOL CFX_Edit::SetRichTextAlignment(int32_t nAlignment) {
1182  CPVT_SecProps SecProps;
1183  SecProps.nAlignment = nAlignment;
1184  return SetRichTextProps(EP_ALIGNMENT, &SecProps, NULL);
1185}
1186
1187FX_BOOL CFX_Edit::SetRichTextProps(EDIT_PROPS_E eProps,
1188                                   const CPVT_SecProps* pSecProps,
1189                                   const CPVT_WordProps* pWordProps) {
1190  FX_BOOL bSet = FALSE;
1191  FX_BOOL bSet1, bSet2;
1192  if (m_pVT->IsValid() && m_pVT->IsRichText()) {
1193    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1194      CPVT_WordRange wrTemp = m_SelState.ConvertToWordRange();
1195
1196      m_pVT->UpdateWordPlace(wrTemp.BeginPos);
1197      m_pVT->UpdateWordPlace(wrTemp.EndPos);
1198      pIterator->SetAt(wrTemp.BeginPos);
1199
1200      BeginGroupUndo(L"");
1201      bSet = SetSecProps(eProps, wrTemp.BeginPos, pSecProps, pWordProps, wrTemp,
1202                         TRUE);
1203
1204      while (pIterator->NextWord()) {
1205        CPVT_WordPlace place = pIterator->GetAt();
1206        if (place.WordCmp(wrTemp.EndPos) > 0)
1207          break;
1208        bSet1 = SetSecProps(eProps, place, pSecProps, pWordProps, wrTemp, TRUE);
1209        bSet2 = SetWordProps(eProps, place, pWordProps, wrTemp, TRUE);
1210
1211        if (!bSet)
1212          bSet = (bSet1 || bSet2);
1213      }
1214
1215      EndGroupUndo();
1216
1217      if (bSet) {
1218        PaintSetProps(eProps, wrTemp);
1219      }
1220    }
1221  }
1222
1223  return bSet;
1224}
1225
1226void CFX_Edit::PaintSetProps(EDIT_PROPS_E eProps, const CPVT_WordRange& wr) {
1227  switch (eProps) {
1228    case EP_LINELEADING:
1229    case EP_LINEINDENT:
1230    case EP_ALIGNMENT:
1231      RearrangePart(wr);
1232      ScrollToCaret();
1233      Refresh(RP_ANALYSE);
1234      SetCaretOrigin();
1235      SetCaretInfo();
1236      break;
1237    case EP_WORDCOLOR:
1238    case EP_UNDERLINE:
1239    case EP_CROSSOUT:
1240      Refresh(RP_OPTIONAL, &wr);
1241      break;
1242    case EP_FONTINDEX:
1243    case EP_FONTSIZE:
1244    case EP_SCRIPTTYPE:
1245    case EP_CHARSPACE:
1246    case EP_HORZSCALE:
1247    case EP_BOLD:
1248    case EP_ITALIC:
1249      RearrangePart(wr);
1250      ScrollToCaret();
1251
1252      CPVT_WordRange wrRefresh(m_pVT->GetSectionBeginPlace(wr.BeginPos),
1253                               m_pVT->GetSectionEndPlace(wr.EndPos));
1254      Refresh(RP_ANALYSE, &wrRefresh);
1255
1256      SetCaretOrigin();
1257      SetCaretInfo();
1258      break;
1259  }
1260}
1261
1262FX_BOOL CFX_Edit::SetSecProps(EDIT_PROPS_E eProps,
1263                              const CPVT_WordPlace& place,
1264                              const CPVT_SecProps* pSecProps,
1265                              const CPVT_WordProps* pWordProps,
1266                              const CPVT_WordRange& wr,
1267                              FX_BOOL bAddUndo) {
1268  if (m_pVT->IsValid() && m_pVT->IsRichText()) {
1269    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1270      FX_BOOL bSet = FALSE;
1271      CPVT_Section secinfo;
1272      CPVT_Section OldSecinfo;
1273
1274      CPVT_WordPlace oldplace = pIterator->GetAt();
1275
1276      if (eProps == EP_LINELEADING || eProps == EP_LINEINDENT ||
1277          eProps == EP_ALIGNMENT) {
1278        if (pSecProps) {
1279          pIterator->SetAt(place);
1280          if (pIterator->GetSection(secinfo)) {
1281            if (bAddUndo)
1282              OldSecinfo = secinfo;
1283
1284            switch (eProps) {
1285              case EP_LINELEADING:
1286                if (!FX_EDIT_IsFloatEqual(secinfo.SecProps.fLineLeading,
1287                                          pSecProps->fLineLeading)) {
1288                  secinfo.SecProps.fLineLeading = pSecProps->fLineLeading;
1289                  bSet = TRUE;
1290                }
1291                break;
1292              case EP_LINEINDENT:
1293                if (!FX_EDIT_IsFloatEqual(secinfo.SecProps.fLineIndent,
1294                                          pSecProps->fLineIndent)) {
1295                  secinfo.SecProps.fLineIndent = pSecProps->fLineIndent;
1296                  bSet = TRUE;
1297                }
1298                break;
1299              case EP_ALIGNMENT:
1300                if (secinfo.SecProps.nAlignment != pSecProps->nAlignment) {
1301                  secinfo.SecProps.nAlignment = pSecProps->nAlignment;
1302                  bSet = TRUE;
1303                }
1304                break;
1305              default:
1306                break;
1307            }
1308          }
1309        }
1310      } else {
1311        if (pWordProps && place == m_pVT->GetSectionBeginPlace(place)) {
1312          pIterator->SetAt(place);
1313          if (pIterator->GetSection(secinfo)) {
1314            if (bAddUndo)
1315              OldSecinfo = secinfo;
1316
1317            switch (eProps) {
1318              case EP_FONTINDEX:
1319                if (secinfo.WordProps.nFontIndex != pWordProps->nFontIndex) {
1320                  secinfo.WordProps.nFontIndex = pWordProps->nFontIndex;
1321                  bSet = TRUE;
1322                }
1323                break;
1324              case EP_FONTSIZE:
1325                if (!FX_EDIT_IsFloatEqual(secinfo.WordProps.fFontSize,
1326                                          pWordProps->fFontSize)) {
1327                  secinfo.WordProps.fFontSize = pWordProps->fFontSize;
1328                  bSet = TRUE;
1329                }
1330                break;
1331              case EP_WORDCOLOR:
1332                if (secinfo.WordProps.dwWordColor != pWordProps->dwWordColor) {
1333                  secinfo.WordProps.dwWordColor = pWordProps->dwWordColor;
1334                  bSet = TRUE;
1335                }
1336                break;
1337              case EP_SCRIPTTYPE:
1338                if (secinfo.WordProps.nScriptType != pWordProps->nScriptType) {
1339                  secinfo.WordProps.nScriptType = pWordProps->nScriptType;
1340                  bSet = TRUE;
1341                }
1342                break;
1343              case EP_CHARSPACE:
1344                if (!FX_EDIT_IsFloatEqual(secinfo.WordProps.fCharSpace,
1345                                          pWordProps->fCharSpace)) {
1346                  secinfo.WordProps.fCharSpace = pWordProps->fCharSpace;
1347                  bSet = TRUE;
1348                }
1349                break;
1350              case EP_HORZSCALE:
1351                if (secinfo.WordProps.nHorzScale != pWordProps->nHorzScale) {
1352                  secinfo.WordProps.nHorzScale = pWordProps->nHorzScale;
1353                  bSet = TRUE;
1354                }
1355                break;
1356              case EP_UNDERLINE:
1357                if (pWordProps->nWordStyle & PVTWORD_STYLE_UNDERLINE) {
1358                  if ((secinfo.WordProps.nWordStyle &
1359                       PVTWORD_STYLE_UNDERLINE) == 0) {
1360                    secinfo.WordProps.nWordStyle |= PVTWORD_STYLE_UNDERLINE;
1361                    bSet = TRUE;
1362                  }
1363                } else {
1364                  if ((secinfo.WordProps.nWordStyle &
1365                       PVTWORD_STYLE_UNDERLINE) != 0) {
1366                    secinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_UNDERLINE;
1367                    bSet = TRUE;
1368                  }
1369                }
1370                break;
1371              case EP_CROSSOUT:
1372                if (pWordProps->nWordStyle & PVTWORD_STYLE_CROSSOUT) {
1373                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) ==
1374                      0) {
1375                    secinfo.WordProps.nWordStyle |= PVTWORD_STYLE_CROSSOUT;
1376                    bSet = TRUE;
1377                  }
1378                } else {
1379                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) !=
1380                      0) {
1381                    secinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_CROSSOUT;
1382                    bSet = TRUE;
1383                  }
1384                }
1385                break;
1386              case EP_BOLD:
1387                if (pWordProps->nWordStyle & PVTWORD_STYLE_BOLD) {
1388                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_BOLD) ==
1389                      0) {
1390                    secinfo.WordProps.nWordStyle |= PVTWORD_STYLE_BOLD;
1391                    bSet = TRUE;
1392                  }
1393                } else {
1394                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_BOLD) !=
1395                      0) {
1396                    secinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_BOLD;
1397                    bSet = TRUE;
1398                  }
1399                }
1400                break;
1401              case EP_ITALIC:
1402                if (pWordProps->nWordStyle & PVTWORD_STYLE_ITALIC) {
1403                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_ITALIC) ==
1404                      0) {
1405                    secinfo.WordProps.nWordStyle |= PVTWORD_STYLE_ITALIC;
1406                    bSet = TRUE;
1407                  }
1408                } else {
1409                  if ((secinfo.WordProps.nWordStyle & PVTWORD_STYLE_ITALIC) !=
1410                      0) {
1411                    secinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_ITALIC;
1412                    bSet = TRUE;
1413                  }
1414                }
1415                break;
1416              default:
1417                break;
1418            }
1419          }
1420        }
1421      }
1422
1423      if (bSet) {
1424        pIterator->SetSection(secinfo);
1425
1426        if (bAddUndo && m_bEnableUndo) {
1427          AddEditUndoItem(new CFXEU_SetSecProps(
1428              this, place, eProps, OldSecinfo.SecProps, OldSecinfo.WordProps,
1429              secinfo.SecProps, secinfo.WordProps, wr));
1430        }
1431      }
1432
1433      pIterator->SetAt(oldplace);
1434
1435      return bSet;
1436    }
1437  }
1438
1439  return FALSE;
1440}
1441
1442FX_BOOL CFX_Edit::SetWordProps(EDIT_PROPS_E eProps,
1443                               const CPVT_WordPlace& place,
1444                               const CPVT_WordProps* pWordProps,
1445                               const CPVT_WordRange& wr,
1446                               FX_BOOL bAddUndo) {
1447  if (m_pVT->IsValid() && m_pVT->IsRichText()) {
1448    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1449      FX_BOOL bSet = FALSE;
1450      CPVT_Word wordinfo;
1451      CPVT_Word OldWordinfo;
1452
1453      CPVT_WordPlace oldplace = pIterator->GetAt();
1454
1455      if (pWordProps) {
1456        pIterator->SetAt(place);
1457        if (pIterator->GetWord(wordinfo)) {
1458          if (bAddUndo)
1459            OldWordinfo = wordinfo;
1460
1461          switch (eProps) {
1462            case EP_FONTINDEX:
1463              if (wordinfo.WordProps.nFontIndex != pWordProps->nFontIndex) {
1464                if (IFX_Edit_FontMap* pFontMap = GetFontMap()) {
1465                  wordinfo.WordProps.nFontIndex = pFontMap->GetWordFontIndex(
1466                      wordinfo.Word, wordinfo.nCharset, pWordProps->nFontIndex);
1467                }
1468                bSet = TRUE;
1469              }
1470              break;
1471            case EP_FONTSIZE:
1472              if (!FX_EDIT_IsFloatEqual(wordinfo.WordProps.fFontSize,
1473                                        pWordProps->fFontSize)) {
1474                wordinfo.WordProps.fFontSize = pWordProps->fFontSize;
1475                bSet = TRUE;
1476              }
1477              break;
1478            case EP_WORDCOLOR:
1479              if (wordinfo.WordProps.dwWordColor != pWordProps->dwWordColor) {
1480                wordinfo.WordProps.dwWordColor = pWordProps->dwWordColor;
1481                bSet = TRUE;
1482              }
1483              break;
1484            case EP_SCRIPTTYPE:
1485              if (wordinfo.WordProps.nScriptType != pWordProps->nScriptType) {
1486                wordinfo.WordProps.nScriptType = pWordProps->nScriptType;
1487                bSet = TRUE;
1488              }
1489              break;
1490            case EP_CHARSPACE:
1491              if (!FX_EDIT_IsFloatEqual(wordinfo.WordProps.fCharSpace,
1492                                        pWordProps->fCharSpace)) {
1493                wordinfo.WordProps.fCharSpace = pWordProps->fCharSpace;
1494                bSet = TRUE;
1495              }
1496              break;
1497            case EP_HORZSCALE:
1498              if (wordinfo.WordProps.nHorzScale != pWordProps->nHorzScale) {
1499                wordinfo.WordProps.nHorzScale = pWordProps->nHorzScale;
1500                bSet = TRUE;
1501              }
1502              break;
1503            case EP_UNDERLINE:
1504              if (pWordProps->nWordStyle & PVTWORD_STYLE_UNDERLINE) {
1505                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_UNDERLINE) ==
1506                    0) {
1507                  wordinfo.WordProps.nWordStyle |= PVTWORD_STYLE_UNDERLINE;
1508                  bSet = TRUE;
1509                }
1510              } else {
1511                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_UNDERLINE) !=
1512                    0) {
1513                  wordinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_UNDERLINE;
1514                  bSet = TRUE;
1515                }
1516              }
1517              break;
1518            case EP_CROSSOUT:
1519              if (pWordProps->nWordStyle & PVTWORD_STYLE_CROSSOUT) {
1520                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) ==
1521                    0) {
1522                  wordinfo.WordProps.nWordStyle |= PVTWORD_STYLE_CROSSOUT;
1523                  bSet = TRUE;
1524                }
1525              } else {
1526                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_CROSSOUT) !=
1527                    0) {
1528                  wordinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_CROSSOUT;
1529                  bSet = TRUE;
1530                }
1531              }
1532              break;
1533            case EP_BOLD:
1534              if (pWordProps->nWordStyle & PVTWORD_STYLE_BOLD) {
1535                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_BOLD) == 0) {
1536                  wordinfo.WordProps.nWordStyle |= PVTWORD_STYLE_BOLD;
1537                  bSet = TRUE;
1538                }
1539              } else {
1540                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_BOLD) != 0) {
1541                  wordinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_BOLD;
1542                  bSet = TRUE;
1543                }
1544              }
1545              break;
1546            case EP_ITALIC:
1547              if (pWordProps->nWordStyle & PVTWORD_STYLE_ITALIC) {
1548                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_ITALIC) ==
1549                    0) {
1550                  wordinfo.WordProps.nWordStyle |= PVTWORD_STYLE_ITALIC;
1551                  bSet = TRUE;
1552                }
1553              } else {
1554                if ((wordinfo.WordProps.nWordStyle & PVTWORD_STYLE_ITALIC) !=
1555                    0) {
1556                  wordinfo.WordProps.nWordStyle &= ~PVTWORD_STYLE_ITALIC;
1557                  bSet = TRUE;
1558                }
1559              }
1560              break;
1561            default:
1562              break;
1563          }
1564        }
1565      }
1566
1567      if (bSet) {
1568        pIterator->SetWord(wordinfo);
1569
1570        if (bAddUndo && m_bEnableUndo) {
1571          AddEditUndoItem(new CFXEU_SetWordProps(this, place, eProps,
1572                                                 OldWordinfo.WordProps,
1573                                                 wordinfo.WordProps, wr));
1574        }
1575      }
1576
1577      pIterator->SetAt(oldplace);
1578      return bSet;
1579    }
1580  }
1581
1582  return FALSE;
1583}
1584
1585void CFX_Edit::SetText(const FX_WCHAR* text,
1586                       int32_t charset,
1587                       const CPVT_SecProps* pSecProps,
1588                       const CPVT_WordProps* pWordProps) {
1589  SetText(text, charset, pSecProps, pWordProps, TRUE, TRUE);
1590}
1591
1592FX_BOOL CFX_Edit::InsertWord(FX_WORD word,
1593                             int32_t charset,
1594                             const CPVT_WordProps* pWordProps) {
1595  return InsertWord(word, charset, pWordProps, TRUE, TRUE);
1596}
1597
1598FX_BOOL CFX_Edit::InsertReturn(const CPVT_SecProps* pSecProps,
1599                               const CPVT_WordProps* pWordProps) {
1600  return InsertReturn(pSecProps, pWordProps, TRUE, TRUE);
1601}
1602
1603FX_BOOL CFX_Edit::Backspace() {
1604  return Backspace(TRUE, TRUE);
1605}
1606
1607FX_BOOL CFX_Edit::Delete() {
1608  return Delete(TRUE, TRUE);
1609}
1610
1611FX_BOOL CFX_Edit::Clear() {
1612  return Clear(TRUE, TRUE);
1613}
1614
1615FX_BOOL CFX_Edit::InsertText(const FX_WCHAR* text,
1616                             int32_t charset,
1617                             const CPVT_SecProps* pSecProps,
1618                             const CPVT_WordProps* pWordProps) {
1619  return InsertText(text, charset, pSecProps, pWordProps, TRUE, TRUE);
1620}
1621
1622FX_FLOAT CFX_Edit::GetFontSize() const {
1623  return m_pVT->GetFontSize();
1624}
1625
1626FX_WORD CFX_Edit::GetPasswordChar() const {
1627  return m_pVT->GetPasswordChar();
1628}
1629
1630int32_t CFX_Edit::GetCharArray() const {
1631  return m_pVT->GetCharArray();
1632}
1633
1634CPDF_Rect CFX_Edit::GetPlateRect() const {
1635  return m_pVT->GetPlateRect();
1636}
1637
1638CPDF_Rect CFX_Edit::GetContentRect() const {
1639  return VTToEdit(m_pVT->GetContentRect());
1640}
1641
1642int32_t CFX_Edit::GetHorzScale() const {
1643  return m_pVT->GetHorzScale();
1644}
1645
1646FX_FLOAT CFX_Edit::GetCharSpace() const {
1647  return m_pVT->GetCharSpace();
1648}
1649
1650CPVT_WordRange CFX_Edit::GetWholeWordRange() const {
1651  if (m_pVT->IsValid())
1652    return CPVT_WordRange(m_pVT->GetBeginWordPlace(), m_pVT->GetEndWordPlace());
1653
1654  return CPVT_WordRange();
1655}
1656
1657CPVT_WordRange CFX_Edit::GetVisibleWordRange() const {
1658  if (m_bEnableOverflow)
1659    return GetWholeWordRange();
1660
1661  if (m_pVT->IsValid()) {
1662    CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1663
1664    CPVT_WordPlace place1 =
1665        m_pVT->SearchWordPlace(EditToVT(CPDF_Point(rcPlate.left, rcPlate.top)));
1666    CPVT_WordPlace place2 = m_pVT->SearchWordPlace(
1667        EditToVT(CPDF_Point(rcPlate.right, rcPlate.bottom)));
1668
1669    return CPVT_WordRange(place1, place2);
1670  }
1671
1672  return CPVT_WordRange();
1673}
1674
1675CPVT_WordPlace CFX_Edit::SearchWordPlace(const CPDF_Point& point) const {
1676  if (m_pVT->IsValid()) {
1677    return m_pVT->SearchWordPlace(EditToVT(point));
1678  }
1679
1680  return CPVT_WordPlace();
1681}
1682
1683void CFX_Edit::Paint() {
1684  if (m_pVT->IsValid()) {
1685    RearrangeAll();
1686    ScrollToCaret();
1687    Refresh(RP_NOANALYSE);
1688    SetCaretOrigin();
1689    SetCaretInfo();
1690  }
1691}
1692
1693void CFX_Edit::RearrangeAll() {
1694  if (m_pVT->IsValid()) {
1695    m_pVT->UpdateWordPlace(m_wpCaret);
1696    m_pVT->RearrangeAll();
1697    m_pVT->UpdateWordPlace(m_wpCaret);
1698    SetScrollInfo();
1699    SetContentChanged();
1700  }
1701}
1702
1703void CFX_Edit::RearrangePart(const CPVT_WordRange& range) {
1704  if (m_pVT->IsValid()) {
1705    m_pVT->UpdateWordPlace(m_wpCaret);
1706    m_pVT->RearrangePart(range);
1707    m_pVT->UpdateWordPlace(m_wpCaret);
1708    SetScrollInfo();
1709    SetContentChanged();
1710  }
1711}
1712
1713void CFX_Edit::SetContentChanged() {
1714  if (m_bNotify && m_pNotify) {
1715    CPDF_Rect rcContent = m_pVT->GetContentRect();
1716    if (rcContent.Width() != m_rcOldContent.Width() ||
1717        rcContent.Height() != m_rcOldContent.Height()) {
1718      if (!m_bNotifyFlag) {
1719        m_bNotifyFlag = TRUE;
1720        m_pNotify->IOnContentChange(rcContent);
1721        m_bNotifyFlag = FALSE;
1722      }
1723      m_rcOldContent = rcContent;
1724    }
1725  }
1726}
1727
1728void CFX_Edit::SelectAll() {
1729  if (m_pVT->IsValid()) {
1730    m_SelState = CFX_Edit_Select(GetWholeWordRange());
1731    SetCaret(m_SelState.EndPos);
1732
1733    ScrollToCaret();
1734    CPVT_WordRange wrVisible = GetVisibleWordRange();
1735    Refresh(RP_OPTIONAL, &wrVisible);
1736    SetCaretInfo();
1737  }
1738}
1739
1740void CFX_Edit::SelectNone() {
1741  if (m_pVT->IsValid()) {
1742    if (m_SelState.IsExist()) {
1743      CPVT_WordRange wrTemp = m_SelState.ConvertToWordRange();
1744      m_SelState.Default();
1745      Refresh(RP_OPTIONAL, &wrTemp);
1746    }
1747  }
1748}
1749
1750FX_BOOL CFX_Edit::IsSelected() const {
1751  return m_SelState.IsExist();
1752}
1753
1754CPDF_Point CFX_Edit::VTToEdit(const CPDF_Point& point) const {
1755  CPDF_Rect rcContent = m_pVT->GetContentRect();
1756  CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1757
1758  FX_FLOAT fPadding = 0.0f;
1759
1760  switch (m_nAlignment) {
1761    case 0:
1762      fPadding = 0.0f;
1763      break;
1764    case 1:
1765      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1766      break;
1767    case 2:
1768      fPadding = rcPlate.Height() - rcContent.Height();
1769      break;
1770  }
1771
1772  return CPDF_Point(point.x - (m_ptScrollPos.x - rcPlate.left),
1773                    point.y - (m_ptScrollPos.y + fPadding - rcPlate.top));
1774}
1775
1776CPDF_Point CFX_Edit::EditToVT(const CPDF_Point& point) const {
1777  CPDF_Rect rcContent = m_pVT->GetContentRect();
1778  CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1779
1780  FX_FLOAT fPadding = 0.0f;
1781
1782  switch (m_nAlignment) {
1783    case 0:
1784      fPadding = 0.0f;
1785      break;
1786    case 1:
1787      fPadding = (rcPlate.Height() - rcContent.Height()) * 0.5f;
1788      break;
1789    case 2:
1790      fPadding = rcPlate.Height() - rcContent.Height();
1791      break;
1792  }
1793
1794  return CPDF_Point(point.x + (m_ptScrollPos.x - rcPlate.left),
1795                    point.y + (m_ptScrollPos.y + fPadding - rcPlate.top));
1796}
1797
1798CPDF_Rect CFX_Edit::VTToEdit(const CPDF_Rect& rect) const {
1799  CPDF_Point ptLeftBottom = VTToEdit(CPDF_Point(rect.left, rect.bottom));
1800  CPDF_Point ptRightTop = VTToEdit(CPDF_Point(rect.right, rect.top));
1801
1802  return CPDF_Rect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, ptRightTop.y);
1803}
1804
1805CPDF_Rect CFX_Edit::EditToVT(const CPDF_Rect& rect) const {
1806  CPDF_Point ptLeftBottom = EditToVT(CPDF_Point(rect.left, rect.bottom));
1807  CPDF_Point ptRightTop = EditToVT(CPDF_Point(rect.right, rect.top));
1808
1809  return CPDF_Rect(ptLeftBottom.x, ptLeftBottom.y, ptRightTop.x, ptRightTop.y);
1810}
1811
1812void CFX_Edit::SetScrollInfo() {
1813  if (m_bNotify && m_pNotify) {
1814    CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1815    CPDF_Rect rcContent = m_pVT->GetContentRect();
1816
1817    if (!m_bNotifyFlag) {
1818      m_bNotifyFlag = TRUE;
1819      m_pNotify->IOnSetScrollInfoX(rcPlate.left, rcPlate.right, rcContent.left,
1820                                   rcContent.right, rcPlate.Width() / 3,
1821                                   rcPlate.Width());
1822
1823      m_pNotify->IOnSetScrollInfoY(rcPlate.bottom, rcPlate.top,
1824                                   rcContent.bottom, rcContent.top,
1825                                   rcPlate.Height() / 3, rcPlate.Height());
1826      m_bNotifyFlag = FALSE;
1827    }
1828  }
1829}
1830
1831void CFX_Edit::SetScrollPosX(FX_FLOAT fx) {
1832  if (!m_bEnableScroll)
1833    return;
1834
1835  if (m_pVT->IsValid()) {
1836    if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.x, fx)) {
1837      m_ptScrollPos.x = fx;
1838      Refresh(RP_NOANALYSE);
1839
1840      if (m_bNotify && m_pNotify) {
1841        if (!m_bNotifyFlag) {
1842          m_bNotifyFlag = TRUE;
1843          m_pNotify->IOnSetScrollPosX(fx);
1844          m_bNotifyFlag = FALSE;
1845        }
1846      }
1847    }
1848  }
1849}
1850
1851void CFX_Edit::SetScrollPosY(FX_FLOAT fy) {
1852  if (!m_bEnableScroll)
1853    return;
1854
1855  if (m_pVT->IsValid()) {
1856    if (!FX_EDIT_IsFloatEqual(m_ptScrollPos.y, fy)) {
1857      m_ptScrollPos.y = fy;
1858      Refresh(RP_NOANALYSE);
1859
1860      if (m_bNotify && m_pNotify) {
1861        if (!m_bNotifyFlag) {
1862          m_bNotifyFlag = TRUE;
1863          m_pNotify->IOnSetScrollPosY(fy);
1864          m_bNotifyFlag = FALSE;
1865        }
1866      }
1867    }
1868  }
1869}
1870
1871void CFX_Edit::SetScrollPos(const CPDF_Point& point) {
1872  SetScrollPosX(point.x);
1873  SetScrollPosY(point.y);
1874  SetScrollLimit();
1875  SetCaretInfo();
1876}
1877
1878CPDF_Point CFX_Edit::GetScrollPos() const {
1879  return m_ptScrollPos;
1880}
1881
1882void CFX_Edit::SetScrollLimit() {
1883  if (m_pVT->IsValid()) {
1884    CPDF_Rect rcContent = m_pVT->GetContentRect();
1885    CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1886
1887    if (rcPlate.Width() > rcContent.Width()) {
1888      SetScrollPosX(rcPlate.left);
1889    } else {
1890      if (FX_EDIT_IsFloatSmaller(m_ptScrollPos.x, rcContent.left)) {
1891        SetScrollPosX(rcContent.left);
1892      } else if (FX_EDIT_IsFloatBigger(m_ptScrollPos.x,
1893                                       rcContent.right - rcPlate.Width())) {
1894        SetScrollPosX(rcContent.right - rcPlate.Width());
1895      }
1896    }
1897
1898    if (rcPlate.Height() > rcContent.Height()) {
1899      SetScrollPosY(rcPlate.top);
1900    } else {
1901      if (FX_EDIT_IsFloatSmaller(m_ptScrollPos.y,
1902                                 rcContent.bottom + rcPlate.Height())) {
1903        SetScrollPosY(rcContent.bottom + rcPlate.Height());
1904      } else if (FX_EDIT_IsFloatBigger(m_ptScrollPos.y, rcContent.top)) {
1905        SetScrollPosY(rcContent.top);
1906      }
1907    }
1908  }
1909}
1910
1911void CFX_Edit::ScrollToCaret() {
1912  SetScrollLimit();
1913
1914  if (m_pVT->IsValid()) {
1915    CPDF_Point ptHead(0, 0);
1916    CPDF_Point ptFoot(0, 0);
1917
1918    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1919      pIterator->SetAt(m_wpCaret);
1920
1921      CPVT_Word word;
1922      CPVT_Line line;
1923      if (pIterator->GetWord(word)) {
1924        ptHead.x = word.ptWord.x + word.fWidth;
1925        ptHead.y = word.ptWord.y + word.fAscent;
1926        ptFoot.x = word.ptWord.x + word.fWidth;
1927        ptFoot.y = word.ptWord.y + word.fDescent;
1928      } else if (pIterator->GetLine(line)) {
1929        ptHead.x = line.ptLine.x;
1930        ptHead.y = line.ptLine.y + line.fLineAscent;
1931        ptFoot.x = line.ptLine.x;
1932        ptFoot.y = line.ptLine.y + line.fLineDescent;
1933      }
1934    }
1935
1936    CPDF_Point ptHeadEdit = VTToEdit(ptHead);
1937    CPDF_Point ptFootEdit = VTToEdit(ptFoot);
1938
1939    CPDF_Rect rcPlate = m_pVT->GetPlateRect();
1940
1941    if (!FX_EDIT_IsFloatEqual(rcPlate.left, rcPlate.right)) {
1942      if (FX_EDIT_IsFloatSmaller(ptHeadEdit.x, rcPlate.left) ||
1943          FX_EDIT_IsFloatEqual(ptHeadEdit.x, rcPlate.left)) {
1944        SetScrollPosX(ptHead.x);
1945      } else if (FX_EDIT_IsFloatBigger(ptHeadEdit.x, rcPlate.right)) {
1946        SetScrollPosX(ptHead.x - rcPlate.Width());
1947      }
1948    }
1949
1950    if (!FX_EDIT_IsFloatEqual(rcPlate.top, rcPlate.bottom)) {
1951      if (FX_EDIT_IsFloatSmaller(ptFootEdit.y, rcPlate.bottom) ||
1952          FX_EDIT_IsFloatEqual(ptFootEdit.y, rcPlate.bottom)) {
1953        if (FX_EDIT_IsFloatSmaller(ptHeadEdit.y, rcPlate.top)) {
1954          SetScrollPosY(ptFoot.y + rcPlate.Height());
1955        }
1956      } else if (FX_EDIT_IsFloatBigger(ptHeadEdit.y, rcPlate.top)) {
1957        if (FX_EDIT_IsFloatBigger(ptFootEdit.y, rcPlate.bottom)) {
1958          SetScrollPosY(ptHead.y);
1959        }
1960      }
1961    }
1962  }
1963}
1964
1965void CFX_Edit::Refresh(REFRESH_PLAN_E ePlan,
1966                       const CPVT_WordRange* pRange1,
1967                       const CPVT_WordRange* pRange2) {
1968  if (m_bEnableRefresh && m_pVT->IsValid()) {
1969    m_Refresh.BeginRefresh();
1970    RefreshPushLineRects(GetVisibleWordRange());
1971
1972    m_Refresh.NoAnalyse();
1973    m_ptRefreshScrollPos = m_ptScrollPos;
1974
1975    if (m_bNotify && m_pNotify) {
1976      if (!m_bNotifyFlag) {
1977        m_bNotifyFlag = TRUE;
1978        if (const CFX_Edit_RectArray* pRects = m_Refresh.GetRefreshRects()) {
1979          for (int32_t i = 0, sz = pRects->GetSize(); i < sz; i++)
1980            m_pNotify->IOnInvalidateRect(pRects->GetAt(i));
1981        }
1982        m_bNotifyFlag = FALSE;
1983      }
1984    }
1985
1986    m_Refresh.EndRefresh();
1987  }
1988}
1989
1990void CFX_Edit::RefreshPushLineRects(const CPVT_WordRange& wr) {
1991  if (m_pVT->IsValid()) {
1992    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
1993      CPVT_WordPlace wpBegin = wr.BeginPos;
1994      m_pVT->UpdateWordPlace(wpBegin);
1995      CPVT_WordPlace wpEnd = wr.EndPos;
1996      m_pVT->UpdateWordPlace(wpEnd);
1997      pIterator->SetAt(wpBegin);
1998
1999      CPVT_Line lineinfo;
2000      do {
2001        if (!pIterator->GetLine(lineinfo))
2002          break;
2003        if (lineinfo.lineplace.LineCmp(wpEnd) > 0)
2004          break;
2005
2006        CPDF_Rect rcLine(lineinfo.ptLine.x,
2007                         lineinfo.ptLine.y + lineinfo.fLineDescent,
2008                         lineinfo.ptLine.x + lineinfo.fLineWidth,
2009                         lineinfo.ptLine.y + lineinfo.fLineAscent);
2010
2011        m_Refresh.Push(CPVT_WordRange(lineinfo.lineplace, lineinfo.lineEnd),
2012                       VTToEdit(rcLine));
2013      } while (pIterator->NextLine());
2014    }
2015  }
2016}
2017
2018void CFX_Edit::RefreshPushRandomRects(const CPVT_WordRange& wr) {
2019  if (m_pVT->IsValid()) {
2020    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2021      CPVT_WordRange wrTemp = wr;
2022
2023      m_pVT->UpdateWordPlace(wrTemp.BeginPos);
2024      m_pVT->UpdateWordPlace(wrTemp.EndPos);
2025      pIterator->SetAt(wrTemp.BeginPos);
2026
2027      CPVT_Word wordinfo;
2028      CPVT_Line lineinfo;
2029      CPVT_WordPlace place;
2030
2031      while (pIterator->NextWord()) {
2032        place = pIterator->GetAt();
2033        if (place.WordCmp(wrTemp.EndPos) > 0)
2034          break;
2035
2036        pIterator->GetWord(wordinfo);
2037        pIterator->GetLine(lineinfo);
2038
2039        if (place.LineCmp(wrTemp.BeginPos) == 0 ||
2040            place.LineCmp(wrTemp.EndPos) == 0) {
2041          CPDF_Rect rcWord(wordinfo.ptWord.x,
2042                           lineinfo.ptLine.y + lineinfo.fLineDescent,
2043                           wordinfo.ptWord.x + wordinfo.fWidth,
2044                           lineinfo.ptLine.y + lineinfo.fLineAscent);
2045
2046          m_Refresh.AddRefresh(VTToEdit(rcWord));
2047        } else {
2048          CPDF_Rect rcLine(lineinfo.ptLine.x,
2049                           lineinfo.ptLine.y + lineinfo.fLineDescent,
2050                           lineinfo.ptLine.x + lineinfo.fLineWidth,
2051                           lineinfo.ptLine.y + lineinfo.fLineAscent);
2052
2053          m_Refresh.AddRefresh(VTToEdit(rcLine));
2054
2055          pIterator->NextLine();
2056        }
2057      }
2058    }
2059  }
2060}
2061
2062void CFX_Edit::RefreshWordRange(const CPVT_WordRange& wr) {
2063  if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2064    CPVT_WordRange wrTemp = wr;
2065
2066    m_pVT->UpdateWordPlace(wrTemp.BeginPos);
2067    m_pVT->UpdateWordPlace(wrTemp.EndPos);
2068    pIterator->SetAt(wrTemp.BeginPos);
2069
2070    CPVT_Word wordinfo;
2071    CPVT_Line lineinfo;
2072    CPVT_WordPlace place;
2073
2074    while (pIterator->NextWord()) {
2075      place = pIterator->GetAt();
2076      if (place.WordCmp(wrTemp.EndPos) > 0)
2077        break;
2078
2079      pIterator->GetWord(wordinfo);
2080      pIterator->GetLine(lineinfo);
2081
2082      if (place.LineCmp(wrTemp.BeginPos) == 0 ||
2083          place.LineCmp(wrTemp.EndPos) == 0) {
2084        CPDF_Rect rcWord(wordinfo.ptWord.x,
2085                         lineinfo.ptLine.y + lineinfo.fLineDescent,
2086                         wordinfo.ptWord.x + wordinfo.fWidth,
2087                         lineinfo.ptLine.y + lineinfo.fLineAscent);
2088
2089        if (m_bNotify && m_pNotify) {
2090          if (!m_bNotifyFlag) {
2091            m_bNotifyFlag = TRUE;
2092            CPDF_Rect rcRefresh = VTToEdit(rcWord);
2093            m_pNotify->IOnInvalidateRect(&rcRefresh);
2094            m_bNotifyFlag = FALSE;
2095          }
2096        }
2097      } else {
2098        CPDF_Rect rcLine(lineinfo.ptLine.x,
2099                         lineinfo.ptLine.y + lineinfo.fLineDescent,
2100                         lineinfo.ptLine.x + lineinfo.fLineWidth,
2101                         lineinfo.ptLine.y + lineinfo.fLineAscent);
2102
2103        if (m_bNotify && m_pNotify) {
2104          if (!m_bNotifyFlag) {
2105            m_bNotifyFlag = TRUE;
2106            CPDF_Rect rcRefresh = VTToEdit(rcLine);
2107            m_pNotify->IOnInvalidateRect(&rcRefresh);
2108            m_bNotifyFlag = FALSE;
2109          }
2110        }
2111
2112        pIterator->NextLine();
2113      }
2114    }
2115  }
2116}
2117
2118void CFX_Edit::SetCaret(const CPVT_WordPlace& place) {
2119  m_wpOldCaret = m_wpCaret;
2120  m_wpCaret = place;
2121}
2122
2123void CFX_Edit::SetCaretInfo() {
2124  if (m_bNotify && m_pNotify) {
2125    if (!m_bNotifyFlag) {
2126      CPDF_Point ptHead(0.0f, 0.0f), ptFoot(0.0f, 0.0f);
2127
2128      if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2129        pIterator->SetAt(m_wpCaret);
2130        CPVT_Word word;
2131        CPVT_Line line;
2132        if (pIterator->GetWord(word)) {
2133          ptHead.x = word.ptWord.x + word.fWidth;
2134          ptHead.y = word.ptWord.y + word.fAscent;
2135          ptFoot.x = word.ptWord.x + word.fWidth;
2136          ptFoot.y = word.ptWord.y + word.fDescent;
2137        } else if (pIterator->GetLine(line)) {
2138          ptHead.x = line.ptLine.x;
2139          ptHead.y = line.ptLine.y + line.fLineAscent;
2140          ptFoot.x = line.ptLine.x;
2141          ptFoot.y = line.ptLine.y + line.fLineDescent;
2142        }
2143      }
2144
2145      m_bNotifyFlag = TRUE;
2146      m_pNotify->IOnSetCaret(!m_SelState.IsExist(), VTToEdit(ptHead),
2147                             VTToEdit(ptFoot), m_wpCaret);
2148      m_bNotifyFlag = FALSE;
2149    }
2150  }
2151
2152  SetCaretChange();
2153}
2154
2155void CFX_Edit::SetCaretChange() {
2156  if (m_wpCaret == m_wpOldCaret)
2157    return;
2158
2159  if (m_bNotify && m_pVT->IsRichText() && m_pNotify) {
2160    CPVT_SecProps SecProps;
2161    CPVT_WordProps WordProps;
2162
2163    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2164      pIterator->SetAt(m_wpCaret);
2165      CPVT_Word word;
2166      CPVT_Section section;
2167
2168      if (pIterator->GetSection(section)) {
2169        SecProps = section.SecProps;
2170        WordProps = section.WordProps;
2171      }
2172
2173      if (pIterator->GetWord(word)) {
2174        WordProps = word.WordProps;
2175      }
2176    }
2177
2178    if (!m_bNotifyFlag) {
2179      m_bNotifyFlag = TRUE;
2180      m_pNotify->IOnCaretChange(SecProps, WordProps);
2181      m_bNotifyFlag = FALSE;
2182    }
2183  }
2184}
2185
2186void CFX_Edit::SetCaret(int32_t nPos) {
2187  if (m_pVT->IsValid()) {
2188    SelectNone();
2189    SetCaret(m_pVT->WordIndexToWordPlace(nPos));
2190    m_SelState.Set(m_wpCaret, m_wpCaret);
2191
2192    ScrollToCaret();
2193    SetCaretOrigin();
2194    SetCaretInfo();
2195  }
2196}
2197
2198void CFX_Edit::OnMouseDown(const CPDF_Point& point,
2199                           FX_BOOL bShift,
2200                           FX_BOOL bCtrl) {
2201  if (m_pVT->IsValid()) {
2202    SelectNone();
2203    SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
2204    m_SelState.Set(m_wpCaret, m_wpCaret);
2205
2206    ScrollToCaret();
2207    SetCaretOrigin();
2208    SetCaretInfo();
2209  }
2210}
2211
2212void CFX_Edit::OnMouseMove(const CPDF_Point& point,
2213                           FX_BOOL bShift,
2214                           FX_BOOL bCtrl) {
2215  if (m_pVT->IsValid()) {
2216    SetCaret(m_pVT->SearchWordPlace(EditToVT(point)));
2217
2218    if (m_wpCaret != m_wpOldCaret) {
2219      m_SelState.SetEndPos(m_wpCaret);
2220
2221      ScrollToCaret();
2222      CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2223      Refresh(RP_OPTIONAL, &wr);
2224      SetCaretOrigin();
2225      SetCaretInfo();
2226    }
2227  }
2228}
2229
2230void CFX_Edit::OnVK_UP(FX_BOOL bShift, FX_BOOL bCtrl) {
2231  if (m_pVT->IsValid()) {
2232    SetCaret(m_pVT->GetUpWordPlace(m_wpCaret, m_ptCaret));
2233
2234    if (bShift) {
2235      if (m_SelState.IsExist())
2236        m_SelState.SetEndPos(m_wpCaret);
2237      else
2238        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2239
2240      if (m_wpOldCaret != m_wpCaret) {
2241        ScrollToCaret();
2242        CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2243        Refresh(RP_OPTIONAL, &wr);
2244        SetCaretInfo();
2245      }
2246    } else {
2247      SelectNone();
2248
2249      ScrollToCaret();
2250      SetCaretInfo();
2251    }
2252  }
2253}
2254
2255void CFX_Edit::OnVK_DOWN(FX_BOOL bShift, FX_BOOL bCtrl) {
2256  if (m_pVT->IsValid()) {
2257    SetCaret(m_pVT->GetDownWordPlace(m_wpCaret, m_ptCaret));
2258
2259    if (bShift) {
2260      if (m_SelState.IsExist())
2261        m_SelState.SetEndPos(m_wpCaret);
2262      else
2263        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2264
2265      if (m_wpOldCaret != m_wpCaret) {
2266        ScrollToCaret();
2267        CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2268        Refresh(RP_OPTIONAL, &wr);
2269        SetCaretInfo();
2270      }
2271    } else {
2272      SelectNone();
2273
2274      ScrollToCaret();
2275      SetCaretInfo();
2276    }
2277  }
2278}
2279
2280void CFX_Edit::OnVK_LEFT(FX_BOOL bShift, FX_BOOL bCtrl) {
2281  if (m_pVT->IsValid()) {
2282    if (bShift) {
2283      if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
2284          m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
2285        SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
2286
2287      SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
2288
2289      if (m_SelState.IsExist())
2290        m_SelState.SetEndPos(m_wpCaret);
2291      else
2292        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2293
2294      if (m_wpOldCaret != m_wpCaret) {
2295        ScrollToCaret();
2296        CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2297        Refresh(RP_OPTIONAL, &wr);
2298        SetCaretInfo();
2299      }
2300    } else {
2301      if (m_SelState.IsExist()) {
2302        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
2303          SetCaret(m_SelState.BeginPos);
2304        else
2305          SetCaret(m_SelState.EndPos);
2306
2307        SelectNone();
2308        ScrollToCaret();
2309        SetCaretInfo();
2310      } else {
2311        if (m_wpCaret == m_pVT->GetLineBeginPlace(m_wpCaret) &&
2312            m_wpCaret != m_pVT->GetSectionBeginPlace(m_wpCaret))
2313          SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
2314
2315        SetCaret(m_pVT->GetPrevWordPlace(m_wpCaret));
2316
2317        ScrollToCaret();
2318        SetCaretOrigin();
2319        SetCaretInfo();
2320      }
2321    }
2322  }
2323}
2324
2325void CFX_Edit::OnVK_RIGHT(FX_BOOL bShift, FX_BOOL bCtrl) {
2326  if (m_pVT->IsValid()) {
2327    if (bShift) {
2328      SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
2329
2330      if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
2331          m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
2332        SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
2333
2334      if (m_SelState.IsExist())
2335        m_SelState.SetEndPos(m_wpCaret);
2336      else
2337        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2338
2339      if (m_wpOldCaret != m_wpCaret) {
2340        ScrollToCaret();
2341        CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2342        Refresh(RP_OPTIONAL, &wr);
2343        SetCaretInfo();
2344      }
2345    } else {
2346      if (m_SelState.IsExist()) {
2347        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
2348          SetCaret(m_SelState.BeginPos);
2349        else
2350          SetCaret(m_SelState.EndPos);
2351
2352        SelectNone();
2353        ScrollToCaret();
2354        SetCaretInfo();
2355      } else {
2356        SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
2357
2358        if (m_wpCaret == m_pVT->GetLineEndPlace(m_wpCaret) &&
2359            m_wpCaret != m_pVT->GetSectionEndPlace(m_wpCaret))
2360          SetCaret(m_pVT->GetNextWordPlace(m_wpCaret));
2361
2362        ScrollToCaret();
2363        SetCaretOrigin();
2364        SetCaretInfo();
2365      }
2366    }
2367  }
2368}
2369
2370void CFX_Edit::OnVK_HOME(FX_BOOL bShift, FX_BOOL bCtrl) {
2371  if (m_pVT->IsValid()) {
2372    if (bShift) {
2373      if (bCtrl)
2374        SetCaret(m_pVT->GetBeginWordPlace());
2375      else
2376        SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
2377
2378      if (m_SelState.IsExist())
2379        m_SelState.SetEndPos(m_wpCaret);
2380      else
2381        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2382
2383      ScrollToCaret();
2384      CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2385      Refresh(RP_OPTIONAL, &wr);
2386      SetCaretInfo();
2387    } else {
2388      if (m_SelState.IsExist()) {
2389        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) < 0)
2390          SetCaret(m_SelState.BeginPos);
2391        else
2392          SetCaret(m_SelState.EndPos);
2393
2394        SelectNone();
2395        ScrollToCaret();
2396        SetCaretInfo();
2397      } else {
2398        if (bCtrl)
2399          SetCaret(m_pVT->GetBeginWordPlace());
2400        else
2401          SetCaret(m_pVT->GetLineBeginPlace(m_wpCaret));
2402
2403        ScrollToCaret();
2404        SetCaretOrigin();
2405        SetCaretInfo();
2406      }
2407    }
2408  }
2409}
2410
2411void CFX_Edit::OnVK_END(FX_BOOL bShift, FX_BOOL bCtrl) {
2412  if (m_pVT->IsValid()) {
2413    if (bShift) {
2414      if (bCtrl)
2415        SetCaret(m_pVT->GetEndWordPlace());
2416      else
2417        SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
2418
2419      if (m_SelState.IsExist())
2420        m_SelState.SetEndPos(m_wpCaret);
2421      else
2422        m_SelState.Set(m_wpOldCaret, m_wpCaret);
2423
2424      ScrollToCaret();
2425      CPVT_WordRange wr(m_wpOldCaret, m_wpCaret);
2426      Refresh(RP_OPTIONAL, &wr);
2427      SetCaretInfo();
2428    } else {
2429      if (m_SelState.IsExist()) {
2430        if (m_SelState.BeginPos.WordCmp(m_SelState.EndPos) > 0)
2431          SetCaret(m_SelState.BeginPos);
2432        else
2433          SetCaret(m_SelState.EndPos);
2434
2435        SelectNone();
2436        ScrollToCaret();
2437        SetCaretInfo();
2438      } else {
2439        if (bCtrl)
2440          SetCaret(m_pVT->GetEndWordPlace());
2441        else
2442          SetCaret(m_pVT->GetLineEndPlace(m_wpCaret));
2443
2444        ScrollToCaret();
2445        SetCaretOrigin();
2446        SetCaretInfo();
2447      }
2448    }
2449  }
2450}
2451
2452void CFX_Edit::SetText(const FX_WCHAR* text,
2453                       int32_t charset,
2454                       const CPVT_SecProps* pSecProps,
2455                       const CPVT_WordProps* pWordProps,
2456                       FX_BOOL bAddUndo,
2457                       FX_BOOL bPaint) {
2458  Empty();
2459  DoInsertText(CPVT_WordPlace(0, 0, -1), text, charset, pSecProps, pWordProps);
2460  if (bPaint)
2461    Paint();
2462  if (m_bOprNotify && m_pOprNotify)
2463    m_pOprNotify->OnSetText(m_wpCaret, m_wpOldCaret);
2464}
2465
2466FX_BOOL CFX_Edit::InsertWord(FX_WORD word,
2467                             int32_t charset,
2468                             const CPVT_WordProps* pWordProps,
2469                             FX_BOOL bAddUndo,
2470                             FX_BOOL bPaint) {
2471  if (IsTextOverflow())
2472    return FALSE;
2473
2474  if (m_pVT->IsValid()) {
2475    m_pVT->UpdateWordPlace(m_wpCaret);
2476
2477    SetCaret(m_pVT->InsertWord(
2478        m_wpCaret, word, GetCharSetFromUnicode(word, charset), pWordProps));
2479    m_SelState.Set(m_wpCaret, m_wpCaret);
2480
2481    if (m_wpCaret != m_wpOldCaret) {
2482      if (bAddUndo && m_bEnableUndo) {
2483        AddEditUndoItem(new CFXEU_InsertWord(this, m_wpOldCaret, m_wpCaret,
2484                                             word, charset, pWordProps));
2485      }
2486
2487      if (bPaint)
2488        PaintInsertText(m_wpOldCaret, m_wpCaret);
2489
2490      if (m_bOprNotify && m_pOprNotify)
2491        m_pOprNotify->OnInsertWord(m_wpCaret, m_wpOldCaret);
2492
2493      return TRUE;
2494    }
2495  }
2496
2497  return FALSE;
2498}
2499
2500FX_BOOL CFX_Edit::InsertReturn(const CPVT_SecProps* pSecProps,
2501                               const CPVT_WordProps* pWordProps,
2502                               FX_BOOL bAddUndo,
2503                               FX_BOOL bPaint) {
2504  if (IsTextOverflow())
2505    return FALSE;
2506
2507  if (m_pVT->IsValid()) {
2508    m_pVT->UpdateWordPlace(m_wpCaret);
2509    SetCaret(m_pVT->InsertSection(m_wpCaret, pSecProps, pWordProps));
2510    m_SelState.Set(m_wpCaret, m_wpCaret);
2511
2512    if (m_wpCaret != m_wpOldCaret) {
2513      if (bAddUndo && m_bEnableUndo) {
2514        AddEditUndoItem(new CFXEU_InsertReturn(this, m_wpOldCaret, m_wpCaret,
2515                                               pSecProps, pWordProps));
2516      }
2517
2518      if (bPaint) {
2519        RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
2520        ScrollToCaret();
2521        CPVT_WordRange wr(m_wpOldCaret, GetVisibleWordRange().EndPos);
2522        Refresh(RP_ANALYSE, &wr);
2523        SetCaretOrigin();
2524        SetCaretInfo();
2525      }
2526
2527      if (m_bOprNotify && m_pOprNotify)
2528        m_pOprNotify->OnInsertReturn(m_wpCaret, m_wpOldCaret);
2529
2530      return TRUE;
2531    }
2532  }
2533
2534  return FALSE;
2535}
2536
2537FX_BOOL CFX_Edit::Backspace(FX_BOOL bAddUndo, FX_BOOL bPaint) {
2538  if (m_pVT->IsValid()) {
2539    if (m_wpCaret == m_pVT->GetBeginWordPlace())
2540      return FALSE;
2541
2542    CPVT_Section section;
2543    CPVT_Word word;
2544
2545    if (bAddUndo) {
2546      if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2547        pIterator->SetAt(m_wpCaret);
2548        pIterator->GetSection(section);
2549        pIterator->GetWord(word);
2550      }
2551    }
2552
2553    m_pVT->UpdateWordPlace(m_wpCaret);
2554    SetCaret(m_pVT->BackSpaceWord(m_wpCaret));
2555    m_SelState.Set(m_wpCaret, m_wpCaret);
2556
2557    if (m_wpCaret != m_wpOldCaret) {
2558      if (bAddUndo && m_bEnableUndo) {
2559        if (m_wpCaret.SecCmp(m_wpOldCaret) != 0)
2560          AddEditUndoItem(new CFXEU_Backspace(
2561              this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
2562              section.SecProps, section.WordProps));
2563        else
2564          AddEditUndoItem(new CFXEU_Backspace(
2565              this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
2566              section.SecProps, word.WordProps));
2567      }
2568
2569      if (bPaint) {
2570        RearrangePart(CPVT_WordRange(m_wpCaret, m_wpOldCaret));
2571        ScrollToCaret();
2572
2573        CPVT_WordRange wr;
2574        if (m_wpCaret.SecCmp(m_wpOldCaret) != 0)
2575          wr = CPVT_WordRange(m_pVT->GetPrevWordPlace(m_wpCaret),
2576                              GetVisibleWordRange().EndPos);
2577        else if (m_wpCaret.LineCmp(m_wpOldCaret) != 0)
2578          wr = CPVT_WordRange(m_pVT->GetLineBeginPlace(m_wpCaret),
2579                              m_pVT->GetSectionEndPlace(m_wpCaret));
2580        else
2581          wr = CPVT_WordRange(m_pVT->GetPrevWordPlace(m_wpCaret),
2582                              m_pVT->GetSectionEndPlace(m_wpCaret));
2583
2584        Refresh(RP_ANALYSE, &wr);
2585
2586        SetCaretOrigin();
2587        SetCaretInfo();
2588      }
2589
2590      if (m_bOprNotify && m_pOprNotify)
2591        m_pOprNotify->OnBackSpace(m_wpCaret, m_wpOldCaret);
2592
2593      return TRUE;
2594    }
2595  }
2596
2597  return FALSE;
2598}
2599
2600FX_BOOL CFX_Edit::Delete(FX_BOOL bAddUndo, FX_BOOL bPaint) {
2601  if (m_pVT->IsValid()) {
2602    if (m_wpCaret == m_pVT->GetEndWordPlace())
2603      return FALSE;
2604
2605    CPVT_Section section;
2606    CPVT_Word word;
2607
2608    if (bAddUndo) {
2609      if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2610        pIterator->SetAt(m_pVT->GetNextWordPlace(m_wpCaret));
2611        pIterator->GetSection(section);
2612        pIterator->GetWord(word);
2613      }
2614    }
2615
2616    m_pVT->UpdateWordPlace(m_wpCaret);
2617    FX_BOOL bSecEnd = (m_wpCaret == m_pVT->GetSectionEndPlace(m_wpCaret));
2618
2619    SetCaret(m_pVT->DeleteWord(m_wpCaret));
2620    m_SelState.Set(m_wpCaret, m_wpCaret);
2621
2622    if (bAddUndo && m_bEnableUndo) {
2623      if (bSecEnd)
2624        AddEditUndoItem(new CFXEU_Delete(
2625            this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
2626            section.SecProps, section.WordProps, bSecEnd));
2627      else
2628        AddEditUndoItem(new CFXEU_Delete(
2629            this, m_wpOldCaret, m_wpCaret, word.Word, word.nCharset,
2630            section.SecProps, word.WordProps, bSecEnd));
2631    }
2632
2633    if (bPaint) {
2634      RearrangePart(CPVT_WordRange(m_wpOldCaret, m_wpCaret));
2635      ScrollToCaret();
2636
2637      CPVT_WordRange wr;
2638      if (bSecEnd)
2639        wr = CPVT_WordRange(m_pVT->GetPrevWordPlace(m_wpOldCaret),
2640                            GetVisibleWordRange().EndPos);
2641      else if (m_wpCaret.LineCmp(m_wpOldCaret) != 0)
2642        wr = CPVT_WordRange(m_pVT->GetLineBeginPlace(m_wpCaret),
2643                            m_pVT->GetSectionEndPlace(m_wpCaret));
2644      else
2645        wr = CPVT_WordRange(m_pVT->GetPrevWordPlace(m_wpOldCaret),
2646                            m_pVT->GetSectionEndPlace(m_wpCaret));
2647
2648      Refresh(RP_ANALYSE, &wr);
2649
2650      SetCaretOrigin();
2651      SetCaretInfo();
2652    }
2653
2654    if (m_bOprNotify && m_pOprNotify)
2655      m_pOprNotify->OnDelete(m_wpCaret, m_wpOldCaret);
2656
2657    return TRUE;
2658  }
2659
2660  return FALSE;
2661}
2662
2663FX_BOOL CFX_Edit::Empty() {
2664  if (m_pVT->IsValid()) {
2665    m_pVT->DeleteWords(GetWholeWordRange());
2666    SetCaret(m_pVT->GetBeginWordPlace());
2667
2668    return TRUE;
2669  }
2670
2671  return FALSE;
2672}
2673
2674FX_BOOL CFX_Edit::Clear(FX_BOOL bAddUndo, FX_BOOL bPaint) {
2675  if (m_pVT->IsValid()) {
2676    if (m_SelState.IsExist()) {
2677      CPVT_WordRange range = m_SelState.ConvertToWordRange();
2678
2679      if (bAddUndo && m_bEnableUndo) {
2680        if (m_pVT->IsRichText()) {
2681          BeginGroupUndo(L"");
2682
2683          if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2684            pIterator->SetAt(range.EndPos);
2685
2686            CPVT_Word wordinfo;
2687            CPVT_Section secinfo;
2688            do {
2689              CPVT_WordPlace place = pIterator->GetAt();
2690              if (place.WordCmp(range.BeginPos) <= 0)
2691                break;
2692
2693              CPVT_WordPlace oldplace = m_pVT->GetPrevWordPlace(place);
2694
2695              if (oldplace.SecCmp(place) != 0) {
2696                if (pIterator->GetSection(secinfo)) {
2697                  AddEditUndoItem(new CFXEU_ClearRich(
2698                      this, oldplace, place, range, wordinfo.Word,
2699                      wordinfo.nCharset, secinfo.SecProps, secinfo.WordProps));
2700                }
2701              } else {
2702                if (pIterator->GetWord(wordinfo)) {
2703                  oldplace = m_pVT->AdjustLineHeader(oldplace, TRUE);
2704                  place = m_pVT->AdjustLineHeader(place, TRUE);
2705
2706                  AddEditUndoItem(new CFXEU_ClearRich(
2707                      this, oldplace, place, range, wordinfo.Word,
2708                      wordinfo.nCharset, secinfo.SecProps, wordinfo.WordProps));
2709                }
2710              }
2711            } while (pIterator->PrevWord());
2712          }
2713          EndGroupUndo();
2714        } else {
2715          AddEditUndoItem(new CFXEU_Clear(this, range, GetSelText()));
2716        }
2717      }
2718
2719      SelectNone();
2720      SetCaret(m_pVT->DeleteWords(range));
2721      m_SelState.Set(m_wpCaret, m_wpCaret);
2722
2723      if (bPaint) {
2724        RearrangePart(range);
2725        ScrollToCaret();
2726
2727        CPVT_WordRange wr(m_wpOldCaret, GetVisibleWordRange().EndPos);
2728        Refresh(RP_ANALYSE, &wr);
2729
2730        SetCaretOrigin();
2731        SetCaretInfo();
2732      }
2733
2734      if (m_bOprNotify && m_pOprNotify)
2735        m_pOprNotify->OnClear(m_wpCaret, m_wpOldCaret);
2736
2737      return TRUE;
2738    }
2739  }
2740
2741  return FALSE;
2742}
2743
2744FX_BOOL CFX_Edit::InsertText(const FX_WCHAR* text,
2745                             int32_t charset,
2746                             const CPVT_SecProps* pSecProps,
2747                             const CPVT_WordProps* pWordProps,
2748                             FX_BOOL bAddUndo,
2749                             FX_BOOL bPaint) {
2750  if (IsTextOverflow())
2751    return FALSE;
2752
2753  m_pVT->UpdateWordPlace(m_wpCaret);
2754  SetCaret(DoInsertText(m_wpCaret, text, charset, pSecProps, pWordProps));
2755  m_SelState.Set(m_wpCaret, m_wpCaret);
2756
2757  if (m_wpCaret != m_wpOldCaret) {
2758    if (bAddUndo && m_bEnableUndo) {
2759      AddEditUndoItem(new CFXEU_InsertText(this, m_wpOldCaret, m_wpCaret, text,
2760                                           charset, pSecProps, pWordProps));
2761    }
2762
2763    if (bPaint)
2764      PaintInsertText(m_wpOldCaret, m_wpCaret);
2765
2766    if (m_bOprNotify && m_pOprNotify)
2767      m_pOprNotify->OnInsertText(m_wpCaret, m_wpOldCaret);
2768
2769    return TRUE;
2770  }
2771  return FALSE;
2772}
2773
2774void CFX_Edit::PaintInsertText(const CPVT_WordPlace& wpOld,
2775                               const CPVT_WordPlace& wpNew) {
2776  if (m_pVT->IsValid()) {
2777    RearrangePart(CPVT_WordRange(wpOld, wpNew));
2778    ScrollToCaret();
2779
2780    CPVT_WordRange wr;
2781    if (m_wpCaret.LineCmp(wpOld) != 0)
2782      wr = CPVT_WordRange(m_pVT->GetLineBeginPlace(wpOld),
2783                          m_pVT->GetSectionEndPlace(wpNew));
2784    else
2785      wr = CPVT_WordRange(wpOld, m_pVT->GetSectionEndPlace(wpNew));
2786    Refresh(RP_ANALYSE, &wr);
2787    SetCaretOrigin();
2788    SetCaretInfo();
2789  }
2790}
2791
2792FX_BOOL CFX_Edit::Redo() {
2793  if (m_bEnableUndo) {
2794    if (m_Undo.CanRedo()) {
2795      m_Undo.Redo();
2796      return TRUE;
2797    }
2798  }
2799
2800  return FALSE;
2801}
2802
2803FX_BOOL CFX_Edit::Undo() {
2804  if (m_bEnableUndo) {
2805    if (m_Undo.CanUndo()) {
2806      m_Undo.Undo();
2807      return TRUE;
2808    }
2809  }
2810
2811  return FALSE;
2812}
2813
2814void CFX_Edit::SetCaretOrigin() {
2815  if (m_pVT->IsValid()) {
2816    if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2817      pIterator->SetAt(m_wpCaret);
2818      CPVT_Word word;
2819      CPVT_Line line;
2820      if (pIterator->GetWord(word)) {
2821        m_ptCaret.x = word.ptWord.x + word.fWidth;
2822        m_ptCaret.y = word.ptWord.y;
2823      } else if (pIterator->GetLine(line)) {
2824        m_ptCaret.x = line.ptLine.x;
2825        m_ptCaret.y = line.ptLine.y;
2826      }
2827    }
2828  }
2829}
2830
2831int32_t CFX_Edit::WordPlaceToWordIndex(const CPVT_WordPlace& place) const {
2832  if (m_pVT->IsValid())
2833    return m_pVT->WordPlaceToWordIndex(place);
2834
2835  return -1;
2836}
2837
2838CPVT_WordPlace CFX_Edit::WordIndexToWordPlace(int32_t index) const {
2839  if (m_pVT->IsValid())
2840    return m_pVT->WordIndexToWordPlace(index);
2841
2842  return CPVT_WordPlace();
2843}
2844
2845FX_BOOL CFX_Edit::IsTextFull() const {
2846  int32_t nTotalWords = m_pVT->GetTotalWords();
2847  int32_t nLimitChar = m_pVT->GetLimitChar();
2848  int32_t nCharArray = m_pVT->GetCharArray();
2849
2850  return IsTextOverflow() || (nLimitChar > 0 && nTotalWords >= nLimitChar) ||
2851         (nCharArray > 0 && nTotalWords >= nCharArray);
2852}
2853
2854FX_BOOL CFX_Edit::IsTextOverflow() const {
2855  if (!m_bEnableScroll && !m_bEnableOverflow) {
2856    CPDF_Rect rcPlate = m_pVT->GetPlateRect();
2857    CPDF_Rect rcContent = m_pVT->GetContentRect();
2858
2859    if (m_pVT->IsMultiLine() && GetTotalLines() > 1) {
2860      if (FX_EDIT_IsFloatBigger(rcContent.Height(), rcPlate.Height()))
2861        return TRUE;
2862    }
2863
2864    if (FX_EDIT_IsFloatBigger(rcContent.Width(), rcPlate.Width()))
2865      return TRUE;
2866  }
2867
2868  return FALSE;
2869}
2870
2871CPVT_WordPlace CFX_Edit::GetLineBeginPlace(const CPVT_WordPlace& place) const {
2872  return m_pVT->GetLineBeginPlace(place);
2873}
2874
2875CPVT_WordPlace CFX_Edit::GetLineEndPlace(const CPVT_WordPlace& place) const {
2876  return m_pVT->GetLineEndPlace(place);
2877}
2878
2879CPVT_WordPlace CFX_Edit::GetSectionBeginPlace(
2880    const CPVT_WordPlace& place) const {
2881  return m_pVT->GetSectionBeginPlace(place);
2882}
2883
2884CPVT_WordPlace CFX_Edit::GetSectionEndPlace(const CPVT_WordPlace& place) const {
2885  return m_pVT->GetSectionEndPlace(place);
2886}
2887
2888FX_BOOL CFX_Edit::CanUndo() const {
2889  if (m_bEnableUndo) {
2890    return m_Undo.CanUndo();
2891  }
2892
2893  return FALSE;
2894}
2895
2896FX_BOOL CFX_Edit::CanRedo() const {
2897  if (m_bEnableUndo) {
2898    return m_Undo.CanRedo();
2899  }
2900
2901  return FALSE;
2902}
2903
2904FX_BOOL CFX_Edit::IsModified() const {
2905  if (m_bEnableUndo) {
2906    return m_Undo.IsModified();
2907  }
2908
2909  return FALSE;
2910}
2911
2912void CFX_Edit::EnableRefresh(FX_BOOL bRefresh) {
2913  m_bEnableRefresh = bRefresh;
2914}
2915
2916void CFX_Edit::EnableUndo(FX_BOOL bUndo) {
2917  m_bEnableUndo = bUndo;
2918}
2919
2920void CFX_Edit::EnableNotify(FX_BOOL bNotify) {
2921  m_bNotify = bNotify;
2922}
2923
2924void CFX_Edit::EnableOprNotify(FX_BOOL bNotify) {
2925  m_bOprNotify = bNotify;
2926}
2927
2928FX_FLOAT CFX_Edit::GetLineTop(const CPVT_WordPlace& place) const {
2929  if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2930    CPVT_WordPlace wpOld = pIterator->GetAt();
2931
2932    pIterator->SetAt(place);
2933    CPVT_Line line;
2934    pIterator->GetLine(line);
2935
2936    pIterator->SetAt(wpOld);
2937
2938    return line.ptLine.y + line.fLineAscent;
2939  }
2940
2941  return 0.0f;
2942}
2943
2944FX_FLOAT CFX_Edit::GetLineBottom(const CPVT_WordPlace& place) const {
2945  if (IPDF_VariableText_Iterator* pIterator = m_pVT->GetIterator()) {
2946    CPVT_WordPlace wpOld = pIterator->GetAt();
2947
2948    pIterator->SetAt(place);
2949    CPVT_Line line;
2950    pIterator->GetLine(line);
2951
2952    pIterator->SetAt(wpOld);
2953
2954    return line.ptLine.y + line.fLineDescent;
2955  }
2956
2957  return 0.0f;
2958}
2959
2960CPVT_WordPlace CFX_Edit::DoInsertText(const CPVT_WordPlace& place,
2961                                      const FX_WCHAR* text,
2962                                      int32_t charset,
2963                                      const CPVT_SecProps* pSecProps,
2964                                      const CPVT_WordProps* pWordProps) {
2965  CPVT_WordPlace wp = place;
2966
2967  if (m_pVT->IsValid()) {
2968    CFX_WideString sText = text;
2969
2970    for (int32_t i = 0, sz = sText.GetLength(); i < sz; i++) {
2971      FX_WORD word = sText[i];
2972      switch (word) {
2973        case 0x0D:
2974          wp = m_pVT->InsertSection(wp, pSecProps, pWordProps);
2975          if (sText[i + 1] == 0x0A)
2976            i++;
2977          break;
2978        case 0x0A:
2979          wp = m_pVT->InsertSection(wp, pSecProps, pWordProps);
2980          if (sText[i + 1] == 0x0D)
2981            i++;
2982          break;
2983        case 0x09:
2984          word = 0x20;
2985        default:
2986          wp = m_pVT->InsertWord(wp, word, GetCharSetFromUnicode(word, charset),
2987                                 pWordProps);
2988          break;
2989      }
2990    }
2991  }
2992
2993  return wp;
2994}
2995
2996int32_t CFX_Edit::GetCharSetFromUnicode(FX_WORD word, int32_t nOldCharset) {
2997  if (IFX_Edit_FontMap* pFontMap = GetFontMap())
2998    return pFontMap->CharSetFromUnicode(word, nOldCharset);
2999  return nOldCharset;
3000}
3001
3002void CFX_Edit::BeginGroupUndo(const CFX_WideString& sTitle) {
3003  ASSERT(!m_pGroupUndoItem);
3004
3005  m_pGroupUndoItem = new CFX_Edit_GroupUndoItem(sTitle);
3006}
3007
3008void CFX_Edit::EndGroupUndo() {
3009  m_pGroupUndoItem->UpdateItems();
3010  m_Undo.AddItem(m_pGroupUndoItem);
3011  if (m_bOprNotify && m_pOprNotify)
3012    m_pOprNotify->OnAddUndo(m_pGroupUndoItem);
3013  m_pGroupUndoItem = NULL;
3014}
3015
3016void CFX_Edit::AddEditUndoItem(CFX_Edit_UndoItem* pEditUndoItem) {
3017  if (m_pGroupUndoItem) {
3018    m_pGroupUndoItem->AddUndoItem(pEditUndoItem);
3019  } else {
3020    m_Undo.AddItem(pEditUndoItem);
3021    if (m_bOprNotify && m_pOprNotify)
3022      m_pOprNotify->OnAddUndo(pEditUndoItem);
3023  }
3024}
3025
3026void CFX_Edit::AddUndoItem(IFX_Edit_UndoItem* pUndoItem) {
3027  m_Undo.AddItem(pUndoItem);
3028  if (m_bOprNotify && m_pOprNotify)
3029    m_pOprNotify->OnAddUndo(pUndoItem);
3030}
3031