summaryrefslogtreecommitdiffstats
path: root/src/gui/text/qfontengine.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text/qfontengine.cpp')
-rw-r--r--src/gui/text/qfontengine.cpp355
1 files changed, 201 insertions, 154 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 07b19d4d19..dff400c18b 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1,41 +1,5 @@
-/****************************************************************************
-**
-** Copyright (C) 2018 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) 2021 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 <qdebug.h>
#include <private/qfontengine_p.h>
@@ -90,17 +54,6 @@ static inline bool qSafeFromBigEndian(const uchar *source, const uchar *end, T *
return true;
}
-// Harfbuzz helper functions
-
-#if QT_CONFIG(harfbuzz)
-Q_GLOBAL_STATIC_WITH_ARGS(bool, useHarfbuzzNG,(qgetenv("QT_HARFBUZZ") != "old"))
-
-bool qt_useHarfbuzzNG()
-{
- return *useHarfbuzzNG();
-}
-#endif
-
int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
{
Q_UNUSED(glyph);
@@ -180,7 +133,7 @@ QFontEngine::~QFontEngine()
QFixed QFontEngine::lineThickness() const
{
// ad hoc algorithm
- int score = fontDef.weight * fontDef.pixelSize;
+ int score = fontDef.weight * fontDef.pixelSize / 10;
int lw = score / 700;
// looks better with thicker line for small pointsizes
@@ -199,20 +152,20 @@ void *QFontEngine::harfbuzzFont() const
{
Q_ASSERT(type() != QFontEngine::Multi);
#if QT_CONFIG(harfbuzz)
- if (qt_useHarfbuzzNG())
- return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
-#endif
+ return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
+#else
return nullptr;
+#endif
}
void *QFontEngine::harfbuzzFace() const
{
Q_ASSERT(type() != QFontEngine::Multi);
#if QT_CONFIG(harfbuzz)
- if (qt_useHarfbuzzNG())
- return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
-#endif
+ return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
+#else
return nullptr;
+#endif
}
bool QFontEngine::supportsScript(QChar::Script script) const
@@ -227,23 +180,23 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return true;
#if QT_CONFIG(harfbuzz)
- if (qt_useHarfbuzzNG()) {
- // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
- uint len;
- if (getSfntTableData(MAKE_TAG('m','o','r','t'), nullptr, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), nullptr, &len))
- return true;
+ // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
+ uint lenMort = 0, lenMorx = 0;
+ if (getSfntTableData(QFont::Tag("mort").value(), nullptr, &lenMort)
+ || getSfntTableData(QFont::Tag("morx").value(), nullptr, &lenMorx)) {
+ return true;
+ }
- if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
- unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
- hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
+ if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
+ unsigned int script_count = HB_OT_MAX_TAGS_PER_SCRIPT;
+ hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
- hb_ot_tags_from_script_and_language(hb_qt_script_to_script(script), HB_LANGUAGE_INVALID,
- &script_count, script_tags,
- nullptr, nullptr);
+ hb_ot_tags_from_script_and_language(hb_qt_script_to_script(script), HB_LANGUAGE_INVALID,
+ &script_count, script_tags,
+ nullptr, nullptr);
- if (hb_ot_layout_table_select_script(face, HB_OT_TAG_GSUB, script_count, script_tags, nullptr, nullptr))
- return true;
- }
+ if (hb_ot_layout_table_select_script(face, HB_OT_TAG_GSUB, script_count, script_tags, nullptr, nullptr))
+ return true;
}
#endif
return false;
@@ -430,11 +383,16 @@ void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rig
bool QFontEngine::processHheaTable() const
{
- QByteArray hhea = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray hhea = getSfntTable(QFont::Tag("hhea").value());
if (hhea.size() >= 10) {
- qint16 ascent = qFromBigEndian<qint16>(hhea.constData() + 4);
- qint16 descent = qFromBigEndian<qint16>(hhea.constData() + 6);
- qint16 leading = qFromBigEndian<qint16>(hhea.constData() + 8);
+ auto ptr = hhea.constData();
+ qint16 ascent = qFromBigEndian<qint16>(ptr + 4);
+ qint16 descent = qFromBigEndian<qint16>(ptr + 6);
+ qint16 leading = qFromBigEndian<qint16>(ptr + 8);
+
+ // Some fonts may have invalid HHEA data. We detect this and bail out.
+ if (ascent == 0 && descent == 0)
+ return false;
QFixed unitsPerEm = emSquareSize();
m_ascent = QFixed::fromReal(ascent * fontDef.pixelSize) / unitsPerEm;
@@ -450,13 +408,22 @@ bool QFontEngine::processHheaTable() const
void QFontEngine::initializeHeightMetrics() const
{
- bool hasEmbeddedBitmaps = !getSfntTable(MAKE_TAG('E', 'B', 'L', 'C')).isEmpty() || !getSfntTable(MAKE_TAG('C', 'B', 'L', 'C')).isEmpty();
+ bool hasEmbeddedBitmaps =
+ !getSfntTable(QFont::Tag("EBLC").value()).isEmpty()
+ || !getSfntTable(QFont::Tag("CBLC").value()).isEmpty()
+ || !getSfntTable(QFont::Tag("bdat").value()).isEmpty();
if (!hasEmbeddedBitmaps) {
// Get HHEA table values if available
processHheaTable();
// Allow OS/2 metrics to override if present
processOS2Table();
+
+ if (!supportsSubPixelPositions()) {
+ m_ascent = m_ascent.round();
+ m_descent = m_descent.round();
+ m_leading = m_leading.round();
+ }
}
m_heightMetricsQueried = true;
@@ -464,24 +431,32 @@ void QFontEngine::initializeHeightMetrics() const
bool QFontEngine::processOS2Table() const
{
- QByteArray os2 = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ QByteArray os2 = getSfntTable(QFont::Tag("OS/2").value());
if (os2.size() >= 78) {
- quint16 fsSelection = qFromBigEndian<quint16>(os2.constData() + 62);
- qint16 typoAscent = qFromBigEndian<qint16>(os2.constData() + 68);
- qint16 typoDescent = qFromBigEndian<qint16>(os2.constData() + 70);
- qint16 typoLineGap = qFromBigEndian<qint16>(os2.constData() + 72);
- quint16 winAscent = qFromBigEndian<quint16>(os2.constData() + 74);
- quint16 winDescent = qFromBigEndian<quint16>(os2.constData() + 76);
+ auto ptr = os2.constData();
+ quint16 fsSelection = qFromBigEndian<quint16>(ptr + 62);
+ qint16 typoAscent = qFromBigEndian<qint16>(ptr + 68);
+ qint16 typoDescent = qFromBigEndian<qint16>(ptr + 70);
+ qint16 typoLineGap = qFromBigEndian<qint16>(ptr + 72);
+ quint16 winAscent = qFromBigEndian<quint16>(ptr + 74);
+ quint16 winDescent = qFromBigEndian<quint16>(ptr + 76);
enum { USE_TYPO_METRICS = 0x80 };
QFixed unitsPerEm = emSquareSize();
if (fsSelection & USE_TYPO_METRICS) {
+ // Some fonts may have invalid OS/2 data. We detect this and bail out.
+ if (typoAscent == 0 && typoDescent == 0)
+ return false;
m_ascent = QFixed::fromReal(typoAscent * fontDef.pixelSize) / unitsPerEm;
m_descent = -QFixed::fromReal(typoDescent * fontDef.pixelSize) / unitsPerEm;
m_leading = QFixed::fromReal(typoLineGap * fontDef.pixelSize) / unitsPerEm;
} else {
+ // Some fonts may have invalid OS/2 data. We detect this and bail out.
+ if (winAscent == 0 && winDescent == 0)
+ return false;
m_ascent = QFixed::fromReal(winAscent * fontDef.pixelSize) / unitsPerEm;
m_descent = QFixed::fromReal(winDescent * fontDef.pixelSize) / unitsPerEm;
+ m_leading = QFixed{};
}
return true;
@@ -532,7 +507,7 @@ qreal QFontEngine::minRightBearing() const
if (m_minRightBearing == kBearingNotInitialized) {
// Try the 'hhea' font table first, which covers the entire font
- QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ QByteArray hheaTable = getSfntTable(QFont::Tag("hhea").value());
if (hheaTable.size() >= int(kMinRightSideBearingOffset + sizeof(qint16))) {
const uchar *tableData = reinterpret_cast<const uchar *>(hheaTable.constData());
Q_ASSERT(q16Dot16ToFloat(qFromBigEndian<quint32>(tableData)) == 1.0);
@@ -589,12 +564,23 @@ qreal QFontEngine::minRightBearing() const
}
if (m_minLeftBearing == kBearingNotInitialized || m_minRightBearing == kBearingNotInitialized)
- qWarning() << "Failed to compute left/right minimum bearings for" << fontDef.family;
+ qWarning() << "Failed to compute left/right minimum bearings for"
+ << fontDef.families.first();
}
return m_minRightBearing;
}
+glyph_metrics_t QFontEngine::boundingBox(const QGlyphLayout &glyphs)
+{
+ QFixed w;
+ for (int i = 0; i < glyphs.numGlyphs; ++i)
+ w += glyphs.effectiveAdvance(i);
+ const QFixed leftBearing = firstLeftBearing(glyphs);
+ const QFixed rightBearing = lastRightBearing(glyphs);
+ return glyph_metrics_t(leftBearing, -(ascent()), w - leftBearing - rightBearing, ascent() + descent(), w, 0);
+}
+
glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
{
glyph_metrics_t overall;
@@ -610,9 +596,9 @@ glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
QFixed y = overall.yoff + glyphs.offsets[i].y + bb.y;
overall.x = qMin(overall.x, x);
overall.y = qMin(overall.y, y);
- xmax = qMax(xmax, x + bb.width);
- ymax = qMax(ymax, y + bb.height);
- overall.xoff += bb.xoff;
+ xmax = qMax(xmax, x.ceil() + bb.width);
+ ymax = qMax(ymax, y.ceil() + bb.height);
+ overall.xoff += glyphs.effectiveAdvance(i);
overall.yoff += bb.yoff;
}
overall.height = qMax(overall.height, ymax - overall.y);
@@ -795,7 +781,7 @@ void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int n
addBitmapFontToPath(x, y, g, path, flags);
}
-QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/)
+QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/)
{
// For font engines don't support subpixel positioning
return alphaMapForGlyph(glyph);
@@ -811,9 +797,9 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
return i;
}
-QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition, const QTransform &t)
{
- if (! supportsSubPixelPositions())
+ if (!supportsHorizontalSubPixelPositions() && !supportsVerticalSubPixelPositions())
return alphaMapForGlyph(glyph, t);
QImage i = alphaMapForGlyph(glyph, subPixelPosition);
@@ -824,7 +810,7 @@ QImage QFontEngine::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, con
return i;
}
-QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition*/, const QTransform &t)
+QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, const QFixedPoint &/*subPixelPosition*/, const QTransform &t)
{
const QImage alphaMask = alphaMapForGlyph(glyph, t);
QImage rgbMask(alphaMask.width(), alphaMask.height(), QImage::Format_RGB32);
@@ -841,32 +827,37 @@ QImage QFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed /*subPixelPosition
return rgbMask;
}
-QImage QFontEngine::bitmapForGlyph(glyph_t, QFixed subPixelPosition, const QTransform&, const QColor &)
+QImage QFontEngine::bitmapForGlyph(glyph_t, const QFixedPoint &subPixelPosition, const QTransform&, const QColor &)
{
Q_UNUSED(subPixelPosition);
return QImage();
}
-QFixed QFontEngine::subPixelPositionForX(QFixed x) const
+QFixedPoint QFontEngine::subPixelPositionFor(const QFixedPoint &position) const
{
- if (m_subPixelPositionCount <= 1 || !supportsSubPixelPositions())
- return QFixed();
+ if (m_subPixelPositionCount <= 1
+ || (!supportsHorizontalSubPixelPositions()
+ && !supportsVerticalSubPixelPositions())) {
+ return QFixedPoint();
+ }
- QFixed subPixelPosition;
- if (x != 0) {
- subPixelPosition = x - x.floor();
- QFixed fraction = (subPixelPosition / QFixed::fromReal(1.0 / m_subPixelPositionCount)).floor();
+ auto f = [&](QFixed v) {
+ if (v != 0) {
+ v = v - v.floor() + QFixed::fromFixed(1);
+ QFixed fraction = (v * m_subPixelPositionCount).floor();
+ v = fraction / QFixed(m_subPixelPositionCount);
+ }
+ return v;
+ };
- // Compensate for precision loss in fixed point to make sure we are always drawing at a subpixel position over
- // the lower boundary for the selected rasterization by adding 1/64.
- subPixelPosition = fraction / QFixed(m_subPixelPositionCount) + QFixed::fromReal(0.015625);
- }
- return subPixelPosition;
+ return QFixedPoint(f(position.x), f(position.y));
}
-QFontEngine::Glyph *QFontEngine::glyphData(glyph_t, QFixed,
- QFontEngine::GlyphFormat, const QTransform &)
+QFontEngine::Glyph *QFontEngine::glyphData(glyph_t,
+ const QFixedPoint &,
+ QFontEngine::GlyphFormat,
+ const QTransform &)
{
return nullptr;
}
@@ -915,12 +906,9 @@ void QFontEngine::removeGlyphFromCache(glyph_t)
QFontEngine::Properties QFontEngine::properties() const
{
Properties p;
- p.postscriptName
- = QFontEngine::convertToPostscriptFontFamilyName(fontDef.family.toUtf8())
- + '-'
- + QByteArray::number(fontDef.style)
- + '-'
- + QByteArray::number(fontDef.weight);
+ p.postscriptName =
+ QFontEngine::convertToPostscriptFontFamilyName(fontDef.families.first().toUtf8()) + '-'
+ + QByteArray::number(fontDef.style) + '-' + QByteArray::number(fontDef.weight);
p.ascent = ascent();
p.descent = descent();
p.leading = leading();
@@ -1027,7 +1015,7 @@ static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *p
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
- if(pairs[middle].left_right == left_right)
+ if (pairs[middle].left_right == left_right)
return pairs[middle].adjust;
if (pairs[middle].left_right < left_right)
@@ -1041,7 +1029,7 @@ static inline QFixed kerning(int left, int right, const QFontEngine::KernPair *p
void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags) const
{
int numPairs = kerning_pairs.size();
- if(!numPairs)
+ if (!numPairs)
return;
const KernPair *pairs = kerning_pairs.constData();
@@ -1059,7 +1047,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
{
kerning_pairs.clear();
- QByteArray tab = getSfntTable(MAKE_TAG('k', 'e', 'r', 'n'));
+ QByteArray tab = getSfntTable(QFont::Tag("kern").value());
if (tab.isEmpty())
return;
@@ -1097,7 +1085,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
goto end;
// qDebug("subtable: version=%d, coverage=%x",version, coverage);
- if(version == 0 && coverage == 0x0001) {
+ if (version == 0 && coverage == 0x0001) {
if (offset + length > tab.size()) {
// qDebug("length ouf ot bounds");
goto end;
@@ -1108,7 +1096,7 @@ void QFontEngine::loadKerningPairs(QFixed scalingFactor)
if (!qSafeFromBigEndian(data, end, &nPairs))
goto end;
- if(nPairs * 6 + 8 > length - 6) {
+ if (nPairs * 6 + 8 > length - 6) {
// qDebug("corrupt table!");
// corrupt table
goto end;
@@ -1148,7 +1136,7 @@ end:
int QFontEngine::glyphCount() const
{
- QByteArray maxpTable = getSfntTable(MAKE_TAG('m', 'a', 'x', 'p'));
+ QByteArray maxpTable = getSfntTable(QFont::Tag("maxp").value());
if (maxpTable.size() < 6)
return 0;
@@ -1195,7 +1183,7 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
int tableToUse = -1;
int score = Invalid;
for (int n = 0; n < numTables; ++n) {
- quint16 platformId;
+ quint16 platformId = 0;
if (!qSafeFromBigEndian(maps + 8 * n, endPtr, &platformId))
return nullptr;
@@ -1246,11 +1234,12 @@ const uchar *QFontEngine::getCMap(const uchar *table, uint tableSize, bool *isSy
default:
break;
}
+ break;
default:
break;
}
}
- if(tableToUse < 0)
+ if (tableToUse < 0)
return nullptr;
resolveTable:
@@ -1325,7 +1314,7 @@ resolveTable:
quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint unicode)
{
const uchar *end = cmap + cmapSize;
- quint16 format;
+ quint16 format = 0;
if (!qSafeFromBigEndian(cmap, end, &format))
return 0;
@@ -1339,10 +1328,10 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
Since 0xffff is never a valid Unicode char anyway, we just get rid of the issue
by returning 0 for 0xffff
*/
- if(unicode >= 0xffff)
+ if (unicode >= 0xffff)
return 0;
- quint16 segCountX2;
+ quint16 segCountX2 = 0;
if (!qSafeFromBigEndian(cmap + 6, end, &segCountX2))
return 0;
@@ -1350,7 +1339,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
int i = 0;
for (; i < segCountX2/2; ++i) {
- quint16 codePoint;
+ quint16 codePoint = 0;
if (!qSafeFromBigEndian(ends + 2 * i, end, &codePoint))
return 0;
if (codePoint >= unicode)
@@ -1359,7 +1348,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
const unsigned char *idx = ends + segCountX2 + 2 + 2*i;
- quint16 startIndex;
+ quint16 startIndex = 0;
if (!qSafeFromBigEndian(idx, end, &startIndex))
return 0;
if (startIndex > unicode)
@@ -1367,20 +1356,20 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
idx += segCountX2;
- quint16 tmp;
+ quint16 tmp = 0;
if (!qSafeFromBigEndian(idx, end, &tmp))
return 0;
qint16 idDelta = qint16(tmp);
idx += segCountX2;
- quint16 idRangeoffset_t;
+ quint16 idRangeoffset_t = 0;
if (!qSafeFromBigEndian(idx, end, &idRangeoffset_t))
return 0;
- quint16 glyphIndex;
+ quint16 glyphIndex = 0;
if (idRangeoffset_t) {
- quint16 id;
+ quint16 id = 0;
if (!qSafeFromBigEndian(idRangeoffset_t + 2 * (unicode - startIndex) + idx, end, &id))
return 0;
@@ -1393,17 +1382,17 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
}
return glyphIndex;
} else if (format == 6) {
- quint16 tableSize;
+ quint16 tableSize = 0;
if (!qSafeFromBigEndian(cmap + 2, end, &tableSize))
return 0;
- quint16 firstCode6;
+ quint16 firstCode6 = 0;
if (!qSafeFromBigEndian(cmap + 6, end, &firstCode6))
return 0;
if (unicode < firstCode6)
return 0;
- quint16 entryCount6;
+ quint16 entryCount6 = 0;
if (!qSafeFromBigEndian(cmap + 8, end, &entryCount6))
return 0;
if (entryCount6 * 2 + 10 > tableSize)
@@ -1419,7 +1408,7 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
qSafeFromBigEndian(cmap + 10 + (entryIndex6 * 2), end, &index);
return index;
} else if (format == 12) {
- quint32 nGroups;
+ quint32 nGroups = 0;
if (!qSafeFromBigEndian(cmap + 12, end, &nGroups))
return 0;
@@ -1429,19 +1418,19 @@ quint32 QFontEngine::getTrueTypeGlyphIndex(const uchar *cmap, int cmapSize, uint
while (left <= right) {
int middle = left + ( ( right - left ) >> 1 );
- quint32 startCharCode;
+ quint32 startCharCode = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle, end, &startCharCode))
return 0;
- if(unicode < startCharCode)
+ if (unicode < startCharCode)
right = middle - 1;
else {
- quint32 endCharCode;
+ quint32 endCharCode = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle + 4, end, &endCharCode))
return 0;
if (unicode <= endCharCode) {
- quint32 index;
+ quint32 index = 0;
if (!qSafeFromBigEndian(cmap + 12 * middle + 8, end, &index))
return 0;
@@ -1483,6 +1472,17 @@ bool QFontEngine::hasUnreliableGlyphOutline() const
return glyphFormat == QFontEngine::Format_ARGB;
}
+QFixed QFontEngine::firstLeftBearing(const QGlyphLayout &glyphs)
+{
+ for (int i = 0; i < glyphs.numGlyphs; ++i) {
+ glyph_t glyph = glyphs.glyphs[i];
+ glyph_metrics_t gi = boundingBox(glyph);
+ if (gi.isValid() && gi.width > 0)
+ return gi.leftBearing();
+ }
+ return 0;
+}
+
QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs)
{
if (glyphs.numGlyphs >= 1) {
@@ -1539,7 +1539,7 @@ QFontEngineBox::~QFontEngineBox()
glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
{
Q_UNUSED(ucs4);
- return 0;
+ return 1;
}
bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
@@ -1554,7 +1554,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
QStringIterator it(str, str + len);
while (it.hasNext()) {
it.advance();
- glyphs->glyphs[ucs4Length++] = 0;
+ glyphs->glyphs[ucs4Length++] = 1;
}
*nglyphs = ucs4Length;
@@ -1670,12 +1670,12 @@ QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
QImage image(_size, _size, QImage::Format_Alpha8);
image.fill(0);
- // FIXME: use qpainter
+ uchar *bits = image.bits();
for (int i=2; i <= _size-3; ++i) {
- image.setPixel(i, 2, 255);
- image.setPixel(i, _size-3, 255);
- image.setPixel(2, i, 255);
- image.setPixel(_size-3, i, 255);
+ bits[i + 2 * image.bytesPerLine()] = 255;
+ bits[i + (_size - 3) * image.bytesPerLine()] = 255;
+ bits[2 + i * image.bytesPerLine()] = 255;
+ bits[_size - 3 + i * image.bytesPerLine()] = 255;
}
return image;
}
@@ -1730,7 +1730,9 @@ void QFontEngineMulti::ensureFallbackFamiliesQueried()
if (styleHint == QFont::AnyStyle && fontDef.fixedPitch)
styleHint = QFont::TypeWriter;
- setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.family, QFont::Style(fontDef.style), styleHint, QChar::Script(m_script)));
+ setFallbackFamiliesList(qt_fallbacksForFamily(fontDef.families.constFirst(),
+ QFont::Style(fontDef.style), styleHint,
+ QChar::Script(m_script)));
}
void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamilies)
@@ -1744,7 +1746,7 @@ void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamili
QFontEngine *engine = m_engines.at(0);
engine->ref.ref();
m_engines[1] = engine;
- m_fallbackFamilies << fontDef.family;
+ m_fallbackFamilies << fontDef.families.constFirst();
} else {
m_engines.resize(m_fallbackFamilies.size() + 1);
}
@@ -1754,7 +1756,7 @@ void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamili
void QFontEngineMulti::ensureEngineAt(int at)
{
- if (!m_fallbackFamiliesQueried)
+ if (!m_fallbackFamiliesQueried && at > 0)
ensureFallbackFamiliesQueried();
Q_ASSERT(at < m_engines.size());
if (!m_engines.at(at)) {
@@ -1771,15 +1773,14 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
{
QFontDef request(fontDef);
request.styleStrategy |= QFont::NoFontMerging;
- request.family = fallbackFamilyAt(at - 1);
- request.families = QStringList(request.family);
+ request.families = QStringList(fallbackFamilyAt(at - 1));
// At this point, the main script of the text has already been considered
// when fetching the list of fallback families from the database, and the
// info about the actual script of the characters may have been discarded,
// so we do not check for writing system support, but instead just load
// the family indiscriminately.
- if (QFontEngine *engine = QFontDatabase::findFont(request, QChar::Script_Common)) {
+ if (QFontEngine *engine = QFontDatabasePrivate::findFont(request, QChar::Script_Common)) {
engine->fontDef.weight = request.weight;
if (request.style > QFont::StyleNormal)
engine->fontDef.style = request.style;
@@ -1834,6 +1835,7 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
QStringIterator it(str, str + len);
int lastFallback = -1;
+ char32_t previousUcs4 = 0;
while (it.hasNext()) {
const char32_t ucs4 = it.peekNext();
@@ -1863,7 +1865,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
&& ucs4 != QChar::LineSeparator
&& ucs4 != QChar::LineFeed
&& ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator) {
+ && ucs4 != QChar::ParagraphSeparator
+ && QChar::category(ucs4) != QChar::Other_Control) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
@@ -1895,10 +1898,50 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
break;
}
}
+
+ // For variant-selectors, they are modifiers to the previous character. If we
+ // end up with different font selections for the selector and the character it
+ // modifies, we try applying the selector font to the preceding character as well
+ const int variantSelectorBlock = 0xFE00;
+ if ((ucs4 & 0xFFF0) == variantSelectorBlock && glyph_pos > 0) {
+ int selectorFontEngine = glyphs->glyphs[glyph_pos] >> 24;
+ int precedingCharacterFontEngine = glyphs->glyphs[glyph_pos - 1] >> 24;
+
+ if (selectorFontEngine != precedingCharacterFontEngine) {
+ // Emoji variant selectors are specially handled and should affect font
+ // selection. If VS-16 is used, then this means we want to select a color
+ // font. If the selected font is already a color font, we do not need search
+ // again. If the VS-15 is used, then this means we want to select a non-color
+ // font. If the selected font is not a color font, we don't do anything.
+ const QFontEngine *selectedEngine = m_engines.at(precedingCharacterFontEngine);
+ const bool colorFont = selectedEngine->isColorFont();
+ const char32_t vs15 = 0xFE0E;
+ const char32_t vs16 = 0xFE0F;
+ bool adaptVariantSelector = ucs4 < vs15
+ || (ucs4 == vs15 && colorFont)
+ || (ucs4 == vs16 && !colorFont);
+
+ if (adaptVariantSelector) {
+ QFontEngine *engine = m_engines.at(selectorFontEngine);
+ glyph_t glyph = engine->glyphIndex(previousUcs4);
+ if (glyph != 0) {
+ glyphs->glyphs[glyph_pos - 1] = glyph;
+ if (!(flags & GlyphIndicesOnly)) {
+ QGlyphLayout g = glyphs->mid(glyph_pos - 1, 1);
+ engine->recalcAdvances(&g, flags);
+ }
+
+ // set the high byte to indicate which engine the glyph came from
+ glyphs->glyphs[glyph_pos - 1] |= (selectorFontEngine << 24);
+ }
+ }
+ }
+ }
}
it.advance();
++glyph_pos;
+ previousUcs4 = ucs4;
}
*nglyphs = glyph_pos;
@@ -2216,7 +2259,7 @@ QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
return engine(which)->alphaMapForGlyph(stripped(glyph));
}
-QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition)
+QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QFixedPoint &subPixelPosition)
{
const int which = highByte(glyph);
return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition);
@@ -2228,13 +2271,17 @@ QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, const QTransform &t)
return engine(which)->alphaMapForGlyph(stripped(glyph), t);
}
-QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
const int which = highByte(glyph);
return engine(which)->alphaMapForGlyph(stripped(glyph), subPixelPosition, t);
}
-QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosition, const QTransform &t)
+QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph,
+ const QFixedPoint &subPixelPosition,
+ const QTransform &t)
{
const int which = highByte(glyph);
return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);