From 8732c5649903fba8935a2ef909e1ac1c691071f2 Mon Sep 17 00:00:00 2001 From: jpirnay Date: Mon, 18 May 2026 08:18:13 +0200 Subject: [PATCH] Properly deal with svg elements --- .../Epub/parsers/ChapterHtmlSlimParser.cpp | 26 +++++++++++++++++++ lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h | 1 + 2 files changed, 27 insertions(+) diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp index 3dc0c968..fefde980 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.cpp @@ -408,6 +408,22 @@ void XMLCALL ChapterHtmlSlimParser::startElement(void* userData, const XML_Char* return; } + // Track SVG nesting depth. Must be checked before the svgDepth>0 guard below so that + // nested elements increment the counter rather than being swallowed as unknowns. + if (strcmp(name, "svg") == 0) { + self->svgDepth += 1; + self->depth += 1; + return; + } + + // Inside SVG: only process elements (raster images); skip everything else. + // SVG child elements like , , , must not reach the layout + // engine — they would accumulate path data and exhaust heap on large inline SVG. + if (self->svgDepth > 0 && !matches(name, IMAGE_TAGS, NUM_IMAGE_TAGS)) { + self->depth += 1; + return; + } + // Extract class, style, and id attributes std::string classAttr; std::string styleAttr; @@ -1319,6 +1335,12 @@ void XMLCALL ChapterHtmlSlimParser::characterData(void* userData, const XML_Char return; } + // Skip SVG text content (path data, coordinates, etc.) — it would be treated as words + // and exhaust heap on EPUBs with large inline SVG elements. + if (self->svgDepth > 0) { + return; + } + // Collect footnote link display text (for the number label) // Remove leading/trailing whitespace and square brackets from the // footnote link text to normalize noterefs like "[1]" → "1" @@ -1559,6 +1581,10 @@ void XMLCALL ChapterHtmlSlimParser::endElement(void* userData, const XML_Char* n self->depth -= 1; + if (strcmp(name, "svg") == 0 && self->svgDepth > 0) { + self->svgDepth -= 1; + } + // Pop list entries whose ul/ol is now out of scope while (!self->listStack.empty() && self->listStack.back().depth >= self->depth) { self->listStack.pop_back(); diff --git a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h index 6c1f9eb9..c632b254 100644 --- a/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h +++ b/lib/Epub/Epub/parsers/ChapterHtmlSlimParser.h @@ -36,6 +36,7 @@ class ChapterHtmlSlimParser final : public Print { int underlineUntilDepth = INT_MAX; int strikethroughUntilDepth = INT_MAX; int preUntilDepth = INT_MAX; // set when inside a
 element; enables \n → line-break handling
+  int svgDepth = 0;             // nesting counter for  elements; text inside SVG is skipped (path data etc.)
   // buffer for building up words from characters, will auto break if longer than this
   // leave one char at end for null pointer
   char partWordBuffer[MAX_WORD_SIZE + 1] = {};