1 /*
2 * Copyright (C) 2004-2010 Geometer Plus <contact@geometerplus.com>
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301, USA.
18 */
19
20 #include <cstdlib>
21
22 #include <ZLStringUtil.h>
23
24 #include "StyleSheetTable.h"
25
isEmpty() const26 bool StyleSheetTable::isEmpty() const {
27 return myControlMap.empty() && myPageBreakBeforeMap.empty() && myPageBreakAfterMap.empty();
28 }
29
addMap(const std::string & tag,const std::string & aClass,const AttributeMap & map)30 void StyleSheetTable::addMap(const std::string &tag, const std::string &aClass, const AttributeMap &map) {
31 if ((!tag.empty() || !aClass.empty()) && !map.empty()) {
32 Key key(tag, aClass);
33 myControlMap[key] = createControl(map);
34 const std::vector<std::string> &pbb = values(map, "page-break-before");
35 if (!pbb.empty()) {
36 if ((pbb[0] == "always") ||
37 (pbb[0] == "left") ||
38 (pbb[0] == "right")) {
39 myPageBreakBeforeMap[key] = true;
40 } else if (pbb[0] == "avoid") {
41 myPageBreakBeforeMap[key] = false;
42 }
43 }
44 const std::vector<std::string> &pba = values(map, "page-break-after");
45 if (!pba.empty()) {
46 if ((pba[0] == "always") ||
47 (pba[0] == "left") ||
48 (pba[0] == "right")) {
49 myPageBreakAfterMap[key] = true;
50 } else if (pba[0] == "avoid") {
51 myPageBreakAfterMap[key] = false;
52 }
53 }
54 }
55 }
56
parseLength(const std::string & toParse,short & size,ZLTextStyleEntry::SizeUnit & unit)57 static void parseLength(const std::string &toParse, short &size, ZLTextStyleEntry::SizeUnit &unit) {
58 if (ZLStringUtil::stringEndsWith(toParse, "%")) {
59 unit = ZLTextStyleEntry::SIZE_UNIT_PERCENT;
60 size = atoi(toParse.c_str());
61 } else if (ZLStringUtil::stringEndsWith(toParse, "em")) {
62 unit = ZLTextStyleEntry::SIZE_UNIT_EM_100;
63 size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
64 } else if (ZLStringUtil::stringEndsWith(toParse, "ex")) {
65 unit = ZLTextStyleEntry::SIZE_UNIT_EX_100;
66 size = (short)(100 * ZLStringUtil::stringToDouble(toParse, 0));
67 } else {
68 unit = ZLTextStyleEntry::SIZE_UNIT_PIXEL;
69 size = atoi(toParse.c_str());
70 }
71 }
72
setLength(ZLTextStyleEntry & entry,ZLTextStyleEntry::Length name,const AttributeMap & map,const std::string & attributeName)73 void StyleSheetTable::setLength(ZLTextStyleEntry &entry, ZLTextStyleEntry::Length name, const AttributeMap &map, const std::string &attributeName) {
74 StyleSheetTable::AttributeMap::const_iterator it = map.find(attributeName);
75 if (it == map.end()) {
76 return;
77 }
78 const std::vector<std::string> &values = it->second;
79 if (!values.empty() && !values[0].empty()) {
80 short size;
81 ZLTextStyleEntry::SizeUnit unit;
82 parseLength(values[0], size, unit);
83 entry.setLength(name, size, unit);
84 }
85 }
86
doBreakBefore(const std::string & tag,const std::string & aClass) const87 bool StyleSheetTable::doBreakBefore(const std::string &tag, const std::string &aClass) const {
88 std::map<Key,bool>::const_iterator it = myPageBreakBeforeMap.find(Key(tag, aClass));
89 if (it != myPageBreakBeforeMap.end()) {
90 return it->second;
91 }
92
93 it = myPageBreakBeforeMap.find(Key("", aClass));
94 if (it != myPageBreakBeforeMap.end()) {
95 return it->second;
96 }
97
98 it = myPageBreakBeforeMap.find(Key(tag, ""));
99 if (it != myPageBreakBeforeMap.end()) {
100 return it->second;
101 }
102
103 return false;
104 }
105
doBreakAfter(const std::string & tag,const std::string & aClass) const106 bool StyleSheetTable::doBreakAfter(const std::string &tag, const std::string &aClass) const {
107 std::map<Key,bool>::const_iterator it = myPageBreakAfterMap.find(Key(tag, aClass));
108 if (it != myPageBreakAfterMap.end()) {
109 return it->second;
110 }
111
112 it = myPageBreakAfterMap.find(Key("", aClass));
113 if (it != myPageBreakAfterMap.end()) {
114 return it->second;
115 }
116
117 it = myPageBreakAfterMap.find(Key(tag, ""));
118 if (it != myPageBreakAfterMap.end()) {
119 return it->second;
120 }
121
122 return false;
123 }
124
control(const std::string & tag,const std::string & aClass) const125 shared_ptr<ZLTextStyleEntry> StyleSheetTable::control(const std::string &tag, const std::string &aClass) const {
126 std::map<Key,shared_ptr<ZLTextStyleEntry> >::const_iterator it =
127 myControlMap.find(Key(tag, aClass));
128 return (it != myControlMap.end()) ? it->second : 0;
129 }
130
values(const AttributeMap & map,const std::string & name)131 const std::vector<std::string> &StyleSheetTable::values(const AttributeMap &map, const std::string &name) {
132 const AttributeMap::const_iterator it = map.find(name);
133 if (it != map.end()) {
134 return it->second;
135 }
136 static const std::vector<std::string> emptyVector;
137 return emptyVector;
138 }
139
createControl(const AttributeMap & styles)140 shared_ptr<ZLTextStyleEntry> StyleSheetTable::createControl(const AttributeMap &styles) {
141 shared_ptr<ZLTextStyleEntry> entry = new ZLTextStyleEntry();
142
143 const std::vector<std::string> &alignment = values(styles, "text-align");
144 if (!alignment.empty()) {
145 if (alignment[0] == "justify") {
146 entry->setAlignmentType(ALIGN_JUSTIFY);
147 } else if (alignment[0] == "left") {
148 entry->setAlignmentType(ALIGN_LEFT);
149 } else if (alignment[0] == "right") {
150 entry->setAlignmentType(ALIGN_RIGHT);
151 } else if (alignment[0] == "center") {
152 entry->setAlignmentType(ALIGN_CENTER);
153 }
154 }
155
156 const std::vector<std::string> &bold = values(styles, "font-weight");
157 if (!bold.empty()) {
158 int num = -1;
159 if (bold[0] == "bold") {
160 num = 700;
161 } else if (bold[0] == "normal") {
162 num = 400;
163 } else if ((bold[0].length() == 3) &&
164 (bold[0][1] == '0') &&
165 (bold[0][2] == '0') &&
166 (bold[0][0] >= '1') &&
167 (bold[0][0] <= '9')) {
168 num = 100 * (bold[0][0] - '0');
169 } else if (bold[0] == "bolder") {
170 } else if (bold[0] == "lighter") {
171 }
172 if (num != -1) {
173 entry->setFontModifier(FONT_MODIFIER_BOLD, num >= 600);
174 }
175 }
176
177 const std::vector<std::string> &italic = values(styles, "font-style");
178 if (!italic.empty()) {
179 entry->setFontModifier(FONT_MODIFIER_ITALIC, italic[0] == "italic");
180 }
181
182 const std::vector<std::string> &variant = values(styles, "font-variant");
183 if (!variant.empty()) {
184 entry->setFontModifier(FONT_MODIFIER_SMALLCAPS, variant[0] == "small-caps");
185 }
186
187 const std::vector<std::string> &fontFamily = values(styles, "font-family");
188 if (!fontFamily.empty() && !fontFamily[0].empty()) {
189 entry->setFontFamily(fontFamily[0]);
190 }
191
192 const std::vector<std::string> &fontSize = values(styles, "font-size");
193 if (!fontSize.empty()) {
194 if (fontSize[0] == "xx-small") {
195 entry->setFontSizeMag(-3);
196 } else if (fontSize[0] == "x-small") {
197 entry->setFontSizeMag(-2);
198 } else if (fontSize[0] == "small") {
199 entry->setFontSizeMag(-1);
200 } else if (fontSize[0] == "medium") {
201 entry->setFontSizeMag(0);
202 } else if (fontSize[0] == "large") {
203 entry->setFontSizeMag(1);
204 } else if (fontSize[0] == "x-large") {
205 entry->setFontSizeMag(2);
206 } else if (fontSize[0] == "xx-large") {
207 entry->setFontSizeMag(3);
208 }
209 }
210
211 setLength(*entry, ZLTextStyleEntry::LENGTH_LEFT_INDENT, styles, "margin-left");
212 setLength(*entry, ZLTextStyleEntry::LENGTH_RIGHT_INDENT, styles, "margin-right");
213 setLength(*entry, ZLTextStyleEntry::LENGTH_FIRST_LINE_INDENT_DELTA, styles, "text-indent");
214 setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "margin-top");
215 setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_BEFORE, styles, "padding-top");
216 setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "margin-bottom");
217 setLength(*entry, ZLTextStyleEntry::LENGTH_SPACE_AFTER, styles, "padding-bottom");
218
219 return entry;
220 }
221