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 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 49 FDE_TXTEDTPARAMS::~FDE_TXTEDTPARAMS() {} 50 51 FDE_TXTEDT_TEXTCHANGE_INFO::FDE_TXTEDT_TEXTCHANGE_INFO() {} 52 53 FDE_TXTEDT_TEXTCHANGE_INFO::~FDE_TXTEDT_TEXTCHANGE_INFO() {} 54 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 75 CFDE_TxtEdtEngine::~CFDE_TxtEdtEngine() { 76 RemoveAllParags(); 77 RemoveAllPages(); 78 m_Param.pEventSink = nullptr; 79 ClearSelection(); 80 } 81 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 92 FDE_TXTEDTPARAMS* CFDE_TxtEdtEngine::GetEditParams() { 93 return &m_Param; 94 } 95 96 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 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 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 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 160 int32_t CFDE_TxtEdtEngine::GetTextLength() const { 161 return GetTextBufLength(); 162 } 163 164 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 175 void CFDE_TxtEdtEngine::ClearText() { 176 DeleteRange(0, -1); 177 } 178 179 int32_t CFDE_TxtEdtEngine::GetCaretRect(CFX_RectF& rtCaret) const { 180 rtCaret = m_rtCaret; 181 return m_nCaret; 182 } 183 184 int32_t CFDE_TxtEdtEngine::GetCaretPos() const { 185 if (IsLocked()) { 186 return 0; 187 } 188 return m_nCaret + (m_bBefore ? 0 : 1); 189 } 190 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 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 306 void CFDE_TxtEdtEngine::Lock() { 307 m_bLock = true; 308 } 309 310 void CFDE_TxtEdtEngine::Unlock() { 311 m_bLock = false; 312 } 313 314 bool CFDE_TxtEdtEngine::IsLocked() const { 315 return m_bLock; 316 } 317 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 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 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 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 515 void CFDE_TxtEdtEngine::SetLimit(int32_t nLimit) { 516 m_nLimit = nLimit; 517 } 518 519 void CFDE_TxtEdtEngine::SetAliasChar(FX_WCHAR wcAlias) { 520 m_wcAliasChar = wcAlias; 521 } 522 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 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 606 int32_t CFDE_TxtEdtEngine::CountSelRanges() const { 607 return m_SelRangePtrArr.GetSize(); 608 } 609 610 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 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 625 bool CFDE_TxtEdtEngine::Redo(const IFDE_TxtEdtDoRecord* pDoRecord) { 626 if (IsLocked()) 627 return false; 628 return pDoRecord->Redo(); 629 } 630 631 bool CFDE_TxtEdtEngine::Undo(const IFDE_TxtEdtDoRecord* pDoRecord) { 632 if (IsLocked()) 633 return false; 634 return pDoRecord->Undo(); 635 } 636 637 int32_t CFDE_TxtEdtEngine::StartLayout() { 638 Lock(); 639 RemoveAllPages(); 640 m_nLayoutPos = 0; 641 m_nLineCount = 0; 642 return 0; 643 } 644 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 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 676 CFDE_TxtEdtBuf* CFDE_TxtEdtEngine::GetTextBuf() const { 677 return m_pTxtBuf.get(); 678 } 679 680 int32_t CFDE_TxtEdtEngine::GetTextBufLength() const { 681 return m_pTxtBuf->GetTextLength() - 1; 682 } 683 684 CFX_TxtBreak* CFDE_TxtEdtEngine::GetTextBreak() const { 685 return m_pTextBreak.get(); 686 } 687 688 int32_t CFDE_TxtEdtEngine::GetLineCount() const { 689 return m_nLineCount; 690 } 691 692 int32_t CFDE_TxtEdtEngine::GetPageLineCount() const { 693 return m_nPageLineCount; 694 } 695 696 int32_t CFDE_TxtEdtEngine::CountParags() const { 697 return m_ParagPtrArray.GetSize(); 698 } 699 700 CFDE_TxtEdtParag* CFDE_TxtEdtEngine::GetParag(int32_t nParagIndex) const { 701 return m_ParagPtrArray[nParagIndex]; 702 } 703 704 IFX_CharIter* CFDE_TxtEdtEngine::CreateCharIter() { 705 if (!m_pTxtBuf) 706 return nullptr; 707 return new CFDE_TxtEdtBuf::Iterator(m_pTxtBuf.get()); 708 } 709 710 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1106 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 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 1192 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 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 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 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 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 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 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 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 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 1368 bool CFDE_TxtEdtEngine::MoveHome() { 1369 UpdateCaretRect(0, true); 1370 return true; 1371 } 1372 1373 bool CFDE_TxtEdtEngine::MoveEnd() { 1374 UpdateCaretRect(GetTextBufLength(), true); 1375 return true; 1376 } 1377 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 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 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 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 1460 bool CFDE_TxtEdtEngine::IsSelect() { 1461 return m_SelRangePtrArr.GetSize() > 0; 1462 } 1463 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