• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "xfa/fde/cfde_txtedtengine.h"
8 
9 #include <algorithm>
10 
11 #include "third_party/base/ptr_util.h"
12 #include "xfa/fde/cfde_txtedtbuf.h"
13 #include "xfa/fde/cfde_txtedtdorecord_deleterange.h"
14 #include "xfa/fde/cfde_txtedtdorecord_insert.h"
15 #include "xfa/fde/cfde_txtedtpage.h"
16 #include "xfa/fde/cfde_txtedtparag.h"
17 #include "xfa/fde/ifx_chariter.h"
18 #include "xfa/fde/tto/fde_textout.h"
19 #include "xfa/fgas/layout/fgas_textbreak.h"
20 #include "xfa/fwl/cfwl_edit.h"
21 
22 namespace {
23 
24 const uint32_t kPageWidthMax = 0xffff;
25 const uint32_t kUnicodeParagraphSeparator = 0x2029;
26 
27 }  // namespace
28 
FDE_TXTEDTPARAMS()29 FDE_TXTEDTPARAMS::FDE_TXTEDTPARAMS()
30     : fPlateWidth(0),
31       fPlateHeight(0),
32       nLineCount(0),
33       dwLayoutStyles(0),
34       dwAlignment(0),
35       dwMode(0),
36       fFontSize(10.0f),
37       dwFontColor(0xff000000),
38       fLineSpace(10.0f),
39       fTabWidth(36),
40       bTabEquidistant(false),
41       wDefChar(0xFEFF),
42       wLineBreakChar('\n'),
43       nCharRotation(0),
44       nLineEnd(0),
45       nHorzScale(100),
46       fCharSpace(0),
47       pEventSink(nullptr) {}
48 
~FDE_TXTEDTPARAMS()49 FDE_TXTEDTPARAMS::~FDE_TXTEDTPARAMS() {}
50 
FDE_TXTEDT_TEXTCHANGE_INFO()51 FDE_TXTEDT_TEXTCHANGE_INFO::FDE_TXTEDT_TEXTCHANGE_INFO() {}
52 
~FDE_TXTEDT_TEXTCHANGE_INFO()53 FDE_TXTEDT_TEXTCHANGE_INFO::~FDE_TXTEDT_TEXTCHANGE_INFO() {}
54 
CFDE_TxtEdtEngine()55 CFDE_TxtEdtEngine::CFDE_TxtEdtEngine()
56     : m_pTxtBuf(new CFDE_TxtEdtBuf()),
57       m_nPageLineCount(20),
58       m_nLineCount(0),
59       m_nAnchorPos(-1),
60       m_nLayoutPos(0),
61       m_fCaretPosReserve(0.0),
62       m_nCaret(0),
63       m_bBefore(true),
64       m_nCaretPage(0),
65       m_dwFindFlags(0),
66       m_bLock(false),
67       m_nLimit(0),
68       m_wcAliasChar(L'*'),
69       m_nFirstLineEnd(FDE_TXTEDIT_LINEEND_Auto),
70       m_bAutoLineEnd(true),
71       m_wLineEnd(kUnicodeParagraphSeparator) {
72   m_bAutoLineEnd = (m_Param.nLineEnd == FDE_TXTEDIT_LINEEND_Auto);
73 }
74 
~CFDE_TxtEdtEngine()75 CFDE_TxtEdtEngine::~CFDE_TxtEdtEngine() {
76   RemoveAllParags();
77   RemoveAllPages();
78   m_Param.pEventSink = nullptr;
79   ClearSelection();
80 }
81 
SetEditParams(const FDE_TXTEDTPARAMS & params)82 void CFDE_TxtEdtEngine::SetEditParams(const FDE_TXTEDTPARAMS& params) {
83   if (!m_pTextBreak)
84     m_pTextBreak = pdfium::MakeUnique<CFX_TxtBreak>(FX_TXTBREAKPOLICY_None);
85 
86   m_Param = params;
87   m_wLineEnd = params.wLineBreakChar;
88   m_bAutoLineEnd = (m_Param.nLineEnd == FDE_TXTEDIT_LINEEND_Auto);
89   UpdateTxtBreak();
90 }
91 
GetEditParams()92 FDE_TXTEDTPARAMS* CFDE_TxtEdtEngine::GetEditParams() {
93   return &m_Param;
94 }
95 
CountPages() const96 int32_t CFDE_TxtEdtEngine::CountPages() const {
97   if (m_nLineCount == 0) {
98     return 0;
99   }
100   return ((m_nLineCount - 1) / m_nPageLineCount) + 1;
101 }
102 
GetPage(int32_t nIndex)103 IFDE_TxtEdtPage* CFDE_TxtEdtEngine::GetPage(int32_t nIndex) {
104   if (m_PagePtrArray.GetSize() <= nIndex) {
105     return nullptr;
106   }
107   return m_PagePtrArray[nIndex];
108 }
109 
SetTextByStream(const CFX_RetainPtr<IFGAS_Stream> & pStream)110 void CFDE_TxtEdtEngine::SetTextByStream(
111     const CFX_RetainPtr<IFGAS_Stream>& pStream) {
112   ResetEngine();
113   int32_t nIndex = 0;
114   if (pStream && pStream->GetLength()) {
115     int32_t nStreamLength = pStream->GetLength();
116     bool bValid = true;
117     if (m_nLimit > 0 && nStreamLength > m_nLimit) {
118       bValid = false;
119     }
120     bool bPreIsCR = false;
121     if (bValid) {
122       uint8_t bom[4];
123       int32_t nPos = pStream->GetBOM(bom);
124       pStream->Seek(FX_STREAMSEEK_Begin, nPos);
125       int32_t nPlateSize = std::min(nStreamLength, m_pTxtBuf->GetChunkSize());
126       FX_WCHAR* lpwstr = FX_Alloc(FX_WCHAR, nPlateSize);
127       bool bEos = false;
128       while (!bEos) {
129         int32_t nRead = pStream->ReadString(lpwstr, nPlateSize, bEos);
130         bPreIsCR = ReplaceParagEnd(lpwstr, nRead, bPreIsCR);
131         m_pTxtBuf->Insert(nIndex, lpwstr, nRead);
132         nIndex += nRead;
133       }
134       FX_Free(lpwstr);
135     }
136   }
137   m_pTxtBuf->Insert(nIndex, &m_wLineEnd, 1);
138   RebuildParagraphs();
139 }
140 
SetText(const CFX_WideString & wsText)141 void CFDE_TxtEdtEngine::SetText(const CFX_WideString& wsText) {
142   ResetEngine();
143   int32_t nLength = wsText.GetLength();
144   if (nLength > 0) {
145     CFX_WideString wsTemp;
146     FX_WCHAR* lpBuffer = wsTemp.GetBuffer(nLength);
147     FXSYS_memcpy(lpBuffer, wsText.c_str(), nLength * sizeof(FX_WCHAR));
148     ReplaceParagEnd(lpBuffer, nLength, false);
149     wsTemp.ReleaseBuffer(nLength);
150     if (m_nLimit > 0 && nLength > m_nLimit) {
151       wsTemp.Delete(m_nLimit, nLength - m_nLimit);
152       nLength = m_nLimit;
153     }
154     m_pTxtBuf->SetText(wsTemp);
155   }
156   m_pTxtBuf->Insert(nLength, &m_wLineEnd, 1);
157   RebuildParagraphs();
158 }
159 
GetTextLength() const160 int32_t CFDE_TxtEdtEngine::GetTextLength() const {
161   return GetTextBufLength();
162 }
163 
GetText(int32_t nStart,int32_t nCount) const164 CFX_WideString CFDE_TxtEdtEngine::GetText(int32_t nStart,
165                                           int32_t nCount) const {
166   int32_t nTextBufLength = GetTextBufLength();
167   if (nCount == -1)
168     nCount = nTextBufLength - nStart;
169 
170   CFX_WideString wsText = m_pTxtBuf->GetRange(nStart, nCount);
171   RecoverParagEnd(wsText);
172   return wsText;
173 }
174 
ClearText()175 void CFDE_TxtEdtEngine::ClearText() {
176   DeleteRange(0, -1);
177 }
178 
GetCaretRect(CFX_RectF & rtCaret) const179 int32_t CFDE_TxtEdtEngine::GetCaretRect(CFX_RectF& rtCaret) const {
180   rtCaret = m_rtCaret;
181   return m_nCaret;
182 }
183 
GetCaretPos() const184 int32_t CFDE_TxtEdtEngine::GetCaretPos() const {
185   if (IsLocked()) {
186     return 0;
187   }
188   return m_nCaret + (m_bBefore ? 0 : 1);
189 }
190 
SetCaretPos(int32_t nIndex,bool bBefore)191 int32_t CFDE_TxtEdtEngine::SetCaretPos(int32_t nIndex, bool bBefore) {
192   if (IsLocked()) {
193     return 0;
194   }
195   ASSERT(nIndex >= 0 && nIndex <= GetTextBufLength());
196   if (m_PagePtrArray.GetSize() <= m_nCaretPage) {
197     return 0;
198   }
199   m_bBefore = bBefore;
200   m_nCaret = nIndex;
201   MovePage2Char(m_nCaret);
202   GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
203   if (!m_bBefore) {
204     m_nCaret++;
205     m_bBefore = true;
206   }
207   m_fCaretPosReserve = m_rtCaret.left;
208   m_Param.pEventSink->OnCaretChanged();
209   m_nAnchorPos = -1;
210   return m_nCaret;
211 }
212 
MoveCaretPos(FDE_TXTEDTMOVECARET eMoveCaret,bool bShift,bool bCtrl)213 int32_t CFDE_TxtEdtEngine::MoveCaretPos(FDE_TXTEDTMOVECARET eMoveCaret,
214                                         bool bShift,
215                                         bool bCtrl) {
216   if (IsLocked()) {
217     return 0;
218   }
219   if (m_PagePtrArray.GetSize() <= m_nCaretPage) {
220     return 0;
221   }
222   bool bSelChange = false;
223   if (IsSelect()) {
224     ClearSelection();
225     bSelChange = true;
226   }
227   if (bShift) {
228     if (m_nAnchorPos == -1) {
229       m_nAnchorPos = m_nCaret;
230     }
231   } else {
232     m_nAnchorPos = -1;
233   }
234 
235   switch (eMoveCaret) {
236     case MC_Left: {
237       bool bBefore = true;
238       int32_t nIndex = MoveBackward(bBefore);
239       if (nIndex >= 0) {
240         UpdateCaretRect(nIndex, bBefore);
241       }
242       break;
243     }
244     case MC_Right: {
245       bool bBefore = true;
246       int32_t nIndex = MoveForward(bBefore);
247       if (nIndex >= 0) {
248         UpdateCaretRect(nIndex, bBefore);
249       }
250       break;
251     }
252     case MC_Up: {
253       CFX_PointF ptCaret;
254       if (MoveUp(ptCaret)) {
255         UpdateCaretIndex(ptCaret);
256       }
257       break;
258     }
259     case MC_Down: {
260       CFX_PointF ptCaret;
261       if (MoveDown(ptCaret)) {
262         UpdateCaretIndex(ptCaret);
263       }
264       break;
265     }
266     case MC_WordBackward:
267       break;
268     case MC_WordForward:
269       break;
270     case MC_LineStart:
271       MoveLineStart();
272       break;
273     case MC_LineEnd:
274       MoveLineEnd();
275       break;
276     case MC_ParagStart:
277       MoveParagStart();
278       break;
279     case MC_ParagEnd:
280       MoveParagEnd();
281       break;
282     case MC_PageDown:
283       break;
284     case MC_PageUp:
285       break;
286     case MC_Home:
287       MoveHome();
288       break;
289     case MC_End:
290       MoveEnd();
291       break;
292     default:
293       break;
294   }
295   if (bShift && m_nAnchorPos != -1 && (m_nAnchorPos != m_nCaret)) {
296     AddSelRange(std::min(m_nAnchorPos, m_nCaret),
297                 FXSYS_abs(m_nAnchorPos - m_nCaret));
298     m_Param.pEventSink->OnSelChanged();
299   }
300   if (bSelChange)
301     m_Param.pEventSink->OnSelChanged();
302 
303   return m_nCaret;
304 }
305 
Lock()306 void CFDE_TxtEdtEngine::Lock() {
307   m_bLock = true;
308 }
309 
Unlock()310 void CFDE_TxtEdtEngine::Unlock() {
311   m_bLock = false;
312 }
313 
IsLocked() const314 bool CFDE_TxtEdtEngine::IsLocked() const {
315   return m_bLock;
316 }
317 
Insert(int32_t nStart,const FX_WCHAR * lpText,int32_t nLength)318 int32_t CFDE_TxtEdtEngine::Insert(int32_t nStart,
319                                   const FX_WCHAR* lpText,
320                                   int32_t nLength) {
321   if (IsLocked()) {
322     return FDE_TXTEDT_MODIFY_RET_F_Locked;
323   }
324   CFX_WideString wsTemp;
325   FX_WCHAR* lpBuffer = wsTemp.GetBuffer(nLength);
326   FXSYS_memcpy(lpBuffer, lpText, nLength * sizeof(FX_WCHAR));
327   ReplaceParagEnd(lpBuffer, nLength, false);
328   wsTemp.ReleaseBuffer(nLength);
329   bool bPart = false;
330   if (m_nLimit > 0) {
331     int32_t nTotalLength = GetTextBufLength();
332     int32_t nCount = m_SelRangePtrArr.GetSize();
333     for (int32_t i = 0; i < nCount; i++) {
334       FDE_TXTEDTSELRANGE* lpSelRange = m_SelRangePtrArr.GetAt(i);
335       nTotalLength -= lpSelRange->nCount;
336     }
337     int32_t nExpectLength = nTotalLength + nLength;
338     if (nTotalLength == m_nLimit) {
339       return FDE_TXTEDT_MODIFY_RET_F_Full;
340     }
341     if (nExpectLength > m_nLimit) {
342       nLength -= (nExpectLength - m_nLimit);
343       bPart = true;
344     }
345   }
346   if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) ||
347       (m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz)) {
348     int32_t nTemp = nLength;
349     if (m_Param.dwMode & FDE_TEXTEDITMODE_Password) {
350       while (nLength > 0) {
351         CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
352         int32_t nTotal = wsText.GetLength();
353         FX_WCHAR* lpBuf = wsText.GetBuffer(nTotal);
354         for (int32_t i = 0; i < nTotal; i++) {
355           lpBuf[i] = m_wcAliasChar;
356         }
357         wsText.ReleaseBuffer(nTotal);
358         if (IsFitArea(wsText)) {
359           break;
360         }
361         nLength--;
362       }
363     } else {
364       while (nLength > 0) {
365         CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
366         if (IsFitArea(wsText)) {
367           break;
368         }
369         nLength--;
370       }
371     }
372     if (nLength == 0) {
373       return FDE_TXTEDT_MODIFY_RET_F_Full;
374     }
375     if (nLength < nTemp) {
376       bPart = true;
377     }
378   }
379   if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
380     CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
381     if (!m_Param.pEventSink->OnValidate(wsText))
382       return FDE_TXTEDT_MODIFY_RET_F_Invalidate;
383   }
384   if (IsSelect()) {
385     DeleteSelect();
386   }
387   m_Param.pEventSink->OnAddDoRecord(
388       pdfium::MakeUnique<CFDE_TxtEdtDoRecord_Insert>(this, m_nCaret, lpBuffer,
389                                                      nLength));
390 
391   m_ChangeInfo.wsPrevText = GetText(0, -1);
392   Inner_Insert(m_nCaret, lpBuffer, nLength);
393   m_ChangeInfo.nChangeType = FDE_TXTEDT_TEXTCHANGE_TYPE_Insert;
394   m_ChangeInfo.wsInsert = CFX_WideString(lpBuffer, nLength);
395   nStart = m_nCaret;
396   nStart += nLength;
397   FX_WCHAR wChar = m_pTxtBuf->GetCharByIndex(nStart - 1);
398   bool bBefore = true;
399   if (wChar != L'\n' && wChar != L'\r') {
400     nStart--;
401     bBefore = false;
402   }
403   SetCaretPos(nStart, bBefore);
404   m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
405   return bPart ? FDE_TXTEDT_MODIFY_RET_S_Part : FDE_TXTEDT_MODIFY_RET_S_Normal;
406 }
407 
Delete(int32_t nStart,bool bBackspace)408 int32_t CFDE_TxtEdtEngine::Delete(int32_t nStart, bool bBackspace) {
409   if (IsLocked()) {
410     return FDE_TXTEDT_MODIFY_RET_F_Locked;
411   }
412   if (IsSelect()) {
413     DeleteSelect();
414     return FDE_TXTEDT_MODIFY_RET_S_Normal;
415   }
416 
417   int32_t nCount = 1;
418   if (bBackspace) {
419     if (nStart == 0) {
420       return FDE_TXTEDT_MODIFY_RET_F_Boundary;
421     }
422     if (nStart > 2 && m_pTxtBuf->GetCharByIndex(nStart - 1) == L'\n' &&
423         m_pTxtBuf->GetCharByIndex(nStart - 2) == L'\r') {
424       nStart--;
425       nCount++;
426     }
427     nStart--;
428   } else {
429     if (nStart == GetTextBufLength()) {
430       return FDE_TXTEDT_MODIFY_RET_F_Full;
431     }
432     if ((nStart + 1 < GetTextBufLength()) &&
433         (m_pTxtBuf->GetCharByIndex(nStart) == L'\r') &&
434         (m_pTxtBuf->GetCharByIndex(nStart + 1) == L'\n')) {
435       nCount++;
436     }
437   }
438   if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
439     CFX_WideString wsText = GetPreDeleteText(nStart, nCount);
440     if (!m_Param.pEventSink->OnValidate(wsText))
441       return FDE_TXTEDT_MODIFY_RET_F_Invalidate;
442   }
443   CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
444   m_Param.pEventSink->OnAddDoRecord(
445       pdfium::MakeUnique<CFDE_TxtEdtDoRecord_DeleteRange>(this, nStart,
446                                                           m_nCaret, wsRange));
447 
448   m_ChangeInfo.nChangeType = FDE_TXTEDT_TEXTCHANGE_TYPE_Delete;
449   m_ChangeInfo.wsDelete = GetText(nStart, nCount);
450   Inner_DeleteRange(nStart, nCount);
451   SetCaretPos(nStart + ((!bBackspace && nStart > 0) ? -1 : 0),
452               (bBackspace || nStart == 0));
453   m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
454   return FDE_TXTEDT_MODIFY_RET_S_Normal;
455 }
456 
DeleteRange(int32_t nStart,int32_t nCount)457 int32_t CFDE_TxtEdtEngine::DeleteRange(int32_t nStart, int32_t nCount) {
458   if (IsLocked())
459     return FDE_TXTEDT_MODIFY_RET_F_Locked;
460   if (nCount == -1)
461     nCount = GetTextBufLength();
462   if (nCount == 0)
463     return FDE_TXTEDT_MODIFY_RET_S_Normal;
464   if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
465     CFX_WideString wsText = GetPreDeleteText(nStart, nCount);
466     if (!m_Param.pEventSink->OnValidate(wsText))
467       return FDE_TXTEDT_MODIFY_RET_F_Invalidate;
468   }
469   DeleteRange_DoRecord(nStart, nCount);
470   m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
471   SetCaretPos(nStart, true);
472   return FDE_TXTEDT_MODIFY_RET_S_Normal;
473 }
474 
Replace(int32_t nStart,int32_t nLength,const CFX_WideString & wsReplace)475 int32_t CFDE_TxtEdtEngine::Replace(int32_t nStart,
476                                    int32_t nLength,
477                                    const CFX_WideString& wsReplace) {
478   if (IsLocked())
479     return FDE_TXTEDT_MODIFY_RET_F_Locked;
480   if (nStart < 0 || (nStart + nLength > GetTextBufLength()))
481     return FDE_TXTEDT_MODIFY_RET_F_Boundary;
482   if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
483     CFX_WideString wsText = GetPreReplaceText(
484         nStart, nLength, wsReplace.c_str(), wsReplace.GetLength());
485     if (!m_Param.pEventSink->OnValidate(wsText))
486       return FDE_TXTEDT_MODIFY_RET_F_Invalidate;
487   }
488   if (IsSelect())
489     ClearSelection();
490 
491   m_ChangeInfo.nChangeType = FDE_TXTEDT_TEXTCHANGE_TYPE_Replace;
492   m_ChangeInfo.wsDelete = GetText(nStart, nLength);
493   if (nLength > 0)
494     Inner_DeleteRange(nStart, nLength);
495 
496   int32_t nTextLength = wsReplace.GetLength();
497   if (nTextLength > 0)
498     Inner_Insert(nStart, wsReplace.c_str(), nTextLength);
499 
500   m_ChangeInfo.wsInsert = CFX_WideString(wsReplace.c_str(), nTextLength);
501   nStart += nTextLength;
502   FX_WCHAR wChar = m_pTxtBuf->GetCharByIndex(nStart - 1);
503   bool bBefore = true;
504   if (wChar != L'\n' && wChar != L'\r') {
505     nStart--;
506     bBefore = false;
507   }
508   SetCaretPos(nStart, bBefore);
509   m_Param.pEventSink->OnPageUnload(m_nCaretPage);
510   m_Param.pEventSink->OnPageLoad(m_nCaretPage);
511   m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
512   return FDE_TXTEDT_MODIFY_RET_S_Normal;
513 }
514 
SetLimit(int32_t nLimit)515 void CFDE_TxtEdtEngine::SetLimit(int32_t nLimit) {
516   m_nLimit = nLimit;
517 }
518 
SetAliasChar(FX_WCHAR wcAlias)519 void CFDE_TxtEdtEngine::SetAliasChar(FX_WCHAR wcAlias) {
520   m_wcAliasChar = wcAlias;
521 }
522 
RemoveSelRange(int32_t nStart,int32_t nCount)523 void CFDE_TxtEdtEngine::RemoveSelRange(int32_t nStart, int32_t nCount) {
524   FDE_TXTEDTSELRANGE* lpTemp = nullptr;
525   int32_t nRangeCount = m_SelRangePtrArr.GetSize();
526   int32_t i = 0;
527   for (i = 0; i < nRangeCount; i++) {
528     lpTemp = m_SelRangePtrArr[i];
529     if (lpTemp->nStart == nStart && lpTemp->nCount == nCount) {
530       delete lpTemp;
531       m_SelRangePtrArr.RemoveAt(i);
532       return;
533     }
534   }
535 }
536 
AddSelRange(int32_t nStart,int32_t nCount)537 void CFDE_TxtEdtEngine::AddSelRange(int32_t nStart, int32_t nCount) {
538   if (nCount == -1) {
539     nCount = GetTextLength() - nStart;
540   }
541   int32_t nSize = m_SelRangePtrArr.GetSize();
542   if (nSize <= 0) {
543     FDE_TXTEDTSELRANGE* lpSelRange = new FDE_TXTEDTSELRANGE;
544     lpSelRange->nStart = nStart;
545     lpSelRange->nCount = nCount;
546     m_SelRangePtrArr.Add(lpSelRange);
547     m_Param.pEventSink->OnSelChanged();
548     return;
549   }
550   FDE_TXTEDTSELRANGE* lpTemp = nullptr;
551   lpTemp = m_SelRangePtrArr[nSize - 1];
552   if (nStart >= lpTemp->nStart + lpTemp->nCount) {
553     FDE_TXTEDTSELRANGE* lpSelRange = new FDE_TXTEDTSELRANGE;
554     lpSelRange->nStart = nStart;
555     lpSelRange->nCount = nCount;
556     m_SelRangePtrArr.Add(lpSelRange);
557     m_Param.pEventSink->OnSelChanged();
558     return;
559   }
560   int32_t nEnd = nStart + nCount - 1;
561   bool bBegin = false;
562   int32_t nRangeBgn = 0;
563   int32_t nRangeCnt = 0;
564   for (int32_t i = 0; i < nSize; i++) {
565     lpTemp = m_SelRangePtrArr[i];
566     int32_t nTempBgn = lpTemp->nStart;
567     int32_t nTempEnd = nTempBgn + lpTemp->nCount - 1;
568     if (bBegin) {
569       if (nEnd < nTempBgn) {
570         break;
571       } else if (nStart >= nTempBgn && nStart <= nTempEnd) {
572         nRangeCnt++;
573         break;
574       }
575       nRangeCnt++;
576     } else {
577       if (nStart <= nTempEnd) {
578         nRangeBgn = i;
579         if (nEnd < nTempBgn) {
580           break;
581         }
582         nRangeCnt = 1;
583         bBegin = true;
584       }
585     }
586   }
587   if (nRangeCnt == 0) {
588     FDE_TXTEDTSELRANGE* lpSelRange = new FDE_TXTEDTSELRANGE;
589     lpSelRange->nStart = nStart;
590     lpSelRange->nCount = nCount;
591     m_SelRangePtrArr.InsertAt(nRangeBgn, lpSelRange);
592   } else {
593     lpTemp = m_SelRangePtrArr[nRangeBgn];
594     lpTemp->nStart = nStart;
595     lpTemp->nCount = nCount;
596     nRangeCnt--;
597     nRangeBgn++;
598     while (nRangeCnt--) {
599       delete m_SelRangePtrArr[nRangeBgn];
600       m_SelRangePtrArr.RemoveAt(nRangeBgn);
601     }
602   }
603   m_Param.pEventSink->OnSelChanged();
604 }
605 
CountSelRanges() const606 int32_t CFDE_TxtEdtEngine::CountSelRanges() const {
607   return m_SelRangePtrArr.GetSize();
608 }
609 
GetSelRange(int32_t nIndex,int32_t * nStart) const610 int32_t CFDE_TxtEdtEngine::GetSelRange(int32_t nIndex, int32_t* nStart) const {
611   if (nStart)
612     *nStart = m_SelRangePtrArr[nIndex]->nStart;
613   return m_SelRangePtrArr[nIndex]->nCount;
614 }
615 
ClearSelection()616 void CFDE_TxtEdtEngine::ClearSelection() {
617   int32_t nCount = m_SelRangePtrArr.GetSize();
618   for (int i = 0; i < nCount; ++i)
619     delete m_SelRangePtrArr[i];
620   m_SelRangePtrArr.RemoveAll();
621   if (nCount && m_Param.pEventSink)
622     m_Param.pEventSink->OnSelChanged();
623 }
624 
Redo(const IFDE_TxtEdtDoRecord * pDoRecord)625 bool CFDE_TxtEdtEngine::Redo(const IFDE_TxtEdtDoRecord* pDoRecord) {
626   if (IsLocked())
627     return false;
628   return pDoRecord->Redo();
629 }
630 
Undo(const IFDE_TxtEdtDoRecord * pDoRecord)631 bool CFDE_TxtEdtEngine::Undo(const IFDE_TxtEdtDoRecord* pDoRecord) {
632   if (IsLocked())
633     return false;
634   return pDoRecord->Undo();
635 }
636 
StartLayout()637 int32_t CFDE_TxtEdtEngine::StartLayout() {
638   Lock();
639   RemoveAllPages();
640   m_nLayoutPos = 0;
641   m_nLineCount = 0;
642   return 0;
643 }
644 
DoLayout(IFX_Pause * pPause)645 int32_t CFDE_TxtEdtEngine::DoLayout(IFX_Pause* pPause) {
646   int32_t nCount = m_ParagPtrArray.GetSize();
647   CFDE_TxtEdtParag* pParag = nullptr;
648   int32_t nLineCount = 0;
649   for (; m_nLayoutPos < nCount; m_nLayoutPos++) {
650     pParag = m_ParagPtrArray[m_nLayoutPos];
651     pParag->CalcLines();
652     nLineCount += pParag->GetLineCount();
653     if (nLineCount > m_nPageLineCount && pPause && pPause->NeedToPauseNow()) {
654       m_nLineCount += nLineCount;
655       return (++m_nLayoutPos * 100) / nCount;
656     }
657   }
658   m_nLineCount += nLineCount;
659   return 100;
660 }
661 
EndLayout()662 void CFDE_TxtEdtEngine::EndLayout() {
663   UpdatePages();
664   int32_t nLength = GetTextLength();
665   if (m_nCaret > nLength)
666     m_nCaret = nLength;
667 
668   int32_t nIndex = m_nCaret;
669   if (!m_bBefore)
670     nIndex--;
671 
672   m_rtCaret = CFX_RectF(0, 0, 1, m_Param.fFontSize);
673   Unlock();
674 }
675 
GetTextBuf() const676 CFDE_TxtEdtBuf* CFDE_TxtEdtEngine::GetTextBuf() const {
677   return m_pTxtBuf.get();
678 }
679 
GetTextBufLength() const680 int32_t CFDE_TxtEdtEngine::GetTextBufLength() const {
681   return m_pTxtBuf->GetTextLength() - 1;
682 }
683 
GetTextBreak() const684 CFX_TxtBreak* CFDE_TxtEdtEngine::GetTextBreak() const {
685   return m_pTextBreak.get();
686 }
687 
GetLineCount() const688 int32_t CFDE_TxtEdtEngine::GetLineCount() const {
689   return m_nLineCount;
690 }
691 
GetPageLineCount() const692 int32_t CFDE_TxtEdtEngine::GetPageLineCount() const {
693   return m_nPageLineCount;
694 }
695 
CountParags() const696 int32_t CFDE_TxtEdtEngine::CountParags() const {
697   return m_ParagPtrArray.GetSize();
698 }
699 
GetParag(int32_t nParagIndex) const700 CFDE_TxtEdtParag* CFDE_TxtEdtEngine::GetParag(int32_t nParagIndex) const {
701   return m_ParagPtrArray[nParagIndex];
702 }
703 
CreateCharIter()704 IFX_CharIter* CFDE_TxtEdtEngine::CreateCharIter() {
705   if (!m_pTxtBuf)
706     return nullptr;
707   return new CFDE_TxtEdtBuf::Iterator(m_pTxtBuf.get());
708 }
709 
Line2Parag(int32_t nStartParag,int32_t nStartLineofParag,int32_t nLineIndex,int32_t & nStartLine) const710 int32_t CFDE_TxtEdtEngine::Line2Parag(int32_t nStartParag,
711                                       int32_t nStartLineofParag,
712                                       int32_t nLineIndex,
713                                       int32_t& nStartLine) const {
714   int32_t nLineTotal = nStartLineofParag;
715   int32_t nCount = m_ParagPtrArray.GetSize();
716   CFDE_TxtEdtParag* pParag = nullptr;
717   int32_t i = nStartParag;
718   for (; i < nCount; i++) {
719     pParag = m_ParagPtrArray[i];
720     nLineTotal += pParag->GetLineCount();
721     if (nLineTotal > nLineIndex) {
722       break;
723     }
724   }
725   nStartLine = nLineTotal - pParag->GetLineCount();
726   return i;
727 }
728 
GetPreDeleteText(int32_t nIndex,int32_t nLength)729 CFX_WideString CFDE_TxtEdtEngine::GetPreDeleteText(int32_t nIndex,
730                                                    int32_t nLength) {
731   CFX_WideString wsText = GetText(0, GetTextBufLength());
732   wsText.Delete(nIndex, nLength);
733   return wsText;
734 }
735 
GetPreInsertText(int32_t nIndex,const FX_WCHAR * lpText,int32_t nLength)736 CFX_WideString CFDE_TxtEdtEngine::GetPreInsertText(int32_t nIndex,
737                                                    const FX_WCHAR* lpText,
738                                                    int32_t nLength) {
739   CFX_WideString wsText = GetText(0, GetTextBufLength());
740   int32_t nSelIndex = 0;
741   int32_t nSelLength = 0;
742   int32_t nSelCount = CountSelRanges();
743   while (nSelCount--) {
744     nSelLength = GetSelRange(nSelCount, &nSelIndex);
745     wsText.Delete(nSelIndex, nSelLength);
746     nIndex = nSelIndex;
747   }
748   CFX_WideString wsTemp;
749   int32_t nOldLength = wsText.GetLength();
750   const FX_WCHAR* pOldBuffer = wsText.c_str();
751   FX_WCHAR* lpBuffer = wsTemp.GetBuffer(nOldLength + nLength);
752   FXSYS_memcpy(lpBuffer, pOldBuffer, (nIndex) * sizeof(FX_WCHAR));
753   FXSYS_memcpy(lpBuffer + nIndex, lpText, nLength * sizeof(FX_WCHAR));
754   FXSYS_memcpy(lpBuffer + nIndex + nLength, pOldBuffer + nIndex,
755                (nOldLength - nIndex) * sizeof(FX_WCHAR));
756   wsTemp.ReleaseBuffer(nOldLength + nLength);
757   wsText = wsTemp;
758   return wsText;
759 }
760 
GetPreReplaceText(int32_t nIndex,int32_t nOriginLength,const FX_WCHAR * lpText,int32_t nLength)761 CFX_WideString CFDE_TxtEdtEngine::GetPreReplaceText(int32_t nIndex,
762                                                     int32_t nOriginLength,
763                                                     const FX_WCHAR* lpText,
764                                                     int32_t nLength) {
765   CFX_WideString wsText = GetText(0, GetTextBufLength());
766   int32_t nSelIndex = 0;
767   int32_t nSelLength = 0;
768   int32_t nSelCount = CountSelRanges();
769   while (nSelCount--) {
770     nSelLength = GetSelRange(nSelCount, &nSelIndex);
771     wsText.Delete(nSelIndex, nSelLength);
772   }
773   wsText.Delete(nIndex, nOriginLength);
774   int32_t i = 0;
775   for (i = 0; i < nLength; i++)
776     wsText.Insert(nIndex++, lpText[i]);
777 
778   return wsText;
779 }
780 
Inner_Insert(int32_t nStart,const FX_WCHAR * lpText,int32_t nLength)781 void CFDE_TxtEdtEngine::Inner_Insert(int32_t nStart,
782                                      const FX_WCHAR* lpText,
783                                      int32_t nLength) {
784   ASSERT(nLength > 0);
785   FDE_TXTEDTPARAGPOS ParagPos;
786   TextPos2ParagPos(nStart, ParagPos);
787   m_Param.pEventSink->OnPageUnload(m_nCaretPage);
788   int32_t nParagCount = m_ParagPtrArray.GetSize();
789   int32_t i = 0;
790   for (i = ParagPos.nParagIndex + 1; i < nParagCount; i++)
791     m_ParagPtrArray[i]->IncrementStartIndex(nLength);
792 
793   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex];
794   int32_t nReserveLineCount = pParag->GetLineCount();
795   int32_t nReserveCharStart = pParag->GetStartIndex();
796   int32_t nLeavePart = ParagPos.nCharIndex;
797   int32_t nCutPart = pParag->GetTextLength() - ParagPos.nCharIndex;
798   int32_t nTextStart = 0;
799   FX_WCHAR wCurChar = L' ';
800   const FX_WCHAR* lpPos = lpText;
801   bool bFirst = true;
802   int32_t nParagIndex = ParagPos.nParagIndex;
803   for (i = 0; i < nLength; i++, lpPos++) {
804     wCurChar = *lpPos;
805     if (wCurChar == m_wLineEnd) {
806       if (bFirst) {
807         pParag->SetTextLength(nLeavePart + (i - nTextStart + 1));
808         pParag->SetLineCount(-1);
809         nReserveCharStart += pParag->GetTextLength();
810         bFirst = false;
811       } else {
812         pParag = new CFDE_TxtEdtParag(this);
813         pParag->SetLineCount(-1);
814         pParag->SetTextLength(i - nTextStart + 1);
815         pParag->SetStartIndex(nReserveCharStart);
816         m_ParagPtrArray.InsertAt(++nParagIndex, pParag);
817         nReserveCharStart += pParag->GetTextLength();
818       }
819       nTextStart = i + 1;
820     }
821   }
822   if (bFirst) {
823     pParag->IncrementTextLength(nLength);
824     pParag->SetLineCount(-1);
825     bFirst = false;
826   } else {
827     pParag = new CFDE_TxtEdtParag(this);
828     pParag->SetLineCount(-1);
829     pParag->SetTextLength(nLength - nTextStart + nCutPart);
830     pParag->SetStartIndex(nReserveCharStart);
831     m_ParagPtrArray.InsertAt(++nParagIndex, pParag);
832   }
833   m_pTxtBuf->Insert(nStart, lpText, nLength);
834   int32_t nTotalLineCount = 0;
835   for (i = ParagPos.nParagIndex; i <= nParagIndex; i++) {
836     pParag = m_ParagPtrArray[i];
837     pParag->CalcLines();
838     nTotalLineCount += pParag->GetLineCount();
839   }
840   m_nLineCount += nTotalLineCount - nReserveLineCount;
841   m_Param.pEventSink->OnPageLoad(m_nCaretPage);
842   UpdatePages();
843 }
844 
Inner_DeleteRange(int32_t nStart,int32_t nCount)845 void CFDE_TxtEdtEngine::Inner_DeleteRange(int32_t nStart, int32_t nCount) {
846   if (nCount == -1) {
847     nCount = m_pTxtBuf->GetTextLength() - nStart;
848   }
849   int32_t nEnd = nStart + nCount - 1;
850   ASSERT(nStart >= 0 && nEnd < m_pTxtBuf->GetTextLength());
851   m_Param.pEventSink->OnPageUnload(m_nCaretPage);
852   FDE_TXTEDTPARAGPOS ParagPosBgn, ParagPosEnd;
853   TextPos2ParagPos(nStart, ParagPosBgn);
854   TextPos2ParagPos(nEnd, ParagPosEnd);
855   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPosEnd.nParagIndex];
856   bool bLastParag = false;
857   if (ParagPosEnd.nCharIndex == pParag->GetTextLength() - 1) {
858     if (ParagPosEnd.nParagIndex < m_ParagPtrArray.GetSize() - 1) {
859       ParagPosEnd.nParagIndex++;
860     } else {
861       bLastParag = true;
862     }
863   }
864   int32_t nTotalLineCount = 0;
865   int32_t nTotalCharCount = 0;
866   int32_t i = 0;
867   for (i = ParagPosBgn.nParagIndex; i <= ParagPosEnd.nParagIndex; i++) {
868     CFDE_TxtEdtParag* pTextParag = m_ParagPtrArray[i];
869     pTextParag->CalcLines();
870     nTotalLineCount += pTextParag->GetLineCount();
871     nTotalCharCount += pTextParag->GetTextLength();
872   }
873   m_pTxtBuf->Delete(nStart, nCount);
874   int32_t nNextParagIndex = (ParagPosBgn.nCharIndex == 0 && bLastParag)
875                                 ? ParagPosBgn.nParagIndex
876                                 : (ParagPosBgn.nParagIndex + 1);
877   for (i = nNextParagIndex; i <= ParagPosEnd.nParagIndex; i++) {
878     delete m_ParagPtrArray[nNextParagIndex];
879     m_ParagPtrArray.RemoveAt(nNextParagIndex);
880   }
881   if (!(bLastParag && ParagPosBgn.nCharIndex == 0)) {
882     pParag = m_ParagPtrArray[ParagPosBgn.nParagIndex];
883     pParag->SetTextLength(nTotalCharCount - nCount);
884     pParag->CalcLines();
885     nTotalLineCount -= pParag->GetTextLength();
886   }
887   int32_t nParagCount = m_ParagPtrArray.GetSize();
888   for (i = nNextParagIndex; i < nParagCount; i++)
889     m_ParagPtrArray[i]->DecrementStartIndex(nCount);
890 
891   m_nLineCount -= nTotalLineCount;
892   UpdatePages();
893   int32_t nPageCount = CountPages();
894   if (m_nCaretPage >= nPageCount) {
895     m_nCaretPage = nPageCount - 1;
896   }
897   m_Param.pEventSink->OnPageLoad(m_nCaretPage);
898 }
899 
DeleteRange_DoRecord(int32_t nStart,int32_t nCount,bool bSel)900 void CFDE_TxtEdtEngine::DeleteRange_DoRecord(int32_t nStart,
901                                              int32_t nCount,
902                                              bool bSel) {
903   ASSERT(nStart >= 0);
904   if (nCount == -1) {
905     nCount = GetTextLength() - nStart;
906   }
907   ASSERT((nStart + nCount) <= m_pTxtBuf->GetTextLength());
908 
909   CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
910   m_Param.pEventSink->OnAddDoRecord(
911       pdfium::MakeUnique<CFDE_TxtEdtDoRecord_DeleteRange>(
912           this, nStart, m_nCaret, wsRange, bSel));
913 
914   m_ChangeInfo.nChangeType = FDE_TXTEDT_TEXTCHANGE_TYPE_Delete;
915   m_ChangeInfo.wsDelete = GetText(nStart, nCount);
916   Inner_DeleteRange(nStart, nCount);
917 }
918 
ResetEngine()919 void CFDE_TxtEdtEngine::ResetEngine() {
920   RemoveAllPages();
921   RemoveAllParags();
922   ClearSelection();
923   m_nCaret = 0;
924   m_pTxtBuf->Clear(false);
925   m_nCaret = 0;
926 }
927 
RebuildParagraphs()928 void CFDE_TxtEdtEngine::RebuildParagraphs() {
929   RemoveAllParags();
930   FX_WCHAR wChar = L' ';
931   int32_t nParagStart = 0;
932   int32_t nIndex = 0;
933   std::unique_ptr<IFX_CharIter> pIter(
934       new CFDE_TxtEdtBuf::Iterator(m_pTxtBuf.get()));
935   pIter->SetAt(0);
936   do {
937     wChar = pIter->GetChar();
938     nIndex = pIter->GetAt();
939     if (wChar == m_wLineEnd) {
940       CFDE_TxtEdtParag* pParag = new CFDE_TxtEdtParag(this);
941       pParag->SetStartIndex(nParagStart);
942       pParag->SetTextLength(nIndex - nParagStart + 1);
943       pParag->SetLineCount(-1);
944       m_ParagPtrArray.Add(pParag);
945       nParagStart = nIndex + 1;
946     }
947   } while (pIter->Next());
948 }
949 
RemoveAllParags()950 void CFDE_TxtEdtEngine::RemoveAllParags() {
951   for (int32_t i = 0; i < m_ParagPtrArray.GetSize(); ++i)
952     delete m_ParagPtrArray[i];
953   m_ParagPtrArray.RemoveAll();
954 }
955 
RemoveAllPages()956 void CFDE_TxtEdtEngine::RemoveAllPages() {
957   for (int32_t i = 0; i < m_PagePtrArray.GetSize(); i++)
958     delete m_PagePtrArray[i];
959   m_PagePtrArray.RemoveAll();
960 }
961 
UpdateParags()962 void CFDE_TxtEdtEngine::UpdateParags() {
963   int32_t nCount = m_ParagPtrArray.GetSize();
964   if (nCount == 0) {
965     return;
966   }
967   CFDE_TxtEdtParag* pParag = nullptr;
968   int32_t nLineCount = 0;
969   int32_t i = 0;
970   for (i = 0; i < nCount; i++) {
971     pParag = m_ParagPtrArray[i];
972     if (pParag->GetLineCount() == -1)
973       pParag->CalcLines();
974 
975     nLineCount += pParag->GetLineCount();
976   }
977   m_nLineCount = nLineCount;
978 }
979 
UpdatePages()980 void CFDE_TxtEdtEngine::UpdatePages() {
981   if (m_nLineCount == 0)
982     return;
983 
984   int32_t nPageCount = (m_nLineCount - 1) / (m_nPageLineCount) + 1;
985   int32_t nSize = m_PagePtrArray.GetSize();
986   if (nSize == nPageCount)
987     return;
988 
989   if (nSize > nPageCount) {
990     for (int32_t i = nSize - 1; i >= nPageCount; i--) {
991       delete m_PagePtrArray[i];
992       m_PagePtrArray.RemoveAt(i);
993     }
994     return;
995   }
996   if (nSize < nPageCount) {
997     for (int32_t i = nSize; i < nPageCount; i++)
998       m_PagePtrArray.Add(IFDE_TxtEdtPage::Create(this, i));
999     return;
1000   }
1001 }
1002 
UpdateTxtBreak()1003 void CFDE_TxtEdtEngine::UpdateTxtBreak() {
1004   uint32_t dwStyle = m_pTextBreak->GetLayoutStyles();
1005   if (m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines) {
1006     dwStyle &= ~FX_TXTLAYOUTSTYLE_SingleLine;
1007   } else {
1008     dwStyle |= FX_TXTLAYOUTSTYLE_SingleLine;
1009   }
1010   dwStyle &= ~FX_TXTLAYOUTSTYLE_VerticalLayout;
1011   dwStyle &= ~FX_TXTLAYOUTSTYLE_ReverseLine;
1012   dwStyle &= ~FX_TXTLAYOUTSTYLE_RTLReadingOrder;
1013 
1014   if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) {
1015     dwStyle |= FX_TXTLAYOUTSTYLE_CombText;
1016   } else {
1017     dwStyle &= ~FX_TXTLAYOUTSTYLE_CombText;
1018   }
1019 
1020   dwStyle &= ~FX_TXTLAYOUTSTYLE_VerticalChars;
1021   dwStyle &= ~FX_TXTLAYOUTSTYLE_ExpandTab;
1022   dwStyle &= ~FX_TXTLAYOUTSTYLE_ArabicContext;
1023   dwStyle &= ~FX_TXTLAYOUTSTYLE_ArabicShapes;
1024 
1025   m_pTextBreak->SetLayoutStyles(dwStyle);
1026   uint32_t dwAligment = 0;
1027   if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Justified) {
1028     dwAligment |= FX_TXTLINEALIGNMENT_Justified;
1029   }
1030   if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Center) {
1031     dwAligment |= FX_TXTLINEALIGNMENT_Center;
1032   } else if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Right) {
1033     dwAligment |= FX_TXTLINEALIGNMENT_Right;
1034   }
1035   m_pTextBreak->SetAlignment(dwAligment);
1036 
1037   if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap) {
1038     m_pTextBreak->SetLineWidth(m_Param.fPlateWidth);
1039   } else {
1040     m_pTextBreak->SetLineWidth(kPageWidthMax);
1041   }
1042 
1043   m_nPageLineCount = m_Param.nLineCount;
1044   if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) {
1045     FX_FLOAT fCombWidth = m_Param.fPlateWidth;
1046     if (m_nLimit > 0) {
1047       fCombWidth /= m_nLimit;
1048     }
1049     m_pTextBreak->SetCombWidth(fCombWidth);
1050   }
1051   m_pTextBreak->SetFont(m_Param.pFont);
1052   m_pTextBreak->SetFontSize(m_Param.fFontSize);
1053   m_pTextBreak->SetTabWidth(m_Param.fTabWidth, m_Param.bTabEquidistant);
1054   m_pTextBreak->SetDefaultChar(m_Param.wDefChar);
1055   m_pTextBreak->SetParagraphBreakChar(m_Param.wLineBreakChar);
1056   m_pTextBreak->SetCharRotation(m_Param.nCharRotation);
1057   m_pTextBreak->SetLineBreakTolerance(m_Param.fFontSize * 0.2f);
1058   m_pTextBreak->SetHorizontalScale(m_Param.nHorzScale);
1059   m_pTextBreak->SetCharSpace(m_Param.fCharSpace);
1060 }
1061 
ReplaceParagEnd(FX_WCHAR * & lpText,int32_t & nLength,bool bPreIsCR)1062 bool CFDE_TxtEdtEngine::ReplaceParagEnd(FX_WCHAR*& lpText,
1063                                         int32_t& nLength,
1064                                         bool bPreIsCR) {
1065   for (int32_t i = 0; i < nLength; i++) {
1066     FX_WCHAR wc = lpText[i];
1067     switch (wc) {
1068       case L'\r': {
1069         lpText[i] = m_wLineEnd;
1070         bPreIsCR = true;
1071       } break;
1072       case L'\n': {
1073         if (bPreIsCR == true) {
1074           int32_t nNext = i + 1;
1075           if (nNext < nLength) {
1076             FXSYS_memmove(lpText + i, lpText + nNext,
1077                           (nLength - nNext) * sizeof(FX_WCHAR));
1078           }
1079           i--;
1080           nLength--;
1081           bPreIsCR = false;
1082           if (m_bAutoLineEnd) {
1083             m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_CRLF;
1084             m_bAutoLineEnd = false;
1085           }
1086         } else {
1087           lpText[i] = m_wLineEnd;
1088           if (m_bAutoLineEnd) {
1089             m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_LF;
1090             m_bAutoLineEnd = false;
1091           }
1092         }
1093       } break;
1094       default: {
1095         if (bPreIsCR && m_bAutoLineEnd) {
1096           m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_CR;
1097           m_bAutoLineEnd = false;
1098         }
1099         bPreIsCR = false;
1100       } break;
1101     }
1102   }
1103   return bPreIsCR;
1104 }
1105 
RecoverParagEnd(CFX_WideString & wsText) const1106 void CFDE_TxtEdtEngine::RecoverParagEnd(CFX_WideString& wsText) const {
1107   FX_WCHAR wc = (m_nFirstLineEnd == FDE_TXTEDIT_LINEEND_CR) ? L'\n' : L'\r';
1108   if (m_nFirstLineEnd == FDE_TXTEDIT_LINEEND_CRLF) {
1109     CFX_ArrayTemplate<int32_t> PosArr;
1110     int32_t nLength = wsText.GetLength();
1111     int32_t i = 0;
1112     FX_WCHAR* lpPos = const_cast<FX_WCHAR*>(wsText.c_str());
1113     for (i = 0; i < nLength; i++, lpPos++) {
1114       if (*lpPos == m_wLineEnd) {
1115         *lpPos = wc;
1116         PosArr.Add(i);
1117       }
1118     }
1119     const FX_WCHAR* lpSrcBuf = wsText.c_str();
1120     CFX_WideString wsTemp;
1121     int32_t nCount = PosArr.GetSize();
1122     FX_WCHAR* lpDstBuf = wsTemp.GetBuffer(nLength + nCount);
1123     int32_t nDstPos = 0;
1124     int32_t nSrcPos = 0;
1125     for (i = 0; i < nCount; i++) {
1126       int32_t nPos = PosArr[i];
1127       int32_t nCopyLen = nPos - nSrcPos + 1;
1128       FXSYS_memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
1129                    nCopyLen * sizeof(FX_WCHAR));
1130       nDstPos += nCopyLen;
1131       nSrcPos += nCopyLen;
1132       lpDstBuf[nDstPos] = L'\n';
1133       nDstPos++;
1134     }
1135     if (nSrcPos < nLength) {
1136       FXSYS_memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
1137                    (nLength - nSrcPos) * sizeof(FX_WCHAR));
1138     }
1139     wsTemp.ReleaseBuffer(nLength + nCount);
1140     wsText = wsTemp;
1141   } else {
1142     int32_t nLength = wsText.GetLength();
1143     FX_WCHAR* lpBuf = const_cast<FX_WCHAR*>(wsText.c_str());
1144     for (int32_t i = 0; i < nLength; i++, lpBuf++) {
1145       if (*lpBuf == m_wLineEnd)
1146         *lpBuf = wc;
1147     }
1148   }
1149 }
1150 
MovePage2Char(int32_t nIndex)1151 int32_t CFDE_TxtEdtEngine::MovePage2Char(int32_t nIndex) {
1152   ASSERT(nIndex >= 0);
1153   ASSERT(nIndex <= m_pTxtBuf->GetTextLength());
1154   if (m_nCaretPage >= 0) {
1155     IFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage];
1156     m_Param.pEventSink->OnPageLoad(m_nCaretPage);
1157     int32_t nPageCharStart = pPage->GetCharStart();
1158     int32_t nPageCharCount = pPage->GetCharCount();
1159     if (nIndex >= nPageCharStart && nIndex < nPageCharStart + nPageCharCount) {
1160       m_Param.pEventSink->OnPageUnload(m_nCaretPage);
1161       return m_nCaretPage;
1162     }
1163     m_Param.pEventSink->OnPageUnload(m_nCaretPage);
1164   }
1165   CFDE_TxtEdtParag* pParag = nullptr;
1166   int32_t nLineCount = 0;
1167   int32_t nParagCount = m_ParagPtrArray.GetSize();
1168   int32_t i = 0;
1169   for (i = 0; i < nParagCount; i++) {
1170     pParag = m_ParagPtrArray[i];
1171     if (pParag->GetStartIndex() <= nIndex &&
1172         nIndex < (pParag->GetStartIndex() + pParag->GetTextLength())) {
1173       break;
1174     }
1175     nLineCount += pParag->GetLineCount();
1176   }
1177   pParag->LoadParag();
1178   int32_t nLineStart = -1;
1179   int32_t nLineCharCount = -1;
1180   for (i = 0; i < pParag->GetLineCount(); i++) {
1181     pParag->GetLineRange(i, nLineStart, nLineCharCount);
1182     if (nLineStart <= nIndex && nIndex < (nLineStart + nLineCharCount))
1183       break;
1184   }
1185   ASSERT(i < pParag->GetLineCount());
1186   nLineCount += (i + 1);
1187   m_nCaretPage = (nLineCount - 1) / m_nPageLineCount + 1 - 1;
1188   pParag->UnloadParag();
1189   return m_nCaretPage;
1190 }
1191 
TextPos2ParagPos(int32_t nIndex,FDE_TXTEDTPARAGPOS & ParagPos) const1192 void CFDE_TxtEdtEngine::TextPos2ParagPos(int32_t nIndex,
1193                                          FDE_TXTEDTPARAGPOS& ParagPos) const {
1194   ASSERT(nIndex >= 0 && nIndex < m_pTxtBuf->GetTextLength());
1195   int32_t nCount = m_ParagPtrArray.GetSize();
1196   int32_t nBgn = 0;
1197   int32_t nMid = 0;
1198   int32_t nEnd = nCount - 1;
1199   while (nEnd > nBgn) {
1200     nMid = (nBgn + nEnd) / 2;
1201     CFDE_TxtEdtParag* pParag = m_ParagPtrArray[nMid];
1202     if (nIndex < pParag->GetStartIndex())
1203       nEnd = nMid - 1;
1204     else if (nIndex >= (pParag->GetStartIndex() + pParag->GetTextLength()))
1205       nBgn = nMid + 1;
1206     else
1207       break;
1208   }
1209   if (nBgn == nEnd)
1210     nMid = nBgn;
1211 
1212   ASSERT(nIndex >= m_ParagPtrArray[nMid]->GetStartIndex() &&
1213          (nIndex < m_ParagPtrArray[nMid]->GetStartIndex() +
1214                        m_ParagPtrArray[nMid]->GetTextLength()));
1215   ParagPos.nParagIndex = nMid;
1216   ParagPos.nCharIndex = nIndex - m_ParagPtrArray[nMid]->GetStartIndex();
1217 }
1218 
MoveForward(bool & bBefore)1219 int32_t CFDE_TxtEdtEngine::MoveForward(bool& bBefore) {
1220   if (m_nCaret == m_pTxtBuf->GetTextLength() - 1)
1221     return -1;
1222 
1223   int32_t nCaret = m_nCaret;
1224   if ((nCaret + 1 < m_pTxtBuf->GetTextLength()) &&
1225       (m_pTxtBuf->GetCharByIndex(nCaret) == L'\r') &&
1226       (m_pTxtBuf->GetCharByIndex(nCaret + 1) == L'\n')) {
1227     nCaret++;
1228   }
1229   nCaret++;
1230   bBefore = true;
1231   return nCaret;
1232 }
1233 
MoveBackward(bool & bBefore)1234 int32_t CFDE_TxtEdtEngine::MoveBackward(bool& bBefore) {
1235   if (m_nCaret == 0)
1236     return false;
1237 
1238   int32_t nCaret = m_nCaret;
1239   if (nCaret > 2 && m_pTxtBuf->GetCharByIndex(nCaret - 1) == L'\n' &&
1240       m_pTxtBuf->GetCharByIndex(nCaret - 2) == L'\r') {
1241     nCaret--;
1242   }
1243   nCaret--;
1244   bBefore = true;
1245   return nCaret;
1246 }
1247 
MoveUp(CFX_PointF & ptCaret)1248 bool CFDE_TxtEdtEngine::MoveUp(CFX_PointF& ptCaret) {
1249   IFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
1250   const CFX_RectF& rtContent = pPage->GetContentsBox();
1251   ptCaret.x = m_fCaretPosReserve;
1252   ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 - m_Param.fLineSpace;
1253   if (ptCaret.y < rtContent.top) {
1254     if (m_nCaretPage == 0) {
1255       return false;
1256     }
1257     ptCaret.y -= rtContent.top;
1258     m_nCaretPage--;
1259     IFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
1260     ptCaret.y += pCurPage->GetContentsBox().bottom();
1261   }
1262 
1263   return true;
1264 }
1265 
MoveDown(CFX_PointF & ptCaret)1266 bool CFDE_TxtEdtEngine::MoveDown(CFX_PointF& ptCaret) {
1267   IFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
1268   const CFX_RectF& rtContent = pPage->GetContentsBox();
1269   ptCaret.x = m_fCaretPosReserve;
1270   ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 + m_Param.fLineSpace;
1271   if (ptCaret.y >= rtContent.bottom()) {
1272     if (m_nCaretPage == CountPages() - 1) {
1273       return false;
1274     }
1275     ptCaret.y -= rtContent.bottom();
1276     m_nCaretPage++;
1277     IFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
1278     ptCaret.y += pCurPage->GetContentsBox().top;
1279   }
1280   return true;
1281 }
1282 
MoveLineStart()1283 bool CFDE_TxtEdtEngine::MoveLineStart() {
1284   int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
1285   FDE_TXTEDTPARAGPOS ParagPos;
1286   TextPos2ParagPos(nIndex, ParagPos);
1287   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex];
1288   pParag->LoadParag();
1289   int32_t nLineCount = pParag->GetLineCount();
1290   int32_t i = 0;
1291   int32_t nStart = 0;
1292   int32_t nCount = 0;
1293   for (; i < nLineCount; i++) {
1294     pParag->GetLineRange(i, nStart, nCount);
1295     if (nIndex >= nStart && nIndex < nStart + nCount) {
1296       break;
1297     }
1298   }
1299   UpdateCaretRect(nStart, true);
1300   pParag->UnloadParag();
1301   return true;
1302 }
1303 
MoveLineEnd()1304 bool CFDE_TxtEdtEngine::MoveLineEnd() {
1305   int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
1306   FDE_TXTEDTPARAGPOS ParagPos;
1307   TextPos2ParagPos(nIndex, ParagPos);
1308   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex];
1309   pParag->LoadParag();
1310   int32_t nLineCount = pParag->GetLineCount();
1311   int32_t i = 0;
1312   int32_t nStart = 0;
1313   int32_t nCount = 0;
1314   for (; i < nLineCount; i++) {
1315     pParag->GetLineRange(i, nStart, nCount);
1316     if (nIndex >= nStart && nIndex < nStart + nCount) {
1317       break;
1318     }
1319   }
1320   nIndex = nStart + nCount - 1;
1321   ASSERT(nIndex <= GetTextBufLength());
1322   FX_WCHAR wChar = m_pTxtBuf->GetCharByIndex(nIndex);
1323   bool bBefore = false;
1324   if (nIndex <= GetTextBufLength()) {
1325     if (wChar == L'\r') {
1326       bBefore = true;
1327     } else if (wChar == L'\n' && nIndex > nStart) {
1328       bBefore = true;
1329       nIndex--;
1330       wChar = m_pTxtBuf->GetCharByIndex(nIndex);
1331       if (wChar != L'\r') {
1332         nIndex++;
1333       }
1334     }
1335   }
1336   UpdateCaretRect(nIndex, bBefore);
1337   pParag->UnloadParag();
1338   return true;
1339 }
1340 
MoveParagStart()1341 bool CFDE_TxtEdtEngine::MoveParagStart() {
1342   int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
1343   FDE_TXTEDTPARAGPOS ParagPos;
1344   TextPos2ParagPos(nIndex, ParagPos);
1345   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex];
1346   UpdateCaretRect(pParag->GetStartIndex(), true);
1347   return true;
1348 }
1349 
MoveParagEnd()1350 bool CFDE_TxtEdtEngine::MoveParagEnd() {
1351   int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
1352   FDE_TXTEDTPARAGPOS ParagPos;
1353   TextPos2ParagPos(nIndex, ParagPos);
1354   CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex];
1355   nIndex = pParag->GetStartIndex() + pParag->GetTextLength() - 1;
1356   FX_WCHAR wChar = m_pTxtBuf->GetCharByIndex(nIndex);
1357   if (wChar == L'\n' && nIndex > 0) {
1358     nIndex--;
1359     wChar = m_pTxtBuf->GetCharByIndex(nIndex);
1360     if (wChar != L'\r') {
1361       nIndex++;
1362     }
1363   }
1364   UpdateCaretRect(nIndex, true);
1365   return true;
1366 }
1367 
MoveHome()1368 bool CFDE_TxtEdtEngine::MoveHome() {
1369   UpdateCaretRect(0, true);
1370   return true;
1371 }
1372 
MoveEnd()1373 bool CFDE_TxtEdtEngine::MoveEnd() {
1374   UpdateCaretRect(GetTextBufLength(), true);
1375   return true;
1376 }
1377 
IsFitArea(CFX_WideString & wsText)1378 bool CFDE_TxtEdtEngine::IsFitArea(CFX_WideString& wsText) {
1379   std::unique_ptr<CFDE_TextOut> pTextOut(new CFDE_TextOut);
1380   pTextOut->SetLineSpace(m_Param.fLineSpace);
1381   pTextOut->SetFont(m_Param.pFont);
1382   pTextOut->SetFontSize(m_Param.fFontSize);
1383   uint32_t dwStyle = 0;
1384   if (!(m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines))
1385     dwStyle |= FDE_TTOSTYLE_SingleLine;
1386 
1387   CFX_RectF rcText;
1388   if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap) {
1389     dwStyle |= FDE_TTOSTYLE_LineWrap;
1390     rcText.width = m_Param.fPlateWidth;
1391   } else {
1392     rcText.width = 65535;
1393   }
1394   pTextOut->SetStyles(dwStyle);
1395   wsText += L"\n";
1396   pTextOut->CalcLogicSize(wsText.c_str(), wsText.GetLength(), rcText);
1397   wsText.Delete(wsText.GetLength() - 1);
1398   if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz) &&
1399       (rcText.width > m_Param.fPlateWidth)) {
1400     return false;
1401   }
1402   if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) &&
1403       (rcText.height > m_Param.fLineSpace * m_Param.nLineCount)) {
1404     return false;
1405   }
1406   return true;
1407 }
1408 
UpdateCaretRect(int32_t nIndex,bool bBefore)1409 void CFDE_TxtEdtEngine::UpdateCaretRect(int32_t nIndex, bool bBefore) {
1410   MovePage2Char(nIndex);
1411   GetCaretRect(m_rtCaret, m_nCaretPage, nIndex, bBefore);
1412   m_nCaret = nIndex;
1413   m_bBefore = bBefore;
1414   if (!m_bBefore) {
1415     m_nCaret++;
1416     m_bBefore = true;
1417   }
1418   m_fCaretPosReserve = m_rtCaret.left;
1419   m_Param.pEventSink->OnCaretChanged();
1420 }
1421 
GetCaretRect(CFX_RectF & rtCaret,int32_t nPageIndex,int32_t nCaret,bool bBefore)1422 void CFDE_TxtEdtEngine::GetCaretRect(CFX_RectF& rtCaret,
1423                                      int32_t nPageIndex,
1424                                      int32_t nCaret,
1425                                      bool bBefore) {
1426   IFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage];
1427   m_Param.pEventSink->OnPageLoad(m_nCaretPage);
1428   bool bCombText = !!(m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText);
1429   int32_t nIndexInpage = nCaret - pPage->GetCharStart();
1430   if (bBefore && bCombText && nIndexInpage > 0) {
1431     nIndexInpage--;
1432     bBefore = false;
1433   }
1434   int32_t nBIDILevel = pPage->GetCharRect(nIndexInpage, rtCaret, bCombText);
1435   if ((!FX_IsOdd(nBIDILevel) && !bBefore) ||
1436       (FX_IsOdd(nBIDILevel) && bBefore)) {
1437     rtCaret.Offset(rtCaret.width - 1.0f, 0);
1438   }
1439   if (rtCaret.width == 0 && rtCaret.left > 1.0f)
1440     rtCaret.left -= 1.0f;
1441 
1442   rtCaret.width = 1.0f;
1443 
1444   m_Param.pEventSink->OnPageUnload(m_nCaretPage);
1445 }
1446 
UpdateCaretIndex(const CFX_PointF & ptCaret)1447 void CFDE_TxtEdtEngine::UpdateCaretIndex(const CFX_PointF& ptCaret) {
1448   IFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage];
1449   m_Param.pEventSink->OnPageLoad(m_nCaretPage);
1450   m_nCaret = pPage->GetCharIndex(ptCaret, m_bBefore);
1451   GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
1452   if (!m_bBefore) {
1453     m_nCaret++;
1454     m_bBefore = true;
1455   }
1456   m_Param.pEventSink->OnCaretChanged();
1457   m_Param.pEventSink->OnPageUnload(m_nCaretPage);
1458 }
1459 
IsSelect()1460 bool CFDE_TxtEdtEngine::IsSelect() {
1461   return m_SelRangePtrArr.GetSize() > 0;
1462 }
1463 
DeleteSelect()1464 void CFDE_TxtEdtEngine::DeleteSelect() {
1465   int32_t nCountRange = CountSelRanges();
1466   if (nCountRange > 0) {
1467     int32_t nSelStart = 0;
1468     while (nCountRange > 0) {
1469       int32_t nSelCount = GetSelRange(--nCountRange, &nSelStart);
1470       delete m_SelRangePtrArr[nCountRange];
1471       m_SelRangePtrArr.RemoveAt(nCountRange);
1472       DeleteRange_DoRecord(nSelStart, nSelCount, true);
1473     }
1474     ClearSelection();
1475     m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
1476     m_Param.pEventSink->OnSelChanged();
1477     SetCaretPos(nSelStart, true);
1478     return;
1479   }
1480 }
1481