diff options
author | Liang Qi <liang.qi@theqtcompany.com> | 2015-04-08 21:24:25 +0200 |
---|---|---|
committer | Liang Qi <liang.qi@theqtcompany.com> | 2015-04-08 21:24:26 +0200 |
commit | 4973786f0d36fc379c7e88a20c51639e93ddea2a (patch) | |
tree | d4d0e3cc8adc4be3aeef13bffb6907154daf95fd /src/gui | |
parent | 0b17d2328592c03503c41af7d594e58233255ff5 (diff) | |
parent | 00540a8345c35703aeaab072fd9e4727c9b61d5a (diff) |
Merge remote-tracking branch 'origin/5.5' into dev
Change-Id: I04f9f2749f68c0cb5a427b8d84e43b44bb143e4d
Diffstat (limited to 'src/gui')
-rw-r--r-- | src/gui/math3d/qquaternion.cpp | 30 | ||||
-rw-r--r-- | src/gui/math3d/qquaternion.h | 2 | ||||
-rw-r--r-- | src/gui/opengl/qopenglframebufferobject.cpp | 6 | ||||
-rw-r--r-- | src/gui/painting/qtextureglyphcache.cpp | 11 | ||||
-rw-r--r-- | src/gui/text/qfontengine_ft.cpp | 253 | ||||
-rw-r--r-- | src/gui/text/qfontengine_ft_p.h | 1 |
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; |