!36985 RichEditor buildSpan 光标移动不正确

Merge pull request !36985 from xieqiqi/master
This commit is contained in:
openharmony_ci 2024-07-06 04:19:24 +00:00 committed by Gitee
commit 56e87fd412
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
3 changed files with 147 additions and 82 deletions

View File

@ -4996,23 +4996,27 @@ bool RichEditorPattern::CursorMoveUp()
CHECK_NULL_RETURN(!SelectOverlayIsOn(), false);
ResetSelection();
float caretHeight = 0.0f;
OffsetF caretOffsetUp;
OffsetF caretOffsetDown;
float leadingMarginOffset = 0.0f;
CaretOffsetInfo caretInfo;
if (static_cast<int32_t>(GetTextContentLength()) > 1) {
int32_t caretPosition = CalcMoveUpPos(caretOffsetUp, caretOffsetDown);
caretInfo = GetCaretOffsetInfoByPosition();
int32_t caretPosition = CalcMoveUpPos(leadingMarginOffset);
CHECK_NULL_RETURN(overlayMod_, false);
auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
auto caretOffsetWidth = overlayMod->GetCaretWidth();
auto rectLineInfo = CalcLineInfoByPosition();
caretPosition = std::clamp(caretPosition, 0, static_cast<int32_t>(GetTextContentLength()));
if (caretPosition_ == caretPosition) {
caretPosition = 0;
}
// at line middle or line end
bool isCaretPosInLineEnd = NearEqual(currentCaretOffsetOverlay.GetX(), caretOffsetUp.GetX(), caretOffsetWidth);
bool cursorNotAtLineStart =
NearEqual(currentCaretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
bool isEnter = NearZero(currentCaretOffsetOverlay.GetX() - richTextRect_.GetX(), rectLineInfo.GetX());
SetCaretPosition(caretPosition);
MoveCaretToContentRect();
if (isCaretPosInLineEnd) {
if (cursorNotAtLineStart && !isEnter) {
OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
SetLastClickOffset(caretOffset);
}
@ -5029,41 +5033,31 @@ bool RichEditorPattern::CursorMoveDown()
CHECK_NULL_RETURN(!SelectOverlayIsOn(), false);
ResetSelection();
if (static_cast<int32_t>(GetTextContentLength()) > 1) {
float caretHeightUp = 0.0f;
float caretLineHeight = 0.0f;
float caretHeight = 0.0f;
float textOffsetDownY = 0.0f;
Offset textOffset;
int32_t caretPositionStart;
float leadingMarginOffset = 0.0f;
CaretOffsetInfo caretInfo;
int32_t caretPositionEnd;
caretPositionStart = caretPosition_;
OffsetF caretOffsetUp = CalcCursorOffsetByPosition(caretPosition_, caretHeightUp, false, false);
OffsetF caretOffsetLine = CalcCursorOffsetByPosition(caretPosition_, caretLineHeight);
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
caretInfo = GetCaretOffsetInfoByPosition();
caretPositionEnd = CalcMoveDownPos(leadingMarginOffset);
CHECK_NULL_RETURN(overlayMod_, false);
auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
auto caretOffsetOverlay = overlayMod->GetCaretOffset();
auto caretOffsetWidth = overlayMod->GetCaretWidth();
float textOffsetX = GetTextRect().GetX();
float textOffsetY = GetTextRect().GetY() - minDet / 2.0;
bool isCaretPosInLineEnd = NearEqual(caretOffsetOverlay.GetX(), caretOffsetUp.GetX(), caretOffsetWidth);
auto lineHeightDis = CalcLineHeightByPosition(caretPosition_);
// at line middle position or line end position or first line start position
if (isCaretPosInLineEnd || caretPositionStart == 0) {
textOffsetDownY = caretOffsetLine.GetY() + lineHeightDis - textOffsetY;
} else {
// at line start position, caretOffsetLine equ caretOffsetUp, so previous line height add currentLineHeight
textOffsetDownY = caretOffsetLine.GetY() + caretLineHeight + lineHeightDis - textOffsetY;
}
textOffset = Offset(caretOffsetOverlay.GetX() - textOffsetX, textOffsetDownY);
caretPositionEnd = paragraphs_.GetIndex(textOffset);
bool cursorNotAtLineStart =
NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
bool isEnter = NearZero(caretOffsetOverlay.GetX() - richTextRect_.GetX(), leadingMarginOffset);
caretPositionEnd = std::clamp(caretPositionEnd, 0, static_cast<int32_t>(GetTextContentLength()));
if (caretPosition_ == caretPositionEnd) {
caretPositionEnd = GetTextContentLength();
if (caretPositionEnd <= caretPosition_) {
float caretHeightEnd = 0.0f;
OffsetF caretOffsetEnd = CalcCursorOffsetByPosition(GetTextContentLength(), caretHeightEnd);
if (NearEqual(caretOffsetEnd.GetY(), caretOffsetOverlay.GetY())) {
caretPositionEnd = GetTextContentLength();
} else {
caretPositionEnd += 1;
}
}
SetCaretPosition(caretPositionEnd);
// at line middle or line end, direct to call SetLastClickOffset
if (isCaretPosInLineEnd && caretPositionStart != 0) {
if (cursorNotAtLineStart && caretPosition_ != 0 && !isEnter) {
OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
SetLastClickOffset(caretOffset);
}
@ -8847,61 +8841,120 @@ OffsetF RichEditorPattern::GetPaintRectGlobalOffset() const
return textPaintOffset - rootOffset;
}
float RichEditorPattern::CalcLineHeightByPosition(int32_t position)
CaretOffsetInfo RichEditorPattern::GetCaretOffsetInfoByPosition()
{
CaretOffsetInfo caretInfo;
caretInfo.caretOffsetUp = CalcCursorOffsetByPosition(caretPosition_, caretInfo.caretHeightUp, false, false);
caretInfo.caretOffsetDown = CalcCursorOffsetByPosition(caretPosition_, caretInfo.caretHeightDown, true, false);
caretInfo.caretOffsetLine = CalcCursorOffsetByPosition(caretPosition_, caretInfo.caretHeightLine);
return caretInfo;
}
void RichEditorPattern::CalcLineSidesIndexByPosition(int32_t& startIndex, int32_t& endIndex)
{
int32_t lineStartIndex;
int32_t lineEndIndex;
Offset textStartOffset;
Offset textEndOffset;
CHECK_NULL_RETURN(overlayMod_, 0.0f);
CHECK_NULL_VOID(overlayMod_);
auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
auto currentCaretOffsetOverlay = overlayMod->GetCaretOffset();
textStartOffset = Offset(0, currentCaretOffsetOverlay.GetY() - GetTextRect().GetY());
textEndOffset = Offset(GetTextRect().Width(), currentCaretOffsetOverlay.GetY() - GetTextRect().GetY());
lineStartIndex = paragraphs_.GetIndex(textStartOffset);
lineEndIndex = paragraphs_.GetIndex(textEndOffset);
auto selectedRects = paragraphs_.GetRects(lineStartIndex, lineEndIndex);
CHECK_NULL_RETURN(selectedRects.size(), 0.0f);
return selectedRects.front().Height();
textStartOffset = Offset(0, currentCaretOffsetOverlay.GetY() - textOffsetY);
textEndOffset = Offset(richTextRect_.Width(), currentCaretOffsetOverlay.GetY() - textOffsetY);
startIndex = paragraphs_.GetIndex(textStartOffset);
endIndex = paragraphs_.GetIndex(textEndOffset);
}
int32_t RichEditorPattern::CalcMoveUpPos(OffsetF& caretOffsetUp, OffsetF& caretOffsetDown)
RectF RichEditorPattern::CalcLineInfoByPosition()
{
int32_t startIndex = 0;
int32_t endIndex = 0;
CalcLineSidesIndexByPosition(startIndex, endIndex);
if (startIndex == endIndex) {
endIndex += 1;
}
auto selectedRects = paragraphs_.GetRects(startIndex, endIndex);
CHECK_NULL_RETURN(selectedRects.size(), {});
return selectedRects.front();
}
int32_t RichEditorPattern::CalcMoveUpPos(float& leadingMarginOffset)
{
int32_t caretPosition;
float caretHeightUp = 0.0f;
float caretHeightDown = 0.0f;
float lineHeightDis = 0.0f;
CaretOffsetInfo caretInfo;
float textOffsetDownY = 0.0f;
int32_t startIndex = 0;
int32_t endIndex = 0;
Offset textOffset;
OffsetF caretOffsetCalcUp = CalcCursorOffsetByPosition(caretPosition_, caretHeightUp, false, false);
OffsetF caretOffsetCalcDown = CalcCursorOffsetByPosition(caretPosition_, caretHeightDown, true, false);
caretInfo = GetCaretOffsetInfoByPosition();
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
caretOffsetUp = caretOffsetCalcUp;
caretOffsetDown = caretOffsetCalcDown;
CHECK_NULL_RETURN(overlayMod_, 0);
auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
auto caretOffsetOverlay = overlayMod->GetCaretOffset();
float textOffsetY = GetTextRect().GetY() + minDet / 2.0; // 2.0 Cursor one half at the center position
float lineHeight = CalcLineHeightByPosition(caretPosition_);
if (lineHeight == 0) {
lineHeightDis = caretHeightUp - overlayMod->GetCaretHeight();
auto caretOffsetWidth = overlayMod->GetCaretWidth();
bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
float textOffsetY = richTextRect_.GetY() + (minDet / 2.0); // 2.0 Cursor one half at the center position
CalcLineSidesIndexByPosition(startIndex, endIndex);
auto rectLineInfo = CalcLineInfoByPosition();
leadingMarginOffset = rectLineInfo.GetX();
if (cursorNotAtLineStart) {
textOffsetDownY = caretInfo.caretOffsetLine.GetY() - textOffsetY;
// lm mean leadingMargin abbr
auto lmSizeOffset = (endIndex - startIndex <= 1 && NearEqual(rectLineInfo.Width(), richTextRect_.Width()))
? rectLineInfo.GetX()
: 0;
textOffset = Offset(caretInfo.caretOffsetLine.GetX() - richTextRect_.GetX() + lmSizeOffset, textOffsetDownY);
} else {
lineHeightDis = lineHeight - overlayMod->GetCaretHeight();
textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
textOffset = Offset(caretOffsetOverlay.GetX() - richTextRect_.GetX(), textOffsetDownY);
}
float textOffsetDownY = caretOffsetOverlay.GetY() - lineHeightDis - textOffsetY;
textOffset = Offset(caretOffsetOverlay.GetX() - GetTextRect().GetX(), textOffsetDownY);
caretPosition = paragraphs_.GetIndex(textOffset);
return caretPosition;
}
int32_t RichEditorPattern::CalcMoveDownPos(float& leadingMarginOffset)
{
CaretOffsetInfo caretInfo;
float textOffsetDownY = 0.0f;
Offset textOffset;
int32_t caretPositionEnd;
caretInfo = GetCaretOffsetInfoByPosition();
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
CHECK_NULL_RETURN(overlayMod_, 0);
auto overlayMod = DynamicCast<RichEditorOverlayModifier>(overlayMod_);
auto caretOffsetOverlay = overlayMod->GetCaretOffset();
auto caretOffsetWidth = overlayMod->GetCaretWidth();
float textOffsetX = richTextRect_.GetX();
float textOffsetY = richTextRect_.GetY() - (minDet / 2.0);
bool cursorNotAtLineStart = NearEqual(caretOffsetOverlay.GetX(), caretInfo.caretOffsetUp.GetX(), caretOffsetWidth);
// midle or enter
auto rectLineInfo = CalcLineInfoByPosition();
leadingMarginOffset = rectLineInfo.GetX();
auto lineHeightDis = rectLineInfo.Height();
// midle or end, first line start position,end line end position
textOffsetDownY = caretInfo.caretOffsetLine.GetY() + caretInfo.caretHeightLine - textOffsetY;
if (cursorNotAtLineStart || caretPosition_ == 0) {
textOffset = Offset(caretInfo.caretOffsetLine.GetX() - textOffsetX, textOffsetDownY);
} else {
textOffsetDownY += lineHeightDis;
textOffset = Offset(caretOffsetOverlay.GetX() - textOffsetX, textOffsetDownY);
}
caretPositionEnd = paragraphs_.GetIndex(textOffset);
return caretPositionEnd;
}
int32_t RichEditorPattern::CalcLineBeginPosition()
{
float caretHeight = 0.0f;
OffsetF caretOffset = CalcCursorOffsetByPosition(caretPosition_, caretHeight, false, false);
auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
auto textOffsetY = caretOffset.GetY() - textPaintOffset.GetY() + minDet / 2.0;
auto textOffsetY = caretOffset.GetY() - textPaintOffset.GetY() + (minDet / 2.0);
Offset textOffset = { 0, textOffsetY };
auto newPos = paragraphs_.GetIndex(textOffset);
return newPos;
@ -8919,26 +8972,26 @@ float RichEditorPattern::GetTextThemeFontSize()
int32_t RichEditorPattern::CalcLineEndPosition()
{
float caretHeightUp = 0.0f;
float caretHeightDown = 0.0f;
float caretHeightLine = 0.0f;
CaretOffsetInfo caretInfo;
int32_t realCaretOffsetY = 0;
int32_t realLastClickOffsetY = 0;
OffsetF caretOffsetUp = CalcCursorOffsetByPosition(caretPosition_, caretHeightUp, false, false);
OffsetF caretOffsetDown = CalcCursorOffsetByPosition(caretPosition_, caretHeightDown, true, false);
OffsetF caretOffsetLine = CalcCursorOffsetByPosition(caretPosition_, caretHeightLine);
caretInfo = GetCaretOffsetInfoByPosition();
if (NearEqual(richTextRect_.GetY(), contentRect_.GetY())) {
realLastClickOffsetY = lastClickOffset_.GetY();
realCaretOffsetY = caretOffsetDown.GetY();
realCaretOffsetY = caretInfo.caretOffsetDown.GetY();
} else {
auto scrollOffset = caretOffsetDown.GetY() - caretOffsetUp.GetY() + caretOffsetLine.GetY();
auto scrollOffset =
caretInfo.caretOffsetDown.GetY() - caretInfo.caretOffsetUp.GetY() + caretInfo.caretOffsetLine.GetY();
realLastClickOffsetY = lastClickOffset_.GetY() + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
realCaretOffsetY = scrollOffset + std::abs(richTextRect_.GetY()) + contentRect_.GetY();
}
auto textPaintOffset = contentRect_.GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
Offset textOffset;
float textWidth = richTextRect_.Width();
float textPaintOffsetY = contentRect_.GetY() - std::min(baselineOffset_, 0.0f) - minDet / 2.0;
auto rectLineInfo = CalcLineInfoByPosition();
float textWidth = richTextRect_.Width() + rectLineInfo.GetX();
float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
float textOffsetClickY = realLastClickOffsetY - textPaintOffsetY;
float textOffsetDownY = realCaretOffsetY - textPaintOffsetY;
if (lastClickOffset_.NonNegative()) {
@ -8963,7 +9016,7 @@ bool RichEditorPattern::CursorMoveLineBegin()
OffsetF caretOffsetDown = CalcCursorOffsetByPosition(caretPosition_, caretHeightDown, true, false);
auto textPaintOffset = GetTextRect().GetOffset() - OffsetF(0.0, std::min(baselineOffset_, 0.0f));
auto minDet = paragraphs_.minParagraphFontSize.value_or(GetTextThemeFontSize());
float textPaintOffsetY = textPaintOffset.GetY() - minDet / 2.0;
float textPaintOffsetY = textPaintOffset.GetY() - (minDet / 2.0);
if (lastClickOffset_.NonNegative()) {
textOffset = { 0, lastClickOffset_.GetY() - textPaintOffsetY };
} else {
@ -9087,7 +9140,7 @@ int32_t RichEditorPattern::HandleSelectPosition(bool isForward)
} else {
float selectEndHeight = 0.0f;
OffsetF selectEndOffset = CalcCursorOffsetByPosition(textSelector_.GetEnd(), selectEndHeight);
careOffsetY = caretOffset.GetY() - GetTextRect().GetY() + caretHeight + minDet / 2.0;
careOffsetY = caretOffset.GetY() - GetTextRect().GetY() + caretHeight + (minDet / 2.0);
newPos = paragraphs_.GetIndex(Offset(caretOffset.GetX() - GetTextRect().GetX(), careOffsetY), true);
OffsetF newCaretOffset = CalcCursorOffsetByPosition(newPos, newCaretHeight);
if (!textSelector_.SelectNothing() && textSelector_.GetTextStart() == caretPosition_ &&

View File

@ -98,6 +98,17 @@ const std::map<std::pair<HandleType, SelectorAdjustPolicy>, MoveDirection> SELEC
{{ HandleType::SECOND, SelectorAdjustPolicy::INCLUDE }, MoveDirection::FORWARD },
{{ HandleType::SECOND, SelectorAdjustPolicy::EXCLUDE }, MoveDirection::BACKWARD }
};
struct CaretOffsetInfo {
// caret front offset info
OffsetF caretOffsetUp;
// caret end offset info
OffsetF caretOffsetDown;
// caret position offset info
OffsetF caretOffsetLine;
float caretHeightUp = 0.0f;
float caretHeightDown = 0.0f;
float caretHeightLine = 0.0f;
};
class RichEditorPattern
: public TextPattern, public ScrollablePattern, public TextInputClient, public Magnifier, public SpanWatcher {
@ -378,8 +389,11 @@ public:
bool CursorMoveToParagraphEnd();
bool CursorMoveHome();
bool CursorMoveEnd();
float CalcLineHeightByPosition(int32_t position);
int32_t CalcMoveUpPos(OffsetF& caretOffsetUp, OffsetF& caretOffsetDown);
void CalcLineSidesIndexByPosition(int32_t& startIndex, int32_t& endIndex);
RectF CalcLineInfoByPosition();
CaretOffsetInfo GetCaretOffsetInfoByPosition();
int32_t CalcMoveUpPos(float& leadingMarginOffset);
int32_t CalcMoveDownPos(float& leadingMarginOffset);
int32_t CalcLineBeginPosition();
float GetTextThemeFontSize();
int32_t CalcLineEndPosition();

View File

@ -447,6 +447,7 @@ HWTEST_F(RichEditorEditTestNg, TestRichEditorCalcMoveUpPos001, TestSize.Level1)
/**
* @tc.steps: step1. declare and init variables.
*/
float lmSizeOffset = 0.0f;
ASSERT_NE(richEditorNode_, nullptr);
auto richEditorPattern = richEditorNode_->GetPattern<RichEditorPattern>();
ASSERT_NE(richEditorPattern, nullptr);
@ -456,19 +457,16 @@ HWTEST_F(RichEditorEditTestNg, TestRichEditorCalcMoveUpPos001, TestSize.Level1)
/**
* @tc.steps: step2. change parameter and call function.
*/
OffsetF caretOffsetUp(-5.0f, 5.0f);
OffsetF caretOffsetDown(5.0f, 10.0f);
richEditorPattern->CalcMoveUpPos(caretOffsetUp, caretOffsetDown);
EXPECT_NE(caretOffsetUp.x_, -5.0f);
EXPECT_NE(caretOffsetDown.x_, 5.0f);
richEditorPattern->CalcMoveUpPos(lmSizeOffset);
EXPECT_EQ(lmSizeOffset, 0.0f);
}
/**
* @tc.name: TestRichEditorCalcLineHeightByPosition001
* @tc.desc: test CalcLineHeightByPosition
* @tc.name: TestRichEditorCalcLineInfoByPosition001
* @tc.desc: test CalcLineInfoByPosition
* @tc.type: FUNC
*/
HWTEST_F(RichEditorEditTestNg, TestRichEditorCalcLineHeightByPosition001, TestSize.Level1)
HWTEST_F(RichEditorEditTestNg, TestRichEditorCalcLineInfoByPosition001, TestSize.Level1)
{
/**
* @tc.steps: step1. declare and init variables.
@ -479,8 +477,8 @@ HWTEST_F(RichEditorEditTestNg, TestRichEditorCalcLineHeightByPosition001, TestSi
richEditorPattern->CreateNodePaintMethod();
EXPECT_NE(richEditorPattern->contentMod_, nullptr);
EXPECT_NE(richEditorPattern->overlayMod_, nullptr);
auto ret = richEditorPattern->CalcLineHeightByPosition(10);
EXPECT_EQ(ret, 0.0f);
auto ret = richEditorPattern->CalcLineInfoByPosition();
EXPECT_EQ(ret.Height(), 0.0f);
}
/**