summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qdistancefield.cpp14
-rw-r--r--src/gui/text/qfont.cpp18
-rw-r--r--src/gui/text/qfont.h2
-rw-r--r--src/gui/text/qfont_p.h17
-rw-r--r--src/gui/text/qfontdatabase.h2
-rw-r--r--src/gui/text/qfontdatabase_qpa.cpp17
-rw-r--r--src/gui/text/qfontengine.cpp221
-rw-r--r--src/gui/text/qfontengine_ft.cpp35
-rw-r--r--src/gui/text/qfontengine_p.h1
-rw-r--r--src/gui/text/qfontengine_qpa.cpp8
-rw-r--r--src/gui/text/qfontmetrics.cpp163
-rw-r--r--src/gui/text/qfontsubset.cpp18
-rw-r--r--src/gui/text/qharfbuzzng.cpp39
-rw-r--r--src/gui/text/qplatformfontdatabase.cpp6
-rw-r--r--src/gui/text/qplatformfontdatabase.h2
-rw-r--r--src/gui/text/qrawfont.cpp21
-rw-r--r--src/gui/text/qtextcursor.cpp1
-rw-r--r--src/gui/text/qtextdocument.cpp94
-rw-r--r--src/gui/text/qtextdocument.h8
-rw-r--r--src/gui/text/qtextdocument_p.h1
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp208
-rw-r--r--src/gui/text/qtextengine_p.h46
-rw-r--r--src/gui/text/qtextformat.cpp127
-rw-r--r--src/gui/text/qtextformat.h11
-rw-r--r--src/gui/text/qtextformat_p.h6
-rw-r--r--src/gui/text/qtexthtmlparser.cpp28
-rw-r--r--src/gui/text/qtextlayout.cpp29
-rw-r--r--src/gui/text/qtextobject.cpp50
-rw-r--r--src/gui/text/qtextobject.h4
30 files changed, 733 insertions, 466 deletions
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
index e584b66a25..f2b88c4692 100644
--- a/src/gui/text/qdistancefield.cpp
+++ b/src/gui/text/qdistancefield.cpp
@@ -739,13 +739,19 @@ bool qt_fontHasNarrowOutlines(QFontEngine *fontEngine)
if (!fe)
return false;
- QGlyphLayout glyphs;
+ const QChar uc(QLatin1Char('O'));
+
glyph_t glyph;
- glyphs.glyphs = &glyph;
+
+ QGlyphLayout glyphs;
glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
int numGlyphs = 1;
- QChar uc = QLatin1Char('O');
- fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly);
+
+ if (!fe->stringToCMap(&uc, 1, &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(numGlyphs == 1);
+
QImage im = fe->alphaMapForGlyph(glyph, QFixed(), QTransform());
Q_ASSERT(fe->ref.load() == 0);
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 49b5a9ba46..83f2d7190b 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2073,6 +2073,18 @@ QString QFont::toString() const
QString::number((int) rawMode());
}
+/*!
+ Returns the hash value for \a font. If specified, \a seed is used
+ to initialize the hash.
+
+ \relates QFont
+ \since 5.3
+*/
+uint qHash(const QFont &font, uint seed) Q_DECL_NOTHROW
+{
+ return qHash(QFontPrivate::get(font)->request, seed);
+}
+
/*!
Sets this font to match the description \a descrip. The description
@@ -2533,8 +2545,10 @@ bool QFontInfo::fixedPitch() const
QChar ch[2] = { QLatin1Char('i'), QLatin1Char('m') };
QGlyphLayoutArray<2> g;
int l = 2;
- engine->stringToCMap(ch, 2, &g, &l, 0);
- engine->fontDef.fixedPitch = g.advances_x[0] == g.advances_x[1];
+ if (!engine->stringToCMap(ch, 2, &g, &l, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(l == 2);
+ engine->fontDef.fixedPitch = g.advances[0] == g.advances[1];
engine->fontDef.fixedPitchComputed = true;
}
#endif
diff --git a/src/gui/text/qfont.h b/src/gui/text/qfont.h
index 6d36f7839b..a207a1d60e 100644
--- a/src/gui/text/qfont.h
+++ b/src/gui/text/qfont.h
@@ -315,6 +315,8 @@ private:
Q_DECLARE_SHARED(QFont)
+Q_GUI_EXPORT uint qHash(const QFont &font, uint seed = 0) Q_DECL_NOTHROW;
+
inline bool QFont::bold() const
{ return weight() > Normal; }
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index 5b7f918e21..6165554388 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -55,6 +55,7 @@
#include "QtGui/qfont.h"
#include "QtCore/qmap.h"
+#include "QtCore/qhash.h"
#include "QtCore/qobject.h"
#include "QtCore/qstringlist.h"
#include <QtGui/qfontdatabase.h>
@@ -133,6 +134,22 @@ struct QFontDef
}
};
+inline uint qHash(const QFontDef &fd, uint seed = 0) Q_DECL_NOTHROW
+{
+ return qHash(qRound64(fd.pixelSize*10000)) // use only 4 fractional digits
+ ^ qHash(fd.weight)
+ ^ qHash(fd.style)
+ ^ qHash(fd.stretch)
+ ^ qHash(fd.styleHint)
+ ^ qHash(fd.styleStrategy)
+ ^ qHash(fd.ignorePitch)
+ ^ qHash(fd.fixedPitch)
+ ^ qHash(fd.family, seed)
+ ^ qHash(fd.styleName)
+ ^ qHash(fd.hintingPreference)
+ ;
+}
+
class QFontEngineData
{
public:
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index 708b8cbd58..9986ef6c60 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -167,8 +167,6 @@ private:
friend class QFontPrivate;
friend class QFontDialog;
friend class QFontDialogPrivate;
- friend class QFontEngineMultiXLFD;
- friend class QFontEngineMultiQWS;
friend class QFontEngineMultiQPA;
QFontDatabasePrivate *d;
diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp
index 6f4971e267..1972f5d58c 100644
--- a/src/gui/text/qfontdatabase_qpa.cpp
+++ b/src/gui/text/qfontdatabase_qpa.cpp
@@ -182,10 +182,17 @@ QFontEngine *loadSingleEngine(int script,
QFontCache::Key key(def,script);
QFontEngine *engine = QFontCache::instance()->findEngine(key);
if (!engine) {
- engine = pfdb->fontEngine(def, QChar::Script(script), size->handle);
+ engine = pfdb->fontEngine(def, size->handle);
if (engine) {
- QFontCache::Key key(def,script);
- QFontCache::instance()->instance()->insertEngine(key,engine);
+ // Also check for OpenType tables when using complex scripts
+ if (!engine->supportsScript(QChar::Script(script))) {
+ qWarning(" OpenType support missing for script %d", script);
+ if (engine->ref.load() == 0)
+ delete engine;
+ return 0;
+ }
+
+ QFontCache::instance()->insertEngine(key, engine);
}
}
return engine;
@@ -221,10 +228,10 @@ QFontEngine *loadEngine(int script, const QFontDef &request,
pfMultiEngine->setFallbackFamiliesList(fallbacks);
engine = pfMultiEngine;
- // Cache Multi font engine as well in case we got the FT single
+ // Cache Multi font engine as well in case we got the single
// font engine when we are actually looking for a Multi one
QFontCache::Key key(request, script, 1);
- QFontCache::instance()->instance()->insertEngine(key, engine);
+ QFontCache::instance()->insertEngine(key, engine);
}
return engine;
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;
}
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index 05bd014bd7..665932e4a5 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -723,7 +723,7 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
FT_Set_Transform(face, &matrix, 0);
freetype->matrix = matrix;
// fake bold
- if ((fontDef.weight == QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
+ if ((fontDef.weight >= QFont::Bold) && !(face->style_flags & FT_STYLE_FLAG_BOLD) && !FT_IS_FIXED_WIDTH(face))
embolden = true;
// underline metrics
line_thickness = QFixed::fromFixed(FT_MulFix(face->underline_thickness, face->size->metrics.y_scale));
@@ -1196,7 +1196,7 @@ int QFontEngineFT::synthesized() const
int s = 0;
if ((fontDef.style != QFont::StyleNormal) && !(freetype->face->style_flags & FT_STYLE_FLAG_ITALIC))
s = SynthesizedItalic;
- if ((fontDef.weight == QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
+ if ((fontDef.weight >= QFont::Bold) && !(freetype->face->style_flags & FT_STYLE_FLAG_BOLD))
s |= SynthesizedBold;
if (fontDef.stretch != 100 && FT_IS_SCALABLE(freetype->face))
s |= SynthesizedStretch;
@@ -1283,13 +1283,22 @@ qreal QFontEngineFT::minRightBearing() const
{
if (rbearing == SHRT_MIN) {
lbearing = rbearing = 0;
- const QChar *ch = (const QChar *)(const void*)char_table;
- QGlyphLayoutArray<char_table_entries> glyphs;
+
+ const QChar *ch = reinterpret_cast<const QChar *>(char_table);
+
+ glyph_t glyphs[char_table_entries];
+
+ QGlyphLayout g;
+ g.glyphs = glyphs;
+ g.numGlyphs = char_table_entries;
int ng = char_table_entries;
- stringToCMap(ch, char_table_entries, &glyphs, &ng, GlyphIndicesOnly);
+ if (!stringToCMap(ch, char_table_entries, &g, &ng, GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(ng == char_table_entries);
+
while (--ng) {
- if (glyphs.glyphs[ng]) {
- glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs.glyphs[ng]);
+ if (glyphs[ng]) {
+ glyph_metrics_t gi = const_cast<QFontEngineFT *>(this)->boundingBox(glyphs[ng]);
lbearing = qMin(lbearing, gi.x);
rbearing = qMin(rbearing, (gi.xoff - gi.x - gi.width));
}
@@ -1525,7 +1534,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
return false;
}
- bool mirrored = flags & QFontEngine::RightToLeft;
int glyph_pos = 0;
if (freetype->symbol_map) {
FT_Face face = freetype->face;
@@ -1561,8 +1569,6 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
FT_Face face = freetype->face;
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
- if (mirrored)
- uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = uc < QFreetypeFace::cmapCacheSize ? freetype->cmapCache[uc] : 0;
if (!glyphs->glyphs[glyph_pos]) {
{
@@ -1607,24 +1613,23 @@ void QFontEngineFT::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFlag
// Since we are passing Format_None to loadGlyph, use same default format logic as loadGlyph
GlyphFormat acceptableFormat = (defaultFormat != Format_None) ? defaultFormat : Format_Mono;
if (g && g->format == acceptableFormat) {
- glyphs->advances_x[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
+ glyphs->advances[i] = design ? QFixed::fromFixed(g->linearAdvance) : QFixed(g->advance);
} else {
if (!face)
face = lockFace();
g = loadGlyph(cacheEnabled ? &defaultGlyphSet : 0, glyphs->glyphs[i], 0, Format_None, true);
- glyphs->advances_x[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
- : QFixed::fromFixed(face->glyph->metrics.horiAdvance).round();
+ glyphs->advances[i] = design ? QFixed::fromFixed(face->glyph->linearHoriAdvance >> 10)
+ : QFixed::fromFixed(face->glyph->metrics.horiAdvance);
if (!cacheEnabled)
delete g;
}
- glyphs->advances_y[i] = 0;
}
if (face)
unlockFace();
if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
for (int i = 0; i < glyphs->numGlyphs; ++i)
- glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances[i] = glyphs->advances[i].round();
}
}
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index a04f4bd0ac..532ebaf8ff 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -121,7 +121,6 @@ public:
};
enum ShaperFlag {
- RightToLeft = 0x0001,
DesignMetrics = 0x0002,
GlyphIndicesOnly = 0x0004
};
diff --git a/src/gui/text/qfontengine_qpa.cpp b/src/gui/text/qfontengine_qpa.cpp
index 28b95bd509..cb40a5388a 100644
--- a/src/gui/text/qfontengine_qpa.cpp
+++ b/src/gui/text/qfontengine_qpa.cpp
@@ -353,13 +353,10 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
const uchar *cmap = externalCMap ? externalCMap : (fontData + cmapOffset);
- bool mirrored = flags & QFontEngine::RightToLeft;
int glyph_pos = 0;
if (symbol) {
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
- if (mirrored)
- uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
if(!glyphs->glyphs[glyph_pos] && uc < 0x100)
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc + 0xf000);
@@ -368,8 +365,6 @@ bool QFontEngineQPA::stringToCMap(const QChar *str, int len, QGlyphLayout *glyph
} else {
for (int i = 0; i < len; ++i) {
unsigned int uc = getChar(str, i, len);
- if (mirrored)
- uc = QChar::mirroredChar(uc);
glyphs->glyphs[glyph_pos] = getTrueTypeGlyphIndex(cmap, uc);
#if 0 && defined(DEBUG_FONTENGINE)
QChar c(uc);
@@ -399,8 +394,7 @@ void QFontEngineQPA::recalcAdvances(QGlyphLayout *glyphs, QFontEngine::ShaperFla
glyphs->glyphs[i] = 0;
continue;
}
- glyphs->advances_x[i] = g->advance;
- glyphs->advances_y[i] = 0;
+ glyphs->advances[i] = g->advance;
}
}
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 1a66657cbd..2f4709afe4 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -458,12 +458,19 @@ int QFontMetrics::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- // ### can nglyphs != 1 happen at all? Not currently I think
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
qreal lb;
- engine->getGlyphBearings(glyphs.glyphs[0], &lb);
+ engine->getGlyphBearings(glyph, &lb);
return qRound(lb);
}
@@ -493,12 +500,19 @@ int QFontMetrics::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- // ### can nglyphs != 1 happen at all? Not currently I think
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
qreal rb;
- engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb);
+ engine->getGlyphBearings(glyph, 0, &rb);
return qRound(rb);
}
@@ -538,15 +552,12 @@ int QFontMetrics::width(const QString &text, int len, int flags) const
int numGlyphs = len;
QVarLengthGlyphLayoutArray glyphs(numGlyphs);
QFontEngine *engine = d->engineForScript(QChar::Script_Common);
- if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0)) {
- glyphs.resize(numGlyphs);
- if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0))
- Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
- }
+ if (!engine->stringToCMap(text.data(), len, &glyphs, &numGlyphs, 0))
+ Q_UNREACHABLE();
QFixed width;
for (int i = 0; i < numGlyphs; ++i)
- width += glyphs.advances_x[i];
+ width += glyphs.advances[i];
return qRound(width);
}
@@ -594,10 +605,20 @@ int QFontMetrics::width(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
- return qRound(glyphs.advances_x[0]);
+ QFixed advance;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyph_t glyph;
+ glyphs.glyphs = &glyph;
+ glyphs.advances = &advance;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ return qRound(advance);
}
/*! \obsolete
@@ -639,10 +660,20 @@ int QFontMetrics::charWidth(const QString &text, int pos) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
- width = qRound(glyphs.advances_x[0]);
+ QFixed advance;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyph_t glyph;
+ glyphs.glyphs = &glyph;
+ glyphs.advances = &advance;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ width = qRound(advance);
}
return width;
}
@@ -708,10 +739,18 @@ QRect QFontMetrics::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]);
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ glyph_metrics_t gm = engine->boundingBox(glyph);
return QRect(qRound(gm.x), qRound(gm.y), qRound(gm.width), qRound(gm.height));
}
@@ -1326,12 +1365,19 @@ qreal QFontMetricsF::leftBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- // ### can nglyphs != 1 happen at all? Not currently I think
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
qreal lb;
- engine->getGlyphBearings(glyphs.glyphs[0], &lb);
+ engine->getGlyphBearings(glyph, &lb);
return lb;
}
@@ -1361,12 +1407,19 @@ qreal QFontMetricsF::rightBearing(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- // ### can nglyphs != 1 happen at all? Not currently I think
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
qreal rb;
- engine->getGlyphBearings(glyphs.glyphs[0], 0, &rb);
+ engine->getGlyphBearings(glyph, 0, &rb);
return rb;
}
@@ -1431,10 +1484,20 @@ qreal QFontMetricsF::width(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
- return glyphs.advances_x[0].toReal();
+ QFixed advance;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyph_t glyph;
+ glyphs.glyphs = &glyph;
+ glyphs.advances = &advance;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ return advance.toReal();
}
/*!
@@ -1496,10 +1559,18 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
d->alterCharForCapitalization(ch);
- QGlyphLayoutArray<10> glyphs;
- int nglyphs = 9;
- engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- glyph_metrics_t gm = engine->boundingBox(glyphs.glyphs[0]);
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &glyph;
+
+ int nglyphs = 1;
+ if (!engine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ glyph_metrics_t gm = engine->boundingBox(glyph);
return QRectF(gm.x.toReal(), gm.y.toReal(), gm.width.toReal(), gm.height.toReal());
}
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index 152e15a54d..2109b16bb5 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -201,12 +201,22 @@ static void checkRanges(QPdf::ByteStream &ts, QByteArray &ranges, int &nranges)
QVector<int> QFontSubset::getReverseMap() const
{
QVector<int> reverseMap(0x10000, 0);
- QGlyphLayoutArray<10> glyphs;
+
+ glyph_t glyph;
+
+ QGlyphLayout glyphs;
+ glyphs.glyphs = &glyph;
+ glyphs.numGlyphs = 1;
+
for (uint uc = 0; uc < 0x10000; ++uc) {
QChar ch(uc);
- int nglyphs = 10;
- fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly);
- int idx = glyph_indices.indexOf(glyphs.glyphs[0]);
+
+ int nglyphs = 1;
+ if (!fontEngine->stringToCMap(&ch, 1, &glyphs, &nglyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ int idx = glyph_indices.indexOf(glyph);
if (idx >= 0 && !reverseMap.at(idx))
reverseMap[idx] = uc;
}
diff --git a/src/gui/text/qharfbuzzng.cpp b/src/gui/text/qharfbuzzng.cpp
index d2e7df9c10..c09f27b665 100644
--- a/src/gui/text/qharfbuzzng.cpp
+++ b/src/gui/text/qharfbuzzng.cpp
@@ -397,13 +397,7 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data,
QFontEngine *fe = (QFontEngine *)font_data;
Q_ASSERT(fe);
- glyph_t glyphs[2] = { 0, 0 };
-
- QGlyphLayout g;
- g.numGlyphs = 2;
- g.glyphs = glyphs;
-
- QChar chars[4];
+ QChar chars[2];
int numChars = 0;
if (Q_UNLIKELY(QChar::requiresSurrogates(unicode))) {
chars[numChars++] = QChar(QChar::highSurrogate(unicode));
@@ -422,11 +416,14 @@ _hb_qt_font_get_glyph(hb_font_t * /*font*/, void *font_data,
}
#endif
- int numGlyphs = g.numGlyphs;
- bool ok = fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly);
- Q_ASSERT(ok); Q_UNUSED(ok)
+ QGlyphLayout g;
+ g.numGlyphs = numChars;
+ g.glyphs = glyph;
- *glyph = g.glyphs[0];
+ int numGlyphs = numChars;
+ if (!fe->stringToCMap(chars, numChars, &g, &numGlyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
+ Q_ASSERT(numGlyphs == 1);
return true;
}
@@ -439,18 +436,16 @@ _hb_qt_font_get_glyph_h_advance(hb_font_t *font, void *font_data,
QFontEngine *fe = (QFontEngine *)font_data;
Q_ASSERT(fe);
- QFixed advance_x;
- QFixed advance_y;
+ QFixed advance;
QGlyphLayout g;
g.numGlyphs = 1;
g.glyphs = &glyph;
- g.advances_x = &advance_x;
- g.advances_y = &advance_y;
+ g.advances = &advance;
fe->recalcAdvances(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font)));
- return g.advances_x[0].value();
+ return advance.value();
}
static hb_position_t
@@ -490,18 +485,16 @@ _hb_qt_font_get_glyph_h_kerning(hb_font_t *font, void *font_data,
Q_ASSERT(fe);
glyph_t glyphs[2] = { first_glyph, second_glyph };
- QFixed advance_x;
- QFixed advance_y;
+ QFixed advance;
QGlyphLayout g;
g.numGlyphs = 2;
g.glyphs = glyphs;
- g.advances_x = &advance_x;
- g.advances_y = &advance_y;
+ g.advances = &advance;
fe->doKerning(&g, QFontEngine::ShaperFlags(hb_qt_font_get_use_design_metrics(font)));
- return g.advances_x[0].value();
+ return advance.value();
}
static hb_position_t
@@ -710,7 +703,11 @@ _hb_qt_font_create(QFontEngine *fe)
const int x_ppem = (fe->fontDef.pixelSize * fe->fontDef.stretch) / 100;
hb_font_set_funcs(font, hb_qt_get_font_funcs(), (void *)fe, NULL);
+#ifdef Q_OS_MAC
+ hb_font_set_scale(font, QFixed(x_ppem).value(), QFixed(y_ppem).value());
+#else
hb_font_set_scale(font, QFixed(x_ppem).value(), -QFixed(y_ppem).value());
+#endif
hb_font_set_ppem(font, x_ppem, y_ppem);
return font;
diff --git a/src/gui/text/qplatformfontdatabase.cpp b/src/gui/text/qplatformfontdatabase.cpp
index 37610a9099..7936831e13 100644
--- a/src/gui/text/qplatformfontdatabase.cpp
+++ b/src/gui/text/qplatformfontdatabase.cpp
@@ -289,13 +289,11 @@ QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine
Returns the font engine that can be used to render the font described by
the font definition, \a fontDef, in the specified \a script.
*/
-QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle)
+QFontEngine *QPlatformFontDatabase::fontEngine(const QFontDef &fontDef, void *handle)
{
- Q_UNUSED(script);
- Q_UNUSED(handle);
QByteArray *fileDataPtr = static_cast<QByteArray *>(handle);
QFontEngineQPA *engine = new QFontEngineQPA(fontDef,*fileDataPtr);
- //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family << script;
+ //qDebug() << fontDef.pixelSize << fontDef.weight << fontDef.style << fontDef.stretch << fontDef.styleHint << fontDef.styleStrategy << fontDef.family;
return engine;
}
diff --git a/src/gui/text/qplatformfontdatabase.h b/src/gui/text/qplatformfontdatabase.h
index 6053f11051..5f2c9a74ba 100644
--- a/src/gui/text/qplatformfontdatabase.h
+++ b/src/gui/text/qplatformfontdatabase.h
@@ -97,7 +97,7 @@ public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QChar::Script script);
- virtual QFontEngine *fontEngine(const QFontDef &fontDef, QChar::Script script, void *handle);
+ virtual QFontEngine *fontEngine(const QFontDef &fontDef, void *handle);
virtual QStringList fallbacksForFamily(const QString &family, QFont::Style style, QFont::StyleHint styleHint, QChar::Script script) const;
virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
virtual void releaseHandle(void *handle);
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index b1b910422c..449278df06 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -479,16 +479,8 @@ QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const
QGlyphLayout glyphs;
glyphs.numGlyphs = numGlyphs;
glyphs.glyphs = glyphIndexes.data();
- if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) {
- glyphIndexes.resize(numGlyphs);
-
- glyphs.numGlyphs = numGlyphs;
- glyphs.glyphs = glyphIndexes.data();
- if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly)) {
- Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
- return QVector<quint32>();
- }
- }
+ if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &numGlyphs, QFontEngine::GlyphIndicesOnly))
+ Q_UNREACHABLE();
glyphIndexes.resize(numGlyphs);
return glyphIndexes;
@@ -565,13 +557,12 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv
if (!d->isValid() || numGlyphs <= 0)
return false;
+ QVarLengthArray<QFixed> tmpAdvances(numGlyphs);
+
QGlyphLayout glyphs;
glyphs.glyphs = const_cast<glyph_t *>(glyphIndexes);
glyphs.numGlyphs = numGlyphs;
- QVarLengthArray<QFixed> advances_x(numGlyphs);
- QVarLengthArray<QFixed> advances_y(numGlyphs);
- glyphs.advances_x = advances_x.data();
- glyphs.advances_y = advances_y.data();
+ glyphs.advances = tmpAdvances.data();
bool design = layoutFlags & UseDesignMetrics;
@@ -580,7 +571,7 @@ bool QRawFont::advancesForGlyphIndexes(const quint32 *glyphIndexes, QPointF *adv
d->fontEngine->doKerning(&glyphs, design ? QFontEngine::DesignMetrics : QFontEngine::ShaperFlag(0));
for (int i=0; i<numGlyphs; ++i)
- advances[i] = QPointF(glyphs.advances_x[i].toReal(), glyphs.advances_y[i].toReal());
+ advances[i] = QPointF(tmpAdvances[i].toReal(), 0.0);
return true;
}
diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp
index d12f3cccd8..ac9762b183 100644
--- a/src/gui/text/qtextcursor.cpp
+++ b/src/gui/text/qtextcursor.cpp
@@ -174,7 +174,6 @@ void QTextCursorPrivate::remove()
} else {
priv->remove(pos1, pos2-pos1, op);
adjusted_anchor = anchor = position;
- priv->finishEdit();
}
}
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 4a34f0d3c3..fa54776b6d 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -551,6 +551,39 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option)
}
/*!
+ \property QTextDocument::baseUrl
+ \since 5.3
+ \brief the base URL used to resolve relative resource URLs within the document.
+
+ Resource URLs are resolved to be within the same directory as the target of the base
+ URL meaning any portion of the path after the last '/' will be ignored.
+
+ \table
+ \header \li Base URL \li Relative URL \li Resolved URL
+ \row \li file:///path/to/content \li images/logo.png \li file:///path/to/images/logo.png
+ \row \li file:///path/to/content/ \li images/logo.png \li file:///path/to/content/images/logo.png
+ \row \li file:///path/to/content/index.html \li images/logo.png \li file:///path/to/content/images/logo.png
+ \row \li file:///path/to/content/images/ \li ../images/logo.png \li file:///path/to/content/images/logo.png
+ \endtable
+*/
+QUrl QTextDocument::baseUrl() const
+{
+ Q_D(const QTextDocument);
+ return d->baseUrl;
+}
+
+void QTextDocument::setBaseUrl(const QUrl &url)
+{
+ Q_D(QTextDocument);
+ if (d->baseUrl != url) {
+ d->baseUrl = url;
+ if (d->lout)
+ d->lout->documentChanged(0, 0, d->length());
+ emit baseUrlChanged(url);
+ }
+}
+
+/*!
\since 4.8
The default cursor movement style is used by all QTextCursor objects
@@ -1849,11 +1882,12 @@ void QTextDocument::print(QPagedPaintDevice *printer) const
QVariant QTextDocument::resource(int type, const QUrl &name) const
{
Q_D(const QTextDocument);
- QVariant r = d->resources.value(name);
+ const QUrl url = d->baseUrl.resolved(name);
+ QVariant r = d->resources.value(url);
if (!r.isValid()) {
- r = d->cachedResources.value(name);
+ r = d->cachedResources.value(url);
if (!r.isValid())
- r = const_cast<QTextDocument *>(this)->loadResource(type, name);
+ r = const_cast<QTextDocument *>(this)->loadResource(type, url);
}
return r;
}
@@ -1924,27 +1958,29 @@ QVariant QTextDocument::loadResource(int type, const QUrl &name)
}
// if resource was not loaded try to load it here
- if (!qobject_cast<QTextDocument *>(p) && r.isNull() && name.isRelative()) {
- QUrl currentURL = d->url;
+ if (!qobject_cast<QTextDocument *>(p) && r.isNull()) {
QUrl resourceUrl = name;
- // For the second case QUrl can merge "#someanchor" with "foo.html"
- // correctly to "foo.html#someanchor"
- if (!(currentURL.isRelative()
- || (currentURL.scheme() == QLatin1String("file")
- && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
- || (name.hasFragment() && name.path().isEmpty())) {
- resourceUrl = currentURL.resolved(name);
- } else {
- // this is our last resort when current url and new url are both relative
- // we try to resolve against the current working directory in the local
- // file system.
- QFileInfo fi(currentURL.toLocalFile());
- if (fi.exists()) {
- resourceUrl =
- QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name);
- } else if (currentURL.isEmpty()) {
- resourceUrl.setScheme(QLatin1String("file"));
+ if (name.isRelative()) {
+ QUrl currentURL = d->url;
+ // For the second case QUrl can merge "#someanchor" with "foo.html"
+ // correctly to "foo.html#someanchor"
+ if (!(currentURL.isRelative()
+ || (currentURL.scheme() == QLatin1String("file")
+ && !QFileInfo(currentURL.toLocalFile()).isAbsolute()))
+ || (name.hasFragment() && name.path().isEmpty())) {
+ resourceUrl = currentURL.resolved(name);
+ } else {
+ // this is our last resort when current url and new url are both relative
+ // we try to resolve against the current working directory in the local
+ // file system.
+ QFileInfo fi(currentURL.toLocalFile());
+ if (fi.exists()) {
+ resourceUrl =
+ QUrl::fromLocalFile(fi.absolutePath() + QDir::separator()).resolved(name);
+ } else if (currentURL.isEmpty()) {
+ resourceUrl.setScheme(QLatin1String("file"));
+ }
}
}
@@ -2124,13 +2160,21 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
html += QLatin1String("pt;");
attributesEmitted = true;
} else if (format.hasProperty(QTextFormat::FontSizeAdjustment)) {
- static const char * const sizeNames[] = {
- "small", "medium", "large", "x-large", "xx-large"
+ static const char sizeNameData[] =
+ "small" "\0"
+ "medium" "\0"
+ "xx-large" ;
+ static const quint8 sizeNameOffsets[] = {
+ 0, // "small"
+ sizeof("small"), // "medium"
+ sizeof("small") + sizeof("medium") + 3, // "large" )
+ sizeof("small") + sizeof("medium") + 1, // "x-large" )> compressed into "xx-large"
+ sizeof("small") + sizeof("medium"), // "xx-large" )
};
const char *name = 0;
const int idx = format.intProperty(QTextFormat::FontSizeAdjustment) + 1;
if (idx >= 0 && idx <= 4) {
- name = sizeNames[idx];
+ name = sizeNameData + sizeNameOffsets[idx];
}
if (name) {
html += QLatin1String(" font-size:");
diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h
index d8f52e9f98..854cb29ed9 100644
--- a/src/gui/text/qtextdocument.h
+++ b/src/gui/text/qtextdocument.h
@@ -47,6 +47,7 @@
#include <QtCore/qrect.h>
#include <QtCore/qvariant.h>
#include <QtGui/qfont.h>
+#include <QtCore/qurl.h>
QT_BEGIN_NAMESPACE
@@ -63,7 +64,6 @@ class QTextFormat;
class QTextFrame;
class QTextBlock;
class QTextCodec;
-class QUrl;
class QVariant;
class QRectF;
class QTextOption;
@@ -116,6 +116,7 @@ class Q_GUI_EXPORT QTextDocument : public QObject
Q_PROPERTY(int maximumBlockCount READ maximumBlockCount WRITE setMaximumBlockCount)
Q_PROPERTY(qreal documentMargin READ documentMargin WRITE setDocumentMargin)
QDOC_PROPERTY(QTextOption defaultTextOption READ defaultTextOption WRITE setDefaultTextOption)
+ Q_PROPERTY(QUrl baseUrl READ baseUrl WRITE setBaseUrl NOTIFY baseUrlChanged)
public:
explicit QTextDocument(QObject *parent = 0);
@@ -258,6 +259,9 @@ public:
QTextOption defaultTextOption() const;
void setDefaultTextOption(const QTextOption &option);
+ QUrl baseUrl() const;
+ void setBaseUrl(const QUrl &url);
+
Qt::CursorMoveStyle defaultCursorMoveStyle() const;
void setDefaultCursorMoveStyle(Qt::CursorMoveStyle style);
@@ -270,7 +274,7 @@ Q_SIGNALS:
void modificationChanged(bool m);
void cursorPositionChanged(const QTextCursor &cursor);
void blockCountChanged(int newBlockCount);
-
+ void baseUrlChanged(const QUrl &url);
void documentLayoutChanged();
public Q_SLOTS:
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index 8d4cab30ae..fa22131c9e 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -355,6 +355,7 @@ public:
QString url;
qreal indentWidth;
qreal documentMargin;
+ QUrl baseUrl;
void mergeCachedResources(const QTextDocumentPrivate *priv);
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index df67fb581a..3bd1e2a801 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -489,7 +489,7 @@ void QTextHtmlImporter::import()
&& currentNode->id != Html_unknown)
{
hasBlock = false;
- } else if (hasBlock) {
+ } else if (blockTagClosed && hasBlock) {
// when collapsing subsequent block tags we need to clear the block format
QTextBlockFormat blockFormat = currentNode->blockFormat;
blockFormat.setIndent(indent);
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index febdaaa86c..eb31c520ed 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -241,7 +241,8 @@ using namespace std;
static const char *directions[] = {
"DirL", "DirR", "DirEN", "DirES", "DirET", "DirAN", "DirCS", "DirB", "DirS", "DirWS", "DirON",
- "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN"
+ "DirLRE", "DirLRO", "DirAL", "DirRLE", "DirRLO", "DirPDF", "DirNSM", "DirBN",
+ "DirLRI", "DirRLI", "DirFSI", "DirPDI"
};
#endif
@@ -928,21 +929,8 @@ void QTextEngine::shapeText(int item) const
int nGlyphs = initialGlyphs.numGlyphs;
QFontEngine::ShaperFlags shaperFlags(QFontEngine::GlyphIndicesOnly);
- if (si.analysis.bidiLevel % 2)
- shaperFlags |= QFontEngine::RightToLeft;
-
- if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
- nGlyphs = qMax(nGlyphs, itemLength); // ### needed for QFontEngine::stringToCMap() to not fail twice
- if (!ensureSpace(nGlyphs)) {
- Q_UNREACHABLE(); // ### report OOM error somehow
- return;
- }
- initialGlyphs = availableGlyphs(&si);
- if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags)) {
- Q_UNREACHABLE(); // ### if this happens there is a bug in the fontengine
- return;
- }
- }
+ if (!fontEngine->stringToCMap(reinterpret_cast<const QChar *>(string), itemLength, &initialGlyphs, &nGlyphs, shaperFlags))
+ Q_UNREACHABLE();
uint lastEngine = ~0u;
for (int i = 0, glyph_pos = 0; i < itemLength; ++i, ++glyph_pos) {
@@ -1014,17 +1002,17 @@ void QTextEngine::shapeText(int item) const
for (int i = 1; i < si.num_glyphs; ++i) {
if (glyphs.attributes[i].clusterStart) {
if (letterSpacingIsAbsolute)
- glyphs.advances_x[i-1] += letterSpacing;
+ glyphs.advances[i - 1] += letterSpacing;
else {
- QFixed &advance = glyphs.advances_x[i-1];
+ QFixed &advance = glyphs.advances[i - 1];
advance += (letterSpacing - 100) * advance / 100;
}
}
}
if (letterSpacingIsAbsolute)
- glyphs.advances_x[si.num_glyphs-1] += letterSpacing;
+ glyphs.advances[si.num_glyphs - 1] += letterSpacing;
else {
- QFixed &advance = glyphs.advances_x[si.num_glyphs-1];
+ QFixed &advance = glyphs.advances[si.num_glyphs - 1];
advance += (letterSpacing - 100) * advance / 100;
}
}
@@ -1036,13 +1024,13 @@ void QTextEngine::shapeText(int item) const
if (i + 1 == si.num_glyphs
||(glyphs.attributes[i+1].justification != QGlyphAttributes::Space
&& glyphs.attributes[i+1].justification != QGlyphAttributes::Arabic_Space))
- glyphs.advances_x[i] += wordSpacing;
+ glyphs.advances[i] += wordSpacing;
}
}
}
for (int i = 0; i < si.num_glyphs; ++i)
- si.width += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ si.width += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
}
#ifdef QT_ENABLE_HARFBUZZ_NG
@@ -1139,8 +1127,7 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
for (uint i = 0; i < num_glyphs; ++i) {
g.glyphs[i] = infos[i].codepoint;
- g.advances_x[i] = QFixed::fromFixed(positions[i].x_advance);
- g.advances_y[i] = QFixed::fromFixed(positions[i].y_advance);
+ g.advances[i] = QFixed::fromFixed(positions[i].x_advance);
g.offsets[i].x = QFixed::fromFixed(positions[i].x_offset);
g.offsets[i].y = QFixed::fromFixed(positions[i].y_offset);
@@ -1163,6 +1150,13 @@ int QTextEngine::shapeTextWithHarfbuzzNG(const QScriptItem &si, const ushort *st
g.glyphs[i] |= (engineIdx << 24);
}
+#ifdef Q_OS_MAC
+ if (actualFontEngine->fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (uint i = 0; i < num_glyphs; ++i)
+ g.advances[i] = g.advances[i].round();
+ }
+#endif
+
glyphs_shaped += num_glyphs;
}
@@ -1238,7 +1232,8 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
if (fontEngine->type() == QFontEngine::Multi) {
actualFontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
- shaper_item.glyphIndicesPresent = true;
+ if ((si.analysis.bidiLevel % 2) == 0)
+ shaper_item.glyphIndicesPresent = true;
}
shaper_item.font = (HB_Font)actualFontEngine->harfbuzzFont();
@@ -1256,7 +1251,7 @@ int QTextEngine::shapeTextWithHarfbuzz(const QScriptItem &si, const ushort *stri
shaper_item.glyphs = reinterpret_cast<HB_Glyph *>(g.glyphs);
shaper_item.attributes = reinterpret_cast<HB_GlyphAttributes *>(g.attributes);
- shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances_x);
+ shaper_item.advances = reinterpret_cast<HB_Fixed *>(g.advances);
shaper_item.offsets = reinterpret_cast<HB_FixedPoint *>(g.offsets);
if (engineIdx != 0 && shaper_item.glyphIndicesPresent) {
@@ -1360,9 +1355,9 @@ void QTextEngine::shape(int item) const
if (layoutData->items[item].analysis.flags == QScriptAnalysis::Object) {
ensureSpace(1);
if (block.docHandle()) {
- QTextFormat format = formats()->format(formatIndex(&layoutData->items[item]));
docLayout()->resizeInlineObject(QTextInlineObject(item, const_cast<QTextEngine *>(this)),
- layoutData->items[item].position + block.position(), format);
+ layoutData->items[item].position + block.position(),
+ format(&layoutData->items[item]));
}
} else if (layoutData->items[item].analysis.flags == QScriptAnalysis::Tab) {
// set up at least the ascent/descent/leading of the script item for the tab
@@ -1394,7 +1389,7 @@ void QTextEngine::invalidate()
minWidth = 0;
maxWidth = 0;
if (specialData)
- specialData->resolvedFormatIndices.clear();
+ specialData->resolvedFormats.clear();
resetFontEngineCache();
}
@@ -1468,8 +1463,18 @@ void QTextEngine::itemize() const
{
QVarLengthArray<uchar> scripts(length);
QUnicodeTools::initScripts(string, length, scripts.data());
- for (int i = 0; i < length; ++i)
- analysis[i].script = scripts.at(i);
+ for (int i = 0; i < length; ++i) {
+ ushort script = scripts.at(i);
+ switch (script) {
+ case QChar::Script_Hiragana:
+ case QChar::Script_Katakana:
+ script = QChar::Script_Han;
+ break;
+ default:
+ break;
+ }
+ analysis[i].script = script;
+ }
}
const ushort *uc = string;
@@ -1563,10 +1568,9 @@ void QTextEngine::itemize() const
#ifndef QT_NO_RAWFONT
if (useRawFont && specialData) {
int lastIndex = 0;
- const QTextFormatCollection *collection = formats();
for (int i = 0; i < specialData->addFormats.size(); ++i) {
const QTextLayout::FormatRange &range = specialData->addFormats.at(i);
- const QTextCharFormat format = collection->charFormat(specialData->addFormatIndices.at(i));
+ const QTextCharFormat &format = range.format;
if (format.hasProperty(QTextFormat::FontCapitalization)) {
itemizer.generate(lastIndex, range.start - lastIndex, QFont::MixedCase);
itemizer.generate(range.start, range.length, format.fontCapitalization());
@@ -1674,7 +1678,7 @@ QFixed QTextEngine::width(int from, int len) const
// qDebug("char: start=%d end=%d / glyph: start = %d, end = %d", charFrom, charEnd, glyphStart, glyphEnd);
for (int i = glyphStart; i < glyphEnd; i++)
- w += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ w += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
}
}
}
@@ -1963,11 +1967,22 @@ static void set(QJustificationPoint *point, int type, const QGlyphLayout &glyph,
if (type >= QGlyphAttributes::Arabic_Normal) {
QChar ch(0x640); // Kashida character
- QGlyphLayoutArray<8> glyphs;
- int nglyphs = 7;
- fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0);
- if (glyphs.glyphs[0] && glyphs.advances_x[0] != 0) {
- point->kashidaWidth = glyphs.advances_x[0];
+
+ glyph_t kashidaGlyph;
+ QFixed kashidaWidth;
+
+ QGlyphLayout glyphs;
+ glyphs.numGlyphs = 1;
+ glyphs.glyphs = &kashidaGlyph;
+ glyphs.advances = &kashidaWidth;
+
+ int nglyphs = 1;
+ if (!fe->stringToCMap(&ch, 1, &glyphs, &nglyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nglyphs == 1);
+
+ if (kashidaGlyph != 0 && kashidaWidth != 0) {
+ point->kashidaWidth = kashidaWidth;
} else {
point->type = QGlyphAttributes::NoJustification;
point->kashidaWidth = 0;
@@ -2209,7 +2224,7 @@ QTextEngine::LayoutData::LayoutData(const QString &str, void **stack_memory, int
int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;
int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;
- available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::spaceNeededForGlyphLayout(1);
+ available_glyphs = ((int)allocated - space_charAttributes - space_logClusters)*(int)sizeof(void*)/(int)QGlyphLayout::SpaceNeeded;
if (available_glyphs < str.length()) {
// need to allocate on the heap
@@ -2251,7 +2266,7 @@ bool QTextEngine::LayoutData::reallocate(int totalGlyphs)
int space_charAttributes = sizeof(QCharAttributes)*string.length()/sizeof(void*) + 1;
int space_logClusters = sizeof(unsigned short)*string.length()/sizeof(void*) + 1;
- int space_glyphs = QGlyphLayout::spaceNeededForGlyphLayout(totalGlyphs)/sizeof(void*) + 2;
+ int space_glyphs = (totalGlyphs * QGlyphLayout::SpaceNeeded) / sizeof(void *) + 2;
int newAllocated = space_charAttributes + space_glyphs + space_logClusters;
// These values can be negative if the length of string/glyphs causes overflow,
@@ -2298,8 +2313,7 @@ void QGlyphLayout::grow(char *address, int totalGlyphs)
// move the existing data
memmove(newLayout.attributes, oldLayout.attributes, numGlyphs * sizeof(QGlyphAttributes));
memmove(newLayout.justifications, oldLayout.justifications, numGlyphs * sizeof(QGlyphJustification));
- memmove(newLayout.advances_y, oldLayout.advances_y, numGlyphs * sizeof(QFixed));
- memmove(newLayout.advances_x, oldLayout.advances_x, numGlyphs * sizeof(QFixed));
+ memmove(newLayout.advances, oldLayout.advances, numGlyphs * sizeof(QFixed));
memmove(newLayout.glyphs, oldLayout.glyphs, numGlyphs * sizeof(glyph_t));
}
@@ -2328,8 +2342,12 @@ void QTextEngine::freeMemory()
int QTextEngine::formatIndex(const QScriptItem *si) const
{
- if (specialData && !specialData->resolvedFormatIndices.isEmpty())
- return specialData->resolvedFormatIndices.at(si - &layoutData->items[0]);
+ if (specialData && !specialData->resolvedFormats.isEmpty()) {
+ QTextFormatCollection *collection = formats();
+ Q_ASSERT(collection);
+ return collection->indexForFormat(specialData->resolvedFormats.at(si - &layoutData->items[0]));
+ }
+
QTextDocumentPrivate *p = block.docHandle();
if (!p)
return -1;
@@ -2442,23 +2460,6 @@ void QTextEngine::setPreeditArea(int position, const QString &preeditText)
clearLineData();
}
-QList<QTextLayout::FormatRange> QTextEngine::additionalFormats() const
-{
- QList<QTextLayout::FormatRange> formatList;
- if (!specialData)
- return formatList;
-
- formatList = specialData->addFormats;
- if (!specialData->addFormatIndices.isEmpty()) {
- const QTextFormatCollection *formats = this->formats();
- Q_ASSERT(formats);
- for (int i = 0; i < specialData->addFormatIndices.size(); ++i)
- formatList[i].format = formats->charFormat(specialData->addFormatIndices.at(i));
- }
-
- return formatList;
-}
-
void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList)
{
if (formatList.isEmpty()) {
@@ -2469,7 +2470,6 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo
specialData = 0;
} else {
specialData->addFormats.clear();
- specialData->addFormatIndices.clear();
}
} else {
if (!specialData) {
@@ -2484,19 +2484,17 @@ void QTextEngine::setAdditionalFormats(const QList<QTextLayout::FormatRange> &fo
void QTextEngine::indexAdditionalFormats()
{
- specialData->addFormatIndices.resize(specialData->addFormats.count());
-
- QTextFormatCollection *formats = this->formats();
-
- if (!formats) {
+ QTextFormatCollection *collection = formats();
+ if (!collection) {
Q_ASSERT(!block.docHandle());
specialData->formats.reset(new QTextFormatCollection);
- formats = specialData->formats.data();
+ collection = specialData->formats.data();
}
+ // replace with shared copies
for (int i = 0; i < specialData->addFormats.count(); ++i) {
- specialData->addFormatIndices[i] = formats->indexForFormat(specialData->addFormats.at(i).format);
- specialData->addFormats[i].format = QTextCharFormat();
+ QTextCharFormat &format = specialData->addFormats[i].format;
+ format = collection->charFormat(collection->indexForFormat(format));
}
}
@@ -2510,7 +2508,8 @@ static inline bool nextCharJoins(const QString &string, int pos)
++pos;
if (pos == string.length())
return false;
- return string.at(pos).joining() != QChar::OtherJoining;
+ QChar::JoiningType joining = string.at(pos).joiningType();
+ return joining != QChar::Joining_None && joining != QChar::Joining_Transparent;
}
static inline bool prevCharJoins(const QString &string, int pos)
@@ -2519,19 +2518,15 @@ static inline bool prevCharJoins(const QString &string, int pos)
--pos;
if (pos == 0)
return false;
- QChar::Joining joining = string.at(pos - 1).joining();
- return (joining == QChar::Dual || joining == QChar::Center);
+ QChar::JoiningType joining = string.at(pos - 1).joiningType();
+ return joining == QChar::Joining_Dual || joining == QChar::Joining_Causing;
}
static inline bool isRetainableControlCode(QChar c)
{
- return (c.unicode() == 0x202a // LRE
- || c.unicode() == 0x202b // LRE
- || c.unicode() == 0x202c // PDF
- || c.unicode() == 0x202d // LRO
- || c.unicode() == 0x202e // RLO
- || c.unicode() == 0x200e // LRM
- || c.unicode() == 0x200f); // RLM
+ return (c.unicode() >= 0x202a && c.unicode() <= 0x202e) // LRE, RLE, PDF, LRO, RLO
+ || (c.unicode() >= 0x200e && c.unicode() <= 0x200f) // LRM, RLM
+ || (c.unicode() >= 0x2066 && c.unicode() <= 0x2069); // LRM, RLM
}
static QString stringMidRetainingBidiCC(const QString &string,
@@ -2619,14 +2614,14 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (feForEllipsis->type() == QFontEngine::Mac)
feForEllipsis = fe;
- if (feForEllipsis->canRender(&ellipsisChar, 1)) {
- int nGlyphs = 1;
- feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0);
- }
+ int nGlyphs = 1;
+ if (!feForEllipsis->stringToCMap(&ellipsisChar, 1, &ellipsisGlyph, &nGlyphs, 0))
+ Q_UNREACHABLE();
+ Q_ASSERT(nGlyphs == 1);
}
if (ellipsisGlyph.glyphs[0]) {
- ellipsisWidth = ellipsisGlyph.advances_x[0];
+ ellipsisWidth = ellipsisGlyph.advances[0];
ellipsisText = ellipsisChar;
} else {
QString dotDotDot(QLatin1String("..."));
@@ -2634,10 +2629,11 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
QGlyphLayoutArray<3> glyphs;
int nGlyphs = 3;
if (!fe->stringToCMap(dotDotDot.constData(), 3, &glyphs, &nGlyphs, 0))
- // should never happen...
- return layoutData->string;
+ Q_UNREACHABLE();
+ Q_ASSERT(nGlyphs == 3);
+
for (int i = 0; i < nGlyphs; ++i)
- ellipsisWidth += glyphs.advances_x[i];
+ ellipsisWidth += glyphs.advances[i];
ellipsisText = dotDotDot;
}
}
@@ -2786,7 +2782,7 @@ void QTextEngine::splitItem(int item, int pos) const
QFixed w = 0;
const QGlyphLayout g = shapedGlyphs(&oldItem);
for(int j = 0; j < breakGlyph; ++j)
- w += g.advances_x[j] * !g.attributes[j].dontPrint;
+ w += g.advances[j] * !g.attributes[j].dontPrint;
newItem.width = oldItem.width - w;
oldItem.width = w;
@@ -2859,9 +2855,9 @@ QFixed QTextEngine::calculateTabWidth(int item, QFixed x) const
QGlyphLayout glyphs = this->shapedGlyphs(&item);
const int end = qMin(item.position + item.num_glyphs, tabSectionEnd) - item.position;
for (int i=0; i < end; i++)
- length += glyphs.advances_x[i] * !glyphs.attributes[i].dontPrint;
+ length += glyphs.advances[i] * !glyphs.attributes[i].dontPrint;
if (end + item.position == tabSectionEnd && tabSpec.type == QTextOption::DelimiterTab) // remove half of matching char
- length -= glyphs.advances_x[end] / 2 * !glyphs.attributes[end].dontPrint;
+ length -= glyphs.advances[end] / 2 * !glyphs.attributes[end].dontPrint;
}
switch (tabSpec.type) {
@@ -2915,14 +2911,13 @@ public:
void QTextEngine::resolveAdditionalFormats() const
{
if (!specialData || specialData->addFormats.isEmpty()
- || !specialData->resolvedFormatIndices.isEmpty())
+ || !specialData->resolvedFormats.isEmpty())
return;
QTextFormatCollection *collection = formats();
- specialData->resolvedFormatIndices.clear();
- QVector<int> indices(layoutData->items.count());
-
+ specialData->resolvedFormats.clear();
+ QVector<QTextCharFormat> resolvedFormats(layoutData->items.count());
QVarLengthArray<int, 64> addFormatSortedByStart;
addFormatSortedByStart.reserve(specialData->addFormats.count());
@@ -2958,21 +2953,24 @@ void QTextEngine::resolveAdditionalFormats() const
currentFormats.remove(currentFormatIterator - currentFormats.begin());
++endIt;
}
- QTextCharFormat format;
+
+ QTextCharFormat &format = resolvedFormats[i];
if (block.docHandle()) {
// when we have a docHandle, formatIndex might still return a valid index based
// on the preeditPosition. for all other cases, we cleared the resolved format indices
format = collection->charFormat(formatIndex(si));
}
-
- foreach (int cur, currentFormats) {
- Q_ASSERT(specialData->addFormats.at(cur).start <= si->position
- && specialData->addFormats.at(cur).start + specialData->addFormats.at(cur).length >= end);
- format.merge(collection->format(specialData->addFormatIndices.at(cur)));
+ if (!currentFormats.isEmpty()) {
+ foreach (int cur, currentFormats) {
+ const QTextLayout::FormatRange &range = specialData->addFormats.at(cur);
+ Q_ASSERT(range.start <= si->position && range.start + range.length >= end);
+ format.merge(range.format);
+ }
+ format = collection->charFormat(collection->indexForFormat(format)); // get shared copy
}
- indices[i] = collection->indexForFormat(format);
}
- specialData->resolvedFormatIndices = indices;
+
+ specialData->resolvedFormats = resolvedFormats;
}
QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)
@@ -3026,7 +3024,7 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in
break;
}
if (clusterLength)
- return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength;
+ return glyphs.advances[glyph_pos] * offsetInCluster / clusterLength;
}
return 0;
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index fb71ab40b8..1616a78937 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -190,11 +190,15 @@ Q_DECLARE_TYPEINFO(QGlyphJustification, Q_PRIMITIVE_TYPE);
struct QGlyphLayout
{
+ enum {
+ SpaceNeeded = sizeof(glyph_t) + sizeof(QFixed) + sizeof(QFixedPoint)
+ + sizeof(QGlyphAttributes) + sizeof(QGlyphJustification)
+ };
+
// init to 0 not needed, done when shaping
QFixedPoint *offsets; // 8 bytes per element
glyph_t *glyphs; // 4 bytes per element
- QFixed *advances_x; // 4 bytes per element
- QFixed *advances_y; // 4 bytes per element
+ QFixed *advances; // 4 bytes per element
QGlyphJustification *justifications; // 4 bytes per element
QGlyphAttributes *attributes; // 2 bytes per element
@@ -208,9 +212,7 @@ struct QGlyphLayout
int offset = totalGlyphs * sizeof(QFixedPoint);
glyphs = reinterpret_cast<glyph_t *>(address + offset);
offset += totalGlyphs * sizeof(glyph_t);
- advances_x = reinterpret_cast<QFixed *>(address + offset);
- offset += totalGlyphs * sizeof(QFixed);
- advances_y = reinterpret_cast<QFixed *>(address + offset);
+ advances = reinterpret_cast<QFixed *>(address + offset);
offset += totalGlyphs * sizeof(QFixed);
justifications = reinterpret_cast<QGlyphJustification *>(address + offset);
offset += totalGlyphs * sizeof(QGlyphJustification);
@@ -221,8 +223,7 @@ struct QGlyphLayout
inline QGlyphLayout mid(int position, int n = -1) const {
QGlyphLayout copy = *this;
copy.glyphs += position;
- copy.advances_x += position;
- copy.advances_y += position;
+ copy.advances += position;
copy.offsets += position;
copy.justifications += position;
copy.attributes += position;
@@ -233,27 +234,20 @@ struct QGlyphLayout
return copy;
}
- static inline int spaceNeededForGlyphLayout(int totalGlyphs) {
- return totalGlyphs * (sizeof(glyph_t) + sizeof(QGlyphAttributes)
- + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
- + sizeof(QGlyphJustification));
- }
-
inline QFixed effectiveAdvance(int item) const
- { return (advances_x[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
+ { return (advances[item] + QFixed::fromFixed(justifications[item].space_18d6)) * !attributes[item].dontPrint; }
inline void clear(int first = 0, int last = -1) {
if (last == -1)
last = numGlyphs;
if (first == 0 && last == numGlyphs
&& reinterpret_cast<char *>(offsets + numGlyphs) == reinterpret_cast<char *>(glyphs)) {
- memset(offsets, 0, spaceNeededForGlyphLayout(numGlyphs));
+ memset(offsets, 0, (numGlyphs * SpaceNeeded));
} else {
const int num = last - first;
memset(offsets + first, 0, num * sizeof(QFixedPoint));
memset(glyphs + first, 0, num * sizeof(glyph_t));
- memset(advances_x + first, 0, num * sizeof(QFixed));
- memset(advances_y + first, 0, num * sizeof(QFixed));
+ memset(advances + first, 0, num * sizeof(QFixed));
memset(justifications + first, 0, num * sizeof(QGlyphJustification));
memset(attributes + first, 0, num * sizeof(QGlyphAttributes));
}
@@ -272,7 +266,7 @@ private:
typedef QVarLengthArray<void *> Array;
public:
QVarLengthGlyphLayoutArray(int totalGlyphs)
- : Array(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1)
+ : Array((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1)
, QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs)
{
memset(Array::data(), 0, Array::size() * sizeof(void *));
@@ -280,7 +274,7 @@ public:
void resize(int totalGlyphs)
{
- Array::resize(spaceNeededForGlyphLayout(totalGlyphs) / sizeof(void *) + 1);
+ Array::resize((totalGlyphs * SpaceNeeded) / sizeof(void *) + 1);
*((QGlyphLayout *)this) = QGlyphLayout(reinterpret_cast<char *>(Array::data()), totalGlyphs);
memset(Array::data(), 0, Array::size() * sizeof(void *));
@@ -297,10 +291,7 @@ public:
}
private:
- void *buffer[(N * (sizeof(glyph_t) + sizeof(QGlyphAttributes)
- + sizeof(QFixed) + sizeof(QFixed) + sizeof(QFixedPoint)
- + sizeof(QGlyphJustification)))
- / sizeof(void *) + 1];
+ void *buffer[(N * SpaceNeeded) / sizeof(void *) + 1];
};
struct QScriptItem;
@@ -449,7 +440,6 @@ public:
typedef QList<ItemDecoration> ItemDecorationList;
- QTextEngine(LayoutData *data);
QTextEngine();
QTextEngine(const QString &str, const QFont &f);
~QTextEngine();
@@ -553,6 +543,7 @@ public:
mutable QScriptLineArray lines;
+private:
struct FontEngineCache {
FontEngineCache();
mutable QFontEngine *prevFontEngine;
@@ -570,6 +561,7 @@ public:
};
mutable FontEngineCache feCache;
+public:
QString text;
mutable QFont fnt;
#ifndef QT_NO_RAWFONT
@@ -611,7 +603,8 @@ public:
void setPreeditArea(int position, const QString &text);
inline bool hasFormats() const { return block.docHandle() || (specialData && !specialData->addFormats.isEmpty()); }
- QList<QTextLayout::FormatRange> additionalFormats() const;
+ inline QList<QTextLayout::FormatRange> additionalFormats() const
+ { return specialData ? specialData->addFormats : QList<QTextLayout::FormatRange>(); }
void setAdditionalFormats(const QList<QTextLayout::FormatRange> &formatList);
private:
@@ -621,8 +614,7 @@ private:
int preeditPosition;
QString preeditText;
QList<QTextLayout::FormatRange> addFormats;
- QVector<int> addFormatIndices;
- QVector<int> resolvedFormatIndices;
+ QVector<QTextCharFormat> resolvedFormats;
// only used when no docHandle is available
QScopedPointer<QTextFormatCollection> formats;
};
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 2389427da0..4854af0d01 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -524,7 +524,7 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
\value BlockFormat The object formats a text block
\value CharFormat The object formats a single character
\value ListFormat The object formats a list
- \value TableFormat The object formats a table
+ \omitvalue TableFormat Unused Value, a table's FormatType is FrameFormat.
\value FrameFormat The object formats a frame
\value UserFormat
@@ -706,6 +706,15 @@ Q_GUI_EXPORT QDataStream &operator>>(QDataStream &stream, QTextFormat &fmt)
*/
/*!
+ \fn bool QTextFormat::isEmpty() const
+ \since 5.3
+
+ Returns true if the format does not store any properties; false otherwise.
+
+ \sa propertyCount(), properties()
+*/
+
+/*!
\fn bool QTextFormat::isCharFormat() const
Returns \c true if this text format is a \c CharFormat; otherwise
@@ -1870,36 +1879,93 @@ QStringList QTextCharFormat::anchorNames() const
*/
/*!
+ \enum QTextCharFormat::FontPropertiesInheritanceBehavior
+ \since 5.3
+
+ This enum specifies how the setFont() function should behave with
+ respect to unset font properties.
+
+ \value FontPropertiesSpecifiedOnly If a property is not explicitly set, do not
+ change the text format's property value.
+ \value FontPropertiesAll If a property is not explicitly set, override the
+ text format's property with a default value.
+
+ \sa setFont()
+*/
+
+/*!
+ \overload
+
Sets the text format's \a font.
+
+ \sa font()
*/
void QTextCharFormat::setFont(const QFont &font)
{
- setFontFamily(font.family());
+ setFont(font, FontPropertiesAll);
+}
- const qreal pointSize = font.pointSizeF();
- if (pointSize > 0) {
- setFontPointSize(pointSize);
- } else {
- const int pixelSize = font.pixelSize();
- if (pixelSize > 0)
- setProperty(QTextFormat::FontPixelSize, pixelSize);
+/*!
+ \since 5.3
+
+ Sets the text format's \a font.
+
+ If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that
+ has not been explicitly set is treated like as it were set with default value;
+ If \a behavior is QTextCharFormat::FontPropertiesAll, the font property that
+ has not been explicitly set is ignored and the respective property value
+ remains unchanged.
+
+ \sa font()
+*/
+void QTextCharFormat::setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior)
+{
+ const uint mask = behavior == FontPropertiesAll ? uint(QFont::AllPropertiesResolved)
+ : font.resolve();
+
+ if (mask & QFont::FamilyResolved)
+ setFontFamily(font.family());
+ if (mask & QFont::SizeResolved) {
+ const qreal pointSize = font.pointSizeF();
+ if (pointSize > 0) {
+ setFontPointSize(pointSize);
+ } else {
+ const int pixelSize = font.pixelSize();
+ if (pixelSize > 0)
+ setProperty(QTextFormat::FontPixelSize, pixelSize);
+ }
}
- setFontWeight(font.weight());
- setFontItalic(font.italic());
- setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline);
- setFontOverline(font.overline());
- setFontStrikeOut(font.strikeOut());
- setFontFixedPitch(font.fixedPitch());
- setFontCapitalization(font.capitalization());
- setFontWordSpacing(font.wordSpacing());
- setFontLetterSpacingType(font.letterSpacingType());
- setFontLetterSpacing(font.letterSpacing());
- setFontStretch(font.stretch());
- setFontStyleHint(font.styleHint());
- setFontStyleStrategy(font.styleStrategy());
- setFontHintingPreference(font.hintingPreference());
- setFontKerning(font.kerning());
+ if (mask & QFont::WeightResolved)
+ setFontWeight(font.weight());
+ if (mask & QFont::StyleResolved)
+ setFontItalic(font.style() != QFont::StyleNormal);
+ if (mask & QFont::UnderlineResolved)
+ setUnderlineStyle(font.underline() ? SingleUnderline : NoUnderline);
+ if (mask & QFont::OverlineResolved)
+ setFontOverline(font.overline());
+ if (mask & QFont::StrikeOutResolved)
+ setFontStrikeOut(font.strikeOut());
+ if (mask & QFont::FixedPitchResolved)
+ setFontFixedPitch(font.fixedPitch());
+ if (mask & QFont::CapitalizationResolved)
+ setFontCapitalization(font.capitalization());
+ if (mask & QFont::LetterSpacingResolved)
+ setFontWordSpacing(font.wordSpacing());
+ if (mask & QFont::LetterSpacingResolved) {
+ setFontLetterSpacingType(font.letterSpacingType());
+ setFontLetterSpacing(font.letterSpacing());
+ }
+ if (mask & QFont::StretchResolved)
+ setFontStretch(font.stretch());
+ if (mask & QFont::StyleHintResolved)
+ setFontStyleHint(font.styleHint());
+ if (mask & QFont::StyleStrategyResolved)
+ setFontStyleStrategy(font.styleStrategy());
+ if (mask & QFont::HintingPreferenceResolved)
+ setFontHintingPreference(font.hintingPreference());
+ if (mask & QFont::KerningResolved)
+ setFontKerning(font.kerning());
}
/*!
@@ -3376,19 +3442,6 @@ bool QTextFormatCollection::hasFormatCached(const QTextFormat &format) const
return false;
}
-QTextFormat QTextFormatCollection::objectFormat(int objectIndex) const
-{
- if (objectIndex == -1)
- return QTextFormat();
- return format(objFormats.at(objectIndex));
-}
-
-void QTextFormatCollection::setObjectFormat(int objectIndex, const QTextFormat &f)
-{
- const int formatIndex = indexForFormat(f);
- objFormats[objectIndex] = formatIndex;
-}
-
int QTextFormatCollection::objectFormatIndex(int objectIndex) const
{
if (objectIndex == -1)
diff --git a/src/gui/text/qtextformat.h b/src/gui/text/qtextformat.h
index 2098369811..5369001a03 100644
--- a/src/gui/text/qtextformat.h
+++ b/src/gui/text/qtextformat.h
@@ -141,7 +141,9 @@ public:
BlockFormat = 1,
CharFormat = 2,
ListFormat = 3,
+#if QT_DEPRECATED_SINCE(5, 3)
TableFormat = 4,
+#endif
FrameFormat = 5,
UserFormat = 100
@@ -295,6 +297,7 @@ public:
void merge(const QTextFormat &other);
inline bool isValid() const { return type() != InvalidFormat; }
+ inline bool isEmpty() const { return propertyCount() == 0; }
int type() const;
@@ -407,7 +410,13 @@ public:
QTextCharFormat();
bool isValid() const { return isCharFormat(); }
- void setFont(const QFont &font);
+
+ enum FontPropertiesInheritanceBehavior {
+ FontPropertiesSpecifiedOnly,
+ FontPropertiesAll
+ };
+ void setFont(const QFont &font, FontPropertiesInheritanceBehavior behavior);
+ void setFont(const QFont &font); // ### Qt6: Merge with above
QFont font() const;
inline void setFontFamily(const QString &family)
diff --git a/src/gui/text/qtextformat_p.h b/src/gui/text/qtextformat_p.h
index 6b2958a4b6..e3998d4f3f 100644
--- a/src/gui/text/qtextformat_p.h
+++ b/src/gui/text/qtextformat_p.h
@@ -68,8 +68,10 @@ public:
QTextFormatCollection(const QTextFormatCollection &rhs);
QTextFormatCollection &operator=(const QTextFormatCollection &rhs);
- QTextFormat objectFormat(int objectIndex) const;
- void setObjectFormat(int objectIndex, const QTextFormat &format);
+ inline QTextFormat objectFormat(int objectIndex) const
+ { return format(objectFormatIndex(objectIndex)); }
+ inline void setObjectFormat(int objectIndex, const QTextFormat &format)
+ { setObjectFormatIndex(objectIndex, indexForFormat(format)); }
int objectFormatIndex(int objectIndex) const;
void setObjectFormatIndex(int objectIndex, int formatIndex);
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 3cb61b9eae..e8a02c44b2 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -1361,33 +1361,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration>
QFont f;
int adjustment = -255;
extractor.extractFont(&f, &adjustment);
- if (f.resolve() & QFont::SizeResolved) {
- if (f.pointSize() > 0) {
- charFormat.setFontPointSize(f.pointSize());
- } else if (f.pixelSize() > 0) {
- charFormat.setProperty(QTextFormat::FontPixelSize, f.pixelSize());
- }
- }
- if (f.resolve() & QFont::StyleResolved)
- charFormat.setFontItalic(f.style() != QFont::StyleNormal);
-
- if (f.resolve() & QFont::WeightResolved)
- charFormat.setFontWeight(f.weight());
-
- if (f.resolve() & QFont::FamilyResolved)
- charFormat.setFontFamily(f.family());
-
- if (f.resolve() & QFont::UnderlineResolved)
- charFormat.setUnderlineStyle(f.underline() ? QTextCharFormat::SingleUnderline : QTextCharFormat::NoUnderline);
-
- if (f.resolve() & QFont::OverlineResolved)
- charFormat.setFontOverline(f.overline());
-
- if (f.resolve() & QFont::StrikeOutResolved)
- charFormat.setFontStrikeOut(f.strikeOut());
-
- if (f.resolve() & QFont::CapitalizationResolved)
- charFormat.setFontCapitalization(f.capitalization());
+ charFormat.setFont(f, QTextCharFormat::FontPropertiesSpecifiedOnly);
if (adjustment >= -1)
charFormat.setProperty(QTextFormat::FontSizeAdjustment, adjustment);
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 66341e186a..0c9866c6cf 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -239,9 +239,7 @@ int QTextInlineObject::formatIndex() const
*/
QTextFormat QTextInlineObject::format() const
{
- if (!eng->block.docHandle())
- return QTextFormat();
- return eng->formats()->format(eng->formatIndex(&eng->layoutData->items[itm]));
+ return eng->format(&eng->layoutData->items[itm]);
}
/*!
@@ -1693,7 +1691,7 @@ static inline void addNextCluster(int &pos, int end, QScriptLine &line, int &gly
} while (pos < end && logClusters[pos] == glyphPosition);
do { // calculate the textWidth for the rest of the current cluster.
if (!glyphs.attributes[glyphPosition].dontPrint)
- line.textWidth += glyphs.advances_x[glyphPosition];
+ line.textWidth += glyphs.advances[glyphPosition];
++glyphPosition;
} while (glyphPosition < current.num_glyphs && !glyphs.attributes[glyphPosition].clusterStart);
@@ -1812,9 +1810,10 @@ void QTextLine::layout_helper(int maxGlyphs)
lbh.whiteSpaceOrObject = true;
lbh.tmpData.length++;
- QTextFormat format = eng->formats()->format(eng->formatIndex(&eng->layoutData->items[item]));
- if (eng->block.docHandle())
- eng->docLayout()->positionInlineObject(QTextInlineObject(item, eng), eng->block.position() + current.position, format);
+ if (eng->block.docHandle()) {
+ QTextInlineObject inlineObject(item, eng);
+ eng->docLayout()->positionInlineObject(inlineObject, eng->block.position() + current.position, inlineObject.format());
+ }
lbh.tmpData.textWidth += current.width;
@@ -1871,9 +1870,9 @@ void QTextLine::layout_helper(int maxGlyphs)
// and thus become invisible again.
//
if (line.length)
- lbh.softHyphenWidth = lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
+ lbh.softHyphenWidth = lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
else if (breakany)
- lbh.tmpData.textWidth += lbh.glyphs.advances_x[lbh.logClusters[lbh.currentPosition - 1]];
+ lbh.tmpData.textWidth += lbh.glyphs.advances[lbh.logClusters[lbh.currentPosition - 1]];
}
// The actual width of the text needs to take the right bearing into account. The
@@ -2249,14 +2248,12 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
if (relativeFrom != (iterator.itemStart - si.position) && !rtl) {
for (int i=itemGlyphsStart; i<glyphsStart; ++i) {
QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
- pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
- glyphLayout.advances_y[i].toReal());
+ pos.rx() += (glyphLayout.advances[i] + justification).toReal();
}
} else if (relativeTo != (iterator.itemEnd - si.position - 1) && rtl) {
for (int i=itemGlyphsEnd; i>glyphsEnd; --i) {
QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
- pos += QPointF((glyphLayout.advances_x[i] + justification).toReal(),
- glyphLayout.advances_y[i].toReal());
+ pos.rx() += (glyphLayout.advances[i] + justification).toReal();
}
}
@@ -2295,10 +2292,8 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
glyphRuns.append(glyphRunWithInfo(multiFontEngine->engine(which),
subLayout, pos, subFlags, x, width));
- for (int i = 0; i < subLayout.numGlyphs; i++) {
- pos += QPointF(subLayout.advances_x[i].toReal(),
- subLayout.advances_y[i].toReal());
- }
+ for (int i = 0; i < subLayout.numGlyphs; ++i)
+ pos.rx() += subLayout.advances[i].toReal();
if (rtl)
end = start;
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index d1a39c6ab6..bd1e970583 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -1233,6 +1233,56 @@ QString QTextBlock::text() const
return text;
}
+/*!
+ \since 5.3
+
+ Returns the block's text format options as a list of continuous ranges
+ of QTextCharFormat. The range's character format is used when inserting text
+ within the range boundaries.
+
+ \sa charFormat(), blockFormat()
+*/
+QList<QTextLayout::FormatRange> QTextBlock::textFormats() const
+{
+ QList<QTextLayout::FormatRange> formats;
+ if (!p || !n)
+ return formats;
+
+ const QTextFormatCollection *formatCollection = p->formatCollection();
+
+ int start = 0;
+ int cur = start;
+ int format = -1;
+
+ const int pos = position();
+ QTextDocumentPrivate::FragmentIterator it = p->find(pos);
+ QTextDocumentPrivate::FragmentIterator end = p->find(pos + length() - 1); // -1 to omit the block separator char
+ for (; it != end; ++it) {
+ const QTextFragmentData * const frag = it.value();
+ if (format != it.value()->format) {
+ if (cur - start > 0) {
+ QTextLayout::FormatRange range;
+ range.start = start;
+ range.length = cur - start;
+ range.format = formatCollection->charFormat(format);
+ formats.append(range);
+ }
+
+ format = frag->format;
+ start = cur;
+ }
+ cur += frag->size_array[0];
+ }
+ if (cur - start > 0) {
+ QTextLayout::FormatRange range;
+ range.start = start;
+ range.length = cur - start;
+ range.format = formatCollection->charFormat(format);
+ formats.append(range);
+ }
+
+ return formats;
+}
/*!
Returns the text document this text block belongs to, or 0 if the
diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h
index 87f2cf6197..6a127f0315 100644
--- a/src/gui/text/qtextobject.h
+++ b/src/gui/text/qtextobject.h
@@ -44,6 +44,7 @@
#include <QtCore/qobject.h>
#include <QtGui/qtextformat.h>
+#include <QtGui/qtextlayout.h>
#include <QtGui/qglyphrun.h>
QT_BEGIN_NAMESPACE
@@ -55,7 +56,6 @@ class QTextDocumentPrivate;
class QTextCursor;
class QTextBlock;
class QTextFragment;
-class QTextLayout;
class QTextList;
class Q_GUI_EXPORT QTextObject : public QObject
@@ -223,6 +223,8 @@ public:
QString text() const;
+ QList<QTextLayout::FormatRange> textFormats() const;
+
const QTextDocument *document() const;
QTextList *textList() const;