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

- Explicit transparent backgrounds and `none` borders override inherited ODF
styles, including after clearing a cell fill and reopening the document.

- ODF charts reject unrepresentable geometry, bound axis/label conversions,
and draw complete single-slice pies and rings without overflowing totals.

Expand Down
71 changes: 39 additions & 32 deletions src/odr/internal/odf/odf_style.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -256,11 +256,27 @@ std::optional<Color> read_color(const pugi::xml_attribute attribute) {
return {};
}

std::optional<std::string> read_border(const pugi::xml_attribute attribute) {
if (attribute && std::strcmp("none", attribute.value()) != 0) {
return attribute.value();
/// A stated `transparent` clears the @p inherited background.
std::optional<Color> read_background(const pugi::xml_attribute attribute,
const std::optional<Color> &inherited) {
if (std::strcmp("transparent", attribute.value()) == 0) {
return {};
}
return {};
const std::optional<Color> color = read_color(attribute);
return color ? color : inherited;
}

/// A stated `none` clears the @p inherited border.
std::optional<std::string>
read_border(const pugi::xml_attribute attribute,
const std::optional<std::string> &inherited) {
if (!attribute) {
return inherited;
}
if (std::strcmp("none", attribute.value()) == 0) {
return {};
}
return attribute.value();
}

PageLayout read_page_layout(const pugi::xml_node node) {
Expand Down Expand Up @@ -396,10 +412,9 @@ void Style::resolve_text_style_(const StyleRegistry *registry,
read_color(text_properties.attribute("fo:color"))) {
result.font_color = font_color;
}
if (const std::optional<Color> background_color =
read_color(text_properties.attribute("fo:background-color"))) {
result.background_color = background_color;
}
result.background_color =
read_background(text_properties.attribute("fo:background-color"),
result.background_color);
if (const pugi::xml_attribute text_position =
text_properties.attribute("style:text-position")) {
if (const std::optional<FontPosition> font_position =
Expand Down Expand Up @@ -528,10 +543,9 @@ void Style::resolve_table_cell_style_(const pugi::xml_node node,
table_cell_properties.attribute("style:wrap-option")) {
result.wrap_text = std::strcmp("wrap", wrap_option.value()) == 0;
}
if (const std::optional<Color> background_color =
read_color(table_cell_properties.attribute("fo:background-color"))) {
result.background_color = background_color;
}
result.background_color =
read_background(table_cell_properties.attribute("fo:background-color"),
result.background_color);
if (const std::optional<Measure> padding =
read_measure(table_cell_properties.attribute("fo:padding"))) {
result.padding = DirectionalStyle(padding);
Expand All @@ -552,26 +566,19 @@ void Style::resolve_table_cell_style_(const pugi::xml_node node,
read_measure(table_cell_properties.attribute("fo:padding-bottom"))) {
result.padding.bottom = padding_bottom;
}
if (const std::optional<std::string> border =
read_border(table_cell_properties.attribute("fo:border"))) {
result.border = DirectionalStyle(border);
}
if (const std::optional<std::string> border_right =
read_border(table_cell_properties.attribute("fo:border-right"))) {
result.border.right = border_right;
}
if (const std::optional<std::string> border_top =
read_border(table_cell_properties.attribute("fo:border-top"))) {
result.border.top = border_top;
}
if (const std::optional<std::string> border_left =
read_border(table_cell_properties.attribute("fo:border-left"))) {
result.border.left = border_left;
}
if (const std::optional<std::string> border_bottom =
read_border(table_cell_properties.attribute("fo:border-bottom"))) {
result.border.bottom = border_bottom;
}
if (const pugi::xml_attribute border =
table_cell_properties.attribute("fo:border")) {
result.border = DirectionalStyle(read_border(border, {}));
}
result.border.right = read_border(
table_cell_properties.attribute("fo:border-right"), result.border.right);
result.border.top = read_border(
table_cell_properties.attribute("fo:border-top"), result.border.top);
result.border.left = read_border(
table_cell_properties.attribute("fo:border-left"), result.border.left);
result.border.bottom =
read_border(table_cell_properties.attribute("fo:border-bottom"),
result.border.bottom);
}

void Style::resolve_graphic_style_(const pugi::xml_node node,
Expand Down
43 changes: 35 additions & 8 deletions test/src/internal/odf/odf_sheet_style_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,42 @@ TEST(OdfSheetStyle, one_delta_on_one_base_is_one_style) {
}

TEST(OdfSheetStyle, a_fill_taken_away_is_written_transparent) {
const Document document =
document_of(flat_sheet(string_cell("a", "ce1"), red_cell_style));
const Sheet sheet = first_sheet(document);

sheet.set_cell_style(0, 0, fill(Color(0, 0, 0, 0)), {});
for (const bool named : {false, true}) {
const Document document = document_of(
flat_sheet(string_cell("a", "ce1"), named ? "" : red_cell_style,
named ? red_cell_style : ""));
const Sheet sheet = first_sheet(document);
sheet.set_cell_style(0, 0, fill(Color(0, 0, 0, 0)), {});

EXPECT_EQ(fill_at(sheet, 0, 0), std::nullopt);
EXPECT_NE(saved(document).find(R"(fo:background-color="transparent")"),
std::string::npos);
EXPECT_EQ(fill_at(first_sheet(document_of(saved(document))), 0, 0),
std::nullopt);
}
}

EXPECT_EQ(fill_at(sheet, 0, 0), std::nullopt);
EXPECT_NE(saved(document).find(R"(fo:background-color="transparent")"),
std::string::npos);
TEST(OdfSheetStyle, explicit_transparency_and_no_border_override_inheritance) {
const Document document = document_of(flat_sheet(
string_cell("a", "child"),
R"(<style:style style:name="child" style:family="table-cell" )"
R"(style:parent-style-name="parent">)"
R"(<style:table-cell-properties fo:border="none" fo:border-left="1pt solid #000000" )"
R"(fo:background-color="transparent"/>)"
R"(<style:text-properties fo:background-color="transparent"/>)"
R"(</style:style>)",
R"(<style:style style:name="parent" style:family="table-cell">)"
R"(<style:table-cell-properties fo:background-color="#ff0000" fo:border="2pt solid #ff0000"/>)"
R"(<style:text-properties fo:background-color="#ff0000"/>)"
R"(</style:style>)"));
const Sheet sheet = first_sheet(document);
const TableCellStyle style = sheet.cell_style(0, 0);
EXPECT_EQ(style.background_color, std::nullopt);
EXPECT_EQ(style.border.top, std::nullopt);
EXPECT_EQ(style.border.right, std::nullopt);
EXPECT_EQ(style.border.bottom, std::nullopt);
EXPECT_EQ(style.border.left, "1pt solid #000000");
EXPECT_EQ(text_style_of(sheet, 0).background_color, std::nullopt);
}

TEST(OdfSheetStyle, an_alignment_is_fixed_on_the_cell) {
Expand Down
Loading