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