Make cache of opentype tables in Harfbuzz face lazy
[profile/ivi/qtbase.git] / src / gui / text / qfontengine.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 QtGui 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 #include <qdebug.h>
43 #include <private/qfontengine_p.h>
44
45 #include "qbitmap.h"
46 #include "qpainter.h"
47 #include "qpainterpath.h"
48 #include "qvarlengtharray.h"
49 #include <qmath.h>
50 #include <qendian.h>
51 #include <private/qharfbuzz_p.h>
52
53 QT_BEGIN_NAMESPACE
54
55 static inline bool qtransform_equals_no_translate(const QTransform &a, const QTransform &b)
56 {
57     if (a.type() <= QTransform::TxTranslate && b.type() <= QTransform::TxTranslate) {
58         return true;
59     } else {
60         // We always use paths for perspective text anyway, so no
61         // point in checking the full matrix...
62         Q_ASSERT(a.type() < QTransform::TxProject);
63         Q_ASSERT(b.type() < QTransform::TxProject);
64
65         return a.m11() == b.m11()
66             && a.m12() == b.m12()
67             && a.m21() == b.m21()
68             && a.m22() == b.m22();
69     }
70 }
71
72 // Harfbuzz helper functions
73
74 static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft)
75 {
76     QFontEngine *fe = (QFontEngine *)font->userData;
77
78     QVarLengthGlyphLayoutArray qglyphs(*numGlyphs);
79
80     QTextEngine::ShaperFlags shaperFlags(QTextEngine::GlyphIndicesOnly);
81     if (rightToLeft)
82         shaperFlags |= QTextEngine::RightToLeft;
83
84     int nGlyphs = *numGlyphs;
85     bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags);
86     *numGlyphs = nGlyphs;
87     if (!result)
88         return false;
89
90     for (hb_uint32 i = 0; i < *numGlyphs; ++i)
91         glyphs[i] = qglyphs.glyphs[i];
92
93     return true;
94 }
95
96 static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags)
97 {
98     QFontEngine *fe = (QFontEngine *)font->userData;
99
100     QVarLengthGlyphLayoutArray qglyphs(numGlyphs);
101
102     for (hb_uint32 i = 0; i < numGlyphs; ++i)
103         qglyphs.glyphs[i] = glyphs[i];
104
105     fe->recalcAdvances(&qglyphs, flags & HB_ShaperFlag_UseDesignMetrics ? QFlags<QTextEngine::ShaperFlag>(QTextEngine::DesignMetrics) : QFlags<QTextEngine::ShaperFlag>(0));
106
107     for (hb_uint32 i = 0; i < numGlyphs; ++i)
108         advances[i] = qglyphs.advances_x[i].value();
109 }
110
111 static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
112 {
113     QFontEngine *fe = (QFontEngine *)font->userData;
114     return fe->canRender(reinterpret_cast<const QChar *>(string), length);
115 }
116
117 static void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
118 {
119     QFontEngine *fe = (QFontEngine *)font->userData;
120     glyph_metrics_t m = fe->boundingBox(glyph);
121     metrics->x = m.x.value();
122     metrics->y = m.y.value();
123     metrics->width = m.width.value();
124     metrics->height = m.height.value();
125     metrics->xOffset = m.xoff.value();
126     metrics->yOffset = m.yoff.value();
127 }
128
129 static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
130 {
131     if (metric == HB_FontAscent) {
132         QFontEngine *fe = (QFontEngine *)font->userData;
133         return fe->ascent().value();
134     }
135     return 0;
136 }
137
138 HB_Error QFontEngine::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
139 {
140     Q_UNUSED(glyph)
141     Q_UNUSED(flags)
142     Q_UNUSED(point)
143     Q_UNUSED(xpos)
144     Q_UNUSED(ypos)
145     Q_UNUSED(nPoints)
146     return HB_Err_Not_Covered;
147 }
148
149 static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
150 {
151     QFontEngine *fe = (QFontEngine *)font->userData;
152     return fe->getPointInOutline(glyph, flags, point, xpos, ypos, nPoints);
153 }
154
155 static const HB_FontClass hb_fontClass = {
156     hb_stringToGlyphs, hb_getAdvances, hb_canRender, hb_getPointInOutline,
157     hb_getGlyphMetrics, hb_getFontMetric
158 };
159
160 static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
161 {
162     QFontEngine *fe = (QFontEngine *)font;
163     if (!fe->getSfntTableData(tableTag, buffer, length))
164         return HB_Err_Invalid_Argument;
165     return HB_Err_Ok;
166 }
167
168 // QFontEngine
169
170 QFontEngine::QFontEngine()
171     : QObject(), ref(0)
172 {
173     cache_count = 0;
174     fsType = 0;
175     symbol = false;
176     memset(&hbFont, 0, sizeof(hbFont));
177     hbFont.klass = &hb_fontClass;
178     hbFont.userData = this;
179
180     hbFace = 0;
181     glyphFormat = -1;
182     m_subPixelPositionCount = 0;
183 }
184
185 QFontEngine::~QFontEngine()
186 {
187     m_glyphCaches.clear();
188     qHBFreeFace(hbFace);
189 }
190
191 QFixed QFontEngine::lineThickness() const
192 {
193     // ad hoc algorithm
194     int score = fontDef.weight * fontDef.pixelSize;
195     int lw = score / 700;
196
197     // looks better with thicker line for small pointsizes
198     if (lw < 2 && score >= 1050) lw = 2;
199     if (lw == 0) lw = 1;
200
201     return lw;
202 }
203
204 QFixed QFontEngine::underlinePosition() const
205 {
206     return ((lineThickness() * 2) + 3) / 6;
207 }
208
209 HB_Font QFontEngine::harfbuzzFont() const
210 {
211     if (!hbFont.x_ppem) {
212         QFixed emSquare = emSquareSize();
213         hbFont.x_ppem = fontDef.pixelSize;
214         hbFont.y_ppem = fontDef.pixelSize * fontDef.stretch / 100;
215         hbFont.x_scale = (QFixed(hbFont.x_ppem * (1 << 16)) / emSquare).value();
216         hbFont.y_scale = (QFixed(hbFont.y_ppem * (1 << 16)) / emSquare).value();
217     }
218     return &hbFont;
219 }
220
221 HB_Face QFontEngine::harfbuzzFace() const
222 {
223     if (!hbFace) {
224         hbFace = qHBNewFace(const_cast<QFontEngine *>(this), hb_getSFntTable);
225         Q_CHECK_PTR(hbFace);
226     }
227     return hbFace;
228 }
229
230 HB_Face QFontEngine::initializedHarfbuzzFace() const
231 {
232     HB_Face face = harfbuzzFace();
233     if (face != 0 && face->font_for_init != 0)
234         face = qHBLoadFace(face);
235
236     return face;
237 }
238
239 glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix)
240 {
241     glyph_metrics_t metrics = boundingBox(glyph);
242
243     if (matrix.type() > QTransform::TxTranslate) {
244         return metrics.transformed(matrix);
245     }
246     return metrics;
247 }
248
249 QFixed QFontEngine::xHeight() const
250 {
251     QGlyphLayoutArray<8> glyphs;
252     int nglyphs = 7;
253     QChar x((ushort)'x');
254     stringToCMap(&x, 1, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly);
255
256     glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]);
257     return bb.height;
258 }
259
260 QFixed QFontEngine::averageCharWidth() const
261 {
262     QGlyphLayoutArray<8> glyphs;
263     int nglyphs = 7;
264     QChar x((ushort)'x');
265     stringToCMap(&x, 1, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly);
266
267     glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]);
268     return bb.xoff;
269 }
270
271
272 void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
273                                     QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions)
274 {
275     QFixed xpos;
276     QFixed ypos;
277
278     const bool transform = matrix.m11() != 1.
279                            || matrix.m12() != 0.
280                            || matrix.m21() != 0.
281                            || matrix.m22() != 1.;
282     if (!transform) {
283         xpos = QFixed::fromReal(matrix.dx());
284         ypos = QFixed::fromReal(matrix.dy());
285     }
286
287     int current = 0;
288     if (flags & QTextItem::RightToLeft) {
289         int i = glyphs.numGlyphs;
290         int totalKashidas = 0;
291         while(i--) {
292             if (glyphs.attributes[i].dontPrint)
293                 continue;
294             xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
295             ypos += glyphs.advances_y[i];
296             totalKashidas += glyphs.justifications[i].nKashidas;
297         }
298         positions.resize(glyphs.numGlyphs+totalKashidas);
299         glyphs_out.resize(glyphs.numGlyphs+totalKashidas);
300
301         i = 0;
302         while(i < glyphs.numGlyphs) {
303             if (glyphs.attributes[i].dontPrint) {
304                 ++i;
305                 continue;
306             }
307             xpos -= glyphs.advances_x[i];
308             ypos -= glyphs.advances_y[i];
309
310             QFixed gpos_x = xpos + glyphs.offsets[i].x;
311             QFixed gpos_y = ypos + glyphs.offsets[i].y;
312             if (transform) {
313                 QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
314                 gpos = gpos * matrix;
315                 gpos_x = QFixed::fromReal(gpos.x());
316                 gpos_y = QFixed::fromReal(gpos.y());
317             }
318             positions[current].x = gpos_x;
319             positions[current].y = gpos_y;
320             glyphs_out[current] = glyphs.glyphs[i];
321             ++current;
322             if (glyphs.justifications[i].nKashidas) {
323                 QChar ch(0x640); // Kashida character
324                 QGlyphLayoutArray<8> g;
325                 int nglyphs = 7;
326                 stringToCMap(&ch, 1, &g, &nglyphs, 0);
327                 for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
328                     xpos -= g.advances_x[0];
329                     ypos -= g.advances_y[0];
330
331                     QFixed gpos_x = xpos + glyphs.offsets[i].x;
332                     QFixed gpos_y = ypos + glyphs.offsets[i].y;
333                     if (transform) {
334                         QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
335                         gpos = gpos * matrix;
336                         gpos_x = QFixed::fromReal(gpos.x());
337                         gpos_y = QFixed::fromReal(gpos.y());
338                     }
339                     positions[current].x = gpos_x;
340                     positions[current].y = gpos_y;
341                     glyphs_out[current] = g.glyphs[0];
342                     ++current;
343                 }
344             } else {
345                 xpos -= QFixed::fromFixed(glyphs.justifications[i].space_18d6);
346             }
347             ++i;
348         }
349     } else {
350         positions.resize(glyphs.numGlyphs);
351         glyphs_out.resize(glyphs.numGlyphs);
352         int i = 0;
353         if (!transform) {
354             while (i < glyphs.numGlyphs) {
355                 if (!glyphs.attributes[i].dontPrint) {
356                     positions[current].x = xpos + glyphs.offsets[i].x;
357                     positions[current].y = ypos + glyphs.offsets[i].y;
358                     glyphs_out[current] = glyphs.glyphs[i];
359                     xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
360                     ypos += glyphs.advances_y[i];
361                     ++current;
362                 }
363                 ++i;
364             }
365         } else {
366             while (i < glyphs.numGlyphs) {
367                 if (!glyphs.attributes[i].dontPrint) {
368                     QFixed gpos_x = xpos + glyphs.offsets[i].x;
369                     QFixed gpos_y = ypos + glyphs.offsets[i].y;
370                     QPointF gpos(gpos_x.toReal(), gpos_y.toReal());
371                     gpos = gpos * matrix;
372                     positions[current].x = QFixed::fromReal(gpos.x());
373                     positions[current].y = QFixed::fromReal(gpos.y());
374                     glyphs_out[current] = glyphs.glyphs[i];
375                     xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
376                     ypos += glyphs.advances_y[i];
377                     ++current;
378                 }
379                 ++i;
380             }
381         }
382     }
383     positions.resize(current);
384     glyphs_out.resize(current);
385     Q_ASSERT(positions.size() == glyphs_out.size());
386 }
387
388 void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
389 {
390     glyph_metrics_t gi = boundingBox(glyph);
391     bool isValid = gi.isValid();
392     if (leftBearing != 0)
393         *leftBearing = isValid ? gi.x.toReal() : 0.0;
394     if (rightBearing != 0)
395         *rightBearing = isValid ? (gi.xoff - gi.x - gi.width).toReal() : 0.0;
396 }
397
398 glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
399 {
400     glyph_metrics_t overall;
401
402     QFixed ymax = 0;
403     QFixed xmax = 0;
404     for (int i = 0; i < glyphs.numGlyphs; i++) {
405         glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);
406         QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;
407         QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;
408         overall.x = qMin(overall.x, x);
409         overall.y = qMin(overall.y, y);
410         xmax = qMax(xmax, x + bb.width);
411         ymax = qMax(ymax, y + bb.height);
412         overall.xoff += bb.xoff;
413         overall.yoff += bb.yoff;
414     }
415     overall.height = qMax(overall.height, ymax - overall.y);
416     overall.width = xmax - overall.x;
417
418     return overall;
419 }
420
421
422 void QFontEngine::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path,
423                                    QTextItem::RenderFlags flags)
424 {
425     if (!glyphs.numGlyphs)
426         return;
427
428     QVarLengthArray<QFixedPoint> positions;
429     QVarLengthArray<glyph_t> positioned_glyphs;
430     QTransform matrix = QTransform::fromTranslate(x, y);
431     getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
432     addGlyphsToPath(positioned_glyphs.data(), positions.data(), positioned_glyphs.size(), path, flags);
433 }
434
435 #define GRID(x, y) grid[(y)*(w+1) + (x)]
436 #define SET(x, y) (*(image_data + (y)*bpl + ((x) >> 3)) & (0x80 >> ((x) & 7)))
437
438 enum { EdgeRight = 0x1,
439        EdgeDown = 0x2,
440        EdgeLeft = 0x4,
441        EdgeUp = 0x8
442 };
443
444 static void collectSingleContour(qreal x0, qreal y0, uint *grid, int x, int y, int w, int h, QPainterPath *path)
445 {
446     Q_UNUSED(h);
447
448     path->moveTo(x + x0, y + y0);
449     while (GRID(x, y)) {
450         if (GRID(x, y) & EdgeRight) {
451             while (GRID(x, y) & EdgeRight) {
452                 GRID(x, y) &= ~EdgeRight;
453                 ++x;
454             }
455             Q_ASSERT(x <= w);
456             path->lineTo(x + x0, y + y0);
457             continue;
458         }
459         if (GRID(x, y) & EdgeDown) {
460             while (GRID(x, y) & EdgeDown) {
461                 GRID(x, y) &= ~EdgeDown;
462                 ++y;
463             }
464             Q_ASSERT(y <= h);
465             path->lineTo(x + x0, y + y0);
466             continue;
467         }
468         if (GRID(x, y) & EdgeLeft) {
469             while (GRID(x, y) & EdgeLeft) {
470                 GRID(x, y) &= ~EdgeLeft;
471                 --x;
472             }
473             Q_ASSERT(x >= 0);
474             path->lineTo(x + x0, y + y0);
475             continue;
476         }
477         if (GRID(x, y) & EdgeUp) {
478             while (GRID(x, y) & EdgeUp) {
479                 GRID(x, y) &= ~EdgeUp;
480                 --y;
481             }
482             Q_ASSERT(y >= 0);
483             path->lineTo(x + x0, y + y0);
484             continue;
485         }
486     }
487     path->closeSubpath();
488 }
489
490 Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data, int bpl, int w, int h, QPainterPath *path)
491 {
492     uint *grid = new uint[(w+1)*(h+1)];
493     // set up edges
494     for (int y = 0; y <= h; ++y) {
495         for (int x = 0; x <= w; ++x) {
496             bool topLeft = (x == 0)|(y == 0) ? false : SET(x - 1, y - 1);
497             bool topRight = (x == w)|(y == 0) ? false : SET(x, y - 1);
498             bool bottomLeft = (x == 0)|(y == h) ? false : SET(x - 1, y);
499             bool bottomRight = (x == w)|(y == h) ? false : SET(x, y);
500
501             GRID(x, y) = 0;
502             if ((!topRight) & bottomRight)
503                 GRID(x, y) |= EdgeRight;
504             if ((!bottomRight) & bottomLeft)
505                 GRID(x, y) |= EdgeDown;
506             if ((!bottomLeft) & topLeft)
507                 GRID(x, y) |= EdgeLeft;
508             if ((!topLeft) & topRight)
509                 GRID(x, y) |= EdgeUp;
510         }
511     }
512
513     // collect edges
514     for (int y = 0; y < h; ++y) {
515         for (int x = 0; x < w; ++x) {
516             if (!GRID(x, y))
517                 continue;
518             // found start of a contour, follow it
519             collectSingleContour(x0, y0, grid, x, y, w, h, path);
520         }
521     }
522     delete [] grid;
523 }
524
525 #undef GRID
526 #undef SET
527
528
529 void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
530                                       QPainterPath *path, QTextItem::RenderFlags flags)
531 {
532 // TODO what to do with 'flags' ??
533     Q_UNUSED(flags);
534     QFixed advanceX = QFixed::fromReal(x);
535     QFixed advanceY = QFixed::fromReal(y);
536     for (int i=0; i < glyphs.numGlyphs; ++i) {
537         glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]);
538         if (metrics.width.value() == 0 || metrics.height.value() == 0) {
539             advanceX += glyphs.advances_x[i];
540             advanceY += glyphs.advances_y[i];
541             continue;
542         }
543         const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);
544
545         const int w = alphaMask.width();
546         const int h = alphaMask.height();
547         const int srcBpl = alphaMask.bytesPerLine();
548         QImage bitmap;
549         if (alphaMask.depth() == 1) {
550             bitmap = alphaMask;
551         } else {
552             bitmap = QImage(w, h, QImage::Format_Mono);
553             const uchar *imageData = alphaMask.bits();
554             const int destBpl = bitmap.bytesPerLine();
555             uchar *bitmapData = bitmap.bits();
556
557             for (int yi = 0; yi < h; ++yi) {
558                 const uchar *src = imageData + yi*srcBpl;
559                 uchar *dst = bitmapData + yi*destBpl;
560                 for (int xi = 0; xi < w; ++xi) {
561                     const int byte = xi / 8;
562                     const int bit = xi % 8;
563                     if (bit == 0)
564                         dst[byte] = 0;
565                     if (src[xi])
566                         dst[byte] |= 128 >> bit;
567                 }
568             }
569         }
570         const uchar *bitmap_data = bitmap.bits();
571         QFixedPoint offset = glyphs.offsets[i];
572         advanceX += offset.x;
573         advanceY += offset.y;
574         qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);
575         advanceX += glyphs.advances_x[i];
576         advanceY += glyphs.advances_y[i];
577     }
578 }
579
580 void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
581                                   QPainterPath *path, QTextItem::RenderFlags flags)
582 {
583     qreal x = positions[0].x.toReal();
584     qreal y = positions[0].y.toReal();
585     QVarLengthGlyphLayoutArray g(nGlyphs);
586
587     for (int i = 0; i < nGlyphs; ++i) {
588         g.glyphs[i] = glyphs[i];
589         if (i < nGlyphs - 1) {
590             g.advances_x[i] = positions[i+1].x - positions[i].x;
591             g.advances_y[i] = positions[i+1].y - positions[i].y;
592         } else {
593             g.advances_x[i] = QFixed::fromReal(maxCharWidth());
594             g.advances_y[i] = 0;
595         }
596     }
597
598     addBitmapFontToPath(x, y, g, path, flags);
599 }
600
601 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)
602 {
603     // For font engines don't support subpixel positioning
604     return alphaMapForGlyph(glyph);
605 }
606
607 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
608 {
609     QImage i = alphaMapForGlyph(glyph);
610     if (t.type() > QTransform::TxTranslate)
611         i = i.transformed(t).convertToFormat(QImage::Format_Indexed8);
612     Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
613
614     return i;
615 }
616
617 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
618 {
619     if (! supportsSubPixelPositions())
620         return alphaMapForGlyph(glyph, t);
621
622     QImage i = alphaMapForGlyph(glyph, subPixelPosition);
623     if (t.type() > QTransform::TxTranslate)
624         i = i.transformed(t).convertToFormat(QImage::Format_Indexed8);
625     Q_ASSERT(i.depth() <= 8); // To verify that transformed didn't change the format...
626
627     return i;
628 }
629
630 QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)
631 {
632     QImage alphaMask = alphaMapForGlyph(glyph, t);
633     QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
634
635     QVector<QRgb> colorTable = alphaMask.colorTable();
636     for (int y=0; y<alphaMask.height(); ++y) {
637         uint *dst = (uint *) rgbMask.scanLine(y);
638         uchar *src = (uchar *) alphaMask.scanLine(y);
639         for (int x=0; x<alphaMask.width(); ++x) {
640             int val = qAlpha(colorTable.at(src[x]));
641             dst[x] = qRgb(val, val, val);
642         }
643     }
644
645     return rgbMask;
646 }
647
648 QFixed QFontEngine::subPixelPositionForX(QFixed x) const
649 {
650     if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
651         return QFixed();
652
653     QFixed subPixelPosition;
654     if (x != 0) {
655         subPixelPosition = x - x.floor();
656         QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
657
658         // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
659         // the lower boundary for the selected rasterization by adding 1/64.
660         subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
661     }
662     return subPixelPosition;
663 }
664
665 QImage *QFontEngine::lockedAlphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition,
666                                             QFontEngine::GlyphFormat neededFormat,
667                                             const QTransform &t, QPoint *offset)
668 {
669     Q_ASSERT(currentlyLockedAlphaMap.isNull());
670     if (neededFormat == Format_None)
671         neededFormat = Format_A32;
672
673     if (neededFormat != Format_A32)
674         currentlyLockedAlphaMap = alphaMapForGlyph(glyph, subPixelPosition, t);
675     else
676         currentlyLockedAlphaMap = alphaRGBMapForGlyph(glyph, subPixelPosition, t);
677
678     if (offset != 0)
679         *offset = QPoint(0, 0);
680
681     return &currentlyLockedAlphaMap;
682 }
683
684 void QFontEngine::unlockAlphaMapForGlyph()
685 {
686     Q_ASSERT(!currentlyLockedAlphaMap.isNull());
687     currentlyLockedAlphaMap = QImage();
688 }
689
690 QImage QFontEngine::alphaMapForGlyph(glyph_t glyph)
691 {
692     glyph_metrics_t gm = boundingBox(glyph);
693     int glyph_x = qFloor(gm.x.toReal());
694     int glyph_y = qFloor(gm.y.toReal());
695     int glyph_width = qCeil((gm.x + gm.width).toReal()) -  glyph_x;
696     int glyph_height = qCeil((gm.y + gm.height).toReal()) - glyph_y;
697
698     if (glyph_width <= 0 || glyph_height <= 0)
699         return QImage();
700     QFixedPoint pt;
701     pt.x = -glyph_x;
702     pt.y = -glyph_y; // the baseline
703     QPainterPath path;
704     QImage im(glyph_width + 4, glyph_height, QImage::Format_ARGB32_Premultiplied);
705     im.fill(Qt::transparent);
706     QPainter p(&im);
707     p.setRenderHint(QPainter::Antialiasing);
708     addGlyphsToPath(&glyph, &pt, 1, &path, 0);
709     p.setPen(Qt::NoPen);
710     p.setBrush(Qt::black);
711     p.drawPath(path);
712     p.end();
713
714     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
715     QVector<QRgb> colors(256);
716     for (int i=0; i<256; ++i)
717         colors[i] = qRgba(0, 0, 0, i);
718     indexed.setColorTable(colors);
719
720     for (int y=0; y<im.height(); ++y) {
721         uchar *dst = (uchar *) indexed.scanLine(y);
722         uint *src = (uint *) im.scanLine(y);
723         for (int x=0; x<im.width(); ++x)
724             dst[x] = qAlpha(src[x]);
725     }
726
727     return indexed;
728 }
729
730 void QFontEngine::removeGlyphFromCache(glyph_t)
731 {
732 }
733
734 QFontEngine::Properties QFontEngine::properties() const
735 {
736     Properties p;
737     QByteArray psname = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8());
738     psname += '-';
739     psname += QByteArray::number(fontDef.style);
740     psname += '-';
741     psname += QByteArray::number(fontDef.weight);
742
743     p.postscriptName = psname;
744     p.ascent = ascent();
745     p.descent = descent();
746     p.leading = leading();
747     p.emSquare = p.ascent;
748     p.boundingBox = QRectF(0, -p.ascent.toReal(), maxCharWidth(), (p.ascent + p.descent).toReal());
749     p.italicAngle = 0;
750     p.capHeight = p.ascent;
751     p.lineWidth = lineThickness();
752     return p;
753 }
754
755 void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
756 {
757     *metrics = boundingBox(glyph);
758     QFixedPoint p;
759     p.x = 0;
760     p.y = 0;
761     addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
762 }
763
764 QByteArray QFontEngine::getSfntTable(uint tag) const
765 {
766     QByteArray table;
767     uint len = 0;
768     if (!getSfntTableData(tag, 0, &len))
769         return table;
770     if (!len)
771         return table;
772     table.resize(len);
773     if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
774         return QByteArray();
775     return table;
776 }
777
778 void QFontEngine::setGlyphCache(void *key, QFontEngineGlyphCache *data)
779 {
780     Q_ASSERT(data);
781
782     GlyphCacheEntry entry;
783     entry.context = key;
784     entry.cache = data;
785     if (m_glyphCaches.contains(entry))
786         return;
787
788     // Limit the glyph caches to 4. This covers all 90 degree rotations and limits
789     // memory use when there is continuous or random rotation
790     if (m_glyphCaches.size() == 4)
791         m_glyphCaches.removeLast();
792
793     m_glyphCaches.push_front(entry);
794
795 }
796
797 QFontEngineGlyphCache *QFontEngine::glyphCache(void *key, QFontEngineGlyphCache::Type type, const QTransform &transform) const
798 {
799     for (QLinkedList<GlyphCacheEntry>::const_iterator it = m_glyphCaches.constBegin(), end = m_glyphCaches.constEnd(); it != end; ++it) {
800         QFontEngineGlyphCache *c = it->cache.data();
801         if (key == it->context
802             && type == c->cacheType()
803             && qtransform_equals_no_translate(c->m_transform, transform)) {
804             return c;
805         }
806     }
807     return 0;
808 }
809
810 static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)
811 {
812     uint left_right = (left << 16) + right;
813
814     left = 0, right = numPairs - 1;
815     while (left <= right) {
816         int middle = left + ( ( right - left ) >> 1 );
817
818         if(pairs[middle].left_right == left_right)
819             return pairs[middle].adjust;
820
821         if (pairs[middle].left_right < left_right)
822             left = middle + 1;
823         else
824             right = middle - 1;
825     }
826     return 0;
827 }
828
829 void QFontEngine::doKerning(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
830 {
831     int numPairs = kerning_pairs.size();
832     if(!numPairs)
833         return;
834
835     const KernPair *pairs = kerning_pairs.constData();
836
837     if(flags & QTextEngine::DesignMetrics) {
838         for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
839             glyphs->advances_x[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
840     } else {
841         for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
842             glyphs->advances_x[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
843     }
844 }
845
846 void QFontEngine::loadKerningPairs(QFixed scalingFactor)
847 {
848     kerning_pairs.clear();
849
850     QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
851     if (tab.isEmpty())
852         return;
853
854     const uchar *table = reinterpret_cast<const uchar *>(tab.constData());
855
856     unsigned short version = qFromBigEndian<quint16>(table);
857     if (version != 0) {
858 //        qDebug("wrong version");
859        return;
860     }
861
862     unsigned short numTables = qFromBigEndian<quint16>(table + 2);
863     {
864         int offset = 4;
865         for(int i = 0; i < numTables; ++i) {
866             if (offset + 6 > tab.size()) {
867 //                qDebug("offset out of bounds");
868                 goto end;
869             }
870             const uchar *header = table + offset;
871
872             ushort version = qFromBigEndian<quint16>(header);
873             ushort length = qFromBigEndian<quint16>(header+2);
874             ushort coverage = qFromBigEndian<quint16>(header+4);
875 //            qDebug("subtable: version=%d, coverage=%x",version, coverage);
876             if(version == 0 && coverage == 0x0001) {
877                 if (offset + length > tab.size()) {
878 //                    qDebug("length ouf ot bounds");
879                     goto end;
880                 }
881                 const uchar *data = table + offset + 6;
882
883                 ushort nPairs = qFromBigEndian<quint16>(data);
884                 if(nPairs * 6 + 8 > length - 6) {
885 //                    qDebug("corrupt table!");
886                     // corrupt table
887                     goto end;
888                 }
889
890                 int off = 8;
891                 for(int i = 0; i < nPairs; ++i) {
892                     QFontEngine::KernPair p;
893                     p.left_right = (((uint)qFromBigEndian<quint16>(data+off)) << 16) + qFromBigEndian<quint16>(data+off+2);
894                     p.adjust = QFixed(((int)(short)qFromBigEndian<quint16>(data+off+4))) / scalingFactor;
895                     kerning_pairs.append(p);
896                     off += 6;
897                 }
898             }
899             offset += length;
900         }
901     }
902 end:
903     qSort(kerning_pairs);
904 //    for (int i = 0; i < kerning_pairs.count(); ++i)
905 //        qDebug() << 'i' << i << "left_right" << hex << kerning_pairs.at(i).left_right;
906 }
907
908
909 int QFontEngine::glyphCount() const
910 {
911     QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
912     if (maxpTable.size() < 6)
913         return 0;
914     return qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(maxpTable.constData() + 4));
915 }
916
917 const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
918 {
919     const uchar *header = table;
920     if (tableSize < 4)
921         return 0;
922
923     const uchar *endPtr = table + tableSize;
924
925     // version check
926     if (qFromBigEndian<quint16>(header) != 0)
927         return 0;
928
929     unsigned short numTables = qFromBigEndian<quint16>(header + 2);
930     const uchar *maps = table + 4;
931     if (maps + 8 * numTables > endPtr)
932         return 0;
933
934     enum {
935         Invalid,
936         AppleRoman,
937         Symbol,
938         Unicode11,
939         Unicode,
940         MicrosoftUnicode,
941         MicrosoftUnicodeExtended
942     };
943
944     int symbolTable = -1;
945     int tableToUse = -1;
946     int score = Invalid;
947     for (int n = 0; n < numTables; ++n) {
948         const quint16 platformId = qFromBigEndian<quint16>(maps + 8 * n);
949         const quint16 platformSpecificId = qFromBigEndian<quint16>(maps + 8 * n + 2);
950         switch (platformId) {
951         case 0: // Unicode
952             if (score < Unicode &&
953                 (platformSpecificId == 0 ||
954                  platformSpecificId == 2 ||
955                  platformSpecificId == 3)) {
956                 tableToUse = n;
957                 score = Unicode;
958             } else if (score < Unicode11 && platformSpecificId == 1) {
959                 tableToUse = n;
960                 score = Unicode11;
961             }
962             break;
963         case 1: // Apple
964             if (score < AppleRoman && platformSpecificId == 0) { // Apple Roman
965                 tableToUse = n;
966                 score = AppleRoman;
967             }
968             break;
969         case 3: // Microsoft
970             switch (platformSpecificId) {
971             case 0:
972                 symbolTable = n;
973                 if (score < Symbol) {
974                     tableToUse = n;
975                     score = Symbol;
976                 }
977                 break;
978             case 1:
979                 if (score < MicrosoftUnicode) {
980                     tableToUse = n;
981                     score = MicrosoftUnicode;
982                 }
983                 break;
984             case 0xa:
985                 if (score < MicrosoftUnicodeExtended) {
986                     tableToUse = n;
987                     score = MicrosoftUnicodeExtended;
988                 }
989                 break;
990             default:
991                 break;
992             }
993         default:
994             break;
995         }
996     }
997     if(tableToUse < 0)
998         return 0;
999
1000 resolveTable:
1001     *isSymbolFont = (symbolTable > -1);
1002
1003     unsigned int unicode_table = qFromBigEndian<quint32>(maps + 8*tableToUse + 4);
1004
1005     if (!unicode_table || unicode_table + 8 > tableSize)
1006         return 0;
1007
1008     // get the header of the unicode table
1009     header = table + unicode_table;
1010
1011     unsigned short format = qFromBigEndian<quint16>(header);
1012     unsigned int length;
1013     if(format < 8)
1014         length = qFromBigEndian<quint16>(header + 2);
1015     else
1016         length = qFromBigEndian<quint32>(header + 4);
1017
1018     if (table + unicode_table + length > endPtr)
1019         return 0;
1020     *cmapSize = length;
1021
1022     // To support symbol fonts that contain a unicode table for the symbol area
1023     // we check the cmap tables and fall back to symbol font unless that would
1024     // involve losing information from the unicode table
1025     if (symbolTable > -1 && ((score == Unicode) || (score == Unicode11))) {
1026         const uchar *selectedTable = table + unicode_table;
1027
1028         // Check that none of the latin1 range are in the unicode table
1029         bool unicodeTableHasLatin1 = false;
1030         for (int uc=0x00; uc<0x100; ++uc) {
1031             if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
1032                 unicodeTableHasLatin1 = true;
1033                 break;
1034             }
1035         }
1036
1037         // Check that at least one symbol char is in the unicode table
1038         bool unicodeTableHasSymbols = false;
1039         if (!unicodeTableHasLatin1) {
1040             for (int uc=0xf000; uc<0xf100; ++uc) {
1041                 if (getTrueTypeGlyphIndex(selectedTable, uc) != 0) {
1042                     unicodeTableHasSymbols = true;
1043                     break;
1044                 }
1045             }
1046         }
1047
1048         // Fall back to symbol table
1049         if (!unicodeTableHasLatin1 && unicodeTableHasSymbols) {
1050             tableToUse = symbolTable;
1051             score = Symbol;
1052             goto resolveTable;
1053         }
1054     }
1055
1056     return table + unicode_table;
1057 }
1058
1059 quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
1060 {
1061     unsigned short format = qFromBigEndian<quint16>(cmap);
1062     if (format == 0) {
1063         if (unicode < 256)
1064             return (int) *(cmap+6+unicode);
1065     } else if (format == 4) {
1066         /* some fonts come with invalid cmap tables, where the last segment
1067            specified end = start = rangeoffset = 0xffff, delta = 0x0001
1068            Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue
1069            by returning 0 for 0xffff
1070         */
1071         if(unicode >= 0xffff)
1072             return 0;
1073         quint16 segCountX2 = qFromBigEndian<quint16>(cmap + 6);
1074         const unsigned char *ends = cmap + 14;
1075         int i = 0;
1076         for (; i < segCountX2/2 && qFromBigEndian<quint16>(ends + 2*i) < unicode; i++) {}
1077
1078         const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
1079         quint16 startIndex = qFromBigEndian<quint16>(idx);
1080
1081         if (startIndex > unicode)
1082             return 0;
1083
1084         idx += segCountX2;
1085         qint16 idDelta = (qint16)qFromBigEndian<quint16>(idx);
1086         idx += segCountX2;
1087         quint16 idRangeoffset_t = (quint16)qFromBigEndian<quint16>(idx);
1088
1089         quint16 glyphIndex;
1090         if (idRangeoffset_t) {
1091             quint16 id = qFromBigEndian<quint16>(idRangeoffset_t + 2*(unicode - startIndex) + idx);
1092             if (id)
1093                 glyphIndex = (idDelta + id) % 0x10000;
1094             else
1095                 glyphIndex = 0;
1096         } else {
1097             glyphIndex = (idDelta + unicode) % 0x10000;
1098         }
1099         return glyphIndex;
1100     } else if (format == 6) {
1101         quint16 tableSize = qFromBigEndian<quint16>(cmap + 2);
1102
1103         quint16 firstCode6 = qFromBigEndian<quint16>(cmap + 6);
1104         if (unicode < firstCode6)
1105             return 0;
1106
1107         quint16 entryCount6 = qFromBigEndian<quint16>(cmap + 8);
1108         if (entryCount6 * 2 + 10 > tableSize)
1109             return 0;
1110
1111         quint16 sentinel6 = firstCode6 + entryCount6;
1112         if (unicode >= sentinel6)
1113             return 0;
1114
1115         quint16 entryIndex6 = unicode - firstCode6;
1116         return qFromBigEndian<quint16>(cmap + 10 + (entryIndex6 * 2));
1117     } else if (format == 12) {
1118         quint32 nGroups = qFromBigEndian<quint32>(cmap + 12);
1119
1120         cmap += 16; // move to start of groups
1121
1122         int left = 0, right = nGroups - 1;
1123         while (left <= right) {
1124             int middle = left + ( ( right - left ) >> 1 );
1125
1126             quint32 startCharCode = qFromBigEndian<quint32>(cmap + 12*middle);
1127             if(unicode < startCharCode)
1128                 right = middle - 1;
1129             else {
1130                 quint32 endCharCode = qFromBigEndian<quint32>(cmap + 12*middle + 4);
1131                 if(unicode <= endCharCode)
1132                     return qFromBigEndian<quint32>(cmap + 12*middle + 8) + unicode - startCharCode;
1133                 left = middle + 1;
1134             }
1135         }
1136     } else {
1137         qDebug("cmap table of format %d not implemented", format);
1138     }
1139
1140     return 0;
1141 }
1142
1143 QByteArray QFontEngine::convertToPostscriptFontFamilyName(const QByteArray &family)
1144 {
1145     QByteArray f = family;
1146     f.replace(' ', "");
1147     f.replace('(', "");
1148     f.replace(')', "");
1149     f.replace('<', "");
1150     f.replace('>', "");
1151     f.replace('[', "");
1152     f.replace(']', "");
1153     f.replace('{', "");
1154     f.replace('}', "");
1155     f.replace('/', "");
1156     f.replace('%', "");
1157     return f;
1158 }
1159
1160 QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
1161 {
1162     if (glyphs.numGlyphs >= 1) {
1163         glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
1164         glyph_metrics_t gi = boundingBox(glyph);
1165         if (gi.isValid())
1166             return round ? QFixed(qRound(gi.xoff - gi.x - gi.width))
1167                          : QFixed(gi.xoff - gi.x - gi.width);
1168     }
1169     return 0;
1170 }
1171
1172 // ------------------------------------------------------------------
1173 // The box font engine
1174 // ------------------------------------------------------------------
1175
1176 QFontEngineBox::QFontEngineBox(int size)
1177     : _size(size)
1178 {
1179     cache_cost = sizeof(QFontEngineBox);
1180 }
1181
1182 QFontEngineBox::~QFontEngineBox()
1183 {
1184 }
1185
1186 bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
1187 {
1188     if (*nglyphs < len) {
1189         *nglyphs = len;
1190         return false;
1191     }
1192
1193     for (int i = 0; i < len; i++) {
1194         glyphs->glyphs[i] = 0;
1195         if (!(flags & QTextEngine::GlyphIndicesOnly)) {
1196             glyphs->advances_x[i] = _size;
1197             glyphs->advances_y[i] = 0;
1198         }
1199     }
1200
1201     *nglyphs = len;
1202     glyphs->numGlyphs = len;
1203     return true;
1204 }
1205
1206 void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags) const
1207 {
1208     for (int i = 0; i < glyphs->numGlyphs; i++) {
1209         glyphs->advances_x[i] = _size;
1210         glyphs->advances_y[i] = 0;
1211     }
1212 }
1213
1214 void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
1215 {
1216     if (!glyphs.numGlyphs)
1217         return;
1218
1219     QVarLengthArray<QFixedPoint> positions;
1220     QVarLengthArray<glyph_t> positioned_glyphs;
1221     QTransform matrix = QTransform::fromTranslate(x, y - _size);
1222     getGlyphPositions(glyphs, matrix, flags, positioned_glyphs, positions);
1223
1224     QSize s(_size - 3, _size - 3);
1225     for (int k = 0; k < positions.size(); k++)
1226         path->addRect(QRectF(positions[k].toPointF(), s));
1227 }
1228
1229 glyph_metrics_t QFontEngineBox::boundingBox(const QGlyphLayout &glyphs)
1230 {
1231     glyph_metrics_t overall;
1232     overall.width = _size*glyphs.numGlyphs;
1233     overall.height = _size;
1234     overall.xoff = overall.width;
1235     return overall;
1236 }
1237
1238 void QFontEngineBox::draw(QPaintEngine *p, qreal x, qreal y, const QTextItemInt &ti)
1239 {
1240     if (!ti.glyphs.numGlyphs)
1241         return;
1242
1243     // any fixes here should probably also be done in QPaintEnginePrivate::drawBoxTextItem
1244     QSize s(_size - 3, _size - 3);
1245
1246     QVarLengthArray<QFixedPoint> positions;
1247     QVarLengthArray<glyph_t> glyphs;
1248     QTransform matrix = QTransform::fromTranslate(x, y - _size);
1249     ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1250     if (glyphs.size() == 0)
1251         return;
1252
1253
1254     QPainter *painter = p->painter();
1255     painter->save();
1256     painter->setBrush(Qt::NoBrush);
1257     QPen pen = painter->pen();
1258     pen.setWidthF(lineThickness().toReal());
1259     painter->setPen(pen);
1260     for (int k = 0; k < positions.size(); k++)
1261         painter->drawRect(QRectF(positions[k].toPointF(), s));
1262     painter->restore();
1263 }
1264
1265 glyph_metrics_t QFontEngineBox::boundingBox(glyph_t)
1266 {
1267     return glyph_metrics_t(0, -_size, _size, _size, _size, 0);
1268 }
1269
1270 QFontEngine *QFontEngineBox::cloneWithSize(qreal pixelSize) const
1271 {
1272     QFontEngineBox *fe = new QFontEngineBox(pixelSize);
1273     return fe;
1274 }
1275
1276 QFixed QFontEngineBox::ascent() const
1277 {
1278     return _size;
1279 }
1280
1281 QFixed QFontEngineBox::descent() const
1282 {
1283     return 0;
1284 }
1285
1286 QFixed QFontEngineBox::leading() const
1287 {
1288     QFixed l = _size * QFixed::fromReal(qreal(0.15));
1289     return l.ceil();
1290 }
1291
1292 qreal QFontEngineBox::maxCharWidth() const
1293 {
1294     return _size;
1295 }
1296
1297
1298 const char *QFontEngineBox::name() const
1299 {
1300     return "null";
1301 }
1302
1303 bool QFontEngineBox::canRender(const QChar *, int)
1304 {
1305     return true;
1306 }
1307
1308 QFontEngine::Type QFontEngineBox::type() const
1309 {
1310     return Box;
1311 }
1312
1313 QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
1314 {
1315     QImage image(_size, _size, QImage::Format_Indexed8);
1316     QVector<QRgb> colors(256);
1317     for (int i=0; i<256; ++i)
1318         colors[i] = qRgba(0, 0, 0, i);
1319     image.setColorTable(colors);
1320     image.fill(0);
1321
1322     // can't use qpainter for index8; so use setPixel to draw our rectangle.
1323     for (int i=2; i <= _size-3; ++i) {
1324         image.setPixel(i, 2, 255);
1325         image.setPixel(i, _size-3, 255);
1326         image.setPixel(2, i, 255);
1327         image.setPixel(_size-3, i, 255);
1328     }
1329     return image;
1330 }
1331
1332 // ------------------------------------------------------------------
1333 // Multi engine
1334 // ------------------------------------------------------------------
1335
1336 static inline uchar highByte(glyph_t glyph)
1337 { return glyph >> 24; }
1338
1339 // strip high byte from glyph
1340 static inline glyph_t stripped(glyph_t glyph)
1341 { return glyph & 0x00ffffff; }
1342
1343 QFontEngineMulti::QFontEngineMulti(int engineCount)
1344 {
1345     engines.fill(0, engineCount);
1346     cache_cost = 0;
1347 }
1348
1349 QFontEngineMulti::~QFontEngineMulti()
1350 {
1351     for (int i = 0; i < engines.size(); ++i) {
1352         QFontEngine *fontEngine = engines.at(i);
1353         if (fontEngine) {
1354             fontEngine->ref.deref();
1355             if (fontEngine->cache_count == 0 && fontEngine->ref.load() == 0)
1356                 delete fontEngine;
1357         }
1358     }
1359 }
1360
1361 bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
1362                                     QGlyphLayout *glyphs, int *nglyphs,
1363                                     QTextEngine::ShaperFlags flags) const
1364 {
1365     int ng = *nglyphs;
1366     if (!engine(0)->stringToCMap(str, len, glyphs, &ng, flags))
1367         return false;
1368
1369     int glyph_pos = 0;
1370     for (int i = 0; i < len; ++i) {
1371         bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate());
1372         uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode();
1373         if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
1374             QGlyphLayoutInstance tmp = glyphs->instance(glyph_pos);
1375             for (int x=1; x < engines.size(); ++x) {
1376                 if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4))
1377                     continue;
1378
1379                 QFontEngine *engine = engines.at(x);
1380                 if (!engine) {
1381                     const_cast<QFontEngineMulti *>(this)->loadEngine(x);
1382                     engine = engines.at(x);
1383                 }
1384                 Q_ASSERT(engine != 0);
1385                 if (engine->type() == Box)
1386                     continue;
1387
1388                 glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0;
1389                 glyphs->offsets[glyph_pos] = QFixedPoint();
1390                 int num = 2;
1391                 QGlyphLayout offs = glyphs->mid(glyph_pos, num);
1392                 engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags);
1393                 Q_ASSERT(num == 1); // surrogates only give 1 glyph
1394                 if (glyphs->glyphs[glyph_pos]) {
1395                     // set the high byte to indicate which engine the glyph came from
1396                     glyphs->glyphs[glyph_pos] |= (x << 24);
1397                     break;
1398                 }
1399             }
1400
1401             // ensure we use metrics from the 1st font when we use the fallback image.
1402             if (!glyphs->glyphs[glyph_pos]) {
1403                 glyphs->setInstance(glyph_pos, tmp);
1404             }
1405         }
1406
1407         if (surrogate)
1408             ++i;
1409         ++glyph_pos;
1410     }
1411
1412     *nglyphs = ng;
1413     glyphs->numGlyphs = ng;
1414     return true;
1415 }
1416
1417 bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
1418 {
1419     Q_UNUSED(at);
1420     Q_UNUSED(ucs4);
1421     return true;
1422 }
1423
1424 void QFontEngineMulti::unloadEngine(int at)
1425 {
1426     QFontEngine *fontEngine = engines.at(at);
1427     if (fontEngine == 0)
1428         return;
1429
1430     // If there are other references to the engine, keep it around and keep the reference
1431     if (fontEngine->ref.load() == 1) {
1432         QFontCache::instance()->removeEngine(fontEngine);
1433         if (fontEngine->cache_count == 0) {
1434             delete fontEngine;
1435             engines[at] = 0;
1436         }
1437     }
1438 }
1439
1440 glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
1441 {
1442     if (glyphs.numGlyphs <= 0)
1443         return glyph_metrics_t();
1444
1445     glyph_metrics_t overall;
1446
1447     int which = highByte(glyphs.glyphs[0]);
1448     int start = 0;
1449     int end, i;
1450     for (end = 0; end < glyphs.numGlyphs; ++end) {
1451         const int e = highByte(glyphs.glyphs[end]);
1452         if (e == which)
1453             continue;
1454
1455         // set the high byte to zero
1456         for (i = start; i < end; ++i)
1457             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1458
1459         // merge the bounding box for this run
1460         const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1461
1462         overall.x = qMin(overall.x, gm.x);
1463         overall.y = qMin(overall.y, gm.y);
1464         overall.width = overall.xoff + gm.width;
1465         overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1466                          qMin(overall.y, gm.y);
1467         overall.xoff += gm.xoff;
1468         overall.yoff += gm.yoff;
1469
1470         // reset the high byte for all glyphs
1471         const int hi = which << 24;
1472         for (i = start; i < end; ++i)
1473             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1474
1475         // change engine
1476         start = end;
1477         which = e;
1478     }
1479
1480     // set the high byte to zero
1481     for (i = start; i < end; ++i)
1482         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1483
1484     // merge the bounding box for this run
1485     const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1486
1487     overall.x = qMin(overall.x, gm.x);
1488     overall.y = qMin(overall.y, gm.y);
1489     overall.width = overall.xoff + gm.width;
1490     overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1491                      qMin(overall.y, gm.y);
1492     overall.xoff += gm.xoff;
1493     overall.yoff += gm.yoff;
1494
1495     // reset the high byte for all glyphs
1496     const int hi = which << 24;
1497     for (i = start; i < end; ++i)
1498         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1499
1500     return overall;
1501 }
1502
1503 void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
1504 {
1505     int which = highByte(glyph);
1506     engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
1507 }
1508
1509 void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
1510                                         QPainterPath *path, QTextItem::RenderFlags flags)
1511 {
1512     if (glyphs.numGlyphs <= 0)
1513         return;
1514
1515     int which = highByte(glyphs.glyphs[0]);
1516     int start = 0;
1517     int end, i;
1518     if (flags & QTextItem::RightToLeft) {
1519         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1520             x += glyphs.advances_x[gl].toReal();
1521             y += glyphs.advances_y[gl].toReal();
1522         }
1523     }
1524     for (end = 0; end < glyphs.numGlyphs; ++end) {
1525         const int e = highByte(glyphs.glyphs[end]);
1526         if (e == which)
1527             continue;
1528
1529         if (flags & QTextItem::RightToLeft) {
1530             for (i = start; i < end; ++i) {
1531                 x -= glyphs.advances_x[i].toReal();
1532                 y -= glyphs.advances_y[i].toReal();
1533             }
1534         }
1535
1536         // set the high byte to zero
1537         for (i = start; i < end; ++i)
1538             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1539         engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
1540         // reset the high byte for all glyphs and update x and y
1541         const int hi = which << 24;
1542         for (i = start; i < end; ++i)
1543             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1544
1545         if (!(flags & QTextItem::RightToLeft)) {
1546             for (i = start; i < end; ++i) {
1547                 x += glyphs.advances_x[i].toReal();
1548                 y += glyphs.advances_y[i].toReal();
1549             }
1550         }
1551
1552         // change engine
1553         start = end;
1554         which = e;
1555     }
1556
1557     if (flags & QTextItem::RightToLeft) {
1558         for (i = start; i < end; ++i) {
1559             x -= glyphs.advances_x[i].toReal();
1560             y -= glyphs.advances_y[i].toReal();
1561         }
1562     }
1563
1564     // set the high byte to zero
1565     for (i = start; i < end; ++i)
1566         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1567
1568     engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
1569
1570     // reset the high byte for all glyphs
1571     const int hi = which << 24;
1572     for (i = start; i < end; ++i)
1573         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1574 }
1575
1576 void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1577 {
1578     if (glyphs->numGlyphs <= 0)
1579         return;
1580
1581     int which = highByte(glyphs->glyphs[0]);
1582     int start = 0;
1583     int end, i;
1584     for (end = 0; end < glyphs->numGlyphs; ++end) {
1585         const int e = highByte(glyphs->glyphs[end]);
1586         if (e == which)
1587             continue;
1588
1589         // set the high byte to zero
1590         for (i = start; i < end; ++i)
1591             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1592
1593         QGlyphLayout offs = glyphs->mid(start, end - start);
1594         engine(which)->recalcAdvances(&offs, flags);
1595
1596         // reset the high byte for all glyphs and update x and y
1597         const int hi = which << 24;
1598         for (i = start; i < end; ++i)
1599             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1600
1601         // change engine
1602         start = end;
1603         which = e;
1604     }
1605
1606     // set the high byte to zero
1607     for (i = start; i < end; ++i)
1608         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1609
1610     QGlyphLayout offs = glyphs->mid(start, end - start);
1611     engine(which)->recalcAdvances(&offs, flags);
1612
1613     // reset the high byte for all glyphs
1614     const int hi = which << 24;
1615     for (i = start; i < end; ++i)
1616         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1617 }
1618
1619 void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1620 {
1621     if (glyphs->numGlyphs <= 0)
1622         return;
1623
1624     int which = highByte(glyphs->glyphs[0]);
1625     int start = 0;
1626     int end, i;
1627     for (end = 0; end < glyphs->numGlyphs; ++end) {
1628         const int e = highByte(glyphs->glyphs[end]);
1629         if (e == which)
1630             continue;
1631
1632         // set the high byte to zero
1633         for (i = start; i < end; ++i)
1634             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1635
1636         QGlyphLayout offs = glyphs->mid(start, end - start);
1637         engine(which)->doKerning(&offs, flags);
1638
1639         // reset the high byte for all glyphs and update x and y
1640         const int hi = which << 24;
1641         for (i = start; i < end; ++i)
1642             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1643
1644         // change engine
1645         start = end;
1646         which = e;
1647     }
1648
1649     // set the high byte to zero
1650     for (i = start; i < end; ++i)
1651         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1652
1653     QGlyphLayout offs = glyphs->mid(start, end - start);
1654     engine(which)->doKerning(&offs, flags);
1655
1656     // reset the high byte for all glyphs
1657     const int hi = which << 24;
1658     for (i = start; i < end; ++i)
1659         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1660 }
1661
1662 glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)
1663 {
1664     const int which = highByte(glyph);
1665     Q_ASSERT(which < engines.size());
1666     return engine(which)->boundingBox(stripped(glyph));
1667 }
1668
1669 QFixed QFontEngineMulti::ascent() const
1670 { return engine(0)->ascent(); }
1671
1672 QFixed QFontEngineMulti::descent() const
1673 { return engine(0)->descent(); }
1674
1675 QFixed QFontEngineMulti::leading() const
1676 {
1677     return engine(0)->leading();
1678 }
1679
1680 QFixed QFontEngineMulti::xHeight() const
1681 {
1682     return engine(0)->xHeight();
1683 }
1684
1685 QFixed QFontEngineMulti::averageCharWidth() const
1686 {
1687     return engine(0)->averageCharWidth();
1688 }
1689
1690 QFixed QFontEngineMulti::lineThickness() const
1691 {
1692     return engine(0)->lineThickness();
1693 }
1694
1695 QFixed QFontEngineMulti::underlinePosition() const
1696 {
1697     return engine(0)->underlinePosition();
1698 }
1699
1700 qreal QFontEngineMulti::maxCharWidth() const
1701 {
1702     return engine(0)->maxCharWidth();
1703 }
1704
1705 qreal QFontEngineMulti::minLeftBearing() const
1706 {
1707     return engine(0)->minLeftBearing();
1708 }
1709
1710 qreal QFontEngineMulti::minRightBearing() const
1711 {
1712     return engine(0)->minRightBearing();
1713 }
1714
1715 bool QFontEngineMulti::canRender(const QChar *string, int len)
1716 {
1717     if (engine(0)->canRender(string, len))
1718         return true;
1719
1720     QVarLengthGlyphLayoutArray glyphs(len);
1721     int nglyphs = len;
1722     if (stringToCMap(string, len, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly) == false) {
1723         glyphs.resize(nglyphs);
1724         stringToCMap(string, len, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly);
1725     }
1726
1727     bool allExist = true;
1728     for (int i = 0; i < nglyphs; i++) {
1729         if (!glyphs.glyphs[i]) {
1730             allExist = false;
1731             break;
1732         }
1733     }
1734
1735     return allExist;
1736 }
1737
1738 /* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.
1739  * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
1740
1741 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
1742 {
1743     const int which = highByte(glyph);
1744     Q_ASSERT(which < engines.size());
1745     return engine(which)->alphaMapForGlyph(stripped(glyph));
1746 }
1747
1748 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
1749 {
1750     const int which = highByte(glyph);
1751     Q_ASSERT(which < engines.size());
1752     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
1753 }
1754
1755 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
1756 {
1757     const int which = highByte(glyph);
1758     Q_ASSERT(which < engines.size());
1759     return engine(which)->alphaMapForGlyph(stripped(glyph), t);
1760 }
1761
1762 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
1763 {
1764     const int which = highByte(glyph);
1765     Q_ASSERT(which < engines.size());
1766     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
1767 }
1768
1769 QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
1770 {
1771     const int which = highByte(glyph);
1772     Q_ASSERT(which < engines.size());
1773     return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
1774 }
1775
1776 QT_END_NAMESPACE