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

View file

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

View file

@ -32,7 +32,7 @@ class StyleSheetTable {
public:
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 getPageBreakAfter(const AttributeMap &map, bool &value);