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

View File

@ -674,7 +674,10 @@ int QTextLayout::nextCursorPosition(int oldPos, CursorMode mode) const
int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
{ {
const QCharAttributes *attributes = d->attributes(); 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; return oldPos;
if (mode == SkipCharacters) { if (mode == SkipCharacters) {

View File

@ -71,6 +71,8 @@ private slots:
void bidiCursorMovement(); void bidiCursorMovement();
void bidiCursorLogicalMovement_data(); void bidiCursorLogicalMovement_data();
void bidiCursorLogicalMovement(); void bidiCursorLogicalMovement();
void bidiInvalidCursorNoMovement_data();
void bidiInvalidCursorNoMovement();
}; };
tst_QComplexText::tst_QComplexText() tst_QComplexText::tst_QComplexText()
@ -272,6 +274,37 @@ void tst_QComplexText::bidiCursorLogicalMovement()
} while (moved); } 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() void tst_QComplexText::bidiCursor_PDF()
{ {
QString str = QString::fromUtf8("\342\200\252hello\342\200\254"); QString str = QString::fromUtf8("\342\200\252hello\342\200\254");