https://bugs.kde.org/show_bug.cgi?id=525963
Bug ID: 525963
Summary: KPIMTextEdit::TextHTMLBuilder unconditionally adds
border="1" to generated HTML <table> elements,
ignoring the table border information stored in
QTextTableFormat.
Classification: Applications
Product: kpimtextedit
Version First 6.8.1
Reported In:
Platform: openSUSE
OS: Linux
Status: REPORTED
Severity: normal
Priority: NOR
Component: general
Assignee: [email protected]
Reporter: [email protected]
Target Milestone: ---
This causes KMail to add visible borders to HTML tables in sent messages even
when the original HTML explicitly specifies border="0" or CSS such as border:
0; border-style: none.
##Affected component
KPIMTextEdit::TextHTMLBuilder
KMail HTML composer
Tested with:
KMail / KDE PIM stack from openSUSE Tumbleweed
libKPim6TextEdit-26.08.1-1.1.x86_64
/usr/lib64/libKPim6TextEdit.so.6.8.1
Qt 6.11.2
##Description
I use an HTML signature in KMail containing a table for layout.
The signature contains a table explicitly defined without a border, for
example:
<table border="0"
width="100%"
cellspacing="2"
cellpadding="2">
KMail displays the signature correctly in the composer/editor: no border is
visible.
However, after sending the message, the generated MIME HTML contains:
<table cellpadding="0" cellspacing="0" width="100%" border="1">
As a result, the recipient (for example Gmail) displays a visible table border.
This is not caused by the recipient's HTML rendering.
I verified the sent MIME source saved email in Sent folder. The `border="1"`
attribute is already present in the HTML generated by KMail.
## Reproduction
A minimal HTML signature containing a table is sufficient:
<table border="0" width="100%" cellspacing="0" cellpadding="0">
<tr>
<td>LEFT</td>
<td>RIGHT</td>
</tr>
</table>
The table is rendered without a border in the KMail composer.
After sending, the resulting MIME HTML contains:
<table cellpadding="0" cellspacing="0" width="100%" border="1">
<tr>
<td width="" colspan="1" rowspan="1">
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">
LEFT
</p>
</td>
<td width="" colspan="1" rowspan="1">
<p style="margin-top:0;margin-bottom:0;margin-left:0;margin-right:0;">
RIGHT
</p>
</td>
</tr>
</table>
I also tested CSS-based variants such as:
<table style="border:0px none transparent; border-collapse:collapse;">
The result is the same: the generated HTML contains `border="1"`.
The KMail signature itself is not modified. The transformation happens when the
composer document is serialized into MIME HTML.
## Where the conversion happens
The relevant KMail code path is:
HTML signature
v
RichTextComposerNg::insertSignature()
v
QTextEdit::insertHtml()
v
QTextDocument / QTextTable
v
KPIMTextEdit::MarkupDirector
v
KPIMTextEdit::TextHTMLBuilder
v
TextPart::setCleanHtml()
v
MIME HTML
In messagelib, RichTextComposerNg::fillComposerTextPart() uses:
KPIMTextEdit::TextHTMLBuilder pb;
KPIMTextEdit::MarkupDirector pmd(&pb);
pmd.processDocument(document());
QString cleanHtml =
u"<html>\n<head>\n<meta http-equiv=\"content-type\" content=\"text/html;
charset=UTF-8\">\n</head>\n<body>%1</body>\n</html>"_s.arg(pb.getResult());
Therefore the final MIME HTML is generated by TextHTMLBuilder, rather than by
Qt's own QTextDocument::toHtml() exporter.
##Root cause
The current TextHTMLBuilder::beginTable() implementation is effectively:
void TextHTMLBuilder::beginTable(qreal cellpadding,
qreal cellspacing,
const QString &width)
{
Q_D(TextHTMLBuilder);
d->mText.append(QStringLiteral(
"<table cellpadding=\"%1\" cellspacing=\"%2\" "
"width=\"%3\" border=\"1\">")
.arg(cellpadding)
.arg(cellspacing)
.arg(width));
}
The important problem is that beginTable() does not receive any border
information.
Its current interface is:
beginTable(qreal cellpadding,
qreal cellspacing,
const QString &width)
Consequently, the table border stored in the QTextTableFormat is lost during
conversion.
The generated HTML then unconditionally contains:
border="1"
regardless of the actual table format.
##Verification against the installed binary
I also verified this directly in the installed libKPim6TextEdit.so.6.8.1
The exported symbol is:
KPIMTextEdit::TextHTMLBuilder::beginTable(double, double, QString const&)
The disassembly shows the construction of the HTML string using the three %1,
%2, %3 arguments.
The referenced string is located at 0x62230 in .rodata.
A dump of that location shows the UTF-16 string:
<table cellpadding="%1" cellspacing="%2" width="%3" border="1">
Specifically, the relevant part of the binary is:
62230 3c00 7400 6100 6200 6c00 6500 ...
...
62290 2500 3300 2200 2000 6200 6f00 7200 6400
622a0 6500 7200 3d00 2200 3100 2200 3e00
So this is not merely a source-code observation: the hard-coded border="1" is
present in the actual installed KPIMTextEdit library.
##Why Qt itself does not appear to be the cause
Qt's HTML importer does preserve table border information in QTextTableFormat.
For example, the Qt HTML parser handles the HTML border attribute and CSS
border properties and stores them in the table format.
QTextTableFormat provides:
FrameBorder
FrameBorderBrush
FrameBorderStyle
Therefore a table with no border can be represented by the Qt document model.
The problem occurs later, when MarkupDirector passes the document to
TextHTMLBuilder.
TextHTMLBuilder currently has no parameter through which the table's border,
border style, or border brush can be communicated.
##Suggested fix
TextHTMLBuilder should not unconditionally emit border="1".
Instead, it should receive the relevant table formatting information from
MarkupDirector and serialize the QTextTableFormat border state.
For example, the interface could be extended along the lines of:
void beginTable(const QTextTableFormat &format);
or, if retaining the existing API is preferred:
void beginTable(qreal cellpadding,
qreal cellspacing,
const QString &width,
qreal border,
QTextFrameFormat::BorderStyle borderStyle,
const QBrush &borderBrush);
The first option would probably be cleaner because it avoids losing information
from the Qt table format and leaves the HTML serialization logic in one place.
The generated HTML should then reflect the actual table format.
##Important compatibility consideration
Simply changing the hard-coded value from:
border="1"
to:
border="0"
would fix the immediate KMail signature problem, but would not be the correct
general solution.
It would instead make TextHTMLBuilder ignore all table border formatting,
including tables which intentionally have borders.
The correct fix is therefore to propagate the QTextTableFormat border
information through MarkupDirector to TextHTMLBuilder.
##Regression test
A regression test should cover at least these cases:
QTextTableFormat with no border:
generated HTML must not contain border="1".
QTextTableFormat with a visible border:
generated HTML must retain a visible border.
Border style BorderStyle_None:
generated HTML must not create a visible border.
Existing cell border formatting should remain unaffected.
A minimal regression test could construct a QTextDocument, insert a QTextTable
with:
QTextTableFormat format;
format.setBorder(0);
format.setBorderStyle(QTextFrameFormat::BorderStyle_None);
and verify that TextHTMLBuilder does not generate:
border="1"
##Expected behavior
If an HTML table is imported into the Qt document model with no border,
serializing that document back to HTML should not introduce a visible border
that was not present in the original document.
In particular:
<table border="0">
should never become:
<table border="1">
as a side effect of KMail's HTML serialization.
##Additional note
The issue is particularly visible with KMail HTML signatures because tables are
commonly used for email layout, and email clients can render border="1" as an
actual visible border.
The same TextHTMLBuilder behavior may affect other HTML generated through
KPIMTextEdit, so this may not be limited to signatures in KMail.
--
You are receiving this mail because:
You are watching all bug changes.