Major refactoring of CSS support
Also, improved support for line breaks.
This commit is contained in:
parent
a7e40b8d34
commit
248b307696
21 changed files with 649 additions and 368 deletions
|
@ -109,6 +109,12 @@ void BookReader::addFixedHSpace(unsigned char length) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BookReader::addLineBreak() {
|
||||||
|
if (myTextParagraphExists) {
|
||||||
|
myCurrentTextModel->addLineBreak();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BookReader::addControl(const ZLTextStyleEntry &entry) {
|
void BookReader::addControl(const ZLTextStyleEntry &entry) {
|
||||||
if (myTextParagraphExists) {
|
if (myTextParagraphExists) {
|
||||||
flushTextBufferToParagraph();
|
flushTextBufferToParagraph();
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
void addHyperlinkLabel(const std::string &label);
|
void addHyperlinkLabel(const std::string &label);
|
||||||
void addHyperlinkLabel(const std::string &label, int paragraphNumber);
|
void addHyperlinkLabel(const std::string &label, int paragraphNumber);
|
||||||
void addFixedHSpace(unsigned char length);
|
void addFixedHSpace(unsigned char length);
|
||||||
|
void addLineBreak();
|
||||||
|
|
||||||
void addImageReference(const std::string &id, short vOffset = 0);
|
void addImageReference(const std::string &id, short vOffset = 0);
|
||||||
void addImage(const std::string &id, shared_ptr<const ZLImage> image);
|
void addImage(const std::string &id, shared_ptr<const ZLImage> image);
|
||||||
|
|
|
@ -28,26 +28,22 @@
|
||||||
StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) {
|
StyleSheetTableParser::StyleSheetTableParser(StyleSheetTable &table) : myTable(table) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetTableParser::storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map) {
|
void StyleSheetTableParser::storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map) {
|
||||||
myTable.addMap(tagName, className, map);
|
myTable.addMap(ZLStringUtil::splitString(selector, " \t+"), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyleEntry> StyleSheetSingleStyleParser::parseString(const char *text, ZLBoolean3 *pageBreakBefore, ZLBoolean3 *pageBreakAfter) {
|
StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text) {
|
||||||
myReadState = ATTRIBUTE_NAME;
|
StyleSheetTable::Style style;
|
||||||
parse(text, strlen(text), true);
|
if (text) {
|
||||||
shared_ptr<ZLTextStyleEntry> control = StyleSheetTable::createControl(NULL, myMap);
|
myReadState = ATTRIBUTE_NAME;
|
||||||
bool value;
|
parse(text, strlen(text), true);
|
||||||
if (pageBreakBefore && StyleSheetTable::getPageBreakBefore(myMap, value)) {
|
StyleSheetTable::updateStyle(style, myMap);
|
||||||
*pageBreakBefore = value ? B3_TRUE : B3_FALSE;
|
reset();
|
||||||
}
|
}
|
||||||
if (pageBreakAfter && StyleSheetTable::getPageBreakAfter(myMap, value)) {
|
return style;
|
||||||
*pageBreakAfter = value ? B3_TRUE : B3_FALSE;
|
|
||||||
}
|
|
||||||
reset();
|
|
||||||
return control;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false) {
|
StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false), myAtBlockDepth(0) {
|
||||||
}
|
}
|
||||||
|
|
||||||
StyleSheetParser::~StyleSheetParser() {
|
StyleSheetParser::~StyleSheetParser() {
|
||||||
|
@ -58,6 +54,7 @@ void StyleSheetParser::reset() {
|
||||||
myAttributeName.erase();
|
myAttributeName.erase();
|
||||||
myReadState = TAG_NAME;
|
myReadState = TAG_NAME;
|
||||||
myInsideComment = false;
|
myInsideComment = false;
|
||||||
|
myAtBlockDepth = 0;
|
||||||
mySelectors.clear();
|
mySelectors.clear();
|
||||||
myMap.clear();
|
myMap.clear();
|
||||||
}
|
}
|
||||||
|
@ -81,7 +78,8 @@ void StyleSheetParser::parse(const char *text, int len, bool final) {
|
||||||
const char *start = text;
|
const char *start = text;
|
||||||
const char *end = text + len;
|
const char *end = text + len;
|
||||||
for (const char *ptr = start; ptr != end; ++ptr) {
|
for (const char *ptr = start; ptr != end; ++ptr) {
|
||||||
if (isspace(*ptr)) {
|
if ((myReadState != TAG_NAME && isspace(*ptr)) ||
|
||||||
|
(myReadState == TAG_NAME && *ptr == ',')) {
|
||||||
if (start != ptr) {
|
if (start != ptr) {
|
||||||
myWord.append(start, ptr - start);
|
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) {
|
void StyleSheetParser::processControl(const char control) {
|
||||||
switch (control) {
|
switch (control) {
|
||||||
case '{':
|
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;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
if (myReadState != BROKEN) {
|
switch (myReadState) {
|
||||||
for (unsigned int i=0; i<mySelectors.size(); i++) {
|
case AT_BLOCK:
|
||||||
std::string selector(mySelectors[i]);
|
if (--myAtBlockDepth > 0) {
|
||||||
std::string tag, klass;
|
return;
|
||||||
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);
|
break;
|
||||||
}
|
case AT_RULE:
|
||||||
|
case BROKEN:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
for (unsigned int i=0; i<mySelectors.size(); i++) {
|
||||||
|
storeData(mySelectors[i], myMap);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
myReadState = TAG_NAME;
|
myReadState = TAG_NAME;
|
||||||
mySelectors.clear();
|
mySelectors.clear();
|
||||||
myMap.clear();
|
myMap.clear();
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
myReadState =
|
switch (myReadState) {
|
||||||
((myReadState == ATTRIBUTE_VALUE) ||
|
case AT_RULE:
|
||||||
(myReadState == ATTRIBUTE_NAME)) ? ATTRIBUTE_NAME : BROKEN;
|
myReadState = TAG_NAME;
|
||||||
|
mySelectors.clear();
|
||||||
|
myMap.clear();
|
||||||
|
break;
|
||||||
|
case AT_BLOCK:
|
||||||
|
break;
|
||||||
|
case ATTRIBUTE_VALUE:
|
||||||
|
case ATTRIBUTE_NAME:
|
||||||
|
myReadState = ATTRIBUTE_NAME;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
myReadState = BROKEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case ':':
|
case ':':
|
||||||
myReadState = (myReadState == ATTRIBUTE_NAME) ? ATTRIBUTE_VALUE : BROKEN;
|
switch (myReadState) {
|
||||||
|
case AT_BLOCK:
|
||||||
|
break;
|
||||||
|
case ATTRIBUTE_NAME:
|
||||||
|
myReadState = ATTRIBUTE_VALUE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
myReadState = BROKEN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -177,18 +213,21 @@ void StyleSheetParser::processWord(std::string &word) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetParser::processWordWithoutComments(const std::string &word) {
|
void StyleSheetParser::processWordWithoutComments(std::string word) {
|
||||||
switch (myReadState) {
|
switch (myReadState) {
|
||||||
|
case AT_RULE:
|
||||||
|
case AT_BLOCK:
|
||||||
|
break;
|
||||||
case TAG_NAME:
|
case TAG_NAME:
|
||||||
|
ZLStringUtil::stripWhiteSpaces(word);
|
||||||
if (!word.empty()) {
|
if (!word.empty()) {
|
||||||
const unsigned int len = word.length();
|
if (word[0] == '@') {
|
||||||
if (word.at(len-1) == ',') {
|
myReadState = AT_RULE;
|
||||||
mySelectors.push_back(word.substr(0, len-1));
|
|
||||||
} else {
|
} else {
|
||||||
mySelectors.push_back(word);
|
mySelectors.push_back(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
myMap.clear();
|
|
||||||
break;
|
break;
|
||||||
case ATTRIBUTE_NAME:
|
case ATTRIBUTE_NAME:
|
||||||
myAttributeName = word;
|
myAttributeName = word;
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#define __STYLESHEETPARSER_H__
|
#define __STYLESHEETPARSER_H__
|
||||||
|
|
||||||
#include "StyleSheetTable.h"
|
#include "StyleSheetTable.h"
|
||||||
#include "ZLBoolean3.h"
|
|
||||||
|
|
||||||
class ZLInputStream;
|
class ZLInputStream;
|
||||||
|
|
||||||
|
@ -37,24 +36,27 @@ public:
|
||||||
void parse(const char *text, int len, bool final = false);
|
void parse(const char *text, int len, bool final = false);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void storeData(const std::string &tagName, const std::string &className, const StyleSheetTable::AttributeMap &map);
|
virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isControlSymbol(const char symbol);
|
bool isControlSymbol(const char symbol);
|
||||||
void processWord(std::string &word);
|
void processWord(std::string &word);
|
||||||
void processWordWithoutComments(const std::string &word);
|
void processWordWithoutComments(std::string word);
|
||||||
void processControl(const char control);
|
void processControl(const char control);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string myWord;
|
std::string myWord;
|
||||||
std::string myAttributeName;
|
std::string myAttributeName;
|
||||||
enum {
|
enum {
|
||||||
|
AT_RULE,
|
||||||
|
AT_BLOCK,
|
||||||
TAG_NAME,
|
TAG_NAME,
|
||||||
ATTRIBUTE_NAME,
|
ATTRIBUTE_NAME,
|
||||||
ATTRIBUTE_VALUE,
|
ATTRIBUTE_VALUE,
|
||||||
BROKEN,
|
BROKEN,
|
||||||
} myReadState;
|
} myReadState;
|
||||||
bool myInsideComment;
|
bool myInsideComment;
|
||||||
|
int myAtBlockDepth;
|
||||||
std::vector<std::string> mySelectors;
|
std::vector<std::string> mySelectors;
|
||||||
StyleSheetTable::AttributeMap myMap;
|
StyleSheetTable::AttributeMap myMap;
|
||||||
|
|
||||||
|
@ -67,7 +69,7 @@ public:
|
||||||
StyleSheetTableParser(StyleSheetTable &table);
|
StyleSheetTableParser(StyleSheetTable &table);
|
||||||
|
|
||||||
private:
|
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:
|
private:
|
||||||
StyleSheetTable &myTable;
|
StyleSheetTable &myTable;
|
||||||
|
@ -76,7 +78,7 @@ private:
|
||||||
class StyleSheetSingleStyleParser : public StyleSheetParser {
|
class StyleSheetSingleStyleParser : public StyleSheetParser {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
shared_ptr<ZLTextStyleEntry> parseString(const char *text, ZLBoolean3* pageBreakBefore, ZLBoolean3* pageBreakAfter);
|
StyleSheetTable::Style parseString(const char *text);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __STYLESHEETPARSER_H__ */
|
#endif /* __STYLESHEETPARSER_H__ */
|
||||||
|
|
|
@ -18,32 +18,99 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <ZLStringUtil.h>
|
#include <ZLStringUtil.h>
|
||||||
|
|
||||||
#include "StyleSheetTable.h"
|
#include "StyleSheetTable.h"
|
||||||
|
|
||||||
bool StyleSheetTable::isEmpty() const {
|
static const std::string WILDCARD("*");
|
||||||
return myControlMap.empty() && myPageBreakBeforeMap.empty() && myPageBreakAfterMap.empty();
|
|
||||||
|
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) {
|
StyleSheetTable::Selector::Selector(const std::string &selector) {
|
||||||
if ((!tag.empty() || !aClass.empty()) && !map.empty()) {
|
std::string buf(selector);
|
||||||
Key key(tag, aClass);
|
const int dot = buf.find('.');
|
||||||
// This will update the existing element if it already exists
|
if (dot >= 0) {
|
||||||
// or create a new one if it wasn't there yet
|
myClass = buf.substr(dot + 1);
|
||||||
myControlMap[key] = createControl(myControlMap[key], map);
|
buf = buf.substr(0, dot);
|
||||||
bool value;
|
}
|
||||||
if (getPageBreakBefore(map, value)) {
|
const int hash = buf.find('#');
|
||||||
myPageBreakBeforeMap[key] = value;
|
if (hash < 0) {
|
||||||
}
|
myType = buf;
|
||||||
if (getPageBreakAfter(map, value)) {
|
} else {
|
||||||
myPageBreakAfterMap[key] = value;
|
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<std::string> &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<std::string> &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<selectors.size(); i++) {
|
||||||
|
const Selector &selector = selectors[i];
|
||||||
|
a += selector.a();
|
||||||
|
b += selector.b();
|
||||||
|
c += selector.c();
|
||||||
|
stack.push_back(selector);
|
||||||
|
}
|
||||||
|
if (a > 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 (!toParse.empty()) {
|
||||||
if (ZLStringUtil::stringEndsWith(toParse, "%")) {
|
if (ZLStringUtil::stringEndsWith(toParse, "%")) {
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT;
|
unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT;
|
||||||
|
@ -72,14 +139,28 @@ static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntr
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) {
|
bool StyleSheetTable::parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
|
||||||
StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName);
|
if (parseLength(toParse, size, unit)) {
|
||||||
if (it == map.end()) {
|
// Negative margins do make sense but we don't really support them
|
||||||
return;
|
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<std::string> &values = it->second;
|
||||||
|
if (!values.empty()) {
|
||||||
|
setLength(entry, name, values[0]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const std::vector<std::string> &values = it->second;
|
|
||||||
if (!values.empty())
|
|
||||||
setLength(entry, name, values[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
|
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 {
|
void StyleSheetTable::setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) {
|
||||||
std::map<Key,bool>::const_iterator it = myPageBreakBeforeMap.find(Key(tag, aClass));
|
AttributeMap::const_iterator it = map.find(attributeName);
|
||||||
if (it != myPageBreakBeforeMap.end()) {
|
if (it != map.end()) {
|
||||||
return it->second;
|
const std::vector<std::string> &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 {
|
void StyleSheetTable::setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
|
||||||
std::map<Key,bool>::const_iterator it = myPageBreakAfterMap.find(Key(tag, aClass));
|
short size;
|
||||||
if (it != myPageBreakAfterMap.end()) {
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
return it->second;
|
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<ZLTextStyleEntry> StyleSheetTable::control(const std::string &tag, const std::string &aClass) const {
|
bool StyleSheetTable::sortBySpecificity(const Entry *e1, const Entry *e2) {
|
||||||
std::map<Key,shared_ptr<ZLTextStyleEntry> >::const_iterator it =
|
return e1->Specificity < e2->Specificity;
|
||||||
myControlMap.find(Key(tag, aClass));
|
}
|
||||||
return (it != myControlMap.end()) ? it->second : 0;
|
|
||||||
|
void StyleSheetTable::applyStyles(const ElementList &stack, Style &style) const {
|
||||||
|
std::vector<const Entry*> entries;
|
||||||
|
for (std::vector<Entry>::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 Entry*>::const_iterator e = entries.begin(); e != entries.end(); ++e) {
|
||||||
|
style.apply((*e)->Style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map, const std::string &name) {
|
const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map, const std::string &name) {
|
||||||
|
@ -143,21 +215,17 @@ const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map,
|
||||||
return emptyVector;
|
return emptyVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextStyleEntry> entry, const AttributeMap &styles) {
|
void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &styles) {
|
||||||
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()) {
|
||||||
if (alignment[0] == "justify") {
|
if (alignment[0] == "justify") {
|
||||||
entry->setAlignmentType(ALIGN_JUSTIFY);
|
entry.setAlignmentType(ALIGN_JUSTIFY);
|
||||||
} else if (alignment[0] == "left") {
|
} else if (alignment[0] == "left") {
|
||||||
entry->setAlignmentType(ALIGN_LEFT);
|
entry.setAlignmentType(ALIGN_LEFT);
|
||||||
} else if (alignment[0] == "right") {
|
} else if (alignment[0] == "right") {
|
||||||
entry->setAlignmentType(ALIGN_RIGHT);
|
entry.setAlignmentType(ALIGN_RIGHT);
|
||||||
} else if (alignment[0] == "center") {
|
} else if (alignment[0] == "center") {
|
||||||
entry->setAlignmentType(ALIGN_CENTER);
|
entry.setAlignmentType(ALIGN_CENTER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,23 +246,23 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextSty
|
||||||
} else if (bold[0] == "lighter") {
|
} else if (bold[0] == "lighter") {
|
||||||
}
|
}
|
||||||
if (num != -1) {
|
if (num != -1) {
|
||||||
entry->setFontModifier(FONT_MODIFIER_BOLD, num >= 600);
|
entry.setFontModifier(FONT_MODIFIER_BOLD, num >= 600);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &italic = values(styles, "font-style");
|
const std::vector<std::string> &italic = values(styles, "font-style");
|
||||||
if (!italic.empty()) {
|
if (!italic.empty()) {
|
||||||
entry->setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic");
|
entry.setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &variant = values(styles, "font-variant");
|
const std::vector<std::string> &variant = values(styles, "font-variant");
|
||||||
if (!variant.empty()) {
|
if (!variant.empty()) {
|
||||||
entry->setFontModifier(FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps");
|
entry.setFontModifier(FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps");
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &fontFamily = values(styles, "font-family");
|
const std::vector<std::string> &fontFamily = values(styles, "font-family");
|
||||||
if (!fontFamily.empty() && !fontFamily[0].empty()) {
|
if (!fontFamily.empty() && !fontFamily[0].empty()) {
|
||||||
entry->setFontFamily(fontFamily[0]);
|
entry.setFontFamily(fontFamily[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
short size;
|
short size;
|
||||||
|
@ -203,19 +271,19 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextSty
|
||||||
if (!fontSize.empty()) {
|
if (!fontSize.empty()) {
|
||||||
std::string value = fontSize[0];
|
std::string value = fontSize[0];
|
||||||
if (value == "xx-small") {
|
if (value == "xx-small") {
|
||||||
entry->setFontSizeMag(-3);
|
entry.setFontSizeMag(-3);
|
||||||
} else if (value == "x-small") {
|
} else if (value == "x-small") {
|
||||||
entry->setFontSizeMag(-2);
|
entry.setFontSizeMag(-2);
|
||||||
} else if (value == "small" || value == "smaller") {
|
} else if (value == "small" || value == "smaller") {
|
||||||
entry->setFontSizeMag(-1);
|
entry.setFontSizeMag(-1);
|
||||||
} else if (value == "medium") {
|
} else if (value == "medium") {
|
||||||
entry->setFontSizeMag(0);
|
entry.setFontSizeMag(0);
|
||||||
} else if (value == "large" || value == "larger") {
|
} else if (value == "large" || value == "larger") {
|
||||||
entry->setFontSizeMag(1);
|
entry.setFontSizeMag(1);
|
||||||
} else if (value == "x-large") {
|
} else if (value == "x-large") {
|
||||||
entry->setFontSizeMag(2);
|
entry.setFontSizeMag(2);
|
||||||
} else if (value == "xx-large") {
|
} else if (value == "xx-large") {
|
||||||
entry->setFontSizeMag(3);
|
entry.setFontSizeMag(3);
|
||||||
} else {
|
} else {
|
||||||
if (parseLength(value, size, unit)) {
|
if (parseLength(value, size, unit)) {
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
|
@ -225,16 +293,21 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextSty
|
||||||
case ZLTextStyleEntry::SIZE_UNIT_EM_100:
|
case ZLTextStyleEntry::SIZE_UNIT_EM_100:
|
||||||
case ZLTextStyleEntry::SIZE_UNIT_EX_100:
|
case ZLTextStyleEntry::SIZE_UNIT_EX_100:
|
||||||
case ZLTextStyleEntry::SIZE_UNIT_PERCENT:
|
case ZLTextStyleEntry::SIZE_UNIT_PERCENT:
|
||||||
entry->setFontSizeMag(
|
entry.setFontSizeMag((size < 100 && size > 80) ? -1 :
|
||||||
(size < 100 && size > 80) ? -1 :
|
(size > 100 && size < 120) ? 1 :
|
||||||
(size > 100 && size < 120) ? 1 :
|
(size - 100)/20);
|
||||||
(size - 100)/20);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> &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<std::string> margins = values(styles, "margin");
|
std::vector<std::string> margins = values(styles, "margin");
|
||||||
if (!margins.empty() && margins.back() == "!important") {
|
if (!margins.empty() && margins.back() == "!important") {
|
||||||
// Ignore the "!important" modifier for now
|
// Ignore the "!important" modifier for now
|
||||||
|
@ -242,78 +315,82 @@ shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(shared_ptr<ZLTextSty
|
||||||
}
|
}
|
||||||
switch (margins.size()) {
|
switch (margins.size()) {
|
||||||
case 1:
|
case 1:
|
||||||
if (parseLength(margins[0], size, unit)) {
|
if (parseMargin(margins[0], size, unit)) {
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_LEFT_INDENT, size, unit);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
if (parseLength(margins[0], size, unit)) {
|
if (parseMargin(margins[0], size, unit)) {
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
|
||||||
}
|
}
|
||||||
if (parseLength(margins[1], size, unit)) {
|
if (parseMargin(margins[1], size, unit)) {
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_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]);
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]);
|
||||||
if (parseLength(margins[1], size, unit)) {
|
if (parseMargin(margins[1], size, unit)) {
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
entry.setLength(ZLTextStyleEntry::LENGTH_RIGHT_INDENT, size, unit);
|
||||||
entry->setLength(ZLTextStyleEntry::LENGTH_LEFT_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;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]);
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, margins[0]);
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]);
|
setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, margins[1]);
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]);
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, margins[2]);
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[3]);
|
setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, margins[3]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left");
|
setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right");
|
setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent");
|
setLength(entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top");
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top");
|
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom");
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom");
|
||||||
setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom");
|
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom");
|
||||||
|
|
||||||
return entry;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleSheetTable::getPageBreakBefore(const AttributeMap &map, bool &value) {
|
bool StyleSheetTable::getPageBreakBefore(const AttributeMap &map, ZLBoolean3 &value) {
|
||||||
const std::vector<std::string> &pbb = values(map, "page-break-before");
|
const std::vector<std::string> &pbb = values(map, "page-break-before");
|
||||||
if (!pbb.empty()) {
|
if (!pbb.empty()) {
|
||||||
if ((pbb[0] == "always") ||
|
if ((pbb[0] == "always") ||
|
||||||
(pbb[0] == "left") ||
|
(pbb[0] == "left") ||
|
||||||
(pbb[0] == "right")) {
|
(pbb[0] == "right")) {
|
||||||
value = true;
|
value = B3_TRUE;
|
||||||
return true;
|
return true;
|
||||||
} else if (pbb[0] == "avoid") {
|
} else if (pbb[0] == "avoid") {
|
||||||
value = false;
|
value = B3_FALSE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleSheetTable::getPageBreakAfter(const AttributeMap &map, bool &value) {
|
bool StyleSheetTable::getPageBreakAfter(const AttributeMap &map, ZLBoolean3 &value) {
|
||||||
const std::vector<std::string> &pba = values(map, "page-break-after");
|
const std::vector<std::string> &pba = values(map, "page-break-after");
|
||||||
if (!pba.empty()) {
|
if (!pba.empty()) {
|
||||||
if ((pba[0] == "always") ||
|
if ((pba[0] == "always") ||
|
||||||
(pba[0] == "left") ||
|
(pba[0] == "left") ||
|
||||||
(pba[0] == "right")) {
|
(pba[0] == "right")) {
|
||||||
value = true;
|
value = B3_TRUE;
|
||||||
return true;
|
return true;
|
||||||
} else if (pba[0] == "avoid") {
|
} else if (pba[0] == "avoid") {
|
||||||
value = false;
|
value = B3_FALSE;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) {
|
||||||
|
updateTextStyle(style.TextStyle, map);
|
||||||
|
getPageBreakBefore(map, style.PageBreakBefore);
|
||||||
|
getPageBreakAfter(map, style.PageBreakAfter);
|
||||||
|
}
|
||||||
|
|
|
@ -27,50 +27,151 @@
|
||||||
#include <shared_ptr.h>
|
#include <shared_ptr.h>
|
||||||
|
|
||||||
#include <ZLTextParagraph.h>
|
#include <ZLTextParagraph.h>
|
||||||
|
#include <ZLBoolean3.h>
|
||||||
|
|
||||||
class StyleSheetTable {
|
class StyleSheetTable {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
struct Element {
|
||||||
|
Element(const std::string &tag, const char *klass, const char* id);
|
||||||
|
std::string Name;
|
||||||
|
std::vector<std::string> 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<std::string> &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<Element> ElementList;
|
||||||
|
typedef std::vector<Selector> SelectorList;
|
||||||
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(shared_ptr<ZLTextStyleEntry> entry, const AttributeMap &map);
|
|
||||||
static bool getPageBreakBefore(const AttributeMap &map, bool &value);
|
struct Style {
|
||||||
static bool getPageBreakAfter(const AttributeMap &map, bool &value);
|
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<Style> StyleList;
|
||||||
|
static void updateStyle(Style &style, const AttributeMap &map);
|
||||||
|
static void updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &map);
|
||||||
|
static bool getPageBreakBefore(const AttributeMap &map, ZLBoolean3 &value);
|
||||||
|
static bool getPageBreakAfter(const AttributeMap &map, ZLBoolean3 &value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map);
|
struct Entry {
|
||||||
|
Entry();
|
||||||
|
Entry(const SelectorList &selectors, int specificity, const AttributeMap &map);
|
||||||
|
Entry &operator = (const Entry &other);
|
||||||
|
bool match(const ElementList &stack) const;
|
||||||
|
|
||||||
|
SelectorList Selectors;
|
||||||
|
int Specificity;
|
||||||
|
struct Style Style;
|
||||||
|
};
|
||||||
|
|
||||||
|
void addMap(const std::vector<std::string> &selectors, const AttributeMap &map);
|
||||||
|
|
||||||
|
static bool parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit);
|
||||||
|
static bool parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit);
|
||||||
static void setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName);
|
static void setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName);
|
||||||
static void setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value);
|
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<std::string> &values(const AttributeMap &map, const std::string &name);
|
static const std::vector<std::string> &values(const AttributeMap &map, const std::string &name);
|
||||||
|
static bool sortBySpecificity(const Entry *e1, const Entry *e2);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
bool doBreakBefore(const std::string &tag, const std::string &aClass) const;
|
void applyStyles(const ElementList &stack, Style &style) const;
|
||||||
bool doBreakAfter(const std::string &tag, const std::string &aClass) const;
|
|
||||||
shared_ptr<ZLTextStyleEntry> control(const std::string &tag, const std::string &aClass) const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Key {
|
std::vector<Entry> myEntries;
|
||||||
Key(const std::string &tag, const std::string &aClass);
|
|
||||||
|
|
||||||
const std::string TagName;
|
|
||||||
const std::string ClassName;
|
|
||||||
|
|
||||||
bool operator < (const Key &key) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::map<Key,shared_ptr<ZLTextStyleEntry> > myControlMap;
|
|
||||||
std::map<Key,bool> myPageBreakBeforeMap;
|
|
||||||
std::map<Key,bool> myPageBreakAfterMap;
|
|
||||||
|
|
||||||
friend class StyleSheetTableParser;
|
friend class StyleSheetTableParser;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline StyleSheetTable::Key::Key(const std::string &tag, const std::string &aClass) : TagName(tag), ClassName(aClass) {
|
inline StyleSheetTable::Selector::Selector(const std::string &type, const std::string &klass, const std::string &id) : myType(type), myClass(klass), myId(id) {}
|
||||||
|
inline StyleSheetTable::Selector::Selector(const std::string &type, const std::string &klass) : myType(type), myClass(klass) {}
|
||||||
|
inline StyleSheetTable::Selector::Selector(const StyleSheetTable::Selector &other) : myType(other.myType), myClass(other.myClass), myId(other.myId) {}
|
||||||
|
inline StyleSheetTable::Selector::Selector() {}
|
||||||
|
inline StyleSheetTable::Selector &StyleSheetTable::Selector::operator = (const StyleSheetTable::Selector &other) {
|
||||||
|
myType = other.myType; myClass = other.myClass; myId = other.myId; return *this;
|
||||||
|
}
|
||||||
|
inline bool StyleSheetTable::Selector::operator == (const Selector &other) const {
|
||||||
|
return (&other == this) || (myType == other.myType && myClass == other.myClass && myId == other.myId);
|
||||||
|
}
|
||||||
|
inline bool StyleSheetTable::Selector::operator != (const Selector &other) const {
|
||||||
|
return (&other != this) && (myType != other.myType || myClass != other.myClass || myId != other.myId);
|
||||||
|
}
|
||||||
|
inline bool StyleSheetTable::Selector::operator < (const StyleSheetTable::Selector &other) const {
|
||||||
|
return myType < other.myType || (myType == other.myType && (myClass < other.myClass || (myClass == other.myClass && myId < other.myId)));
|
||||||
|
}
|
||||||
|
inline bool StyleSheetTable::Selector::match(const Element &element) const {
|
||||||
|
return match(myType, element.Name) && match(myId, element.Id) && match(myClass, element.Classes);
|
||||||
|
}
|
||||||
|
inline int StyleSheetTable::Selector::a() const { return myId.empty() ? 0 : 1; }
|
||||||
|
inline int StyleSheetTable::Selector::b() const { return myClass.empty() ? 0 : 1; }
|
||||||
|
inline int StyleSheetTable::Selector::c() const { return myType.empty() ? 0 : 1; }
|
||||||
|
inline const std::string &StyleSheetTable::Selector::type() const { return myType; }
|
||||||
|
inline const std::string &StyleSheetTable::Selector::klass() const { return myClass; }
|
||||||
|
inline const std::string &StyleSheetTable::Selector::id() const { return myId; }
|
||||||
|
|
||||||
|
inline StyleSheetTable::Style::Style() : PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED) {}
|
||||||
|
inline StyleSheetTable::Style::Style(const StyleSheetTable::Style &other) : TextStyle(other.TextStyle), PageBreakBefore(other.PageBreakBefore), PageBreakAfter(other.PageBreakAfter) {}
|
||||||
|
inline StyleSheetTable::Style::Style(const StyleSheetTable::AttributeMap &map) : PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED) {
|
||||||
|
updateStyle(*this, map);
|
||||||
|
}
|
||||||
|
inline StyleSheetTable::Style &StyleSheetTable::Style::operator = (const StyleSheetTable::Style &other) {
|
||||||
|
TextStyle = other.TextStyle;
|
||||||
|
PageBreakBefore = other.PageBreakBefore;
|
||||||
|
PageBreakAfter = other.PageBreakAfter;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool StyleSheetTable::Key::operator < (const StyleSheetTable::Key &key) const {
|
inline StyleSheetTable::Entry::Entry() : Specificity(0) {}
|
||||||
return (TagName < key.TagName) || ((TagName == key.TagName) && (ClassName < key.ClassName));
|
inline StyleSheetTable::Entry::Entry(const SelectorList &selectors, int specificity, const AttributeMap &map) : Selectors(selectors), Specificity(specificity), Style(map) {}
|
||||||
|
inline StyleSheetTable::Entry &StyleSheetTable::Entry::operator = (const StyleSheetTable::Entry &other) {
|
||||||
|
Selectors = other.Selectors;
|
||||||
|
Style = other.Style;
|
||||||
|
Specificity = other.Specificity;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline bool StyleSheetTable::isEmpty() const { return myEntries.empty(); }
|
||||||
|
|
||||||
#endif /* __STYLESHEETTABLE_H__ */
|
#endif /* __STYLESHEETTABLE_H__ */
|
||||||
|
|
|
@ -41,6 +41,12 @@ std::map<std::string,XHTMLTagAction*> XHTMLReader::ourTagActions;
|
||||||
XHTMLTagAction::~XHTMLTagAction() {
|
XHTMLTagAction::~XHTMLTagAction() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void XHTMLTagAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLTagAction::doAtEnd(XHTMLReader &reader) {
|
||||||
|
}
|
||||||
|
|
||||||
BookReader &XHTMLTagAction::bookReader(XHTMLReader &reader) {
|
BookReader &XHTMLTagAction::bookReader(XHTMLReader &reader) {
|
||||||
return reader.myModelReader;
|
return reader.myModelReader;
|
||||||
}
|
}
|
||||||
|
@ -68,7 +74,6 @@ class XHTMLTagLinkAction : public XHTMLTagAction {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
||||||
void doAtEnd(XHTMLReader &reader);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class XHTMLTagParagraphAction : public XHTMLTagAction {
|
class XHTMLTagParagraphAction : public XHTMLTagAction {
|
||||||
|
@ -89,6 +94,11 @@ class XHTMLTagRestartParagraphAction : public XHTMLTagAction {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
||||||
|
};
|
||||||
|
|
||||||
|
class XHTMLTagLineBreakAction : public XHTMLTagAction {
|
||||||
|
|
||||||
|
public:
|
||||||
void doAtEnd(XHTMLReader &reader);
|
void doAtEnd(XHTMLReader &reader);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -99,7 +109,6 @@ public:
|
||||||
XHTMLTagImageAction(const std::string &attributeName);
|
XHTMLTagImageAction(const std::string &attributeName);
|
||||||
|
|
||||||
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
||||||
void doAtEnd(XHTMLReader &reader);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
shared_ptr<ZLXMLReader::AttributeNamePredicate> myPredicate;
|
shared_ptr<ZLXMLReader::AttributeNamePredicate> myPredicate;
|
||||||
|
@ -224,9 +233,6 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut
|
||||||
//reader.myStyleSheetTable.dump();
|
//reader.myStyleSheetTable.dump();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagLinkAction::doAtEnd(XHTMLReader&) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
if (!reader.myNewParagraphInProgress) {
|
if (!reader.myNewParagraphInProgress) {
|
||||||
beginParagraph(reader);
|
beginParagraph(reader);
|
||||||
|
@ -255,7 +261,8 @@ void XHTMLTagRestartParagraphAction::doAtStart(XHTMLReader &reader, const char**
|
||||||
beginParagraph(reader);
|
beginParagraph(reader);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagRestartParagraphAction::doAtEnd(XHTMLReader&) {
|
void XHTMLTagLineBreakAction::doAtEnd(XHTMLReader& reader) {
|
||||||
|
bookReader(reader).addLineBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagItemAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagItemAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
|
@ -280,6 +287,11 @@ XHTMLTagImageAction::XHTMLTagImageAction(const std::string &attributeName) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagImageAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
void XHTMLTagImageAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
||||||
|
// Ignore transparent images
|
||||||
|
if (!reader.myOpacityStack.back()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const char *fileName = reader.attributeValue(xmlattributes, *myPredicate);
|
const char *fileName = reader.attributeValue(xmlattributes, *myPredicate);
|
||||||
if (fileName == 0) {
|
if (fileName == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -302,6 +314,7 @@ void XHTMLTagImageAction::doAtStart(XHTMLReader &reader, const char **xmlattribu
|
||||||
if (flag) {
|
if (flag) {
|
||||||
beginParagraph(reader);
|
beginParagraph(reader);
|
||||||
}
|
}
|
||||||
|
reader.myElementHasContents.back() = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
XHTMLTagSvgAction::XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate) : myPredicate(predicate) {
|
XHTMLTagSvgAction::XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate) : myPredicate(predicate) {
|
||||||
|
@ -322,9 +335,6 @@ bool XHTMLSvgImageAttributeNamePredicate::accepts(const ZLXMLReader &reader, con
|
||||||
return myIsEnabled && NamespaceAttributeNamePredicate::accepts(reader, name);
|
return myIsEnabled && NamespaceAttributeNamePredicate::accepts(reader, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagImageAction::doAtEnd(XHTMLReader&) {
|
|
||||||
}
|
|
||||||
|
|
||||||
XHTMLTagControlAction::XHTMLTagControlAction(FBTextKind control) : myControl(control) {
|
XHTMLTagControlAction::XHTMLTagControlAction(FBTextKind control) : myControl(control) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -387,7 +397,7 @@ void XHTMLTagParagraphWithControlAction::doAtEnd(XHTMLReader &reader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
reader.myPreformatted = true;
|
reader.myPreformatted++;
|
||||||
beginParagraph(reader);
|
beginParagraph(reader);
|
||||||
bookReader(reader).addControl(CODE, true);
|
bookReader(reader).addControl(CODE, true);
|
||||||
}
|
}
|
||||||
|
@ -395,7 +405,7 @@ void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) {
|
void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) {
|
||||||
bookReader(reader).addControl(CODE, false);
|
bookReader(reader).addControl(CODE, false);
|
||||||
endParagraph(reader);
|
endParagraph(reader);
|
||||||
reader.myPreformatted = false;
|
reader.myPreformatted--;
|
||||||
}
|
}
|
||||||
|
|
||||||
XHTMLTagAction *XHTMLReader::addAction(const std::string &tag, XHTMLTagAction *action) {
|
XHTMLTagAction *XHTMLReader::addAction(const std::string &tag, XHTMLTagAction *action) {
|
||||||
|
@ -440,8 +450,9 @@ void XHTMLReader::fillTagTable() {
|
||||||
addAction("cite", new XHTMLTagControlAction(CITE));
|
addAction("cite", new XHTMLTagControlAction(CITE));
|
||||||
addAction("sub", new XHTMLTagControlAction(SUB));
|
addAction("sub", new XHTMLTagControlAction(SUB));
|
||||||
addAction("sup", new XHTMLTagControlAction(SUP));
|
addAction("sup", new XHTMLTagControlAction(SUP));
|
||||||
addAction("dd", new XHTMLTagControlAction(DEFINITION_DESCRIPTION));
|
addAction("dd", new XHTMLTagParagraphWithControlAction(DEFINITION_DESCRIPTION));
|
||||||
addAction("dfn", new XHTMLTagControlAction(DEFINITION));
|
addAction("dt", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
||||||
|
addAction("dfn", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
||||||
addAction("strike", new XHTMLTagControlAction(STRIKETHROUGH));
|
addAction("strike", new XHTMLTagControlAction(STRIKETHROUGH));
|
||||||
|
|
||||||
addAction("a", new XHTMLTagHyperlinkAction());
|
addAction("a", new XHTMLTagHyperlinkAction());
|
||||||
|
@ -457,7 +468,7 @@ void XHTMLReader::fillTagTable() {
|
||||||
|
|
||||||
//addAction("base", new XHTMLTagAction());
|
//addAction("base", new XHTMLTagAction());
|
||||||
//addAction("blockquote", new XHTMLTagAction());
|
//addAction("blockquote", new XHTMLTagAction());
|
||||||
addAction("br", new XHTMLTagRestartParagraphAction());
|
addAction("br", new XHTMLTagLineBreakAction());
|
||||||
//addAction("center", new XHTMLTagAction());
|
//addAction("center", new XHTMLTagAction());
|
||||||
addAction("div", new XHTMLTagParagraphAction());
|
addAction("div", new XHTMLTagParagraphAction());
|
||||||
addAction("dt", new XHTMLTagParagraphAction());
|
addAction("dt", new XHTMLTagParagraphAction());
|
||||||
|
@ -495,13 +506,14 @@ bool XHTMLReader::readFile(const ZLFile &file, const std::string &referenceName)
|
||||||
const int index = referenceName.rfind('/', referenceName.length() - 1);
|
const int index = referenceName.rfind('/', referenceName.length() - 1);
|
||||||
myReferenceDirName = referenceName.substr(0, index + 1);
|
myReferenceDirName = referenceName.substr(0, index + 1);
|
||||||
|
|
||||||
myPreformatted = false;
|
myPreformatted = 0;
|
||||||
myNewParagraphInProgress = false;
|
myNewParagraphInProgress = false;
|
||||||
myReadState = READ_NOTHING;
|
myReadState = READ_NOTHING;
|
||||||
|
|
||||||
myCSSStack.clear();
|
myElementStack.clear();
|
||||||
myStyleEntryStack.clear();
|
myStyleStack.clear();
|
||||||
myStylesToRemove = 0;
|
myElementHasContents.clear();
|
||||||
|
myOpacityStack.clear();
|
||||||
|
|
||||||
return readDocument(file);
|
return readDocument(file);
|
||||||
}
|
}
|
||||||
|
@ -516,80 +528,45 @@ shared_ptr<ZLTextStyleEntry> XHTMLReader::addStyleEntry(shared_ptr<ZLTextStyleEn
|
||||||
|
|
||||||
void XHTMLReader::startElementHandler(const char *tag, const char **attributes) {
|
void XHTMLReader::startElementHandler(const char *tag, const char **attributes) {
|
||||||
static const std::string HASH = "#";
|
static const std::string HASH = "#";
|
||||||
static const std::string EMPTY;
|
|
||||||
const char *id = attributeValue(attributes, "id");
|
const char *id = attributeValue(attributes, "id");
|
||||||
|
const char *style = attributeValue(attributes, "style");
|
||||||
|
const char *klass = attributeValue(attributes, "class");
|
||||||
if (id != 0) {
|
if (id != 0) {
|
||||||
myModelReader.addHyperlinkLabel(myReferenceName + HASH + id);
|
myModelReader.addHyperlinkLabel(myReferenceName + HASH + id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string sTag = ZLUnicodeUtil::toLower(tag);
|
const std::string sTag = ZLUnicodeUtil::toLower(tag);
|
||||||
|
myElementStack.push_back(StyleSheetTable::Element(sTag, klass, id));
|
||||||
|
|
||||||
const char *aClass = attributeValue(attributes, "class");
|
StyleSheetTable::Style cssStyle;
|
||||||
std::vector<std::string> classes;
|
myStyleSheetTable.applyStyles(myElementStack, cssStyle);
|
||||||
if (aClass != 0) {
|
|
||||||
classes = ZLStringUtil::splitString(aClass, ", \n");
|
|
||||||
}
|
|
||||||
if (classes.empty()) {
|
|
||||||
classes.push_back(EMPTY);
|
|
||||||
}
|
|
||||||
|
|
||||||
shared_ptr<ZLTextStyleEntry> inlineStyle;
|
|
||||||
const char *style = attributeValue(attributes, "style");
|
|
||||||
ZLBoolean3 pageBreakBefore(B3_UNDEFINED), pageBreakAfter(B3_UNDEFINED);
|
|
||||||
if (style != 0) {
|
if (style != 0) {
|
||||||
inlineStyle = myStyleParser.parseString(style, &pageBreakBefore, &pageBreakAfter);
|
cssStyle.apply(myStyleParser.parseString(style));
|
||||||
}
|
}
|
||||||
if (pageBreakBefore == B3_UNDEFINED) {
|
if (cssStyle.PageBreakBefore == B3_TRUE) {
|
||||||
for (unsigned int i=0; i<classes.size(); i++) {
|
|
||||||
if (myStyleSheetTable.doBreakBefore(sTag, classes[i])) {
|
|
||||||
pageBreakBefore = B3_TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pageBreakAfter == B3_UNDEFINED) {
|
|
||||||
for (unsigned int i=0; i<classes.size(); i++) {
|
|
||||||
if (myStyleSheetTable.doBreakAfter(sTag, classes[i])) {
|
|
||||||
pageBreakAfter = B3_TRUE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (pageBreakBefore == B3_TRUE) {
|
|
||||||
myModelReader.insertEndOfSectionParagraph();
|
myModelReader.insertEndOfSectionParagraph();
|
||||||
}
|
}
|
||||||
myDoPageBreakAfterStack.push_back(pageBreakAfter == B3_TRUE);
|
|
||||||
|
int opacity = myOpacityStack.empty() ? 255 : myOpacityStack.back();
|
||||||
|
if (cssStyle.TextStyle.opacitySupported()) {
|
||||||
|
opacity *= cssStyle.TextStyle.opacity();
|
||||||
|
opacity /= 255;
|
||||||
|
}
|
||||||
|
|
||||||
|
myStyleStack.push_back(cssStyle);
|
||||||
|
myElementHasContents.push_back(false);
|
||||||
|
myOpacityStack.push_back((unsigned char)opacity);
|
||||||
|
|
||||||
XHTMLTagAction *action = ourTagActions[sTag];
|
XHTMLTagAction *action = ourTagActions[sTag];
|
||||||
if (action != 0) {
|
if (action != 0) {
|
||||||
action->doAtStart(*this, attributes);
|
action->doAtStart(*this, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyleEntry> entry;
|
myModelReader.addControl(cssStyle.TextStyle);
|
||||||
entry = addStyleEntry(entry, myStyleSheetTable.control(sTag, EMPTY));
|
|
||||||
for (unsigned int i=0; i<classes.size(); i++) {
|
|
||||||
std::string klass = classes[i];
|
|
||||||
entry = addStyleEntry(entry, myStyleSheetTable.control(EMPTY, klass));
|
|
||||||
if (!klass.empty()) {
|
|
||||||
entry = addStyleEntry(entry, myStyleSheetTable.control(sTag, klass));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entry = addStyleEntry(entry, inlineStyle);
|
|
||||||
if (!entry.isNull()) {
|
|
||||||
myModelReader.addControl(*entry);
|
|
||||||
myStyleEntryStack.push_back(entry);
|
|
||||||
myCSSStack.push_back(1);
|
|
||||||
} else {
|
|
||||||
myCSSStack.push_back(0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::endElementHandler(const char *tag) {
|
void XHTMLReader::endElementHandler(const char *tag) {
|
||||||
for (int i = myCSSStack.back(); i > 0; --i) {
|
myModelReader.addControl(REGULAR, false);
|
||||||
myModelReader.addControl(REGULAR, false);
|
|
||||||
}
|
|
||||||
myStylesToRemove = myCSSStack.back();
|
|
||||||
myCSSStack.pop_back();
|
|
||||||
|
|
||||||
XHTMLTagAction *action = ourTagActions[ZLUnicodeUtil::toLower(tag)];
|
XHTMLTagAction *action = ourTagActions[ZLUnicodeUtil::toLower(tag)];
|
||||||
if (action != 0) {
|
if (action != 0) {
|
||||||
|
@ -597,58 +574,32 @@ void XHTMLReader::endElementHandler(const char *tag) {
|
||||||
myNewParagraphInProgress = false;
|
myNewParagraphInProgress = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (; myStylesToRemove > 0; --myStylesToRemove) {
|
const bool haveContents = myElementHasContents.back();
|
||||||
myStyleEntryStack.pop_back();
|
if (myStyleStack.back().PageBreakAfter == B3_TRUE && haveContents) {
|
||||||
}
|
|
||||||
|
|
||||||
if (myDoPageBreakAfterStack.back()) {
|
|
||||||
myModelReader.insertEndOfSectionParagraph();
|
myModelReader.insertEndOfSectionParagraph();
|
||||||
}
|
}
|
||||||
myDoPageBreakAfterStack.pop_back();
|
|
||||||
|
myElementStack.pop_back();
|
||||||
|
myStyleStack.pop_back();
|
||||||
|
myElementHasContents.pop_back();
|
||||||
|
myOpacityStack.pop_back();
|
||||||
|
|
||||||
|
if (!myElementHasContents.empty() && haveContents) {
|
||||||
|
myElementHasContents.back() = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::beginParagraph() {
|
void XHTMLReader::beginParagraph() {
|
||||||
myCurrentParagraphIsEmpty = true;
|
myCurrentParagraphIsEmpty = true;
|
||||||
myModelReader.beginParagraph();
|
myModelReader.beginParagraph();
|
||||||
bool doBlockSpaceBefore = false;
|
if (!myStyleStack.empty()) {
|
||||||
for (std::vector<shared_ptr<ZLTextStyleEntry> >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end(); ++it) {
|
for (StyleSheetTable::StyleList::const_iterator it = myStyleStack.begin(); it != myStyleStack.end(); ++it) {
|
||||||
myModelReader.addControl(**it);
|
myModelReader.addControl(((*it).TextStyle));
|
||||||
doBlockSpaceBefore =
|
}
|
||||||
doBlockSpaceBefore ||
|
|
||||||
(*it)->lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (doBlockSpaceBefore) {
|
|
||||||
ZLTextStyleEntry blockingEntry;
|
|
||||||
blockingEntry.setLength(
|
|
||||||
ZLTextStyleEntry::LENGTH_SPACE_BEFORE,
|
|
||||||
0,
|
|
||||||
ZLTextStyleEntry::SIZE_UNIT_PIXEL
|
|
||||||
);
|
|
||||||
myModelReader.addControl(blockingEntry);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::endParagraph() {
|
void XHTMLReader::endParagraph() {
|
||||||
bool doBlockSpaceAfter = false;
|
|
||||||
for (std::vector<shared_ptr<ZLTextStyleEntry> >::const_iterator it = myStyleEntryStack.begin(); it != myStyleEntryStack.end() - myStylesToRemove; ++it) {
|
|
||||||
doBlockSpaceAfter =
|
|
||||||
doBlockSpaceAfter ||
|
|
||||||
(*it)->lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER);
|
|
||||||
}
|
|
||||||
if (doBlockSpaceAfter) {
|
|
||||||
ZLTextStyleEntry blockingEntry;
|
|
||||||
blockingEntry.setLength(
|
|
||||||
ZLTextStyleEntry::LENGTH_SPACE_AFTER,
|
|
||||||
0,
|
|
||||||
ZLTextStyleEntry::SIZE_UNIT_PIXEL
|
|
||||||
);
|
|
||||||
myModelReader.addControl(blockingEntry);
|
|
||||||
}
|
|
||||||
for (; myStylesToRemove > 0; --myStylesToRemove) {
|
|
||||||
myModelReader.addControl(*myStyleEntryStack.back());
|
|
||||||
myStyleEntryStack.pop_back();
|
|
||||||
}
|
|
||||||
myModelReader.endParagraph();
|
myModelReader.endParagraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -662,35 +613,35 @@ void XHTMLReader::characterDataHandler(const char *text, size_t len) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_BODY:
|
case READ_BODY:
|
||||||
if (myPreformatted) {
|
if (myOpacityStack.back()) {
|
||||||
if ((*text == '\r') || (*text == '\n')) {
|
if (myPreformatted) {
|
||||||
myModelReader.addControl(CODE, false);
|
if ((*text == '\r') || (*text == '\n')) {
|
||||||
endParagraph();
|
myModelReader.addLineBreak();
|
||||||
beginParagraph();
|
}
|
||||||
myModelReader.addControl(CODE, true);
|
size_t spaceCounter = 0;
|
||||||
}
|
while ((spaceCounter < len) && isspace((unsigned char)*(text + spaceCounter))) {
|
||||||
size_t spaceCounter = 0;
|
++spaceCounter;
|
||||||
while ((spaceCounter < len) && isspace((unsigned char)*(text + spaceCounter))) {
|
}
|
||||||
++spaceCounter;
|
myModelReader.addFixedHSpace(spaceCounter);
|
||||||
}
|
text += spaceCounter;
|
||||||
myModelReader.addFixedHSpace(spaceCounter);
|
len -= spaceCounter;
|
||||||
text += spaceCounter;
|
} else if ((myNewParagraphInProgress) || !myModelReader.paragraphIsOpen()) {
|
||||||
len -= spaceCounter;
|
while (isspace((unsigned char)*text)) {
|
||||||
} else if ((myNewParagraphInProgress) || !myModelReader.paragraphIsOpen()) {
|
++text;
|
||||||
while (isspace((unsigned char)*text)) {
|
if (--len == 0) {
|
||||||
++text;
|
break;
|
||||||
if (--len == 0) {
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
if (len > 0) {
|
||||||
if (len > 0) {
|
myCurrentParagraphIsEmpty = false;
|
||||||
myCurrentParagraphIsEmpty = false;
|
myElementHasContents.back() = true;
|
||||||
if (!myModelReader.paragraphIsOpen()) {
|
if (!myModelReader.paragraphIsOpen()) {
|
||||||
myModelReader.beginParagraph();
|
myModelReader.beginParagraph();
|
||||||
|
}
|
||||||
|
myModelReader.addData(std::string(text, len));
|
||||||
|
myNewParagraphInProgress = false;
|
||||||
}
|
}
|
||||||
myModelReader.addData(std::string(text, len));
|
|
||||||
myNewParagraphInProgress = false;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,8 @@ class XHTMLTagAction {
|
||||||
public:
|
public:
|
||||||
virtual ~XHTMLTagAction();
|
virtual ~XHTMLTagAction();
|
||||||
|
|
||||||
virtual void doAtStart(XHTMLReader &reader, const char **xmlattributes) = 0;
|
virtual void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
||||||
virtual void doAtEnd(XHTMLReader &reader) = 0;
|
virtual void doAtEnd(XHTMLReader &reader);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static BookReader &bookReader(XHTMLReader &reader);
|
static BookReader &bookReader(XHTMLReader &reader);
|
||||||
|
@ -80,13 +80,13 @@ private:
|
||||||
std::string myPathPrefix;
|
std::string myPathPrefix;
|
||||||
std::string myReferenceName;
|
std::string myReferenceName;
|
||||||
std::string myReferenceDirName;
|
std::string myReferenceDirName;
|
||||||
bool myPreformatted;
|
int myPreformatted;
|
||||||
bool myNewParagraphInProgress;
|
bool myNewParagraphInProgress;
|
||||||
StyleSheetTable myStyleSheetTable;
|
StyleSheetTable myStyleSheetTable;
|
||||||
std::vector<int> myCSSStack;
|
StyleSheetTable::ElementList myElementStack;
|
||||||
std::vector<shared_ptr<ZLTextStyleEntry> > myStyleEntryStack;
|
StyleSheetTable::StyleList myStyleStack;
|
||||||
int myStylesToRemove;
|
std::vector<unsigned char> myOpacityStack;
|
||||||
std::vector<bool> myDoPageBreakAfterStack;
|
std::vector<bool> myElementHasContents;
|
||||||
bool myCurrentParagraphIsEmpty;
|
bool myCurrentParagraphIsEmpty;
|
||||||
StyleSheetSingleStyleParser myStyleParser;
|
StyleSheetSingleStyleParser myStyleParser;
|
||||||
shared_ptr<StyleSheetTableParser> myTableParser;
|
shared_ptr<StyleSheetTableParser> myTableParser;
|
||||||
|
@ -104,6 +104,7 @@ private:
|
||||||
friend class XHTMLTagParagraphAction;
|
friend class XHTMLTagParagraphAction;
|
||||||
friend class XHTMLTagBodyAction;
|
friend class XHTMLTagBodyAction;
|
||||||
friend class XHTMLTagRestartParagraphAction;
|
friend class XHTMLTagRestartParagraphAction;
|
||||||
|
friend class XHTMLTagImageAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __XHTMLREADER_H__ */
|
#endif /* __XHTMLREADER_H__ */
|
||||||
|
|
|
@ -91,17 +91,18 @@ void ZLStringUtil::stripWhiteSpaces(std::string &str) {
|
||||||
str.erase(r_counter, length - r_counter);
|
str.erase(r_counter, length - r_counter);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ZLStringUtil::splitString(const std::string &str, const char* delim)
|
std::vector<std::string> ZLStringUtil::splitString(const char *str, const char* delim) {
|
||||||
{
|
|
||||||
std::vector<std::string> tokens;
|
std::vector<std::string> tokens;
|
||||||
char *buf = strdup(str.c_str());
|
if (str != 0) {
|
||||||
char *saveptr;
|
char *buf = strdup(str);
|
||||||
char *token = strtok_r(buf, delim, &saveptr);
|
char *saveptr;
|
||||||
while (token) {
|
char *token = strtok_r(buf, delim, &saveptr);
|
||||||
tokens.push_back(std::string(token));
|
while (token) {
|
||||||
token = strtok_r(NULL, delim, &saveptr);
|
tokens.push_back(std::string(token));
|
||||||
|
token = strtok_r(NULL, delim, &saveptr);
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
}
|
}
|
||||||
free(buf);
|
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@ public:
|
||||||
static void appendNumber(std::string &str, unsigned int n);
|
static void appendNumber(std::string &str, unsigned int n);
|
||||||
static void append(std::string &str, const std::vector<std::string> &buffer);
|
static void append(std::string &str, const std::vector<std::string> &buffer);
|
||||||
static void stripWhiteSpaces(std::string &str);
|
static void stripWhiteSpaces(std::string &str);
|
||||||
|
static std::vector<std::string> splitString(const char *str, const char* delim);
|
||||||
static std::vector<std::string> splitString(const std::string &str, const char* delim);
|
static std::vector<std::string> splitString(const std::string &str, const char* delim);
|
||||||
|
|
||||||
static std::string printf(const std::string &format, const std::string &arg0);
|
static std::string printf(const std::string &format, const std::string &arg0);
|
||||||
|
@ -42,4 +43,8 @@ public:
|
||||||
static double stringToDouble(const std::string &value, double defaultValue);
|
static double stringToDouble(const std::string &value, double defaultValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline std::vector<std::string> ZLStringUtil::splitString(const std::string &str, const char* delim) {
|
||||||
|
return ZLStringUtil::splitString(str.c_str(), delim);
|
||||||
|
}
|
||||||
|
|
||||||
#endif /* __ZLSTRINGUTIL_H__ */
|
#endif /* __ZLSTRINGUTIL_H__ */
|
||||||
|
|
|
@ -103,6 +103,7 @@ int ZLTextArea::Style::elementWidth(const ZLTextElement &element, unsigned int c
|
||||||
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
return metrics.FullWidth + abs(textStyle()->lineStartIndent(metrics, false)) + abs(textStyle()->lineEndIndent(metrics, false)) + abs(textStyle()->firstLineIndentDelta(metrics)) + 1;
|
return metrics.FullWidth + abs(textStyle()->lineStartIndent(metrics, false)) + abs(textStyle()->lineEndIndent(metrics, false)) + abs(textStyle()->firstLineIndentDelta(metrics)) + 1;
|
||||||
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
case ZLTextElement::FORCED_CONTROL_ELEMENT:
|
case ZLTextElement::FORCED_CONTROL_ELEMENT:
|
||||||
case ZLTextElement::CONTROL_ELEMENT:
|
case ZLTextElement::CONTROL_ELEMENT:
|
||||||
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
||||||
|
@ -131,6 +132,7 @@ int ZLTextArea::Style::elementHeight(const ZLTextElement &element, const ZLTextS
|
||||||
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
||||||
return - textStyle()->spaceBefore(metrics);
|
return - textStyle()->spaceBefore(metrics);
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
return myArea.context().stringHeight();
|
return myArea.context().stringHeight();
|
||||||
case ZLTextElement::INDENT_ELEMENT:
|
case ZLTextElement::INDENT_ELEMENT:
|
||||||
case ZLTextElement::HSPACE_ELEMENT:
|
case ZLTextElement::HSPACE_ELEMENT:
|
||||||
|
|
|
@ -66,6 +66,15 @@ void ZLTextArea::prepareTextLine(Style &style, const ZLTextLineInfo &info, int y
|
||||||
const bool endOfParagraph = info.End.isEndOfParagraph();
|
const bool endOfParagraph = info.End.isEndOfParagraph();
|
||||||
bool wordOccured = false;
|
bool wordOccured = false;
|
||||||
|
|
||||||
|
bool endsWithLineBreak = false;
|
||||||
|
if (info.RealStart < info.End) {
|
||||||
|
ZLTextWordCursor last(info.End);
|
||||||
|
last.previousWord();
|
||||||
|
if (last.element().kind() == ZLTextElement::LINE_BREAK_ELEMENT) {
|
||||||
|
endsWithLineBreak = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int x = info.StartIndent;
|
int x = info.StartIndent;
|
||||||
|
|
||||||
const int fontSize = style.textStyle()->fontSize();
|
const int fontSize = style.textStyle()->fontSize();
|
||||||
|
@ -89,7 +98,7 @@ void ZLTextArea::prepareTextLine(Style &style, const ZLTextLineInfo &info, int y
|
||||||
x += (metrics.FullWidth - style.textStyle()->lineEndIndent(metrics, isRtl()) - info.Width) / 2;
|
x += (metrics.FullWidth - style.textStyle()->lineEndIndent(metrics, isRtl()) - info.Width) / 2;
|
||||||
break;
|
break;
|
||||||
case ALIGN_JUSTIFY:
|
case ALIGN_JUSTIFY:
|
||||||
if (!endOfParagraph && (info.End.element().kind() != ZLTextElement::AFTER_PARAGRAPH_ELEMENT)) {
|
if (!endsWithLineBreak && !endOfParagraph && info.End.element().kind() != ZLTextElement::AFTER_PARAGRAPH_ELEMENT) {
|
||||||
fullCorrection = metrics.FullWidth - style.textStyle()->lineEndIndent(metrics, isRtl()) - info.Width;
|
fullCorrection = metrics.FullWidth - style.textStyle()->lineEndIndent(metrics, isRtl()) - info.Width;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -140,6 +149,7 @@ void ZLTextArea::prepareTextLine(Style &style, const ZLTextLineInfo &info, int y
|
||||||
case ZLTextElement::BEFORE_PARAGRAPH_ELEMENT:
|
case ZLTextElement::BEFORE_PARAGRAPH_ELEMENT:
|
||||||
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
||||||
break;
|
break;
|
||||||
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
||||||
|
|
|
@ -177,7 +177,11 @@ ZLTextLineInfoPtr ZLTextArea::processTextLine(Style &style, const ZLTextWordCurs
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newInfo.Width > maxWidth && info.Start != info.End) {
|
if (elementKind == ZLTextElement::LINE_BREAK_ELEMENT) {
|
||||||
|
newInfo.End.nextWord();
|
||||||
|
newInfo.setTo(info);
|
||||||
|
break;
|
||||||
|
} else if (newInfo.Width > maxWidth && info.Start != info.End) {
|
||||||
if (!info.End.equalElementIndex(start)) {
|
if (!info.End.equalElementIndex(start)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -222,8 +226,7 @@ ZLTextLineInfoPtr ZLTextArea::processTextLine(Style &style, const ZLTextWordCurs
|
||||||
}
|
}
|
||||||
} while (!newInfo.End.equalElementIndex(end));
|
} while (!newInfo.End.equalElementIndex(end));
|
||||||
|
|
||||||
if (!newInfo.End.equalElementIndex(end) && useHyphenator &&
|
if (elementKind != ZLTextElement::LINE_BREAK_ELEMENT && !newInfo.End.equalElementIndex(end) && useHyphenator && style.textStyle()->allowHyphenations()) {
|
||||||
style.textStyle()->allowHyphenations()) {
|
|
||||||
const ZLTextElement &element = paragraphCursor[newInfo.End.elementIndex()];
|
const ZLTextElement &element = paragraphCursor[newInfo.End.elementIndex()];
|
||||||
if (element.kind() == ZLTextElement::WORD_ELEMENT) {
|
if (element.kind() == ZLTextElement::WORD_ELEMENT) {
|
||||||
const int startCharIndex = newInfo.End.charIndex();
|
const int startCharIndex = newInfo.End.charIndex();
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
BEFORE_PARAGRAPH_ELEMENT,
|
BEFORE_PARAGRAPH_ELEMENT,
|
||||||
AFTER_PARAGRAPH_ELEMENT,
|
AFTER_PARAGRAPH_ELEMENT,
|
||||||
EMPTY_LINE_ELEMENT,
|
EMPTY_LINE_ELEMENT,
|
||||||
|
LINE_BREAK_ELEMENT,
|
||||||
START_REVERSED_SEQUENCE_ELEMENT,
|
START_REVERSED_SEQUENCE_ELEMENT,
|
||||||
END_REVERSED_SEQUENCE_ELEMENT,
|
END_REVERSED_SEQUENCE_ELEMENT,
|
||||||
};
|
};
|
||||||
|
|
|
@ -108,6 +108,9 @@ void ZLTextParagraphCursor::Builder::fill() {
|
||||||
updateBidiLevel(myBaseBidiLevel);
|
updateBidiLevel(myBaseBidiLevel);
|
||||||
myLatestBidiLevel = myBaseBidiLevel;
|
myLatestBidiLevel = myBaseBidiLevel;
|
||||||
break;
|
break;
|
||||||
|
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
||||||
|
myElements.push_back(myTextElementPool.LineBreakElement);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,6 +46,7 @@ ZLTextElementVector::~ZLTextElementVector() {
|
||||||
case ZLTextElement::BEFORE_PARAGRAPH_ELEMENT:
|
case ZLTextElement::BEFORE_PARAGRAPH_ELEMENT:
|
||||||
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
case ZLTextElement::AFTER_PARAGRAPH_ELEMENT:
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
||||||
case ZLTextElement::END_REVERSED_SEQUENCE_ELEMENT:
|
case ZLTextElement::END_REVERSED_SEQUENCE_ELEMENT:
|
||||||
break;
|
break;
|
||||||
|
@ -59,6 +60,7 @@ ZLTextElementPool::ZLTextElementPool() {
|
||||||
BeforeParagraphElement = new ZLTextSpecialElement(ZLTextElement::BEFORE_PARAGRAPH_ELEMENT);
|
BeforeParagraphElement = new ZLTextSpecialElement(ZLTextElement::BEFORE_PARAGRAPH_ELEMENT);
|
||||||
AfterParagraphElement = new ZLTextSpecialElement(ZLTextElement::AFTER_PARAGRAPH_ELEMENT);
|
AfterParagraphElement = new ZLTextSpecialElement(ZLTextElement::AFTER_PARAGRAPH_ELEMENT);
|
||||||
EmptyLineElement = new ZLTextSpecialElement(ZLTextElement::EMPTY_LINE_ELEMENT);
|
EmptyLineElement = new ZLTextSpecialElement(ZLTextElement::EMPTY_LINE_ELEMENT);
|
||||||
|
LineBreakElement = new ZLTextSpecialElement(ZLTextElement::LINE_BREAK_ELEMENT);
|
||||||
StartReversedSequenceElement = new ZLTextSpecialElement(ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT);
|
StartReversedSequenceElement = new ZLTextSpecialElement(ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT);
|
||||||
EndReversedSequenceElement = new ZLTextSpecialElement(ZLTextElement::END_REVERSED_SEQUENCE_ELEMENT);
|
EndReversedSequenceElement = new ZLTextSpecialElement(ZLTextElement::END_REVERSED_SEQUENCE_ELEMENT);
|
||||||
}
|
}
|
||||||
|
@ -69,6 +71,7 @@ ZLTextElementPool::~ZLTextElementPool() {
|
||||||
delete BeforeParagraphElement;
|
delete BeforeParagraphElement;
|
||||||
delete AfterParagraphElement;
|
delete AfterParagraphElement;
|
||||||
delete EmptyLineElement;
|
delete EmptyLineElement;
|
||||||
|
delete LineBreakElement;
|
||||||
delete StartReversedSequenceElement;
|
delete StartReversedSequenceElement;
|
||||||
delete EndReversedSequenceElement;
|
delete EndReversedSequenceElement;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,7 @@ public:
|
||||||
ZLTextElement *BeforeParagraphElement;
|
ZLTextElement *BeforeParagraphElement;
|
||||||
ZLTextElement *AfterParagraphElement;
|
ZLTextElement *AfterParagraphElement;
|
||||||
ZLTextElement *EmptyLineElement;
|
ZLTextElement *EmptyLineElement;
|
||||||
|
ZLTextElement *LineBreakElement;
|
||||||
ZLTextElement *StartReversedSequenceElement;
|
ZLTextElement *StartReversedSequenceElement;
|
||||||
ZLTextElement *EndReversedSequenceElement;
|
ZLTextElement *EndReversedSequenceElement;
|
||||||
|
|
||||||
|
|
|
@ -214,24 +214,40 @@ void ZLTextModel::addControl(ZLTextKind textKind, bool isStart) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLTextModel::addControl(const ZLTextStyleEntry &entry) {
|
void ZLTextModel::addControl(const ZLTextStyleEntry &entry) {
|
||||||
int len = sizeof(int) + 5 + ZLTextStyleEntry::NUMBER_OF_LENGTHS * (sizeof(short) + 1);
|
int len = sizeof(int) + 2;
|
||||||
|
if (entry.myMask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
||||||
|
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
||||||
|
if (entry.myMask & (1 << i)) {
|
||||||
|
len += (sizeof(short) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (entry.opacitySupported()) ++len;
|
||||||
|
if (entry.alignmentTypeSupported()) ++len;
|
||||||
|
if (entry.supportedFontModifier()) ++len;
|
||||||
|
if (entry.fontSizeSupported()) ++len;
|
||||||
if (entry.fontFamilySupported()) {
|
if (entry.fontFamilySupported()) {
|
||||||
len += entry.fontFamily().length() + 1;
|
len += entry.fontFamily().length() + 1;
|
||||||
}
|
}
|
||||||
myLastEntryStart = myAllocator.allocate(len);
|
myLastEntryStart = myAllocator.allocate(len);
|
||||||
char *address = myLastEntryStart;
|
char *address = myLastEntryStart;
|
||||||
*address++ = ZLTextParagraphEntry::STYLE_ENTRY;
|
*address++ = ZLTextParagraphEntry::STYLE_ENTRY;
|
||||||
|
*address++ = entry.mySupportedFontModifier;
|
||||||
memcpy(address, &entry.myMask, sizeof(int));
|
memcpy(address, &entry.myMask, sizeof(int));
|
||||||
address += sizeof(int);
|
address += sizeof(int);
|
||||||
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
if (entry.myMask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
||||||
*address++ = entry.myLengths[i].Unit;
|
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
||||||
memcpy(address, &entry.myLengths[i].Size, sizeof(short));
|
if (entry.myMask & (1 << i)) {
|
||||||
address += sizeof(short);
|
*address++ = entry.myLengths[i].Unit;
|
||||||
|
memcpy(address, &entry.myLengths[i].Size, sizeof(short));
|
||||||
|
address += sizeof(short);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
*address++ = entry.mySupportedFontModifier;
|
if (entry.opacitySupported()) *address++ = entry.myOpacity;
|
||||||
*address++ = entry.myFontModifier;
|
if (entry.alignmentTypeSupported()) *address++ = entry.myAlignmentType;
|
||||||
*address++ = entry.myAlignmentType;
|
if (entry.supportedFontModifier()) *address++ = entry.myFontModifier;
|
||||||
*address++ = entry.myFontSizeMag;
|
if (entry.fontSizeSupported()) *address++ = entry.myFontSizeMag;
|
||||||
if (entry.fontFamilySupported()) {
|
if (entry.fontFamilySupported()) {
|
||||||
memcpy(address, entry.fontFamily().data(), entry.fontFamily().length());
|
memcpy(address, entry.fontFamily().data(), entry.fontFamily().length());
|
||||||
address += entry.fontFamily().length();
|
address += entry.fontFamily().length();
|
||||||
|
@ -267,3 +283,9 @@ void ZLTextModel::addBidiReset() {
|
||||||
*myLastEntryStart = ZLTextParagraphEntry::RESET_BIDI_ENTRY;
|
*myLastEntryStart = ZLTextParagraphEntry::RESET_BIDI_ENTRY;
|
||||||
myParagraphs.back()->addEntry(myLastEntryStart);
|
myParagraphs.back()->addEntry(myLastEntryStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZLTextModel::addLineBreak() {
|
||||||
|
myLastEntryStart = myAllocator.allocate(1);
|
||||||
|
*myLastEntryStart = ZLTextParagraphEntry::LINE_BREAK_ENTRY;
|
||||||
|
myParagraphs.back()->addEntry(myLastEntryStart);
|
||||||
|
}
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
void addImage(const std::string &id, const ZLImageMap &imageMap, short vOffset);
|
void addImage(const std::string &id, const ZLImageMap &imageMap, short vOffset);
|
||||||
void addFixedHSpace(unsigned char length);
|
void addFixedHSpace(unsigned char length);
|
||||||
void addBidiReset();
|
void addBidiReset();
|
||||||
|
void addLineBreak();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addParagraphInternal(ZLTextParagraph *paragraph);
|
void addParagraphInternal(ZLTextParagraph *paragraph);
|
||||||
|
|
|
@ -58,22 +58,39 @@ short ZLTextStyleEntry::length(Length name, const Metrics &metrics) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextStyleEntry::ZLTextStyleEntry(char *address) {
|
ZLTextStyleEntry::ZLTextStyleEntry(char *address) {
|
||||||
|
mySupportedFontModifier = *address++;
|
||||||
memcpy(&myMask, address, sizeof(int));
|
memcpy(&myMask, address, sizeof(int));
|
||||||
address += sizeof(int);
|
address += sizeof(int);
|
||||||
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
||||||
myLengths[i].Unit = (SizeUnit)*address++;
|
if (myMask & (1 << i)) {
|
||||||
memcpy(&myLengths[i].Size, address, sizeof(short));
|
myLengths[i].Unit = (SizeUnit)*address++;
|
||||||
address += sizeof(short);
|
memcpy(&myLengths[i].Size, address, sizeof(short));
|
||||||
|
address += sizeof(short);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (opacitySupported()) {
|
||||||
|
myOpacity = *address++;
|
||||||
|
}
|
||||||
|
if (alignmentTypeSupported()) {
|
||||||
|
myAlignmentType = (ZLTextAlignmentType)*address++;
|
||||||
|
}
|
||||||
|
if (supportedFontModifier()) {
|
||||||
|
myFontModifier = *address++;
|
||||||
|
}
|
||||||
|
if (fontSizeSupported()) {
|
||||||
|
myFontSizeMag = (signed char)*address++;
|
||||||
}
|
}
|
||||||
mySupportedFontModifier = *address++;
|
|
||||||
myFontModifier = *address++;
|
|
||||||
myAlignmentType = (ZLTextAlignmentType)*address++;
|
|
||||||
myFontSizeMag = (signed char)*address++;
|
|
||||||
if (fontFamilySupported()) {
|
if (fontFamilySupported()) {
|
||||||
myFontFamily = address;
|
myFontFamily = address;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZLTextStyleEntry::reset() {
|
||||||
|
mySupportedFontModifier = 0;
|
||||||
|
myMask = 0;
|
||||||
|
myFontFamily.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void ZLTextStyleEntry::apply(const ZLTextStyleEntry &entry) {
|
void ZLTextStyleEntry::apply(const ZLTextStyleEntry &entry) {
|
||||||
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
||||||
if (entry.lengthSupported((Length)i)) {
|
if (entry.lengthSupported((Length)i)) {
|
||||||
|
@ -81,6 +98,9 @@ void ZLTextStyleEntry::apply(const ZLTextStyleEntry &entry) {
|
||||||
myMask |= 1 << i;
|
myMask |= 1 << i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (entry.opacitySupported()) {
|
||||||
|
setOpacity(entry.opacity());
|
||||||
|
}
|
||||||
if (entry.alignmentTypeSupported()) {
|
if (entry.alignmentTypeSupported()) {
|
||||||
setAlignmentType(entry.alignmentType());
|
setAlignmentType(entry.alignmentType());
|
||||||
}
|
}
|
||||||
|
@ -171,10 +191,21 @@ void ZLTextParagraph::Iterator::next() {
|
||||||
case ZLTextParagraphEntry::STYLE_ENTRY:
|
case ZLTextParagraphEntry::STYLE_ENTRY:
|
||||||
{
|
{
|
||||||
int mask;
|
int mask;
|
||||||
memcpy(&mask, myPointer + 1, sizeof(int));
|
const unsigned char supportedFontModifier = myPointer[1];
|
||||||
bool withFontFamily = (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILY) == ZLTextStyleEntry::SUPPORT_FONT_FAMILY;
|
memcpy(&mask, myPointer + 2, sizeof(int));
|
||||||
myPointer += sizeof(int) + ZLTextStyleEntry::NUMBER_OF_LENGTHS * (sizeof(short) + 1) + 5;
|
myPointer += sizeof(int) + 2;
|
||||||
if (withFontFamily) {
|
if (mask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
||||||
|
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
||||||
|
if (mask & (1 << i)) {
|
||||||
|
myPointer += (sizeof(short) + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mask & ZLTextStyleEntry::SUPPORT_OPACITY) ++myPointer;
|
||||||
|
if (mask & ZLTextStyleEntry::SUPPORT_ALIGNMENT_TYPE) ++myPointer;
|
||||||
|
if (supportedFontModifier) ++myPointer;
|
||||||
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_SIZE) ++myPointer;
|
||||||
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILY) {
|
||||||
while (*myPointer != '\0') {
|
while (*myPointer != '\0') {
|
||||||
++myPointer;
|
++myPointer;
|
||||||
}
|
}
|
||||||
|
@ -186,6 +217,7 @@ void ZLTextParagraph::Iterator::next() {
|
||||||
myPointer += 2;
|
myPointer += 2;
|
||||||
break;
|
break;
|
||||||
case ZLTextParagraphEntry::RESET_BIDI_ENTRY:
|
case ZLTextParagraphEntry::RESET_BIDI_ENTRY:
|
||||||
|
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
||||||
++myPointer;
|
++myPointer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
STYLE_ENTRY = 5,
|
STYLE_ENTRY = 5,
|
||||||
FIXED_HSPACE_ENTRY = 6,
|
FIXED_HSPACE_ENTRY = 6,
|
||||||
RESET_BIDI_ENTRY = 7,
|
RESET_BIDI_ENTRY = 7,
|
||||||
|
LINE_BREAK_ENTRY = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -93,10 +94,13 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZLTextStyleEntry();
|
ZLTextStyleEntry();
|
||||||
|
ZLTextStyleEntry(const ZLTextStyleEntry &other);
|
||||||
ZLTextStyleEntry(char *address);
|
ZLTextStyleEntry(char *address);
|
||||||
~ZLTextStyleEntry();
|
~ZLTextStyleEntry();
|
||||||
|
|
||||||
|
void reset();
|
||||||
void apply(const ZLTextStyleEntry &entry);
|
void apply(const ZLTextStyleEntry &entry);
|
||||||
|
ZLTextStyleEntry &operator = (const ZLTextStyleEntry &other);
|
||||||
|
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
|
|
||||||
|
@ -104,6 +108,10 @@ public:
|
||||||
short length(Length name, const Metrics &metrics) const;
|
short length(Length name, const Metrics &metrics) const;
|
||||||
void setLength(Length name, short length, SizeUnit unit);
|
void setLength(Length name, short length, SizeUnit unit);
|
||||||
|
|
||||||
|
bool opacitySupported() const;
|
||||||
|
unsigned char opacity() const;
|
||||||
|
void setOpacity(unsigned char opacity);
|
||||||
|
|
||||||
bool alignmentTypeSupported() const;
|
bool alignmentTypeSupported() const;
|
||||||
ZLTextAlignmentType alignmentType() const;
|
ZLTextAlignmentType alignmentType() const;
|
||||||
void setAlignmentType(ZLTextAlignmentType alignmentType);
|
void setAlignmentType(ZLTextAlignmentType alignmentType);
|
||||||
|
@ -120,9 +128,12 @@ public:
|
||||||
const std::string &fontFamily() const;
|
const std::string &fontFamily() const;
|
||||||
void setFontFamily(const std::string &fontFamily);
|
void setFontFamily(const std::string &fontFamily);
|
||||||
|
|
||||||
static const int SUPPORT_ALIGNMENT_TYPE = 1 << NUMBER_OF_LENGTHS;
|
enum {
|
||||||
static const int SUPPORT_FONT_SIZE = 1 << (NUMBER_OF_LENGTHS + 1);
|
SUPPORT_ALIGNMENT_TYPE = 1 << NUMBER_OF_LENGTHS,
|
||||||
static const int SUPPORT_FONT_FAMILY = 1 << (NUMBER_OF_LENGTHS + 2);
|
SUPPORT_FONT_SIZE = 1 << (NUMBER_OF_LENGTHS + 1),
|
||||||
|
SUPPORT_FONT_FAMILY = 1 << (NUMBER_OF_LENGTHS + 2),
|
||||||
|
SUPPORT_OPACITY = 1 << (NUMBER_OF_LENGTHS + 3)
|
||||||
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int myMask;
|
int myMask;
|
||||||
|
@ -130,6 +141,7 @@ private:
|
||||||
LengthType myLengths[NUMBER_OF_LENGTHS];
|
LengthType myLengths[NUMBER_OF_LENGTHS];
|
||||||
|
|
||||||
ZLTextAlignmentType myAlignmentType;
|
ZLTextAlignmentType myAlignmentType;
|
||||||
|
unsigned char myOpacity;
|
||||||
unsigned char mySupportedFontModifier;
|
unsigned char mySupportedFontModifier;
|
||||||
unsigned char myFontModifier;
|
unsigned char myFontModifier;
|
||||||
signed char myFontSizeMag;
|
signed char myFontSizeMag;
|
||||||
|
@ -333,12 +345,15 @@ private:
|
||||||
inline ZLTextParagraphEntry::ZLTextParagraphEntry() {}
|
inline ZLTextParagraphEntry::ZLTextParagraphEntry() {}
|
||||||
inline ZLTextParagraphEntry::~ZLTextParagraphEntry() {}
|
inline ZLTextParagraphEntry::~ZLTextParagraphEntry() {}
|
||||||
|
|
||||||
inline ZLTextStyleEntry::ZLTextStyleEntry() : myMask(0), mySupportedFontModifier(0), myFontModifier(0) {}
|
inline ZLTextStyleEntry::ZLTextStyleEntry() : myMask(0), mySupportedFontModifier(0) {}
|
||||||
|
inline ZLTextStyleEntry::ZLTextStyleEntry(const ZLTextStyleEntry &other) : ZLTextParagraphEntry(), myMask(0), mySupportedFontModifier(0) { apply(other); }
|
||||||
|
|
||||||
inline ZLTextStyleEntry::~ZLTextStyleEntry() {}
|
inline ZLTextStyleEntry::~ZLTextStyleEntry() {}
|
||||||
|
|
||||||
inline ZLTextStyleEntry::Metrics::Metrics(int fontSize, int fontXHeight, int fullWidth, int fullHeight) : FontSize(fontSize), FontXHeight(fontXHeight), FullWidth(fullWidth), FullHeight(fullHeight) {}
|
inline ZLTextStyleEntry::Metrics::Metrics(int fontSize, int fontXHeight, int fullWidth, int fullHeight) : FontSize(fontSize), FontXHeight(fontXHeight), FullWidth(fullWidth), FullHeight(fullHeight) {}
|
||||||
|
|
||||||
inline bool ZLTextStyleEntry::isEmpty() const { return myMask == 0 && mySupportedFontModifier == 0; }
|
inline bool ZLTextStyleEntry::isEmpty() const { return myMask == 0 && mySupportedFontModifier == 0; }
|
||||||
|
inline ZLTextStyleEntry &ZLTextStyleEntry::operator = (const ZLTextStyleEntry &other) { reset(); apply(other); return *this; }
|
||||||
|
|
||||||
inline bool ZLTextStyleEntry::lengthSupported(Length name) const { return (myMask & (1 << name)) != 0; }
|
inline bool ZLTextStyleEntry::lengthSupported(Length name) const { return (myMask & (1 << name)) != 0; }
|
||||||
inline void ZLTextStyleEntry::setLength(Length name, short length, SizeUnit unit) {
|
inline void ZLTextStyleEntry::setLength(Length name, short length, SizeUnit unit) {
|
||||||
|
@ -347,7 +362,11 @@ inline void ZLTextStyleEntry::setLength(Length name, short length, SizeUnit unit
|
||||||
myMask |= 1 << name;
|
myMask |= 1 << name;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool ZLTextStyleEntry::alignmentTypeSupported() const { return (myMask & SUPPORT_ALIGNMENT_TYPE) == SUPPORT_ALIGNMENT_TYPE; }
|
inline bool ZLTextStyleEntry::opacitySupported() const { return (myMask & SUPPORT_OPACITY) != 0; }
|
||||||
|
inline unsigned char ZLTextStyleEntry::opacity() const { return myOpacity; }
|
||||||
|
inline void ZLTextStyleEntry::setOpacity(unsigned char opacity) { myOpacity = opacity; myMask |= SUPPORT_OPACITY; }
|
||||||
|
|
||||||
|
inline bool ZLTextStyleEntry::alignmentTypeSupported() const { return (myMask & SUPPORT_ALIGNMENT_TYPE) != 0; }
|
||||||
inline ZLTextAlignmentType ZLTextStyleEntry::alignmentType() const { return myAlignmentType; }
|
inline ZLTextAlignmentType ZLTextStyleEntry::alignmentType() const { return myAlignmentType; }
|
||||||
inline void ZLTextStyleEntry::setAlignmentType(ZLTextAlignmentType alignmentType) { myAlignmentType = alignmentType; myMask |= SUPPORT_ALIGNMENT_TYPE; }
|
inline void ZLTextStyleEntry::setAlignmentType(ZLTextAlignmentType alignmentType) { myAlignmentType = alignmentType; myMask |= SUPPORT_ALIGNMENT_TYPE; }
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue