From 248b307696e0445966f0d8429b69b0d2f785d406 Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Tue, 7 Jul 2015 18:30:51 +0300 Subject: [PATCH] Major refactoring of CSS support Also, improved support for line breaks. --- .../fbreader/src/bookmodel/BookReader.cpp | 6 + .../fbreader/src/bookmodel/BookReader.h | 1 + .../src/formats/css/StyleSheetParser.cpp | 117 ++++--- .../src/formats/css/StyleSheetParser.h | 12 +- .../src/formats/css/StyleSheetTable.cpp | 313 +++++++++++------- .../src/formats/css/StyleSheetTable.h | 145 ++++++-- .../src/formats/xhtml/XHTMLReader.cpp | 229 +++++-------- .../fbreader/src/formats/xhtml/XHTMLReader.h | 15 +- .../zlibrary/core/src/util/ZLStringUtil.cpp | 19 +- .../zlibrary/core/src/util/ZLStringUtil.h | 5 + .../text/src/area/ZLTextAreaStyle.cpp | 2 + .../src/area/ZLTextArea_prepareTextLine.cpp | 12 +- .../src/area/ZLTextArea_processTextLine.cpp | 9 +- .../zlibrary/text/src/area/ZLTextElement.h | 1 + .../text/src/area/ZLTextParagraphBuilder.cpp | 3 + .../text/src/area/ZLTextParagraphCursor.cpp | 3 + .../text/src/area/ZLTextParagraphCursor.h | 1 + .../zlibrary/text/src/model/ZLTextModel.cpp | 40 ++- .../zlibrary/text/src/model/ZLTextModel.h | 1 + .../text/src/model/ZLTextParagraph.cpp | 54 ++- .../zlibrary/text/src/model/ZLTextParagraph.h | 29 +- 21 files changed, 649 insertions(+), 368 deletions(-) diff --git a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp index aeee7b5..937a134 100644 --- a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp +++ b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp @@ -109,6 +109,12 @@ void BookReader::addFixedHSpace(unsigned char length) { } } +void BookReader::addLineBreak() { + if (myTextParagraphExists) { + myCurrentTextModel->addLineBreak(); + } +} + void BookReader::addControl(const ZLTextStyleEntry &entry) { if (myTextParagraphExists) { flushTextBufferToParagraph(); diff --git a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h index bdd42e1..35cc941 100644 --- a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h +++ b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h @@ -58,6 +58,7 @@ public: void addHyperlinkLabel(const std::string &label); void addHyperlinkLabel(const std::string &label, int paragraphNumber); void addFixedHSpace(unsigned char length); + void addLineBreak(); void addImageReference(const std::string &id, short vOffset = 0); void addImage(const std::string &id, shared_ptr image); diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp index 2c01f49..70d9feb 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp @@ -28,26 +28,22 @@ StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) { } -void StyleSheetTableParser::storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map) { - myTable.addMap(tagName, className, map); +void StyleSheetTableParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) { + myTable.addMap(ZLStringUtil::splitString(selector, " \t+"), map); } -shared_ptr StyleSheetSingleStyleParser::parseString(const char *text, ZLBoolean3 *pageBreakBefore, ZLBoolean3 *pageBreakAfter) { - myReadState = ATTRIBUTE_NAME; - parse(text, strlen(text), true); - shared_ptr control = StyleSheetTable::createControl(NULL, myMap); - bool value; - if (pageBreakBefore && StyleSheetTable::getPageBreakBefore(myMap, value)) { - *pageBreakBefore = value ? B3_TRUE : B3_FALSE; +StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text) { + StyleSheetTable::Style style; + if (text) { + myReadState = ATTRIBUTE_NAME; + parse(text, strlen(text), true); + StyleSheetTable::updateStyle(style, myMap); + reset(); } - if (pageBreakAfter && StyleSheetTable::getPageBreakAfter(myMap, value)) { - *pageBreakAfter = value ? B3_TRUE : B3_FALSE; - } - reset(); - return control; + return style; } -StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false) { +StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false), myAtBlockDepth(0) { } StyleSheetParser::~StyleSheetParser() { @@ -58,6 +54,7 @@ void StyleSheetParser::reset() { myAttributeName.erase(); myReadState = TAG_NAME; myInsideComment = false; + myAtBlockDepth = 0; mySelectors.clear(); myMap.clear(); } @@ -81,7 +78,8 @@ void StyleSheetParser::parse(const char *text, int len, bool final) { const char *start = text; const char *end = text + len; for (const char *ptr = start; ptr != end; ++ptr) { - if (isspace(*ptr)) { + if ((myReadState != TAG_NAME && isspace(*ptr)) || + (myReadState == TAG_NAME && *ptr == ',')) { if (start != ptr) { myWord.append(start, ptr - start); } @@ -121,40 +119,78 @@ bool StyleSheetParser::isControlSymbol(const char symbol) { } } -void StyleSheetParser::storeData(const std::string&, const std::string&, const StyleSheetTable::AttributeMap&) { +void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) { } void StyleSheetParser::processControl(const char control) { switch (control) { case '{': - myReadState = (myReadState == TAG_NAME) ? ATTRIBUTE_NAME : BROKEN; + switch (myReadState) { + case AT_RULE: + myReadState = AT_BLOCK; + myAtBlockDepth = 1; + break; + case AT_BLOCK: + myAtBlockDepth++; + break; + case TAG_NAME: + myReadState = ATTRIBUTE_NAME; + myMap.clear(); + break; + default: + myReadState = BROKEN; + break; + } break; case '}': - if (myReadState != BROKEN) { - for (unsigned int i=0; i 0) { + return; } - storeData(tag, klass, myMap); - } + break; + case AT_RULE: + case BROKEN: + break; + default: + for (unsigned int i=0; i mySelectors; StyleSheetTable::AttributeMap myMap; @@ -67,7 +69,7 @@ public: StyleSheetTableParser(StyleSheetTable &table); private: - void storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map); + void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map); private: StyleSheetTable &myTable; @@ -76,7 +78,7 @@ private: class StyleSheetSingleStyleParser : public StyleSheetParser { public: - shared_ptr parseString(const char *text, ZLBoolean3* pageBreakBefore, ZLBoolean3* pageBreakAfter); + StyleSheetTable::Style parseString(const char *text); }; #endif /* __STYLESHEETPARSER_H__ */ diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp index c426a0c..ded215c 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp @@ -18,32 +18,99 @@ */ #include +#include #include #include "StyleSheetTable.h" -bool StyleSheetTable::isEmpty() const { - return myControlMap.empty() && myPageBreakBeforeMap.empty() && myPageBreakAfterMap.empty(); +static const std::string WILDCARD("*"); + +StyleSheetTable::Element::Element(const std::string &tag, const char *klass, const char* id) : + Name(tag), Classes(ZLStringUtil::splitString(klass, ", \n")) { + if (id) Id = id; } -void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map) { - if ((!tag.empty() || !aClass.empty()) && !map.empty()) { - Key key(tag, aClass); - // This will update the existing element if it already exists - // or create a new one if it wasn't there yet - myControlMap[key] = createControl(myControlMap[key], map); - bool value; - if (getPageBreakBefore(map, value)) { - myPageBreakBeforeMap[key] = value; - } - if (getPageBreakAfter(map, value)) { - myPageBreakAfterMap[key] = value; - } +StyleSheetTable::Selector::Selector(const std::string &selector) { + std::string buf(selector); + const int dot = buf.find('.'); + if (dot >= 0) { + myClass = buf.substr(dot + 1); + buf = buf.substr(0, dot); + } + const int hash = buf.find('#'); + if (hash < 0) { + myType = buf; + } else { + myType = buf.substr(0, hash); + myId = buf.substr(hash + 1); + } + if (myType == "*") myType.clear(); +} + +bool StyleSheetTable::Selector::match(const std::string &pattern, const std::string &str) { + return pattern.empty() || pattern == WILDCARD || pattern == str; +} + +bool StyleSheetTable::Selector::match(const std::string &pattern, const std::vector &strings) { + return pattern.empty() || pattern == WILDCARD || std::find(strings.begin(), strings.end(), pattern) != strings.end(); +} + +void StyleSheetTable::Style::apply(const Style &other) { + TextStyle.apply(other.TextStyle); + if (other.PageBreakBefore != B3_UNDEFINED) { + PageBreakBefore = other.PageBreakBefore; + } + if (other.PageBreakAfter != B3_UNDEFINED) { + PageBreakAfter = other.PageBreakAfter; } } -static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) { +bool StyleSheetTable::Entry::match(const ElementList &stack) const { + if (!stack.empty() && !Selectors.empty()) { + SelectorList::const_reverse_iterator it(Selectors.rbegin()); + ElementList::const_reverse_iterator match_it(stack.rbegin()); + if ((*it).match(*match_it)) { + ++it; + ++match_it; + while (it != Selectors.rend()) { + const Selector &selector = (*it); + while (match_it != stack.rend() && !selector.match(*match_it)) { + ++match_it; + } + if (match_it == stack.rend()) { + break; + } + ++it; + } + if (it == Selectors.rend()) { + return true; + } + } + } + return false; +} + +void StyleSheetTable::addMap(const std::vector &selectors, const AttributeMap &map) { + if ((!selectors.empty()) && !map.empty()) { + // http://www.w3.org/TR/selectors/#specificity + int a = 0, b = 0, c = 0; + SelectorList stack; + for (unsigned int i=0; i 255) a = 255; + if (b > 255) b = 255; + if (c > 255) c = 255; + myEntries.push_back(Entry(stack, (a << 16) + (b << 8) + c, map)); + } +} + +bool StyleSheetTable::parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) { if (!toParse.empty()) { if (ZLStringUtil::stringEndsWith(toParse, "%")) { unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT; @@ -72,14 +139,28 @@ static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntr return false; } -void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) { - StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName); - if (it == map.end()) { - return; +bool StyleSheetTable::parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) { + if (parseLength(toParse, size, unit)) { + // Negative margins do make sense but we don't really support them + if (size < 0) size = 0; + return true; + } else if (toParse == "auto") { + size = 0; + unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL; + return true; + } else { + return false; + } +} + +void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) { + AttributeMap::const_iterator it = map.find(attributeName); + if (it != map.end()) { + const std::vector &values = it->second; + if (!values.empty()) { + setLength(entry, name, values[0]); + } } - const std::vector &values = it->second; - if (!values.empty()) - setLength(entry, name, values[0]); } void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) { @@ -90,48 +171,39 @@ void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Lengt } } -bool StyleSheetTable::doBreakBefore(const std::string &tag, const std::string &aClass) const { - std::map::const_iterator it = myPageBreakBeforeMap.find(Key(tag, aClass)); - if (it != myPageBreakBeforeMap.end()) { - return it->second; +void StyleSheetTable::setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) { + AttributeMap::const_iterator it = map.find(attributeName); + if (it != map.end()) { + const std::vector &values = it->second; + if (!values.empty()) { + setMargin(entry, name, values[0]); + } } - - it = myPageBreakBeforeMap.find(Key("", aClass)); - if (it != myPageBreakBeforeMap.end()) { - return it->second; - } - - it = myPageBreakBeforeMap.find(Key(tag, "")); - if (it != myPageBreakBeforeMap.end()) { - return it->second; - } - - return false; } -bool StyleSheetTable::doBreakAfter(const std::string &tag, const std::string &aClass) const { - std::map::const_iterator it = myPageBreakAfterMap.find(Key(tag, aClass)); - if (it != myPageBreakAfterMap.end()) { - return it->second; +void StyleSheetTable::setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) { + short size; + ZLTextStyleEntry::SizeUnit unit; + if (parseMargin(value, size, unit)) { + entry.setLength(name, size, unit); } - - it = myPageBreakAfterMap.find(Key("", aClass)); - if (it != myPageBreakAfterMap.end()) { - return it->second; - } - - it = myPageBreakAfterMap.find(Key(tag, "")); - if (it != myPageBreakAfterMap.end()) { - return it->second; - } - - return false; } -shared_ptr StyleSheetTable::control(const std::string &tag, const std::string &aClass) const { - std::map >::const_iterator it = - myControlMap.find(Key(tag, aClass)); - return (it != myControlMap.end()) ? it->second : 0; +bool StyleSheetTable::sortBySpecificity(const Entry *e1, const Entry *e2) { + return e1->Specificity < e2->Specificity; +} + +void StyleSheetTable::applyStyles(const ElementList &stack, Style &style) const { + std::vector entries; + for (std::vector::const_iterator i = myEntries.begin(); i != myEntries.end(); ++i) { + if ((*i).match(stack)) { + entries.push_back(&(*i)); + } + } + std::sort(entries.begin(), entries.end(), sortBySpecificity); + for (std::vector::const_iterator e = entries.begin(); e != entries.end(); ++e) { + style.apply((*e)->Style); + } } const std::vector &StyleSheetTable::values(const AttributeMap &map, const std::string &name) { @@ -143,21 +215,17 @@ const std::vector &StyleSheetTable::values(const AttributeMap &map, return emptyVector; } -shared_ptr StyleSheetTable::createControl(shared_ptr entry, const AttributeMap &styles) { - if (entry.isNull()) { - entry = new ZLTextStyleEntry(); - } - +void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &styles) { const std::vector &alignment = values(styles, "text-align"); if (!alignment.empty()) { if (alignment[0] == "justify") { - entry->setAlignmentType(ALIGN_JUSTIFY); + entry.setAlignmentType(ALIGN_JUSTIFY); } else if (alignment[0] == "left") { - entry->setAlignmentType(ALIGN_LEFT); + entry.setAlignmentType(ALIGN_LEFT); } else if (alignment[0] == "right") { - entry->setAlignmentType(ALIGN_RIGHT); + entry.setAlignmentType(ALIGN_RIGHT); } else if (alignment[0] == "center") { - entry->setAlignmentType(ALIGN_CENTER); + entry.setAlignmentType(ALIGN_CENTER); } } @@ -178,23 +246,23 @@ shared_ptr StyleSheetTable::createControl(shared_ptrsetFontModifier(FONT_MODIFIER_BOLD, num >= 600); + entry.setFontModifier(FONT_MODIFIER_BOLD, num >= 600); } } const std::vector &italic = values(styles, "font-style"); if (!italic.empty()) { - entry->setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic"); + entry.setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic"); } const std::vector &variant = values(styles, "font-variant"); if (!variant.empty()) { - entry->setFontModifier(FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps"); + entry.setFontModifier(FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps"); } const std::vector &fontFamily = values(styles, "font-family"); if (!fontFamily.empty() && !fontFamily[0].empty()) { - entry->setFontFamily(fontFamily[0]); + entry.setFontFamily(fontFamily[0]); } short size; @@ -203,19 +271,19 @@ shared_ptr StyleSheetTable::createControl(shared_ptrsetFontSizeMag(-3); + entry.setFontSizeMag(-3); } else if (value == "x-small") { - entry->setFontSizeMag(-2); + entry.setFontSizeMag(-2); } else if (value == "small" || value == "smaller") { - entry->setFontSizeMag(-1); + entry.setFontSizeMag(-1); } else if (value == "medium") { - entry->setFontSizeMag(0); + entry.setFontSizeMag(0); } else if (value == "large" || value == "larger") { - entry->setFontSizeMag(1); + entry.setFontSizeMag(1); } else if (value == "x-large") { - entry->setFontSizeMag(2); + entry.setFontSizeMag(2); } else if (value == "xx-large") { - entry->setFontSizeMag(3); + entry.setFontSizeMag(3); } else { if (parseLength(value, size, unit)) { switch (unit) { @@ -225,16 +293,21 @@ shared_ptr StyleSheetTable::createControl(shared_ptrsetFontSizeMag( - (size < 100 && size > 80) ? -1 : - (size > 100 && size < 120) ? 1 : - (size - 100)/20); + entry.setFontSizeMag((size < 100 && size > 80) ? -1 : + (size > 100 && size < 120) ? 1 : + (size - 100)/20); break; } } } } + const std::vector &opacity = values(styles, "opacity"); + if (!opacity.empty()) { + const int value = (int)(255 * ZLStringUtil::stringToDouble(opacity[0], 1)); + entry.setOpacity((unsigned char)((value < 0) ? 0 : (value > 255) ? 255 : value)); + } + std::vector margins = values(styles, "margin"); if (!margins.empty() && margins.back() == "!important") { // Ignore the "!important" modifier for now @@ -242,78 +315,82 @@ shared_ptr StyleSheetTable::createControl(shared_ptrsetLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); + if (parseMargin(margins[0], size, unit)) { + entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); } break; case 2: - if (parseLength(margins[0], size, unit)) { - entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit); + if (parseMargin(margins[0], size, unit)) { + entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit); } - if (parseLength(margins[1], size, unit)) { - entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); + if (parseMargin(margins[1], size, unit)) { + entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); } break; case 3: - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); - if (parseLength(margins[1], size, unit)) { - entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); - entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); + if (parseMargin(margins[1], size, unit)) { + entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit); + entry.setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit); } - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]); break; case 4: - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); - setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]); - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]); - setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[3]); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); + setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]); + setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[3]); break; } - setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left"); - setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right"); - setLength(*entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent"); - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top"); - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top"); - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom"); - setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom"); - - return entry; + setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left"); + setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right"); + setLength(entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent"); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top"); + setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top"); + setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom"); + setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom"); } -bool StyleSheetTable::getPageBreakBefore(const AttributeMap &map, bool &value) { +bool StyleSheetTable::getPageBreakBefore(const AttributeMap &map, ZLBoolean3 &value) { const std::vector &pbb = values(map, "page-break-before"); if (!pbb.empty()) { if ((pbb[0] == "always") || (pbb[0] == "left") || (pbb[0] == "right")) { - value = true; + value = B3_TRUE; return true; } else if (pbb[0] == "avoid") { - value = false; + value = B3_FALSE; return true; } } return false; } -bool StyleSheetTable::getPageBreakAfter(const AttributeMap &map, bool &value) { +bool StyleSheetTable::getPageBreakAfter(const AttributeMap &map, ZLBoolean3 &value) { const std::vector &pba = values(map, "page-break-after"); if (!pba.empty()) { if ((pba[0] == "always") || (pba[0] == "left") || (pba[0] == "right")) { - value = true; + value = B3_TRUE; return true; } else if (pba[0] == "avoid") { - value = false; + value = B3_FALSE; return true; } } return false; } + +void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) { + updateTextStyle(style.TextStyle, map); + getPageBreakBefore(map, style.PageBreakBefore); + getPageBreakAfter(map, style.PageBreakAfter); +} diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h index 97cb205..0b70011 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h @@ -27,50 +27,151 @@ #include #include +#include class StyleSheetTable { public: + struct Element { + Element(const std::string &tag, const char *klass, const char* id); + std::string Name; + std::vector Classes; + std::string Id; + }; + + class Selector { + public: + Selector(const std::string &type, const std::string &klass, const std::string &id); + Selector(const std::string &type, const std::string &klass); + Selector(const std::string &selector); + Selector(const Selector &other); + Selector(); + + Selector &operator = (const Selector &other); + bool operator == (const Selector &other) const; + bool operator != (const Selector &other) const; + bool operator < (const Selector &other) const; + bool match(const Element &element) const; + + static bool match(const std::string &pattern, const std::string &str); + static bool match(const std::string &pattern, const std::vector &strings); + + const std::string &type() const; + const std::string &klass() const; + const std::string &id() const; + int a() const; + int b() const; + int c() const; + + private: + std::string myType; + std::string myClass; + std::string myId; + }; + + typedef std::vector ElementList; + typedef std::vector SelectorList; typedef std::map > AttributeMap; - static shared_ptr createControl(shared_ptr entry, const AttributeMap &map); - static bool getPageBreakBefore(const AttributeMap &map, bool &value); - static bool getPageBreakAfter(const AttributeMap &map, bool &value); + + struct Style { + Style(); + Style(const Style &other); + Style(const AttributeMap &map); + + Style &operator = (const Style &other); + void apply(const Style &other); + + ZLTextStyleEntry TextStyle; + ZLBoolean3 PageBreakBefore; + ZLBoolean3 PageBreakAfter; + }; + + typedef std::vector