diff --git a/src/declarative/items/qquicktext.cpp b/src/declarative/items/qquicktext.cpp index 4a3308626af1ac5371a48aba4e1ead9b593ac937..e11e4be0891b391f2582b4c5bfdc66f8047f67da 100644 --- a/src/declarative/items/qquicktext.cpp +++ b/src/declarative/items/qquicktext.cpp @@ -42,7 +42,6 @@ #include "qquicktext_p.h" #include "qquicktext_p_p.h" -#include <private/qsgdistancefieldglyphcache_p.h> #include <private/qsgcontext_p.h> #include <private/qsgadaptationlayer_p.h> #include "qquicktextnode_p.h" diff --git a/src/declarative/items/qquicktextedit.cpp b/src/declarative/items/qquicktextedit.cpp index 18d2cb8edeb6a1d678ce3027f795abe7b1f0fa10..c5b2f5750b11fde9e0490d1cea7302ebb5c3df8e 100644 --- a/src/declarative/items/qquicktextedit.cpp +++ b/src/declarative/items/qquicktextedit.cpp @@ -56,7 +56,6 @@ #include <private/qdeclarativeglobal_p.h> #include <private/qtextcontrol_p.h> #include <private/qtextengine_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <private/qsgtexture_p.h> #include <private/qsgadaptationlayer_p.h> diff --git a/src/declarative/items/qquicktextinput.cpp b/src/declarative/items/qquicktextinput.cpp index 69f699446a6bd85ff6ae864d80ee775a6fc24fe5..218a313a17ff724370379e56b7398e298a7689aa 100644 --- a/src/declarative/items/qquicktextinput.cpp +++ b/src/declarative/items/qquicktextinput.cpp @@ -44,7 +44,6 @@ #include "qquickcanvas.h" #include <private/qdeclarativeglobal_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <QtDeclarative/qdeclarativeinfo.h> #include <QtGui/qevent.h> diff --git a/src/declarative/items/qquicktextnode.cpp b/src/declarative/items/qquicktextnode.cpp index 5cc372f9e117513be79aabf72df67806e5235f0b..56c3b54cd7ad337c3983de026a5c3a13d8ef5319 100644 --- a/src/declarative/items/qquicktextnode.cpp +++ b/src/declarative/items/qquicktextnode.cpp @@ -42,7 +42,6 @@ #include "qquicktextnode_p.h" #include "qsgsimplerectnode.h" #include <private/qsgadaptationlayer_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <private/qsgdistancefieldglyphnode_p.h> #include <private/qsgcontext_p.h> diff --git a/src/declarative/scenegraph/qsgadaptationlayer.cpp b/src/declarative/scenegraph/qsgadaptationlayer.cpp index e573e5f3444c99b31bb18cdd8b0f0ccc66f0edf4..966a24acd3d2cb02ae6399a463836cea0a7900cc 100644 --- a/src/declarative/scenegraph/qsgadaptationlayer.cpp +++ b/src/declarative/scenegraph/qsgadaptationlayer.cpp @@ -40,3 +40,276 @@ ****************************************************************************/ #include "qsgadaptationlayer_p.h" + +#include <qmath.h> +#include <private/qsgdistancefieldutil_p.h> +#include <private/qsgdistancefieldglyphnode_p.h> +#include <private/qrawfont_p.h> +#include <QtGui/qguiapplication.h> +#include <qdir.h> + +QT_BEGIN_NAMESPACE + + +QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_caches_data; + +QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) + : ctx(c) + , m_manager(man) +{ + Q_ASSERT(font.isValid()); + m_font = font; + + m_cacheData = cacheData(); + + QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); + m_glyphCount = fontD->fontEngine->glyphCount(); + + m_cacheData->doubleGlyphResolution = qt_fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT; + + m_referenceFont = m_font; + m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution)); + Q_ASSERT(m_referenceFont.isValid()); +} + +QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache() +{ +} + +QSGDistanceFieldGlyphCache::GlyphCacheData *QSGDistanceFieldGlyphCache::cacheData() +{ + QString key = QString::fromLatin1("%1_%2_%3_%4") + .arg(m_font.familyName()) + .arg(m_font.styleName()) + .arg(m_font.weight()) + .arg(m_font.style()); + return m_caches_data[key].value<QSGDistanceFieldGlyphCache::GlyphCacheData>(ctx); +} + +qreal QSGDistanceFieldGlyphCache::fontScale() const +{ + return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE(m_cacheData->doubleGlyphResolution); +} + +int QSGDistanceFieldGlyphCache::distanceFieldRadius() const +{ + return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution); +} + +QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph) +{ + QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph); + if (metric == m_metrics.end()) { + QPainterPath path = m_font.pathForGlyph(glyph); + QRectF br = path.boundingRect(); + + Metrics m; + m.width = br.width(); + m.height = br.height(); + m.baselineX = br.x(); + m.baselineY = -br.y(); + + metric = m_metrics.insert(glyph, m); + } + + return metric.value(); +} + +QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph) const +{ + return m_cacheData->texCoords.value(glyph); +} + +static QSGDistanceFieldGlyphCache::Texture g_emptyTexture; + +const QSGDistanceFieldGlyphCache::Texture *QSGDistanceFieldGlyphCache::glyphTexture(glyph_t glyph) const +{ + QHash<glyph_t, Texture*>::const_iterator it = m_cacheData->glyphTextures.find(glyph); + if (it == m_cacheData->glyphTextures.constEnd()) + return &g_emptyTexture; + return it.value(); +} + +void QSGDistanceFieldGlyphCache::populate(const QVector<glyph_t> &glyphs) +{ + QSet<glyph_t> newGlyphs; + int count = glyphs.count(); + for (int i = 0; i < count; ++i) { + glyph_t glyphIndex = glyphs.at(i); + if ((int) glyphIndex >= glyphCount()) { + qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex); + continue; + } + + if (m_cacheData->texCoords.contains(glyphIndex) || newGlyphs.contains(glyphIndex)) + continue; + + QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex); + m_cacheData->glyphPaths.insert(glyphIndex, path); + if (path.isEmpty()) { + TexCoord c; + c.width = 0; + c.height = 0; + m_cacheData->texCoords.insert(glyphIndex, c); + continue; + } + + newGlyphs.insert(glyphIndex); + } + + if (newGlyphs.isEmpty()) + return; + + QVector<glyph_t> glyphsVec; + QSet<glyph_t>::const_iterator it = newGlyphs.constBegin(); + while (it != newGlyphs.constEnd()) { + glyphsVec.append(*it); + ++it; + } + requestGlyphs(glyphsVec); +} + +void QSGDistanceFieldGlyphCache::release(const QVector<glyph_t> &glyphs) +{ + releaseGlyphs(glyphs); +} + +void QSGDistanceFieldGlyphCache::update() +{ + if (m_cacheData->pendingGlyphs.isEmpty()) + return; + + QHash<glyph_t, QImage> distanceFields; + + // ### Remove before final release + static bool cacheDistanceFields = QGuiApplication::arguments().contains(QLatin1String("--cache-distance-fields")); + + QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath()); + QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob") + .arg(tmpPath) + .arg(m_font.familyName()) + .arg(m_font.styleName()) + .arg(m_font.weight()) + .arg(m_font.style()); + + if (cacheDistanceFields && !QFile::exists(tmpPath)) + QDir(tmpPath).mkpath(tmpPath); + + for (int i = 0; i < m_cacheData->pendingGlyphs.size(); ++i) { + glyph_t glyphIndex = m_cacheData->pendingGlyphs.at(i); + + if (cacheDistanceFields) { + QString key = keyBase.arg(glyphIndex); + QFile file(key); + if (file.open(QFile::ReadOnly)) { + int fileSize = file.size(); + int dim = sqrt(float(fileSize)); + QByteArray blob = file.readAll(); + QImage df(dim, dim, QImage::Format_Indexed8); + memcpy(df.bits(), blob.constData(), fileSize); + distanceFields.insert(glyphIndex, df); + continue; + } + } + + QImage distanceField = qt_renderDistanceFieldGlyph(m_font, glyphIndex, m_cacheData->doubleGlyphResolution); + distanceFields.insert(glyphIndex, distanceField); + + if (cacheDistanceFields) { + QString key = keyBase.arg(glyphIndex); + QFile file(key); + file.open(QFile::WriteOnly); + file.write((const char *) distanceField.constBits(), distanceField.width() * distanceField.height()); + } + } + + m_cacheData->pendingGlyphs.reset(); + + storeGlyphs(distanceFields); +} + +void QSGDistanceFieldGlyphCache::addGlyphPositions(const QList<GlyphPosition> &glyphs) +{ + int count = glyphs.count(); + for (int i = 0; i < count; ++i) { + GlyphPosition glyph = glyphs.at(i); + + QPainterPath path = m_cacheData->glyphPaths.value(glyph.glyph); + QRectF br = path.boundingRect(); + TexCoord c; + c.xMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution)); + c.yMargin = QT_DISTANCEFIELD_RADIUS(m_cacheData->doubleGlyphResolution) / qreal(QT_DISTANCEFIELD_SCALE(m_cacheData->doubleGlyphResolution)); + c.x = glyph.position.x(); + c.y = glyph.position.y(); + c.width = br.width(); + c.height = br.height(); + + m_cacheData->texCoords.insert(glyph.glyph, c); + } +} + +void QSGDistanceFieldGlyphCache::addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex) +{ + int i = m_cacheData->textures.indexOf(tex); + if (i == -1) { + m_cacheData->textures.append(tex); + i = m_cacheData->textures.size() - 1; + } else { + m_cacheData->textures[i].size = tex.size; + } + Texture *texture = &(m_cacheData->textures[i]); + + int count = glyphs.count(); + for (int j = 0; j < count; ++j) + m_cacheData->glyphTextures.insert(glyphs.at(j), texture); + + QLinkedList<QSGDistanceFieldGlyphNode *>::iterator it = m_cacheData->m_registeredNodes.begin(); + while (it != m_cacheData->m_registeredNodes.end()) { + (*it)->updateGeometry(); + ++it; + } +} + +void QSGDistanceFieldGlyphCache::markGlyphsToRender(const QVector<glyph_t> &glyphs) +{ + int count = glyphs.count(); + for (int i = 0; i < count; ++i) + m_cacheData->pendingGlyphs.add(glyphs.at(i)); +} + +void QSGDistanceFieldGlyphCache::removeGlyph(glyph_t glyph) +{ + m_cacheData->texCoords.remove(glyph); + m_cacheData->glyphTextures.remove(glyph); +} + +void QSGDistanceFieldGlyphCache::updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize) +{ + int count = m_cacheData->textures.count(); + for (int i = 0; i < count; ++i) { + Texture &tex = m_cacheData->textures[i]; + if (tex.textureId == oldTex) { + tex.textureId = newTex; + tex.size = newTexSize; + return; + } + } +} + +bool QSGDistanceFieldGlyphCache::containsGlyph(glyph_t glyph) const +{ + return m_cacheData->texCoords.contains(glyph); +} + +void QSGDistanceFieldGlyphCache::registerGlyphNode(QSGDistanceFieldGlyphNode *node) +{ + m_cacheData->m_registeredNodes.append(node); +} + +void QSGDistanceFieldGlyphCache::unregisterGlyphNode(QSGDistanceFieldGlyphNode *node) +{ + m_cacheData->m_registeredNodes.removeOne(node); +} + + +QT_END_NAMESPACE diff --git a/src/declarative/scenegraph/qsgadaptationlayer_p.h b/src/declarative/scenegraph/qsgadaptationlayer_p.h index 0ad60913b3cf7d98a4fa6beca0dd9a922276c509..82e0c7cf42a13aaedf9234d0fc128b6b56be59b1 100644 --- a/src/declarative/scenegraph/qsgadaptationlayer_p.h +++ b/src/declarative/scenegraph/qsgadaptationlayer_p.h @@ -51,6 +51,9 @@ #include <QtCore/qsharedpointer.h> #include <QtGui/qglyphrun.h> #include <QtCore/qurl.h> +#include <private/qfontengine_p.h> +#include <QtGui/private/qdatabuffer_p.h> +#include <private/qopenglcontext_p.h> // ### remove #include <private/qquicktext_p.h> @@ -64,6 +67,8 @@ QT_MODULE(Declarative) class QSGNode; class QImage; class TextureReference; +class QSGDistanceFieldGlyphCacheManager; +class QSGDistanceFieldGlyphNode; // TODO: Rename from XInterface to AbstractX. class Q_DECLARATIVE_EXPORT QSGRectangleNode : public QSGGeometryNode @@ -124,6 +129,126 @@ protected: QRectF m_bounding_rect; }; +class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache +{ +public: + QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + virtual ~QSGDistanceFieldGlyphCache(); + + struct Metrics { + qreal width; + qreal height; + qreal baselineX; + qreal baselineY; + + bool isNull() const { return width == 0 || height == 0; } + }; + + struct TexCoord { + qreal x; + qreal y; + qreal width; + qreal height; + qreal xMargin; + qreal yMargin; + + TexCoord() : x(0), y(0), width(-1), height(-1), xMargin(0), yMargin(0) { } + + bool isNull() const { return width <= 0 || height <= 0; } + bool isValid() const { return width >= 0 && height >= 0; } + }; + + struct Texture { + GLuint textureId; + QSize size; + + Texture() : textureId(0), size(QSize()) { } + bool operator == (const Texture &other) const { return textureId == other.textureId; } + }; + + const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; } + + const QRawFont &font() const { return m_font; } + + qreal fontScale() const; + int distanceFieldRadius() const; + int glyphCount() const { return m_glyphCount; } + bool doubleGlyphResolution() const { return m_cacheData->doubleGlyphResolution; } + + Metrics glyphMetrics(glyph_t glyph); + TexCoord glyphTexCoord(glyph_t glyph) const; + const Texture *glyphTexture(glyph_t glyph) const; + + void populate(const QVector<glyph_t> &glyphs); + void release(const QVector<glyph_t> &glyphs); + + void update(); + + void registerGlyphNode(QSGDistanceFieldGlyphNode *node); + void unregisterGlyphNode(QSGDistanceFieldGlyphNode *node); + +protected: + struct GlyphPosition { + glyph_t glyph; + QPointF position; + }; + + virtual void requestGlyphs(const QVector<glyph_t> &glyphs) = 0; + virtual void storeGlyphs(const QHash<glyph_t, QImage> &glyphs) = 0; + virtual void releaseGlyphs(const QVector<glyph_t> &glyphs) = 0; + + void addGlyphPositions(const QList<GlyphPosition> &glyphs); + void addGlyphTextures(const QVector<glyph_t> &glyphs, const Texture &tex); + void markGlyphsToRender(const QVector<glyph_t> &glyphs); + void removeGlyph(glyph_t glyph); + + void updateTexture(GLuint oldTex, GLuint newTex, const QSize &newTexSize); + + bool containsGlyph(glyph_t glyph) const; + + QOpenGLContext *ctx; + +private: + struct GlyphCacheData : public QOpenGLSharedResource { + QList<Texture> textures; + QHash<glyph_t, Texture*> glyphTextures; + QHash<glyph_t, TexCoord> texCoords; + QDataBuffer<glyph_t> pendingGlyphs; + QHash<glyph_t, QPainterPath> glyphPaths; + bool doubleGlyphResolution; + QLinkedList<QSGDistanceFieldGlyphNode*> m_registeredNodes; + + GlyphCacheData(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) + , pendingGlyphs(64) + , doubleGlyphResolution(false) + {} + + void invalidateResource() + { + textures.clear(); + glyphTextures.clear(); + texCoords.clear(); + } + + void freeResource(QOpenGLContext *) + { + } + }; + + QSGDistanceFieldGlyphCacheManager *m_manager; + + QRawFont m_font; + QRawFont m_referenceFont; + + int m_glyphCount; + QHash<glyph_t, Metrics> m_metrics; + + GlyphCacheData *cacheData(); + GlyphCacheData *m_cacheData; + static QHash<QString, QOpenGLMultiGroupSharedResource> m_caches_data; +}; + QT_END_NAMESPACE diff --git a/src/declarative/scenegraph/qsgcontext.cpp b/src/declarative/scenegraph/qsgcontext.cpp index f995f9e76e465246d5d3fed94b46aae94cb2a94e..87beb72b5b36ed8951aff6ecc575315fafbd465e 100644 --- a/src/declarative/scenegraph/qsgcontext.cpp +++ b/src/declarative/scenegraph/qsgcontext.cpp @@ -45,11 +45,12 @@ #include <private/qsgdefaultrenderer_p.h> +#include <private/qsgdistancefieldutil_p.h> +#include <private/qsgdefaultdistancefieldglyphcache_p.h> #include <private/qsgdefaultrectanglenode_p.h> #include <private/qsgdefaultimagenode_p.h> #include <private/qsgdefaultglyphnode_p.h> #include <private/qsgdistancefieldglyphnode_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <private/qsgtexture_p.h> #include <qsgengine.h> @@ -288,6 +289,15 @@ QSGImageNode *QSGContext::createImageNode() return new QSGDefaultImageNode; } +/*! + Factory function for scene graph backends of the distance-field glyph cache. + */ +QSGDistanceFieldGlyphCache *QSGContext::createDistanceFieldGlyphCache(const QRawFont &font) +{ + Q_D(QSGContext); + return new QSGDefaultDistanceFieldGlyphCache(d->distanceFieldCacheManager, glContext(), font); +} + /*! Factory function for scene graph backends of the Text elements; */ @@ -304,7 +314,7 @@ QSGGlyphNode *QSGContext::createGlyphNode() return new QSGDefaultGlyphNode; } else { if (!d->distanceFieldCacheManager) { - d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager(d->gl); + d->distanceFieldCacheManager = new QSGDistanceFieldGlyphCacheManager(this); if (doSubpixel) d->distanceFieldCacheManager->setDefaultAntialiasingMode(QSGGlyphNode::HighQualitySubPixelAntialiasing); else if (doLowQualSubpixel) diff --git a/src/declarative/scenegraph/qsgcontext_p.h b/src/declarative/scenegraph/qsgcontext_p.h index 6fdd4aed37658cae1271972e327bc06b410f7496..328b85eb2bdc2ef7d79f85e8a40f957e729ab9b6 100644 --- a/src/declarative/scenegraph/qsgcontext_p.h +++ b/src/declarative/scenegraph/qsgcontext_p.h @@ -48,6 +48,8 @@ #include <QtGui/QImage> #include <QtGui/QSurfaceFormat> +#include <private/qrawfont_p.h> + #include "qsgnode.h" QT_BEGIN_HEADER @@ -61,6 +63,7 @@ class QSGRectangleNode; class QSGImageNode; class QSGGlyphNode; class QSGRenderer; +class QSGDistanceFieldGlyphCache; class QSGTexture; class QSGMaterial; @@ -95,6 +98,8 @@ public: virtual void renderNextFrame(QOpenGLFramebufferObject *fbo = 0); + virtual QSGDistanceFieldGlyphCache *createDistanceFieldGlyphCache(const QRawFont &font); + virtual QSGRectangleNode *createRectangleNode(); virtual QSGImageNode *createImageNode(); virtual QSGGlyphNode *createGlyphNode(); diff --git a/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a03cde026075e58bf486ca8829800de4875ea12 --- /dev/null +++ b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache.cpp @@ -0,0 +1,389 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "qsgdefaultdistancefieldglyphcache_p.h" + +#include <private/qsgdistancefieldutil_p.h> +#include <qopenglshaderprogram.h> +#include <QtGui/private/qopenglengineshadersource_p.h> +#include <qopenglfunctions.h> + + +class TextureBlitHelper +{ +public: + TextureBlitHelper() + { + m_vertexCoordinateArray[0] = -1.0f; + m_vertexCoordinateArray[1] = -1.0f; + m_vertexCoordinateArray[2] = 1.0f; + m_vertexCoordinateArray[3] = -1.0f; + m_vertexCoordinateArray[4] = 1.0f; + m_vertexCoordinateArray[5] = 1.0f; + m_vertexCoordinateArray[6] = -1.0f; + m_vertexCoordinateArray[7] = 1.0f; + + m_textureCoordinateArray[0] = 0.0f; + m_textureCoordinateArray[1] = 0.0f; + m_textureCoordinateArray[2] = 1.0f; + m_textureCoordinateArray[3] = 0.0f; + m_textureCoordinateArray[4] = 1.0f; + m_textureCoordinateArray[5] = 1.0f; + m_textureCoordinateArray[6] = 0.0f; + m_textureCoordinateArray[7] = 1.0f; + + m_blitProgram = new QOpenGLShaderProgram; + { + QString source; + source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader)); + source.append(QLatin1String(qopenglslUntransformedPositionVertexShader)); + + QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram); + vertexShader->compileSourceCode(source); + + m_blitProgram->addShader(vertexShader); + } + { + QString source; + source.append(QLatin1String(qopenglslMainFragmentShader)); + source.append(QLatin1String(qopenglslImageSrcFragmentShader)); + + QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram); + fragmentShader->compileSourceCode(source); + + m_blitProgram->addShader(fragmentShader); + } + m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); + m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); + m_blitProgram->link(); + } + + ~TextureBlitHelper() + { + delete m_blitProgram; + } + + QOpenGLShaderProgram *blitProgram() { return m_blitProgram; } + const GLfloat *blitVertexArray() const { return &m_vertexCoordinateArray[0]; } + const GLfloat *blitTextureArray() const { return &m_textureCoordinateArray[0]; } + +private: + QOpenGLShaderProgram *m_blitProgram; + GLfloat m_vertexCoordinateArray[8]; + GLfloat m_textureCoordinateArray[8]; +}; + +static TextureBlitHelper *g_textureBlitHelper = 0; + +QHash<QString, QOpenGLMultiGroupSharedResource> QSGDefaultDistanceFieldGlyphCache::m_textures_data; + +QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDefaultDistanceFieldGlyphCache::textureData() +{ + QString key = QString::fromLatin1("%1_%2_%3_%4") + .arg(font().familyName()) + .arg(font().styleName()) + .arg(font().weight()) + .arg(font().style()); + return m_textures_data[key].value<QSGDefaultDistanceFieldGlyphCache::DistanceFieldTextureData>(QOpenGLContext::currentContext()); +} + +QSGDefaultDistanceFieldGlyphCache::QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) + : QSGDistanceFieldGlyphCache(man, c, font) + , m_maxTextureSize(0) +{ + m_textureData = textureData(); +} + +void QSGDefaultDistanceFieldGlyphCache::requestGlyphs(const QVector<glyph_t> &glyphs) +{ + int count = glyphs.count(); + + // Avoid useless and costly glyph re-generation + if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) { + for (int i = 0; i < count; ++i) { + glyph_t glyphIndex = glyphs.at(i); + if (containsGlyph(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex)) + m_textureData->unusedGlyphs.remove(glyphIndex); + } + } + + QList<GlyphPosition> glyphPositions; + QVector<glyph_t> glyphsToRender; + + for (int i = 0; i < count; ++i) { + glyph_t glyphIndex = glyphs.at(i); + + if (++m_textureData->glyphRefCount[glyphIndex] == 1) + m_textureData->unusedGlyphs.remove(glyphIndex); + + if (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()) + continue; + + GlyphPosition p; + p.glyph = glyphIndex; + p.position = QPointF(m_textureData->currX, m_textureData->currY); + + if (!cacheIsFull()) { + m_textureData->currX += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()); + if (m_textureData->currX >= maxTextureSize()) { + m_textureData->currX = 0; + m_textureData->currY += QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()); + } + } else { + // Recycle glyphs + if (!m_textureData->unusedGlyphs.isEmpty()) { + glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin(); + TexCoord unusedCoord = glyphTexCoord(unusedGlyph); + p.position = QPointF(unusedCoord.x, unusedCoord.y); + m_textureData->unusedGlyphs.remove(unusedGlyph); + removeGlyph(unusedGlyph); + } + } + + if (p.position.y() < maxTextureSize()) { + glyphPositions.append(p); + glyphsToRender.append(glyphIndex); + } + } + + addGlyphPositions(glyphPositions); + markGlyphsToRender(glyphsToRender); +} + +void QSGDefaultDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs) +{ + int requiredWidth = maxTextureSize(); + int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution())); // Enough rows to fill the latin1 set by default.. + int requiredHeight = qMin(maxTextureSize(), + qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()), + QT_DISTANCEFIELD_TILESIZE(doubleGlyphResolution()) * rows)); + + resizeTexture((requiredWidth), (requiredHeight)); + glBindTexture(GL_TEXTURE_2D, m_textureData->texture); + + QVector<glyph_t> glyphTextures; + + QHash<glyph_t, QImage>::const_iterator it; + for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) { + glyph_t glyphIndex = it.key(); + TexCoord c = glyphTexCoord(glyphIndex); + + glyphTextures.append(glyphIndex); + + QImage glyph = it.value(); + + if (useWorkaroundBrokenFBOReadback()) { + uchar *inBits = glyph.scanLine(0); + uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x); + for (int y = 0; y < glyph.height(); ++y) { + qMemCopy(outBits, inBits, glyph.width()); + inBits += glyph.bytesPerLine(); + outBits += m_textureData->image.bytesPerLine(); + } + } + + glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits()); + } + + Texture t; + t.textureId = m_textureData->texture; + t.size = m_textureData->size; + addGlyphTextures(glyphTextures, t); +} + +void QSGDefaultDistanceFieldGlyphCache::releaseGlyphs(const QVector<glyph_t> &glyphs) +{ + int count = glyphs.count(); + for (int i = 0; i < count; ++i) { + glyph_t glyphIndex = glyphs.at(i); + if (--m_textureData->glyphRefCount[glyphIndex] == 0 && !glyphTexCoord(glyphIndex).isNull()) + m_textureData->unusedGlyphs.insert(glyphIndex); + } +} + +void QSGDefaultDistanceFieldGlyphCache::createTexture(int width, int height) +{ + if (useWorkaroundBrokenFBOReadback() && m_textureData->image.isNull()) + m_textureData->image = QImage(width, height, QImage::Format_Indexed8); + + while (glGetError() != GL_NO_ERROR) { } + + glGenTextures(1, &m_textureData->texture); + glBindTexture(GL_TEXTURE_2D, m_textureData->texture); + + glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + m_textureData->size = QSize(width, height); + + GLuint error = glGetError(); + if (error != GL_NO_ERROR) { + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &m_textureData->texture); + m_textureData->texture = 0; + } + +} + +void QSGDefaultDistanceFieldGlyphCache::resizeTexture(int width, int height) +{ + int oldWidth = m_textureData->size.width(); + int oldHeight = m_textureData->size.height(); + if (width == oldWidth && height == oldHeight) + return; + + GLuint oldTexture = m_textureData->texture; + createTexture(width, height); + + if (!oldTexture) + return; + + updateTexture(oldTexture, m_textureData->texture, m_textureData->size); + + if (useWorkaroundBrokenFBOReadback()) { + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, m_textureData->image.constBits()); + m_textureData->image = m_textureData->image.copy(0, 0, width, height); + glDeleteTextures(1, &oldTexture); + return; + } + + if (!g_textureBlitHelper) + g_textureBlitHelper = new TextureBlitHelper; + + if (!m_textureData->fbo) + ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo); + ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_textureData->fbo); + + GLuint tmp_texture; + glGenTextures(1, &tmp_texture); + glBindTexture(GL_TEXTURE_2D, tmp_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glBindTexture(GL_TEXTURE_2D, 0); + ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tmp_texture, 0); + + ctx->functions()->glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, oldTexture); + + // save current render states + GLboolean stencilTestEnabled; + GLboolean depthTestEnabled; + GLboolean scissorTestEnabled; + GLboolean blendEnabled; + GLint viewport[4]; + GLint oldProgram; + glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled); + glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled); + glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled); + glGetBooleanv(GL_BLEND, &blendEnabled); + glGetIntegerv(GL_VIEWPORT, &viewport[0]); + glGetIntegerv(GL_CURRENT_PROGRAM, &oldProgram); + + glDisable(GL_STENCIL_TEST); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + + glViewport(0, 0, oldWidth, oldHeight); + + ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, g_textureBlitHelper->blitVertexArray()); + ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, g_textureBlitHelper->blitTextureArray()); + + g_textureBlitHelper->blitProgram()->bind(); + g_textureBlitHelper->blitProgram()->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR)); + g_textureBlitHelper->blitProgram()->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR)); + g_textureBlitHelper->blitProgram()->disableAttributeArray(int(QT_OPACITY_ATTR)); + g_textureBlitHelper->blitProgram()->setUniformValue("imageTexture", GLuint(0)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindTexture(GL_TEXTURE_2D, m_textureData->texture); + + glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); + + ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_RENDERBUFFER, 0); + glDeleteTextures(1, &tmp_texture); + glDeleteTextures(1, &oldTexture); + + ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); + + // restore render states + if (stencilTestEnabled) + glEnable(GL_STENCIL_TEST); + if (depthTestEnabled) + glEnable(GL_DEPTH_TEST); + if (scissorTestEnabled) + glEnable(GL_SCISSOR_TEST); + if (blendEnabled) + glEnable(GL_BLEND); + glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); + ctx->functions()->glUseProgram(oldProgram); +} + +bool QSGDefaultDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const +{ + static bool set = false; + static bool useWorkaround = false; + if (!set) { + QOpenGLContextPrivate *ctx_p = static_cast<QOpenGLContextPrivate *>(QOpenGLContextPrivate::get(ctx)); + useWorkaround = ctx_p->workaround_brokenFBOReadBack; + set = true; + } + return useWorkaround; +} + +int QSGDefaultDistanceFieldGlyphCache::maxTextureSize() const +{ + if (!m_maxTextureSize) + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); + return m_maxTextureSize; +} + +QT_END_NAMESPACE diff --git a/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h new file mode 100644 index 0000000000000000000000000000000000000000..aed8d72174f53d741df24ade3fcb244eb66c4395 --- /dev/null +++ b/src/declarative/scenegraph/qsgdefaultdistancefieldglyphcache_p.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H +#define QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H + +#include <QtGui/qopenglfunctions.h> +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +class Q_DECLARATIVE_EXPORT QSGDefaultDistanceFieldGlyphCache : public QSGDistanceFieldGlyphCache +{ +public: + QSGDefaultDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); + + void requestGlyphs(const QVector<glyph_t> &glyphs); + void storeGlyphs(const QHash<glyph_t, QImage> &glyphs); + void releaseGlyphs(const QVector<glyph_t> &glyphs); + + bool cacheIsFull() const { return m_textureData->currY >= maxTextureSize(); } + bool useWorkaroundBrokenFBOReadback() const; + int maxTextureSize() const; + +private: + void createTexture(int width, int height); + void resizeTexture(int width, int height); + + mutable int m_maxTextureSize; + + struct DistanceFieldTextureData : public QOpenGLSharedResource { + GLuint texture; + GLuint fbo; + QSize size; + QHash<glyph_t, quint32> glyphRefCount; + QSet<glyph_t> unusedGlyphs; + int currX; + int currY; + QImage image; + + DistanceFieldTextureData(QOpenGLContext *ctx) + : QOpenGLSharedResource(ctx->shareGroup()) + , texture(0) + , fbo(0) + , currX(0) + , currY(0) + {} + + void invalidateResource() + { + texture = 0; + fbo = 0; + size = QSize(); + } + + void freeResource(QOpenGLContext *ctx) + { + glDeleteTextures(1, &texture); + ctx->functions()->glDeleteFramebuffers(1, &fbo); + } + }; + + DistanceFieldTextureData *textureData(); + DistanceFieldTextureData *m_textureData; + static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data; +}; + +QT_END_NAMESPACE + +#endif // QSGDEFAULTDISTANCEFIELDGLYPHCACHE_H diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h deleted file mode 100644 index aea7c5952f1741939624dfe98a9bd88123e0f967..0000000000000000000000000000000000000000 --- a/src/declarative/scenegraph/qsgdistancefieldglyphcache_p.h +++ /dev/null @@ -1,210 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). -** All rights reserved. -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** GNU Lesser General Public License Usage -** This file may be used under the terms of the GNU Lesser General Public -** License version 2.1 as published by the Free Software Foundation and -** appearing in the file LICENSE.LGPL included in the packaging of this -** file. Please review the following information to ensure the GNU Lesser -** General Public License version 2.1 requirements will be met: -** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** In addition, as a special exception, Nokia gives you certain additional -** rights. These rights are described in the Nokia Qt LGPL Exception -** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU General -** Public License version 3.0 as published by the Free Software Foundation -** and appearing in the file LICENSE.GPL included in the packaging of this -** file. Please review the following information to ensure the GNU General -** Public License version 3.0 requirements will be met: -** http://www.gnu.org/copyleft/gpl.html. -** -** Other Usage -** Alternatively, this file may be used in accordance with the terms and -** conditions contained in a signed written agreement between you and Nokia. -** -** -** -** -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef DISTANCEFIELDGLYPHCACHE_H -#define DISTANCEFIELDGLYPHCACHE_H - -#include <qopengl.h> -#include <qrawfont.h> -#include <private/qopenglcontext_p.h> -#include <QtGui/qopenglfunctions.h> -#include <private/qfont_p.h> -#include <private/qfontengine_p.h> -#include <QtGui/private/qdatabuffer_p.h> -#include <private/qsgadaptationlayer_p.h> - -QT_BEGIN_NAMESPACE - -typedef float (*ThresholdFunc)(float glyphScale); -typedef float (*AntialiasingSpreadFunc)(float glyphScale); - -class QOpenGLShaderProgram; -class QSGDistanceFieldGlyphCache; - -class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCacheManager -{ -public: - QSGDistanceFieldGlyphCacheManager(QOpenGLContext *c); - ~QSGDistanceFieldGlyphCacheManager(); - - QSGDistanceFieldGlyphCache *cache(const QRawFont &font); - - QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; } - void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; } - - ThresholdFunc thresholdFunc() const { return m_threshold_func; } - void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; } - - AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; } - void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } - - QOpenGLShaderProgram *blitProgram() { return m_blitProgram; } - const GLfloat *blitVertexArray() const { return &m_vertexCoordinateArray[0]; } - const GLfloat *blitTextureArray() const { return &m_textureCoordinateArray[0]; } - - int maxTextureSize() const; - -private: - QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches; - - QOpenGLContext *ctx; - - QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode; - ThresholdFunc m_threshold_func; - AntialiasingSpreadFunc m_antialiasingSpread_func; - - mutable int m_maxTextureSize; - - QOpenGLShaderProgram *m_blitProgram; - GLfloat m_vertexCoordinateArray[8]; - GLfloat m_textureCoordinateArray[8]; -}; - -class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCache -{ -public: - ~QSGDistanceFieldGlyphCache(); - - struct Metrics { - qreal width; - qreal height; - qreal baselineX; - qreal baselineY; - - bool isNull() const { return width == 0 || height == 0; } - }; - Metrics glyphMetrics(glyph_t glyph); - - struct TexCoord { - qreal x; - qreal y; - qreal width; - qreal height; - qreal xMargin; - qreal yMargin; - - TexCoord() : x(0), y(0), width(0), height(0), xMargin(0), yMargin(0) { } - - bool isNull() const { return width == 0 || height == 0; } - }; - TexCoord glyphTexCoord(glyph_t glyph); - - const QSGDistanceFieldGlyphCacheManager *manager() const { return m_manager; } - - GLuint texture(); - QSize textureSize() const; - qreal fontScale() const; - int distanceFieldRadius() const; - QImage renderDistanceFieldGlyph(glyph_t glyph) const; - - int glyphCount() const; - - void populate(int count, const glyph_t *glyphs); - void derefGlyphs(int count, const glyph_t *glyphs); - void updateCache(); - - bool cacheIsFull() const { return m_textureData->currY >= m_manager->maxTextureSize(); } - - bool useWorkaroundBrokenFBOReadback() const; - -private: - QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font); - - void createTexture(int width, int height); - void resizeTexture(int width, int height); - - QSGDistanceFieldGlyphCacheManager *m_manager; - - QOpenGLContext *ctx; - - QRawFont m_font; - QRawFont m_referenceFont; - - int m_glyphCount; - QHash<glyph_t, Metrics> m_metrics; - - struct DistanceFieldTextureData : public QOpenGLSharedResource { - GLuint texture; - GLuint fbo; - QSize size; - QHash<glyph_t, TexCoord> texCoords; - QDataBuffer<glyph_t> pendingGlyphs; - QHash<glyph_t, quint32> glyphRefCount; - QSet<glyph_t> unusedGlyphs; - int currX; - int currY; - QImage image; - bool doubleGlyphResolution; - - DistanceFieldTextureData(QOpenGLContext *ctx) - : QOpenGLSharedResource(ctx->shareGroup()) - , texture(0) - , fbo(0) - , pendingGlyphs(64) - , currX(0) - , currY(0) - , doubleGlyphResolution(false) - {} - - void invalidateResource() - { - texture = 0; - fbo = 0; - size = QSize(); - } - - void freeResource(QOpenGLContext *ctx) - { - glDeleteTextures(1, &texture); - ctx->functions()->glDeleteFramebuffers(1, &fbo); - } - }; - - DistanceFieldTextureData *textureData(); - DistanceFieldTextureData *m_textureData; - static QHash<QString, QOpenGLMultiGroupSharedResource> m_textures_data; - - friend class QSGDistanceFieldGlyphCacheManager; -}; - -QT_END_NAMESPACE - -#endif // DISTANCEFIELDGLYPHCACHE_H diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp index e25b1520a1e9595eba8985eba78e1b7e8a592606..e4a39e484bd433b0d805689616195b407026cc7a 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp +++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode.cpp @@ -41,7 +41,7 @@ #include "qsgdistancefieldglyphnode_p.h" #include "qsgdistancefieldglyphnode_p_p.h" -#include "qsgdistancefieldglyphcache_p.h" +#include <private/qsgdistancefieldutil_p.h> #include <private/qsgcontext_p.h> QT_BEGIN_NAMESPACE @@ -53,7 +53,6 @@ QSGDistanceFieldGlyphNode::QSGDistanceFieldGlyphNode(QSGDistanceFieldGlyphCacheM , m_geometry(QSGGeometry::defaultAttributes_TexturedPoint2D(), 0) , m_style(QQuickText::Normal) , m_antialiasingMode(GrayAntialiasing) - , m_dirtyFont(false) , m_dirtyGeometry(false) , m_dirtyMaterial(false) { @@ -69,8 +68,8 @@ QSGDistanceFieldGlyphNode::~QSGDistanceFieldGlyphNode() { delete m_material; if (m_glyph_cache) { - const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes(); - m_glyph_cache->derefGlyphs(glyphIndexes.count(), glyphIndexes.constData()); + m_glyph_cache->release(m_glyphs.glyphIndexes()); + m_glyph_cache->unregisterGlyphNode(this); } } @@ -97,7 +96,24 @@ void QSGDistanceFieldGlyphNode::setGlyphs(const QPointF &position, const QGlyphR m_position = QPointF(position.x(), position.y() - font.ascent()); m_glyphs = glyphs; - m_dirtyFont = true; + QSGDistanceFieldGlyphCache *oldCache = m_glyph_cache; + m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont()); + if (m_glyph_cache != oldCache) { + if (oldCache) + oldCache->unregisterGlyphNode(this); + m_glyph_cache->registerGlyphNode(this); + } + m_glyph_cache->populate(glyphs.glyphIndexes()); + + const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes(); + const QVector<QPointF> &glyphPositions = m_glyphs.positions(); + for (int i = 0; i < glyphIndexes.size(); ++i) { + GlyphInfo g; + g.glyphIndex = glyphIndexes.at(i); + g.position = glyphPositions.at(i); + m_glyphsToAdd.append(g); + } + m_dirtyGeometry = true; m_dirtyMaterial = true; } @@ -120,78 +136,74 @@ void QSGDistanceFieldGlyphNode::setStyleColor(const QColor &color) void QSGDistanceFieldGlyphNode::update() { - if (m_dirtyFont) - updateFont(); - if (m_dirtyGeometry) - updateGeometry(); if (m_dirtyMaterial) updateMaterial(); + if (m_dirtyGeometry) + updateGeometry(); } void QSGDistanceFieldGlyphNode::updateGeometry() { Q_ASSERT(m_glyph_cache); - QSGGeometry *g = geometry(); - QRectF boundingRect; - - const QVector<quint32> &glyphIndexes = m_glyphs.glyphIndexes(); + if (m_glyphsToAdd.isEmpty()) + return; - m_glyph_cache->populate(glyphIndexes.count(), glyphIndexes.constData()); + QSGGeometry *g = geometry(); Q_ASSERT(g->indexType() == GL_UNSIGNED_SHORT); int oldVertexCount = g->vertexCount(); int oldIndexCount = g->indexCount(); - // We could potentially move the realloc part into the QSGGeometry object as a - // grow() function... + QVector<QSGGeometry::TexturedPoint2D> vp; + vp.reserve(m_glyphsToAdd.size() * 4); + QVector<ushort> ip; + ip.reserve(m_glyphsToAdd.size() * 6); - void *data = 0; - if (oldVertexCount && oldIndexCount) { - int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D) - + oldIndexCount * sizeof(quint16); - data = qMalloc(byteSize); - memcpy(data, g->vertexData(), byteSize); - } + QPointF margins(2, 2); + QPointF texMargins = margins / m_glyph_cache->fontScale(); - g->allocate(oldVertexCount + glyphIndexes.size() * 4, oldIndexCount + glyphIndexes.size() * 6); + const QSGDistanceFieldGlyphCache::Texture *textureToUse = 0; - if (data) { - memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)); - memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D), - oldIndexCount * sizeof(quint16)); - qFree(data); - } + QLinkedList<GlyphInfo>::iterator it = m_glyphsToAdd.begin(); + while (it != m_glyphsToAdd.end()) { + quint32 glyphIndex = it->glyphIndex; + QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex); - QSGGeometry::TexturedPoint2D *vp = g->vertexDataAsTexturedPoint2D() + oldVertexCount; - ushort *ip = g->indexDataAsUShort() + oldIndexCount; + if (c.isNull()) { + if (!c.isValid()) + ++it; + else + it = m_glyphsToAdd.erase(it); + continue; + } - QPointF margins(2, 2); - QPointF texMargins = margins / m_glyph_cache->fontScale(); + const QSGDistanceFieldGlyphCache::Texture *texture = m_glyph_cache->glyphTexture(glyphIndex); + if (!texture->textureId) { + ++it; + continue; + } - QVector<QPointF> glyphPositions = m_glyphs.positions(); - for (int i = 0; i < glyphIndexes.size(); ++i) { - quint32 glyphIndex = glyphIndexes.at(i); QSGDistanceFieldGlyphCache::Metrics metrics = m_glyph_cache->glyphMetrics(glyphIndex); - QSGDistanceFieldGlyphCache::TexCoord c = m_glyph_cache->glyphTexCoord(glyphIndex); - if (!metrics.isNull() && !c.isNull()) { - metrics.width += margins.x() * 2; - metrics.height += margins.y() * 2; - metrics.baselineX -= margins.x(); - metrics.baselineY += margins.y(); - c.xMargin -= texMargins.x(); - c.yMargin -= texMargins.y(); - c.width += texMargins.x() * 2; - c.height += texMargins.y() * 2; - } + if (!textureToUse) + textureToUse = texture; - const QPointF &glyphPosition = glyphPositions.at(i); + metrics.width += margins.x() * 2; + metrics.height += margins.y() * 2; + metrics.baselineX -= margins.x(); + metrics.baselineY += margins.y(); + c.xMargin -= texMargins.x(); + c.yMargin -= texMargins.y(); + c.width += texMargins.x() * 2; + c.height += texMargins.y() * 2; + + const QPointF &glyphPosition = it->position; qreal x = glyphPosition.x() + metrics.baselineX + m_position.x(); qreal y = glyphPosition.y() - metrics.baselineY + m_position.y(); - boundingRect |= QRectF(x, y, metrics.width, metrics.height); + m_boundingRect |= QRectF(x, y, metrics.width, metrics.height); float cx1 = x; float cx2 = x + metrics.width; @@ -206,49 +218,60 @@ void QSGDistanceFieldGlyphNode::updateGeometry() if (m_baseLine.isNull()) m_baseLine = glyphPosition; - int vi = i & 1 ? (glyphIndexes.size() + 1) / 2 + i / 2 : i / 2; - vp[4 * vi + 0].set(cx1, cy1, tx1, ty1); - vp[4 * vi + 1].set(cx2, cy1, tx2, ty1); - vp[4 * vi + 2].set(cx1, cy2, tx1, ty2); - vp[4 * vi + 3].set(cx2, cy2, tx2, ty2); - - int o = i * 4 + oldVertexCount; - ip[6 * i + 0] = o + 0; - ip[6 * i + 1] = o + 2; - ip[6 * i + 2] = o + 3; - ip[6 * i + 3] = o + 3; - ip[6 * i + 4] = o + 1; - ip[6 * i + 5] = o + 0; + int i = vp.size(); + + QSGGeometry::TexturedPoint2D v1; + v1.set(cx1, cy1, tx1, ty1); + QSGGeometry::TexturedPoint2D v2; + v2.set(cx2, cy1, tx2, ty1); + QSGGeometry::TexturedPoint2D v3; + v3.set(cx1, cy2, tx1, ty2); + QSGGeometry::TexturedPoint2D v4; + v4.set(cx2, cy2, tx2, ty2); + vp.append(v1); + vp.append(v2); + vp.append(v3); + vp.append(v4); + + int o = i + oldVertexCount; + ip.append(o + 0); + ip.append(o + 2); + ip.append(o + 3); + ip.append(o + 3); + ip.append(o + 1); + ip.append(o + 0); + + it = m_glyphsToAdd.erase(it); } -// printf("Vertices:\n"); -// for (int v=0; v<g->vertexCount(); ++v) { -// QSGGeometry::TexturedPoint2D *t = g->vertexDataAsTexturedPoint2D() + v; -// printf(" - %d -- %f %f -- %.3f %.3f\n", v, t->x, t->y, t->tx, t->ty); -// } - -// printf("Indices:\n"); -// for (int i=0; i<g->indexCount();) { - -// printf(" - %[ ", i); -// printf("%d, ", g->indexDataAsUShort()[i++]); -// printf("%d, ", g->indexDataAsUShort()[i++]); -// printf("%d, ", g->indexDataAsUShort()[i++]); -// printf("%d, ", g->indexDataAsUShort()[i++]); -// printf("%d, ", g->indexDataAsUShort()[i++]); -// printf("%d", g->indexDataAsUShort()[i++]); -// printf(" ]\n"); -// } - - setBoundingRect(boundingRect); + if (vp.isEmpty()) + return; + + void *data = 0; + if (oldVertexCount && oldIndexCount) { + int byteSize = oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D) + + oldIndexCount * sizeof(quint16); + data = qMalloc(byteSize); + memcpy(data, g->vertexData(), byteSize); + } + + g->allocate(oldVertexCount + vp.size(), oldIndexCount + ip.size()); + + if (data) { + memcpy(g->vertexData(), data, oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D)); + memcpy(g->indexData(), ((char *) data) + oldVertexCount * sizeof(QSGGeometry::TexturedPoint2D), + oldIndexCount * sizeof(quint16)); + qFree(data); + } + + memcpy(g->vertexDataAsTexturedPoint2D() + oldVertexCount, vp.constData(), vp.size() * sizeof(QSGGeometry::TexturedPoint2D)); + memcpy(g->indexDataAsUShort() + oldIndexCount, ip.constData(), ip.size() * sizeof(quint16)); + + setBoundingRect(m_boundingRect); markDirty(DirtyGeometry); m_dirtyGeometry = false; -} -void QSGDistanceFieldGlyphNode::updateFont() -{ - m_glyph_cache = m_glyph_cacheManager->cache(m_glyphs.rawFont()); - m_dirtyFont = false; + m_material->setTexture(textureToUse); } void QSGDistanceFieldGlyphNode::updateMaterial() diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp index a7dbb3b7f64a4e9b92785790e16b6ebde6a76b7e..a506e23cc1c37a43844d33104c451abeb618b970 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp +++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.cpp @@ -40,7 +40,7 @@ ****************************************************************************/ #include "qsgdistancefieldglyphnode_p_p.h" -#include "qsgdistancefieldglyphcache_p.h" +#include <private/qsgdistancefieldutil_p.h> #include <private/qsgtexture_p.h> #include <QtGui/qopenglfunctions.h> #include <qmath.h> @@ -138,9 +138,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q QSGDistanceFieldTextMaterial *material = static_cast<QSGDistanceFieldTextMaterial *>(newEffect); QSGDistanceFieldTextMaterial *oldMaterial = static_cast<QSGDistanceFieldTextMaterial *>(oldEffect); - bool updated = material->updateTexture(); - if (updated && !material->glyphCache()->useWorkaroundBrokenFBOReadback()) - activate(); + bool updated = material->updateCache(); if (oldMaterial == 0 || material->color() != oldMaterial->color() @@ -171,10 +169,10 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q if (updated || oldMaterial == 0 - || oldMaterial->glyphCache()->texture() != material->glyphCache()->texture()) { - program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->glyphCache()->textureSize().width(), - 1.0 / material->glyphCache()->textureSize().height())); - glBindTexture(GL_TEXTURE_2D, material->glyphCache()->texture()); + || oldMaterial->texture()->textureId != material->texture()->textureId) { + program()->setUniformValue(m_textureScale_id, QVector2D(1.0 / material->textureSize().width(), + 1.0 / material->textureSize().height())); + glBindTexture(GL_TEXTURE_2D, material->texture()->textureId); if (updated) { // Set the mag/min filters to be linear. We only need to do this when the texture @@ -189,6 +187,7 @@ void QSGDistanceFieldTextMaterialShader::updateState(const RenderState &state, Q QSGDistanceFieldTextMaterial::QSGDistanceFieldTextMaterial() : m_glyph_cache(0) + , m_texture(0) { setFlag(Blending, true); } @@ -208,10 +207,12 @@ QSGMaterialShader *QSGDistanceFieldTextMaterial::createShader() const return new QSGDistanceFieldTextMaterialShader; } -bool QSGDistanceFieldTextMaterial::updateTexture() +bool QSGDistanceFieldTextMaterial::updateCache() { - m_glyph_cache->updateCache(); - QSize glyphCacheSize = m_glyph_cache->textureSize(); + m_glyph_cache->update(); + if (!m_texture) + m_texture = m_glyph_cache->glyphTexture(-1); // invalid texture + QSize glyphCacheSize = m_texture->size; if (glyphCacheSize != m_size) { m_size = glyphCacheSize; @@ -433,7 +434,7 @@ void DistanceFieldShiftedStyleTextMaterialShader::updateState(const RenderState if (oldMaterial == 0 || oldMaterial->glyphCache()->fontScale() != material->glyphCache()->fontScale() || oldMaterial->shift() != material->shift() - || oldMaterial->glyphCache()->textureSize() != material->glyphCache()->textureSize()) { + || oldMaterial->textureSize() != material->textureSize()) { updateShift(material->glyphCache(), material->shift()); } } diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h index 1d8bcea86868dc9da71c672ef32a938ac1aaf363..f4877b0a1df77b6840afdf863d0dfd18936b3742 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h +++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p.h @@ -53,7 +53,6 @@ QT_BEGIN_NAMESPACE QT_MODULE(Declarative) -class QSGDistanceFieldGlyphCache; class QSGDistanceFieldGlyphCacheManager; class QSGDistanceFieldTextMaterial; class QSGDistanceFieldGlyphNode: public QSGGlyphNode @@ -73,9 +72,9 @@ public: virtual void update(); -private: void updateGeometry(); - void updateFont(); + +private: void updateMaterial(); QColor m_color; @@ -89,8 +88,14 @@ private: QQuickText::TextStyle m_style; QColor m_styleColor; AntialiasingMode m_antialiasingMode; + QRectF m_boundingRect; + + struct GlyphInfo { + quint32 glyphIndex; + QPointF position; + }; + QLinkedList<GlyphInfo> m_glyphsToAdd; - uint m_dirtyFont: 1; uint m_dirtyGeometry: 1; uint m_dirtyMaterial: 1; }; diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h index 8733edf203d97cae39e64d1c300e6ab282ccca14..c8c73bfac0725ce9e48a08e321f5a7a7c0201509 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h +++ b/src/declarative/scenegraph/qsgdistancefieldglyphnode_p_p.h @@ -44,11 +44,10 @@ #include <qsgmaterial.h> #include "qsgdistancefieldglyphnode_p.h" +#include "qsgadaptationlayer_p.h" QT_BEGIN_NAMESPACE -class QSGDistanceFieldGlyphCache; - class QSGDistanceFieldTextMaterial: public QSGMaterial { public: @@ -65,12 +64,18 @@ public: void setGlyphCache(QSGDistanceFieldGlyphCache *a) { m_glyph_cache = a; } QSGDistanceFieldGlyphCache *glyphCache() const { return m_glyph_cache; } - bool updateTexture(); + void setTexture(const QSGDistanceFieldGlyphCache::Texture * tex) { m_texture = tex; } + const QSGDistanceFieldGlyphCache::Texture * texture() const { return m_texture; } + + QSize textureSize() const { return m_size; } + + bool updateCache(); protected: QSize m_size; QColor m_color; QSGDistanceFieldGlyphCache *m_glyph_cache; + const QSGDistanceFieldGlyphCache::Texture *m_texture; }; class QSGDistanceFieldStyledTextMaterial : public QSGDistanceFieldTextMaterial diff --git a/src/declarative/scenegraph/scenegraph.pri b/src/declarative/scenegraph/scenegraph.pri index d4e0707ba3455bef71ba2dbf03d171ba7eff561d..0adc20502d0a1459b9d8e9b29cecb4c3aeeb8466 100644 --- a/src/declarative/scenegraph/scenegraph.pri +++ b/src/declarative/scenegraph/scenegraph.pri @@ -33,7 +33,8 @@ HEADERS += \ $$PWD/util/qsgtexture.h \ $$PWD/util/qsgtexture_p.h \ $$PWD/util/qsgtextureprovider_p.h \ - $$PWD/util/qsgpainternode_p.h + $$PWD/util/qsgpainternode_p.h \ + $$PWD/util/qsgdistancefieldutil_p.h SOURCES += \ $$PWD/util/qsgareaallocator.cpp \ @@ -45,7 +46,8 @@ SOURCES += \ $$PWD/util/qsgvertexcolormaterial.cpp \ $$PWD/util/qsgtexture.cpp \ $$PWD/util/qsgtextureprovider.cpp \ - $$PWD/util/qsgpainternode.cpp + $$PWD/util/qsgpainternode.cpp \ + $$PWD/util/qsgdistancefieldutil.cpp # QML / Adaptations API @@ -54,7 +56,7 @@ HEADERS += \ $$PWD/qsgcontext_p.h \ $$PWD/qsgcontextplugin_p.h \ $$PWD/qsgdefaultglyphnode_p.h \ - $$PWD/qsgdistancefieldglyphcache_p.h \ + $$PWD/qsgdefaultdistancefieldglyphcache_p.h \ $$PWD/qsgdistancefieldglyphnode_p.h \ $$PWD/qsgdistancefieldglyphnode_p_p.h \ $$PWD/qsgdefaultglyphnode_p_p.h \ @@ -69,10 +71,16 @@ SOURCES += \ $$PWD/qsgcontextplugin.cpp \ $$PWD/qsgdefaultglyphnode.cpp \ $$PWD/qsgdefaultglyphnode_p.cpp \ - $$PWD/qsgdistancefieldglyphcache.cpp \ + $$PWD/qsgdefaultdistancefieldglyphcache.cpp \ $$PWD/qsgdistancefieldglyphnode.cpp \ $$PWD/qsgdistancefieldglyphnode_p.cpp \ $$PWD/qsgdefaultimagenode.cpp \ $$PWD/qsgdefaultrectanglenode.cpp \ $$PWD/qsgflashnode.cpp \ $$PWD/qsgpathsimplifier.cpp + + + + + + diff --git a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp b/src/declarative/scenegraph/util/qsgdistancefieldutil.cpp similarity index 65% rename from src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp rename to src/declarative/scenegraph/util/qsgdistancefieldutil.cpp index 60e5bb77273ff33f684a3d0728f7a2deec6227e0..a74c96b8088e8a2050ff3752a56b57cac59cc31b 100644 --- a/src/declarative/scenegraph/qsgdistancefieldglyphcache.cpp +++ b/src/declarative/scenegraph/util/qsgdistancefieldutil.cpp @@ -39,53 +39,14 @@ ** ****************************************************************************/ -#include "qsgdistancefieldglyphcache_p.h" +#include "qsgdistancefieldutil_p.h" #include <qmath.h> #include <private/qsgpathsimplifier_p.h> -#include <private/qdeclarativeglobal_p.h> -#include <qopenglshaderprogram.h> +#include <private/qsgadaptationlayer_p.h> #include <QtGui/private/qopenglengineshadersource_p.h> #include <private/qsgcontext_p.h> -#include <private/qrawfont_p.h> -#include <qopenglfunctions.h> -#include <qglyphrun.h> -#include <qrawfont.h> -#include <qdir.h> -#include <QtGui/qguiapplication.h> - -QT_BEGIN_NAMESPACE - -#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54 -#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64 -#define QT_DISTANCEFIELD_DEFAULT_SCALE 16 -#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80 -#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000 - -#define QT_DISTANCEFIELD_BASEFONTSIZE \ - (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \ - QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE) -#define QT_DISTANCEFIELD_TILESIZE \ - (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \ - QT_DISTANCEFIELD_DEFAULT_TILESIZE) -#define QT_DISTANCEFIELD_SCALE \ - (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \ - QT_DISTANCEFIELD_DEFAULT_SCALE) -#define QT_DISTANCEFIELD_RADIUS \ - (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \ - QT_DISTANCEFIELD_DEFAULT_RADIUS) - -static inline int qt_next_power_of_two(int v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; - ++v; - return v; -} + static float defaultThresholdFunc(float glyphScale) { @@ -748,7 +709,7 @@ static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfSca return image; } -static bool fontHasNarrowOutlines(const QRawFont &f) +bool qt_fontHasNarrowOutlines(const QRawFont &f) { QRawFont font = f; font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE); @@ -798,65 +759,36 @@ static bool fontHasNarrowOutlines(const QRawFont &f) return minHThick == 1 || minVThick == 1; } -QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QOpenGLContext *c) - : ctx(c) +QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution) +{ + QRawFont renderFont = font; + renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(doubleResolution) * QT_DISTANCEFIELD_SCALE(doubleResolution)); + + QPainterPath path = renderFont.pathForGlyph(glyph); + path.translate(-path.boundingRect().topLeft()); + path.setFillRule(Qt::WindingFill); + + QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution), + path, + QT_DISTANCEFIELD_SCALE(doubleResolution), + QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution)); + return im; +} + +QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(QSGContext *c) + : sgCtx(c) , m_threshold_func(defaultThresholdFunc) , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc) - , m_maxTextureSize(0) { #ifndef QT_OPENGL_ES m_defaultAntialiasingMode = QSGGlyphNode::HighQualitySubPixelAntialiasing; #else m_defaultAntialiasingMode = QSGGlyphNode::GrayAntialiasing; #endif - - m_vertexCoordinateArray[0] = -1.0f; - m_vertexCoordinateArray[1] = -1.0f; - m_vertexCoordinateArray[2] = 1.0f; - m_vertexCoordinateArray[3] = -1.0f; - m_vertexCoordinateArray[4] = 1.0f; - m_vertexCoordinateArray[5] = 1.0f; - m_vertexCoordinateArray[6] = -1.0f; - m_vertexCoordinateArray[7] = 1.0f; - - m_textureCoordinateArray[0] = 0.0f; - m_textureCoordinateArray[1] = 0.0f; - m_textureCoordinateArray[2] = 1.0f; - m_textureCoordinateArray[3] = 0.0f; - m_textureCoordinateArray[4] = 1.0f; - m_textureCoordinateArray[5] = 1.0f; - m_textureCoordinateArray[6] = 0.0f; - m_textureCoordinateArray[7] = 1.0f; - - m_blitProgram = new QOpenGLShaderProgram; - { - QString source; - source.append(QLatin1String(qopenglslMainWithTexCoordsVertexShader)); - source.append(QLatin1String(qopenglslUntransformedPositionVertexShader)); - - QOpenGLShader *vertexShader = new QOpenGLShader(QOpenGLShader::Vertex, m_blitProgram); - vertexShader->compileSourceCode(source); - - m_blitProgram->addShader(vertexShader); - } - { - QString source; - source.append(QLatin1String(qopenglslMainFragmentShader)); - source.append(QLatin1String(qopenglslImageSrcFragmentShader)); - - QOpenGLShader *fragmentShader = new QOpenGLShader(QOpenGLShader::Fragment, m_blitProgram); - fragmentShader->compileSourceCode(source); - - m_blitProgram->addShader(fragmentShader); - } - m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR); - m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR); - m_blitProgram->link(); } QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager() { - delete m_blitProgram; qDeleteAll(m_caches.values()); } @@ -865,393 +797,6 @@ QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawF QRawFontPrivate *fontD = QRawFontPrivate::get(font); QHash<QFontEngine *, QSGDistanceFieldGlyphCache *>::iterator cache = m_caches.find(fontD->fontEngine); if (cache == m_caches.end()) - cache = m_caches.insert(fontD->fontEngine, new QSGDistanceFieldGlyphCache(this, ctx, font)); + cache = m_caches.insert(fontD->fontEngine, sgCtx->createDistanceFieldGlyphCache(font)); return cache.value(); } - -int QSGDistanceFieldGlyphCacheManager::maxTextureSize() const -{ - if (!m_maxTextureSize) - glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize); - return m_maxTextureSize; -} - - -QHash<QString, QOpenGLMultiGroupSharedResource> QSGDistanceFieldGlyphCache::m_textures_data; - -QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData() -{ - QString key = QString::fromLatin1("%1_%2_%3_%4") - .arg(m_font.familyName()) - .arg(m_font.styleName()) - .arg(m_font.weight()) - .arg(m_font.style()); - return m_textures_data[key].value<QSGDistanceFieldGlyphCache::DistanceFieldTextureData>(QOpenGLContext::currentContext()); -} - -QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, QOpenGLContext *c, const QRawFont &font) - : m_manager(man) - , ctx(c) -{ - Q_ASSERT(font.isValid()); - m_font = font; - - m_textureData = textureData(); - - QRawFontPrivate *fontD = QRawFontPrivate::get(m_font); - m_glyphCount = fontD->fontEngine->glyphCount(); - - m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT; - - m_referenceFont = m_font; - m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE); - Q_ASSERT(m_referenceFont.isValid()); -} - -QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache() -{ -} - -GLuint QSGDistanceFieldGlyphCache::texture() -{ - return m_textureData->texture; -} - -QSize QSGDistanceFieldGlyphCache::textureSize() const -{ - return m_textureData->size; -} - -QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph) -{ - QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph); - if (metric == m_metrics.end()) { - QPainterPath path = m_font.pathForGlyph(glyph); - QRectF br = path.boundingRect(); - - Metrics m; - m.width = br.width(); - m.height = br.height(); - m.baselineX = br.x(); - m.baselineY = -br.y(); - - metric = m_metrics.insert(glyph, m); - } - - return metric.value(); -} - -QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph) -{ - return m_textureData->texCoords.value(glyph); -} - -QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const -{ - QRawFont renderFont = m_font; - renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE); - - QPainterPath path = renderFont.pathForGlyph(glyph); - path.translate(-path.boundingRect().topLeft()); - path.setFillRule(Qt::WindingFill); - - QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE, - path, - QT_DISTANCEFIELD_SCALE, - QT_DISTANCEFIELD_RADIUS / QT_DISTANCEFIELD_SCALE); - return im; -} - -qreal QSGDistanceFieldGlyphCache::fontScale() const -{ - return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE; -} - -int QSGDistanceFieldGlyphCache::distanceFieldRadius() const -{ - return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE; -} - -void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs) -{ - // Avoid useless and costly glyph re-generation - if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) { - for (int i = 0; i < count; ++i) { - glyph_t glyphIndex = glyphs[i]; - if (m_textureData->texCoords.contains(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex)) - m_textureData->unusedGlyphs.remove(glyphIndex); - } - } - - for (int i = 0; i < count; ++i) { - glyph_t glyphIndex = glyphs[i]; - if ((int) glyphIndex >= glyphCount()) { - qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex); - continue; - } - - if (++m_textureData->glyphRefCount[glyphIndex] == 1) - m_textureData->unusedGlyphs.remove(glyphIndex); - - if (m_textureData->texCoords.contains(glyphIndex) - || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty())) - continue; - - QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex); - if (path.isEmpty()) { - m_textureData->texCoords.insert(glyphIndex, TexCoord()); - continue; - } - QRectF br = path.boundingRect(); - - TexCoord c; - c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE); - c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE); - c.x = m_textureData->currX; - c.y = m_textureData->currY; - c.width = br.width(); - c.height = br.height(); - - if (!cacheIsFull()) { - m_textureData->currX += QT_DISTANCEFIELD_TILESIZE; - if (m_textureData->currX >= m_manager->maxTextureSize()) { - m_textureData->currX = 0; - m_textureData->currY += QT_DISTANCEFIELD_TILESIZE; - } - } else { - // Recycle glyphs - if (!m_textureData->unusedGlyphs.isEmpty()) { - glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin(); - TexCoord unusedCoord = glyphTexCoord(unusedGlyph); - c.x = unusedCoord.x; - c.y = unusedCoord.y; - m_textureData->unusedGlyphs.remove(unusedGlyph); - m_textureData->texCoords.remove(unusedGlyph); - } - } - - if (c.y < m_manager->maxTextureSize()) { - m_textureData->texCoords.insert(glyphIndex, c); - m_textureData->pendingGlyphs.add(glyphIndex); - } - } -} - -void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs) -{ - for (int i = 0; i < count; ++i) - if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull()) - m_textureData->unusedGlyphs.insert(glyphs[i]); -} - -void QSGDistanceFieldGlyphCache::createTexture(int width, int height) -{ - if (ctx->d_func()->workaround_brokenFBOReadBack && m_textureData->image.isNull()) - m_textureData->image = QImage(width, height, QImage::Format_Indexed8); - - while (glGetError() != GL_NO_ERROR) { } - - glGenTextures(1, &m_textureData->texture); - glBindTexture(GL_TEXTURE_2D, m_textureData->texture); - - glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, 0); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - m_textureData->size = QSize(width, height); - - GLuint error = glGetError(); - if (error != GL_NO_ERROR) { - glBindTexture(GL_TEXTURE_2D, 0); - glDeleteTextures(1, &m_textureData->texture); - m_textureData->texture = 0; - } - -} - -void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height) -{ - int oldWidth = m_textureData->size.width(); - int oldHeight = m_textureData->size.height(); - if (width == oldWidth && height == oldHeight) - return; - - GLuint oldTexture = m_textureData->texture; - createTexture(width, height); - - if (!oldTexture) - return; - - if (ctx->d_func()->workaround_brokenFBOReadBack) { - m_textureData->image = m_textureData->image.copy(0, 0, width, height); - QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits()); - glDeleteTextures(1, &oldTexture); - return; - } - - if (!m_textureData->fbo) - ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo); - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, m_textureData->fbo); - - GLuint tmp_texture; - glGenTextures(1, &tmp_texture); - glBindTexture(GL_TEXTURE_2D, tmp_texture); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glBindTexture(GL_TEXTURE_2D, 0); - ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tmp_texture, 0); - - ctx->functions()->glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, oldTexture); - - // save current render states - GLboolean stencilTestEnabled; - GLboolean depthTestEnabled; - GLboolean scissorTestEnabled; - GLboolean blendEnabled; - GLint viewport[4]; - glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled); - glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled); - glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled); - glGetBooleanv(GL_BLEND, &blendEnabled); - glGetIntegerv(GL_VIEWPORT, &viewport[0]); - - glDisable(GL_STENCIL_TEST); - glDisable(GL_DEPTH_TEST); - glDisable(GL_SCISSOR_TEST); - glDisable(GL_BLEND); - - glViewport(0, 0, oldWidth, oldHeight); - - ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitVertexArray()); - ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitTextureArray()); - - m_manager->blitProgram()->bind(); - m_manager->blitProgram()->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR)); - m_manager->blitProgram()->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR)); - m_manager->blitProgram()->disableAttributeArray(int(QT_OPACITY_ATTR)); - m_manager->blitProgram()->setUniformValue("imageTexture", GLuint(0)); - - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - - glBindTexture(GL_TEXTURE_2D, m_textureData->texture); - - glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight); - - ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, 0); - glDeleteTextures(1, &tmp_texture); - glDeleteTextures(1, &oldTexture); - - ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER, 0); - - // restore render states - if (stencilTestEnabled) - glEnable(GL_STENCIL_TEST); - if (depthTestEnabled) - glEnable(GL_DEPTH_TEST); - if (scissorTestEnabled) - glEnable(GL_SCISSOR_TEST); - if (blendEnabled) - glEnable(GL_BLEND); - glViewport(viewport[0], viewport[1], viewport[2], viewport[3]); -} - -void QSGDistanceFieldGlyphCache::updateCache() -{ - if (m_textureData->pendingGlyphs.isEmpty()) - return; - - int requiredWidth = m_manager->maxTextureSize(); - int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE); // Enough rows to fill the latin1 set by default.. - int requiredHeight = qMin(m_manager->maxTextureSize(), qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE, QT_DISTANCEFIELD_TILESIZE * rows)); - - resizeTexture((requiredWidth), (requiredHeight)); - glBindTexture(GL_TEXTURE_2D, m_textureData->texture); - - // ### Remove before final release - static bool cacheDistanceFields = QGuiApplication::arguments().contains(QLatin1String("--cache-distance-fields")); - -// #define QSGDISTANCEFIELDS_TIME_CREATION -#ifdef QSGDISTANCEFIELDS_TIME_CREATION - QTime time; - time.start(); -#endif - - QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath()); - QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob") - .arg(tmpPath) - .arg(m_font.familyName()) - .arg(m_font.styleName()) - .arg(m_font.weight()) - .arg(m_font.style()); - - if (cacheDistanceFields && !QFile::exists(tmpPath)) - QDir(tmpPath).mkpath(tmpPath); - - for (int i = 0; i < m_textureData->pendingGlyphs.size(); ++i) { - glyph_t glyphIndex = m_textureData->pendingGlyphs.at(i); - TexCoord c = m_textureData->texCoords.value(glyphIndex); - - if (cacheDistanceFields) { - QString key = keyBase.arg(glyphIndex); - QFile file(key); - if (file.open(QFile::ReadOnly)) { - int fileSize = file.size(); - int dim = sqrt(float(fileSize)); - QByteArray blob = file.readAll(); - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, dim, dim, GL_ALPHA, GL_UNSIGNED_BYTE, blob.constData()); - continue; - } - } - - QImage glyph = renderDistanceFieldGlyph(glyphIndex); - - if (ctx->d_func()->workaround_brokenFBOReadBack) { - uchar *inBits = glyph.scanLine(0); - uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x); - for (int y = 0; y < glyph.height(); ++y) { - qMemCopy(outBits, inBits, glyph.width()); - inBits += glyph.bytesPerLine(); - outBits += m_textureData->image.bytesPerLine(); - } - } - - glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits()); - - if (cacheDistanceFields) { - QString key = keyBase.arg(glyphIndex); - QFile file(key); - file.open(QFile::WriteOnly); - file.write((const char *) glyph.constBits(), glyph.width() * glyph.height()); - } - } - -#ifdef QSGDISTANCEFIELDS_TIME_CREATION - static int totalTime; - totalTime += time.elapsed(); - printf("time: %d\n", totalTime); -#endif - - m_textureData->pendingGlyphs.reset(); -} - -bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const -{ - return ctx->d_func()->workaround_brokenFBOReadBack; -} - -int QSGDistanceFieldGlyphCache::glyphCount() const -{ - return m_glyphCount; -} - -QT_END_NAMESPACE diff --git a/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h b/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h new file mode 100644 index 0000000000000000000000000000000000000000..93dffab76eb78e0de08bbd048564cf8e6587b9dc --- /dev/null +++ b/src/declarative/scenegraph/util/qsgdistancefieldutil_p.h @@ -0,0 +1,111 @@ +/**************************************************************************** +** +** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). +** All rights reserved. +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** This file is part of the QtDeclarative module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** This file may be used under the terms of the GNU Lesser General Public +** License version 2.1 as published by the Free Software Foundation and +** appearing in the file LICENSE.LGPL included in the packaging of this +** file. Please review the following information to ensure the GNU Lesser +** General Public License version 2.1 requirements will be met: +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Nokia gives you certain additional +** rights. These rights are described in the Nokia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU General +** Public License version 3.0 as published by the Free Software Foundation +** and appearing in the file LICENSE.GPL included in the packaging of this +** file. Please review the following information to ensure the GNU General +** Public License version 3.0 requirements will be met: +** http://www.gnu.org/copyleft/gpl.html. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QSGDISTANCEFIELDUTIL_H +#define QSGDISTANCEFIELDUTIL_H + +#include <qrawfont.h> +#include <private/qfontengine_p.h> +#include <private/qsgadaptationlayer_p.h> + +QT_BEGIN_NAMESPACE + +#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54 +#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64 +#define QT_DISTANCEFIELD_DEFAULT_SCALE 16 +#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80 +#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000 + +#define QT_DISTANCEFIELD_BASEFONTSIZE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \ + QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE) +#define QT_DISTANCEFIELD_TILESIZE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \ + QT_DISTANCEFIELD_DEFAULT_TILESIZE) +#define QT_DISTANCEFIELD_SCALE(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \ + QT_DISTANCEFIELD_DEFAULT_SCALE) +#define QT_DISTANCEFIELD_RADIUS(NarrowOutlineFont) \ + (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \ + QT_DISTANCEFIELD_DEFAULT_RADIUS) + + +typedef float (*ThresholdFunc)(float glyphScale); +typedef float (*AntialiasingSpreadFunc)(float glyphScale); + +bool qt_fontHasNarrowOutlines(const QRawFont &f); +QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution); + + +class QOpenGLShaderProgram; +class QSGDistanceFieldGlyphCache; +class QSGContext; + +class Q_DECLARATIVE_EXPORT QSGDistanceFieldGlyphCacheManager +{ +public: + QSGDistanceFieldGlyphCacheManager(QSGContext *c); + ~QSGDistanceFieldGlyphCacheManager(); + + QSGDistanceFieldGlyphCache *cache(const QRawFont &font); + + QSGGlyphNode::AntialiasingMode defaultAntialiasingMode() const { return m_defaultAntialiasingMode; } + void setDefaultAntialiasingMode(QSGGlyphNode::AntialiasingMode mode) { m_defaultAntialiasingMode = mode; } + + ThresholdFunc thresholdFunc() const { return m_threshold_func; } + void setThresholdFunc(ThresholdFunc func) { m_threshold_func = func; } + + AntialiasingSpreadFunc antialiasingSpreadFunc() const { return m_antialiasingSpread_func; } + void setAntialiasingSpreadFunc(AntialiasingSpreadFunc func) { m_antialiasingSpread_func = func; } + +private: + QHash<QFontEngine *, QSGDistanceFieldGlyphCache *> m_caches; + + QSGContext *sgCtx; + + QSGGlyphNode::AntialiasingMode m_defaultAntialiasingMode; + ThresholdFunc m_threshold_func; + AntialiasingSpreadFunc m_antialiasingSpread_func; +}; + +QT_END_NAMESPACE + +#endif // QSGDISTANCEFIELDUTIL_H diff --git a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp index 8ac3a078bc9ff34a45e5d7fba044d9c442209246..a8852fbc9f9a223564e2d1ed63a4b36532ae3a81 100644 --- a/tests/auto/declarative/qquicktext/tst_qquicktext.cpp +++ b/tests/auto/declarative/qquicktext/tst_qquicktext.cpp @@ -45,7 +45,6 @@ #include <private/qquicktext_p.h> #include <private/qquicktext_p_p.h> #include <private/qdeclarativevaluetype_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <QFontMetrics> #include <QGraphicsSceneMouseEvent> #include <qmath.h> diff --git a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp index 693619f638b80ce429304f6dad087b133da84af6..116d6307febc067438f8b0956950bb69b02a2fda 100644 --- a/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp +++ b/tests/auto/declarative/qquicktextedit/tst_qquicktextedit.cpp @@ -51,7 +51,6 @@ #include <QtGui/qguiapplication.h> #include <private/qquicktextedit_p.h> #include <private/qquicktextedit_p_p.h> -#include <private/qsgdistancefieldglyphcache_p.h> #include <QFontMetrics> #include <QQuickView> #include <QDir> diff --git a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp index bf29f88ff1d2a4ad2da9c03ca056ad3c243cd314..210099c2a46eb0df3304cdd0a0d9bcf1f65e7836 100644 --- a/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp +++ b/tests/auto/declarative/qquicktextinput/tst_qquicktextinput.cpp @@ -52,7 +52,6 @@ #include <QDir> #include <QStyle> #include <QInputContext> -#include <private/qsgdistancefieldglyphcache_p.h> #include <QtOpenGL/QGLShaderProgram> #include <math.h>