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