[fbreader] Refactored CSS and XHTML support
This significantly improves EPUB rendering.
This commit is contained in:
parent
ab68bef4e6
commit
c6e46b94a2
34 changed files with 1349 additions and 590 deletions
|
@ -1,24 +1,27 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<DefaultStyles>
|
<DefaultStyles>
|
||||||
<style id="0" name="Regular Paragraph" firstLineIndentDelta="40" allowHyphenations="true"/>
|
<style id="0" name="Regular Paragraph" firstLineIndentDelta="1em" allowHyphenations="true"/>
|
||||||
<style id="1" name="Title" fontSizeDelta="10" bold="true" spaceBefore="2" spaceAfter="7" alignment="center" allowHyphenations="false"/>
|
<style id="1" name="Title" fontSizeDelta="10" bold="true" spaceBefore="2" spaceAfter="7" alignment="center" allowHyphenations="false"/>
|
||||||
<style id="3" name="Poem Title" fontSizeDelta="2" bold="true" spaceBefore="6" spaceAfter="6" leftIndent="40" allowHyphenations="false"/>
|
<style id="3" name="Poem Title" fontSizeDelta="2" bold="true" spaceBefore="6" spaceAfter="6" leftIndent="40" allowHyphenations="false"/>
|
||||||
<style id="2" name="Section Title" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/>
|
<style id="2" name="Section Title" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/>
|
||||||
<style id="31" name="Header 1" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/>
|
|
||||||
<style id="32" name="Header 2" fontSizeDelta="6" bold="true" spaceAfter="5" alignment="center" allowHyphenations="false"/>
|
|
||||||
<style id="5" name="Annotation" fontSizeDelta="-2" firstLineIndentDelta="20" allowHyphenations="true"/>
|
<style id="5" name="Annotation" fontSizeDelta="-2" firstLineIndentDelta="20" allowHyphenations="true"/>
|
||||||
<style id="6" name="Epigraph" fontSizeDelta="-2" italic="true" leftIndent="80" allowHyphenations="true"/>
|
<style id="6" name="Epigraph" fontSizeDelta="-2" italic="true" leftIndent="80" allowHyphenations="true"/>
|
||||||
<style id="4" name="Subtitle" bold="true" allowHyphenations="true"/>
|
<style id="4" name="Subtitle" bold="true" allowHyphenations="true"/>
|
||||||
<style id="33" name="Header 3" bold="true" allowHyphenations="true"/>
|
|
||||||
<style id="34" name="Header 4" bold="true" allowHyphenations="true"/>
|
|
||||||
<style id="13" name="Author" leftIndent="20" allowHyphenations="false"/>
|
<style id="13" name="Author" leftIndent="20" allowHyphenations="false"/>
|
||||||
<style id="14" name="Date" leftIndent="40" allowHyphenations="false"/>
|
<style id="14" name="Date" leftIndent="40" allowHyphenations="false"/>
|
||||||
<style id="7" name="Stanza" spaceBefore="6" spaceAfter="6" alignment="linestart" allowHyphenations="false"/>
|
<style id="7" name="Stanza" spaceBefore="6" spaceAfter="6" alignment="linestart" allowHyphenations="false"/>
|
||||||
<style id="8" name="Verse" leftIndent="20" alignment="linestart" allowHyphenations="false"/>
|
<style id="8" name="Verse" leftIndent="20" alignment="linestart" allowHyphenations="false"/>
|
||||||
<style id="10" name="Image" spaceBefore="8" alignment="center"/>
|
<style id="10" name="Image" spaceBefore="8" spaceAfter="8" alignment="center"/>
|
||||||
<style id="23" name="Contents Table" spaceAfter="7" leftIndent="20" firstLineIndentDelta="-20" alignment="linestart"/>
|
<style id="23" name="Contents Table" spaceAfter="7" leftIndent="20" firstLineIndentDelta="-20" alignment="linestart"/>
|
||||||
<style id="25" name="Library Entry" alignment="linestart" allowHyphenations="false"/>
|
<style id="25" name="Library Entry" alignment="linestart" allowHyphenations="false"/>
|
||||||
<style id="9" name="Preformatted text" italic="true" alignment="linestart" allowHyphenations="false"/>
|
<style id="9" name="Preformatted text" firstLineIndentDelta="0" alignment="linestart" allowHyphenations="false" family="monospace"/>
|
||||||
|
<style id="31" name="Header 1" firstLineIndentDelta="0" fontSizeDelta="6" spaceAfter="1em" bold="true" allowHyphenations="false"/>
|
||||||
|
<style id="32" name="Header 2" firstLineIndentDelta="0" fontSizeDelta="4" spaceAfter="1em" bold="true" allowHyphenations="false"/>
|
||||||
|
<style id="33" name="Header 3" firstLineIndentDelta="0" spaceBefore="1em" spaceAfter="1em" bold="true" allowHyphenations="true"/>
|
||||||
|
<style id="34" name="Header 4" firstLineIndentDelta="0" spaceBefore="1em" spaceAfter="1em" bold="true" allowHyphenations="true"/>
|
||||||
|
<style id="35" name="Header 5" firstLineIndentDelta="0" spaceBefore="1em" spaceAfter="1em" bold="true"/>
|
||||||
|
<style id="36" name="Header 6" firstLineIndentDelta="0" spaceBefore="1em" spaceAfter="1em" bold="true"/>
|
||||||
|
<style id="39" name="Quote" spaceBefore="1em" spaceAfter="1em" leftIndent="2em" rightIndent="1em"/>
|
||||||
|
|
||||||
<style id="12" partial="true" name="Cite" italic="true"/>
|
<style id="12" partial="true" name="Cite" italic="true"/>
|
||||||
<style id="15" partial="true" name="Internal Hyperlink" allowHyphenations="false" hyperlink="internal"/>
|
<style id="15" partial="true" name="Internal Hyperlink" allowHyphenations="false" hyperlink="internal"/>
|
||||||
|
@ -27,14 +30,12 @@
|
||||||
<style id="16" partial="true" name="Footnote" fontSizeDelta="-6" vShift="10" allowHyphenations="false" hyperlink="internal"/>
|
<style id="16" partial="true" name="Footnote" fontSizeDelta="-6" vShift="10" allowHyphenations="false" hyperlink="internal"/>
|
||||||
<style id="17" partial="true" name="Emphasis" italic="true"/>
|
<style id="17" partial="true" name="Emphasis" italic="true"/>
|
||||||
<style id="18" partial="true" name="Strong" bold="true"/>
|
<style id="18" partial="true" name="Strong" bold="true"/>
|
||||||
<style id="35" name="Header 5" bold="true"/>
|
|
||||||
<style id="36" name="Header 6" bold="true"/>
|
|
||||||
<style id="19" partial="true" name="Subscript" fontSizeDelta="-4" vShift="-4" allowHyphenations="false"/>
|
<style id="19" partial="true" name="Subscript" fontSizeDelta="-4" vShift="-4" allowHyphenations="false"/>
|
||||||
<style id="20" partial="true" name="Superscript" fontSizeDelta="-4" vShift="10" allowHyphenations="false"/>
|
<style id="20" partial="true" name="Superscript" fontSizeDelta="-4" vShift="10" allowHyphenations="false"/>
|
||||||
<style id="21" partial="true" name="Code" italic="false" allowHyphenations="false"/>
|
<style id="21" partial="true" name="Code" firstLineIndentDelta="0" allowHyphenations="false" family="monospace"/>
|
||||||
<style id="22" partial="true" name="StrikeThrough"/>
|
<style id="22" partial="true" name="StrikeThrough"/>
|
||||||
<style id="27" partial="true" name="Italic" italic="true"/>
|
<style id="27" partial="true" name="Italic" italic="true"/>
|
||||||
<style id="28" partial="true" name="Bold" bold="true"/>
|
<style id="28" partial="true" name="Bold" bold="true"/>
|
||||||
<style id="29" partial="true" name="Definition" italic="true"/>
|
<style id="29" partial="true" name="Definition" italic="true"/>
|
||||||
<style id="30" partial="true" name="Definition Description" bold="true" italic="true"/>
|
<style id="30" partial="true" name="Definition Description" bold="true" italic="true"/>
|
||||||
</DefaultStyles>
|
</DefaultStyles>
|
||||||
|
|
|
@ -65,7 +65,7 @@ public:
|
||||||
|
|
||||||
bool isDecorated() const;
|
bool isDecorated() const;
|
||||||
|
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
|
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
bool bold() const;
|
bool bold() const;
|
||||||
|
@ -102,10 +102,10 @@ BooksSettings::TextStyle::isDecorated() const
|
||||||
return iDefaultStyle->isDecorated();
|
return iDefaultStyle->isDecorated();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string&
|
const std::vector<std::string>&
|
||||||
BooksSettings::TextStyle::fontFamily() const
|
BooksSettings::TextStyle::fontFamilies() const
|
||||||
{
|
{
|
||||||
return iDefaultStyle->fontFamily();
|
return iDefaultStyle->fontFamilies();
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
|
|
@ -54,6 +54,11 @@ shared_ptr<ZLTextStyle> BooksTextStyle::defaults()
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BooksTextStyle::BooksTextStyle()
|
||||||
|
{
|
||||||
|
iFontFamilies.push_back(Default::FONT_FAMILY);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
BooksTextStyle::equalLayout(
|
BooksTextStyle::equalLayout(
|
||||||
shared_ptr<ZLTextStyle> aStyle1,
|
shared_ptr<ZLTextStyle> aStyle1,
|
||||||
|
@ -74,9 +79,9 @@ bool BooksTextStyle::isDecorated() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string& BooksTextStyle::fontFamily() const
|
const std::vector<std::string>& BooksTextStyle::fontFamilies() const
|
||||||
{
|
{
|
||||||
return Default::FONT_FAMILY;
|
return iFontFamilies;
|
||||||
}
|
}
|
||||||
|
|
||||||
int BooksTextStyle::fontSize() const
|
int BooksTextStyle::fontSize() const
|
||||||
|
|
|
@ -49,18 +49,18 @@ private:
|
||||||
static weak_ptr<ZLTextStyle> gInstance;
|
static weak_ptr<ZLTextStyle> gInstance;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BooksTextStyle() {}
|
BooksTextStyle();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool isDecorated() const;
|
bool isDecorated() const;
|
||||||
|
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string>& fontFamilies() const;
|
||||||
|
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
bool bold() const;
|
bool bold() const;
|
||||||
bool italic() const;
|
bool italic() const;
|
||||||
|
|
||||||
const std::string &colorStyle() const;
|
const std::string& colorStyle() const;
|
||||||
|
|
||||||
short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
short spaceBefore(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||||
short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
short spaceAfter(const ZLTextStyleEntry::Metrics& aMetrics) const;
|
||||||
|
@ -73,6 +73,9 @@ public:
|
||||||
|
|
||||||
double lineSpace() const;
|
double lineSpace() const;
|
||||||
bool allowHyphenations() const;
|
bool allowHyphenations() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<std::string> iFontFamilies;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // BOOKS_TEXT_STYLE_H
|
#endif // BOOKS_TEXT_STYLE_H
|
||||||
|
|
|
@ -117,6 +117,13 @@ void BookReader::addLineBreak() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BookReader::addEmpty() {
|
||||||
|
if (myTextParagraphExists) {
|
||||||
|
flushTextBufferToParagraph();
|
||||||
|
myCurrentTextModel->addEmpty();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void BookReader::addControl(const ZLTextStyleEntry &entry) {
|
void BookReader::addControl(const ZLTextStyleEntry &entry) {
|
||||||
if (myTextParagraphExists) {
|
if (myTextParagraphExists) {
|
||||||
flushTextBufferToParagraph();
|
flushTextBufferToParagraph();
|
||||||
|
@ -189,7 +196,7 @@ void BookReader::addContentsData(const std::string &data) {
|
||||||
|
|
||||||
void BookReader::flushTextBufferToParagraph() {
|
void BookReader::flushTextBufferToParagraph() {
|
||||||
myCurrentTextModel->addText(myBuffer);
|
myCurrentTextModel->addText(myBuffer);
|
||||||
myBuffer.clear();
|
myBuffer.resize(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BookReader::addImage(const std::string &id, shared_ptr<const ZLImage> image) {
|
void BookReader::addImage(const std::string &id, shared_ptr<const ZLImage> image) {
|
||||||
|
@ -239,7 +246,7 @@ void BookReader::beginContentsParagraph(int referenceNumber) {
|
||||||
ZLTextTreeParagraph *peek = myTOCStack.empty() ? 0 : myTOCStack.top();
|
ZLTextTreeParagraph *peek = myTOCStack.empty() ? 0 : myTOCStack.top();
|
||||||
if (!myContentsBuffer.empty()) {
|
if (!myContentsBuffer.empty()) {
|
||||||
contentsModel.addText(myContentsBuffer);
|
contentsModel.addText(myContentsBuffer);
|
||||||
myContentsBuffer.clear();
|
myContentsBuffer.resize(0);
|
||||||
myLastTOCParagraphIsEmpty = false;
|
myLastTOCParagraphIsEmpty = false;
|
||||||
}
|
}
|
||||||
if (myLastTOCParagraphIsEmpty) {
|
if (myLastTOCParagraphIsEmpty) {
|
||||||
|
@ -259,7 +266,7 @@ void BookReader::endContentsParagraph() {
|
||||||
ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel;
|
ContentsModel &contentsModel = (ContentsModel&)*myModel.myContentsModel;
|
||||||
if (!myContentsBuffer.empty()) {
|
if (!myContentsBuffer.empty()) {
|
||||||
contentsModel.addText(myContentsBuffer);
|
contentsModel.addText(myContentsBuffer);
|
||||||
myContentsBuffer.clear();
|
myContentsBuffer.resize(0);
|
||||||
myLastTOCParagraphIsEmpty = false;
|
myLastTOCParagraphIsEmpty = false;
|
||||||
}
|
}
|
||||||
if (myLastTOCParagraphIsEmpty) {
|
if (myLastTOCParagraphIsEmpty) {
|
||||||
|
|
|
@ -59,6 +59,7 @@ public:
|
||||||
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 addLineBreak();
|
||||||
|
void addEmpty();
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -65,6 +65,7 @@ enum FBTextKind {
|
||||||
H6 = 36,
|
H6 = 36,
|
||||||
EXTERNAL_HYPERLINK = 37,
|
EXTERNAL_HYPERLINK = 37,
|
||||||
BOOK_HYPERLINK = 38,
|
BOOK_HYPERLINK = 38,
|
||||||
|
BLOCKQUOTE = 39
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* __FBTEXTKIND_H__ */
|
#endif /* __FBTEXTKIND_H__ */
|
||||||
|
|
|
@ -35,28 +35,39 @@ void StyleSheetTableParser::storeData(const std::string &selector, const StyleSh
|
||||||
StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text) {
|
StyleSheetTable::Style StyleSheetSingleStyleParser::parseString(const char *text) {
|
||||||
StyleSheetTable::Style style;
|
StyleSheetTable::Style style;
|
||||||
if (text) {
|
if (text) {
|
||||||
myReadState = ATTRIBUTE_NAME;
|
reset(ATTRIBUTE_NAME);
|
||||||
parse(text, strlen(text), true);
|
parse(text, strlen(text), true);
|
||||||
|
if (!myStateStack.empty()) {
|
||||||
|
switch (myStateStack.top()) {
|
||||||
|
case ATTRIBUTE_VALUE_SPACE:
|
||||||
|
case ATTRIBUTE_VALUE_COMMA:
|
||||||
|
finishAttributeValue();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
StyleSheetTable::updateStyle(style, myMap);
|
StyleSheetTable::updateStyle(style, myMap);
|
||||||
reset();
|
|
||||||
}
|
}
|
||||||
return style;
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
StyleSheetParser::StyleSheetParser() : myReadState(TAG_NAME), myInsideComment(false), myAtBlockDepth(0) {
|
StyleSheetParser::StyleSheetParser() :
|
||||||
|
myBuffer1(0), myBuffer2(0), myBuffer3(0) {
|
||||||
|
myStateStack.push(SELECTOR);
|
||||||
}
|
}
|
||||||
|
|
||||||
StyleSheetParser::~StyleSheetParser() {
|
StyleSheetParser::~StyleSheetParser() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetParser::reset() {
|
void StyleSheetParser::reset(ReadState state) {
|
||||||
myWord.erase();
|
myWord.resize(0);
|
||||||
myAttributeName.erase();
|
myAttributeName.resize(0);
|
||||||
myReadState = TAG_NAME;
|
myStateStack = std::stack<ReadState>();
|
||||||
myInsideComment = false;
|
myStateStack.push(state);
|
||||||
myAtBlockDepth = 0;
|
mySelectors.resize(0);
|
||||||
mySelectors.clear();
|
|
||||||
myMap.clear();
|
myMap.clear();
|
||||||
|
myBuffer1 = myBuffer2 = myBuffer3 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetParser::parse(ZLInputStream &stream) {
|
void StyleSheetParser::parse(ZLInputStream &stream) {
|
||||||
|
@ -78,165 +89,279 @@ void StyleSheetParser::parse(const char *text, int len, bool final) {
|
||||||
const char *start = text;
|
const char *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 ((myReadState != TAG_NAME && isspace(*ptr)) ||
|
processChar1(*ptr);
|
||||||
(myReadState == TAG_NAME && *ptr == ',')) {
|
|
||||||
if (start != ptr) {
|
|
||||||
myWord.append(start, ptr - start);
|
|
||||||
}
|
|
||||||
processWord(myWord);
|
|
||||||
myWord.erase();
|
|
||||||
start = ptr + 1;
|
|
||||||
} else if (isControlSymbol(*ptr)) {
|
|
||||||
if (start != ptr) {
|
|
||||||
myWord.append(start, ptr - start);
|
|
||||||
}
|
|
||||||
processWord(myWord);
|
|
||||||
myWord.erase();
|
|
||||||
if (!myInsideComment) {
|
|
||||||
processControl(*ptr);
|
|
||||||
}
|
|
||||||
start = ptr + 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (start < end) {
|
|
||||||
myWord.append(start, end - start);
|
|
||||||
if (final) {
|
|
||||||
processWord(myWord);
|
|
||||||
myWord.erase();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StyleSheetParser::isControlSymbol(const char symbol) {
|
|
||||||
switch (symbol) {
|
|
||||||
case '{':
|
|
||||||
case '}':
|
|
||||||
case ';':
|
|
||||||
case ':':
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) {
|
void StyleSheetParser::storeData(const std::string&, const StyleSheetTable::AttributeMap&) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetParser::processControl(const char control) {
|
/* Converts \r\n into \n */
|
||||||
switch (control) {
|
void StyleSheetParser::processChar1(char c) {
|
||||||
case '{':
|
if (myBuffer1 == '\r') {
|
||||||
switch (myReadState) {
|
myBuffer1 = 0;
|
||||||
case AT_RULE:
|
if (c == '\n') {
|
||||||
myReadState = AT_BLOCK;
|
processChar2('\n');
|
||||||
myAtBlockDepth = 1;
|
} else {
|
||||||
break;
|
processChar2('\r');
|
||||||
case AT_BLOCK:
|
}
|
||||||
myAtBlockDepth++;
|
} else if (c == '\r') {
|
||||||
break;
|
myBuffer1 = '\r';
|
||||||
case TAG_NAME:
|
} else {
|
||||||
myReadState = ATTRIBUTE_NAME;
|
processChar2(c);
|
||||||
myMap.clear();
|
}
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
myReadState = BROKEN;
|
/* Glues continued lines together */
|
||||||
break;
|
void StyleSheetParser::processChar2(char c) {
|
||||||
|
if (myBuffer2 == '\\') {
|
||||||
|
myBuffer2 = 0;
|
||||||
|
if (c != '\n') {
|
||||||
|
processChar3('\\');
|
||||||
|
processChar3(c);
|
||||||
|
}
|
||||||
|
} else if (c == '\\') {
|
||||||
|
myBuffer2 = '\\';
|
||||||
|
} else {
|
||||||
|
processChar3(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handles comments */
|
||||||
|
void StyleSheetParser::processChar3(char c) {
|
||||||
|
switch (myStateStack.top()) {
|
||||||
|
case COMMENT:
|
||||||
|
if (myBuffer3 == '*' && c == '/') {
|
||||||
|
myBuffer3 = 0;
|
||||||
|
myStateStack.pop();
|
||||||
|
} else {
|
||||||
|
myBuffer3 = (c == '*') ? '*' : 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case STRING_LITERAL_SINGLE:
|
||||||
|
case STRING_LITERAL_DOUBLE:
|
||||||
|
processChar4(c);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (myBuffer3 == '/' && c == '*') {
|
||||||
|
myStateStack.push(COMMENT);
|
||||||
|
} else {
|
||||||
|
if (myBuffer3) processChar4(myBuffer3);
|
||||||
|
if (c == '/') {
|
||||||
|
myBuffer3 = c;
|
||||||
|
} else {
|
||||||
|
myBuffer3 = 0;
|
||||||
|
processChar4(c);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Handles clean input */
|
||||||
|
void StyleSheetParser::processChar4(char c) {
|
||||||
|
switch (myStateStack.top()) {
|
||||||
|
case SELECTOR:
|
||||||
|
switch (c) {
|
||||||
|
case ',':
|
||||||
|
if (ZLStringUtil::stripWhiteSpaces(myWord)) {
|
||||||
|
mySelectors.push_back(myWord);
|
||||||
|
myWord.resize(0);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '{':
|
||||||
|
if (ZLStringUtil::stripWhiteSpaces(myWord)) mySelectors.push_back(myWord);
|
||||||
|
if (!mySelectors.empty()) {
|
||||||
|
if (mySelectors[0][0] == '@') {
|
||||||
|
// Ignore AT-rules
|
||||||
|
mySelectors.resize(0);
|
||||||
|
myStateStack.push(SKIP_BLOCK_CURLY);
|
||||||
|
} else {
|
||||||
|
myMap.clear();
|
||||||
|
myStateStack.push(ATTRIBUTE_NAME);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
myStateStack.push(SKIP_BLOCK_CURLY);
|
||||||
|
}
|
||||||
|
myWord.resize(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (!isspace(c) || !myWord.empty()) {
|
||||||
|
myWord.append(1, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATTRIBUTE_NAME:
|
||||||
|
switch (c) {
|
||||||
|
case ':':
|
||||||
|
if (ZLStringUtil::stripWhiteSpaces(myWord)) {
|
||||||
|
myAttributeName = myWord;
|
||||||
|
myMap[myAttributeName].resize(0);
|
||||||
|
myWord.resize(0);
|
||||||
|
static const std::string FONT_FAMILY("font-family");
|
||||||
|
if (myAttributeName == FONT_FAMILY) {
|
||||||
|
myStateStack.top() = ATTRIBUTE_VALUE_COMMA;
|
||||||
|
} else {
|
||||||
|
myStateStack.top() = ATTRIBUTE_VALUE_SPACE;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
finishAttribute();
|
||||||
|
myStateStack.top() = ATTRIBUTE_IGNORE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
case ';':
|
||||||
|
finishAttribute();
|
||||||
break;
|
break;
|
||||||
case '}':
|
case '}':
|
||||||
switch (myReadState) {
|
finishRule();
|
||||||
case AT_BLOCK:
|
myStateStack.pop();
|
||||||
if (--myAtBlockDepth > 0) {
|
break;
|
||||||
return;
|
default:
|
||||||
}
|
if (!isspace(c) || !myWord.empty()) {
|
||||||
break;
|
myWord.append(1, c);
|
||||||
case AT_RULE:
|
|
||||||
case BROKEN:
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
for (unsigned int i=0; i<mySelectors.size(); i++) {
|
|
||||||
storeData(mySelectors[i], myMap);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
myReadState = TAG_NAME;
|
break;
|
||||||
mySelectors.clear();
|
}
|
||||||
myMap.clear();
|
break;
|
||||||
|
|
||||||
|
case ATTRIBUTE_VALUE_SPACE:
|
||||||
|
case ATTRIBUTE_VALUE_COMMA:
|
||||||
|
switch (c) {
|
||||||
|
case '\'':
|
||||||
|
myStateStack.push(STRING_LITERAL_SINGLE);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
myStateStack.push(STRING_LITERAL_DOUBLE);
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
finishAttributeValue();
|
||||||
|
finishRule();
|
||||||
|
myStateStack.pop();
|
||||||
break;
|
break;
|
||||||
case ';':
|
case ';':
|
||||||
switch (myReadState) {
|
case '\n':
|
||||||
case AT_RULE:
|
finishAttributeValue();
|
||||||
myReadState = TAG_NAME;
|
finishAttribute();
|
||||||
mySelectors.clear();
|
myStateStack.top() = ATTRIBUTE_NAME;
|
||||||
|
break;
|
||||||
|
case ',':
|
||||||
|
if (myStateStack.top() == ATTRIBUTE_VALUE_COMMA) {
|
||||||
|
finishAttributeValue();
|
||||||
|
} else {
|
||||||
|
myWord.append(1, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (isspace(c)) {
|
||||||
|
if (myStateStack.top() == ATTRIBUTE_VALUE_SPACE) {
|
||||||
|
finishAttributeValue();
|
||||||
|
} else if (!myWord.empty()) {
|
||||||
|
myWord.append(1, c);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
myWord.append(1, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ATTRIBUTE_IGNORE:
|
||||||
|
switch (c) {
|
||||||
|
case '\n':
|
||||||
|
case ';':
|
||||||
|
finishAttribute();
|
||||||
|
myStateStack.top() = ATTRIBUTE_NAME;
|
||||||
|
break;
|
||||||
|
case '}':
|
||||||
|
finishRule();
|
||||||
|
myStateStack.pop();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case STRING_LITERAL_SINGLE:
|
||||||
|
case STRING_LITERAL_DOUBLE:
|
||||||
|
if (c == myStateStack.top()) {
|
||||||
|
myStateStack.pop();
|
||||||
|
} else if (c == '\n') {
|
||||||
|
// User agents must close strings upon reaching
|
||||||
|
// the end of a line (i.e., before an unescaped
|
||||||
|
// line feed, carriage return or form feed character),
|
||||||
|
// but then drop the construct (declaration or rule)
|
||||||
|
// in which the string was found.
|
||||||
|
myStateStack.pop();
|
||||||
|
switch (myStateStack.top()) {
|
||||||
|
case ATTRIBUTE_VALUE_SPACE:
|
||||||
|
case ATTRIBUTE_VALUE_COMMA:
|
||||||
|
myStateStack.top() = ATTRIBUTE_IGNORE;
|
||||||
|
myMap[myAttributeName].resize(0);
|
||||||
|
myAttributeName.resize(0);
|
||||||
|
myWord.resize(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
myWord.append(1, c);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case SKIP_BLOCK_CURLY:
|
||||||
|
case SKIP_BLOCK_SQUARE:
|
||||||
|
switch (c) {
|
||||||
|
case '{':
|
||||||
|
myStateStack.push(SKIP_BLOCK_CURLY);
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
myStateStack.push(SKIP_BLOCK_SQUARE);
|
||||||
|
break;
|
||||||
|
case '\'':
|
||||||
|
myStateStack.push(STRING_LITERAL_SINGLE);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
myStateStack.push(STRING_LITERAL_DOUBLE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (c == myStateStack.top()) {
|
||||||
|
myStateStack.pop();
|
||||||
|
if (myStateStack.top() == SELECTOR) {
|
||||||
|
myWord.resize(0);
|
||||||
|
mySelectors.resize(0);
|
||||||
myMap.clear();
|
myMap.clear();
|
||||||
break;
|
|
||||||
case AT_BLOCK:
|
|
||||||
break;
|
|
||||||
case ATTRIBUTE_VALUE:
|
|
||||||
case ATTRIBUTE_NAME:
|
|
||||||
myReadState = ATTRIBUTE_NAME;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
myReadState = BROKEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case ':':
|
|
||||||
switch (myReadState) {
|
|
||||||
case AT_BLOCK:
|
|
||||||
break;
|
|
||||||
case ATTRIBUTE_NAME:
|
|
||||||
myReadState = ATTRIBUTE_VALUE;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
myReadState = BROKEN;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StyleSheetParser::processWord(std::string &word) {
|
|
||||||
while (!word.empty()) {
|
|
||||||
int index = word.find(myInsideComment ? "*/" : "/*");
|
|
||||||
if (!myInsideComment) {
|
|
||||||
if (index == -1) {
|
|
||||||
processWordWithoutComments(word);
|
|
||||||
} else if (index > 0) {
|
|
||||||
processWordWithoutComments(word.substr(0, index));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (index == -1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
myInsideComment = !myInsideComment;
|
|
||||||
word.erase(0, index + 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void StyleSheetParser::processWordWithoutComments(std::string word) {
|
|
||||||
switch (myReadState) {
|
|
||||||
case AT_RULE:
|
|
||||||
case AT_BLOCK:
|
|
||||||
break;
|
|
||||||
case TAG_NAME:
|
|
||||||
ZLStringUtil::stripWhiteSpaces(word);
|
|
||||||
if (!word.empty()) {
|
|
||||||
if (word[0] == '@') {
|
|
||||||
myReadState = AT_RULE;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
mySelectors.push_back(word);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ATTRIBUTE_NAME:
|
}
|
||||||
myAttributeName = word;
|
break;
|
||||||
myMap[myAttributeName].clear();
|
|
||||||
break;
|
case COMMENT: // Comments are handled elsewhere
|
||||||
case ATTRIBUTE_VALUE:
|
break;
|
||||||
myMap[myAttributeName].push_back(word);
|
|
||||||
break;
|
|
||||||
case BROKEN:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StyleSheetParser::finishAttributeValue() {
|
||||||
|
if (ZLStringUtil::stripWhiteSpaces(myWord)) {
|
||||||
|
myMap[myAttributeName].push_back(myWord);
|
||||||
|
myWord.resize(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StyleSheetParser::finishAttribute() {
|
||||||
|
myAttributeName.resize(0);
|
||||||
|
myWord.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StyleSheetParser::finishRule() {
|
||||||
|
for (unsigned int i=0; i<mySelectors.size(); i++) {
|
||||||
|
storeData(mySelectors[i], myMap);
|
||||||
|
}
|
||||||
|
myAttributeName.resize(0);
|
||||||
|
myWord.resize(0);
|
||||||
|
mySelectors.resize(0);
|
||||||
|
myMap.clear();
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
|
|
||||||
#include "StyleSheetTable.h"
|
#include "StyleSheetTable.h"
|
||||||
|
|
||||||
|
#include <stack>
|
||||||
|
|
||||||
class ZLInputStream;
|
class ZLInputStream;
|
||||||
|
|
||||||
class StyleSheetParser {
|
class StyleSheetParser {
|
||||||
|
@ -39,26 +41,37 @@ protected:
|
||||||
virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map);
|
virtual void storeData(const std::string &selector, const StyleSheetTable::AttributeMap &map);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool isControlSymbol(const char symbol);
|
enum ReadState {
|
||||||
void processWord(std::string &word);
|
COMMENT,
|
||||||
void processWordWithoutComments(std::string word);
|
SELECTOR,
|
||||||
void processControl(const char control);
|
ATTRIBUTE_NAME,
|
||||||
|
ATTRIBUTE_VALUE_SPACE,
|
||||||
|
ATTRIBUTE_VALUE_COMMA,
|
||||||
|
ATTRIBUTE_IGNORE,
|
||||||
|
STRING_LITERAL_SINGLE = '\'',
|
||||||
|
STRING_LITERAL_DOUBLE = '"',
|
||||||
|
SKIP_BLOCK_CURLY = '}',
|
||||||
|
SKIP_BLOCK_SQUARE = ']'
|
||||||
|
};
|
||||||
|
|
||||||
|
void reset(ReadState state);
|
||||||
|
void processChar1(char c);
|
||||||
|
void processChar2(char c);
|
||||||
|
void processChar3(char c);
|
||||||
|
void processChar4(char c);
|
||||||
|
void finishRule();
|
||||||
|
void finishAttribute();
|
||||||
|
void finishAttributeValue();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::string myWord;
|
std::string myWord;
|
||||||
std::string myAttributeName;
|
std::string myAttributeName;
|
||||||
enum {
|
std::stack<ReadState> myStateStack;
|
||||||
AT_RULE,
|
|
||||||
AT_BLOCK,
|
|
||||||
TAG_NAME,
|
|
||||||
ATTRIBUTE_NAME,
|
|
||||||
ATTRIBUTE_VALUE,
|
|
||||||
BROKEN,
|
|
||||||
} myReadState;
|
|
||||||
bool myInsideComment;
|
|
||||||
int myAtBlockDepth;
|
|
||||||
std::vector<std::string> mySelectors;
|
std::vector<std::string> mySelectors;
|
||||||
StyleSheetTable::AttributeMap myMap;
|
StyleSheetTable::AttributeMap myMap;
|
||||||
|
char myBuffer1;
|
||||||
|
char myBuffer2;
|
||||||
|
char myBuffer3;
|
||||||
|
|
||||||
friend class StyleSheetSingleStyleParser;
|
friend class StyleSheetSingleStyleParser;
|
||||||
};
|
};
|
||||||
|
@ -81,4 +94,6 @@ public:
|
||||||
StyleSheetTable::Style parseString(const char *text);
|
StyleSheetTable::Style parseString(const char *text);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
inline void StyleSheetParser::reset() { reset(SELECTOR); }
|
||||||
|
|
||||||
#endif /* __STYLESHEETPARSER_H__ */
|
#endif /* __STYLESHEETPARSER_H__ */
|
||||||
|
|
|
@ -64,6 +64,30 @@ void StyleSheetTable::Style::apply(const Style &other) {
|
||||||
if (other.PageBreakAfter != B3_UNDEFINED) {
|
if (other.PageBreakAfter != B3_UNDEFINED) {
|
||||||
PageBreakAfter = other.PageBreakAfter;
|
PageBreakAfter = other.PageBreakAfter;
|
||||||
}
|
}
|
||||||
|
if (other.WhiteSpace != WS_UNDEFINED) {
|
||||||
|
WhiteSpace = other.WhiteSpace;
|
||||||
|
}
|
||||||
|
if (other.DisplayNone) {
|
||||||
|
DisplayNone = other.DisplayNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void StyleSheetTable::Style::inherit(const Style &other) {
|
||||||
|
TextStyle.inherit(other.TextStyle);
|
||||||
|
if (other.WhiteSpace != WS_UNDEFINED) {
|
||||||
|
WhiteSpace = other.WhiteSpace;
|
||||||
|
}
|
||||||
|
if (other.DisplayNone) {
|
||||||
|
DisplayNone = other.DisplayNone;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool StyleSheetTable::Style::equals(const Style &other) const {
|
||||||
|
return PageBreakBefore == other.PageBreakBefore &&
|
||||||
|
PageBreakAfter == other.PageBreakAfter &&
|
||||||
|
WhiteSpace == other.WhiteSpace &&
|
||||||
|
DisplayNone == other.DisplayNone &&
|
||||||
|
TextStyle.equals(other.TextStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleSheetTable::Entry::match(const ElementList &stack) const {
|
bool StyleSheetTable::Entry::match(const ElementList &stack) const {
|
||||||
|
@ -93,54 +117,28 @@ bool StyleSheetTable::Entry::match(const ElementList &stack) const {
|
||||||
|
|
||||||
void StyleSheetTable::addMap(const std::vector<std::string> &selectors, const AttributeMap &map) {
|
void StyleSheetTable::addMap(const std::vector<std::string> &selectors, const AttributeMap &map) {
|
||||||
if ((!selectors.empty()) && !map.empty()) {
|
if ((!selectors.empty()) && !map.empty()) {
|
||||||
// http://www.w3.org/TR/selectors/#specificity
|
Style style(map);
|
||||||
int a = 0, b = 0, c = 0;
|
if (!style.empty()) {
|
||||||
SelectorList stack;
|
// http://www.w3.org/TR/selectors/#specificity
|
||||||
for (unsigned int i=0; i<selectors.size(); i++) {
|
int a = 0, b = 0, c = 0;
|
||||||
const Selector &selector = selectors[i];
|
SelectorList stack;
|
||||||
a += selector.a();
|
for (unsigned int i=0; i<selectors.size(); i++) {
|
||||||
b += selector.b();
|
const Selector &selector = selectors[i];
|
||||||
c += selector.c();
|
a += selector.a();
|
||||||
stack.push_back(selector);
|
b += selector.b();
|
||||||
}
|
c += selector.c();
|
||||||
if (a > 255) a = 255;
|
stack.push_back(selector);
|
||||||
if (b > 255) b = 255;
|
}
|
||||||
if (c > 255) c = 255;
|
if (a > 255) a = 255;
|
||||||
myEntries.push_back(Entry(stack, (a << 16) + (b << 8) + c, map));
|
if (b > 255) b = 255;
|
||||||
}
|
if (c > 255) c = 255;
|
||||||
}
|
myEntries.push_back(Entry(stack, (a << 16) + (b << 8) + c, style));
|
||||||
|
|
||||||
bool StyleSheetTable::parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
|
|
||||||
if (!toParse.empty()) {
|
|
||||||
if (ZLStringUtil::stringEndsWith(toParse, "%")) {
|
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT;
|
|
||||||
size = atoi(toParse.c_str());
|
|
||||||
return true;
|
|
||||||
} else if (ZLStringUtil::stringEndsWith(toParse, "em")) {
|
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_EM_100;
|
|
||||||
size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
|
|
||||||
return true;
|
|
||||||
} else if (ZLStringUtil::stringEndsWith(toParse, "ex")) {
|
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_EX_100;
|
|
||||||
size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
|
|
||||||
return true;
|
|
||||||
} else if (ZLStringUtil::stringEndsWith(toParse, "px") ||
|
|
||||||
ZLStringUtil::stringEndsWith(toParse, "pt") ||
|
|
||||||
ZLStringUtil::stringEndsWith(toParse, "pc")) {
|
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
|
||||||
size = atoi(toParse.c_str());
|
|
||||||
return true;
|
|
||||||
} else if (toParse == "0") {
|
|
||||||
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
|
||||||
size = 0;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleSheetTable::parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
|
bool StyleSheetTable::parseMargin(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
|
||||||
if (parseLength(toParse, size, unit)) {
|
if (ZLTextStyleEntry::parseLength(toParse, size, unit)) {
|
||||||
// Negative margins do make sense but we don't really support them
|
// Negative margins do make sense but we don't really support them
|
||||||
if (size < 0) size = 0;
|
if (size < 0) size = 0;
|
||||||
return true;
|
return true;
|
||||||
|
@ -166,7 +164,7 @@ void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Lengt
|
||||||
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
|
void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value) {
|
||||||
short size;
|
short size;
|
||||||
ZLTextStyleEntry::SizeUnit unit;
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
if (parseLength(value, size, unit)) {
|
if (ZLTextStyleEntry::parseLength(value, size, unit)) {
|
||||||
entry.setLength(name, size, unit);
|
entry.setLength(name, size, unit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -200,9 +198,11 @@ void StyleSheetTable::applyStyles(const ElementList &stack, Style &style) const
|
||||||
entries.push_back(&(*i));
|
entries.push_back(&(*i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
std::sort(entries.begin(), entries.end(), sortBySpecificity);
|
if (!entries.empty()) {
|
||||||
for (std::vector<const Entry*>::const_iterator e = entries.begin(); e != entries.end(); ++e) {
|
std::sort(entries.begin(), entries.end(), sortBySpecificity);
|
||||||
style.apply((*e)->Style);
|
for (std::vector<const Entry*>::const_iterator e = entries.begin(); e != entries.end(); ++e) {
|
||||||
|
style.apply((*e)->Style);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -216,60 +216,77 @@ const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map,
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &styles) {
|
void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &styles) {
|
||||||
const std::vector<std::string> &alignment = values(styles, "text-align");
|
static const std::string TEXT_ALIGN("text-align");
|
||||||
|
const std::vector<std::string> &alignment = values(styles, TEXT_ALIGN);
|
||||||
if (!alignment.empty()) {
|
if (!alignment.empty()) {
|
||||||
if (alignment[0] == "justify") {
|
const std::string &value = alignment.at(0);
|
||||||
|
if (value == "justify") {
|
||||||
entry.setAlignmentType(ALIGN_JUSTIFY);
|
entry.setAlignmentType(ALIGN_JUSTIFY);
|
||||||
} else if (alignment[0] == "left") {
|
} else if (value == "left") {
|
||||||
entry.setAlignmentType(ALIGN_LEFT);
|
entry.setAlignmentType(ALIGN_LEFT);
|
||||||
} else if (alignment[0] == "right") {
|
} else if (value == "right") {
|
||||||
entry.setAlignmentType(ALIGN_RIGHT);
|
entry.setAlignmentType(ALIGN_RIGHT);
|
||||||
} else if (alignment[0] == "center") {
|
} else if (value == "center") {
|
||||||
entry.setAlignmentType(ALIGN_CENTER);
|
entry.setAlignmentType(ALIGN_CENTER);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
static const std::string FLOAT("float");
|
||||||
|
const std::vector<std::string> &floatVal = values(styles, FLOAT);
|
||||||
|
if (!floatVal.empty()) {
|
||||||
|
const std::string &value = floatVal.at(0);
|
||||||
|
if (value == "left") {
|
||||||
|
entry.setAlignmentType(ALIGN_LEFT);
|
||||||
|
} else if (value == "right") {
|
||||||
|
entry.setAlignmentType(ALIGN_RIGHT);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &bold = values(styles, "font-weight");
|
static const std::string FONT_WEIGHT("font-weight");
|
||||||
if (!bold.empty()) {
|
const std::vector<std::string> &weight = values(styles, FONT_WEIGHT);
|
||||||
|
if (!weight.empty()) {
|
||||||
int num = -1;
|
int num = -1;
|
||||||
if (bold[0] == "bold") {
|
const std::string &value = weight.at(0);
|
||||||
|
if (value == "bold") {
|
||||||
num = 700;
|
num = 700;
|
||||||
} else if (bold[0] == "normal") {
|
} else if (value == "normal") {
|
||||||
num = 400;
|
num = 400;
|
||||||
} else if ((bold[0].length() == 3) &&
|
} else if ((value.length() == 3) &&
|
||||||
(bold[0][1] == '0') &&
|
(value[1] == '0') &&
|
||||||
(bold[0][2] == '0') &&
|
(value[2] == '0') &&
|
||||||
(bold[0][0] >= '1') &&
|
(value[0] >= '1') &&
|
||||||
(bold[0][0] <= '9')) {
|
(value[0] <= '9')) {
|
||||||
num = 100 * (bold[0][0] - '0');
|
num = 100 * (value[0] - '0');
|
||||||
} else if (bold[0] == "bolder") {
|
} else if (value == "bolder") {
|
||||||
} else if (bold[0] == "lighter") {
|
} else if (value == "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");
|
static const std::string FONT_STYLE("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");
|
static const std::string FONT_VARIANT("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");
|
static const std::string FONT_FAMILY("font-family");
|
||||||
if (!fontFamily.empty() && !fontFamily[0].empty()) {
|
const std::vector<std::string> &fontFamilies = values(styles, FONT_FAMILY);
|
||||||
entry.setFontFamily(fontFamily[0]);
|
if (!fontFamilies.empty()) entry.setFontFamilies(fontFamilies);
|
||||||
}
|
|
||||||
|
|
||||||
short size;
|
short size;
|
||||||
ZLTextStyleEntry::SizeUnit unit;
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
const std::vector<std::string> &fontSize = values(styles, "font-size");
|
static const std::string FONT_SIZE("font-size");
|
||||||
|
const std::vector<std::string> &fontSize = values(styles, FONT_SIZE);
|
||||||
if (!fontSize.empty()) {
|
if (!fontSize.empty()) {
|
||||||
std::string value = fontSize[0];
|
const std::string &value = fontSize.at(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") {
|
||||||
|
@ -285,7 +302,7 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
|
||||||
} else if (value == "xx-large") {
|
} else if (value == "xx-large") {
|
||||||
entry.setFontSizeMag(3);
|
entry.setFontSizeMag(3);
|
||||||
} else {
|
} else {
|
||||||
if (parseLength(value, size, unit)) {
|
if (ZLTextStyleEntry::parseLength(value, size, unit)) {
|
||||||
switch (unit) {
|
switch (unit) {
|
||||||
case ZLTextStyleEntry::SIZE_UNIT_PIXEL:
|
case ZLTextStyleEntry::SIZE_UNIT_PIXEL:
|
||||||
// What to do with pixels?
|
// What to do with pixels?
|
||||||
|
@ -293,26 +310,68 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
|
||||||
case ZLTextStyleEntry::SIZE_UNIT_EM_100:
|
case ZLTextStyleEntry::SIZE_UNIT_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((size < 100 && size > 80) ? -1 :
|
// Percent to magnification mapping algorithm
|
||||||
(size > 100 && size < 120) ? 1 :
|
// matches ZLTextForcedStyle::fontSize() logic
|
||||||
(size - 100)/20);
|
if (size < 100) {
|
||||||
|
if (size >= 80) {
|
||||||
|
entry.setFontSizeMag(-1);
|
||||||
|
} else {
|
||||||
|
int mag;
|
||||||
|
unsigned int x1 = 5*100, x2 = 6*size;
|
||||||
|
// Too many iterations would cause 32-bit
|
||||||
|
// overflow and generally don't make sense.
|
||||||
|
for (mag=1; mag<=6 && x1<x2; ++mag) {
|
||||||
|
x1 *= 5; x2 *= 6;
|
||||||
|
}
|
||||||
|
entry.setFontSizeMag(-mag);
|
||||||
|
}
|
||||||
|
} else if (size > 100) {
|
||||||
|
if (size < 120) {
|
||||||
|
entry.setFontSizeMag(1);
|
||||||
|
} else {
|
||||||
|
int mag;
|
||||||
|
unsigned int x1 = 6*100, x2 = 5*size;
|
||||||
|
for (mag=1; mag<=6 && x1<x2; ++mag) {
|
||||||
|
x1 *= 6; x2 *= 5;
|
||||||
|
}
|
||||||
|
entry.setFontSizeMag(mag);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entry.setFontSizeMag(0);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &opacity = values(styles, "opacity");
|
static const std::string OPACITY("opacity");
|
||||||
|
const std::vector<std::string> &opacity = values(styles, OPACITY);
|
||||||
if (!opacity.empty()) {
|
if (!opacity.empty()) {
|
||||||
const int value = (int)(255 * ZLStringUtil::stringToDouble(opacity[0], 1));
|
const int value = (int)(255 * ZLStringUtil::stringToDouble(opacity[0], 1));
|
||||||
entry.setOpacity((unsigned char)((value < 0) ? 0 : (value > 255) ? 255 : value));
|
entry.setOpacity((unsigned char)((value < 0) ? 0 : (value > 255) ? 255 : value));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> margins = values(styles, "margin");
|
// Margins will overwrite padding, sorry
|
||||||
if (!margins.empty() && margins.back() == "!important") {
|
static const std::string PADDING_TOP("padding-top");
|
||||||
|
static const std::string PADDING_BOTTOM("padding-bottom");
|
||||||
|
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, PADDING_TOP);
|
||||||
|
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, PADDING_BOTTOM);
|
||||||
|
|
||||||
|
static const std::string MARGIN("margin");
|
||||||
|
std::vector<std::string> margins = values(styles, MARGIN);
|
||||||
|
if (!margins.empty()) {
|
||||||
// Ignore the "!important" modifier for now
|
// Ignore the "!important" modifier for now
|
||||||
margins.pop_back();
|
if (margins.back() == "!important") {
|
||||||
|
margins.pop_back();
|
||||||
|
} else if (margins.back() == "important") {
|
||||||
|
margins.pop_back();
|
||||||
|
if (!margins.empty() && margins.back() == "!") {
|
||||||
|
margins.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (margins.size()) {
|
switch (margins.size()) {
|
||||||
case 1:
|
case 1:
|
||||||
if (parseMargin(margins[0], size, unit)) {
|
if (parseMargin(margins[0], size, unit)) {
|
||||||
|
@ -348,49 +407,61 @@ void StyleSheetTable::updateTextStyle(ZLTextStyleEntry &entry, const AttributeMa
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left");
|
static const std::string MARGIN_LEFT("margin-left");
|
||||||
setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right");
|
static const std::string MARGIN_RIGHT("margin-right");
|
||||||
setLength(entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent");
|
static const std::string MARGIN_TOP("margin-top");
|
||||||
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top");
|
static const std::string MARGIN_BOTTOM("margin-bottom");
|
||||||
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top");
|
static const std::string TEXT_INDENT("text-indent");
|
||||||
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom");
|
|
||||||
setLength(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom");
|
setMargin(entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, MARGIN_LEFT);
|
||||||
|
setMargin(entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, MARGIN_RIGHT);
|
||||||
|
setLength(entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, TEXT_INDENT);
|
||||||
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, MARGIN_TOP);
|
||||||
|
setMargin(entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, MARGIN_BOTTOM);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool StyleSheetTable::getPageBreakBefore(const AttributeMap &map, ZLBoolean3 &value) {
|
void StyleSheetTable::getPageBreakValue(const std::vector<std::string> &values, ZLBoolean3 &value) {
|
||||||
const std::vector<std::string> &pbb = values(map, "page-break-before");
|
if (!values.empty()) {
|
||||||
if (!pbb.empty()) {
|
const std::string &first = values.at(0);
|
||||||
if ((pbb[0] == "always") ||
|
if ((first == "always") ||
|
||||||
(pbb[0] == "left") ||
|
(first == "left") ||
|
||||||
(pbb[0] == "right")) {
|
(first == "right")) {
|
||||||
value = B3_TRUE;
|
value = B3_TRUE;
|
||||||
return true;
|
} else if (first == "avoid") {
|
||||||
} else if (pbb[0] == "avoid") {
|
|
||||||
value = B3_FALSE;
|
value = B3_FALSE;
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool StyleSheetTable::getPageBreakAfter(const AttributeMap &map, ZLBoolean3 &value) {
|
|
||||||
const std::vector<std::string> &pba = values(map, "page-break-after");
|
|
||||||
if (!pba.empty()) {
|
|
||||||
if ((pba[0] == "always") ||
|
|
||||||
(pba[0] == "left") ||
|
|
||||||
(pba[0] == "right")) {
|
|
||||||
value = B3_TRUE;
|
|
||||||
return true;
|
|
||||||
} else if (pba[0] == "avoid") {
|
|
||||||
value = B3_FALSE;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) {
|
void StyleSheetTable::updateStyle(Style &style, const AttributeMap &map) {
|
||||||
updateTextStyle(style.TextStyle, map);
|
updateTextStyle(style.TextStyle, map);
|
||||||
getPageBreakBefore(map, style.PageBreakBefore);
|
|
||||||
getPageBreakAfter(map, style.PageBreakAfter);
|
static const std::string PAGE_BREAK_BEFORE("page-break-before");
|
||||||
|
getPageBreakValue(values(map, PAGE_BREAK_BEFORE), style.PageBreakBefore);
|
||||||
|
|
||||||
|
static const std::string PAGE_BREAK_AFTER("page-break-after");
|
||||||
|
getPageBreakValue(values(map, PAGE_BREAK_AFTER), style.PageBreakAfter);
|
||||||
|
|
||||||
|
static const std::string WHITE_SPACE("white-space");
|
||||||
|
const std::vector<std::string> &whiteSpace = values(map, WHITE_SPACE);
|
||||||
|
if (!whiteSpace.empty()) {
|
||||||
|
const std::string &value = whiteSpace.at(0);
|
||||||
|
if (value == "normal") {
|
||||||
|
style.WhiteSpace = WS_NORMAL;
|
||||||
|
} else if (value == "nowrap") {
|
||||||
|
style.WhiteSpace = WS_NOWRAP;
|
||||||
|
} else if (value == "pre") {
|
||||||
|
style.WhiteSpace = WS_PRE;
|
||||||
|
} else if (value == "pre-wrap") {
|
||||||
|
style.WhiteSpace = WS_PRE_WRAP;
|
||||||
|
} else if (value == "pre-line") {
|
||||||
|
style.WhiteSpace = WS_PRE_LINE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const std::string DISPLAY("display");
|
||||||
|
const std::vector<std::string> &display = values(map, DISPLAY);
|
||||||
|
if (!display.empty() && display[0] == "none") {
|
||||||
|
style.DisplayNone = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -73,29 +73,43 @@ public:
|
||||||
typedef std::vector<Selector> SelectorList;
|
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;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
WS_UNDEFINED,
|
||||||
|
WS_NORMAL,
|
||||||
|
WS_NOWRAP,
|
||||||
|
WS_PRE,
|
||||||
|
WS_PRE_WRAP,
|
||||||
|
WS_PRE_LINE
|
||||||
|
} WhiteSpaceValue;
|
||||||
|
|
||||||
struct Style {
|
struct Style {
|
||||||
Style();
|
Style();
|
||||||
Style(const Style &other);
|
Style(const Style &other);
|
||||||
Style(const AttributeMap &map);
|
Style(const AttributeMap &map);
|
||||||
|
|
||||||
Style &operator = (const Style &other);
|
Style &operator = (const Style &other);
|
||||||
void apply(const Style &other);
|
bool operator == (const Style &other) const;
|
||||||
|
bool equals(const Style &other) const;
|
||||||
|
void apply(const Style &other);
|
||||||
|
void inherit(const Style &other);
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
ZLTextStyleEntry TextStyle;
|
ZLTextStyleEntry TextStyle;
|
||||||
ZLBoolean3 PageBreakBefore;
|
ZLBoolean3 PageBreakBefore;
|
||||||
ZLBoolean3 PageBreakAfter;
|
ZLBoolean3 PageBreakAfter;
|
||||||
|
WhiteSpaceValue WhiteSpace;
|
||||||
|
bool DisplayNone;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<Style> StyleList;
|
typedef std::vector<Style> StyleList;
|
||||||
static void updateStyle(Style &style, const AttributeMap &map);
|
static void updateStyle(Style &style, const AttributeMap &map);
|
||||||
static void updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &map);
|
static void updateTextStyle(ZLTextStyleEntry &entry, const AttributeMap &map);
|
||||||
static bool getPageBreakBefore(const AttributeMap &map, ZLBoolean3 &value);
|
static void getPageBreakValue(const std::vector<std::string> &values, ZLBoolean3 &value);
|
||||||
static bool getPageBreakAfter(const AttributeMap &map, ZLBoolean3 &value);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
struct Entry {
|
struct Entry {
|
||||||
Entry();
|
Entry();
|
||||||
Entry(const SelectorList &selectors, int specificity, const AttributeMap &map);
|
Entry(const SelectorList &selectors, int specificity, const Style &style);
|
||||||
Entry &operator = (const Entry &other);
|
Entry &operator = (const Entry &other);
|
||||||
bool match(const ElementList &stack) const;
|
bool match(const ElementList &stack) const;
|
||||||
|
|
||||||
|
@ -106,13 +120,12 @@ private:
|
||||||
|
|
||||||
void addMap(const std::vector<std::string> &selectors, const AttributeMap &map);
|
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 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 AttributeMap &map, const std::string &attributeName);
|
||||||
static void setMargin(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const std::string &value);
|
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);
|
static bool sortBySpecificity(const Entry *e1, const Entry *e2);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -129,7 +142,7 @@ inline StyleSheetTable::Selector::Selector(const std::string &type, const std::s
|
||||||
inline StyleSheetTable::Selector::Selector(const std::string &type, const std::string &klass) : myType(type), myClass(klass) {}
|
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(const StyleSheetTable::Selector &other) : myType(other.myType), myClass(other.myClass), myId(other.myId) {}
|
||||||
inline StyleSheetTable::Selector::Selector() {}
|
inline StyleSheetTable::Selector::Selector() {}
|
||||||
inline StyleSheetTable::Selector &StyleSheetTable::Selector::operator = (const StyleSheetTable::Selector &other) {
|
inline StyleSheetTable::Selector &StyleSheetTable::Selector::operator = (const Selector &other) {
|
||||||
myType = other.myType; myClass = other.myClass; myId = other.myId; return *this;
|
myType = other.myType; myClass = other.myClass; myId = other.myId; return *this;
|
||||||
}
|
}
|
||||||
inline bool StyleSheetTable::Selector::operator == (const Selector &other) const {
|
inline bool StyleSheetTable::Selector::operator == (const Selector &other) const {
|
||||||
|
@ -138,7 +151,7 @@ inline bool StyleSheetTable::Selector::operator == (const Selector &other) const
|
||||||
inline bool StyleSheetTable::Selector::operator != (const Selector &other) const {
|
inline bool StyleSheetTable::Selector::operator != (const Selector &other) const {
|
||||||
return (&other != this) && (myType != other.myType || myClass != other.myClass || myId != other.myId);
|
return (&other != this) && (myType != other.myType || myClass != other.myClass || myId != other.myId);
|
||||||
}
|
}
|
||||||
inline bool StyleSheetTable::Selector::operator < (const StyleSheetTable::Selector &other) const {
|
inline bool StyleSheetTable::Selector::operator < (const Selector &other) const {
|
||||||
return myType < other.myType || (myType == other.myType && (myClass < other.myClass || (myClass == other.myClass && myId < other.myId)));
|
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 {
|
inline bool StyleSheetTable::Selector::match(const Element &element) const {
|
||||||
|
@ -151,21 +164,30 @@ inline const std::string &StyleSheetTable::Selector::type() const { return myTyp
|
||||||
inline const std::string &StyleSheetTable::Selector::klass() const { return myClass; }
|
inline const std::string &StyleSheetTable::Selector::klass() const { return myClass; }
|
||||||
inline const std::string &StyleSheetTable::Selector::id() const { return myId; }
|
inline const std::string &StyleSheetTable::Selector::id() const { return myId; }
|
||||||
|
|
||||||
inline StyleSheetTable::Style::Style() : PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED) {}
|
inline StyleSheetTable::Style::Style() :
|
||||||
inline StyleSheetTable::Style::Style(const StyleSheetTable::Style &other) : TextStyle(other.TextStyle), PageBreakBefore(other.PageBreakBefore), PageBreakAfter(other.PageBreakAfter) {}
|
PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED), WhiteSpace(WS_UNDEFINED), DisplayNone(false) {}
|
||||||
inline StyleSheetTable::Style::Style(const StyleSheetTable::AttributeMap &map) : PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED) {
|
inline StyleSheetTable::Style::Style(const StyleSheetTable::Style &other) :
|
||||||
|
TextStyle(other.TextStyle), PageBreakBefore(other.PageBreakBefore), PageBreakAfter(other.PageBreakAfter), WhiteSpace(other.WhiteSpace), DisplayNone(other.DisplayNone) {}
|
||||||
|
inline StyleSheetTable::Style::Style(const StyleSheetTable::AttributeMap &map) :
|
||||||
|
PageBreakBefore(B3_UNDEFINED), PageBreakAfter(B3_UNDEFINED), WhiteSpace(WS_UNDEFINED), DisplayNone(false) {
|
||||||
updateStyle(*this, map);
|
updateStyle(*this, map);
|
||||||
}
|
}
|
||||||
inline StyleSheetTable::Style &StyleSheetTable::Style::operator = (const StyleSheetTable::Style &other) {
|
inline bool StyleSheetTable::Style::empty() const {
|
||||||
|
return TextStyle.isEmpty() && PageBreakBefore == B3_UNDEFINED && PageBreakAfter == B3_UNDEFINED && WhiteSpace == WS_UNDEFINED && !DisplayNone;
|
||||||
|
}
|
||||||
|
inline bool StyleSheetTable::Style::operator == (const Style &other) const { return equals(other); }
|
||||||
|
inline StyleSheetTable::Style &StyleSheetTable::Style::operator = (const Style &other) {
|
||||||
TextStyle = other.TextStyle;
|
TextStyle = other.TextStyle;
|
||||||
PageBreakBefore = other.PageBreakBefore;
|
PageBreakBefore = other.PageBreakBefore;
|
||||||
PageBreakAfter = other.PageBreakAfter;
|
PageBreakAfter = other.PageBreakAfter;
|
||||||
|
WhiteSpace = other.WhiteSpace;
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline StyleSheetTable::Entry::Entry() : Specificity(0) {}
|
inline StyleSheetTable::Entry::Entry() : Specificity(0) {}
|
||||||
inline StyleSheetTable::Entry::Entry(const SelectorList &selectors, int specificity, const AttributeMap &map) : Selectors(selectors), Specificity(specificity), Style(map) {}
|
inline StyleSheetTable::Entry::Entry(const SelectorList &selectors, int specificity, const StyleSheetTable::Style &style) :
|
||||||
inline StyleSheetTable::Entry &StyleSheetTable::Entry::operator = (const StyleSheetTable::Entry &other) {
|
Selectors(selectors), Specificity(specificity), Style(style) {}
|
||||||
|
inline StyleSheetTable::Entry &StyleSheetTable::Entry::operator = (const Entry &other) {
|
||||||
Selectors = other.Selectors;
|
Selectors = other.Selectors;
|
||||||
Style = other.Style;
|
Style = other.Style;
|
||||||
Specificity = other.Specificity;
|
Specificity = other.Specificity;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <ZLUnicodeUtil.h>
|
#include <ZLUnicodeUtil.h>
|
||||||
#include <ZLStringUtil.h>
|
#include <ZLStringUtil.h>
|
||||||
#include <ZLXMLNamespace.h>
|
#include <ZLXMLNamespace.h>
|
||||||
|
#include <ZLTextStyleCollection.h>
|
||||||
|
|
||||||
#include "XHTMLReader.h"
|
#include "XHTMLReader.h"
|
||||||
#include "../util/EntityFilesCollector.h"
|
#include "../util/EntityFilesCollector.h"
|
||||||
|
@ -90,12 +91,6 @@ public:
|
||||||
void doAtEnd(XHTMLReader &reader);
|
void doAtEnd(XHTMLReader &reader);
|
||||||
};
|
};
|
||||||
|
|
||||||
class XHTMLTagRestartParagraphAction : public XHTMLTagAction {
|
|
||||||
|
|
||||||
public:
|
|
||||||
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
|
||||||
};
|
|
||||||
|
|
||||||
class XHTMLTagLineBreakAction : public XHTMLTagAction {
|
class XHTMLTagLineBreakAction : public XHTMLTagAction {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -160,7 +155,6 @@ public:
|
||||||
XHTMLTagControlAction(FBTextKind control);
|
XHTMLTagControlAction(FBTextKind control);
|
||||||
|
|
||||||
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
void doAtStart(XHTMLReader &reader, const char **xmlattributes);
|
||||||
void doAtEnd(XHTMLReader &reader);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
FBTextKind myControl;
|
FBTextKind myControl;
|
||||||
|
@ -186,10 +180,8 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
void XHTMLTagStyleAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
void XHTMLTagStyleAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
||||||
static const std::string TYPE = "text/css";
|
|
||||||
|
|
||||||
const char *type = reader.attributeValue(xmlattributes, "type");
|
const char *type = reader.attributeValue(xmlattributes, "type");
|
||||||
if ((type == 0) || (TYPE != type)) {
|
if (!type || strcmp(type, "text/css")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,15 +199,13 @@ void XHTMLTagStyleAction::doAtEnd(XHTMLReader &reader) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
||||||
static const std::string REL = "stylesheet";
|
|
||||||
const char *rel = reader.attributeValue(xmlattributes, "rel");
|
const char *rel = reader.attributeValue(xmlattributes, "rel");
|
||||||
if ((rel == 0) || (REL != rel)) {
|
if (!rel || strcmp(rel, "stylesheet")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
static const std::string TYPE = "text/css";
|
|
||||||
|
|
||||||
const char *type = reader.attributeValue(xmlattributes, "type");
|
const char *type = reader.attributeValue(xmlattributes, "type");
|
||||||
if ((type == 0) || (TYPE != type)) {
|
if (!type || strcmp(type, "text/css")) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,10 +224,7 @@ void XHTMLTagLinkAction::doAtStart(XHTMLReader &reader, const char **xmlattribut
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
if (!reader.myNewParagraphInProgress) {
|
endParagraph(reader);
|
||||||
beginParagraph(reader);
|
|
||||||
reader.myNewParagraphInProgress = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagParagraphAction::doAtEnd(XHTMLReader &reader) {
|
void XHTMLTagParagraphAction::doAtEnd(XHTMLReader &reader) {
|
||||||
|
@ -253,16 +240,15 @@ void XHTMLTagBodyAction::doAtEnd(XHTMLReader &reader) {
|
||||||
reader.myReadState = XHTMLReader::READ_NOTHING;
|
reader.myReadState = XHTMLReader::READ_NOTHING;
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagRestartParagraphAction::doAtStart(XHTMLReader &reader, const char**) {
|
|
||||||
if (reader.myCurrentParagraphIsEmpty) {
|
|
||||||
bookReader(reader).addData(" ");
|
|
||||||
}
|
|
||||||
endParagraph(reader);
|
|
||||||
beginParagraph(reader);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XHTMLTagLineBreakAction::doAtEnd(XHTMLReader& reader) {
|
void XHTMLTagLineBreakAction::doAtEnd(XHTMLReader& reader) {
|
||||||
bookReader(reader).addLineBreak();
|
BookReader &br = bookReader(reader);
|
||||||
|
if (br.paragraphIsOpen()) {
|
||||||
|
br.addLineBreak();
|
||||||
|
} else {
|
||||||
|
beginParagraph(reader);
|
||||||
|
br.addLineBreak();
|
||||||
|
endParagraph(reader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagItemAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagItemAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
|
@ -288,7 +274,7 @@ 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
|
// Ignore transparent images
|
||||||
if (!reader.myOpacityStack.back()) {
|
if (!reader.myParseStack.back().opacity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -302,19 +288,14 @@ void XHTMLTagImageAction::doAtStart(XHTMLReader &reader, const char **xmlattribu
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool flag = bookReader(reader).paragraphIsOpen();
|
|
||||||
if (flag) {
|
|
||||||
endParagraph(reader);
|
|
||||||
}
|
|
||||||
if ((strlen(fileName) > 2) && strncmp(fileName, "./", 2) == 0) {
|
if ((strlen(fileName) > 2) && strncmp(fileName, "./", 2) == 0) {
|
||||||
fileName +=2;
|
fileName +=2;
|
||||||
}
|
}
|
||||||
bookReader(reader).addImageReference(fullfileName);
|
|
||||||
bookReader(reader).addImage(fullfileName, new ZLFileImage(ZLFile(fullfileName), 0));
|
reader.myParseStack.back().kind = IMAGE;
|
||||||
if (flag) {
|
reader.haveContent();
|
||||||
beginParagraph(reader);
|
reader.myModelReader.addImageReference(fullfileName);
|
||||||
}
|
reader.myModelReader.addImage(fullfileName, new ZLFileImage(ZLFile(fullfileName), 0));
|
||||||
reader.myElementHasContents.back() = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
XHTMLTagSvgAction::XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate) : myPredicate(predicate) {
|
XHTMLTagSvgAction::XHTMLTagSvgAction(XHTMLSvgImageAttributeNamePredicate &predicate) : myPredicate(predicate) {
|
||||||
|
@ -339,13 +320,7 @@ XHTMLTagControlAction::XHTMLTagControlAction(FBTextKind control) : myControl(con
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagControlAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagControlAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
bookReader(reader).pushKind(myControl);
|
reader.myParseStack.back().kind = myControl;
|
||||||
bookReader(reader).addControl(myControl, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XHTMLTagControlAction::doAtEnd(XHTMLReader &reader) {
|
|
||||||
bookReader(reader).addControl(myControl, false);
|
|
||||||
bookReader(reader).popKind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagHyperlinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
void XHTMLTagHyperlinkAction::doAtStart(XHTMLReader &reader, const char **xmlattributes) {
|
||||||
|
@ -387,25 +362,25 @@ void XHTMLTagParagraphWithControlAction::doAtStart(XHTMLReader &reader, const ch
|
||||||
if ((myControl == TITLE) && (bookReader(reader).model().bookTextModel()->paragraphsNumber() > 1)) {
|
if ((myControl == TITLE) && (bookReader(reader).model().bookTextModel()->paragraphsNumber() > 1)) {
|
||||||
bookReader(reader).insertEndOfSectionParagraph();
|
bookReader(reader).insertEndOfSectionParagraph();
|
||||||
}
|
}
|
||||||
bookReader(reader).pushKind(myControl);
|
reader.myParseStack.back().kind = myControl;
|
||||||
beginParagraph(reader);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagParagraphWithControlAction::doAtEnd(XHTMLReader &reader) {
|
void XHTMLTagParagraphWithControlAction::doAtEnd(XHTMLReader &reader) {
|
||||||
endParagraph(reader);
|
endParagraph(reader);
|
||||||
bookReader(reader).popKind();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
|
void XHTMLTagPreAction::doAtStart(XHTMLReader &reader, const char**) {
|
||||||
reader.myPreformatted++;
|
endParagraph(reader);
|
||||||
beginParagraph(reader);
|
reader.myParseStack.back().kind = PREFORMATTED;
|
||||||
bookReader(reader).addControl(CODE, true);
|
if (++reader.myPreformatted == 1) {
|
||||||
|
beginParagraph(reader);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) {
|
void XHTMLTagPreAction::doAtEnd(XHTMLReader &reader) {
|
||||||
bookReader(reader).addControl(CODE, false);
|
if (!--reader.myPreformatted) {
|
||||||
endParagraph(reader);
|
endParagraph(reader);
|
||||||
reader.myPreformatted--;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
XHTMLTagAction *XHTMLReader::addAction(const std::string &tag, XHTMLTagAction *action) {
|
XHTMLTagAction *XHTMLReader::addAction(const std::string &tag, XHTMLTagAction *action) {
|
||||||
|
@ -454,6 +429,7 @@ void XHTMLReader::fillTagTable() {
|
||||||
addAction("dt", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
addAction("dt", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
||||||
addAction("dfn", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
addAction("dfn", new XHTMLTagParagraphWithControlAction(DEFINITION));
|
||||||
addAction("strike", new XHTMLTagControlAction(STRIKETHROUGH));
|
addAction("strike", new XHTMLTagControlAction(STRIKETHROUGH));
|
||||||
|
addAction("blockquote", new XHTMLTagParagraphWithControlAction(BLOCKQUOTE));
|
||||||
|
|
||||||
addAction("a", new XHTMLTagHyperlinkAction());
|
addAction("a", new XHTMLTagHyperlinkAction());
|
||||||
|
|
||||||
|
@ -467,7 +443,6 @@ void XHTMLReader::fillTagTable() {
|
||||||
//addAction("map", new XHTMLTagAction());
|
//addAction("map", new XHTMLTagAction());
|
||||||
|
|
||||||
//addAction("base", new XHTMLTagAction());
|
//addAction("base", new XHTMLTagAction());
|
||||||
//addAction("blockquote", new XHTMLTagAction());
|
|
||||||
addAction("br", new XHTMLTagLineBreakAction());
|
addAction("br", new XHTMLTagLineBreakAction());
|
||||||
//addAction("center", new XHTMLTagAction());
|
//addAction("center", new XHTMLTagAction());
|
||||||
addAction("div", new XHTMLTagParagraphAction());
|
addAction("div", new XHTMLTagParagraphAction());
|
||||||
|
@ -507,29 +482,19 @@ bool XHTMLReader::readFile(const ZLFile &file, const std::string &referenceName)
|
||||||
myReferenceDirName = referenceName.substr(0, index + 1);
|
myReferenceDirName = referenceName.substr(0, index + 1);
|
||||||
|
|
||||||
myPreformatted = 0;
|
myPreformatted = 0;
|
||||||
myNewParagraphInProgress = false;
|
|
||||||
myReadState = READ_NOTHING;
|
myReadState = READ_NOTHING;
|
||||||
|
|
||||||
myElementStack.clear();
|
myElementStack.clear();
|
||||||
myStyleStack.clear();
|
myStyleStack.clear();
|
||||||
myElementHasContents.clear();
|
myParseStack.resize(1);
|
||||||
myOpacityStack.clear();
|
|
||||||
|
|
||||||
return readDocument(file);
|
return readDocument(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyleEntry> XHTMLReader::addStyleEntry(shared_ptr<ZLTextStyleEntry> entry, shared_ptr<ZLTextStyleEntry> styleEntry) {
|
|
||||||
if (!styleEntry.isNull() && !styleEntry->isEmpty()) {
|
|
||||||
if (entry.isNull()) entry = new ZLTextStyleEntry;
|
|
||||||
entry->apply(*styleEntry);
|
|
||||||
}
|
|
||||||
return entry;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = "#";
|
||||||
const char *id = attributeValue(attributes, "id");
|
const char *id = attributeValue(attributes, "id");
|
||||||
const char *style = attributeValue(attributes, "style");
|
const char *inlineStyle = attributeValue(attributes, "style");
|
||||||
const char *klass = attributeValue(attributes, "class");
|
const char *klass = attributeValue(attributes, "class");
|
||||||
if (id != 0) {
|
if (id != 0) {
|
||||||
myModelReader.addHyperlinkLabel(myReferenceName + HASH + id);
|
myModelReader.addHyperlinkLabel(myReferenceName + HASH + id);
|
||||||
|
@ -538,69 +503,242 @@ void XHTMLReader::startElementHandler(const char *tag, const char **attributes)
|
||||||
const std::string sTag = ZLUnicodeUtil::toLower(tag);
|
const std::string sTag = ZLUnicodeUtil::toLower(tag);
|
||||||
myElementStack.push_back(StyleSheetTable::Element(sTag, klass, id));
|
myElementStack.push_back(StyleSheetTable::Element(sTag, klass, id));
|
||||||
|
|
||||||
StyleSheetTable::Style cssStyle;
|
myStyleStack.resize(myStyleStack.size() + 1);
|
||||||
myStyleSheetTable.applyStyles(myElementStack, cssStyle);
|
StyleSheetTable::Style *style = &myStyleStack.back();
|
||||||
if (style != 0) {
|
if (myStyleStack.size() > 1) {
|
||||||
cssStyle.apply(myStyleParser.parseString(style));
|
style->inherit(myStyleStack.at(myStyleStack.size()-2));
|
||||||
}
|
|
||||||
if (cssStyle.PageBreakBefore == B3_TRUE) {
|
|
||||||
myModelReader.insertEndOfSectionParagraph();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int opacity = myOpacityStack.empty() ? 255 : myOpacityStack.back();
|
myStyleSheetTable.applyStyles(myElementStack, *style);
|
||||||
if (cssStyle.TextStyle.opacitySupported()) {
|
if (inlineStyle) {
|
||||||
opacity *= cssStyle.TextStyle.opacity();
|
style->apply(myStyleParser.parseString(inlineStyle));
|
||||||
|
}
|
||||||
|
|
||||||
|
myParseStack.resize(myParseStack.size() + 1);
|
||||||
|
ParseContext &prev(myParseStack.at(myParseStack.size()-2));
|
||||||
|
ParseContext &context(myParseStack.back());
|
||||||
|
if (style->TextStyle.opacitySupported()) {
|
||||||
|
int opacity = prev.opacity;
|
||||||
|
opacity *= style->TextStyle.opacity();
|
||||||
opacity /= 255;
|
opacity /= 255;
|
||||||
|
context.opacity = opacity;
|
||||||
|
} else {
|
||||||
|
context.opacity = prev.opacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
myStyleStack.push_back(cssStyle);
|
// Don't collect empty styles
|
||||||
myElementHasContents.push_back(false);
|
if (style->empty()) {
|
||||||
myOpacityStack.push_back((unsigned char)opacity);
|
myStyleStack.resize(myStyleStack.size()-1);
|
||||||
|
style = NULL;
|
||||||
|
} else {
|
||||||
|
context.styleIndex = myStyleStack.size() - 1;
|
||||||
|
if (style->PageBreakBefore == B3_TRUE) {
|
||||||
|
addPageBreak();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XHTMLTagAction *action = ourTagActions[sTag];
|
XHTMLTagAction *action = ourTagActions[sTag];
|
||||||
if (action != 0) {
|
if (action != 0) {
|
||||||
action->doAtStart(*this, attributes);
|
action->doAtStart(*this, attributes);
|
||||||
}
|
}
|
||||||
|
|
||||||
myModelReader.addControl(cssStyle.TextStyle);
|
if (context.kind >= 0) {
|
||||||
|
context.decoration = ZLTextStyleCollection::Instance().decoration(context.kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (myModelReader.paragraphIsOpen()) {
|
||||||
|
applyStyles(myParseStack.back());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::endElementHandler(const char *tag) {
|
void XHTMLReader::endElementHandler(const char *tag) {
|
||||||
myModelReader.addControl(REGULAR, false);
|
bool pageBreak = false;
|
||||||
|
ParseContext &context(myParseStack.back());
|
||||||
|
if (context.styleIndex >= 0) {
|
||||||
|
if (myStyleStack[context.styleIndex].PageBreakAfter == B3_TRUE) {
|
||||||
|
// If we are about to have a page break, we don't want
|
||||||
|
// endParagraph() to apply pending bottom margins.
|
||||||
|
myBottomMargins.resize(0);
|
||||||
|
pageBreak = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
XHTMLTagAction *action = ourTagActions[ZLUnicodeUtil::toLower(tag)];
|
XHTMLTagAction *action = ourTagActions[ZLUnicodeUtil::toLower(tag)];
|
||||||
if (action != 0) {
|
if (action != 0) {
|
||||||
action->doAtEnd(*this);
|
action->doAtEnd(*this);
|
||||||
myNewParagraphInProgress = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool haveContents = myElementHasContents.back();
|
if (pageBreak) {
|
||||||
if (myStyleStack.back().PageBreakAfter == B3_TRUE && haveContents) {
|
addPageBreak();
|
||||||
myModelReader.insertEndOfSectionParagraph();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (myModelReader.paragraphIsOpen()) {
|
||||||
|
if (context.styleIndex >= 0) {
|
||||||
|
myModelReader.addControl(REGULAR, false);
|
||||||
|
}
|
||||||
|
if (context.kind >= 0) {
|
||||||
|
myModelReader.addControl((FBTextKind)context.kind, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!context.bottomMarginApplied && elementHasBottomMargin(context)) {
|
||||||
|
ZLTextStyleEntry::SizeUnit unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
||||||
|
short size = 0;
|
||||||
|
if (context.styleIndex >= 0 && myStyleStack[context.styleIndex].TextStyle.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER)) {
|
||||||
|
size = myStyleStack[context.styleIndex].TextStyle.length(ZLTextStyleEntry::LENGTH_SPACE_AFTER, unit);
|
||||||
|
} else if (context.decoration) {
|
||||||
|
const ZLTextFullStyleDecoration *decoration = context.decoration->fullDecoration();
|
||||||
|
if (decoration) {
|
||||||
|
size = decoration->SpaceAfterOption.value();
|
||||||
|
unit = decoration->SpaceAfterOptionUnit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (size > 0) {
|
||||||
|
addBottomMargin(size, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!myModelReader.paragraphIsOpen()) {
|
||||||
|
applyBottomMargins();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (context.styleIndex >= 0) {
|
||||||
|
myStyleStack.pop_back();
|
||||||
|
}
|
||||||
myElementStack.pop_back();
|
myElementStack.pop_back();
|
||||||
myStyleStack.pop_back();
|
myParseStack.pop_back();
|
||||||
myElementHasContents.pop_back();
|
}
|
||||||
myOpacityStack.pop_back();
|
|
||||||
|
|
||||||
if (!myElementHasContents.empty() && haveContents) {
|
void XHTMLReader::addPageBreak() {
|
||||||
myElementHasContents.back() = true;
|
myBottomMargins.resize(0);
|
||||||
|
endParagraph();
|
||||||
|
myModelReader.insertEndOfSectionParagraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLReader::addBottomMargin(short size, ZLTextStyleEntry::SizeUnit unit) {
|
||||||
|
for (std::vector<ZLTextStyleEntry>::iterator it = myBottomMargins.begin(); it != myBottomMargins.end(); ++it) {
|
||||||
|
ZLTextStyleEntry::SizeUnit entryUnit;
|
||||||
|
short entrySize = it->length(ZLTextStyleEntry::LENGTH_SPACE_AFTER, entryUnit);
|
||||||
|
if (entryUnit == unit) {
|
||||||
|
it->setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, entrySize + size, unit);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// No such unit yet
|
||||||
|
myBottomMargins.resize(myBottomMargins.size()+1);
|
||||||
|
myBottomMargins.back().setLength(ZLTextStyleEntry::LENGTH_SPACE_AFTER, size, unit);
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLReader::applyBottomMargins() {
|
||||||
|
if (!myBottomMargins.empty()) {
|
||||||
|
myModelReader.endParagraph();
|
||||||
|
for (std::vector<ZLTextStyleEntry>::const_iterator it = myBottomMargins.begin(); it != myBottomMargins.end(); ++it) {
|
||||||
|
addStyleParagraph(*it);
|
||||||
|
}
|
||||||
|
myBottomMargins.resize(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XHTMLReader::elementHasTopMargin(const ParseContext &context) const {
|
||||||
|
return
|
||||||
|
(context.styleIndex >= 0 && myStyleStack[context.styleIndex].TextStyle.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE)) ||
|
||||||
|
(context.decoration && context.decoration->fullDecoration());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool XHTMLReader::elementHasBottomMargin(const ParseContext &context) const {
|
||||||
|
return
|
||||||
|
(context.styleIndex >= 0 && myStyleStack[context.styleIndex].TextStyle.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER)) ||
|
||||||
|
(context.decoration && context.decoration->fullDecoration());
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLReader::addStyleParagraph(const ZLTextStyleEntry &style) {
|
||||||
|
myModelReader.beginParagraph();
|
||||||
|
myModelReader.addControl(style);
|
||||||
|
myModelReader.addEmpty();
|
||||||
|
myModelReader.endParagraph();
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLReader::applyStyles(ParseContext &context) {
|
||||||
|
if (!context.stylesApplied) {
|
||||||
|
context.stylesApplied = true;
|
||||||
|
if (context.kind >= 0) {
|
||||||
|
myModelReader.addControl((FBTextKind)context.kind, true);
|
||||||
|
}
|
||||||
|
if (context.styleIndex >= 0) {
|
||||||
|
myModelReader.addControl(myStyleStack[context.styleIndex].TextStyle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::beginParagraph() {
|
void XHTMLReader::beginParagraph() {
|
||||||
myCurrentParagraphIsEmpty = true;
|
if (!myModelReader.paragraphIsOpen()) {
|
||||||
myModelReader.beginParagraph();
|
myModelReader.beginParagraph();
|
||||||
if (!myStyleStack.empty()) {
|
for (std::vector<ParseContext>::iterator it = myParseStack.begin(); it != myParseStack.end(); ++it) {
|
||||||
for (StyleSheetTable::StyleList::const_iterator it = myStyleStack.begin(); it != myStyleStack.end(); ++it) {
|
applyStyles(*it);
|
||||||
myModelReader.addControl(((*it).TextStyle));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::endParagraph() {
|
void XHTMLReader::endParagraph() {
|
||||||
myModelReader.endParagraph();
|
if (myModelReader.paragraphIsOpen()) {
|
||||||
|
myModelReader.endParagraph();
|
||||||
|
|
||||||
|
// Find which bottom margins have been applied
|
||||||
|
// and at the same time reset stylesApplied flag.
|
||||||
|
std::vector<ParseContext>::reverse_iterator it = myParseStack.rbegin();
|
||||||
|
for (; it != myParseStack.rend(); ++it) {
|
||||||
|
it->stylesApplied = false;
|
||||||
|
if (elementHasBottomMargin(*it)) {
|
||||||
|
it->bottomMarginApplied = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset stylesApplied for the remaining entries
|
||||||
|
for (; it != myParseStack.rend(); ++it) {
|
||||||
|
it->stylesApplied = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply pending bottom margins
|
||||||
|
applyBottomMargins();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void XHTMLReader::haveContent() {
|
||||||
|
if (!myParseStack.back().haveContent) {
|
||||||
|
// Create empty paragraphs for other parent entries that haven't
|
||||||
|
// had any content yet, in order to apply their top margins. Skip
|
||||||
|
// the last entry as it will be applied for the paragraph we are
|
||||||
|
// about to start.
|
||||||
|
bool skippedLastEntry = false;
|
||||||
|
for (std::vector<ParseContext>::reverse_iterator it = myParseStack.rbegin(); it != myParseStack.rend() && !it->haveContent; ++it) {
|
||||||
|
it->haveContent = true;
|
||||||
|
if (elementHasTopMargin(*it)) {
|
||||||
|
if (!skippedLastEntry) {
|
||||||
|
skippedLastEntry = true;
|
||||||
|
} else {
|
||||||
|
ZLTextStyleEntry::SizeUnit unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
||||||
|
short size = 0;
|
||||||
|
if (it->styleIndex >= 0 && myStyleStack[it->styleIndex].TextStyle.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE)) {
|
||||||
|
size = myStyleStack[it->styleIndex].TextStyle.length(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, unit);
|
||||||
|
} else if (it->decoration) {
|
||||||
|
const ZLTextFullStyleDecoration *decoration = it->decoration->fullDecoration();
|
||||||
|
if (decoration) {
|
||||||
|
size = decoration->SpaceBeforeOption.value();
|
||||||
|
unit = decoration->SpaceBeforeOptionUnit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (size > 0) {
|
||||||
|
ZLTextStyleEntry style;
|
||||||
|
style.setLength(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, size, unit);
|
||||||
|
addStyleParagraph(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
myBottomMargins.resize(0);
|
||||||
|
beginParagraph();
|
||||||
}
|
}
|
||||||
|
|
||||||
void XHTMLReader::characterDataHandler(const char *text, size_t len) {
|
void XHTMLReader::characterDataHandler(const char *text, size_t len) {
|
||||||
|
@ -613,34 +751,49 @@ void XHTMLReader::characterDataHandler(const char *text, size_t len) {
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case READ_BODY:
|
case READ_BODY:
|
||||||
if (myOpacityStack.back()) {
|
if (myParseStack.back().opacity && !myStyleStack.empty() && !myStyleStack.back().DisplayNone) {
|
||||||
if (myPreformatted) {
|
const StyleSheetTable::WhiteSpaceValue whiteSpace = myStyleStack.back().WhiteSpace;
|
||||||
if ((*text == '\r') || (*text == '\n')) {
|
if (myPreformatted || whiteSpace == StyleSheetTable::WS_PRE || whiteSpace == StyleSheetTable::WS_PRE_WRAP) {
|
||||||
myModelReader.addLineBreak();
|
|
||||||
}
|
|
||||||
size_t spaceCounter = 0;
|
size_t spaceCounter = 0;
|
||||||
while ((spaceCounter < len) && isspace((unsigned char)*(text + spaceCounter))) {
|
while (len > 0 && isspace(*text)) {
|
||||||
++spaceCounter;
|
if (*text == '\n') {
|
||||||
}
|
haveContent();
|
||||||
myModelReader.addFixedHSpace(spaceCounter);
|
if (spaceCounter) {
|
||||||
text += spaceCounter;
|
myModelReader.addFixedHSpace(spaceCounter);
|
||||||
len -= spaceCounter;
|
spaceCounter = 0;
|
||||||
} else if ((myNewParagraphInProgress) || !myModelReader.paragraphIsOpen()) {
|
}
|
||||||
while (isspace((unsigned char)*text)) {
|
myModelReader.addLineBreak();
|
||||||
|
} else if (*text != '\r') {
|
||||||
|
spaceCounter++;
|
||||||
|
}
|
||||||
++text;
|
++text;
|
||||||
if (--len == 0) {
|
--len;
|
||||||
|
}
|
||||||
|
if (spaceCounter) {
|
||||||
|
haveContent();
|
||||||
|
myModelReader.addFixedHSpace(spaceCounter);
|
||||||
|
}
|
||||||
|
} else if (!myModelReader.paragraphIsOpen()) {
|
||||||
|
while (len > 0 && isspace(*text)) {
|
||||||
|
switch (whiteSpace) {
|
||||||
|
case StyleSheetTable::WS_PRE:
|
||||||
|
case StyleSheetTable::WS_PRE_WRAP:
|
||||||
|
case StyleSheetTable::WS_PRE_LINE:
|
||||||
|
if (*text == '\n') {
|
||||||
|
haveContent();
|
||||||
|
myModelReader.addLineBreak();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
++text;
|
||||||
|
--len;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
myCurrentParagraphIsEmpty = false;
|
haveContent();
|
||||||
myElementHasContents.back() = true;
|
|
||||||
if (!myModelReader.paragraphIsOpen()) {
|
|
||||||
myModelReader.beginParagraph();
|
|
||||||
}
|
|
||||||
myModelReader.addData(std::string(text, len));
|
myModelReader.addData(std::string(text, len));
|
||||||
myNewParagraphInProgress = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -25,11 +25,13 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <ZLXMLReader.h>
|
#include <ZLXMLReader.h>
|
||||||
|
#include <ZLTextParagraph.h>
|
||||||
|
|
||||||
#include "../css/StyleSheetTable.h"
|
#include "../css/StyleSheetTable.h"
|
||||||
#include "../css/StyleSheetParser.h"
|
#include "../css/StyleSheetParser.h"
|
||||||
|
|
||||||
class ZLFile;
|
class ZLFile;
|
||||||
|
class ZLTextStyleDecoration;
|
||||||
|
|
||||||
class BookReader;
|
class BookReader;
|
||||||
class XHTMLReader;
|
class XHTMLReader;
|
||||||
|
@ -63,7 +65,18 @@ public:
|
||||||
bool readFile(const ZLFile &file, const std::string &referenceName);
|
bool readFile(const ZLFile &file, const std::string &referenceName);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void startElementHandler(const char *tag, const char **attributes);
|
struct ParseContext {
|
||||||
|
int kind;
|
||||||
|
int styleIndex;
|
||||||
|
unsigned char opacity;
|
||||||
|
bool haveContent;
|
||||||
|
bool stylesApplied;
|
||||||
|
bool bottomMarginApplied;
|
||||||
|
const ZLTextStyleDecoration *decoration;
|
||||||
|
ParseContext() : kind(-1), styleIndex(-1), opacity(255), haveContent(false), stylesApplied(false), bottomMarginApplied(false), decoration(NULL) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
void startElementHandler(const char *tag, const char **attributes);
|
||||||
void endElementHandler(const char *tag);
|
void endElementHandler(const char *tag);
|
||||||
void characterDataHandler(const char *text, size_t len);
|
void characterDataHandler(const char *text, size_t len);
|
||||||
|
|
||||||
|
@ -71,9 +84,16 @@ private:
|
||||||
|
|
||||||
bool processNamespaces() const;
|
bool processNamespaces() const;
|
||||||
|
|
||||||
void beginParagraph();
|
void haveContent();
|
||||||
|
void beginParagraph();
|
||||||
void endParagraph();
|
void endParagraph();
|
||||||
static shared_ptr<ZLTextStyleEntry> addStyleEntry(shared_ptr<ZLTextStyleEntry> entry, shared_ptr<ZLTextStyleEntry> styleEntry);
|
void applyStyles(ParseContext &context);
|
||||||
|
void addStyleParagraph(const ZLTextStyleEntry &style);
|
||||||
|
void addBottomMargin(short size, ZLTextStyleEntry::SizeUnit unit);
|
||||||
|
bool elementHasTopMargin(const ParseContext &context) const;
|
||||||
|
bool elementHasBottomMargin(const ParseContext &context) const;
|
||||||
|
void applyBottomMargins();
|
||||||
|
void addPageBreak();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BookReader &myModelReader;
|
BookReader &myModelReader;
|
||||||
|
@ -81,13 +101,11 @@ private:
|
||||||
std::string myReferenceName;
|
std::string myReferenceName;
|
||||||
std::string myReferenceDirName;
|
std::string myReferenceDirName;
|
||||||
int myPreformatted;
|
int myPreformatted;
|
||||||
bool myNewParagraphInProgress;
|
|
||||||
StyleSheetTable myStyleSheetTable;
|
StyleSheetTable myStyleSheetTable;
|
||||||
StyleSheetTable::ElementList myElementStack;
|
StyleSheetTable::ElementList myElementStack;
|
||||||
StyleSheetTable::StyleList myStyleStack;
|
StyleSheetTable::StyleList myStyleStack;
|
||||||
std::vector<unsigned char> myOpacityStack;
|
std::vector<ParseContext> myParseStack;
|
||||||
std::vector<bool> myElementHasContents;
|
std::vector<ZLTextStyleEntry> myBottomMargins;
|
||||||
bool myCurrentParagraphIsEmpty;
|
|
||||||
StyleSheetSingleStyleParser myStyleParser;
|
StyleSheetSingleStyleParser myStyleParser;
|
||||||
shared_ptr<StyleSheetTableParser> myTableParser;
|
shared_ptr<StyleSheetTableParser> myTableParser;
|
||||||
enum {
|
enum {
|
||||||
|
@ -97,13 +115,13 @@ private:
|
||||||
} myReadState;
|
} myReadState;
|
||||||
|
|
||||||
friend class XHTMLTagAction;
|
friend class XHTMLTagAction;
|
||||||
friend class XHTMLTagStyleAction;
|
friend class XHTMLTagStyleAction;
|
||||||
friend class XHTMLTagLinkAction;
|
friend class XHTMLTagLinkAction;
|
||||||
friend class XHTMLTagHyperlinkAction;
|
friend class XHTMLTagHyperlinkAction;
|
||||||
friend class XHTMLTagPreAction;
|
friend class XHTMLTagPreAction;
|
||||||
friend class XHTMLTagParagraphAction;
|
friend class XHTMLTagControlAction;
|
||||||
friend class XHTMLTagBodyAction;
|
friend class XHTMLTagParagraphWithControlAction;
|
||||||
friend class XHTMLTagRestartParagraphAction;
|
friend class XHTMLTagBodyAction;
|
||||||
friend class XHTMLTagImageAction;
|
friend class XHTMLTagImageAction;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,14 @@ bool ZLStringUtil::stringStartsWith(const std::string &str, const std::string &s
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ZLStringUtil::caseInsensitiveEqual(const std::string &str1, const std::string &str2) {
|
||||||
|
return !strcasecmp(str1.c_str(), str2.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZLStringUtil::caseInsensitiveSort(const std::string &str1, const std::string &str2) {
|
||||||
|
return strcasecmp(str1.c_str(), str2.c_str()) < 0;
|
||||||
|
}
|
||||||
|
|
||||||
void ZLStringUtil::appendNumber(std::string &str, unsigned int n) {
|
void ZLStringUtil::appendNumber(std::string &str, unsigned int n) {
|
||||||
int len;
|
int len;
|
||||||
if (n > 0) {
|
if (n > 0) {
|
||||||
|
@ -75,20 +83,29 @@ void ZLStringUtil::append(std::string &str, const std::vector<std::string> &text
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLStringUtil::stripWhiteSpaces(std::string &str) {
|
// Returns true if there's anything left
|
||||||
size_t counter = 0;
|
bool ZLStringUtil::stripWhiteSpaces(std::string &str) {
|
||||||
size_t length = str.length();
|
const size_t old_length = str.length();
|
||||||
while ((counter < length) && isspace((unsigned char)str[counter])) {
|
if (old_length > 0) {
|
||||||
counter++;
|
size_t end = old_length;
|
||||||
}
|
while ((end > 0) && isspace((unsigned char)str[end - 1])) {
|
||||||
str.erase(0, counter);
|
end--;
|
||||||
length -= counter;
|
}
|
||||||
|
if (end < old_length) {
|
||||||
|
str.erase(end, old_length - end);
|
||||||
|
}
|
||||||
|
|
||||||
size_t r_counter = length;
|
size_t start = 0;
|
||||||
while ((r_counter > 0) && isspace((unsigned char)str[r_counter - 1])) {
|
while ((start < end) && isspace((unsigned char)str[start])) {
|
||||||
r_counter--;
|
start++;
|
||||||
|
}
|
||||||
|
if (start > 0) {
|
||||||
|
str.erase(0, start);
|
||||||
|
}
|
||||||
|
return !str.empty();
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
str.erase(r_counter, length - r_counter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> ZLStringUtil::splitString(const char *str, const char* delim) {
|
std::vector<std::string> ZLStringUtil::splitString(const char *str, const char* delim) {
|
||||||
|
@ -106,6 +123,14 @@ std::vector<std::string> ZLStringUtil::splitString(const char *str, const char*
|
||||||
return tokens;
|
return tokens;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZLStringUtil::replaceAll(std::string &str, const std::string &find, const std::string &replaceWith) {
|
||||||
|
size_t pos = 0;
|
||||||
|
while ((pos == str.find(find, pos)) != std::string::npos) {
|
||||||
|
str.replace(pos, find.length(), replaceWith);
|
||||||
|
pos += replaceWith.length();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
std::string ZLStringUtil::printf(const std::string &format, const std::string &arg0) {
|
std::string ZLStringUtil::printf(const std::string &format, const std::string &arg0) {
|
||||||
int index = format.find("%s");
|
int index = format.find("%s");
|
||||||
if (index == -1) {
|
if (index == -1) {
|
||||||
|
|
|
@ -31,11 +31,15 @@ private:
|
||||||
public:
|
public:
|
||||||
static bool stringStartsWith(const std::string &str, const std::string &start);
|
static bool stringStartsWith(const std::string &str, const std::string &start);
|
||||||
static bool stringEndsWith(const std::string &str, const std::string &end);
|
static bool stringEndsWith(const std::string &str, const std::string &end);
|
||||||
|
static bool endsWith(const std::string &str, char c);
|
||||||
|
static bool caseInsensitiveEqual(const std::string &str1, const std::string &str2);
|
||||||
|
static bool caseInsensitiveSort(const std::string &str1, const std::string &str2);
|
||||||
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 bool stripWhiteSpaces(std::string &str);
|
||||||
static std::vector<std::string> splitString(const char *str, const char* delim);
|
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 void replaceAll(std::string &str, const std::string &find, const std::string &replaceWith);
|
||||||
|
|
||||||
static std::string printf(const std::string &format, const std::string &arg0);
|
static std::string printf(const std::string &format, const std::string &arg0);
|
||||||
|
|
||||||
|
@ -46,5 +50,7 @@ public:
|
||||||
inline std::vector<std::string> ZLStringUtil::splitString(const std::string &str, const char* delim) {
|
inline std::vector<std::string> ZLStringUtil::splitString(const std::string &str, const char* delim) {
|
||||||
return ZLStringUtil::splitString(str.c_str(), delim);
|
return ZLStringUtil::splitString(str.c_str(), delim);
|
||||||
}
|
}
|
||||||
|
inline bool ZLStringUtil::endsWith(const std::string &str, char c) {
|
||||||
|
return !str.empty() && str[str.length()-1] == c;
|
||||||
|
}
|
||||||
#endif /* __ZLSTRINGUTIL_H__ */
|
#endif /* __ZLSTRINGUTIL_H__ */
|
||||||
|
|
|
@ -18,6 +18,10 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "ZLPaintContext.h"
|
#include "ZLPaintContext.h"
|
||||||
|
#include "ZLStringUtil.h"
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <strings.h>
|
||||||
|
|
||||||
ZLPaintContext::ZLPaintContext() {
|
ZLPaintContext::ZLPaintContext() {
|
||||||
}
|
}
|
||||||
|
@ -25,9 +29,29 @@ ZLPaintContext::ZLPaintContext() {
|
||||||
ZLPaintContext::~ZLPaintContext() {
|
ZLPaintContext::~ZLPaintContext() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ZLPaintContext::pickFontFamily(const std::vector<std::string> &fonts) const
|
||||||
|
{
|
||||||
|
if (!fonts.empty()) {
|
||||||
|
if (fonts.size() > 1) {
|
||||||
|
const std::vector<std::string> &available = fontFamilies();
|
||||||
|
for (std::vector<std::string>::const_iterator it = fonts.begin(); it != fonts.end(); ++it) {
|
||||||
|
const std::vector<std::string>::const_iterator found =
|
||||||
|
std::lower_bound(available.begin(), available.end(), *it,
|
||||||
|
ZLStringUtil::caseInsensitiveSort);
|
||||||
|
if (found != available.end() && ZLStringUtil::caseInsensitiveEqual(*found, *it)) {
|
||||||
|
return *found;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fonts.front();
|
||||||
|
}
|
||||||
|
return std::string();
|
||||||
|
}
|
||||||
|
|
||||||
const std::vector<std::string> &ZLPaintContext::fontFamilies() const {
|
const std::vector<std::string> &ZLPaintContext::fontFamilies() const {
|
||||||
if (myFamilies.empty()) {
|
if (myFamilies.empty()) {
|
||||||
fillFamiliesList(myFamilies);
|
fillFamiliesList(myFamilies);
|
||||||
|
std::sort(myFamilies.begin(), myFamilies.end(), ZLStringUtil::caseInsensitiveSort);
|
||||||
}
|
}
|
||||||
return myFamilies;
|
return myFamilies;
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
virtual void fillRectangle(int x0, int y0, int x1, int y1) = 0;
|
virtual void fillRectangle(int x0, int y0, int x1, int y1) = 0;
|
||||||
virtual void drawFilledCircle(int x, int y, int r) = 0;
|
virtual void drawFilledCircle(int x, int y, int r) = 0;
|
||||||
|
|
||||||
|
std::string pickFontFamily(const std::vector<std::string> & fonts) const;
|
||||||
const std::vector<std::string> &fontFamilies() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
virtual const std::string realFontFamilyName(std::string &fontFamily) const = 0;
|
virtual const std::string realFontFamilyName(std::string &fontFamily) const = 0;
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
ZLTextArea::Style::Style(const ZLTextArea &area, shared_ptr<ZLTextStyle> style) : myArea(area) {
|
ZLTextArea::Style::Style(const ZLTextArea &area, shared_ptr<ZLTextStyle> style) : myArea(area) {
|
||||||
myTextStyle = style;
|
myTextStyle = style;
|
||||||
myWordHeight = -1;
|
myWordHeight = -1;
|
||||||
myArea.context().setFont(myTextStyle->fontFamily(), myTextStyle->fontSize(), myTextStyle->bold(), myTextStyle->italic());
|
myArea.context().setFont(myArea.context().pickFontFamily(myTextStyle->fontFamilies()), myTextStyle->fontSize(), myTextStyle->bold(), myTextStyle->italic());
|
||||||
myBidiLevel = myArea.isRtl() ? 1 : 0;
|
myBidiLevel = myArea.isRtl() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ void ZLTextArea::Style::setTextStyle(shared_ptr<ZLTextStyle> style, unsigned cha
|
||||||
myTextStyle = style;
|
myTextStyle = style;
|
||||||
myWordHeight = -1;
|
myWordHeight = -1;
|
||||||
}
|
}
|
||||||
myArea.context().setFont(myTextStyle->fontFamily(), myTextStyle->fontSize(), myTextStyle->bold(), myTextStyle->italic());
|
myArea.context().setFont(myArea.context().pickFontFamily(myTextStyle->fontFamilies()), myTextStyle->fontSize(), myTextStyle->bold(), myTextStyle->italic());
|
||||||
myBidiLevel = bidiLevel;
|
myBidiLevel = bidiLevel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,6 +108,7 @@ int ZLTextArea::Style::elementWidth(const ZLTextElement &element, unsigned int c
|
||||||
case ZLTextElement::CONTROL_ELEMENT:
|
case ZLTextElement::CONTROL_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:
|
||||||
|
case ZLTextElement::EMPTY_ELEMENT:
|
||||||
return 0;
|
return 0;
|
||||||
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
||||||
return myArea.context().spaceWidth() * ((const ZLTextFixedHSpaceElement&)element).length();
|
return myArea.context().spaceWidth() * ((const ZLTextFixedHSpaceElement&)element).length();
|
||||||
|
@ -119,6 +120,8 @@ int ZLTextArea::Style::elementHeight(const ZLTextElement &element, const ZLTextS
|
||||||
switch (element.kind()) {
|
switch (element.kind()) {
|
||||||
case ZLTextElement::NB_HSPACE_ELEMENT:
|
case ZLTextElement::NB_HSPACE_ELEMENT:
|
||||||
case ZLTextElement::WORD_ELEMENT:
|
case ZLTextElement::WORD_ELEMENT:
|
||||||
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
if (myWordHeight == -1) {
|
if (myWordHeight == -1) {
|
||||||
myWordHeight = myArea.context().stringHeight() * textStyle()->lineSpacePercent() / 100 + textStyle()->verticalShift();
|
myWordHeight = myArea.context().stringHeight() * textStyle()->lineSpacePercent() / 100 + textStyle()->verticalShift();
|
||||||
}
|
}
|
||||||
|
@ -131,9 +134,6 @@ int ZLTextArea::Style::elementHeight(const ZLTextElement &element, const ZLTextS
|
||||||
return - textStyle()->spaceAfter(metrics);
|
return - textStyle()->spaceAfter(metrics);
|
||||||
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::LINE_BREAK_ELEMENT:
|
|
||||||
return myArea.context().stringHeight();
|
|
||||||
case ZLTextElement::INDENT_ELEMENT:
|
case ZLTextElement::INDENT_ELEMENT:
|
||||||
case ZLTextElement::HSPACE_ELEMENT:
|
case ZLTextElement::HSPACE_ELEMENT:
|
||||||
case ZLTextElement::FORCED_CONTROL_ELEMENT:
|
case ZLTextElement::FORCED_CONTROL_ELEMENT:
|
||||||
|
@ -141,6 +141,7 @@ int ZLTextArea::Style::elementHeight(const ZLTextElement &element, const ZLTextS
|
||||||
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
case ZLTextElement::FIXED_HSPACE_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:
|
||||||
|
case ZLTextElement::EMPTY_ELEMENT:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -167,6 +167,7 @@ void ZLTextArea::prepareTextLine(Style &style, const ZLTextLineInfo &info, int y
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
case ZLTextElement::LINE_BREAK_ELEMENT:
|
case ZLTextElement::LINE_BREAK_ELEMENT:
|
||||||
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
case ZLTextElement::FIXED_HSPACE_ELEMENT:
|
||||||
|
case ZLTextElement::EMPTY_ELEMENT:
|
||||||
break;
|
break;
|
||||||
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
case ZLTextElement::START_REVERSED_SEQUENCE_ELEMENT:
|
||||||
//context().setColor(ZLColor(0, 255, 0));
|
//context().setColor(ZLColor(0, 255, 0));
|
||||||
|
|
|
@ -170,6 +170,7 @@ ZLTextLineInfoPtr ZLTextArea::processTextLine(Style &style, const ZLTextWordCurs
|
||||||
newInfo.Width += lastSpaceWidth;
|
newInfo.Width += lastSpaceWidth;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case ZLTextElement::EMPTY_ELEMENT:
|
||||||
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
case ZLTextElement::EMPTY_LINE_ELEMENT:
|
||||||
newInfo.IsVisible = true;
|
newInfo.IsVisible = true;
|
||||||
break;
|
break;
|
||||||
|
@ -178,6 +179,7 @@ ZLTextLineInfoPtr ZLTextArea::processTextLine(Style &style, const ZLTextWordCurs
|
||||||
}
|
}
|
||||||
|
|
||||||
if (elementKind == ZLTextElement::LINE_BREAK_ELEMENT) {
|
if (elementKind == ZLTextElement::LINE_BREAK_ELEMENT) {
|
||||||
|
newInfo.IsVisible = true;
|
||||||
newInfo.End.nextWord();
|
newInfo.End.nextWord();
|
||||||
newInfo.setTo(info);
|
newInfo.setTo(info);
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -48,6 +48,7 @@ public:
|
||||||
LINE_BREAK_ELEMENT,
|
LINE_BREAK_ELEMENT,
|
||||||
START_REVERSED_SEQUENCE_ELEMENT,
|
START_REVERSED_SEQUENCE_ELEMENT,
|
||||||
END_REVERSED_SEQUENCE_ELEMENT,
|
END_REVERSED_SEQUENCE_ELEMENT,
|
||||||
|
EMPTY_ELEMENT
|
||||||
};
|
};
|
||||||
|
|
||||||
virtual Kind kind() const = 0;
|
virtual Kind kind() const = 0;
|
||||||
|
|
|
@ -111,6 +111,9 @@ void ZLTextParagraphCursor::Builder::fill() {
|
||||||
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
||||||
myElements.push_back(myTextElementPool.LineBreakElement);
|
myElements.push_back(myTextElementPool.LineBreakElement);
|
||||||
break;
|
break;
|
||||||
|
case ZLTextParagraphEntry::EMPTY_ENTRY:
|
||||||
|
myElements.push_back(myTextElementPool.EmptyElement);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,6 +49,7 @@ ZLTextElementVector::~ZLTextElementVector() {
|
||||||
case ZLTextElement::LINE_BREAK_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:
|
||||||
|
case ZLTextElement::EMPTY_ELEMENT:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -63,6 +64,7 @@ ZLTextElementPool::ZLTextElementPool() {
|
||||||
LineBreakElement = new ZLTextSpecialElement(ZLTextElement::LINE_BREAK_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);
|
||||||
|
EmptyElement = new ZLTextSpecialElement(ZLTextElement::EMPTY_ELEMENT);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextElementPool::~ZLTextElementPool() {
|
ZLTextElementPool::~ZLTextElementPool() {
|
||||||
|
@ -74,6 +76,7 @@ ZLTextElementPool::~ZLTextElementPool() {
|
||||||
delete LineBreakElement;
|
delete LineBreakElement;
|
||||||
delete StartReversedSequenceElement;
|
delete StartReversedSequenceElement;
|
||||||
delete EndReversedSequenceElement;
|
delete EndReversedSequenceElement;
|
||||||
|
delete EmptyElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextParagraphCursorPtr ZLTextParagraphCursorCache::cursor(const ZLTextModel &model, size_t index) {
|
ZLTextParagraphCursorPtr ZLTextParagraphCursorCache::cursor(const ZLTextModel &model, size_t index) {
|
||||||
|
|
|
@ -65,6 +65,7 @@ public:
|
||||||
ZLTextElement *LineBreakElement;
|
ZLTextElement *LineBreakElement;
|
||||||
ZLTextElement *StartReversedSequenceElement;
|
ZLTextElement *StartReversedSequenceElement;
|
||||||
ZLTextElement *EndReversedSequenceElement;
|
ZLTextElement *EndReversedSequenceElement;
|
||||||
|
ZLTextElement *EmptyElement;
|
||||||
|
|
||||||
ZLTextWord *getWord(const char *data, unsigned short length, size_t paragraphOffset, unsigned char bidiLevel);
|
ZLTextWord *getWord(const char *data, unsigned short length, size_t paragraphOffset, unsigned char bidiLevel);
|
||||||
void storeWord(ZLTextWord *word);
|
void storeWord(ZLTextWord *word);
|
||||||
|
|
|
@ -215,43 +215,53 @@ void ZLTextModel::addControl(ZLTextKind textKind, bool isStart) {
|
||||||
|
|
||||||
void ZLTextModel::addControl(const ZLTextStyleEntry &entry) {
|
void ZLTextModel::addControl(const ZLTextStyleEntry &entry) {
|
||||||
int len = sizeof(int) + 2;
|
int len = sizeof(int) + 2;
|
||||||
if (entry.myMask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
const int mask = entry.myMask;
|
||||||
|
if (mask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
||||||
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
||||||
if (entry.myMask & (1 << i)) {
|
if (mask & (1 << i)) {
|
||||||
len += (sizeof(short) + 1);
|
len += (sizeof(short) + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.opacitySupported()) ++len;
|
if (mask & ZLTextStyleEntry::SUPPORT_OPACITY) ++len;
|
||||||
if (entry.alignmentTypeSupported()) ++len;
|
if (mask & ZLTextStyleEntry::SUPPORT_ALIGNMENT_TYPE) ++len;
|
||||||
if (entry.supportedFontModifier()) ++len;
|
if (entry.supportedFontModifier()) ++len;
|
||||||
if (entry.fontSizeSupported()) ++len;
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_SIZE) ++len;
|
||||||
if (entry.fontFamilySupported()) {
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILIES) {
|
||||||
len += entry.fontFamily().length() + 1;
|
const unsigned char n = entry.myFontFamilies.size();
|
||||||
|
len += 1; // Number of entries
|
||||||
|
for (unsigned int i = 0; i < n; ++i) {
|
||||||
|
len += entry.myFontFamilies.at(i).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;
|
*address++ = entry.mySupportedFontModifier;
|
||||||
memcpy(address, &entry.myMask, sizeof(int));
|
memcpy(address, &mask, sizeof(int));
|
||||||
address += sizeof(int);
|
address += sizeof(int);
|
||||||
if (entry.myMask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
if (mask & ((1 << ZLTextStyleEntry::NUMBER_OF_LENGTHS) - 1)) {
|
||||||
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
for (int i = 0; i < ZLTextStyleEntry::NUMBER_OF_LENGTHS; ++i) {
|
||||||
if (entry.myMask & (1 << i)) {
|
if (mask & (1 << i)) {
|
||||||
*address++ = entry.myLengths[i].Unit;
|
*address++ = entry.myLengths[i].Unit;
|
||||||
memcpy(address, &entry.myLengths[i].Size, sizeof(short));
|
memcpy(address, &entry.myLengths[i].Size, sizeof(short));
|
||||||
address += sizeof(short);
|
address += sizeof(short);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.opacitySupported()) *address++ = entry.myOpacity;
|
if (mask & ZLTextStyleEntry::SUPPORT_OPACITY) *address++ = entry.myOpacity;
|
||||||
if (entry.alignmentTypeSupported()) *address++ = entry.myAlignmentType;
|
if (mask & ZLTextStyleEntry::SUPPORT_ALIGNMENT_TYPE) *address++ = entry.myAlignmentType;
|
||||||
if (entry.supportedFontModifier()) *address++ = entry.myFontModifier;
|
if (entry.supportedFontModifier()) *address++ = entry.myFontModifier;
|
||||||
if (entry.fontSizeSupported()) *address++ = entry.myFontSizeMag;
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_SIZE) *address++ = entry.myFontSizeMag;
|
||||||
if (entry.fontFamilySupported()) {
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILIES) {
|
||||||
memcpy(address, entry.fontFamily().data(), entry.fontFamily().length());
|
const unsigned char n = entry.myFontFamilies.size();
|
||||||
address += entry.fontFamily().length();
|
*address++ = n;
|
||||||
*address++ = '\0';
|
for (unsigned int i = 0; i < n; ++i) {
|
||||||
|
const std::string &font = entry.myFontFamilies.at(i);
|
||||||
|
const unsigned int nbytes = font.length() + 1;
|
||||||
|
memcpy(address, font.c_str(), nbytes);
|
||||||
|
address += nbytes;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
myParagraphs.back()->addEntry(myLastEntryStart);
|
myParagraphs.back()->addEntry(myLastEntryStart);
|
||||||
}
|
}
|
||||||
|
@ -289,3 +299,9 @@ void ZLTextModel::addLineBreak() {
|
||||||
*myLastEntryStart = ZLTextParagraphEntry::LINE_BREAK_ENTRY;
|
*myLastEntryStart = ZLTextParagraphEntry::LINE_BREAK_ENTRY;
|
||||||
myParagraphs.back()->addEntry(myLastEntryStart);
|
myParagraphs.back()->addEntry(myLastEntryStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZLTextModel::addEmpty() {
|
||||||
|
myLastEntryStart = myAllocator.allocate(1);
|
||||||
|
*myLastEntryStart = ZLTextParagraphEntry::EMPTY_ENTRY;
|
||||||
|
myParagraphs.back()->addEntry(myLastEntryStart);
|
||||||
|
}
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
void addFixedHSpace(unsigned char length);
|
void addFixedHSpace(unsigned char length);
|
||||||
void addBidiReset();
|
void addBidiReset();
|
||||||
void addLineBreak();
|
void addLineBreak();
|
||||||
|
void addEmpty();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void addParagraphInternal(ZLTextParagraph *paragraph);
|
void addParagraphInternal(ZLTextParagraph *paragraph);
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include <ZLUnicodeUtil.h>
|
#include <ZLUnicodeUtil.h>
|
||||||
|
#include <ZLStringUtil.h>
|
||||||
#include <ZLImage.h>
|
#include <ZLImage.h>
|
||||||
|
|
||||||
#include "ZLTextParagraph.h"
|
#include "ZLTextParagraph.h"
|
||||||
|
@ -34,26 +35,46 @@ size_t ZLTextEntry::dataLength() const {
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
short ZLTextStyleEntry::length(Length name, const Metrics &metrics) const {
|
int ZLTextStyleEntry::hlength(int size, SizeUnit unit, const Metrics &metrics)
|
||||||
switch (myLengths[name].Unit) {
|
{
|
||||||
|
switch (unit) {
|
||||||
default:
|
default:
|
||||||
case SIZE_UNIT_PIXEL:
|
case SIZE_UNIT_PIXEL:
|
||||||
return myLengths[name].Size;
|
return size;
|
||||||
case SIZE_UNIT_EM_100:
|
case SIZE_UNIT_EM_100:
|
||||||
return (myLengths[name].Size * metrics.FontSize + 50) / 100;
|
return (size * metrics.FontSize + 50) / 100;
|
||||||
case SIZE_UNIT_EX_100:
|
case SIZE_UNIT_EX_100:
|
||||||
return (myLengths[name].Size * metrics.FontXHeight + 50) / 100;
|
return (size * metrics.FontXHeight + 50) / 100;
|
||||||
case SIZE_UNIT_PERCENT:
|
case SIZE_UNIT_PERCENT:
|
||||||
switch (name) {
|
return (size * metrics.FullWidth + 50) / 100;
|
||||||
default:
|
}
|
||||||
case LENGTH_LEFT_INDENT:
|
}
|
||||||
case LENGTH_RIGHT_INDENT:
|
|
||||||
case LENGTH_FIRST_LINE_INDENT_DELTA:
|
int ZLTextStyleEntry::vlength(int size, SizeUnit unit, const Metrics &metrics)
|
||||||
return (myLengths[name].Size * metrics.FullWidth + 50) / 100;
|
{
|
||||||
case LENGTH_SPACE_BEFORE:
|
switch (unit) {
|
||||||
case LENGTH_SPACE_AFTER:
|
default:
|
||||||
return (myLengths[name].Size * metrics.FullHeight + 50) / 100;
|
case SIZE_UNIT_PIXEL:
|
||||||
}
|
return size;
|
||||||
|
case SIZE_UNIT_EM_100:
|
||||||
|
return (size * metrics.FontSize + 50) / 100;
|
||||||
|
case SIZE_UNIT_EX_100:
|
||||||
|
return (size * metrics.FontXHeight + 50) / 100;
|
||||||
|
case SIZE_UNIT_PERCENT:
|
||||||
|
return (size * metrics.FullHeight + 50) / 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
short ZLTextStyleEntry::length(Length name, const Metrics &metrics) const {
|
||||||
|
switch (name) {
|
||||||
|
default:
|
||||||
|
case LENGTH_LEFT_INDENT:
|
||||||
|
case LENGTH_RIGHT_INDENT:
|
||||||
|
case LENGTH_FIRST_LINE_INDENT_DELTA:
|
||||||
|
return hlength(myLengths[name].Size, myLengths[name].Unit, metrics);
|
||||||
|
case LENGTH_SPACE_BEFORE:
|
||||||
|
case LENGTH_SPACE_AFTER:
|
||||||
|
return vlength(myLengths[name].Size, myLengths[name].Unit, metrics);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,43 +101,145 @@ ZLTextStyleEntry::ZLTextStyleEntry(char *address) {
|
||||||
if (fontSizeSupported()) {
|
if (fontSizeSupported()) {
|
||||||
myFontSizeMag = (signed char)*address++;
|
myFontSizeMag = (signed char)*address++;
|
||||||
}
|
}
|
||||||
if (fontFamilySupported()) {
|
if (fontFamiliesSupported()) {
|
||||||
myFontFamily = address;
|
unsigned char n = *address++;
|
||||||
|
for (unsigned int i = 0; i < n; ++i) {
|
||||||
|
std::string font(address);
|
||||||
|
address += font.length() + 1;
|
||||||
|
myFontFamilies.push_back(font);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLTextStyleEntry::reset() {
|
void ZLTextStyleEntry::reset() {
|
||||||
mySupportedFontModifier = 0;
|
mySupportedFontModifier = 0;
|
||||||
myMask = 0;
|
myMask = 0;
|
||||||
myFontFamily.clear();
|
myFontFamilies.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLTextStyleEntry::apply(const ZLTextStyleEntry &entry) {
|
void ZLTextStyleEntry::apply(const ZLTextStyleEntry &other) {
|
||||||
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
if (other.myMask & ((1 << NUMBER_OF_LENGTHS) - 1)) {
|
||||||
if (entry.lengthSupported((Length)i)) {
|
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
||||||
myLengths[i] = entry.myLengths[i];
|
if (other.myMask & (1 << i)) {
|
||||||
myMask |= 1 << i;
|
myLengths[i] = other.myLengths[i];
|
||||||
|
myMask |= (1 << i);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (entry.opacitySupported()) {
|
if (other.myMask & SUPPORT_OPACITY) {
|
||||||
setOpacity(entry.opacity());
|
setOpacity(other.myOpacity);
|
||||||
}
|
}
|
||||||
if (entry.alignmentTypeSupported()) {
|
if (other.myMask & SUPPORT_ALIGNMENT_TYPE) {
|
||||||
setAlignmentType(entry.alignmentType());
|
setAlignmentType(other.myAlignmentType);
|
||||||
}
|
}
|
||||||
if (entry.mySupportedFontModifier) {
|
if (other.mySupportedFontModifier) {
|
||||||
myFontModifier &= ~entry.mySupportedFontModifier;
|
myFontModifier &= ~other.mySupportedFontModifier;
|
||||||
myFontModifier |= (entry.myFontModifier & entry.mySupportedFontModifier);
|
myFontModifier |= (other.myFontModifier & other.mySupportedFontModifier);
|
||||||
mySupportedFontModifier |= entry.mySupportedFontModifier;
|
mySupportedFontModifier |= other.mySupportedFontModifier;
|
||||||
}
|
}
|
||||||
if (entry.fontSizeSupported()) {
|
if (other.myMask & SUPPORT_FONT_SIZE) {
|
||||||
setFontSizeMag(entry.fontSizeMag());
|
setFontSizeMag(other.myFontSizeMag);
|
||||||
}
|
}
|
||||||
if (entry.fontFamilySupported()) {
|
if (other.myMask & SUPPORT_FONT_FAMILIES) {
|
||||||
setFontFamily(entry.fontFamily());
|
setFontFamilies(other.myFontFamilies);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ZLTextStyleEntry::inherit(const ZLTextStyleEntry &other) {
|
||||||
|
// text-indent
|
||||||
|
if (other.myMask & (1 << LENGTH_FIRST_LINE_INDENT_DELTA)) {
|
||||||
|
myLengths[LENGTH_FIRST_LINE_INDENT_DELTA] = other.myLengths[LENGTH_FIRST_LINE_INDENT_DELTA];
|
||||||
|
myMask |= (1 << LENGTH_FIRST_LINE_INDENT_DELTA);
|
||||||
|
}
|
||||||
|
// text-align
|
||||||
|
if (other.myMask & SUPPORT_ALIGNMENT_TYPE) {
|
||||||
|
setAlignmentType(other.myAlignmentType);
|
||||||
|
}
|
||||||
|
// font-style, font-variant, font-weight
|
||||||
|
if (other.mySupportedFontModifier) {
|
||||||
|
myFontModifier &= ~other.mySupportedFontModifier;
|
||||||
|
myFontModifier |= (other.myFontModifier & other.mySupportedFontModifier);
|
||||||
|
mySupportedFontModifier |= other.mySupportedFontModifier;
|
||||||
|
}
|
||||||
|
// font-size
|
||||||
|
if (other.myMask & SUPPORT_FONT_SIZE) {
|
||||||
|
setFontSizeMag(other.myFontSizeMag);
|
||||||
|
}
|
||||||
|
// font-family
|
||||||
|
if (other.myMask & SUPPORT_FONT_FAMILIES) {
|
||||||
|
setFontFamilies(other.myFontFamilies);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZLTextStyleEntry::equals(const ZLTextStyleEntry &other) const {
|
||||||
|
if (myMask == other.myMask && mySupportedFontModifier == other.mySupportedFontModifier) {
|
||||||
|
if (myMask & ((1 << NUMBER_OF_LENGTHS) - 1)) {
|
||||||
|
for (int i = 0; i < NUMBER_OF_LENGTHS; ++i) {
|
||||||
|
if (myMask & (1 << i)) {
|
||||||
|
if (myLengths[i].Size != other.myLengths[i].Size ||
|
||||||
|
myLengths[i].Unit != other.myLengths[i].Unit) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((myMask & SUPPORT_OPACITY) && myOpacity != other.myOpacity) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((myMask & SUPPORT_ALIGNMENT_TYPE) && myAlignmentType != other.myAlignmentType) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((myFontModifier & mySupportedFontModifier) != (other.myFontModifier & mySupportedFontModifier)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((myMask & SUPPORT_FONT_SIZE) && myFontSizeMag != other.myFontSizeMag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((myMask & SUPPORT_FONT_FAMILIES) && myFontFamilies != other.myFontFamilies) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZLTextStyleEntry::parseLength(const std::string &toParse, short &size, SizeUnit &unit) {
|
||||||
|
if (!toParse.empty()) {
|
||||||
|
static const std::string PERCENT("%");
|
||||||
|
static const std::string ZERO("0");
|
||||||
|
static const std::string EM("em");
|
||||||
|
static const std::string EX("ex");
|
||||||
|
static const std::string PX("px");
|
||||||
|
static const std::string PT("pt");
|
||||||
|
static const std::string PC("pc");
|
||||||
|
if (ZLStringUtil::stringEndsWith(toParse, PERCENT)) {
|
||||||
|
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 == ZERO) {
|
||||||
|
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
||||||
|
size = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const shared_ptr<ZLTextParagraphEntry> ZLTextParagraph::Iterator::entry() const {
|
const shared_ptr<ZLTextParagraphEntry> ZLTextParagraph::Iterator::entry() const {
|
||||||
if (myEntry.isNull()) {
|
if (myEntry.isNull()) {
|
||||||
switch (*myPointer) {
|
switch (*myPointer) {
|
||||||
|
@ -205,11 +328,11 @@ void ZLTextParagraph::Iterator::next() {
|
||||||
if (mask & ZLTextStyleEntry::SUPPORT_ALIGNMENT_TYPE) ++myPointer;
|
if (mask & ZLTextStyleEntry::SUPPORT_ALIGNMENT_TYPE) ++myPointer;
|
||||||
if (supportedFontModifier) ++myPointer;
|
if (supportedFontModifier) ++myPointer;
|
||||||
if (mask & ZLTextStyleEntry::SUPPORT_FONT_SIZE) ++myPointer;
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_SIZE) ++myPointer;
|
||||||
if (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILY) {
|
if (mask & ZLTextStyleEntry::SUPPORT_FONT_FAMILIES) {
|
||||||
while (*myPointer != '\0') {
|
unsigned char n = *myPointer++;
|
||||||
++myPointer;
|
for (unsigned int i = 0; i < n; ++i) {
|
||||||
|
while (*myPointer++);
|
||||||
}
|
}
|
||||||
++myPointer;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -218,6 +341,7 @@ void ZLTextParagraph::Iterator::next() {
|
||||||
break;
|
break;
|
||||||
case ZLTextParagraphEntry::RESET_BIDI_ENTRY:
|
case ZLTextParagraphEntry::RESET_BIDI_ENTRY:
|
||||||
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
case ZLTextParagraphEntry::LINE_BREAK_ENTRY:
|
||||||
|
case ZLTextParagraphEntry::EMPTY_ENTRY:
|
||||||
++myPointer;
|
++myPointer;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ 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
|
LINE_BREAK_ENTRY = 8,
|
||||||
|
EMPTY_ENTRY = 9
|
||||||
};
|
};
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -99,15 +100,23 @@ public:
|
||||||
~ZLTextStyleEntry();
|
~ZLTextStyleEntry();
|
||||||
|
|
||||||
void reset();
|
void reset();
|
||||||
void apply(const ZLTextStyleEntry &entry);
|
void apply(const ZLTextStyleEntry &other);
|
||||||
|
void inherit(const ZLTextStyleEntry &other);
|
||||||
|
bool equals(const ZLTextStyleEntry &other) const;
|
||||||
|
bool operator == (const ZLTextStyleEntry &other) const;
|
||||||
ZLTextStyleEntry &operator = (const ZLTextStyleEntry &other);
|
ZLTextStyleEntry &operator = (const ZLTextStyleEntry &other);
|
||||||
|
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
|
|
||||||
bool lengthSupported(Length name) const;
|
bool lengthSupported(Length name) const;
|
||||||
short length(Length name, const Metrics &metrics) const;
|
short length(Length name, const Metrics &metrics) const;
|
||||||
|
short length(Length name, SizeUnit &unit) const;
|
||||||
void setLength(Length name, short length, SizeUnit unit);
|
void setLength(Length name, short length, SizeUnit unit);
|
||||||
|
|
||||||
|
static int hlength(int size, SizeUnit unit, const Metrics &metrics);
|
||||||
|
static int vlength(int size, SizeUnit unit, const Metrics &metrics);
|
||||||
|
static bool parseLength(const std::string &toParse, short &size, SizeUnit &unit);
|
||||||
|
|
||||||
bool opacitySupported() const;
|
bool opacitySupported() const;
|
||||||
unsigned char opacity() const;
|
unsigned char opacity() const;
|
||||||
void setOpacity(unsigned char opacity);
|
void setOpacity(unsigned char opacity);
|
||||||
|
@ -124,14 +133,14 @@ public:
|
||||||
signed char fontSizeMag() const;
|
signed char fontSizeMag() const;
|
||||||
void setFontSizeMag(signed char fontSizeMag);
|
void setFontSizeMag(signed char fontSizeMag);
|
||||||
|
|
||||||
bool fontFamilySupported() const;
|
bool fontFamiliesSupported() const;
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
void setFontFamily(const std::string &fontFamily);
|
void setFontFamilies(const std::vector<std::string> &fontFamilies);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
SUPPORT_ALIGNMENT_TYPE = 1 << NUMBER_OF_LENGTHS,
|
SUPPORT_ALIGNMENT_TYPE = 1 << NUMBER_OF_LENGTHS,
|
||||||
SUPPORT_FONT_SIZE = 1 << (NUMBER_OF_LENGTHS + 1),
|
SUPPORT_FONT_SIZE = 1 << (NUMBER_OF_LENGTHS + 1),
|
||||||
SUPPORT_FONT_FAMILY = 1 << (NUMBER_OF_LENGTHS + 2),
|
SUPPORT_FONT_FAMILIES = 1 << (NUMBER_OF_LENGTHS + 2),
|
||||||
SUPPORT_OPACITY = 1 << (NUMBER_OF_LENGTHS + 3)
|
SUPPORT_OPACITY = 1 << (NUMBER_OF_LENGTHS + 3)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -145,7 +154,7 @@ private:
|
||||||
unsigned char mySupportedFontModifier;
|
unsigned char mySupportedFontModifier;
|
||||||
unsigned char myFontModifier;
|
unsigned char myFontModifier;
|
||||||
signed char myFontSizeMag;
|
signed char myFontSizeMag;
|
||||||
std::string myFontFamily;
|
std::vector<std::string> myFontFamilies;
|
||||||
|
|
||||||
friend class ZLTextModel;
|
friend class ZLTextModel;
|
||||||
};
|
};
|
||||||
|
@ -353,9 +362,11 @@ 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 bool ZLTextStyleEntry::operator == (const ZLTextStyleEntry &other) const { return equals(other); }
|
||||||
inline ZLTextStyleEntry &ZLTextStyleEntry::operator = (const ZLTextStyleEntry &other) { reset(); apply(other); return *this; }
|
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 short ZLTextStyleEntry::length(Length name, SizeUnit &unit) const { unit = myLengths[name].Unit; return myLengths[name].Size; }
|
||||||
inline void ZLTextStyleEntry::setLength(Length name, short length, SizeUnit unit) {
|
inline void ZLTextStyleEntry::setLength(Length name, short length, SizeUnit unit) {
|
||||||
myLengths[name].Size = length;
|
myLengths[name].Size = length;
|
||||||
myLengths[name].Unit = unit;
|
myLengths[name].Unit = unit;
|
||||||
|
@ -385,9 +396,9 @@ inline bool ZLTextStyleEntry::fontSizeSupported() const { return (myMask & SUPPO
|
||||||
inline signed char ZLTextStyleEntry::fontSizeMag() const { return myFontSizeMag; }
|
inline signed char ZLTextStyleEntry::fontSizeMag() const { return myFontSizeMag; }
|
||||||
inline void ZLTextStyleEntry::setFontSizeMag(signed char fontSizeMag) { myFontSizeMag = fontSizeMag; myMask |= SUPPORT_FONT_SIZE; }
|
inline void ZLTextStyleEntry::setFontSizeMag(signed char fontSizeMag) { myFontSizeMag = fontSizeMag; myMask |= SUPPORT_FONT_SIZE; }
|
||||||
|
|
||||||
inline bool ZLTextStyleEntry::fontFamilySupported() const { return (myMask & SUPPORT_FONT_FAMILY) == SUPPORT_FONT_FAMILY; }
|
inline bool ZLTextStyleEntry::fontFamiliesSupported() const { return (myMask & SUPPORT_FONT_FAMILIES) == SUPPORT_FONT_FAMILIES; }
|
||||||
inline const std::string &ZLTextStyleEntry::fontFamily() const { return myFontFamily; }
|
inline const std::vector<std::string> &ZLTextStyleEntry::fontFamilies() const { return myFontFamilies; }
|
||||||
inline void ZLTextStyleEntry::setFontFamily(const std::string &fontFamily) { myFontFamily = fontFamily; myMask |= SUPPORT_FONT_FAMILY; }
|
inline void ZLTextStyleEntry::setFontFamilies(const std::vector<std::string> &fontFamilies) { myFontFamilies = fontFamilies; myMask |= SUPPORT_FONT_FAMILIES; }
|
||||||
|
|
||||||
inline ZLTextControlEntry::ZLTextControlEntry(ZLTextKind kind, bool isStart) : myKind(kind), myStart(isStart) {}
|
inline ZLTextControlEntry::ZLTextControlEntry(ZLTextKind kind, bool isStart) : myKind(kind), myStart(isStart) {}
|
||||||
inline ZLTextControlEntry::~ZLTextControlEntry() {}
|
inline ZLTextControlEntry::~ZLTextControlEntry() {}
|
||||||
|
|
|
@ -30,7 +30,7 @@ ZLTextStyleDecoration::ZLTextStyleDecoration(const std::string &name, int fontSi
|
||||||
ItalicOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":italic", italic),
|
ItalicOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":italic", italic),
|
||||||
VerticalShiftOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":vShift", verticalShift),
|
VerticalShiftOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":vShift", verticalShift),
|
||||||
AllowHyphenationsOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":allowHyphenations", allowHyphenations),
|
AllowHyphenationsOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":allowHyphenations", allowHyphenations),
|
||||||
myName(name) {
|
myName(name), myFirstLineIndentDelta(NULL), myFirstLineIndentDeltaUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL) {
|
||||||
}
|
}
|
||||||
|
|
||||||
ZLTextFullStyleDecoration::ZLTextFullStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, short spaceBefore, short spaceAfter, short lineStartIndent, short lineEndIndent, short firstLineIndentDelta, int verticalShift, ZLTextAlignmentType alignment, double lineSpace, ZLBoolean3 allowHyphenations) : ZLTextStyleDecoration(name, fontSizeDelta, bold, italic, verticalShift, allowHyphenations),
|
ZLTextFullStyleDecoration::ZLTextFullStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, short spaceBefore, short spaceAfter, short lineStartIndent, short lineEndIndent, short firstLineIndentDelta, int verticalShift, ZLTextAlignmentType alignment, double lineSpace, ZLBoolean3 allowHyphenations) : ZLTextStyleDecoration(name, fontSizeDelta, bold, italic, verticalShift, allowHyphenations),
|
||||||
|
@ -38,23 +38,74 @@ ZLTextFullStyleDecoration::ZLTextFullStyleDecoration(const std::string &name, in
|
||||||
SpaceAfterOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":spaceAfter", -10, 100, spaceAfter),
|
SpaceAfterOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":spaceAfter", -10, 100, spaceAfter),
|
||||||
LineStartIndentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":leftIndent", -300, 300, lineStartIndent),
|
LineStartIndentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":leftIndent", -300, 300, lineStartIndent),
|
||||||
LineEndIndentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":rightIndent", -300, 300, lineEndIndent),
|
LineEndIndentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":rightIndent", -300, 300, lineEndIndent),
|
||||||
FirstLineIndentDeltaOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":firstLineIndentDelta", -300, 300, firstLineIndentDelta),
|
|
||||||
AlignmentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":alignment", alignment),
|
AlignmentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":alignment", alignment),
|
||||||
LineSpaceOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":lineSpace", lineSpace),
|
LineSpaceOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":lineSpace", lineSpace),
|
||||||
LineSpacePercentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":lineSpacePercent", (lineSpace == 0.0) ? -1 : (int)(lineSpace * 100)) {
|
LineSpacePercentOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":lineSpacePercent", (lineSpace == 0.0) ? -1 : (int)(lineSpace * 100)),
|
||||||
|
FirstLineIndentDeltaOption(ZLCategoryKey::LOOK_AND_FEEL, STYLE, name + ":firstLineIndentDelta", -300, 300, firstLineIndentDelta),
|
||||||
|
SpaceBeforeOptionUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL),
|
||||||
|
SpaceAfterOptionUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL),
|
||||||
|
LineStartIndentOptionUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL),
|
||||||
|
LineEndIndentOptionUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL),
|
||||||
|
FirstLineIndentDeltaOptionUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL) {
|
||||||
|
}
|
||||||
|
|
||||||
|
const ZLTextFullStyleDecoration *ZLTextStyleDecoration::fullDecoration() const {
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyle> ZLTextStyleDecoration::createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const {
|
shared_ptr<ZLTextStyle> ZLTextStyleDecoration::createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const {
|
||||||
return new ZLTextPartialDecoratedStyle(base, *this);
|
return new ZLTextPartialDecoratedStyle(base, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ZLTextFullStyleDecoration *ZLTextFullStyleDecoration::fullDecoration() const {
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
shared_ptr<ZLTextStyle> ZLTextFullStyleDecoration::createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const {
|
shared_ptr<ZLTextStyle> ZLTextFullStyleDecoration::createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const {
|
||||||
return new ZLTextFullDecoratedStyle(base, *this);
|
return new ZLTextFullDecoratedStyle(base, *this);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ZLTextPartialDecoratedStyle::fontFamily() const {
|
short ZLTextFullDecoratedStyle::spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
|
return ZLTextStyleEntry::vlength(myDecoration.SpaceBeforeOption.value(), myDecoration.SpaceBeforeOptionUnit, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
short ZLTextFullDecoratedStyle::spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
|
return ZLTextStyleEntry::vlength(myDecoration.SpaceAfterOption.value(), myDecoration.SpaceAfterOptionUnit, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
short ZLTextFullDecoratedStyle::lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const {
|
||||||
|
return base()->lineEndIndent(metrics, rtl) + (rtl ?
|
||||||
|
ZLTextStyleEntry::hlength(myDecoration.LineEndIndentOption.value(), myDecoration.LineEndIndentOptionUnit, metrics) :
|
||||||
|
ZLTextStyleEntry::hlength(myDecoration.LineStartIndentOption.value(), myDecoration.LineStartIndentOptionUnit, metrics));
|
||||||
|
}
|
||||||
|
|
||||||
|
short ZLTextFullDecoratedStyle::lineEndIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const {
|
||||||
|
return base()->lineStartIndent(metrics, rtl) + (rtl ?
|
||||||
|
ZLTextStyleEntry::hlength(myDecoration.LineStartIndentOption.value(), myDecoration.LineStartIndentOptionUnit, metrics) :
|
||||||
|
ZLTextStyleEntry::hlength(myDecoration.LineEndIndentOption.value(), myDecoration.LineEndIndentOptionUnit, metrics));
|
||||||
|
}
|
||||||
|
|
||||||
|
int ZLTextFullStyleDecoration::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
|
int size;
|
||||||
|
int* indent = ZLTextStyleDecoration::firstLineIndentDelta(unit);
|
||||||
|
if (indent) {
|
||||||
|
size = *indent;
|
||||||
|
} else {
|
||||||
|
size = FirstLineIndentDeltaOption.value();
|
||||||
|
unit = FirstLineIndentDeltaOptionUnit;
|
||||||
|
}
|
||||||
|
return ZLTextStyleEntry::hlength(size, unit, metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZLTextPartialDecoratedStyle::ZLTextPartialDecoratedStyle(const shared_ptr<ZLTextStyle> base, const ZLTextStyleDecoration &decoration) :
|
||||||
|
ZLTextDecoratedStyle(base), myDecoration(decoration) {
|
||||||
const std::string &family = myDecoration.FontFamilyOption.value();
|
const std::string &family = myDecoration.FontFamilyOption.value();
|
||||||
return (!family.empty()) ? family : base()->fontFamily();
|
if (!family.empty()) myFontFamilies.push_back(family);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<std::string> &ZLTextPartialDecoratedStyle::fontFamilies() const {
|
||||||
|
return (!myFontFamilies.empty()) ? myFontFamilies : base()->fontFamilies();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZLTextPartialDecoratedStyle::fontSize() const {
|
int ZLTextPartialDecoratedStyle::fontSize() const {
|
||||||
|
@ -74,16 +125,26 @@ bool ZLTextPartialDecoratedStyle::italic() const {
|
||||||
bool ZLTextPartialDecoratedStyle::allowHyphenations() const {
|
bool ZLTextPartialDecoratedStyle::allowHyphenations() const {
|
||||||
ZLBoolean3 a = myDecoration.AllowHyphenationsOption.value();
|
ZLBoolean3 a = myDecoration.AllowHyphenationsOption.value();
|
||||||
return (a == B3_UNDEFINED) ? base()->allowHyphenations() : (a == B3_TRUE);
|
return (a == B3_UNDEFINED) ? base()->allowHyphenations() : (a == B3_TRUE);
|
||||||
return true;
|
}
|
||||||
|
|
||||||
|
short ZLTextPartialDecoratedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
|
int* indent = myDecoration.firstLineIndentDelta(unit);
|
||||||
|
return indent ? ZLTextStyleEntry::hlength(*indent, unit, metrics) :base()->firstLineIndentDelta(metrics);
|
||||||
|
}
|
||||||
|
|
||||||
|
ZLTextFullDecoratedStyle::ZLTextFullDecoratedStyle(const shared_ptr<ZLTextStyle> base, const ZLTextFullStyleDecoration &decoration) :
|
||||||
|
ZLTextDecoratedStyle(base), myDecoration(decoration) {
|
||||||
|
const std::string &family = myDecoration.FontFamilyOption.value();
|
||||||
|
if (!family.empty()) myFontFamilies.push_back(family);
|
||||||
}
|
}
|
||||||
|
|
||||||
short ZLTextFullDecoratedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
short ZLTextFullDecoratedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
return (alignment() == ALIGN_CENTER) ? 0 : base()->firstLineIndentDelta(metrics) + myDecoration.FirstLineIndentDeltaOption.value();
|
return (alignment() == ALIGN_CENTER) ? 0 : myDecoration.firstLineIndentDelta(metrics);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ZLTextFullDecoratedStyle::fontFamily() const {
|
const std::vector<std::string> &ZLTextFullDecoratedStyle::fontFamilies() const {
|
||||||
const std::string &family = myDecoration.FontFamilyOption.value();
|
return (!myFontFamilies.empty()) ? myFontFamilies : base()->fontFamilies();
|
||||||
return (!family.empty()) ? family : base()->fontFamily();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int ZLTextFullDecoratedStyle::fontSize() const {
|
int ZLTextFullDecoratedStyle::fontSize() const {
|
||||||
|
@ -108,7 +169,6 @@ ZLTextAlignmentType ZLTextFullDecoratedStyle::alignment() const {
|
||||||
bool ZLTextFullDecoratedStyle::allowHyphenations() const {
|
bool ZLTextFullDecoratedStyle::allowHyphenations() const {
|
||||||
ZLBoolean3 a = myDecoration.AllowHyphenationsOption.value();
|
ZLBoolean3 a = myDecoration.AllowHyphenationsOption.value();
|
||||||
return (a == B3_UNDEFINED) ? base()->allowHyphenations() : (a == B3_TRUE);
|
return (a == B3_UNDEFINED) ? base()->allowHyphenations() : (a == B3_TRUE);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ZLTextPartialDecoratedStyle::colorStyle() const {
|
const std::string &ZLTextPartialDecoratedStyle::colorStyle() const {
|
||||||
|
@ -150,25 +210,17 @@ short ZLTextForcedStyle::lineEndIndent(const ZLTextStyleEntry::Metrics &metrics,
|
||||||
}
|
}
|
||||||
|
|
||||||
short ZLTextForcedStyle::spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const {
|
short ZLTextForcedStyle::spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
if (myEntry.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE)) {
|
return
|
||||||
const short baseSpace = base()->spaceBefore(metrics);
|
myEntry.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_BEFORE) ?
|
||||||
ZLTextStyleEntry::Metrics adjusted(metrics);
|
myEntry.length(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, metrics) :
|
||||||
adjusted.FullHeight -= baseSpace + base()->spaceAfter(metrics);
|
base()->spaceBefore(metrics);
|
||||||
return baseSpace + myEntry.length(ZLTextStyleEntry::LENGTH_SPACE_BEFORE, adjusted);
|
|
||||||
} else {
|
|
||||||
return base()->spaceBefore(metrics);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
short ZLTextForcedStyle::spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const {
|
short ZLTextForcedStyle::spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
if (myEntry.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER)) {
|
return
|
||||||
const short baseSpace = base()->spaceBefore(metrics);
|
myEntry.lengthSupported(ZLTextStyleEntry::LENGTH_SPACE_AFTER) ?
|
||||||
ZLTextStyleEntry::Metrics adjusted(metrics);
|
myEntry.length(ZLTextStyleEntry::LENGTH_SPACE_AFTER, metrics) :
|
||||||
adjusted.FullHeight -= baseSpace + base()->spaceBefore(metrics);
|
base()->spaceAfter(metrics);
|
||||||
return baseSpace + myEntry.length(ZLTextStyleEntry::LENGTH_SPACE_AFTER, adjusted);
|
|
||||||
} else {
|
|
||||||
return base()->spaceAfter(metrics);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
short ZLTextForcedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
short ZLTextForcedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const {
|
||||||
|
@ -221,10 +273,10 @@ int ZLTextForcedStyle::fontSize() const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ZLTextForcedStyle::fontFamily() const {
|
const std::vector<std::string> &ZLTextForcedStyle::fontFamilies() const {
|
||||||
return (!ZLTextStyleCollection::Instance().OverrideSpecifiedFontsOption.value() &&
|
return (!ZLTextStyleCollection::Instance().OverrideSpecifiedFontsOption.value() &&
|
||||||
myEntry.fontFamilySupported()) ?
|
myEntry.fontFamiliesSupported()) ?
|
||||||
myEntry.fontFamily() : base()->fontFamily();
|
myEntry.fontFamilies() : base()->fontFamilies();
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string &ZLTextStyleDecoration::colorStyle() const {
|
const std::string &ZLTextStyleDecoration::colorStyle() const {
|
||||||
|
|
|
@ -46,7 +46,7 @@ public:
|
||||||
ZLTextForcedStyle(shared_ptr<ZLTextStyle> base, const ZLTextStyleEntry &entry);
|
ZLTextForcedStyle(shared_ptr<ZLTextStyle> base, const ZLTextStyleEntry &entry);
|
||||||
~ZLTextForcedStyle();
|
~ZLTextForcedStyle();
|
||||||
|
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
|
|
||||||
bool bold() const;
|
bool bold() const;
|
||||||
|
@ -77,7 +77,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual ~ZLTextPartialDecoratedStyle();
|
virtual ~ZLTextPartialDecoratedStyle();
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
bool bold() const;
|
bool bold() const;
|
||||||
bool italic() const;
|
bool italic() const;
|
||||||
|
@ -98,6 +98,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ZLTextStyleDecoration &myDecoration;
|
const ZLTextStyleDecoration &myDecoration;
|
||||||
|
std::vector<std::string> myFontFamilies;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZLTextFullDecoratedStyle : public ZLTextDecoratedStyle {
|
class ZLTextFullDecoratedStyle : public ZLTextDecoratedStyle {
|
||||||
|
@ -108,7 +109,7 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~ZLTextFullDecoratedStyle();
|
~ZLTextFullDecoratedStyle();
|
||||||
const std::string &fontFamily() const;
|
const std::vector<std::string> &fontFamilies() const;
|
||||||
int fontSize() const;
|
int fontSize() const;
|
||||||
bool bold() const;
|
bool bold() const;
|
||||||
bool italic() const;
|
bool italic() const;
|
||||||
|
@ -129,6 +130,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const ZLTextFullStyleDecoration &myDecoration;
|
const ZLTextFullStyleDecoration &myDecoration;
|
||||||
|
std::vector<std::string> myFontFamilies;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ZLTextDecoratedStyle::ZLTextDecoratedStyle(const shared_ptr<ZLTextStyle> base) : myBase(base) {}
|
inline ZLTextDecoratedStyle::ZLTextDecoratedStyle(const shared_ptr<ZLTextStyle> base) : myBase(base) {}
|
||||||
|
@ -143,23 +145,16 @@ inline int ZLTextForcedStyle::verticalShift() const { return base()->verticalShi
|
||||||
inline double ZLTextForcedStyle::lineSpace() const { return base()->lineSpace(); }
|
inline double ZLTextForcedStyle::lineSpace() const { return base()->lineSpace(); }
|
||||||
inline bool ZLTextForcedStyle::allowHyphenations() const { return base()->allowHyphenations(); }
|
inline bool ZLTextForcedStyle::allowHyphenations() const { return base()->allowHyphenations(); }
|
||||||
|
|
||||||
inline ZLTextPartialDecoratedStyle::ZLTextPartialDecoratedStyle(const shared_ptr<ZLTextStyle> base, const ZLTextStyleDecoration &decoration) : ZLTextDecoratedStyle(base), myDecoration(decoration) {}
|
|
||||||
inline ZLTextPartialDecoratedStyle::~ZLTextPartialDecoratedStyle() {}
|
inline ZLTextPartialDecoratedStyle::~ZLTextPartialDecoratedStyle() {}
|
||||||
inline short ZLTextPartialDecoratedStyle::spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const { return base()->spaceBefore(metrics); }
|
inline short ZLTextPartialDecoratedStyle::spaceBefore(const ZLTextStyleEntry::Metrics &metrics) const { return base()->spaceBefore(metrics); }
|
||||||
inline short ZLTextPartialDecoratedStyle::spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const { return base()->spaceAfter(metrics); }
|
inline short ZLTextPartialDecoratedStyle::spaceAfter(const ZLTextStyleEntry::Metrics &metrics) const { return base()->spaceAfter(metrics); }
|
||||||
inline short ZLTextPartialDecoratedStyle::lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineStartIndent(metrics, rtl); }
|
inline short ZLTextPartialDecoratedStyle::lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineStartIndent(metrics, rtl); }
|
||||||
inline short ZLTextPartialDecoratedStyle::lineEndIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineEndIndent(metrics, rtl); }
|
inline short ZLTextPartialDecoratedStyle::lineEndIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineEndIndent(metrics, rtl); }
|
||||||
inline short ZLTextPartialDecoratedStyle::firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const { return base()->firstLineIndentDelta(metrics); }
|
|
||||||
inline int ZLTextPartialDecoratedStyle::verticalShift() const { return base()->verticalShift() + myDecoration.VerticalShiftOption.value(); }
|
inline int ZLTextPartialDecoratedStyle::verticalShift() const { return base()->verticalShift() + myDecoration.VerticalShiftOption.value(); }
|
||||||
inline ZLTextAlignmentType ZLTextPartialDecoratedStyle::alignment() const { return base()->alignment(); }
|
inline ZLTextAlignmentType ZLTextPartialDecoratedStyle::alignment() const { return base()->alignment(); }
|
||||||
inline double ZLTextPartialDecoratedStyle::lineSpace() const { return base()->lineSpace(); }
|
inline double ZLTextPartialDecoratedStyle::lineSpace() const { return base()->lineSpace(); }
|
||||||
|
|
||||||
inline ZLTextFullDecoratedStyle::ZLTextFullDecoratedStyle(const shared_ptr<ZLTextStyle> base, const ZLTextFullStyleDecoration &decoration) : ZLTextDecoratedStyle(base), myDecoration(decoration) {}
|
|
||||||
inline ZLTextFullDecoratedStyle::~ZLTextFullDecoratedStyle() {}
|
inline ZLTextFullDecoratedStyle::~ZLTextFullDecoratedStyle() {}
|
||||||
inline short ZLTextFullDecoratedStyle::spaceBefore(const ZLTextStyleEntry::Metrics&) const { return myDecoration.SpaceBeforeOption.value(); }
|
|
||||||
inline short ZLTextFullDecoratedStyle::spaceAfter(const ZLTextStyleEntry::Metrics&) const { return myDecoration.SpaceAfterOption.value(); }
|
|
||||||
inline short ZLTextFullDecoratedStyle::lineStartIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineStartIndent(metrics, rtl) + myDecoration.LineStartIndentOption.value(); }
|
|
||||||
inline short ZLTextFullDecoratedStyle::lineEndIndent(const ZLTextStyleEntry::Metrics &metrics, bool rtl) const { return base()->lineEndIndent(metrics, rtl) + myDecoration.LineEndIndentOption.value(); }
|
|
||||||
inline int ZLTextFullDecoratedStyle::verticalShift() const { return base()->verticalShift() + myDecoration.VerticalShiftOption.value(); }
|
inline int ZLTextFullDecoratedStyle::verticalShift() const { return base()->verticalShift() + myDecoration.VerticalShiftOption.value(); }
|
||||||
inline double ZLTextFullDecoratedStyle::lineSpace() const {
|
inline double ZLTextFullDecoratedStyle::lineSpace() const {
|
||||||
const int spacing = myDecoration.LineSpacePercentOption.value();
|
const int spacing = myDecoration.LineSpacePercentOption.value();
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
#define __ZLTEXTSTYLE_H__
|
#define __ZLTEXTSTYLE_H__
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <shared_ptr.h>
|
#include <shared_ptr.h>
|
||||||
|
|
||||||
|
@ -43,7 +44,7 @@ public:
|
||||||
|
|
||||||
virtual bool isDecorated() const = 0;
|
virtual bool isDecorated() const = 0;
|
||||||
|
|
||||||
virtual const std::string &fontFamily() const = 0;
|
virtual const std::vector<std::string> &fontFamilies() const = 0;
|
||||||
virtual int fontSize() const = 0;
|
virtual int fontSize() const = 0;
|
||||||
|
|
||||||
virtual bool bold() const = 0;
|
virtual bool bold() const = 0;
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <limits.h>
|
||||||
|
|
||||||
#include <ZLibrary.h>
|
#include <ZLibrary.h>
|
||||||
#include <ZLFile.h>
|
#include <ZLFile.h>
|
||||||
|
@ -52,6 +54,7 @@ public:
|
||||||
void startElementHandler(const char *tag, const char **attributes);
|
void startElementHandler(const char *tag, const char **attributes);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
int lengthValue(const char **attributes, const char *name, ZLTextStyleEntry::SizeUnit &unit, int defaultValue = 0);
|
||||||
int intValue(const char **attributes, const char *name, int defaultValue = 0);
|
int intValue(const char **attributes, const char *name, int defaultValue = 0);
|
||||||
bool booleanValue(const char **attributes, const char *name);
|
bool booleanValue(const char **attributes, const char *name);
|
||||||
ZLBoolean3 b3Value(const char **attributes, const char *name);
|
ZLBoolean3 b3Value(const char **attributes, const char *name);
|
||||||
|
@ -62,6 +65,31 @@ private:
|
||||||
|
|
||||||
static const std::string TRUE_STRING = "true";
|
static const std::string TRUE_STRING = "true";
|
||||||
|
|
||||||
|
int ZLTextStyleReader::lengthValue(const char **attributes, const char *name, ZLTextStyleEntry::SizeUnit &unit, int defaultValue) {
|
||||||
|
const char *stringValue = attributeValue(attributes, name);
|
||||||
|
if (stringValue) {
|
||||||
|
short size;
|
||||||
|
if (ZLTextStyleEntry::parseLength(stringValue, size, unit)) {
|
||||||
|
return size;
|
||||||
|
} else {
|
||||||
|
const char *s = stringValue;
|
||||||
|
while (*s && isspace(*s)) s++;
|
||||||
|
char* endptr = NULL;
|
||||||
|
long number = strtol(s, &endptr, 10);
|
||||||
|
if (endptr && endptr != s) {
|
||||||
|
if ((number != LONG_MAX && number != LONG_MIN) || (errno != ERANGE)) {
|
||||||
|
while (*endptr && isspace(*endptr)) endptr++;
|
||||||
|
if (!*endptr) {
|
||||||
|
unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
inline int ZLTextStyleReader::intValue(const char **attributes, const char *name, int defaultValue) {
|
inline int ZLTextStyleReader::intValue(const char **attributes, const char *name, int defaultValue) {
|
||||||
const char *stringValue = attributeValue(attributes, name);
|
const char *stringValue = attributeValue(attributes, name);
|
||||||
return (stringValue == 0) ? defaultValue : atoi(stringValue);
|
return (stringValue == 0) ? defaultValue : atoi(stringValue);
|
||||||
|
@ -95,12 +123,25 @@ void ZLTextStyleReader::startElementHandler(const char *tag, const char **attrib
|
||||||
|
|
||||||
if (booleanValue(attributes, "partial")) {
|
if (booleanValue(attributes, "partial")) {
|
||||||
decoration = new ZLTextStyleDecoration(name, fontSizeDelta, bold, italic, verticalShift, allowHyphenations);
|
decoration = new ZLTextStyleDecoration(name, fontSizeDelta, bold, italic, verticalShift, allowHyphenations);
|
||||||
|
const char *indentValue = attributeValue(attributes, "firstLineIndentDelta");
|
||||||
|
if (indentValue) {
|
||||||
|
short size;
|
||||||
|
ZLTextStyleEntry::SizeUnit unit;
|
||||||
|
if (ZLTextStyleEntry::parseLength(indentValue, size, unit)) {
|
||||||
|
decoration->setFirstLineIndentDelta(size, unit);
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
int spaceBefore = intValue(attributes, "spaceBefore");
|
ZLTextStyleEntry::SizeUnit spaceBeforeUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL);
|
||||||
int spaceAfter = intValue(attributes, "spaceAfter");
|
ZLTextStyleEntry::SizeUnit spaceAfterUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL);
|
||||||
int leftIndent = intValue(attributes, "leftIndent");
|
ZLTextStyleEntry::SizeUnit leftIndentUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL);
|
||||||
int rightIndent = intValue(attributes, "rightIndent");
|
ZLTextStyleEntry::SizeUnit rightIndentUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL);
|
||||||
int firstLineIndentDelta = intValue(attributes, "firstLineIndentDelta");
|
ZLTextStyleEntry::SizeUnit firstLineIndentDeltaUnit(ZLTextStyleEntry::SIZE_UNIT_PIXEL);
|
||||||
|
int spaceBefore = lengthValue(attributes, "spaceBefore", spaceBeforeUnit);
|
||||||
|
int spaceAfter = lengthValue(attributes, "spaceAfter", spaceAfterUnit);
|
||||||
|
int leftIndent = lengthValue(attributes, "leftIndent", leftIndentUnit);
|
||||||
|
int rightIndent = lengthValue(attributes, "rightIndent", rightIndentUnit);
|
||||||
|
int firstLineIndentDelta = lengthValue(attributes, "firstLineIndentDelta", firstLineIndentDeltaUnit);
|
||||||
|
|
||||||
ZLTextAlignmentType alignment = ALIGN_UNDEFINED;
|
ZLTextAlignmentType alignment = ALIGN_UNDEFINED;
|
||||||
const char *alignmentString = attributeValue(attributes, "alignment");
|
const char *alignmentString = attributeValue(attributes, "alignment");
|
||||||
|
@ -120,7 +161,13 @@ void ZLTextStyleReader::startElementHandler(const char *tag, const char **attrib
|
||||||
const int lineSpacingPercent = intValue(attributes, "lineSpacingPercent", -1);
|
const int lineSpacingPercent = intValue(attributes, "lineSpacingPercent", -1);
|
||||||
const double lineSpace = (lineSpacingPercent == -1) ? 0.0 : (lineSpacingPercent / 100.0);
|
const double lineSpace = (lineSpacingPercent == -1) ? 0.0 : (lineSpacingPercent / 100.0);
|
||||||
|
|
||||||
decoration = new ZLTextFullStyleDecoration(name, fontSizeDelta, bold, italic, spaceBefore, spaceAfter, leftIndent, rightIndent, firstLineIndentDelta, verticalShift, alignment, lineSpace, allowHyphenations);
|
ZLTextFullStyleDecoration *dec = new ZLTextFullStyleDecoration(name, fontSizeDelta, bold, italic, spaceBefore, spaceAfter, leftIndent, rightIndent, firstLineIndentDelta, verticalShift, alignment, lineSpace, allowHyphenations);
|
||||||
|
dec->SpaceBeforeOptionUnit = spaceBeforeUnit;
|
||||||
|
dec->SpaceAfterOptionUnit = spaceAfterUnit;
|
||||||
|
dec->LineStartIndentOptionUnit = leftIndentUnit;
|
||||||
|
dec->LineEndIndentOptionUnit = rightIndentUnit;
|
||||||
|
dec->FirstLineIndentDeltaOptionUnit = firstLineIndentDeltaUnit;
|
||||||
|
decoration = dec;
|
||||||
}
|
}
|
||||||
const char *hyperlink = attributeValue(attributes, "hyperlink");
|
const char *hyperlink = attributeValue(attributes, "hyperlink");
|
||||||
if (hyperlink != 0) {
|
if (hyperlink != 0) {
|
||||||
|
|
|
@ -24,6 +24,9 @@
|
||||||
|
|
||||||
#include <ZLOptions.h>
|
#include <ZLOptions.h>
|
||||||
#include <ZLTextStyle.h>
|
#include <ZLTextStyle.h>
|
||||||
|
#include <ZLTextParagraph.h>
|
||||||
|
|
||||||
|
class ZLTextFullStyleDecoration;
|
||||||
|
|
||||||
class ZLTextStyleDecoration {
|
class ZLTextStyleDecoration {
|
||||||
|
|
||||||
|
@ -31,7 +34,7 @@ public:
|
||||||
ZLTextStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, int verticalShift, ZLBoolean3 allowHyphenations);
|
ZLTextStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, int verticalShift, ZLBoolean3 allowHyphenations);
|
||||||
virtual ~ZLTextStyleDecoration();
|
virtual ~ZLTextStyleDecoration();
|
||||||
|
|
||||||
virtual bool isFullDecoration() const;
|
virtual const ZLTextFullStyleDecoration *fullDecoration() const;
|
||||||
|
|
||||||
virtual shared_ptr<ZLTextStyle> createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const;
|
virtual shared_ptr<ZLTextStyle> createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const;
|
||||||
|
|
||||||
|
@ -40,6 +43,9 @@ public:
|
||||||
const std::string &colorStyle() const;
|
const std::string &colorStyle() const;
|
||||||
void setColorStyle(const std::string &colorStyle);
|
void setColorStyle(const std::string &colorStyle);
|
||||||
|
|
||||||
|
void setFirstLineIndentDelta(int indent, ZLTextStyleEntry::SizeUnit unit);
|
||||||
|
int* firstLineIndentDelta(ZLTextStyleEntry::SizeUnit &unit) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ZLStringOption FontFamilyOption;
|
ZLStringOption FontFamilyOption;
|
||||||
ZLIntegerRangeOption FontSizeDeltaOption;
|
ZLIntegerRangeOption FontSizeDeltaOption;
|
||||||
|
@ -54,6 +60,8 @@ private:
|
||||||
std::string myName;
|
std::string myName;
|
||||||
|
|
||||||
std::string myColorStyle;
|
std::string myColorStyle;
|
||||||
|
int* myFirstLineIndentDelta;
|
||||||
|
ZLTextStyleEntry::SizeUnit myFirstLineIndentDeltaUnit;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZLTextFullStyleDecoration : public ZLTextStyleDecoration {
|
class ZLTextFullStyleDecoration : public ZLTextStyleDecoration {
|
||||||
|
@ -62,8 +70,9 @@ public:
|
||||||
ZLTextFullStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, short spaceBefore, short spaceAfter, short lineStartIndent, short lineEndIndent, short firstLineIndentDelta, int verticalShift, ZLTextAlignmentType alignment, double lineSpace, ZLBoolean3 allowHyphenations);
|
ZLTextFullStyleDecoration(const std::string &name, int fontSizeDelta, ZLBoolean3 bold, ZLBoolean3 italic, short spaceBefore, short spaceAfter, short lineStartIndent, short lineEndIndent, short firstLineIndentDelta, int verticalShift, ZLTextAlignmentType alignment, double lineSpace, ZLBoolean3 allowHyphenations);
|
||||||
~ZLTextFullStyleDecoration();
|
~ZLTextFullStyleDecoration();
|
||||||
|
|
||||||
virtual bool isFullDecoration() const;
|
int firstLineIndentDelta(const ZLTextStyleEntry::Metrics &metrics) const;
|
||||||
|
|
||||||
|
const ZLTextFullStyleDecoration *fullDecoration() const;
|
||||||
shared_ptr<ZLTextStyle> createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const;
|
shared_ptr<ZLTextStyle> createDecoratedStyle(const shared_ptr<ZLTextStyle> base) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -71,12 +80,21 @@ public:
|
||||||
ZLIntegerRangeOption SpaceAfterOption;
|
ZLIntegerRangeOption SpaceAfterOption;
|
||||||
ZLIntegerRangeOption LineStartIndentOption;
|
ZLIntegerRangeOption LineStartIndentOption;
|
||||||
ZLIntegerRangeOption LineEndIndentOption;
|
ZLIntegerRangeOption LineEndIndentOption;
|
||||||
ZLIntegerRangeOption FirstLineIndentDeltaOption;
|
|
||||||
|
|
||||||
ZLIntegerOption AlignmentOption;
|
ZLIntegerOption AlignmentOption;
|
||||||
|
|
||||||
ZLDoubleOption LineSpaceOption;
|
ZLDoubleOption LineSpaceOption;
|
||||||
ZLIntegerOption LineSpacePercentOption;
|
ZLIntegerOption LineSpacePercentOption;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ZLIntegerRangeOption FirstLineIndentDeltaOption;
|
||||||
|
|
||||||
|
public:
|
||||||
|
ZLTextStyleEntry::SizeUnit SpaceBeforeOptionUnit;
|
||||||
|
ZLTextStyleEntry::SizeUnit SpaceAfterOptionUnit;
|
||||||
|
ZLTextStyleEntry::SizeUnit LineStartIndentOptionUnit;
|
||||||
|
ZLTextStyleEntry::SizeUnit LineEndIndentOptionUnit;
|
||||||
|
ZLTextStyleEntry::SizeUnit FirstLineIndentDeltaOptionUnit;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZLTextStyleCollection {
|
class ZLTextStyleCollection {
|
||||||
|
@ -103,11 +121,15 @@ private:
|
||||||
friend class ZLTextStyleReader;
|
friend class ZLTextStyleReader;
|
||||||
};
|
};
|
||||||
|
|
||||||
inline ZLTextStyleDecoration::~ZLTextStyleDecoration() {}
|
inline ZLTextStyleDecoration::~ZLTextStyleDecoration() { delete myFirstLineIndentDelta; }
|
||||||
inline bool ZLTextStyleDecoration::isFullDecoration() const { return false; }
|
|
||||||
inline const std::string &ZLTextStyleDecoration::name() const { return myName; }
|
inline const std::string &ZLTextStyleDecoration::name() const { return myName; }
|
||||||
|
inline int* ZLTextStyleDecoration::firstLineIndentDelta(ZLTextStyleEntry::SizeUnit &unit) const {
|
||||||
|
unit = myFirstLineIndentDeltaUnit; return myFirstLineIndentDelta;
|
||||||
|
}
|
||||||
|
inline void ZLTextStyleDecoration::setFirstLineIndentDelta(int indent, ZLTextStyleEntry::SizeUnit unit) {
|
||||||
|
delete myFirstLineIndentDelta; myFirstLineIndentDelta = new int(indent); myFirstLineIndentDeltaUnit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
inline ZLTextFullStyleDecoration::~ZLTextFullStyleDecoration() {}
|
inline ZLTextFullStyleDecoration::~ZLTextFullStyleDecoration() {}
|
||||||
inline bool ZLTextFullStyleDecoration::isFullDecoration() const { return true; }
|
|
||||||
|
|
||||||
#endif /* __ZLTEXTSTYLECOLLECTION_H__ */
|
#endif /* __ZLTEXTSTYLECOLLECTION_H__ */
|
||||||
|
|
|
@ -114,7 +114,7 @@ size_t ZLTextView::PositionIndicator::endTextIndex() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZLTextView::PositionIndicator::drawExtraText(const std::string &text) {
|
void ZLTextView::PositionIndicator::drawExtraText(const std::string &text) {
|
||||||
context().setFont(myTextView.baseStyle()->fontFamily(), myInfo.fontSize(), false, false);
|
context().setFont(context().pickFontFamily(myTextView.baseStyle()->fontFamilies()), myInfo.fontSize(), false, false);
|
||||||
context().setColor(myTextView.color());
|
context().setColor(myTextView.color());
|
||||||
|
|
||||||
int width = context().stringWidth(text.data(), text.length(), false);
|
int width = context().stringWidth(text.data(), text.length(), false);
|
||||||
|
|
Loading…
Reference in a new issue