Support multiple selectors per CSS rule

Also, added more length units for margins
This commit is contained in:
Slava Monich 2015-07-04 02:25:14 +03:00
parent eb5928a5ba
commit c787512e99
4 changed files with 93 additions and 59 deletions

View file

@ -35,7 +35,7 @@ void StyleSheetTableParser::storeData(const std::string &tagName, const std::str
shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseString(const char *text, ZLBoolean3 *pageBreakBefore, ZLBoolean3 *pageBreakAfter) { shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseString(const char *text, ZLBoolean3 *pageBreakBefore, ZLBoolean3 *pageBreakAfter) {
myReadState = ATTRIBUTE_NAME; myReadState = ATTRIBUTE_NAME;
parse(text, strlen(text), true); parse(text, strlen(text), true);
shared_ptr<ZLTextStyleEntry> control = StyleSheetTable::createControl(myMap); shared_ptr<ZLTextStyleEntry> control = StyleSheetTable::createControl(NULL, myMap);
bool value; bool value;
if (pageBreakBefore && StyleSheetTable::getPageBreakBefore(myMap, value)) { if (pageBreakBefore && StyleSheetTable::getPageBreakBefore(myMap, value)) {
*pageBreakBefore = value ? B3_TRUE : B3_FALSE; *pageBreakBefore = value ? B3_TRUE : B3_FALSE;
@ -58,8 +58,7 @@ void StyleSheetParser::reset() {
myAttributeName.erase(); myAttributeName.erase();
myReadState = TAG_NAME; myReadState = TAG_NAME;
myInsideComment = false; myInsideComment = false;
myTagName.erase(); mySelectors.clear();
myClassName.erase();
myMap.clear(); myMap.clear();
} }
@ -132,11 +131,21 @@ void StyleSheetParser::processControl(const char control) {
break; break;
case '}': case '}':
if (myReadState != BROKEN) { if (myReadState != BROKEN) {
storeData(myTagName, myClassName, myMap); for (unsigned int i=0; i<mySelectors.size(); i++) {
std::string selector(mySelectors[i]);
std::string tag, klass;
const int index = selector.find('.');
if (index == -1) {
tag = selector;
} else {
tag = selector.substr(0, index);
klass = selector.substr(index + 1);
}
storeData(tag, klass, myMap);
}
} }
myReadState = TAG_NAME; myReadState = TAG_NAME;
myTagName.erase(); mySelectors.clear();
myClassName.erase();
myMap.clear(); myMap.clear();
break; break;
case ';': case ';':
@ -171,26 +180,16 @@ void StyleSheetParser::processWord(std::string &word) {
void StyleSheetParser::processWordWithoutComments(const std::string &word) { void StyleSheetParser::processWordWithoutComments(const std::string &word) {
switch (myReadState) { switch (myReadState) {
case TAG_NAME: case TAG_NAME:
{ if (!word.empty()) {
int index = word.find('.'); const unsigned int len = word.length();
if (index == -1) { if (word.at(len-1) == ',') {
if (myTagName.empty()) { mySelectors.push_back(word.substr(0, len-1));
myTagName = word;
} else { } else {
myTagName += ' ' + word; mySelectors.push_back(word);
}
} else {
if (myTagName.empty()) {
myTagName = word.substr(0, index);
myClassName = word.substr(index + 1);
} else {
myTagName += ' ' + word.substr(0, index);
myClassName += ' ' + word.substr(index + 1);
} }
} }
myMap.clear(); myMap.clear();
break; break;
}
case ATTRIBUTE_NAME: case ATTRIBUTE_NAME:
myAttributeName = word; myAttributeName = word;
myMap[myAttributeName].clear(); myMap[myAttributeName].clear();

View file

@ -55,8 +55,7 @@ private:
BROKEN, BROKEN,
} myReadState; } myReadState;
bool myInsideComment; bool myInsideComment;
std::string myTagName; std::vector<std::string> mySelectors;
std::string myClassName;
StyleSheetTable::AttributeMap myMap; StyleSheetTable::AttributeMap myMap;
friend class StyleSheetSingleStyleParser; friend class StyleSheetSingleStyleParser;

View file

@ -30,7 +30,9 @@ bool StyleSheetTable::isEmpty() const {
void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map) { void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map) {
if ((!tag.empty() || !aClass.empty()) && !map.empty()) { if ((!tag.empty() || !aClass.empty()) && !map.empty()) {
Key key(tag, aClass); Key key(tag, aClass);
myControlMap[key] = createControl(map); // 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; bool value;
if (getPageBreakBefore(map, value)) { if (getPageBreakBefore(map, value)) {
myPageBreakBeforeMap[key] = value; myPageBreakBeforeMap[key] = value;
@ -41,21 +43,34 @@ void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass,
} }
} }
static void parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) { static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
if (!toParse.empty()) {
if (ZLStringUtil::stringEndsWith(toParse, "%")) { if (ZLStringUtil::stringEndsWith(toParse, "%")) {
unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT; unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT;
size = atoi(toParse.c_str()); size = atoi(toParse.c_str());
return true;
} else if (ZLStringUtil::stringEndsWith(toParse, "em")) { } else if (ZLStringUtil::stringEndsWith(toParse, "em")) {
unit = ZLTextStyleEntry::SIZE_UNIT_EM_100; unit = ZLTextStyleEntry::SIZE_UNIT_EM_100;
size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0)); size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
return true;
} else if (ZLStringUtil::stringEndsWith(toParse, "ex")) { } else if (ZLStringUtil::stringEndsWith(toParse, "ex")) {
unit = ZLTextStyleEntry::SIZE_UNIT_EX_100; unit = ZLTextStyleEntry::SIZE_UNIT_EX_100;
size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0)); size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
} else { return true;
} else if (ZLStringUtil::stringEndsWith(toParse, "px") ||
ZLStringUtil::stringEndsWith(toParse, "pt") ||
ZLStringUtil::stringEndsWith(toParse, "pc")) {
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL; unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
size = atoi(toParse.c_str()); size = atoi(toParse.c_str());
return true;
} else if (toParse == "0") {
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
size = 0;
return true;
} }
} }
return false;
}
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) { void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) {
StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName); StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName);
@ -68,10 +83,9 @@ void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Lengt
} }
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) { void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
if (!value.empty()) {
short size; short size;
ZLTextStyleEntry::SizeUnit unit; ZLTextStyleEntry::SizeUnit unit;
parseLength(value, size, unit); if (parseLength(value, size, unit)) {
entry.setLength(name, size, unit); entry.setLength(name, size, unit);
} }
} }
@ -129,8 +143,10 @@ const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map,
return emptyVector; return emptyVector;
} }
shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &styles) { shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextStyleEntry> entry, const AttributeMap &styles) {
shared_ptr<ZLTextStyleEntry> entry = new ZLTextStyleEntry(); if (entry.isNull()) {
entry = new ZLTextStyleEntry();
}
const std::vector<std::string> &alignment = values(styles, "text-align"); const std::vector<std::string> &alignment = values(styles, "text-align");
if (!alignment.empty()) { if (!alignment.empty()) {
@ -181,6 +197,8 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &
entry->setFontFamily(fontFamily[0]); entry->setFontFamily(fontFamily[0]);
} }
short size;
ZLTextStyleEntry::SizeUnit unit;
const std::vector<std::string> &fontSize = values(styles, "font-size"); const std::vector<std::string> &fontSize = values(styles, "font-size");
if (!fontSize.empty()) { if (!fontSize.empty()) {
std::string value = fontSize[0]; std::string value = fontSize[0];
@ -198,11 +216,21 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &
entry->setFontSizeMag(2); entry->setFontSizeMag(2);
} else if (value == "xx-large") { } else if (value == "xx-large") {
entry->setFontSizeMag(3); entry->setFontSizeMag(3);
} else if (value.size() > 1 && value[value.size()-1] == '%') { } else {
value.erase(value.size()-1, 1); if (parseLength(value, size, unit)) {
int percent = atoi(value.c_str()); switch (unit) {
if (percent > 0) { case ZLTextStyleEntry::SIZE_UNIT_PIXEL:
entry->setFontSizeMag((percent - 100)/20); // What to do with pixels?
break;
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);
break;
}
} }
} }
} }
@ -214,21 +242,29 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &
} }
switch (margins.size()) { switch (margins.size()) {
case 1: case 1:
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); if (parseLength(margins[0], size, unit)) {
setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[0]); entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[0]); entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[0]); entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit);
}
break; break;
case 2: case 2:
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); if (parseLength(margins[0], size, unit)) {
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[0]); entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]); entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[1]); }
if (parseLength(margins[1], size, unit)) {
entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit);
}
break; break;
case 3: case 3:
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]); setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]);
setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]); if (parseLength(margins[1], size, unit)) {
setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[1]); entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit);
}
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]); setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]);
break; break;
case 4: case 4:

View file

@ -32,7 +32,7 @@ class StyleSheetTable {
public: public:
typedef std::map<std::string,std::vector<std::string> > AttributeMap; typedef std::map<std::string,std::vector<std::string> > AttributeMap;
static shared_ptr<ZLTextStyleEntry> createControl(const AttributeMap &map); static shared_ptr<ZLTextStyleEntry> createControl(shared_ptr<ZLTextStyleEntry> entry, const AttributeMap &map);
static bool getPageBreakBefore(const AttributeMap &map, bool &value); static bool getPageBreakBefore(const AttributeMap &map, bool &value);
static bool getPageBreakAfter(const AttributeMap &map, bool &value); static bool getPageBreakAfter(const AttributeMap &map, bool &value);