1 /*
2  For general Scribus (>=1.3.2) copyright and licensing information please refer
3  to the COPYING file provided with the program. Following this notice may exist
4  a copyright and/or license notice that predates the release of Scribus 1.3.2
5  for which a new license (GPL+exception) is in place.
6  */
7 
8 
9 #include <QObject>
10 #include <QDebug>
11 
12 #include "commonstrings.h"
13 #include "sctextstruct.h"
14 #include "scfonts.h"
15 #include "resourcecollection.h"
16 
17 #include "styles/style.h"
18 #include "charstyle.h"
19 #include "desaxe/saxiohelper.h"
20 #include "desaxe/simple_actions.h"
21 #include "prefsmanager.h"
22 #include "util_math.h"
23 
operator &=(const StyleFlag & right)24 StyleFlag& StyleFlag::operator&= (const StyleFlag& right)
25 {
26 	int result = static_cast<int>(value) & static_cast<int>(right.value);
27 	value = static_cast<StyleFlagValue>(result);
28 	return *this;
29 }
30 
operator |=(const StyleFlag & right)31 StyleFlag& StyleFlag::operator|= (const StyleFlag& right)
32 {
33 	int result = static_cast<int>(value) | static_cast<int>(right.value);
34 	value = static_cast<StyleFlagValue>(result);
35 	return *this;
36 }
37 
operator &(const StyleFlag & right)38 StyleFlag StyleFlag::operator& (const StyleFlag& right)
39 {
40 	int val = static_cast<int>(value) & static_cast<int>(right.value);
41 	StyleFlag result(static_cast<StyleFlagValue>(val));
42 	return result;
43 }
44 
operator &(int right)45 StyleFlag StyleFlag::operator& (int right)
46 {
47 	int val = static_cast<int>(value) & right;
48 	StyleFlag result(static_cast<StyleFlagValue>(val));
49 	return result;
50 }
51 
operator |(const StyleFlag & right)52 StyleFlag StyleFlag::operator| (const StyleFlag& right)
53 {
54 	int val = static_cast<int>(value) | static_cast<int>(right.value);
55 	StyleFlag result(static_cast<StyleFlagValue>(val));
56 	return result;
57 }
58 
operator ^(const StyleFlag & right)59 StyleFlag StyleFlag::operator^ (const StyleFlag& right)
60 {
61 	int val = static_cast<int>(value) ^ static_cast<int>(right.value);
62 	StyleFlag result(static_cast<StyleFlagValue>(val));
63 	return result;
64 }
65 
operator ^(int right)66 StyleFlag StyleFlag::operator^ (int right)
67 {
68 	int val = static_cast<int>(value) ^ right;
69 	StyleFlag result(static_cast<StyleFlagValue>(val));
70 	return result;
71 }
72 
operator ~()73 StyleFlag StyleFlag::operator~ ()
74 {
75 	int val = ~ static_cast<int>(value);
76 	StyleFlag result(static_cast<StyleFlagValue>(val));
77 	return result;
78 }
79 
equivForShaping(const StyleFlag & right) const80 bool StyleFlag::equivForShaping(const StyleFlag& right) const
81 {
82 	int result = static_cast<int>( (value ^ right.value) & ScStyle_RunBreakingStyles);
83 	return (result == 0);
84 }
85 
operator ==(const StyleFlag & right) const86 bool StyleFlag::operator== (const StyleFlag& right) const
87 {
88 	int result = static_cast<int>( (value ^ right.value) & ScStyle_UserStyles);
89 	return (result == 0);
90 }
91 
operator ==(const StyleFlagValue right) const92 bool StyleFlag::operator== (const StyleFlagValue right) const
93 {
94 	int result = static_cast<int>( (value ^ right) & ScStyle_UserStyles);
95 	return (result == 0);
96 }
97 
operator ==(int right) const98 bool StyleFlag::operator== (int right) const
99 {
100 	int result = static_cast<int>( (value ^ right) & ScStyle_UserStyles);
101 	return (result == 0);
102 }
103 
operator !=(const StyleFlag & right) const104 bool StyleFlag::operator!= (const StyleFlag& right) const
105 {
106 	return !(*this == right);
107 }
108 
operator !=(const StyleFlagValue right) const109 bool StyleFlag::operator!= (const StyleFlagValue right) const
110 {
111 	return !(*this == right);
112 }
113 
114 
applyCharStyle(const CharStyle & other)115 void CharStyle::applyCharStyle(const CharStyle & other)
116 {
117 	if (other.hasParent() && (other.parent() != BaseStyle::INHERIT_PARENT))
118 	{
119 		setStyle(other);
120 		return;
121 	}
122 	BaseStyle::applyStyle(other);
123 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
124 	if (! other.inh_##attr_NAME) \
125 		set##attr_NAME(other.m_##attr_NAME);
126 #include "charstyle.attrdefs.cxx"
127 #undef ATTRDEF
128 	updateFeatures();
129 }
130 
eraseCharStyle(const CharStyle & other)131 void CharStyle::eraseCharStyle(const CharStyle & other)
132 {
133 	other.validate();
134 	BaseStyle::eraseStyle(other);
135 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
136 	if (!inh_##attr_NAME && m_##attr_NAME == other.m_##attr_NAME) \
137 		reset##attr_NAME();
138 #include "charstyle.attrdefs.cxx"
139 #undef ATTRDEF
140 	updateFeatures();
141 }
142 
eraseDirectFormatting()143 void CharStyle::eraseDirectFormatting()
144 {
145 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
146 	if (!inh_##attr_NAME) \
147 		reset##attr_NAME();
148 #include "charstyle.attrdefs.cxx"
149 #undef ATTRDEF
150 	updateFeatures();
151 }
152 
equiv(const BaseStyle & other) const153 bool CharStyle::equiv(const BaseStyle & other) const
154 {
155 	other.validate();
156 	const CharStyle * oth = reinterpret_cast<const CharStyle*> ( & other );
157 	return  oth &&
158 		parent() == oth->parent()
159 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
160 		&& (inh_##attr_NAME == oth->inh_##attr_NAME) \
161 		&& (inh_##attr_NAME || isequiv(m_##attr_NAME, oth->m_##attr_NAME))
162 #include "charstyle.attrdefs.cxx"
163 #undef ATTRDEF
164 	    ;
165 }
166 
equivForShaping(const CharStyle & other) const167 bool CharStyle::equivForShaping(const CharStyle& other) const
168 {
169 	other.validate();
170 
171 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
172 	if (attr_BREAKSHAPING && !isequiv(m_##attr_NAME, other.m_##attr_NAME)) \
173 		return false;
174 #include "charstyle.attrdefs.cxx"
175 #undef ATTRDEF
176 	if (!m_Effects.equivForShaping(other.m_Effects))
177 		return false;
178 	return true;
179 }
180 
displayName() const181 QString CharStyle::displayName() const
182 {
183 	if (isDefaultStyle())
184 		return CommonStrings::trDefaultCharacterStyle;
185 	if (hasName() || !hasParent() || ! m_context)
186 		return name();
187 //	else if ( inheritsAll() )
188 //		return parent()->displayName();
189 	return parentStyle()->displayName() + "+";
190 }
191 
asString() const192 QString CharStyle::asString() const
193 {
194 	//This function creates the string used for text properties changes in Action History
195 	QString result;
196 	if (!inh_Font)
197 		result += (QObject::tr("font %1").arg(font().scName()) + " ");
198 	if (!inh_FontSize)
199 		result += (QObject::tr("size %1").arg(fontSize()) + " ");
200 	if (!inh_FontFeatures)
201 		result += (QObject::tr("+fontfeatures %1").arg(fontFeatures()) + " ");
202 	if (!inh_Features)
203 		result += (QObject::tr("+style") + " ");
204 	if (!inh_StrokeColor || !inh_StrokeShade || !inh_FillColor || !inh_FillShade)
205 		result += (QObject::tr("+color") + " ");
206 	if (!inh_UnderlineWidth || !inh_UnderlineOffset)
207 		result += ((underlineWidth() > 0 ? QObject::tr("+underline") : QObject::tr("-underline")) + " ");
208 	if (!inh_StrikethruWidth || !inh_StrikethruOffset )
209 		result += ((strikethruWidth() > 0 ? QObject::tr("+strikeout") : QObject::tr("-strikeout")) + " ");
210 	if (!inh_ShadowXOffset || !inh_ShadowYOffset )
211 		result += ((shadowXOffset() != 0 || shadowYOffset() != 0 ? QObject::tr("+shadow") : QObject::tr("-shadow")) + " ");
212 	if (!inh_OutlineWidth)
213 		result += ((outlineWidth() > 0 ? QObject::tr("+outline") : QObject::tr("-outline")) + " ");
214 	if (!inh_Tracking)
215 		result += ((tracking() > 0 ? QObject::tr("+tracking %1").arg(tracking()) : QObject::tr("-tracking")) + " ");
216 	if (!inh_BaselineOffset)
217 		result += (QObject::tr("+baseline %1").arg(baselineOffset()) + " ");
218 	if (!inh_ScaleH || !inh_ScaleV)
219 		result += (QObject::tr("+stretch") + " ");
220 	if (hasParent())
221 		result += QObject::tr("parent= %1").arg(parent());
222 	return result.trimmed();
223 }
224 
225 
update(const StyleContext * context)226 void CharStyle::update(const StyleContext* context)
227 {
228 	BaseStyle::update(context);
229 	const CharStyle * oth = dynamic_cast<const CharStyle*> ( parentStyle() );
230 	if (oth) {
231 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
232 		if (inh_##attr_NAME) \
233 			m_##attr_NAME = oth->attr_GETTER();
234 #include "charstyle.attrdefs.cxx"
235 #undef ATTRDEF
236 	}
237 	updateFeatures();
238 }
239 
240 
241 const QString CharStyle::INHERIT = "inherit";
242 const QString CharStyle::BOLD = "bold";
243 const QString CharStyle::ITALIC = "italic";
244 const QString CharStyle::UNDERLINE = "underline";
245 const QString CharStyle::UNDERLINEWORDS = "underlinewords";
246 const QString CharStyle::STRIKETHROUGH = "strike";
247 const QString CharStyle::SUPERSCRIPT = "superscript";
248 const QString CharStyle::SUBSCRIPT = "subscript";
249 const QString CharStyle::OUTLINE = "outline";
250 const QString CharStyle::SHADOWED = "shadowed";
251 const QString CharStyle::ALLCAPS = "allcaps";
252 const QString CharStyle::SMALLCAPS = "smallcaps";
253 // This is for loading legacy docs only. Scribus 1.3.4 should write soft hyphens in another way
254 static const QString SHYPHEN = "shyphen";
255 
256 
featureList() const257 QStringList StyleFlag::featureList() const
258 {
259 	QStringList result(CharStyle::INHERIT);
260 	if (*this & ScStyle_Underline)
261 		result << CharStyle::UNDERLINE;
262 	if (*this & ScStyle_UnderlineWords)
263 		result << CharStyle::UNDERLINEWORDS;
264 	if (*this & ScStyle_Strikethrough)
265 		result << CharStyle::STRIKETHROUGH;
266 	if (*this & ScStyle_Superscript)
267 		result << CharStyle::SUPERSCRIPT;
268 	if (*this & ScStyle_Subscript)
269 		result << CharStyle::SUBSCRIPT;
270 	if (*this & ScStyle_Outline)
271 		result << CharStyle::OUTLINE;
272 	if (*this & ScStyle_Shadowed)
273 		result << CharStyle::SHADOWED;
274 	if (*this & ScStyle_AllCaps)
275 		result << CharStyle::ALLCAPS;
276 	if (*this & ScStyle_SmallCaps)
277 		result << CharStyle::SMALLCAPS;
278 	if (*this & ScStyle_HyphenationPossible)
279 		result << SHYPHEN;
280 	return result;
281 }
282 
283 
updateFeatures()284 void CharStyle::updateFeatures()
285 {
286 	m_Effects &= ~ScStyle_UserStyles;
287 	runFeatures(m_Features, reinterpret_cast<const CharStyle*>(parentStyle()));
288 /* need to access global fontlist :-/
289 	if (!font().name().endsWith(fontVariant()))
290 	{
291 		m_font = ScFonts.instance().findFont(font().family() + fontVariant());
292 	}
293  */
294 }
295 
296 
runFeatures(const QStringList & featureList,const CharStyle * parent)297 void CharStyle::runFeatures(const QStringList& featureList, const CharStyle* parent)
298 {
299 	QStringList::ConstIterator it;
300 	QStringList::ConstIterator itEnd = featureList.end();
301 	for (it = featureList.begin(); it != itEnd; ++it)
302 	{
303 		QString feature = it->trimmed();
304 		if (feature == INHERIT)
305 		{
306 			if (parent)
307 				runFeatures(parent->features(), reinterpret_cast<const CharStyle*>(parent->parentStyle()));
308 			continue;
309 		}
310 		int set = feature.startsWith('-') ? 0 : 1;
311 		int invert = 1 - set;
312 		if (invert)
313 			feature = feature.mid(1);
314 
315 //		if (feature == BOLD)
316 //		{
317 //			// (de)select bolder font
318 //		}
319 //		else if (feature == ITALIC)
320 //		{
321 //			// (de)select italic font
322 //		}
323 //		else
324 		if (feature == UNDERLINE)
325 		{
326 			m_Effects &= ~(invert * ScStyle_Underline);
327 			m_Effects |= set * ScStyle_Underline;
328 		}
329 		else if (feature == UNDERLINEWORDS)
330 		{
331 			m_Effects &= ~(invert * ScStyle_UnderlineWords);
332 			m_Effects |= set * ScStyle_UnderlineWords;
333 		}
334 		else if (feature == STRIKETHROUGH)
335 		{
336 			m_Effects &= ~(invert * ScStyle_Strikethrough);
337 			m_Effects |= set * ScStyle_Strikethrough;
338 		}
339 		else if (feature == SUPERSCRIPT)
340 		{
341 			m_Effects &= ~(invert * ScStyle_Superscript);
342 			m_Effects |= set * ScStyle_Superscript;
343 		}
344 		else if (feature == SUBSCRIPT)
345 		{
346 			m_Effects &= ~(invert * ScStyle_Subscript);
347 			m_Effects |= set * ScStyle_Subscript;
348 		}
349 		else if (feature == OUTLINE)
350 		{
351 			m_Effects &= ~(invert * ScStyle_Outline);
352 			m_Effects |= set * ScStyle_Outline;
353 		}
354 		else if (feature == SHADOWED)
355 		{
356 			m_Effects &= ~(invert * ScStyle_Shadowed);
357 			m_Effects |= set * ScStyle_Shadowed;
358 		}
359 		else if (feature == ALLCAPS)
360 		{
361 			m_Effects &= ~(invert * ScStyle_AllCaps);
362 			m_Effects |= set * ScStyle_AllCaps;
363 		}
364 		else if (feature == SMALLCAPS)
365 		{
366 			m_Effects &= ~(invert * ScStyle_SmallCaps);
367 			m_Effects |= set * ScStyle_SmallCaps;
368 		}
369 		else if (feature == SHYPHEN)
370 		{
371 			m_Effects &= ~(invert * ScStyle_HyphenationPossible);
372 			m_Effects |= set * ScStyle_HyphenationPossible;
373 		}
374 		else {
375 			qDebug("CharStyle: unknown feature: %s", feature.toLocal8Bit().constData());
376 		}
377 
378 	}
379 }
380 
381 
setStyle(const CharStyle & other)382 void CharStyle::setStyle(const CharStyle& other)
383 {
384 	other.validate();
385 	setParent(other.parent());
386 	m_contextversion = -1;
387 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
388 	inh_##attr_NAME = other.inh_##attr_NAME; \
389 	m_##attr_NAME = other.m_##attr_NAME;
390 #include "charstyle.attrdefs.cxx"
391 #undef ATTRDEF
392 	updateFeatures();
393 }
394 
getNamedResources(ResourceCollection & lists) const395 void CharStyle::getNamedResources(ResourceCollection& lists) const
396 {
397 //	QString colorName;
398 
399 	for (const BaseStyle* sty = parentStyle(); sty != nullptr; sty = sty->parentStyle())
400 		lists.collectCharStyle(sty->name());
401 
402 	const QString& fillColorName = fillColor();
403 	if (fillColorName != CommonStrings::None)
404 		lists.collectColor(fillColorName);
405 
406 	lists.collectFontfeatures(fontFeatures());
407 
408 	const QString& strokeColorName = strokeColor();
409 	if (strokeColorName != CommonStrings::None)
410 		lists.collectColor(strokeColorName);
411 
412 	const QString& backColorName = backColor();
413 	if (backColorName != CommonStrings::None)
414 		lists.collectColor(backColorName);
415 
416 	lists.collectFont(font().scName());
417 }
418 
replaceNamedResources(ResourceCollection & newNames)419 void CharStyle::replaceNamedResources(ResourceCollection& newNames)
420 {
421 	QMap<QString, QString>::ConstIterator it;
422 
423 	if (!inh_FillColor && (it = newNames.colors().find(fillColor())) != newNames.colors().end())
424 		setFillColor(it.value());
425 
426 	if (!inh_FontFeatures && (it = newNames.fontfeatures().find(fontFeatures())) != newNames.fontfeatures().end())
427 		setFontFeatures(it.value());
428 
429 	if (!inh_StrokeColor && (it = newNames.colors().find(strokeColor())) != newNames.colors().end())
430 		setStrokeColor(it.value());
431 
432 	if (!inh_BackColor && (it = newNames.colors().find(backColor())) != newNames.colors().end())
433 		setBackColor(it.value());
434 
435 	if (hasParent() && (it = newNames.charStyles().find(parent())) != newNames.charStyles().end())
436 		setParent(it.value());
437 
438 	if (!inh_Font && (it = newNames.fonts().find(font().scName())) != newNames.fonts().end())
439 		setFont(newNames.availableFonts->findFont(it.value(), nullptr));
440 	updateFeatures();
441 }
442 
443 /*
444 bool CharStyle::definesAll() const
445 {
446 	return definesLineSpacing() &&
447 	definesLeftMargin() &&
448 	definesRightMargin() &&
449 	definesFirstIndent() &&
450 	definesAlignment() &&
451 	definesGapBefore()  &&
452 	definesLineSpacingMode()  &&
453 	definesGapAfter()  &&
454 	definesHasDropCap() &&
455 	definesDropCapOffset() &&
456 	definesDropCapLines() &&
457 	definesUseBaselineGrid() &&
458 	charStyle().definesAll() ;
459 
460 }
461 
462 // equiv. to "*this == CharStyle()"
463 bool CharStyle::inheritsAll() const
464 {
465 	return inheritsLineSpacing() &&
466 	inheritsLeftMargin() &&
467 	inheritsRightMargin() &&
468 	inheritsFirstIndent() &&
469 	inheritsAlignment() &&
470 	inheritsGapBefore()  &&
471 	inheritsLineSpacingMode()  &&
472 	inheritsGapAfter()  &&
473 	inheritsHasDropCap() &&
474 	inheritsDropCapOffset() &&
475 	inheritsDropCapLines() &&
476 	inheritsUseBaselineGrid() &&
477 	charStyle().inheritsAll() ;
478 }
479 */
480 
481 
toXMLString(StyleFlag val)482 Xml_string toXMLString(StyleFlag val)
483 {
484 	return toXMLString(static_cast<unsigned int>(val & ScStyle_UserStyles));
485 }
486 
487 
saxx(SaxHandler & handler,const Xml_string & elemtag) const488 void CharStyle::saxx(SaxHandler& handler, const Xml_string& elemtag) const
489 {
490 	Xml_attr att;
491 	BaseStyle::saxxAttributes(att);
492 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
493 	if (!inh_##attr_NAME) \
494 		att.insert(# attr_NAME, toXMLString(m_##attr_NAME));
495 #include "charstyle.attrdefs.cxx"
496 #undef ATTRDEF
497 	if (!name().isEmpty())
498 		att["id"] = mkXMLName(elemtag + name());
499 	handler.begin(elemtag, att);
500 //	if (hasParent() && parentStyle())
501 //		parentStyle()->saxx(handler);
502 	handler.end(elemtag);
503 }
504 
505 
506 template<>
parse(const Xml_string & str)507 StyleFlag parse<StyleFlag>(const Xml_string& str)
508 {
509 	return StyleFlag(parseInt(str));
510 }
511 
512 template<>
parse(const Xml_string & str)513 ScFace parse<ScFace>(const Xml_string& str)
514 {
515 	// FIXME: enable font substitution here
516 	return PrefsManager::instance().appPrefs.fontPrefs.AvailFonts[str];
517 }
518 
519 
520 using namespace desaxe;
521 
522 
523 const Xml_string CharStyle::saxxDefaultElem("charstyle");
524 
desaxeRules(const Xml_string & prefixPattern,Digester & ruleset,const Xml_string & elemtag)525 void CharStyle::desaxeRules(const Xml_string& prefixPattern, Digester& ruleset, const Xml_string& elemtag)
526 {
527 	Xml_string stylePrefix(Digester::concat(prefixPattern, elemtag));
528 	ruleset.addRule(stylePrefix, Factory<CharStyle>());
529 	ruleset.addRule(stylePrefix, IdRef<CharStyle>());
530 	BaseStyle::desaxeRules<CharStyle>(prefixPattern, ruleset, elemtag);
531 #define ATTRDEF(attr_TYPE, attr_GETTER, attr_NAME, attr_DEFAULT, attr_BREAKSHAPING) \
532 	ruleset.addRule(stylePrefix, SetAttributeWithConversion<CharStyle, attr_TYPE> ( & CharStyle::set##attr_NAME,  # attr_NAME, &parse<attr_TYPE> ));
533 #include "charstyle.attrdefs.cxx"
534 #undef ATTRDEF
535 }
536 
537 //kate: replace-tabs 0;
538