summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qdistancefield.cpp67
-rw-r--r--src/gui/text/qdistancefield_p.h2
-rw-r--r--src/gui/text/qfont.cpp14
-rw-r--r--src/gui/text/qfont_p.h1
-rw-r--r--src/gui/text/qfontengine.cpp20
-rw-r--r--src/gui/text/qfontengine_p.h7
-rw-r--r--src/gui/text/qglyphrun.h2
-rw-r--r--src/gui/text/qtextengine.cpp99
-rw-r--r--src/gui/text/qtextengine_p.h32
-rw-r--r--src/gui/text/qtextlayout.cpp13
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);