blob: 31cbfc0773fa2f7a3757cf18d5ef9915eb6e92c1 [file] [log] [blame]
// Copyright 2014 PDFium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
#include "xfa/fde/cfde_txtedtengine.h"
#include <algorithm>
#include <utility>
#include "core/fxcrt/ifx_chariter.h"
#include "third_party/base/ptr_util.h"
#include "xfa/fde/cfde_textout.h"
#include "xfa/fde/cfde_txtedtbuf.h"
#include "xfa/fde/cfde_txtedtpage.h"
#include "xfa/fde/cfde_txtedtparag.h"
#include "xfa/fgas/layout/cfx_txtbreak.h"
#include "xfa/fwl/cfwl_edit.h"
namespace {
const uint32_t kPageWidthMax = 0xffff;
const uint32_t kUnicodeParagraphSeparator = 0x2029;
enum FDE_TXTEDT_MODIFY_RET {
FDE_TXTEDT_MODIFY_RET_F_Locked = -5,
FDE_TXTEDT_MODIFY_RET_F_Invalidate = -4,
FDE_TXTEDT_MODIFY_RET_F_Full = -2,
FDE_TXTEDT_MODIFY_RET_S_Normal = 0,
};
enum FDE_TXTEDIT_LINEEND {
FDE_TXTEDIT_LINEEND_Auto,
FDE_TXTEDIT_LINEEND_CRLF,
FDE_TXTEDIT_LINEEND_CR,
FDE_TXTEDIT_LINEEND_LF,
};
class InsertOperation : public IFDE_TxtEdtDoRecord {
public:
InsertOperation(CFDE_TxtEdtEngine* pEngine,
int32_t nCaret,
const CFX_WideString& str)
: m_pEngine(pEngine), m_nCaret(nCaret), m_wsInsert(str) {
ASSERT(m_pEngine);
}
~InsertOperation() override {}
void Undo() const override {
if (m_pEngine->IsSelect())
m_pEngine->ClearSelection();
m_pEngine->Inner_DeleteRange(m_nCaret, m_wsInsert.GetLength());
m_pEngine->UpdateChangeInfoDelete(FDE_TXTEDT_TEXTCHANGE_TYPE_Delete,
m_wsInsert);
m_pEngine->GetParams()->pEventSink->OnTextChanged(
*m_pEngine->GetChangeInfo());
m_pEngine->SetCaretPos(m_nCaret, true);
}
void Redo() const override {
m_pEngine->Inner_Insert(m_nCaret, m_wsInsert.c_str(),
m_wsInsert.GetLength());
m_pEngine->UpdateChangeInfoInsert(FDE_TXTEDT_TEXTCHANGE_TYPE_Insert,
m_wsInsert);
m_pEngine->GetParams()->pEventSink->OnTextChanged(
*m_pEngine->GetChangeInfo());
m_pEngine->SetCaretPos(m_nCaret, false);
}
private:
CFDE_TxtEdtEngine* m_pEngine;
int32_t m_nCaret;
CFX_WideString m_wsInsert;
};
class DeleteOperation : public IFDE_TxtEdtDoRecord {
public:
DeleteOperation(CFDE_TxtEdtEngine* pEngine,
int32_t nIndex,
int32_t nCaret,
const CFX_WideString& wsRange,
bool bSel)
: m_pEngine(pEngine),
m_bSel(bSel),
m_nIndex(nIndex),
m_nCaret(nCaret),
m_wsRange(wsRange) {
ASSERT(m_pEngine);
}
~DeleteOperation() override {}
void Undo() const override {
if (m_pEngine->IsSelect())
m_pEngine->ClearSelection();
m_pEngine->Inner_Insert(m_nIndex, m_wsRange.c_str(), m_wsRange.GetLength());
if (m_bSel)
m_pEngine->AddSelRange(m_nIndex, m_wsRange.GetLength());
m_pEngine->UpdateChangeInfoInsert(FDE_TXTEDT_TEXTCHANGE_TYPE_Insert,
m_wsRange);
m_pEngine->GetParams()->pEventSink->OnTextChanged(
*m_pEngine->GetChangeInfo());
m_pEngine->SetCaretPos(m_nCaret, true);
}
void Redo() const override {
m_pEngine->Inner_DeleteRange(m_nIndex, m_wsRange.GetLength());
if (m_bSel)
m_pEngine->RemoveSelRange(m_nIndex, m_wsRange.GetLength());
m_pEngine->UpdateChangeInfoDelete(FDE_TXTEDT_TEXTCHANGE_TYPE_Delete,
m_wsRange);
m_pEngine->GetParams()->pEventSink->OnTextChanged(
*m_pEngine->GetChangeInfo());
m_pEngine->SetCaretPos(m_nIndex, true);
}
private:
CFDE_TxtEdtEngine* m_pEngine;
bool m_bSel;
int32_t m_nIndex;
int32_t m_nCaret;
CFX_WideString m_wsRange;
};
} // namespace
FDE_TXTEDTPARAMS::FDE_TXTEDTPARAMS()
: fPlateWidth(0),
fPlateHeight(0),
nLineCount(0),
dwLayoutStyles(0),
dwAlignment(0),
dwMode(0),
fFontSize(10.0f),
dwFontColor(0xff000000),
fLineSpace(10.0f),
fTabWidth(36),
wDefChar(0xFEFF),
wLineBreakChar('\n'),
nLineEnd(0),
nHorzScale(100),
fCharSpace(0),
pEventSink(nullptr) {}
FDE_TXTEDTPARAMS::~FDE_TXTEDTPARAMS() {}
FDE_TXTEDT_TEXTCHANGE_INFO::FDE_TXTEDT_TEXTCHANGE_INFO() {}
FDE_TXTEDT_TEXTCHANGE_INFO::~FDE_TXTEDT_TEXTCHANGE_INFO() {}
CFDE_TxtEdtEngine::CFDE_TxtEdtEngine()
: m_pTxtBuf(pdfium::MakeUnique<CFDE_TxtEdtBuf>()),
m_nPageLineCount(20),
m_nLineCount(0),
m_nAnchorPos(-1),
m_fCaretPosReserve(0.0),
m_nCaret(0),
m_bBefore(true),
m_nCaretPage(0),
m_bLock(false),
m_nLimit(0),
m_wcAliasChar(L'*'),
m_nFirstLineEnd(FDE_TXTEDIT_LINEEND_Auto),
m_bAutoLineEnd(true),
m_wLineEnd(kUnicodeParagraphSeparator) {
m_bAutoLineEnd = (m_Param.nLineEnd == FDE_TXTEDIT_LINEEND_Auto);
}
CFDE_TxtEdtEngine::~CFDE_TxtEdtEngine() {
RemoveAllParags();
RemoveAllPages();
m_Param.pEventSink = nullptr;
ClearSelection();
}
void CFDE_TxtEdtEngine::SetEditParams(const FDE_TXTEDTPARAMS& params) {
if (!m_pTextBreak)
m_pTextBreak = pdfium::MakeUnique<CFX_TxtBreak>();
m_Param = params;
m_wLineEnd = params.wLineBreakChar;
m_bAutoLineEnd = m_Param.nLineEnd == FDE_TXTEDIT_LINEEND_Auto;
UpdateTxtBreak();
}
CFDE_TxtEdtPage* CFDE_TxtEdtEngine::GetPage(int32_t nIndex) {
if (!pdfium::IndexInBounds(m_PagePtrArray, nIndex))
return nullptr;
return m_PagePtrArray[nIndex].get();
}
void CFDE_TxtEdtEngine::SetText(const CFX_WideString& wsText) {
ResetEngine();
int32_t nLength = wsText.GetLength();
if (nLength > 0) {
CFX_WideString wsTemp;
wchar_t* lpBuffer = wsTemp.GetBuffer(nLength);
memcpy(lpBuffer, wsText.c_str(), nLength * sizeof(wchar_t));
ReplaceParagEnd(lpBuffer, nLength, false);
wsTemp.ReleaseBuffer(nLength);
if (m_nLimit > 0 && nLength > m_nLimit) {
wsTemp.Delete(m_nLimit, nLength - m_nLimit);
nLength = m_nLimit;
}
m_pTxtBuf->SetText(wsTemp);
}
m_pTxtBuf->Insert(nLength, &m_wLineEnd, 1);
RebuildParagraphs();
}
CFX_WideString CFDE_TxtEdtEngine::GetText(int32_t nStart,
int32_t nCount) const {
int32_t nTextBufLength = GetTextLength();
if (nCount == -1)
nCount = nTextBufLength - nStart;
CFX_WideString wsText = m_pTxtBuf->GetRange(nStart, nCount);
RecoverParagEnd(wsText);
return wsText;
}
void CFDE_TxtEdtEngine::ClearText() {
if (IsLocked())
return;
int32_t len = GetTextLength();
if (len == 0)
return;
if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
CFX_WideString wsText = GetPreDeleteText(0, len);
if (!m_Param.pEventSink->OnValidate(wsText))
return;
}
DeleteRange_DoRecord(0, len, false);
m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
SetCaretPos(0, true);
}
int32_t CFDE_TxtEdtEngine::SetCaretPos(int32_t nIndex, bool bBefore) {
if (IsLocked())
return 0;
ASSERT(nIndex >= 0 && nIndex <= GetTextLength());
if (!pdfium::IndexInBounds(m_PagePtrArray, m_nCaretPage))
return 0;
m_bBefore = bBefore;
m_nCaret = nIndex;
MovePage2Char(m_nCaret);
GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
if (!m_bBefore) {
m_nCaret++;
m_bBefore = true;
}
m_fCaretPosReserve = m_rtCaret.left;
m_Param.pEventSink->OnCaretChanged();
m_nAnchorPos = -1;
return m_nCaret;
}
int32_t CFDE_TxtEdtEngine::MoveCaretPos(FDE_CaretMove eMoveCaret, bool bShift) {
if (IsLocked() || !pdfium::IndexInBounds(m_PagePtrArray, m_nCaretPage))
return 0;
bool bSelChange = false;
if (IsSelect()) {
ClearSelection();
bSelChange = true;
}
if (bShift) {
if (m_nAnchorPos == -1)
m_nAnchorPos = m_nCaret;
} else {
m_nAnchorPos = -1;
}
switch (eMoveCaret) {
case FDE_CaretMove::Left: {
bool bBefore = true;
int32_t nIndex = MoveBackward(bBefore);
if (nIndex >= 0)
UpdateCaretRect(nIndex, bBefore);
break;
}
case FDE_CaretMove::Right: {
bool bBefore = true;
int32_t nIndex = MoveForward(bBefore);
if (nIndex >= 0)
UpdateCaretRect(nIndex, bBefore);
break;
}
case FDE_CaretMove::Up: {
CFX_PointF ptCaret;
if (MoveUp(ptCaret))
UpdateCaretIndex(ptCaret);
break;
}
case FDE_CaretMove::Down: {
CFX_PointF ptCaret;
if (MoveDown(ptCaret))
UpdateCaretIndex(ptCaret);
break;
}
case FDE_CaretMove::LineStart:
MoveLineStart();
break;
case FDE_CaretMove::LineEnd:
MoveLineEnd();
break;
case FDE_CaretMove::Home:
MoveHome();
break;
case FDE_CaretMove::End:
MoveEnd();
break;
}
if (bShift && m_nAnchorPos != -1 && (m_nAnchorPos != m_nCaret)) {
AddSelRange(std::min(m_nAnchorPos, m_nCaret), abs(m_nAnchorPos - m_nCaret));
m_Param.pEventSink->OnSelChanged();
}
if (bSelChange)
m_Param.pEventSink->OnSelChanged();
return m_nCaret;
}
int32_t CFDE_TxtEdtEngine::Insert(const CFX_WideString& str) {
if (IsLocked())
return FDE_TXTEDT_MODIFY_RET_F_Locked;
int32_t nLength = str.GetLength();
CFX_WideString wsTemp;
wchar_t* lpBuffer = wsTemp.GetBuffer(nLength);
memcpy(lpBuffer, str.c_str(), nLength * sizeof(wchar_t));
ReplaceParagEnd(lpBuffer, nLength, false);
wsTemp.ReleaseBuffer(nLength);
if (m_nLimit > 0) {
int32_t nTotalLength = GetTextLength();
for (const auto& lpSelRange : m_SelRangePtrArr)
nTotalLength -= lpSelRange->nCount;
int32_t nExpectLength = nTotalLength + nLength;
if (nTotalLength == m_nLimit)
return FDE_TXTEDT_MODIFY_RET_F_Full;
if (nExpectLength > m_nLimit)
nLength -= (nExpectLength - m_nLimit);
}
if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) ||
(m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz)) {
if (m_Param.dwMode & FDE_TEXTEDITMODE_Password) {
while (nLength > 0) {
CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
int32_t nTotal = wsText.GetLength();
wchar_t* lpBuf = wsText.GetBuffer(nTotal);
for (int32_t i = 0; i < nTotal; i++) {
lpBuf[i] = m_wcAliasChar;
}
wsText.ReleaseBuffer(nTotal);
if (IsFitArea(wsText)) {
break;
}
nLength--;
}
} else {
while (nLength > 0) {
CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
if (IsFitArea(wsText)) {
break;
}
nLength--;
}
}
if (nLength == 0)
return FDE_TXTEDT_MODIFY_RET_F_Full;
}
if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
CFX_WideString wsText = GetPreInsertText(m_nCaret, lpBuffer, nLength);
if (!m_Param.pEventSink->OnValidate(wsText))
return FDE_TXTEDT_MODIFY_RET_F_Invalidate;
}
if (IsSelect()) {
DeleteSelect();
}
m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<InsertOperation>(
this, m_nCaret, CFX_WideString(lpBuffer, nLength)));
m_ChangeInfo.wsPrevText = GetText(0, -1);
Inner_Insert(m_nCaret, lpBuffer, nLength);
m_ChangeInfo.nChangeType = FDE_TXTEDT_TEXTCHANGE_TYPE_Insert;
m_ChangeInfo.wsInsert = CFX_WideString(lpBuffer, nLength);
int32_t nStart = m_nCaret;
nStart += nLength;
wchar_t wChar = m_pTxtBuf->GetCharByIndex(nStart - 1);
bool bBefore = true;
if (wChar != L'\n' && wChar != L'\r') {
nStart--;
bBefore = false;
}
SetCaretPos(nStart, bBefore);
m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
return FDE_TXTEDT_MODIFY_RET_S_Normal;
}
void CFDE_TxtEdtEngine::Delete(bool bBackspace) {
if (IsLocked())
return;
if (IsSelect()) {
DeleteSelect();
return;
}
int32_t nCount = 1;
int32_t nStart = m_nCaret;
if (bBackspace) {
if (nStart == 0)
return;
if (nStart > 2 && m_pTxtBuf->GetCharByIndex(nStart - 1) == L'\n' &&
m_pTxtBuf->GetCharByIndex(nStart - 2) == L'\r') {
nStart--;
nCount++;
}
nStart--;
} else {
if (nStart == GetTextLength())
return;
if ((nStart + 1 < GetTextLength()) &&
(m_pTxtBuf->GetCharByIndex(nStart) == L'\r') &&
(m_pTxtBuf->GetCharByIndex(nStart + 1) == L'\n')) {
nCount++;
}
}
if (m_Param.dwMode & FDE_TEXTEDITMODE_Validate) {
CFX_WideString wsText = GetPreDeleteText(nStart, nCount);
if (!m_Param.pEventSink->OnValidate(wsText))
return;
}
CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<DeleteOperation>(
this, nStart, m_nCaret, wsRange, false));
UpdateChangeInfoDelete(FDE_TXTEDT_TEXTCHANGE_TYPE_Delete,
GetText(nStart, nCount));
Inner_DeleteRange(nStart, nCount);
SetCaretPos(nStart + ((!bBackspace && nStart > 0) ? -1 : 0),
(bBackspace || nStart == 0));
m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
}
void CFDE_TxtEdtEngine::RemoveSelRange(int32_t nStart, int32_t nCount) {
int32_t nRangeCount = pdfium::CollectionSize<int32_t>(m_SelRangePtrArr);
for (int32_t i = 0; i < nRangeCount; i++) {
FDE_TXTEDTSELRANGE* lpTemp = m_SelRangePtrArr[i].get();
if (lpTemp->nStart == nStart && lpTemp->nCount == nCount) {
m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + i);
return;
}
}
}
void CFDE_TxtEdtEngine::AddSelRange(int32_t nStart, int32_t nCount) {
if (nCount == -1)
nCount = GetTextLength() - nStart;
if (m_SelRangePtrArr.empty()) {
auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
lpSelRange->nStart = nStart;
lpSelRange->nCount = nCount;
m_SelRangePtrArr.push_back(std::move(lpSelRange));
m_Param.pEventSink->OnSelChanged();
return;
}
auto* lpTemp = m_SelRangePtrArr.back().get();
if (nStart >= lpTemp->nStart + lpTemp->nCount) {
auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
lpSelRange->nStart = nStart;
lpSelRange->nCount = nCount;
m_SelRangePtrArr.push_back(std::move(lpSelRange));
m_Param.pEventSink->OnSelChanged();
return;
}
int32_t nEnd = nStart + nCount - 1;
bool bBegin = false;
int32_t nRangeBgn = 0;
int32_t nRangeCnt = 0;
for (int32_t i = 0, nSize = pdfium::CollectionSize<int32_t>(m_SelRangePtrArr);
i < nSize; i++) {
lpTemp = m_SelRangePtrArr[i].get();
int32_t nTempBgn = lpTemp->nStart;
int32_t nTempEnd = nTempBgn + lpTemp->nCount - 1;
if (bBegin) {
if (nEnd < nTempBgn) {
break;
} else if (nStart >= nTempBgn && nStart <= nTempEnd) {
nRangeCnt++;
break;
}
nRangeCnt++;
} else {
if (nStart <= nTempEnd) {
nRangeBgn = i;
if (nEnd < nTempBgn) {
break;
}
nRangeCnt = 1;
bBegin = true;
}
}
}
if (nRangeCnt == 0) {
auto lpSelRange = pdfium::MakeUnique<FDE_TXTEDTSELRANGE>();
lpSelRange->nStart = nStart;
lpSelRange->nCount = nCount;
m_SelRangePtrArr.insert(m_SelRangePtrArr.begin() + nRangeBgn,
std::move(lpSelRange));
} else {
lpTemp = m_SelRangePtrArr[nRangeBgn].get();
lpTemp->nStart = nStart;
lpTemp->nCount = nCount;
nRangeCnt--;
nRangeBgn++;
m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + nRangeBgn,
m_SelRangePtrArr.begin() + nRangeBgn + nRangeCnt);
}
m_Param.pEventSink->OnSelChanged();
}
int32_t CFDE_TxtEdtEngine::GetSelRange(int32_t nIndex, int32_t* nStart) const {
if (nStart)
*nStart = m_SelRangePtrArr[nIndex]->nStart;
return m_SelRangePtrArr[nIndex]->nCount;
}
void CFDE_TxtEdtEngine::ClearSelection() {
if (m_SelRangePtrArr.empty())
return;
m_SelRangePtrArr.clear();
if (m_Param.pEventSink)
m_Param.pEventSink->OnSelChanged();
}
bool CFDE_TxtEdtEngine::Redo(const IFDE_TxtEdtDoRecord* pDoRecord) {
if (IsLocked())
return false;
pDoRecord->Redo();
return true;
}
bool CFDE_TxtEdtEngine::Undo(const IFDE_TxtEdtDoRecord* pDoRecord) {
if (IsLocked())
return false;
pDoRecord->Undo();
return true;
}
void CFDE_TxtEdtEngine::Layout() {
CFX_AutoRestorer<bool> lock(&m_bLock);
m_bLock = true;
RemoveAllPages();
UpdateLineCounts();
UpdatePages();
m_nCaret = std::min(m_nCaret, GetTextLength());
m_rtCaret = CFX_RectF(0, 0, 1, m_Param.fFontSize);
}
int32_t CFDE_TxtEdtEngine::Line2Parag(int32_t nStartParag,
int32_t nStartLineofParag,
int32_t nLineIndex,
int32_t& nStartLine) const {
int32_t nLineTotal = nStartLineofParag;
int32_t nCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
CFDE_TxtEdtParag* pParag = nullptr;
int32_t i = nStartParag;
for (; i < nCount; i++) {
pParag = m_ParagPtrArray[i].get();
nLineTotal += pParag->GetLineCount();
if (nLineTotal > nLineIndex) {
break;
}
}
nStartLine = nLineTotal - pParag->GetLineCount();
return i;
}
CFX_WideString CFDE_TxtEdtEngine::GetPreDeleteText(int32_t nIndex,
int32_t nLength) {
CFX_WideString wsText = GetText(0, GetTextLength());
wsText.Delete(nIndex, nLength);
return wsText;
}
CFX_WideString CFDE_TxtEdtEngine::GetPreInsertText(int32_t nIndex,
const wchar_t* lpText,
int32_t nLength) {
CFX_WideString wsText = GetText(0, GetTextLength());
int32_t nSelIndex = 0;
int32_t nSelLength = 0;
int32_t nSelCount = CountSelRanges();
while (nSelCount--) {
nSelLength = GetSelRange(nSelCount, &nSelIndex);
wsText.Delete(nSelIndex, nSelLength);
nIndex = nSelIndex;
}
CFX_WideString wsTemp;
int32_t nOldLength = wsText.GetLength();
const wchar_t* pOldBuffer = wsText.c_str();
wchar_t* lpBuffer = wsTemp.GetBuffer(nOldLength + nLength);
memcpy(lpBuffer, pOldBuffer, (nIndex) * sizeof(wchar_t));
memcpy(lpBuffer + nIndex, lpText, nLength * sizeof(wchar_t));
memcpy(lpBuffer + nIndex + nLength, pOldBuffer + nIndex,
(nOldLength - nIndex) * sizeof(wchar_t));
wsTemp.ReleaseBuffer(nOldLength + nLength);
wsText = wsTemp;
return wsText;
}
CFX_WideString CFDE_TxtEdtEngine::GetPreReplaceText(int32_t nIndex,
int32_t nOriginLength,
const wchar_t* lpText,
int32_t nLength) {
CFX_WideString wsText = GetText(0, GetTextLength());
int32_t nSelIndex = 0;
int32_t nSelLength = 0;
int32_t nSelCount = CountSelRanges();
while (nSelCount--) {
nSelLength = GetSelRange(nSelCount, &nSelIndex);
wsText.Delete(nSelIndex, nSelLength);
}
wsText.Delete(nIndex, nOriginLength);
int32_t i = 0;
for (i = 0; i < nLength; i++)
wsText.Insert(nIndex++, lpText[i]);
return wsText;
}
void CFDE_TxtEdtEngine::Inner_Insert(int32_t nStart,
const wchar_t* lpText,
int32_t nLength) {
ASSERT(nLength > 0);
FDE_TXTEDTPARAGPOS ParagPos;
TextPos2ParagPos(nStart, ParagPos);
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
for (int32_t i = ParagPos.nParagIndex + 1; i < nParagCount; i++)
m_ParagPtrArray[i]->IncrementStartIndex(nLength);
CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
int32_t nReserveLineCount = pParag->GetLineCount();
int32_t nReserveCharStart = pParag->GetStartIndex();
int32_t nLeavePart = ParagPos.nCharIndex;
int32_t nCutPart = pParag->GetTextLength() - ParagPos.nCharIndex;
int32_t nTextStart = 0;
wchar_t wCurChar = L' ';
const wchar_t* lpPos = lpText;
bool bFirst = true;
int32_t nParagIndex = ParagPos.nParagIndex;
for (int32_t i = 0; i < nLength; i++, lpPos++) {
wCurChar = *lpPos;
if (wCurChar == m_wLineEnd) {
if (bFirst) {
pParag->SetTextLength(nLeavePart + (i - nTextStart + 1));
pParag->SetLineCount(-1);
nReserveCharStart += pParag->GetTextLength();
bFirst = false;
} else {
auto pParag2 = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
pParag2->SetLineCount(-1);
pParag2->SetTextLength(i - nTextStart + 1);
pParag2->SetStartIndex(nReserveCharStart);
nReserveCharStart += pParag2->GetTextLength();
m_ParagPtrArray.insert(m_ParagPtrArray.begin() + ++nParagIndex,
std::move(pParag2));
}
nTextStart = i + 1;
}
}
if (bFirst) {
pParag->IncrementTextLength(nLength);
pParag->SetLineCount(-1);
bFirst = false;
} else {
auto pParag2 = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
pParag2->SetLineCount(-1);
pParag2->SetTextLength(nLength - nTextStart + nCutPart);
pParag2->SetStartIndex(nReserveCharStart);
m_ParagPtrArray.insert(m_ParagPtrArray.begin() + ++nParagIndex,
std::move(pParag2));
}
m_pTxtBuf->Insert(nStart, lpText, nLength);
int32_t nTotalLineCount = 0;
for (int32_t i = ParagPos.nParagIndex; i <= nParagIndex; i++) {
pParag = m_ParagPtrArray[i].get();
pParag->CalcLines();
nTotalLineCount += pParag->GetLineCount();
}
m_nLineCount += nTotalLineCount - nReserveLineCount;
m_Param.pEventSink->OnPageLoad(m_nCaretPage);
UpdatePages();
}
void CFDE_TxtEdtEngine::Inner_DeleteRange(int32_t nStart, int32_t nCount) {
if (nCount == -1) {
nCount = m_pTxtBuf->GetTextLength() - nStart;
}
int32_t nEnd = nStart + nCount - 1;
ASSERT(nStart >= 0 && nEnd < m_pTxtBuf->GetTextLength());
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
FDE_TXTEDTPARAGPOS ParagPosBgn, ParagPosEnd;
TextPos2ParagPos(nStart, ParagPosBgn);
TextPos2ParagPos(nEnd, ParagPosEnd);
CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPosEnd.nParagIndex].get();
bool bLastParag = false;
if (ParagPosEnd.nCharIndex == pParag->GetTextLength() - 1) {
if (ParagPosEnd.nParagIndex <
pdfium::CollectionSize<int32_t>(m_ParagPtrArray) - 1) {
ParagPosEnd.nParagIndex++;
} else {
bLastParag = true;
}
}
int32_t nTotalLineCount = 0;
int32_t nTotalCharCount = 0;
int32_t i = 0;
for (i = ParagPosBgn.nParagIndex; i <= ParagPosEnd.nParagIndex; i++) {
CFDE_TxtEdtParag* pTextParag = m_ParagPtrArray[i].get();
pTextParag->CalcLines();
nTotalLineCount += pTextParag->GetLineCount();
nTotalCharCount += pTextParag->GetTextLength();
}
m_pTxtBuf->Delete(nStart, nCount);
int32_t nNextParagIndex = (ParagPosBgn.nCharIndex == 0 && bLastParag)
? ParagPosBgn.nParagIndex
: (ParagPosBgn.nParagIndex + 1);
m_ParagPtrArray.erase(m_ParagPtrArray.begin() + nNextParagIndex,
m_ParagPtrArray.begin() + ParagPosEnd.nParagIndex + 1);
if (!(bLastParag && ParagPosBgn.nCharIndex == 0)) {
pParag = m_ParagPtrArray[ParagPosBgn.nParagIndex].get();
pParag->SetTextLength(nTotalCharCount - nCount);
pParag->CalcLines();
nTotalLineCount -= pParag->GetTextLength();
}
int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
for (i = nNextParagIndex; i < nParagCount; i++)
m_ParagPtrArray[i]->DecrementStartIndex(nCount);
m_nLineCount -= nTotalLineCount;
UpdatePages();
int32_t nPageCount = CountPages();
if (m_nCaretPage >= nPageCount) {
m_nCaretPage = nPageCount - 1;
}
m_Param.pEventSink->OnPageLoad(m_nCaretPage);
}
void CFDE_TxtEdtEngine::DeleteRange_DoRecord(int32_t nStart,
int32_t nCount,
bool bSel) {
ASSERT(nStart >= 0);
if (nCount == -1) {
nCount = GetTextLength() - nStart;
}
ASSERT((nStart + nCount) <= m_pTxtBuf->GetTextLength());
CFX_WideString wsRange = m_pTxtBuf->GetRange(nStart, nCount);
m_Param.pEventSink->OnAddDoRecord(pdfium::MakeUnique<DeleteOperation>(
this, nStart, m_nCaret, wsRange, bSel));
UpdateChangeInfoDelete(FDE_TXTEDT_TEXTCHANGE_TYPE_Delete,
GetText(nStart, nCount));
Inner_DeleteRange(nStart, nCount);
}
void CFDE_TxtEdtEngine::ResetEngine() {
RemoveAllPages();
RemoveAllParags();
ClearSelection();
m_nCaret = 0;
m_pTxtBuf->Clear(false);
m_nCaret = 0;
}
void CFDE_TxtEdtEngine::RebuildParagraphs() {
RemoveAllParags();
wchar_t wChar = L' ';
int32_t nParagStart = 0;
int32_t nIndex = 0;
auto pIter = pdfium::MakeUnique<CFDE_TxtEdtBuf::Iterator>(m_pTxtBuf.get(), 0);
pIter->SetAt(0);
do {
wChar = pIter->GetChar();
nIndex = pIter->GetAt();
if (wChar == m_wLineEnd) {
auto pParag = pdfium::MakeUnique<CFDE_TxtEdtParag>(this);
pParag->SetStartIndex(nParagStart);
pParag->SetTextLength(nIndex - nParagStart + 1);
pParag->SetLineCount(-1);
m_ParagPtrArray.push_back(std::move(pParag));
nParagStart = nIndex + 1;
}
} while (pIter->Next());
}
void CFDE_TxtEdtEngine::UpdateLineCounts() {
if (m_ParagPtrArray.empty())
return;
int32_t nLineCount = 0;
for (auto& pParag : m_ParagPtrArray) {
pParag->CalcLines();
nLineCount += pParag->GetLineCount();
}
m_nLineCount = nLineCount;
}
void CFDE_TxtEdtEngine::UpdatePages() {
if (m_nLineCount == 0)
return;
int32_t nPageCount = (m_nLineCount - 1) / (m_nPageLineCount) + 1;
int32_t nSize = pdfium::CollectionSize<int32_t>(m_PagePtrArray);
if (nSize == nPageCount)
return;
if (nSize > nPageCount) {
m_PagePtrArray.erase(m_PagePtrArray.begin() + nPageCount,
m_PagePtrArray.end());
return;
}
for (int32_t i = nSize; i < nPageCount; i++)
m_PagePtrArray.push_back(pdfium::MakeUnique<CFDE_TxtEdtPage>(this, i));
}
void CFDE_TxtEdtEngine::UpdateTxtBreak() {
uint32_t dwStyle = m_pTextBreak->GetLayoutStyles();
if (m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines)
dwStyle &= ~FX_LAYOUTSTYLE_SingleLine;
else
dwStyle |= FX_LAYOUTSTYLE_SingleLine;
if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText)
dwStyle |= FX_LAYOUTSTYLE_CombText;
else
dwStyle &= ~FX_LAYOUTSTYLE_CombText;
m_pTextBreak->SetLayoutStyles(dwStyle);
uint32_t dwAligment = 0;
if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Justified)
dwAligment |= CFX_TxtLineAlignment_Justified;
if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Center)
dwAligment |= CFX_TxtLineAlignment_Center;
else if (m_Param.dwAlignment & FDE_TEXTEDITALIGN_Right)
dwAligment |= CFX_TxtLineAlignment_Right;
m_pTextBreak->SetAlignment(dwAligment);
if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap)
m_pTextBreak->SetLineWidth(m_Param.fPlateWidth);
else
m_pTextBreak->SetLineWidth(kPageWidthMax);
m_nPageLineCount = m_Param.nLineCount;
if (m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText) {
float fCombWidth = m_Param.fPlateWidth;
if (m_nLimit > 0)
fCombWidth /= m_nLimit;
m_pTextBreak->SetCombWidth(fCombWidth);
}
m_pTextBreak->SetFont(m_Param.pFont);
m_pTextBreak->SetFontSize(m_Param.fFontSize);
m_pTextBreak->SetTabWidth(m_Param.fTabWidth);
m_pTextBreak->SetDefaultChar(m_Param.wDefChar);
m_pTextBreak->SetParagraphBreakChar(m_Param.wLineBreakChar);
m_pTextBreak->SetLineBreakTolerance(m_Param.fFontSize * 0.2f);
m_pTextBreak->SetHorizontalScale(m_Param.nHorzScale);
m_pTextBreak->SetCharSpace(m_Param.fCharSpace);
}
bool CFDE_TxtEdtEngine::ReplaceParagEnd(wchar_t*& lpText,
int32_t& nLength,
bool bPreIsCR) {
for (int32_t i = 0; i < nLength; i++) {
wchar_t wc = lpText[i];
switch (wc) {
case L'\r': {
lpText[i] = m_wLineEnd;
bPreIsCR = true;
} break;
case L'\n': {
if (bPreIsCR == true) {
int32_t nNext = i + 1;
if (nNext < nLength) {
memmove(lpText + i, lpText + nNext,
(nLength - nNext) * sizeof(wchar_t));
}
i--;
nLength--;
bPreIsCR = false;
if (m_bAutoLineEnd) {
m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_CRLF;
m_bAutoLineEnd = false;
}
} else {
lpText[i] = m_wLineEnd;
if (m_bAutoLineEnd) {
m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_LF;
m_bAutoLineEnd = false;
}
}
} break;
default: {
if (bPreIsCR && m_bAutoLineEnd) {
m_nFirstLineEnd = FDE_TXTEDIT_LINEEND_CR;
m_bAutoLineEnd = false;
}
bPreIsCR = false;
} break;
}
}
return bPreIsCR;
}
void CFDE_TxtEdtEngine::RecoverParagEnd(CFX_WideString& wsText) const {
wchar_t wc = (m_nFirstLineEnd == FDE_TXTEDIT_LINEEND_CR) ? L'\n' : L'\r';
if (m_nFirstLineEnd == FDE_TXTEDIT_LINEEND_CRLF) {
std::vector<int32_t> PosArr;
int32_t nLength = wsText.GetLength();
wchar_t* lpPos = const_cast<wchar_t*>(wsText.c_str());
for (int32_t i = 0; i < nLength; i++, lpPos++) {
if (*lpPos == m_wLineEnd) {
*lpPos = wc;
PosArr.push_back(i);
}
}
const wchar_t* lpSrcBuf = wsText.c_str();
CFX_WideString wsTemp;
int32_t nCount = pdfium::CollectionSize<int32_t>(PosArr);
wchar_t* lpDstBuf = wsTemp.GetBuffer(nLength + nCount);
int32_t nDstPos = 0;
int32_t nSrcPos = 0;
for (int32_t i = 0; i < nCount; i++) {
int32_t nPos = PosArr[i];
int32_t nCopyLen = nPos - nSrcPos + 1;
memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
nCopyLen * sizeof(wchar_t));
nDstPos += nCopyLen;
nSrcPos += nCopyLen;
lpDstBuf[nDstPos] = L'\n';
nDstPos++;
}
if (nSrcPos < nLength) {
memcpy(lpDstBuf + nDstPos, lpSrcBuf + nSrcPos,
(nLength - nSrcPos) * sizeof(wchar_t));
}
wsTemp.ReleaseBuffer(nLength + nCount);
wsText = wsTemp;
} else {
int32_t nLength = wsText.GetLength();
wchar_t* lpBuf = const_cast<wchar_t*>(wsText.c_str());
for (int32_t i = 0; i < nLength; i++, lpBuf++) {
if (*lpBuf == m_wLineEnd)
*lpBuf = wc;
}
}
}
int32_t CFDE_TxtEdtEngine::MovePage2Char(int32_t nIndex) {
ASSERT(nIndex >= 0);
ASSERT(nIndex <= m_pTxtBuf->GetTextLength());
if (m_nCaretPage >= 0) {
CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
m_Param.pEventSink->OnPageLoad(m_nCaretPage);
int32_t nPageCharStart = pPage->GetCharStart();
int32_t nPageCharCount = pPage->GetCharCount();
if (nIndex >= nPageCharStart && nIndex < nPageCharStart + nPageCharCount) {
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
return m_nCaretPage;
}
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
}
CFDE_TxtEdtParag* pParag = nullptr;
int32_t nLineCount = 0;
int32_t nParagCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
int32_t i = 0;
for (i = 0; i < nParagCount; i++) {
pParag = m_ParagPtrArray[i].get();
if (pParag->GetStartIndex() <= nIndex &&
nIndex < (pParag->GetStartIndex() + pParag->GetTextLength())) {
break;
}
nLineCount += pParag->GetLineCount();
}
pParag->LoadParag();
int32_t nLineStart = -1;
int32_t nLineCharCount = -1;
for (i = 0; i < pParag->GetLineCount(); i++) {
pParag->GetLineRange(i, nLineStart, nLineCharCount);
if (nLineStart <= nIndex && nIndex < (nLineStart + nLineCharCount))
break;
}
ASSERT(i < pParag->GetLineCount());
nLineCount += (i + 1);
m_nCaretPage = (nLineCount - 1) / m_nPageLineCount + 1 - 1;
pParag->UnloadParag();
return m_nCaretPage;
}
void CFDE_TxtEdtEngine::TextPos2ParagPos(int32_t nIndex,
FDE_TXTEDTPARAGPOS& ParagPos) const {
ASSERT(nIndex >= 0 && nIndex < m_pTxtBuf->GetTextLength());
int32_t nCount = pdfium::CollectionSize<int32_t>(m_ParagPtrArray);
int32_t nBgn = 0;
int32_t nMid = 0;
int32_t nEnd = nCount - 1;
while (nEnd > nBgn) {
nMid = (nBgn + nEnd) / 2;
CFDE_TxtEdtParag* pParag = m_ParagPtrArray[nMid].get();
if (nIndex < pParag->GetStartIndex())
nEnd = nMid - 1;
else if (nIndex >= (pParag->GetStartIndex() + pParag->GetTextLength()))
nBgn = nMid + 1;
else
break;
}
if (nBgn == nEnd)
nMid = nBgn;
ASSERT(nIndex >= m_ParagPtrArray[nMid]->GetStartIndex() &&
(nIndex < m_ParagPtrArray[nMid]->GetStartIndex() +
m_ParagPtrArray[nMid]->GetTextLength()));
ParagPos.nParagIndex = nMid;
ParagPos.nCharIndex = nIndex - m_ParagPtrArray[nMid]->GetStartIndex();
}
int32_t CFDE_TxtEdtEngine::MoveForward(bool& bBefore) {
if (m_nCaret == m_pTxtBuf->GetTextLength() - 1)
return -1;
int32_t nCaret = m_nCaret;
if ((nCaret + 1 < m_pTxtBuf->GetTextLength()) &&
(m_pTxtBuf->GetCharByIndex(nCaret) == L'\r') &&
(m_pTxtBuf->GetCharByIndex(nCaret + 1) == L'\n')) {
nCaret++;
}
nCaret++;
bBefore = true;
return nCaret;
}
int32_t CFDE_TxtEdtEngine::MoveBackward(bool& bBefore) {
if (m_nCaret == 0)
return false;
int32_t nCaret = m_nCaret;
if (nCaret > 2 && m_pTxtBuf->GetCharByIndex(nCaret - 1) == L'\n' &&
m_pTxtBuf->GetCharByIndex(nCaret - 2) == L'\r') {
nCaret--;
}
nCaret--;
bBefore = true;
return nCaret;
}
bool CFDE_TxtEdtEngine::MoveUp(CFX_PointF& ptCaret) {
CFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
const CFX_RectF& rtContent = pPage->GetContentsBox();
ptCaret.x = m_fCaretPosReserve;
ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 - m_Param.fLineSpace;
if (ptCaret.y < rtContent.top) {
if (m_nCaretPage == 0) {
return false;
}
ptCaret.y -= rtContent.top;
m_nCaretPage--;
CFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
ptCaret.y += pCurPage->GetContentsBox().bottom();
}
return true;
}
bool CFDE_TxtEdtEngine::MoveDown(CFX_PointF& ptCaret) {
CFDE_TxtEdtPage* pPage = GetPage(m_nCaretPage);
const CFX_RectF& rtContent = pPage->GetContentsBox();
ptCaret.x = m_fCaretPosReserve;
ptCaret.y = m_rtCaret.top + m_rtCaret.height / 2 + m_Param.fLineSpace;
if (ptCaret.y >= rtContent.bottom()) {
if (m_nCaretPage == CountPages() - 1) {
return false;
}
ptCaret.y -= rtContent.bottom();
m_nCaretPage++;
CFDE_TxtEdtPage* pCurPage = GetPage(m_nCaretPage);
ptCaret.y += pCurPage->GetContentsBox().top;
}
return true;
}
bool CFDE_TxtEdtEngine::MoveLineStart() {
int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
FDE_TXTEDTPARAGPOS ParagPos;
TextPos2ParagPos(nIndex, ParagPos);
CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
pParag->LoadParag();
int32_t nLineCount = pParag->GetLineCount();
int32_t i = 0;
int32_t nStart = 0;
int32_t nCount = 0;
for (; i < nLineCount; i++) {
pParag->GetLineRange(i, nStart, nCount);
if (nIndex >= nStart && nIndex < nStart + nCount) {
break;
}
}
UpdateCaretRect(nStart, true);
pParag->UnloadParag();
return true;
}
bool CFDE_TxtEdtEngine::MoveLineEnd() {
int32_t nIndex = m_bBefore ? m_nCaret : m_nCaret - 1;
FDE_TXTEDTPARAGPOS ParagPos;
TextPos2ParagPos(nIndex, ParagPos);
CFDE_TxtEdtParag* pParag = m_ParagPtrArray[ParagPos.nParagIndex].get();
pParag->LoadParag();
int32_t nLineCount = pParag->GetLineCount();
int32_t i = 0;
int32_t nStart = 0;
int32_t nCount = 0;
for (; i < nLineCount; i++) {
pParag->GetLineRange(i, nStart, nCount);
if (nIndex >= nStart && nIndex < nStart + nCount) {
break;
}
}
nIndex = nStart + nCount - 1;
ASSERT(nIndex <= GetTextLength());
wchar_t wChar = m_pTxtBuf->GetCharByIndex(nIndex);
bool bBefore = false;
if (nIndex <= GetTextLength()) {
if (wChar == L'\r') {
bBefore = true;
} else if (wChar == L'\n' && nIndex > nStart) {
bBefore = true;
nIndex--;
wChar = m_pTxtBuf->GetCharByIndex(nIndex);
if (wChar != L'\r') {
nIndex++;
}
}
}
UpdateCaretRect(nIndex, bBefore);
pParag->UnloadParag();
return true;
}
bool CFDE_TxtEdtEngine::MoveHome() {
UpdateCaretRect(0, true);
return true;
}
bool CFDE_TxtEdtEngine::MoveEnd() {
UpdateCaretRect(GetTextLength(), true);
return true;
}
bool CFDE_TxtEdtEngine::IsFitArea(CFX_WideString& wsText) {
auto pTextOut = pdfium::MakeUnique<CFDE_TextOut>();
pTextOut->SetLineSpace(m_Param.fLineSpace);
pTextOut->SetFont(m_Param.pFont);
pTextOut->SetFontSize(m_Param.fFontSize);
FDE_TextStyle dwStyle;
if (!(m_Param.dwMode & FDE_TEXTEDITMODE_MultiLines))
dwStyle.single_line_ = true;
CFX_RectF rcText;
if (m_Param.dwMode & FDE_TEXTEDITMODE_AutoLineWrap) {
dwStyle.line_wrap_ = true;
rcText.width = m_Param.fPlateWidth;
} else {
rcText.width = 65535;
}
pTextOut->SetStyles(dwStyle);
wsText += L"\n";
pTextOut->CalcLogicSize(wsText.c_str(), wsText.GetLength(), rcText);
wsText.Delete(wsText.GetLength() - 1);
if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Horz) &&
(rcText.width > m_Param.fPlateWidth)) {
return false;
}
if ((m_Param.dwMode & FDE_TEXTEDITMODE_LimitArea_Vert) &&
(rcText.height > m_Param.fLineSpace * m_Param.nLineCount)) {
return false;
}
return true;
}
void CFDE_TxtEdtEngine::UpdateCaretRect(int32_t nIndex, bool bBefore) {
MovePage2Char(nIndex);
GetCaretRect(m_rtCaret, m_nCaretPage, nIndex, bBefore);
m_nCaret = nIndex;
m_bBefore = bBefore;
if (!m_bBefore) {
m_nCaret++;
m_bBefore = true;
}
m_fCaretPosReserve = m_rtCaret.left;
m_Param.pEventSink->OnCaretChanged();
}
void CFDE_TxtEdtEngine::GetCaretRect(CFX_RectF& rtCaret,
int32_t nPageIndex,
int32_t nCaret,
bool bBefore) {
CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
m_Param.pEventSink->OnPageLoad(m_nCaretPage);
bool bCombText = !!(m_Param.dwLayoutStyles & FDE_TEXTEDITLAYOUT_CombText);
int32_t nIndexInpage = nCaret - pPage->GetCharStart();
if (bBefore && bCombText && nIndexInpage > 0) {
nIndexInpage--;
bBefore = false;
}
int32_t nBIDILevel = pPage->GetCharRect(nIndexInpage, rtCaret, bCombText);
if ((!FX_IsOdd(nBIDILevel) && !bBefore) ||
(FX_IsOdd(nBIDILevel) && bBefore)) {
rtCaret.Offset(rtCaret.width - 1.0f, 0);
}
if (rtCaret.width == 0 && rtCaret.left > 1.0f)
rtCaret.left -= 1.0f;
rtCaret.width = 1.0f;
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
}
void CFDE_TxtEdtEngine::UpdateCaretIndex(const CFX_PointF& ptCaret) {
CFDE_TxtEdtPage* pPage = m_PagePtrArray[m_nCaretPage].get();
m_Param.pEventSink->OnPageLoad(m_nCaretPage);
m_nCaret = pPage->GetCharIndex(ptCaret, m_bBefore);
GetCaretRect(m_rtCaret, m_nCaretPage, m_nCaret, m_bBefore);
if (!m_bBefore) {
m_nCaret++;
m_bBefore = true;
}
m_Param.pEventSink->OnCaretChanged();
m_Param.pEventSink->OnPageUnload(m_nCaretPage);
}
void CFDE_TxtEdtEngine::DeleteSelect() {
int32_t nCountRange = CountSelRanges();
if (nCountRange <= 0)
return;
int32_t nSelStart = 0;
while (nCountRange > 0) {
int32_t nSelCount = GetSelRange(--nCountRange, &nSelStart);
m_SelRangePtrArr.erase(m_SelRangePtrArr.begin() + nCountRange);
DeleteRange_DoRecord(nSelStart, nSelCount, true);
}
ClearSelection();
m_Param.pEventSink->OnTextChanged(m_ChangeInfo);
m_Param.pEventSink->OnSelChanged();
SetCaretPos(nSelStart, true);
}