Add support for horizontal rulers

This commit is contained in:
jpirnay
2026-05-15 11:12:56 +02:00
parent 501d9a4d19
commit 4a5c2a4ed5
9 changed files with 80 additions and 1 deletions
+23
View File
@@ -49,6 +49,25 @@ std::unique_ptr<PageImage> PageImage::deserialize(FsFile& file) {
return std::unique_ptr<PageImage>(new PageImage(std::move(ib), xPos, yPos));
}
void PageHR::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) {
renderer.drawLine(xPos + xOffset, yPos + yOffset, xPos + xOffset + width - 1, yPos + yOffset);
}
bool PageHR::serialize(FsFile& file) {
serialization::writePod(file, xPos);
serialization::writePod(file, yPos);
serialization::writePod(file, width);
return true;
}
std::unique_ptr<PageHR> PageHR::deserialize(FsFile& file) {
int16_t xPos, yPos, width;
serialization::readPod(file, xPos);
serialization::readPod(file, yPos);
serialization::readPod(file, width);
return std::unique_ptr<PageHR>(new PageHR(xPos, yPos, width));
}
void PageTableFragment::render(GfxRenderer& renderer, const int fontId, const int xOffset, const int yOffset) {
const int drawX = xPos + xOffset;
const int drawY = yPos + yOffset;
@@ -237,6 +256,10 @@ std::unique_ptr<Page> Page::deserialize(FsFile& file) {
auto pt = PageTableFragment::deserialize(file);
if (!pt) return nullptr;
page->elements.push_back(std::move(pt));
} else if (tag == TAG_PageHR) {
auto hr = PageHR::deserialize(file);
if (!hr) return nullptr;
page->elements.push_back(std::move(hr));
} else {
LOG_ERR("PGE", "Deserialization failed: Unknown tag %u", tag);
return nullptr;
+12
View File
@@ -21,6 +21,7 @@ enum PageElementTag : uint8_t {
TAG_PageLine = 1,
TAG_PageImage = 2,
TAG_PageTable = 3,
TAG_PageHR = 4,
};
// represents something that has been added to a page
@@ -63,6 +64,17 @@ class PageImage final : public PageElement {
const ImageBlock& getImageBlock() const { return *imageBlock; }
};
class PageHR final : public PageElement {
int16_t width;
public:
PageHR(const int16_t xPos, const int16_t yPos, const int16_t width) : PageElement(xPos, yPos), width(width) {}
void render(GfxRenderer& renderer, int fontId, int xOffset, int yOffset) override;
bool serialize(FsFile& file) override;
PageElementTag getTag() const override { return TAG_PageHR; }
static std::unique_ptr<PageHR> deserialize(FsFile& file);
};
struct TableCell {
std::vector<std::shared_ptr<TextBlock>> lines;
bool isHeader = false;
+1 -1
View File
@@ -14,7 +14,7 @@
#include "parsers/ChapterHtmlSlimParser.h"
namespace {
constexpr uint8_t SECTION_FILE_VERSION = 27;
constexpr uint8_t SECTION_FILE_VERSION = 28;
constexpr uint32_t HEADER_SIZE = sizeof(uint8_t) + // SECTION_FILE_VERSION
sizeof(int) + // fontId
sizeof(float) + // lineCompression
@@ -1049,6 +1049,26 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char*
self->preUntilDepth = std::min(self->preUntilDepth, self->depth);
}
}
} else if (strcmp(name, "hr") == 0) {
if (self->partWordBufferIndex > 0) self->flushPartWordBuffer();
self->makePages();
if (!self->currentPage) {
self->currentPage.reset(new Page());
self->currentPageNextY = 0;
}
const int lineHeight = self->renderer.getLineHeight(self->fontId) * self->lineCompression;
const int16_t marginV = static_cast<int16_t>(lineHeight / 2);
self->currentPageNextY += marginV;
if (self->currentPageNextY + 1 + marginV > self->viewportHeight) {
self->emitPage(self->lastBodyChildByteOffset);
self->currentPage.reset(new Page());
self->currentPageNextY = 0;
}
self->currentPage->elements.push_back(
std::make_shared<PageHR>(0, self->currentPageNextY, static_cast<int16_t>(self->viewportWidth)));
self->currentPageNextY += 1 + marginV;
BlockStyle emptyStyle;
self->startNewTextBlock(emptyStyle);
} else if (matches(name, UNDERLINE_TAGS, NUM_UNDERLINE_TAGS) ||
matches(name, STRIKETHROUGH_TAGS, NUM_STRIKETHROUGH_TAGS)) {
// Flush buffer before style change so preceding text gets current style
+24
View File
@@ -1014,6 +1014,7 @@ def main():
<li>pre element: intrinsic line breaks preserved</li>
<li>pre element: leading/trailing blank lines</li>
<li>pre with inline code element</li>
<li>horizontal rules between paragraphs</li>
</ul>
""",
),
@@ -1061,6 +1062,29 @@ Fifth line (blank line above)</pre>
greet("World");</code></pre>
<p>Normal paragraph after pre/code block.</p>
""",
),
[],
),
(
"4. Horizontal Rules",
make_chapter(
"Horizontal Rule Tests",
"""
<p>A plain &lt;hr&gt; between two paragraphs. A thin line should appear between the two blocks of text.</p>
<p>Paragraph before the first rule. Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>
<hr/>
<p>Paragraph after the first rule. The rule above should be a full-width horizontal line.</p>
<hr/>
<p>Second rule above. Two rules in a row with no text between them:</p>
<hr/>
<hr/>
<p>Two rules appeared above. Now a rule at the very start of a section (right after the heading):</p>
<hr/>
<p>Rule appeared right after the heading. Finally, a rule near the end of the page to verify it does not cause a spurious page break when there is still room:</p>
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.</p>
<hr/>
<p>End of horizontal rule tests.</p>
""",
),
[],
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.