From 3efa0f9ff7482091fe21d8339e0d04b2b8c69e8c Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Thu, 6 Aug 2026 08:01:02 +0200 Subject: [PATCH 1/2] feat(html): floor a text document's page box at one page height MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A text document renders as a single box that grows with its content, so a document shorter than a page produced a sliver of white instead of a page. The page height was discarded outright; it now floors the box as a `min-height`, which leaves anything longer than a page untouched. Only affects `text_document_margin`, so the reference outputs — generated with the default config, which draws no page box for text documents — are unchanged. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01CebbfAJfN4veeUPJXSqqY8 --- src/odr/internal/html/document.cpp | 10 ++--- src/odr/internal/html/document_style.cpp | 13 +++++++ src/odr/internal/html/document_style.hpp | 3 ++ test/CMakeLists.txt | 1 + .../src/internal/html/document_style_test.cpp | 37 +++++++++++++++++++ 5 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 test/src/internal/html/document_style_test.cpp diff --git a/src/odr/internal/html/document.cpp b/src/odr/internal/html/document.cpp index 26df47f99..d9ff9df81 100644 --- a/src/odr/internal/html/document.cpp +++ b/src/odr/internal/html/document.cpp @@ -299,13 +299,13 @@ class TextHtmlFragment final : public HtmlFragmentBase { const TextRoot element = root.as_text_root(); if (state.config().text_document_margin) { - auto page_layout = element.page_layout(); - page_layout.height = {}; + const PageLayout page_layout = element.page_layout(); out.write_element_begin( - "div", HtmlElementOptions() - .set_class("odr-page-outer") - .set_style(translate_outer_page_style(page_layout))); + "div", + HtmlElementOptions() + .set_class("odr-page-outer") + .set_style(translate_outer_flowing_page_style(page_layout))); out.write_element_begin( "div", HtmlElementOptions() .set_class("odr-page-inner") diff --git a/src/odr/internal/html/document_style.cpp b/src/odr/internal/html/document_style.cpp index 2ead0ef68..fb87a4218 100644 --- a/src/odr/internal/html/document_style.cpp +++ b/src/odr/internal/html/document_style.cpp @@ -97,6 +97,19 @@ std::string html::translate_outer_page_style(const PageLayout &page_layout) { return result; } +std::string +html::translate_outer_flowing_page_style(const PageLayout &page_layout) { + PageLayout flowing_page_layout = page_layout; + flowing_page_layout.height = {}; + + std::string result = translate_outer_page_style(flowing_page_layout); + if (const std::optional height = page_layout.height; + height.has_value()) { + result.append("min-height:").append(height->to_string()).append(";"); + } + return result; +} + std::string html::translate_inner_page_style(const PageLayout &page_layout) { std::string result; if (const std::optional> margin_right = diff --git a/src/odr/internal/html/document_style.hpp b/src/odr/internal/html/document_style.hpp index 29174320e..5e379f1f9 100644 --- a/src/odr/internal/html/document_style.hpp +++ b/src/odr/internal/html/document_style.hpp @@ -35,6 +35,9 @@ const char *translate_font_style(FontStyle font_style); const char *translate_font_position(FontPosition font_position); std::string translate_outer_page_style(const PageLayout &page_layout); +/// Like `translate_outer_page_style`, but the page height only floors the box +/// so that content may flow past it. +std::string translate_outer_flowing_page_style(const PageLayout &page_layout); std::string translate_inner_page_style(const PageLayout &page_layout); std::string translate_text_style(const TextStyle &text_style); std::string translate_paragraph_style(const ParagraphStyle ¶graph_style); diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8907510f4..0ed6e9f96 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -37,6 +37,7 @@ add_executable(odr_test "src/table_position_test.cpp" "src/internal/html/common_test.cpp" + "src/internal/html/document_style_test.cpp" "src/internal/html/image_file_test.cpp" "src/internal/html/media_file_test.cpp" diff --git a/test/src/internal/html/document_style_test.cpp b/test/src/internal/html/document_style_test.cpp new file mode 100644 index 000000000..25be0f6a8 --- /dev/null +++ b/test/src/internal/html/document_style_test.cpp @@ -0,0 +1,37 @@ +#include +#include + +#include + +#include + +using namespace odr; +namespace ihtml = odr::internal::html; + +namespace { + +PageLayout a4_page_layout() { + PageLayout page_layout; + page_layout.width = Measure("21cm"); + page_layout.height = Measure("29.7cm"); + return page_layout; +} + +} // namespace + +TEST(html_document_style, outer_page_style_fixes_both_dimensions) { + EXPECT_EQ(ihtml::translate_outer_page_style(a4_page_layout()), + "width:21cm;height:29.7cm;"); +} + +TEST(html_document_style, outer_flowing_page_style_floors_the_height) { + EXPECT_EQ(ihtml::translate_outer_flowing_page_style(a4_page_layout()), + "width:21cm;min-height:29.7cm;"); +} + +TEST(html_document_style, outer_flowing_page_style_without_height) { + PageLayout page_layout = a4_page_layout(); + page_layout.height = {}; + EXPECT_EQ(ihtml::translate_outer_flowing_page_style(page_layout), + "width:21cm;"); +} From eb7f7fafb583e8e5f93f7f52209e4d3a3bee1be0 Mon Sep 17 00:00:00 2001 From: Andreas Stefl Date: Thu, 6 Aug 2026 19:48:42 +0200 Subject: [PATCH 2/2] Update src/odr/internal/html/document_style.hpp --- src/odr/internal/html/document_style.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/odr/internal/html/document_style.hpp b/src/odr/internal/html/document_style.hpp index 5e379f1f9..640e6f6a2 100644 --- a/src/odr/internal/html/document_style.hpp +++ b/src/odr/internal/html/document_style.hpp @@ -35,8 +35,6 @@ const char *translate_font_style(FontStyle font_style); const char *translate_font_position(FontPosition font_position); std::string translate_outer_page_style(const PageLayout &page_layout); -/// Like `translate_outer_page_style`, but the page height only floors the box -/// so that content may flow past it. std::string translate_outer_flowing_page_style(const PageLayout &page_layout); std::string translate_inner_page_style(const PageLayout &page_layout); std::string translate_text_style(const TextStyle &text_style);