DirectWrite font engine: don't leak the font table buffer
[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(const 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(const 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     const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
1370     int glyph_pos = 0;
1371     for (int i = 0; i < len; ++i) {
1372         bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate());
1373         uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode();
1374         if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
1375             QGlyphLayoutInstance tmp = glyphs->instance(glyph_pos);
1376             for (int x=1; x < engines.size(); ++x) {
1377                 if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4))
1378                     continue;
1379
1380                 QFontEngine *engine = engines.at(x);
1381                 if (!engine) {
1382                     const_cast<QFontEngineMulti *>(this)->loadEngine(x);
1383                     engine = engines.at(x);
1384                 }
1385                 Q_ASSERT(engine != 0);
1386                 if (engine->type() == Box)
1387                     continue;
1388
1389                 glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0;
1390                 glyphs->offsets[glyph_pos] = QFixedPoint();
1391                 int num = 2;
1392                 QGlyphLayout offs = glyphs->mid(glyph_pos, num);
1393                 engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags);
1394                 Q_ASSERT(num == 1); // surrogates only give 1 glyph
1395                 if (glyphs->glyphs[glyph_pos]) {
1396                     // set the high byte to indicate which engine the glyph came from
1397                     glyphs->glyphs[glyph_pos] |= (x << 24);
1398                     break;
1399                 }
1400             }
1401
1402             // ensure we use metrics from the 1st font when we use the fallback image.
1403             if (!glyphs->glyphs[glyph_pos]) {
1404                 glyphs->setInstance(glyph_pos, tmp);
1405             }
1406         }
1407
1408         if (surrogate)
1409             ++i;
1410         ++glyph_pos;
1411     }
1412
1413     *nglyphs = ng;
1414     glyphs->numGlyphs = ng;
1415     return true;
1416 }
1417
1418 bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
1419 {
1420     Q_UNUSED(at);
1421     Q_UNUSED(ucs4);
1422     return true;
1423 }
1424
1425 glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
1426 {
1427     if (glyphs.numGlyphs <= 0)
1428         return glyph_metrics_t();
1429
1430     glyph_metrics_t overall;
1431
1432     int which = highByte(glyphs.glyphs[0]);
1433     int start = 0;
1434     int end, i;
1435     for (end = 0; end < glyphs.numGlyphs; ++end) {
1436         const int e = highByte(glyphs.glyphs[end]);
1437         if (e == which)
1438             continue;
1439
1440         // set the high byte to zero
1441         for (i = start; i < end; ++i)
1442             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1443
1444         // merge the bounding box for this run
1445         const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1446
1447         overall.x = qMin(overall.x, gm.x);
1448         overall.y = qMin(overall.y, gm.y);
1449         overall.width = overall.xoff + gm.width;
1450         overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1451                          qMin(overall.y, gm.y);
1452         overall.xoff += gm.xoff;
1453         overall.yoff += gm.yoff;
1454
1455         // reset the high byte for all glyphs
1456         const int hi = which << 24;
1457         for (i = start; i < end; ++i)
1458             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1459
1460         // change engine
1461         start = end;
1462         which = e;
1463     }
1464
1465     // set the high byte to zero
1466     for (i = start; i < end; ++i)
1467         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1468
1469     // merge the bounding box for this run
1470     const glyph_metrics_t gm = engine(which)->boundingBox(glyphs.mid(start, end - start));
1471
1472     overall.x = qMin(overall.x, gm.x);
1473     overall.y = qMin(overall.y, gm.y);
1474     overall.width = overall.xoff + gm.width;
1475     overall.height = qMax(overall.height + overall.y, gm.height + gm.y) -
1476                      qMin(overall.y, gm.y);
1477     overall.xoff += gm.xoff;
1478     overall.yoff += gm.yoff;
1479
1480     // reset the high byte for all glyphs
1481     const int hi = which << 24;
1482     for (i = start; i < end; ++i)
1483         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1484
1485     return overall;
1486 }
1487
1488 void QFontEngineMulti::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rightBearing)
1489 {
1490     int which = highByte(glyph);
1491     engine(which)->getGlyphBearings(stripped(glyph), leftBearing, rightBearing);
1492 }
1493
1494 void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs,
1495                                         QPainterPath *path, QTextItem::RenderFlags flags)
1496 {
1497     if (glyphs.numGlyphs <= 0)
1498         return;
1499
1500     int which = highByte(glyphs.glyphs[0]);
1501     int start = 0;
1502     int end, i;
1503     if (flags & QTextItem::RightToLeft) {
1504         for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
1505             x += glyphs.advances_x[gl].toReal();
1506             y += glyphs.advances_y[gl].toReal();
1507         }
1508     }
1509     for (end = 0; end < glyphs.numGlyphs; ++end) {
1510         const int e = highByte(glyphs.glyphs[end]);
1511         if (e == which)
1512             continue;
1513
1514         if (flags & QTextItem::RightToLeft) {
1515             for (i = start; i < end; ++i) {
1516                 x -= glyphs.advances_x[i].toReal();
1517                 y -= glyphs.advances_y[i].toReal();
1518             }
1519         }
1520
1521         // set the high byte to zero
1522         for (i = start; i < end; ++i)
1523             glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1524         engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
1525         // reset the high byte for all glyphs and update x and y
1526         const int hi = which << 24;
1527         for (i = start; i < end; ++i)
1528             glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1529
1530         if (!(flags & QTextItem::RightToLeft)) {
1531             for (i = start; i < end; ++i) {
1532                 x += glyphs.advances_x[i].toReal();
1533                 y += glyphs.advances_y[i].toReal();
1534             }
1535         }
1536
1537         // change engine
1538         start = end;
1539         which = e;
1540     }
1541
1542     if (flags & QTextItem::RightToLeft) {
1543         for (i = start; i < end; ++i) {
1544             x -= glyphs.advances_x[i].toReal();
1545             y -= glyphs.advances_y[i].toReal();
1546         }
1547     }
1548
1549     // set the high byte to zero
1550     for (i = start; i < end; ++i)
1551         glyphs.glyphs[i] = stripped(glyphs.glyphs[i]);
1552
1553     engine(which)->addOutlineToPath(x, y, glyphs.mid(start, end - start), path, flags);
1554
1555     // reset the high byte for all glyphs
1556     const int hi = which << 24;
1557     for (i = start; i < end; ++i)
1558         glyphs.glyphs[i] = hi | glyphs.glyphs[i];
1559 }
1560
1561 void QFontEngineMulti::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1562 {
1563     if (glyphs->numGlyphs <= 0)
1564         return;
1565
1566     int which = highByte(glyphs->glyphs[0]);
1567     int start = 0;
1568     int end, i;
1569     for (end = 0; end < glyphs->numGlyphs; ++end) {
1570         const int e = highByte(glyphs->glyphs[end]);
1571         if (e == which)
1572             continue;
1573
1574         // set the high byte to zero
1575         for (i = start; i < end; ++i)
1576             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1577
1578         QGlyphLayout offs = glyphs->mid(start, end - start);
1579         engine(which)->recalcAdvances(&offs, flags);
1580
1581         // reset the high byte for all glyphs and update x and y
1582         const int hi = which << 24;
1583         for (i = start; i < end; ++i)
1584             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1585
1586         // change engine
1587         start = end;
1588         which = e;
1589     }
1590
1591     // set the high byte to zero
1592     for (i = start; i < end; ++i)
1593         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1594
1595     QGlyphLayout offs = glyphs->mid(start, end - start);
1596     engine(which)->recalcAdvances(&offs, flags);
1597
1598     // reset the high byte for all glyphs
1599     const int hi = which << 24;
1600     for (i = start; i < end; ++i)
1601         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1602 }
1603
1604 void QFontEngineMulti::doKerning(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
1605 {
1606     if (glyphs->numGlyphs <= 0)
1607         return;
1608
1609     int which = highByte(glyphs->glyphs[0]);
1610     int start = 0;
1611     int end, i;
1612     for (end = 0; end < glyphs->numGlyphs; ++end) {
1613         const int e = highByte(glyphs->glyphs[end]);
1614         if (e == which)
1615             continue;
1616
1617         // set the high byte to zero
1618         for (i = start; i < end; ++i)
1619             glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1620
1621         QGlyphLayout offs = glyphs->mid(start, end - start);
1622         engine(which)->doKerning(&offs, flags);
1623
1624         // reset the high byte for all glyphs and update x and y
1625         const int hi = which << 24;
1626         for (i = start; i < end; ++i)
1627             glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1628
1629         // change engine
1630         start = end;
1631         which = e;
1632     }
1633
1634     // set the high byte to zero
1635     for (i = start; i < end; ++i)
1636         glyphs->glyphs[i] = stripped(glyphs->glyphs[i]);
1637
1638     QGlyphLayout offs = glyphs->mid(start, end - start);
1639     engine(which)->doKerning(&offs, flags);
1640
1641     // reset the high byte for all glyphs
1642     const int hi = which << 24;
1643     for (i = start; i < end; ++i)
1644         glyphs->glyphs[i] = hi | glyphs->glyphs[i];
1645 }
1646
1647 glyph_metrics_t QFontEngineMulti::boundingBox(glyph_t glyph)
1648 {
1649     const int which = highByte(glyph);
1650     Q_ASSERT(which < engines.size());
1651     return engine(which)->boundingBox(stripped(glyph));
1652 }
1653
1654 QFixed QFontEngineMulti::ascent() const
1655 { return engine(0)->ascent(); }
1656
1657 QFixed QFontEngineMulti::descent() const
1658 { return engine(0)->descent(); }
1659
1660 QFixed QFontEngineMulti::leading() const
1661 {
1662     return engine(0)->leading();
1663 }
1664
1665 QFixed QFontEngineMulti::xHeight() const
1666 {
1667     return engine(0)->xHeight();
1668 }
1669
1670 QFixed QFontEngineMulti::averageCharWidth() const
1671 {
1672     return engine(0)->averageCharWidth();
1673 }
1674
1675 QFixed QFontEngineMulti::lineThickness() const
1676 {
1677     return engine(0)->lineThickness();
1678 }
1679
1680 QFixed QFontEngineMulti::underlinePosition() const
1681 {
1682     return engine(0)->underlinePosition();
1683 }
1684
1685 qreal QFontEngineMulti::maxCharWidth() const
1686 {
1687     return engine(0)->maxCharWidth();
1688 }
1689
1690 qreal QFontEngineMulti::minLeftBearing() const
1691 {
1692     return engine(0)->minLeftBearing();
1693 }
1694
1695 qreal QFontEngineMulti::minRightBearing() const
1696 {
1697     return engine(0)->minRightBearing();
1698 }
1699
1700 bool QFontEngineMulti::canRender(const QChar *string, int len)
1701 {
1702     if (engine(0)->canRender(string, len))
1703         return true;
1704
1705     QVarLengthGlyphLayoutArray glyphs(len);
1706     int nglyphs = len;
1707     if (stringToCMap(string, len, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly) == false) {
1708         glyphs.resize(nglyphs);
1709         stringToCMap(string, len, &glyphs, &nglyphs, QTextEngine::GlyphIndicesOnly);
1710     }
1711
1712     bool allExist = true;
1713     for (int i = 0; i < nglyphs; i++) {
1714         if (!glyphs.glyphs[i]) {
1715             allExist = false;
1716             break;
1717         }
1718     }
1719
1720     return allExist;
1721 }
1722
1723 /* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.
1724  * Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
1725
1726 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
1727 {
1728     const int which = highByte(glyph);
1729     Q_ASSERT(which < engines.size());
1730     return engine(which)->alphaMapForGlyph(stripped(glyph));
1731 }
1732
1733 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
1734 {
1735     const int which = highByte(glyph);
1736     Q_ASSERT(which < engines.size());
1737     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
1738 }
1739
1740 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
1741 {
1742     const int which = highByte(glyph);
1743     Q_ASSERT(which < engines.size());
1744     return engine(which)->alphaMapForGlyph(stripped(glyph), t);
1745 }
1746
1747 QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
1748 {
1749     const int which = highByte(glyph);
1750     Q_ASSERT(which < engines.size());
1751     return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
1752 }
1753
1754 QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
1755 {
1756     const int which = highByte(glyph);
1757     Q_ASSERT(which < engines.size());
1758     return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
1759 }
1760
1761 QT_END_NAMESPACE