diff options
Diffstat (limited to 'src/gui/text/coretext/qfontengine_coretext.mm')
-rw-r--r-- | src/gui/text/coretext/qfontengine_coretext.mm | 217 |
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; } |