Support rendering CSS 'border' property for html table

We supported CSS 'border-width', 'border-style' and 'border-color'
for HTML tables since 8a9bec35fb0c60a0e5990c1a12ffe6f39fdbf2d.
Now we also support the 'border' property, which is shorthand to
set all four borders' width, style and color.

Fixes: QTBUG-123167
Pick-to: 6.6
Change-Id: I5f29b94ab9facf412a9c230d554efb5c69368b6b
Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
(cherry picked from commit 26e75d452eeb2762fa3ece1c63e94d01587c6260)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Santhosh Kumar 2024-03-22 15:16:29 +01:00 committed by Qt Cherry-pick Bot
parent f02ccd86c7
commit 732962d604
4 changed files with 110 additions and 12 deletions

View File

@ -979,9 +979,11 @@ void ValueExtractor::borderValue(const Declaration &decl, int *width, QCss::Bord
} }
data.color = parseBrushValue(decl.d->values.at(i), pal); data.color = parseBrushValue(decl.d->values.at(i), pal);
*color = brushFromData(data.color, pal); if (data.color.type != BrushData::Invalid) {
if (data.color.type != BrushData::DependsOnThePalette) *color = brushFromData(data.color, pal);
decl.d->parsed = QVariant::fromValue<BorderData>(data); if (data.color.type != BrushData::DependsOnThePalette)
decl.d->parsed = QVariant::fromValue<BorderData>(data);
}
} }
static void parseShorthandBackgroundProperty(const QList<QCss::Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal) static void parseShorthandBackgroundProperty(const QList<QCss::Value> &values, BrushData *brush, QString *image, Repeat *repeat, Qt::Alignment *alignment, const QPalette &pal)

View File

@ -1818,11 +1818,20 @@ void QTextDocumentLayoutPrivate::drawTableCell(const QRectF &cellRect, QPainter
if (r >= headerRowCount) if (r >= headerRowCount)
topMargin += td->headerHeight.toReal(); topMargin += td->headerHeight.toReal();
if (!td->borderCollapse && td->border != 0) { // If cell border configured, don't draw default border for cells. It will be taken care later by
// drawTableCellBorder().
bool cellBorderConfigured = (cell.format().hasProperty(QTextFormat::TableCellLeftBorder) ||
cell.format().hasProperty(QTextFormat::TableCellTopBorder) ||
cell.format().hasProperty(QTextFormat::TableCellRightBorder) ||
cell.format().hasProperty(QTextFormat::TableCellBottomBorder));
if (!td->borderCollapse && td->border != 0 && !cellBorderConfigured) {
const QBrush oldBrush = painter->brush(); const QBrush oldBrush = painter->brush();
const QPen oldPen = painter->pen(); const QPen oldPen = painter->pen();
const qreal border = td->border.toReal(); // If border is configured for the table (and not explicitly for the cell), then
// always draw 1px border around the cell
const qreal border = 1;
QRectF borderRect(cellRect.left() - border, cellRect.top() - border, cellRect.width() + border, cellRect.height() + border); QRectF borderRect(cellRect.left() - border, cellRect.top() - border, cellRect.width() + border, cellRect.height() + border);
@ -1885,7 +1894,8 @@ void QTextDocumentLayoutPrivate::drawTableCell(const QRectF &cellRect, QPainter
} }
// paint over the background - otherwise we would have to adjust the background paint cellRect for the border values // paint over the background - otherwise we would have to adjust the background paint cellRect for the border values
drawTableCellBorder(cellRect, painter, table, td, cell); if (cellBorderConfigured)
drawTableCellBorder(cellRect, painter, table, td, cell);
const QFixed verticalOffset = td->cellVerticalOffsets.at(c + r * table->columns()); const QFixed verticalOffset = td->cellVerticalOffsets.at(c + r * table->columns());

View File

@ -1181,7 +1181,7 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
QCss::ValueExtractor extractor(declarations); QCss::ValueExtractor extractor(declarations);
extractor.extractBox(margin, padding); 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]; QCss::BorderStyle cssStyles[4];
int cssBorder[4]; int cssBorder[4];
QSize cssRadii[4]; // unused QSize cssRadii[4]; // unused
@ -1193,12 +1193,16 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
// QCss::BorderWidth parsing below which expects a single value // QCss::BorderWidth parsing below which expects a single value
// will not work as expected - which in this case does not matter // will not work as expected - which in this case does not matter
// because tableBorder is not relevant for cells. // 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) { for (int i = 0; i < 4; ++i) {
tableCellBorderStyle[i] = toQTextFrameFormat(cssStyles[i]); borderStyles[i] = toQTextFrameFormat(cssStyles[i]);
tableCellBorder[i] = static_cast<qreal>(cssBorder[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.size(); ++i) { for (int i = 0; i < declarations.size(); ++i) {
const QCss::Declaration &decl = declarations.at(i); const QCss::Declaration &decl = declarations.at(i);
@ -1220,6 +1224,19 @@ void QTextHtmlParserNode::applyCssDeclarations(const QList<QCss::Declaration> &d
tableBorder = borders[0]; tableBorder = borders[0];
} }
break; 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: case QCss::BorderCollapse:
borderCollapse = decl.borderCollapseValue(); borderCollapse = decl.borderCollapseValue();
break; break;
@ -1697,7 +1714,8 @@ void QTextHtmlParser::applyAttributes(const QStringList &attributes)
} }
break; break;
case Html_table: 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); setFloatAttribute(&node->tableBorder, value);
} else if (key == "bgcolor"_L1) { } else if (key == "bgcolor"_L1) {
QColor c = QColor::fromString(value); QColor c = QColor::fromString(value);

View File

@ -75,6 +75,8 @@ private slots:
#endif #endif
void checkBorderAttributes_data(); void checkBorderAttributes_data();
void checkBorderAttributes(); void checkBorderAttributes();
void checkTableBorderAttributes_data();
void checkTableBorderAttributes();
#ifndef QT_NO_WIDGETS #ifndef QT_NO_WIDGETS
void columnWidthWithSpans(); void columnWidthWithSpans();
@ -1261,6 +1263,72 @@ void tst_QTextTable::checkBorderAttributes()
} }
} }
void tst_QTextTable::checkTableBorderAttributes_data()
{
QTest::addColumn<QString>("html");
QTest::addColumn<qreal>("tableBorderWidth");
QTest::addColumn<QTextFrameFormat::BorderStyle>("tableBorderStyle");
QTest::addColumn<QBrush>("tableBorderBrush");
const QString tableHtmlStart = QStringLiteral("<html><head><style>");
const QString tableHtmlEnd1 = QStringLiteral("</style></head><body>"
"<table><tr><td>One</td><td>Two</td></tr></table>"
"</body></html>");
const QString tableHtmlEnd2 = QStringLiteral("</style></head><body>"
"<table border=10><tr><td>One</td><td>Two</td></tr></table>"
"</body></html>");
QTest::newRow("table-border-attributes-shorthand")
<< QString("%1"
"table {"
"border: 2px solid red;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd1)
<< 2.0 << QTextFrameFormat::BorderStyle_Solid << QBrush(Qt::red);
QTest::newRow("table-border-attributes-explicit")
<< QString("%1"
"table {"
"border-width: 2px;"
"border-color: red;"
"border-style: dashed;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd1)
<< 2.0 << QTextFrameFormat::BorderStyle_Dashed << QBrush(Qt::red);
QTest::newRow("table-border-override")
<< QString("%1"
"table {"
"border: 2px solid red;"
"}"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd2)
<< 2.0 << QTextFrameFormat::BorderStyle_Solid << QBrush(Qt::red);
QTest::newRow("table-border-default")
<< QString("%1"
"%2").arg(tableHtmlStart).arg(tableHtmlEnd2)
<< 10.0 << QTextFrameFormat::BorderStyle_Outset << QBrush(Qt::darkGray);
}
void tst_QTextTable::checkTableBorderAttributes()
{
QFETCH(QString, html);
QFETCH(qreal, tableBorderWidth);
QFETCH(QTextFrameFormat::BorderStyle, tableBorderStyle);
QFETCH(QBrush, tableBorderBrush);
QTextDocument doc;
doc.setHtml(html);
QTextCursor cursor(doc.firstBlock());
cursor.movePosition(QTextCursor::Right);
QTextTable *currentTable = cursor.currentTable();
QVERIFY(currentTable);
QCOMPARE(currentTable->format().border(), tableBorderWidth);
QCOMPARE(currentTable->format().borderStyle(), tableBorderStyle);
QCOMPARE(currentTable->format().borderBrush(), tableBorderBrush);
}
#ifndef QT_NO_WIDGETS #ifndef QT_NO_WIDGETS
void tst_QTextTable::columnWidthWithSpans() void tst_QTextTable::columnWidthWithSpans()
{ {