summaryrefslogtreecommitdiffstats
path: root/src/gui/text/coretext/qfontengine_coretext.mm
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/coretext/qfontengine_coretext.mm')
-rw-r--r--src/gui/text/coretext/qfontengine_coretext.mm217
1 files changed, 80 insertions, 137 deletions
diff --git a/src/gui/text/coretext/qfontengine_coretext.mm b/src/gui/text/coretext/qfontengine_coretext.mm
index 57fbf6032e..87ed95f3ac 100644
--- a/src/gui/text/coretext/qfontengine_coretext.mm
+++ b/src/gui/text/coretext/qfontengine_coretext.mm
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2016 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU Lesser General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU Lesser
-** General Public License version 3 as published by the Free Software
-** Foundation and appearing in the file LICENSE.LGPL3 included in the
-** packaging of this file. Please review the following information to
-** ensure the GNU Lesser General Public License version 3 requirements
-** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 2.0 or (at your option) the GNU General
-** Public license version 3 or any later version approved by the KDE Free
-** Qt Foundation. The licenses are as published by the Free Software
-** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-2.0.html and
-** https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
+// Copyright (C) 2016 The Qt Company Ltd.
+// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
#include "qfontengine_coretext_p.h"
@@ -48,6 +12,9 @@
#include <QtGui/qpainterpath.h>
#include <private/qcoregraphics_p.h>
#include <private/qimage_p.h>
+#include <private/qguiapplication_p.h>
+#include <private/qstringiterator_p.h>
+#include <qpa/qplatformtheme.h>
#include <cmath>
@@ -86,8 +53,6 @@
QT_BEGIN_NAMESPACE
-Q_LOGGING_CATEGORY(lcQpaFonts, "qt.qpa.fonts")
-
static float SYNTHETIC_ITALIC_SKEW = std::tan(14.f * std::acos(0.f) / 90.f);
bool QCoreTextFontEngine::ct_getSfntTable(void *user_data, uint tag, uchar *buffer, uint *length)
@@ -163,9 +128,13 @@ public:
QByteArray m_fontData;
};
-QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData, qreal pixelSize, QFont::HintingPreference hintingPreference)
+QCoreTextFontEngine *QCoreTextFontEngine::create(const QByteArray &fontData,
+ qreal pixelSize,
+ QFont::HintingPreference hintingPreference,
+ const QMap<QFont::Tag, float> &variableAxisValues)
{
Q_UNUSED(hintingPreference);
+ Q_UNUSED(variableAxisValues);
QCFType<CFDataRef> fontDataReference = fontData.toRawCFData();
QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithCFData(fontDataReference);
@@ -224,9 +193,10 @@ void QCoreTextFontEngine::init()
face_id.index = 0;
QCFString name = CTFontCopyName(ctfont, kCTFontUniqueNameKey);
face_id.filename = QString::fromCFString(name).toUtf8();
+ face_id.variableAxes = fontDef.variableAxisValues;
QCFString family = CTFontCopyFamilyName(ctfont);
- fontDef.family = family;
+ fontDef.families = QStringList(family);
QCFString styleName = (CFStringRef) CTFontCopyAttribute(ctfont, kCTFontStyleNameAttribute);
fontDef.styleName = styleName;
@@ -255,19 +225,20 @@ void QCoreTextFontEngine::init()
};
QCFType<CFDictionaryRef> allTraits = CTFontCopyTraits(ctfont);
- fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait));
int slant = static_cast<int>(getTraitValue(allTraits, kCTFontSlantTrait) * 500 + 500);
if (slant > 500 && !(traits & kCTFontItalicTrait))
fontDef.style = QFont::StyleOblique;
- if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait))
+ if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_BOLD"))
synthesisFlags |= SynthesizedBold;
- // XXX: we probably don't need to synthesis italic for oblique font
- if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait))
+ else
+ fontDef.weight = QCoreTextFontEngine::qtWeightFromCFWeight(getTraitValue(allTraits, kCTFontWeightTrait));
+
+ if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait) && !qEnvironmentVariableIsSet("QT_NO_SYNTHESIZED_ITALIC"))
synthesisFlags |= SynthesizedItalic;
avgCharWidth = 0;
- QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ QByteArray os2Table = getSfntTable(QFont::Tag("OS/2").value());
unsigned emSize = CTFontGetUnitsPerEm(ctfont);
if (os2Table.size() >= 10) {
fsType = qFromBigEndian<quint16>(os2Table.constData() + 8);
@@ -304,29 +275,30 @@ glyph_t QCoreTextFontEngine::glyphIndex(uint ucs4) const
return glyphIndices[0];
}
-bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
- int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QFontEngine::ShaperFlags flags) const
{
Q_ASSERT(glyphs->numGlyphs >= *nglyphs);
if (*nglyphs < len) {
*nglyphs = len;
- return false;
+ return -1;
}
QVarLengthArray<CGGlyph> cgGlyphs(len);
CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
int glyph_pos = 0;
- for (int i = 0; i < len; ++i) {
- glyphs->glyphs[glyph_pos] = cgGlyphs[i];
- if (glyph_pos < i)
- cgGlyphs[glyph_pos] = cgGlyphs[i];
- glyph_pos++;
-
- // If it's a non-BMP char, skip the lower part of surrogate pair and go
- // directly to the next char without increasing glyph_pos
- if (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate())
- ++i;
+ int mappedGlyphs = 0;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ qsizetype idx = it.index();
+ char32_t ucs4 = it.next();
+ glyphs->glyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyph_pos < idx)
+ cgGlyphs[glyph_pos] = cgGlyphs[idx];
+ if (glyphs->glyphs[glyph_pos] != 0 || isIgnorableChar(ucs4))
+ mappedGlyphs++;
+ glyph_pos++;
}
*nglyphs = glyph_pos;
@@ -335,22 +307,7 @@ bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *
if (!(flags & GlyphIndicesOnly))
loadAdvancesForGlyphs(cgGlyphs, glyphs);
- return true;
-}
-
-glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
-{
- QFixed w;
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- bool round = fontDef.styleStrategy & QFont::ForceIntegerMetrics;
-QT_WARNING_POP
-
- for (int i = 0; i < glyphs.numGlyphs; ++i) {
- w += round ? glyphs.effectiveAdvance(i).round()
- : glyphs.effectiveAdvance(i);
- }
- return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
+ return mappedGlyphs;
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
@@ -370,14 +327,6 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
ret.xoff = QFixed::fromReal(advances[0].width);
ret.yoff = QFixed::fromReal(advances[0].height);
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
-QT_WARNING_POP
- ret.xoff = ret.xoff.round();
- ret.yoff = ret.yoff.round();
- }
-
return ret;
}
@@ -387,7 +336,10 @@ void QCoreTextFontEngine::initializeHeightMetrics() const
m_descent = QFixed::fromReal(CTFontGetDescent(ctfont));
m_leading = QFixed::fromReal(CTFontGetLeading(ctfont));
- QFontEngine::initializeHeightMetrics();
+ if (preferTypoLineMetrics())
+ QFontEngine::initializeHeightMetrics();
+ else
+ m_heightMetricsQueried = true;
}
QFixed QCoreTextFontEngine::capHeight() const
@@ -396,32 +348,17 @@ QFixed QCoreTextFontEngine::capHeight() const
if (c <= 0)
return calculatedCapHeight();
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
-QT_WARNING_POP
- c = c.round();
-
return c;
}
QFixed QCoreTextFontEngine::xHeight() const
{
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- ? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
- : QFixed::fromReal(CTFontGetXHeight(ctfont));
-QT_WARNING_POP
+ return QFixed::fromReal(CTFontGetXHeight(ctfont));
}
QFixed QCoreTextFontEngine::averageCharWidth() const
{
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- ? avgCharWidth.round() : avgCharWidth;
-QT_WARNING_POP
+ return avgCharWidth;
}
qreal QCoreTextFontEngine::maxCharWidth() const
@@ -437,6 +374,7 @@ bool QCoreTextFontEngine::hasColorGlyphs() const
return glyphFormat == QFontEngine::Format_ARGB;
}
+Q_GUI_EXPORT extern bool qt_scaleForTransform(const QTransform &transform, qreal *scale); // qtransform.cpp
void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
{
QVarLengthArray<QFixedPoint> positions;
@@ -453,7 +391,8 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt
CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, -1, 0, -paintDeviceHeight);
- CGAffineTransformConcat(cgMatrix, oldTextMatrix);
+ // FIXME: Should we include the old matrix here? If so we need to assign it.
+ Q_UNUSED(CGAffineTransformConcat(cgMatrix, oldTextMatrix));
if (synthesisFlags & QFontEngine::SynthesizedItalic)
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMake(1, 0, -SYNTHETIC_ITALIC_SKEW, 1, 0, 0));
@@ -480,7 +419,15 @@ void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextIt
CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx);
if (synthesisFlags & QFontEngine::SynthesizedBold) {
- CGContextSetTextPosition(ctx, positions[0].x.toReal() + 0.5 * lineThickness().toReal(),
+ QTransform matrix(cgMatrix.a, cgMatrix.b, cgMatrix.c, cgMatrix.d, cgMatrix.tx, cgMatrix.ty);
+
+ qreal boldOffset = 0.5 * lineThickness().toReal();
+ qreal scale;
+ qt_scaleForTransform(matrix, &scale);
+ boldOffset *= scale;
+
+ CGContextSetTextPosition(ctx,
+ positions[0].x.toReal() + boldOffset,
positions[0].y.toReal());
CTFontDrawGlyphs(ctfont, cgGlyphs.data(), cgPositions.data(), glyphs.size(), ctx);
}
@@ -564,13 +511,17 @@ static void qcoretextfontengine_scaleMetrics(glyph_metrics_t &br, const QTransfo
}
}
-glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, GlyphFormat format)
+glyph_metrics_t QCoreTextFontEngine::alphaMapBoundingBox(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, GlyphFormat format)
{
if (matrix.type() > QTransform::TxScale)
return QFontEngine::alphaMapBoundingBox(glyph, subPixelPosition, matrix, format);
glyph_metrics_t br = boundingBox(glyph);
- qcoretextfontengine_scaleMetrics(br, matrix);
+
+ QTransform xform = matrix;
+ if (fontDef.stretch != 100 && fontDef.stretch != QFont::AnyStretch)
+ xform.scale(fontDef.stretch / 100.0, 1.0);
+ qcoretextfontengine_scaleMetrics(br, xform);
// Normalize width and height
if (br.width < 0)
@@ -746,7 +697,7 @@ qreal QCoreTextFontEngine::fontSmoothingGamma()
return 2.0;
}
-QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &matrix, const QColor &color)
+QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &matrix, const QColor &color)
{
glyph_metrics_t br = alphaMapBoundingBox(glyph, subPixelPosition, matrix, glyphFormat);
@@ -777,10 +728,12 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
// draw with white or black fill, and then invert the glyph image in the latter case,
// producing an alpha map. This covers the most common use-cases, but longer term we
// should propagate the fill color all the way from the paint engine, and include it
- //in the key for the glyph cache.
+ // in the key for the glyph cache.
- if (!qt_mac_applicationIsInDarkMode())
- return kCGColorBlack;
+ if (auto *platformTheme = QGuiApplicationPrivate::platformTheme()) {
+ if (platformTheme->colorScheme() != Qt::ColorScheme::Dark)
+ return kCGColorBlack;
+ }
}
return kCGColorWhite;
}();
@@ -806,8 +759,9 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
cgMatrix = CGAffineTransformConcat(cgMatrix, CGAffineTransformMakeScale(matrix.m11(), matrix.m22()));
CGGlyph cgGlyph = glyph;
- qreal pos_x = -br.x.truncate() + subPixelPosition.toReal();
- qreal pos_y = im.height() + br.y.toReal();
+
+ qreal pos_x = -br.x.truncate() + subPixelPosition.x.toReal();
+ qreal pos_y = im.height() + br.y.toReal() - subPixelPosition.y.toReal();
if (!hasColorGlyphs()) {
CGContextSetTextMatrix(ctx, cgMatrix);
@@ -822,7 +776,13 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
if (synthesisFlags & QFontEngine::SynthesizedBold) {
- CGContextSetTextPosition(ctx, pos_x + 0.5 * lineThickness().toReal(), pos_y);
+ qreal boldOffset = 0.5 * lineThickness().toReal();
+
+ qreal scale;
+ qt_scaleForTransform(matrix, &scale);
+ boldOffset *= scale;
+
+ CGContextSetTextPosition(ctx, pos_x + boldOffset, pos_y);
CTFontDrawGlyphs(ctfont, &cgGlyph, &CGPointZero, 1, ctx);
}
} else {
@@ -850,12 +810,12 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
return im;
}
-QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition)
{
return alphaMapForGlyph(glyph, subPixelPosition, QTransform());
}
-QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x)
+QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &x)
{
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaMapForGlyph(glyph, subPixelPosition, x);
@@ -877,7 +837,7 @@ QImage QCoreTextFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosit
return alphaMap;
}
-QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &x)
+QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &x)
{
if (x.type() > QTransform::TxScale)
return QFontEngine::alphaRGBMapForGlyph(glyph, subPixelPosition, x);
@@ -885,7 +845,7 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
return imageForGlyph(glyph, subPixelPosition, x);
}
-QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t, const QColor &color)
+QImage QCoreTextFontEngine::bitmapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t, const QColor &color)
{
if (t.type() > QTransform::TxScale)
return QFontEngine::bitmapForGlyph(glyph, subPixelPosition, t, color);
@@ -914,14 +874,9 @@ void QCoreTextFontEngine::loadAdvancesForGlyphs(QVarLengthArray<CGGlyph> &cgGlyp
QVarLengthArray<CGSize> advances(numGlyphs);
CTFontGetAdvancesForGlyphs(ctfont, kCTFontOrientationHorizontal, cgGlyphs.data(), advances.data(), numGlyphs);
- for (int i = 0; i < numGlyphs; ++i) {
- QFixed advance = QFixed::fromReal(advances[i].width);
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- glyphs->advances[i] = fontDef.styleStrategy & QFont::ForceIntegerMetrics
- ? advance.round() : advance;
-QT_WARNING_POP
- }
+ qreal stretch = fontDef.stretch != QFont::AnyStretch ? fontDef.stretch / 100.0 : 1.0;
+ for (int i = 0; i < numGlyphs; ++i)
+ glyphs->advances[i] = QFixed::fromReal(advances[i].width * stretch);
}
QFontEngine::FaceId QCoreTextFontEngine::faceId() const
@@ -1029,18 +984,6 @@ QFontEngine::Properties QCoreTextFontEngine::properties() const
result.capHeight = QFixed::fromReal(CTFontGetCapHeight(ctfont) * scale);
result.lineWidth = QFixed::fromReal(CTFontGetUnderlineThickness(ctfont) * scale);
-QT_WARNING_PUSH
-QT_WARNING_DISABLE_DEPRECATED
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
-QT_WARNING_POP
- result.ascent = result.ascent.round();
- result.descent = result.descent.round();
- result.leading = result.leading.round();
- result.italicAngle = result.italicAngle.round();
- result.capHeight = result.capHeight.round();
- result.lineWidth = result.lineWidth.round();
- }
-
return result;
}