Fix bug which caused repeated characters in a QML Text
[profile/ivi/qtbase.git] / src / gui / text / qtextlayout.cpp
index cb5ba0e..f9bfcbf 100644 (file)
@@ -7,29 +7,29 @@
 ** This file is part of the QtGui module of the Qt Toolkit.
 **
 ** $QT_BEGIN_LICENSE:LGPL$
-** No Commercial Usage
-** This file contains pre-release code and may not be distributed.
-** You may use this file in accordance with the terms and conditions
-** contained in the Technology Preview License Agreement accompanying
-** this package.
-**
 ** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 2.1 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL included in the
-** packaging of this file.  Please review the following information to
-** ensure the GNU Lesser General Public License version 2.1 requirements
-** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
 **
 ** In addition, as a special exception, Nokia gives you certain additional
-** rights.  These rights are described in the Nokia Qt LGPL Exception
+** rights. These rights are described in the Nokia Qt LGPL Exception
 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
 **
-** If you have questions regarding the use of this file, please contact
-** Nokia at qt-info@nokia.com.
-**
-**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
 **
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
 **
 **
 **
@@ -52,8 +52,8 @@
 #include "qtextformat_p.h"
 #include "qstyleoption.h"
 #include "qpainterpath.h"
-#include "qglyphs.h"
-#include "qglyphs_p.h"
+#include "qglyphrun.h"
+#include "qglyphrun_p.h"
 #include "qrawfont.h"
 #include "qrawfont_p.h"
 #include <limits.h>
@@ -579,27 +579,27 @@ bool QTextLayout::cacheEnabled() const
 }
 
 /*!
-    Set the visual cursor movement style. If the QTextLayout is backed by
-    a document, you can ignore this and use the option in QTextDocument,
-    this option is for widgets like QLineEdit or custom widgets without
-    a QTextDocument. Default value is QTextCursor::Logical.
+    Sets the visual cursor movement style to the given \a style. If the
+    QTextLayout is backed by a document, you can ignore this and use the option
+    in QTextDocument, this option is for widgets like QLineEdit or custom
+    widgets without a QTextDocument. Default value is QTextCursor::Logical.
 
-    \sa setCursorMoveStyle()
+    \sa cursorMoveStyle()
 */
-void QTextLayout::setCursorMoveStyle(QTextCursor::MoveStyle style)
+void QTextLayout::setCursorMoveStyle(Qt::CursorMoveStyle style)
 {
-    d->visualMovement = style == QTextCursor::Visual ? true : false;
+    d->visualMovement = style == Qt::VisualMoveStyle ? true : false;
 }
 
 /*!
     The cursor movement style of this QTextLayout. The default is
-    QTextCursor::Logical.
+    Qt::LogicalMoveStyle.
 
     \sa setCursorMoveStyle()
 */
-QTextCursor::MoveStyle QTextLayout::cursorMoveStyle() const
+Qt::CursorMoveStyle QTextLayout::cursorMoveStyle() const
 {
-    return d->visualMovement ? QTextCursor::Visual : QTextCursor::Logical;
+    return d->visualMovement ? Qt::VisualMoveStyle : Qt::LogicalMoveStyle;
 }
 
 /*!
@@ -994,14 +994,23 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
 
     \since 4.8
 
-    \sa draw(), QPainter::drawGlyphs()
+    \sa draw(), QPainter::drawGlyphRun()
 */
 #if !defined(QT_NO_RAWFONT)
-QList<QGlyphs> QTextLayout::glyphs() const
-{
-    QList<QGlyphs> glyphs;
-    for (int i=0; i<d->lines.size(); ++i)
-        glyphs += QTextLine(i, d).glyphs(-1, -1);
+QList<QGlyphRun> QTextLayout::glyphRuns(int from, int length) const
+{    
+    if (from < 0)
+        from = 0;
+    if (length < 0)
+        length = text().length();
+
+    QList<QGlyphRun> glyphs;
+    for (int i=0; i<d->lines.size(); ++i) {
+        if (d->lines[i].from > from + length)
+            break;
+        else if (d->lines[i].from + d->lines[i].length >= from)
+            glyphs += QTextLine(i, d).glyphRuns(from, length);
+    }
 
     return glyphs;
 }
@@ -1211,8 +1220,6 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
         d->itemize();
 
     QPointF position = pos + d->position;
-    QFixed pos_x = QFixed::fromReal(position.x());
-    QFixed pos_y = QFixed::fromReal(position.y());
 
     cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
     int line = d->lineNumberForTextPosition(cursorPosition);
@@ -2086,24 +2093,31 @@ namespace {
 }
 
 /*!
-    \internal
+    Returns the glyph indexes and positions for all glyphs in this QTextLine for characters
+    in the range defined by \a from and \a length. The \a from index is relative to the beginning
+    of the text in the containing QTextLayout, and the range must be within the range of QTextLine
+    as given by functions textStart() and textLength().
 
-    Returns the glyph indexes and positions for all glyphs in this QTextLine which reside in
-    QScriptItems that overlap with the range defined by \a from and \a length. The arguments
-    specify characters, relative to the text in the layout. Note that it is not possible to
-    use this function to retrieve a subset of the glyphs in a QScriptItem.
+    If \a from is negative, it will default to textStart(), and if \a length is negative it will
+    default to the return value of textLength().
 
-    \since 4.8
+    \since 5.0
 
-    \sa QTextLayout::glyphs()
+    \sa QTextLayout::glyphRuns()
 */
 #if !defined(QT_NO_RAWFONT)
-QList<QGlyphs> QTextLine::glyphs(int from, int length) const
+QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 {
     const QScriptLine &line = eng->lines[i];
 
     if (line.length == 0)
-        return QList<QGlyphs>();
+        return QList<QGlyphRun>();
+
+    if (from < 0)
+        from = textStart();
+
+    if (length < 0)
+        length = textLength();
 
     QHash<QFontEngine *, GlyphInfo> glyphLayoutHash;
 
@@ -2116,8 +2130,9 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
 
         QPointF pos(iterator.x.toReal(), y);
         if (from >= 0 && length >= 0 &&
-            (from >= si.position + eng->length(&si) || from + length <= si.position))
+            (from >= si.position + eng->length(&si) || from + length <= si.position)) {
             continue;
+        }
 
         QFont font = eng->font(si);
 
@@ -2128,11 +2143,42 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
             flags |= QTextItem::Underline;
         if (font.strikeOut())
             flags |= QTextItem::StrikeOut;
-        if (si.analysis.bidiLevel % 2)
+
+        bool rtl = false;
+        if (si.analysis.bidiLevel % 2) {
             flags |= QTextItem::RightToLeft;
+            rtl = true;
+        }
+
+        int relativeFrom = qMax(iterator.itemStart, from) - si.position;
+        int relativeTo = qMin(iterator.itemEnd - 1, from + length - 1) - si.position;
+
+        unsigned short *logClusters = eng->logClusters(&si);
+        int glyphsStart = logClusters[relativeFrom];
+        int glyphsEnd = (relativeTo == eng->length(&si))
+                         ? si.num_glyphs - 1
+                         : logClusters[relativeTo];
+
+        QGlyphLayout glyphLayout = eng->shapedGlyphs(&si);
+
+        // Calculate new x position of glyph layout for a subset. This becomes somewhat complex
+        // when we're breaking a RTL script item, since the expected position passed into
+        // getGlyphPositions() is the left-most edge of the left-most glyph in an RTL run.
+        if (relativeFrom != (iterator.itemStart - si.position) && !rtl) {
+            for (int i=0; i<glyphsStart; ++i) {
+                QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+                pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
+                               glyphLayout.advances_y[i].toReal());
+            }
+        } else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) {
+            for (int i=glyphLayout.numGlyphs - 1; i>glyphsEnd; --i) {
+                QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+                pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
+                               glyphLayout.advances_y[i].toReal());
+            }
+        }
 
-        QGlyphLayout glyphLayout = eng->shapedGlyphs(&si).mid(iterator.glyphsStart,
-                                                              iterator.glyphsEnd - iterator.glyphsStart);
+        glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1);
 
         if (glyphLayout.numGlyphs > 0) {
             QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
@@ -2149,9 +2195,10 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
                     glyphLayoutHash.insertMulti(multiFontEngine->engine(which),
                                                 GlyphInfo(subLayout, pos, flags));
-                    for (int i = 0; i < subLayout.numGlyphs; i++)
+                    for (int i = 0; i < subLayout.numGlyphs; i++) {
                         pos += QPointF(subLayout.advances_x[i].toReal(),
                                        subLayout.advances_y[i].toReal());
+                    }
 
                     start = end;
                     which = e;
@@ -2168,7 +2215,7 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
         }
     }
 
-    QHash<QPair<QFontEngine *, int>, QGlyphs> glyphsHash;
+    QHash<QPair<QFontEngine *, int>, QGlyphRun> glyphsHash;
 
     QList<QFontEngine *> keys = glyphLayoutHash.uniqueKeys();
     for (int i=0; i<keys.size(); ++i) {
@@ -2225,20 +2272,30 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
                 positions.append(positionsArray.at(i).toPointF() + pos);
             }
 
-            QGlyphs glyphIndexes;
+            QGlyphRun glyphIndexes;
             glyphIndexes.setGlyphIndexes(glyphs);
             glyphIndexes.setPositions(positions);
 
             glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline));
             glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline));
             glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
-            glyphIndexes.setFont(font);
+            glyphIndexes.setRawFont(font);
 
             QPair<QFontEngine *, int> key(fontEngine, int(flags));
-            if (!glyphsHash.contains(key))
+            if (!glyphsHash.contains(key)) {
                 glyphsHash.insert(key, glyphIndexes);
-            else
-                glyphsHash[key] += glyphIndexes;
+            } else {
+                QGlyphRun &glyphRun = glyphsHash[key];
+
+                QVector<quint32> indexes = glyphRun.glyphIndexes();
+                QVector<QPointF> positions = glyphRun.positions();
+
+                indexes += glyphIndexes.glyphIndexes();
+                positions += glyphIndexes.positions();
+
+                glyphRun.setGlyphIndexes(indexes);
+                glyphRun.setPositions(positions);
+            }
         }
     }
 
@@ -2503,8 +2560,9 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
         pos = 0;
 
     int glyph_pos = pos == l ? si->num_glyphs : logClusters[pos];
-    if (edge == Trailing) {
+    if (edge == Trailing && glyph_pos < si->num_glyphs) {
         // trailing edge is leading edge of next cluster
+        glyph_pos++;
         while (glyph_pos < si->num_glyphs && !glyphs.attributes[glyph_pos].clusterStart)
             glyph_pos++;
     }
@@ -2561,8 +2619,8 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
     } else {
         bool rtl = eng->isRightToLeft();
         bool visual = eng->visualCursorMovement();
+        int end = qMin(lineEnd, si->position + l) - si->position;
         if (reverse) {
-            int end = qMin(lineEnd, si->position + l) - si->position;
             int glyph_end = end == l ? si->num_glyphs : logClusters[end];
             int glyph_start = glyph_pos;
             if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
@@ -2578,7 +2636,7 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
             for (int i = glyph_start; i <= glyph_end; i++)
                 x += glyphs.effectiveAdvance(i);
         }
-        x += eng->offsetInLigature(si, pos, line.length, glyph_pos);
+        x += eng->offsetInLigature(si, pos, end, glyph_pos);
     }
 
     *cursorPos = pos + si->position;
@@ -2693,6 +2751,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
             }
 
             int glyph_pos = -1;
+            QFixed edge;
             // has to be inside run
             if (cpos == QTextLine::CursorOnCharacter) {
                 if (si.analysis.bidiLevel % 2) {
@@ -2703,6 +2762,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                             if (pos < x)
                                 break;
                             glyph_pos = gs;
+                            edge = pos;
                             break;
                         }
                         pos -= glyphs.effectiveAdvance(gs);
@@ -2715,6 +2775,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                             if (pos > x)
                                 break;
                             glyph_pos = gs;
+                            edge = pos;
                         }
                         pos += glyphs.effectiveAdvance(gs);
                         ++gs;
@@ -2728,6 +2789,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                         while (gs <= ge) {
                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
                                 glyph_pos = gs;
+                                edge = pos;
                                 dist = qAbs(x-pos);
                             }
                             pos -= glyphs.effectiveAdvance(gs);
@@ -2737,6 +2799,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                         while (ge >= gs) {
                             if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
                                 glyph_pos = ge;
+                                edge = pos;
                                 dist = qAbs(x-pos);
                             }
                             pos += glyphs.effectiveAdvance(ge);
@@ -2748,6 +2811,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                         while (gs <= ge) {
                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
                                 glyph_pos = gs;
+                                edge = pos;
                                 dist = qAbs(x-pos);
                             }
                             pos += glyphs.effectiveAdvance(gs);
@@ -2759,6 +2823,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                             pos += glyphs.effectiveAdvance(gs);
                             if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
                                 glyph_pos = gs;
+                                edge = pos;
                                 dist = qAbs(x-pos);
                             }
                             ++gs;
@@ -2775,16 +2840,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
                         if (rtl && nchars > 0)
                             return insertionPoints[lastLine ? nchars : nchars - 1];
                     }
-                    return si.position + end;
+                    return eng->positionInLigature(&si, end, x, pos, -1,
+                                                   cpos == QTextLine::CursorOnCharacter);
                 }
             }
             Q_ASSERT(glyph_pos != -1);
-            int j;
-            for (j = 0; j < eng->length(item); ++j)
-                if (logClusters[j] == glyph_pos)
-                    break;
-//             qDebug("at pos %d (in run: %d)", si.position + j, j);
-            return si.position + j;
+            return eng->positionInLigature(&si, end, x, edge, glyph_pos,
+                                           cpos == QTextLine::CursorOnCharacter);
         }
     }
     // right of last item