{"list-item", css_display_value::DISPLAY_BLOCK},
{"run-in", css_display_value::DISPLAY_INLINE},
{"table", css_display_value::DISPLAY_BLOCK},
- {"table-caption", css_display_value::DISPLAY_BLOCK},
- {"table-column-group", css_display_value::DISPLAY_BLOCK},
- {"table-header-group", css_display_value::DISPLAY_BLOCK},
- {"table-footer-group", css_display_value::DISPLAY_BLOCK},
- {"table-row-group", css_display_value::DISPLAY_BLOCK},
- {"table-cell", css_display_value::DISPLAY_BLOCK},
- {"table-column", css_display_value::DISPLAY_BLOCK},
- {"table-row", css_display_value::DISPLAY_BLOCK},
+ {"table-caption", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-column-group", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-header-group", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-footer-group", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-row-group", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-cell", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-column", css_display_value::DISPLAY_TABLE_ROW},
+ {"table-row", css_display_value::DISPLAY_TABLE_ROW},
{"initial", css_display_value::DISPLAY_INLINE},
});
case css_display_value::DISPLAY_INLINE:
ret += "inline";
break;
+ case css_display_value::DISPLAY_TABLE_ROW:
+ ret += "table_row";
+ break;
}
}
else if constexpr (std::is_integral_v<T>) {
GList **exceptions,
khash_t (rspamd_url_hash) *url_set) -> goffset
{
- auto is_visible = true, is_block = false;
+ auto is_visible = true, is_block = false, is_spaces = false;
goffset next_tag_offset = tag->closing.end,
initial_dest_offset = hc->parsed.size();
+ auto append_margin = [&](char c) -> void {
+ if (is_visible) {
+ if (!hc->parsed.empty() && hc->parsed.back() != c && hc->parsed.back() != '\n') {
+ if (hc->parsed.back() == ' ') {
+ /* We also strip extra spaces at the end */
+ hc->parsed.erase(std::find_if(hc->parsed.rbegin(), hc->parsed.rend(),
+ [](auto ch) -> auto {
+ return ch != ' ';
+ }).base(),
+ hc->parsed.end());
+ }
+ hc->parsed.push_back(c);
+ }
+ }
+ };
+
if (tag->id == Tag_BR || tag->id == Tag_HR) {
hc->parsed.append("\n");
else if (!tag->block->is_visible()) {
is_visible = false;
}
- else {
- is_block = tag->block->has_display() &&
- tag->block->display == css::css_display_value::DISPLAY_BLOCK;
+ else if (tag->block->has_display()) {
+ if (tag->block->display == css::css_display_value::DISPLAY_BLOCK) {
+ is_block = true;
+ }
+ else if (tag->block->display == css::css_display_value::DISPLAY_TABLE_ROW) {
+ is_spaces = true;
+ }
}
}
if (is_block) {
- if (!hc->parsed.empty() && hc->parsed.back() != '\n') {
- hc->parsed.append("\n");
- }
+ append_margin('\n');
+ }
+ else if (is_spaces) {
+ append_margin(' ');
}
goffset cur_offset = tag->content_offset;
std::size_t(final_part_len)});
}
}
-
- if (is_block && is_visible) {
- if (!hc->parsed.empty() && hc->parsed.back() != '\n') {
- hc->parsed.append("\n");
- }
+ if (is_block) {
+ append_margin('\n');
+ }
+ else if (is_spaces) {
+ append_margin(' ');
}
if (is_visible) {
if (tag->block) {
if (!tag->block->has_display()) {
/* If we have no display field, we can check it by tag */
- if (tag->flags & CM_BLOCK) {
+ if (tag->flags & (CM_BLOCK|CM_TABLE)) {
tag->block->set_display(css::css_display_value::DISPLAY_BLOCK);
}
else if (tag->flags & CM_HEAD) {
tag->block->set_display(css::css_display_value::DISPLAY_HIDDEN);
}
+ else if (tag->flags & CM_ROW) {
+ tag->block->set_display(css::css_display_value::DISPLAY_TABLE_ROW);
+ }
else {
tag->block->set_display(css::css_display_value::DISPLAY_INLINE);
}
{
const std::vector<std::pair<std::string, std::string>> cases{
+ /* Tables */
+ {"<table>\n"
+ " <tr>\n"
+ " <th>heada</th>\n"
+ " <th>headb</th>\n"
+ " </tr>\n"
+ " <tr>\n"
+ " <td>data1</td>\n"
+ " <td>data2</td>\n"
+ " </tr>\n"
+ " </table>", "heada headb\ndata1 data2\n"},
/* XML tags */
{"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
" <!DOCTYPE html\n"
" </P>\n"
" <b>stuff</p>?\n"
" </body>\n"
- "</html>", "Hello, world! test\ndata<> \nstuff?"},
+ "</html>", "Hello, world! test\ndata<>\nstuff?"},
{"<p><!--comment-->test</br></hr><br>", "test\n"},
};