QTextLayout: Fix cursor movement from invalid position

Actually guarantee cursor doesn't move in this case for both logical
and visual modes (just what the documentation says we already do ;)

Change-Id: Iabdca7aa1d205672386a0095e3487e585611cdb5
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
This commit is contained in:
Konstantin Ritt 2014-04-04 07:31:24 +03:00 committed by The Qt Project
parent 47056e78d3
commit 330f6e3598
3 changed files with 46 additions and 7 deletions

View File

@ -3138,11 +3138,12 @@ int QTextEngine::positionInLigature(const QScriptItem *si, int end,
int QTextEngine::previousLogicalPosition(int oldPos) const
{
const QCharAttributes *attrs = attributes();
if (!attrs || oldPos < 0)
int len = block.isValid() ? block.length() - 1
: layoutData->string.length();
Q_ASSERT(len <= layoutData->string.length());
if (!attrs || oldPos <= 0 || oldPos > len)
return oldPos;
if (oldPos <= 0)
return 0;
oldPos--;
while (oldPos && !attrs[oldPos].graphemeBoundary)
oldPos--;
@ -3224,8 +3225,7 @@ int QTextEngine::beginningOfLine(int lineNum)
int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op)
{
if (!layoutData)
itemize();
itemize();
bool moveRight = (op == QTextCursor::Right);
bool alignRight = isRightToLeft();
@ -3233,7 +3233,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation
return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos);
int lineNum = lineNumberForTextPosition(pos);
Q_ASSERT(lineNum >= 0);
if (lineNum < 0)
return pos;
QVector<int> insertionPoints;
insertionPointsForLine(lineNum, insertionPoints);
@ -3256,6 +3257,8 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation
if (lineNum > 0)
return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);
}
break;
}
return pos;

View File

@ -674,7 +674,10 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
{
const QCharAttributes *attributes = d->attributes();
if (!attributes || oldPos <= 0 || oldPos > d->layoutData->string.length())
int len = d->block.isValid() ? d->block.length() - 1
: d->layoutData->string.length();
Q_ASSERT(len <= d->layoutData->string.length());
if (!attributes || oldPos <= 0 || oldPos > len)
return oldPos;
if (mode == SkipCharacters) {

View File

@ -71,6 +71,8 @@ private slots:
void bidiCursorMovement();
void bidiCursorLogicalMovement_data();
void bidiCursorLogicalMovement();
void bidiInvalidCursorNoMovement_data();
void bidiInvalidCursorNoMovement();
};
tst_QComplexText::tst_QComplexText()
@ -272,6 +274,37 @@ void tst_QComplexText::bidiCursorLogicalMovement()
} while (moved);
}
void tst_QComplexText::bidiInvalidCursorNoMovement_data()
{
bidiCursorMovement_data();
}
void tst_QComplexText::bidiInvalidCursorNoMovement()
{
QFETCH(QString, logical);
QFETCH(int, basicDir);
QTextLayout layout(logical);
QTextOption option = layout.textOption();
option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft);
layout.setTextOption(option);
// visual
QCOMPARE(layout.rightCursorPosition(-1000), -1000);
QCOMPARE(layout.rightCursorPosition(1000), 1000);
QCOMPARE(layout.leftCursorPosition(-1000), -1000);
QCOMPARE(layout.leftCursorPosition(1000), 1000);
// logical
QCOMPARE(layout.nextCursorPosition(-1000), -1000);
QCOMPARE(layout.nextCursorPosition(1000), 1000);
QCOMPARE(layout.previousCursorPosition(-1000), -1000);
QCOMPARE(layout.previousCursorPosition(1000), 1000);
}
void tst_QComplexText::bidiCursor_PDF()
{
QString str = QString::fromUtf8("\342\200\252hello\342\200\254");