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