diff --git a/ChangeLog b/ChangeLog index e0a374f95..07ece51eb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,6 @@ ===== 1.9.7 (Mar ??, 2014) ===== * Experimental video support +* CSS parsing optimization for ePubs (do not parse css files multiple times) ===== 1.9.6.1 (Feb 24, 2014) ===== * Fixed some config vaues reading (e.g. background) diff --git a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp index a57ce3c35..964917956 100644 --- a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp +++ b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.cpp @@ -26,51 +26,6 @@ #include "StyleSheetParser.h" -StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) { - //ZLLogger::Instance().registerClass("CSS"); -} - -void StyleSheetTableParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) { - std::string s = selector; - ZLStringUtil::stripWhiteSpaces(s); - - if (s.empty()) { - return; - } - - if (s[0] == '@') { - processAtRule(s, map); - return; - } - - const std::vector ids = ZLStringUtil::split(s, ","); - for (std::vector::const_iterator it = ids.begin(); it != ids.end(); ++it) { - std::string id = *it; - ZLStringUtil::stripWhiteSpaces(id); - if (!id.empty()) { - const std::size_t index = id.find('.'); - if (index == std::string::npos) { - myTable.addMap(id, std::string(), map); - } else { - myTable.addMap(id.substr(0, index), id.substr(index + 1), map); - } - } - } -} - -void StyleSheetTableParser::processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map) { - if (name == "@font-face") { - } -} - -shared_ptr StyleSheetSingleStyleParser::parseString(const char *text) { - myReadState = WAITING_FOR_ATTRIBUTE; - parse(text, std::strlen(text), true); - shared_ptr control = StyleSheetTable::createControl(myMap); - reset(); - return control; -} - StyleSheetParser::StyleSheetParser() { reset(); } @@ -87,21 +42,6 @@ void StyleSheetParser::reset() { myMap.clear(); } -void StyleSheetParser::parse(ZLInputStream &stream) { - if (stream.open()) { - char *buffer = new char[1024]; - while (true) { - int len = stream.read(buffer, 1024); - if (len == 0) { - break; - } - parse(buffer, len); - } - delete[] buffer; - stream.close(); - } -} - void StyleSheetParser::parse(const char *text, int len, bool final) { const char *start = text; const char *end = text + len; @@ -151,9 +91,6 @@ bool StyleSheetParser::isControlSymbol(const char symbol) { void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) { } -void StyleSheetParser::processAtRule(const std::string&, const StyleSheetTable::AttributeMap&) { -} - void StyleSheetParser::processControl(const char control) { switch (myReadState) { case WAITING_FOR_SELECTOR: @@ -241,3 +178,77 @@ void StyleSheetParser::processWordWithoutComments(const std::string &word) { } } } + +shared_ptr StyleSheetSingleStyleParser::parseString(const char *text) { + myReadState = WAITING_FOR_ATTRIBUTE; + parse(text, std::strlen(text), true); + shared_ptr control = StyleSheetTable::createControl(myMap); + reset(); + return control; +} + +void StyleSheetMultiStyleParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) { + std::string s = selector; + ZLStringUtil::stripWhiteSpaces(s); + + if (s.empty()) { + return; + } + + if (s[0] == '@') { + processAtRule(s, map); + return; + } + + const std::vector ids = ZLStringUtil::split(s, ","); + for (std::vector::const_iterator it = ids.begin(); it != ids.end(); ++it) { + std::string id = *it; + ZLStringUtil::stripWhiteSpaces(id); + if (!id.empty()) { + const std::size_t index = id.find('.'); + if (index == std::string::npos) { + store(id, std::string(), map); + } else { + store(id.substr(0, index), id.substr(index + 1), map); + } + } + } +} + +void StyleSheetMultiStyleParser::processAtRule(const std::string &name, const StyleSheetTable::AttributeMap&) { + if (name == "@font-face") { + } +} + +void StyleSheetMultiStyleParser::parseStream(ZLInputStream &stream) { + if (stream.open()) { + char *buffer = new char[1024]; + while (true) { + int len = stream.read(buffer, 1024); + if (len == 0) { + break; + } + parse(buffer, len); + } + delete[] buffer; + stream.close(); + } +} + +StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) { +} + +void StyleSheetTableParser::store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) { + myTable.addMap(tag, aClass, map); +} + +void StyleSheetParserWithCache::store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) { + myEntries.push_back(new Entry(tag, aClass, map)); +} + +void StyleSheetParserWithCache::applyToTable(StyleSheetTable &table) const { + for (std::list >::const_iterator it = myEntries.begin(); it != myEntries.end(); ++it) { + const Entry &entry = **it; + table.addMap(entry.Tag, entry.Class, entry.Map); + } +} diff --git a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h index 89122734d..3f23a61eb 100644 --- a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h +++ b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetParser.h @@ -20,6 +20,8 @@ #ifndef __STYLESHEETPARSER_H__ #define __STYLESHEETPARSER_H__ +#include + #include "StyleSheetTable.h" class ZLInputStream; @@ -32,12 +34,10 @@ protected: public: virtual ~StyleSheetParser(); void reset(); - void parse(ZLInputStream &stream); void parse(const char *text, int len, bool final = false); protected: virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); - virtual void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map); private: bool isControlSymbol(const char symbol); @@ -62,23 +62,59 @@ private: friend class StyleSheetSingleStyleParser; }; -class StyleSheetTableParser : public StyleSheetParser { - -public: - StyleSheetTableParser(StyleSheetTable &table); - -private: - void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); - void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map); - -private: - StyleSheetTable &myTable; -}; - class StyleSheetSingleStyleParser : public StyleSheetParser { public: shared_ptr parseString(const char *text); }; +class StyleSheetMultiStyleParser : public StyleSheetParser { + +public: + void parseStream(ZLInputStream &stream); + +protected: + virtual void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) = 0; + +private: + void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); + void processAtRule(const std::string &name, const StyleSheetTable::AttributeMap &map); +}; + +class StyleSheetTableParser : public StyleSheetMultiStyleParser { + +public: + StyleSheetTableParser(StyleSheetTable &table); + +private: + void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map); + +private: + StyleSheetTable &myTable; +}; + +class StyleSheetParserWithCache : public StyleSheetMultiStyleParser { + +private: + struct Entry { + const std::string Tag; + const std::string Class; + const StyleSheetTable::AttributeMap Map; + + Entry(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map); + }; + +public: + void applyToTable(StyleSheetTable &table) const; + +private: + void store(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map); + +private: + std::list > myEntries; +}; + +inline StyleSheetParserWithCache::Entry::Entry(const std::string &tag, const std::string &aClass, const StyleSheetTable::AttributeMap &map) : Tag(tag), Class(aClass), Map(map) { +} + #endif /* __STYLESHEETPARSER_H__ */ diff --git a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetTable.h b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetTable.h index cf7821ffb..5ebbb47de 100644 --- a/jni/NativeFormats/fbreader/src/formats/css/StyleSheetTable.h +++ b/jni/NativeFormats/fbreader/src/formats/css/StyleSheetTable.h @@ -64,6 +64,7 @@ private: std::map myPageBreakAfterMap; friend class StyleSheetTableParser; +friend class StyleSheetParserWithCache; }; inline StyleSheetTable::Key::Key(const std::string &tag, const std::string &aClass) : TagName(tag), ClassName(aClass) { diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp index 99a13d677..f65c9c372 100644 --- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp +++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.cpp @@ -260,15 +260,21 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut } const std::string cssFilePath = reader.myPathPrefix + MiscUtil::decodeHtmlURL(href); + //ZLLogger::Instance().registerClass("CSS"); ZLLogger::Instance().println("CSS", "style file: " + cssFilePath); - shared_ptr cssStream = ZLFile(cssFilePath).inputStream(reader.myEncryptionMap); - if (cssStream.isNull()) { - return; + const ZLFile cssFile(cssFilePath); + shared_ptr parser = reader.myFileParsers[cssFile.path()]; + if (parser.isNull()) { + parser = new StyleSheetParserWithCache(); + reader.myFileParsers[cssFile.path()] = parser; + ZLLogger::Instance().println("CSS", "creating stream"); + shared_ptr cssStream = ZLFile(cssFilePath).inputStream(reader.myEncryptionMap); + if (!cssStream.isNull()) { + ZLLogger::Instance().println("CSS", "parsing file"); + parser->parseStream(*cssStream); + } } - ZLLogger::Instance().println("CSS", "parsing file"); - StyleSheetTableParser parser(reader.myStyleSheetTable); - parser.parse(*cssStream); - //reader.myStyleSheetTable.dump(); + parser->applyToTable(reader.myStyleSheetTable); } void XHTMLTagLinkAction::doAtEnd(XHTMLReader&) { diff --git a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h index b7aacd63f..270eeff2a 100644 --- a/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h +++ b/jni/NativeFormats/fbreader/src/formats/xhtml/XHTMLReader.h @@ -112,6 +112,7 @@ private: bool myCurrentParagraphIsEmpty; shared_ptr myStyleParser; shared_ptr myTableParser; + std::map > myFileParsers; XHTMLReadingState myReadState; int myBodyCounter; bool myMarkNextImageAsCover;