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, 128 insertions, 93 deletions
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 9eea2e786f..14ce5d2396 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -48,6 +48,7 @@
#include "qvarlengtharray.h"
#include <qmath.h>
#include <qendian.h>
+#include <private/qstringiterator_p.h>
#ifdef QT_ENABLE_HARFBUZZ_NG
# include "qharfbuzzng_p.h"
@@ -89,18 +90,48 @@ static HB_Bool hb_stringToGlyphs(HB_Font font, const HB_UChar16 *string, hb_uint
{
QFontEngine *fe = (QFontEngine *)font->userData;
+ const QChar *str = reinterpret_cast<const QChar *>(string);
+
QGlyphLayout qglyphs;
qglyphs.numGlyphs = *numGlyphs;
qglyphs.glyphs = glyphs;
-
- QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
- if (rightToLeft)
- shaperFlags |= QFontEngine::RightToLeft;
-
int nGlyphs = *numGlyphs;
- bool result = fe->stringToCMap(reinterpret_cast<const QChar *>(string), length, &qglyphs, &nGlyphs, shaperFlags);
+ bool result = fe->stringToCMap(str, length, &qglyphs, &nGlyphs, QFontEngine::GlyphIndicesOnly);
*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);
+ }
+ }
+ }
+
return result;
}
@@ -108,13 +139,10 @@ static void hb_getAdvances(HB_Font font, const HB_Glyph *glyphs, hb_uint32 numGl
{
QFontEngine *fe = (QFontEngine *)font->userData;
- QVarLengthArray<QFixed> advances_y(numGlyphs);
-
QGlyphLayout qglyphs;
qglyphs.numGlyphs = numGlyphs;
qglyphs.glyphs = const_cast<glyph_t *>(glyphs);
- qglyphs.advances_x = reinterpret_cast<QFixed *>(advances);
- qglyphs.advances_y = advances_y.data(); // not used
+ qglyphs.advances = reinterpret_cast<QFixed *>(advances);
fe->recalcAdvances(&qglyphs, (flags & HB_ShaperFlag_UseDesignMetrics) ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlags(0));
}
@@ -278,6 +306,10 @@ void *QFontEngine::harfbuzzFont() const
return hb_qt_font_get_for_engine(const_cast<QFontEngine *>(this));
#endif
if (!font_) {
+ HB_Face hbFace = (HB_Face)harfbuzzFace();
+ if (hbFace->font_for_init != 0)
+ q_check_ptr(qHBLoadFace(hbFace));
+
HB_FontRec *hbFont = (HB_FontRec *) malloc(sizeof(HB_FontRec));
Q_CHECK_PTR(hbFont);
hbFont->klass = &hb_fontClass;
@@ -308,8 +340,6 @@ void *QFontEngine::harfbuzzFace() const
if (!face_) {
HB_Face hbFace = qHBNewFace(const_cast<QFontEngine *>(this), hb_getSFntTable);
Q_CHECK_PTR(hbFace);
- if (hbFace->font_for_init != 0)
- hbFace = qHBLoadFace(hbFace);
hbFace->isSymbolFont = symbol;
face_ = (void *)hbFace;
@@ -349,6 +379,8 @@ bool QFontEngine::supportsScript(QChar::Script script) const
}
#endif
HB_Face hbFace = (HB_Face)harfbuzzFace();
+ if (hbFace->font_for_init != 0)
+ q_check_ptr(qHBLoadFace(hbFace));
return hbFace->supported_scripts[script_to_hbscript(script)];
}
@@ -364,23 +396,39 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix
QFixed QFontEngine::xHeight() const
{
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
QChar x((ushort)'x');
- stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly);
- glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]);
+ 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);
+
+ glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.height;
}
QFixed QFontEngine::averageCharWidth() const
{
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
QChar x((ushort)'x');
- stringToCMap(&x, 1, &glyphs, &nglyphs, GlyphIndicesOnly);
- glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyphs.glyphs[0]);
+ 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);
+
+ glyph_metrics_t bb = const_cast<QFontEngine *>(this)->boundingBox(glyph);
return bb.xoff;
}
@@ -411,8 +459,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
while(i--) {
if (glyphs.attributes[i].dontPrint)
continue;
- xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
- ypos += glyphs.advances_y[i];
+ xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
totalKashidas += glyphs.justifications[i].nKashidas;
}
positions.resize(glyphs.numGlyphs+totalKashidas);
@@ -424,8 +471,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
++i;
continue;
}
- xpos -= glyphs.advances_x[i];
- ypos -= glyphs.advances_y[i];
+ xpos -= glyphs.advances[i];
QFixed gpos_x = xpos + glyphs.offsets[i].x;
QFixed gpos_y = ypos + glyphs.offsets[i].y;
@@ -441,12 +487,22 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
++current;
if (glyphs.justifications[i].nKashidas) {
QChar ch(0x640); // Kashida character
- QGlyphLayoutArray<8> g;
- int nglyphs = 7;
- stringToCMap(&ch, 1, &g, &nglyphs, 0);
+
+ glyph_t kashidaGlyph;
+ 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);
+
for (uint k = 0; k < glyphs.justifications[i].nKashidas; ++k) {
- xpos -= g.advances_x[0];
- ypos -= g.advances_y[0];
+ xpos -= kashidaWidth;
QFixed gpos_x = xpos + glyphs.offsets[i].x;
QFixed gpos_y = ypos + glyphs.offsets[i].y;
@@ -458,7 +514,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
}
positions[current].x = gpos_x;
positions[current].y = gpos_y;
- glyphs_out[current] = g.glyphs[0];
+ glyphs_out[current] = kashidaGlyph;
++current;
}
} else {
@@ -476,8 +532,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
positions[current].x = xpos + glyphs.offsets[i].x;
positions[current].y = ypos + glyphs.offsets[i].y;
glyphs_out[current] = glyphs.glyphs[i];
- xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
- ypos += glyphs.advances_y[i];
+ xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
++current;
}
++i;
@@ -492,8 +547,7 @@ void QFontEngine::getGlyphPositions(const QGlyphLayout &glyphs, const QTransform
positions[current].x = QFixed::fromReal(gpos.x());
positions[current].y = QFixed::fromReal(gpos.y());
glyphs_out[current] = glyphs.glyphs[i];
- xpos += glyphs.advances_x[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
- ypos += glyphs.advances_y[i];
+ xpos += glyphs.advances[i] + QFixed::fromFixed(glyphs.justifications[i].space_18d6);
++current;
}
++i;
@@ -656,8 +710,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp
for (int i=0; i < glyphs.numGlyphs; ++i) {
glyph_metrics_t metrics = boundingBox(glyphs.glyphs[i]);
if (metrics.width.value() == 0 || metrics.height.value() == 0) {
- advanceX += glyphs.advances_x[i];
- advanceY += glyphs.advances_y[i];
+ advanceX += glyphs.advances[i];
continue;
}
const QImage alphaMask = alphaMapForGlyph(glyphs.glyphs[i]);
@@ -692,8 +745,7 @@ void QFontEngine::addBitmapFontToPath(qreal x, qreal y, const QGlyphLayout &glyp
advanceX += offset.x;
advanceY += offset.y;
qt_addBitmapToPath((advanceX + metrics.x).toReal(), (advanceY + metrics.y).toReal(), bitmap_data, bitmap.bytesPerLine(), w, h, path);
- advanceX += glyphs.advances_x[i];
- advanceY += glyphs.advances_y[i];
+ advanceX += glyphs.advances[i];
}
}
@@ -704,16 +756,12 @@ void QFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int n
qreal y = positions[0].y.toReal();
QVarLengthGlyphLayoutArray g(nGlyphs);
- for (int i = 0; i < nGlyphs; ++i) {
+ for (int i = 0; i < nGlyphs - 1; ++i) {
g.glyphs[i] = glyphs[i];
- if (i < nGlyphs - 1) {
- g.advances_x[i] = positions[i+1].x - positions[i].x;
- g.advances_y[i] = positions[i+1].y - positions[i].y;
- } else {
- g.advances_x[i] = QFixed::fromReal(maxCharWidth());
- g.advances_y[i] = 0;
- }
+ g.advances[i] = positions[i + 1].x - positions[i].x;
}
+ g.glyphs[nGlyphs - 1] = glyphs[nGlyphs - 1];
+ g.advances[nGlyphs - 1] = QFixed::fromReal(maxCharWidth());
addBitmapFontToPath(x, y, g, path, flags);
}
@@ -973,10 +1021,10 @@ void QFontEngine::doKerning(QGlyphLayout *glyphs, QFontEngine::ShaperFlags flags
if (flags & DesignMetrics) {
for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
- glyphs->advances_x[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
+ glyphs->advances[i] += kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs);
} else {
for(int i = 0; i < glyphs->numGlyphs - 1; ++i)
- glyphs->advances_x[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
+ glyphs->advances[i] += qRound(kerning(glyphs->glyphs[i], glyphs->glyphs[i+1] , pairs, numPairs));
}
}
@@ -1320,17 +1368,22 @@ QFontEngineBox::~QFontEngineBox()
{
}
-bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
+bool QFontEngineBox::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QFontEngine::ShaperFlags flags) const
{
if (*nglyphs < len) {
*nglyphs = len;
return false;
}
- memset(glyphs->glyphs, 0, len * sizeof(glyph_t));
+ int ucs4Length = 0;
+ QStringIterator it(str, str + len);
+ while (it.hasNext()) {
+ it.advance();
+ glyphs->glyphs[ucs4Length++] = 0;
+ }
- *nglyphs = len;
- glyphs->numGlyphs = len;
+ *nglyphs = ucs4Length;
+ glyphs->numGlyphs = ucs4Length;
if (!(flags & GlyphIndicesOnly))
recalcAdvances(glyphs, flags);
@@ -1340,10 +1393,8 @@ bool QFontEngineBox::stringToCMap(const QChar *, int len, QGlyphLayout *glyphs,
void QFontEngineBox::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlags) const
{
- for (int i = 0; i < glyphs->numGlyphs; i++) {
- glyphs->advances_x[i] = _size;
- glyphs->advances_y[i] = 0;
- }
+ for (int i = 0; i < glyphs->numGlyphs; i++)
+ glyphs->advances[i] = _size;
}
void QFontEngineBox::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &glyphs, QPainterPath *path, QTextItem::RenderFlags flags)
@@ -1503,11 +1554,9 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
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) {
- QFixedPoint tmpAdvance;
- if (!(flags & GlyphIndicesOnly)) {
- tmpAdvance.x = glyphs->advances_x[glyph_pos];
- tmpAdvance.y = glyphs->advances_y[glyph_pos];
- }
+ QFixed tmpAdvance;
+ if (!(flags & GlyphIndicesOnly))
+ tmpAdvance = glyphs->advances[glyph_pos];
for (int x = 1, n = qMin(engines.size(), 256); x < n; ++x) {
if (engines.at(x) == 0 && !shouldLoadFontEngineForCharacter(x, ucs4))
continue;
@@ -1522,11 +1571,12 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
continue;
if (!(flags & GlyphIndicesOnly))
- glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0;
+ glyphs->advances[glyph_pos] = QFixed();
int num = 2;
- QGlyphLayout offs = glyphs->mid(glyph_pos, num);
- engine->stringToCMap(str + i, surrogate ? 2 : 1, &offs, &num, flags);
- Q_ASSERT(num == 1); // surrogates only give 1 glyph
+ 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]) {
// set the high byte to indicate which engine the glyph came from
glyphs->glyphs[glyph_pos] |= (x << 24);
@@ -1535,10 +1585,8 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
}
// ensure we use metrics from the 1st font when we use the fallback image.
- if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0) {
- glyphs->advances_x[glyph_pos] = tmpAdvance.x;
- glyphs->advances_y[glyph_pos] = tmpAdvance.y;
- }
+ if (!(flags & GlyphIndicesOnly) && glyphs->glyphs[glyph_pos] == 0)
+ glyphs->advances[glyph_pos] = tmpAdvance;
}
if (surrogate)
@@ -1639,10 +1687,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl
int start = 0;
int end, i;
if (flags & QTextItem::RightToLeft) {
- for (int gl = 0; gl < glyphs.numGlyphs; gl++) {
- x += glyphs.advances_x[gl].toReal();
- y += glyphs.advances_y[gl].toReal();
- }
+ for (int gl = 0; gl < glyphs.numGlyphs; gl++)
+ x += glyphs.advances[gl].toReal();
}
for (end = 0; end < glyphs.numGlyphs; ++end) {
const int e = highByte(glyphs.glyphs[end]);
@@ -1650,10 +1696,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl
continue;
if (flags & QTextItem::RightToLeft) {
- for (i = start; i < end; ++i) {
- x -= glyphs.advances_x[i].toReal();
- y -= glyphs.advances_y[i].toReal();
- }
+ for (i = start; i < end; ++i)
+ x -= glyphs.advances[i].toReal();
}
// set the high byte to zero
@@ -1666,10 +1710,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl
glyphs.glyphs[i] = hi | glyphs.glyphs[i];
if (!(flags & QTextItem::RightToLeft)) {
- for (i = start; i < end; ++i) {
- x += glyphs.advances_x[i].toReal();
- y += glyphs.advances_y[i].toReal();
- }
+ for (i = start; i < end; ++i)
+ x += glyphs.advances[i].toReal();
}
// change engine
@@ -1678,10 +1720,8 @@ void QFontEngineMulti::addOutlineToPath(qreal x, qreal y, const QGlyphLayout &gl
}
if (flags & QTextItem::RightToLeft) {
- for (i = start; i < end; ++i) {
- x -= glyphs.advances_x[i].toReal();
- y -= glyphs.advances_y[i].toReal();
- }
+ for (i = start; i < end; ++i)
+ x -= glyphs.advances[i].toReal();
}
// set the high byte to zero
@@ -1847,16 +1887,11 @@ bool QFontEngineMulti::canRender(const QChar *string, int len)
QGlyphLayout g;
g.numGlyphs = nglyphs;
g.glyphs = glyphs.data();
- if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly)) {
- glyphs.resize(nglyphs);
- g.numGlyphs = nglyphs;
- g.glyphs = glyphs.data();
- if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
- Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
- }
+ if (!stringToCMap(string, len, &g, &nglyphs, GlyphIndicesOnly))
+ Q_UNREACHABLE();
for (int i = 0; i < nglyphs; i++) {
- if (g.glyphs[i] == 0)
+ if (glyphs[i] == 0)
return false;
}