diff options
Diffstat (limited to 'src/gui/text')
-rw-r--r-- | src/gui/text/qdistancefield.cpp | 67 | ||||
-rw-r--r-- | src/gui/text/qdistancefield_p.h | 2 | ||||
-rw-r--r-- | src/gui/text/qfont.cpp | 14 | ||||
-rw-r--r-- | src/gui/text/qfont_p.h | 1 | ||||
-rw-r--r-- | src/gui/text/qfontengine.cpp | 20 | ||||
-rw-r--r-- | src/gui/text/qfontengine_p.h | 7 | ||||
-rw-r--r-- | src/gui/text/qglyphrun.h | 2 | ||||
-rw-r--r-- | src/gui/text/qtextengine.cpp | 99 | ||||
-rw-r--r-- | src/gui/text/qtextengine_p.h | 32 | ||||
-rw-r--r-- | src/gui/text/qtextlayout.cpp | 13 |
10 files changed, 200 insertions, 57 deletions
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp index fb06a26c8f..a1deb47175 100644 --- a/src/gui/text/qdistancefield.cpp +++ b/src/gui/text/qdistancefield.cpp @@ -692,17 +692,8 @@ static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfSca return image; } -bool qt_fontHasNarrowOutlines(const QRawFont &f) +static bool imageHasNarrowOutlines(const QImage &im) { - QRawFont font = f; - font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); - Q_ASSERT(font.isValid()); - - QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O")); - if (glyphIndices.size() < 1) - return false; - - QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing); if (im.isNull()) return false; @@ -742,6 +733,56 @@ bool qt_fontHasNarrowOutlines(const QRawFont &f) return minHThick == 1 || minVThick == 1; } +bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine) +{ + QFontEngine *fe = fontEngine->cloneWithSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); + + QGlyphLayout glyphs; + glyph_t glyph; + glyphs.glyphs = &glyph; + int numGlyphs; + QChar *chars = QString(QLatin1String("O")).data(); + fe->stringToCMap(chars, 1, &glyphs, &numGlyphs, QTextEngine::GlyphIndicesOnly); + QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform()); + delete fe; + + return imageHasNarrowOutlines(im); +} + +bool qt_fontHasNarrowOutlines(const QRawFont &f) +{ + QRawFont font = f; + font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); + Q_ASSERT(font.isValid()); + + QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O")); + if (glyphIndices.size() < 1) + return false; + + return imageHasNarrowOutlines(font.alphaMapForGlyph(glyphIndices.at(0), + QRawFont::PixelAntialiasing)); +} + +static QImage renderDistanceFieldPath(const QPainterPath &path, bool doubleResolution) +{ + QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), + path, + QT_DISTANCEFIELD_SCALE(doubleResolution), + QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); + return im; +} + +QImage qt_renderDistanceFieldGlyph(QFontEngine *fe, glyph_t glyph, bool doubleResolution) +{ + QFixedPoint position; + QPainterPath path; + fe->addGlyphsToPath(&glyph, &position, 1, &path, 0); + path.translate(-path.boundingRect().topLeft()); + path.setFillRule(Qt::WindingFill); + + return renderDistanceFieldPath(path, doubleResolution); +} + QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution) { QRawFont renderFont = font; @@ -751,11 +792,7 @@ QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool dou path.translate(-path.boundingRect().topLeft()); path.setFillRule(Qt::WindingFill); - QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), - path, - QT_DISTANCEFIELD_SCALE(doubleResolution), - QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); - return im; + return renderDistanceFieldPath(path, doubleResolution); } QT_END_NAMESPACE diff --git a/src/gui/text/qdistancefield_p.h b/src/gui/text/qdistancefield_p.h index 486d291b78..bf87e7d3cb 100644 --- a/src/gui/text/qdistancefield_p.h +++ b/src/gui/text/qdistancefield_p.h @@ -79,6 +79,8 @@ QT_BEGIN_NAMESPACE bool Q_GUI_EXPORT qt_fontHasNarrowOutlines(const QRawFont &f); QImage Q_GUI_EXPORT qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution); +bool Q_GUI_EXPORT qt_fontHasNarrowOutlines(QFontEngine *fontEngine); +QImage Q_GUI_EXPORT qt_renderDistanceFieldGlyph(QFontEngine *fontEngine, glyph_t glyph, bool doubleResolution); QT_END_NAMESPACE diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp index c68452d55a..56ff298d9b 100644 --- a/src/gui/text/qfont.cpp +++ b/src/gui/text/qfont.cpp @@ -2733,20 +2733,6 @@ void QFontCache::updateHitCountAndTimeStamp(Engine &value) value.data->name()); } -void QFontCache::removeEngine(QFontEngine *engine) -{ - EngineCache::iterator it = engineCache.begin(); - while (it != engineCache.end()) { - if (it.value().data == engine) { - it = engineCache.erase(it); - if (--engine->cache_count == 0) - decreaseCost(engine->cache_cost); - } else { - ++it; - } - } -} - void QFontCache::insertEngine(const Key &key, QFontEngine *engine, bool insertMulti) { FC_DEBUG("QFontCache: inserting new engine %p", engine); diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h index 06cf787880..13e5fcbedd 100644 --- a/src/gui/text/qfont_p.h +++ b/src/gui/text/qfont_p.h @@ -245,7 +245,6 @@ public: void updateHitCountAndTimeStamp(Engine &value); void insertEngine(const Key &key, QFontEngine *engine, bool insertMulti = false); - void removeEngine(QFontEngine *engine); private: void increaseCost(uint cost); diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp index 142d627100..364a356b96 100644 --- a/src/gui/text/qfontengine.cpp +++ b/src/gui/text/qfontengine.cpp @@ -775,7 +775,7 @@ QByteArray QFontEngine::getSfntTable(uint tag) const return table; } -void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data) +void QFontEngine::setGlyphCache(const void *key, QFontEngineGlyphCache *data) { Q_ASSERT(data); @@ -794,7 +794,7 @@ void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data) } -QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const +QFontEngineGlyphCache *QFontEngine::glyphCache(const void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const { for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) { QFontEngineGlyphCache *c = it->cache.data(); @@ -1421,22 +1421,6 @@ bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const return true; } -void QFontEngineMulti::unloadEngine(int at) -{ - QFontEngine *fontEngine = engines.at(at); - if (fontEngine == 0) - return; - - // If there are other references to the engine, keep it around and keep the reference - if (fontEngine->ref.load() == 1) { - QFontCache::instance()->removeEngine(fontEngine); - if (fontEngine->cache_count == 0) { - delete fontEngine; - engines[at] = 0; - } - } -} - glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs) { if (glyphs.numGlyphs <= 0) diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h index 660e3be459..1114cdf12c 100644 --- a/src/gui/text/qfontengine_p.h +++ b/src/gui/text/qfontengine_p.h @@ -239,8 +239,8 @@ public: virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints); - void setGlyphCache(void *key, QFontEngineGlyphCache *data); - QFontEngineGlyphCache *glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const; + void setGlyphCache(const void *key, QFontEngineGlyphCache *data); + QFontEngineGlyphCache *glyphCache(const void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const; static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize); static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode); @@ -284,7 +284,7 @@ protected: private: struct GlyphCacheEntry { - void *context; + const void *context; QExplicitlySharedDataPointer<QFontEngineGlyphCache> cache; bool operator==(const GlyphCacheEntry &other) const { return context == other.context && cache == other.cache; } }; @@ -401,7 +401,6 @@ protected: friend class QPSPrintEngineFontMulti; friend class QRawFont; virtual void loadEngine(int at) = 0; - virtual void unloadEngine(int at); QVector<QFontEngine *> engines; }; diff --git a/src/gui/text/qglyphrun.h b/src/gui/text/qglyphrun.h index 847b7e4852..b590775d8b 100644 --- a/src/gui/text/qglyphrun.h +++ b/src/gui/text/qglyphrun.h @@ -124,6 +124,8 @@ private: QExplicitlySharedDataPointer<QGlyphRunPrivate> d; }; +Q_DECLARE_TYPEINFO(QGlyphRun, Q_MOVABLE_TYPE); + QT_END_NAMESPACE QT_END_HEADER diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp index dae02def07..3d58d91169 100644 --- a/src/gui/text/qtextengine.cpp +++ b/src/gui/text/qtextengine.cpp @@ -1174,6 +1174,7 @@ static void init(QTextEngine *e) e->cacheGlyphs = false; e->forceJustification = false; e->visualMovement = false; + e->delayDecorations = false; e->layoutData = 0; @@ -2913,6 +2914,104 @@ int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation return pos; } +void QTextEngine::addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList) +{ + if (delayDecorations) { + decorationList->append(ItemDecoration(line.x1(), line.x2(), line.y1(), painter->pen())); + } else { + painter->drawLine(line); + } +} + +void QTextEngine::addUnderline(QPainter *painter, const QLineF &line) +{ + // qDebug() << "Adding underline:" << line; + addItemDecoration(painter, line, &underlineList); +} + +void QTextEngine::addStrikeOut(QPainter *painter, const QLineF &line) +{ + addItemDecoration(painter, line, &strikeOutList); +} + +void QTextEngine::addOverline(QPainter *painter, const QLineF &line) +{ + addItemDecoration(painter, line, &overlineList); +} + +void QTextEngine::drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList) +{ + // qDebug() << "Drawing" << decorationList.size() << "decorations"; + if (decorationList.isEmpty()) + return; + + foreach (const ItemDecoration decoration, decorationList) { + painter->setPen(decoration.pen); + QLineF line(decoration.x1, decoration.y, decoration.x2, decoration.y); + painter->drawLine(line); + } +} + +void QTextEngine::drawDecorations(QPainter *painter) +{ + QPen oldPen = painter->pen(); + + adjustUnderlines(); + drawItemDecorationList(painter, underlineList); + drawItemDecorationList(painter, strikeOutList); + drawItemDecorationList(painter, overlineList); + + painter->setPen(oldPen); + clearDecorations(); +} + +void QTextEngine::clearDecorations() +{ + underlineList.clear(); + strikeOutList.clear(); + overlineList.clear(); +} + +void QTextEngine::adjustUnderlines() +{ + // qDebug() << __PRETTY_FUNCTION__ << underlineList.count() << "underlines"; + if (underlineList.isEmpty()) + return; + + ItemDecorationList::iterator start = underlineList.begin(); + ItemDecorationList::iterator end = underlineList.end(); + ItemDecorationList::iterator it = start; + qreal underlinePos = start->y; + qreal penWidth = start->pen.widthF(); + qreal lastLineEnd = start->x1; + + while (it != end) { + if (qFuzzyCompare(lastLineEnd, it->x1)) { // no gap between underlines + underlinePos = qMax(underlinePos, it->y); + penWidth = qMax(penWidth, it->pen.widthF()); + } else { // gap between this and the last underline + adjustUnderlines(start, it, underlinePos, penWidth); + start = it; + underlinePos = start->y; + penWidth = start->pen.widthF(); + } + lastLineEnd = it->x2; + ++it; + } + + adjustUnderlines(start, end, underlinePos, penWidth); +} + +void QTextEngine::adjustUnderlines(ItemDecorationList::iterator start, + ItemDecorationList::iterator end, + qreal underlinePos, qreal penWidth) +{ + for (ItemDecorationList::iterator it = start; it != end; ++it) { + it->y = underlinePos; + it->pen.setWidth(penWidth); + } +} + QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f) : QTextEngine(string, f), _layoutData(string, _memory, MemSize) diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h index 6f1fd713f1..03581eb6a2 100644 --- a/src/gui/text/qtextengine_p.h +++ b/src/gui/text/qtextengine_p.h @@ -446,6 +446,18 @@ public: bool reallocate(int totalGlyphs); }; + struct ItemDecoration { + ItemDecoration(qreal x1, qreal x2, qreal y, const QPen &pen): + x1(x1), x2(x2), y(y), pen(pen) {} + + qreal x1; + qreal x2; + qreal y; + QPen pen; + }; + + typedef QList<ItemDecoration> ItemDecorationList; + QTextEngine(LayoutData *data); QTextEngine(); QTextEngine(const QString &str, const QFont &f); @@ -597,6 +609,7 @@ public: uint stackEngine : 1; uint forceJustification : 1; uint visualMovement : 1; + uint delayDecorations: 1; #ifndef QT_NO_RAWFONT uint useRawFont : 1; #endif @@ -605,6 +618,10 @@ public: mutable LayoutData *layoutData; + ItemDecorationList underlineList; + ItemDecorationList strikeOutList; + ItemDecorationList overlineList; + inline bool hasFormats() const { return (block.docHandle() || specialData); } inline bool visualCursorMovement() const { @@ -639,7 +656,22 @@ public: void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints); void resetFontEngineCache(); + void enableDelayDecorations(bool enable = true) { delayDecorations = enable; } + + void addUnderline(QPainter *painter, const QLineF &line); + void addStrikeOut(QPainter *painter, const QLineF &line); + void addOverline(QPainter *painter, const QLineF &line); + + void drawDecorations(QPainter *painter); + void clearDecorations(); + void adjustUnderlines(); + private: + void addItemDecoration(QPainter *painter, const QLineF &line, ItemDecorationList *decorationList); + void adjustUnderlines(ItemDecorationList::iterator start, + ItemDecorationList::iterator end, + qreal underlinePos, qreal penWidth); + void drawItemDecorationList(QPainter *painter, const ItemDecorationList &decorationList); void setBoundary(int strPos) const; void addRequiredBoundaries() const; void shapeText(int item) const; diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp index d5b05a8957..56098b0bdb 100644 --- a/src/gui/text/qtextlayout.cpp +++ b/src/gui/text/qtextlayout.cpp @@ -60,6 +60,7 @@ #include <qdebug.h> #include "qfontengine_p.h" +#include <private/qpainter_p.h> QT_BEGIN_NAMESPACE @@ -2062,7 +2063,7 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, if (rtl) x -= w; if (gf.num_chars) - p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng); if (!rtl) x += w; if (ul && *ul != -1 && *ul < end) { @@ -2083,7 +2084,7 @@ static void drawMenuText(QPainter *p, QFixed x, QFixed y, const QScriptItem &si, gf.underlineStyle = QTextCharFormat::SingleUnderline; if (rtl) x -= w; - p->drawTextItem(QPointF(x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(x.toReal(), y.toReal()), gf, eng); if (!rtl) x += w; gf.underlineStyle = QTextCharFormat::NoUnderline; @@ -2379,6 +2380,8 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR QTextLineItemIterator iterator(eng, index, pos, selection); QFixed lineBase = line.base(); + eng->clearDecorations(); + eng->enableDelayDecorations(); const QFixed y = QFixed::fromReal(pos.y()) + line.y + lineBase; @@ -2451,7 +2454,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR gf.chars = 0; gf.num_chars = 0; gf.width = iterator.itemWidth; - p->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf); + QPainterPrivate::get(p)->drawTextItem(QPointF(iterator.x.toReal(), y.toReal()), gf, eng); if (eng->option.flags() & QTextOption::ShowTabsAndSpaces) { QChar visualTab(0x2192); int w = QFontMetrics(f).width(visualTab); @@ -2529,7 +2532,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR } else { if (noText) gf.glyphs.numGlyphs = 0; // slightly less elegant than it should be - p->drawTextItem(pos, gf); + QPainterPrivate::get(p)->drawTextItem(pos, gf, eng); } } if (si.analysis.flags == QScriptAnalysis::Space @@ -2542,7 +2545,7 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR p->setPen(pen); } } - + eng->drawDecorations(p); if (eng->hasFormats()) p->setPen(pen); |