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.cpp221
1 files changed, 112 insertions, 109 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 83e64a51a6..a72ac23418 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -101,35 +101,13 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint
*numGlyphs = nGlyphs;
if (rightToLeft && result && !fe->symbol) {
- uint glyph_pos = 0;
- for (uint i = 0; i < length; ++i, ++glyph_pos) {
- uint ucs4 = str[i].unicode();
- if (Q_UNLIKELY(QChar::isHighSurrogate(ucs4) && i + 1 < length)) {
- uint low = str[i + 1].unicode();
- if (Q_LIKELY(QChar::isLowSurrogate(low))) {
- ucs4 = QChar::surrogateToUcs4(ucs4, low);
- ++i;
- }
- }
-
- uint mirrored = QChar::mirroredChar(ucs4);
- if (Q_UNLIKELY(mirrored != ucs4)) {
- QChar chars[2];
- uint numChars = 0;
- if (Q_UNLIKELY(QChar::requiresSurrogates(mirrored))) {
- chars[numChars++] = QChar(QChar::highSurrogate(mirrored));
- chars[numChars++] = QChar(QChar::lowSurrogate(mirrored));
- } else {
- chars[numChars++] = QChar(mirrored);
- }
-
- qglyphs.numGlyphs = numChars;
- qglyphs.glyphs = glyphs + glyph_pos;
- nGlyphs = numChars;
- if (!fe->stringToCMap(chars, numChars, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nGlyphs == 1);
- }
+ 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;
}
}
@@ -242,8 +220,8 @@ Q_AUTOTEST_EXPORT QList<QFontEngine *> QFontEngine_stopCollectingEngines()
// QFontEngine
-QFontEngine::QFontEngine()
- : ref(0),
+QFontEngine::QFontEngine(Type type)
+ : m_type(type), ref(0),
font_(0), font_destroy_func(0),
face_(0), face_destroy_func(0)
{
@@ -359,6 +337,15 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return true;
}
+#ifdef Q_OS_MAC
+ {
+ // 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
+
#ifdef QT_ENABLE_HARFBUZZ_NG
if (useHarfbuzzNG) {
bool ret = false;
@@ -385,6 +372,17 @@ bool QFontEngine::supportsScript(QChar::Script script) const
return hbFace->supported_scripts[script_to_hbscript(script)];
}
+bool QFontEngine::canRender(const QChar *str, int len) const
+{
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ if (glyphIndex(it.next()) == 0)
+ return false;
+ }
+
+ return true;
+}
+
glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix)
{
glyph_metrics_t metrics = boundingBox(glyph);
@@ -397,38 +395,14 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix
QFixed QFontEngine::xHeight() const
{
- QChar x((ushort)'x');
-
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
-
+ const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.height;
}
QFixed QFontEngine::averageCharWidth() const
{
- QChar x((ushort)'x');
-
- glyph_t glyph;
-
- QGlyphLayout glyphs;
- glyphs.numGlyphs = 1;
- glyphs.glyphs = &glyph;
-
- int nglyphs = 1;
- if (!stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
-
+ const glyph_t glyph = glyphIndex('x');
glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.xoff;
}
@@ -489,18 +463,14 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
if (glyphs.justifications[i].nKashidas) {
QChar ch(0x640); // Kashida character
- glyph_t kashidaGlyph;
+ glyph_t kashidaGlyph = glyphIndex(ch.unicode());
QFixed kashidaWidth;
QGlyphLayout g;
g.numGlyphs = 1;
g.glyphs = &kashidaGlyph;
g.advances = &kashidaWidth;
-
- int nglyphs = 1;
- if (!stringToCMap(&ch, 1, &g, &nglyphs, 0))
- Q_UNREACHABLE();
- Q_ASSERT(nglyphs == 1);
+ recalcAdvances(&g, 0);
for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
xpos -= kashidaWidth;
@@ -937,14 +907,31 @@ void QFontEngine::getUnscaledGlyph(glyph_t glyph, QPainterPath *path, glyph_metr
addGlyphsToPath(&glyph, &p, 1, path, QFlag(0));
}
+/*!
+ Returns \c true if the font table idetified by \a tag exists in the font;
+ returns \c false otherwise.
+
+ If \a buffer is NULL, stores the size of the buffer required for the font table data,
+ in bytes, in \a length. If \a buffer is not NULL and the capacity
+ of the buffer, passed in \a length, is sufficient to store the font table data,
+ also copies the font table data to \a buffer.
+
+ Note: returning \c false when the font table exists could lead to an undefined behavior.
+*/
+bool QFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ Q_UNUSED(tag)
+ Q_UNUSED(buffer)
+ Q_UNUSED(length)
+ return false;
+}
+
QByteArray QFontEngine::getSfntTable(uint tag) const
{
QByteArray table;
uint len = 0;
if (!getSfntTableData(tag, 0, &len))
return table;
- if (!len)
- return table;
table.resize(len);
if (!getSfntTableData(tag, reinterpret_cast<uchar *>(table.data()), &len))
return QByteArray();
@@ -1382,7 +1369,15 @@ QFontEngine::GlyphCacheEntry &QFontEngine::GlyphCacheEntry::operator=(const Glyp
// ------------------------------------------------------------------
QFontEngineBox::QFontEngineBox(int size)
- : _size(size)
+ : QFontEngine(Box),
+ _size(size)
+{
+ cache_cost = sizeof(QFontEngineBox);
+}
+
+QFontEngineBox::QFontEngineBox(Type type, int size)
+ : QFontEngine(type),
+ _size(size)
{
cache_cost = sizeof(QFontEngineBox);
}
@@ -1391,8 +1386,15 @@ QFontEngineBox::~QFontEngineBox()
{
}
+glyph_t QFontEngineBox::glyphIndex(uint ucs4) const
+{
+ Q_UNUSED(ucs4)
+ return 0;
+}
+
bool 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;
@@ -1503,22 +1505,11 @@ qreal QFontEngineBox::maxCharWidth() const
return _size;
}
-
-const char *QFontEngineBox::name() const
-{
- return "null";
-}
-
-bool QFontEngineBox::canRender(const QChar *, int)
+bool QFontEngineBox::canRender(const QChar *, int) const
{
return true;
}
-QFontEngine::Type QFontEngineBox::type() const
-{
- return Box;
-}
-
QImage QFontEngineBox::alphaMapForGlyph(glyph_t)
{
QImage image(_size, _size, QImage::Format_Indexed8);
@@ -1550,6 +1541,7 @@ static inline glyph_t stripped(glyph_t glyph)
{ return glyph & 0x00ffffff; }
QFontEngineMulti::QFontEngineMulti(int engineCount)
+ : QFontEngine(Multi)
{
engines.fill(0, engineCount);
cache_cost = 0;
@@ -1564,6 +1556,35 @@ QFontEngineMulti::~QFontEngineMulti()
}
}
+glyph_t QFontEngineMulti::glyphIndex(uint ucs4) const
+{
+ glyph_t glyph = engine(0)->glyphIndex(ucs4);
+ if (glyph == 0 && ucs4 != QChar::LineSeparator) {
+ const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
+ for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) {
+ QFontEngine *engine = engines.at(x);
+ if (!engine) {
+ if (!shouldLoadFontEngineForCharacter(x, ucs4))
+ continue;
+ const_cast<QFontEngineMulti *>(this)->loadEngine(x);
+ engine = engines.at(x);
+ }
+ Q_ASSERT(engine != 0);
+ if (engine->type() == Box)
+ continue;
+
+ glyph = engine->glyphIndex(ucs4);
+ if (glyph != 0) {
+ // set the high byte to indicate which engine the glyph came from
+ glyph |= (x << 24);
+ break;
+ }
+ }
+ }
+
+ return glyph;
+}
+
bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
QGlyphLayout *glyphs, int *nglyphs,
QFontEngine::ShaperFlags flags) const
@@ -1573,13 +1594,10 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
const_cast<QFontEngineMulti *>(this)->ensureFallbackFamiliesQueried();
int glyph_pos = 0;
- for (int i = 0; i < len; ++i) {
- bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate());
- uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode();
- if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
- QFixed tmpAdvance;
- if (!(flags & GlyphIndicesOnly))
- tmpAdvance = glyphs->advances[glyph_pos];
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ const uint ucs4 = it.peekNext();
+ if (glyphs->glyphs[glyph_pos] == 0 && ucs4 != QChar::LineSeparator) {
for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) {
if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4))
continue;
@@ -1593,27 +1611,21 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
if (engine->type() == Box)
continue;
- if (!(flags & GlyphIndicesOnly))
- glyphs->advances[glyph_pos] = QFixed();
- int num = 2;
- QGlyphLayout g = glyphs->mid(glyph_pos, num);
- if (!engine->stringToCMap(str + i, surrogate ? 2 : 1, &g, &num, flags))
- Q_UNREACHABLE();
- Q_ASSERT(num == 1);
- if (glyphs->glyphs[glyph_pos]) {
+ glyph_t glyph = engine->glyphIndex(ucs4);
+ if (glyph != 0) {
+ glyphs->glyphs[glyph_pos] = glyph;
+ if (!(flags & GlyphIndicesOnly)) {
+ QGlyphLayout g = glyphs->mid(glyph_pos, 1);
+ engine->recalcAdvances(&g, flags);
+ }
// set the high byte to indicate which engine the glyph came from
glyphs->glyphs[glyph_pos] |= (x << 24);
break;
}
}
-
- // ensure we use metrics from the 1st font when we use the fallback image.
- if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0)
- glyphs->advances[glyph_pos] = tmpAdvance;
}
- if (surrogate)
- ++i;
+ it.advance();
++glyph_pos;
}
@@ -1898,7 +1910,7 @@ qreal QFontEngineMulti::minRightBearing() const
return engine(0)->minRightBearing();
}
-bool QFontEngineMulti::canRender(const QChar *string, int len)
+bool QFontEngineMulti::canRender(const QChar *string, int len) const
{
if (engine(0)->canRender(string, len))
return true;
@@ -1959,13 +1971,4 @@ QImage QFontEngineMulti::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPosit
return engine(which)->alphaRGBMapForGlyph(stripped(glyph), subPixelPosition, t);
}
-QTestFontEngine::QTestFontEngine(int size)
- : QFontEngineBox(size)
-{}
-
-QFontEngine::Type QTestFontEngine::type() const
-{
- return TestFontEngine;
-}
-
QT_END_NAMESPACE