summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorLiang Qi <liang.qi@theqtcompany.com>2015-04-08 21:24:25 +0200
committerLiang Qi <liang.qi@theqtcompany.com>2015-04-08 21:24:26 +0200
commit4973786f0d36fc379c7e88a20c51639e93ddea2a (patch)
treed4d0e3cc8adc4be3aeef13bffb6907154daf95fd /src/gui
parent0b17d2328592c03503c41af7d594e58233255ff5 (diff)
parent00540a8345c35703aeaab072fd9e4727c9b61d5a (diff)
Merge remote-tracking branch 'origin/5.5' into dev
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/math3d/qquaternion.cpp30
-rw-r--r--src/gui/math3d/qquaternion.h2
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp6
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp11
-rw-r--r--src/gui/text/qfontengine_ft.cpp253
-rw-r--r--src/gui/text/qfontengine_ft_p.h1
6 files changed, 136 insertions, 167 deletions
diff --git a/src/gui/math3d/qquaternion.cpp b/src/gui/math3d/qquaternion.cpp
index 6914a0b45e..4b35ee4e79 100644
--- a/src/gui/math3d/qquaternion.cpp
+++ b/src/gui/math3d/qquaternion.cpp
@@ -720,8 +720,38 @@ QQuaternion QQuaternion::fromAxes(const QVector3D &xAxis, const QVector3D &yAxis
/*!
\since 5.5
+ Constructs the quaternion using specified forward direction \a direction
+ and upward direction \a up.
+ If the upward direction was not specified or the forward and upward
+ vectors are collinear, a new orthonormal upward direction will be generated.
+
+ \sa fromAxes(), rotationTo()
+*/
+QQuaternion QQuaternion::fromDirection(const QVector3D &direction, const QVector3D &up)
+{
+ if (qFuzzyIsNull(direction.x()) && qFuzzyIsNull(direction.y()) && qFuzzyIsNull(direction.z()))
+ return QQuaternion();
+
+ const QVector3D zAxis(direction.normalized());
+ QVector3D xAxis(QVector3D::crossProduct(up, zAxis));
+ if (qFuzzyIsNull(xAxis.lengthSquared())) {
+ // collinear or invalid up vector; derive shortest arc to new direction
+ return QQuaternion::rotationTo(QVector3D(0.0f, 0.0f, 1.0f), zAxis);
+ }
+
+ xAxis.normalize();
+ const QVector3D yAxis(QVector3D::crossProduct(zAxis, xAxis));
+
+ return QQuaternion::fromAxes(xAxis, yAxis, zAxis);
+}
+
+/*!
+ \since 5.5
+
Returns the shortest arc quaternion to rotate from the direction described by the vector \a from
to the direction described by the vector \a to.
+
+ \sa fromDirection()
*/
QQuaternion QQuaternion::rotationTo(const QVector3D &from, const QVector3D &to)
{
diff --git a/src/gui/math3d/qquaternion.h b/src/gui/math3d/qquaternion.h
index c3918645d4..240e31a5c2 100644
--- a/src/gui/math3d/qquaternion.h
+++ b/src/gui/math3d/qquaternion.h
@@ -138,6 +138,8 @@ public:
void getAxes(QVector3D *xAxis, QVector3D *yAxis, QVector3D *zAxis) const;
static QQuaternion fromAxes(const QVector3D &xAxis, const QVector3D &yAxis, const QVector3D &zAxis);
+ static QQuaternion fromDirection(const QVector3D &direction, const QVector3D &up);
+
static QQuaternion rotationTo(const QVector3D &from, const QVector3D &to);
#endif
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index c4deeea4c9..8d298496df 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -1484,8 +1484,10 @@ void QOpenGLFramebufferObject::blitFramebuffer(QOpenGLFramebufferObject *target,
const int ty0 = targetRect.top();
const int ty1 = targetRect.top() + targetRect.height();
- extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : 0);
- extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : 0);
+ const GLuint defaultFboId = ctx->defaultFramebufferObject();
+
+ extensions.glBindFramebuffer(GL_READ_FRAMEBUFFER, source ? source->handle() : defaultFboId);
+ extensions.glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target ? target->handle() : defaultFboId);
extensions.glBlitFramebuffer(sx0, sy0, sx1, sy1,
tx0, ty0, tx1, ty1,
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 881fae9afc..4c879cf05d 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -123,17 +123,6 @@ bool QTextureGlyphCache::populate(QFontEngine *fontEngine, int numGlyphs, const
if (listItemCoordinates.contains(GlyphAndSubPixelPosition(glyph, subPixelPosition)))
continue;
- // This is a rather crude hack, but it works.
- // The FreeType font engine is not capable of getting precise metrics for the alphamap
- // without first rasterizing the glyph. If we force the glyph to be rasterized before
- // we ask for the alphaMapBoundingBox(), the glyph will be loaded, rasterized and its
- // proper metrics will be cached and used later.
- if (fontEngine->hasInternalCaching()) {
- QImage *locked = fontEngine->lockedAlphaMapForGlyph(glyph, subPixelPosition, m_format);
- if (locked && !locked->isNull())
- fontEngine->unlockAlphaMapForGlyph();
- }
-
glyph_metrics_t metrics = fontEngine->alphaMapBoundingBox(glyph, subPixelPosition, m_transform, m_format);
#ifdef CACHE_DEBUG
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index 8176ede994..931c71dc63 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -43,6 +43,7 @@
#include "qfile.h"
#include "qfileinfo.h"
+#include <qscopedvaluerollback.h>
#include "qthreadstorage.h"
#include <qmath.h>
@@ -800,6 +801,17 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
return load_flags;
}
+static inline bool areMetricsTooLarge(const QFontEngineFT::GlyphInfo &info)
+{
+ // false if exceeds QFontEngineFT::Glyph metrics
+ return (short)(info.linearAdvance) != info.linearAdvance
+ || (signed char)(info.xOff) != info.xOff
+ || (uchar)(info.width) != info.width
+ || (uchar)(info.height) != info.height
+ || (signed char)(info.x) != info.x
+ || (signed char)(info.y) != info.y;
+}
+
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
QFixed subPixelPosition,
GlyphFormat format,
@@ -807,13 +819,9 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
{
// Q_ASSERT(freetype->lock == 1);
- if (format == Format_None) {
- if (defaultFormat != Format_None) {
- format = defaultFormat;
- } else {
- format = Format_Mono;
- }
- }
+ if (format == Format_None)
+ format = defaultFormat != Format_None ? defaultFormat : Format_Mono;
+ Q_ASSERT(format != Format_None);
Glyph *g = set ? set->getGlyph(glyph, subPixelPosition) : 0;
if (g && g->format == format && (fetchMetricsOnly || g->data))
@@ -822,32 +830,28 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
if (!g && set && set->isGlyphMissing(glyph))
return &emptyGlyph;
- QFontEngineFT::GlyphInfo info;
- Q_ASSERT(format != Format_None);
+ FT_Face face = freetype->face;
+
+ FT_Matrix matrix = freetype->matrix;
+
+ FT_Vector v;
+ v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.value());
+ v.y = 0;
+ FT_Set_Transform(face, &matrix, &v);
+
bool hsubpixel = false;
int vfactor = 1;
int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
- if (format != Format_Mono && !embeddedbitmap)
- load_flags |= FT_LOAD_NO_BITMAP;
-
- FT_Matrix matrix = freetype->matrix;
bool transform = matrix.xx != 0x10000
|| matrix.yy != 0x10000
|| matrix.xy != 0
|| matrix.yx != 0;
- if (transform)
+ if (transform || (format != Format_Mono && !embeddedbitmap))
load_flags |= FT_LOAD_NO_BITMAP;
- FT_Face face = freetype->face;
-
- FT_Vector v;
- v.x = format == Format_Mono ? 0 : FT_Pos(subPixelPosition.toReal() * 64);
- v.y = 0;
- FT_Set_Transform(face, &freetype->matrix, &v);
-
FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
load_flags &= ~FT_LOAD_NO_BITMAP;
@@ -891,6 +895,8 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
FT_Matrix_Multiply(&m, &matrix);
}
+ GlyphInfo info;
+ info.linearAdvance = slot->linearHoriAdvance >> 10;
info.xOff = TRUNC(ROUND(slot->advance.x));
info.yOff = 0;
@@ -899,27 +905,23 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
int right = CEIL(slot->metrics.horiBearingX + slot->metrics.width);
int top = CEIL(slot->metrics.horiBearingY);
int bottom = FLOOR(slot->metrics.horiBearingY - slot->metrics.height);
- int width = right-left;
- int height = top-bottom;
+ info.x = TRUNC(left);
+ info.y = TRUNC(top);
+ info.width = TRUNC(right - left);
+ info.height = TRUNC(top - bottom);
// If any of the metrics are too large to fit, don't cache them
- if (qAbs(info.xOff) >= 128
- || qAbs(TRUNC(top)) >= 128
- || TRUNC(width) >= 256
- || TRUNC(height) >= 256
- || qAbs(TRUNC(left)) >= 128
- || qAbs(TRUNC(ROUND(slot->advance.x))) >= 128) {
+ if (areMetricsTooLarge(info))
return 0;
- }
g = new Glyph;
g->data = 0;
- g->linearAdvance = slot->linearHoriAdvance >> 10;
- g->width = TRUNC(width);
- g->height = TRUNC(height);
- g->x = TRUNC(left);
- g->y = TRUNC(top);
- g->advance = TRUNC(ROUND(slot->advance.x));
+ g->linearAdvance = info.linearAdvance;
+ g->width = info.width;
+ g->height = info.height;
+ g->x = info.x;
+ g->y = info.y;
+ g->advance = info.xOff;
g->format = format;
if (set)
@@ -948,7 +950,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
info.height = slot->bitmap.rows / vfactor;
info.width = hsubpixel ? slot->bitmap.width / 3 : slot->bitmap.width;
- info.x = -slot->bitmap_left;
+ info.x = slot->bitmap_left;
info.y = slot->bitmap_top;
glyph_buffer_size = info.width * info.height * 4;
@@ -1013,23 +1015,16 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
hpixels = hpixels*3 + 8;
info.width = hpixels;
info.height = TRUNC(top - bottom);
- info.x = -TRUNC(left);
+ info.x = TRUNC(left);
info.y = TRUNC(top);
if (hsubpixel) {
info.width /= 3;
- info.x += 1;
+ info.x -= 1;
}
- bool large_glyph = (((short)(slot->linearHoriAdvance>>10) != slot->linearHoriAdvance>>10)
- || ((uchar)(info.width) != info.width)
- || ((uchar)(info.height) != info.height)
- || ((signed char)(info.x) != info.x)
- || ((signed char)(info.y) != info.y)
- || ((signed char)(info.xOff) != info.xOff));
-
- if (large_glyph) {
+ // If any of the metrics are too large to fit, don't cache them
+ if (areMetricsTooLarge(info))
return 0;
- }
int pitch = (format == Format_Mono ? ((info.width + 31) & ~31) >> 3 :
(format == Format_A8 ? (info.width + 3) & ~3 : info.width * 4));
@@ -1142,10 +1137,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
g->data = 0;
}
- g->linearAdvance = slot->linearHoriAdvance >> 10;
+ g->linearAdvance = info.linearAdvance;
g->width = info.width;
g->height = info.height;
- g->x = -info.x;
+ g->x = info.x;
g->y = info.y;
g->advance = info.xOff;
g->format = format;
@@ -1725,100 +1720,60 @@ glyph_metrics_t QFontEngineFT::alphaMapBoundingBox(glyph_t glyph, QFixed subPixe
return overall;
}
-QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
- QFontEngine::GlyphFormat neededFormat,
- const QTransform &t, QPoint *offset)
+static inline QImage alphaMapFromGlyphData(QFontEngineFT::Glyph *glyph, QFontEngine::GlyphFormat glyphFormat)
{
- Q_ASSERT(currentlyLockedAlphaMap.isNull());
- lockFace();
-
- if (isBitmapFont())
- neededFormat = Format_Mono;
- else if (neededFormat == Format_None && defaultFormat != Format_None)
- neededFormat = defaultFormat;
- else if (neededFormat == Format_None)
- neededFormat = Format_A8;
+ if (glyph == Q_NULLPTR)
+ return QImage();
QImage::Format format;
- switch (neededFormat) {
- case Format_Mono:
+ int bytesPerLine;
+ switch (glyphFormat) {
+ case QFontEngine::Format_Mono:
format = QImage::Format_Mono;
+ bytesPerLine = ((glyph->width + 31) & ~31) >> 3;
break;
- case Format_A8:
+ case QFontEngine::Format_A8:
format = QImage::Format_Alpha8;
+ bytesPerLine = (glyph->width + 3) & ~3;
break;
- case Format_A32:
+ case QFontEngine::Format_A32:
format = QImage::Format_ARGB32;
+ bytesPerLine = glyph->width * 4;
break;
default:
- Q_ASSERT(false);
- format = QImage::Format_Invalid;
+ Q_UNREACHABLE();
};
- QFontEngineFT::Glyph *glyph;
- if (cacheEnabled) {
- QGlyphSet *gset = loadGlyphSet(t);
- QFontEngine::HintStyle hintStyle = default_hint_style;
- if (t.type() >= QTransform::TxScale) {
- // disable hinting if the glyphs are transformed
- default_hint_style = HintNone;
- }
-
- if (gset) {
- FT_Matrix m = matrix;
- FT_Matrix_Multiply(&gset->transformationMatrix, &m);
- FT_Set_Transform(freetype->face, &m, 0);
- freetype->matrix = m;
- }
+ return QImage(static_cast<const uchar *>(glyph->data), glyph->width, glyph->height, bytesPerLine, format);
+}
- if (!gset || gset->outline_drawing || !(glyph = loadGlyph(gset, glyphIndex, subPixelPosition,
- neededFormat))) {
- default_hint_style = hintStyle;
- return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t,
- offset);
- }
- default_hint_style = hintStyle;
- } else {
- FT_Matrix m = matrix;
- FT_Matrix extra = QTransformToFTMatrix(t);
- FT_Matrix_Multiply(&extra, &m);
- FT_Set_Transform(freetype->face, &m, 0);
- freetype->matrix = m;
- glyph = loadGlyph(0, glyphIndex, subPixelPosition, neededFormat);
- }
+QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixelPosition,
+ QFontEngine::GlyphFormat neededFormat,
+ const QTransform &t, QPoint *offset)
+{
+ Q_ASSERT(currentlyLockedAlphaMap.isNull());
- if (glyph == 0 || glyph->data == 0 || glyph->width == 0 || glyph->height == 0) {
- if (!cacheEnabled && glyph != &emptyGlyph)
- delete glyph;
- unlockFace();
- return 0;
- }
+ if (isBitmapFont())
+ neededFormat = Format_Mono;
+ else if (neededFormat == Format_None && defaultFormat != Format_None)
+ neededFormat = defaultFormat;
+ else if (neededFormat == Format_None)
+ neededFormat = Format_A8;
- int pitch;
- switch (neededFormat) {
- case Format_Mono:
- pitch = ((glyph->width + 31) & ~31) >> 3;
- break;
- case Format_A8:
- pitch = (glyph->width + 3) & ~3;
- break;
- case Format_A32:
- pitch = glyph->width * 4;
- break;
- default:
- Q_ASSERT(false);
- pitch = 0;
- };
+ Glyph *glyph = loadGlyphFor(glyphIndex, subPixelPosition, neededFormat, t);
- if (offset != 0)
+ if (offset != 0 && glyph != 0)
*offset = QPoint(glyph->x, -glyph->y);
- currentlyLockedAlphaMap = QImage(glyph->data, glyph->width, glyph->height, pitch, format);
+ currentlyLockedAlphaMap = alphaMapFromGlyphData(glyph, neededFormat);
+
if (!cacheEnabled && glyph != &emptyGlyph) {
currentlyLockedAlphaMap = currentlyLockedAlphaMap.copy();
delete glyph;
}
- Q_ASSERT(!currentlyLockedAlphaMap.isNull());
+
+ if (currentlyLockedAlphaMap.isNull())
+ return QFontEngine::lockedAlphaMapForGlyph(glyphIndex, subPixelPosition, neededFormat, t, offset);
QImageData *data = currentlyLockedAlphaMap.data_ptr();
data->is_locked = true;
@@ -1828,9 +1783,7 @@ QImage *QFontEngineFT::lockedAlphaMapForGlyph(glyph_t glyphIndex, QFixed subPixe
void QFontEngineFT::unlockAlphaMapForGlyph()
{
- Q_ASSERT(!currentlyLockedAlphaMap.isNull());
- unlockFace();
- currentlyLockedAlphaMap = QImage();
+ QFontEngine::unlockAlphaMapForGlyph();
}
QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
@@ -1845,6 +1798,10 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyphFor(glyph_t g,
Glyph *glyph = glyphSet != 0 ? glyphSet->getGlyph(g, subPixelPosition) : 0;
if (!glyph || glyph->format != format || (!fetchBoundingBox && !glyph->data)) {
+ QScopedValueRollback<HintStyle> saved_default_hint_style(default_hint_style);
+ if (t.type() >= QTransform::TxScale)
+ default_hint_style = HintNone; // disable hinting if the glyphs are transformed
+
lockFace();
FT_Matrix m = this->matrix;
FT_Matrix ftMatrix = glyphSet != 0 ? glyphSet->transformationMatrix : QTransformToFTMatrix(t);
@@ -1864,32 +1821,20 @@ QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition)
QImage QFontEngineFT::alphaMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
{
- Glyph *glyph = loadGlyphFor(g, subPixelPosition, antialias ? Format_A8 : Format_Mono, t);
- if (!glyph || !glyph->data) {
- if (!cacheEnabled && glyph != &emptyGlyph)
- delete glyph;
- return QFontEngine::alphaMapForGlyph(g);
- }
+ const GlyphFormat neededFormat = antialias ? Format_A8 : Format_Mono;
- const int pitch = antialias ? (glyph->width + 3) & ~3 : ((glyph->width + 31)/32) * 4;
+ Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t);
- QImage img(glyph->width, glyph->height, antialias ? QImage::Format_Alpha8 : QImage::Format_Mono);
- if (!antialias) {
- QVector<QRgb> colors(2);
- colors[0] = qRgba(0, 0, 0, 0);
- colors[1] = qRgba(0, 0, 0, 255);
- img.setColorTable(colors);
- }
- Q_ASSERT(img.bytesPerLine() == pitch);
- if (glyph->width) {
- for (int y = 0; y < glyph->height; ++y)
- memcpy(img.scanLine(y), &glyph->data[y * pitch], pitch);
- }
+ QImage img = alphaMapFromGlyphData(glyph, neededFormat);
+ img = img.copy();
if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph;
- return img;
+ if (!img.isNull())
+ return img;
+
+ return QFontEngine::alphaMapForGlyph(g);
}
QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, const QTransform &t)
@@ -1897,20 +1842,20 @@ QImage QFontEngineFT::alphaRGBMapForGlyph(glyph_t g, QFixed subPixelPosition, co
if (t.type() > QTransform::TxRotate)
return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
- Glyph *glyph = loadGlyphFor(g, subPixelPosition, Format_A32, t);
- if (!glyph || !glyph->data) {
- if (!cacheEnabled && glyph != &emptyGlyph)
- delete glyph;
- return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
- }
+ const GlyphFormat neededFormat = Format_A32;
- QImage img(glyph->width, glyph->height, QImage::Format_RGB32);
- memcpy(img.bits(), glyph->data, 4 * glyph->width * glyph->height);
+ Glyph *glyph = loadGlyphFor(g, subPixelPosition, neededFormat, t);
+
+ QImage img = alphaMapFromGlyphData(glyph, neededFormat);
+ img = img.copy();
if (!cacheEnabled && glyph != &emptyGlyph)
delete glyph;
- return img;
+ if (!img.isNull())
+ return img;
+
+ return QFontEngine::alphaRGBMapForGlyph(g, subPixelPosition, t);
}
void QFontEngineFT::removeGlyphFromCache(glyph_t glyph)
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index e9d058d50c..7b28a4064f 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -143,6 +143,7 @@ public:
};
struct GlyphInfo {
+ int linearAdvance;
unsigned short width;
unsigned short height;
short x;