## Summary Continue my changes to introduce the HAL infrastructure from https://github.com/crosspoint-reader/crosspoint-reader/pull/522 This PR touches quite a lot of files, but most of them are just name changing. It should not have any impacts to the end behavior. ## Additional Context My plan is to firstly add this small shim layer, which sounds useless at first, but then I'll implement an emulated driver which can be helpful for testing and for development. Currently, on my fork, I'm using a FS driver that allow "mounting" a local directory from my computer to the device, much like the `-v` mount option on docker. This allows me to quickly reset `.crosspoint` directory if anything goes wrong. I plan to upstream this feature when this PR get merged. --- ### AI Usage While CrossPoint doesn't have restrictions on AI tools in contributing, please be transparent about their usage as it helps set the right context for reviewers. Did you use AI tools to help write this code? NO
115 lines
3.7 KiB
C++
115 lines
3.7 KiB
C++
#pragma once
|
|
|
|
#include <HalStorage.h>
|
|
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <vector>
|
|
|
|
#include "CssStyle.h"
|
|
|
|
/**
|
|
* Lightweight CSS parser for EPUB stylesheets
|
|
*
|
|
* Parses CSS files and extracts styling information relevant for e-ink display.
|
|
* Uses a two-phase approach: first tokenizes the CSS content, then builds
|
|
* a rule database that can be queried during HTML parsing.
|
|
*
|
|
* Supported selectors:
|
|
* - Element selectors: p, div, h1, etc.
|
|
* - Class selectors: .classname
|
|
* - Combined: element.classname
|
|
* - Grouped: selector1, selector2 { }
|
|
*
|
|
* Not supported (silently ignored):
|
|
* - Descendant/child selectors
|
|
* - Pseudo-classes and pseudo-elements
|
|
* - Media queries (content is skipped)
|
|
* - @import, @font-face, etc.
|
|
*/
|
|
class CssParser {
|
|
public:
|
|
CssParser() = default;
|
|
~CssParser() = default;
|
|
|
|
// Non-copyable
|
|
CssParser(const CssParser&) = delete;
|
|
CssParser& operator=(const CssParser&) = delete;
|
|
|
|
/**
|
|
* Load and parse CSS from a file stream.
|
|
* Can be called multiple times to accumulate rules from multiple stylesheets.
|
|
* @param source Open file handle to read from
|
|
* @return true if parsing completed (even if no rules found)
|
|
*/
|
|
bool loadFromStream(FsFile& source);
|
|
|
|
/**
|
|
* Look up the style for an HTML element, considering tag name and class attributes.
|
|
* Applies CSS cascade: element style < class style < element.class style
|
|
*
|
|
* @param tagName The HTML element name (e.g., "p", "div")
|
|
* @param classAttr The class attribute value (may contain multiple space-separated classes)
|
|
* @return Combined style with all applicable rules merged
|
|
*/
|
|
[[nodiscard]] CssStyle resolveStyle(const std::string& tagName, const std::string& classAttr) const;
|
|
|
|
/**
|
|
* Parse an inline style attribute string.
|
|
* @param styleValue The value of a style="" attribute
|
|
* @return Parsed style properties
|
|
*/
|
|
[[nodiscard]] static CssStyle parseInlineStyle(const std::string& styleValue);
|
|
|
|
/**
|
|
* Check if any rules have been loaded
|
|
*/
|
|
[[nodiscard]] bool empty() const { return rulesBySelector_.empty(); }
|
|
|
|
/**
|
|
* Get count of loaded rule sets
|
|
*/
|
|
[[nodiscard]] size_t ruleCount() const { return rulesBySelector_.size(); }
|
|
|
|
/**
|
|
* Clear all loaded rules
|
|
*/
|
|
void clear() { rulesBySelector_.clear(); }
|
|
|
|
/**
|
|
* Save parsed CSS rules to a cache file.
|
|
* @param file Open file handle to write to
|
|
* @return true if cache was written successfully
|
|
*/
|
|
bool saveToCache(FsFile& file) const;
|
|
|
|
/**
|
|
* Load CSS rules from a cache file.
|
|
* Clears any existing rules before loading.
|
|
* @param file Open file handle to read from
|
|
* @return true if cache was loaded successfully
|
|
*/
|
|
bool loadFromCache(FsFile& file);
|
|
|
|
private:
|
|
// Storage: maps normalized selector -> style properties
|
|
std::unordered_map<std::string, CssStyle> rulesBySelector_;
|
|
|
|
// Internal parsing helpers
|
|
void processRuleBlock(const std::string& selectorGroup, const std::string& declarations);
|
|
static CssStyle parseDeclarations(const std::string& declBlock);
|
|
|
|
// Individual property value parsers
|
|
static CssTextAlign interpretAlignment(const std::string& val);
|
|
static CssFontStyle interpretFontStyle(const std::string& val);
|
|
static CssFontWeight interpretFontWeight(const std::string& val);
|
|
static CssTextDecoration interpretDecoration(const std::string& val);
|
|
static CssLength interpretLength(const std::string& val);
|
|
static int8_t interpretSpacing(const std::string& val);
|
|
|
|
// String utilities
|
|
static std::string normalized(const std::string& s);
|
|
static std::vector<std::string> splitOnChar(const std::string& s, char delimiter);
|
|
static std::vector<std::string> splitWhitespace(const std::string& s);
|
|
};
|