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>
This commit is contained in:
Eskil Abrahamsen Blomfeldt 2021-01-15 09:11:07 +01:00
parent 80e87ca05c
commit d79a9b1a4f
23 changed files with 316 additions and 153 deletions

View File

@ -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);

View File

@ -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();

View File

@ -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,

View File

@ -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

View File

@ -87,6 +87,7 @@ public:
Antialiasing = 0x01,
TextAntialiasing = 0x02,
SmoothPixmapTransform = 0x04,
VerticalSubpixelPositioning = 0x08,
LosslessImageRendering = 0x40,
};
Q_FLAG(RenderHint)

View File

@ -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);

View File

@ -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; }

View File

@ -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);

View File

@ -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;

View File

@ -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])

View File

@ -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];

View File

@ -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;

View File

@ -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();
QFixed subPixelPosition;
if (x != 0) {
subPixelPosition = x - x.floor();
QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
// 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;
if (m_subPixelPositionCount <= 1
|| (!supportsHorizontalSubPixelPositions()
&& !supportsVerticalSubPixelPositions())) {
return QFixedPoint();
}
QFontEngine::Glyph *QFontEngine::glyphData(glyph_t, QFixed,
QFontEngine::GlyphFormat, const QTransform &)
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;
};
return QFixedPoint(f(position.x), f(position.y));
}
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);

View File

@ -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;

View File

@ -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);
}
/*!

View File

@ -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();
}

View File

@ -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;

View File

@ -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;

View File

@ -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,18 +623,19 @@ 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,
const QFixedPoint &subPixelPosition,
int margin,
const QTransform &originalTransform,
const QColor &color)
@ -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);
}

View File

@ -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);

View File

@ -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));

View File

@ -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) {

View File

@ -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;