summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-01-15 09:11:07 +0100
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>2021-01-25 15:56:50 +0100
commitd79a9b1a4f694a227ce62ccab9b44685a9755916 (patch)
treee943780120ee3abcf987ecd0c05440f9ed5a9b7b
parent80e87ca05c2b421dbca9fc8f9a8f290a3eabc206 (diff)
Implement vertical subpixel positioning where available
For some use cases, vertical subpixel positioning may be useful, as it allows you to vertically align text with other painting primitives. This does impose an overhead, so we make it opt-int with a render hint on the painter. Note that this is only supported on Freetype currently. It might be possible to support on older macOS versions, prior to Mojave (which has disabled subpixel positioning entirely), but since it would have limited usefulness and Freetype is cross-platform anyway, I skipped that. Note: This drive-by-fixes an issue with subpixel positioning where glyphs would always be offset by 1/64, because we added the aliasing offset *after* we had determined the closest subpixel position. The idea of this, as far as I can understand, is rather to snap to nearest subpixel position upwards, not to add an offset to all glyphs, so it should be added before finding the correct position. It had a subtle visual effect when animating the position. It might be that we could get rid of it entirely, as I haven't been able to reproduce any issues with that, but I have moved it instead, to match what I believe the intention was. [ChangeLog][QtGui][Text] Added render hint flag QPainter::VerticalSubpixelPositioning which will position text at subpixel positions vertically whenever supported. In absence of this, text position will be rounded vertically as before. Fixes: QTBUG-35682 Change-Id: I8ce7a72a64e5a0924dac7c244e3e07c2938bfd09 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
-rw-r--r--src/gui/painting/qfixed_p.h4
-rw-r--r--src/gui/painting/qpaintengine.cpp2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp26
-rw-r--r--src/gui/painting/qpainter.cpp10
-rw-r--r--src/gui/painting/qpainter.h1
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp25
-rw-r--r--src/gui/painting/qtextureglyphcache_p.h29
-rw-r--r--src/gui/text/coretext/qfontengine_coretext.mm17
-rw-r--r--src/gui/text/coretext/qfontengine_coretext_p.h15
-rw-r--r--src/gui/text/freetype/qfontengine_ft.cpp65
-rw-r--r--src/gui/text/freetype/qfontengine_ft_p.h72
-rw-r--r--src/gui/text/qdistancefield.cpp2
-rw-r--r--src/gui/text/qfontengine.cpp55
-rw-r--r--src/gui/text/qfontengine_p.h33
-rw-r--r--src/gui/text/qrawfont.cpp6
-rw-r--r--src/gui/text/qtextengine.cpp2
-rw-r--r--src/gui/text/windows/qwindowsfontengine.cpp9
-rw-r--r--src/gui/text/windows/qwindowsfontengine_p.h9
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite.cpp30
-rw-r--r--src/gui/text/windows/qwindowsfontenginedirectwrite_p.h25
-rw-r--r--src/opengl/qopenglpaintengine.cpp22
-rw-r--r--src/opengl/qopengltextureglyphcache.cpp4
-rw-r--r--src/opengl/qopengltextureglyphcache_p.h4
23 files changed, 315 insertions, 152 deletions
diff --git a/src/gui/painting/qfixed_p.h b/src/gui/painting/qfixed_p.h
index 90d214fe96..7580069153 100644
--- a/src/gui/painting/qfixed_p.h
+++ b/src/gui/painting/qfixed_p.h
@@ -196,6 +196,10 @@ struct QFixedPoint {
constexpr static QFixedPoint fromPointF(const QPointF &p) {
return QFixedPoint(QFixed::fromReal(p.x()), QFixed::fromReal(p.y()));
}
+ constexpr inline bool operator==(const QFixedPoint &other) const
+ {
+ return x == other.x && y == other.y;
+ }
};
Q_DECLARE_TYPEINFO(QFixedPoint, Q_PRIMITIVE_TYPE);
diff --git a/src/gui/painting/qpaintengine.cpp b/src/gui/painting/qpaintengine.cpp
index 5a0d268c1e..42606a93f0 100644
--- a/src/gui/painting/qpaintengine.cpp
+++ b/src/gui/painting/qpaintengine.cpp
@@ -766,7 +766,7 @@ void QPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
bool((painter()->renderHints() & QPainter::TextAntialiasing)
&& !(painter()->font().styleStrategy() & QFont::NoAntialias)));
for (int i = 0; i < ti.glyphs.numGlyphs; ++i) {
- QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixed(), QTransform());
+ QImage glyph = ti.fontEngine->bitmapForGlyph(glyphs[i], QFixedPoint(), QTransform());
painter()->drawImage(positions[i].x.toReal(), positions[i].y.toReal(), glyph);
}
painter()->restore();
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index ca1c4f831e..26f8de5b8b 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -2812,6 +2812,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
+ bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
+ && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
+
if (fontEngine->hasInternalCaching()) {
QFontEngine::GlyphFormat neededFormat =
painter()->device()->devType() == QInternal::Widget
@@ -2822,7 +2825,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
neededFormat = QFontEngine::Format_Mono;
for (int i = 0; i < numGlyphs; i++) {
- QFixed spp = fontEngine->subPixelPositionForX(positions[i].x);
+ QFixedPoint spp = fontEngine->subPixelPositionFor(positions[i]);
+ if (!verticalSubPixelPositions)
+ spp.y = 0;
const QFontEngine::Glyph *alphaMap = fontEngine->glyphData(glyphs[i], spp, neededFormat, s->matrix);
if (!alphaMap)
@@ -2847,9 +2852,13 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
Q_UNREACHABLE();
};
+ QFixed y = verticalSubPixelPositions
+ ? qFloor(positions[i].y)
+ : qRound(positions[i].y);
+
alphaPenBlt(alphaMap->data, bytesPerLine, depth,
qFloor(positions[i].x) + alphaMap->x,
- qRound(positions[i].y) - alphaMap->y,
+ qFloor(y) - alphaMap->y,
alphaMap->width, alphaMap->height,
fontEngine->expectsGammaCorrectedBlending());
}
@@ -2864,7 +2873,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
fontEngine->setGlyphCache(nullptr, cache);
}
- cache->populate(fontEngine, numGlyphs, glyphs, positions);
+ cache->populate(fontEngine, numGlyphs, glyphs, positions, s->renderHints);
cache->fillInPendingGlyphs();
const QImage &image = cache->image();
@@ -2881,15 +2890,20 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
int margin = fontEngine->glyphMargin(glyphFormat);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
+ QFixedPoint subPixelPosition = fontEngine->subPixelPositionFor(positions[i]);
+ if (!verticalSubPixelPositions)
+ subPixelPosition.y = 0;
- QFixed subPixelPosition = fontEngine->subPixelPositionForX(positions[i].x);
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(glyphs[i], subPixelPosition);
const QTextureGlyphCache::Coord &c = cache->coords[glyph];
if (c.isNull())
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qRound(positions[i].y) - c.baseLineY - margin;
+ int y = (verticalSubPixelPositions
+ ? qFloor(positions[i].y)
+ : qRound(positions[i].y));
+ y -= c.baseLineY + margin;
// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
// c.x, c.y,
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index f965761567..38ce9bf604 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -1429,6 +1429,16 @@ void QPainterPrivate::updateState(QPainterState *newState)
a smooth pixmap transformation algorithm (such as bilinear) rather
than nearest neighbor.
+ \value VerticalSubpixelPositioning Allow text to be positioned at fractions
+ of pixels vertically as well as horizontally, if this is supported by the
+ font engine. This is currently supported by Freetype on all platforms when
+ the hinting preference is QFont::PreferNoHinting, and also on macOS. For
+ most use cases this will not improve visual quality, but may increase memory
+ consumption and some reduction in text rendering performance. Therefore, enabling
+ this is not recommended unless the use case requires it. One such use case could
+ be aligning glyphs with other visual primitives.
+ This value was added in Qt 6.1.
+
\value LosslessImageRendering Use a lossless image rendering, whenever possible.
Currently, this hint is only used when QPainter is employed to output a PDF
file through QPrinter or QPdfWriter, where drawImage()/drawPixmap() calls
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index 68f5fc421b..8d471e938d 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -87,6 +87,7 @@ public:
Antialiasing = 0x01,
TextAntialiasing = 0x02,
SmoothPixmapTransform = 0x04,
+ VerticalSubpixelPositioning = 0x08,
LosslessImageRendering = 0x40,
};
Q_FLAG(RenderHint)
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 3728060caf..dfb937ed84 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -64,7 +64,7 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
QImage images[NumSubpixelPositions];
int numImages = 0;
for (int i = 0; i < NumSubpixelPositions; ++i) {
- QImage img = textureMapForGlyph(glyph, QFixed::fromReal(i / 12.0));
+ QImage img = textureMapForGlyph(glyph, QFixedPoint(QFixed::fromReal(i / 12.0), 0));
if (numImages == 0) {
QPainterPath path;
@@ -92,8 +92,11 @@ int QTextureGlyphCache::calculateSubPixelPositionCount(glyph_t glyph) const
return numImages;
}
-bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions)
+bool QTextureGlyphCache::populate(QFontEngine *fontEngine,
+ int numGlyphs,
+ const glyph_t *glyphs,
+ const QFixedPoint *positions,
+ QPainter::RenderHints renderHints)
{
#ifdef CACHE_DEBUG
printf("Populating with %d glyphs\n", numGlyphs);
@@ -105,6 +108,8 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
const int paddingDoubled = padding * 2;
bool supportsSubPixelPositions = fontEngine->supportsSubPixelPositions();
+ bool verticalSubPixelPositions = fontEngine->supportsVerticalSubPixelPositions()
+ && (renderHints & QPainter::VerticalSubpixelPositioning) != 0;
if (fontEngine->m_subPixelPositionCount == 0) {
if (!supportsSubPixelPositions) {
fontEngine->m_subPixelPositionCount = 1;
@@ -127,10 +132,12 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
for (int i=0; i < numGlyphs; ++i) {
const glyph_t glyph = glyphs[i];
- QFixed subPixelPosition;
+ QFixedPoint subPixelPosition;
if (supportsSubPixelPositions) {
- QFixed x = positions != nullptr ? positions[i].x : QFixed();
- subPixelPosition = fontEngine->subPixelPositionForX(x);
+ QFixedPoint pos = positions != nullptr ? positions[i] : QFixedPoint();
+ subPixelPosition = fontEngine->subPixelPositionFor(pos);
+ if (!verticalSubPixelPositions)
+ subPixelPosition.y = 0;
}
if (coords.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
@@ -263,7 +270,7 @@ void QTextureGlyphCache::fillInPendingGlyphs()
m_pendingGlyphs.clear();
}
-QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const
+QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition) const
{
switch (m_format) {
case QFontEngine::Format_A32:
@@ -317,7 +324,9 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
m_image.fill(0);
}
-void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subPixelPosition)
+void QImageTextureGlyphCache::fillTexture(const Coord &c,
+ glyph_t g,
+ const QFixedPoint &subPixelPosition)
{
QImage mask = textureMapForGlyph(g, subPixelPosition);
diff --git a/src/gui/painting/qtextureglyphcache_p.h b/src/gui/painting/qtextureglyphcache_p.h
index e34687d816..a401778a63 100644
--- a/src/gui/painting/qtextureglyphcache_p.h
+++ b/src/gui/painting/qtextureglyphcache_p.h
@@ -83,7 +83,8 @@ public:
struct GlyphAndSubPixelPosition
{
- GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
+ GlyphAndSubPixelPosition(glyph_t g, const QFixedPoint &spp)
+ : glyph(g), subPixelPosition(spp) {}
bool operator==(const GlyphAndSubPixelPosition &other) const
{
@@ -91,7 +92,7 @@ public:
}
glyph_t glyph;
- QFixed subPixelPosition;
+ QFixedPoint subPixelPosition;
};
struct Coord {
@@ -109,8 +110,11 @@ public:
}
};
- bool populate(QFontEngine *fontEngine, int numGlyphs, const glyph_t *glyphs,
- const QFixedPoint *positions);
+ bool populate(QFontEngine *fontEngine,
+ int numGlyphs,
+ const glyph_t *glyphs,
+ const QFixedPoint *positions,
+ QPainter::RenderHints renderHints = QPainter::RenderHints());
bool hasPendingGlyphs() const { return !m_pendingGlyphs.isEmpty(); }
void fillInPendingGlyphs();
@@ -119,7 +123,9 @@ public:
virtual int glyphPadding() const { return 0; }
virtual void beginFillTexture() { }
- virtual void fillTexture(const Coord &coord, glyph_t glyph, QFixed subPixelPosition) = 0;
+ virtual void fillTexture(const Coord &coord,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition) = 0;
virtual void endFillTexture() { }
inline void createCache(int width, int height) {
@@ -141,7 +147,7 @@ public:
virtual int maxTextureWidth() const { return QT_DEFAULT_TEXTURE_GLYPH_CACHE_WIDTH; }
virtual int maxTextureHeight() const { return -1; }
- QImage textureMapForGlyph(glyph_t g, QFixed subPixelPosition) const;
+ QImage textureMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition) const;
protected:
int calculateSubPixelPositionCount(glyph_t) const;
@@ -156,9 +162,12 @@ protected:
int m_currentRowHeight; // Height of last row
};
-inline size_t qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g)
+inline size_t qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g, size_t seed = 0)
{
- return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();
+ return qHashMulti(seed,
+ g.glyph,
+ g.subPixelPosition.x.value(),
+ g.subPixelPosition.y.value());
}
@@ -171,7 +180,9 @@ public:
virtual void createTextureData(int width, int height) override;
virtual void resizeTextureData(int width, int height) override;
- virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) override;
+ virtual void fillTexture(const Coord &c,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition) override;
inline const QImage &image() const { return m_image; }
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm
index 0070e18ade..33a3f22e67 100644
--- a/src/gui/text/coretext/qfontengine_coretext.mm
+++ b/src/gui/text/coretext/qfontengine_coretext.mm
@@ -531,7 +531,7 @@ static void qcoretextfontengine_scaleMetrics(glyph_metrics_t &br, const QTransfo
}
}
-glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, GlyphFormat format)
+glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, GlyphFormat format)
{
if (matrix.type() > QTransform::TxScale)
return QFontEngine::alphaMapBoundingBox(glyph, subPixelPosition, matrix, format);
@@ -713,7 +713,7 @@ qreal QCoreTextFontEngine::fontSmoothingGamma()
return 2.0;
}
-QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, const QColor &color)
+QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, const QColor &color)
{
glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat);
@@ -773,8 +773,9 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(matrix.m11(), matrix.m22()));
CGGlyph cgGlyph = glyph;
- qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
- qreal pos_y = im.height() + br.y.toReal();
+
+ qreal pos_x = -br.x.truncate() + subPixelPosition.x.toReal();
+ qreal pos_y = im.height() + br.y.toReal() - subPixelPosition.y.toReal();
if (!hasColorGlyphs()) {
CGContextSetTextMatrix(ctx, cgMatrix);
@@ -817,12 +818,12 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
return im;
}
-QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition)
{
return alphaMapForGlyph(glyph, subPixelPosition, QTransform());
}
-QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x)
+QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &x)
{
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x);
@@ -844,7 +845,7 @@ QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosit
return alphaMap;
}
-QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x)
+QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &x)
{
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x);
@@ -852,7 +853,7 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
return imageForGlyph(glyph, subPixelPosition, x);
}
-QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color)
+QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color)
{
if (t.type() > QTransform::TxScale)
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t, color);
diff --git a/src/gui/text/coretext/qfontengine_coretext_p.h b/src/gui/text/coretext/qfontengine_coretext_p.h
index 1239072677..361153b37a 100644
--- a/src/gui/text/coretext/qfontengine_coretext_p.h
+++ b/src/gui/text/coretext/qfontengine_coretext_p.h
@@ -91,7 +91,8 @@ public:
bool canRender(const QChar *string, int len) const override;
int synthesized() const override { return synthesisFlags; }
- bool supportsSubPixelPositions() const override { return true; }
+ bool supportsHorizontalSubPixelPositions() const override { return true; }
+ bool supportsVerticalSubPixelPositions() const override { return false; }
QFixed lineThickness() const override;
QFixed underlinePosition() const override;
@@ -101,11 +102,11 @@ public:
FaceId faceId() const override;
bool getSfntTableData(uint /*tag*/, uchar * /*buffer*/, uint * /*length*/) const override;
void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics) override;
- QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition) override;
- QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override;
- QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
- glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override;
- QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
+ QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition) override;
+ QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t) override;
+ QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
+ glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &, const QTransform &matrix, GlyphFormat) override;
+ QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color) override;
QFixed emSquareSize() const override;
void doKerning(QGlyphLayout *g, ShaperFlags flags) const override;
@@ -132,7 +133,7 @@ public:
protected:
QCoreTextFontEngine(const QFontDef &def);
void init();
- QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m, const QColor &color = QColor());
+ QImage imageForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &m, const QColor &color = QColor());
void loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const;
bool hasColorGlyphs() const;
bool shouldAntialias() const;
diff --git a/src/gui/text/freetype/qfontengine_ft.cpp b/src/gui/text/freetype/qfontengine_ft.cpp
index 2937857f71..42985fcaa6 100644
--- a/src/gui/text/freetype/qfontengine_ft.cpp
+++ b/src/gui/text/freetype/qfontengine_ft.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -943,7 +943,7 @@ static inline void transformBoundingBox(int *left, int *top, int *right, int *bo
}
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
- QFixed subPixelPosition,
+ const QFixedPoint &subPixelPosition,
GlyphFormat format,
bool fetchMetricsOnly,
bool disableOutlineDrawing) const
@@ -967,8 +967,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
FT_Matrix matrix = freetype->matrix;
FT_Vector v;
- v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.value());
- v.y = 0;
+ v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.x.value());
+ v.y = format == Format_Mono ? 0 : FT_Pos(-subPixelPosition.y.value());
FT_Set_Transform(face, &matrix, &v);
bool hsubpixel = false;
@@ -1644,7 +1644,11 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag
} else {
if (!face)
face = lockFace();
- g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyphs->glyphs[i], 0, Format_None, true);
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
+ glyphs->glyphs[i],
+ QFixedPoint(),
+ Format_None,
+ true);
if (g)
glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
else
@@ -1685,7 +1689,11 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
if (!g) {
if (!face)
face = lockFace();
- g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyphs.glyphs[i], 0, Format_None, true);
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
+ glyphs.glyphs[i],
+ QFixedPoint(),
+ Format_None,
+ true);
}
if (g) {
QFixed x = overall.xoff + glyphs.offsets[i].x + g->x;
@@ -1730,7 +1738,11 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
Glyph *g = cacheEnabled ? defaultGlyphSet.getGlyph(glyph) : nullptr;
if (!g) {
face = lockFace();
- g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, 0, Format_None, true);
+ g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
+ glyph,
+ QFixedPoint(),
+ Format_None,
+ true);
}
if (g) {
overall.x = g->x;
@@ -1762,10 +1774,13 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph, const QTransform &matrix)
{
- return alphaMapBoundingBox(glyph, 0, matrix, QFontEngine::Format_None);
+ return alphaMapBoundingBox(glyph, QFixedPoint(), matrix, QFontEngine::Format_None);
}
-glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, QFontEngine::GlyphFormat format)
+glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &matrix,
+ QFontEngine::GlyphFormat format)
{
Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true);
@@ -1828,8 +1843,10 @@ static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEng
return img;
}
-QFontEngine::Glyph *QFontEngineFT::glyphData(glyph_t glyphIndex, QFixed subPixelPosition,
- QFontEngine::GlyphFormat neededFormat, const QTransform &t)
+QFontEngine::Glyph *QFontEngineFT::glyphData(glyph_t glyphIndex,
+ const QFixedPoint &subPixelPosition,
+ QFontEngine::GlyphFormat neededFormat,
+ const QTransform &t)
{
Q_ASSERT(cacheEnabled);
@@ -1854,7 +1871,7 @@ static inline bool is2dRotation(const QTransform &t)
}
QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
- QFixed subPixelPosition,
+ const QFixedPoint &subPixelPosition,
GlyphFormat format,
const QTransform &t,
bool fetchBoundingBox,
@@ -1882,12 +1899,14 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
return glyph;
}
-QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
+QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, const QFixedPoint &subPixelPosition)
{
return alphaMapForGlyph(g, subPixelPosition, QTransform());
}
-QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineFT::alphaMapForGlyph(glyph_t g,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono;
@@ -1902,7 +1921,9 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const
return img;
}
-QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
if (t.type() > QTransform::TxRotate)
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
@@ -1923,7 +1944,10 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, co
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
}
-QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t, const QColor &color)
+QImage QFontEngineFT::bitmapForGlyph(glyph_t g,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t,
+ const QColor &color)
{
Q_UNUSED(color);
@@ -1952,7 +1976,7 @@ QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const Q
void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
{
- defaultGlyphSet.removeGlyphFromCache(glyph, 0);
+ defaultGlyphSet.removeGlyphFromCache(glyph, QFixedPoint());
}
int QFontEngineFT::glyphCount() const
@@ -2033,7 +2057,8 @@ void QFontEngineFT::QGlyphSet::clear()
glyph_data.clear();
}
-void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPixelPosition)
+void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index,
+ const QFixedPoint &subPixelPosition)
{
if (useFastGlyphData(index, subPixelPosition)) {
if (fast_glyph_data[index]) {
@@ -2047,7 +2072,9 @@ void QFontEngineFT::QGlyphSet::removeGlyphFromCache(glyph_t index, QFixed subPix
}
}
-void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index, QFixed subPixelPosition, Glyph *glyph)
+void QFontEngineFT::QGlyphSet::setGlyph(glyph_t index,
+ const QFixedPoint &subPixelPosition,
+ Glyph *glyph)
{
if (useFastGlyphData(index, subPixelPosition)) {
if (!fast_glyph_data[index])
diff --git a/src/gui/text/freetype/qfontengine_ft_p.h b/src/gui/text/freetype/qfontengine_ft_p.h
index 8962327cd1..e9234e7d69 100644
--- a/src/gui/text/freetype/qfontengine_ft_p.h
+++ b/src/gui/text/freetype/qfontengine_ft_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -143,7 +143,7 @@ public:
struct GlyphAndSubPixelPosition
{
- GlyphAndSubPixelPosition(glyph_t g, QFixed spp) : glyph(g), subPixelPosition(spp) {}
+ GlyphAndSubPixelPosition(glyph_t g, const QFixedPoint spp) : glyph(g), subPixelPosition(spp) {}
bool operator==(const GlyphAndSubPixelPosition &other) const
{
@@ -151,7 +151,7 @@ public:
}
glyph_t glyph;
- QFixed subPixelPosition;
+ QFixedPoint subPixelPosition;
};
struct QGlyphSet
@@ -161,13 +161,14 @@ public:
FT_Matrix transformationMatrix;
bool outline_drawing;
- void removeGlyphFromCache(glyph_t index, QFixed subPixelPosition);
+ void removeGlyphFromCache(glyph_t index, const QFixedPoint &subPixelPosition);
void clear();
- inline bool useFastGlyphData(glyph_t index, QFixed subPixelPosition) const {
- return (index < 256 && subPixelPosition == 0);
+ inline bool useFastGlyphData(glyph_t index, const QFixedPoint &subPixelPosition) const {
+ return (index < 256 && subPixelPosition.x == 0 && subPixelPosition.y == 0);
}
- inline Glyph *getGlyph(glyph_t index, QFixed subPixelPosition = 0) const;
- void setGlyph(glyph_t index, QFixed spp, Glyph *glyph);
+ inline Glyph *getGlyph(glyph_t index,
+ const QFixedPoint &subPixelPositionX = QFixedPoint()) const;
+ void setGlyph(glyph_t index, const QFixedPoint &spp, Glyph *glyph);
inline bool isGlyphMissing(glyph_t index) const { return missing_glyphs.contains(index); }
inline void setGlyphMissing(glyph_t index) const { missing_glyphs.insert(index); }
@@ -182,12 +183,17 @@ private:
QFontEngine::FaceId faceId() const override;
QFontEngine::Properties properties() const override;
QFixed emSquareSize() const override;
- bool supportsSubPixelPositions() const override
+ bool supportsHorizontalSubPixelPositions() const override
{
return default_hint_style == HintLight ||
default_hint_style == HintNone;
}
+ bool supportsVerticalSubPixelPositions() const override
+ {
+ return supportsHorizontalSubPixelPositions();
+ }
+
bool getSfntTableData(uint tag, uchar *buffer, uint *length) const override;
int synthesized() const override;
@@ -219,17 +225,19 @@ private:
glyph_metrics_t boundingBox(glyph_t glyph, const QTransform &matrix) override;
void recalcAdvances(QGlyphLayout *glyphs, ShaperFlags flags) const override;
- QImage alphaMapForGlyph(glyph_t g) override { return alphaMapForGlyph(g, 0); }
- QImage alphaMapForGlyph(glyph_t, QFixed) override;
- QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override;
- QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
- QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
+ QImage alphaMapForGlyph(glyph_t g) override { return alphaMapForGlyph(g, QFixedPoint()); }
+ QImage alphaMapForGlyph(glyph_t, const QFixedPoint &) override;
+ QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t) override;
+ QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
+ QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color) override;
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
- QFixed subPixelPosition,
+ const QFixedPoint &subPixelPosition,
const QTransform &matrix,
QFontEngine::GlyphFormat format) override;
- Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition,
- GlyphFormat neededFormat, const QTransform &t) override;
+ Glyph *glyphData(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ GlyphFormat neededFormat,
+ const QTransform &t) override;
bool hasInternalCaching() const override { return cacheEnabled; }
bool expectsGammaCorrectedBlending() const override;
@@ -252,10 +260,24 @@ private:
inline bool isBitmapFont() const { return defaultFormat == Format_Mono; }
inline bool isScalableBitmap() const { return freetype->isScalableBitmap(); }
- inline Glyph *loadGlyph(uint glyph, QFixed subPixelPosition, GlyphFormat format = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const
+ inline Glyph *loadGlyph(uint glyph,
+ const QFixedPoint &subPixelPosition,
+ GlyphFormat format = Format_None,
+ bool fetchMetricsOnly = false,
+ bool disableOutlineDrawing = false) const
{ return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
- Glyph *loadGlyph(QGlyphSet *set, uint glyph, QFixed subPixelPosition, GlyphFormat = Format_None, bool fetchMetricsOnly = false, bool disableOutlineDrawing = false) const;
- Glyph *loadGlyphFor(glyph_t g, QFixed subPixelPosition, GlyphFormat format, const QTransform &t, bool fetchBoundingBox = false, bool disableOutlineDrawing = false);
+ Glyph *loadGlyph(QGlyphSet *set,
+ uint glyph,
+ const QFixedPoint &subPixelPosition,
+ GlyphFormat = Format_None,
+ bool fetchMetricsOnly = false,
+ bool disableOutlineDrawing = false) const;
+ Glyph *loadGlyphFor(glyph_t g,
+ const QFixedPoint &subPixelPosition,
+ GlyphFormat format,
+ const QTransform &t,
+ bool fetchBoundingBox = false,
+ bool disableOutlineDrawing = false);
QGlyphSet *loadGlyphSet(const QTransform &matrix);
@@ -341,12 +363,16 @@ private:
Q_DECLARE_TYPEINFO(QFontEngineFT::QGlyphSet, Q_RELOCATABLE_TYPE);
-inline size_t qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g)
+inline size_t qHash(const QFontEngineFT::GlyphAndSubPixelPosition &g, size_t seed)
{
- return (g.glyph << 8) | (g.subPixelPosition * 10).round().toInt();
+ return qHashMulti(seed,
+ g.glyph,
+ g.subPixelPosition.x.value(),
+ g.subPixelPosition.y.value());
}
-inline QFontEngineFT::Glyph *QFontEngineFT::QGlyphSet::getGlyph(glyph_t index, QFixed subPixelPosition) const
+inline QFontEngineFT::Glyph *QFontEngineFT::QGlyphSet::getGlyph(glyph_t index,
+ const QFixedPoint &subPixelPosition) const
{
if (useFastGlyphData(index, subPixelPosition))
return fast_glyph_data[index];
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index c621d7bab8..a3fdfd63d1 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -780,7 +780,7 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine)
const glyph_t glyph = fe->glyphIndex('O');
if (glyph != 0)
- im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
+ im = fe->alphaMapForGlyph(glyph, QFixedPoint(), QTransform());
Q_ASSERT(fe->ref.loadRelaxed() == 0);
delete fe;
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index d526dcc7ac..0a8de97b38 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -796,7 +796,7 @@ void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int n
addBitmapFontToPath(x, y, g, path, flags);
}
-QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)
+QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/)
{
// For font engines don't support subpixel positioning
return alphaMapForGlyph(glyph);
@@ -812,9 +812,9 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
return i;
}
-QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t)
{
- if (! supportsSubPixelPositions())
+ if (!supportsHorizontalSubPixelPositions() && !supportsVerticalSubPixelPositions())
return alphaMapForGlyph(glyph, t);
QImage i = alphaMapForGlyph(glyph, subPixelPosition);
@@ -825,7 +825,7 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, con
return i;
}
-QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)
+QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/, const QTransform &t)
{
const QImage alphaMask = alphaMapForGlyph(glyph, t);
QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
@@ -842,32 +842,37 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition
return rgbMask;
}
-QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&, const QColor &)
+QImage QFontEngine::bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform&, const QColor &)
{
Q_UNUSED(subPixelPosition);
return QImage();
}
-QFixed QFontEngine::subPixelPositionForX(QFixed x) const
+QFixedPoint QFontEngine::subPixelPositionFor(const QFixedPoint &position) const
{
- if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
- return QFixed();
+ if (m_subPixelPositionCount <= 1
+ || (!supportsHorizontalSubPixelPositions()
+ && !supportsVerticalSubPixelPositions())) {
+ return QFixedPoint();
+ }
- QFixed subPixelPosition;
- if (x != 0) {
- subPixelPosition = x - x.floor();
- QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
+ auto f = [&](QFixed v) {
+ if (v != 0) {
+ v = v - v.floor() + QFixed::fromFixed(1);
+ QFixed fraction = (v / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
+ v = fraction / QFixed(m_subPixelPositionCount);
+ }
+ return v;
+ };
- // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
- // the lower boundary for the selected rasterization by adding 1/64.
- subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
- }
- return subPixelPosition;
+ return QFixedPoint(f(position.x), f(position.y));
}
-QFontEngine::Glyph *QFontEngine::glyphData(glyph_t, QFixed,
- QFontEngine::GlyphFormat, const QTransform &)
+QFontEngine::Glyph *QFontEngine::glyphData(glyph_t,
+ const QFixedPoint &,
+ QFontEngine::GlyphFormat,
+ const QTransform &)
{
return nullptr;
}
@@ -2215,7 +2220,7 @@ QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
return engine(which)->alphaMapForGlyph(stripped(glyph));
}
-QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition)
{
const int which = highByte(glyph);
return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
@@ -2227,13 +2232,17 @@ QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
return engine(which)->alphaMapForGlyph(stripped(glyph), t);
}
-QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
const int which = highByte(glyph);
return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
}
-QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
const int which = highByte(glyph);
return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 9b71a2fd0d..1169e0b779 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2016 The Qt Company Ltd.
+** Copyright (C) 2021 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module of the Qt Toolkit.
@@ -176,8 +176,17 @@ public:
SynthesizedStretch = 0x4
};
virtual int synthesized() const { return 0; }
- virtual bool supportsSubPixelPositions() const { return false; }
- virtual QFixed subPixelPositionForX(QFixed x) const;
+ inline bool supportsSubPixelPositions() const
+ {
+ return supportsHorizontalSubPixelPositions() || supportsVerticalSubPixelPositions();
+ }
+ virtual bool supportsHorizontalSubPixelPositions() const { return false; }
+ virtual bool supportsVerticalSubPixelPositions() const { return false; }
+ virtual QFixedPoint subPixelPositionFor(const QFixedPoint &position) const;
+ QFixed subPixelPositionForX(const QFixed &x) const
+ {
+ return subPixelPositionFor(QFixedPoint(x, 0)).x;
+ }
virtual QFixed emSquareSize() const { return ascent(); }
@@ -201,15 +210,15 @@ public:
*/
// ### Refactor this into a smaller and more flexible API.
virtual QImage alphaMapForGlyph(glyph_t);
- virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition);
+ virtual QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition);
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t);
- virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
- virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
- virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color = QColor());
- virtual Glyph *glyphData(glyph_t glyph, QFixed subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
+ virtual QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
+ virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t);
+ virtual QImage bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color = QColor());
+ virtual Glyph *glyphData(glyph_t glyph, const QFixedPoint &subPixelPosition, GlyphFormat neededFormat, const QTransform &t);
virtual bool hasInternalCaching() const { return false; }
- virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/)
+ virtual glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/, const QTransform &matrix, GlyphFormat /*format*/)
{
return boundingBox(glyph, matrix);
}
@@ -472,10 +481,10 @@ public:
virtual QFixed xHeight() const override;
virtual QFixed averageCharWidth() const override;
virtual QImage alphaMapForGlyph(glyph_t) override;
- virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override;
+ virtual QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition) override;
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t) override;
- virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
- virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t) override;
+ virtual QImage alphaMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
+ virtual QImage alphaRGBMapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform &t) override;
virtual QFixed lineThickness() const override;
virtual QFixed underlinePosition() const override;
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index 918cec6fa2..00a2939e79 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -281,12 +281,12 @@ QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialias
return QImage();
if (d->fontEngine->glyphFormat == QFontEngine::Format_ARGB)
- return d->fontEngine->bitmapForGlyph(glyphIndex, QFixed(), transform);
+ return d->fontEngine->bitmapForGlyph(glyphIndex, QFixedPoint(), transform);
if (antialiasingType == SubPixelAntialiasing)
- return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), transform);
+ return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixedPoint(), transform);
- return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform);
+ return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixedPoint(), transform);
}
/*!
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index d3a28d8d02..f8ce0ba8af 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -1736,7 +1736,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si,
g.glyphs[i] |= (engineIdx << 24);
}
- if (!actualFontEngine->supportsSubPixelPositions()) {
+ if (!actualFontEngine->supportsHorizontalSubPixelPositions()) {
for (uint i = 0; i < num_glyphs; ++i)
g.advances[i] = g.advances[i].round();
}
diff --git a/src/gui/text/windows/qwindowsfontengine.cpp b/src/gui/text/windows/qwindowsfontengine.cpp
index 3335fcdc99..f4ef9f8a23 100644
--- a/src/gui/text/windows/qwindowsfontengine.cpp
+++ b/src/gui/text/windows/qwindowsfontengine.cpp
@@ -1043,7 +1043,10 @@ QWindowsNativeImage *QWindowsFontEngine::drawGDIGlyph(HFONT font, glyph_t glyph,
return ni;
}
-glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat format)
+glyph_metrics_t QWindowsFontEngine::alphaMapBoundingBox(glyph_t glyph,
+ const QFixedPoint &,
+ const QTransform &matrix,
+ GlyphFormat format)
{
int margin = 0;
if (format == QFontEngine::Format_A32 || format == QFontEngine::Format_ARGB)
@@ -1108,7 +1111,9 @@ QImage QWindowsFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &xfo
#define SPI_GETFONTSMOOTHINGCONTRAST 0x200C
#define SPI_SETFONTSMOOTHINGCONTRAST 0x200D
-QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed, const QTransform &t)
+QImage QWindowsFontEngine::alphaRGBMapForGlyph(glyph_t glyph,
+ const QFixedPoint &,
+ const QTransform &t)
{
HFONT font = hfont;
diff --git a/src/gui/text/windows/qwindowsfontengine_p.h b/src/gui/text/windows/qwindowsfontengine_p.h
index 22130924ad..57b619bc1c 100644
--- a/src/gui/text/windows/qwindowsfontengine_p.h
+++ b/src/gui/text/windows/qwindowsfontengine_p.h
@@ -107,8 +107,13 @@ public:
QImage alphaMapForGlyph(glyph_t t) override { return alphaMapForGlyph(t, QTransform()); }
QImage alphaMapForGlyph(glyph_t, const QTransform &xform) override;
- QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override;
- glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed, const QTransform &matrix, GlyphFormat) override;
+ QImage alphaRGBMapForGlyph(glyph_t t,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &xform) override;
+ glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
+ const QFixedPoint &,
+ const QTransform &matrix,
+ GlyphFormat) override;
QFontEngine *cloneWithSize(qreal pixelSize) const override;
Qt::HANDLE handle() const override;
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
index c17139ab8b..20063a0610 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite.cpp
@@ -602,7 +602,9 @@ qreal QWindowsFontEngineDirectWrite::maxCharWidth() const
return m_maxAdvanceWidth.toReal();
}
-QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
QImage im = imageForGlyph(glyph, subPixelPosition, glyphMargin(Format_A8), t);
@@ -621,21 +623,22 @@ QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed sub
return alphaMap;
}
-QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+QImage QWindowsFontEngineDirectWrite::alphaMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition)
{
return alphaMapForGlyph(glyph, subPixelPosition, QTransform());
}
-bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const
+bool QWindowsFontEngineDirectWrite::supportsHorizontalSubPixelPositions() const
{
return true;
}
QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
- QFixed subPixelPosition,
- int margin,
- const QTransform &originalTransform,
- const QColor &color)
+ const QFixedPoint &subPixelPosition,
+ int margin,
+ const QTransform &originalTransform,
+ const QColor &color)
{
UINT16 glyphIndex = t;
FLOAT glyphAdvance = 0;
@@ -659,7 +662,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
xform.scale(fontDef.stretch / 100.0, 1.0);
DWRITE_MATRIX transform;
- transform.dx = subPixelPosition.toReal();
+ transform.dx = subPixelPosition.x.toReal();
transform.dy = 0;
transform.m11 = xform.m11();
transform.m12 = xform.m12();
@@ -880,7 +883,7 @@ void QWindowsFontEngineDirectWrite::renderGlyphRun(QImage *destination,
}
QImage QWindowsFontEngineDirectWrite::alphaRGBMapForGlyph(glyph_t t,
- QFixed subPixelPosition,
+ const QFixedPoint &subPixelPosition,
const QTransform &xform)
{
QImage mask = imageForGlyph(t,
@@ -936,7 +939,7 @@ QString QWindowsFontEngineDirectWrite::fontNameSubstitute(const QString &familyN
}
glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph,
- QFixed subPixelPosition,
+ const QFixedPoint &subPixelPosition,
const QTransform &originalTransform,
GlyphFormat format)
{
@@ -966,7 +969,7 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
glyphRun.glyphOffsets = &glyphOffset;
DWRITE_MATRIX transform;
- transform.dx = subPixelPosition.toReal();
+ transform.dx = subPixelPosition.x.toReal();
transform.dy = 0;
transform.m11 = matrix.m11();
transform.m12 = matrix.m12();
@@ -1008,7 +1011,10 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
}
}
-QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color)
+QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t,
+ const QColor &color)
{
return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_ARGB), t, color);
}
diff --git a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
index 5be021d37a..4d19c3908a 100644
--- a/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
+++ b/src/gui/text/windows/qwindowsfontenginedirectwrite_p.h
@@ -97,7 +97,7 @@ public:
glyph_metrics_t boundingBox(const QGlyphLayout &glyphs) override;
glyph_metrics_t boundingBox(glyph_t g) override;
- glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, QFixed,
+ glyph_metrics_t alphaMapBoundingBox(glyph_t glyph, const QFixedPoint&,
const QTransform &matrix, GlyphFormat) override;
QFixed capHeight() const override;
@@ -105,12 +105,19 @@ public:
qreal maxCharWidth() const override;
FaceId faceId() const override;
- bool supportsSubPixelPositions() const override;
+ bool supportsHorizontalSubPixelPositions() const override;
- QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition) override;
- QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t) override;
- QImage alphaRGBMapForGlyph(glyph_t t, QFixed subPixelPosition, const QTransform &xform) override;
- QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
+ QImage alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition) override;
+ QImage alphaMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t) override;
+ QImage alphaRGBMapForGlyph(glyph_t t,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &xform) override;
+ QImage bitmapForGlyph(glyph_t,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t,
+ const QColor &color) override;
QFontEngine *cloneWithSize(qreal pixelSize) const override;
Qt::HANDLE handle() const override;
@@ -126,7 +133,11 @@ public:
void initializeHeightMetrics() const override;
private:
- QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform, const QColor &color = QColor());
+ QImage imageForGlyph(glyph_t t,
+ const QFixedPoint &subPixelPosition,
+ int margin,
+ const QTransform &xform,
+ const QColor &color = QColor());
void collectMetrics();
void renderGlyphRun(QImage *destination, float r, float g, float b, float a, IDWriteGlyphRunAnalysis *glyphAnalysis, const QRect &boundingRect);
static QString filenameFromFontFile(IDWriteFontFile *fontFile);
diff --git a/src/opengl/qopenglpaintengine.cpp b/src/opengl/qopenglpaintengine.cpp
index 3bb3496de5..9c8325ca11 100644
--- a/src/opengl/qopenglpaintengine.cpp
+++ b/src/opengl/qopenglpaintengine.cpp
@@ -1797,11 +1797,13 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
if (recreateVertexArrays) {
cache->setPaintEnginePrivate(this);
if (!cache->populate(fe, staticTextItem->numGlyphs,
- staticTextItem->glyphs, staticTextItem->glyphPositions)) {
+ staticTextItem->glyphs, staticTextItem->glyphPositions,
+ s->renderHints)) {
// No space for glyphs in cache. We need to reset it and try again.
cache->clear();
cache->populate(fe, staticTextItem->numGlyphs,
- staticTextItem->glyphs, staticTextItem->glyphPositions);
+ staticTextItem->glyphs, staticTextItem->glyphPositions,
+ s->renderHints);
}
if (cache->hasPendingGlyphs()) {
@@ -1874,10 +1876,15 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
textureCoordinates->clear();
bool supportsSubPixelPositions = fe->supportsSubPixelPositions();
+ bool verticalSubPixelPositions = fe->supportsVerticalSubPixelPositions()
+ && (s->renderHints & QPainter::VerticalSubpixelPositioning) != 0;
for (int i=0; i<staticTextItem->numGlyphs; ++i) {
- QFixed subPixelPosition;
- if (supportsSubPixelPositions)
- subPixelPosition = fe->subPixelPositionForX(staticTextItem->glyphPositions[i].x);
+ QFixedPoint subPixelPosition;
+ if (supportsSubPixelPositions) {
+ subPixelPosition = fe->subPixelPositionFor(staticTextItem->glyphPositions[i]);
+ if (!verticalSubPixelPositions)
+ subPixelPosition.y = 0;
+ }
QTextureGlyphCache::GlyphAndSubPixelPosition glyph(staticTextItem->glyphs[i], subPixelPosition);
@@ -1886,7 +1893,10 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngine::GlyphFormat gly
continue;
int x = qFloor(staticTextItem->glyphPositions[i].x.toReal() * cache->transform().m11()) + c.baseLineX - margin;
- int y = qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22()) - c.baseLineY - margin;
+ int y = verticalSubPixelPositions
+ ? qRound(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22())
+ : qFloor(staticTextItem->glyphPositions[i].y.toReal() * cache->transform().m22());
+ y -= c.baseLineY + margin;
vertexCoordinates->addQuad(QRectF(x, y, c.w, c.h));
textureCoordinates->addQuad(QRectF(c.x*dx, c.y*dy, c.w * dx, c.h * dy));
diff --git a/src/opengl/qopengltextureglyphcache.cpp b/src/opengl/qopengltextureglyphcache.cpp
index a38d4328cc..6c8971fddb 100644
--- a/src/opengl/qopengltextureglyphcache.cpp
+++ b/src/opengl/qopengltextureglyphcache.cpp
@@ -421,7 +421,9 @@ void QOpenGLTextureGlyphCache::resizeTextureData(int width, int height)
}
}
-void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition)
+void QOpenGLTextureGlyphCache::fillTexture(const Coord &c,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition)
{
QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (ctx == nullptr) {
diff --git a/src/opengl/qopengltextureglyphcache_p.h b/src/opengl/qopengltextureglyphcache_p.h
index 15ecd6209b..5b30881e55 100644
--- a/src/opengl/qopengltextureglyphcache_p.h
+++ b/src/opengl/qopengltextureglyphcache_p.h
@@ -115,7 +115,9 @@ public:
virtual void createTextureData(int width, int height) override;
virtual void resizeTextureData(int width, int height) override;
- virtual void fillTexture(const Coord &c, glyph_t glyph, QFixed subPixelPosition) override;
+ virtual void fillTexture(const Coord &c,
+ glyph_t glyph,
+ const QFixedPoint &subPixelPosition) override;
virtual int glyphPadding() const override;
virtual int maxTextureWidth() const override;
virtual int maxTextureHeight() const override;