Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ The release run heads these entries with the version and opens a fresh

## Unreleased

- Spreadsheet text no longer spills over a cell that a merged cell from a row
above covers.

- PDF annotations reject malformed indices, colors and geometry, and bound
squiggle generation before writing output.

Expand Down
11 changes: 10 additions & 1 deletion src/odr/internal/html/document_element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -702,6 +702,9 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
const ElementRange shapes = sheet.shapes();
const bool has_shapes = shapes.begin() != shapes.end();

// per column, the row where a cell spanning down from above ends
std::vector<std::uint32_t> span_end_row(end_column, 0);

TableCursor cursor;
for (std::uint32_t row_index = cursor.row(); row_index < end_row;
row_index = cursor.row()) {
Expand Down Expand Up @@ -782,7 +785,9 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
const SheetCell cell_ahead = ahead == next_column && next.has_value()
? *next
: sheet.cell(ahead, row_index);
if (!is_blank(cell_ahead)) {
// The merged cell from a row above paints over a covered position,
// which a reader may give as a blank cell.
if (span_end_row[ahead] > row_index || !is_blank(cell_ahead)) {
bounded = true;
break;
}
Expand Down Expand Up @@ -887,6 +892,10 @@ void html::translate_sheet(const Sheet &sheet, const WritingState &state) {
}
state.out().write_element_end("td");

for (std::uint32_t column = column_index;
column < std::min(next_column, end_column); ++column) {
span_end_row[column] = row_index + cell_span.rows;
}
cursor.add_cell(cell_span.columns, cell_span.rows);
if (cursor.column() == next_column) {
pending = next;
Expand Down
4 changes: 2 additions & 2 deletions test/data.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ odr_test_data(
odr_test_data(
PATH "reference-output/odr-public"
URL "https://github.com/opendocument-app/OpenDocument.test.output.git"
REVISION "429287e50942c53dd25afbc754217970c7499750")
REVISION "78e30814a59ef0c1409948628c6541da1449b027")

odr_test_data(
PATH "reference-output/odr-private"
URL "https://github.com/opendocument-app/OpenDocument.test-private.output.git"
REVISION "9ade3a517a9787ffb2bcbb356e989b6d0cdbfd19")
REVISION "2e4e8efc8c2c3596280fa3bea57ebd7897e5cf66")
18 changes: 18 additions & 0 deletions test/src/html_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1631,6 +1631,24 @@ TEST(html, a_cell_spills_over_a_blank_neighbour_and_is_cut_by_a_full_one) {
EXPECT_EQ(spills.find("nowrap;overflow:hidden"), std::string::npos);
}

// A covered cell shows the merged cell from the row above, so a spill stops
// before it.
TEST(html, a_cell_does_not_spill_into_a_merged_cell) {
const std::string page = render_sheet(
fods_file(fods_row(fods_blank() + fods_blank() +
R"(<table:table-cell table:number-rows-spanned="2">)"
R"(<text:p>merged</text:p></table:table-cell>)") +
fods_row(fods_cell("one") + fods_blank() +
"<table:covered-table-cell/>"),
fods_columns(3)),
HtmlConfig());

EXPECT_NE(page.find("max-width:0;white-space:nowrap;"
"clip-path:inset(0 -96px 0 0)"),
std::string::npos);
EXPECT_EQ(page.find("clip-path:inset(0 -192px 0 0)"), std::string::npos);
}

// #822: and where nothing follows it at all, out onto the canvas — there is no
// content to the right of the last column for it to paint over.
TEST(html, a_cell_at_the_end_of_its_row_is_not_cut) {
Expand Down
Loading