Qt 4.8
qfontengine_mac.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_mac_p.h"
43 
44 #include <private/qapplication_p.h>
45 #include <private/qfontengine_p.h>
46 #include <private/qpainter_p.h>
47 #include <private/qtextengine_p.h>
48 #include <qbitmap.h>
49 #include <private/qpaintengine_mac_p.h>
50 #include <private/qprintengine_mac_p.h>
51 #include <qglobal.h>
52 #include <qpixmap.h>
53 #include <qpixmapcache.h>
54 #include <qvarlengtharray.h>
55 #include <qdebug.h>
56 #include <qendian.h>
57 #include <qmath.h>
58 #include <private/qimage_p.h>
59 
60 #include <ApplicationServices/ApplicationServices.h>
61 #include <AppKit/AppKit.h>
62 
64 
65 /*****************************************************************************
66  QFontEngine debug facilities
67  *****************************************************************************/
68 //#define DEBUG_ADVANCES
69 
70 extern int qt_antialiasing_threshold; // QApplication.cpp
71 
72 #ifndef FixedToQFixed
73 #define FixedToQFixed(a) QFixed::fromFixed((a) >> 10)
74 #define QFixedToFixed(x) ((x).value() << 10)
75 #endif
76 
78 {
79  float x, y;
81 public:
82  inline QMacFontPath(float _x, float _y, QPainterPath *_path) : x(_x), y(_y), path(_path) { }
83  inline void setPosition(float _x, float _y) { x = _x; y = _y; }
84  inline void advance(float _x) { x += _x; }
85  static OSStatus lineTo(const Float32Point *, void *);
86  static OSStatus cubicTo(const Float32Point *, const Float32Point *,
87  const Float32Point *, void *);
88  static OSStatus moveTo(const Float32Point *, void *);
89  static OSStatus closePath(void *);
90 };
91 
92 OSStatus QMacFontPath::lineTo(const Float32Point *pt, void *data)
93 
94 {
95  QMacFontPath *p = static_cast<QMacFontPath*>(data);
96  p->path->lineTo(p->x + pt->x, p->y + pt->y);
97  return noErr;
98 }
99 
100 OSStatus QMacFontPath::cubicTo(const Float32Point *cp1, const Float32Point *cp2,
101  const Float32Point *ep, void *data)
102 
103 {
104  QMacFontPath *p = static_cast<QMacFontPath*>(data);
105  p->path->cubicTo(p->x + cp1->x, p->y + cp1->y,
106  p->x + cp2->x, p->y + cp2->y,
107  p->x + ep->x, p->y + ep->y);
108  return noErr;
109 }
110 
111 OSStatus QMacFontPath::moveTo(const Float32Point *pt, void *data)
112 {
113  QMacFontPath *p = static_cast<QMacFontPath*>(data);
114  p->path->moveTo(p->x + pt->x, p->y + pt->y);
115  return noErr;
116 }
117 
119 {
120  static_cast<QMacFontPath*>(data)->path->closeSubpath();
121  return noErr;
122 }
123 
124 
125 #ifndef QT_MAC_USE_COCOA
126 QFontEngineMacMulti::QFontEngineMacMulti(const ATSFontFamilyRef &atsFamily, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning)
127  : QFontEngineMulti(0)
128 {
129  this->fontDef = fontDef;
130  this->kerning = kerning;
131 
132  // hopefully (CTFontCreateWithName or CTFontCreateWithFontDescriptor) + CTFontCreateCopyWithSymbolicTraits
133  // (or CTFontCreateWithQuickdrawInstance)
134  FMFontFamily fmFamily;
135  FMFontStyle fntStyle = 0;
136  fmFamily = FMGetFontFamilyFromATSFontFamilyRef(atsFamily);
137  if (fmFamily == kInvalidFontFamily) {
138  // Use the ATSFont then...
139  fontID = FMGetFontFromATSFontRef(atsFontRef);
140  } else {
141  if (fontDef.weight >= QFont::Bold)
142  fntStyle |= ::bold;
143  if (fontDef.style != QFont::StyleNormal)
144  fntStyle |= ::italic;
145 
146  FMFontStyle intrinsicStyle;
147  FMFont fnt = 0;
148  if (FMGetFontFromFontFamilyInstance(fmFamily, fntStyle, &fnt, &intrinsicStyle) == noErr)
149  fontID = FMGetATSFontRefFromFont(fnt);
150  }
151 
152  // CFDictionaryRef, <CTStringAttributes.h>
154 
155  status = ATSUCreateTextLayout(&textLayout);
156  Q_ASSERT(status == noErr);
157 
158  const int maxAttributeCount = 5;
159  ATSUAttributeTag tags[maxAttributeCount + 1];
160  ByteCount sizes[maxAttributeCount + 1];
161  ATSUAttributeValuePtr values[maxAttributeCount + 1];
162  int attributeCount = 0;
163 
164  Fixed size = FixRatio(fontDef.pixelSize, 1);
165  tags[attributeCount] = kATSUSizeTag;
166  sizes[attributeCount] = sizeof(size);
167  values[attributeCount] = &size;
168  ++attributeCount;
169 
170  tags[attributeCount] = kATSUFontTag;
171  sizes[attributeCount] = sizeof(fontID);
172  values[attributeCount] = &this->fontID;
173  ++attributeCount;
174 
175  transform = CGAffineTransformIdentity;
176  if (fontDef.stretch != 100) {
177  transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
178  tags[attributeCount] = kATSUFontMatrixTag;
179  sizes[attributeCount] = sizeof(transform);
180  values[attributeCount] = &transform;
181  ++attributeCount;
182  }
183 
184  status = ATSUCreateStyle(&style);
185  Q_ASSERT(status == noErr);
186 
187  Q_ASSERT(attributeCount < maxAttributeCount + 1);
188  status = ATSUSetAttributes(style, attributeCount, tags, sizes, values);
189  Q_ASSERT(status == noErr);
190 
191  QFontEngineMac *fe = new QFontEngineMac(style, fontID, fontDef, this);
192  fe->ref.ref();
193  engines.append(fe);
194 }
195 
197 {
198  ATSUDisposeTextLayout(textLayout);
199  ATSUDisposeStyle(style);
200 
201  for (int i = 0; i < engines.count(); ++i) {
202  QFontEngineMac *fe = const_cast<QFontEngineMac *>(static_cast<const QFontEngineMac *>(engines.at(i)));
203  fe->multiEngine = 0;
204  if (!fe->ref.deref())
205  delete fe;
206  }
207  engines.clear();
208 }
209 
211 {
213  int *numGlyphs;
216  QTextEngine::ShaperFlags flags;
218  unsigned int styleStrategy;
219 };
220 
221 static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATSULineRef lineRef, URefCon refCon,
222  void *operationExtraParameter, ATSULayoutOperationCallbackStatus *callbackStatus)
223 {
224  Q_UNUSED(selector);
225  Q_UNUSED(operationExtraParameter);
226 
227  QGlyphLayoutInfo *nfo = reinterpret_cast<QGlyphLayoutInfo *>(refCon);
228  nfo->callbackCalled = true;
229 
230  ATSLayoutRecord *layoutData = 0;
231  ItemCount itemCount = 0;
232 
233  OSStatus e = noErr;
234  e = ATSUDirectGetLayoutDataArrayPtrFromLineRef(lineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
235  /*iCreate =*/ false,
236  (void **) &layoutData,
237  &itemCount);
238  if (e != noErr)
239  return e;
240 
241  *nfo->numGlyphs = itemCount - 1;
242 
243  Fixed *baselineDeltas = 0;
244 
245  e = ATSUDirectGetLayoutDataArrayPtrFromLineRef(lineRef, kATSUDirectDataBaselineDeltaFixedArray,
246  /*iCreate =*/ true,
247  (void **) &baselineDeltas,
248  &itemCount);
249  if (e != noErr)
250  return e;
251 
252  int nextCharStop = -1;
253  int currentClusterGlyph = -1; // first glyph in log cluster
255  if (item->charAttributes) {
256  item = nfo->shaperItem;
257 #if !defined(QT_NO_DEBUG)
258  int surrogates = 0;
259  const QChar *str = item->string;
260  for (int i = item->from; i < item->from + item->length - 1; ++i)
261  surrogates += (str[i].isHighSurrogate() && str[i+1].isLowSurrogate());
262 #endif
263  for (nextCharStop = item->from; nextCharStop < item->from + item->length; ++nextCharStop)
264  if (item->charAttributes[nextCharStop].charStop)
265  break;
266  nextCharStop -= item->from;
267  }
268 
269  nfo->glyphs->attributes[0].clusterStart = true;
270  int glyphIdx = 0;
271  int glyphIncrement = 1;
272  if (nfo->flags & QTextEngine::RightToLeft) {
273  glyphIdx = itemCount - 2;
274  glyphIncrement = -1;
275  }
276  for (int i = 0; i < *nfo->numGlyphs; ++i, glyphIdx += glyphIncrement) {
277 
278  int charOffset = layoutData[glyphIdx].originalOffset / sizeof(UniChar);
279  const int fontIdx = nfo->mappedFonts[charOffset];
280 
281  ATSGlyphRef glyphId = layoutData[glyphIdx].glyphID;
282 
283  QFixed yAdvance = FixedToQFixed(baselineDeltas[glyphIdx]);
284  QFixed xAdvance = FixedToQFixed(layoutData[glyphIdx + 1].realPos - layoutData[glyphIdx].realPos);
285 
287  yAdvance = yAdvance.round();
288  xAdvance = xAdvance.round();
289  }
290 
291  if (glyphId != 0xffff || i == 0) {
292  if (i < nfo->glyphs->numGlyphs)
293  {
294  nfo->glyphs->glyphs[i] = (glyphId & 0x00ffffff) | (fontIdx << 24);
295 
296  nfo->glyphs->advances_y[i] = yAdvance;
297  nfo->glyphs->advances_x[i] = xAdvance;
298  }
299  } else {
300  // ATSUI gives us 0xffff as glyph id at the index in the glyph array for
301  // a character position that maps to a ligtature. Such a glyph id does not
302  // result in any visual glyph, but it may have an advance, which is why we
303  // sum up the glyph advances.
304  --i;
305  nfo->glyphs->advances_y[i] += yAdvance;
306  nfo->glyphs->advances_x[i] += xAdvance;
307  *nfo->numGlyphs -= 1;
308  }
309 
310  if (item->log_clusters) {
311  if (charOffset >= nextCharStop) {
312  nfo->glyphs->attributes[i].clusterStart = true;
313  currentClusterGlyph = i;
314 
315  ++nextCharStop;
316  for (; nextCharStop < item->length; ++nextCharStop)
317  if (item->charAttributes[item->from + nextCharStop].charStop)
318  break;
319  } else {
320  if (currentClusterGlyph == -1)
321  currentClusterGlyph = i;
322  }
323  item->log_clusters[charOffset] = currentClusterGlyph;
324 
325  // surrogate handling
326  if (charOffset < item->length - 1) {
327  QChar current = item->string[item->from + charOffset];
328  QChar next = item->string[item->from + charOffset + 1];
329  if (current.isHighSurrogate() && next.isLowSurrogate())
330  item->log_clusters[charOffset + 1] = currentClusterGlyph;
331  }
332  }
333  }
334 
335  /*
336  if (item) {
337  qDebug() << "resulting logclusters:";
338  for (int i = 0; i < item->length; ++i)
339  qDebug() << "logClusters[" << i << "] =" << item->log_clusters[i];
340  qDebug() << "clusterstarts:";
341  for (int i = 0; i < *nfo->numGlyphs; ++i)
342  qDebug() << "clusterStart[" << i << "] =" << nfo->glyphs[i].attributes.clusterStart;
343  }
344  */
345 
346  ATSUDirectReleaseLayoutDataArrayPtr(lineRef, kATSUDirectDataBaselineDeltaFixedArray,
347  (void **) &baselineDeltas);
348 
349  ATSUDirectReleaseLayoutDataArrayPtr(lineRef, kATSUDirectDataLayoutRecordATSLayoutRecordCurrent,
350  (void **) &layoutData);
351 
352  *callbackStatus = kATSULayoutOperationCallbackStatusHandled;
353  return noErr;
354 }
355 
357 {
358  for (int i = 0; i < engines.count(); ++i) {
359  if (engineAt(i)->fontID == id)
360  return i;
361  }
362 
363  QFontEngineMacMulti *that = const_cast<QFontEngineMacMulti *>(this);
364  QFontEngineMac *fe = new QFontEngineMac(style, id, fontDef, that);
365  fe->ref.ref();
366  that->engines.append(fe);
367  return engines.count() - 1;
368 }
369 
370 bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
371 {
372  return stringToCMap(str, len, glyphs, nglyphs, flags, /*logClusters=*/0, /*charAttributes=*/0, /*si=*/0);
373 }
374 
375 bool QFontEngineMacMulti::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags,
376  unsigned short *logClusters, const HB_CharAttributes *charAttributes, QScriptItem *) const
377 {
378  if (*nglyphs < len) {
379  *nglyphs = len;
380  return false;
381  }
382 
383  ShaperItem shaperItem;
384  shaperItem.string = str;
385  shaperItem.from = 0;
386  shaperItem.length = len;
387  shaperItem.glyphs = *glyphs;
388  shaperItem.glyphs.numGlyphs = *nglyphs;
389  shaperItem.flags = flags;
390  shaperItem.log_clusters = logClusters;
391  shaperItem.charAttributes = charAttributes;
392 
393  const int maxChars = qMax(1,
394  int(SHRT_MAX / maxCharWidth())
395  - 10 // subtract a few to be on the safe side
396  );
397  if (len < maxChars || !charAttributes)
398  return stringToCMapInternal(str, len, glyphs, nglyphs, flags, &shaperItem);
399 
400  int charIdx = 0;
401  int glyphIdx = 0;
402  ShaperItem tmpItem = shaperItem;
403 
404  do {
405  tmpItem.from = shaperItem.from + charIdx;
406 
407  int charCount = qMin(maxChars, len - charIdx);
408 
409  int lastWhitespace = tmpItem.from + charCount - 1;
410  int lastSoftBreak = lastWhitespace;
411  int lastCharStop = lastSoftBreak;
412  for (int i = lastCharStop; i >= tmpItem.from; --i) {
413  if (tmpItem.charAttributes[i].whiteSpace) {
414  lastWhitespace = i;
415  break;
416  } if (tmpItem.charAttributes[i].lineBreakType != HB_NoBreak) {
417  lastSoftBreak = i;
418  } if (tmpItem.charAttributes[i].charStop) {
419  lastCharStop = i;
420  }
421  }
422  charCount = qMin(lastWhitespace, qMin(lastSoftBreak, lastCharStop)) - tmpItem.from + 1;
423 
424  int glyphCount = shaperItem.glyphs.numGlyphs - glyphIdx;
425  if (glyphCount <= 0)
426  return false;
427  tmpItem.length = charCount;
428  tmpItem.glyphs = shaperItem.glyphs.mid(glyphIdx, glyphCount);
429  tmpItem.log_clusters = shaperItem.log_clusters + charIdx;
430  if (!stringToCMapInternal(tmpItem.string + tmpItem.from, tmpItem.length,
431  &tmpItem.glyphs, &glyphCount, flags,
432  &tmpItem)) {
433  *nglyphs = glyphIdx + glyphCount;
434  return false;
435  }
436  for (int i = 0; i < charCount; ++i)
437  tmpItem.log_clusters[i] += glyphIdx;
438  glyphIdx += glyphCount;
439  charIdx += charCount;
440  } while (charIdx < len);
441  *nglyphs = glyphIdx;
442  glyphs->numGlyphs = glyphIdx;
443 
444  return true;
445 }
446 
447 bool QFontEngineMacMulti::stringToCMapInternal(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags,ShaperItem *shaperItem) const
448 {
449  //qDebug() << "stringToCMap" << QString(str, len);
450 
451  OSStatus e = noErr;
452 
453  e = ATSUSetTextPointerLocation(textLayout, (UniChar *)(str), 0, len, len);
454  if (e != noErr) {
455  qWarning("Qt: internal: %ld: Error ATSUSetTextPointerLocation %s: %d", long(e), __FILE__, __LINE__);
456  return false;
457  }
458 
459  QGlyphLayoutInfo nfo;
460  nfo.glyphs = glyphs;
461  nfo.numGlyphs = nglyphs;
462  nfo.callbackCalled = false;
463  nfo.flags = flags;
464  nfo.shaperItem = shaperItem;
466 
467  int prevNumGlyphs = *nglyphs;
468 
469  QVarLengthArray<int> mappedFonts(len);
470  for (int i = 0; i < len; ++i)
471  mappedFonts[i] = 0;
472  nfo.mappedFonts = mappedFonts.data();
473 
474  Q_ASSERT(sizeof(void *) <= sizeof(URefCon));
475  e = ATSUSetTextLayoutRefCon(textLayout, (URefCon)&nfo);
476  if (e != noErr) {
477  qWarning("Qt: internal: %ld: Error ATSUSetTextLayoutRefCon %s: %d", long(e), __FILE__, __LINE__);
478  return false;
479  }
480 
481  {
482  const int maxAttributeCount = 3;
483  ATSUAttributeTag tags[maxAttributeCount + 1];
484  ByteCount sizes[maxAttributeCount + 1];
485  ATSUAttributeValuePtr values[maxAttributeCount + 1];
486  int attributeCount = 0;
487 
488  tags[attributeCount] = kATSULineLayoutOptionsTag;
489  ATSLineLayoutOptions layopts = kATSLineHasNoOpticalAlignment
490  | kATSLineIgnoreFontLeading
491  | kATSLineNoSpecialJustification // we do kashidas ourselves
492  | kATSLineDisableAllJustification
493  ;
494 
496  layopts |= kATSLineNoAntiAliasing;
497 
498  if (!kerning)
499  layopts |= kATSLineDisableAllKerningAdjustments;
500 
501  values[attributeCount] = &layopts;
502  sizes[attributeCount] = sizeof(layopts);
503  ++attributeCount;
504 
505  tags[attributeCount] = kATSULayoutOperationOverrideTag;
506  ATSULayoutOperationOverrideSpecifier spec;
507  spec.operationSelector = kATSULayoutOperationPostLayoutAdjustment;
508  spec.overrideUPP = atsuPostLayoutCallback;
509  values[attributeCount] = &spec;
510  sizes[attributeCount] = sizeof(spec);
511  ++attributeCount;
512 
513  // CTWritingDirection
515  if (flags & QTextEngine::RightToLeft)
516  direction = kATSURightToLeftBaseDirection;
517  else
518  direction = kATSULeftToRightBaseDirection;
519  tags[attributeCount] = kATSULineDirectionTag;
520  values[attributeCount] = &direction;
521  sizes[attributeCount] = sizeof(direction);
522  ++attributeCount;
523 
524  Q_ASSERT(attributeCount < maxAttributeCount + 1);
525  e = ATSUSetLayoutControls(textLayout, attributeCount, tags, sizes, values);
526  if (e != noErr) {
527  qWarning("Qt: internal: %ld: Error ATSUSetLayoutControls %s: %d", long(e), __FILE__, __LINE__);
528  return false;
529  }
530 
531  }
532 
533  e = ATSUSetRunStyle(textLayout, style, 0, len);
534  if (e != noErr) {
535  qWarning("Qt: internal: %ld: Error ATSUSetRunStyle %s: %d", long(e), __FILE__, __LINE__);
536  return false;
537  }
538 
540  int pos = 0;
541  do {
542  ATSUFontID substFont = 0;
543  UniCharArrayOffset changedOffset = 0;
544  UniCharCount changeCount = 0;
545 
546  e = ATSUMatchFontsToText(textLayout, pos, len - pos,
547  &substFont, &changedOffset,
548  &changeCount);
549  if (e == kATSUFontsMatched) {
550  int fontIdx = fontIndexForFontID(substFont);
551  for (uint i = 0; i < changeCount; ++i)
552  mappedFonts[changedOffset + i] = fontIdx;
553  pos = changedOffset + changeCount;
554  ATSUSetRunStyle(textLayout, engineAt(fontIdx)->style, changedOffset, changeCount);
555  } else if (e == kATSUFontsNotMatched) {
556  pos = changedOffset + changeCount;
557  }
558  } while (pos < len && e != noErr);
559  }
560  { // trigger the a layout
561  // CFAttributedStringCreate, CTFramesetterCreateWithAttributedString (or perhaps Typesetter)
562  Rect rect;
563  e = ATSUMeasureTextImage(textLayout, kATSUFromTextBeginning, kATSUToTextEnd,
564  /*iLocationX =*/ 0, /*iLocationY =*/ 0,
565  &rect);
566  if (e != noErr) {
567  qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage %s: %d", long(e), __FILE__, __LINE__);
568  return false;
569  }
570  }
571 
572  if (!nfo.callbackCalled) {
573  qWarning("Qt: internal: %ld: Error ATSUMeasureTextImage did not trigger callback %s: %d", long(e), __FILE__, __LINE__);
574  return false;
575  }
576 
577  ATSUClearLayoutCache(textLayout, kATSUFromTextBeginning);
578  if (prevNumGlyphs < *nfo.numGlyphs)
579  return false;
580  return true;
581 }
582 
583 void QFontEngineMacMulti::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
584 {
585  Q_ASSERT(false);
586  Q_UNUSED(glyphs);
587  Q_UNUSED(flags);
588 }
589 
590 void QFontEngineMacMulti::doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const
591 {
592  //Q_ASSERT(false);
593 }
594 
596 {
597  // should never be called!
598  Q_ASSERT(false);
599 }
600 
601 bool QFontEngineMacMulti::canRender(const QChar *string, int len)
602 {
603  ATSUSetTextPointerLocation(textLayout, reinterpret_cast<const UniChar *>(string), 0, len, len);
604  ATSUSetRunStyle(textLayout, style, 0, len);
605 
606  OSStatus e = noErr;
607  int pos = 0;
608  do {
609  FMFont substFont = 0;
610  UniCharArrayOffset changedOffset = 0;
611  UniCharCount changeCount = 0;
612 
613  // CTFontCreateForString
614  e = ATSUMatchFontsToText(textLayout, pos, len - pos,
615  &substFont, &changedOffset,
616  &changeCount);
617  if (e == kATSUFontsMatched) {
618  pos = changedOffset + changeCount;
619  } else if (e == kATSUFontsNotMatched) {
620  break;
621  }
622  } while (pos < len && e != noErr);
623 
624  return e == noErr || e == kATSUFontsMatched;
625 }
626 
627 QFontEngineMac::QFontEngineMac(ATSUStyle baseStyle, ATSUFontID fontID, const QFontDef &def, QFontEngineMacMulti *multiEngine)
628  : fontID(fontID), multiEngine(multiEngine), cmap(0), symbolCMap(false)
629 {
630  fontDef = def;
631  ATSUCreateAndCopyStyle(baseStyle, &style);
632  ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
633  cgFont = CGFontCreateWithPlatformFont(&atsFont);
634 
635  const int maxAttributeCount = 4;
636  ATSUAttributeTag tags[maxAttributeCount + 1];
637  ByteCount sizes[maxAttributeCount + 1];
638  ATSUAttributeValuePtr values[maxAttributeCount + 1];
639  int attributeCount = 0;
640 
641  synthesisFlags = 0;
642 
643  // synthesizing using CG is not recommended
644  quint16 macStyle = 0;
645  {
646  uchar data[4];
647  ByteCount len = 4;
648  if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 44, 4, &data, &len) == noErr)
649  macStyle = qFromBigEndian<quint16>(data);
650  }
651 
652  Boolean atsuBold = false;
653  Boolean atsuItalic = false;
654  if (fontDef.weight >= QFont::Bold) {
655  if (!(macStyle & 1)) {
657  atsuBold = true;
658  tags[attributeCount] = kATSUQDBoldfaceTag;
659  sizes[attributeCount] = sizeof(atsuBold);
660  values[attributeCount] = &atsuBold;
661  ++attributeCount;
662  }
663  }
665  if (!(macStyle & 2)) {
667  atsuItalic = true;
668  tags[attributeCount] = kATSUQDItalicTag;
669  sizes[attributeCount] = sizeof(atsuItalic);
670  values[attributeCount] = &atsuItalic;
671  ++attributeCount;
672  }
673  }
674 
675  tags[attributeCount] = kATSUFontTag;
676  values[attributeCount] = &fontID;
677  sizes[attributeCount] = sizeof(fontID);
678  ++attributeCount;
679 
680  Q_ASSERT(attributeCount < maxAttributeCount + 1);
681  OSStatus err = ATSUSetAttributes(style, attributeCount, tags, sizes, values);
682  Q_ASSERT(err == noErr);
683  Q_UNUSED(err);
684 
685  // CTFontCopyTable
686  quint16 tmpFsType;
687  if (ATSFontGetTable(atsFont, MAKE_TAG('O', 'S', '/', '2'), 8, 2, &tmpFsType, 0) == noErr)
688  fsType = qFromBigEndian<quint16>(tmpFsType);
689  else
690  fsType = 0;
691 
692  if (multiEngine)
693  transform = multiEngine->transform;
694  else
695  transform = CGAffineTransformIdentity;
696 
697  ATSUTextMeasurement metric;
698 
699  ATSUGetAttribute(style, kATSUAscentTag, sizeof(metric), &metric, 0);
700  m_ascent = FixRound(metric);
701 
702  ATSUGetAttribute(style, kATSUDescentTag, sizeof(metric), &metric, 0);
703  m_descent = FixRound(metric);
704 
705  ATSUGetAttribute(style, kATSULeadingTag, sizeof(metric), &metric, 0);
706  m_leading = FixRound(metric);
707 
708  ATSFontMetrics metrics;
709 
710  ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
711  m_maxCharWidth = metrics.maxAdvanceWidth * fontDef.pointSize;
712 
713  ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
714  m_xHeight = QFixed::fromReal(metrics.xHeight * fontDef.pointSize);
715 
716  ATSFontGetHorizontalMetrics(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &metrics);
717  m_averageCharWidth = QFixed::fromReal(metrics.avgAdvanceWidth * fontDef.pointSize);
718 
719  // Use width of 'X' if ATSFontGetHorizontalMetrics returns 0 for avgAdvanceWidth.
720  if (m_averageCharWidth == QFixed(0)) {
721  QChar c('X');
722  QGlyphLayoutArray<1> glyphs;
723  int nglyphs = 1;
724  stringToCMap(&c, 1, &glyphs, &nglyphs, 0);
725  glyph_metrics_t metrics = boundingBox(glyphs);
726  m_averageCharWidth = metrics.width;
727  }
728 }
729 
731 {
732  ATSUDisposeStyle(style);
733 }
734 
735 static inline unsigned int getChar(const QChar *str, int &i, const int len)
736 {
737  uint ucs4 = str[i].unicode();
738  if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate()) {
739  ++i;
740  ucs4 = QChar::surrogateToUcs4(ucs4, str[i].unicode());
741  }
742  return ucs4;
743 }
744 
745 // Not used directly for shaping, only used to calculate m_averageCharWidth
746 bool QFontEngineMac::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
747 {
748  if (!cmap) {
749  cmapTable = getSfntTable(MAKE_TAG('c', 'm', 'a', 'p'));
750  int size = 0;
751  cmap = getCMap(reinterpret_cast<const uchar *>(cmapTable.constData()), cmapTable.size(), &symbolCMap, &size);
752  if (!cmap)
753  return false;
754  }
755  if (symbolCMap) {
756  for (int i = 0; i < len; ++i) {
757  unsigned int uc = getChar(str, i, len);
758  glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
759  if(!glyphs->glyphs[i] && uc < 0x100)
760  glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
761  }
762  } else {
763  for (int i = 0; i < len; ++i) {
764  unsigned int uc = getChar(str, i, len);
765  glyphs->glyphs[i] = getTrueTypeGlyphIndex(cmap, uc);
766  }
767  }
768 
769  *nglyphs = len;
770  glyphs->numGlyphs = *nglyphs;
771 
772  if (!(flags & QTextEngine::GlyphIndicesOnly))
773  recalcAdvances(glyphs, flags);
774 
775  return true;
776 }
777 
778 void QFontEngineMac::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
779 {
780  Q_UNUSED(flags)
781 
782  QVarLengthArray<GlyphID> atsuGlyphs(glyphs->numGlyphs);
783  for (int i = 0; i < glyphs->numGlyphs; ++i)
784  atsuGlyphs[i] = glyphs->glyphs[i];
785 
787 
788  ATSUGlyphGetScreenMetrics(style, glyphs->numGlyphs, atsuGlyphs.data(), sizeof(GlyphID),
789  /* iForcingAntiAlias =*/ false,
790  /* iAntiAliasSwitch =*/true,
791  metrics.data());
792 
793  for (int i = 0; i < glyphs->numGlyphs; ++i) {
794  glyphs->advances_x[i] = QFixed::fromReal(metrics[i].deviceAdvance.x);
795  glyphs->advances_y[i] = QFixed::fromReal(metrics[i].deviceAdvance.y);
796 
798  glyphs->advances_x[i] = glyphs->advances_x[i].round();
799  glyphs->advances_y[i] = glyphs->advances_y[i].round();
800  }
801  }
802 }
803 
805 {
806  QFixed w;
808  for (int i = 0; i < glyphs.numGlyphs; ++i) {
809  w += round ? glyphs.effectiveAdvance(i).round()
810  : glyphs.effectiveAdvance(i);
811  }
812  return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
813 }
814 
816 {
817  GlyphID atsuGlyph = glyph;
818 
819  ATSGlyphScreenMetrics metrics;
820 
821  ATSUGlyphGetScreenMetrics(style, 1, &atsuGlyph, 0,
822  /* iForcingAntiAlias =*/ false,
823  /* iAntiAliasSwitch =*/true,
824  &metrics);
825 
826  // ### check again
827 
828  glyph_metrics_t gm;
829  gm.width = int(metrics.width);
830  gm.height = int(metrics.height);
831  gm.x = QFixed::fromReal(metrics.topLeft.x);
832  gm.y = -QFixed::fromReal(metrics.topLeft.y);
833  gm.xoff = QFixed::fromReal(metrics.deviceAdvance.x);
834  gm.yoff = QFixed::fromReal(metrics.deviceAdvance.y);
835 
837  gm.x = gm.x.floor();
838  gm.y = gm.y.floor();
839  gm.xoff = gm.xoff.round();
840  gm.yoff = gm.yoff.round();
841  }
842 
843  return gm;
844 }
845 
847 {
849  ? m_ascent.round()
850  : m_ascent;
851 }
852 
854 {
855  // subtract a pixel to even out the historical +1 in QFontMetrics::height().
856  // Fix in Qt 5.
858  ? m_descent.round() - 1
859  : m_descent;
860 }
861 
863 {
865  ? m_leading.round()
866  : m_leading;
867 }
868 
870 {
873  : m_maxCharWidth;
874 }
875 
877 {
879  ? m_xHeight.round()
880  : m_xHeight;
881 }
882 
884 {
888 }
889 
890 static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path)
891 {
892  if (!numGlyphs)
893  return;
894 
895  OSStatus e;
896 
897  QMacFontPath fontpath(0, 0, path);
898  ATSCubicMoveToUPP moveTo = NewATSCubicMoveToUPP(QMacFontPath::moveTo);
899  ATSCubicLineToUPP lineTo = NewATSCubicLineToUPP(QMacFontPath::lineTo);
900  ATSCubicCurveToUPP cubicTo = NewATSCubicCurveToUPP(QMacFontPath::cubicTo);
901  ATSCubicClosePathUPP closePath = NewATSCubicClosePathUPP(QMacFontPath::closePath);
902 
903  // CTFontCreatePathForGlyph
904  for (int i = 0; i < numGlyphs; ++i) {
905  GlyphID glyph = glyphs[i];
906 
907  fontpath.setPosition(positions[i].x.toReal(), positions[i].y.toReal());
908  ATSUGlyphGetCubicPaths(style, glyph, moveTo, lineTo,
909  cubicTo, closePath, &fontpath, &e);
910  }
911 
912  DisposeATSCubicMoveToUPP(moveTo);
913  DisposeATSCubicLineToUPP(lineTo);
914  DisposeATSCubicCurveToUPP(cubicTo);
915  DisposeATSCubicClosePathUPP(closePath);
916 }
917 
919  QTextItem::RenderFlags)
920 {
921  addGlyphsToPathHelper(style, glyphs, positions, numGlyphs, path);
922 }
923 
924 
929 QImage QFontEngineMac::imageForGlyph(glyph_t glyph, int margin, bool colorful)
930 {
931  const glyph_metrics_t br = boundingBox(glyph);
933  im.fill(0xff000000);
934 
936  uint cgflags = kCGImageAlphaNoneSkipFirst;
937 #ifdef kCGBitmapByteOrder32Host //only needed because CGImage.h added symbols in the minor version
938  cgflags |= kCGBitmapByteOrder32Host;
939 #endif
940  CGContextRef ctx = CGBitmapContextCreate(im.bits(), im.width(), im.height(),
941  8, im.bytesPerLine(), colorspace,
942  cgflags);
943  CGContextSetFontSize(ctx, fontDef.pixelSize);
944  CGContextSetShouldAntialias(ctx, fontDef.pointSize > qt_antialiasing_threshold && !(fontDef.styleStrategy & QFont::NoAntialias));
945  // turn off sub-pixel hinting - no support for that in OpenGL
946  CGContextSetShouldSmoothFonts(ctx, colorful);
947  CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
948  CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
949  CGAffineTransformConcat(cgMatrix, oldTextMatrix);
950 
952  cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, tanf(14 * acosf(0) / 90), 1, 0, 0));
953 
954  cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
955 
956  CGContextSetTextMatrix(ctx, cgMatrix);
957  CGContextSetRGBFillColor(ctx, 1, 1, 1, 1);
958  CGContextSetTextDrawingMode(ctx, kCGTextFill);
959  CGContextSetFont(ctx, cgFont);
960 
961  qreal pos_x = -br.x.toReal() + 1;
962  qreal pos_y = im.height() + br.y.toReal() - 2;
963  CGContextSetTextPosition(ctx, pos_x, pos_y);
964 
965  CGSize advance;
966  advance.width = 0;
967  advance.height = 0;
968  CGGlyph cgGlyph = glyph;
969  CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
970 
972  CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
973  CGContextShowGlyphsWithAdvances(ctx, &cgGlyph, &advance, 1);
974  }
975 
976  CGContextRelease(ctx);
977 
978  return im;
979 }
980 
982 {
983  QImage im = imageForGlyph(glyph, 2, false);
984 
985  QImage indexed(im.width(), im.height(), QImage::Format_Indexed8);
986  QVector<QRgb> colors(256);
987  for (int i=0; i<256; ++i)
988  colors[i] = qRgba(0, 0, 0, i);
989  indexed.setColorTable(colors);
990 
991  for (int y=0; y<im.height(); ++y) {
992  uint *src = (uint*) im.scanLine(y);
993  uchar *dst = indexed.scanLine(y);
994  for (int x=0; x<im.width(); ++x) {
995  *dst = qGray(*src);
996  ++dst;
997  ++src;
998  }
999  }
1000 
1001  return indexed;
1002 }
1003 
1005 {
1006  QImage im = imageForGlyph(glyph, margin, true);
1007 
1008  if (t.type() >= QTransform::TxScale) {
1009  im = im.transformed(t);
1010  }
1011 
1013 
1014  return im;
1015 }
1016 
1017 
1018 bool QFontEngineMac::canRender(const QChar *string, int len)
1019 {
1020  Q_ASSERT(false);
1021  Q_UNUSED(string);
1022  Q_UNUSED(len);
1023  return false;
1024 }
1025 
1026 void QFontEngineMac::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
1027 {
1029  QVarLengthArray<glyph_t> glyphs;
1030  QTransform matrix;
1031  matrix.translate(x, y);
1032  getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
1033  if (glyphs.size() == 0)
1034  return;
1035 
1036  CGContextSetFontSize(ctx, fontDef.pixelSize);
1037 
1038  CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
1039 
1040  CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight);
1041 
1042  CGAffineTransformConcat(cgMatrix, oldTextMatrix);
1043 
1045  cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -tanf(14 * acosf(0) / 90), 1, 0, 0));
1046 
1047  cgMatrix = CGAffineTransformConcat(cgMatrix, transform);
1048 
1049  CGContextSetTextMatrix(ctx, cgMatrix);
1050 
1051  CGContextSetTextDrawingMode(ctx, kCGTextFill);
1052 
1053 
1054  QVarLengthArray<CGSize> advances(glyphs.size());
1055  QVarLengthArray<CGGlyph> cgGlyphs(glyphs.size());
1056 
1057  for (int i = 0; i < glyphs.size() - 1; ++i) {
1058  advances[i].width = (positions[i + 1].x - positions[i].x).toReal();
1059  advances[i].height = (positions[i + 1].y - positions[i].y).toReal();
1060  cgGlyphs[i] = glyphs[i];
1061  }
1062  advances[glyphs.size() - 1].width = 0;
1063  advances[glyphs.size() - 1].height = 0;
1064  cgGlyphs[glyphs.size() - 1] = glyphs[glyphs.size() - 1];
1065 
1066  CGContextSetFont(ctx, cgFont);
1067 
1068  CGContextSetTextPosition(ctx, positions[0].x.toReal(), positions[0].y.toReal());
1069 
1070  CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
1071 
1073  CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(),
1074  positions[0].y.toReal());
1075 
1076  CGContextShowGlyphsWithAdvances(ctx, cgGlyphs.data(), advances.data(), glyphs.size());
1077  }
1078 
1079  CGContextSetTextMatrix(ctx, oldTextMatrix);
1080 }
1081 
1083 {
1084  FaceId ret;
1085 #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
1087  // CTFontGetPlatformFont
1088  FSRef ref;
1089  if (ATSFontGetFileReference(FMGetATSFontRefFromFont(fontID), &ref) != noErr)
1090  return ret;
1091  ret.filename = QByteArray(128, 0);
1092  ret.index = fontID;
1093  FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
1094 }else
1095 #endif
1096 {
1097  FSSpec spec;
1098  if (ATSFontGetFileSpecification(FMGetATSFontRefFromFont(fontID), &spec) != noErr)
1099  return ret;
1100 
1101  FSRef ref;
1102  FSpMakeFSRef(&spec, &ref);
1103  ret.filename = QByteArray(128, 0);
1104  ret.index = fontID;
1105  FSRefMakePath(&ref, (UInt8 *)ret.filename.data(), ret.filename.size());
1106 }
1107  return ret;
1108 }
1109 
1111 {
1112  ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
1113 
1114  ByteCount length;
1115  OSStatus status = ATSFontGetTable(atsFont, tag, 0, 0, 0, &length);
1116  if (status != noErr)
1117  return QByteArray();
1118  QByteArray table(length, 0);
1119  // CTFontCopyTable
1120  status = ATSFontGetTable(atsFont, tag, 0, table.length(), table.data(), &length);
1121  if (status != noErr)
1122  return QByteArray();
1123  return table;
1124 }
1125 
1127 {
1129  ATSFontRef atsFont = FMGetATSFontRefFromFont(fontID);
1130  quint16 tmp;
1131  // CTFontGetUnitsPerEm
1132  if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 18, 2, &tmp, 0) == noErr)
1133  props.emSquare = qFromBigEndian<quint16>(tmp);
1134  struct {
1135  qint16 xMin;
1136  qint16 yMin;
1137  qint16 xMax;
1138  qint16 yMax;
1139  } bbox;
1140  bbox.xMin = bbox.xMax = bbox.yMin = bbox.yMax = 0;
1141  // CTFontGetBoundingBox
1142  if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'e', 'a', 'd'), 36, 8, &bbox, 0) == noErr) {
1143  bbox.xMin = qFromBigEndian<quint16>(bbox.xMin);
1144  bbox.yMin = qFromBigEndian<quint16>(bbox.yMin);
1145  bbox.xMax = qFromBigEndian<quint16>(bbox.xMax);
1146  bbox.yMax = qFromBigEndian<quint16>(bbox.yMax);
1147  }
1148  struct {
1149  qint16 ascender;
1150  qint16 descender;
1151  qint16 linegap;
1152  } metrics;
1153  metrics.ascender = metrics.descender = metrics.linegap = 0;
1154  // CTFontGetAscent, etc.
1155  if (ATSFontGetTable(atsFont, MAKE_TAG('h', 'h', 'e', 'a'), 4, 6, &metrics, 0) == noErr) {
1156  metrics.ascender = qFromBigEndian<quint16>(metrics.ascender);
1157  metrics.descender = qFromBigEndian<quint16>(metrics.descender);
1158  metrics.linegap = qFromBigEndian<quint16>(metrics.linegap);
1159  }
1160  props.ascent = metrics.ascender;
1161  props.descent = -metrics.descender;
1162  props.leading = metrics.linegap;
1163  props.boundingBox = QRectF(bbox.xMin, -bbox.yMax,
1164  bbox.xMax - bbox.xMin,
1165  bbox.yMax - bbox.yMin);
1166  props.italicAngle = 0;
1167  props.capHeight = props.ascent;
1168 
1169  qint16 lw = 0;
1170  // fonts lie
1171  if (ATSFontGetTable(atsFont, MAKE_TAG('p', 'o', 's', 't'), 10, 2, &lw, 0) == noErr)
1172  lw = qFromBigEndian<quint16>(lw);
1173  props.lineWidth = lw;
1174 
1175  // CTFontCopyPostScriptName
1176  QCFString psName;
1177  if (ATSFontGetPostScriptName(FMGetATSFontRefFromFont(fontID), kATSOptionFlagsDefault, &psName) == noErr)
1178  props.postscriptName = QString(psName).toUtf8();
1180  return props;
1181 }
1182 
1184 {
1185  ATSUStyle unscaledStyle;
1186  ATSUCreateAndCopyStyle(style, &unscaledStyle);
1187 
1188  int emSquare = properties().emSquare.toInt();
1189 
1190  const int maxAttributeCount = 4;
1191  ATSUAttributeTag tags[maxAttributeCount + 1];
1192  ByteCount sizes[maxAttributeCount + 1];
1193  ATSUAttributeValuePtr values[maxAttributeCount + 1];
1194  int attributeCount = 0;
1195 
1196  Fixed size = FixRatio(emSquare, 1);
1197  tags[attributeCount] = kATSUSizeTag;
1198  sizes[attributeCount] = sizeof(size);
1199  values[attributeCount] = &size;
1200  ++attributeCount;
1201 
1202  Q_ASSERT(attributeCount < maxAttributeCount + 1);
1203  OSStatus err = ATSUSetAttributes(unscaledStyle, attributeCount, tags, sizes, values);
1204  Q_ASSERT(err == noErr);
1205  Q_UNUSED(err);
1206 
1207  // various CTFont metrics functions: CTFontGetBoundingRectsForGlyphs, CTFontGetAdvancesForGlyphs
1208  GlyphID atsuGlyph = glyph;
1209  ATSGlyphScreenMetrics atsuMetrics;
1210  ATSUGlyphGetScreenMetrics(unscaledStyle, 1, &atsuGlyph, 0,
1211  /* iForcingAntiAlias =*/ false,
1212  /* iAntiAliasSwitch =*/true,
1213  &atsuMetrics);
1214 
1215  metrics->width = int(atsuMetrics.width);
1216  metrics->height = int(atsuMetrics.height);
1217  metrics->x = QFixed::fromReal(atsuMetrics.topLeft.x);
1218  metrics->y = -QFixed::fromReal(atsuMetrics.topLeft.y);
1219  metrics->xoff = QFixed::fromReal(atsuMetrics.deviceAdvance.x);
1220  metrics->yoff = QFixed::fromReal(atsuMetrics.deviceAdvance.y);
1221 
1222  QFixedPoint p;
1223  addGlyphsToPathHelper(unscaledStyle, &glyph, &p, 1, path);
1224 
1225  ATSUDisposeStyle(unscaledStyle);
1226 }
1227 #endif // !QT_MAC_USE_COCOA
1228 
QAtomicInt ref
virtual QFixed lineThickness() const
static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path)
virtual FaceId faceId() const
static CGColorSpaceRef macGenericColorSpace()
#define FixedToQFixed(a)
QFixed * advances_y
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path, QTextItem::RenderFlags)
QCFType< CGFontRef > cgFont
double qreal
Definition: qglobal.h:1193
virtual int glyphCount() const
unsigned char c[8]
Definition: qnumeric_p.h:62
Q_DECL_CONSTEXPR const T & qMin(const T &a, const T &b)
Definition: qglobal.h:1215
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
virtual bool canRender(const QChar *string, int len)
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
QFixed * advances_x
ushort unicode() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: qchar.h:251
virtual QFixed ascent() const
qreal pointSize
Definition: qfont_p.h:89
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
QByteArray toUtf8() const Q_REQUIRED_RESULT
Returns a UTF-8 representation of the string as a QByteArray.
Definition: qstring.cpp:4074
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition: qimage.cpp:2032
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
RenderFlags flags
static OSStatus closePath(void *)
ATSUTextLayout textLayout
void closeSubpath()
Closes the current subpath by drawing a line to the beginning of the subpath, automatically starting ...
virtual void doKerning(QGlyphLayout *, QTextEngine::ShaperFlags) const
static const uchar * getCMap(const uchar *table, uint tableSize, bool *isSymbolFont, int *cmapSize)
static QColor cmap[256]
Definition: qgl_mac.mm:760
bool isLowSurrogate() const
Returns true if the QChar is the low part of a utf16 surrogate (ie.
Definition: qchar.h:279
static LibLoadStatus status
Definition: qlocale_icu.cpp:69
unsigned int styleStrategy
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
void qGamma_correct_back_to_linear_cs(QImage *image)
Definition: qimage.cpp:3938
static OSStatus lineTo(const Float32Point *, void *)
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 OSStatus cubicTo(const Float32Point *, const Float32Point *, const Float32Point *, void *)
The QString class provides a Unicode character string.
Definition: qstring.h:83
virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const
QGlyphLayout mid(int position, int n=-1) const
static QFixed fromReal(qreal r)
Definition: qfixed_p.h:70
bool isHighSurrogate() const
Returns true if the QChar is the high part of a utf16 surrogate (ie.
Definition: qchar.h:276
#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
void draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
bool stringToCMapInternal(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags, ShaperItem *item) const
Q_DECL_CONSTEXPR const T & qMax(const T &a, const T &b)
Definition: qglobal.h:1217
int fontIndexForFontID(ATSUFontID id) const
static quint32 getTrueTypeGlyphIndex(const uchar *cmap, uint unicode)
virtual ~QFontEngineMac()
#define MAKE_TAG(ch1, ch2, ch3, ch4)
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs)
void lineTo(const QPointF &p)
Adds a straight line from the current position to the given endPoint.
QGlyphLayout glyphs
unsigned char uchar
Definition: qglobal.h:994
static OSStatus moveTo(const Float32Point *, void *)
QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round=false)
QFixed floor() const
Definition: qfixed_p.h:81
#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
The QRectF class defines a rectangle in the plane using floating point precision. ...
Definition: qrect.h:511
QImage imageForGlyph(glyph_t glyph, int margin, bool colorful)
Helper function for alphaMapForGlyph and alphaRGBMapForGlyph.
QFixed y
Definition: qfixed_p.h:191
QMacFontPath(float _x, float _y, QPainterPath *_path)
void advance(float _x)
void clear()
Removes all the elements from the vector and releases the memory used by the vector.
Definition: qvector.h:347
static const QCssKnownValue positions[NumKnownPositionModes - 1]
Definition: qcssparser.cpp:329
QFontEngineMacMulti(const ATSFontFamilyRef &atsFamily, const ATSFontRef &atsFontRef, const QFontDef &fontDef, bool kerning)
QFixed round() const
Definition: qfixed_p.h:80
QFontEngineMacMulti * multiEngine
virtual qreal maxCharWidth() const
bool deref()
Atomically decrements the value of this QAtomicInt.
short qint16
Definition: qglobal.h:935
virtual QFixed descent() 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
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
Internal QTextItem.
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *numGlyphs, QTextEngine::ShaperFlags flags) const
int toInt() const
Definition: qfixed_p.h:76
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
uint weight
Definition: qfont_p.h:95
virtual void getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metrics_t *metrics)
QImage transformed(const QMatrix &matrix, Qt::TransformationMode mode=Qt::FastTransformation) const
Returns a copy of the image that is transformed using the given transformation matrix and transformat...
Definition: qimage.cpp:4698
quint16 values[128]
signed long OSStatus
int qt_antialiasing_threshold
static unsigned int getChar(const QChar *str, int &i, const int len)
qreal pixelSize
Definition: qfont_p.h:90
const T & at(int i) const
Returns the item at index position i in the vector.
Definition: qvector.h:350
QVector< QFontEngine * > engines
virtual ~QFontEngineMacMulti()
quint16 qFromBigEndian< quint16 >(const uchar *src)
Definition: qendian.h:249
virtual bool canRender(const QChar *string, int len)
int length() const
Same as size().
Definition: qbytearray.h:356
const char * constData() const
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:433
Q_GUI_EXPORT_INLINE int qGray(int r, int g, int b)
Definition: qrgb.h:75
uchar * bits()
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1946
const HB_CharAttributes * charAttributes
friend class QFontEngineMac
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
struct CGColorSpace * CGColorSpaceRef
quint16 GlyphID
QByteArray cmapTable
uint style
Definition: qfont_p.h:97
#define ctx
Definition: qgl.cpp:6094
static QByteArray convertToPostscriptFontFamilyName(const QByteArray &fontFamily)
QFontEngineMacMulti::ShaperItem * shaperItem
QTextEngine::ShaperFlags flags
QGlyphLayout * glyphs
static OSStatus atsuPostLayoutCallback(ATSULayoutOperationSelector selector, ATSULineRef lineRef, URefCon refCon, void *operationExtraParameter, ATSULayoutOperationCallbackStatus *callbackStatus)
virtual QImage alphaMapForGlyph(glyph_t)
qreal toReal() const
Definition: qfixed_p.h:77
const unsigned char * cmap
uint stretch
Definition: qfont_p.h:98
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
static uint surrogateToUcs4(ushort high, ushort low)
Converts a UTF16 surrogate pair with the given high and low values to its UCS-4 code point...
Definition: qchar.h:297
const QFontEngineMac * engineAt(int i) const
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
virtual Properties properties() const
void cubicTo(const QPointF &ctrlPt1, const QPointF &ctrlPt2, const QPointF &endPt)
Adds a cubic Bezier curve between the current position and the given endPoint using the control point...
QFixed effectiveAdvance(int item) 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
void setPosition(float _x, float _y)
CGAffineTransform transform
virtual QFixed leading() const
QFontEngineMac(ATSUStyle baseStyle, ATSUFontID fontID, const QFontDef &def, QFontEngineMacMulti *multiEngine=0)
static QFixed kerning(int left, int right, const QFontEngine::KernPair *pairs, int numPairs)
virtual QFixed averageCharWidth() const
virtual QFixed xHeight() const
QTextEngine::ShaperFlags flags
struct CGContext * CGContextRef
virtual void loadEngine(int at)
QFontDef fontDef
virtual QByteArray getSfntTable(uint tag) const
uint styleStrategy
Definition: qfont_p.h:92
QPainterPath * path
#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 void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const
unsigned int glyph_t
virtual qreal maxCharWidth() const
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
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t)
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
Qt::LayoutDirection direction
CGAffineTransform transform