Implement COLRv0 support in Freetype engine
COLRv0 fonts are both scalable and in color, which was not previously handled in the Freetype backend because it only supported color fonts with embedded bitmaps. This patch simply correctly detects the scalable color fonts and render them through the same mechanism as other color fonts. [ChangeLog][Freetype] Added support for COLRv0 format color fonts. Pick-to: 6.8 6.9 Task-number: QTBUG-131116 Change-Id: I290e7525c24b4cf2ec872a366e5193f54712a3a4 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
parent
213a2610d8
commit
39df9e1858
@ -559,7 +559,12 @@ void QFreetypeFace::computeSize(const QFontDef &fontDef, int *xsize, int *ysize,
|
|||||||
*xsize = *ysize = 0;
|
*xsize = *ysize = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
*outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
|
#if defined FT_HAS_COLOR
|
||||||
|
if (FT_HAS_COLOR(face))
|
||||||
|
*outline_drawing = false;
|
||||||
|
else
|
||||||
|
#endif
|
||||||
|
*outline_drawing = (*xsize > (QT_MAX_CACHED_GLYPH_SIZE<<6) || *ysize > (QT_MAX_CACHED_GLYPH_SIZE<<6));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -570,7 +575,11 @@ QFontEngine::Properties QFreetypeFace::properties() const
|
|||||||
PS_FontInfoRec font_info;
|
PS_FontInfoRec font_info;
|
||||||
if (FT_Get_PS_Font_Info(face, &font_info) == 0)
|
if (FT_Get_PS_Font_Info(face, &font_info) == 0)
|
||||||
p.copyright = font_info.notice;
|
p.copyright = font_info.notice;
|
||||||
if (FT_IS_SCALABLE(face)) {
|
if (FT_IS_SCALABLE(face)
|
||||||
|
#if defined(FT_HAS_COLOR)
|
||||||
|
&& !FT_HAS_COLOR(face)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
p.ascent = face->ascender;
|
p.ascent = face->ascender;
|
||||||
p.descent = -face->descender;
|
p.descent = -face->descender;
|
||||||
p.leading = face->height - face->ascender + face->descender;
|
p.leading = face->height - face->ascender + face->descender;
|
||||||
@ -953,7 +962,11 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
|||||||
|
|
||||||
FT_Face face = lockFace();
|
FT_Face face = lockFace();
|
||||||
|
|
||||||
if (FT_IS_SCALABLE(face)) {
|
if (FT_IS_SCALABLE(face)
|
||||||
|
#if defined(FT_HAS_COLOR)
|
||||||
|
&& !FT_HAS_COLOR(face)
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
bool isItalic = calculateActualItalic(freetype, face, faceId);
|
bool isItalic = calculateActualItalic(freetype, face, faceId);
|
||||||
bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !isItalic && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
|
bool fake_oblique = (fontDef.style != QFont::StyleNormal) && !isItalic && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC");
|
||||||
if (fake_oblique)
|
if (fake_oblique)
|
||||||
@ -982,8 +995,10 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
|
|||||||
underline_position = ((line_thickness * 2) + 3) / 6;
|
underline_position = ((line_thickness * 2) + 3) / 6;
|
||||||
|
|
||||||
cacheEnabled = false;
|
cacheEnabled = false;
|
||||||
if (isScalableBitmap())
|
#if defined(FT_HAS_COLOR)
|
||||||
|
if (FT_HAS_COLOR(face))
|
||||||
glyphFormat = defaultFormat = GlyphFormat::Format_ARGB;
|
glyphFormat = defaultFormat = GlyphFormat::Format_ARGB;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
if (line_thickness < 1)
|
if (line_thickness < 1)
|
||||||
line_thickness = 1;
|
line_thickness = 1;
|
||||||
@ -1158,6 +1173,7 @@ static inline void transformBoundingBox(int *left, int *top, int *right, int *bo
|
|||||||
|
|
||||||
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
|
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
|
||||||
const QFixedPoint &subPixelPosition,
|
const QFixedPoint &subPixelPosition,
|
||||||
|
QColor color,
|
||||||
GlyphFormat format,
|
GlyphFormat format,
|
||||||
bool fetchMetricsOnly,
|
bool fetchMetricsOnly,
|
||||||
bool disableOutlineDrawing) const
|
bool disableOutlineDrawing) const
|
||||||
@ -1390,15 +1406,32 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
|
|||||||
}
|
}
|
||||||
info.linearAdvance = info.xOff = slot->bitmap.width;
|
info.linearAdvance = info.xOff = slot->bitmap.width;
|
||||||
} else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
|
} else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_GRAY) {
|
||||||
Q_ASSERT(format == Format_A8);
|
if (format == Format_A8) {
|
||||||
uchar *src = slot->bitmap.buffer;
|
uchar *src = slot->bitmap.buffer;
|
||||||
uchar *dst = glyph_buffer.get();
|
uchar *dst = glyph_buffer.get();
|
||||||
int h = slot->bitmap.rows;
|
int h = slot->bitmap.rows;
|
||||||
int bytes = info.width;
|
int bytes = info.width;
|
||||||
while (h--) {
|
while (h--) {
|
||||||
memcpy (dst, src, bytes);
|
memcpy (dst, src, bytes);
|
||||||
dst += pitch;
|
dst += pitch;
|
||||||
src += slot->bitmap.pitch;
|
src += slot->bitmap.pitch;
|
||||||
|
}
|
||||||
|
} else if (format == Format_ARGB) {
|
||||||
|
uchar *src = slot->bitmap.buffer;
|
||||||
|
quint32 *dstPixel = reinterpret_cast<quint32 *>(glyph_buffer.get());
|
||||||
|
int h = slot->bitmap.rows;
|
||||||
|
while (h--) {
|
||||||
|
for (int x = 0; x < static_cast<int>(slot->bitmap.width); ++x) {
|
||||||
|
uchar alpha = src[x];
|
||||||
|
float alphaF = alpha / 255.0;
|
||||||
|
dstPixel[x] = qRgba(qRound(alphaF * color.red()),
|
||||||
|
qRound(alphaF * color.green()),
|
||||||
|
qRound(alphaF * color.blue()),
|
||||||
|
alpha);
|
||||||
|
}
|
||||||
|
src += slot->bitmap.pitch;
|
||||||
|
dstPixel += info.width;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
|
} else if (slot->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
|
||||||
Q_ASSERT(format == Format_A32);
|
Q_ASSERT(format == Format_A32);
|
||||||
@ -1899,6 +1932,7 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag
|
|||||||
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
||||||
glyphs->glyphs[i],
|
glyphs->glyphs[i],
|
||||||
QFixedPoint(),
|
QFixedPoint(),
|
||||||
|
QColor(),
|
||||||
Format_None,
|
Format_None,
|
||||||
true);
|
true);
|
||||||
if (g)
|
if (g)
|
||||||
@ -1944,6 +1978,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
|
|||||||
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
||||||
glyphs.glyphs[i],
|
glyphs.glyphs[i],
|
||||||
QFixedPoint(),
|
QFixedPoint(),
|
||||||
|
QColor(),
|
||||||
Format_None,
|
Format_None,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -1992,6 +2027,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(glyph_t glyph)
|
|||||||
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
||||||
glyph,
|
glyph,
|
||||||
QFixedPoint(),
|
QFixedPoint(),
|
||||||
|
QColor(),
|
||||||
Format_None,
|
Format_None,
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@ -2041,7 +2077,7 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph,
|
|||||||
&& matrix.type() > QTransform::TxTranslate;
|
&& matrix.type() > QTransform::TxTranslate;
|
||||||
if (needsImageTransform && format == QFontEngine::Format_Mono)
|
if (needsImageTransform && format == QFontEngine::Format_Mono)
|
||||||
format = QFontEngine::Format_A8;
|
format = QFontEngine::Format_A8;
|
||||||
Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, true, true);
|
Glyph *g = loadGlyphFor(glyph, subPixelPosition, format, matrix, QColor(), true, true);
|
||||||
|
|
||||||
glyph_metrics_t overall;
|
glyph_metrics_t overall;
|
||||||
if (g) {
|
if (g) {
|
||||||
@ -2116,7 +2152,7 @@ QFontEngine::Glyph *QFontEngineFT::glyphData(glyph_t glyphIndex,
|
|||||||
else if (neededFormat == Format_None)
|
else if (neededFormat == Format_None)
|
||||||
neededFormat = Format_A8;
|
neededFormat = Format_A8;
|
||||||
|
|
||||||
Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);
|
Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t, QColor());
|
||||||
if (!glyph || !glyph->width || !glyph->height)
|
if (!glyph || !glyph->width || !glyph->height)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
@ -2133,6 +2169,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
|
|||||||
const QFixedPoint &subPixelPosition,
|
const QFixedPoint &subPixelPosition,
|
||||||
GlyphFormat format,
|
GlyphFormat format,
|
||||||
const QTransform &t,
|
const QTransform &t,
|
||||||
|
QColor color,
|
||||||
bool fetchBoundingBox,
|
bool fetchBoundingBox,
|
||||||
bool disableOutlineDrawing)
|
bool disableOutlineDrawing)
|
||||||
{
|
{
|
||||||
@ -2151,7 +2188,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
|
|||||||
FT_Matrix ftMatrix = glyphSet != nullptr ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
|
FT_Matrix ftMatrix = glyphSet != nullptr ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
|
||||||
FT_Matrix_Multiply(&ftMatrix, &m);
|
FT_Matrix_Multiply(&ftMatrix, &m);
|
||||||
freetype->matrix = m;
|
freetype->matrix = m;
|
||||||
glyph = loadGlyph(glyphSet, g, subPixelPosition, format, false, disableOutlineDrawing);
|
glyph = loadGlyph(glyphSet, g, subPixelPosition, color, format, false, disableOutlineDrawing);
|
||||||
unlockFace();
|
unlockFace();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2171,7 +2208,7 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g,
|
|||||||
&& t.type() > QTransform::TxTranslate;
|
&& t.type() > QTransform::TxTranslate;
|
||||||
const GlyphFormat neededFormat = antialias || needsImageTransform ? Format_A8 : Format_Mono;
|
const GlyphFormat neededFormat = antialias || needsImageTransform ? Format_A8 : Format_Mono;
|
||||||
|
|
||||||
Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
|
Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, QColor(), false, true);
|
||||||
|
|
||||||
QImage img = alphaMapFromGlyphData(glyph, neededFormat);
|
QImage img = alphaMapFromGlyphData(glyph, neededFormat);
|
||||||
if (needsImageTransform)
|
if (needsImageTransform)
|
||||||
@ -2198,7 +2235,7 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g,
|
|||||||
|
|
||||||
const GlyphFormat neededFormat = Format_A32;
|
const GlyphFormat neededFormat = Format_A32;
|
||||||
|
|
||||||
Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, false, true);
|
Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t, QColor(), false, true);
|
||||||
|
|
||||||
QImage img = alphaMapFromGlyphData(glyph, neededFormat);
|
QImage img = alphaMapFromGlyphData(glyph, neededFormat);
|
||||||
if (needsImageTransform)
|
if (needsImageTransform)
|
||||||
@ -2220,9 +2257,7 @@ QImage QFontEngineFT::bitmapForGlyph(glyph_t g,
|
|||||||
const QTransform &t,
|
const QTransform &t,
|
||||||
const QColor &color)
|
const QColor &color)
|
||||||
{
|
{
|
||||||
Q_UNUSED(color);
|
Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t, color);
|
||||||
|
|
||||||
Glyph *glyph = loadGlyphFor(g, subPixelPosition, defaultFormat, t);
|
|
||||||
if (glyph == nullptr)
|
if (glyph == nullptr)
|
||||||
return QImage();
|
return QImage();
|
||||||
|
|
||||||
@ -2232,7 +2267,7 @@ QImage QFontEngineFT::bitmapForGlyph(glyph_t g,
|
|||||||
else if (defaultFormat == GlyphFormat::Format_Mono)
|
else if (defaultFormat == GlyphFormat::Format_Mono)
|
||||||
img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy();
|
img = QImage(glyph->data, glyph->width, glyph->height, QImage::Format_Mono).copy();
|
||||||
|
|
||||||
if (!img.isNull() && (!t.isIdentity() || scalableBitmapScaleFactor != 1)) {
|
if (!img.isNull() && (scalableBitmapScaleFactor != 1 || (!t.isIdentity() && !isSmoothlyScalable))) {
|
||||||
QTransform trans(t);
|
QTransform trans(t);
|
||||||
const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
|
const qreal scaleFactor = scalableBitmapScaleFactor.toReal();
|
||||||
trans.scale(scaleFactor, scaleFactor);
|
trans.scale(scaleFactor, scaleFactor);
|
||||||
|
@ -242,10 +242,19 @@ private:
|
|||||||
GlyphFormat format = Format_None,
|
GlyphFormat format = Format_None,
|
||||||
bool fetchMetricsOnly = false,
|
bool fetchMetricsOnly = false,
|
||||||
bool disableOutlineDrawing = false) const
|
bool disableOutlineDrawing = false) const
|
||||||
{ return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr, glyph, subPixelPosition, format, fetchMetricsOnly, disableOutlineDrawing); }
|
{
|
||||||
|
return loadGlyph(cacheEnabled ? &defaultGlyphSet : nullptr,
|
||||||
|
glyph,
|
||||||
|
subPixelPosition,
|
||||||
|
QColor(),
|
||||||
|
format,
|
||||||
|
fetchMetricsOnly,
|
||||||
|
disableOutlineDrawing);
|
||||||
|
}
|
||||||
Glyph *loadGlyph(QGlyphSet *set,
|
Glyph *loadGlyph(QGlyphSet *set,
|
||||||
uint glyph,
|
uint glyph,
|
||||||
const QFixedPoint &subPixelPosition,
|
const QFixedPoint &subPixelPosition,
|
||||||
|
QColor color,
|
||||||
GlyphFormat = Format_None,
|
GlyphFormat = Format_None,
|
||||||
bool fetchMetricsOnly = false,
|
bool fetchMetricsOnly = false,
|
||||||
bool disableOutlineDrawing = false) const;
|
bool disableOutlineDrawing = false) const;
|
||||||
@ -253,6 +262,7 @@ private:
|
|||||||
const QFixedPoint &subPixelPosition,
|
const QFixedPoint &subPixelPosition,
|
||||||
GlyphFormat format,
|
GlyphFormat format,
|
||||||
const QTransform &t,
|
const QTransform &t,
|
||||||
|
QColor color,
|
||||||
bool fetchBoundingBox = false,
|
bool fetchBoundingBox = false,
|
||||||
bool disableOutlineDrawing = false);
|
bool disableOutlineDrawing = false);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user