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