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