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