Add support for color glyphs (Emoji) on Mac OS X and iOS
A new glyph type is added to the glyph caches for ARGB bitmap glyphs, and the raster and OpenGL paint engines have been modified to support this glyph type for drawCachedGlyphs(). The CoreText font engine implements support for these glyphs through the CTFontDrawGlyphs API, since CGContextShowGlyphsWithAdvances does not handle color glyphs. Change-Id: Idad9ce75a911cae130d65aebe59142772a16fc12 Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@digia.com>
This commit is contained in:
parent
a65157e5b7
commit
d1ee718955
@ -624,7 +624,7 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
|
|||||||
if (newMode == mode)
|
if (newMode == mode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
|
if (mode != BrushDrawingMode) {
|
||||||
lastTextureUsed = GLuint(-1);
|
lastTextureUsed = GLuint(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,9 +639,11 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
|
|||||||
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
|
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newMode == ImageArrayDrawingMode) {
|
if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) {
|
||||||
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
|
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
|
||||||
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
|
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
|
||||||
|
|
||||||
|
if (newMode == ImageOpacityArrayDrawingMode)
|
||||||
setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
|
setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1085,7 +1087,7 @@ bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGl
|
|||||||
|
|
||||||
bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
|
bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
|
||||||
{
|
{
|
||||||
if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
|
if (brushTextureDirty && (mode == TextDrawingMode || mode == BrushDrawingMode))
|
||||||
updateBrushTexture();
|
updateBrushTexture();
|
||||||
|
|
||||||
if (compositionModeDirty)
|
if (compositionModeDirty)
|
||||||
@ -1105,12 +1107,12 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
|
|||||||
}
|
}
|
||||||
|
|
||||||
QOpenGLEngineShaderManager::OpacityMode opacityMode;
|
QOpenGLEngineShaderManager::OpacityMode opacityMode;
|
||||||
if (mode == ImageArrayDrawingMode) {
|
if (mode == ImageOpacityArrayDrawingMode) {
|
||||||
opacityMode = QOpenGLEngineShaderManager::AttributeOpacity;
|
opacityMode = QOpenGLEngineShaderManager::AttributeOpacity;
|
||||||
} else {
|
} else {
|
||||||
opacityMode = stateHasOpacity ? QOpenGLEngineShaderManager::UniformOpacity
|
opacityMode = stateHasOpacity ? QOpenGLEngineShaderManager::UniformOpacity
|
||||||
: QOpenGLEngineShaderManager::NoOpacity;
|
: QOpenGLEngineShaderManager::NoOpacity;
|
||||||
if (stateHasOpacity && (mode != ImageDrawingMode)) {
|
if (stateHasOpacity && (mode != ImageDrawingMode && mode != ImageArrayDrawingMode)) {
|
||||||
// Using a brush
|
// Using a brush
|
||||||
bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
|
bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
|
||||||
(currentBrush.style() <= Qt::DiagCrossPattern);
|
(currentBrush.style() <= Qt::DiagCrossPattern);
|
||||||
@ -1130,7 +1132,7 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
|
|||||||
matrixUniformDirty = true;
|
matrixUniformDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
|
if (brushUniformsDirty && (mode == TextDrawingMode || mode == BrushDrawingMode))
|
||||||
updateBrushUniforms();
|
updateBrushUniforms();
|
||||||
|
|
||||||
if (opacityMode == QOpenGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
|
if (opacityMode == QOpenGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
|
||||||
@ -1602,6 +1604,9 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
|
|||||||
if (cache->width() == 0 || cache->height() == 0)
|
if (cache->width() == 0 || cache->height() == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
if (glyphType == QFontEngineGlyphCache::Raster_ARGB)
|
||||||
|
transferMode(ImageArrayDrawingMode);
|
||||||
|
else
|
||||||
transferMode(TextDrawingMode);
|
transferMode(TextDrawingMode);
|
||||||
|
|
||||||
int margin = fe->glyphMargin(glyphType);
|
int margin = fe->glyphMargin(glyphType);
|
||||||
@ -1698,8 +1703,10 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (glyphType != QFontEngineGlyphCache::Raster_ARGB || recreateVertexArrays) {
|
||||||
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
|
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
|
||||||
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
|
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
|
||||||
|
}
|
||||||
|
|
||||||
if (!snapToPixelGrid) {
|
if (!snapToPixelGrid) {
|
||||||
snapToPixelGrid = true;
|
snapToPixelGrid = true;
|
||||||
@ -1782,6 +1789,11 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
|
|||||||
glBlendFunc(GL_ONE, GL_ONE);
|
glBlendFunc(GL_ONE, GL_ONE);
|
||||||
}
|
}
|
||||||
compositionModeDirty = true;
|
compositionModeDirty = true;
|
||||||
|
} else if (glyphType == QFontEngineGlyphCache::Raster_ARGB) {
|
||||||
|
currentBrush = noBrush;
|
||||||
|
shaderManager->setSrcPixelType(QOpenGLEngineShaderManager::ImageSrc);
|
||||||
|
if (prepareForCachedGlyphDraw(*cache))
|
||||||
|
shaderManager->currentProgram()->setUniformValue(location(QOpenGLEngineShaderManager::ImageTexture), QT_IMAGE_TEXTURE_UNIT);
|
||||||
} else {
|
} else {
|
||||||
// Greyscale/mono glyphs
|
// Greyscale/mono glyphs
|
||||||
|
|
||||||
@ -1792,7 +1804,11 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
|
|||||||
QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest;
|
QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest;
|
||||||
if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) {
|
if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) {
|
||||||
|
|
||||||
|
if (glyphType == QFontEngineGlyphCache::Raster_ARGB)
|
||||||
|
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
|
||||||
|
else
|
||||||
funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
|
funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
|
||||||
|
|
||||||
if (lastMaskTextureUsed != cache->texture()) {
|
if (lastMaskTextureUsed != cache->texture()) {
|
||||||
glBindTexture(GL_TEXTURE_2D, cache->texture());
|
glBindTexture(GL_TEXTURE_2D, cache->texture());
|
||||||
lastMaskTextureUsed = cache->texture();
|
lastMaskTextureUsed = cache->texture();
|
||||||
@ -1908,7 +1924,7 @@ void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFra
|
|||||||
|
|
||||||
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
|
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
|
||||||
GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap);
|
GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap);
|
||||||
transferMode(ImageArrayDrawingMode);
|
transferMode(ImageOpacityArrayDrawingMode);
|
||||||
|
|
||||||
bool isBitmap = pixmap.isQBitmap();
|
bool isBitmap = pixmap.isQBitmap();
|
||||||
bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
|
bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
|
||||||
|
@ -70,7 +70,8 @@ enum EngineMode {
|
|||||||
ImageDrawingMode,
|
ImageDrawingMode,
|
||||||
TextDrawingMode,
|
TextDrawingMode,
|
||||||
BrushDrawingMode,
|
BrushDrawingMode,
|
||||||
ImageArrayDrawingMode
|
ImageArrayDrawingMode,
|
||||||
|
ImageOpacityArrayDrawingMode
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
@ -120,7 +120,7 @@ void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
|
|||||||
m_textureResource->m_width = width;
|
m_textureResource->m_width = width;
|
||||||
m_textureResource->m_height = height;
|
m_textureResource->m_height = height;
|
||||||
|
|
||||||
if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
|
if (m_type == QFontEngineGlyphCache::Raster_RGBMask || m_type == QFontEngineGlyphCache::Raster_ARGB) {
|
||||||
QVarLengthArray<uchar> data(width * height * 4);
|
QVarLengthArray<uchar> data(width * height * 4);
|
||||||
for (int i = 0; i < data.size(); ++i)
|
for (int i = 0; i < data.size(); ++i)
|
||||||
data[i] = 0;
|
data[i] = 0;
|
||||||
@ -314,16 +314,25 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
|
|||||||
for (int x = 0; x < maskWidth; ++x)
|
for (int x = 0; x < maskWidth; ++x)
|
||||||
src[x] = -src[x]; // convert 0 and 1 into 0 and 255
|
src[x] = -src[x]; // convert 0 and 1 into 0 and 255
|
||||||
}
|
}
|
||||||
} else if (mask.format() == QImage::Format_RGB32) {
|
} else if (mask.depth() == 32) {
|
||||||
// Make the alpha component equal to the average of the RGB values.
|
if (mask.format() == QImage::Format_RGB32
|
||||||
|
// We need to make the alpha component equal to the average of the RGB values.
|
||||||
// This is needed when drawing sub-pixel antialiased text on translucent targets.
|
// This is needed when drawing sub-pixel antialiased text on translucent targets.
|
||||||
|
#if defined(QT_OPENGL_ES_2)
|
||||||
|
|| !hasBGRA // We need to reverse the bytes
|
||||||
|
#endif
|
||||||
|
) {
|
||||||
for (int y = 0; y < maskHeight; ++y) {
|
for (int y = 0; y < maskHeight; ++y) {
|
||||||
quint32 *src = (quint32 *) mask.scanLine(y);
|
quint32 *src = (quint32 *) mask.scanLine(y);
|
||||||
for (int x = 0; x < maskWidth; ++x) {
|
for (int x = 0; x < maskWidth; ++x) {
|
||||||
uchar r = src[x] >> 16;
|
uchar r = src[x] >> 16;
|
||||||
uchar g = src[x] >> 8;
|
uchar g = src[x] >> 8;
|
||||||
uchar b = src[x];
|
uchar b = src[x];
|
||||||
quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding.
|
quint32 avg;
|
||||||
|
if (mask.format() == QImage::Format_RGB32)
|
||||||
|
avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding.
|
||||||
|
else // Format_ARGB_Premultiplied
|
||||||
|
avg = src[x] >> 24;
|
||||||
|
|
||||||
#if defined(QT_OPENGL_ES_2)
|
#if defined(QT_OPENGL_ES_2)
|
||||||
if (!hasBGRA) {
|
if (!hasBGRA) {
|
||||||
@ -335,9 +344,10 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
|
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
|
||||||
if (mask.format() == QImage::Format_RGB32) {
|
if (mask.depth() == 32) {
|
||||||
#if defined(QT_OPENGL_ES_2)
|
#if defined(QT_OPENGL_ES_2)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, hasBGRA ? GL_BGRA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, mask.bits());
|
glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, maskWidth, maskHeight, hasBGRA ? GL_BGRA_EXT : GL_RGBA, GL_UNSIGNED_BYTE, mask.bits());
|
||||||
#else
|
#else
|
||||||
|
@ -2857,7 +2857,19 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
|
|||||||
// x, y,
|
// x, y,
|
||||||
// positions[i].x.toInt(), positions[i].y.toInt());
|
// positions[i].x.toInt(), positions[i].y.toInt());
|
||||||
|
|
||||||
alphaPenBlt(bits + ((c.x << leftShift) >> rightShift) + c.y * bpl, bpl, depth, x, y, c.w, c.h);
|
const uchar *glyphBits = bits + ((c.x << leftShift) >> rightShift) + c.y * bpl;
|
||||||
|
|
||||||
|
if (glyphType == QFontEngineGlyphCache::Raster_ARGB) {
|
||||||
|
// The current state transform has already been applied to the positions,
|
||||||
|
// so we prevent drawImage() from re-applying the transform by clearing
|
||||||
|
// the state for the duration of the call.
|
||||||
|
QTransform originalTransform = s->matrix;
|
||||||
|
s->matrix = QTransform();
|
||||||
|
drawImage(QPoint(x, y), QImage(glyphBits, c.w, c.h, bpl, image.format()));
|
||||||
|
s->matrix = originalTransform;
|
||||||
|
} else {
|
||||||
|
alphaPenBlt(glyphBits, bpl, depth, x, y, c.w, c.h);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1088,6 +1088,9 @@ bool QPaintEngineEx::requiresPretransformedGlyphPositions(QFontEngine *, const Q
|
|||||||
|
|
||||||
bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const
|
bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const
|
||||||
{
|
{
|
||||||
|
if (fontEngine->glyphFormat == QFontEngineGlyphCache::Raster_ARGB)
|
||||||
|
return true;
|
||||||
|
|
||||||
qreal pixelSize = fontEngine->fontDef.pixelSize;
|
qreal pixelSize = fontEngine->fontDef.pixelSize;
|
||||||
return (pixelSize * pixelSize * qAbs(m.determinant())) <
|
return (pixelSize * pixelSize * qAbs(m.determinant())) <
|
||||||
QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
|
QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
|
||||||
|
@ -129,6 +129,7 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
|
|||||||
switch (m_type) {
|
switch (m_type) {
|
||||||
case Raster_A8: format = QFontEngine::Format_A8; break;
|
case Raster_A8: format = QFontEngine::Format_A8; break;
|
||||||
case Raster_RGBMask: format = QFontEngine::Format_A32; break;
|
case Raster_RGBMask: format = QFontEngine::Format_A32; break;
|
||||||
|
case Raster_ARGB: format = QFontEngine::Format_ARGB; break;
|
||||||
default: format = QFontEngine::Format_Mono; break;
|
default: format = QFontEngine::Format_Mono; break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,6 +276,8 @@ QImage QTextureGlyphCache::textureMapForGlyph(glyph_t g, QFixed subPixelPosition
|
|||||||
{
|
{
|
||||||
if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
|
if (m_type == QFontEngineGlyphCache::Raster_RGBMask)
|
||||||
return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, m_transform);
|
return m_current_fontengine->alphaRGBMapForGlyph(g, subPixelPosition, m_transform);
|
||||||
|
else if (m_type == QFontEngineGlyphCache::Raster_ARGB)
|
||||||
|
return m_current_fontengine->bitmapForGlyph(g, subPixelPosition, m_transform);
|
||||||
return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform);
|
return m_current_fontengine->alphaMapForGlyph(g, subPixelPosition, m_transform);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -306,6 +309,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
|
|||||||
m_image = QImage(width, height, QImage::Format_RGB32);
|
m_image = QImage(width, height, QImage::Format_RGB32);
|
||||||
break;
|
break;
|
||||||
case QFontEngineGlyphCache::Raster_ARGB:
|
case QFontEngineGlyphCache::Raster_ARGB:
|
||||||
|
m_image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -322,7 +326,8 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (m_type == QFontEngineGlyphCache::Raster_RGBMask) {
|
if (m_type == QFontEngineGlyphCache::Raster_RGBMask
|
||||||
|
|| m_type == QFontEngineGlyphCache::Raster_ARGB) {
|
||||||
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
|
QImage ref(m_image.bits() + (c.x * 4 + c.y * m_image.bytesPerLine()),
|
||||||
qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
|
qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
|
||||||
m_image.format());
|
m_image.format());
|
||||||
|
@ -649,6 +649,13 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition
|
|||||||
return rgbMask;
|
return rgbMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&)
|
||||||
|
{
|
||||||
|
Q_UNUSED(subPixelPosition);
|
||||||
|
|
||||||
|
return QImage();
|
||||||
|
}
|
||||||
|
|
||||||
QFixed QFontEngine::subPixelPositionForX(QFixed x) const
|
QFixed QFontEngine::subPixelPositionForX(QFixed x) const
|
||||||
{
|
{
|
||||||
if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
|
if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
|
||||||
|
@ -112,7 +112,8 @@ public:
|
|||||||
Format_Render = Format_None,
|
Format_Render = Format_None,
|
||||||
Format_Mono,
|
Format_Mono,
|
||||||
Format_A8,
|
Format_A8,
|
||||||
Format_A32
|
Format_A32,
|
||||||
|
Format_ARGB
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ShaperFlag {
|
enum ShaperFlag {
|
||||||
@ -191,6 +192,7 @@ public:
|
|||||||
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t);
|
virtual QImage alphaMapForGlyph(glyph_t, const QTransform &t);
|
||||||
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition, 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 alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
|
||||||
|
virtual QImage bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform &t);
|
||||||
virtual QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
|
virtual QImage *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
|
||||||
GlyphFormat neededFormat,
|
GlyphFormat neededFormat,
|
||||||
const QTransform &t = QTransform(),
|
const QTransform &t = QTransform(),
|
||||||
|
@ -158,7 +158,7 @@ void QCoreTextFontEngine::init()
|
|||||||
synthesisFlags = 0;
|
synthesisFlags = 0;
|
||||||
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
|
CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
|
||||||
|
|
||||||
#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||||
if (supportsColorGlyphs() && (traits & kCTFontColorGlyphsTrait))
|
if (supportsColorGlyphs() && (traits & kCTFontColorGlyphsTrait))
|
||||||
glyphFormat = QFontEngineGlyphCache::Raster_ARGB;
|
glyphFormat = QFontEngineGlyphCache::Raster_ARGB;
|
||||||
else
|
else
|
||||||
@ -457,7 +457,9 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
|
|||||||
br.y = QFixed::fromReal(br.y.toReal() * vscale);
|
br.y = QFixed::fromReal(br.y.toReal() * vscale);
|
||||||
}
|
}
|
||||||
|
|
||||||
QImage im(qAbs(qRound(br.width))+2, qAbs(qRound(br.height))+2, QImage::Format_RGB32);
|
bool isColorGlyph = glyphFormat == QFontEngineGlyphCache::Raster_ARGB;
|
||||||
|
QImage::Format format = isColorGlyph ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
|
||||||
|
QImage im(qAbs(qRound(br.width)) + 2, qAbs(qRound(br.height)) + 2, format);
|
||||||
im.fill(0);
|
im.fill(0);
|
||||||
|
|
||||||
#ifndef Q_OS_IOS
|
#ifndef Q_OS_IOS
|
||||||
@ -465,7 +467,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
|
|||||||
#else
|
#else
|
||||||
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
|
||||||
#endif
|
#endif
|
||||||
uint cgflags = kCGImageAlphaNoneSkipFirst;
|
uint cgflags = isColorGlyph ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
|
||||||
#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
|
#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
|
||||||
cgflags |= kCGBitmapByteOrder32Host;
|
cgflags |= kCGBitmapByteOrder32Host;
|
||||||
#endif
|
#endif
|
||||||
@ -476,38 +478,49 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
|
|||||||
CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > antialiasingThreshold)
|
CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > antialiasingThreshold)
|
||||||
&& !(fontDef.styleStrategy & QFont::NoAntialias));
|
&& !(fontDef.styleStrategy & QFont::NoAntialias));
|
||||||
CGContextSetShouldSmoothFonts(ctx, aa);
|
CGContextSetShouldSmoothFonts(ctx, aa);
|
||||||
CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
|
|
||||||
CGAffineTransform cgMatrix = CGAffineTransformIdentity;
|
|
||||||
|
|
||||||
CGAffineTransformConcat(cgMatrix, oldTextMatrix);
|
CGAffineTransform cgMatrix = CGAffineTransformIdentity;
|
||||||
|
|
||||||
if (synthesisFlags & QFontEngine::SynthesizedItalic)
|
if (synthesisFlags & QFontEngine::SynthesizedItalic)
|
||||||
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
|
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
|
||||||
|
|
||||||
|
if (!isColorGlyph) // CTFontDrawGlyphs incorporates the font's matrix already
|
||||||
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
|
cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
|
||||||
|
|
||||||
if (m.isScaling())
|
if (m.isScaling())
|
||||||
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(m.m11(), m.m22()));
|
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(m.m11(), m.m22()));
|
||||||
|
|
||||||
|
CGGlyph cgGlyph = glyph;
|
||||||
|
qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
|
||||||
|
qreal pos_y = im.height() + br.y.toReal();
|
||||||
|
|
||||||
|
if (!isColorGlyph) {
|
||||||
CGContextSetTextMatrix(ctx, cgMatrix);
|
CGContextSetTextMatrix(ctx, cgMatrix);
|
||||||
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
|
CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
|
||||||
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
CGContextSetTextDrawingMode(ctx, kCGTextFill);
|
||||||
|
|
||||||
CGContextSetFont(ctx, cgFont);
|
CGContextSetFont(ctx, cgFont);
|
||||||
|
|
||||||
qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
|
|
||||||
qreal pos_y = im.height() + br.y.toReal();
|
|
||||||
CGContextSetTextPosition(ctx, pos_x, pos_y);
|
CGContextSetTextPosition(ctx, pos_x, pos_y);
|
||||||
|
|
||||||
CGSize advance;
|
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1);
|
||||||
advance.width = 0;
|
|
||||||
advance.height = 0;
|
|
||||||
CGGlyph cgGlyph = glyph;
|
|
||||||
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
|
|
||||||
|
|
||||||
if (synthesisFlags & QFontEngine::SynthesizedBold) {
|
if (synthesisFlags & QFontEngine::SynthesizedBold) {
|
||||||
CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
|
CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
|
||||||
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
|
CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#if defined(Q_OS_IOS) || MAC_OS_X_VERSION_MAX_ALLOWED >= 1070
|
||||||
|
else if (supportsColorGlyphs()) {
|
||||||
|
// 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.
|
||||||
|
CGContextTranslateCTM(ctx, pos_x, pos_y);
|
||||||
|
CGContextConcatCTM(ctx, cgMatrix);
|
||||||
|
|
||||||
|
// CGContextShowGlyphsWithAdvances does not support the 'sbix' color-bitmap
|
||||||
|
// glyphs in the Apple Color Emoji font, so we use CTFontDrawGlyphs instead.
|
||||||
|
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
CGContextRelease(ctx);
|
CGContextRelease(ctx);
|
||||||
CGColorSpaceRelease(colorspace);
|
CGColorSpaceRelease(colorspace);
|
||||||
@ -556,6 +569,14 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
|
|||||||
return im;
|
return im;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
|
||||||
|
{
|
||||||
|
if (t.type() > QTransform::TxScale)
|
||||||
|
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t);
|
||||||
|
|
||||||
|
return imageForGlyph(glyph, subPixelPosition, true, t);
|
||||||
|
}
|
||||||
|
|
||||||
void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
|
void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
|
||||||
{
|
{
|
||||||
int i, numGlyphs = glyphs->numGlyphs;
|
int i, numGlyphs = glyphs->numGlyphs;
|
||||||
|
@ -98,6 +98,7 @@ public:
|
|||||||
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition);
|
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition);
|
||||||
virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t);
|
virtual QImage alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t);
|
||||||
virtual QImage alphaRGBMapForGlyph(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 qreal minRightBearing() const;
|
virtual qreal minRightBearing() const;
|
||||||
virtual qreal minLeftBearing() const;
|
virtual qreal minLeftBearing() const;
|
||||||
virtual QFixed emSquareSize() const;
|
virtual QFixed emSquareSize() const;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user