From 97ce479c5008ebaf2d294cd5c4b72d4a0e08022a Mon Sep 17 00:00:00 2001 From: Slava Monich Date: Tue, 11 Aug 2015 13:53:21 +0300 Subject: [PATCH] [fbreader] Added support for text color Specified with CSS color attribute --- app/src/BooksPaintContext.cpp | 14 +- app/src/BooksPaintContext.h | 10 + app/src/BooksTextView.cpp | 41 ++- app/src/BooksTextView.h | 7 +- .../src/formats/css/StyleSheetParser.cpp | 9 +- .../src/formats/css/StyleSheetParser.h | 2 + .../src/formats/css/StyleSheetTable.cpp | 260 +++++++++++++++++- .../src/formats/css/StyleSheetTable.h | 13 +- .../fbreader/zlibrary/core/src/util/ZLColor.h | 4 + .../zlibrary/core/src/util/ZLStringUtil.cpp | 26 ++ .../zlibrary/core/src/util/ZLStringUtil.h | 12 + .../zlibrary/text/src/model/ZLTextModel.cpp | 7 + .../text/src/model/ZLTextParagraph.cpp | 21 +- .../zlibrary/text/src/model/ZLTextParagraph.h | 14 +- .../text/src/style/ZLTextDecoratedStyle.cpp | 12 + .../text/src/style/ZLTextDecoratedStyle.h | 4 +- .../zlibrary/text/src/style/ZLTextStyle.cpp | 9 + .../zlibrary/text/src/style/ZLTextStyle.h | 3 + .../text/src/style/ZLTextStyleCollection.cpp | 20 +- test/test-css/data/basic/in.css | 8 + test/test-css/data/basic/out.css | 18 ++ test/test-css/data/test1/out.css | 16 ++ test/test-css/main.cpp | 4 + 23 files changed, 483 insertions(+), 51 deletions(-) diff --git a/app/src/BooksPaintContext.cpp b/app/src/BooksPaintContext.cpp index c2a3f11..e621696 100644 --- a/app/src/BooksPaintContext.cpp +++ b/app/src/BooksPaintContext.cpp @@ -47,13 +47,13 @@ static const std::string HELVETICA = "Helvetica"; BooksPaintContext::BooksPaintContext() : iPainter(NULL), iWidth(0), iHeight(0), - iSpaceWidth(0), iDescent(0) + iSpaceWidth(0), iDescent(0), iInvertColors(false) { } BooksPaintContext::BooksPaintContext(int aWidth, int aHeight) : iPainter(NULL), iWidth(aWidth), iHeight(aHeight), - iSpaceWidth(0), iDescent(0) + iSpaceWidth(0), iDescent(0), iInvertColors(false) { } @@ -199,8 +199,7 @@ void BooksPaintContext::drawImage(int x, int y, const ZLImageData& image, QSize(imageWidth(image, width, height, type), imageHeight(image, width, height, type)), Qt::KeepAspectRatio, - Qt::SmoothTransformation - ); + Qt::SmoothTransformation); iPainter->drawImage(x, y - scaled.height(), scaled); } } @@ -255,3 +254,10 @@ int BooksPaintContext::height() const { return iHeight; } + +ZLColor BooksPaintContext::realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const +{ + return iInvertColors ? + ZLColor(255-aRed, 255-aGreen, 255-aBlue) : + ZLColor(aRed, aGreen, aBlue); +} diff --git a/app/src/BooksPaintContext.h b/app/src/BooksPaintContext.h index 7db4de7..5777ef5 100644 --- a/app/src/BooksPaintContext.h +++ b/app/src/BooksPaintContext.h @@ -36,6 +36,7 @@ #include "BooksTypes.h" +#include "ZLColor.h" #include "ZLPaintContext.h" #include @@ -86,12 +87,17 @@ public: void fillRectangle(int x0, int y0, int x1, int y1); void drawFilledCircle(int x, int y, int r); + void setInvertColors(bool aInvertColors); + ZLColor realColor(quint8 aRed, quint8 aGreen, quint8 aBlue) const; + ZLColor realColor(const ZLColor aColor) const; + private: QPainter* iPainter; int iWidth; int iHeight; mutable int iSpaceWidth; int iDescent; + bool iInvertColors; QFont iFont; }; @@ -108,5 +114,9 @@ inline QSize BooksPaintContext::size() const inline QColor qtColor(const ZLColor& aColor) { return QColor(aColor.Red, aColor.Green, aColor.Blue); } +inline ZLColor BooksPaintContext::realColor(const ZLColor aColor) const + { return realColor(aColor.Red, aColor.Green, aColor.Blue); } +inline void BooksPaintContext::setInvertColors(bool aInvertColors) + { iInvertColors = aInvertColors; } #endif /* BOOKS_PAINT_CONTEXT_H */ diff --git a/app/src/BooksTextView.cpp b/app/src/BooksTextView.cpp index 2b11444..a29dd9d 100644 --- a/app/src/BooksTextView.cpp +++ b/app/src/BooksTextView.cpp @@ -34,18 +34,20 @@ #include "BooksTextView.h" #include "BooksTextStyle.h" +#include "ZLStringUtil.h" + #define SUPER ZLTextView const ZLColor BooksTextView::DEFAULT_BACKGROUND(255, 255, 255); const ZLColor BooksTextView::INVERTED_BACKGROUND(0, 0, 0); BooksTextView::BooksTextView( - ZLPaintContext& aContext, + BooksPaintContext& aContext, shared_ptr aTextStyle, BooksMargins aMargins) : SUPER(aContext), iMargins(aMargins), - iInvertColors(false), + iPaintContext(aContext), iTextStyle(aTextStyle) { } @@ -82,7 +84,7 @@ int BooksTextView::bottomMargin() const ZLColor BooksTextView::backgroundColor() const { - return iInvertColors ? INVERTED_BACKGROUND : DEFAULT_BACKGROUND; + return iPaintContext.realColor(DEFAULT_BACKGROUND); } ZLColor BooksTextView::color(const std::string &aStyle) const @@ -91,21 +93,34 @@ ZLColor BooksTextView::color(const std::string &aStyle) const static const std::string EXTERNAL_HYPERLINK("external"); static const std::string BOOK_HYPERLINK("book"); - if (aStyle == INTERNAL_HYPERLINK) { - return ZLColor(33, 96, 180); + if (ZLStringUtil::startsWith(aStyle, '#')) { + if (aStyle.length() == 7) { + int i, value = 0; + for (i=1; i<7; i++) { + int nibble = ZLStringUtil::fromHex(aStyle[i]); + if (nibble >= 0) { + value <<= 4; + value |= nibble; + } else { + break; + } + } + if (i == 7) { + return iPaintContext.realColor(ZLColor(value)); + } + } + } else if (aStyle == INTERNAL_HYPERLINK) { + return iPaintContext.realColor(33, 96, 180); } else if (aStyle == EXTERNAL_HYPERLINK) { - return ZLColor(33, 96, 180); + return iPaintContext.realColor(33, 96, 180); } else if (aStyle == BOOK_HYPERLINK) { - return ZLColor(23, 68, 128); + return iPaintContext.realColor(23, 68, 128); } else if (aStyle == ZLTextStyle::SELECTION_BACKGROUND) { - return ZLColor(82, 131, 194); + return iPaintContext.realColor(82, 131, 194); } else if (aStyle == ZLTextStyle::HIGHLIGHTED_TEXT) { - return ZLColor(60, 139, 255); - } else if (iInvertColors) { - return ZLColor(255, 255, 255); - } else { - return ZLColor(0, 0, 0); + return iPaintContext.realColor(60, 139, 255); } + return iPaintContext.realColor(0, 0, 0); } shared_ptr BooksTextView::baseStyle() const diff --git a/app/src/BooksTextView.h b/app/src/BooksTextView.h index 32c9d99..fdd3076 100644 --- a/app/src/BooksTextView.h +++ b/app/src/BooksTextView.h @@ -36,6 +36,7 @@ #include "BooksTypes.h" #include "BooksPos.h" +#include "BooksPaintContext.h" #include "ZLColor.h" #include "ZLTextView.h" @@ -46,7 +47,7 @@ class BooksTextView: public ZLTextView { public: - BooksTextView(ZLPaintContext& aContext, + BooksTextView(BooksPaintContext& aContext, shared_ptr aTextStyle, BooksMargins aMargin); @@ -80,7 +81,7 @@ public: private: BooksMargins iMargins; - bool iInvertColors; + BooksPaintContext& iPaintContext; std::string iCaption; shared_ptr iTextStyle; }; @@ -88,6 +89,6 @@ private: inline BooksPos BooksTextView::position() const { return BooksPos(textArea().startCursor()); } inline void BooksTextView::setInvertColors(bool aInvertColors) - { iInvertColors = aInvertColors; } + { iPaintContext.setInvertColors(aInvertColors); } #endif // BOOKS_TEXT_VIEW_H diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp index 992e260..01e2ba7 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -39,6 +40,7 @@ StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text parse(text, strlen(text), true); if (!myStateStack.empty()) { switch (myStateStack.top()) { + case ATTRIBUTE_VALUE: case ATTRIBUTE_VALUE_SPACE: case ATTRIBUTE_VALUE_COMMA: finishAttributeValue(); @@ -201,7 +203,10 @@ void StyleSheetParser::processChar4(char c) { myMap[myAttributeName].resize(0); myWord.resize(0); static const std::string FONT_FAMILY("font-family"); - if (myAttributeName == FONT_FAMILY) { + static const std::string COLOR("color"); + if (myAttributeName == COLOR) { + myStateStack.top() = ATTRIBUTE_VALUE; + } else if (myAttributeName == FONT_FAMILY) { myStateStack.top() = ATTRIBUTE_VALUE_COMMA; } else { myStateStack.top() = ATTRIBUTE_VALUE_SPACE; @@ -227,6 +232,7 @@ void StyleSheetParser::processChar4(char c) { } break; + case ATTRIBUTE_VALUE: case ATTRIBUTE_VALUE_SPACE: case ATTRIBUTE_VALUE_COMMA: switch (c) { @@ -296,6 +302,7 @@ void StyleSheetParser::processChar4(char c) { // in which the string was found. myStateStack.pop(); switch (myStateStack.top()) { + case ATTRIBUTE_VALUE: case ATTRIBUTE_VALUE_SPACE: case ATTRIBUTE_VALUE_COMMA: myStateStack.top() = ATTRIBUTE_IGNORE; diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.h b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.h index 1f69466..5dbf4c7 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.h +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetParser.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -45,6 +46,7 @@ private: COMMENT, SELECTOR, ATTRIBUTE_NAME, + ATTRIBUTE_VALUE, ATTRIBUTE_VALUE_SPACE, ATTRIBUTE_VALUE_COMMA, ATTRIBUTE_IGNORE, diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp index 33bbc69..e5d8c30 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +20,10 @@ #include #include +#include -#include +#include "ZLStringUtil.h" +#include "ZLUnicodeUtil.h" #include "StyleSheetTable.h" @@ -219,7 +222,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa static const std::string TEXT_ALIGN("text-align"); const std::vector &alignment = values(styles, TEXT_ALIGN); if (!alignment.empty()) { - const std::string &value = alignment.at(0); + const std::string &value = alignment[0]; if (value == "justify") { entry.setAlignmentType(ALIGN_JUSTIFY); } else if (value == "left") { @@ -233,7 +236,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa static const std::string FLOAT("float"); const std::vector &floatVal = values(styles, FLOAT); if (!floatVal.empty()) { - const std::string &value = floatVal.at(0); + const std::string &value = floatVal[0]; if (value == "left") { entry.setAlignmentType(ALIGN_LEFT); } else if (value == "right") { @@ -246,7 +249,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa const std::vector &weight = values(styles, FONT_WEIGHT); if (!weight.empty()) { int num = -1; - const std::string &value = weight.at(0); + const std::string &value = weight[0]; if (value == "bold") { num = 700; } else if (value == "normal") { @@ -286,7 +289,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa static const std::string FONT_SIZE("font-size"); const std::vector &fontSize = values(styles, FONT_SIZE); if (!fontSize.empty()) { - const std::string &value = fontSize.at(0); + const std::string &value = fontSize[0]; if (value == "xx-small") { entry.setFontSizeMag(-3); } else if (value == "x-small") { @@ -418,11 +421,20 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa 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); + + static const std::string COLOR("color"); + std::vector colors = values(styles, COLOR); + if (colors.size() == 1) { + ZLColor color; + if (stringToColor(colors[0], color)) { + entry.setColor(color); + } + } } void StyleSheetTable::getPageBreakValue(const std::vector &values, ZLBoolean3 &value) { if (!values.empty()) { - const std::string &first = values.at(0); + const std::string &first = values[0]; if ((first == "always") || (first == "left") || (first == "right")) { @@ -445,7 +457,7 @@ void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) { 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); + const std::string &value = whiteSpace[0]; if (value == "normal") { style.WhiteSpace = WS_NORMAL; } else if (value == "nowrap") { @@ -465,3 +477,237 @@ void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) { style.DisplayNone = true; } } + +bool StyleSheetTable::stringToColor(const std::string &text, ZLColor &color) { + std::string str(text); + ZLStringUtil::stripWhiteSpaces(str); + if (!str.empty()) { + // Color spec must be an ASCII string + if (ZLUnicodeUtil::utf8Length(str) == (int)str.length()) { + static const std::string RGB("rgb"); + if (str[0] == '#') { + if (str.length() == 4) { + // Hexadecimal notation #RGB + int rgb[3]; + for (int i=0; i<3; i++) { + if ((rgb[i] = ZLStringUtil::fromHex(str[i+1])) < 0) { + return false; + } + } + color.Red = ((rgb[0] << 4) | rgb[0]); + color.Green = ((rgb[1] << 4) | rgb[1]); + color.Blue = ((rgb[2] << 4) | rgb[2]); + return true; + } else if (str.length() == 7) { + // Hexadecimal notation #RRGGBB + int rrggbb[6]; + for (int i=0; i<6; i++) { + if ((rrggbb[i] = ZLStringUtil::fromHex(str[i+1])) < 0) { + return false; + } + } + color.Red = ((rrggbb[0] << 4) | rrggbb[1]); + color.Green = ((rrggbb[2] << 4) | rrggbb[3]); + color.Blue = ((rrggbb[4] << 4) | rrggbb[5]); + return true; + } + } else if (ZLStringUtil::stringStartsWith(str, RGB)) { + // Functional Notation rgb(R,G,B) + str.erase(0,3); + ZLStringUtil::stripWhiteSpaces(str); + if (ZLStringUtil::startsWith(str, '(') && ZLStringUtil::endsWith(str, ')')) { + str = str.substr(1,str.length()-2); + std::vector rgb = ZLStringUtil::splitString(str, ","); + if (rgb.size() == 3) { + int i; + long c[3]; + for (i=0; i<3; i++) { + std::string tmp(rgb[i]); + ZLStringUtil::stripWhiteSpaces(tmp); + if (ZLStringUtil::endsWith(tmp, '%')) { + tmp.resize(tmp.length()-1); + if (ZLStringUtil::stringToLong(tmp, c[i]) && c[i] >= 0 && c[i] <= 100) { + c[i] = (c[i] * 255 + 50) / 100; + continue; + } + } else if (ZLStringUtil::stringToLong(tmp, c[i]) && c[i] >= 0 && c[i] <= 255) { + continue; + } + } + if (i == 3) { + color.Red = c[0]; + color.Green = c[1]; + color.Blue = c[2]; + return true; + } + } + } + } else { + // Color keywords + static const struct _CSSColorEntry { + const char* stringValue; + long intValue; + } knownColors [] = { + { "aliceblue", 0xf0f8ff }, + { "antiquewhite", 0xfaebd7 }, + { "aqua", 0x00ffff }, + { "aquamarine", 0x7fffd4 }, + { "azure", 0xf0ffff }, + { "beige", 0xf5f5dc }, + { "bisque", 0xffe4c4 }, + { "black", 0x000000 }, + { "blanchedalmond", 0xffe4c4 }, + { "blue", 0x0000ff }, + { "blueviolet", 0x8a2be2 }, + { "brown", 0xa52a2a }, + { "burlywood", 0xdeb887 }, + { "cadetblue", 0x5f9ea0 }, + { "chartreuse", 0x7fff00 }, + { "chocolate", 0xd2691e }, + { "coral", 0xff7f50 }, + { "cornflowerblue", 0x6495ed }, + { "cornsilk", 0xfff8dc }, + { "crimson", 0xdc143c }, + { "darkblue", 0x00008b }, + { "darkcyan", 0x008b8b }, + { "darkgoldenrod", 0xb8860b }, + { "darkgray", 0xa9a9a9 }, + { "darkgreen", 0x006400 }, + { "darkkhaki", 0xbdb76b }, + { "darkmagenta", 0x8b008b }, + { "darkolivegreen", 0x556b2f }, + { "darkorange", 0xff8c00 }, + { "darkorchid", 0x9932cc }, + { "darkred", 0x8b0000 }, + { "darksalmon", 0xe9967a }, + { "darkseagreen", 0x8fbc8f }, + { "darkslateblue", 0x483d8b }, + { "darkslategray", 0x2f4f4f }, + { "darkturquoise", 0x00ced1 }, + { "darkviolet", 0x9400d3 }, + { "deeppink", 0xff1493 }, + { "deepskyblue", 0x00bfff }, + { "dimgray", 0x696969 }, + { "dodgerblue", 0x1e90ff }, + { "firebrick", 0xb22222 }, + { "floralwhite", 0xfffaf0 }, + { "forestgreen", 0x228b22 }, + { "fuchsia", 0xff00ff }, + { "gainsboro", 0xdcdcdc }, + { "ghostwhite", 0xf8f8ff }, + { "goldenrod", 0xdaa520 }, + { "gold", 0xffd700 }, + { "gray", 0x808080 }, + { "green", 0x008000 }, + { "greenyellow", 0xadff2f }, + { "grey", 0x808080 }, + { "honeydew", 0xf0fff0 }, + { "hotpink", 0xff69b4 }, + { "indianred", 0xcd5c5c }, + { "indigo", 0x4b0082 }, + { "ivory", 0xfffff0 }, + { "khaki", 0xf0e68c }, + { "lavenderblush", 0xfff0f5 }, + { "lavender", 0xe6e6fa }, + { "lawngreen", 0x7cfc00 }, + { "lemonchiffon", 0xfffacd }, + { "lightblue", 0xadd8e6 }, + { "lightcoral", 0xf08080 }, + { "lightcyan", 0xe0ffff }, + { "lightgoldenrodyellow", 0xfafad2 }, + { "lightgreen", 0x90ee90 }, + { "lightgrey", 0xd3d3d3 }, + { "lightpink", 0xffb6c1 }, + { "lightsalmon", 0xffa07a }, + { "lightseagreen", 0x20b2aa }, + { "lightskyblue", 0x87cefa }, + { "lightslategray", 0x778899 }, + { "lightsteelblue", 0xb0c4de }, + { "lightyellow", 0xffffe0 }, + { "lime", 0x00ff00 }, + { "limegreen", 0x32cd32 }, + { "linen", 0xfaf0e6 }, + { "maroon", 0x800000 }, + { "mediumaquamarine", 0x66cdaa }, + { "mediumblue", 0x0000cd }, + { "mediumorchid", 0xba55d3 }, + { "mediumpurple", 0x9370db }, + { "mediumseagreen", 0x3cb371 }, + { "mediumslateblue", 0x7b68ee }, + { "mediumspringgreen", 0x00fa9a }, + { "mediumturquoise", 0x48d1cc }, + { "mediumvioletred", 0xc71585 }, + { "midnightblue", 0x191970 }, + { "mintcream", 0xf5fffa }, + { "mistyrose", 0xffe4e1 }, + { "moccasin", 0xffe4b5 }, + { "navajowhite", 0xffdead }, + { "navy", 0x000080 }, + { "oldlace", 0xfdf5e6 }, + { "olive", 0x808000 }, + { "olivedrab", 0x6b8e23 }, + { "orange", 0xffa500 }, + { "orangered", 0xff4500 }, + { "orchid", 0xda70d6 }, + { "palegoldenrod", 0xeee8aa }, + { "palegreen", 0x98fb98 }, + { "paleturquoise", 0xafeeee }, + { "palevioletred", 0xdb7093 }, + { "papayawhip", 0xffefd5 }, + { "peachpuff", 0xffdab9 }, + { "peru", 0xcd853f }, + { "pink", 0xffc0cb }, + { "plum", 0xdda0dd }, + { "powderblue", 0xb0e0e6 }, + { "purple", 0x800080 }, + { "rebeccapurple", 0x663399 }, + { "red", 0xff0000 }, + { "rosybrown", 0xbc8f8f }, + { "royalblue", 0x4169e1 }, + { "saddlebrown", 0x8b4513 }, + { "salmon", 0xfa8072 }, + { "sandybrown", 0xf4a460 }, + { "seagreen", 0x2e8b57 }, + { "seashell", 0xfff5ee }, + { "sienna", 0xa0522d }, + { "silver", 0xc0c0c0 }, + { "skyblue", 0x87ceeb }, + { "slateblue", 0x6a5acd }, + { "slategrey", 0x708090 }, + { "snow", 0xfffafa }, + { "springgreen", 0x00ff7f }, + { "steelblue", 0x4682b4 }, + { "tan", 0xd2b48c }, + { "teal", 0x008080 }, + { "thistle", 0xd8bfd8 }, + { "tomato", 0xff6347 }, + { "turquoise", 0x40e0d0 }, + { "violet", 0xee82ee }, + { "wheat", 0xf5deb3 }, + { "white", 0xffffff }, + { "whitesmoke", 0xf5f5f5 }, + { "yellow", 0xffff00 }, + { "yellowgreen", 0x9acd32 } + }; + + int low = 0; + int high = (sizeof(knownColors)/sizeof(knownColors[0]))-1; + const char* key = str.c_str(); + + while (low <= high) { + const int mid = (low + high)/2; + int cmp = strcasecmp(knownColors[mid].stringValue, key); + if (cmp < 0) { + low = mid + 1; + } else if (cmp > 0) { + high = mid - 1; + } else { + color.setIntValue(knownColors[mid].intValue); + return true; + } + } + } + } + } + return false; +} diff --git a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h index 896df12..3541f18 100644 --- a/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h +++ b/fbreader/fbreader/fbreader/src/formats/css/StyleSheetTable.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,7 @@ #include +#include #include #include @@ -88,10 +90,10 @@ public: Style(const AttributeMap &map); Style &operator = (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 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; @@ -125,8 +127,9 @@ private: static void setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value); static void setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName); static void setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value); - static const std::vector &values(const AttributeMap &map, const std::string &name); + static const std::vector &values(const AttributeMap &map, const std::string &name); static bool sortBySpecificity(const Entry *e1, const Entry *e2); + static bool stringToColor(const std::string &text, ZLColor &color); public: bool isEmpty() const; diff --git a/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h b/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h index f64fccb..638a70f 100644 --- a/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h +++ b/fbreader/fbreader/zlibrary/core/src/util/ZLColor.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +28,8 @@ struct ZLColor { ZLColor(unsigned char r, unsigned char g, unsigned char b); ZLColor(long longValue = 0); + + void setIntValue(long longValue); long intValue(); bool operator == (const ZLColor &color) const; @@ -35,6 +38,7 @@ struct ZLColor { inline ZLColor::ZLColor(unsigned char r, unsigned char g, unsigned char b) : Red(r), Green(g), Blue(b) {} inline ZLColor::ZLColor(long longValue) : Red((unsigned char)(longValue >> 16)), Green((unsigned char)(longValue >> 8)), Blue((unsigned char)longValue) {} +inline void ZLColor::setIntValue(long longValue) { Red = (unsigned char)(longValue >> 16); Green = (unsigned char)(longValue >> 8); Blue = (unsigned char)longValue; } inline long ZLColor::intValue() { return (((long)Red) << 16) + (((long)Green) << 8) + Blue; } inline bool ZLColor::operator == (const ZLColor &color) const { return (Red == color.Red) && (Green == color.Green) && (Blue == color.Blue); } inline bool ZLColor::operator != (const ZLColor &color) const { return !operator==(color); } diff --git a/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.cpp b/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.cpp index d02bfbf..cf62615 100644 --- a/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.cpp +++ b/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +21,11 @@ #include #include #include + #include #include +#include +#include #include "ZLStringUtil.h" @@ -154,3 +158,25 @@ double ZLStringUtil::stringToDouble(const std::string &value, double defaultValu return defaultValue; } } + +bool ZLStringUtil::stringToLong(const char *s, long &result) { + while (*s && isspace(*s)) s++; + char* endptr = NULL; + long number = strtol(s, &endptr, 10); + if (endptr && endptr != s) { + if ((number != LONG_MAX && number != LONG_MIN) || (errno != ERANGE)) { + while (*endptr && isspace(*endptr)) endptr++; + if (!*endptr) { + result = number; + return true; + } + } + } + return false; +} + +int ZLStringUtil::fromHex(char hex) { + return (hex >= '0' && hex <= '9') ? (hex - '0') : + (hex >= 'a' && hex <= 'z') ? (hex - 'a' + 10) : + (hex >= 'A' && hex <= 'Z') ? (hex - 'A' + 10) : -1; +} diff --git a/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.h b/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.h index 42701ee..46aa284 100644 --- a/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.h +++ b/fbreader/fbreader/zlibrary/core/src/util/ZLStringUtil.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +32,7 @@ private: public: static bool stringStartsWith(const std::string &str, const std::string &start); static bool stringEndsWith(const std::string &str, const std::string &end); + static bool startsWith(const std::string &str, char c); static bool endsWith(const std::string &str, char c); static bool caseInsensitiveEqual(const std::string &str1, const std::string &str2); static bool caseInsensitiveSort(const std::string &str1, const std::string &str2); @@ -45,12 +47,22 @@ public: static std::string doubleToString(double value); static double stringToDouble(const std::string &value, double defaultValue); + static bool stringToLong(const std::string &str, long &result); + static bool stringToLong(const char *str, long &result); + static int fromHex(char hex); }; inline std::vector ZLStringUtil::splitString(const std::string &str, const char* delim) { return ZLStringUtil::splitString(str.c_str(), delim); } +inline bool ZLStringUtil::startsWith(const std::string &str, char c) { + return !str.empty() && str[0] == c; +} inline bool ZLStringUtil::endsWith(const std::string &str, char c) { return !str.empty() && str[str.length()-1] == c; } +inline bool ZLStringUtil::stringToLong(const std::string &str, long &result) { + return stringToLong(str.c_str(), result); +} + #endif /* __ZLSTRINGUTIL_H__ */ diff --git a/fbreader/fbreader/zlibrary/text/src/model/ZLTextModel.cpp b/fbreader/fbreader/zlibrary/text/src/model/ZLTextModel.cpp index 48b50ac..3b196d1 100644 --- a/fbreader/fbreader/zlibrary/text/src/model/ZLTextModel.cpp +++ b/fbreader/fbreader/zlibrary/text/src/model/ZLTextModel.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -234,6 +235,7 @@ void ZLTextModel::addControl(const ZLTextStyleEntry &entry) { len += entry.myFontFamilies.at(i).length() + 1; } } + if (mask & ZLTextStyleEntry::SUPPORT_COLOR) len += 3; myLastEntryStart = myAllocator.allocate(len); char *address = myLastEntryStart; *address++ = ZLTextParagraphEntry::STYLE_ENTRY; @@ -263,6 +265,11 @@ void ZLTextModel::addControl(const ZLTextStyleEntry &entry) { address += nbytes; } } + if (mask & ZLTextStyleEntry::SUPPORT_COLOR) { + *address++ = entry.myColor.Red; + *address++ = entry.myColor.Green; + *address++ = entry.myColor.Blue; + } myParagraphs.back()->addEntry(myLastEntryStart); } diff --git a/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.cpp b/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.cpp index 0ee1d1d..ead6f48 100644 --- a/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.cpp +++ b/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -109,12 +110,19 @@ ZLTextStyleEntry::ZLTextStyleEntry(char *address) { myFontFamilies.push_back(font); } } + if (colorSupported()) { + ZLColor color; + color.Red = (unsigned char)*address++; + color.Green = (unsigned char)*address++; + color.Blue = (unsigned char)*address++; + setColor(color); + } } void ZLTextStyleEntry::reset() { mySupportedFontModifier = 0; myMask = 0; - myFontFamilies.clear(); + myFontFamilies.resize(0); } void ZLTextStyleEntry::apply(const ZLTextStyleEntry &other) { @@ -143,6 +151,9 @@ void ZLTextStyleEntry::apply(const ZLTextStyleEntry &other) { if (other.myMask & SUPPORT_FONT_FAMILIES) { setFontFamilies(other.myFontFamilies); } + if (other.myMask & SUPPORT_COLOR) { + setColor(other.myColor); + } } void ZLTextStyleEntry::inherit(const ZLTextStyleEntry &other) { @@ -169,6 +180,10 @@ void ZLTextStyleEntry::inherit(const ZLTextStyleEntry &other) { if (other.myMask & SUPPORT_FONT_FAMILIES) { setFontFamilies(other.myFontFamilies); } + // color + if (other.myMask & SUPPORT_COLOR) { + setColor(other.myColor); + } } bool ZLTextStyleEntry::equals(const ZLTextStyleEntry &other) const { @@ -198,6 +213,9 @@ bool ZLTextStyleEntry::equals(const ZLTextStyleEntry &other) const { if ((myMask & SUPPORT_FONT_FAMILIES) && myFontFamilies != other.myFontFamilies) { return false; } + if ((myMask & SUPPORT_OPACITY) && myColor != other.myColor) { + return false; + } return true; } else { return false; @@ -334,6 +352,7 @@ void ZLTextParagraph::Iterator::next() { while (*myPointer++); } } + if (mask & ZLTextStyleEntry::SUPPORT_COLOR) myPointer += 3; break; } case ZLTextParagraphEntry::FIXED_HSPACE_ENTRY: diff --git a/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.h b/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.h index 578d953..6ec7b24 100644 --- a/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.h +++ b/fbreader/fbreader/zlibrary/text/src/model/ZLTextParagraph.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -26,6 +27,7 @@ #include +#include #include #include #include @@ -137,11 +139,16 @@ public: const std::vector &fontFamilies() const; void setFontFamilies(const std::vector &fontFamilies); + bool colorSupported() const; + const ZLColor &color() const; + void setColor(const ZLColor &color); + enum { SUPPORT_ALIGNMENT_TYPE = 1 << NUMBER_OF_LENGTHS, SUPPORT_FONT_SIZE = 1 << (NUMBER_OF_LENGTHS + 1), SUPPORT_FONT_FAMILIES = 1 << (NUMBER_OF_LENGTHS + 2), - SUPPORT_OPACITY = 1 << (NUMBER_OF_LENGTHS + 3) + SUPPORT_OPACITY = 1 << (NUMBER_OF_LENGTHS + 3), + SUPPORT_COLOR = 1 << (NUMBER_OF_LENGTHS + 4) }; private: @@ -155,6 +162,7 @@ private: unsigned char myFontModifier; signed char myFontSizeMag; std::vector myFontFamilies; + ZLColor myColor; friend class ZLTextModel; }; @@ -400,6 +408,10 @@ inline bool ZLTextStyleEntry::fontFamiliesSupported() const { return (myMask & S inline const std::vector &ZLTextStyleEntry::fontFamilies() const { return myFontFamilies; } inline void ZLTextStyleEntry::setFontFamilies(const std::vector &fontFamilies) { myFontFamilies = fontFamilies; myMask |= SUPPORT_FONT_FAMILIES; } +inline bool ZLTextStyleEntry::colorSupported() const { return (myMask & SUPPORT_COLOR) != 0; } +inline const ZLColor &ZLTextStyleEntry::color() const { return myColor; } +inline void ZLTextStyleEntry::setColor(const ZLColor &color) { myColor = color; myMask |= SUPPORT_COLOR; } + inline ZLTextControlEntry::ZLTextControlEntry(ZLTextKind kind, bool isStart) : myKind(kind), myStart(isStart) {} inline ZLTextControlEntry::~ZLTextControlEntry() {} inline ZLTextKind ZLTextControlEntry::kind() const { return myKind; } diff --git a/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.cpp b/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.cpp index 6a1e9ec..88ad1c7 100644 --- a/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.cpp +++ b/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -181,6 +182,13 @@ const std::string &ZLTextFullDecoratedStyle::colorStyle() const { return style.empty() ? base()->colorStyle() : style; } +ZLTextForcedStyle::ZLTextForcedStyle(shared_ptr base, const ZLTextStyleEntry &entry) : + ZLTextDecoratedStyle(base), myEntry(entry) { + if (myEntry.colorSupported()) { + myColorStyle = ZLTextStyle::colorStyle(myEntry.color()); + } +} + short ZLTextForcedStyle::lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { ZLTextStyleEntry::Length lengthType = rtl ? ZLTextStyleEntry::LENGTH_RIGHT_INDENT : @@ -279,6 +287,10 @@ const std::vector &ZLTextForcedStyle::fontFamilies() const { myEntry.fontFamilies() : base()->fontFamilies(); } +const std::string &ZLTextForcedStyle::colorStyle() const { + return myEntry.colorSupported() ? myColorStyle : base()->colorStyle(); +} + const std::string &ZLTextStyleDecoration::colorStyle() const { return myColorStyle; } diff --git a/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.h b/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.h index f9b108c..200cae1 100644 --- a/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.h +++ b/fbreader/fbreader/zlibrary/text/src/style/ZLTextDecoratedStyle.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -67,6 +68,7 @@ public: private: const ZLTextStyleEntry &myEntry; + std::string myColorStyle; }; class ZLTextPartialDecoratedStyle : public ZLTextDecoratedStyle { @@ -138,9 +140,7 @@ inline ZLTextDecoratedStyle::~ZLTextDecoratedStyle() {} inline bool ZLTextDecoratedStyle::isDecorated() const { return true; } inline const shared_ptr ZLTextDecoratedStyle::base() const { return myBase; } -inline ZLTextForcedStyle::ZLTextForcedStyle(shared_ptr base, const ZLTextStyleEntry &entry) : ZLTextDecoratedStyle(base), myEntry(entry) {} inline ZLTextForcedStyle::~ZLTextForcedStyle() {} -inline const std::string &ZLTextForcedStyle::colorStyle() const { return base()->colorStyle(); } inline int ZLTextForcedStyle::verticalShift() const { return base()->verticalShift(); } inline double ZLTextForcedStyle::lineSpace() const { return base()->lineSpace(); } inline bool ZLTextForcedStyle::allowHyphenations() const { return base()->allowHyphenations(); } diff --git a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.cpp b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.cpp index c8329bf..4ab637d 100644 --- a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.cpp +++ b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,9 +18,17 @@ * 02110-1301, USA. */ +#include + #include "ZLTextStyle.h" const std::string ZLTextStyle::REGULAR_TEXT = ""; const std::string ZLTextStyle::SELECTION_BACKGROUND = "selectionBackground"; const std::string ZLTextStyle::HIGHLIGHTED_TEXT = "highlightedText"; const std::string ZLTextStyle::TREE_LINES = "treeLines"; + +std::string ZLTextStyle::colorStyle(ZLColor color) { + char buf[8]; + snprintf(buf, sizeof(buf), "#%02x%02x%02x", color.Red, color.Green, color.Blue); + return std::string(buf); +} diff --git a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.h b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.h index 6ddfc65..1864ed4 100644 --- a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.h +++ b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyle.h @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -25,6 +26,7 @@ #include +#include #include #include @@ -64,6 +66,7 @@ public: virtual bool allowHyphenations() const = 0; int lineSpacePercent() const; + static std::string colorStyle(ZLColor color); }; inline ZLTextStyle::ZLTextStyle() {} diff --git a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyleCollection.cpp b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyleCollection.cpp index 69f7091..eae0334 100644 --- a/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyleCollection.cpp +++ b/fbreader/fbreader/zlibrary/text/src/style/ZLTextStyleCollection.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2004-2010 Geometer Plus + * Copyright (C) 2015 Slava Monich * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -19,8 +20,6 @@ #include #include -#include -#include #include #include @@ -29,6 +28,7 @@ #include "ZLTextStyle.h" #include "ZLTextStyleCollection.h" #include "ZLTextDecoratedStyle.h" +#include "ZLStringUtil.h" ZLTextStyleCollection *ZLTextStyleCollection::ourInstance = 0; @@ -72,18 +72,10 @@ int ZLTextStyleReader::lengthValue(const char **attributes, const char *name, ZL if (ZLTextStyleEntry::parseLength(stringValue, size, unit)) { return size; } else { - const char *s = stringValue; - while (*s && isspace(*s)) s++; - char* endptr = NULL; - long number = strtol(s, &endptr, 10); - if (endptr && endptr != s) { - if ((number != LONG_MAX && number != LONG_MIN) || (errno != ERANGE)) { - while (*endptr && isspace(*endptr)) endptr++; - if (!*endptr) { - unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL; - return number; - } - } + long number; + if (ZLStringUtil::stringToLong(stringValue, number)) { + unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL; + return number; } } } diff --git a/test/test-css/data/basic/in.css b/test/test-css/data/basic/in.css index 414f3e4..a6179a5 100644 --- a/test/test-css/data/basic/in.css +++ b/test/test-css/data/basic/in.css @@ -30,3 +30,11 @@ body,h1,h2, /*///****/ div, p { /* 12: Known style with missing semicolon */ font-style: italic } + +/* 13. Sypported ways to represent colors */ +.red { color: #f00; } +.green { color: "#00ff00"; } +.blue { color: rgb(0,0, 255); } +.olive { color: rgb(50%, 50%, 0%); } +.orangered { color: orangered } +.palegreen { color: "palegreen"; } diff --git a/test/test-css/data/basic/out.css b/test/test-css/data/basic/out.css index 433cf49..2aaa0f1 100644 --- a/test/test-css/data/basic/out.css +++ b/test/test-css/data/basic/out.css @@ -18,3 +18,21 @@ p { font-style: italic; font-family: "Foo Bar"; } +.red { + color: #ff0000; +} +.green { + color: #00ff00; +} +.blue { + color: #0000ff; +} +.olive { + color: #808000; +} +.orangered { + color: #ff4500; +} +.palegreen { + color: #98fb98; +} diff --git a/test/test-css/data/test1/out.css b/test/test-css/data/test1/out.css index 7d24288..0d54527 100644 --- a/test/test-css/data/test1/out.css +++ b/test/test-css/data/test1/out.css @@ -42,6 +42,9 @@ .calibre5 { font-style: italic; } +.calibre6 { + color: #4183c4; +} .calibre8 { font-weight: bold; } @@ -70,6 +73,18 @@ font-weight: bold; font-size: 144%; /* 2 */ } +.hljs-comment { + color: #8e908c; +} +.hljs-keyword { + color: #8959a8; +} +.hljs-preprocessor { + color: #f5871f; +} +.hljs-string { + color: #718c00; +} .lang-c { margin-left: 0; margin-bottom: 0; @@ -86,6 +101,7 @@ } .page { font-family: "sans-serif"; + color: #333333; } .table { margin-bottom: 16px; diff --git a/test/test-css/main.cpp b/test/test-css/main.cpp index 1ed3252..c2bb5cf 100644 --- a/test/test-css/main.cpp +++ b/test/test-css/main.cpp @@ -39,6 +39,7 @@ #include "ZLInputStream.h" #include "ZLStringUtil.h" +#include "ZLTextStyle.h" #include "ZLFile.h" #include "filesystem/ZLQtFSManager.h" @@ -161,6 +162,9 @@ dump_style( } out << size << "%; /* " << ((int)mag) << " */\n"; } + if (style.TextStyle.colorSupported()) { + out << " color: " << ZLTextStyle::colorStyle(style.TextStyle.color()) << ";\n"; + } } static void