diff options
author | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2024-03-15 15:42:51 +0100 |
---|---|---|
committer | Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io> | 2024-03-18 20:28:36 +0100 |
commit | 6ee5fcc45637bf45ecd7d5412db8ab58bde7fe39 (patch) | |
tree | 2a3c4ee8672f6411dba33d978d0306dd999baa6f /src/gui/text | |
parent | e205edfff611922ddf04d8de71ed9cb92704eafc (diff) |
Support foreground gradient in CSS parser and HTML generator
Qt supports some complex foreground brushes which we cannot
express using normal CSS, so we introduce a Qt-specific property
for this. We already had some support for background gradients
in widget style sheets, but this expands support to foreground
brushes of text when converting a QTextDocument from and to HTML.
It also adds an optional "coordinatemode" attribute to the
gradient functions so that this can be faithfully restored from HTML.
Task-number: QTBUG-123357
Change-Id: I3d6dd828f68272995c8525bec5a7b421fdbed670
Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
Diffstat (limited to 'src/gui/text')
-rw-r--r-- | src/gui/text/qcssparser.cpp | 18 | ||||
-rw-r--r-- | src/gui/text/qcssparser_p.h | 1 | ||||
-rw-r--r-- | src/gui/text/qtextdocument.cpp | 47 | ||||
-rw-r--r-- | src/gui/text/qtexthtmlparser.cpp | 6 |
4 files changed, 66 insertions, 6 deletions
diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index 5861003de6..ac6ddc69a8 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -39,6 +39,7 @@ static const QCssKnownValue properties[NumProperties - 1] = { { "-qt-background-role", QtBackgroundRole }, { "-qt-block-indent", QtBlockIndent }, { "-qt-fg-texture-cachekey", QtForegroundTextureCacheKey }, + { "-qt-foreground", QtForeground }, { "-qt-line-height-type", QtLineHeightType }, { "-qt-list-indent", QtListIndent }, { "-qt-list-number-prefix", QtListNumberPrefix }, @@ -814,6 +815,10 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) QStringList spreads; spreads << "pad"_L1 << "reflect"_L1 << "repeat"_L1; + int coordinateMode = -1; + QStringList coordinateModes; + coordinateModes << "logical"_L1 << "stretchtodevice"_L1 << "objectbounding"_L1 << "object"_L1; + bool dependsOnThePalette = false; Parser parser(lst.at(1)); while (parser.hasNext()) { @@ -840,11 +845,12 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) parser.next(); QCss::Value value; (void)parser.parseTerm(&value); - if (attr.compare("spread"_L1, Qt::CaseInsensitive) == 0) { + if (attr.compare("spread"_L1, Qt::CaseInsensitive) == 0) spread = spreads.indexOf(value.variant.toString()); - } else { + else if (attr.compare("coordinatemode"_L1, Qt::CaseInsensitive) == 0) + coordinateMode = coordinateModes.indexOf(value.variant.toString()); + else vars[attr] = value.variant.toReal(); - } } parser.skipSpace(); (void)parser.test(COMMA); @@ -853,7 +859,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) if (gradType == 0) { QLinearGradient lg(vars.value("x1"_L1), vars.value("y1"_L1), vars.value("x2"_L1), vars.value("y2"_L1)); - lg.setCoordinateMode(QGradient::ObjectBoundingMode); + lg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode)); lg.setStops(stops); if (spread != -1) lg.setSpread(QGradient::Spread(spread)); @@ -867,7 +873,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) QRadialGradient rg(vars.value("cx"_L1), vars.value("cy"_L1), vars.value("radius"_L1), vars.value("fx"_L1), vars.value("fy"_L1)); - rg.setCoordinateMode(QGradient::ObjectBoundingMode); + rg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode)); rg.setStops(stops); if (spread != -1) rg.setSpread(QGradient::Spread(spread)); @@ -879,7 +885,7 @@ static BrushData parseBrushValue(const QCss::Value &v, const QPalette &pal) if (gradType == 2) { QConicalGradient cg(vars.value("cx"_L1), vars.value("cy"_L1), vars.value("angle"_L1)); - cg.setCoordinateMode(QGradient::ObjectBoundingMode); + cg.setCoordinateMode(coordinateMode < 0 ? QGradient::ObjectBoundingMode : QGradient::CoordinateMode(coordinateMode)); cg.setStops(stops); if (spread != -1) cg.setSpread(QGradient::Spread(spread)); diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index a2d3622c7d..c1cfb1ac9b 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -169,6 +169,7 @@ enum Property { QtAccent, QtStrokeWidth, QtStrokeColor, + QtForeground, NumProperties }; diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp index dc94643e8a..15a313e13d 100644 --- a/src/gui/text/qtextdocument.cpp +++ b/src/gui/text/qtextdocument.cpp @@ -2646,6 +2646,53 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format) html += " -qt-fg-texture-cachekey:"_L1; html += QString::number(cacheKey); html += ";"_L1; + } else if (brush.style() == Qt::LinearGradientPattern + || brush.style() == Qt::RadialGradientPattern + || brush.style() == Qt::ConicalGradientPattern) { + const QGradient *gradient = brush.gradient(); + if (gradient->type() == QGradient::LinearGradient) { + const QLinearGradient *linearGradient = static_cast<const QLinearGradient *>(brush.gradient()); + + html += " -qt-foreground: qlineargradient("_L1; + html += "x1:"_L1 + QString::number(linearGradient->start().x()) + u','; + html += "y1:"_L1 + QString::number(linearGradient->start().y()) + u','; + html += "x2:"_L1 + QString::number(linearGradient->finalStop().x()) + u','; + html += "y2:"_L1 + QString::number(linearGradient->finalStop().y()) + u','; + } else if (gradient->type() == QGradient::RadialGradient) { + const QRadialGradient *radialGradient = static_cast<const QRadialGradient *>(brush.gradient()); + + html += " -qt-foreground: qradialgradient("_L1; + html += "cx:"_L1 + QString::number(radialGradient->center().x()) + u','; + html += "cy:"_L1 + QString::number(radialGradient->center().y()) + u','; + html += "fx:"_L1 + QString::number(radialGradient->focalPoint().x()) + u','; + html += "fy:"_L1 + QString::number(radialGradient->focalPoint().y()) + u','; + html += "radius:"_L1 + QString::number(radialGradient->radius()) + u','; + } else { + const QConicalGradient *conicalGradient = static_cast<const QConicalGradient *>(brush.gradient()); + + html += " -qt-foreground: qconicalgradient("_L1; + html += "cx:"_L1 + QString::number(conicalGradient->center().x()) + u','; + html += "cy:"_L1 + QString::number(conicalGradient->center().y()) + u','; + html += "angle:"_L1 + QString::number(conicalGradient->angle()) + u','; + } + + const QStringList coordinateModes = { "logical"_L1, "stretchtodevice"_L1, "objectbounding"_L1, "object"_L1 }; + html += "coordinatemode:"_L1; + html += coordinateModes.at(int(gradient->coordinateMode())); + html += u','; + + const QStringList spreads = { "pad"_L1, "reflect"_L1, "repeat"_L1 }; + html += "spread:"_L1; + html += spreads.at(int(gradient->spread())); + + for (const QGradientStop &stop : gradient->stops()) { + html += ",stop:"_L1; + html += QString::number(stop.first); + html += u' '; + html += colorValue(stop.second); + } + + html += ");"_L1; } else { html += " color:"_L1; html += colorValue(brush.color()); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index df6e678827..05b9a1385f 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1405,6 +1405,12 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d } break; } + case QCss::QtForeground: + { + QBrush brush = decl.brushValue(); + charFormat.setForeground(brush); + break; + } default: break; } } |