QSGDistanceFieldGlyphCache code refactoring.
[profile/ivi/qtdeclarative.git] / src / declarative / scenegraph / qsgdistancefieldglyphcache.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qsgdistancefieldglyphcache_p.h"
43
44 #include <qmath.h>
45 #include <private/qsgpathsimplifier_p.h>
46 #include <private/qdeclarativeglobal_p.h>
47 #include <qglshaderprogram.h>
48 #include <private/qglengineshadersource_p.h>
49 #include <private/qsgcontext_p.h>
50 #include <private/qrawfont_p.h>
51 #include <qglfunctions.h>
52 #include <qglyphrun.h>
53 #include <qrawfont.h>
54 #include <qdir.h>
55
56 QT_BEGIN_NAMESPACE
57
58 #define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
59 #define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
60 #define QT_DISTANCEFIELD_DEFAULT_SCALE 16
61 #define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
62 #define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
63
64 #define QT_DISTANCEFIELD_BASEFONTSIZE \
65     (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
66                                            QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
67 #define QT_DISTANCEFIELD_TILESIZE \
68     (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
69                                            QT_DISTANCEFIELD_DEFAULT_TILESIZE)
70 #define QT_DISTANCEFIELD_SCALE \
71     (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
72                                            QT_DISTANCEFIELD_DEFAULT_SCALE)
73 #define QT_DISTANCEFIELD_RADIUS \
74     (m_textureData->doubleGlyphResolution ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
75                                            QT_DISTANCEFIELD_DEFAULT_RADIUS)
76
77 static inline int qt_next_power_of_two(int v)
78 {
79     v--;
80     v |= v >> 1;
81     v |= v >> 2;
82     v |= v >> 4;
83     v |= v >> 8;
84     v |= v >> 16;
85     ++v;
86     return v;
87 }
88
89 static float defaultThresholdFunc(float glyphScale)
90 {
91     static float base = qgetenv("QT_DF_BASE").isEmpty() ? 0.5f : qgetenv("QT_DF_BASE").toFloat();
92     static float baseDev = qgetenv("QT_DF_BASEDEVIATION").isEmpty() ? 0.065f : qgetenv("QT_DF_BASEDEVIATION").toFloat();
93     static float devScaleMin = qgetenv("QT_DF_SCALEFORMAXDEV").isEmpty() ? 0.15f : qgetenv("QT_DF_SCALEFORMAXDEV").toFloat();
94     static float devScaleMax = qgetenv("QT_DF_SCALEFORNODEV").isEmpty() ? 0.3f : qgetenv("QT_DF_SCALEFORNODEV").toFloat();
95     return base - ((qBound(devScaleMin, glyphScale, devScaleMax) - devScaleMin) / (devScaleMax - devScaleMin) * -baseDev + baseDev);
96 }
97
98 static float defaultAntialiasingSpreadFunc(float glyphScale)
99 {
100     static float range = qgetenv("QT_DF_RANGE").isEmpty() ? 0.06f : qgetenv("QT_DF_RANGE").toFloat();
101     return range / glyphScale;
102 }
103
104 namespace
105 {
106     enum FillHDir
107     {
108         LeftToRight,
109         RightToLeft
110     };
111
112     enum FillVDir
113     {
114         TopDown,
115         BottomUp
116     };
117
118     enum FillClip
119     {
120         NoClip,
121         Clip
122     };
123 }
124
125 template <FillClip clip, FillHDir dir>
126 inline void fillLine(qint32 *, int, int, int, qint32, qint32)
127 {
128 }
129
130 template <>
131 inline void fillLine<Clip, LeftToRight>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd)
132 {
133     int fromX = qMax(0, lx >> 8);
134     int toX = qMin(width, rx >> 8);
135     int x = toX - fromX;
136     if (x <= 0)
137         return;
138     qint32 val = d + (((fromX << 8) + 0xff - lx) * dd >> 8);
139     line += fromX;
140     do {
141         *line = abs(val) < abs(*line) ? val : *line;
142         val += dd;
143         ++line;
144     } while (--x);
145 }
146
147 template <>
148 inline void fillLine<Clip, RightToLeft>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd)
149 {
150     int fromX = qMax(0, lx >> 8);
151     int toX = qMin(width, rx >> 8);
152     int x = toX - fromX;
153     if (x <= 0)
154         return;
155     qint32 val = d + (((toX << 8) + 0xff - rx) * dd >> 8);
156     line += toX;
157     do {
158         val -= dd;
159         --line;
160         *line = abs(val) < abs(*line) ? val : *line;
161     } while (--x);
162 }
163
164 template <>
165 inline void fillLine<NoClip, LeftToRight>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd)
166 {
167     int fromX = lx >> 8;
168     int toX = rx >> 8;
169     int x = toX - fromX;
170     if (x <= 0)
171         return;
172     qint32 val = d + ((~lx & 0xff) * dd >> 8);
173     line += fromX;
174     do {
175         *line = abs(val) < abs(*line) ? val : *line;
176         val += dd;
177         ++line;
178     } while (--x);
179 }
180
181 template <>
182 inline void fillLine<NoClip, RightToLeft>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd)
183 {
184     int fromX = lx >> 8;
185     int toX = rx >> 8;
186     int x = toX - fromX;
187     if (x <= 0)
188         return;
189     qint32 val = d + ((~rx & 0xff) * dd >> 8);
190     line += toX;
191     do {
192         val -= dd;
193         --line;
194         *line = abs(val) < abs(*line) ? val : *line;
195     } while (--x);
196 }
197
198 template <FillClip clip, FillVDir vDir, FillHDir hDir>
199 inline void fillLines(qint32 *bits, int width, int height, int upperY, int lowerY,
200                       int &lx, int ldx, int &rx, int rdx, qint32 &d, qint32 ddy, qint32 ddx)
201 {
202     Q_UNUSED(height);
203     Q_ASSERT(upperY < lowerY);
204     int y = lowerY - upperY;
205     if (vDir == TopDown) {
206         qint32 *line = bits + upperY * width;
207         do {
208             fillLine<clip, hDir>(line, width, lx, rx, d, ddx);
209             lx += ldx;
210             d += ddy;
211             rx += rdx;
212             line += width;
213         } while (--y);
214     } else {
215         qint32 *line = bits + lowerY * width;
216         do {
217             lx -= ldx;
218             d -= ddy;
219             rx -= rdx;
220             line -= width;
221             fillLine<clip, hDir>(line, width, lx, rx, d, ddx);
222         } while (--y);
223     }
224 }
225
226 template <FillClip clip>
227 void drawTriangle(qint32 *bits, int width, int height, const QPoint *center,
228                   const QPoint *v1, const QPoint *v2, qint32 value)
229 {
230     const int y1 = clip == Clip ? qBound(0, v1->y() >> 8, height) : v1->y() >> 8;
231     const int y2 = clip == Clip ? qBound(0, v2->y() >> 8, height) : v2->y() >> 8;
232     const int yC = clip == Clip ? qBound(0, center->y() >> 8, height) : center->y() >> 8;
233
234     const int v1Frac = clip == Clip ? (y1 << 8) + 0xff - v1->y() : ~v2->y() & 0xff;
235     const int v2Frac = clip == Clip ? (y2 << 8) + 0xff - v2->y() : ~v1->y() & 0xff;
236     const int centerFrac = clip == Clip ? (yC << 8) + 0xff - center->y() : ~center->y() & 0xff;
237
238     int dx1, x1, dx2, x2;
239     qint32 dd1, d1, dd2, d2;
240     if (v1->y() != center->y()) {
241         dx1 = ((v1->x() - center->x()) << 8) / (v1->y() - center->y());
242         x1 = center->x() + centerFrac * (v1->x() - center->x()) / (v1->y() - center->y());
243     }
244     if (v2->y() != center->y()) {
245         dx2 = ((v2->x() - center->x()) << 8) / (v2->y() - center->y());
246         x2 = center->x() + centerFrac * (v2->x() - center->x()) / (v2->y() - center->y());
247     }
248
249     const qint32 div = (v2->x() - center->x()) * (v1->y() - center->y())
250                      - (v2->y() - center->y()) * (v1->x() - center->x());
251     const qint32 dd = div ? qint32((qint64(value * (v1->y() - v2->y())) << 8) / div) : 0;
252
253     if (y2 < yC) {
254         if (y1 < yC) {
255             // Center at the bottom.
256             if (y2 < y1) {
257                 // y2 < y1 < yC
258                 // Long right edge.
259                 d1 = centerFrac * value / (v1->y() - center->y());
260                 dd1 = ((value << 8) / (v1->y() - center->y()));
261                 fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y1, yC, x1, dx1,
262                                                        x2, dx2, d1, dd1, dd);
263                 dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
264                 x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
265                 fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, y1, x1, dx1,
266                                                        x2, dx2, value, 0, dd);
267             } else {
268                 // y1 <= y2 < yC
269                 // Long left edge.
270                 d2 = centerFrac * value / (v2->y() - center->y());
271                 dd2 = ((value << 8) / (v2->y() - center->y()));
272                 fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y2, yC, x1, dx1,
273                                                        x2, dx2, d2, dd2, dd);
274                 if (y1 != y2) {
275                     dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
276                     x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
277                     fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, y2, x1, dx1,
278                                                            x2, dx2, value, 0, dd);
279                 }
280             }
281         } else {
282             // y2 < yC <= y1
283             // Center to the right.
284             int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
285             int xUp, xDn;
286             xUp = xDn = v2->x() + (clip == Clip ? (yC << 8) + 0xff - v2->y()
287                                                 : (center->y() | 0xff) - v2->y())
288                         * (v1->x() - v2->x()) / (v1->y() - v2->y());
289             fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, yC, xUp, dx,
290                                                    x2, dx2, value, 0, dd);
291             if (yC != y1)
292                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y1, xDn, dx,
293                                                       x1, dx1, value, 0, dd);
294         }
295     } else {
296         if (y1 < yC) {
297             // y1 < yC <= y2
298             // Center to the left.
299             int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
300             int xUp, xDn;
301             xUp = xDn = v1->x() + (clip == Clip ? (yC << 8) + 0xff - v1->y()
302                                                 : (center->y() | 0xff) - v1->y())
303                         * (v1->x() - v2->x()) / (v1->y() - v2->y());
304             fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, yC, x1, dx1,
305                                                    xUp, dx, value, 0, dd);
306             if (yC != y2)
307                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y2, x2, dx2,
308                                                       xDn, dx, value, 0, dd);
309         } else {
310             // Center at the top.
311             if (y2 < y1) {
312                 // yC <= y2 < y1
313                 // Long right edge.
314                 if (yC != y2) {
315                     d2 = centerFrac * value / (v2->y() - center->y());
316                     dd2 = ((value << 8) / (v2->y() - center->y()));
317                     fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y2, x2, dx2,
318                                                           x1, dx1, d2, dd2, dd);
319                 }
320                 dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
321                 x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
322                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, y2, y1, x2, dx2,
323                                                       x1, dx1, value, 0, dd);
324             } else {
325                 // Long left edge.
326                 // yC <= y1 <= y2
327                 if (yC != y1) {
328                     d1 = centerFrac * value / (v1->y() - center->y());
329                     dd1 = ((value << 8) / (v1->y() - center->y()));
330                     fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y1, x2, dx2,
331                                                           x1, dx1, d1, dd1, dd);
332                 }
333                 if (y1 != y2) {
334                     dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
335                     x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
336                     fillLines<clip, TopDown, RightToLeft>(bits, width, height, y1, y2, x2, dx2,
337                                                           x1, dx1, value, 0, dd);
338                 }
339             }
340         }
341     }
342 }
343
344 template <FillClip clip>
345 void drawRectangle(qint32 *bits, int width, int height,
346                    const QPoint *int1, const QPoint *center1, const QPoint *ext1,
347                    const QPoint *int2, const QPoint *center2, const QPoint *ext2,
348                    qint32 extValue)
349 {
350     if (center1->y() > center2->y()) {
351         qSwap(center1, center2);
352         qSwap(int1, ext2);
353         qSwap(ext1, int2);
354         extValue = -extValue;
355     }
356
357     Q_ASSERT(ext1->x() - center1->x() == center1->x() - int1->x());
358     Q_ASSERT(ext1->y() - center1->y() == center1->y() - int1->y());
359     Q_ASSERT(ext2->x() - center2->x() == center2->x() - int2->x());
360     Q_ASSERT(ext2->y() - center2->y() == center2->y() - int2->y());
361
362     const int yc1 = clip == Clip ? qBound(0, center1->y() >> 8, height) : center1->y() >> 8;
363     const int yc2 = clip == Clip ? qBound(0, center2->y() >> 8, height) : center2->y() >> 8;
364     const int yi1 = clip == Clip ? qBound(0, int1->y() >> 8, height) : int1->y() >> 8;
365     const int yi2 = clip == Clip ? qBound(0, int2->y() >> 8, height) : int2->y() >> 8;
366     const int ye1 = clip == Clip ? qBound(0, ext1->y() >> 8, height) : ext1->y() >> 8;
367     const int ye2 = clip == Clip ? qBound(0, ext2->y() >> 8, height) : ext2->y() >> 8;
368
369     const int center1Frac = clip == Clip ? (yc1 << 8) + 0xff - center1->y() : ~center1->y() & 0xff;
370     const int center2Frac = clip == Clip ? (yc2 << 8) + 0xff - center2->y() : ~center2->y() & 0xff;
371     const int int1Frac = clip == Clip ? (yi1 << 8) + 0xff - int1->y() : ~int1->y() & 0xff;
372     const int ext1Frac = clip == Clip ? (ye1 << 8) + 0xff - ext1->y() : ~ext1->y() & 0xff;
373
374     int dxC, dxE; // cap slope, edge slope
375     qint32 ddC;
376     if (ext1->y() != int1->y()) {
377         dxC = ((ext1->x() - int1->x()) << 8) / (ext1->y() - int1->y());
378         ddC = (extValue << 9) / (ext1->y() - int1->y());
379     }
380     if (ext1->y() != ext2->y())
381         dxE = ((ext1->x() - ext2->x()) << 8) / (ext1->y() - ext2->y());
382
383     const qint32 div = (ext1->x() - int1->x()) * (ext2->y() - int1->y())
384                      - (ext1->y() - int1->y()) * (ext2->x() - int1->x());
385     const qint32 dd = div ? qint32((qint64(extValue * (ext2->y() - ext1->y())) << 9) / div) : 0;
386
387     int xe1, xe2, xc1, xc2;
388     qint32 d;
389
390     qint32 intValue = -extValue;
391
392     if (center2->x() < center1->x()) {
393         // Leaning to the right. '/'
394         if (int1->y() < ext2->y()) {
395             // Mostly vertical.
396             Q_ASSERT(ext1->y() != ext2->y());
397             xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
398             xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
399             if (ye1 != yi1) {
400                 xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
401                 xc2 += (ye1 - yc1) * dxC;
402                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, yi1, xe1, dxE,
403                                                       xc2, dxC, extValue, 0, dd);
404             }
405             if (yi1 != ye2)
406                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi1, ye2, xe1, dxE,
407                                                       xe2, dxE, extValue, 0, dd);
408             if (ye2 != yi2) {
409                 xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
410                 xc1 += (ye2 - yc2) * dxC;
411                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye2, yi2, xc1, dxC,
412                                                       xe2, dxE, intValue, 0, dd);
413             }
414         } else {
415             // Mostly horizontal.
416             Q_ASSERT(ext1->y() != int1->y());
417             xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
418             xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
419             xc1 += (ye2 - yc2) * dxC;
420             xc2 += (ye1 - yc1) * dxC;
421             if (ye1 != ye2) {
422                 xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
423                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE,
424                                                       xc2, dxC, extValue, 0, dd);
425             }
426             if (ye2 != yi1) {
427                 d = (clip == Clip ? (ye2 << 8) + 0xff - center2->y()
428                                   : (ext2->y() | 0xff) - center2->y())
429                     * 2 * extValue / (ext1->y() - int1->y());
430                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye2, yi1, xc1, dxC,
431                                                       xc2, dxC, d, ddC, dd);
432             }
433             if (yi1 != yi2) {
434                 xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
435                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC,
436                                                       xe2, dxE, intValue, 0, dd);
437             }
438         }
439     } else {
440         // Leaning to the left. '\'
441         if (ext1->y() < int2->y()) {
442             // Mostly vertical.
443             Q_ASSERT(ext1->y() != ext2->y());
444             xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
445             xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
446             if (yi1 != ye1) {
447                 xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
448                 xc1 += (yi1 - yc1) * dxC;
449                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, ye1, xc1, dxC,
450                                                       xe2, dxE, intValue, 0, dd);
451             }
452             if (ye1 != yi2)
453                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye1, yi2, xe1, dxE,
454                                                       xe2, dxE, intValue, 0, dd);
455             if (yi2 != ye2) {
456                 xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
457                 xc2 += (yi2 - yc2) * dxC;
458                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi2, ye2, xe1, dxE,
459                                                       xc2, dxC, extValue, 0, dd);
460             }
461         } else {
462             // Mostly horizontal.
463             Q_ASSERT(ext1->y() != int1->y());
464             xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
465             xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
466             xc1 += (yi1 - yc1) * dxC;
467             xc2 += (yi2 - yc2) * dxC;
468             if (yi1 != yi2) {
469                 xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
470                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC,
471                                                       xe2, dxE, intValue, 0, dd);
472             }
473             if (yi2 != ye1) {
474                 d = (clip == Clip ? (yi2 << 8) + 0xff - center2->y()
475                                   : (int2->y() | 0xff) - center2->y())
476                     * 2 * extValue / (ext1->y() - int1->y());
477                 fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi2, ye1, xc1, dxC,
478                                                       xc2, dxC, d, ddC, dd);
479             }
480             if (ye1 != ye2) {
481                 xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
482                 fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE,
483                                                       xc2, dxC, extValue, 0, dd);
484             }
485         }
486     }
487 }
488
489 static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vertices,
490                          const quint32 *indices, int indexCount, qint32 value)
491 {
492     Q_ASSERT(indexCount != 0);
493     Q_ASSERT(height <= 128);
494     QVarLengthArray<quint8, 16> scans[128];
495     int first = 0;
496     for (int i = 1; i < indexCount; ++i) {
497         quint32 idx1 = indices[i - 1];
498         quint32 idx2 = indices[i];
499         Q_ASSERT(idx1 != quint32(-1));
500         if (idx2 == quint32(-1)) {
501             idx2 = indices[first];
502             Q_ASSERT(idx2 != quint32(-1));
503             first = ++i;
504         }
505         const QPoint *v1 = &vertices[idx1];
506         const QPoint *v2 = &vertices[idx2];
507         if (v2->y() < v1->y())
508             qSwap(v1, v2);
509         int fromY = qMax(0, v1->y() >> 8);
510         int toY = qMin(height, v2->y() >> 8);
511         if (fromY >= toY)
512             continue;
513         int dx = ((v2->x() - v1->x()) << 8) / (v2->y() - v1->y());
514         int x = v1->x() + ((fromY << 8) + 0xff - v1->y()) * (v2->x() - v1->x()) / (v2->y() - v1->y());
515         for (int y = fromY; y < toY; ++y) {
516             quint32 c = quint32(x >> 8);
517             if (c < quint32(width))
518                 scans[y].append(quint8(c));
519             x += dx;
520         }
521     }
522     for (int i = 0; i < height; ++i) {
523         quint8 *scanline = scans[i].data();
524         int size = scans[i].size();
525         for (int j = 1; j < size; ++j) {
526             int k = j;
527             quint8 value = scanline[k];
528             for (; k != 0 && value < scanline[k - 1]; --k)
529                 scanline[k] = scanline[k - 1];
530             scanline[k] = value;
531         }
532         qint32 *line = bits + i * width;
533         int j = 0;
534         for (; j + 1 < size; j += 2) {
535             for (quint8 x = scanline[j]; x < scanline[j + 1]; ++x)
536                 line[x] = value;
537         }
538         if (j < size) {
539             for (int x = scanline[j]; x < width; ++x)
540                 line[x] = value;
541         }
542     }
543 }
544
545 static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, int offs)
546 {
547     QImage image(imgSize, imgSize, QImage::Format_Indexed8);
548
549     if (path.isEmpty()) {
550         image.fill(0);
551         return image;
552     }
553
554     QTransform transform;
555     transform.translate(offs, offs);
556     transform.scale(qreal(1) / dfScale, qreal(1) / dfScale);
557
558     QDataBuffer<quint32> pathIndices(0);
559     QDataBuffer<QPoint> pathVertices(0);
560     qSimplifyPath(path, pathVertices, pathIndices, transform);
561
562     const qint32 interiorColor = -0x7f80; // 8:8 signed format, -127.5
563     const qint32 exteriorColor = 0x7f80; // 8:8 signed format, 127.5
564
565     QScopedArrayPointer<qint32> bits(new qint32[imgSize * imgSize]);
566     for (int i = 0; i < imgSize * imgSize; ++i)
567         bits[i] = exteriorColor;
568
569     const qreal angleStep = qreal(15 * 3.141592653589793238 / 180);
570     const QPoint rotation(qRound(cos(angleStep) * 0x4000),
571                           qRound(sin(angleStep) * 0x4000)); // 2:14 signed
572
573     const quint32 *indices = pathIndices.data();
574     QVarLengthArray<QPoint> normals;
575     QVarLengthArray<QPoint> vertices;
576     QVarLengthArray<bool> isConvex;
577     QVarLengthArray<bool> needsClipping;
578
579     drawPolygons(bits.data(), imgSize, imgSize, pathVertices.data(), indices, pathIndices.size(),
580                  interiorColor);
581
582     int index = 0;
583
584     while (index < pathIndices.size()) {
585         normals.clear();
586         vertices.clear();
587         needsClipping.clear();
588
589         // Find end of polygon.
590         int end = index;
591         while (indices[end] != quint32(-1))
592             ++end;
593
594         // Calculate vertex normals.
595         for (int next = index, prev = end - 1; next < end; prev = next++) {
596             quint32 fromVertexIndex = indices[prev];
597             quint32 toVertexIndex = indices[next];
598
599             const QPoint &from = pathVertices.at(fromVertexIndex);
600             const QPoint &to = pathVertices.at(toVertexIndex);
601
602             QPoint n(to.y() - from.y(), from.x() - to.x());
603             if (n.x() == 0 && n.y() == 0)
604                 continue;
605             int scale = qRound((offs << 16) / sqrt(qreal(n.x() * n.x() + n.y() * n.y()))); // 8:16
606             n.rx() = n.x() * scale >> 8;
607             n.ry() = n.y() * scale >> 8;
608             normals.append(n);
609             QPoint v(to.x() + 0x7f, to.y() + 0x7f);
610             vertices.append(v);
611             needsClipping.append((to.x() < offs << 8) || (to.x() >= (imgSize - offs) << 8)
612                                  || (to.y() < offs << 8) || (to.y() >= (imgSize - offs) << 8));
613         }
614
615         isConvex.resize(normals.count());
616         for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
617             isConvex[prev] = normals.at(prev).x() * normals.at(next).y()
618                            - normals.at(prev).y() * normals.at(next).x() < 0;
619         }
620
621         // Draw quads.
622         for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
623             QPoint n = normals.at(next);
624             QPoint intPrev = vertices.at(prev);
625             QPoint extPrev = vertices.at(prev);
626             QPoint intNext = vertices.at(next);
627             QPoint extNext = vertices.at(next);
628
629             extPrev.rx() -= n.x();
630             extPrev.ry() -= n.y();
631             intPrev.rx() += n.x();
632             intPrev.ry() += n.y();
633             extNext.rx() -= n.x();
634             extNext.ry() -= n.y();
635             intNext.rx() += n.x();
636             intNext.ry() += n.y();
637
638             if (needsClipping[prev] || needsClipping[next]) {
639                 drawRectangle<Clip>(bits.data(), imgSize, imgSize,
640                                     &intPrev, &vertices.at(prev), &extPrev,
641                                     &intNext, &vertices.at(next), &extNext,
642                                     exteriorColor);
643             } else {
644                 drawRectangle<NoClip>(bits.data(), imgSize, imgSize,
645                                       &intPrev, &vertices.at(prev), &extPrev,
646                                       &intNext, &vertices.at(next), &extNext,
647                                       exteriorColor);
648             }
649
650             if (isConvex.at(prev)) {
651                 QPoint p = extPrev;
652                 if (needsClipping[prev]) {
653                     for (;;) {
654                         QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14,
655                                   (n.y() * rotation.x() + n.x() * rotation.y()) >> 14);
656                         n = rn;
657                         if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) {
658                             p.rx() = vertices.at(prev).x() - normals.at(prev).x();
659                             p.ry() = vertices.at(prev).y() - normals.at(prev).y();
660                             drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
661                                                &extPrev, &p, exteriorColor);
662                             break;
663                         }
664
665                         p.rx() = vertices.at(prev).x() - n.x();
666                         p.ry() = vertices.at(prev).y() - n.y();
667                         drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
668                                            &extPrev, &p, exteriorColor);
669                         extPrev = p;
670                     }
671                 } else {
672                     for (;;) {
673                         QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14,
674                                   (n.y() * rotation.x() + n.x() * rotation.y()) >> 14);
675                         n = rn;
676                         if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) {
677                             p.rx() = vertices.at(prev).x() - normals.at(prev).x();
678                             p.ry() = vertices.at(prev).y() - normals.at(prev).y();
679                             drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
680                                                  &extPrev, &p, exteriorColor);
681                             break;
682                         }
683
684                         p.rx() = vertices.at(prev).x() - n.x();
685                         p.ry() = vertices.at(prev).y() - n.y();
686                         drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
687                                              &extPrev, &p, exteriorColor);
688                         extPrev = p;
689                     }
690                 }
691             } else {
692                 QPoint p = intPrev;
693                 if (needsClipping[prev]) {
694                     for (;;) {
695                         QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14,
696                                   (n.y() * rotation.x() - n.x() * rotation.y()) >> 14);
697                         n = rn;
698                         if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) {
699                             p.rx() = vertices.at(prev).x() + normals.at(prev).x();
700                             p.ry() = vertices.at(prev).y() + normals.at(prev).y();
701                             drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
702                                                &p, &intPrev, interiorColor);
703                             break;
704                         }
705
706                         p.rx() = vertices.at(prev).x() + n.x();
707                         p.ry() = vertices.at(prev).y() + n.y();
708                         drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
709                                            &p, &intPrev, interiorColor);
710                         intPrev = p;
711                     }
712                 } else {
713                     for (;;) {
714                         QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14,
715                                   (n.y() * rotation.x() - n.x() * rotation.y()) >> 14);
716                         n = rn;
717                         if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) {
718                             p.rx() = vertices.at(prev).x() + normals.at(prev).x();
719                             p.ry() = vertices.at(prev).y() + normals.at(prev).y();
720                             drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
721                                                  &p, &intPrev, interiorColor);
722                             break;
723                         }
724
725                         p.rx() = vertices.at(prev).x() + n.x();
726                         p.ry() = vertices.at(prev).y() + n.y();
727                         drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
728                                              &p, &intPrev, interiorColor);
729                         intPrev = p;
730                     }
731                 }
732             }
733         }
734
735         index = end + 1;
736     }
737
738     const qint32 *inLine = bits.data();
739     uchar *outLine = image.bits();
740     int padding = image.bytesPerLine() - image.width();
741     for (int y = 0; y < imgSize; ++y) {
742         for (int x = 0; x < imgSize; ++x, ++inLine, ++outLine)
743             *outLine = uchar((0x7f80 - *inLine) >> 8);
744         outLine += padding;
745     }
746
747     return image;
748 }
749
750 static bool fontHasNarrowOutlines(const QRawFont &f)
751 {
752     QRawFont font = f;
753     font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE);
754     Q_ASSERT(font.isValid());
755
756     QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O"));
757     if (glyphIndices.size() < 1)
758         return false;
759
760     QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing);
761     if (im.isNull())
762         return false;
763
764     int minHThick = 999;
765     int minVThick = 999;
766
767     int thick = 0;
768     bool in = false;
769     int y = (im.height() + 1) / 2;
770     for (int x = 0; x < im.width(); ++x) {
771         int a = qAlpha(im.pixel(x, y));
772         if (a > 127) {
773             in = true;
774             ++thick;
775         } else if (in) {
776             in = false;
777             minHThick = qMin(minHThick, thick);
778             thick = 0;
779         }
780     }
781
782     thick = 0;
783     in = false;
784     int x = (im.width() + 1) / 2;
785     for (int y = 0; y < im.height(); ++y) {
786         int a = qAlpha(im.pixel(x, y));
787         if (a > 127) {
788             in = true;
789             ++thick;
790         } else if (in) {
791             in = false;
792             minVThick = qMin(minVThick, thick);
793             thick = 0;
794         }
795     }
796
797     return minHThick == 1 || minVThick == 1;
798 }
799
800 QSGDistanceFieldGlyphCacheManager::QSGDistanceFieldGlyphCacheManager(const QGLContext *c)
801     : ctx(c)
802     , m_threshold_func(defaultThresholdFunc)
803     , m_antialiasingSpread_func(defaultAntialiasingSpreadFunc)
804     , m_maxTextureSize(0)
805 {
806 #ifndef QT_OPENGL_ES
807     m_defaultAntialiasingMode = QSGGlyphNode::SubPixelAntialiasing;
808 #else
809     m_defaultAntialiasingMode = QSGGlyphNode::GrayAntialiasing;
810 #endif
811
812     m_vertexCoordinateArray[0] = -1.0f;
813     m_vertexCoordinateArray[1] = -1.0f;
814     m_vertexCoordinateArray[2] =  1.0f;
815     m_vertexCoordinateArray[3] = -1.0f;
816     m_vertexCoordinateArray[4] =  1.0f;
817     m_vertexCoordinateArray[5] =  1.0f;
818     m_vertexCoordinateArray[6] = -1.0f;
819     m_vertexCoordinateArray[7] =  1.0f;
820
821     m_textureCoordinateArray[0] = 0.0f;
822     m_textureCoordinateArray[1] = 0.0f;
823     m_textureCoordinateArray[2] = 1.0f;
824     m_textureCoordinateArray[3] = 0.0f;
825     m_textureCoordinateArray[4] = 1.0f;
826     m_textureCoordinateArray[5] = 1.0f;
827     m_textureCoordinateArray[6] = 0.0f;
828     m_textureCoordinateArray[7] = 1.0f;
829
830     m_blitProgram = new QGLShaderProgram;
831     {
832         QString source;
833         source.append(QLatin1String(qglslMainWithTexCoordsVertexShader));
834         source.append(QLatin1String(qglslUntransformedPositionVertexShader));
835
836         QGLShader *vertexShader = new QGLShader(QGLShader::Vertex, m_blitProgram);
837         vertexShader->compileSourceCode(source);
838
839         m_blitProgram->addShader(vertexShader);
840     }
841     {
842         QString source;
843         source.append(QLatin1String(qglslMainFragmentShader));
844         source.append(QLatin1String(qglslImageSrcFragmentShader));
845
846         QGLShader *fragmentShader = new QGLShader(QGLShader::Fragment, m_blitProgram);
847         fragmentShader->compileSourceCode(source);
848
849         m_blitProgram->addShader(fragmentShader);
850     }
851     m_blitProgram->bindAttributeLocation("vertexCoordsArray", QT_VERTEX_COORDS_ATTR);
852     m_blitProgram->bindAttributeLocation("textureCoordArray", QT_TEXTURE_COORDS_ATTR);
853     m_blitProgram->link();
854 }
855
856 QSGDistanceFieldGlyphCacheManager::~QSGDistanceFieldGlyphCacheManager()
857 {
858     delete m_blitProgram;
859     qDeleteAll(m_caches.values());
860 }
861
862 QSGDistanceFieldGlyphCache *QSGDistanceFieldGlyphCacheManager::cache(const QRawFont &font)
863 {
864     QRawFontPrivate *fontD = QRawFontPrivate::get(font);
865     QHash<QFontEngine *, QSGDistanceFieldGlyphCache *>::iterator cache = m_caches.find(fontD->fontEngine);
866     if (cache == m_caches.end())
867         cache = m_caches.insert(fontD->fontEngine, new QSGDistanceFieldGlyphCache(this, ctx, font));
868     return cache.value();
869 }
870
871 int QSGDistanceFieldGlyphCacheManager::maxTextureSize() const
872 {
873     if (!m_maxTextureSize)
874         glGetIntegerv(GL_MAX_TEXTURE_SIZE, &m_maxTextureSize);
875     return m_maxTextureSize;
876 }
877
878
879 QHash<QString, QGLContextGroupResource<QSGDistanceFieldGlyphCache::DistanceFieldTextureData> > QSGDistanceFieldGlyphCache::m_textures_data;
880
881 QSGDistanceFieldGlyphCache::DistanceFieldTextureData *QSGDistanceFieldGlyphCache::textureData()
882 {
883     QString key = QString::fromLatin1("%1_%2_%3_%4")
884             .arg(m_font.familyName())
885             .arg(m_font.styleName())
886             .arg(m_font.weight())
887             .arg(m_font.style());
888     return m_textures_data[key].value(ctx);
889 }
890
891 QSGDistanceFieldGlyphCache::QSGDistanceFieldGlyphCache(QSGDistanceFieldGlyphCacheManager *man, const QGLContext *c, const QRawFont &font)
892     : m_manager(man)
893     , ctx(c)
894 {
895     Q_ASSERT(font.isValid());
896     m_font = font;
897
898     m_textureData = textureData();
899
900     QRawFontPrivate *fontD = QRawFontPrivate::get(m_font);
901     m_glyphCount = fontD->fontEngine->glyphCount();
902
903     m_textureData->doubleGlyphResolution = fontHasNarrowOutlines(font) && m_glyphCount < QT_DISTANCEFIELD_HIGHGLYPHCOUNT;
904
905     m_referenceFont = m_font;
906     m_referenceFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE);
907     Q_ASSERT(m_referenceFont.isValid());
908 }
909
910 QSGDistanceFieldGlyphCache::~QSGDistanceFieldGlyphCache()
911 {
912 }
913
914 GLuint QSGDistanceFieldGlyphCache::texture()
915 {
916     return m_textureData->texture;
917 }
918
919 QSize QSGDistanceFieldGlyphCache::textureSize() const
920 {
921     return m_textureData->size;
922 }
923
924 QSGDistanceFieldGlyphCache::Metrics QSGDistanceFieldGlyphCache::glyphMetrics(glyph_t glyph)
925 {
926     QHash<glyph_t, Metrics>::iterator metric = m_metrics.find(glyph);
927     if (metric == m_metrics.end()) {
928         QPainterPath path = m_font.pathForGlyph(glyph);
929         QRectF br = path.boundingRect();
930
931         Metrics m;
932         m.width = br.width();
933         m.height = br.height();
934         m.baselineX = br.x();
935         m.baselineY = -br.y();
936
937         metric = m_metrics.insert(glyph, m);
938     }
939
940     return metric.value();
941 }
942
943 QSGDistanceFieldGlyphCache::TexCoord QSGDistanceFieldGlyphCache::glyphTexCoord(glyph_t glyph)
944 {
945     return m_textureData->texCoords.value(glyph);
946 }
947
948 QImage QSGDistanceFieldGlyphCache::renderDistanceFieldGlyph(glyph_t glyph) const
949 {
950     QRawFont renderFont = m_font;
951     renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE * QT_DISTANCEFIELD_SCALE);
952
953     QPainterPath path = renderFont.pathForGlyph(glyph);
954     path.translate(-path.boundingRect().topLeft());
955     path.setFillRule(Qt::WindingFill);
956
957     QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE,
958                                   path,
959                                   QT_DISTANCEFIELD_SCALE,
960                                   QT_DISTANCEFIELD_RADIUS / QT_DISTANCEFIELD_SCALE);
961     return im;
962 }
963
964 qreal QSGDistanceFieldGlyphCache::fontScale() const
965 {
966     return qreal(m_font.pixelSize()) / QT_DISTANCEFIELD_BASEFONTSIZE;
967 }
968
969 int QSGDistanceFieldGlyphCache::distanceFieldRadius() const
970 {
971     return QT_DISTANCEFIELD_DEFAULT_RADIUS / QT_DISTANCEFIELD_SCALE;
972 }
973
974 void QSGDistanceFieldGlyphCache::populate(int count, const glyph_t *glyphs)
975 {
976     // Avoid useless and costly glyph re-generation
977     if (cacheIsFull() && !m_textureData->unusedGlyphs.isEmpty()) {
978         for (int i = 0; i < count; ++i) {
979             glyph_t glyphIndex = glyphs[i];
980             if (m_textureData->texCoords.contains(glyphIndex) && m_textureData->unusedGlyphs.contains(glyphIndex))
981                 m_textureData->unusedGlyphs.remove(glyphIndex);
982         }
983     }
984
985     for (int i = 0; i < count; ++i) {
986         glyph_t glyphIndex = glyphs[i];
987         if ((int) glyphIndex >= glyphCount()) {
988             qWarning("Warning: distance-field glyph is not available with index %d", glyphIndex);
989             continue;
990         }
991
992         if (++m_textureData->glyphRefCount[glyphIndex] == 1)
993             m_textureData->unusedGlyphs.remove(glyphIndex);
994
995         if (m_textureData->texCoords.contains(glyphIndex)
996                 || (cacheIsFull() && m_textureData->unusedGlyphs.isEmpty()))
997             continue;
998
999         QPainterPath path = m_referenceFont.pathForGlyph(glyphIndex);
1000         if (path.isEmpty()) {
1001             m_textureData->texCoords.insert(glyphIndex, TexCoord());
1002             continue;
1003         }
1004         QRectF br = path.boundingRect();
1005
1006         TexCoord c;
1007         c.xMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
1008         c.yMargin = QT_DISTANCEFIELD_RADIUS / qreal(QT_DISTANCEFIELD_SCALE);
1009         c.x = m_textureData->currX;
1010         c.y = m_textureData->currY;
1011         c.width = br.width();
1012         c.height = br.height();
1013
1014         if (!cacheIsFull()) {
1015             m_textureData->currX += QT_DISTANCEFIELD_TILESIZE;
1016             if (m_textureData->currX >= m_manager->maxTextureSize()) {
1017                 m_textureData->currX = 0;
1018                 m_textureData->currY += QT_DISTANCEFIELD_TILESIZE;
1019             }
1020         } else {
1021             // Recycle glyphs
1022             if (!m_textureData->unusedGlyphs.isEmpty()) {
1023                 glyph_t unusedGlyph = *m_textureData->unusedGlyphs.constBegin();
1024                 TexCoord unusedCoord = glyphTexCoord(unusedGlyph);
1025                 c.x = unusedCoord.x;
1026                 c.y = unusedCoord.y;
1027                 m_textureData->unusedGlyphs.remove(unusedGlyph);
1028                 m_textureData->texCoords.remove(unusedGlyph);
1029             }
1030         }
1031
1032         if (c.y < m_manager->maxTextureSize()) {
1033             m_textureData->texCoords.insert(glyphIndex, c);
1034             m_textureData->pendingGlyphs.add(glyphIndex);
1035         }
1036     }
1037 }
1038
1039 void QSGDistanceFieldGlyphCache::derefGlyphs(int count, const glyph_t *glyphs)
1040 {
1041     for (int i = 0; i < count; ++i)
1042         if (--m_textureData->glyphRefCount[glyphs[i]] == 0 && !glyphTexCoord(glyphs[i]).isNull())
1043             m_textureData->unusedGlyphs.insert(glyphs[i]);
1044 }
1045
1046 void QSGDistanceFieldGlyphCache::createTexture(int width, int height)
1047 {
1048     if (ctx->d_ptr->workaround_brokenFBOReadBack && m_textureData->image.isNull())
1049         m_textureData->image = QImage(width, height, QImage::Format_Indexed8);
1050
1051     while (glGetError() != GL_NO_ERROR) { }
1052
1053     glGenTextures(1, &m_textureData->texture);
1054     glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
1055
1056     QVarLengthArray<uchar> data(width * height);
1057     for (int i = 0; i < data.size(); ++i)
1058         data[i] = 0;
1059     glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &data[0]);
1060     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1061     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1062     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1063     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1064
1065     m_textureData->size = QSize(width, height);
1066
1067     GLuint error = glGetError();
1068     if (error != GL_NO_ERROR) {
1069         glBindTexture(GL_TEXTURE_2D, 0);
1070         glDeleteTextures(1, &m_textureData->texture);
1071         m_textureData->texture = 0;
1072     }
1073
1074 }
1075
1076 void QSGDistanceFieldGlyphCache::resizeTexture(int width, int height)
1077 {
1078     int oldWidth = m_textureData->size.width();
1079     int oldHeight = m_textureData->size.height();
1080     if (width == oldWidth && height == oldHeight)
1081         return;
1082
1083     GLuint oldTexture = m_textureData->texture;
1084     createTexture(width, height);
1085
1086     if (!oldTexture)
1087         return;
1088
1089     if (ctx->d_ptr->workaround_brokenFBOReadBack) {
1090         m_textureData->image = m_textureData->image.copy(0, 0, width, height);
1091         QImage copy = m_textureData->image.copy(0, 0, oldWidth, oldHeight);
1092         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, oldWidth, oldHeight, GL_ALPHA, GL_UNSIGNED_BYTE, copy.constBits());
1093         glDeleteTextures(1, &oldTexture);
1094         return;
1095     }
1096
1097     if (!m_textureData->fbo)
1098         ctx->functions()->glGenFramebuffers(1, &m_textureData->fbo);
1099     ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, m_textureData->fbo);
1100
1101     GLuint tmp_texture;
1102     glGenTextures(1, &tmp_texture);
1103     glBindTexture(GL_TEXTURE_2D, tmp_texture);
1104     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, oldWidth, oldHeight, 0,
1105                  GL_RGBA, GL_UNSIGNED_BYTE, NULL);
1106     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1107     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1108     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
1109     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
1110     glBindTexture(GL_TEXTURE_2D, 0);
1111     ctx->functions()->glFramebufferTexture2D(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1112                                              GL_TEXTURE_2D, tmp_texture, 0);
1113
1114     ctx->functions()->glActiveTexture(GL_TEXTURE0);
1115     glBindTexture(GL_TEXTURE_2D, oldTexture);
1116
1117     // save current render states
1118     GLboolean stencilTestEnabled;
1119     GLboolean depthTestEnabled;
1120     GLboolean scissorTestEnabled;
1121     GLboolean blendEnabled;
1122     GLint viewport[4];
1123     glGetBooleanv(GL_STENCIL_TEST, &stencilTestEnabled);
1124     glGetBooleanv(GL_DEPTH_TEST, &depthTestEnabled);
1125     glGetBooleanv(GL_SCISSOR_TEST, &scissorTestEnabled);
1126     glGetBooleanv(GL_BLEND, &blendEnabled);
1127     glGetIntegerv(GL_VIEWPORT, &viewport[0]);
1128
1129     glDisable(GL_STENCIL_TEST);
1130     glDisable(GL_DEPTH_TEST);
1131     glDisable(GL_SCISSOR_TEST);
1132     glDisable(GL_BLEND);
1133
1134     glViewport(0, 0, oldWidth, oldHeight);
1135
1136     ctx->functions()->glVertexAttribPointer(QT_VERTEX_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitVertexArray());
1137     ctx->functions()->glVertexAttribPointer(QT_TEXTURE_COORDS_ATTR, 2, GL_FLOAT, GL_FALSE, 0, m_manager->blitTextureArray());
1138
1139     m_manager->blitProgram()->bind();
1140     m_manager->blitProgram()->enableAttributeArray(int(QT_VERTEX_COORDS_ATTR));
1141     m_manager->blitProgram()->enableAttributeArray(int(QT_TEXTURE_COORDS_ATTR));
1142     m_manager->blitProgram()->disableAttributeArray(int(QT_OPACITY_ATTR));
1143     m_manager->blitProgram()->setUniformValue("imageTexture", GLuint(0));
1144
1145     glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1146
1147     glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
1148
1149     glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, oldWidth, oldHeight);
1150
1151     ctx->functions()->glFramebufferRenderbuffer(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
1152                                                 GL_RENDERBUFFER_EXT, 0);
1153     glDeleteTextures(1, &tmp_texture);
1154     glDeleteTextures(1, &oldTexture);
1155
1156     ctx->functions()->glBindFramebuffer(GL_FRAMEBUFFER_EXT, 0);
1157
1158     // restore render states
1159     if (stencilTestEnabled)
1160         glEnable(GL_STENCIL_TEST);
1161     if (depthTestEnabled)
1162         glEnable(GL_DEPTH_TEST);
1163     if (scissorTestEnabled)
1164         glEnable(GL_SCISSOR_TEST);
1165     if (blendEnabled)
1166         glEnable(GL_BLEND);
1167     glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
1168 }
1169
1170 void QSGDistanceFieldGlyphCache::updateCache()
1171 {
1172     if (m_textureData->pendingGlyphs.isEmpty())
1173         return;
1174
1175     int requiredWidth = m_manager->maxTextureSize();
1176     int rows = 128 / (requiredWidth / QT_DISTANCEFIELD_TILESIZE); // Enough rows to fill the latin1 set by default..
1177     int requiredHeight = qMin(m_manager->maxTextureSize(), qMax(m_textureData->currY + QT_DISTANCEFIELD_TILESIZE, QT_DISTANCEFIELD_TILESIZE * rows));
1178
1179     resizeTexture((requiredWidth), (requiredHeight));
1180     glBindTexture(GL_TEXTURE_2D, m_textureData->texture);
1181
1182     // ### Remove before final release
1183     static bool cacheDistanceFields = QApplication::arguments().contains("--cache-distance-fields");
1184
1185 // #define QSGDISTANCEFIELDS_TIME_CREATION
1186 #ifdef QSGDISTANCEFIELDS_TIME_CREATION
1187     QTime time;
1188     time.start();
1189 #endif
1190
1191     QString tmpPath = QString::fromLatin1("%1/.qt/").arg(QDir::tempPath());
1192     QString keyBase = QString::fromLatin1("%1%2%3_%4_%5_%6.fontblob")
1193             .arg(tmpPath)
1194             .arg(m_font.familyName())
1195             .arg(m_font.styleName())
1196             .arg(m_font.weight())
1197             .arg(m_font.style());
1198
1199     if (cacheDistanceFields && !QFile::exists(tmpPath))
1200         QDir(tmpPath).mkpath(tmpPath);
1201
1202     for (int i = 0; i < m_textureData->pendingGlyphs.size(); ++i) {
1203         glyph_t glyphIndex = m_textureData->pendingGlyphs.at(i);
1204         TexCoord c = m_textureData->texCoords.value(glyphIndex);
1205
1206         if (cacheDistanceFields) {
1207             QString key = keyBase.arg(glyphIndex);
1208             QFile file(key);
1209             if (file.open(QFile::ReadOnly)) {
1210                 int fileSize = file.size();
1211                 int dim = sqrt(float(fileSize));
1212                 QByteArray blob = file.readAll();
1213                 glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, dim, dim, GL_ALPHA, GL_UNSIGNED_BYTE, blob.constData());
1214                 continue;
1215             }
1216         }
1217
1218         QImage glyph = renderDistanceFieldGlyph(glyphIndex);
1219
1220         if (ctx->d_ptr->workaround_brokenFBOReadBack) {
1221             uchar *inBits = glyph.scanLine(0);
1222             uchar *outBits = m_textureData->image.scanLine(int(c.y)) + int(c.x);
1223             for (int y = 0; y < glyph.height(); ++y) {
1224                 qMemCopy(outBits, inBits, glyph.width());
1225                 inBits += glyph.bytesPerLine();
1226                 outBits += m_textureData->image.bytesPerLine();
1227             }
1228         }
1229
1230         glTexSubImage2D(GL_TEXTURE_2D, 0, c.x, c.y, glyph.width(), glyph.height(), GL_ALPHA, GL_UNSIGNED_BYTE, glyph.constBits());
1231
1232         if (cacheDistanceFields) {
1233             QString key = keyBase.arg(glyphIndex);
1234             QFile file(key);
1235             file.open(QFile::WriteOnly);
1236             file.write((const char *) glyph.constBits(), glyph.width() * glyph.height());
1237         }
1238     }
1239
1240 #ifdef QSGDISTANCEFIELDS_TIME_CREATION
1241         static int totalTime;
1242     totalTime += time.elapsed();
1243     printf("time: %d\n", totalTime);
1244 #endif
1245
1246     m_textureData->pendingGlyphs.reset();
1247 }
1248
1249 bool QSGDistanceFieldGlyphCache::useWorkaroundBrokenFBOReadback() const
1250 {
1251     return ctx->d_ptr->workaround_brokenFBOReadBack;
1252 }
1253
1254 int QSGDistanceFieldGlyphCache::glyphCount() const
1255 {
1256     return m_glyphCount;
1257 }
1258
1259 QT_END_NAMESPACE