diff --git a/app/data/default/styles.xml b/app/data/default/styles.xml
index f4d8aea..464da94 100644
--- a/app/data/default/styles.xml
+++ b/app/data/default/styles.xml
@@ -1,24 +1,27 @@
-
+
-
-
-
-
-
+
-
+
+
+
+
+
+
+
+
@@ -27,14 +30,12 @@
-
-
-
+
-
+
diff --git a/app/src/BooksSettings.cpp b/app/src/BooksSettings.cpp
index aa9d5d4..e4944a1 100644
--- a/app/src/BooksSettings.cpp
+++ b/app/src/BooksSettings.cpp
@@ -65,7 +65,7 @@ public:
bool isDecorated() const;
- const std::string &fontFamily() const;
+ const std::vector &fontFamilies() const;
int fontSize() const;
bool bold() const;
@@ -102,10 +102,10 @@ BooksSettings::TextStyle::isDecorated() const
return iDefaultStyle->isDecorated();
}
-const std::string&
-BooksSettings::TextStyle::fontFamily() const
+const std::vector&
+BooksSettings::TextStyle::fontFamilies() const
{
- return iDefaultStyle->fontFamily();
+ return iDefaultStyle->fontFamilies();
}
int
diff --git a/app/src/BooksTextStyle.cpp b/app/src/BooksTextStyle.cpp
index 0a88fec..45924b9 100644
--- a/app/src/BooksTextStyle.cpp
+++ b/app/src/BooksTextStyle.cpp
@@ -54,6 +54,11 @@ shared_ptr BooksTextStyle::defaults()
return style;
}
+BooksTextStyle::BooksTextStyle()
+{
+ iFontFamilies.push_back(Default::FONT_FAMILY);
+}
+
bool
BooksTextStyle::equalLayout(
shared_ptr aStyle1,
@@ -74,9 +79,9 @@ bool BooksTextStyle::isDecorated() const
return false;
}
-const std::string& BooksTextStyle::fontFamily() const
+const std::vector& BooksTextStyle::fontFamilies() const
{
- return Default::FONT_FAMILY;
+ return iFontFamilies;
}
int BooksTextStyle::fontSize() const
diff --git a/app/src/BooksTextStyle.h b/app/src/BooksTextStyle.h
index 3996a84..f4e92c8 100644
--- a/app/src/BooksTextStyle.h
+++ b/app/src/BooksTextStyle.h
@@ -49,18 +49,18 @@ private:
static weak_ptr gInstance;
private:
- BooksTextStyle() {}
+ BooksTextStyle();
public:
bool isDecorated() const;
- const std::string &fontFamily() const;
+ const std::vector& fontFamilies() const;
int fontSize() const;
bool bold() const;
bool italic() const;
- const std::string &colorStyle() const;
+ const std::string& colorStyle() const;
short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const;
short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const;
@@ -73,6 +73,9 @@ public:
double lineSpace() const;
bool allowHyphenations() const;
+
+private:
+ std::vector iFontFamilies;
};
#endif // BOOKS_TEXT_STYLE_H
diff --git a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp
index 868a27c..ae136f5 100644
--- a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp
+++ b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.cpp
@@ -117,6 +117,13 @@ void BookReader::addLineBreak() {
}
}
+void BookReader::addEmpty() {
+ if (myTextParagraphExists) {
+ flushTextBufferToParagraph();
+ myCurrentTextModel->addEmpty();
+ }
+}
+
void BookReader::addControl(const ZLTextStyleEntry &entry) {
if (myTextParagraphExists) {
flushTextBufferToParagraph();
@@ -189,7 +196,7 @@ void BookReader::addContentsData(const std::string &data) {
void BookReader::flushTextBufferToParagraph() {
myCurrentTextModel->addText(myBuffer);
- myBuffer.clear();
+ myBuffer.resize(0);
}
void BookReader::addImage(const std::string &id, shared_ptr image) {
@@ -239,7 +246,7 @@ void BookReader::beginContentsParagraph(int referenceNumber) {
ZLTextTreeParagraph *peek = myTOCStack.empty() ? 0 : myTOCStack.top();
if (!myContentsBuffer.empty()) {
contentsModel.addText(myContentsBuffer);
- myContentsBuffer.clear();
+ myContentsBuffer.resize(0);
myLastTOCParagraphIsEmpty = false;
}
if (myLastTOCParagraphIsEmpty) {
@@ -259,7 +266,7 @@ void BookReader::endContentsParagraph() {
ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel;
if (!myContentsBuffer.empty()) {
contentsModel.addText(myContentsBuffer);
- myContentsBuffer.clear();
+ myContentsBuffer.resize(0);
myLastTOCParagraphIsEmpty = false;
}
if (myLastTOCParagraphIsEmpty) {
diff --git a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h
index 35cc941..dce9403 100644
--- a/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h
+++ b/fbreader/fbreader/fbreader/src/bookmodel/BookReader.h
@@ -59,6 +59,7 @@ public:
void addHyperlinkLabel(const std::string &label, int paragraphNumber);
void addFixedHSpace(unsigned char length);
void addLineBreak();
+ void addEmpty();
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/bookmodel/FBTextKind.h b/fbreader/fbreader/fbreader/src/bookmodel/FBTextKind.h
index 0f255e0..1b5a2c5 100644
--- a/fbreader/fbreader/fbreader/src/bookmodel/FBTextKind.h
+++ b/fbreader/fbreader/fbreader/src/bookmodel/FBTextKind.h
@@ -65,6 +65,7 @@ enum FBTextKind {
H6 = 36,
EXTERNAL_HYPERLINK = 37,
BOOK_HYPERLINK = 38,
+ BLOCKQUOTE = 39
};
#endif /* __FBTEXTKIND_H__ */
diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp
index 70d9feb..992e260 100644
--- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp
+++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp
@@ -35,28 +35,39 @@ void StyleSheetTableParser::storeData(const std::string &selector, const StyleSh
StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text) {
StyleSheetTable::Style style;
if (text) {
- myReadState = ATTRIBUTE_NAME;
+ reset(ATTRIBUTE_NAME);
parse(text, strlen(text), true);
+ if (!myStateStack.empty()) {
+ switch (myStateStack.top()) {
+ case ATTRIBUTE_VALUE_SPACE:
+ case ATTRIBUTE_VALUE_COMMA:
+ finishAttributeValue();
+ break;
+ default:
+ break;
+ }
+ }
StyleSheetTable::updateStyle(style, myMap);
- reset();
}
return style;
}
-StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false), myAtBlockDepth(0) {
+StyleSheetParser::StyleSheetParser() :
+ myBuffer1(0), myBuffer2(0), myBuffer3(0) {
+ myStateStack.push(SELECTOR);
}
StyleSheetParser::~StyleSheetParser() {
}
-void StyleSheetParser::reset() {
- myWord.erase();
- myAttributeName.erase();
- myReadState = TAG_NAME;
- myInsideComment = false;
- myAtBlockDepth = 0;
- mySelectors.clear();
+void StyleSheetParser::reset(ReadState state) {
+ myWord.resize(0);
+ myAttributeName.resize(0);
+ myStateStack = std::stack();
+ myStateStack.push(state);
+ mySelectors.resize(0);
myMap.clear();
+ myBuffer1 = myBuffer2 = myBuffer3 = 0;
}
void StyleSheetParser::parse(ZLInputStream &stream) {
@@ -78,165 +89,279 @@ 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 ((myReadState != TAG_NAME && isspace(*ptr)) ||
- (myReadState == TAG_NAME && *ptr == ',')) {
- if (start != ptr) {
- myWord.append(start, ptr - start);
- }
- processWord(myWord);
- myWord.erase();
- start = ptr + 1;
- } else if (isControlSymbol(*ptr)) {
- if (start != ptr) {
- myWord.append(start, ptr - start);
- }
- processWord(myWord);
- myWord.erase();
- if (!myInsideComment) {
- processControl(*ptr);
- }
- start = ptr + 1;
- }
- }
- if (start < end) {
- myWord.append(start, end - start);
- if (final) {
- processWord(myWord);
- myWord.erase();
- }
- }
-}
-
-bool StyleSheetParser::isControlSymbol(const char symbol) {
- switch (symbol) {
- case '{':
- case '}':
- case ';':
- case ':':
- return true;
- default:
- return false;
+ processChar1(*ptr);
}
}
void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) {
}
-void StyleSheetParser::processControl(const char control) {
- switch (control) {
- case '{':
- 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;
+/* Converts \r\n into \n */
+void StyleSheetParser::processChar1(char c) {
+ if (myBuffer1 == '\r') {
+ myBuffer1 = 0;
+ if (c == '\n') {
+ processChar2('\n');
+ } else {
+ processChar2('\r');
+ }
+ } else if (c == '\r') {
+ myBuffer1 = '\r';
+ } else {
+ processChar2(c);
+ }
+}
+
+/* Glues continued lines together */
+void StyleSheetParser::processChar2(char c) {
+ if (myBuffer2 == '\\') {
+ myBuffer2 = 0;
+ if (c != '\n') {
+ processChar3('\\');
+ processChar3(c);
+ }
+ } else if (c == '\\') {
+ myBuffer2 = '\\';
+ } else {
+ processChar3(c);
+ }
+}
+
+/* Handles comments */
+void StyleSheetParser::processChar3(char c) {
+ switch (myStateStack.top()) {
+ case COMMENT:
+ if (myBuffer3 == '*' && c == '/') {
+ myBuffer3 = 0;
+ myStateStack.pop();
+ } else {
+ myBuffer3 = (c == '*') ? '*' : 0;
+ }
+ break;
+ case STRING_LITERAL_SINGLE:
+ case STRING_LITERAL_DOUBLE:
+ processChar4(c);
+ break;
+ default:
+ if (myBuffer3 == '/' && c == '*') {
+ myStateStack.push(COMMENT);
+ } else {
+ if (myBuffer3) processChar4(myBuffer3);
+ if (c == '/') {
+ myBuffer3 = c;
+ } else {
+ myBuffer3 = 0;
+ processChar4(c);
}
+ }
+ break;
+ }
+}
+
+/* Handles clean input */
+void StyleSheetParser::processChar4(char c) {
+ switch (myStateStack.top()) {
+ case SELECTOR:
+ switch (c) {
+ case ',':
+ if (ZLStringUtil::stripWhiteSpaces(myWord)) {
+ mySelectors.push_back(myWord);
+ myWord.resize(0);
+ }
+ break;
+ case '{':
+ if (ZLStringUtil::stripWhiteSpaces(myWord)) mySelectors.push_back(myWord);
+ if (!mySelectors.empty()) {
+ if (mySelectors[0][0] == '@') {
+ // Ignore AT-rules
+ mySelectors.resize(0);
+ myStateStack.push(SKIP_BLOCK_CURLY);
+ } else {
+ myMap.clear();
+ myStateStack.push(ATTRIBUTE_NAME);
+ }
+ } else {
+ myStateStack.push(SKIP_BLOCK_CURLY);
+ }
+ myWord.resize(0);
+ break;
+ default:
+ if (!isspace(c) || !myWord.empty()) {
+ myWord.append(1, c);
+ }
+ break;
+ }
+ break;
+
+ case ATTRIBUTE_NAME:
+ switch (c) {
+ case ':':
+ if (ZLStringUtil::stripWhiteSpaces(myWord)) {
+ myAttributeName = myWord;
+ myMap[myAttributeName].resize(0);
+ myWord.resize(0);
+ static const std::string FONT_FAMILY("font-family");
+ if (myAttributeName == FONT_FAMILY) {
+ myStateStack.top() = ATTRIBUTE_VALUE_COMMA;
+ } else {
+ myStateStack.top() = ATTRIBUTE_VALUE_SPACE;
+ }
+ } else {
+ finishAttribute();
+ myStateStack.top() = ATTRIBUTE_IGNORE;
+ }
+ break;
+ case '\n':
+ case ';':
+ finishAttribute();
break;
case '}':
- switch (myReadState) {
- case AT_BLOCK:
- if (--myAtBlockDepth > 0) {
- return;
- }
- break;
- case AT_RULE:
- case BROKEN:
- break;
- default:
- for (unsigned int i=0; i 0) {
- processWordWithoutComments(word.substr(0, index));
- }
- }
- if (index == -1) {
- break;
- }
- myInsideComment = !myInsideComment;
- word.erase(0, index + 2);
- }
-}
-
-void StyleSheetParser::processWordWithoutComments(std::string word) {
- switch (myReadState) {
- case AT_RULE:
- case AT_BLOCK:
- break;
- case TAG_NAME:
- ZLStringUtil::stripWhiteSpaces(word);
- if (!word.empty()) {
- if (word[0] == '@') {
- myReadState = AT_RULE;
-
- } else {
- mySelectors.push_back(word);
}
}
break;
- case ATTRIBUTE_NAME:
- myAttributeName = word;
- myMap[myAttributeName].clear();
- break;
- case ATTRIBUTE_VALUE:
- myMap[myAttributeName].push_back(word);
- break;
- case BROKEN:
- break;
+ }
+ break;
+
+ case COMMENT: // Comments are handled elsewhere
+ break;
}
}
+
+void StyleSheetParser::finishAttributeValue() {
+ if (ZLStringUtil::stripWhiteSpaces(myWord)) {
+ myMap[myAttributeName].push_back(myWord);
+ myWord.resize(0);
+ }
+}
+
+void StyleSheetParser::finishAttribute() {
+ myAttributeName.resize(0);
+ myWord.resize(0);
+}
+
+void StyleSheetParser::finishRule() {
+ for (unsigned int i=0; i
+
class ZLInputStream;
class StyleSheetParser {
@@ -39,26 +41,37 @@ protected:
virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map);
private:
- bool isControlSymbol(const char symbol);
- void processWord(std::string &word);
- void processWordWithoutComments(std::string word);
- void processControl(const char control);
+ enum ReadState {
+ COMMENT,
+ SELECTOR,
+ ATTRIBUTE_NAME,
+ ATTRIBUTE_VALUE_SPACE,
+ ATTRIBUTE_VALUE_COMMA,
+ ATTRIBUTE_IGNORE,
+ STRING_LITERAL_SINGLE = '\'',
+ STRING_LITERAL_DOUBLE = '"',
+ SKIP_BLOCK_CURLY = '}',
+ SKIP_BLOCK_SQUARE = ']'
+ };
+
+ void reset(ReadState state);
+ void processChar1(char c);
+ void processChar2(char c);
+ void processChar3(char c);
+ void processChar4(char c);
+ void finishRule();
+ void finishAttribute();
+ void finishAttributeValue();
private:
std::string myWord;
std::string myAttributeName;
- enum {
- AT_RULE,
- AT_BLOCK,
- TAG_NAME,
- ATTRIBUTE_NAME,
- ATTRIBUTE_VALUE,
- BROKEN,
- } myReadState;
- bool myInsideComment;
- int myAtBlockDepth;
+ std::stack myStateStack;
std::vector mySelectors;
StyleSheetTable::AttributeMap myMap;
+ char myBuffer1;
+ char myBuffer2;
+ char myBuffer3;
friend class StyleSheetSingleStyleParser;
};
@@ -81,4 +94,6 @@ public:
StyleSheetTable::Style parseString(const char *text);
};
+inline void StyleSheetParser::reset() { reset(SELECTOR); }
+
#endif /* __STYLESHEETPARSER_H__ */
diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp
index ded215c..33bbc69 100644
--- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp
+++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp
@@ -64,6 +64,30 @@ void StyleSheetTable::Style::apply(const Style &other) {
if (other.PageBreakAfter != B3_UNDEFINED) {
PageBreakAfter = other.PageBreakAfter;
}
+ if (other.WhiteSpace != WS_UNDEFINED) {
+ WhiteSpace = other.WhiteSpace;
+ }
+ if (other.DisplayNone) {
+ DisplayNone = other.DisplayNone;
+ }
+}
+
+void StyleSheetTable::Style::inherit(const Style &other) {
+ TextStyle.inherit(other.TextStyle);
+ if (other.WhiteSpace != WS_UNDEFINED) {
+ WhiteSpace = other.WhiteSpace;
+ }
+ if (other.DisplayNone) {
+ DisplayNone = other.DisplayNone;
+ }
+}
+
+bool StyleSheetTable::Style::equals(const Style &other) const {
+ return PageBreakBefore == other.PageBreakBefore &&
+ PageBreakAfter == other.PageBreakAfter &&
+ WhiteSpace == other.WhiteSpace &&
+ DisplayNone == other.DisplayNone &&
+ TextStyle.equals(other.TextStyle);
}
bool StyleSheetTable::Entry::match(const ElementList &stack) const {
@@ -93,54 +117,28 @@ bool StyleSheetTable::Entry::match(const ElementList &stack) const {
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;
- size = atoi(toParse.c_str());
- return true;
- } else if (ZLStringUtil::stringEndsWith(toParse, "em")) {
- unit = ZLTextStyleEntry::SIZE_UNIT_EM_100;
- size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
- return true;
- } else if (ZLStringUtil::stringEndsWith(toParse, "ex")) {
- unit = ZLTextStyleEntry::SIZE_UNIT_EX_100;
- size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
- return true;
- } else if (ZLStringUtil::stringEndsWith(toParse, "px") ||
- ZLStringUtil::stringEndsWith(toParse, "pt") ||
- ZLStringUtil::stringEndsWith(toParse, "pc")) {
- unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
- size = atoi(toParse.c_str());
- return true;
- } else if (toParse == "0") {
- unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
- size = 0;
- return true;
+ Style style(map);
+ if (!style.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, style));
}
}
- return false;
}
bool StyleSheetTable::parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
- if (parseLength(toParse, size, unit)) {
+ if (ZLTextStyleEntry::parseLength(toParse, size, unit)) {
// Negative margins do make sense but we don't really support them
if (size < 0) size = 0;
return true;
@@ -166,7 +164,7 @@ void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Lengt
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
short size;
ZLTextStyleEntry::SizeUnit unit;
- if (parseLength(value, size, unit)) {
+ if (ZLTextStyleEntry::parseLength(value, size, unit)) {
entry.setLength(name, size, unit);
}
}
@@ -200,9 +198,11 @@ void StyleSheetTable::applyStyles(const ElementList &stack, Style &style) const
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);
+ if (!entries.empty()) {
+ std::sort(entries.begin(), entries.end(), sortBySpecificity);
+ for (std::vector::const_iterator e = entries.begin(); e != entries.end(); ++e) {
+ style.apply((*e)->Style);
+ }
}
}
@@ -216,60 +216,77 @@ const std::vector &StyleSheetTable::values(const AttributeMap &map,
}
void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &styles) {
- const std::vector &alignment = values(styles, "text-align");
+ static const std::string TEXT_ALIGN("text-align");
+ const std::vector &alignment = values(styles, TEXT_ALIGN);
if (!alignment.empty()) {
- if (alignment[0] == "justify") {
+ const std::string &value = alignment.at(0);
+ if (value == "justify") {
entry.setAlignmentType(ALIGN_JUSTIFY);
- } else if (alignment[0] == "left") {
+ } else if (value == "left") {
entry.setAlignmentType(ALIGN_LEFT);
- } else if (alignment[0] == "right") {
+ } else if (value == "right") {
entry.setAlignmentType(ALIGN_RIGHT);
- } else if (alignment[0] == "center") {
+ } else if (value == "center") {
entry.setAlignmentType(ALIGN_CENTER);
}
+ } else {
+ static const std::string FLOAT("float");
+ const std::vector &floatVal = values(styles, FLOAT);
+ if (!floatVal.empty()) {
+ const std::string &value = floatVal.at(0);
+ if (value == "left") {
+ entry.setAlignmentType(ALIGN_LEFT);
+ } else if (value == "right") {
+ entry.setAlignmentType(ALIGN_RIGHT);
+ }
+ }
}
- const std::vector &bold = values(styles, "font-weight");
- if (!bold.empty()) {
+ static const std::string FONT_WEIGHT("font-weight");
+ const std::vector &weight = values(styles, FONT_WEIGHT);
+ if (!weight.empty()) {
int num = -1;
- if (bold[0] == "bold") {
+ const std::string &value = weight.at(0);
+ if (value == "bold") {
num = 700;
- } else if (bold[0] == "normal") {
+ } else if (value == "normal") {
num = 400;
- } else if ((bold[0].length() == 3) &&
- (bold[0][1] == '0') &&
- (bold[0][2] == '0') &&
- (bold[0][0] >= '1') &&
- (bold[0][0] <= '9')) {
- num = 100 * (bold[0][0] - '0');
- } else if (bold[0] == "bolder") {
- } else if (bold[0] == "lighter") {
+ } else if ((value.length() == 3) &&
+ (value[1] == '0') &&
+ (value[2] == '0') &&
+ (value[0] >= '1') &&
+ (value[0] <= '9')) {
+ num = 100 * (value[0] - '0');
+ } else if (value == "bolder") {
+ } else if (value == "lighter") {
}
if (num != -1) {
entry.setFontModifier(FONT_MODIFIER_BOLD, num >= 600);
}
}
- const std::vector &italic = values(styles, "font-style");
+ static const std::string FONT_STYLE("font-style");
+ const std::vector &italic = values(styles, FONT_STYLE);
if (!italic.empty()) {
entry.setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic");
}
- const std::vector &variant = values(styles, "font-variant");
+ static const std::string FONT_VARIANT("font-variant");
+ const std::vector &variant = values(styles, FONT_VARIANT);
if (!variant.empty()) {
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]);
- }
+ static const std::string FONT_FAMILY("font-family");
+ const std::vector &fontFamilies = values(styles, FONT_FAMILY);
+ if (!fontFamilies.empty()) entry.setFontFamilies(fontFamilies);
short size;
ZLTextStyleEntry::SizeUnit unit;
- const std::vector &fontSize = values(styles, "font-size");
+ static const std::string FONT_SIZE("font-size");
+ const std::vector &fontSize = values(styles, FONT_SIZE);
if (!fontSize.empty()) {
- std::string value = fontSize[0];
+ const std::string &value = fontSize.at(0);
if (value == "xx-small") {
entry.setFontSizeMag(-3);
} else if (value == "x-small") {
@@ -285,7 +302,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
} else if (value == "xx-large") {
entry.setFontSizeMag(3);
} else {
- if (parseLength(value, size, unit)) {
+ if (ZLTextStyleEntry::parseLength(value, size, unit)) {
switch (unit) {
case ZLTextStyleEntry::SIZE_UNIT_PIXEL:
// What to do with pixels?
@@ -293,26 +310,68 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
case ZLTextStyleEntry::SIZE_UNIT_EM_100:
case ZLTextStyleEntry::SIZE_UNIT_EX_100:
case ZLTextStyleEntry::SIZE_UNIT_PERCENT:
- entry.setFontSizeMag((size < 100 && size > 80) ? -1 :
- (size > 100 && size < 120) ? 1 :
- (size - 100)/20);
+ // Percent to magnification mapping algorithm
+ // matches ZLTextForcedStyle::fontSize() logic
+ if (size < 100) {
+ if (size >= 80) {
+ entry.setFontSizeMag(-1);
+ } else {
+ int mag;
+ unsigned int x1 = 5*100, x2 = 6*size;
+ // Too many iterations would cause 32-bit
+ // overflow and generally don't make sense.
+ for (mag=1; mag<=6 && x1 100) {
+ if (size < 120) {
+ entry.setFontSizeMag(1);
+ } else {
+ int mag;
+ unsigned int x1 = 6*100, x2 = 5*size;
+ for (mag=1; mag<=6 && x1 &opacity = values(styles, "opacity");
+ static const std::string OPACITY("opacity");
+ 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") {
+ // Margins will overwrite padding, sorry
+ static const std::string PADDING_TOP("padding-top");
+ static const std::string PADDING_BOTTOM("padding-bottom");
+ setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, PADDING_TOP);
+ setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, PADDING_BOTTOM);
+
+ static const std::string MARGIN("margin");
+ std::vector margins = values(styles, MARGIN);
+ if (!margins.empty()) {
// Ignore the "!important" modifier for now
- margins.pop_back();
+ if (margins.back() == "!important") {
+ margins.pop_back();
+ } else if (margins.back() == "important") {
+ margins.pop_back();
+ if (!margins.empty() && margins.back() == "!") {
+ margins.pop_back();
+ }
+ }
}
+
switch (margins.size()) {
case 1:
if (parseMargin(margins[0], size, unit)) {
@@ -348,49 +407,61 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
break;
}
- 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");
+ static const std::string MARGIN_LEFT("margin-left");
+ static const std::string MARGIN_RIGHT("margin-right");
+ static const std::string MARGIN_TOP("margin-top");
+ static const std::string MARGIN_BOTTOM("margin-bottom");
+ static const std::string TEXT_INDENT("text-indent");
+
+ 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);
+ setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, MARGIN_BOTTOM);
}
-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")) {
+void StyleSheetTable::getPageBreakValue(const std::vector &values, ZLBoolean3 &value) {
+ if (!values.empty()) {
+ const std::string &first = values.at(0);
+ if ((first == "always") ||
+ (first == "left") ||
+ (first == "right")) {
value = B3_TRUE;
- return true;
- } else if (pbb[0] == "avoid") {
+ } else if (first == "avoid") {
value = B3_FALSE;
- return true;
}
}
- return false;
-}
-
-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 = B3_TRUE;
- return true;
- } else if (pba[0] == "avoid") {
- 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);
+
+ static const std::string PAGE_BREAK_BEFORE("page-break-before");
+ getPageBreakValue(values(map, PAGE_BREAK_BEFORE), style.PageBreakBefore);
+
+ static const std::string PAGE_BREAK_AFTER("page-break-after");
+ getPageBreakValue(values(map, PAGE_BREAK_AFTER), style.PageBreakAfter);
+
+ static const std::string WHITE_SPACE("white-space");
+ const std::vector &whiteSpace = values(map, WHITE_SPACE);
+ if (!whiteSpace.empty()) {
+ const std::string &value = whiteSpace.at(0);
+ if (value == "normal") {
+ style.WhiteSpace = WS_NORMAL;
+ } else if (value == "nowrap") {
+ style.WhiteSpace = WS_NOWRAP;
+ } else if (value == "pre") {
+ style.WhiteSpace = WS_PRE;
+ } else if (value == "pre-wrap") {
+ style.WhiteSpace = WS_PRE_WRAP;
+ } else if (value == "pre-line") {
+ style.WhiteSpace = WS_PRE_LINE;
+ }
+ }
+
+ static const std::string DISPLAY("display");
+ const std::vector &display = values(map, DISPLAY);
+ if (!display.empty() && display[0] == "none") {
+ style.DisplayNone = true;
+ }
}
diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h
index 0b70011..896df12 100644
--- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h
+++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h
@@ -73,29 +73,43 @@ public:
typedef std::vector SelectorList;
typedef std::map > AttributeMap;
+ typedef enum {
+ WS_UNDEFINED,
+ WS_NORMAL,
+ WS_NOWRAP,
+ WS_PRE,
+ WS_PRE_WRAP,
+ WS_PRE_LINE
+ } WhiteSpaceValue;
+
struct Style {
Style();
Style(const Style &other);
Style(const AttributeMap &map);
Style &operator = (const Style &other);
- void apply(const Style &other);
+ bool operator == (const Style &other) const;
+ bool equals(const Style &other) const;
+ void apply(const Style &other);
+ void inherit(const Style &other);
+ bool empty() const;
ZLTextStyleEntry TextStyle;
ZLBoolean3 PageBreakBefore;
ZLBoolean3 PageBreakAfter;
+ WhiteSpaceValue WhiteSpace;
+ bool DisplayNone;
};
typedef std::vector