From ab3efc09b3a57e1c9e97470368040c5f75ff560b Mon Sep 17 00:00:00 2001 From: Samuel Gaist Date: Thu, 27 Nov 2014 09:20:12 +0100 Subject: [PATCH] QTextDocument: Don't use QRegExp for string search overloads Currently both find function with QString input uses QRegExp under the hood. This patch aims to use only QString search facility to allow the proper disabling of QRegExp Change-Id: I3525fd0e969eced635f3d98feb54eb6a05950d8f Reviewed-by: Konstantin Ritt --- src/gui/text/qtextdocument.cpp | 76 ++++++++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index 3a11266e0a..2eb6f232fb 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -1244,6 +1244,39 @@ void QTextDocument::setHtml(const QString &html) \sa metaInformation(), setMetaInformation() */ +static bool findInBlock(const QTextBlock &block, const QString &expression, int offset, + QTextDocument::FindFlags options, QTextCursor *cursor) +{ + QString text = block.text(); + text.replace(QChar::Nbsp, QLatin1Char(' ')); + Qt::CaseSensitivity sensitivity = options & QTextDocument::FindCaseSensitively ? Qt::CaseSensitive : Qt::CaseInsensitive; + int idx = -1; + + while (offset >= 0 && offset <= text.length()) { + idx = (options & QTextDocument::FindBackward) ? + text.lastIndexOf(expression, offset, sensitivity) : text.indexOf(expression, offset, sensitivity); + if (idx == -1) + return false; + + if (options & QTextDocument::FindWholeWords) { + const int start = idx; + const int end = start + expression.length(); + if ((start != 0 && text.at(start - 1).isLetterOrNumber()) + || (end != text.length() && text.at(end).isLetterOrNumber())) { + //if this is not a whole word, continue the search in the string + offset = (options & QTextDocument::FindBackward) ? idx-1 : end+1; + idx = -1; + continue; + } + } + //we have a hit, return the cursor for that. + *cursor = QTextCursor(block.docHandle(), block.position() + idx); + cursor->setPosition(cursor->position() + expression.length(), QTextCursor::KeepAnchor); + return true; + } + return false; +} + /*! \fn QTextCursor QTextDocument::find(const QString &subString, int position, FindFlags options) const @@ -1262,11 +1295,41 @@ void QTextDocument::setHtml(const QString &html) */ QTextCursor QTextDocument::find(const QString &subString, int from, FindFlags options) const { - QRegExp expr(subString); - expr.setPatternSyntax(QRegExp::FixedString); - expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); + Q_D(const QTextDocument); - return find(expr, from, options); + if (subString.isEmpty()) + return QTextCursor(); + + int pos = from; + //the cursor is positioned between characters, so for a backward search + //do not include the character given in the position. + if (options & FindBackward) { + --pos ; + if (pos < subString.size()) + return QTextCursor(); + } + + QTextCursor cursor; + QTextBlock block = d->blocksFind(pos); + int blockOffset = pos - block.position(); + + if (!(options & FindBackward)) { + while (block.isValid()) { + if (findInBlock(block, subString, blockOffset, options, &cursor)) + return cursor; + block = block.next(); + blockOffset = 0; + } + } else { + while (block.isValid()) { + if (findInBlock(block, subString, blockOffset, options, &cursor)) + return cursor; + block = block.previous(); + blockOffset = block.length() - 2; + } + } + + return QTextCursor(); } /*! @@ -1293,11 +1356,8 @@ QTextCursor QTextDocument::find(const QString &subString, const QTextCursor &cur else pos = cursor.selectionEnd(); } - QRegExp expr(subString); - expr.setPatternSyntax(QRegExp::FixedString); - expr.setCaseSensitivity((options & QTextDocument::FindCaseSensitively) ? Qt::CaseSensitive : Qt::CaseInsensitive); - return find(expr, pos, options); + return find(subString, pos, options); }