feat: add RTL support in epub and txt readers (#1700)
Co-authored-by: Zach Nelson <zach@zdnelson.com>
This commit is contained in:
co-authored by
Zach Nelson
parent
cc2079a578
commit
f5bc554ae7
@@ -344,6 +344,15 @@ void CssParser::parseDeclarationIntoStyle(const std::string& decl, CssStyle& sty
|
||||
const std::string_view displayValue = stripTrailingImportant(propValueBuf);
|
||||
style.display = (displayValue == "none") ? CssDisplay::None : CssDisplay::Block;
|
||||
style.defined.display = 1;
|
||||
} else if (propNameBuf == "direction") {
|
||||
const std::string_view directionValue = stripTrailingImportant(propValueBuf);
|
||||
if (directionValue == "rtl") {
|
||||
style.direction = CssTextDirection::Rtl;
|
||||
style.defined.direction = 1;
|
||||
} else if (directionValue == "ltr") {
|
||||
style.direction = CssTextDirection::Ltr;
|
||||
style.defined.direction = 1;
|
||||
}
|
||||
} else if (propNameBuf == "vertical-align") {
|
||||
const std::string v = normalized(propValueBuf);
|
||||
if (v == "super") {
|
||||
@@ -710,6 +719,7 @@ bool CssParser::saveToCache() const {
|
||||
file.write(static_cast<uint8_t>(style.fontStyle));
|
||||
file.write(static_cast<uint8_t>(style.fontWeight));
|
||||
file.write(static_cast<uint8_t>(style.textDecoration));
|
||||
file.write(static_cast<uint8_t>(style.direction));
|
||||
|
||||
// Write CssLength fields (value + unit)
|
||||
auto writeLength = [&file](const CssLength& len) {
|
||||
@@ -731,7 +741,7 @@ bool CssParser::saveToCache() const {
|
||||
file.write(static_cast<uint8_t>(style.display));
|
||||
file.write(static_cast<uint8_t>(style.verticalAlign));
|
||||
|
||||
// Write defined flags as uint16_t
|
||||
// Write defined flags as uint32_t
|
||||
uint32_t definedBits = 0;
|
||||
if (style.defined.textAlign) definedBits |= 1 << 0;
|
||||
if (style.defined.fontStyle) definedBits |= 1 << 1;
|
||||
@@ -749,7 +759,8 @@ bool CssParser::saveToCache() const {
|
||||
if (style.defined.imageHeight) definedBits |= 1 << 13;
|
||||
if (style.defined.imageWidth) definedBits |= 1 << 14;
|
||||
if (style.defined.display) definedBits |= 1 << 15;
|
||||
if (style.defined.verticalAlign) definedBits |= 1 << 16;
|
||||
if (style.defined.direction) definedBits |= 1 << 16;
|
||||
if (style.defined.verticalAlign) definedBits |= 1 << 17;
|
||||
file.write(reinterpret_cast<const uint8_t*>(&definedBits), sizeof(definedBits));
|
||||
}
|
||||
|
||||
@@ -862,6 +873,12 @@ bool CssParser::loadFromCache() {
|
||||
}
|
||||
style.textDecoration = static_cast<CssTextDecoration>(enumVal);
|
||||
|
||||
if (file.read(&enumVal, 1) != 1) {
|
||||
rulesBySelector_.clear();
|
||||
return false;
|
||||
}
|
||||
style.direction = static_cast<CssTextDirection>(enumVal);
|
||||
|
||||
// Read CssLength fields
|
||||
auto readLength = [&file](CssLength& len) -> bool {
|
||||
if (file.read(&len.value, sizeof(len.value)) != sizeof(len.value)) {
|
||||
@@ -921,7 +938,8 @@ bool CssParser::loadFromCache() {
|
||||
style.defined.imageHeight = (definedBits & 1 << 13) != 0;
|
||||
style.defined.imageWidth = (definedBits & 1 << 14) != 0;
|
||||
style.defined.display = (definedBits & 1 << 15) != 0;
|
||||
style.defined.verticalAlign = (definedBits & 1 << 16) != 0;
|
||||
style.defined.direction = (definedBits & 1 << 16) != 0;
|
||||
style.defined.verticalAlign = (definedBits & 1 << 17) != 0;
|
||||
|
||||
rulesBySelector_[selector] = style;
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
class CssParser {
|
||||
public:
|
||||
// Bump when CSS cache format or rules change; section caches are invalidated when this changes
|
||||
static constexpr uint8_t CSS_CACHE_VERSION = 5;
|
||||
static constexpr uint8_t CSS_CACHE_VERSION = 6;
|
||||
|
||||
explicit CssParser(std::string cachePath) : cachePath(std::move(cachePath)) {}
|
||||
~CssParser() = default;
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
// Matches order of PARAGRAPH_ALIGNMENT in CrossPointSettings
|
||||
enum class CssTextAlign : uint8_t { Justify = 0, Left = 1, Center = 2, Right = 3, None = 4 };
|
||||
enum class CssUnit : uint8_t { Pixels = 0, Em = 1, Rem = 2, Points = 3, Percent = 4 };
|
||||
enum class CssTextDirection : uint8_t { Ltr = 0, Rtl = 1 };
|
||||
|
||||
// Represents a CSS length value with its unit, allowing deferred resolution to pixels
|
||||
struct CssLength {
|
||||
@@ -78,6 +79,7 @@ struct CssPropertyFlags {
|
||||
uint16_t imageHeight : 1;
|
||||
uint16_t imageWidth : 1;
|
||||
uint16_t display : 1;
|
||||
uint16_t direction : 1;
|
||||
uint16_t verticalAlign : 1;
|
||||
|
||||
CssPropertyFlags()
|
||||
@@ -97,22 +99,27 @@ struct CssPropertyFlags {
|
||||
imageHeight(0),
|
||||
imageWidth(0),
|
||||
display(0),
|
||||
direction(0),
|
||||
verticalAlign(0) {}
|
||||
|
||||
[[nodiscard]] bool anySet() const {
|
||||
return textAlign || fontStyle || fontWeight || textDecoration || textIndent || marginTop || marginBottom ||
|
||||
marginLeft || marginRight || paddingTop || paddingBottom || paddingLeft || paddingRight || imageHeight ||
|
||||
imageWidth || display || verticalAlign;
|
||||
imageWidth || display || direction || verticalAlign;
|
||||
}
|
||||
|
||||
void clearAll() {
|
||||
textAlign = fontStyle = fontWeight = textDecoration = textIndent = 0;
|
||||
marginTop = marginBottom = marginLeft = marginRight = 0;
|
||||
paddingTop = paddingBottom = paddingLeft = paddingRight = 0;
|
||||
imageHeight = imageWidth = display = verticalAlign = 0;
|
||||
imageHeight = imageWidth = display = direction = verticalAlign = 0;
|
||||
}
|
||||
};
|
||||
|
||||
// Cache serializes defined flags as uint32_t with bit indices 0..17.
|
||||
static_assert(sizeof(CssPropertyFlags) <= sizeof(uint32_t),
|
||||
"CssPropertyFlags exceeds 32 bits; update cache read/write in CssParser.cpp");
|
||||
|
||||
// Represents a collection of CSS style properties
|
||||
// Only stores properties relevant to e-ink text rendering
|
||||
// Length values are stored as CssLength (value + unit) for deferred resolution
|
||||
@@ -121,6 +128,7 @@ struct CssStyle {
|
||||
CssFontStyle fontStyle = CssFontStyle::Normal;
|
||||
CssFontWeight fontWeight = CssFontWeight::Normal;
|
||||
CssTextDecoration textDecoration = CssTextDecoration::None;
|
||||
CssTextDirection direction = CssTextDirection::Ltr;
|
||||
|
||||
CssLength textIndent; // First-line indent (deferred resolution)
|
||||
CssLength marginTop; // Vertical spacing before block
|
||||
@@ -205,6 +213,10 @@ struct CssStyle {
|
||||
display = base.display;
|
||||
defined.display = 1;
|
||||
}
|
||||
if (base.hasDirection()) {
|
||||
direction = base.direction;
|
||||
defined.direction = 1;
|
||||
}
|
||||
if (base.hasVerticalAlign()) {
|
||||
verticalAlign = base.verticalAlign;
|
||||
defined.verticalAlign = 1;
|
||||
@@ -227,6 +239,7 @@ struct CssStyle {
|
||||
[[nodiscard]] bool hasImageHeight() const { return defined.imageHeight; }
|
||||
[[nodiscard]] bool hasImageWidth() const { return defined.imageWidth; }
|
||||
[[nodiscard]] bool hasDisplay() const { return defined.display; }
|
||||
[[nodiscard]] bool hasDirection() const { return defined.direction; }
|
||||
[[nodiscard]] bool hasVerticalAlign() const { return defined.verticalAlign; }
|
||||
|
||||
void reset() {
|
||||
@@ -234,6 +247,7 @@ struct CssStyle {
|
||||
fontStyle = CssFontStyle::Normal;
|
||||
fontWeight = CssFontWeight::Normal;
|
||||
textDecoration = CssTextDecoration::None;
|
||||
direction = CssTextDirection::Ltr;
|
||||
textIndent = CssLength{};
|
||||
marginTop = marginBottom = marginLeft = marginRight = CssLength{};
|
||||
paddingTop = paddingBottom = paddingLeft = paddingRight = CssLength{};
|
||||
|
||||
Reference in New Issue
Block a user