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