From 5feefb0c039dae04290d1fca7c2f24276b6f7582 Mon Sep 17 00:00:00 2001 From: Eskil Abrahamsen Blomfeldt Date: Mon, 9 May 2011 09:07:02 +0200 Subject: Enablers for TextInput In order to use the scene graph text node in TextInput, we need enablers. Most of this is to enable selections, which in turn means we need to be able to extract a certain set of glyphs from a QTextLine. --- src/gui/text/qglyphrun.cpp | 29 ++++++++++++++ src/gui/text/qglyphrun.h | 2 + src/gui/text/qrawfont.cpp | 14 +++++++ src/gui/text/qrawfont.h | 1 + src/gui/text/qtextlayout.cpp | 84 ++++++++++++++++++++++++++++++++-------- src/gui/text/qtextlayout.h | 10 ++--- src/gui/text/qtextobject.cpp | 2 +- src/gui/widgets/qlinecontrol_p.h | 7 ++++ 8 files changed, 126 insertions(+), 23 deletions(-) diff --git a/src/gui/text/qglyphrun.cpp b/src/gui/text/qglyphrun.cpp index ea527886cd..38ca998dd3 100644 --- a/src/gui/text/qglyphrun.cpp +++ b/src/gui/text/qglyphrun.cpp @@ -319,6 +319,35 @@ void QGlyphRun::setStrikeOut(bool strikeOut) d->strikeOut = strikeOut; } +/*! + Returns the smallest rectangle that contains all glyphs in this QGlyphRun. + + \since 5.0 +*/ +QRectF QGlyphRun::boundingRect() const +{ + qreal minX, minY, maxX, maxY; + + for (int i=0; iglyphPositions.size(), d->glyphIndexes.size()); ++i) { + QRectF glyphRect = d->rawFont.boundingRect(d->glyphIndexes.at(i)); + glyphRect.translate(d->glyphPositions.at(i)); + + if (i == 0) { + minX = glyphRect.left(); + minY = glyphRect.top(); + maxX = glyphRect.right(); + maxY = glyphRect.bottom(); + } else { + minX = qMin(glyphRect.left(), minX); + minY = qMin(glyphRect.top(), minY); + maxX = qMax(glyphRect.right(),maxX); + maxY = qMax(glyphRect.bottom(), maxY); + } + } + + return QRectF(QPointF(minX, minY), QPointF(maxX, maxY)); +} + QT_END_NAMESPACE #endif // QT_NO_RAWFONT diff --git a/src/gui/text/qglyphrun.h b/src/gui/text/qglyphrun.h index dcc166ea3e..18afb2e1d8 100644 --- a/src/gui/text/qglyphrun.h +++ b/src/gui/text/qglyphrun.h @@ -87,6 +87,8 @@ public: void setStrikeOut(bool strikeOut); bool strikeOut() const; + QRectF boundingRect() const; + private: friend class QGlyphRunPrivate; friend class QTextLine; diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp index 44ddfd2d75..1c7d5ad4b6 100644 --- a/src/gui/text/qrawfont.cpp +++ b/src/gui/text/qrawfont.cpp @@ -718,6 +718,20 @@ void QRawFontPrivate::cleanUp() hintingPreference = QFont::PreferDefaultHinting; } +/*! + Returns the smallest rectangle containing the glyph with the given \a glyphIndex. + + \since 5.0 +*/ +QRectF QRawFont::boundingRect(quint32 glyphIndex) const +{ + if (!isValid()) + return QRectF(); + + glyph_metrics_t gm = d->fontEngine->boundingBox(glyphIndex); + return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal()); +} + #endif // QT_NO_RAWFONT QT_END_NAMESPACE diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h index 3875fec641..63f3d882aa 100644 --- a/src/gui/text/qrawfont.h +++ b/src/gui/text/qrawfont.h @@ -97,6 +97,7 @@ public: AntialiasingType antialiasingType = SubPixelAntialiasing, const QTransform &transform = QTransform()) const; QPainterPath pathForGlyph(quint32 glyphIndex) const; + QRectF boundingRect(quint32 glyphIndex) const; void setPixelSize(qreal pixelSize); qreal pixelSize() const; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index 07aeb72a49..91809c3266 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -997,11 +997,20 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip) \sa draw(), QPainter::drawGlyphRun() */ #if !defined(QT_NO_RAWFONT) -QList QTextLayout::glyphRuns() const -{ +QList QTextLayout::glyphRuns(int from, int length) const +{ + if (from < 0) + from = 0; + if (length < 0) + length = text().length(); + QList glyphs; - for (int i=0; ilines.size(); ++i) - glyphs += QTextLine(i, d).glyphs(-1, -1); + for (int i=0; ilines.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; } @@ -2084,25 +2093,32 @@ 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::glyphRuns() */ #if !defined(QT_NO_RAWFONT) -QList QTextLine::glyphs(int from, int length) const +QList QTextLine::glyphRuns(int from, int length) const { const QScriptLine &line = eng->lines[i]; if (line.length == 0) return QList(); + if (from < 0) + from = textStart(); + + if (length < 0) + length = textLength(); + QHash glyphLayoutHash; QTextLineItemIterator iterator(eng, i); @@ -2114,8 +2130,9 @@ QList 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); @@ -2126,11 +2143,42 @@ QList 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; + } - QGlyphLayout glyphLayout = eng->shapedGlyphs(&si).mid(iterator.glyphsStart, - iterator.glyphsEnd - iterator.glyphsStart); + int relativeFrom = qMax(iterator.itemStart, from) - si.position; + int relativeTo = qMin(iterator.itemEnd, 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; iglyphsEnd; --i) { + QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6); + pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(), + glyphLayout.advances_y[i].toReal()); + } + } + + glyphLayout = glyphLayout.mid(glyphsStart, glyphsEnd - glyphsStart + 1); if (glyphLayout.numGlyphs > 0) { QFontEngine *mainFontEngine = font.d->engineForScript(si.analysis.script); @@ -2147,9 +2195,10 @@ QList 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; @@ -2501,8 +2550,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++; } diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h index 89fbfb2072..9840a37eec 100644 --- a/src/gui/text/qtextlayout.h +++ b/src/gui/text/qtextlayout.h @@ -174,7 +174,7 @@ public: qreal maximumWidth() const; #if !defined(QT_NO_RAWFONT) - QList glyphRuns() const; + QList glyphRuns(int from = -1, int length = -1) const; #endif QTextEngine *engine() const { return d; } @@ -244,14 +244,14 @@ public: void draw(QPainter *p, const QPointF &point, const QTextLayout::FormatRange *selection = 0) const; +#if !defined(QT_NO_RAWFONT) + QList glyphRuns(int from = -1, int length = -1) const; +#endif + private: QTextLine(int line, QTextEngine *e) : i(line), eng(e) {} void layout_helper(int numGlyphs); -#if !defined(QT_NO_RAWFONT) - QList glyphs(int from, int length) const; -#endif - friend class QTextLayout; friend class QTextFragment; int i; diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp index 8dabcc771b..4c03dafe1d 100644 --- a/src/gui/text/qtextobject.cpp +++ b/src/gui/text/qtextobject.cpp @@ -1685,7 +1685,7 @@ QList QTextFragment::glyphRuns() const QList ret; for (int i=0; ilineCount(); ++i) { QTextLine textLine = layout->lineAt(i); - ret += textLine.glyphs(pos, len); + ret += textLine.glyphRuns(pos, len); } return ret; diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h index 9764ba9c59..1530c756dc 100644 --- a/src/gui/widgets/qlinecontrol_p.h +++ b/src/gui/widgets/qlinecontrol_p.h @@ -302,6 +302,8 @@ public: void setCursorBlinkPeriod(int msec); void resetCursorBlinkTimer(); + bool cursorBlinkStatus() const { return m_blinkStatus; } + QString cancelText() const { return m_cancelText; } void setCancelText(const QString &text) { m_cancelText = text; } @@ -318,6 +320,11 @@ public: bool processEvent(QEvent *ev); + QTextLayout *textLayout() + { + return &m_textLayout; + } + private: void init(const QString &txt); void removeSelectedText(); -- cgit v1.2.3