Support pen color with color fonts

Color fonts may also contain regular alphabet characters that
should be rendered with the current pen. In Qt, however, these
characters were drawn into the cache with a default pen color
of black.

Since all characters in a font is currently backed by the same cache,
and it would require a lot of plumbing to get around this, a step
in the right direction is to include the current pen color in the
cache as long as it is an RGB cache. This means that drawing
text with the color font with different pen colors will create
different caches.

There is no API to select font color on Freetype currently, but
this problem has also not been observed there, as the fonts
in question, with both regular and color glyphs, are not being
detected as color fonts (so the text color will be correct).
So Freetype will be left out for now.

[ChangeLog][QtGui][Text] Fixed bug where regular text rendered
with a color font would always display in black.

Task-number: QTBUG-55096
Task-number: QTBUG-74761
Change-Id: Icc7dbf73241db1e7cc6a0de18c2de927aeecf713
Reviewed-by: Tor Arne Vestbø <tor.arne.vestbo@qt.io>
bb10
Eskil Abrahamsen Blomfeldt 2019-06-20 14:52:19 +02:00
parent 72ebc7458d
commit 78caba7ae6
12 changed files with 69 additions and 34 deletions

View File

@ -2927,9 +2927,9 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
QFontEngine::GlyphFormat glyphFormat = fontEngine->glyphFormat != QFontEngine::Format_None ? fontEngine->glyphFormat : d->glyphCacheFormat;
QImageTextureGlyphCache *cache =
static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphFormat, s->matrix));
static_cast<QImageTextureGlyphCache *>(fontEngine->glyphCache(0, glyphFormat, s->matrix, QColor(s->penData.solid.color)));
if (!cache) {
cache = new QImageTextureGlyphCache(glyphFormat, s->matrix);
cache = new QImageTextureGlyphCache(glyphFormat, s->matrix, QColor(s->penData.solid.color));
fontEngine->setGlyphCache(0, cache);
}

View File

@ -267,7 +267,7 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition
case QFontEngine::Format_A32:
return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, m_transform);
case QFontEngine::Format_ARGB:
return m_current_fontengine->bitmapForGlyph(g, subPixelPosition, m_transform);
return m_current_fontengine->bitmapForGlyph(g, subPixelPosition, m_transform, color());
default:
return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform);
}

View File

@ -74,8 +74,8 @@ class QTextItemInt;
class Q_GUI_EXPORT QTextureGlyphCache : public QFontEngineGlyphCache
{
public:
QTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix)
: QFontEngineGlyphCache(format, matrix), m_current_fontengine(0),
QTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix, const QColor &color = QColor())
: QFontEngineGlyphCache(format, matrix, color), m_current_fontengine(0),
m_w(0), m_h(0), m_cx(0), m_cy(0), m_currentRowHeight(0)
{ }
@ -165,8 +165,8 @@ inline uint qHash(const QTextureGlyphCache::GlyphAndSubPixelPosition &g)
class Q_GUI_EXPORT QImageTextureGlyphCache : public QTextureGlyphCache
{
public:
QImageTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix)
: QTextureGlyphCache(format, matrix) { }
QImageTextureGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix, const QColor &color = QColor())
: QTextureGlyphCache(format, matrix, color) { }
~QImageTextureGlyphCache();
virtual void createTextureData(int width, int height) override;

View File

@ -899,7 +899,7 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition
return rgbMask;
}
QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&)
QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&, const QColor &)
{
Q_UNUSED(subPixelPosition);
@ -1075,7 +1075,10 @@ void QFontEngine::setGlyphCache(const void *context, QFontEngineGlyphCache *cach
}
QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context, GlyphFormat format, const QTransform &transform) const
QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context,
GlyphFormat format,
const QTransform &transform,
const QColor &color) const
{
const QHash<const void*, GlyphCaches>::const_iterator caches = m_glyphCaches.constFind(context);
if (caches == m_glyphCaches.cend())
@ -1083,8 +1086,11 @@ QFontEngineGlyphCache *QFontEngine::glyphCache(const void *context, GlyphFormat
for (GlyphCaches::const_iterator it = caches->begin(), end = caches->end(); it != end; ++it) {
QFontEngineGlyphCache *cache = it->cache.data();
if (format == cache->glyphFormat() && qtransform_equals_no_translate(cache->m_transform, transform))
if (format == cache->glyphFormat()
&& (format != Format_ARGB || color == cache->color())
&& qtransform_equals_no_translate(cache->m_transform, transform)) {
return cache;
}
}
return nullptr;

View File

@ -190,7 +190,7 @@ public:
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);
virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color = QColor());
virtual QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
GlyphFormat neededFormat,
const QTransform &t = QTransform(),
@ -252,7 +252,7 @@ public:
void clearGlyphCache(const void *key);
void setGlyphCache(const void *key, QFontEngineGlyphCache *data);
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform) const;
QFontEngineGlyphCache *glyphCache(const void *key, GlyphFormat format, const QTransform &transform, const QColor &color = QColor()) const;
static const uchar *getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize);
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode);

View File

@ -65,7 +65,10 @@ QT_BEGIN_NAMESPACE
class Q_GUI_EXPORT QFontEngineGlyphCache: public QSharedData
{
public:
QFontEngineGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix) : m_format(format), m_transform(matrix)
QFontEngineGlyphCache(QFontEngine::GlyphFormat format, const QTransform &matrix, const QColor &color = QColor())
: m_format(format)
, m_transform(matrix)
, m_color(color)
{
Q_ASSERT(m_format != QFontEngine::Format_None);
}
@ -74,9 +77,11 @@ public:
QFontEngine::GlyphFormat glyphFormat() const { return m_format; }
const QTransform &transform() const { return m_transform; }
const QColor &color() const { return m_color; }
QFontEngine::GlyphFormat m_format;
QTransform m_transform;
QColor m_color;
};
typedef QHash<void *, QList<QFontEngineGlyphCache *> > GlyphPointerHash;
typedef QHash<int, QList<QFontEngineGlyphCache *> > GlyphIntHash;

View File

@ -2105,8 +2105,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)
QImage QFontEngineFT::bitmapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t, const QColor &color)
{
Q_UNUSED(color);
Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t);
if (glyph == nullptr)
return QImage();

View File

@ -236,7 +236,7 @@ private:
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) override;
QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
glyph_metrics_t alphaMapBoundingBox(glyph_t glyph,
QFixed subPixelPosition,
const QTransform &matrix,

View File

@ -747,7 +747,7 @@ qreal QCoreTextFontEngine::fontSmoothingGamma()
return 2.0;
}
QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix)
QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, const QColor &color)
{
glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat);
@ -827,6 +827,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
}
} else {
CGContextSetRGBFillColor(ctx, color.redF(), color.greenF(), color.blueF(), color.alphaF());
// CGContextSetTextMatrix does not work with color glyphs, so we use
// the CTM instead. This means we must translate the CTM as well, to
// set the glyph position, instead of using CGContextSetTextPosition.
@ -884,12 +886,12 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
return imageForGlyph(glyph, subPixelPosition, x);
}
QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color)
{
if (t.type() > QTransform::TxScale)
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t);
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t, color);
return imageForGlyph(glyph, subPixelPosition, t);
return imageForGlyph(glyph, subPixelPosition, t, color);
}
void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const

View File

@ -110,7 +110,7 @@ public:
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) override;
QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
QFixed emSquareSize() const override;
void doKerning(QGlyphLayout *g, ShaperFlags flags) const override;
@ -137,7 +137,7 @@ public:
protected:
QCoreTextFontEngine(const QFontDef &def);
void init();
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m);
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &m, const QColor &color = QColor());
void loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyphs, QGlyphLayout *glyphs) const;
bool hasColorGlyphs() const;
bool shouldAntialias() const;

View File

@ -650,7 +650,8 @@ bool QWindowsFontEngineDirectWrite::supportsSubPixelPositions() const
QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
QFixed subPixelPosition,
int margin,
const QTransform &originalTransform)
const QTransform &originalTransform,
const QColor &color)
{
UINT16 glyphIndex = t;
FLOAT glyphAdvance = 0;
@ -735,6 +736,7 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
#if defined(QT_USE_DIRECTWRITE2)
BOOL ok = true;
if (SUCCEEDED(hr)) {
while (SUCCEEDED(hr) && ok) {
const DWRITE_COLOR_GLYPH_RUN *colorGlyphRun = 0;
@ -759,10 +761,18 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
break;
}
float r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f);
float g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f);
float b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f);
float a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f);
float r, g, b, a;
if (colorGlyphRun->paletteIndex == 0xFFFF) {
r = float(color.redF());
g = float(color.greenF());
b = float(color.blueF());
a = float(color.alphaF());
} else {
r = qBound(0.0f, colorGlyphRun->runColor.r, 1.0f);
g = qBound(0.0f, colorGlyphRun->runColor.g, 1.0f);
b = qBound(0.0f, colorGlyphRun->runColor.b, 1.0f);
a = qBound(0.0f, colorGlyphRun->runColor.a, 1.0f);
}
if (!qFuzzyIsNull(a)) {
renderGlyphRun(&image,
@ -784,11 +794,21 @@ QImage QWindowsFontEngineDirectWrite::imageForGlyph(glyph_t t,
} else
#endif
{
float r, g, b, a;
if (glyphFormat == QFontEngine::Format_ARGB) {
r = float(color.redF());
g = float(color.greenF());
b = float(color.blueF());
a = float(color.alphaF());
} else {
r = g = b = a = 0.0;
}
renderGlyphRun(&image,
0.0,
0.0,
0.0,
1.0,
r,
g,
b,
a,
glyphAnalysis,
boundingRect);
}
@ -1001,9 +1021,9 @@ glyph_metrics_t QWindowsFontEngineDirectWrite::alphaMapBoundingBox(glyph_t glyph
}
}
QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
QImage QWindowsFontEngineDirectWrite::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color)
{
return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_A32), t);
return imageForGlyph(glyph, subPixelPosition, glyphMargin(QFontEngine::Format_A32), t, color);
}
QT_END_NAMESPACE

View File

@ -112,7 +112,7 @@ public:
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) override;
QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t, const QColor &color) override;
QFontEngine *cloneWithSize(qreal pixelSize) const override;
Qt::HANDLE handle() const override;
@ -126,7 +126,7 @@ public:
void setUniqueFamilyName(const QString &newName) { m_uniqueFamilyName = newName; }
private:
QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform);
QImage imageForGlyph(glyph_t t, QFixed 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);