QtQuick: Fix string related warnings, single character strings.
[profile/ivi/qtdeclarative.git] / src / quick / scenegraph / qsgshareddistancefieldglyphcache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the QtQml module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #define EGL_EGLEXT_PROTOTYPES
43 #define GL_GLEXT_PROTOTYPES
44 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
45 #include <GLES2/gl2.h>
46 #include <GLES2/gl2ext.h>
47 #endif
48
49 #include "qsgshareddistancefieldglyphcache_p.h"
50
51 #include <QtCore/qhash.h>
52 #include <QtCore/qthread.h>
53 #include <qpa/qplatformsharedgraphicscache.h>
54
55 #include <QtQuick/qquickcanvas.h>
56
57 // #define QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG
58
59 Q_DECLARE_METATYPE(QVector<quint32>)
60 Q_DECLARE_METATYPE(QVector<QImage>)
61
62 QT_BEGIN_NAMESPACE
63
64 QSGSharedDistanceFieldGlyphCache::QSGSharedDistanceFieldGlyphCache(const QByteArray &cacheId,
65                                                                    QPlatformSharedGraphicsCache *sharedGraphicsCache,
66                                                                    QSGDistanceFieldGlyphCacheManager *man,
67                                                                    QOpenGLContext *c,
68                                                                    const QRawFont &font)
69     : QSGDistanceFieldGlyphCache(man, c, font)
70     , m_cacheId(cacheId)
71     , m_sharedGraphicsCache(sharedGraphicsCache)
72 {
73 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
74     qDebug("QSGSharedDistanceFieldGlyphCache with id %s created in thread %p",
75            cacheId.constData(), QThread::currentThreadId());
76 #endif
77
78     Q_ASSERT(sizeof(glyph_t) == sizeof(quint32));
79     Q_ASSERT(sharedGraphicsCache != 0);
80
81     qRegisterMetaType<QVector<quint32> >();
82     qRegisterMetaType<QVector<QImage> >();
83
84     connect(sharedGraphicsCache, SIGNAL(itemsMissing(QByteArray,QVector<quint32>)),
85             this, SLOT(reportItemsMissing(QByteArray,QVector<quint32>)),
86             Qt::DirectConnection);
87     connect(sharedGraphicsCache, SIGNAL(itemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
88             this, SLOT(reportItemsAvailable(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
89             Qt::DirectConnection);
90     connect(sharedGraphicsCache, SIGNAL(itemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
91             this, SLOT(reportItemsUpdated(QByteArray,void*,QVector<quint32>,QVector<QPoint>)),
92             Qt::DirectConnection);
93     connect(sharedGraphicsCache, SIGNAL(itemsInvalidated(QByteArray,QVector<quint32>)),
94             this, SLOT(reportItemsInvalidated(QByteArray,QVector<quint32>)),
95             Qt::DirectConnection);
96 }
97
98 QSGSharedDistanceFieldGlyphCache::~QSGSharedDistanceFieldGlyphCache()
99 {
100     {
101         QHash<glyph_t, void *>::const_iterator it = m_bufferForGlyph.constBegin();
102         while (it != m_bufferForGlyph.constEnd()) {
103             m_sharedGraphicsCache->dereferenceBuffer(it.value());
104             ++it;
105         }
106     }
107
108     {
109         QHash<quint32, PendingGlyph>::const_iterator it = m_pendingReadyGlyphs.constBegin();
110         while (it != m_pendingReadyGlyphs.constEnd()) {
111             m_sharedGraphicsCache->dereferenceBuffer(it.value().buffer);
112             ++it;
113         }
114     }
115 }
116
117 void QSGSharedDistanceFieldGlyphCache::requestGlyphs(const QSet<glyph_t> &glyphs)
118 {
119     QMutexLocker locker(&m_pendingGlyphsMutex);
120
121 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
122     qDebug("QSGSharedDistanceFieldGlyphCache::requestGlyphs() called for %s (%d glyphs)",
123            m_cacheId.constData(), glyphs.size());
124 #endif
125
126     m_requestedGlyphsThatHaveNotBeenReturned.unite(glyphs);
127     m_requestedGlyphs.unite(glyphs);
128
129     QVector<quint32> glyphsVector;
130     glyphsVector.reserve(glyphs.size());
131
132     QSet<glyph_t>::const_iterator it;
133     for (it = glyphs.constBegin(); it != glyphs.constEnd(); ++it) {
134         Q_ASSERT(!m_bufferForGlyph.contains(*it));
135         glyphsVector.append(*it);
136     }
137
138     // Invoke method on queued connection to make sure it's called asynchronously on the
139     // correct thread (requestGlyphs() is called from the rendering thread.)
140     QMetaObject::invokeMethod(m_sharedGraphicsCache, "requestItems", Qt::QueuedConnection,
141                               Q_ARG(QByteArray, m_cacheId),
142                               Q_ARG(QVector<quint32>, glyphsVector));
143 }
144
145 void QSGSharedDistanceFieldGlyphCache::waitForGlyphs()
146 {
147     {
148         QMutexLocker locker(&m_pendingGlyphsMutex);
149         while (!m_requestedGlyphsThatHaveNotBeenReturned.isEmpty())
150             m_pendingGlyphsCondition.wait(&m_pendingGlyphsMutex);
151     }
152 }
153
154 void QSGSharedDistanceFieldGlyphCache::storeGlyphs(const QHash<glyph_t, QImage> &glyphs)
155 {
156     {
157         QMutexLocker locker(&m_pendingGlyphsMutex);
158 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
159         qDebug("QSGSharedDistanceFieldGlyphCache::storeGlyphs() called for %s (%d glyphs)",
160                m_cacheId.constData(), glyphs.size());
161 #endif
162
163         int glyphCount = glyphs.size();
164         QVector<quint32> glyphIds(glyphCount);
165         QVector<QImage> images(glyphCount);
166         QHash<glyph_t, QImage>::const_iterator it = glyphs.constBegin();
167         int i=0;
168         while (it != glyphs.constEnd()) {
169             m_requestedGlyphsThatHaveNotBeenReturned.insert(it.key());
170             glyphIds[i] = it.key();
171             images[i] = it.value();
172
173             ++it; ++i;
174         }
175
176         QMetaObject::invokeMethod(m_sharedGraphicsCache, "insertItems", Qt::QueuedConnection,
177                                   Q_ARG(QByteArray, m_cacheId),
178                                   Q_ARG(QVector<quint32>, glyphIds),
179                                   Q_ARG(QVector<QImage>, images));
180     }
181
182     processPendingGlyphs();
183 }
184
185 void QSGSharedDistanceFieldGlyphCache::referenceGlyphs(const QSet<glyph_t> &glyphs)
186 {
187     Q_UNUSED(glyphs);
188
189     // Intentionally empty. Not required in this implementation, since the glyphs are reference
190     // counted outside and releaseGlyphs() will only be called when there are no more references.
191 }
192
193 void QSGSharedDistanceFieldGlyphCache::releaseGlyphs(const QSet<glyph_t> &glyphs)
194 {
195 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
196     qDebug("QSGSharedDistanceFieldGlyphCache::releaseGlyphs() called for %s (%d glyphs)",
197            m_cacheId.constData(), glyphs.size());
198 #endif
199
200     m_requestedGlyphs.subtract(glyphs);
201
202     QVector<quint32> glyphsVector;
203     glyphsVector.reserve(glyphs.size());
204
205     QSet<glyph_t>::const_iterator glyphsIt;
206     for (glyphsIt = glyphs.constBegin(); glyphsIt != glyphs.constEnd(); ++glyphsIt) {
207         QHash<glyph_t, void *>::iterator bufferIt = m_bufferForGlyph.find(*glyphsIt);
208         if (bufferIt != m_bufferForGlyph.end()) {
209             void *buffer = bufferIt.value();
210             removeGlyph(*glyphsIt);
211             m_bufferForGlyph.erase(bufferIt);
212             Q_ASSERT(!m_bufferForGlyph.contains(*glyphsIt));
213
214             if (!m_sharedGraphicsCache->dereferenceBuffer(buffer)) {
215 #if !defined(QT_NO_DEBUG)
216                 bufferIt = m_bufferForGlyph.begin();
217                 while (bufferIt != m_bufferForGlyph.end()) {
218                     Q_ASSERT(bufferIt.value() != buffer);
219                     ++bufferIt;
220                 }
221 #endif
222             }
223         }
224
225         glyphsVector.append(*glyphsIt);
226     }
227
228     QMetaObject::invokeMethod(m_sharedGraphicsCache, "releaseItems", Qt::QueuedConnection,
229                               Q_ARG(QByteArray, m_cacheId),
230                               Q_ARG(QVector<quint32>, glyphsVector));
231 }
232
233 void QSGSharedDistanceFieldGlyphCache::registerOwnerElement(QQuickItem *ownerElement)
234 {
235     Owner &owner = m_registeredOwners[ownerElement];
236     if (owner.ref == 0) {
237         owner.item = ownerElement;
238
239         bool ok = connect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
240         Q_ASSERT_X(ok, Q_FUNC_INFO, "QML element that owns a glyph node must have triggerPreprocess() slot");
241         Q_UNUSED(ok);
242     }
243     ++owner.ref;
244 }
245
246 void QSGSharedDistanceFieldGlyphCache::unregisterOwnerElement(QQuickItem *ownerElement)
247 {
248     QHash<QQuickItem *, Owner>::iterator it = m_registeredOwners.find(ownerElement);
249     if (it != m_registeredOwners.end() && --it->ref <= 0) {
250         if (it->item)
251             disconnect(this, SIGNAL(glyphsPending()), ownerElement, SLOT(triggerPreprocess()));
252         m_registeredOwners.erase(it);
253     }
254 }
255
256 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_)
257 #  include <QtOpenGL/private/qglextensions_p.h>
258
259 void QSGSharedDistanceFieldGlyphCache::saveTexture(GLuint textureId, int width, int height)
260 {
261     GLuint fboId;
262     glGenFramebuffers(1, &fboId);
263
264     GLuint tmpTexture = 0;
265     glGenTextures(1, &tmpTexture);
266     glBindTexture(GL_TEXTURE_2D, tmpTexture);
267     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
268     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
269     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
270     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
271     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
272     glBindTexture(GL_TEXTURE_2D, 0);
273
274     glBindFramebuffer(GL_FRAMEBUFFER_EXT, fboId);
275     glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D,
276                            tmpTexture, 0);
277
278     glActiveTexture(GL_TEXTURE0);
279     glBindTexture(GL_TEXTURE_2D, textureId);
280
281     glDisable(GL_STENCIL_TEST);
282     glDisable(GL_DEPTH_TEST);
283     glDisable(GL_SCISSOR_TEST);
284     glDisable(GL_BLEND);
285
286     GLfloat textureCoordinateArray[8];
287     textureCoordinateArray[0] = 0.0f;
288     textureCoordinateArray[1] = 0.0f;
289     textureCoordinateArray[2] = 1.0f;
290     textureCoordinateArray[3] = 0.0f;
291     textureCoordinateArray[4] = 1.0f;
292     textureCoordinateArray[5] = 1.0f;
293     textureCoordinateArray[6] = 0.0f;
294     textureCoordinateArray[7] = 1.0f;
295
296     GLfloat vertexCoordinateArray[8];
297     vertexCoordinateArray[0] = -1.0f;
298     vertexCoordinateArray[1] = -1.0f;
299     vertexCoordinateArray[2] =  1.0f;
300     vertexCoordinateArray[3] = -1.0f;
301     vertexCoordinateArray[4] =  1.0f;
302     vertexCoordinateArray[5] =  1.0f;
303     vertexCoordinateArray[6] = -1.0f;
304     vertexCoordinateArray[7] =  1.0f;
305
306     glViewport(0, 0, width, height);
307     glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, vertexCoordinateArray);
308     glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinateArray);
309
310     {
311         static const char *vertexShaderSource =
312                 "attribute highp   vec4      vertexCoordsArray; \n"
313                 "attribute highp   vec2      textureCoordArray; \n"
314                 "varying   highp   vec2      textureCoords;     \n"
315                 "void main(void) \n"
316                 "{ \n"
317                 "    gl_Position = vertexCoordsArray;   \n"
318                 "    textureCoords = textureCoordArray; \n"
319                 "} \n";
320
321         static const char *fragmentShaderSource =
322                 "varying   highp   vec2      textureCoords; \n"
323                 "uniform   sampler2D         texture;       \n"
324                 "void main() \n"
325                 "{ \n"
326                 "    gl_FragColor = texture2D(texture, textureCoords); \n"
327                 "} \n";
328
329         GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
330         GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
331
332         if (vertexShader == 0 || fragmentShader == 0) {
333             GLenum error = glGetError();
334             qWarning("SharedGraphicsCacheServer::setupShaderPrograms: Failed to create shaders. (GL error: %x)",
335                      error);
336             return;
337         }
338
339         glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
340         glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
341         glCompileShader(vertexShader);
342
343         GLint len = 1;
344         glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &len);
345
346         char infoLog[2048];
347         glGetShaderInfoLog(vertexShader, 2048, NULL, infoLog);
348         if (qstrlen(infoLog) > 0) {
349             qWarning("SharedGraphicsCacheServer::setupShaderPrograms, problems compiling vertex shader:\n %s",
350                      infoLog);
351             //return;
352         }
353
354         glCompileShader(fragmentShader);
355         glGetShaderInfoLog(fragmentShader, 2048, NULL, infoLog);
356         if (qstrlen(infoLog) > 0) {
357             qWarning("SharedGraphicsCacheServer::setupShaderPrograms, problems compiling fragent shader:\n %s",
358                      infoLog);
359             //return;
360         }
361
362         GLuint shaderProgram = glCreateProgram();
363         glAttachShader(shaderProgram, vertexShader);
364         glAttachShader(shaderProgram, fragmentShader);
365
366         glBindAttribLocation(shaderProgram, 0, "vertexCoordsArray");
367         glBindAttribLocation(shaderProgram, 1, "textureCoordArray");
368
369         glLinkProgram(shaderProgram);
370         glGetProgramInfoLog(shaderProgram, 2048, NULL, infoLog);
371         if (qstrlen(infoLog) > 0) {
372             qWarning("SharedGraphicsCacheServer::setupShaderPrograms, problems linking shaders:\n %s",
373                      infoLog);
374             //return;
375         }
376
377         glUseProgram(shaderProgram);
378         glEnableVertexAttribArray(0);
379         glEnableVertexAttribArray(1);
380
381         int textureUniformLocation = glGetUniformLocation(shaderProgram, "texture");
382         glUniform1i(textureUniformLocation, 0);
383     }
384
385     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
386
387     {
388         GLenum error = glGetError();
389         if (error != GL_NO_ERROR) {
390             qWarning("SharedGraphicsCacheServer::readBackBuffer: glDrawArrays reported error 0x%x",
391                      error);
392         }
393     }
394
395     uchar *data = new uchar[width * height * 4];
396
397     glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data);
398
399     QImage image(width, height, QImage::Format_ARGB32);
400     quint32 *dest = reinterpret_cast<quint32 *>(image.bits());
401     for (int i=0; i<width*height; ++i)
402         dest[i] = qRgba(0xff, 0xff, 0xff, data[i]);
403
404     QByteArray fileName = m_cacheId + ' ' + QByteArray::number(textureId);
405     fileName = fileName.replace('/', '_').replace(' ', '_') + ".png";
406     image.save(QString::fromLocal8Bit(fileName));
407
408     {
409         GLenum error = glGetError();
410         if (error != GL_NO_ERROR) {
411             qWarning("SharedGraphicsCacheServer::readBackBuffer: glReadPixels reported error 0x%x",
412                      error);
413         }
414     }
415
416     glDisableVertexAttribArray(0);
417     glDisableVertexAttribArray(1);
418
419     glDeleteFramebuffers(1, &fboId);
420     glDeleteTextures(1, &tmpTexture);
421
422     delete[] data;
423 }
424 #endif
425
426 namespace {
427     struct TextureContent {
428         QSize size;
429         QVector<glyph_t> glyphs;
430     };
431 }
432
433 void QSGSharedDistanceFieldGlyphCache::processPendingGlyphs()
434 {
435     Q_ASSERT(QThread::currentThread() == thread());
436
437     waitForGlyphs();
438
439     {
440         QMutexLocker locker(&m_pendingGlyphsMutex);
441         if (m_pendingMissingGlyphs.isEmpty()
442             && m_pendingReadyGlyphs.isEmpty()
443             && m_pendingInvalidatedGlyphs.isEmpty()) {
444             return;
445         }
446
447         {
448             QVector<glyph_t> pendingMissingGlyphs;
449             pendingMissingGlyphs.reserve(m_pendingMissingGlyphs.size());
450
451             QSet<glyph_t>::const_iterator it = m_pendingMissingGlyphs.constBegin();
452             while (it != m_pendingMissingGlyphs.constEnd()) {
453                 pendingMissingGlyphs.append(*it);
454                 ++it;
455             }
456
457             markGlyphsToRender(pendingMissingGlyphs);
458         }
459
460         {
461             QVector<glyph_t> filteredPendingInvalidatedGlyphs;
462             filteredPendingInvalidatedGlyphs.reserve(m_pendingInvalidatedGlyphs.size());
463
464             QSet<glyph_t>::const_iterator it = m_pendingInvalidatedGlyphs.constBegin();
465             while (it != m_pendingInvalidatedGlyphs.constEnd()) {
466                 bool rerequestGlyph = false;
467
468                 // The glyph was invalidated right after being posted as ready, we throw away
469                 // the ready glyph and rerequest it to be certain
470                 QHash<quint32, PendingGlyph>::iterator pendingGlyphIt = m_pendingReadyGlyphs.find(*it);
471                 if (pendingGlyphIt != m_pendingReadyGlyphs.end()) {
472                     m_sharedGraphicsCache->dereferenceBuffer(pendingGlyphIt.value().buffer);
473                     pendingGlyphIt = m_pendingReadyGlyphs.erase(pendingGlyphIt);
474                     rerequestGlyph = true;
475                 }
476
477                 void *bufferId = m_bufferForGlyph.value(*it, 0);
478                 if (bufferId != 0) {
479                     m_sharedGraphicsCache->dereferenceBuffer(bufferId);
480                     m_bufferForGlyph.remove(*it);
481                     rerequestGlyph = true;
482                 }
483
484                 if (rerequestGlyph)
485                     filteredPendingInvalidatedGlyphs.append(*it);
486
487                 ++it;
488             }
489
490             // If this cache is still using the glyphs, reset the texture held by them, and mark them
491             // to be rendered again since they are still needed.
492             if (!filteredPendingInvalidatedGlyphs.isEmpty()) {
493                 setGlyphsTexture(filteredPendingInvalidatedGlyphs, Texture());
494                 markGlyphsToRender(filteredPendingInvalidatedGlyphs);
495             }
496         }
497
498         {
499             QList<GlyphPosition> glyphPositions;
500
501             QHash<void *, TextureContent> textureContentForBuffer;
502             {
503                 QHash<quint32, PendingGlyph>::iterator it = m_pendingReadyGlyphs.begin();
504                 while (it != m_pendingReadyGlyphs.end()) {
505                     void *currentGlyphBuffer = m_bufferForGlyph.value(it.key(), 0);
506                     if (currentGlyphBuffer != 0) {
507                         if (!m_sharedGraphicsCache->dereferenceBuffer(currentGlyphBuffer)) {
508                             Q_ASSERT(!textureContentForBuffer.contains(currentGlyphBuffer));
509                         }
510                     }
511
512                     PendingGlyph &pendingGlyph  = it.value();
513
514                     // We don't ref or deref the buffer here, since it was already referenced when
515                     // added to the pending ready glyphs
516                     m_bufferForGlyph[it.key()] = pendingGlyph.buffer;
517
518                     textureContentForBuffer[pendingGlyph.buffer].size = pendingGlyph.bufferSize;
519                     textureContentForBuffer[pendingGlyph.buffer].glyphs.append(it.key());
520
521                     GlyphPosition glyphPosition;
522                     glyphPosition.glyph = it.key();
523                     glyphPosition.position = pendingGlyph.position;
524
525                     glyphPositions.append(glyphPosition);
526
527                     ++it;
528                 }
529             }
530
531             setGlyphsPosition(glyphPositions);
532
533             {
534                 QHash<void *, TextureContent>::const_iterator it = textureContentForBuffer.constBegin();
535                 while (it != textureContentForBuffer.constEnd()) {
536                     Texture texture;
537                     texture.textureId = m_sharedGraphicsCache->textureIdForBuffer(it.key());
538                     texture.size = m_sharedGraphicsCache->sizeOfBuffer(it.key());
539
540 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG_)
541                     saveTexture(texture.textureId, texture.size.width(), texture.size.height());
542 #endif
543                     setGlyphsTexture(it.value().glyphs, texture);
544
545                     ++it;
546                 }
547             }
548         }
549
550         m_pendingMissingGlyphs.clear();
551         m_pendingInvalidatedGlyphs.clear();
552         m_pendingReadyGlyphs.clear();
553     }
554 }
555
556 void QSGSharedDistanceFieldGlyphCache::reportItemsAvailable(const QByteArray &cacheId,
557                                                             void *bufferId,
558                                                             const QVector<quint32> &itemIds,
559                                                             const QVector<QPoint> &positions)
560 {
561     bool requestedItemsInList = false;
562     {
563         QMutexLocker locker(&m_pendingGlyphsMutex);
564         if (m_cacheId != cacheId)
565             return;
566
567 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
568             qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsAvailable() called for %s (%d glyphs)",
569                    cacheId.constData(), itemIds.size());
570 #endif
571
572         for (int i=0; i<itemIds.size(); ++i) {
573             if (m_requestedGlyphsThatHaveNotBeenReturned.contains(itemIds.at(i))) {
574                 requestedItemsInList = true;
575                 break;
576             }
577         }
578     }
579
580     if (requestedItemsInList)
581         reportItemsUpdated(cacheId, bufferId,itemIds, positions);
582 }
583
584 void QSGSharedDistanceFieldGlyphCache::reportItemsUpdated(const QByteArray &cacheId,
585                                                           void *bufferId,
586                                                           const QVector<quint32> &itemIds,
587                                                           const QVector<QPoint> &positions)
588 {
589     {
590         QMutexLocker locker(&m_pendingGlyphsMutex);
591         if (m_cacheId != cacheId)
592             return;
593
594         Q_ASSERT(itemIds.size() == positions.size());
595
596 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
597         qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsUpdated() called for %s (%d glyphs)",
598                cacheId.constData(), itemIds.size());
599 #endif
600
601         for (int i=0; i<itemIds.size(); ++i) {
602             if (m_requestedGlyphs.contains(itemIds.at(i))) {
603                 PendingGlyph &pendingGlyph = m_pendingReadyGlyphs[itemIds.at(i)];
604                 void *oldBuffer = pendingGlyph.buffer;
605
606                 pendingGlyph.buffer = bufferId;
607                 pendingGlyph.position = positions.at(i);
608
609                 m_sharedGraphicsCache->referenceBuffer(bufferId);
610                 if (oldBuffer != 0)
611                     m_sharedGraphicsCache->dereferenceBuffer(oldBuffer);
612
613                 m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i));
614             }
615         }
616     }
617
618     m_pendingGlyphsCondition.wakeAll();
619     emit glyphsPending();
620 }
621
622 void QSGSharedDistanceFieldGlyphCache::reportItemsInvalidated(const QByteArray &cacheId,
623                                                               const QVector<quint32> &itemIds)
624 {
625     {
626         QMutexLocker locker(&m_pendingGlyphsMutex);
627         if (m_cacheId != cacheId)
628             return;
629
630         for (int i=0; i<itemIds.size(); ++i) {
631             if (m_requestedGlyphs.contains(itemIds.at(i)))
632                 m_pendingInvalidatedGlyphs.insert(itemIds.at(i));
633         }
634     }
635
636     emit glyphsPending();
637 }
638
639
640 void QSGSharedDistanceFieldGlyphCache::reportItemsMissing(const QByteArray &cacheId,
641                                                           const QVector<quint32> &itemIds)
642 {
643     {
644         QMutexLocker locker(&m_pendingGlyphsMutex);
645         if (m_cacheId != cacheId)
646             return;
647
648 #if defined(QSGSHAREDDISTANCEFIELDGLYPHCACHE_DEBUG)
649         qDebug("QSGSharedDistanceFieldGlyphCache::reportItemsMissing() called for %s (%d glyphs)",
650                cacheId.constData(), itemIds.size());
651 #endif
652
653         for (int i=0; i<itemIds.size(); ++i) {
654             if (m_requestedGlyphsThatHaveNotBeenReturned.remove(itemIds.at(i)))
655                 m_pendingMissingGlyphs.insert(itemIds.at(i));
656         }
657     }
658
659     m_pendingGlyphsCondition.wakeAll();
660     emit glyphsPending();
661 }
662
663 QT_END_NAMESPACE