summaryrefslogtreecommitdiffstats
path: root/src/gui/text
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/text')
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp6
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.h1
-rw-r--r--src/gui/text/qcssparser.cpp6
-rw-r--r--src/gui/text/qfont.cpp35
-rw-r--r--src/gui/text/qfontdatabase.cpp98
-rw-r--r--src/gui/text/qfontdatabase.h2
-rw-r--r--src/gui/text/qfontengine.cpp2
-rw-r--r--src/gui/text/qfontmetrics.cpp22
-rw-r--r--src/gui/text/qfontsubset.cpp18
-rw-r--r--src/gui/text/qfontsubset_p.h1
-rw-r--r--src/gui/text/qinputcontrol.cpp5
-rw-r--r--src/gui/text/qrawfont.cpp2
-rw-r--r--src/gui/text/qtextdocument.cpp31
-rw-r--r--src/gui/text/qtextdocument_p.cpp5
-rw-r--r--src/gui/text/qtextdocument_p.h1
-rw-r--r--src/gui/text/qtextdocumentfragment.cpp3
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp28
-rw-r--r--src/gui/text/qtextdocumentwriter.cpp7
-rw-r--r--src/gui/text/qtextengine.cpp50
-rw-r--r--src/gui/text/qtextformat.cpp2
-rw-r--r--src/gui/text/qtexthtmlparser.cpp8
-rw-r--r--src/gui/text/qtexthtmlparser_p.h4
-rw-r--r--src/gui/text/qtextimagehandler.cpp50
-rw-r--r--src/gui/text/qtextlayout.cpp68
-rw-r--r--src/gui/text/qtextlist.cpp2
-rw-r--r--src/gui/text/qtextmarkdownimporter.cpp4
-rw-r--r--src/gui/text/qtextmarkdownwriter.cpp2
-rw-r--r--src/gui/text/qtextobject.cpp2
-rw-r--r--src/gui/text/qtextodfwriter.cpp4
-rw-r--r--src/gui/text/qtexttable.cpp15
-rw-r--r--src/gui/text/qtexttable_p.h7
-rw-r--r--src/gui/text/qzip.cpp20
32 files changed, 340 insertions, 171 deletions
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
index 8528f59844..7aa3aa7453 100644
--- a/src/gui/text/qabstracttextdocumentlayout.cpp
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -436,7 +436,8 @@ void QAbstractTextDocumentLayout::registerHandler(int objectType, QObject *compo
if (!iface)
return; // ### print error message on terminal?
- connect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
+ QObjectPrivate::connect(component, &QObject::destroyed, d,
+ &QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed);
QTextObjectHandler h;
h.iface = iface;
@@ -457,7 +458,8 @@ void QAbstractTextDocumentLayout::unregisterHandler(int objectType, QObject *com
const auto it = d->handlers.constFind(objectType);
if (it != d->handlers.cend() && (!component || component == it->component)) {
if (component)
- disconnect(component, SIGNAL(destroyed(QObject*)), this, SLOT(_q_handlerDestroyed(QObject*)));
+ QObjectPrivate::disconnect(component, &QObject::destroyed, d,
+ &QAbstractTextDocumentLayoutPrivate::_q_handlerDestroyed);
d->handlers.erase(it);
}
}
diff --git a/src/gui/text/qabstracttextdocumentlayout.h b/src/gui/text/qabstracttextdocumentlayout.h
index 397dcd37d4..1e97ba3785 100644
--- a/src/gui/text/qabstracttextdocumentlayout.h
+++ b/src/gui/text/qabstracttextdocumentlayout.h
@@ -129,7 +129,6 @@ private:
friend class QTextEngine;
friend class QTextLayout;
friend class QTextLine;
- Q_PRIVATE_SLOT(d_func(), void _q_handlerDestroyed(QObject *obj))
Q_PRIVATE_SLOT(d_func(), int _q_dynamicPageCountSlot())
Q_PRIVATE_SLOT(d_func(), QSizeF _q_dynamicDocumentSizeSlot())
};
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp
index 663f727145..bcdeafdbbd 100644
--- a/src/gui/text/qcssparser.cpp
+++ b/src/gui/text/qcssparser.cpp
@@ -1140,14 +1140,14 @@ static bool setFontSizeFromValue(QCss::Value value, QFont *font, int *fontSizeAd
s.chop(2);
value.variant = s;
if (value.variant.convert((QVariant::Type)qMetaTypeId<qreal>())) {
- font->setPointSizeF(value.variant.toReal());
+ font->setPointSizeF(qBound(qreal(0), value.variant.toReal(), qreal(1 << 24) - 1));
valid = true;
}
} else if (s.endsWith(QLatin1String("px"), Qt::CaseInsensitive)) {
s.chop(2);
value.variant = s;
if (value.variant.convert(QMetaType::Int)) {
- font->setPixelSize(value.variant.toInt());
+ font->setPixelSize(qBound(0, value.variant.toInt(), (1 << 24) - 1));
valid = true;
}
}
@@ -1192,7 +1192,7 @@ static bool setFontWeightFromValue(const QCss::Value &value, QFont *font)
}
if (value.type != Value::Number)
return false;
- font->setWeight(qMin(value.variant.toInt() / 8, 99));
+ font->setWeight(qRound(qBound(0.0, value.variant.toDouble() / 8.0, 99.0)));
return true;
}
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index 94020dc665..9f16af0222 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -220,8 +220,10 @@ QFontPrivate::~QFontPrivate()
if (engineData && !engineData->ref.deref())
delete engineData;
engineData = nullptr;
- if (scFont && scFont != this)
- scFont->ref.deref();
+ if (scFont && scFont != this) {
+ if (!scFont->ref.deref())
+ delete scFont;
+ }
scFont = nullptr;
}
@@ -630,8 +632,10 @@ void QFont::detach()
if (d->engineData && !d->engineData->ref.deref())
delete d->engineData;
d->engineData = nullptr;
- if (d->scFont && d->scFont != d.data())
- d->scFont->ref.deref();
+ if (d->scFont && d->scFont != d.data()) {
+ if (!d->scFont->ref.deref())
+ delete d->scFont;
+ }
d->scFont = nullptr;
return;
}
@@ -2080,7 +2084,26 @@ QString QFont::key() const
/*!
Returns a description of the font. The description is a
comma-separated list of the attributes, perfectly suited for use
- in QSettings.
+ in QSettings, and consists of the following:
+
+ \list
+ \li Font family
+ \li Point size
+ \li Pixel size
+ \li Style hint
+ \li Font weight
+ \li Font style
+ \li Underline
+ \li Strike out
+ \li Fixed pitch
+ \li Always \e{0}
+ \li Capitalization
+ \li Letter spacing
+ \li Word spacing
+ \li Stretch
+ \li Style strategy
+ \li Font style (omitted when unavailable)
+ \endlist
\sa fromString()
*/
@@ -3297,3 +3320,5 @@ QDebug operator<<(QDebug stream, const QFont &font)
#endif
QT_END_NAMESPACE
+
+#include "moc_qfont.cpp"
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 1a4d8f938b..2011f935a9 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -414,6 +414,25 @@ void QtFontFamily::ensurePopulated()
Q_ASSERT_X(populated, Q_FUNC_INFO, qPrintable(name));
}
+/*!
+ \internal
+
+ Tests if the given family \a family supports writing system \a writingSystem,
+ including the special case for Han script mapping to several subsequent writing systems
+*/
+static bool familySupportsWritingSystem(QtFontFamily *family, size_t writingSystem)
+{
+ Q_ASSERT(family != nullptr);
+ Q_ASSERT(writingSystem != QFontDatabase::Any && writingSystem < QFontDatabase::WritingSystemsCount);
+
+ size_t ws = writingSystem;
+ do {
+ if ((family->writingSystems[ws] & QtFontFamily::Supported) != 0)
+ return true;
+ } while (writingSystem >= QFontDatabase::SimplifiedChinese && writingSystem <= QFontDatabase::Japanese && ++ws <= QFontDatabase::Japanese);
+
+ return false;
+}
struct FallbacksCacheKey {
QString family;
@@ -826,7 +845,7 @@ QStringList QPlatformFontDatabase::fallbacksForFamily(const QString &family, QFo
f->ensurePopulated();
- if (writingSystem > QFontDatabase::Any && f->writingSystems[writingSystem] != QtFontFamily::Supported)
+ if (writingSystem > QFontDatabase::Any && !familySupportsWritingSystem(f, writingSystem))
continue;
for (int j = 0; j < f->count; ++j) {
@@ -1219,9 +1238,13 @@ static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
Tries to find the best match for a given request and family/foundry
*/
-static int match(int script, const QFontDef &request,
- const QString &family_name, const QString &foundry_name,
- QtFontDesc *desc, const QList<int> &blacklistedFamilies)
+static int match(int script,
+ const QFontDef &request,
+ const QString &family_name,
+ const QString &foundry_name,
+ QtFontDesc *desc,
+ const QList<int> &blacklistedFamilies,
+ unsigned int *resultingScore = nullptr)
{
int result = -1;
@@ -1271,8 +1294,10 @@ static int match(int script, const QFontDef &request,
test.family->ensurePopulated();
// Check if family is supported in the script we want
- if (writingSystem != QFontDatabase::Any && !(test.family->writingSystems[writingSystem] & QtFontFamily::Supported))
+ if (writingSystem != QFontDatabase::Any
+ && !familySupportsWritingSystem(test.family, writingSystem)) {
continue;
+ }
// as we know the script is supported, we can be sure
// to find a matching font here.
@@ -1296,6 +1321,10 @@ static int match(int script, const QFontDef &request,
if (newscore < 10) // xlfd instead of FT... just accept it
break;
}
+
+ if (resultingScore != nullptr)
+ *resultingScore = score;
+
return result;
}
@@ -1729,13 +1758,19 @@ bool QFontDatabase::isSmoothlyScalable(const QString &family, const QString &sty
for (int j = 0; j < f->count; j++) {
QtFontFoundry *foundry = f->foundries[j];
if (foundryName.isEmpty() || foundry->name.compare(foundryName, Qt::CaseInsensitive) == 0) {
- for (int k = 0; k < foundry->count; k++)
- if ((style.isEmpty() ||
- foundry->styles[k]->styleName == style ||
- foundry->styles[k]->key == styleKey) && foundry->styles[k]->smoothScalable) {
- smoothScalable = true;
+ for (int k = 0; k < foundry->count; k++) {
+ QtFontStyle *fontStyle = foundry->styles[k];
+ smoothScalable =
+ fontStyle->smoothScalable
+ && ((style.isEmpty()
+ || fontStyle->styleName == style
+ || fontStyle->key == styleKey)
+ || (fontStyle->styleName.isEmpty()
+ && style == styleStringHelper(fontStyle->key.weight,
+ QFont::Style(fontStyle->key.style))));
+ if (smoothScalable)
goto end;
- }
+ }
}
}
end:
@@ -2474,13 +2509,12 @@ bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
+//! [add-application-font-doc]
The function returns -1 if the font could not be loaded.
Currently only TrueType fonts, TrueType font collections, and OpenType fonts are
supported.
-
- \note Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+//! [add-application-font-doc]
\sa addApplicationFontFromData(), applicationFontFamilies(), removeApplicationFont()
*/
@@ -2508,12 +2542,7 @@ int QFontDatabase::addApplicationFont(const QString &fileName)
with removeApplicationFont() or to retrieve the list of family names contained
in the font.
- The function returns -1 if the font could not be loaded.
-
- Currently only TrueType fonts and TrueType font collections are supported.
-
- \b{Note:} Adding application fonts on Unix/X11 platforms without fontconfig is
- currently not supported.
+ \include qfontdatabase.cpp add-application-font-doc
\sa addApplicationFont(), applicationFontFamilies(), removeApplicationFont()
*/
@@ -2648,7 +2677,9 @@ bool QFontDatabase::supportsThreadedFontRendering()
/*!
\internal
*/
-QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
+QFontEngine *QFontDatabase::findFont(const QFontDef &request,
+ int script,
+ bool preferScriptOverFamily)
{
QMutexLocker locker(fontDatabaseMutex());
@@ -2679,16 +2710,31 @@ QFontEngine *QFontDatabase::findFont(const QFontDef &request, int script)
return engine;
}
+ if (request.pixelSize > 0xffff) {
+ // Stop absurd requests reaching the engines; pixel size is assumed to fit ushort
+ qCDebug(lcFontMatch, "Rejecting request for pixel size %g2, returning box engine", double(request.pixelSize));
+ return new QFontEngineBox(32); // not request.pixelSize, to avoid overflow/DOS
+ }
+
QString family_name, foundry_name;
const QString requestFamily = request.families.size() > 0 ? request.families.at(0) : request.family;
parseFontName(requestFamily, foundry_name, family_name);
QtFontDesc desc;
QList<int> blackListed;
- int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
- if (index < 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
+ unsigned int score = UINT_MAX;
+ int index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed, &score);
+ if (score > 0 && QGuiApplicationPrivate::platformIntegration()->fontDatabase()->populateFamilyAliases(family_name)) {
// We populated familiy aliases (e.g. localized families), so try again
index = match(multi ? QChar::Script_Common : script, request, family_name, foundry_name, &desc, blackListed);
}
+
+ // If we do not find a match and NoFontMerging is set, use the requested font even if it does
+ // not support the script.
+ //
+ // (we do this at the end to prefer foundries that support the script if they exist)
+ if (index < 0 && !multi && !preferScriptOverFamily)
+ index = match(QChar::Script_Common, request, family_name, foundry_name, &desc, blackListed);
+
if (index >= 0) {
QFontDef fontDef = request;
@@ -2881,10 +2927,8 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
}
uint order = i;
- if (testFamily == nullptr
- || (testFamily->writingSystems[writingSystem] & QtFontFamily::Supported) == 0) {
+ if (testFamily == nullptr || !familySupportsWritingSystem(testFamily, writingSystem))
order |= 1u << 31;
- }
supported.insert(order, family);
}
@@ -2894,3 +2938,5 @@ Q_GUI_EXPORT QStringList qt_sort_families_by_writing_system(QChar::Script script
QT_END_NAMESPACE
+#include "moc_qfontdatabase.cpp"
+
diff --git a/src/gui/text/qfontdatabase.h b/src/gui/text/qfontdatabase.h
index 80b092f177..b581f30a19 100644
--- a/src/gui/text/qfontdatabase.h
+++ b/src/gui/text/qfontdatabase.h
@@ -160,7 +160,7 @@ private:
static void createDatabase();
static void parseFontName(const QString &name, QString &foundry, QString &family);
static QString resolveFontFamilyAlias(const QString &family);
- static QFontEngine *findFont(const QFontDef &request, int script /* QChar::Script */);
+ static QFontEngine *findFont(const QFontDef &request, int script /* QChar::Script */, bool preferScriptOverFamily = false);
static void load(const QFontPrivate *d, int script /* QChar::Script */);
friend struct QFontDef;
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index f1fd755e91..d9c0239940 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1815,7 +1815,7 @@ void QFontEngineMulti::setFallbackFamiliesList(const QStringList &fallbackFamili
void QFontEngineMulti::ensureEngineAt(int at)
{
- if (!m_fallbackFamiliesQueried)
+ if (!m_fallbackFamiliesQueried && at > 0)
ensureFallbackFamiliesQueried();
Q_ASSERT(at < m_engines.size());
if (!m_engines.at(at)) {
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index 73fcc4bc78..72e3969427 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -273,9 +273,8 @@ bool QFontMetrics::operator ==(const QFontMetrics &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so it
+ is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -310,8 +309,8 @@ int QFontMetrics::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
@@ -1242,9 +1241,8 @@ bool QFontMetricsF::operator ==(const QFontMetricsF &other) const
The ascent of a font is the distance from the baseline to the
highest position characters extend to. In practice, some font
designers break this rule, e.g. when they put more than one accent
- on top of a character, or to accommodate an unusual character in
- an exotic language, so it is possible (though rare) that this
- value will be too small.
+ on top of a character, or to accommodate a certain character, so
+ it is possible (though rare) that this value will be too small.
\sa descent()
*/
@@ -1280,8 +1278,8 @@ qreal QFontMetricsF::capHeight() const
The descent is the distance from the base line to the lowest point
characters extend to. (Note that this is different from X, which
adds 1 pixel.) In practice, some font designers break this rule,
- e.g. to accommodate an unusual character in an exotic language, so
- it is possible (though rare) that this value will be too small.
+ e.g. to accommodate a certain character, so it is possible (though
+ rare) that this value will be too small.
\sa ascent()
*/
@@ -1697,7 +1695,9 @@ QRectF QFontMetricsF::boundingRect(QChar ch) const
Returns the bounding rectangle of the characters in the given \a text.
This is the set of pixels the text would cover if drawn when constrained
- to the bounding rectangle specified by \a rect.
+ to the bounding rectangle specified by \a rect. If \a rect is a reference
+ to a \nullptr object, e.g. when passing a default constructed QRectF, the
+ bounding rectangle will not constrain itself to the size.
The \a flags argument is the bitwise OR of the following flags:
\list
diff --git a/src/gui/text/qfontsubset.cpp b/src/gui/text/qfontsubset.cpp
index d56516fa04..75639ee525 100644
--- a/src/gui/text/qfontsubset.cpp
+++ b/src/gui/text/qfontsubset.cpp
@@ -112,24 +112,6 @@ QByteArray QFontSubset::glyphName(unsigned short unicode, bool symbol)
return buffer;
}
-QByteArray QFontSubset::glyphName(unsigned int glyph, const QVector<int> &reverseMap) const
-{
- uint glyphIndex = glyph_indices[glyph];
-
- if (glyphIndex == 0)
- return "/.notdef";
-
- QByteArray ba;
- QPdf::ByteStream s(&ba);
- if (reverseMap[glyphIndex] && reverseMap[glyphIndex] < 0x10000) {
- s << '/' << glyphName(reverseMap[glyphIndex], false);
- } else {
- s << "/gl" << (int)glyphIndex;
- }
- return ba;
-}
-
-
QByteArray QFontSubset::widthArray() const
{
Q_ASSERT(!widths.isEmpty());
diff --git a/src/gui/text/qfontsubset_p.h b/src/gui/text/qfontsubset_p.h
index e7c6053beb..5b605aac59 100644
--- a/src/gui/text/qfontsubset_p.h
+++ b/src/gui/text/qfontsubset_p.h
@@ -77,7 +77,6 @@ public:
QByteArray widthArray() const;
QByteArray createToUnicodeMap() const;
QVector<int> getReverseMap() const;
- QByteArray glyphName(unsigned int glyph, const QVector<int> &reverseMap) const;
static QByteArray glyphName(unsigned short unicode, bool symbol);
diff --git a/src/gui/text/qinputcontrol.cpp b/src/gui/text/qinputcontrol.cpp
index 3381fdb673..8c05346730 100644
--- a/src/gui/text/qinputcontrol.cpp
+++ b/src/gui/text/qinputcontrol.cpp
@@ -79,6 +79,9 @@ bool QInputControl::isAcceptableInput(const QKeyEvent *event) const
if (c.category() == QChar::Other_PrivateUse)
return true;
+ if (c.isHighSurrogate() && text.length() > 1 && text.at(1).isLowSurrogate())
+ return true;
+
if (m_type == TextEdit && c == QLatin1Char('\t'))
return true;
@@ -137,3 +140,5 @@ bool QInputControl::isCommonTextEditShortcut(const QKeyEvent *ke)
}
QT_END_NAMESPACE
+
+#include "moc_qinputcontrol_p.cpp"
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
index b4b60cbaaf..3d6b70a995 100644
--- a/src/gui/text/qrawfont.cpp
+++ b/src/gui/text/qrawfont.cpp
@@ -760,7 +760,7 @@ QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writ
QFontDef request(multiEngine->fontDef);
request.styleStrategy |= QFont::NoFontMerging;
- if (QFontEngine *engine = QFontDatabase::findFont(request, script)) {
+ if (QFontEngine *engine = QFontDatabase::findFont(request, script, true)) {
if (request.weight > QFont::Normal)
engine->fontDef.weight = request.weight;
if (request.style > QFont::StyleNormal)
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 7ee9898537..b75904e885 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -3032,10 +3032,12 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (fragmentMarkers && block.position() + block.length() == doc->docHandle()->length())
html += QLatin1String("<!--EndFragment-->");
+ QString closeTags;
+
if (pre)
html += QLatin1String("</pre>");
else if (list)
- html += QLatin1String("</li>");
+ closeTags += QLatin1String("</li>");
else {
int headingLevel = blockFormat.headingLevel();
if (headingLevel > 0 && headingLevel <= 6)
@@ -3047,9 +3049,30 @@ void QTextHtmlExporter::emitBlock(const QTextBlock &block)
if (list) {
if (list->itemNumber(block) == list->count() - 1) { // last item? close list
if (isOrderedList(list->format().style()))
- html += QLatin1String("</ol>");
+ closeTags += QLatin1String("</ol>");
else
- html += QLatin1String("</ul>");
+ closeTags += QLatin1String("</ul>");
+ }
+ const QTextBlock nextBlock = block.next();
+ // If the next block is the beginning of a new deeper nested list, then we don't
+ // want to close the current list item just yet. This should be closed when this
+ // item is fully finished
+ if (nextBlock.isValid() && nextBlock.textList() &&
+ nextBlock.textList()->itemNumber(nextBlock) == 0 &&
+ nextBlock.textList()->format().indent() > list->format().indent()) {
+ QString lastTag;
+ if (!closingTags.isEmpty() && list->itemNumber(block) == list->count() - 1)
+ lastTag = closingTags.takeLast();
+ lastTag.prepend(closeTags);
+ closingTags << lastTag;
+ } else if (list->itemNumber(block) == list->count() - 1) {
+ // If we are at the end of the list now then we can add in the closing tags for that
+ // current block
+ html += closeTags;
+ if (!closingTags.isEmpty())
+ html += closingTags.takeLast();
+ } else {
+ html += closeTags;
}
}
@@ -3476,3 +3499,5 @@ QTextDocumentPrivate *QTextDocument::docHandle() const
*/
QT_END_NAMESPACE
+
+#include "moc_qtextdocument.cpp"
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 524931ebde..c22dd95d48 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -381,8 +381,11 @@ int QTextDocumentPrivate::insert_block(int pos, uint strPos, int format, int blo
Q_ASSERT(blocks.length() == fragments.length());
QTextBlockGroup *group = qobject_cast<QTextBlockGroup *>(objectForFormat(blockFormat));
- if (group)
+ if (group) {
group->blockInserted(QTextBlock(this, b));
+ docChangeOldLength--;
+ docChangeLength--;
+ }
QTextFrame *frame = qobject_cast<QTextFrame *>(objectForFormat(formats.format(format)));
if (frame) {
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index 7f85d27ba0..9908f14ba3 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -405,6 +405,7 @@ private:
QTextCharFormat defaultCharFormat;
const QTextDocument *doc;
bool fragmentMarkers;
+ QStringList closingTags;
};
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocumentfragment.cpp b/src/gui/text/qtextdocumentfragment.cpp
index d7bc707491..2fdfcaa2d2 100644
--- a/src/gui/text/qtextdocumentfragment.cpp
+++ b/src/gui/text/qtextdocumentfragment.cpp
@@ -1296,5 +1296,6 @@ QTextDocumentFragment QTextDocumentFragment::fromHtml(const QString &html, const
return res;
}
-QT_END_NAMESPACE
#endif // QT_NO_TEXTHTMLPARSER
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index a2b3c8dc76..72267e9380 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -105,14 +105,13 @@ public:
bool sizeDirty;
bool layoutDirty;
- bool fullLayoutCompleted;
QVector<QPointer<QTextFrame> > floats;
};
QTextFrameData::QTextFrameData()
: maximumWidth(QFIXED_MAX),
- currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true), fullLayoutCompleted(false)
+ currentLayoutStruct(nullptr), sizeDirty(true), layoutDirty(true)
{
}
@@ -2124,7 +2123,7 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
{
Q_Q(const QTextDocumentLayout);
const QTextBlockFormat blockFormat = bl.blockFormat();
- const QTextCharFormat charFormat = QTextCursor(bl).charFormat();
+ const QTextCharFormat charFormat = bl.charFormat();
QFont font(charFormat.font());
if (q->paintDevice())
font = QFont(font, q->paintDevice());
@@ -2187,9 +2186,11 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
painter->setRenderHint(QPainter::Antialiasing);
+ const bool marker = bl.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker;
if (selectionFormat) {
painter->setPen(QPen(selectionFormat->foreground(), 0));
- painter->fillRect(r, selectionFormat->background());
+ if (!marker)
+ painter->fillRect(r, selectionFormat->background());
} else {
QBrush fg = charFormat.foreground();
if (fg == Qt::NoBrush)
@@ -2199,19 +2200,21 @@ void QTextDocumentLayoutPrivate::drawListItem(const QPointF &offset, QPainter *p
QBrush brush = context.palette.brush(QPalette::Text);
- bool marker = bl.blockFormat().marker() != QTextBlockFormat::MarkerType::NoMarker;
if (marker) {
int adj = fontMetrics.lineSpacing() / 6;
r.adjust(-adj, 0, -adj, 0);
+ const QRectF outer = r.adjusted(-adj, -adj, adj, adj);
+ if (selectionFormat)
+ painter->fillRect(outer, selectionFormat->background());
if (bl.blockFormat().marker() == QTextBlockFormat::MarkerType::Checked) {
- // ### Qt6: render with QStyle / PE_IndicatorCheckBox. We don't currently
+ // ### Qt7: render with QStyle / PE_IndicatorCheckBox. We don't currently
// have access to that here, because it would be a widget dependency.
painter->setPen(QPen(painter->pen().color(), 2));
painter->drawLine(r.topLeft(), r.bottomRight());
painter->drawLine(r.topRight(), r.bottomLeft());
painter->setPen(QPen(painter->pen().color(), 0));
}
- painter->drawRect(r.adjusted(-adj, -adj, adj, adj));
+ painter->drawRect(outer);
}
switch (style) {
@@ -2358,9 +2361,10 @@ QTextLayoutStruct QTextDocumentLayoutPrivate::layoutCell(QTextTable *t, const QT
floatMinWidth = qMax(floatMinWidth, cd->minimumWidth);
}
- // constraint the maximumWidth by the minimum width of the fixed size floats, to
- // keep them visible
+ // constraint the maximum/minimumWidth by the minimum width of the fixed size floats,
+ // to keep them visible
layoutStruct.maximumWidth = qMax(layoutStruct.maximumWidth, floatMinWidth);
+ layoutStruct.minimumWidth = qMax(layoutStruct.minimumWidth, floatMinWidth);
// as floats in cells get added to the table's float list but must not affect
// floats in other cells we must clear the list here.
@@ -2537,6 +2541,8 @@ recalc_minmax_widths:
for (int n = 0; n < cspan; ++n) {
const int col = i + n;
QFixed w = widthToDistribute / (cspan - n);
+ if (td->maxWidths[col] != QFIXED_MAX)
+ w = qMax(td->maxWidths[col], w);
td->maxWidths[col] = qMax(td->minWidths.at(col), w);
widthToDistribute -= td->maxWidths.at(col);
if (widthToDistribute <= 0)
@@ -2944,7 +2950,7 @@ QRectF QTextDocumentLayoutPrivate::layoutFrame(QTextFrame *f, int layoutFrom, in
QTextFrameData *fd = data(f);
QFixed newContentsWidth;
- bool fullLayout = (f == document->rootFrame() && !fd->fullLayoutCompleted);
+ bool fullLayout = false;
{
QTextFrameFormat fformat = f->frameFormat();
// set sizes of this frame from the format
@@ -3398,7 +3404,6 @@ void QTextDocumentLayoutPrivate::layoutFlow(QTextFrame::Iterator it, QTextLayout
cp.contentsWidth = layoutStruct->contentsWidth;
checkPoints.append(cp);
checkPoints.reserve(checkPoints.size());
- fd->fullLayoutCompleted = true;
} else {
currentLazyLayoutPosition = checkPoints.constLast().positionInFrame;
// #######
@@ -3810,7 +3815,6 @@ void QTextDocumentLayout::documentChanged(int from, int oldLength, int length)
d->contentHasAlignment = false;
d->currentLazyLayoutPosition = 0;
d->checkPoints.clear();
- data(d->docPrivate->rootFrame())->fullLayoutCompleted = false;
d->layoutStep();
} else {
d->ensureLayoutedByPosition(from);
diff --git a/src/gui/text/qtextdocumentwriter.cpp b/src/gui/text/qtextdocumentwriter.cpp
index 0bafa5d9ff..800b72ea9c 100644
--- a/src/gui/text/qtextdocumentwriter.cpp
+++ b/src/gui/text/qtextdocumentwriter.cpp
@@ -83,7 +83,6 @@ public:
\inmodule QtGui
\ingroup richtext-processing
- \ingroup io
To write a document, construct a QTextDocumentWriter object with either a
file name or a device object, and specify the document format to be
@@ -249,9 +248,11 @@ QString QTextDocumentWriter::fileName () const
*/
bool QTextDocumentWriter::write(const QTextDocument *document)
{
- QByteArray suffix;
+ if (!d->device)
+ return false;
- if (d->device && d->format.isEmpty()) {
+ QByteArray suffix;
+ if (d->format.isEmpty()) {
// if there's no format, see if device is a file, and if so, find
// the file suffix
if (QFile *file = qobject_cast<QFile *>(d->device))
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index b7459bf826..6336fadf74 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -258,7 +258,7 @@ struct QBidiAlgorithm {
for (int i = 0; i < length; ++i) {
int pos = i;
uint uc = text[i].unicode();
- if (QChar::isHighSurrogate(uc) && i < length - 1) {
+ if (QChar::isHighSurrogate(uc) && i < length - 1 && text[i + 1].isLowSurrogate()) {
++i;
analysis[i].bidiDirection = QChar::DirNSM;
uc = QChar::surrogateToUcs4(ushort(uc), text[i].unicode());
@@ -1373,9 +1373,15 @@ static void applyVisibilityRules(ushort ucs, QGlyphLayout *glyphs, uint glyphPos
if (!fontEngine->symbol) {
// U+00AD [SOFT HYPHEN] is a default ignorable codepoint,
// so we replace its glyph and metrics with ones for
- // U+002D [HYPHEN-MINUS] and make it visible if it appears at line-break
+ // U+002D [HYPHEN-MINUS] or U+2010 [HYPHEN] and make
+ // it visible if it appears at line-break
const uint engineIndex = glyphs->glyphs[glyphPosition] & 0xff000000;
- glyphs->glyphs[glyphPosition] = fontEngine->glyphIndex('-');
+ glyph_t glyph = fontEngine->glyphIndex(0x002d);
+ if (glyph == 0)
+ glyph = fontEngine->glyphIndex(0x2010);
+ if (glyph == 0)
+ glyph = fontEngine->glyphIndex(0x00ad);
+ glyphs->glyphs[glyphPosition] = glyph;
if (Q_LIKELY(glyphs->glyphs[glyphPosition] != 0)) {
glyphs->glyphs[glyphPosition] |= engineIndex;
QGlyphLayout tmp = glyphs->mid(glyphPosition, 1);
@@ -1547,12 +1553,27 @@ void QTextEngine::shapeText(int item) const
} else {
si.num_glyphs = shapeTextWithHarfbuzz(si, string, itemLength, fontEngine, itemBoundaries, kerningEnabled);
}
+
if (Q_UNLIKELY(si.num_glyphs == 0)) {
- Q_UNREACHABLE(); // ### report shaping errors somehow
+ if (Q_UNLIKELY(!ensureSpace(si.glyph_data_offset + 1))) {
+ qWarning() << "Unable to allocate space for place-holder glyph";
+ return;
+ }
+
+ si.num_glyphs = 1;
+
+ // Overwrite with 0 token to indicate failure
+ QGlyphLayout g = availableGlyphs(&si);
+ g.glyphs[0] = 0;
+ g.attributes[0].clusterStart = true;
+
+ ushort *log_clusters = logClusters(&si);
+ for (int i = 0; i < itemLength; ++i)
+ log_clusters[i] = 0;
+
return;
}
-
layoutData->used += si.num_glyphs;
QGlyphLayout glyphs = shapedGlyphs(&si);
@@ -2164,20 +2185,35 @@ void QTextEngine::itemize() const
QTextDocumentPrivate::FragmentIterator end = p->find(block.position() + block.length() - 1); // -1 to omit the block separator char
int format = it.value()->format;
+ int preeditPosition = s ? s->preeditPosition : INT_MAX;
int prevPosition = 0;
int position = prevPosition;
while (1) {
const QTextFragmentData * const frag = it.value();
if (it == end || format != frag->format) {
- if (s && position >= s->preeditPosition) {
+ if (s && position >= preeditPosition) {
position += s->preeditText.length();
- s = nullptr;
+ preeditPosition = INT_MAX;
}
Q_ASSERT(position <= length);
QFont::Capitalization capitalization =
formatCollection()->charFormat(format).hasProperty(QTextFormat::FontCapitalization)
? formatCollection()->charFormat(format).fontCapitalization()
: formatCollection()->defaultFont().capitalization();
+ if (s) {
+ for (const auto &range : qAsConst(s->formats)) {
+ if (range.start + range.length <= prevPosition || range.start >= position)
+ continue;
+ if (range.format.hasProperty(QTextFormat::FontCapitalization)) {
+ if (range.start > prevPosition)
+ itemizer.generate(prevPosition, range.start - prevPosition, capitalization);
+ int newStart = std::max(prevPosition, range.start);
+ int newEnd = std::min(position, range.start + range.length);
+ itemizer.generate(newStart, newEnd - newStart, range.format.fontCapitalization());
+ prevPosition = newEnd;
+ }
+ }
+ }
itemizer.generate(prevPosition, position - prevPosition, capitalization);
if (it == end) {
if (position < length)
diff --git a/src/gui/text/qtextformat.cpp b/src/gui/text/qtextformat.cpp
index 4e5ee41e24..560a0a1c5f 100644
--- a/src/gui/text/qtextformat.cpp
+++ b/src/gui/text/qtextformat.cpp
@@ -3929,3 +3929,5 @@ QDebug operator<<(QDebug dbg, const QTextFormat &f)
#endif
QT_END_NAMESPACE
+
+#include "moc_qtextformat.cpp"
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp
index 8b58f69770..5458e646c5 100644
--- a/src/gui/text/qtexthtmlparser.cpp
+++ b/src/gui/text/qtexthtmlparser.cpp
@@ -784,8 +784,8 @@ void QTextHtmlParser::parseCloseTag()
void QTextHtmlParser::parseExclamationTag()
{
++pos;
- if (hasPrefix(QLatin1Char('-'),1) && hasPrefix(QLatin1Char('-'),2)) {
- pos += 3;
+ if (hasPrefix(QLatin1Char('-')) && hasPrefix(QLatin1Char('-'), 1)) {
+ pos += 2;
// eat comments
int end = txt.indexOf(QLatin1String("-->"), pos);
pos = (end >= 0 ? end + 3 : len);
@@ -880,7 +880,7 @@ QString QTextHtmlParser::parseWord()
while (pos < len) {
QChar c = txt.at(pos++);
if (c == QLatin1Char('>')
- || (c == QLatin1Char('/') && hasPrefix(QLatin1Char('>'), 1))
+ || (c == QLatin1Char('/') && hasPrefix(QLatin1Char('>')))
|| c == QLatin1Char('<')
|| c == QLatin1Char('=')
|| c.isSpace()) {
@@ -1677,7 +1677,7 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
node->tableCellRowSpan = qMax(1, node->tableCellRowSpan);
} else if (key == QLatin1String("colspan")) {
if (setIntAttribute(&node->tableCellColSpan, value))
- node->tableCellColSpan = qMax(1, node->tableCellColSpan);
+ node->tableCellColSpan = qBound(1, node->tableCellColSpan, 20480);
}
break;
case Html_table:
diff --git a/src/gui/text/qtexthtmlparser_p.h b/src/gui/text/qtexthtmlparser_p.h
index 31f558709f..e5622afe9d 100644
--- a/src/gui/text/qtexthtmlparser_p.h
+++ b/src/gui/text/qtexthtmlparser_p.h
@@ -323,7 +323,9 @@ protected:
void applyAttributes(const QStringList &attributes);
void eatSpace();
inline bool hasPrefix(QChar c, int lookahead = 0) const
- {return pos + lookahead < len && txt.at(pos) == c; }
+ {
+ return pos + lookahead < len && txt.at(pos + lookahead) == c;
+ }
int margin(int i, int mar) const;
bool nodeIsChildOf(int i, QTextHTMLElements id) const;
diff --git a/src/gui/text/qtextimagehandler.cpp b/src/gui/text/qtextimagehandler.cpp
index 0d87a2135d..e650984c63 100644
--- a/src/gui/text/qtextimagehandler.cpp
+++ b/src/gui/text/qtextimagehandler.cpp
@@ -53,40 +53,21 @@ QT_BEGIN_NAMESPACE
extern QString qt_findAtNxFile(const QString &baseFileName, qreal targetDevicePixelRatio,
qreal *sourceDevicePixelRatio);
-static QString resolveFileName(QString fileName, QUrl *url, qreal targetDevicePixelRatio,
- qreal *sourceDevicePixelRatio)
-{
- // We might use the fileName for loading if url loading fails
- // try to make sure it is a valid file path.
- // Also, QFile{Info}::exists works only on filepaths (not urls)
-
- if (url->isValid()) {
- if (url->scheme() == QLatin1String("qrc")) {
- fileName = fileName.right(fileName.length() - 3);
- }
- else if (url->scheme() == QLatin1String("file")) {
- fileName = url->toLocalFile();
- }
- }
- if (targetDevicePixelRatio <= 1.0)
- return fileName;
-
- // try to find a Nx version
- return qt_findAtNxFile(fileName, targetDevicePixelRatio, sourceDevicePixelRatio);
+static inline QUrl fromLocalfileOrResources(QString path)
+{
+ if (path.startsWith(QLatin1String(":/"))) // auto-detect resources and convert them to url
+ path.prepend(QLatin1String("qrc"));
+ return QUrl(path);
}
-
static QPixmap getPixmap(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0)
{
- QPixmap pm;
-
- QString name = format.name();
- if (name.startsWith(QLatin1String(":/"))) // auto-detect resources and convert them to url
- name.prepend(QLatin1String("qrc"));
- QUrl url = QUrl(name);
qreal sourcePixelRatio = 1.0;
- name = resolveFileName(name, &url, devicePixelRatio, &sourcePixelRatio);
+ const QString name = qt_findAtNxFile(format.name(), devicePixelRatio, &sourcePixelRatio);
+ const QUrl url = fromLocalfileOrResources(name);
+
+ QPixmap pm;
const QVariant data = doc->resource(QTextDocument::ImageResource, url);
if (data.userType() == QMetaType::QPixmap || data.userType() == QMetaType::QImage) {
pm = qvariant_cast<QPixmap>(data);
@@ -161,14 +142,11 @@ static QSize getPixmapSize(QTextDocument *doc, const QTextImageFormat &format)
static QImage getImage(QTextDocument *doc, const QTextImageFormat &format, const qreal devicePixelRatio = 1.0)
{
- QImage image;
-
- QString name = format.name();
- if (name.startsWith(QLatin1String(":/"))) // auto-detect resources
- name.prepend(QLatin1String("qrc"));
- QUrl url = QUrl(name);
qreal sourcePixelRatio = 1.0;
- name = resolveFileName(name, &url, devicePixelRatio, &sourcePixelRatio);
+ const QString name = qt_findAtNxFile(format.name(), devicePixelRatio, &sourcePixelRatio);
+ const QUrl url = fromLocalfileOrResources(name);
+
+ QImage image;
const QVariant data = doc->resource(QTextDocument::ImageResource, url);
if (data.userType() == QMetaType::QImage) {
image = qvariant_cast<QImage>(data);
@@ -266,3 +244,5 @@ void QTextImageHandler::drawObject(QPainter *p, const QRectF &rect, QTextDocumen
}
QT_END_NAMESPACE
+
+#include "moc_qtextimagehandler_p.cpp"
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index b2f12ef1ce..7e1fb822fc 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -850,6 +850,10 @@ QTextLine QTextLayout::createLine()
int l = d->lines.size();
if (l && d->lines.at(l-1).length < 0) {
QTextLine(l-1, d).setNumColumns(INT_MAX);
+ if (d->maxWidth > QFIXED_MAX / 2) {
+ qWarning("QTextLayout: text too long, truncated.");
+ return QTextLine();
+ }
}
int from = l > 0 ? d->lines.at(l-1).from + d->lines.at(l-1).length + d->lines.at(l-1).trailingSpaces : 0;
int strlen = d->layoutData->string.length();
@@ -1169,10 +1173,17 @@ void QTextLayout::draw(QPainter *p, const QPointF &pos, const QVector<FormatRang
QRectF fullLineRect(tl.rect());
fullLineRect.translate(position);
fullLineRect.setRight(QFIXED_MAX);
- if (!selectionEndInLine)
- region.addRect(clipIfValid(QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
- if (!selectionStartInLine)
- region.addRect(clipIfValid(QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
+
+ const bool rightToLeft = d->isRightToLeft();
+
+ if (!selectionEndInLine) {
+ region.addRect(clipIfValid(rightToLeft ? QRectF(fullLineRect.topLeft(), lineRect.bottomLeft())
+ : QRectF(lineRect.topRight(), fullLineRect.bottomRight()), clip));
+ }
+ if (!selectionStartInLine) {
+ region.addRect(clipIfValid(rightToLeft ? QRectF(lineRect.topRight(), fullLineRect.bottomRight())
+ : QRectF(fullLineRect.topLeft(), lineRect.bottomLeft()), clip));
+ }
} else if (!selectionEndInLine
&& isLastLineInBlock
&&!(d->option.flags() & QTextOption::ShowLineAndParagraphSeparators)) {
@@ -1325,13 +1336,13 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
bool rightToLeft = d->isRightToLeft();
if (itm >= 0) {
const QScriptItem &si = d->layoutData->items.at(itm);
- if (si.ascent > 0)
+ if (si.ascent >= 0)
base = si.ascent;
- if (si.descent > 0)
+ if (si.descent >= 0)
descent = si.descent;
rightToLeft = si.analysis.bidiLevel % 2;
}
- qreal y = position.y() + (sl.y + sl.base() - base).toReal();
+ qreal y = position.y() + (sl.y + sl.base() + sl.descent - base - descent).toReal();
bool toggleAntialiasing = !(p->renderHints() & QPainter::Antialiasing)
&& (p->transform().type() > QTransform::TxTranslate);
if (toggleAntialiasing)
@@ -1339,7 +1350,20 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
QPainter::CompositionMode origCompositionMode = p->compositionMode();
if (p->paintEngine()->hasFeature(QPaintEngine::RasterOpModes))
p->setCompositionMode(QPainter::RasterOp_NotDestination);
- p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush());
+ const QTransform &deviceTransform = p->deviceTransform();
+ const qreal xScale = deviceTransform.m11();
+ if (deviceTransform.type() != QTransform::TxScale || std::trunc(xScale) == xScale) {
+ p->fillRect(QRectF(x, y, qreal(width), (base + descent).toReal()), p->pen().brush());
+ } else {
+ // Ensure consistently rendered cursor width under fractional scaling
+ const QPen origPen = p->pen();
+ QPen pen(origPen.brush(), qRound(width * xScale), Qt::SolidLine, Qt::FlatCap);
+ pen.setCosmetic(true);
+ const qreal center = x + qreal(width) / 2;
+ p->setPen(pen);
+ p->drawLine(QPointF(center, y), QPointF(center, y + (base + descent).toReal()));
+ p->setPen(origPen);
+ }
p->setCompositionMode(origCompositionMode);
if (toggleAntialiasing)
p->setRenderHint(QPainter::Antialiasing, false);
@@ -1976,7 +2000,8 @@ void QTextLine::layout_helper(int maxGlyphs)
if (lbh.currentPosition >= eng->layoutData->string.length()
|| isBreakableSpace
- || attributes[lbh.currentPosition].lineBreak) {
+ || attributes[lbh.currentPosition].lineBreak
+ || lbh.tmpData.textWidth >= QFIXED_MAX) {
sb_or_ws = true;
break;
} else if (attributes[lbh.currentPosition].graphemeBoundary) {
@@ -2393,14 +2418,18 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
// when we're breaking a RTL script item, since the expected position passed into
// getGlyphPositions() is the left-most edge of the left-most glyph in an RTL run.
if (relativeFrom != (iterator.itemStart - si.position) && !rtl) {
- for (int i=itemGlyphsStart; i<glyphsStart; ++i) {
- QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
- pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ for (int i = itemGlyphsStart; i < glyphsStart; ++i) {
+ if (!glyphLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+ 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.rx() += (glyphLayout.advances[i] + justification).toReal();
+ for (int i = itemGlyphsEnd; i > glyphsEnd; --i) {
+ if (!glyphLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(glyphLayout.justifications[i].space_18d6);
+ pos.rx() += (glyphLayout.advances[i] + justification).toReal();
+ }
}
}
@@ -2449,8 +2478,10 @@ QList<QGlyphRun> QTextLine::glyphRuns(int from, int length) const
relativeFrom + si.position,
relativeTo - relativeFrom + 1));
for (int i = 0; i < subLayout.numGlyphs; ++i) {
- QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6);
- pos.rx() += (subLayout.advances[i] + justification).toReal();
+ if (!subLayout.attributes[i].dontPrint) {
+ QFixed justification = QFixed::fromFixed(subLayout.justifications[i].space_18d6);
+ pos.rx() += (subLayout.advances[i] + justification).toReal();
+ }
}
if (rtl)
@@ -2535,6 +2566,9 @@ void QTextLine::draw(QPainter *p, const QPointF &pos, const QTextLayout::FormatR
return;
}
+ static QRectF maxFixedRect(QPointF(-QFIXED_MAX, -QFIXED_MAX), QPointF(QFIXED_MAX, QFIXED_MAX));
+ if (!maxFixedRect.contains(pos))
+ return;
QTextLineItemIterator iterator(eng, index, pos, selection);
QFixed lineBase = line.base();
diff --git a/src/gui/text/qtextlist.cpp b/src/gui/text/qtextlist.cpp
index 5857afa048..523c22ff87 100644
--- a/src/gui/text/qtextlist.cpp
+++ b/src/gui/text/qtextlist.cpp
@@ -320,3 +320,5 @@ void QTextList::add(const QTextBlock &block)
}
QT_END_NAMESPACE
+
+#include "moc_qtextlist.cpp"
diff --git a/src/gui/text/qtextmarkdownimporter.cpp b/src/gui/text/qtextmarkdownimporter.cpp
index e0d16d2d2a..7296a6fe41 100644
--- a/src/gui/text/qtextmarkdownimporter.cpp
+++ b/src/gui/text/qtextmarkdownimporter.cpp
@@ -418,6 +418,7 @@ int QTextMarkdownImporter::cbEnterSpan(int spanType, void *det)
}
case MD_SPAN_CODE:
charFmt.setFont(m_monoFont);
+ charFmt.setFontFixedPitch(true);
break;
case MD_SPAN_DEL:
charFmt.setFontStrikeOut(true);
@@ -607,6 +608,9 @@ void QTextMarkdownImporter::insertBlock()
if (m_doc->isEmpty()) {
m_cursor->setBlockFormat(blockFormat);
m_cursor->setCharFormat(charFormat);
+ } else if (m_listItem) {
+ m_cursor->insertBlock(blockFormat, QTextCharFormat());
+ m_cursor->setCharFormat(charFormat);
} else {
m_cursor->insertBlock(blockFormat, charFormat);
}
diff --git a/src/gui/text/qtextmarkdownwriter.cpp b/src/gui/text/qtextmarkdownwriter.cpp
index ae63fcb4dd..3b4d794c1a 100644
--- a/src/gui/text/qtextmarkdownwriter.cpp
+++ b/src/gui/text/qtextmarkdownwriter.cpp
@@ -531,7 +531,7 @@ int QTextMarkdownWriter::writeBlock(const QTextBlock &block, bool wrap, bool ign
col += s.length();
} else {
QFontInfo fontInfo(fmt.font());
- bool monoFrag = fontInfo.fixedPitch();
+ bool monoFrag = fontInfo.fixedPitch() || fmt.fontFixedPitch();
QString markers;
if (!ignoreFormat) {
if (monoFrag != mono && !m_indentedCodeBlock && !m_fencedCodeBlock) {
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index 77dcae0dc8..2d307ab30e 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -1863,3 +1863,5 @@ QString QTextFragment::text() const
}
QT_END_NAMESPACE
+
+#include "moc_qtextobject.cpp"
diff --git a/src/gui/text/qtextodfwriter.cpp b/src/gui/text/qtextodfwriter.cpp
index 155ec43c50..b3ec43702c 100644
--- a/src/gui/text/qtextodfwriter.cpp
+++ b/src/gui/text/qtextodfwriter.cpp
@@ -455,7 +455,7 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF
name.prepend(QLatin1String("qrc"));
QUrl url = QUrl(name);
const QVariant variant = m_document->resource(QTextDocument::ImageResource, url);
- if (variant.userType() == QMetaType::QImage) {
+ if (variant.userType() == QMetaType::QPixmap || variant.userType() == QMetaType::QImage) {
image = qvariant_cast<QImage>(variant);
} else if (variant.userType() == QMetaType::QByteArray) {
data = variant.toByteArray();
@@ -476,7 +476,7 @@ void QTextOdfWriter::writeInlineCharacter(QXmlStreamWriter &writer, const QTextF
QBuffer imageBytes;
int imgQuality = imageFormat.quality();
- if (imgQuality >= 100 || imgQuality < 0 || image.hasAlphaChannel()) {
+ if (imgQuality >= 100 || imgQuality <= 0 || image.hasAlphaChannel()) {
QImageWriter imageWriter(&imageBytes, "png");
imageWriter.write(image);
diff --git a/src/gui/text/qtexttable.cpp b/src/gui/text/qtexttable.cpp
index 39f26d5d42..0b656ce8a1 100644
--- a/src/gui/text/qtexttable.cpp
+++ b/src/gui/text/qtexttable.cpp
@@ -318,13 +318,6 @@ QTextFrame::iterator QTextTableCell::end() const
Destroys the table cell.
*/
-QTextTablePrivate::~QTextTablePrivate()
-{
- if (grid)
- free(grid);
-}
-
-
QTextTable *QTextTablePrivate::createTable(QTextDocumentPrivate *pieceTable, int pos, int rows, int cols, const QTextTableFormat &tableFormat)
{
QTextTableFormat fmt = tableFormat;
@@ -446,8 +439,7 @@ void QTextTablePrivate::update() const
nRows = (cells.size() + nCols-1)/nCols;
// qDebug(">>>> QTextTablePrivate::update, nRows=%d, nCols=%d", nRows, nCols);
- grid = q_check_ptr((int *)realloc(grid, nRows*nCols*sizeof(int)));
- memset(grid, 0, nRows*nCols*sizeof(int));
+ grid.assign(nRows * nCols, 0);
QTextDocumentPrivate *p = pieceTable;
QTextFormatCollection *c = p->formatCollection();
@@ -470,8 +462,7 @@ void QTextTablePrivate::update() const
cellIndices[i] = cell;
if (r + rowspan > nRows) {
- grid = q_check_ptr((int *)realloc(grid, sizeof(int)*(r + rowspan)*nCols));
- memset(grid + (nRows*nCols), 0, sizeof(int)*(r+rowspan-nRows)*nCols);
+ grid.resize((r + rowspan) * nCols, 0);
nRows = r + rowspan;
}
@@ -1344,3 +1335,5 @@ void QTextTable::setFormat(const QTextTableFormat &format)
*/
QT_END_NAMESPACE
+
+#include "moc_qtexttable.cpp"
diff --git a/src/gui/text/qtexttable_p.h b/src/gui/text/qtexttable_p.h
index 5c05611009..784c8824ba 100644
--- a/src/gui/text/qtexttable_p.h
+++ b/src/gui/text/qtexttable_p.h
@@ -55,14 +55,15 @@
#include "private/qtextobject_p.h"
#include "private/qtextdocument_p.h"
+#include <vector>
+
QT_BEGIN_NAMESPACE
class QTextTablePrivate : public QTextFramePrivate
{
Q_DECLARE_PUBLIC(QTextTable)
public:
- QTextTablePrivate(QTextDocument *document) : QTextFramePrivate(document), grid(nullptr), nRows(0), nCols(0), dirty(true), blockFragmentUpdates(false) {}
- ~QTextTablePrivate();
+ QTextTablePrivate(QTextDocument *document) : QTextFramePrivate(document), nRows(0), nCols(0), dirty(true), blockFragmentUpdates(false) {}
static QTextTable *createTable(QTextDocumentPrivate *, int pos, int rows, int cols, const QTextTableFormat &tableFormat);
void fragmentAdded(QChar type, uint fragment) override;
@@ -76,7 +77,7 @@ public:
// symmetric to cells array and maps to indecs in grid,
// used for fast-lookup for row/column by fragment
mutable QVector<int> cellIndices;
- mutable int *grid;
+ mutable std::vector<int> grid;
mutable int nRows;
mutable int nCols;
mutable bool dirty;
diff --git a/src/gui/text/qzip.cpp b/src/gui/text/qzip.cpp
index 80c0f122e8..feab5b85b9 100644
--- a/src/gui/text/qzip.cpp
+++ b/src/gui/text/qzip.cpp
@@ -1024,13 +1024,33 @@ bool QZipReader::extractAll(const QString &destinationDir) const
// create directories first
const QVector<FileInfo> allFiles = fileInfoList();
+ bool foundDirs = false;
+ bool hasDirs = false;
for (const FileInfo &fi : allFiles) {
const QString absPath = destinationDir + QDir::separator() + fi.filePath;
if (fi.isDir) {
+ foundDirs = true;
if (!baseDir.mkpath(fi.filePath))
return false;
if (!QFile::setPermissions(absPath, fi.permissions))
return false;
+ } else if (!hasDirs && fi.filePath.contains(u"/")) {
+ // filePath does not have leading or trailing '/', so if we find
+ // one, than the file path contains directories.
+ hasDirs = true;
+ }
+ }
+
+ // Some zip archives can be broken in the sense that they do not report
+ // separate entries for directories, only for files. In this case we
+ // need to recreate directory structure based on the file paths.
+ if (hasDirs && !foundDirs) {
+ for (const FileInfo &fi : allFiles) {
+ const auto dirPath = fi.filePath.left(fi.filePath.lastIndexOf(u"/"));
+ if (!baseDir.mkpath(dirPath))
+ return false;
+ // We will leave the directory permissions default in this case,
+ // because setting dir permissions based on file is incorrect
}
}