Enablers for using QGlyphRun in SceneGraph
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
Wed, 1 Jun 2011 13:33:38 +0000 (15:33 +0200)
committerQt by Nokia <qt-info@nokia.com>
Fri, 19 Aug 2011 08:18:04 +0000 (10:18 +0200)
Several required fixes and changes to fix problems that arose
when porting SceneGraph's QSGTextInput and QSGTextEdit to
use QSGTextNode, especially related to having selections
on the text.

Also fixes crashes with the threaded renderer on Mac OS X
when using the TextEdit or TextInput elements.

Task-number: QTBUG-18019, QTBUG-20017
Change-Id: I67f24465352daa1d2cb12b6d2f378feb676c9804
Reviewed-on: http://codereview.qt.nokia.com/2864
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Reviewed-by: Jiang Jiang <jiang.jiang@nokia.com>
src/gui/text/qglyphrun.cpp
src/gui/text/qglyphrun.h
src/gui/text/qglyphrun_p.h
src/gui/text/qtextcontrol.cpp
src/gui/text/qtextcontrol_p.h
src/gui/text/qtextlayout.cpp
src/gui/text/qtextobject.cpp
src/gui/text/qtextobject.h
src/gui/widgets/qlinecontrol.cpp
src/gui/widgets/qlinecontrol_p.h

index cc82552..be9c058 100644 (file)
@@ -45,6 +45,7 @@
 
 #include "qglyphrun.h"
 #include "qglyphrun_p.h"
 
 #include "qglyphrun.h"
 #include "qglyphrun_p.h"
+#include <qdebug.h>
 
 QT_BEGIN_NAMESPACE
 
 
 QT_BEGIN_NAMESPACE
 
@@ -343,12 +344,44 @@ void QGlyphRun::setStrikeOut(bool strikeOut)
 }
 
 /*!
 }
 
 /*!
-  Returns the smallest rectangle that contains all glyphs in this QGlyphRun.
+  Sets the bounding rect of the glyphs in this QGlyphRun to be \a boundingRect. This rectangle
+  will be returned by boundingRect() unless it is empty, in which case the bounding rectangle of the
+  glyphs in the glyph run will be returned instead.
+
+  \note Unless you are implementing text shaping, you should not have to use this function.
+  It is used specifically when the QGlyphRun should represent an area which is smaller than the
+  area of the glyphs it contains. This could happen e.g. if the glyph run is retrieved by calling
+  QTextLayout::glyphRuns() and the specified range only includes part of a ligature (where two or
+  more characters are combined to a single glyph.) When this is the case, the bounding rect should
+  only include the appropriate part of the ligature glyph, based on a calculation of the average
+  width of the characters in the ligature.
+
+  In order to support such a case (an example is selections which should be drawn with a different
+  color than the main text color), it is necessary to clip the painting mechanism to the rectangle
+  returned from boundingRect() to avoid drawing the entire ligature glyph.
+
+  \sa boundingRect()
+
+  \since 5.0
+*/
+void QGlyphRun::setBoundingRect(const QRectF &boundingRect)
+{
+    detach();
+    d->boundingRect = boundingRect;
+}
+
+/*!
+  Returns the smallest rectangle that contains all glyphs in this QGlyphRun. If a bounding rect
+  has been set using setBoundingRect(), then this will be returned. Otherwise the bounding rect
+  will be calculated based on the font metrics of the glyphs in the glyph run.
 
   \since 5.0
 */
 QRectF QGlyphRun::boundingRect() const
 {
 
   \since 5.0
 */
 QRectF QGlyphRun::boundingRect() const
 {
+    if (!d->boundingRect.isEmpty())
+        return d->boundingRect;
+
     qreal minX, minY, maxX, maxY;
 
     for (int i=0; i<qMin(d->glyphPositions.size(), d->glyphIndexes.size()); ++i) {
     qreal minX, minY, maxX, maxY;
 
     for (int i=0; i<qMin(d->glyphPositions.size(), d->glyphIndexes.size()); ++i) {
@@ -371,6 +404,16 @@ QRectF QGlyphRun::boundingRect() const
     return QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
 }
 
     return QRectF(QPointF(minX, minY), QPointF(maxX, maxY));
 }
 
+/*!
+  Returns true if the QGlyphRun does not contain any glyphs.
+
+  \since 5.0
+*/
+bool QGlyphRun::isEmpty() const
+{
+    return d->glyphIndexes.isEmpty();
+}
+
 QT_END_NAMESPACE
 
 #endif // QT_NO_RAWFONT
 QT_END_NAMESPACE
 
 #endif // QT_NO_RAWFONT
index b4f02f0..da88bc7 100644 (file)
@@ -91,8 +91,11 @@ public:
     void setStrikeOut(bool strikeOut);
     bool strikeOut() const;
 
     void setStrikeOut(bool strikeOut);
     bool strikeOut() const;
 
+    void setBoundingRect(const QRectF &boundingRect);
     QRectF boundingRect() const;
 
     QRectF boundingRect() const;
 
+    bool isEmpty() const;
+
 private:
     friend class QGlyphRunPrivate;
     friend class QTextLine;
 private:
     friend class QGlyphRunPrivate;
     friend class QTextLine;
index a7745e6..b632678 100644 (file)
@@ -83,6 +83,7 @@ public:
       , glyphIndexes(other.glyphIndexes)
       , glyphPositions(other.glyphPositions)
       , rawFont(other.rawFont)
       , glyphIndexes(other.glyphIndexes)
       , glyphPositions(other.glyphPositions)
       , rawFont(other.rawFont)
+      , boundingRect(other.boundingRect)
       , overline(other.overline)
       , underline(other.underline)
       , strikeOut(other.strikeOut)
       , overline(other.overline)
       , underline(other.underline)
       , strikeOut(other.strikeOut)
@@ -96,6 +97,7 @@ public:
     QVector<quint32> glyphIndexes;
     QVector<QPointF> glyphPositions;
     QRawFont rawFont;
     QVector<quint32> glyphIndexes;
     QVector<QPointF> glyphPositions;
     QRawFont rawFont;
+    QRectF boundingRect;
 
     uint overline  : 1;
     uint underline : 1;
 
     uint overline  : 1;
     uint underline : 1;
index 424d197..c29379e 100644 (file)
@@ -409,6 +409,8 @@ void QTextControlPrivate::init(Qt::TextFormat format, const QString &text, QText
 
     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
     q->setCursorWidth(-1);
 
     doc->setUndoRedoEnabled(interactionFlags & Qt::TextEditable);
     q->setCursorWidth(-1);
+
+    QObject::connect(q, SIGNAL(updateCursorRequest(QRectF)), q, SIGNAL(updateRequest(QRectF)));
 }
 
 void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
 }
 
 void QTextControlPrivate::setContent(Qt::TextFormat format, const QString &text, QTextDocument *document)
@@ -547,7 +549,7 @@ void QTextControlPrivate::setCursorPosition(int pos, QTextCursor::MoveMode mode)
 void QTextControlPrivate::repaintCursor()
 {
     Q_Q(QTextControl);
 void QTextControlPrivate::repaintCursor()
 {
     Q_Q(QTextControl);
-    emit q->updateRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
+    emit q->updateCursorRequest(cursorRectPlusUnicodeDirectionMarkers(cursor));
 }
 
 void QTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
 }
 
 void QTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelection)
@@ -565,9 +567,16 @@ void QTextControlPrivate::repaintOldAndNewSelection(const QTextCursor &oldSelect
         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
         emit q->updateRequest(q->selectionRect(differenceSelection));
     } else {
         differenceSelection.setPosition(cursor.position(), QTextCursor::KeepAnchor);
         emit q->updateRequest(q->selectionRect(differenceSelection));
     } else {
-        if (!oldSelection.isNull())
-            emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
-        emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
+        if (!oldSelection.hasSelection() && !cursor.hasSelection()) {
+            if (!oldSelection.isNull())
+                emit q->updateCursorRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
+            emit q->updateCursorRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
+
+        } else {
+            if (!oldSelection.isNull())
+                emit q->updateRequest(q->selectionRect(oldSelection) | cursorRectPlusUnicodeDirectionMarkers(oldSelection));
+            emit q->updateRequest(q->selectionRect() | cursorRectPlusUnicodeDirectionMarkers(cursor));
+        }
     }
 }
 
     }
 }
 
@@ -2959,6 +2968,12 @@ void QTextControl::setPalette(const QPalette &pal)
     d->palette = pal;
 }
 
     d->palette = pal;
 }
 
+bool QTextControl::cursorOn() const
+{
+    Q_D(const QTextControl);
+    return d->cursorOn;
+}
+
 QAbstractTextDocumentLayout::PaintContext QTextControl::getPaintContext(QWidget *widget) const
 {
     Q_D(const QTextControl);
 QAbstractTextDocumentLayout::PaintContext QTextControl::getPaintContext(QWidget *widget) const
 {
     Q_D(const QTextControl);
@@ -3146,6 +3161,7 @@ void QTextEditMimeData::setup() const
     fragment = QTextDocumentFragment();
 }
 
     fragment = QTextDocumentFragment();
 }
 
+
 QT_END_NAMESPACE
 
 #include "moc_qtextcontrol_p.cpp"
 QT_END_NAMESPACE
 
 #include "moc_qtextcontrol_p.cpp"
index cbf26d2..c5ed0ee 100644 (file)
@@ -226,6 +226,7 @@ Q_SIGNALS:
     void cursorPositionChanged();
 
     // control signals
     void cursorPositionChanged();
 
     // control signals
+    void updateCursorRequest(const QRectF &rect = QRectF());
     void updateRequest(const QRectF &rect = QRectF());
     void documentSizeChanged(const QSizeF &);
     void blockCountChanged(int newBlockCount);
     void updateRequest(const QRectF &rect = QRectF());
     void documentSizeChanged(const QSizeF &);
     void blockCountChanged(int newBlockCount);
@@ -258,6 +259,8 @@ public:
     bool setFocusToNextOrPreviousAnchor(bool next);
     bool findNextPrevAnchor(const QTextCursor& from, bool next, QTextCursor& newAnchor);
 
     bool setFocusToNextOrPreviousAnchor(bool next);
     bool findNextPrevAnchor(const QTextCursor& from, bool next, QTextCursor& newAnchor);
 
+    bool cursorOn() const;
+
 protected:
     virtual void timerEvent(QTimerEvent *e);
 
 protected:
     virtual void timerEvent(QTimerEvent *e);
 
index 2535fad..8c5e63d 100644 (file)
@@ -42,6 +42,7 @@
 #include "qtextlayout.h"
 #include "qtextengine_p.h"
 
 #include "qtextlayout.h"
 #include "qtextengine_p.h"
 
+#include <qthread.h>
 #include <qfont.h>
 #include <qapplication.h>
 #include <qpainter.h>
 #include <qfont.h>
 #include <qapplication.h>
 #include <qpainter.h>
@@ -2108,8 +2109,10 @@ static void setPenAndDrawBackground(QPainter *p, const QPen &defaultPen, const Q
 
 }
 
 
 }
 
+#if !defined(QT_NO_RAWFONT)
 static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &glyphLayout,
 static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &glyphLayout,
-                                  const QPointF &pos, const QTextItem::RenderFlags &flags)
+                                  const QPointF &pos, const QTextItem::RenderFlags &flags,
+                                  const QFixed &selectionX, const QFixed &selectionWidth)
 {
     QGlyphRun glyphRun;
 
 {
     QGlyphRun glyphRun;
 
@@ -2117,6 +2120,7 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &g
     QRawFont font;
     QRawFontPrivate *fontD = QRawFontPrivate::get(font);
     fontD->fontEngine = fontEngine;
     QRawFont font;
     QRawFontPrivate *fontD = QRawFontPrivate::get(font);
     fontD->fontEngine = fontEngine;
+    fontD->thread = QThread::currentThread();
     fontD->fontEngine->ref.ref();
 
 #if defined(Q_WS_WIN)
     fontD->fontEngine->ref.ref();
 
 #if defined(Q_WS_WIN)
@@ -2151,13 +2155,27 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &g
                                   positionsArray);
     Q_ASSERT(glyphsArray.size() == positionsArray.size());
 
                                   positionsArray);
     Q_ASSERT(glyphsArray.size() == positionsArray.size());
 
+    qreal fontHeight = font.ascent() + font.descent();
+    qreal minY;
+    qreal maxY;
     QVector<quint32> glyphs;
     QVector<QPointF> positions;
     for (int i=0; i<glyphsArray.size(); ++i) {
         glyphs.append(glyphsArray.at(i) & 0xffffff);
     QVector<quint32> glyphs;
     QVector<QPointF> positions;
     for (int i=0; i<glyphsArray.size(); ++i) {
         glyphs.append(glyphsArray.at(i) & 0xffffff);
-        positions.append(positionsArray.at(i).toPointF() + pos);
+
+        QPointF position = positionsArray.at(i).toPointF() + pos;
+        positions.append(position);
+
+        if (i == 0) {
+            maxY = minY = position.y();
+        } else {
+            minY = qMin(minY, position.y());
+            maxY = qMax(maxY, position.y());
+        }
     }
 
     }
 
+    qreal height = maxY + fontHeight - minY;
+
     glyphRun.setGlyphIndexes(glyphs);
     glyphRun.setPositions(positions);
 
     glyphRun.setGlyphIndexes(glyphs);
     glyphRun.setPositions(positions);
 
@@ -2166,6 +2184,8 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &g
     glyphRun.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
     glyphRun.setRawFont(font);
 
     glyphRun.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
     glyphRun.setRawFont(font);
 
+    glyphRun.setBoundingRect(QRectF(selectionX.toReal(), minY, selectionWidth.toReal(), height));
+
     return glyphRun;
 }
 
     return glyphRun;
 }
 
@@ -2182,7 +2202,6 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &g
 
     \sa QTextLayout::glyphRuns()
 */
 
     \sa QTextLayout::glyphRuns()
 */
-#if !defined(QT_NO_RAWFONT)
 QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 {
     const QScriptLine &line = eng->lines[i];
 QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 {
     const QScriptLine &line = eng->lines[i];
@@ -2196,7 +2215,14 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
     if (length < 0)
         length = textLength();
 
     if (length < 0)
         length = textLength();
 
-    QTextLineItemIterator iterator(eng, i);
+    if (length == 0)
+        return QList<QGlyphRun>();
+
+    QTextLayout::FormatRange selection;
+    selection.start = from;
+    selection.length = length;
+
+    QTextLineItemIterator iterator(eng, i, QPointF(), &selection);
     qreal y = line.y.toReal() + line.base().toReal();
     QList<QGlyphRun> glyphRuns;
     while (!iterator.atEnd()) {
     qreal y = line.y.toReal() + line.base().toReal();
     QList<QGlyphRun> glyphRuns;
     while (!iterator.atEnd()) {
@@ -2206,7 +2232,10 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 
         QPointF pos(iterator.x.toReal(), y);
         if (from >= 0 && length >= 0 &&
 
         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
+             || from + length <= iterator.itemStart
+             || from >= iterator.itemEnd)) {
             continue;
         }
 
             continue;
         }
 
@@ -2235,19 +2264,22 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
                          ? si.num_glyphs - 1
                          : logClusters[relativeTo];
 
                          ? si.num_glyphs - 1
                          : logClusters[relativeTo];
 
+        int itemGlyphsStart = logClusters[iterator.itemStart - si.position];
+        int itemGlyphsEnd = logClusters[iterator.itemEnd - 1 - si.position];
+
         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) {
         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) {
+            for (int i=itemGlyphsStart; 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) {
                 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) {
+            for (int i=itemGlyphsEnd; 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());
                 QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
                 pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
                                glyphLayout.advances_y[i].toReal());
@@ -2256,6 +2288,10 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 
         glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1);
 
 
         glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1);
 
+        QFixed x;
+        QFixed width;
+        iterator.getSelectionBounds(&x, &width);
+
         if (glyphLayout.numGlyphs > 0) {
             QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
             if (mainFontEngine->type() == QFontEngine::Multi) {
         if (glyphLayout.numGlyphs > 0) {
             QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script);
             if (mainFontEngine->type() == QFontEngine::Multi) {
@@ -2270,7 +2306,7 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
 
                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
                     glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which),
 
                     QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
                     glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which),
-                                                      subLayout, pos, flags));
+                                                      subLayout, pos, flags, x, width));
                     for (int i = 0; i < subLayout.numGlyphs; i++) {
                         pos += QPointF(subLayout.advances_x[i].toReal(),
                                        subLayout.advances_y[i].toReal());
                     for (int i = 0; i < subLayout.numGlyphs; i++) {
                         pos += QPointF(subLayout.advances_x[i].toReal(),
                                        subLayout.advances_y[i].toReal());
@@ -2281,10 +2317,15 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
                 }
 
                 QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
                 }
 
                 QGlyphLayout subLayout = glyphLayout.mid(start, end - start);
-                glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which),
-                                                  subLayout, pos, flags));
+                QGlyphRun glyphRun = glyphRunWithInfo(multiFontEngine->engine(which),
+                                                      subLayout, pos, flags, x, width);
+                if (!glyphRun.isEmpty())
+                    glyphRuns.append(glyphRun);
             } else {
             } else {
-                glyphRuns.append(glyphRunWithInfo(mainFontEngine, glyphLayout, pos, flags));
+                QGlyphRun glyphRun = glyphRunWithInfo(mainFontEngine, glyphLayout, pos, flags, x,
+                                                      width);
+                if (!glyphRun.isEmpty())
+                    glyphRuns.append(glyphRun);
             }
         }
     }
             }
         }
     }
index cea5eac..d641266 100644 (file)
@@ -1667,21 +1667,24 @@ QTextBlock::iterator &QTextBlock::iterator::operator--()
     \sa QGlyphRun, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphRun()
 */
 #if !defined(QT_NO_RAWFONT)
     \sa QGlyphRun, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphRun()
 */
 #if !defined(QT_NO_RAWFONT)
-QList<QGlyphRun> QTextFragment::glyphRuns() const
+QList<QGlyphRun> QTextFragment::glyphRuns(int pos, int len) const
 {
     if (!p || !n)
         return QList<QGlyphRun>();
 
 {
     if (!p || !n)
         return QList<QGlyphRun>();
 
-    int pos = position();
-    int len = length();
-    if (len == 0)
-        return QList<QGlyphRun>();
-
-    int blockNode = p->blockMap().findNode(pos);
+    int blockNode = p->blockMap().findNode(position());
 
     const QTextBlockData *blockData = p->blockMap().fragment(blockNode);
     QTextLayout *layout = blockData->layout;
 
 
     const QTextBlockData *blockData = p->blockMap().fragment(blockNode);
     QTextLayout *layout = blockData->layout;
 
+    int blockPosition = p->blockMap().position(blockNode);
+    if (pos < 0)
+        pos = position() - blockPosition;
+    if (len < 0)
+        len = length();
+    if (len == 0)
+        return QList<QGlyphRun>();
+
     QList<QGlyphRun> ret;
     for (int i=0; i<layout->lineCount(); ++i) {
         QTextLine textLine = layout->lineAt(i);
     QList<QGlyphRun> ret;
     for (int i=0; i<layout->lineCount(); ++i) {
         QTextLine textLine = layout->lineAt(i);
index 9c5cc13..c2b46e4 100644 (file)
@@ -317,7 +317,7 @@ public:
     QString text() const;
 
 #if !defined(QT_NO_RAWFONT)
     QString text() const;
 
 #if !defined(QT_NO_RAWFONT)
-    QList<QGlyphRun> glyphRuns() const;
+    QList<QGlyphRun> glyphRuns(int from = -1, int length = -1) const;
 #endif
 
 private:
 #endif
 
 private:
index 92c84d7..9b7d9b8 100644 (file)
@@ -76,6 +76,28 @@ static int qt_passwordEchoDelay = QT_GUI_PASSWORD_ECHO_DELAY;
 */
 
 /*!
 */
 
 /*!
+   \internal
+
+   Updates the internal text layout. Returns the ascent of the
+   created QTextLine.
+*/
+int QLineControl::redoTextLayout() const
+{
+    m_textLayout.clearLayout();
+
+    m_textLayout.beginLayout();
+    QTextLine l = m_textLayout.createLine();
+    m_textLayout.endLayout();
+
+#if defined(Q_WS_MAC)
+    if (m_threadChecks)
+        m_textLayoutThread = QThread::currentThread();
+#endif
+
+    return qRound(l.ascent());
+}
+
+/*!
     \internal
 
     Updates the display text based of the current edit text
     \internal
 
     Updates the display text based of the current edit text
@@ -124,15 +146,12 @@ void QLineControl::updateDisplayText(bool forceUpdate)
 
     m_textLayout.setText(str);
 
 
     m_textLayout.setText(str);
 
-    QTextOption option;
+    QTextOption option = m_textLayout.textOption();
     option.setTextDirection(m_layoutDirection);
     option.setFlags(QTextOption::IncludeTrailingSpaces);
     m_textLayout.setTextOption(option);
 
     option.setTextDirection(m_layoutDirection);
     option.setFlags(QTextOption::IncludeTrailingSpaces);
     m_textLayout.setTextOption(option);
 
-    m_textLayout.beginLayout();
-    QTextLine l = m_textLayout.createLine();
-    m_textLayout.endLayout();
-    m_ascent = qRound(l.ascent());
+    m_ascent = redoTextLayout();
 
     if (str != orig || forceUpdate)
         emit displayTextChanged(str);
 
     if (str != orig || forceUpdate)
         emit displayTextChanged(str);
@@ -228,7 +247,7 @@ void QLineControl::del()
     if (hasSelectedText()) {
         removeSelectedText();
     } else {
     if (hasSelectedText()) {
         removeSelectedText();
     } else {
-        int n = m_textLayout.nextCursorPosition(m_cursor) - m_cursor;
+        int n = textLayout()->nextCursorPosition(m_cursor) - m_cursor;
         while (n--)
             internalDelete();
     }
         while (n--)
             internalDelete();
     }
@@ -357,7 +376,7 @@ void QLineControl::updatePasswordEchoEditing(bool editing)
 */
 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
 {
 */
 int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
 {
-    return m_textLayout.lineAt(0).xToCursor(x, betweenOrOn);
+    return textLayout()->lineAt(0).xToCursor(x, betweenOrOn);
 }
 
 /*!
 }
 
 /*!
@@ -368,7 +387,7 @@ int QLineControl::xToPos(int x, QTextLine::CursorPosition betweenOrOn) const
 */
 QRect QLineControl::cursorRect() const
 {
 */
 QRect QLineControl::cursorRect() const
 {
-    QTextLine l = m_textLayout.lineAt(0);
+    QTextLine l = textLayout()->lineAt(0);
     int c = m_cursor;
     if (m_preeditCursor != -1)
         c += m_preeditCursor;
     int c = m_cursor;
     if (m_preeditCursor != -1)
         c += m_preeditCursor;
@@ -578,14 +597,14 @@ void QLineControl::draw(QPainter *painter, const QPoint &offset, const QRect &cl
     }
 
     if (flags & DrawText)
     }
 
     if (flags & DrawText)
-        m_textLayout.draw(painter, offset, selections, clip);
+        textLayout()->draw(painter, offset, selections, clip);
 
     if (flags & DrawCursor){
         int cursor = m_cursor;
         if (m_preeditCursor != -1)
             cursor += m_preeditCursor;
         if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
 
     if (flags & DrawCursor){
         int cursor = m_cursor;
         if (m_preeditCursor != -1)
             cursor += m_preeditCursor;
         if (!m_hideCursor && (!m_blinkPeriod || m_blinkStatus))
-            m_textLayout.drawCursor(painter, offset, cursor, m_cursorWidth);
+            textLayout()->drawCursor(painter, offset, cursor, m_cursorWidth);
     }
 }
 
     }
 }
 
@@ -601,10 +620,10 @@ void QLineControl::selectWordAtPos(int cursor)
     int next = cursor + 1;
     if(next > end())
         --next;
     int next = cursor + 1;
     if(next > end())
         --next;
-    int c = m_textLayout.previousCursorPosition(next, QTextLayout::SkipWords);
+    int c = textLayout()->previousCursorPosition(next, QTextLayout::SkipWords);
     moveCursor(c, false);
     // ## text layout should support end of words.
     moveCursor(c, false);
     // ## text layout should support end of words.
-    int end = m_textLayout.nextCursorPosition(c, QTextLayout::SkipWords);
+    int end = textLayout()->nextCursorPosition(c, QTextLayout::SkipWords);
     while (end > cursor && m_text[end-1].isSpace())
         --end;
     moveCursor(end, true);
     while (end > cursor && m_text[end-1].isSpace())
         --end;
     moveCursor(end, true);
index 44bd721..d4c4154 100644 (file)
@@ -65,6 +65,7 @@
 #include "QtCore/qpoint.h"
 #include "QtGui/qcompleter.h"
 #include "QtGui/qaccessible.h"
 #include "QtCore/qpoint.h"
 #include "QtGui/qcompleter.h"
 #include "QtGui/qaccessible.h"
+#include "QtCore/qthread.h"
 
 #include "qplatformdefs.h"
 
 
 #include "qplatformdefs.h"
 
@@ -90,6 +91,10 @@ public:
 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
         , m_passwordEchoTimer(0)
 #endif
 #ifdef QT_GUI_PASSWORD_ECHO_DELAY
         , m_passwordEchoTimer(0)
 #endif
+#if defined(Q_WS_MAC)
+        , m_threadChecks(false)
+        , m_textLayoutThread(0)
+ #endif
     {
         init(txt);
     }
     {
         init(txt);
     }
@@ -332,11 +337,27 @@ public:
 
     bool processEvent(QEvent *ev);
 
 
     bool processEvent(QEvent *ev);
 
-    QTextLayout *textLayout()
+    QTextLayout *textLayout() const
     {
     {
+#if defined(Q_WS_MAC)
+        if (m_threadChecks && QThread::currentThread() != m_textLayoutThread)
+            redoTextLayout();
+#endif
         return &m_textLayout;
     }
 
         return &m_textLayout;
     }
 
+#if defined(Q_WS_MAC)
+    void setThreadChecks(bool threadChecks)
+    {
+        m_threadChecks = threadChecks;
+    }
+
+    bool threadChecks() const
+    {
+        return m_threadChecks;
+    }
+#endif
+
 private:
     void init(const QString &txt);
     void removeSelectedText();
 private:
     void init(const QString &txt);
     void removeSelectedText();
@@ -433,8 +454,8 @@ private:
     QString stripString(const QString &str) const;
     int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
 
     QString stripString(const QString &str) const;
     int findInMask(int pos, bool forward, bool findSeparator, QChar searchChar = QChar()) const;
 
-    // complex text layout
-    QTextLayout m_textLayout;
+    // complex text layout (must be mutable so it can be reshaped at will)
+    mutable QTextLayout m_textLayout;
 
     bool m_passwordEchoEditing;
     QChar m_passwordCharacter;
 
     bool m_passwordEchoEditing;
     QChar m_passwordCharacter;
@@ -451,6 +472,12 @@ private:
 #endif
     }
 
 #endif
     }
 
+    int redoTextLayout() const;
+#if defined(Q_WS_MAC)
+    bool m_threadChecks;
+    mutable QThread *m_textLayoutThread;
+#endif
+
 Q_SIGNALS:
     void cursorPositionChanged(int, int);
     void selectionChanged();
 Q_SIGNALS:
     void cursorPositionChanged(int, int);
     void selectionChanged();