QCssParser: don't allow negative values for cuts in border-image

The spec does not allow this and qDrawBorderPixmap can not handle it.

Pick-to: 6.9 6.8 6.5
Fixes: QTBUG-107904
Change-Id: I5873dec2312865fb96ccccd3cc2292c6b9e1d4f0
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Christian Ehrlicher 2024-11-12 19:49:37 +01:00
parent 49f462b7f8
commit 254fc6a978
2 changed files with 123 additions and 0 deletions

View File

@ -1821,6 +1821,13 @@ void Declaration::borderImageValue(QString *image, int *cuts,
if (v.type != Value::Number)
break;
cuts[i] = v.variant.toString().toInt();
if (cuts[i] < 0) {
qWarning("Declaration::borderImageValue: Invalid cut value %d at position %d",
cuts[i], i);
cuts[0] = cuts[1] = cuts[2] = cuts[3] = -1;
i = 4;
break;
}
}
if (i == 0) cuts[0] = cuts[1] = cuts[2] = cuts[3] = 0;
else if (i == 1) cuts[3] = cuts[2] = cuts[1] = cuts[0];

View File

@ -55,6 +55,10 @@ private slots:
void extractFontSize();
void extractBorder_data();
void extractBorder();
void extractBorderImage_data();
void extractBorderImage();
void extractBorderImageCuts_data();
void extractBorderImageCuts();
void noTextDecoration();
void quotedAndUnquotedIdentifiers();
void whitespaceValues_data();
@ -1812,6 +1816,118 @@ void tst_QCssParser::extractBorder()
QCOMPARE(colors[QCss::TopEdge].color(), expectedTopColor);
}
void tst_QCssParser::extractBorderImage_data()
{
QTest::addColumn<QString>("css");
QTest::addColumn<QString>("imgUrl");
QTest::addColumn<QCss::TileMode>("tileMode1");
QTest::addColumn<QCss::TileMode>("tileMode2");
QTest::newRow("no valid url, 1 stretch")
<< "border-image: stretch" << QString()
<< QCss::TileMode::TileMode_Stretch
<< QCss::TileMode::TileMode_Stretch;
QTest::newRow("tilemode stretch")
<< "border-image: url(:/image.png) 1 stretch" << ":/image.png"
<< QCss::TileMode::TileMode_Stretch
<< QCss::TileMode::TileMode_Stretch;
QTest::newRow("tilemode repeat")
<< "border-image: url(:/image.png) 1 2 repeat" << ":/image.png"
<< QCss::TileMode::TileMode_Repeat
<< QCss::TileMode::TileMode_Repeat;
QTest::newRow("tilemode repeat and stretch")
<< "border-image: url(:/image.png) 1 2 3 repeat stretch" << ":/image.png"
<< QCss::TileMode::TileMode_Repeat
<< QCss::TileMode::TileMode_Stretch;
}
void tst_QCssParser::extractBorderImage()
{
QFETCH(QString, css);
QFETCH(QString, imgUrl);
QFETCH(QCss::TileMode, tileMode1);
QFETCH(QCss::TileMode, tileMode2);
css.prepend("dummy {");
css.append(QLatin1Char('}'));
QCss::Parser parser(css);
QCss::StyleSheet sheet;
QVERIFY(parser.parse(&sheet));
QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1);
QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
sheet.styleRules.at(0) : *sheet.nameIndex.begin();
const QList<QCss::Declaration> decls = rule.declarations;
QVERIFY(!decls.isEmpty());
QString uri;
QCss::TileMode horizStretch, vertStretch;
int cuts[4];
for (const auto& decl : decls) {
if (decl.d->propertyId == QCss::BorderImage) {
decl.borderImageValue(&uri, cuts, &horizStretch, &vertStretch);
QCOMPARE(uri, imgUrl);
QCOMPARE(horizStretch, tileMode1);
QCOMPARE(vertStretch, tileMode2);
}
}
}
void tst_QCssParser::extractBorderImageCuts_data()
{
QTest::addColumn<QString>("css");
QTest::addColumn<int>("expCut1");
QTest::addColumn<int>("expCut2");
QTest::addColumn<int>("expCut3");
QTest::addColumn<int>("expCut4");
const QString url = "border-image: url(:/image.png)";
QTest::newRow("no cuts") << url << -1 << -1 << -1 << -1;
QTest::newRow("1 cut, valid") << url + " 2" << 2 << 2 << 2 << 2;
QTest::newRow("1 cut, invalid") << url + " -42" << -1 << -1 << -1 << -1;
QTest::newRow("2 cuts, valid") << url + " 2 3" << 2 << 3 << 2 << 3;
QTest::newRow("2 cuts, invalid") << url + " 2 -3" << -1 << -1 << -1 << -1;
QTest::newRow("3 cuts, valid") << url + " 2 3 4" << 2 << 3 << 4 << 3;
QTest::newRow("3 cuts, invalid") << url + " 2 3 -4" << -1 << -1 << -1 << -1;
QTest::newRow("4 cuts, valid") << url + " 2 3 4 5" << 2 << 3 << 4 << 5;
QTest::newRow("4 cuts, invalid") << url + " 2 3 4 -5" << -1 << -1 << -1 << -1;
}
void tst_QCssParser::extractBorderImageCuts()
{
QFETCH(QString, css);
QFETCH(int, expCut1);
QFETCH(int, expCut2);
QFETCH(int, expCut3);
QFETCH(int, expCut4);
css.prepend("dummy {");
css.append(QLatin1Char('}'));
QCss::Parser parser(css);
QCss::StyleSheet sheet;
QVERIFY(parser.parse(&sheet));
QCOMPARE(sheet.styleRules.size() + sheet.nameIndex.size(), 1);
QCss::StyleRule rule = (!sheet.styleRules.isEmpty()) ?
sheet.styleRules.at(0) : *sheet.nameIndex.begin();
const QList<QCss::Declaration> decls = rule.declarations;
QVERIFY(!decls.isEmpty());
QString uri;
QCss::TileMode horizStretch, vertStretch;
int cuts[4];
for (const auto& decl : decls) {
if (decl.d->propertyId == QCss::BorderImage) {
decl.borderImageValue(&uri, cuts, &horizStretch, &vertStretch);
QCOMPARE(cuts[0], expCut1);
QCOMPARE(cuts[1], expCut2);
QCOMPARE(cuts[2], expCut3);
QCOMPARE(cuts[3], expCut4);
}
}
}
void tst_QCssParser::noTextDecoration()
{
QCss::Parser parser("dummy { text-decoration: none; }");