diff options
Diffstat (limited to 'src/gui/text/qtexthtmlparser.cpp')
-rw-r--r-- | src/gui/text/qtexthtmlparser.cpp | 227 |
1 files changed, 169 insertions, 58 deletions
diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index ded2dd185a..95f882be22 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -413,17 +413,17 @@ static const QTextHtmlElement elements[Html_NumElements]= { { "var", Html_var, QTextHtmlElement::DisplayInline }, }; -static bool operator<(const QString &str, const QTextHtmlElement &e) +static bool operator<(QStringView str, const QTextHtmlElement &e) { return str < QLatin1StringView(e.name); } -static bool operator<(const QTextHtmlElement &e, const QString &str) +static bool operator<(const QTextHtmlElement &e, QStringView str) { return QLatin1StringView(e.name) < str; } -static const QTextHtmlElement *lookupElementHelper(const QString &element) +static const QTextHtmlElement *lookupElementHelper(QStringView element) { const QTextHtmlElement *start = &elements[0]; const QTextHtmlElement *end = &elements[Html_NumElements]; @@ -433,7 +433,7 @@ static const QTextHtmlElement *lookupElementHelper(const QString &element) return e; } -int QTextHtmlParser::lookupElement(const QString &element) +int QTextHtmlParser::lookupElement(QStringView element) { const QTextHtmlElement *e = lookupElementHelper(element); if (!e) @@ -488,7 +488,7 @@ QTextHtmlParserNode *QTextHtmlParser::newNode(int parent) bool reuseLastNode = true; - if (nodes.count() == 1) { + if (nodes.size() == 1) { reuseLastNode = false; } else if (lastNode->tag.isEmpty()) { @@ -496,7 +496,7 @@ QTextHtmlParserNode *QTextHtmlParser::newNode(int parent) reuseLastNode = true; } else { // last node is a text node (empty tag) with some text - if (lastNode->text.length() == 1 && lastNode->text.at(0).isSpace()) { + if (lastNode->text.size() == 1 && lastNode->text.at(0).isSpace()) { int lastSibling = count() - 2; while (lastSibling @@ -543,7 +543,7 @@ void QTextHtmlParser::parse(const QString &text, const QTextDocument *_resourceP nodes.append(new QTextHtmlParserNode); txt = text; pos = 0; - len = txt.length(); + len = txt.size(); textEditMode = false; resourceProvider = _resourceProvider; parse(); @@ -672,7 +672,7 @@ void QTextHtmlParser::parseTag() resolveNode(); #ifndef QT_NO_CSSPARSER - const int nodeIndex = nodes.count() - 1; // this new node is always the last + const int nodeIndex = nodes.size() - 1; // this new node is always the last node->applyCssDeclarations(declarationsForNode(nodeIndex), resourceProvider); #endif applyAttributes(node->attributes); @@ -771,7 +771,7 @@ QString QTextHtmlParser::parseEntity(QStringView entity) if (!resolved.isNull()) return QString(resolved); - if (entity.length() > 1 && entity.at(0) == u'#') { + if (entity.size() > 1 && entity.at(0) == u'#') { entity = entity.mid(1); // removing leading # int base = 10; @@ -838,7 +838,7 @@ QString QTextHtmlParser::parseWord() while (pos < len) { QChar c = txt.at(pos++); // Allow for escaped single quotes as they may be part of the string - if (c == u'\'' && (txt.length() > 1 && txt.at(pos - 2) != u'\\')) + if (c == u'\'' && (txt.size() > 1 && txt.at(pos - 2) != u'\\')) break; else word += c; @@ -876,21 +876,21 @@ QTextHtmlParserNode *QTextHtmlParser::resolveParent() n = at(n).parent; if (!n) { - nodes.insert(nodes.count() - 1, new QTextHtmlParserNode); - nodes.insert(nodes.count() - 1, new QTextHtmlParserNode); + nodes.insert(nodes.size() - 1, new QTextHtmlParserNode); + nodes.insert(nodes.size() - 1, new QTextHtmlParserNode); - QTextHtmlParserNode *table = nodes[nodes.count() - 3]; + QTextHtmlParserNode *table = nodes[nodes.size() - 3]; table->parent = p; table->id = Html_table; table->tag = "table"_L1; - table->children.append(nodes.count() - 2); // add row as child + table->children.append(nodes.size() - 2); // add row as child - QTextHtmlParserNode *row = nodes[nodes.count() - 2]; - row->parent = nodes.count() - 3; // table as parent + QTextHtmlParserNode *row = nodes[nodes.size() - 2]; + row->parent = nodes.size() - 3; // table as parent row->id = Html_tr; row->tag = "tr"_L1; - p = nodes.count() - 2; + p = nodes.size() - 2; node = nodes.last(); // re-initialize pointer } } @@ -901,12 +901,12 @@ QTextHtmlParserNode *QTextHtmlParser::resolveParent() n = at(n).parent; if (!n) { - nodes.insert(nodes.count() - 1, new QTextHtmlParserNode); - QTextHtmlParserNode *table = nodes[nodes.count() - 2]; + nodes.insert(nodes.size() - 1, new QTextHtmlParserNode); + QTextHtmlParserNode *table = nodes[nodes.size() - 2]; table->parent = p; table->id = Html_table; table->tag = "table"_L1; - p = nodes.count() - 2; + p = nodes.size() - 2; node = nodes.last(); // re-initialize pointer } } @@ -954,7 +954,7 @@ QTextHtmlParserNode *QTextHtmlParser::resolveParent() node->parent = p; // makes it easier to traverse the tree, later - nodes[p]->children.append(nodes.count() - 1); + nodes[p]->children.append(nodes.size() - 1); return node; } @@ -1029,7 +1029,7 @@ void QTextHtmlParserNode::initializeProperties(const QTextHtmlParserNode *parent // set element specific attributes switch (id) { case Html_a: - for (int i = 0; i < attributes.count(); i += 2) { + for (int i = 0; i < attributes.size(); i += 2) { const QString key = attributes.at(i); if (key.compare("href"_L1, Qt::CaseInsensitive) == 0 && !attributes.at(i + 1).isEmpty()) { @@ -1117,7 +1117,7 @@ void QTextHtmlParserNode::initializeProperties(const QTextHtmlParserNode *parent #ifndef QT_NO_CSSPARSER void QTextHtmlParserNode::setListStyle(const QList<QCss::Value> &cssValues) { - for (int i = 0; i < cssValues.count(); ++i) { + for (int i = 0; i < cssValues.size(); ++i) { if (cssValues.at(i).type == QCss::Value::KnownIdentifier) { switch (static_cast<QCss::KnownValue>(cssValues.at(i).variant.toInt())) { case QCss::Value_None: hasOwnListStyle = true; listStyle = QTextListFormat::ListStyleUndefined; break; @@ -1181,7 +1181,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d QCss::ValueExtractor extractor(declarations); extractor.extractBox(margin, padding); - if (id == Html_td || id == Html_th) { + auto getBorderValues = [&extractor](qreal *borderWidth, QBrush *borderBrush, QTextFrameFormat::BorderStyle *borderStyles) { QCss::BorderStyle cssStyles[4]; int cssBorder[4]; QSize cssRadii[4]; // unused @@ -1193,23 +1193,33 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d // QCss::BorderWidth parsing below which expects a single value // will not work as expected - which in this case does not matter // because tableBorder is not relevant for cells. - extractor.extractBorder(cssBorder, tableCellBorderBrush, cssStyles, cssRadii); + bool hit = extractor.extractBorder(cssBorder, borderBrush, cssStyles, cssRadii); for (int i = 0; i < 4; ++i) { - tableCellBorderStyle[i] = toQTextFrameFormat(cssStyles[i]); - tableCellBorder[i] = static_cast<qreal>(cssBorder[i]); + borderStyles[i] = toQTextFrameFormat(cssStyles[i]); + borderWidth[i] = static_cast<qreal>(cssBorder[i]); } - } + return hit; + }; + + if (id == Html_td || id == Html_th) + getBorderValues(tableCellBorder, tableCellBorderBrush, tableCellBorderStyle); - for (int i = 0; i < declarations.count(); ++i) { + for (int i = 0; i < declarations.size(); ++i) { const QCss::Declaration &decl = declarations.at(i); if (decl.d->values.isEmpty()) continue; QCss::KnownValue identifier = QCss::UnknownValue; - if (decl.d->values.first().type == QCss::Value::KnownIdentifier) - identifier = static_cast<QCss::KnownValue>(decl.d->values.first().variant.toInt()); + if (decl.d->values.constFirst().type == QCss::Value::KnownIdentifier) + identifier = static_cast<QCss::KnownValue>(decl.d->values.constFirst().variant.toInt()); switch (decl.d->propertyId) { - case QCss::BorderColor: borderBrush = QBrush(decl.colorValue()); break; + case QCss::BorderColor: { + QBrush bordersBrush[4]; + decl.brushValues(bordersBrush); + if (bordersBrush[0].color().isValid()) + borderBrush = bordersBrush[0]; + break; + } case QCss::BorderStyles: if (decl.styleValue() != QCss::BorderStyle_Unknown && decl.styleValue() != QCss::BorderStyle_Native) borderStyle = static_cast<QTextFrameFormat::BorderStyle>(decl.styleValue() - 1); @@ -1220,6 +1230,19 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d tableBorder = borders[0]; } break; + case QCss::Border: { + qreal tblBorder[4]; + QBrush tblBorderBrush[4]; + QTextFrameFormat::BorderStyle tblBorderStyle[4]; + if (getBorderValues(tblBorder, tblBorderBrush, tblBorderStyle)) { + tableBorder = tblBorder[0]; + if (tblBorderBrush[0].color().isValid()) + borderBrush = tblBorderBrush[0]; + if (tblBorderStyle[0] != static_cast<QTextFrameFormat::BorderStyle>(-1)) + borderStyle = tblBorderStyle[0]; + } + } + break; case QCss::BorderCollapse: borderCollapse = decl.borderCollapseValue(); break; @@ -1233,10 +1256,10 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d } break; case QCss::QtBlockIndent: - blockFormat.setIndent(decl.d->values.first().variant.toInt()); + blockFormat.setIndent(decl.d->values.constFirst().variant.toInt()); break; case QCss::QtLineHeightType: { - QString lineHeightTypeName = decl.d->values.first().variant.toString(); + QString lineHeightTypeName = decl.d->values.constFirst().variant.toString(); QTextBlockFormat::LineHeightTypes lineHeightType; if (lineHeightTypeName.compare("proportional"_L1, Qt::CaseInsensitive) == 0) lineHeightType = QTextBlockFormat::ProportionalHeight; @@ -1265,7 +1288,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d lineHeightType = QTextBlockFormat::MinimumHeight; } else { bool ok; - QCss::Value cssValue = decl.d->values.first(); + QCss::Value cssValue = decl.d->values.constFirst(); QString value = cssValue.toString(); lineHeight = value.toDouble(&ok); if (ok) { @@ -1297,19 +1320,19 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d hasCssListIndent = true; break; case QCss::QtParagraphType: - if (decl.d->values.first().variant.toString().compare("empty"_L1, Qt::CaseInsensitive) == 0) + if (decl.d->values.constFirst().variant.toString().compare("empty"_L1, Qt::CaseInsensitive) == 0) isEmptyParagraph = true; break; case QCss::QtTableType: - if (decl.d->values.first().variant.toString().compare("frame"_L1, Qt::CaseInsensitive) == 0) + if (decl.d->values.constFirst().variant.toString().compare("frame"_L1, Qt::CaseInsensitive) == 0) isTextFrame = true; - else if (decl.d->values.first().variant.toString().compare("root"_L1, Qt::CaseInsensitive) == 0) { + else if (decl.d->values.constFirst().variant.toString().compare("root"_L1, Qt::CaseInsensitive) == 0) { isTextFrame = true; isRootFrame = true; } break; case QCss::QtUserState: - userState = decl.d->values.first().variant.toInt(); + userState = decl.d->values.constFirst().variant.toInt(); break; case QCss::Whitespace: switch (identifier) { @@ -1363,10 +1386,10 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d setListStyle(decl.d->values); break; case QCss::QtListNumberPrefix: - textListNumberPrefix = decl.d->values.first().variant.toString(); + textListNumberPrefix = decl.d->values.constFirst().variant.toString(); break; case QCss::QtListNumberSuffix: - textListNumberSuffix = decl.d->values.first().variant.toString(); + textListNumberSuffix = decl.d->values.constFirst().variant.toString(); break; case QCss::TextAlignment: switch (identifier) { @@ -1381,12 +1404,98 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d { if (resourceProvider != nullptr && QTextDocumentPrivate::get(resourceProvider) != nullptr) { bool ok; - qint64 searchKey = decl.d->values.first().variant.toLongLong(&ok); + qint64 searchKey = decl.d->values.constFirst().variant.toLongLong(&ok); if (ok) applyForegroundImage(searchKey, resourceProvider); } break; } + case QCss::QtStrokeColor: + { + QPen pen = charFormat.textOutline(); + pen.setStyle(Qt::SolidLine); + pen.setColor(decl.colorValue()); + charFormat.setTextOutline(pen); + break; + } + case QCss::QtStrokeWidth: + { + qreal width; + if (decl.realValue(&width, "px")) { + QPen pen = charFormat.textOutline(); + pen.setWidthF(width); + charFormat.setTextOutline(pen); + } + break; + } + case QCss::QtStrokeLineCap: + { + QPen pen = charFormat.textOutline(); + switch (identifier) { + case QCss::Value_SquareCap: pen.setCapStyle(Qt::SquareCap); break; + case QCss::Value_FlatCap: pen.setCapStyle(Qt::FlatCap); break; + case QCss::Value_RoundCap: pen.setCapStyle(Qt::RoundCap); break; + default: break; + } + charFormat.setTextOutline(pen); + break; + } + case QCss::QtStrokeLineJoin: + { + QPen pen = charFormat.textOutline(); + switch (identifier) { + case QCss::Value_MiterJoin: pen.setJoinStyle(Qt::MiterJoin); break; + case QCss::Value_BevelJoin: pen.setJoinStyle(Qt::BevelJoin); break; + case QCss::Value_RoundJoin: pen.setJoinStyle(Qt::RoundJoin); break; + case QCss::Value_SvgMiterJoin: pen.setJoinStyle(Qt::SvgMiterJoin); break; + default: break; + } + charFormat.setTextOutline(pen); + break; + } + case QCss::QtStrokeMiterLimit: + { + qreal miterLimit; + if (decl.realValue(&miterLimit)) { + QPen pen = charFormat.textOutline(); + pen.setMiterLimit(miterLimit); + charFormat.setTextOutline(pen); + } + break; + } + case QCss::QtStrokeDashArray: + { + QList<qreal> dashes = decl.dashArray(); + if (!dashes.empty()) { + QPen pen = charFormat.textOutline(); + pen.setDashPattern(dashes); + charFormat.setTextOutline(pen); + } + break; + } + case QCss::QtStrokeDashOffset: + { + qreal dashOffset; + if (decl.realValue(&dashOffset)) { + QPen pen = charFormat.textOutline(); + pen.setDashOffset(dashOffset); + charFormat.setTextOutline(pen); + } + break; + } + case QCss::QtForeground: + { + QBrush brush = decl.brushValue(); + charFormat.setForeground(brush); + break; + } + case QCss::MaximumWidth: + if (id == Html_img) { + auto imageFormat = charFormat.toImageFormat(); + imageFormat.setMaximumWidth(extractor.textLength(decl)); + charFormat = imageFormat; + } + break; default: break; } } @@ -1487,7 +1596,7 @@ void QTextHtmlParserNode::applyBackgroundImage(const QString &url, const QTextDo bool QTextHtmlParserNode::hasOnlyWhitespace() const { - for (int i = 0; i < text.length(); ++i) + for (int i = 0; i < text.size(); ++i) if (!text.at(i).isSpace() || text.at(i) == QChar::LineSeparator) return false; return true; @@ -1537,7 +1646,7 @@ void QTextHtmlParserNode::parseStyleAttribute(const QString &value, const QTextD QCss::Parser parser(css); QCss::StyleSheet sheet; parser.parse(&sheet, Qt::CaseInsensitive); - if (sheet.styleRules.count() != 1) return; + if (sheet.styleRules.size() != 1) return; applyCssDeclarations(sheet.styleRules.at(0).declarations, resourceProvider); } #endif @@ -1575,12 +1684,12 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes) QString linkHref; QString linkType; - if (attributes.count() % 2 == 1) + if (attributes.size() % 2 == 1) return; QTextHtmlParserNode *node = nodes.last(); - for (int i = 0; i < attributes.count(); i += 2) { + for (int i = 0; i < attributes.size(); i += 2) { QString key = attributes.at(i); QString value = attributes.at(i + 1); @@ -1594,10 +1703,9 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes) node->charFormat.setProperty(QTextFormat::FontSizeAdjustment, n); } else if (key == "face"_L1) { if (value.contains(u',')) { - const QStringList values = value.split(u','); QStringList families; - for (const QString &family : values) - families << family.trimmed(); + for (auto family : value.tokenize(u',')) + families << family.trimmed().toString(); node->charFormat.setFontFamilies(families); } else { node->charFormat.setFontFamilies(QStringList(value)); @@ -1634,6 +1742,8 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes) else if (value == "none"_L1) node->listStyle = QTextListFormat::ListStyleUndefined; } + } else if (key == "start"_L1) { + setIntAttribute(&node->listStart, value); } break; case Html_li: @@ -1696,7 +1806,8 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes) } break; case Html_table: - if (key == "border"_L1) { + // If table border already set through css style, prefer that one otherwise consider this value + if (key == "border"_L1 && !node->tableBorder) { setFloatAttribute(&node->tableBorder, value); } else if (key == "bgcolor"_L1) { QColor c = QColor::fromString(value); @@ -1900,7 +2011,7 @@ void QTextHtmlStyleSelector::freeNode(NodePtr) const void QTextHtmlParser::resolveStyleSheetImports(const QCss::StyleSheet &sheet) { - for (int i = 0; i < sheet.importRules.count(); ++i) { + for (int i = 0; i < sheet.importRules.size(); ++i) { const QCss::ImportRule &rule = sheet.importRules.at(i); if (rule.media.isEmpty() || rule.media.contains("screen"_L1, Qt::CaseInsensitive)) importStyleSheet(rule.href); @@ -1911,7 +2022,7 @@ void QTextHtmlParser::importStyleSheet(const QString &href) { if (!resourceProvider) return; - for (int i = 0; i < externalStyleSheets.count(); ++i) + for (int i = 0; i < externalStyleSheets.size(); ++i) if (externalStyleSheets.at(i).url == href) return; @@ -1942,7 +2053,7 @@ QList<QCss::Declaration> standardDeclarationForNode(const QTextHtmlParserNode &n case Html_u: { bool needsUnderline = (node.id == Html_u) ? true : false; if (node.id == Html_a) { - for (int i = 0; i < node.attributes.count(); i += 2) { + for (int i = 0; i < node.attributes.size(); i += 2) { const QString key = node.attributes.at(i); if (key.compare("href"_L1, Qt::CaseInsensitive) == 0 && !node.attributes.at(i + 1).isEmpty()) { @@ -2078,7 +2189,7 @@ QList<QCss::Declaration> standardDeclarationForNode(const QTextHtmlParserNode &n decl.d->propertyId = QCss::FontFamily; QList<QCss::Value> values; val.type = QCss::Value::String; - val.variant = QFontDatabase::systemFont(QFontDatabase::FixedFont).families().first(); + val.variant = QFontDatabase::systemFont(QFontDatabase::FixedFont).families().constFirst(); values << val; decl.d->values = values; decl.d->inheritable = true; @@ -2117,15 +2228,15 @@ QList<QCss::Declaration> QTextHtmlParser::declarationsForNode(int node) const int idx = 0; selector.styleSheets.resize((resourceProvider ? 1 : 0) - + externalStyleSheets.count() - + inlineStyleSheets.count()); + + externalStyleSheets.size() + + inlineStyleSheets.size()); if (resourceProvider) selector.styleSheets[idx++] = QTextDocumentPrivate::get(resourceProvider)->parsedDefaultStyleSheet; - for (int i = 0; i < externalStyleSheets.count(); ++i, ++idx) + for (int i = 0; i < externalStyleSheets.size(); ++i, ++idx) selector.styleSheets[idx] = externalStyleSheets.at(i).sheet; - for (int i = 0; i < inlineStyleSheets.count(); ++i, ++idx) + for (int i = 0; i < inlineStyleSheets.size(); ++i, ++idx) selector.styleSheets[idx] = inlineStyleSheets.at(i); selector.medium = resourceProvider ? resourceProvider->metaInformation(QTextDocument::CssMedia) : "screen"_L1; |