fix: Fix img layout issue / support CSS display:none for elements and images (#1443)
## Summary - Add CSS `display: none` support to the EPUB rendering pipeline (fixes #1431) - Parse `display` property in stylesheets and inline styles, with full cascade resolution (element, class, element.class, inline) - Skip hidden elements and all their descendants in `ChapterHtmlSlimParser` - Separate display:none check for `<img>` tags (image code path is independent of the general element handler) - Flush pending text blocks before placing images to fix layout ordering (text preceding an image now correctly renders above it) - Bump CSS cache version to 4 to invalidate stale caches - Add test EPUB (`test_display_none.epub`) covering class selectors, element selectors, combined selectors, inline styles, nested hidden content, hidden images, style priority/override, and realistic use cases
This commit is contained in:
@@ -54,6 +54,9 @@ enum class CssFontWeight : uint8_t { Normal = 0, Bold = 1 };
|
||||
// Text decoration options
|
||||
enum class CssTextDecoration : uint8_t { None = 0, Underline = 1 };
|
||||
|
||||
// Display options - only None and Block are relevant for e-ink rendering
|
||||
enum class CssDisplay : uint8_t { Block = 0, None = 1 };
|
||||
|
||||
// Bitmask for tracking which properties have been explicitly set
|
||||
struct CssPropertyFlags {
|
||||
uint16_t textAlign : 1;
|
||||
@@ -71,6 +74,7 @@ struct CssPropertyFlags {
|
||||
uint16_t paddingRight : 1;
|
||||
uint16_t imageHeight : 1;
|
||||
uint16_t imageWidth : 1;
|
||||
uint16_t display : 1;
|
||||
|
||||
CssPropertyFlags()
|
||||
: textAlign(0),
|
||||
@@ -87,19 +91,20 @@ struct CssPropertyFlags {
|
||||
paddingLeft(0),
|
||||
paddingRight(0),
|
||||
imageHeight(0),
|
||||
imageWidth(0) {}
|
||||
imageWidth(0),
|
||||
display(0) {}
|
||||
|
||||
[[nodiscard]] bool anySet() const {
|
||||
return textAlign || fontStyle || fontWeight || textDecoration || textIndent || marginTop || marginBottom ||
|
||||
marginLeft || marginRight || paddingTop || paddingBottom || paddingLeft || paddingRight || imageHeight ||
|
||||
imageWidth;
|
||||
imageWidth || display;
|
||||
}
|
||||
|
||||
void clearAll() {
|
||||
textAlign = fontStyle = fontWeight = textDecoration = textIndent = 0;
|
||||
marginTop = marginBottom = marginLeft = marginRight = 0;
|
||||
paddingTop = paddingBottom = paddingLeft = paddingRight = 0;
|
||||
imageHeight = imageWidth = 0;
|
||||
imageHeight = imageWidth = display = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -123,6 +128,7 @@ struct CssStyle {
|
||||
CssLength paddingRight; // Padding right
|
||||
CssLength imageHeight; // Height for img (e.g. 2em) – width derived from aspect ratio when only height set
|
||||
CssLength imageWidth; // Width for img when both or only width set
|
||||
CssDisplay display = CssDisplay::Block; // display property (Block or None)
|
||||
|
||||
CssPropertyFlags defined; // Tracks which properties were explicitly set
|
||||
|
||||
@@ -189,6 +195,10 @@ struct CssStyle {
|
||||
imageWidth = base.imageWidth;
|
||||
defined.imageWidth = 1;
|
||||
}
|
||||
if (base.hasDisplay()) {
|
||||
display = base.display;
|
||||
defined.display = 1;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] bool hasTextAlign() const { return defined.textAlign; }
|
||||
@@ -206,6 +216,7 @@ struct CssStyle {
|
||||
[[nodiscard]] bool hasPaddingRight() const { return defined.paddingRight; }
|
||||
[[nodiscard]] bool hasImageHeight() const { return defined.imageHeight; }
|
||||
[[nodiscard]] bool hasImageWidth() const { return defined.imageWidth; }
|
||||
[[nodiscard]] bool hasDisplay() const { return defined.display; }
|
||||
|
||||
void reset() {
|
||||
textAlign = CssTextAlign::Left;
|
||||
@@ -216,6 +227,7 @@ struct CssStyle {
|
||||
marginTop = marginBottom = marginLeft = marginRight = CssLength{};
|
||||
paddingTop = paddingBottom = paddingLeft = paddingRight = CssLength{};
|
||||
imageHeight = imageWidth = CssLength{};
|
||||
display = CssDisplay::Block;
|
||||
defined.clearAll();
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user