Fix uses of qRound on non-floating-point types.
[profile/ivi/qtbase.git] / src / gui / text / qfontengine_coretext.mm
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 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 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qfontengine_coretext_p.h"
43
44 #include <QtCore/qendian.h>
45 #include <QtCore/qsettings.h>
46
47 #include <private/qimage_p.h>
48
49 #if !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
50
51 QT_BEGIN_NAMESPACE
52
53 static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90);
54
55 static void loadAdvancesForGlyphs(CTFontRef ctfont,
56                                   QVarLengthArray<CGGlyph> &cgGlyphs,
57                                   QGlyphLayout *glyphs, int len,
58                                   QTextEngine::ShaperFlags flags,
59                                   const QFontDef &fontDef)
60 {
61     Q_UNUSED(flags);
62     QVarLengthArray<CGSize> advances(len);
63     CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
64
65     for (int i = 0; i < len; ++i) {
66         if (glyphs->glyphs[i] & 0xff000000)
67             continue;
68         glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
69         glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
70     }
71
72     if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
73         for (int i = 0; i < len; ++i) {
74             glyphs->advances_x[i] = glyphs->advances_x[i].round();
75             glyphs->advances_y[i] = glyphs->advances_y[i].round();
76         }
77     }
78 }
79
80 QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning)
81     : QFontEngineMulti(0)
82 {
83     this->fontDef = fontDef;
84     CTFontSymbolicTraits symbolicTraits = 0;
85     if (fontDef.weight >= QFont::Bold)
86         symbolicTraits |= kCTFontBoldTrait;
87     switch (fontDef.style) {
88     case QFont::StyleNormal:
89         break;
90     case QFont::StyleItalic:
91     case QFont::StyleOblique:
92         symbolicTraits |= kCTFontItalicTrait;
93         break;
94     }
95
96     transform = CGAffineTransformIdentity;
97     if (fontDef.stretch != 100) {
98         transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
99     }
100
101     QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize);
102     QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, &transform);
103     ctfont = NULL;
104     // There is a side effect in Core Text: if we apply 0 as symbolic traits to a font in normal weight,
105     // we will get the light version of that font (while the way supposed to work doesn't:
106     // setting kCTFontWeightTrait to some value between -1.0 to 0.0 has no effect on font selection)
107     if (fontDef.weight != QFont::Normal || symbolicTraits)
108         ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits);
109
110     // CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does
111     // not exist for the given font. (for example italic)
112     if (ctfont == 0) {
113         ctfont = baseFont;
114         CFRetain(ctfont);
115     }
116     init(kerning);
117 }
118
119 QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CTFontRef ctFontRef, const QFontDef &fontDef, bool kerning)
120     : QFontEngineMulti(0)
121 {
122     this->fontDef = fontDef;
123     ctfont = (CTFontRef) CFRetain(ctFontRef);
124     init(kerning);
125 }
126
127 QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
128 {
129     CFRelease(ctfont);
130 }
131
132 void QCoreTextFontEngineMulti::init(bool kerning)
133 {
134     Q_ASSERT(ctfont != NULL);
135     attributeDict = CFDictionaryCreateMutable(0, 2,
136                                        &kCFTypeDictionaryKeyCallBacks,
137                                        &kCFTypeDictionaryValueCallBacks);
138     CFDictionaryAddValue(attributeDict, NSFontAttributeName, ctfont);
139     if (!kerning) {
140         float zero = 0.0;
141         QCFType<CFNumberRef> noKern = CFNumberCreate(kCFAllocatorDefault, kCFNumberFloatType, &zero);
142         CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern);
143     }
144
145     QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef);
146     fontDef.family = fe->fontDef.family;
147     fontDef.styleName = fe->fontDef.styleName;
148     transform = fe->transform;
149     fe->ref.ref();
150     engines.append(fe);
151 }
152
153 uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const
154 {
155     for (int i = 0; i < engines.count(); ++i) {
156         if (CFEqual(engineAt(i)->ctfont, font))
157             return i;
158     }
159
160     QCoreTextFontEngineMulti *that = const_cast<QCoreTextFontEngineMulti *>(this);
161     QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef);
162     fe->ref.ref();
163     that->engines.append(fe);
164     return engines.count() - 1;
165 }
166
167 bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
168                                             int *nglyphs, QTextEngine::ShaperFlags flags,
169                                             unsigned short *logClusters, const HB_CharAttributes *,
170                                             QScriptItem *si) const
171 {
172     QCFType<CFStringRef> cfstring = CFStringCreateWithCharactersNoCopy(0,
173                                                                reinterpret_cast<const UniChar *>(str),
174                                                                len, kCFAllocatorNull);
175     QCFType<CFAttributedStringRef> attributedString = CFAttributedStringCreate(0, cfstring, attributeDict);
176     QCFType<CTTypesetterRef> typeSetter;
177
178 #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
179     if (flags & QTextEngine::RightToLeft) {
180         const void *optionKeys[] = { kCTTypesetterOptionForcedEmbeddingLevel };
181         const short rtlForcedEmbeddingLevelValue = 1;
182         const void *rtlOptionValues[] = { CFNumberCreate(kCFAllocatorDefault, kCFNumberShortType, &rtlForcedEmbeddingLevelValue) };
183         QCFType<CFDictionaryRef> options = CFDictionaryCreate(kCFAllocatorDefault, optionKeys, rtlOptionValues, 1,
184                                                               &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
185         typeSetter = CTTypesetterCreateWithAttributedStringAndOptions(attributedString, options);
186     } else
187 #else
188     Q_UNUSED(flags);
189 #endif
190         typeSetter = CTTypesetterCreateWithAttributedString(attributedString);
191
192     CFRange range = {0, 0};
193     QCFType<CTLineRef> line = CTTypesetterCreateLine(typeSetter, range);
194     CFArrayRef array = CTLineGetGlyphRuns(line);
195     uint arraySize = CFArrayGetCount(array);
196     glyph_t *outGlyphs = glyphs->glyphs;
197     HB_GlyphAttributes *outAttributes = glyphs->attributes;
198     QFixed *outAdvances_x = glyphs->advances_x;
199     QFixed *outAdvances_y = glyphs->advances_y;
200     glyph_t *initialGlyph = outGlyphs;
201
202     if (arraySize == 0) {
203         // CoreText failed to shape the text we gave it, so we assume one glyph
204         // per character and build a list of invalid glyphs with zero advance
205         *nglyphs = len;
206         for (int i = 0; i < len; ++i) {
207             outGlyphs[i] = 0;
208             if (logClusters)
209                 logClusters[i] = i;
210             outAdvances_x[i] = QFixed();
211             outAdvances_y[i] = QFixed();
212             outAttributes[i].clusterStart = true;
213         }
214         return true;
215     }
216
217     const bool rtl = (CTRunGetStatus(static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, 0))) & kCTRunStatusRightToLeft);
218
219     bool outOBounds = false;
220     for (uint i = 0; i < arraySize; ++i) {
221         CTRunRef run = static_cast<CTRunRef>(CFArrayGetValueAtIndex(array, rtl ? (arraySize - 1 - i) : i));
222         CFIndex glyphCount = CTRunGetGlyphCount(run);
223         if (glyphCount == 0)
224             continue;
225
226         Q_ASSERT((CTRunGetStatus(run) & kCTRunStatusRightToLeft) == rtl);
227         CFRange stringRange = CTRunGetStringRange(run);
228         int prepend = 0;
229 #if MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5
230         UniChar beginGlyph = CFStringGetCharacterAtIndex(cfstring, stringRange.location);
231         QChar dir = QChar::direction(beginGlyph);
232         bool beginWithOverride = dir == QChar::DirLRO || dir == QChar::DirRLO || dir == QChar::DirLRE || dir == QChar::DirRLE;
233         if (beginWithOverride) {
234             logClusters[stringRange.location] = 0;
235             outGlyphs[0] = 0xFFFF;
236             outAdvances_x[0] = 0;
237             outAdvances_y[0] = 0;
238             outAttributes[0].clusterStart = true;
239             outAttributes[0].dontPrint = true;
240             outGlyphs++;
241             outAdvances_x++;
242             outAdvances_y++;
243             outAttributes++;
244             prepend = 1;
245         }
246 #endif
247         UniChar endGlyph = CFStringGetCharacterAtIndex(cfstring, stringRange.location + stringRange.length - 1);
248         bool endWithPDF = QChar::direction(endGlyph) == QChar::DirPDF;
249         if (endWithPDF)
250             glyphCount++;
251
252         if (!outOBounds && outGlyphs + glyphCount - initialGlyph > *nglyphs) {
253             outOBounds = true;
254         }
255         if (!outOBounds) {
256             CFDictionaryRef runAttribs = CTRunGetAttributes(run);
257             //NSLog(@"Dictionary %@", runAttribs);
258             if (!runAttribs)
259                 runAttribs = attributeDict;
260             CTFontRef runFont = static_cast<CTFontRef>(CFDictionaryGetValue(runAttribs, NSFontAttributeName));
261             uint fontIndex = fontIndexForFont(runFont);
262             const QFontEngine *engine = engineAt(fontIndex);
263             fontIndex <<= 24;
264             si->ascent = qMax(engine->ascent(), si->ascent);
265             si->descent = qMax(engine->descent(), si->descent);
266             si->leading = qMax(engine->leading(), si->leading);
267             //NSLog(@"Run Font Name = %@", CTFontCopyFamilyName(runFont));
268             if (endWithPDF)
269                 glyphCount--;
270
271             QVarLengthArray<CGGlyph, 512> cgglyphs(0);
272             const CGGlyph *tmpGlyphs = CTRunGetGlyphsPtr(run);
273             if (!tmpGlyphs) {
274                 cgglyphs.resize(glyphCount);
275                 CTRunGetGlyphs(run, range, cgglyphs.data());
276                 tmpGlyphs = cgglyphs.constData();
277             }
278             QVarLengthArray<CGPoint, 512> cgpoints(0);
279             const CGPoint *tmpPoints = CTRunGetPositionsPtr(run);
280             if (!tmpPoints) {
281                 cgpoints.resize(glyphCount);
282                 CTRunGetPositions(run, range, cgpoints.data());
283                 tmpPoints = cgpoints.constData();
284             }
285
286             const int rtlOffset = rtl ? (glyphCount - 1) : 0;
287             const int rtlSign = rtl ? -1 : 1;
288
289             if (logClusters) {
290                 CFRange stringRange = CTRunGetStringRange(run);
291                 QVarLengthArray<CFIndex, 512> stringIndices(0);
292                 const CFIndex *tmpIndices = CTRunGetStringIndicesPtr(run);
293                 if (!tmpIndices) {
294                     stringIndices.resize(glyphCount);
295                     CTRunGetStringIndices(run, range, stringIndices.data());
296                     tmpIndices = stringIndices.constData();
297                 }
298
299                 const int firstGlyphIndex = outGlyphs - initialGlyph;
300                 outAttributes[0].clusterStart = true;
301
302                 CFIndex k = 0;
303                 CFIndex i = 0;
304                 for (i = stringRange.location + prepend;
305                      (i < stringRange.location + stringRange.length) && (k < glyphCount); ++i) {
306                     if (tmpIndices[k * rtlSign + rtlOffset] == i || i == stringRange.location + prepend) {
307                         logClusters[i] = k + firstGlyphIndex;
308                         outAttributes[k].clusterStart = true;
309                         ++k;
310                     } else {
311                         logClusters[i] = k + firstGlyphIndex - 1;
312                     }
313                 }
314                 // in case of a ligature at the end, fill the remaining logcluster entries
315                 for (;i < stringRange.location + stringRange.length; i++) {
316                     logClusters[i] = k + firstGlyphIndex - 1;
317                 }
318             }
319             for (CFIndex i = 0; i < glyphCount - 1; ++i) {
320                 int idx = rtlOffset + rtlSign * i;
321                 outGlyphs[idx] = tmpGlyphs[i] | fontIndex;
322                 outAdvances_x[idx] = QFixed::fromReal(tmpPoints[i + 1].x - tmpPoints[i].x);
323                 // Use negative y advance for flipped coordinate system
324                 outAdvances_y[idx] = QFixed::fromReal(tmpPoints[i].y - tmpPoints[i + 1].y);
325
326                 if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
327                     outAdvances_x[idx] = outAdvances_x[idx].round();
328                     outAdvances_y[idx] = outAdvances_y[idx].round();
329                 }
330             }
331             CGSize lastGlyphAdvance;
332             CTFontGetAdvancesForGlyphs(runFont, kCTFontHorizontalOrientation, tmpGlyphs + glyphCount - 1, &lastGlyphAdvance, 1);
333
334             outGlyphs[rtl ? 0 : (glyphCount - 1)] = tmpGlyphs[glyphCount - 1] | fontIndex;
335             outAdvances_x[rtl ? 0 : (glyphCount - 1)] =
336                     (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
337                     ? QFixed::fromReal(lastGlyphAdvance.width).round()
338                     : QFixed::fromReal(lastGlyphAdvance.width);
339
340             if (endWithPDF) {
341                 logClusters[stringRange.location + stringRange.length - 1] = glyphCount + prepend;
342                 outGlyphs[glyphCount] = 0xFFFF;
343                 outAdvances_x[glyphCount] = 0;
344                 outAdvances_y[glyphCount] = 0;
345                 outAttributes[glyphCount].clusterStart = true;
346                 outAttributes[glyphCount].dontPrint = true;
347                 glyphCount++;
348             }
349         }
350         outGlyphs += glyphCount;
351         outAttributes += glyphCount;
352         outAdvances_x += glyphCount;
353         outAdvances_y += glyphCount;
354     }
355     *nglyphs = (outGlyphs - initialGlyph);
356     return !outOBounds;
357 }
358
359 bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
360                                             int *nglyphs, QTextEngine::ShaperFlags flags) const
361 {
362     *nglyphs = len;
363     QCFType<CFStringRef> cfstring;
364
365     QVarLengthArray<CGGlyph> cgGlyphs(len);
366     CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
367
368     for (int i = 0; i < len; ++i) {
369         if (cgGlyphs[i]) {
370             glyphs->glyphs[i] = cgGlyphs[i];
371         } else {
372             if (!cfstring)
373                 cfstring = CFStringCreateWithCharactersNoCopy(0, reinterpret_cast<const UniChar *>(str), len, kCFAllocatorNull);
374             QCFType<CTFontRef> substituteFont = CTFontCreateForString(ctfont, cfstring, CFRangeMake(i, 1));
375             CGGlyph substituteGlyph = 0;
376             CTFontGetGlyphsForCharacters(substituteFont, (const UniChar*)str + i, &substituteGlyph, 1);
377             if (substituteGlyph) {
378                 const uint fontIndex = (fontIndexForFont(substituteFont) << 24);
379                 glyphs->glyphs[i] = substituteGlyph | fontIndex;
380                 if (!(flags & QTextEngine::GlyphIndicesOnly)) {
381                     CGSize advance;
382                     CTFontGetAdvancesForGlyphs(substituteFont, kCTFontHorizontalOrientation, &substituteGlyph, &advance, 1);
383                     glyphs->advances_x[i] = QFixed::fromReal(advance.width);
384                     glyphs->advances_y[i] = QFixed::fromReal(advance.height);
385                 }
386             }
387         }
388     }
389
390     if (flags & QTextEngine::GlyphIndicesOnly)
391         return true;
392
393     loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
394     return true;
395 }
396
397 void QCoreTextFontEngineMulti::loadEngine(int)
398 {
399     // Do nothing
400     Q_ASSERT(false);
401 }
402
403 extern int qt_antialiasing_threshold; // from qapplication.cpp
404
405 CGAffineTransform qt_transform_from_fontdef(const QFontDef &fontDef)
406 {
407     CGAffineTransform transform = CGAffineTransformIdentity;
408     if (fontDef.stretch != 100)
409         transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
410     return transform;
411 }
412
413 QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
414 {
415     fontDef = def;
416     transform = qt_transform_from_fontdef(fontDef);
417     ctfont = font;
418     CFRetain(ctfont);
419     cgFont = CTFontCopyGraphicsFont(font, NULL);
420     init();
421 }
422
423 QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def)
424 {
425     fontDef = def;
426     transform = qt_transform_from_fontdef(fontDef);
427     cgFont = font;
428     // Keep reference count balanced
429     CFRetain(cgFont);
430     ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL);
431     init();
432 }
433
434 QCoreTextFontEngine::~QCoreTextFontEngine()
435 {
436     CFRelease(cgFont);
437     CFRelease(ctfont);
438 }
439
440 extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
441
442 int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait)
443 {
444     if (CFDictionaryContainsKey(allTraits, trait)) {
445         CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait);
446         float v = 0;
447         CFNumberGetValue(traitNum, kCFNumberFloatType, &v);
448         // the value we get from CFNumberRef is from -1.0 to 1.0
449         int value = v * 500 + 500;
450         return value;
451     }
452
453     return 0;
454 }
455
456 void QCoreTextFontEngine::init()
457 {
458     Q_ASSERT(ctfont != NULL);
459     Q_ASSERT(cgFont != NULL);
460
461     QCFString family = CTFontCopyFamilyName(ctfont);
462     fontDef.family = family;
463
464     QCFString styleName = (CFStringRef) CTFontCopyAttribute(ctfont, kCTFontStyleNameAttribute);
465     fontDef.styleName = styleName;
466
467     synthesisFlags = 0;
468     CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
469     if (traits & kCTFontItalicTrait)
470         fontDef.style = QFont::StyleItalic;
471
472     CFDictionaryRef allTraits = CTFontCopyTraits(ctfont);
473     fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait));
474     int slant = getTraitValue(allTraits, kCTFontSlantTrait);
475     if (slant > 500 && !(traits & kCTFontItalicTrait))
476         fontDef.style = QFont::StyleOblique;
477     CFRelease(allTraits);
478
479     if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait))
480         synthesisFlags |= SynthesizedBold;
481     // XXX: we probably don't need to synthesis italic for oblique font
482     if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait))
483         synthesisFlags |= SynthesizedItalic;
484
485     avgCharWidth = 0;
486     QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
487     unsigned emSize = CTFontGetUnitsPerEm(ctfont);
488     if (os2Table.size() >= 10) {
489         fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
490         // qAbs is a workaround for weird fonts like Lucida Grande
491         qint16 width = qAbs(qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 2)));
492         avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize);
493     } else
494         avgCharWidth = QFontEngine::averageCharWidth();
495 }
496
497 bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
498                                        int *nglyphs, QTextEngine::ShaperFlags flags) const
499 {
500     *nglyphs = len;
501     QCFType<CFStringRef> cfstring;
502
503     QVarLengthArray<CGGlyph> cgGlyphs(len);
504     CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
505
506     for (int i = 0; i < len; ++i)
507         if (cgGlyphs[i])
508             glyphs->glyphs[i] = cgGlyphs[i];
509
510     if (flags & QTextEngine::GlyphIndicesOnly)
511         return true;
512
513     loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
514     return true;
515 }
516
517 glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
518 {
519     QFixed w;
520     bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
521
522     for (int i = 0; i < glyphs.numGlyphs; ++i) {
523         w += round ? glyphs.effectiveAdvance(i).round()
524                    : glyphs.effectiveAdvance(i);
525     }
526     return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
527 }
528
529 glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
530 {
531     glyph_metrics_t ret;
532     CGGlyph g = glyph;
533     CGRect rect = CTFontGetBoundingRectsForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, 0, 1);
534     if (synthesisFlags & QFontEngine::SynthesizedItalic) {
535         rect.size.width += rect.size.height * SYNTHETIC_ITALIC_SKEW;
536     }
537     ret.width = QFixed::fromReal(rect.size.width);
538     ret.height = QFixed::fromReal(rect.size.height);
539     ret.x = QFixed::fromReal(rect.origin.x);
540     ret.y = -QFixed::fromReal(rect.origin.y) - ret.height;
541     CGSize advances[1];
542     CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, &g, advances, 1);
543     ret.xoff = QFixed::fromReal(advances[0].width);
544     ret.yoff = QFixed::fromReal(advances[0].height);
545
546     if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
547         ret.xoff = ret.xoff.round();
548         ret.yoff = ret.yoff.round();
549     }
550
551     return ret;
552 }
553
554 QFixed QCoreTextFontEngine::ascent() const
555 {
556     return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
557             ? QFixed::fromReal(CTFontGetAscent(ctfont)).round()
558             : QFixed::fromReal(CTFontGetAscent(ctfont));
559 }
560 QFixed QCoreTextFontEngine::descent() const
561 {
562     QFixed d = QFixed::fromReal(CTFontGetDescent(ctfont));
563     if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
564         d = d.round();
565
566     // subtract a pixel to even out the historical +1 in QFontMetrics::height().
567     // Fix in Qt 5.
568     return d - 1;
569 }
570 QFixed QCoreTextFontEngine::leading() const
571 {
572     return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
573             ? QFixed::fromReal(CTFontGetLeading(ctfont)).round()
574             : QFixed::fromReal(CTFontGetLeading(ctfont));
575 }
576 QFixed QCoreTextFontEngine::xHeight() const
577 {
578     return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
579             ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
580             : QFixed::fromReal(CTFontGetXHeight(ctfont));
581 }
582
583 QFixed QCoreTextFontEngine::averageCharWidth() const
584 {
585     return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
586             ? avgCharWidth.round() : avgCharWidth;
587 }
588
589 qreal QCoreTextFontEngine::maxCharWidth() const
590 {
591     return 0;
592 }
593
594 qreal QCoreTextFontEngine::minLeftBearing() const
595 {
596     return 0;
597 }
598
599 qreal QCoreTextFontEngine::minRightBearing() const
600 {
601     return 0;
602 }
603
604 void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
605 {
606     QVarLengthArray<QFixedPoint> positions;
607     QVarLengthArray<glyph_t> glyphs;
608     QTransform matrix;
609     matrix.translate(x, y);
610     getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
611     if (glyphs.size() == 0)
612         return;
613
614     CGContextSetFontSize(ctx, fontDef.pixelSize);
615
616     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
617
618     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight);
619
620     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
621
622     if (synthesisFlags & QFontEngine::SynthesizedItalic)
623         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
624
625     cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
626
627     CGContextSetTextMatrix(ctx, cgMatrix);
628
629     CGContextSetTextDrawingMode(ctx, kCGTextFill);
630
631
632     QVarLengthArray<CGSize> advances(glyphs.size());
633     QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size());
634
635     for (int i = 0; i < glyphs.size() - 1; ++i) {
636         advances[i].width = (positions[i + 1].x - positions[i].x).toReal();
637         advances[i].height = (positions[i + 1].y - positions[i].y).toReal();
638         cgGlyphs[i] = glyphs[i];
639     }
640     advances[glyphs.size() - 1].width = 0;
641     advances[glyphs.size() - 1].height = 0;
642     cgGlyphs[glyphs.size() - 1] = glyphs[glyphs.size() - 1];
643
644     CGContextSetFont(ctx, cgFont);
645     //NSLog(@"Font inDraw %@  ctfont %@", CGFontCopyFullName(cgFont), CTFontCopyFamilyName(ctfont));
646
647     CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal());
648
649     CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
650
651     if (synthesisFlags & QFontEngine::SynthesizedBold) {
652         CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(),
653                                  positions[0].y.toReal());
654
655         CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
656     }
657
658     CGContextSetTextMatrix(ctx, oldTextMatrix);
659 }
660
661 struct ConvertPathInfo
662 {
663     ConvertPathInfo(QPainterPath *newPath, const QPointF &newPos) : path(newPath), pos(newPos) {}
664     QPainterPath *path;
665     QPointF pos;
666 };
667
668 static void convertCGPathToQPainterPath(void *info, const CGPathElement *element)
669 {
670     ConvertPathInfo *myInfo = static_cast<ConvertPathInfo *>(info);
671     switch(element->type) {
672         case kCGPathElementMoveToPoint:
673             myInfo->path->moveTo(element->points[0].x + myInfo->pos.x(),
674                                  element->points[0].y + myInfo->pos.y());
675             break;
676         case kCGPathElementAddLineToPoint:
677             myInfo->path->lineTo(element->points[0].x + myInfo->pos.x(),
678                                  element->points[0].y + myInfo->pos.y());
679             break;
680         case kCGPathElementAddQuadCurveToPoint:
681             myInfo->path->quadTo(element->points[0].x + myInfo->pos.x(),
682                                  element->points[0].y + myInfo->pos.y(),
683                                  element->points[1].x + myInfo->pos.x(),
684                                  element->points[1].y + myInfo->pos.y());
685             break;
686         case kCGPathElementAddCurveToPoint:
687             myInfo->path->cubicTo(element->points[0].x + myInfo->pos.x(),
688                                   element->points[0].y + myInfo->pos.y(),
689                                   element->points[1].x + myInfo->pos.x(),
690                                   element->points[1].y + myInfo->pos.y(),
691                                   element->points[2].x + myInfo->pos.x(),
692                                   element->points[2].y + myInfo->pos.y());
693             break;
694         case kCGPathElementCloseSubpath:
695             myInfo->path->closeSubpath();
696             break;
697         default:
698             qDebug() << "Unhandled path transform type: " << element->type;
699     }
700
701 }
702
703 void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nGlyphs,
704                                           QPainterPath *path, QTextItem::RenderFlags)
705 {
706     CGAffineTransform cgMatrix = CGAffineTransformIdentity;
707     cgMatrix = CGAffineTransformScale(cgMatrix, 1, -1);
708
709     if (synthesisFlags & QFontEngine::SynthesizedItalic)
710         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
711
712     for (int i = 0; i < nGlyphs; ++i) {
713         QCFType<CGPathRef> cgpath = CTFontCreatePathForGlyph(ctfont, glyphs[i], &cgMatrix);
714         ConvertPathInfo info(path, positions[i].toPointF());
715         CGPathApply(cgpath, &info, convertCGPathToQPainterPath);
716     }
717 }
718
719 QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa)
720 {
721     const glyph_metrics_t br = boundingBox(glyph);
722     QImage im(qRound(br.width)+2, qRound(br.height)+2, QImage::Format_RGB32);
723     im.fill(0);
724
725     CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
726     uint cgflags = kCGImageAlphaNoneSkipFirst;
727 #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
728     cgflags |= kCGBitmapByteOrder32Host;
729 #endif
730     CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
731                                              8, im.bytesPerLine(), colorspace,
732                                              cgflags);
733     CGContextSetFontSize(ctx, fontDef.pixelSize);
734     CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > qt_antialiasing_threshold)
735                                  && !(fontDef.styleStrategy & QFont::NoAntialias));
736     CGContextSetShouldSmoothFonts(ctx, aa);
737     CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
738     CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
739
740     CGAffineTransformConcat(cgMatrix, oldTextMatrix);
741
742     if (synthesisFlags & QFontEngine::SynthesizedItalic)
743         cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
744
745     cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
746
747     CGContextSetTextMatrix(ctx, cgMatrix);
748     CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
749     CGContextSetTextDrawingMode(ctx, kCGTextFill);
750
751     CGContextSetFont(ctx, cgFont);
752
753     qreal pos_x = -br.x.toReal() + subPixelPosition.toReal();
754     qreal pos_y = im.height() + br.y.toReal() - 1;
755     CGContextSetTextPosition(ctx, pos_x, pos_y);
756
757     CGSize advance;
758     advance.width = 0;
759     advance.height = 0;
760     CGGlyph cgGlyph = glyph;
761     CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
762
763     if (synthesisFlags & QFontEngine::SynthesizedBold) {
764         CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
765         CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
766     }
767
768     CGContextRelease(ctx);
769
770     return im;
771 }
772
773 QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
774 {
775     QImage im = imageForGlyph(glyph, subPixelPosition, 0, false);
776
777     QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
778     QVector<QRgb> colors(256);
779     for (int i=0; i<256; ++i)
780         colors[i] = qRgba(0, 0, 0, i);
781     indexed.setColorTable(colors);
782
783     for (int y=0; y<im.height(); ++y) {
784         uint *src = (uint*) im.scanLine(y);
785         uchar *dst = indexed.scanLine(y);
786         for (int x=0; x<im.width(); ++x) {
787             *dst = qGray(*src);
788             ++dst;
789             ++src;
790         }
791     }
792
793     return indexed;
794 }
795
796 QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, const QTransform &x)
797 {
798     if (x.type() >= QTransform::TxScale)
799         return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, margin, x);
800
801     QImage im = imageForGlyph(glyph, subPixelPosition, margin, true);
802     qGamma_correct_back_to_linear_cs(&im);
803     return im;
804 }
805
806 void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
807 {
808     int i, numGlyphs = glyphs->numGlyphs;
809     QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs);
810
811     for (i = 0; i < numGlyphs; ++i) {
812         if (glyphs->glyphs[i] & 0xff000000)
813             cgGlyphs[i] = 0;
814         else
815             cgGlyphs[i] = glyphs->glyphs[i];
816     }
817
818     loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef);
819 }
820
821 QFontEngine::FaceId QCoreTextFontEngine::faceId() const
822 {
823     return QFontEngine::FaceId();
824 }
825
826 bool QCoreTextFontEngine::canRender(const QChar *string, int len)
827 {
828     QVarLengthArray<CGGlyph> cgGlyphs(len);
829     return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len);
830 }
831
832 bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
833 {
834     QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
835     if (!table || !length)
836         return false;
837     CFIndex tableLength = CFDataGetLength(table);
838     int availableLength = *length;
839     *length = tableLength;
840     if (buffer) {
841         if (tableLength > availableLength)
842             return false;
843         CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
844     }
845     return true;
846 }
847
848 void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *)
849 {
850     // ###
851 }
852
853 QFixed QCoreTextFontEngine::emSquareSize() const
854 {
855     return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
856 }
857
858 QFontEngine *QCoreTextFontEngine::cloneWithSize(qreal pixelSize) const
859 {
860     QFontDef newFontDef = fontDef;
861     newFontDef.pixelSize = pixelSize;
862     newFontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi();
863
864     return new QCoreTextFontEngine(cgFont, newFontDef);
865 }
866
867 QT_END_NAMESPACE
868
869 #endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
870