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.cpp696
1 files changed, 359 insertions, 337 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 3ca9e9bbde..4e78aaac2e 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>
@@ -49,15 +13,15 @@
#include "qpainter.h"
#include "qpainterpath.h"
#include "qvarlengtharray.h"
+#include "qtextengine_p.h"
#include <qmath.h>
#include <qendian.h>
#include <private/qstringiterator_p.h>
#if QT_CONFIG(harfbuzz)
# include "qharfbuzzng_p.h"
-# include <harfbuzz/hb-ot.h>
+# include <hb-ot.h>
#endif
-#include <private/qharfbuzz_p.h>
#include <algorithm>
#include <limits.h>
@@ -91,127 +55,17 @@ 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
-
-Q_STATIC_ASSERT(sizeof(HB_Glyph) == sizeof(glyph_t));
-Q_STATIC_ASSERT(sizeof(HB_Fixed) == sizeof(QFixed));
-
-static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint32 length, HB_Glyph *glyphs, hb_uint32 *numGlyphs, HB_Bool rightToLeft)
-{
- QFontEngine *fe = (QFontEngine *)font->userData;
-
- const QChar *str = reinterpret_cast<const QChar *>(string);
-
- QGlyphLayout qglyphs;
- qglyphs.numGlyphs = *numGlyphs;
- qglyphs.glyphs = glyphs;
- int nGlyphs = *numGlyphs;
- bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly);
- *numGlyphs = nGlyphs;
-
- if (rightToLeft && result && !fe->symbol) {
- QStringIterator it(str, str + length);
- while (it.hasNext()) {
- const uint ucs4 = it.next();
- const uint mirrored = QChar::mirroredChar(ucs4);
- if (Q_UNLIKELY(mirrored != ucs4))
- *glyphs = fe->glyphIndex(mirrored);
- ++glyphs;
- }
- }
-
- return result;
-}
-
-static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGlyphs, HB_Fixed *advances, int flags)
-{
- QFontEngine *fe = (QFontEngine *)font->userData;
-
- QGlyphLayout qglyphs;
- qglyphs.numGlyphs = numGlyphs;
- qglyphs.glyphs = const_cast<glyph_t *>(glyphs);
- qglyphs.advances = reinterpret_cast<QFixed *>(advances);
-
- fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags{});
-}
-
-static HB_Bool hb_canRender(HB_Font font, const HB_UChar16 *string, hb_uint32 length)
-{
- QFontEngine *fe = (QFontEngine *)font->userData;
- return fe->canRender(reinterpret_cast<const QChar *>(string), length);
-}
-
-static void hb_getGlyphMetrics(HB_Font font, HB_Glyph glyph, HB_GlyphMetrics *metrics)
-{
- QFontEngine *fe = (QFontEngine *)font->userData;
- glyph_metrics_t m = fe->boundingBox(glyph);
- metrics->x = m.x.value();
- metrics->y = m.y.value();
- metrics->width = m.width.value();
- metrics->height = m.height.value();
- metrics->xOffset = m.xoff.value();
- metrics->yOffset = m.yoff.value();
-}
-
-static HB_Fixed hb_getFontMetric(HB_Font font, HB_FontMetric metric)
-{
- if (metric == HB_FontAscent) {
- QFontEngine *fe = (QFontEngine *)font->userData;
- return fe->ascent().value();
- }
- return 0;
-}
-
int QFontEngine::getPointInOutline(glyph_t glyph, int flags, quint32 point, QFixed *xpos, QFixed *ypos, quint32 *nPoints)
{
- Q_UNUSED(glyph)
- Q_UNUSED(flags)
- Q_UNUSED(point)
- Q_UNUSED(xpos)
- Q_UNUSED(ypos)
- Q_UNUSED(nPoints)
+ Q_UNUSED(glyph);
+ Q_UNUSED(flags);
+ Q_UNUSED(point);
+ Q_UNUSED(xpos);
+ Q_UNUSED(ypos);
+ Q_UNUSED(nPoints);
return Err_Not_Covered;
}
-static HB_Error hb_getPointInOutline(HB_Font font, HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints)
-{
- QFontEngine *fe = (QFontEngine *)font->userData;
- return (HB_Error)fe->getPointInOutline(glyph, flags, point, (QFixed *)xpos, (QFixed *)ypos, (quint32 *)nPoints);
-}
-
-static const HB_FontClass hb_fontClass = {
- hb_stringToGlyphs, hb_getAdvances, hb_canRender, hb_getPointInOutline,
- hb_getGlyphMetrics, hb_getFontMetric
-};
-
-static HB_Error hb_getSFntTable(void *font, HB_Tag tableTag, HB_Byte *buffer, HB_UInt *length)
-{
- QFontEngine::FaceData *data = (QFontEngine::FaceData *)font;
- Q_ASSERT(data);
-
- qt_get_font_table_func_t get_font_table = data->get_font_table;
- Q_ASSERT(get_font_table);
-
- if (!get_font_table(data->user_data, tableTag, buffer, length))
- return HB_Err_Invalid_Argument;
- return HB_Err_Ok;
-}
-
-static void hb_freeFace(void *face)
-{
- qHBFreeFace((HB_Face)face);
-}
-
-
static bool qt_get_font_table_default(void *user_data, uint tag, uchar *buffer, uint *length)
{
QFontEngine *fe = (QFontEngine *)user_data;
@@ -248,6 +102,7 @@ QFontEngine::QFontEngine(Type type)
: m_type(type), ref(0),
font_(),
face_(),
+ m_heightMetricsQueried(false),
m_minLeftBearing(kBearingNotInitialized),
m_minRightBearing(kBearingNotInitialized)
{
@@ -279,7 +134,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
@@ -298,57 +153,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));
+ return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
+#else
+ return nullptr;
#endif
- if (!font_) {
- HB_Face hbFace = (HB_Face)harfbuzzFace();
- if (hbFace->font_for_init) {
- void *data = hbFace->font_for_init;
- q_check_ptr(qHBLoadFace(hbFace));
- free(data);
- }
-
- HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec));
- Q_CHECK_PTR(hbFont);
- hbFont->klass = &hb_fontClass;
- hbFont->userData = const_cast<QFontEngine *>(this);
-
- qint64 emSquare = emSquareSize().truncate();
- Q_ASSERT(emSquare == emSquareSize().toInt()); // ensure no truncation
- if (emSquare == 0)
- emSquare = 1000; // a fallback value suitable for Type1 fonts
- hbFont->y_ppem = fontDef.pixelSize;
- hbFont->x_ppem = fontDef.pixelSize * fontDef.stretch / 100;
- // same as QFixed(x)/QFixed(emSquare) but without int32 overflow for x
- hbFont->x_scale = (((qint64)hbFont->x_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare;
- hbFont->y_scale = (((qint64)hbFont->y_ppem << 6) * 0x10000L + (emSquare >> 1)) / emSquare;
-
- font_ = Holder(hbFont, free);
- }
- return font_.get();
}
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));
+ return hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this));
+#else
+ return nullptr;
#endif
- if (!face_) {
- QFontEngine::FaceData *data = (QFontEngine::FaceData *)malloc(sizeof(QFontEngine::FaceData));
- Q_CHECK_PTR(data);
- data->user_data = faceData.user_data;
- data->get_font_table = faceData.get_font_table;
-
- HB_Face hbFace = qHBNewFace(data, hb_getSFntTable);
- Q_CHECK_PTR(hbFace);
- hbFace->isSymbolFont = symbol;
-
- face_ = Holder(hbFace, hb_freeFace);
- }
- return face_.get();
}
bool QFontEngine::supportsScript(QChar::Script script) const
@@ -363,37 +181,26 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return true;
#if QT_CONFIG(harfbuzz)
- if (qt_useHarfbuzzNG()) {
-#if defined(Q_OS_DARWIN)
- // in AAT fonts, 'gsub' table is effectively replaced by 'mort'/'morx' table
- uint len;
- if (getSfntTableData(MAKE_TAG('m','o','r','t'), 0, &len) || getSfntTableData(MAKE_TAG('m','o','r','x'), 0, &len))
- return true;
-#endif
+ // 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;
+ }
- bool ret = false;
- if (hb_face_t *face = hb_qt_face_get_for_engine(const_cast<QFontEngine *>(this))) {
- hb_tag_t script_tag_1, script_tag_2;
- hb_ot_tags_from_script(hb_qt_script_to_script(script), &script_tag_1, &script_tag_2);
-
- unsigned int script_index;
- ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_1, &script_index);
- if (!ret) {
- ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, script_tag_2, &script_index);
- if (!ret && script_tag_2 != HB_OT_TAG_DEFAULT_SCRIPT)
- ret = hb_ot_layout_table_find_script(face, HB_OT_TAG_GSUB, HB_OT_TAG_DEFAULT_SCRIPT, &script_index);
- }
- }
- return ret;
+ 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);
+
+ if (hb_ot_layout_table_select_script(face, HB_OT_TAG_GSUB, script_count, script_tags, nullptr, nullptr))
+ return true;
}
#endif
- HB_Face hbFace = (HB_Face)harfbuzzFace();
- if (hbFace->font_for_init) {
- void *data = hbFace->font_for_init;
- q_check_ptr(qHBLoadFace(hbFace));
- free(data);
- }
- return hbFace->supported_scripts[script_to_hbscript(script)];
+ return false;
}
bool QFontEngine::canRender(const QChar *str, int len) const
@@ -497,7 +304,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
glyphs_out[current] = glyphs.glyphs[i];
++current;
if (glyphs.justifications[i].nKashidas) {
- QChar ch(0x640); // Kashida character
+ QChar ch = u'\x640'; // Kashida character
glyph_t kashidaGlyph = glyphIndex(ch.unicode());
QFixed kashidaWidth;
@@ -575,6 +382,114 @@ void QFontEngine::getGlyphBearings(glyph_t glyph, qreal *leftBearing, qreal *rig
*rightBearing = gi.rightBearing().toReal();
}
+bool QFontEngine::processHheaTable() const
+{
+ QByteArray hhea = getSfntTable(QFont::Tag("hhea").value());
+ if (hhea.size() >= 10) {
+ 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;
+ m_descent = -QFixed::fromReal(descent * fontDef.pixelSize) / unitsPerEm;
+
+ m_leading = QFixed::fromReal(leading * fontDef.pixelSize) / unitsPerEm;
+
+ return true;
+ }
+
+ return false;
+}
+
+void QFontEngine::initializeHeightMetrics() const
+{
+ 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;
+}
+
+bool QFontEngine::processOS2Table() const
+{
+ QByteArray os2 = getSfntTable(QFont::Tag("OS/2").value());
+ if (os2.size() >= 78) {
+ 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;
+ }
+
+ return false;
+}
+
+QFixed QFontEngine::leading() const
+{
+ if (!m_heightMetricsQueried)
+ initializeHeightMetrics();
+
+ return m_leading;
+}
+
+QFixed QFontEngine::ascent() const
+{
+ if (!m_heightMetricsQueried)
+ initializeHeightMetrics();
+
+ return m_ascent;
+}
+
+QFixed QFontEngine::descent() const
+{
+ if (!m_heightMetricsQueried)
+ initializeHeightMetrics();
+
+ return m_descent;
+}
+
qreal QFontEngine::minLeftBearing() const
{
if (m_minLeftBearing == kBearingNotInitialized)
@@ -593,7 +508,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);
@@ -650,12 +565,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;
@@ -663,14 +589,17 @@ glyph_metrics_t QFontEngine::tightBoundingBox(const QGlyphLayout &glyphs)
QFixed ymax = 0;
QFixed xmax = 0;
for (int i = 0; i < glyphs.numGlyphs; i++) {
+ // If shaping has found this should be ignored, ignore it.
+ if (!glyphs.advances[i] || glyphs.attributes[i].dontPrint)
+ continue;
glyph_metrics_t bb = boundingBox(glyphs.glyphs[i]);
QFixed x = overall.xoff + glyphs.offsets[i].x + bb.x;
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);
@@ -754,10 +683,10 @@ Q_GUI_EXPORT void qt_addBitmapToPath(qreal x0, qreal y0, const uchar *image_data
// set up edges
for (int y = 0; y <= h; ++y) {
for (int x = 0; x <= w; ++x) {
- bool topLeft = (x == 0)|(y == 0) ? false : SET(x - 1, y - 1);
- bool topRight = (x == w)|(y == 0) ? false : SET(x, y - 1);
- bool bottomLeft = (x == 0)|(y == h) ? false : SET(x - 1, y);
- bool bottomRight = (x == w)|(y == h) ? false : SET(x, y);
+ bool topLeft = (x == 0 || y == 0) ? false : SET(x - 1, y - 1);
+ bool topRight = (x == w || y == 0) ? false : SET(x, y - 1);
+ bool bottomLeft = (x == 0 || y == h) ? false : SET(x - 1, y);
+ bool bottomRight = (x == w || y == h) ? false : SET(x, y);
GRID(x, y) = 0;
if ((!topRight) & bottomRight)
@@ -804,14 +733,14 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp
const int w = alphaMask.width();
const int h = alphaMask.height();
- const int srcBpl = alphaMask.bytesPerLine();
+ const qsizetype srcBpl = alphaMask.bytesPerLine();
QImage bitmap;
if (alphaMask.depth() == 1) {
bitmap = alphaMask;
} else {
bitmap = QImage(w, h, QImage::Format_Mono);
const uchar *imageData = alphaMask.bits();
- const int destBpl = bitmap.bytesPerLine();
+ const qsizetype destBpl = bitmap.bytesPerLine();
uchar *bitmapData = bitmap.bits();
for (int yi = 0; yi < h; ++yi) {
@@ -853,7 +782,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);
@@ -869,9 +798,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);
@@ -882,7 +811,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);
@@ -899,32 +828,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;
}
@@ -973,12 +907,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();
@@ -1012,9 +943,9 @@ void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metr
*/
bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
{
- Q_UNUSED(tag)
- Q_UNUSED(buffer)
- Q_UNUSED(length)
+ Q_UNUSED(tag);
+ Q_UNUSED(buffer);
+ Q_UNUSED(length);
return false;
}
@@ -1085,7 +1016,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)
@@ -1099,7 +1030,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();
@@ -1117,7 +1048,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;
@@ -1155,7 +1086,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;
@@ -1166,7 +1097,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;
@@ -1206,7 +1137,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;
@@ -1253,7 +1184,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;
@@ -1304,11 +1235,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:
@@ -1383,7 +1315,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;
@@ -1397,10 +1329,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;
@@ -1408,7 +1340,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)
@@ -1417,7 +1349,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)
@@ -1425,20 +1357,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;
@@ -1451,17 +1383,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)
@@ -1477,7 +1409,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;
@@ -1487,19 +1419,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;
@@ -1541,13 +1473,24 @@ bool QFontEngine::hasUnreliableGlyphOutline() const
return glyphFormat == QFontEngine::Format_ARGB;
}
-QFixed QFontEngine::lastRightBearing(const QGlyphLayout &glyphs, bool round)
+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) {
glyph_t glyph = glyphs.glyphs[glyphs.numGlyphs - 1];
glyph_metrics_t gi = boundingBox(glyph);
if (gi.isValid())
- return round ? qRound(gi.rightBearing()) : gi.rightBearing();
+ return gi.rightBearing();
}
return 0;
}
@@ -1596,23 +1539,23 @@ QFontEngineBox::~QFontEngineBox()
glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
{
- Q_UNUSED(ucs4)
- return 0;
+ Q_UNUSED(ucs4);
+ return 1;
}
-bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+int QFontEngineBox::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;
}
int ucs4Length = 0;
QStringIterator it(str, str + len);
while (it.hasNext()) {
it.advance();
- glyphs->glyphs[ucs4Length++] = 0;
+ glyphs->glyphs[ucs4Length++] = 1;
}
*nglyphs = ucs4Length;
@@ -1621,7 +1564,7 @@ bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
- return true;
+ return *nglyphs;
}
void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
@@ -1728,12 +1671,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;
}
@@ -1788,7 +1731,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)
@@ -1802,7 +1747,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);
}
@@ -1812,7 +1757,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)) {
@@ -1829,15 +1774,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;
@@ -1850,11 +1794,7 @@ QFontEngine *QFontEngineMulti::loadEngine(int at)
glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
{
glyph_t glyph = engine(0)->glyphIndex(ucs4);
- if (glyph == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator) {
+ if (glyph == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
@@ -1881,24 +1821,67 @@ glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
return glyph;
}
-bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
- QGlyphLayout *glyphs, int *nglyphs,
- QFontEngine::ShaperFlags flags) const
+int QFontEngineMulti::stringToCMap(const QChar *str, int len,
+ QGlyphLayout *glyphs, int *nglyphs,
+ QFontEngine::ShaperFlags flags) const
{
- if (!engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags))
- return false;
+ const int originalNumGlyphs = glyphs->numGlyphs;
+ int mappedGlyphCount = engine(0)->stringToCMap(str, len, glyphs, nglyphs, flags);
+ if (mappedGlyphCount < 0)
+ return -1;
+ // If ContextFontMerging is set and the match for the string was incomplete, we try all
+ // fallbacks on the full string until we find the best match.
+ bool contextFontMerging = mappedGlyphCount < *nglyphs && (fontDef.styleStrategy & QFont::ContextFontMerging);
+ if (contextFontMerging) {
+ QVarLengthGlyphLayoutArray tempLayout(len);
+ if (!m_fallbackFamiliesQueried)
+ const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
+
+ int maxGlyphCount = 0;
+ uchar engineIndex = 0;
+ for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ int numGlyphs = len;
+ const_cast<QFontEngineMulti *>(this)->ensureEngineAt(x);
+ maxGlyphCount = engine(x)->stringToCMap(str, len, &tempLayout, &numGlyphs, flags);
+
+ // If we found a better match, we copy data into the main QGlyphLayout
+ if (maxGlyphCount > mappedGlyphCount) {
+ *nglyphs = numGlyphs;
+ glyphs->numGlyphs = originalNumGlyphs;
+ glyphs->copy(&tempLayout);
+ engineIndex = x;
+ if (maxGlyphCount == numGlyphs)
+ break;
+ }
+ }
+
+ if (engineIndex > 0) {
+ for (int y = 0; y < glyphs->numGlyphs; ++y) {
+ if (glyphs->glyphs[y] != 0)
+ glyphs->glyphs[y] |= (engineIndex << 24);
+ }
+ } else {
+ contextFontMerging = false;
+ }
+
+ mappedGlyphCount = maxGlyphCount;
+ }
+
+ // Fill in missing glyphs by going through string one character at the time and finding
+ // the first viable fallback.
int glyph_pos = 0;
QStringIterator it(str, str + len);
int lastFallback = -1;
+ char32_t previousUcs4 = 0;
while (it.hasNext()) {
- const uint ucs4 = it.peekNext();
+ const char32_t ucs4 = it.peekNext();
// If we applied a fallback font to previous glyph, and the current is either
// ZWJ or ZWNJ, we should also try applying the same fallback font to that, in order
// to get the correct shaping rules applied.
- if (lastFallback >= 0 && (ucs4 == QChar(0x200d) || ucs4 == QChar(0x200c))) {
+ if (lastFallback >= 0 && (ucs4 == 0x200d || ucs4 == 0x200c)) {
QFontEngine *engine = m_engines.at(lastFallback);
glyph_t glyph = engine->glyphIndex(ucs4);
if (glyph != 0) {
@@ -1917,14 +1900,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
lastFallback = -1;
}
- if (glyphs->glyphs[glyph_pos] == 0
- && ucs4 != QChar::LineSeparator
- && ucs4 != QChar::LineFeed
- && ucs4 != QChar::CarriageReturn
- && ucs4 != QChar::ParagraphSeparator) {
+ if (glyphs->glyphs[glyph_pos] == 0 && !isIgnorableChar(ucs4)) {
if (!m_fallbackFamiliesQueried)
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
- for (int x = 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
+ for (int x = contextFontMerging ? 0 : 1, n = qMin(m_engines.size(), 256); x < n; ++x) {
QFontEngine *engine = m_engines.at(x);
if (!engine) {
if (!shouldLoadFontEngineForCharacter(x, ucs4))
@@ -1953,16 +1932,55 @@ 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;
glyphs->numGlyphs = glyph_pos;
-
- return true;
+ return mappedGlyphCount;
}
bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
@@ -2254,7 +2272,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const
QGlyphLayout g;
g.numGlyphs = nglyphs;
g.glyphs = glyphs.data();
- if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
+ if (stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly) < 0)
Q_UNREACHABLE();
for (int i = 0; i < nglyphs; i++) {
@@ -2265,7 +2283,7 @@ bool QFontEngineMulti::canRender(const QChar *string, int len) const
return true;
}
-/* Implement alphaMapForGlyph() which is called by Lighthouse/Windows code.
+/* Implement alphaMapForGlyph() which is called by QPA Windows code.
* Ideally, that code should be fixed to correctly handle QFontEngineMulti. */
QImage QFontEngineMulti::alphaMapForGlyph(glyph_t glyph)
@@ -2274,7 +2292,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);
@@ -2286,13 +2304,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);