src/gui/text/qfontengine_mac.mm
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 <private/qapplication_p.h>
       
    43 #include <private/qfontengine_p.h>
       
    44 #include <private/qpainter_p.h>
       
    45 #include <private/qtextengine_p.h>
       
    46 #include <qbitmap.h>
       
    47 #include <private/qpaintengine_mac_p.h>
       
    48 #include <private/qprintengine_mac_p.h>
       
    49 #include <private/qpdf_p.h>
       
    50 #include <qglobal.h>
       
    51 #include <qpixmap.h>
       
    52 #include <qpixmapcache.h>
       
    53 #include <qvarlengtharray.h>
       
    54 #include <qdebug.h>
       
    55 #include <qendian.h>
       
    56 
       
    57 #include <ApplicationServices/ApplicationServices.h>
       
    58 #include <AppKit/AppKit.h>
       
    59 
       
    60 QT_BEGIN_NAMESPACE
       
    61 
       
    62 /*****************************************************************************
       
    63   QFontEngine debug facilities
       
    64  *****************************************************************************/
       
    65 //#define DEBUG_ADVANCES
       
    66 
       
    67 extern int qt_antialiasing_threshold; // QApplication.cpp
       
    68 
       
    69 #ifndef FixedToQFixed
       
    70 #define FixedToQFixed(a) QFixed::fromFixed((a) >> 10)
       
    71 #define QFixedToFixed(x) ((x).value() << 10)
       
    72 #endif
       
    73 
       
    74 class QMacFontPath
       
    75 {
       
    76     float x, y;
       
    77     QPainterPath *path;
       
    78 public:
       
    79     inline QMacFontPath(float _x, float _y, QPainterPath *_path) : x(_x), y(_y), path(_path) { }
       
    80     inline void setPosition(float _x, float _y) { x = _x; y = _y; }
       
    81     inline void advance(float _x) { x += _x; }
       
    82     static OSStatus lineTo(const Float32Point *, void *);
       
    83     static OSStatus cubicTo(const Float32Point *, const Float32Point *,
       
    84                             const Float32Point *, void *);
       
    85     static OSStatus moveTo(const Float32Point *, void *);
       
    86     static OSStatus closePath(void *);
       
    87 };
       
    88 
       
    89 OSStatus QMacFontPath::lineTo(const Float32Point *pt, void *data)
       
    90 
       
    91 {
       
    92     QMacFontPath *p = static_cast<QMacFontPath*>(data);
       
    93     p->path->lineTo(p->x + pt->x, p->y + pt->y);
       
    94     return noErr;
       
    95 }
       
    96 
       
    97 OSStatus QMacFontPath::cubicTo(const Float32Point *cp1, const Float32Point *cp2,
       
    98                                const Float32Point *ep, void *data)
       
    99 
       
   100 {
       
   101     QMacFontPath *p = static_cast<QMacFontPath*>(data);
       
   102     p->path->cubicTo(p->x + cp1->x, p->y + cp1->y,
       
   103                      p->x + cp2->x, p->y + cp2->y,
       
   104                      p->x + ep->x, p->y + ep->y);
       
   105     return noErr;
       
   106 }
       
   107 
       
   108 OSStatus QMacFontPath::moveTo(const Float32Point *pt, void *data)
       
   109 {
       
   110     QMacFontPath *p = static_cast<QMacFontPath*>(data);
       
   111     p->path->moveTo(p->x + pt->x, p->y + pt->y);
       
   112     return noErr;
       
   113 }
       
   114 
       
   115 OSStatus QMacFontPath::closePath(void *data)
       
   116 {
       
   117     static_cast<QMacFontPath*>(data)->path->closeSubpath();
       
   118     return noErr;
       
   119 }
       
   120 
       
   121 
       
   122 
       
   123 void qmacfontengine_gamma_correct(QImage *image)
       
   124 {
       
   125     extern uchar qt_pow_rgb_gamma[256];
       
   126 
       
   127     // gamma correct the pixels back to linear color space...
       
   128     int h = image->height();
       
   129     int w = image->width();
       
   130 
       
   131     for (int y=0; y<h; ++y) {
       
   132         uint *pixels = (uint *) image->scanLine(y);
       
   133         for (int x=0; x<w; ++x) {
       
   134             uint p = pixels[x];
       
   135             uint r = qt_pow_rgb_gamma[qRed(p)];
       
   136             uint g = qt_pow_rgb_gamma[qGreen(p)];
       
   137             uint b = qt_pow_rgb_gamma[qBlue(p)];
       
   138             pixels[x] = (r << 16) | (g << 8) | b | 0xff000000;
       
   139         }
       
   140     }
       
   141 }
       
   142 
       
   143 
       
   144 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
       
   145 QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const ATSFontFamilyRef &, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning)
       
   146     : QFontEngineMulti(0)
       
   147 {
       
   148     this->fontDef = fontDef;
       
   149     CTFontSymbolicTraits symbolicTraits = 0;
       
   150     if (fontDef.weight >= QFont::Bold)
       
   151         symbolicTraits |= kCTFontBoldTrait;
       
   152     switch (fontDef.style) {
       
   153     case QFont::StyleNormal:
       
   154         break;
       
   155     case QFont::StyleItalic:
       
   156     case QFont::StyleOblique:
       
   157         symbolicTraits |= kCTFontItalicTrait;
       
   158         break;
       
   159     }
       
   160 
       
   161     QCFString name;
       
   162     ATSFontGetName(atsFontRef, kATSOptionFlagsDefault, &name);
       
   163 
       
   164     QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize);
       
   165     QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, 0);
       
   166     ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, 0, symbolicTraits, symbolicTraits);
       
   167 
       
   168     // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does
       
   169     // not exist for the given font. (for example italic)
       
   170     if (ctfont == 0) {
       
   171         ctfont = baseFont;
       
   172         CFRetain(ctfont);
       
   173     }
       
   174 
       
   175     attributeDict = CFDictionaryCreateMutable(0, 2,
       
   176                                        &kCFTypeDictionaryKeyCallBacks,
       
   177                                        &kCFTypeDictionaryValueCallBacks);
       
   178     CFDictionaryAddValue(attributeDict, NSFontAttributeName, ctfont);
       
   179     if (!kerning) {
       
   180         float zero = 0.0;
       
   181         QCFType<CFNumberRef> noKern = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &zero);
       
   182         CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern);
       
   183     }
       
   184 
       
   185     QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this);
       
   186     fe->ref.ref();
       
   187     engines.append(fe);
       
   188 
       
   189 }
       
   190 
       
   191 QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
       
   192 {
       
   193     CFRelease(ctfont);
       
   194 }
       
   195 
       
   196 uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const
       
   197 {
       
   198     for (int i = 0; i < engines.count(); ++i) {
       
   199         if (CFEqual(engineAt(i)->ctfont, id))
       
   200             return i;
       
   201     }
       
   202 
       
   203     QCoreTextFontEngineMulti *that = const_cast<QCoreTextFontEngineMulti *>(this);
       
   204     QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that);
       
   205     fe->ref.ref();
       
   206     that->engines.append(fe);
       
   207     return engines.count() - 1;
       
   208 }
       
   209 
       
   210 bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags,
       
   211                   unsigned short *logClusters, const HB_CharAttributes *) const
       
   212 {
       
   213     QCFType<CFStringRef> cfstring = CFStringCreateWithCharactersNoCopy(0,
       
   214                                                                reinterpret_cast<const UniChar *>(str),
       
   215                                                                len, kCFAllocatorNull);
       
   216     QCFType<CFAttributedStringRef> attributedString = CFAttributedStringCreate(0, cfstring, attributeDict);
       
   217     QCFType<CTTypesetterRef> typeSetter = CTTypesetterCreateWithAttributedString(attributedString);
       
   218     CFRange range = {0, 0};
       
   219     QCFType<CTLineRef> line = CTTypesetterCreateLine(typeSetter, range);
       
   220     CFArrayRef array = CTLineGetGlyphRuns(line);
       
   221     uint arraySize = CFArrayGetCount(array);
       
   222     glyph_t *outGlyphs = glyphs->glyphs;
       
   223     HB_GlyphAttributes *outAttributes = glyphs->attributes;
       
   224     QFixed *outAdvances_x = glyphs->advances_x;
       
   225     QFixed *outAdvances_y = glyphs->advances_y;
       
   226     glyph_t *initialGlyph = outGlyphs;
       
   227 
       
   228     if (arraySize == 0)
       
   229         return false;
       
   230 
       
   231     const bool rtl = (CTRunGetStatus(static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, 0))) & kCTRunStatusRightToLeft);
       
   232 
       
   233     bool outOBounds = false;
       
   234     for (uint i = 0; i < arraySize; ++i) {
       
   235         CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, rtl ? (arraySize - 1 - i) : i));
       
   236         CFIndex glyphCount = CTRunGetGlyphCount(run);
       
   237         if (glyphCount == 0)
       
   238             continue;
       
   239 
       
   240         Q_ASSERT((CTRunGetStatus(run) & kCTRunStatusRightToLeft) == rtl);
       
   241 
       
   242         if (!outOBounds && outGlyphs + glyphCount - initialGlyph > *nglyphs) {
       
   243             outOBounds = true;
       
   244         }
       
   245         if (!outOBounds) {
       
   246             CFDictionaryRef runAttribs = CTRunGetAttributes(run);
       
   247             //NSLog(@"Dictionary %@", runAttribs);
       
   248             if (!runAttribs)
       
   249                 runAttribs = attributeDict;
       
   250             CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttribs, NSFontAttributeName));
       
   251             const uint fontIndex = (fontIndexForFont(runFont) << 24);
       
   252             //NSLog(@"Run Font Name = %@", CTFontCopyFamilyName(runFont));
       
   253             QVarLengthArray<CGGlyph, 512> cgglyphs(0);
       
   254             const CGGlyph *tmpGlyphs = CTRunGetGlyphsPtr(run);
       
   255             if (!tmpGlyphs) {
       
   256                 cgglyphs.resize(glyphCount);
       
   257                 CTRunGetGlyphs(run, range, cgglyphs.data());
       
   258                 tmpGlyphs = cgglyphs.constData();
       
   259             }
       
   260             QVarLengthArray<CGPoint, 512> cgpoints(0);
       
   261             const CGPoint *tmpPoints = CTRunGetPositionsPtr(run);
       
   262             if (!tmpPoints) {
       
   263                 cgpoints.resize(glyphCount);
       
   264                 CTRunGetPositions(run, range, cgpoints.data());
       
   265                 tmpPoints = cgpoints.constData();
       
   266             }
       
   267 
       
   268             const int rtlOffset = rtl ? (glyphCount - 1) : 0;
       
   269             const int rtlSign = rtl ? -1 : 1;
       
   270 
       
   271             if (logClusters) {
       
   272                 CFRange stringRange = CTRunGetStringRange(run);
       
   273                 QVarLengthArray<CFIndex, 512> stringIndices(0);
       
   274                 const CFIndex *tmpIndices = CTRunGetStringIndicesPtr(run);
       
   275                 if (!tmpIndices) {
       
   276                     stringIndices.resize(glyphCount);
       
   277                     CTRunGetStringIndices(run, range, stringIndices.data());
       
   278                     tmpIndices = stringIndices.constData();
       
   279                 }
       
   280 
       
   281                 const int firstGlyphIndex = outGlyphs - initialGlyph;
       
   282                 outAttributes[0].clusterStart = true;
       
   283 
       
   284                 CFIndex k = 0;
       
   285                 CFIndex i = 0;
       
   286                 for (i = stringRange.location;
       
   287                      (i < stringRange.location + stringRange.length) && (k < glyphCount); ++i) {
       
   288                     if (tmpIndices[k * rtlSign + rtlOffset] == i || i == stringRange.location) {
       
   289                         logClusters[i] = k + firstGlyphIndex;
       
   290                         outAttributes[k].clusterStart = true;
       
   291                         ++k;
       
   292                     } else {
       
   293                         logClusters[i] = k + firstGlyphIndex - 1;
       
   294                     }
       
   295                 }
       
   296                 // in case of a ligature at the end, fill the remaining logcluster entries
       
   297                 for (;i < stringRange.location + stringRange.length; i++) {
       
   298                     logClusters[i] = k + firstGlyphIndex - 1;
       
   299                 }
       
   300             }
       
   301             for (CFIndex i = 0; i < glyphCount - 1; ++i) {
       
   302                 int idx = rtlOffset + rtlSign * i;
       
   303                 outGlyphs[idx] = tmpGlyphs[i] | fontIndex;
       
   304                 outAdvances_x[idx] = QFixed::fromReal(tmpPoints[i + 1].x - tmpPoints[i].x);
       
   305                 outAdvances_y[idx] = QFixed::fromReal(tmpPoints[i + 1].y - tmpPoints[i].y);
       
   306             }
       
   307             CGSize lastGlyphAdvance;
       
   308             CTFontGetAdvancesForGlyphs(runFont, kCTFontHorizontalOrientation, tmpGlyphs + glyphCount - 1, &lastGlyphAdvance, 1);
       
   309 
       
   310             outGlyphs[rtl ? 0 : (glyphCount - 1)] = tmpGlyphs[glyphCount - 1] | fontIndex;
       
   311             outAdvances_x[rtl ? 0 : (glyphCount - 1)] = QFixed::fromReal(lastGlyphAdvance.width).ceil();
       
   312         }
       
   313         outGlyphs += glyphCount;
       
   314         outAttributes += glyphCount;
       
   315         outAdvances_x += glyphCount;
       
   316         outAdvances_y += glyphCount;
       
   317     }
       
   318     *nglyphs = (outGlyphs - initialGlyph);
       
   319     return !outOBounds;
       
   320 }
       
   321 
       
   322 bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
       
   323                                             int *nglyphs, QTextEngine::ShaperFlags flags) const
       
   324 {
       
   325     return stringToCMap(str, len, glyphs, nglyphs, flags, 0, 0);
       
   326 }
       
   327 
       
   328 void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
       
   329 {
       
   330 }
       
   331 void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
       
   332 {
       
   333 }
       
   334 
       
   335 void QCoreTextFontEngineMulti::loadEngine(int)
       
   336 {
       
   337     // Do nothing
       
   338     Q_ASSERT(false);
       
   339 }
       
   340 
       
   341 
       
   342 
       
   343 QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def,
       
   344                                          QCoreTextFontEngineMulti *multiEngine)
       
   345 {
       
   346     fontDef = def;
       
   347     parentEngine = multiEngine;
       
   348     synthesisFlags = 0;
       
   349     ctfont = font;
       
   350     CFRetain(ctfont);
       
   351     ATSFontRef atsfont = CTFontGetPlatformFont(ctfont, 0);
       
   352     cgFont = CGFontCreateWithPlatformFont(&atsfont);
       
   353     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
       
   354     if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) {
       
   355          synthesisFlags |= SynthesizedBold;
       
   356     }
       
   357 
       
   358     if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) {
       
   359         synthesisFlags |= SynthesizedItalic;
       
   360     }
       
   361 
       
   362     QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
       
   363     if (os2Table.size() >= 10)
       
   364         fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
       
   365 }
       
   366 
       
   367 QCoreTextFontEngine::~QCoreTextFontEngine()
       
   368 {
       
   369     CFRelease(ctfont);
       
   370     CFRelease(cgFont);
       
   371 }
       
   372 
       
   373 bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const
       
   374 {
       
   375     return false;
       
   376 }
       
   377 
       
   378 glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
       
   379 {
       
   380     QFixed w;
       
   381     for (int i = 0; i < glyphs.numGlyphs; ++i)
       
   382         w += glyphs.effectiveAdvance(i);
       
   383     return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
       
   384 }
       
   385 glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
       
   386 {
       
   387     glyph_metrics_t ret;
       
   388     CGGlyph g = glyph;
       
   389     CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, 0, 1);
       
   390     ret.width = QFixed::fromReal(rect.size.width);
       
   391     ret.height = QFixed::fromReal(rect.size.height);
       
   392     ret.x = QFixed::fromReal(rect.origin.x);
       
   393     ret.y = -QFixed::fromReal(rect.origin.y) - ret.height;
       
   394     CGSize advances[1];
       
   395     CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1);
       
   396     ret.xoff = QFixed::fromReal(advances[0].width).ceil();
       
   397     ret.yoff = QFixed::fromReal(advances[0].height).ceil();
       
   398     return ret;
       
   399 }
       
   400 
       
   401 QFixed QCoreTextFontEngine::ascent() const
       
   402 {
       
   403     return QFixed::fromReal(CTFontGetAscent(ctfont)).ceil();
       
   404 }
       
   405 QFixed QCoreTextFontEngine::descent() const
       
   406 {
       
   407     return QFixed::fromReal(CTFontGetDescent(ctfont)).ceil();
       
   408 }
       
   409 QFixed QCoreTextFontEngine::leading() const
       
   410 {
       
   411     return QFixed::fromReal(CTFontGetLeading(ctfont)).ceil();
       
   412 }
       
   413 QFixed QCoreTextFontEngine::xHeight() const
       
   414 {
       
   415     return QFixed::fromReal(CTFontGetXHeight(ctfont)).ceil();
       
   416 }
       
   417 QFixed QCoreTextFontEngine::averageCharWidth() const
       
   418 {
       
   419     // ### Need to implement properly and get the information from the OS/2 Table.
       
   420     return QFontEngine::averageCharWidth();
       
   421 }
       
   422 
       
   423 qreal QCoreTextFontEngine::maxCharWidth() const
       
   424 {
       
   425     // ### Max Help!
       
   426     return 0;
       
   427 
       
   428 }
       
   429 qreal QCoreTextFontEngine::minLeftBearing() const
       
   430 {
       
   431     // ### Min Help!
       
   432     return 0;
       
   433 
       
   434 }
       
   435 qreal QCoreTextFontEngine::minRightBearing() const
       
   436 {
       
   437     // ### Max Help! (even thought it's right)
       
   438     return 0;
       
   439 
       
   440 }
       
   441 
       
   442 void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
       
   443 {
       
   444     QVarLengthArray<QFixedPoint> positions;
       
   445     QVarLengthArray<glyph_t> glyphs;
       
   446     QTransform matrix;
       
   447     matrix.translate(x, y);
       
   448     getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
   449     if (glyphs.size() == 0)
       
   450         return;
       
   451 
       
   452     CGContextSetFontSize(ctx, fontDef.pixelSize);
       
   453 
       
   454     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
       
   455 
       
   456     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight);
       
   457 
       
   458     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
       
   459 
       
   460     if (synthesisFlags & QFontEngine::SynthesizedItalic)
       
   461         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
       
   462 
       
   463 // ###    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
       
   464 
       
   465     CGContextSetTextMatrix(ctx, cgMatrix);
       
   466 
       
   467     CGContextSetTextDrawingMode(ctx, kCGTextFill);
       
   468 
       
   469 
       
   470     QVarLengthArray<CGSize> advances(glyphs.size());
       
   471     QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size());
       
   472 
       
   473     for (int i = 0; i < glyphs.size() - 1; ++i) {
       
   474         advances[i].width = (positions[i + 1].x - positions[i].x).toReal();
       
   475         advances[i].height = (positions[i + 1].y - positions[i].y).toReal();
       
   476         cgGlyphs[i] = glyphs[i];
       
   477     }
       
   478     advances[glyphs.size() - 1].width = 0;
       
   479     advances[glyphs.size() - 1].height = 0;
       
   480     cgGlyphs[glyphs.size() - 1] = glyphs[glyphs.size() - 1];
       
   481 
       
   482     CGContextSetFont(ctx, cgFont);
       
   483     //NSLog(@"Font inDraw %@  ctfont %@", CGFontCopyFullName(cgFont), CTFontCopyFamilyName(ctfont));
       
   484 
       
   485     CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal());
       
   486 
       
   487     CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
       
   488 
       
   489     if (synthesisFlags & QFontEngine::SynthesizedBold) {
       
   490         CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(),
       
   491                                  positions[0].y.toReal());
       
   492 
       
   493         CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
       
   494     }
       
   495 
       
   496     CGContextSetTextMatrix(ctx, oldTextMatrix);
       
   497 }
       
   498 
       
   499 struct ConvertPathInfo
       
   500 {
       
   501     ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos) : path(newPath), pos(newPos) {}
       
   502     QPainterPath *path;
       
   503     QPointF pos;
       
   504 };
       
   505 
       
   506 static void convertCGPathToQPainterPath(void *info, const CGPathElement *element)
       
   507 {
       
   508     ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info);
       
   509     switch(element->type) {
       
   510         case kCGPathElementMoveToPoint:
       
   511             myInfo->path->moveTo(element->points[0].x + myInfo->pos.x(),
       
   512                                  element->points[0].y + myInfo->pos.y());
       
   513             break;
       
   514         case kCGPathElementAddLineToPoint:
       
   515             myInfo->path->lineTo(element->points[0].x + myInfo->pos.x(),
       
   516                                  element->points[0].y + myInfo->pos.y());
       
   517             break;
       
   518         case kCGPathElementAddQuadCurveToPoint:
       
   519             myInfo->path->quadTo(element->points[0].x + myInfo->pos.x(),
       
   520                                  element->points[0].y + myInfo->pos.y(),
       
   521                                  element->points[1].x + myInfo->pos.x(),
       
   522                                  element->points[1].y + myInfo->pos.y());
       
   523             break;
       
   524         case kCGPathElementAddCurveToPoint:
       
   525             myInfo->path->cubicTo(element->points[0].x + myInfo->pos.x(),
       
   526                                   element->points[0].y + myInfo->pos.y(),
       
   527                                   element->points[1].x + myInfo->pos.x(),
       
   528                                   element->points[1].y + myInfo->pos.y(),
       
   529                                   element->points[2].x + myInfo->pos.x(),
       
   530                                   element->points[2].y + myInfo->pos.y());
       
   531             break;
       
   532         case kCGPathElementCloseSubpath:
       
   533             myInfo->path->closeSubpath();
       
   534             break;
       
   535         default:
       
   536             qDebug() << "Unhandled path transform type: " << element->type;
       
   537     }
       
   538 
       
   539 }
       
   540 
       
   541 void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
       
   542                                           QPainterPath *path, QTextItem::RenderFlags)
       
   543 {
       
   544 
       
   545     CGAffineTransform cgMatrix = CGAffineTransformIdentity;
       
   546     cgMatrix = CGAffineTransformScale(cgMatrix, 1, -1);
       
   547 
       
   548     if (synthesisFlags & QFontEngine::SynthesizedItalic)
       
   549         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
       
   550 
       
   551 
       
   552     for (int i = 0; i < nGlyphs; ++i) {
       
   553         QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix);
       
   554         ConvertPathInfo info(path, positions[i].toPointF());
       
   555         CGPathApply(cgpath, &info, convertCGPathToQPainterPath);
       
   556     }
       
   557 }
       
   558 
       
   559 QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, int margin, bool aa)
       
   560 {
       
   561     const glyph_metrics_t br = boundingBox(glyph);
       
   562     QImage im(qRound(br.width)+2, qRound(br.height)+2, QImage::Format_RGB32);
       
   563     im.fill(0);
       
   564 
       
   565     CGColorSpaceRef colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
       
   566     uint cgflags = kCGImageAlphaNoneSkipFirst;
       
   567 #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
       
   568     cgflags |= kCGBitmapByteOrder32Host;
       
   569 #endif
       
   570     CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
       
   571                                              8, im.bytesPerLine(), colorspace,
       
   572                                              cgflags);
       
   573     CGContextSetFontSize(ctx, fontDef.pixelSize);
       
   574     CGContextSetShouldAntialias(ctx, aa ||
       
   575                                 (fontDef.pointSize > qt_antialiasing_threshold
       
   576                                  && !(fontDef.styleStrategy & QFont::NoAntialias)));
       
   577     CGContextSetShouldSmoothFonts(ctx, aa);
       
   578     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
       
   579     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
       
   580 
       
   581     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
       
   582 
       
   583     if (synthesisFlags & QFontEngine::SynthesizedItalic)
       
   584         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
       
   585 
       
   586 // ###    cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
       
   587 
       
   588     CGContextSetTextMatrix(ctx, cgMatrix);
       
   589     CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
       
   590     CGContextSetTextDrawingMode(ctx, kCGTextFill);
       
   591 
       
   592     ATSFontRef atsfont = CTFontGetPlatformFont(ctfont, 0);
       
   593     QCFType<CGFontRef> cgFont = CGFontCreateWithPlatformFont(&atsfont);
       
   594     CGContextSetFont(ctx, cgFont);
       
   595 
       
   596     qreal pos_x = -br.x.toReal()+1, pos_y = im.height()+br.y.toReal();
       
   597     CGContextSetTextPosition(ctx, pos_x, pos_y);
       
   598 
       
   599     CGSize advance;
       
   600     advance.width = 0;
       
   601     advance.height = 0;
       
   602     CGGlyph cgGlyph = glyph;
       
   603     CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
       
   604 
       
   605     if (synthesisFlags & QFontEngine::SynthesizedBold) {
       
   606         CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
       
   607         CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
       
   608     }
       
   609 
       
   610     CGContextRelease(ctx);
       
   611 
       
   612     return im;
       
   613 }
       
   614 
       
   615 QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph)
       
   616 {
       
   617     QImage im = imageForGlyph(glyph, 0, false);
       
   618 
       
   619     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
       
   620     QVector<QRgb> colors(256);
       
   621     for (int i=0; i<256; ++i)
       
   622         colors[i] = qRgba(0, 0, 0, i);
       
   623     indexed.setColorTable(colors);
       
   624 
       
   625     for (int y=0; y<im.height(); ++y) {
       
   626         uint *src = (uint*) im.scanLine(y);
       
   627         uchar *dst = indexed.scanLine(y);
       
   628         for (int x=0; x<im.width(); ++x) {
       
   629             *dst = qGray(*src);
       
   630             ++dst;
       
   631             ++src;
       
   632         }
       
   633     }
       
   634 
       
   635     return indexed;
       
   636 }
       
   637 
       
   638 QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, int margin, const QTransform &x)
       
   639 {
       
   640     if (x.type() >= QTransform::TxScale)
       
   641         return QFontEngine::alphaRGBMapForGlyph(glyph, margin, x);
       
   642 
       
   643     QImage im = imageForGlyph(glyph, margin, true);
       
   644     qmacfontengine_gamma_correct(&im);
       
   645     return im;
       
   646 }
       
   647 
       
   648 void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
       
   649 {
       
   650     Q_ASSERT(false);
       
   651     Q_UNUSED(numGlyphs);
       
   652     Q_UNUSED(glyphs);
       
   653     Q_UNUSED(flags);
       
   654 }
       
   655 
       
   656 QFontEngine::FaceId QCoreTextFontEngine::faceId() const
       
   657 {
       
   658     return QFontEngine::FaceId();
       
   659 }
       
   660 
       
   661 bool QCoreTextFontEngine::canRender(const QChar *string, int len)
       
   662 {
       
   663     QCFType<CTFontRef> retFont = CTFontCreateForString(ctfont,
       
   664                   QCFType<CFStringRef>(CFStringCreateWithCharactersNoCopy(0,
       
   665                                                               reinterpret_cast<const UniChar *>(string),
       
   666                                                                           len, kCFAllocatorNull)),
       
   667                           CFRangeMake(0, len));
       
   668     return retFont != 0;
       
   669     return false;
       
   670 }
       
   671 
       
   672  bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
       
   673  {
       
   674      QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
       
   675      if (!table || !length)
       
   676          return false;
       
   677      CFIndex tableLength = CFDataGetLength(table);
       
   678      int availableLength = *length;
       
   679      *length = tableLength;
       
   680      if (buffer) {
       
   681          if (tableLength > availableLength)
       
   682              return false;
       
   683          CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
       
   684      }
       
   685      return true;
       
   686  }
       
   687 
       
   688 void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *)
       
   689 {
       
   690     // ###
       
   691 }
       
   692 
       
   693 #endif // MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5
       
   694 
       
   695 #ifndef QT_MAC_USE_COCOA
       
   696 QFontEngineMacMulti::QFontEngineMacMulti(const ATSFontFamilyRef &atsFamily, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning)
       
   697     : QFontEngineMulti(0)
       
   698 {
       
   699     this->fontDef = fontDef;
       
   700     this->kerning = kerning;
       
   701 
       
   702     // hopefully (CTFontCreateWithName or CTFontCreateWithFontDescriptor) + CTFontCreateCopyWithSymbolicTraits
       
   703     // (or CTFontCreateWithQuickdrawInstance)
       
   704     FMFontFamily fmFamily;
       
   705     FMFontStyle fntStyle = 0;
       
   706     fmFamily = FMGetFontFamilyFromATSFontFamilyRef(atsFamily);
       
   707     if (fmFamily == kInvalidFontFamily) {
       
   708         // Use the ATSFont then...
       
   709         fontID = FMGetFontFromATSFontRef(atsFontRef);
       
   710     } else {
       
   711         if (fontDef.weight >= QFont::Bold)
       
   712             fntStyle |= ::bold;
       
   713         if (fontDef.style != QFont::StyleNormal)
       
   714             fntStyle |= ::italic;
       
   715 
       
   716         FMFontStyle intrinsicStyle;
       
   717         FMFont fnt = 0;
       
   718         if (FMGetFontFromFontFamilyInstance(fmFamily, fntStyle, &fnt, &intrinsicStyle) == noErr)
       
   719            fontID = FMGetATSFontRefFromFont(fnt);
       
   720     }
       
   721 
       
   722     // CFDictionaryRef, <CTStringAttributes.h>
       
   723     OSStatus status;
       
   724 
       
   725     status = ATSUCreateTextLayout(&textLayout);
       
   726     Q_ASSERT(status == noErr);
       
   727 
       
   728     const int maxAttributeCount = 5;
       
   729     ATSUAttributeTag tags[maxAttributeCount + 1];
       
   730     ByteCount sizes[maxAttributeCount + 1];
       
   731     ATSUAttributeValuePtr values[maxAttributeCount + 1];
       
   732     int attributeCount = 0;
       
   733 
       
   734     Fixed size = FixRatio(fontDef.pixelSize, 1);
       
   735     tags[attributeCount] = kATSUSizeTag;
       
   736     sizes[attributeCount] = sizeof(size);
       
   737     values[attributeCount] = &size;
       
   738     ++attributeCount;
       
   739 
       
   740     tags[attributeCount] = kATSUFontTag;
       
   741     sizes[attributeCount] = sizeof(fontID);
       
   742     values[attributeCount] = &this->fontID;
       
   743     ++attributeCount;
       
   744 
       
   745     transform = CGAffineTransformIdentity;
       
   746     if (fontDef.stretch != 100) {
       
   747         transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
       
   748         tags[attributeCount] = kATSUFontMatrixTag;
       
   749         sizes[attributeCount] = sizeof(transform);
       
   750         values[attributeCount] = &transform;
       
   751         ++attributeCount;
       
   752     }
       
   753 
       
   754     status = ATSUCreateStyle(&style);
       
   755     Q_ASSERT(status == noErr);
       
   756 
       
   757     Q_ASSERT(attributeCount < maxAttributeCount + 1);
       
   758     status = ATSUSetAttributes(style, attributeCount, tags, sizes, values);
       
   759     Q_ASSERT(status == noErr);
       
   760 
       
   761     QFontEngineMac *fe = new QFontEngineMac(style, fontID, fontDef, this);
       
   762     fe->ref.ref();
       
   763     engines.append(fe);
       
   764 }
       
   765 
       
   766 QFontEngineMacMulti::~QFontEngineMacMulti()
       
   767 {
       
   768     ATSUDisposeTextLayout(textLayout);
       
   769     ATSUDisposeStyle(style);
       
   770 
       
   771     for (int i = 0; i < engines.count(); ++i) {
       
   772         QFontEngineMac *fe = const_cast<QFontEngineMac *>(static_cast<const QFontEngineMac *>(engines.at(i)));
       
   773         fe->multiEngine = 0;
       
   774         if (!fe->ref.deref())
       
   775             delete fe;
       
   776     }
       
   777     engines.clear();
       
   778 }
       
   779 
       
   780 struct QGlyphLayoutInfo
       
   781 {
       
   782     QGlyphLayout *glyphs;
       
   783     int *numGlyphs;
       
   784     bool callbackCalled;
       
   785     int *mappedFonts;
       
   786     QTextEngine::ShaperFlags flags;
       
   787     QFontEngineMacMulti::ShaperItem *shaperItem;
       
   788 };
       
   789 
       
   790 static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATSULineRef lineRef, URefCon refCon,
       
   791                                  void *operationExtraParameter, ATSULayoutOperationCallbackStatus *callbackStatus)
       
   792 {
       
   793     Q_UNUSED(selector);
       
   794     Q_UNUSED(operationExtraParameter);
       
   795 
       
   796     QGlyphLayoutInfo *nfo = reinterpret_cast<QGlyphLayoutInfo *>(refCon);
       
   797     nfo->callbackCalled = true;
       
   798 
       
   799     ATSLayoutRecord *layoutData = 0;
       
   800     ItemCount itemCount = 0;
       
   801 
       
   802     OSStatus e = noErr;
       
   803     e = ATSUDirectGetLayoutDataArrayPtrFromLineRef(lineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
       
   804                                                    /*iCreate =*/ false,
       
   805                                                    (void **) &layoutData,
       
   806                                                    &itemCount);
       
   807     if (e != noErr)
       
   808         return e;
       
   809 
       
   810     *nfo->numGlyphs = itemCount - 1;
       
   811 
       
   812     Fixed *baselineDeltas = 0;
       
   813 
       
   814     e = ATSUDirectGetLayoutDataArrayPtrFromLineRef(lineRef, kATSUDirectDataBaselineDeltaFixedArray,
       
   815                                                    /*iCreate =*/ true,
       
   816                                                    (void **) &baselineDeltas,
       
   817                                                    &itemCount);
       
   818     if (e != noErr)
       
   819         return e;
       
   820 
       
   821     int nextCharStop = -1;
       
   822     int currentClusterGlyph = -1; // first glyph in log cluster
       
   823     QFontEngineMacMulti::ShaperItem *item = nfo->shaperItem;
       
   824     if (item->charAttributes) {
       
   825         item = nfo->shaperItem;
       
   826 #if !defined(QT_NO_DEBUG)
       
   827         int surrogates = 0;
       
   828         const QChar *str = item->string;
       
   829         for (int i = item->from; i < item->from + item->length - 1; ++i) {
       
   830             surrogates += (str[i].unicode() >= 0xd800 && str[i].unicode() < 0xdc00
       
   831                            && str[i+1].unicode() >= 0xdc00 && str[i+1].unicode() < 0xe000);
       
   832         }
       
   833 #endif
       
   834         for (nextCharStop = item->from; nextCharStop < item->from + item->length; ++nextCharStop)
       
   835             if (item->charAttributes[nextCharStop].charStop)
       
   836                 break;
       
   837         nextCharStop -= item->from;
       
   838     }
       
   839 
       
   840     nfo->glyphs->attributes[0].clusterStart = true;
       
   841     int glyphIdx = 0;
       
   842     int glyphIncrement = 1;
       
   843     if (nfo->flags & QTextEngine::RightToLeft) {
       
   844         glyphIdx  = itemCount - 2;
       
   845         glyphIncrement = -1;
       
   846     }
       
   847     for (int i = 0; i < *nfo->numGlyphs; ++i, glyphIdx += glyphIncrement) {
       
   848 
       
   849         int charOffset = layoutData[glyphIdx].originalOffset / sizeof(UniChar);
       
   850         const int fontIdx = nfo->mappedFonts[charOffset];
       
   851 
       
   852         ATSGlyphRef glyphId = layoutData[glyphIdx].glyphID;
       
   853 
       
   854         QFixed yAdvance = FixedToQFixed(baselineDeltas[glyphIdx]);
       
   855         QFixed xAdvance = FixedToQFixed(layoutData[glyphIdx + 1].realPos - layoutData[glyphIdx].realPos);
       
   856 
       
   857         if (glyphId != 0xffff || i == 0) {
       
   858             if (i < nfo->glyphs->numGlyphs)
       
   859             {
       
   860                 nfo->glyphs->glyphs[i] = (glyphId & 0x00ffffff) | (fontIdx << 24);
       
   861 
       
   862                 nfo->glyphs->advances_y[i] = yAdvance;
       
   863                 nfo->glyphs->advances_x[i] = xAdvance;
       
   864             }
       
   865         } else {
       
   866             // ATSUI gives us 0xffff as glyph id at the index in the glyph array for
       
   867             // a character position that maps to a ligtature. Such a glyph id does not
       
   868             // result in any visual glyph, but it may have an advance, which is why we
       
   869             // sum up the glyph advances.
       
   870             --i;
       
   871             nfo->glyphs->advances_y[i] += yAdvance;
       
   872             nfo->glyphs->advances_x[i] += xAdvance;
       
   873             *nfo->numGlyphs -= 1;
       
   874         }
       
   875 
       
   876         if (item->log_clusters) {
       
   877             if (charOffset >= nextCharStop) {
       
   878                 nfo->glyphs->attributes[i].clusterStart = true;
       
   879                 currentClusterGlyph = i;
       
   880 
       
   881                 ++nextCharStop;
       
   882                 for (; nextCharStop < item->length; ++nextCharStop)
       
   883                     if (item->charAttributes[item->from + nextCharStop].charStop)
       
   884                         break;
       
   885             } else {
       
   886                 if (currentClusterGlyph == -1)
       
   887                     currentClusterGlyph = i;
       
   888             }
       
   889             item->log_clusters[charOffset] = currentClusterGlyph;
       
   890 
       
   891             // surrogate handling
       
   892             if (charOffset < item->length - 1) {
       
   893                 QChar current = item->string[item->from + charOffset];
       
   894                 QChar next = item->string[item->from + charOffset + 1];
       
   895                 if (current.unicode() >= 0xd800 && current.unicode() < 0xdc00
       
   896                     && next.unicode() >= 0xdc00 && next.unicode() < 0xe000) {
       
   897                     item->log_clusters[charOffset + 1] = currentClusterGlyph;
       
   898                 }
       
   899             }
       
   900         }
       
   901     }
       
   902 
       
   903     /*
       
   904     if (item) {
       
   905         qDebug() << "resulting logclusters:";
       
   906         for (int i = 0; i < item->length; ++i)
       
   907             qDebug() << "logClusters[" << i << "] =" << item->log_clusters[i];
       
   908         qDebug() << "clusterstarts:";
       
   909         for (int i = 0; i < *nfo->numGlyphs; ++i)
       
   910             qDebug() << "clusterStart[" << i << "] =" << nfo->glyphs[i].attributes.clusterStart;
       
   911     }
       
   912     */
       
   913 
       
   914     ATSUDirectReleaseLayoutDataArrayPtr(lineRef, kATSUDirectDataBaselineDeltaFixedArray,
       
   915                                         (void **) &baselineDeltas);
       
   916 
       
   917     ATSUDirectReleaseLayoutDataArrayPtr(lineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
       
   918                                         (void **) &layoutData);
       
   919 
       
   920     *callbackStatus = kATSULayoutOperationCallbackStatusHandled;
       
   921     return noErr;
       
   922 }
       
   923 
       
   924 int QFontEngineMacMulti::fontIndexForFontID(ATSUFontID id) const
       
   925 {
       
   926     for (int i = 0; i < engines.count(); ++i) {
       
   927         if (engineAt(i)->fontID == id)
       
   928             return i;
       
   929     }
       
   930 
       
   931     QFontEngineMacMulti *that = const_cast<QFontEngineMacMulti *>(this);
       
   932     QFontEngineMac *fe = new QFontEngineMac(style, id, fontDef, that);
       
   933     fe->ref.ref();
       
   934     that->engines.append(fe);
       
   935     return engines.count() - 1;
       
   936 }
       
   937 
       
   938 bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
       
   939 {
       
   940     return stringToCMap(str, len, glyphs, nglyphs, flags, /*logClusters=*/0, /*charAttributes=*/0);
       
   941 }
       
   942 
       
   943 bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags,
       
   944                                        unsigned short *logClusters, const HB_CharAttributes *charAttributes) const
       
   945 {
       
   946     if (*nglyphs < len) {
       
   947         *nglyphs = len;
       
   948         return false;
       
   949     }
       
   950 
       
   951     ShaperItem shaperItem;
       
   952     shaperItem.string = str;
       
   953     shaperItem.from = 0;
       
   954     shaperItem.length = len;
       
   955     shaperItem.glyphs = *glyphs;
       
   956     shaperItem.glyphs.numGlyphs = *nglyphs;
       
   957     shaperItem.flags = flags;
       
   958     shaperItem.log_clusters = logClusters;
       
   959     shaperItem.charAttributes = charAttributes;
       
   960 
       
   961     const int maxChars = qMax(1,
       
   962                               int(SHRT_MAX / maxCharWidth())
       
   963                               - 10 // subtract a few to be on the safe side
       
   964                              );
       
   965     if (len < maxChars || !charAttributes)
       
   966         return stringToCMapInternal(str, len, glyphs, nglyphs, flags, &shaperItem);
       
   967 
       
   968     int charIdx = 0;
       
   969     int glyphIdx = 0;
       
   970     ShaperItem tmpItem = shaperItem;
       
   971 
       
   972     do {
       
   973         tmpItem.from = shaperItem.from + charIdx;
       
   974 
       
   975         int charCount = qMin(maxChars, len - charIdx);
       
   976 
       
   977         int lastWhitespace = tmpItem.from + charCount - 1;
       
   978         int lastSoftBreak = lastWhitespace;
       
   979         int lastCharStop = lastSoftBreak;
       
   980         for (int i = lastCharStop; i >= tmpItem.from; --i) {
       
   981             if (tmpItem.charAttributes[i].whiteSpace) {
       
   982                 lastWhitespace = i;
       
   983                 break;
       
   984             } if (tmpItem.charAttributes[i].lineBreakType != HB_NoBreak) {
       
   985                 lastSoftBreak = i;
       
   986             } if (tmpItem.charAttributes[i].charStop) {
       
   987                 lastCharStop = i;
       
   988             }
       
   989         }
       
   990         charCount = qMin(lastWhitespace, qMin(lastSoftBreak, lastCharStop)) - tmpItem.from + 1;
       
   991 
       
   992         int glyphCount = shaperItem.glyphs.numGlyphs - glyphIdx;
       
   993         if (glyphCount <= 0)
       
   994             return false;
       
   995         tmpItem.length = charCount;
       
   996         tmpItem.glyphs = shaperItem.glyphs.mid(glyphIdx, glyphCount);
       
   997         tmpItem.log_clusters = shaperItem.log_clusters + charIdx;
       
   998         if (!stringToCMapInternal(tmpItem.string + tmpItem.from, tmpItem.length,
       
   999                                   &tmpItem.glyphs, &glyphCount, flags,
       
  1000                                   &tmpItem)) {
       
  1001             *nglyphs = glyphIdx + glyphCount;
       
  1002             return false;
       
  1003 	}
       
  1004         for (int i = 0; i < charCount; ++i)
       
  1005             tmpItem.log_clusters[i] += glyphIdx;
       
  1006         glyphIdx += glyphCount;
       
  1007         charIdx += charCount;
       
  1008     } while (charIdx < len);
       
  1009     *nglyphs = glyphIdx;
       
  1010     glyphs->numGlyphs = glyphIdx;
       
  1011 
       
  1012     return true;
       
  1013 }
       
  1014 
       
  1015 bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags,ShaperItem *shaperItem) const
       
  1016 {
       
  1017     //qDebug() << "stringToCMap" << QString(str, len);
       
  1018 
       
  1019     OSStatus e = noErr;
       
  1020 
       
  1021     e = ATSUSetTextPointerLocation(textLayout, (UniChar *)(str), 0, len, len);
       
  1022     if (e != noErr) {
       
  1023         qWarning("Qt: internal: %ld: Error ATSUSetTextPointerLocation %s: %d", long(e), __FILE__, __LINE__);
       
  1024         return false;
       
  1025     }
       
  1026 
       
  1027     QGlyphLayoutInfo nfo;
       
  1028     nfo.glyphs = glyphs;
       
  1029     nfo.numGlyphs = nglyphs;
       
  1030     nfo.callbackCalled = false;
       
  1031     nfo.flags = flags;
       
  1032     nfo.shaperItem = shaperItem;
       
  1033 
       
  1034     int prevNumGlyphs = *nglyphs;
       
  1035 
       
  1036     QVarLengthArray<int> mappedFonts(len);
       
  1037     for (int i = 0; i < len; ++i)
       
  1038         mappedFonts[i] = 0;
       
  1039     nfo.mappedFonts = mappedFonts.data();
       
  1040 
       
  1041     Q_ASSERT(sizeof(void *) <= sizeof(URefCon));
       
  1042     e = ATSUSetTextLayoutRefCon(textLayout, (URefCon)&nfo);
       
  1043     if (e != noErr) {
       
  1044         qWarning("Qt: internal: %ld: Error ATSUSetTextLayoutRefCon %s: %d", long(e), __FILE__, __LINE__);
       
  1045         return false;
       
  1046     }
       
  1047 
       
  1048     {
       
  1049         const int maxAttributeCount = 3;
       
  1050         ATSUAttributeTag tags[maxAttributeCount + 1];
       
  1051         ByteCount sizes[maxAttributeCount + 1];
       
  1052         ATSUAttributeValuePtr values[maxAttributeCount + 1];
       
  1053         int attributeCount = 0;
       
  1054 
       
  1055         tags[attributeCount] = kATSULineLayoutOptionsTag;
       
  1056         ATSLineLayoutOptions layopts = kATSLineHasNoOpticalAlignment
       
  1057                                        | kATSLineIgnoreFontLeading
       
  1058                                        | kATSLineNoSpecialJustification // we do kashidas ourselves
       
  1059                                        | kATSLineDisableAllJustification
       
  1060                                        ;
       
  1061 
       
  1062 	layopts |= kATSLineUseDeviceMetrics;
       
  1063 
       
  1064         if (fontDef.styleStrategy & QFont::NoAntialias)
       
  1065             layopts |= kATSLineNoAntiAliasing;
       
  1066 
       
  1067         if (!kerning)
       
  1068             layopts |= kATSLineDisableAllKerningAdjustments;
       
  1069 
       
  1070         values[attributeCount] = &layopts;
       
  1071         sizes[attributeCount] = sizeof(layopts);
       
  1072         ++attributeCount;
       
  1073 
       
  1074         tags[attributeCount] = kATSULayoutOperationOverrideTag;
       
  1075         ATSULayoutOperationOverrideSpecifier spec;
       
  1076         spec.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
       
  1077         spec.overrideUPP = atsuPostLayoutCallback;
       
  1078         values[attributeCount] = &spec;
       
  1079         sizes[attributeCount] = sizeof(spec);
       
  1080         ++attributeCount;
       
  1081 
       
  1082         // CTWritingDirection
       
  1083         Boolean direction;
       
  1084         if (flags & QTextEngine::RightToLeft)
       
  1085             direction = kATSURightToLeftBaseDirection;
       
  1086         else
       
  1087             direction = kATSULeftToRightBaseDirection;
       
  1088         tags[attributeCount] = kATSULineDirectionTag;
       
  1089         values[attributeCount] = &direction;
       
  1090         sizes[attributeCount] = sizeof(direction);
       
  1091         ++attributeCount;
       
  1092 
       
  1093         Q_ASSERT(attributeCount < maxAttributeCount + 1);
       
  1094         e = ATSUSetLayoutControls(textLayout, attributeCount, tags, sizes, values);
       
  1095         if (e != noErr) {
       
  1096             qWarning("Qt: internal: %ld: Error ATSUSetLayoutControls %s: %d", long(e), __FILE__, __LINE__);
       
  1097             return false;
       
  1098         }
       
  1099 
       
  1100     }
       
  1101 
       
  1102     e = ATSUSetRunStyle(textLayout, style, 0, len);
       
  1103     if (e != noErr) {
       
  1104         qWarning("Qt: internal: %ld: Error ATSUSetRunStyle %s: %d", long(e), __FILE__, __LINE__);
       
  1105         return false;
       
  1106     }
       
  1107 
       
  1108     if (!(fontDef.styleStrategy & QFont::NoFontMerging)) {
       
  1109         int pos = 0;
       
  1110         do {
       
  1111             ATSUFontID substFont = 0;
       
  1112             UniCharArrayOffset changedOffset = 0;
       
  1113             UniCharCount changeCount = 0;
       
  1114 
       
  1115             e = ATSUMatchFontsToText(textLayout, pos, len - pos,
       
  1116                                      &substFont, &changedOffset,
       
  1117                                      &changeCount);
       
  1118             if (e == kATSUFontsMatched) {
       
  1119                 int fontIdx = fontIndexForFontID(substFont);
       
  1120                 for (uint i = 0; i < changeCount; ++i)
       
  1121                     mappedFonts[changedOffset + i] = fontIdx;
       
  1122                 pos = changedOffset + changeCount;
       
  1123                 ATSUSetRunStyle(textLayout, engineAt(fontIdx)->style, changedOffset, changeCount);
       
  1124             } else if (e == kATSUFontsNotMatched) {
       
  1125                 pos = changedOffset + changeCount;
       
  1126             }
       
  1127         } while (pos < len && e != noErr);
       
  1128     }
       
  1129     {    // trigger the a layout
       
  1130         // CFAttributedStringCreate, CTFramesetterCreateWithAttributedString (or perhaps Typesetter)
       
  1131         Rect rect;
       
  1132         e = ATSUMeasureTextImage(textLayout, kATSUFromTextBeginning, kATSUToTextEnd,
       
  1133                                  /*iLocationX =*/ 0, /*iLocationY =*/ 0,
       
  1134                                  &rect);
       
  1135         if (e != noErr) {
       
  1136             qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage %s: %d", long(e), __FILE__, __LINE__);
       
  1137             return false;
       
  1138         }
       
  1139     }
       
  1140 
       
  1141     if (!nfo.callbackCalled) {
       
  1142             qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage did not trigger callback %s: %d", long(e), __FILE__, __LINE__);
       
  1143             return false;
       
  1144     }
       
  1145 
       
  1146     ATSUClearLayoutCache(textLayout, kATSUFromTextBeginning);
       
  1147     if (prevNumGlyphs < *nfo.numGlyphs)
       
  1148         return false;
       
  1149     return true;
       
  1150 }
       
  1151 
       
  1152 void QFontEngineMacMulti::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
       
  1153 {
       
  1154     Q_ASSERT(false);
       
  1155     Q_UNUSED(glyphs);
       
  1156     Q_UNUSED(flags);
       
  1157 }
       
  1158 
       
  1159 void QFontEngineMacMulti::doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const
       
  1160 {
       
  1161     //Q_ASSERT(false);
       
  1162 }
       
  1163 
       
  1164 void QFontEngineMacMulti::loadEngine(int /*at*/)
       
  1165 {
       
  1166     // should never be called!
       
  1167     Q_ASSERT(false);
       
  1168 }
       
  1169 
       
  1170 bool QFontEngineMacMulti::canRender(const QChar *string, int len)
       
  1171 {
       
  1172     ATSUSetTextPointerLocation(textLayout, reinterpret_cast<const UniChar *>(string), 0, len, len);
       
  1173     ATSUSetRunStyle(textLayout, style, 0, len);
       
  1174 
       
  1175     OSStatus e = noErr;
       
  1176     int pos = 0;
       
  1177     do {
       
  1178         FMFont substFont = 0;
       
  1179         UniCharArrayOffset changedOffset = 0;
       
  1180         UniCharCount changeCount = 0;
       
  1181 
       
  1182         // CTFontCreateForString
       
  1183         e = ATSUMatchFontsToText(textLayout, pos, len - pos,
       
  1184                                  &substFont, &changedOffset,
       
  1185                                  &changeCount);
       
  1186         if (e == kATSUFontsMatched) {
       
  1187             pos = changedOffset + changeCount;
       
  1188         } else if (e == kATSUFontsNotMatched) {
       
  1189             break;
       
  1190         }
       
  1191     } while (pos < len && e != noErr);
       
  1192 
       
  1193     return e == noErr || e == kATSUFontsMatched;
       
  1194 }
       
  1195 
       
  1196 QFontEngineMac::QFontEngineMac(ATSUStyle baseStyle, ATSUFontID fontID, const QFontDef &def, QFontEngineMacMulti *multiEngine)
       
  1197     : fontID(fontID), multiEngine(multiEngine), cmap(0), symbolCMap(false)
       
  1198 {
       
  1199     fontDef = def;
       
  1200     ATSUCreateAndCopyStyle(baseStyle, &style);
       
  1201     ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
       
  1202     cgFont = CGFontCreateWithPlatformFont(&atsFont);
       
  1203 
       
  1204     const int maxAttributeCount = 4;
       
  1205     ATSUAttributeTag tags[maxAttributeCount + 1];
       
  1206     ByteCount sizes[maxAttributeCount + 1];
       
  1207     ATSUAttributeValuePtr values[maxAttributeCount + 1];
       
  1208     int attributeCount = 0;
       
  1209 
       
  1210     synthesisFlags = 0;
       
  1211 
       
  1212     // synthesizing using CG is not recommended
       
  1213     quint16 macStyle = 0;
       
  1214     {
       
  1215         uchar data[4];
       
  1216         ByteCount len = 4;
       
  1217         if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 44, 4, &data, &len) == noErr)
       
  1218             macStyle = qFromBigEndian<quint16>(data);
       
  1219     }
       
  1220 
       
  1221     Boolean atsuBold = false;
       
  1222     Boolean atsuItalic = false;
       
  1223     if (fontDef.weight >= QFont::Bold) {
       
  1224         if (!(macStyle & 1)) {
       
  1225             synthesisFlags |= SynthesizedBold;
       
  1226             atsuBold = true;
       
  1227             tags[attributeCount] = kATSUQDBoldfaceTag;
       
  1228             sizes[attributeCount] = sizeof(atsuBold);
       
  1229             values[attributeCount] = &atsuBold;
       
  1230             ++attributeCount;
       
  1231         }
       
  1232     }
       
  1233     if (fontDef.style != QFont::StyleNormal) {
       
  1234         if (!(macStyle & 2)) {
       
  1235             synthesisFlags |= SynthesizedItalic;
       
  1236             atsuItalic = true;
       
  1237             tags[attributeCount] = kATSUQDItalicTag;
       
  1238             sizes[attributeCount] = sizeof(atsuItalic);
       
  1239             values[attributeCount] = &atsuItalic;
       
  1240             ++attributeCount;
       
  1241         }
       
  1242     }
       
  1243 
       
  1244     tags[attributeCount] = kATSUFontTag;
       
  1245     values[attributeCount] = &fontID;
       
  1246     sizes[attributeCount] = sizeof(fontID);
       
  1247     ++attributeCount;
       
  1248 
       
  1249     Q_ASSERT(attributeCount < maxAttributeCount + 1);
       
  1250     OSStatus err = ATSUSetAttributes(style, attributeCount, tags, sizes, values);
       
  1251     Q_ASSERT(err == noErr);
       
  1252     Q_UNUSED(err);
       
  1253 
       
  1254     // CTFontCopyTable
       
  1255     quint16 tmpFsType;
       
  1256     if (ATSFontGetTable(atsFont, MAKE_TAG('O', 'S', '/', '2'), 8, 2, &tmpFsType, 0) == noErr)
       
  1257        fsType = qFromBigEndian<quint16>(tmpFsType);
       
  1258     else
       
  1259         fsType = 0;
       
  1260 
       
  1261     if (multiEngine)
       
  1262 	transform = multiEngine->transform;
       
  1263     else
       
  1264 	transform = CGAffineTransformIdentity;
       
  1265 
       
  1266     ATSUTextMeasurement metric;
       
  1267 
       
  1268     ATSUGetAttribute(style, kATSUAscentTag, sizeof(metric), &metric, 0);
       
  1269     m_ascent = FixRound(metric);
       
  1270 
       
  1271     ATSUGetAttribute(style, kATSUDescentTag, sizeof(metric), &metric, 0);
       
  1272     m_descent = FixRound(metric);
       
  1273 
       
  1274     ATSUGetAttribute(style, kATSULeadingTag, sizeof(metric), &metric, 0);
       
  1275     m_leading = FixRound(metric);
       
  1276 
       
  1277     ATSFontMetrics metrics;
       
  1278 
       
  1279     ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
       
  1280     m_maxCharWidth = metrics.maxAdvanceWidth * fontDef.pointSize;
       
  1281 
       
  1282     ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
       
  1283     m_xHeight = QFixed::fromReal(metrics.xHeight * fontDef.pointSize);
       
  1284 
       
  1285     ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
       
  1286     m_averageCharWidth = QFixed::fromReal(metrics.avgAdvanceWidth * fontDef.pointSize);
       
  1287 
       
  1288     // Use width of 'X' if ATSFontGetHorizontalMetrics returns 0 for avgAdvanceWidth.
       
  1289     if (m_averageCharWidth == QFixed(0)) {
       
  1290         QChar c('X');
       
  1291         QGlyphLayoutArray<1> glyphs;
       
  1292         int nglyphs = 1;
       
  1293         stringToCMap(&c, 1, &glyphs, &nglyphs, 0);
       
  1294         glyph_metrics_t metrics = boundingBox(glyphs);
       
  1295         m_averageCharWidth =  metrics.width;
       
  1296     }
       
  1297 }
       
  1298 
       
  1299 QFontEngineMac::~QFontEngineMac()
       
  1300 {
       
  1301     ATSUDisposeStyle(style);
       
  1302 }
       
  1303 
       
  1304 static inline unsigned int getChar(const QChar *str, int &i, const int len)
       
  1305 {
       
  1306     unsigned int uc = str[i].unicode();
       
  1307     if (uc >= 0xd800 && uc < 0xdc00 && i < len-1) {
       
  1308         uint low = str[i+1].unicode();
       
  1309        if (low >= 0xdc00 && low < 0xe000) {
       
  1310             uc = (uc - 0xd800)*0x400 + (low - 0xdc00) + 0x10000;
       
  1311             ++i;
       
  1312         }
       
  1313     }
       
  1314     return uc;
       
  1315 }
       
  1316 
       
  1317 bool QFontEngineMac::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
       
  1318 {
       
  1319     if (!cmap) {
       
  1320         cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
       
  1321         int size = 0;
       
  1322         cmap = getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), cmapTable.size(), &symbolCMap, &size);
       
  1323         if (!cmap)
       
  1324             return false;
       
  1325     }
       
  1326     if (symbolCMap) {
       
  1327         for (int i = 0; i < len; ++i) {
       
  1328             unsigned int uc = getChar(str, i, len);
       
  1329             glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
       
  1330             if(!glyphs->glyphs[i] && uc < 0x100)
       
  1331                 glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
       
  1332         }
       
  1333     } else {
       
  1334         for (int i = 0; i < len; ++i) {
       
  1335             unsigned int uc = getChar(str, i, len);
       
  1336             glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
       
  1337         }
       
  1338     }
       
  1339 
       
  1340     *nglyphs = len;
       
  1341     glyphs->numGlyphs = *nglyphs;
       
  1342 
       
  1343     if (!(flags & QTextEngine::GlyphIndicesOnly))
       
  1344         recalcAdvances(glyphs, flags);
       
  1345 
       
  1346     return true;
       
  1347 }
       
  1348 
       
  1349 void QFontEngineMac::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
       
  1350 {
       
  1351     Q_UNUSED(flags)
       
  1352 
       
  1353     QVarLengthArray<GlyphID> atsuGlyphs(glyphs->numGlyphs);
       
  1354     for (int i = 0; i < glyphs->numGlyphs; ++i)
       
  1355         atsuGlyphs[i] = glyphs->glyphs[i];
       
  1356 
       
  1357     QVarLengthArray<ATSGlyphScreenMetrics> metrics(glyphs->numGlyphs);
       
  1358 
       
  1359     ATSUGlyphGetScreenMetrics(style, glyphs->numGlyphs, atsuGlyphs.data(), sizeof(GlyphID),
       
  1360                               /* iForcingAntiAlias =*/ false,
       
  1361                               /* iAntiAliasSwitch =*/true,
       
  1362                               metrics.data());
       
  1363 
       
  1364     for (int i = 0; i < glyphs->numGlyphs; ++i) {
       
  1365         glyphs->advances_x[i] = QFixed::fromReal(metrics[i].deviceAdvance.x);
       
  1366         glyphs->advances_y[i] = QFixed::fromReal(metrics[i].deviceAdvance.y);
       
  1367     }
       
  1368 }
       
  1369 
       
  1370 glyph_metrics_t QFontEngineMac::boundingBox(const QGlyphLayout &glyphs)
       
  1371 {
       
  1372     QFixed w;
       
  1373     for (int i = 0; i < glyphs.numGlyphs; ++i)
       
  1374         w += glyphs.effectiveAdvance(i);
       
  1375     return glyph_metrics_t(0, -(ascent()), w, ascent()+descent(), w, 0);
       
  1376 }
       
  1377 
       
  1378 glyph_metrics_t QFontEngineMac::boundingBox(glyph_t glyph)
       
  1379 {
       
  1380     GlyphID atsuGlyph = glyph;
       
  1381 
       
  1382     ATSGlyphScreenMetrics metrics;
       
  1383 
       
  1384     ATSUGlyphGetScreenMetrics(style, 1, &atsuGlyph, 0,
       
  1385                               /* iForcingAntiAlias =*/ false,
       
  1386                               /* iAntiAliasSwitch =*/true,
       
  1387                               &metrics);
       
  1388 
       
  1389     // ### check again
       
  1390 
       
  1391     glyph_metrics_t gm;
       
  1392     gm.width = int(metrics.width);
       
  1393     gm.height = int(metrics.height);
       
  1394     gm.x = QFixed::fromReal(metrics.topLeft.x);
       
  1395     gm.y = -QFixed::fromReal(metrics.topLeft.y);
       
  1396     gm.xoff = QFixed::fromReal(metrics.deviceAdvance.x);
       
  1397     gm.yoff = QFixed::fromReal(metrics.deviceAdvance.y);
       
  1398 
       
  1399     return gm;
       
  1400 }
       
  1401 
       
  1402 QFixed QFontEngineMac::ascent() const
       
  1403 {
       
  1404     return m_ascent;
       
  1405 }
       
  1406 
       
  1407 QFixed QFontEngineMac::descent() const
       
  1408 {
       
  1409     return m_descent;
       
  1410 }
       
  1411 
       
  1412 QFixed QFontEngineMac::leading() const
       
  1413 {
       
  1414     return m_leading;
       
  1415 }
       
  1416 
       
  1417 qreal QFontEngineMac::maxCharWidth() const
       
  1418 {
       
  1419     return m_maxCharWidth;
       
  1420 }
       
  1421 
       
  1422 QFixed QFontEngineMac::xHeight() const
       
  1423 {
       
  1424     return m_xHeight;
       
  1425 }
       
  1426 
       
  1427 QFixed QFontEngineMac::averageCharWidth() const
       
  1428 {
       
  1429     return m_averageCharWidth;
       
  1430 }
       
  1431 
       
  1432 static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path)
       
  1433 {
       
  1434     if (!numGlyphs)
       
  1435         return;
       
  1436 
       
  1437     OSStatus e;
       
  1438 
       
  1439     QMacFontPath fontpath(0, 0, path);
       
  1440     ATSCubicMoveToUPP moveTo = NewATSCubicMoveToUPP(QMacFontPath::moveTo);
       
  1441     ATSCubicLineToUPP lineTo = NewATSCubicLineToUPP(QMacFontPath::lineTo);
       
  1442     ATSCubicCurveToUPP cubicTo = NewATSCubicCurveToUPP(QMacFontPath::cubicTo);
       
  1443     ATSCubicClosePathUPP closePath = NewATSCubicClosePathUPP(QMacFontPath::closePath);
       
  1444 
       
  1445     // CTFontCreatePathForGlyph
       
  1446     for (int i = 0; i < numGlyphs; ++i) {
       
  1447         GlyphID glyph = glyphs[i];
       
  1448 
       
  1449         fontpath.setPosition(positions[i].x.toReal(), positions[i].y.toReal());
       
  1450         ATSUGlyphGetCubicPaths(style, glyph, moveTo, lineTo,
       
  1451                                cubicTo, closePath, &fontpath, &e);
       
  1452     }
       
  1453 
       
  1454     DisposeATSCubicMoveToUPP(moveTo);
       
  1455     DisposeATSCubicLineToUPP(lineTo);
       
  1456     DisposeATSCubicCurveToUPP(cubicTo);
       
  1457     DisposeATSCubicClosePathUPP(closePath);
       
  1458 }
       
  1459 
       
  1460 void QFontEngineMac::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path,
       
  1461                                            QTextItem::RenderFlags)
       
  1462 {
       
  1463     addGlyphsToPathHelper(style, glyphs, positions, numGlyphs, path);
       
  1464 }
       
  1465 
       
  1466 
       
  1467 /*!
       
  1468   Helper function for alphaMapForGlyph and alphaRGBMapForGlyph. The two are identical, except for
       
  1469   the subpixel antialiasing...
       
  1470 */
       
  1471 QImage QFontEngineMac::imageForGlyph(glyph_t glyph, int margin, bool colorful)
       
  1472 {
       
  1473     const glyph_metrics_t br = boundingBox(glyph);
       
  1474     QImage im(qRound(br.width)+2, qRound(br.height)+4, QImage::Format_RGB32);
       
  1475     im.fill(0xff000000);
       
  1476 
       
  1477     CGColorSpaceRef colorspace = QCoreGraphicsPaintEngine::macGenericColorSpace();
       
  1478     uint cgflags = kCGImageAlphaNoneSkipFirst;
       
  1479 #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
       
  1480     cgflags |= kCGBitmapByteOrder32Host;
       
  1481 #endif
       
  1482     CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
       
  1483                                              8, im.bytesPerLine(), colorspace,
       
  1484                                              cgflags);
       
  1485     CGContextSetFontSize(ctx, fontDef.pixelSize);
       
  1486     CGContextSetShouldAntialias(ctx, fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias));
       
  1487     // turn off sub-pixel hinting - no support for that in OpenGL
       
  1488     CGContextSetShouldSmoothFonts(ctx, colorful);
       
  1489     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
       
  1490     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
       
  1491     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
       
  1492 
       
  1493     if (synthesisFlags & QFontEngine::SynthesizedItalic)
       
  1494         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
       
  1495 
       
  1496     cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
       
  1497 
       
  1498     CGContextSetTextMatrix(ctx, cgMatrix);
       
  1499     CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
       
  1500     CGContextSetTextDrawingMode(ctx, kCGTextFill);
       
  1501     CGContextSetFont(ctx, cgFont);
       
  1502 
       
  1503     qreal pos_x = -br.x.toReal() + 1;
       
  1504     qreal pos_y = im.height() + br.y.toReal() - 2;
       
  1505     CGContextSetTextPosition(ctx, pos_x, pos_y);
       
  1506 
       
  1507     CGSize advance;
       
  1508     advance.width = 0;
       
  1509     advance.height = 0;
       
  1510     CGGlyph cgGlyph = glyph;
       
  1511     CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
       
  1512 
       
  1513     if (synthesisFlags & QFontEngine::SynthesizedBold) {
       
  1514         CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
       
  1515         CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
       
  1516     }
       
  1517 
       
  1518     CGContextRelease(ctx);
       
  1519 
       
  1520     return im;
       
  1521 }
       
  1522 
       
  1523 QImage QFontEngineMac::alphaMapForGlyph(glyph_t glyph)
       
  1524 {
       
  1525     QImage im = imageForGlyph(glyph, 2, false);
       
  1526 
       
  1527     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
       
  1528     QVector<QRgb> colors(256);
       
  1529     for (int i=0; i<256; ++i)
       
  1530         colors[i] = qRgba(0, 0, 0, i);
       
  1531     indexed.setColorTable(colors);
       
  1532 
       
  1533     for (int y=0; y<im.height(); ++y) {
       
  1534         uint *src = (uint*) im.scanLine(y);
       
  1535         uchar *dst = indexed.scanLine(y);
       
  1536         for (int x=0; x<im.width(); ++x) {
       
  1537             *dst = qGray(*src);
       
  1538             ++dst;
       
  1539             ++src;
       
  1540         }
       
  1541     }
       
  1542 
       
  1543     return indexed;
       
  1544 }
       
  1545 
       
  1546 QImage QFontEngineMac::alphaRGBMapForGlyph(glyph_t glyph, int margin, const QTransform &t)
       
  1547 {
       
  1548     QImage im = imageForGlyph(glyph, margin, true);
       
  1549 
       
  1550     if (t.type() >= QTransform::TxScale) {
       
  1551         im = im.transformed(t);
       
  1552     }
       
  1553 
       
  1554     qmacfontengine_gamma_correct(&im);
       
  1555 
       
  1556     return im;
       
  1557 }
       
  1558 
       
  1559 
       
  1560 bool QFontEngineMac::canRender(const QChar *string, int len)
       
  1561 {
       
  1562     Q_ASSERT(false);
       
  1563     Q_UNUSED(string);
       
  1564     Q_UNUSED(len);
       
  1565     return false;
       
  1566 }
       
  1567 
       
  1568 void QFontEngineMac::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
       
  1569 {
       
  1570     QVarLengthArray<QFixedPoint> positions;
       
  1571     QVarLengthArray<glyph_t> glyphs;
       
  1572     QTransform matrix;
       
  1573     matrix.translate(x, y);
       
  1574     getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
       
  1575     if (glyphs.size() == 0)
       
  1576         return;
       
  1577 
       
  1578     CGContextSetFontSize(ctx, fontDef.pixelSize);
       
  1579 
       
  1580     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
       
  1581 
       
  1582     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight);
       
  1583 
       
  1584     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
       
  1585 
       
  1586     if (synthesisFlags & QFontEngine::SynthesizedItalic)
       
  1587         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
       
  1588 
       
  1589     cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
       
  1590 
       
  1591     CGContextSetTextMatrix(ctx, cgMatrix);
       
  1592 
       
  1593     CGContextSetTextDrawingMode(ctx, kCGTextFill);
       
  1594 
       
  1595 
       
  1596     QVarLengthArray<CGSize> advances(glyphs.size());
       
  1597     QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size());
       
  1598 
       
  1599     for (int i = 0; i < glyphs.size() - 1; ++i) {
       
  1600         advances[i].width = (positions[i + 1].x - positions[i].x).toReal();
       
  1601         advances[i].height = (positions[i + 1].y - positions[i].y).toReal();
       
  1602         cgGlyphs[i] = glyphs[i];
       
  1603     }
       
  1604     advances[glyphs.size() - 1].width = 0;
       
  1605     advances[glyphs.size() - 1].height = 0;
       
  1606     cgGlyphs[glyphs.size() - 1] = glyphs[glyphs.size() - 1];
       
  1607 
       
  1608     CGContextSetFont(ctx, cgFont);
       
  1609 
       
  1610     CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal());
       
  1611 
       
  1612     CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
       
  1613 
       
  1614     if (synthesisFlags & QFontEngine::SynthesizedBold) {
       
  1615         CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(),
       
  1616                                       positions[0].y.toReal());
       
  1617 
       
  1618         CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
       
  1619     }
       
  1620 
       
  1621     CGContextSetTextMatrix(ctx, oldTextMatrix);
       
  1622 }
       
  1623 
       
  1624 QFontEngine::FaceId QFontEngineMac::faceId() const
       
  1625 {
       
  1626     FaceId ret;
       
  1627 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
       
  1628 if (QSysInfo::MacintoshVersion >= QSysInfo::MV_10_5) {
       
  1629     // CTFontGetPlatformFont
       
  1630     FSRef ref;
       
  1631     if (ATSFontGetFileReference(FMGetATSFontRefFromFont(fontID), &ref) != noErr)
       
  1632         return ret;
       
  1633     ret.filename = QByteArray(128, 0);
       
  1634     ret.index = fontID;
       
  1635     FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
       
  1636 }else
       
  1637 #endif
       
  1638 {
       
  1639     FSSpec spec;
       
  1640     if (ATSFontGetFileSpecification(FMGetATSFontRefFromFont(fontID), &spec) != noErr)
       
  1641         return ret;
       
  1642 
       
  1643     FSRef ref;
       
  1644     FSpMakeFSRef(&spec, &ref);
       
  1645     ret.filename = QByteArray(128, 0);
       
  1646     ret.index = fontID;
       
  1647     FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
       
  1648 }
       
  1649     return ret;
       
  1650 }
       
  1651 
       
  1652 QByteArray QFontEngineMac::getSfntTable(uint tag) const
       
  1653 {
       
  1654     ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
       
  1655 
       
  1656     ByteCount length;
       
  1657     OSStatus status = ATSFontGetTable(atsFont, tag, 0, 0, 0, &length);
       
  1658     if (status != noErr)
       
  1659         return QByteArray();
       
  1660     QByteArray table(length, 0);
       
  1661     // CTFontCopyTable
       
  1662     status = ATSFontGetTable(atsFont, tag, 0, table.length(), table.data(), &length);
       
  1663     if (status != noErr)
       
  1664         return QByteArray();
       
  1665     return table;
       
  1666 }
       
  1667 
       
  1668 QFontEngine::Properties QFontEngineMac::properties() const
       
  1669 {
       
  1670     QFontEngine::Properties props;
       
  1671     ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
       
  1672     quint16 tmp;
       
  1673     // CTFontGetUnitsPerEm
       
  1674     if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 18, 2, &tmp, 0) == noErr)
       
  1675        props.emSquare = qFromBigEndian<quint16>(tmp);
       
  1676     struct {
       
  1677         qint16 xMin;
       
  1678         qint16 yMin;
       
  1679         qint16 xMax;
       
  1680         qint16 yMax;
       
  1681     } bbox;
       
  1682     bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
       
  1683     // CTFontGetBoundingBox
       
  1684     if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 36, 8, &bbox, 0) == noErr) {
       
  1685         bbox.xMin = qFromBigEndian<quint16>(bbox.xMin);
       
  1686         bbox.yMin = qFromBigEndian<quint16>(bbox.yMin);
       
  1687         bbox.xMax = qFromBigEndian<quint16>(bbox.xMax);
       
  1688         bbox.yMax = qFromBigEndian<quint16>(bbox.yMax);
       
  1689     }
       
  1690     struct {
       
  1691         qint16 ascender;
       
  1692         qint16 descender;
       
  1693         qint16 linegap;
       
  1694     } metrics;
       
  1695     metrics.ascender = metrics.descender = metrics.linegap = 0;
       
  1696     // CTFontGetAscent, etc.
       
  1697     if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'h', 'e', 'a'), 4, 6, &metrics, 0) == noErr) {
       
  1698         metrics.ascender = qFromBigEndian<quint16>(metrics.ascender);
       
  1699         metrics.descender = qFromBigEndian<quint16>(metrics.descender);
       
  1700         metrics.linegap = qFromBigEndian<quint16>(metrics.linegap);
       
  1701     }
       
  1702     props.ascent = metrics.ascender;
       
  1703     props.descent = -metrics.descender;
       
  1704     props.leading = metrics.linegap;
       
  1705     props.boundingBox = QRectF(bbox.xMin, -bbox.yMax,
       
  1706                            bbox.xMax - bbox.xMin,
       
  1707                            bbox.yMax - bbox.yMin);
       
  1708     props.italicAngle = 0;
       
  1709     props.capHeight = props.ascent;
       
  1710 
       
  1711     qint16 lw = 0;
       
  1712     // fonts lie
       
  1713     if (ATSFontGetTable(atsFont, MAKE_TAG('p', 'o', 's', 't'), 10, 2, &lw, 0) == noErr)
       
  1714        lw = qFromBigEndian<quint16>(lw);
       
  1715     props.lineWidth = lw;
       
  1716 
       
  1717     // CTFontCopyPostScriptName
       
  1718     QCFString psName;
       
  1719     if (ATSFontGetPostScriptName(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &psName) == noErr)
       
  1720         props.postscriptName = QString(psName).toUtf8();
       
  1721     props.postscriptName = QPdf::stripSpecialCharacters(props.postscriptName);
       
  1722     return props;
       
  1723 }
       
  1724 
       
  1725 void QFontEngineMac::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
       
  1726 {
       
  1727     ATSUStyle unscaledStyle;
       
  1728     ATSUCreateAndCopyStyle(style, &unscaledStyle);
       
  1729 
       
  1730     int emSquare = properties().emSquare.toInt();
       
  1731 
       
  1732     const int maxAttributeCount = 4;
       
  1733     ATSUAttributeTag tags[maxAttributeCount + 1];
       
  1734     ByteCount sizes[maxAttributeCount + 1];
       
  1735     ATSUAttributeValuePtr values[maxAttributeCount + 1];
       
  1736     int attributeCount = 0;
       
  1737 
       
  1738     Fixed size = FixRatio(emSquare, 1);
       
  1739     tags[attributeCount] = kATSUSizeTag;
       
  1740     sizes[attributeCount] = sizeof(size);
       
  1741     values[attributeCount] = &size;
       
  1742     ++attributeCount;
       
  1743 
       
  1744     Q_ASSERT(attributeCount < maxAttributeCount + 1);
       
  1745     OSStatus err = ATSUSetAttributes(unscaledStyle, attributeCount, tags, sizes, values);
       
  1746     Q_ASSERT(err == noErr);
       
  1747     Q_UNUSED(err);
       
  1748 
       
  1749     // various CTFont metrics functions: CTFontGetBoundingRectsForGlyphs, CTFontGetAdvancesForGlyphs
       
  1750     GlyphID atsuGlyph = glyph;
       
  1751     ATSGlyphScreenMetrics atsuMetrics;
       
  1752     ATSUGlyphGetScreenMetrics(unscaledStyle, 1, &atsuGlyph, 0,
       
  1753                               /* iForcingAntiAlias =*/ false,
       
  1754                               /* iAntiAliasSwitch =*/true,
       
  1755                               &atsuMetrics);
       
  1756 
       
  1757     metrics->width = int(atsuMetrics.width);
       
  1758     metrics->height = int(atsuMetrics.height);
       
  1759     metrics->x = QFixed::fromReal(atsuMetrics.topLeft.x);
       
  1760     metrics->y = -QFixed::fromReal(atsuMetrics.topLeft.y);
       
  1761     metrics->xoff = QFixed::fromReal(atsuMetrics.deviceAdvance.x);
       
  1762     metrics->yoff = QFixed::fromReal(atsuMetrics.deviceAdvance.y);
       
  1763 
       
  1764     QFixedPoint p;
       
  1765     addGlyphsToPathHelper(unscaledStyle, &glyph, &p, 1, path);
       
  1766 
       
  1767     ATSUDisposeStyle(unscaledStyle);
       
  1768 }
       
  1769 #endif // !QT_MAC_USE_COCOA
       
  1770 
       
  1771 QT_END_NAMESPACE