summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontengine_coretext.mm
diff options
context:
space:
mode:
authorEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2011-03-22 10:57:59 +0100
committerEskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>2011-04-15 12:56:26 +0200
commit1348f4f0853155182d2ea5836902794d1e43980c (patch)
treef51a9882326ff3d89876902a65af0493436d3146 /src/gui/text/qfontengine_coretext.mm
parent3bff1637cd49617d334c1be63c20e008fac93be1 (diff)
Long live QRawFont!
The QGlyphs API was initially attempted with a bastardization of QFont which was meant to encapsulate a single, physical font instance (a QFontEngine) where a set of glyph indexes would make sense. This is not how QFont was intended to be used, and it caused several issues. At the same time, the requirement for loading a font from ttf/otf data and be able to access it and use it without polluting the rest of the process with the font arose. To support these two APIs we introduce QRawFont, which is an abstraction on top of a single physical font. Done-with: Jiang Jiang
Diffstat (limited to 'src/gui/text/qfontengine_coretext.mm')
-rw-r--r--src/gui/text/qfontengine_coretext.mm316
1 files changed, 206 insertions, 110 deletions
diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm
index 4d9192e3c1..20b37300fa 100644
--- a/src/gui/text/qfontengine_coretext.mm
+++ b/src/gui/text/qfontengine_coretext.mm
@@ -52,6 +52,31 @@ QT_BEGIN_NAMESPACE
static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90);
+static void loadAdvancesForGlyphs(CTFontRef ctfont,
+ QVarLengthArray<CGGlyph> &cgGlyphs,
+ QGlyphLayout *glyphs, int len,
+ QTextEngine::ShaperFlags flags,
+ const QFontDef &fontDef)
+{
+ Q_UNUSED(flags);
+ QVarLengthArray<CGSize> advances(len);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
+
+ for (int i = 0; i < len; ++i) {
+ if (glyphs->glyphs[i] & 0xff000000)
+ continue;
+ glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
+ glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
+ }
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (int i = 0; i < len; ++i) {
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances_y[i] = glyphs->advances_y[i].round();
+ }
+ }
+}
+
QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning)
: QFontEngineMulti(0)
{
@@ -83,7 +108,31 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const
ctfont = baseFont;
CFRetain(ctfont);
}
+ init(kerning);
+}
+
+QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning)
+ : QFontEngineMulti(0)
+{
+ this->fontDef = fontDef;
+
+ transform = CGAffineTransformIdentity;
+ if (fontDef.stretch != 100) {
+ transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
+ }
+
+ ctfont = CTFontCreateWithGraphicsFont(cgFontRef, fontDef.pixelSize, &transform, NULL);
+ init(kerning);
+}
+
+QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
+{
+ CFRelease(ctfont);
+}
+void QCoreTextFontEngineMulti::init(bool kerning)
+{
+ Q_ASSERT(ctfont != NULL);
attributeDict = CFDictionaryCreateMutable(0, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
@@ -94,26 +143,20 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const
CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern);
}
- QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this);
+ QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef);
fe->ref.ref();
engines.append(fe);
-
-}
-
-QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
-{
- CFRelease(ctfont);
}
-uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const
+uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const
{
for (int i = 0; i < engines.count(); ++i) {
- if (CFEqual(engineAt(i)->ctfont, id))
+ if (CFEqual(engineAt(i)->ctfont, font))
return i;
}
QCoreTextFontEngineMulti *that = const_cast<QCoreTextFontEngineMulti *>(this);
- QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that);
+ QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef);
fe->ref.ref();
that->engines.append(fe);
return engines.count() - 1;
@@ -317,72 +360,45 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay
if (flags & QTextEngine::GlyphIndicesOnly)
return true;
- QVarLengthArray<CGSize> advances(len);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
-
- for (int i = 0; i < len; ++i) {
- if (glyphs->glyphs[i] & 0xff000000)
- continue;
- glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
- glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
- }
-
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
- for (int i = 0; i < len; ++i) {
- glyphs->advances_x[i] = glyphs->advances_x[i].round();
- glyphs->advances_y[i] = glyphs->advances_y[i].round();
- }
- }
-
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
return true;
}
-void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
-{
-}
-void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
-{
-}
-
void QCoreTextFontEngineMulti::loadEngine(int)
{
// Do nothing
Q_ASSERT(false);
}
+extern int qt_antialiasing_threshold; // from qapplication.cpp
+static inline CGAffineTransform transformFromFontDef(const QFontDef &fontDef)
+{
+ CGAffineTransform transform = CGAffineTransformIdentity;
+ if (fontDef.stretch != 100)
+ transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
+ return transform;
+}
-QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def,
- QCoreTextFontEngineMulti *multiEngine)
+QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
{
fontDef = def;
- parentEngine = multiEngine;
- synthesisFlags = 0;
+ transform = transformFromFontDef(fontDef);
ctfont = font;
CFRetain(ctfont);
- cgFont = CTFontCopyGraphicsFont(ctfont, NULL);
- CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
- if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) {
- synthesisFlags |= SynthesizedBold;
- }
-
- if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) {
- synthesisFlags |= SynthesizedItalic;
- }
- transform = CGAffineTransformIdentity;
- if (fontDef.stretch != 100) {
- transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
- }
- QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
- if (os2Table.size() >= 10)
- fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
+ cgFont = CTFontCopyGraphicsFont(font, NULL);
+ init();
+}
- QSettings appleSettings(QLatin1String("apple.com"));
- QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold"));
- if (appleValue.isValid())
- antialiasing_threshold = appleValue.toInt();
- else
- antialiasing_threshold = -1;
+QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def)
+{
+ fontDef = def;
+ transform = transformFromFontDef(fontDef);
+ cgFont = font;
+ // Keep reference count balanced
+ CFRetain(cgFont);
+ ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL);
+ init();
}
QCoreTextFontEngine::~QCoreTextFontEngine()
@@ -391,9 +407,89 @@ QCoreTextFontEngine::~QCoreTextFontEngine()
CFRelease(ctfont);
}
-bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait)
{
- return false;
+ if (CFDictionaryContainsKey(allTraits, trait)) {
+ CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait);
+ float v = 0;
+ CFNumberGetValue(traitNum, kCFNumberFloatType, &v);
+ // the value we get from CFNumberRef is from -1.0 to 1.0
+ int value = v * 500 + 500;
+ return value;
+ }
+
+ return 0;
+}
+
+void QCoreTextFontEngine::init()
+{
+ Q_ASSERT(ctfont != NULL);
+ Q_ASSERT(cgFont != NULL);
+
+ QCFString family = CTFontCopyFamilyName(ctfont);
+ fontDef.family = family;
+
+ synthesisFlags = 0;
+ CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
+ if (traits & kCTFontItalicTrait)
+ fontDef.style = QFont::StyleItalic;
+
+ CFDictionaryRef allTraits = CTFontCopyTraits(ctfont);
+ fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait));
+ int slant = getTraitValue(allTraits, kCTFontSlantTrait);
+ if (slant > 500 && !(traits & kCTFontItalicTrait))
+ fontDef.style = QFont::StyleOblique;
+ CFRelease(allTraits);
+
+ if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait))
+ synthesisFlags |= SynthesizedBold;
+ // XXX: we probably don't need to synthesis italic for oblique font
+ if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait))
+ synthesisFlags |= SynthesizedItalic;
+
+ avgCharWidth = 0;
+ QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ unsigned emSize = CTFontGetUnitsPerEm(ctfont);
+ if (os2Table.size() >= 10) {
+ fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
+ // qAbs is a workaround for weird fonts like Lucida Grande
+ qint16 width = qAbs(qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 2)));
+ avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize);
+ } else
+ avgCharWidth = QFontEngine::averageCharWidth();
+
+ ctMaxCharWidth = ctMinLeftBearing = ctMinRightBearing = 0;
+ QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ if (hheaTable.size() >= 16) {
+ quint16 width = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 10));
+ ctMaxCharWidth = width * fontDef.pixelSize / emSize;
+ qint16 bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 12));
+ ctMinLeftBearing = bearing * fontDef.pixelSize / emSize;
+ bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 14));
+ ctMinRightBearing = bearing * fontDef.pixelSize / emSize;
+ }
+}
+
+bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ *nglyphs = len;
+ QCFType<CFStringRef> cfstring;
+
+ QVarLengthArray<CGGlyph> cgGlyphs(len);
+ CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
+
+ for (int i = 0; i < len; ++i)
+ if (cgGlyphs[i])
+ glyphs->glyphs[i] = cgGlyphs[i];
+
+ if (flags & QTextEngine::GlyphIndicesOnly)
+ return true;
+
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
+ return true;
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
@@ -407,6 +503,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
}
return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
}
+
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
{
glyph_metrics_t ret;
@@ -460,31 +557,29 @@ QFixed QCoreTextFontEngine::xHeight() const
? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
: QFixed::fromReal(CTFontGetXHeight(ctfont));
}
+
QFixed QCoreTextFontEngine::averageCharWidth() const
{
- // ### Need to implement properly and get the information from the OS/2 Table.
return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- ? QFontEngine::averageCharWidth().round()
- : QFontEngine::averageCharWidth();
+ ? avgCharWidth.round() : avgCharWidth;
}
qreal QCoreTextFontEngine::maxCharWidth() const
{
- // ### Max Help!
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMaxCharWidth) : ctMaxCharWidth;
}
+
qreal QCoreTextFontEngine::minLeftBearing() const
{
- // ### Min Help!
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMinLeftBearing) : ctMinLeftBearing;
}
+
qreal QCoreTextFontEngine::minRightBearing() const
{
- // ### Max Help! (even thought it's right)
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMinRightBearing) : ctMinLeftBearing;
}
void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
@@ -602,12 +697,6 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position
}
}
-QFont QCoreTextFontEngine::createExplicitFont() const
-{
- QString familyName = QCFString::toQString(CTFontCopyFamilyName(ctfont));
- return createExplicitFontWithName(familyName);
-}
-
QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa)
{
const glyph_metrics_t br = boundingBox(glyph);
@@ -624,7 +713,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
cgflags);
CGContextSetFontSize(ctx, fontDef.pixelSize);
CGContextSetShouldAntialias(ctx, aa ||
- (fontDef.pointSize > antialiasing_threshold
+ (fontDef.pointSize > qt_antialiasing_threshold
&& !(fontDef.styleStrategy & QFont::NoAntialias)));
CGContextSetShouldSmoothFonts(ctx, aa);
CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
@@ -696,12 +785,19 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
return im;
}
-void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
{
- Q_ASSERT(false);
- Q_UNUSED(numGlyphs);
- Q_UNUSED(glyphs);
- Q_UNUSED(flags);
+ int i, numGlyphs = glyphs->numGlyphs;
+ QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs);
+
+ for (i = 0; i < numGlyphs; ++i) {
+ if (glyphs->glyphs[i] & 0xff000000)
+ cgGlyphs[i] = 0;
+ else
+ cgGlyphs[i] = glyphs->glyphs[i];
+ }
+
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef);
}
QFontEngine::FaceId QCoreTextFontEngine::faceId() const
@@ -711,36 +807,36 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const
bool QCoreTextFontEngine::canRender(const QChar *string, int len)
{
- QCFType<CTFontRef> retFont = CTFontCreateForString(ctfont,
- QCFType<CFStringRef>(CFStringCreateWithCharactersNoCopy(0,
- reinterpret_cast<const UniChar *>(string),
- len, kCFAllocatorNull)),
- CFRangeMake(0, len));
- return retFont != 0;
- return false;
-}
-
- bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
- {
- QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
- if (!table || !length)
- return false;
- CFIndex tableLength = CFDataGetLength(table);
- int availableLength = *length;
- *length = tableLength;
- if (buffer) {
- if (tableLength > availableLength)
- return false;
- CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
- }
- return true;
- }
+ QVarLengthArray<CGGlyph> cgGlyphs(len);
+ return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len);
+}
+
+bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
+ if (!table || !length)
+ return false;
+ CFIndex tableLength = CFDataGetLength(table);
+ int availableLength = *length;
+ *length = tableLength;
+ if (buffer) {
+ if (tableLength > availableLength)
+ return false;
+ CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
+ }
+ return true;
+}
void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *)
{
// ###
}
+QFixed QCoreTextFontEngine::emSquareSize() const
+{
+ return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
+}
+
QT_END_NAMESPACE
#endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)