summaryrefslogtreecommitdiffstats
path: root/src/gui/opengl
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/gui/opengl
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/gui/opengl')
-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
3 files changed, 57 insertions, 30 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