Qt Style Sheets: add support for hsl(a) colors

The Qt stylesheets color property did not support hsl or hsla although
CSS 2.1 does support it. Since QColor natively supports this color model
only the color parsing needed to be adjusted.
This also adds some stricter checks for a valid css color definition and
prints a warning about the issue.

[ChangeLog][QtGui][CSS] Added support for hsl/hsla colors

Fixes: QTBUG-58804
Change-Id: Ief65a36a7e0ed0d705dc1fe5a8658e8d07fe9a13
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Christian Ehrlicher 2018-09-29 21:54:35 +02:00
parent 4afd9234c2
commit d65631daa4
5 changed files with 62 additions and 24 deletions

View File

@ -723,7 +723,8 @@ static ColorData parseColorValue(QCss::Value v)
if (lst.count() != 2)
return ColorData();
if ((lst.at(0).compare(QLatin1String("palette"), Qt::CaseInsensitive)) == 0) {
const QString &identifier = lst.at(0);
if ((identifier.compare(QLatin1String("palette"), Qt::CaseInsensitive)) == 0) {
int role = findKnownValue(lst.at(1).trimmed(), values, NumKnownValues);
if (role >= Value_FirstColorRole && role <= Value_LastColorRole)
return (QPalette::ColorRole)(role-Value_FirstColorRole);
@ -731,8 +732,16 @@ static ColorData parseColorValue(QCss::Value v)
return ColorData();
}
bool rgb = lst.at(0).startsWith(QLatin1String("rgb"));
bool rgba = lst.at(0).startsWith(QLatin1String("rgba"));
const bool rgb = identifier.startsWith(QLatin1String("rgb"));
const bool hsv = !rgb && identifier.startsWith(QLatin1String("hsv"));
const bool hsl = !rgb && !hsv && identifier.startsWith(QLatin1String("hsl"));
if (!rgb && !hsv && !hsl)
return ColorData();
const bool hasAlpha = identifier.size() == 4 && identifier.at(3) == QLatin1Char('a');
if (identifier.size() > 3 && !hasAlpha)
return ColorData();
Parser p(lst.at(1));
if (!p.testExpr())
@ -756,20 +765,29 @@ static ColorData parseColorValue(QCss::Value v)
if (tokenCount < 5)
return ColorData();
// ### Qt6: replace this with a check and return invalid color when token count does not match
if (hasAlpha && tokenCount != 7)
qWarning("QCssParser::parseColorValue: Specified color with alpha value but no alpha given: '%s'", qPrintable(lst.join(QLatin1Char(' '))));
if (!hasAlpha && tokenCount != 5)
qWarning("QCssParser::parseColorValue: Specified color without alpha value but alpha given: '%s'", qPrintable(lst.join(QLatin1Char(' '))));
int v1 = colorDigits.at(0).variant.toInt();
int v2 = colorDigits.at(2).variant.toInt();
int v3 = colorDigits.at(4).variant.toInt();
int alpha = 255;
if (tokenCount >= 7) {
if (tokenCount == 7) {
int alphaValue = colorDigits.at(6).variant.toInt();
if (rgba && alphaValue <= 1)
if (alphaValue <= 1)
alpha = colorDigits.at(6).variant.toReal() * 255.;
else
alpha = alphaValue;
}
return rgb ? QColor::fromRgb(v1, v2, v3, alpha)
: QColor::fromHsv(v1, v2, v3, alpha);
if (rgb)
return QColor::fromRgb(v1, v2, v3, alpha);
if (hsv)
return QColor::fromHsv(v1, v2, v3, alpha);
return QColor::fromHsl(v1, v2, v3, alpha);
}
static QColor colorFromData(const ColorData& c, const QPalette &pal)

View File

@ -514,13 +514,15 @@ QLabel { border-width: 1px 2px 3px 4px } /* 1px 2px 3px 4px */
//! [84]
QLabel { border-color: red } /* opaque red */
QLabel { border-color: #FF0000 } /* opaque red */
QLabel { border-color: rgba(255, 0, 0, 75%) } /* 75% opaque red */
QLabel { border-color: rgb(255, 0, 0) } /* opaque red */
QLabel { border-color: rgb(100%, 0%, 0%) } /* opaque red */
QLabel { border-color: hsv(60, 255, 255) } /* opaque yellow */
QLabel { border-color: hsva(240, 255, 255, 75%) } /* 75% blue */
QLabel { border-color: red } /* opaque red */
QLabel { border-color: #FF0000 } /* opaque red */
QLabel { border-color: rgba(255, 0, 0, 75%) } /* 75% opaque red */
QLabel { border-color: rgb(255, 0, 0) } /* opaque red */
QLabel { border-color: rgb(100%, 0%, 0%) } /* opaque red */
QLabel { border-color: hsv(60, 100%, 100%) } /* opaque yellow */
QLabel { border-color: hsva(240, 255, 255, 75%) } /* 75% blue */
QLabel { border-color: hsl(60, 100%, 50%) } /* opaque yellow */
QLabel { border-color: hsla(240, 255, 50%, 75%) } /* 75% blue */
//! [84]

View File

@ -2881,14 +2881,20 @@
| \tt{rgba(\e{r}, \e{g}, \e{b}, \e{a})} \br
| \tt{hsv(\e{h}, \e{s}, \e{v})} \br
| \tt{hsva(\e{h}, \e{s}, \e{v}, \e{a})} \br
| \tt{hsl(\e{h}, \e{s}, \e{l})} \br
| \tt{hsla(\e{h}, \e{s}, \e{l}, \e{a})} \br
| \tt{#\e{rrggbb}} \br
| \l{QColor::setNamedColor()}{Color Name} \br
\li Specifies a color as RGB (red, green, blue) or RGBA
(red, green, blue, alpha) or HSV (hue, saturation, value) or HSVA
(hue, saturation, value, alpha) or a named color. The \c rgb() or \c rgba()
syntax can be used with integer values between 0 and 255, or with
percentages. The value of s, v, and a in \c hsv() or \c hsva() must all
be in the range 0-255; the value of h must be in the range 0-359.
\li Specifies a color as RGB (red, green, blue), RGBA (red,
green, blue, alpha), HSV (hue, saturation, value), HSVA
(hue, saturation, value, alpha), HSL (hue, saturation,
lightness), HSLA (hue, saturation, lightness, alpha) or a
named color. The \c rgb() or \c rgba() syntax can be used
with integer values between 0 and 255, or with percentages.
The value of s, v, l and a in \c hsv(), \c hsva() \c hsl()
or \c hsla() must all be in the range 0-255 or with
percentages, the value of h must be in the range 0-359.
The support for HSL(A) is available since 5.13.
Examples:

View File

@ -835,17 +835,29 @@ void tst_QCssParser::colorValue_data()
QTest::newRow("hexcolor") << "color: #12af0e" << QColor(0x12, 0xaf, 0x0e);
QTest::newRow("functional1") << "color: rgb(21, 45, 73)" << QColor(21, 45, 73);
QTest::newRow("functional2") << "color: rgb(100%, 0%, 100%)" << QColor(0xff, 0, 0xff);
QTest::newRow("rgb") << "color: rgb(10, 20, 30)" << QColor(10, 20, 30);
QTest::newRow("rgba") << "color: rgba(10, 20, 30, 40)" << QColor(10, 20, 30, 40);
QTest::newRow("rgbaf") << "color: rgba(10, 20, 30, 0.5)" << QColor(10, 20, 30, 127);
QTest::newRow("rgb") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40);
QTest::newRow("hsl") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30, 255);
QTest::newRow("hsla") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40);
QTest::newRow("hsv") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30);
QTest::newRow("hsva") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40);
QTest::newRow("hsvaf") << "color: hsva(10, 20, 30, 0.5)" << QColor::fromHsv(10, 20, 30, 127);
QTest::newRow("hsl") << "color: hsl(60, 100%, 50%)" << QColor::fromHsl(60., 255, 127);
QTest::newRow("hsla") << "color: hsla(240, 255, 127, 192)" << QColor::fromHsl(240, 255, 127, 192);
QTest::newRow("hslaf") << "color: hsla(240, 255, 127, 0.25)" << QColor::fromHsl(240, 255, 127, 63);
QTest::newRow("invalid1") << "color: rgb(why, does, it, always, rain, on, me)" << QColor();
QTest::newRow("invalid2") << "color: rgba(i, meant, norway)" << QColor();
QTest::newRow("invalid3") << "color: rgb(21)" << QColor();
QTest::newRow("invalid4") << "color: rgbx(1, 2, 3)" << QColor();
QTest::newRow("invalid5") << "color: rgbax(1, 2, 3, 4)" << QColor();
QTest::newRow("invalid6") << "color: hsv(360, 0, 0)" << QColor();
QTest::newRow("invalid7") << "color: hsla(1, a, 1, 21)" << QColor();
QTest::newRow("role") << "color: palette(base)" << qApp->palette().color(QPalette::Base);
QTest::newRow("role2") << "color: palette( window-text ) " << qApp->palette().color(QPalette::WindowText);
QTest::newRow("transparent") << "color: transparent" << QColor(Qt::transparent);
// ### Qt6: no longer valid
QTest::newRow("rgb-invalid") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40);
QTest::newRow("rgba-invalid") << "color: rgba(10, 20, 30)" << QColor(10, 20, 30, 255);
}
void tst_QCssParser::colorValue()

View File

@ -1189,7 +1189,7 @@ void tst_QStyleSheetStyle::transparent()
QPushButton *p3=new QPushButton(&w);
p1->setStyleSheet("background:transparent");
p2->setStyleSheet("background-color:transparent");
p3->setStyleSheet("background:rgb(0,0,0,0)");
p3->setStyleSheet("background:rgba(0,0,0,0)");
QCOMPARE(BACKGROUND(*p1) , QColor(0,0,0,0));
QCOMPARE(BACKGROUND(*p2) , QColor(0,0,0,0));
QCOMPARE(BACKGROUND(*p3) , QColor(0,0,0,0));