summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTor Arne Vestbø <tor.arne.vestbo@digia.com>2013-02-11 18:16:49 +0100
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-02-13 02:04:16 +0100
commitd1ee7189553e13337b198fe4ba66d79fb7a7f41d (patch)
tree2260be276c82026558086596f396f7fc0922106f /src
parenta65157e5b7a2a1c2f018507f9d45f5b311cd387c (diff)
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>
Diffstat (limited to 'src')
-rw-r--r--src/gui/opengl/qopenglpaintengine.cpp40
-rw-r--r--src/gui/opengl/qopenglpaintengine_p.h3
-rw-r--r--src/gui/opengl/qopengltextureglyphcache.cpp44
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp14
-rw-r--r--src/gui/painting/qpaintengineex.cpp3
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp7
-rw-r--r--src/gui/text/qfontengine.cpp7
-rw-r--r--src/gui/text/qfontengine_p.h4
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm65
-rw-r--r--src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h1
10 files changed, 133 insertions, 55 deletions
diff --git a/src/gui/opengl/qopenglpaintengine.cpp b/src/gui/opengl/qopenglpaintengine.cpp
index d248d2b8e5..555c47f265 100644
--- a/src/gui/opengl/qopenglpaintengine.cpp
+++ b/src/gui/opengl/qopenglpaintengine.cpp
@@ -624,7 +624,7 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
if (newMode == mode)
return;
- if (mode == TextDrawingMode || mode == ImageDrawingMode || mode == ImageArrayDrawingMode) {
+ if (mode != BrushDrawingMode) {
lastTextureUsed = GLuint(-1);
}
@@ -639,10 +639,12 @@ void QOpenGL2PaintEngineExPrivate::transferMode(EngineMode newMode)
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, staticTextureCoordinateArray);
}
- if (newMode == ImageArrayDrawingMode) {
+ if (newMode == ImageArrayDrawingMode || newMode == ImageOpacityArrayDrawingMode) {
setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinateArray.data());
setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinateArray.data());
- setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
+
+ if (newMode == ImageOpacityArrayDrawingMode)
+ setVertexAttributePointer(QT_OPACITY_ATTR, (GLfloat*)opacityArray.data());
}
// This needs to change when we implement high-quality anti-aliasing...
@@ -1085,7 +1087,7 @@ bool QOpenGL2PaintEngineExPrivate::prepareForCachedGlyphDraw(const QFontEngineGl
bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
{
- if (brushTextureDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
+ if (brushTextureDirty && (mode == TextDrawingMode || mode == BrushDrawingMode))
updateBrushTexture();
if (compositionModeDirty)
@@ -1105,12 +1107,12 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
}
QOpenGLEngineShaderManager::OpacityMode opacityMode;
- if (mode == ImageArrayDrawingMode) {
+ if (mode == ImageOpacityArrayDrawingMode) {
opacityMode = QOpenGLEngineShaderManager::AttributeOpacity;
} else {
opacityMode = stateHasOpacity ? QOpenGLEngineShaderManager::UniformOpacity
: QOpenGLEngineShaderManager::NoOpacity;
- if (stateHasOpacity && (mode != ImageDrawingMode)) {
+ if (stateHasOpacity && (mode != ImageDrawingMode && mode != ImageArrayDrawingMode)) {
// Using a brush
bool brushIsPattern = (currentBrush.style() >= Qt::Dense1Pattern) &&
(currentBrush.style() <= Qt::DiagCrossPattern);
@@ -1130,7 +1132,7 @@ bool QOpenGL2PaintEngineExPrivate::prepareForDraw(bool srcPixelsAreOpaque)
matrixUniformDirty = true;
}
- if (brushUniformsDirty && mode != ImageDrawingMode && mode != ImageArrayDrawingMode)
+ if (brushUniformsDirty && (mode == TextDrawingMode || mode == BrushDrawingMode))
updateBrushUniforms();
if (opacityMode == QOpenGLEngineShaderManager::UniformOpacity && opacityUniformDirty) {
@@ -1602,7 +1604,10 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
if (cache->width() == 0 || cache->height() == 0)
return;
- transferMode(TextDrawingMode);
+ if (glyphType == QFontEngineGlyphCache::Raster_ARGB)
+ transferMode(ImageArrayDrawingMode);
+ else
+ transferMode(TextDrawingMode);
int margin = fe->glyphMargin(glyphType);
@@ -1698,8 +1703,10 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
#endif
}
- setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
- setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
+ if (glyphType != QFontEngineGlyphCache::Raster_ARGB || recreateVertexArrays) {
+ setVertexAttributePointer(QT_VERTEX_COORDS_ATTR, (GLfloat*)vertexCoordinates->data());
+ setVertexAttributePointer(QT_TEXTURE_COORDS_ATTR, (GLfloat*)textureCoordinates->data());
+ }
if (!snapToPixelGrid) {
snapToPixelGrid = true;
@@ -1782,6 +1789,11 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
glBlendFunc(GL_ONE, GL_ONE);
}
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 {
// Greyscale/mono glyphs
@@ -1792,7 +1804,11 @@ void QOpenGL2PaintEngineExPrivate::drawCachedGlyphs(QFontEngineGlyphCache::Type
QOpenGLTextureGlyphCache::FilterMode filterMode = (s->matrix.type() > QTransform::TxTranslate)?QOpenGLTextureGlyphCache::Linear:QOpenGLTextureGlyphCache::Nearest;
if (lastMaskTextureUsed != cache->texture() || cache->filterMode() != filterMode) {
- funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+ if (glyphType == QFontEngineGlyphCache::Raster_ARGB)
+ funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
+ else
+ funcs.glActiveTexture(GL_TEXTURE0 + QT_MASK_TEXTURE_UNIT);
+
if (lastMaskTextureUsed != cache->texture()) {
glBindTexture(GL_TEXTURE_2D, cache->texture());
lastMaskTextureUsed = cache->texture();
@@ -1908,7 +1924,7 @@ void QOpenGL2PaintEngineExPrivate::drawPixmapFragments(const QPainter::PixmapFra
funcs.glActiveTexture(GL_TEXTURE0 + QT_IMAGE_TEXTURE_UNIT);
GLuint id = QOpenGLTextureCache::cacheForContext(ctx)->bindTexture(ctx, pixmap);
- transferMode(ImageArrayDrawingMode);
+ transferMode(ImageOpacityArrayDrawingMode);
bool isBitmap = pixmap.isQBitmap();
bool isOpaque = !isBitmap && (!pixmap.hasAlpha() || (hints & QPainter::OpaqueHint)) && allOpaque;
diff --git a/src/gui/opengl/qopenglpaintengine_p.h b/src/gui/opengl/qopenglpaintengine_p.h
index 9c54eae3b3..d51f0e5256 100644
--- a/src/gui/opengl/qopenglpaintengine_p.h
+++ b/src/gui/opengl/qopenglpaintengine_p.h
@@ -70,7 +70,8 @@ enum EngineMode {
ImageDrawingMode,
TextDrawingMode,
BrushDrawingMode,
- ImageArrayDrawingMode
+ ImageArrayDrawingMode,
+ ImageOpacityArrayDrawingMode
};
QT_BEGIN_NAMESPACE
diff --git a/src/gui/opengl/qopengltextureglyphcache.cpp b/src/gui/opengl/qopengltextureglyphcache.cpp
index b751629117..83f407575e 100644
--- a/src/gui/opengl/qopengltextureglyphcache.cpp
+++ b/src/gui/opengl/qopengltextureglyphcache.cpp
@@ -120,7 +120,7 @@ void QOpenGLTextureGlyphCache::createTextureData(int width, int height)
m_textureResource->m_width = width;
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);
for (int i = 0; i < data.size(); ++i)
data[i] = 0;
@@ -314,30 +314,40 @@ void QOpenGLTextureGlyphCache::fillTexture(const Coord &c, glyph_t glyph, QFixed
for (int x = 0; x < maskWidth; ++x)
src[x] = -src[x]; // convert 0 and 1 into 0 and 255
}
- } else if (mask.format() == QImage::Format_RGB32) {
- // Make the alpha component equal to the average of the RGB values.
- // This is needed when drawing sub-pixel antialiased text on translucent targets.
- for (int y = 0; y < maskHeight; ++y) {
- quint32 *src = (quint32 *) mask.scanLine(y);
- for (int x = 0; x < maskWidth; ++x) {
- uchar r = src[x] >> 16;
- uchar g = src[x] >> 8;
- uchar b = src[x];
- quint32 avg = (quint32(r) + quint32(g) + quint32(b) + 1) / 3; // "+1" for rounding.
+ } else if (mask.depth() == 32) {
+ 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.
+#if defined(QT_OPENGL_ES_2)
+ || !hasBGRA // We need to reverse the bytes
+#endif
+ ) {
+ for (int y = 0; y < maskHeight; ++y) {
+ quint32 *src = (quint32 *) mask.scanLine(y);
+ for (int x = 0; x < maskWidth; ++x) {
+ uchar r = src[x] >> 16;
+ uchar g = src[x] >> 8;
+ uchar b = src[x];
+ 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 (!hasBGRA) {
- // Reverse bytes to match GL_RGBA
- src[x] = (avg << 24) | (quint32(r) << 0) | (quint32(g) << 8) | (quint32(b) << 16);
- } else
+ if (!hasBGRA) {
+ // Reverse bytes to match GL_RGBA
+ src[x] = (avg << 24) | (quint32(r) << 0) | (quint32(g) << 8) | (quint32(b) << 16);
+ } else
#endif
- src[x] = (src[x] & 0x00ffffff) | (avg << 24);
+ src[x] = (src[x] & 0x00ffffff) | (avg << 24);
+ }
}
}
}
glBindTexture(GL_TEXTURE_2D, m_textureResource->m_texture);
- if (mask.format() == QImage::Format_RGB32) {
+ if (mask.depth() == 32) {
#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());
#else
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index b9202e1612..fd867ebde6 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -2857,7 +2857,19 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
// x, y,
// 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;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 5ca6075423..6e72b5db7f 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -1088,6 +1088,9 @@ bool QPaintEngineEx::requiresPretransformedGlyphPositions(QFontEngine *, const Q
bool QPaintEngineEx::shouldDrawCachedGlyphs(QFontEngine *fontEngine, const QTransform &m) const
{
+ if (fontEngine->glyphFormat == QFontEngineGlyphCache::Raster_ARGB)
+ return true;
+
qreal pixelSize = fontEngine->fontDef.pixelSize;
return (pixelSize * pixelSize * qAbs(m.determinant())) <
QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE;
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 2ffdc9cd59..8769aeaba9 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -129,6 +129,7 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
switch (m_type) {
case Raster_A8: format = QFontEngine::Format_A8; break;
case Raster_RGBMask: format = QFontEngine::Format_A32; break;
+ case Raster_ARGB: format = QFontEngine::Format_ARGB; 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)
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);
}
@@ -306,6 +309,7 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
m_image = QImage(width, height, QImage::Format_RGB32);
break;
case QFontEngineGlyphCache::Raster_ARGB:
+ m_image = QImage(width, height, QImage::Format_ARGB32_Premultiplied);
break;
}
}
@@ -322,7 +326,8 @@ void QImageTextureGlyphCache::fillTexture(const Coord &c, glyph_t g, QFixed subP
}
#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()),
qMax(mask.width(), c.w), qMax(mask.height(), c.h), m_image.bytesPerLine(),
m_image.format());
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index b320dc0e66..1a7f2b7b4d 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -649,6 +649,13 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition
return rgbMask;
}
+QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&)
+{
+ Q_UNUSED(subPixelPosition);
+
+ return QImage();
+}
+
QFixed QFontEngine::subPixelPositionForX(QFixed x) const
{
if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 854f6fbbb6..a373c3d5f1 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -112,7 +112,8 @@ public:
Format_Render = Format_None,
Format_Mono,
Format_A8,
- Format_A32
+ Format_A32,
+ Format_ARGB
};
enum ShaperFlag {
@@ -191,6 +192,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 *lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
GlyphFormat neededFormat,
const QTransform &t = QTransform(),
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
index 70416bc2dd..078b639fa8 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext.mm
@@ -158,7 +158,7 @@ void QCoreTextFontEngine::init()
synthesisFlags = 0;
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))
glyphFormat = QFontEngineGlyphCache::Raster_ARGB;
else
@@ -457,7 +457,9 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
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);
#ifndef Q_OS_IOS
@@ -465,7 +467,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
#else
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
#endif
- uint cgflags = kCGImageAlphaNoneSkipFirst;
+ uint cgflags = isColorGlyph ? kCGImageAlphaPremultipliedFirst : kCGImageAlphaNoneSkipFirst;
#ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
cgflags |= kCGBitmapByteOrder32Host;
#endif
@@ -476,38 +478,49 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > antialiasingThreshold)
&& !(fontDef.styleStrategy & QFont::NoAntialias));
CGContextSetShouldSmoothFonts(ctx, aa);
- CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
- CGAffineTransform cgMatrix = CGAffineTransformIdentity;
- CGAffineTransformConcat(cgMatrix, oldTextMatrix);
+ CGAffineTransform cgMatrix = CGAffineTransformIdentity;
if (synthesisFlags & QFontEngine::SynthesizedItalic)
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
- cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
+ if (!isColorGlyph) // CTFontDrawGlyphs incorporates the font's matrix already
+ cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
+
if (m.isScaling())
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(m.m11(), m.m22()));
- CGContextSetTextMatrix(ctx, cgMatrix);
- CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
- CGContextSetTextDrawingMode(ctx, kCGTextFill);
-
- CGContextSetFont(ctx, cgFont);
-
+ CGGlyph cgGlyph = glyph;
qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
qreal pos_y = im.height() + br.y.toReal();
- CGContextSetTextPosition(ctx, pos_x, pos_y);
- CGSize advance;
- advance.width = 0;
- advance.height = 0;
- CGGlyph cgGlyph = glyph;
- CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
+ if (!isColorGlyph) {
+ CGContextSetTextMatrix(ctx, cgMatrix);
+ CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
+ CGContextSetTextDrawingMode(ctx, kCGTextFill);
+ CGContextSetFont(ctx, cgFont);
+ CGContextSetTextPosition(ctx, pos_x, pos_y);
- if (synthesisFlags & QFontEngine::SynthesizedBold) {
- CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
- CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
+ CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &CGSizeZero, 1);
+
+ if (synthesisFlags & QFontEngine::SynthesizedBold) {
+ CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
+ 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);
CGColorSpaceRelease(colorspace);
@@ -556,6 +569,14 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
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
{
int i, numGlyphs = glyphs->numGlyphs;
diff --git a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
index e7fec4be14..7c8f28aabd 100644
--- a/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
+++ b/src/platformsupport/fontdatabases/mac/qfontengine_coretext_p.h
@@ -98,6 +98,7 @@ public:
virtual QImage alphaMapForGlyph(glyph_t, QFixed subPixelPosition);
virtual QImage alphaMapForGlyph(glyph_t glyph, 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 minLeftBearing() const;
virtual QFixed emSquareSize() const;