1 /* This file is part of the KDE project
2  * Copyright (C) 2006-2009 Thomas Zander <zander@kde.org>
3  * Copyright (C) 2007 Sebastian Sauer <mail@dipe.org>
4  *  Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
5  * Copyright (C) 2008 Girish Ramakrishnan <girish@forwardbias.in>
6  * Copyright (C) 2011 Stuart Dickson <stuart@furkinfantasic.net>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 #include "KoCharacterStyle.h"
24 
25 #include "Styles_p.h"
26 
27 #include <QTextBlock>
28 #include <QTextCursor>
29 #include <QFontDatabase>
30 
31 #include <KoOdfLoadingContext.h>
32 #include <KoOdfStylesReader.h>
33 #include <KoXmlNS.h>
34 #include <KoXmlReader.h>
35 #include <KoUnit.h>
36 #include <KoStore.h>
37 #include <KoStoreDevice.h>
38 #include <KoGenStyle.h>
39 #include <KoShadowStyle.h>
40 #include <KoShapeLoadingContext.h>
41 #include <KoStyleStack.h>
42 #include "KoTextDocument.h"
43 
44 #ifdef SHOULD_BUILD_FONT_CONVERSION
45 #include <string.h>
46 #include <fontconfig/fontconfig.h>
47 #include <fontconfig/fcfreetype.h>
48 #include <ft2build.h>
49 #include FT_FREETYPE_H
50 #include FT_GLYPH_H
51 #include FT_TYPES_H
52 #include FT_OUTLINE_H
53 #include FT_RENDER_H
54 #include FT_TRUETYPE_TABLES_H
55 #include FT_SFNT_NAMES_H
56 #endif
57 
58 #include "TextDebug.h"
59 #include "KoTextDebug.h"
60 
61 #ifdef SHOULD_BUILD_FONT_CONVERSION
62     QMap<QString,qreal> textScaleMap;
63 #endif //SHOULD_BUILD_FONT_CONVERSION
64 
65 class Q_DECL_HIDDEN KoCharacterStyle::Private
66 {
67 public:
68     Private();
~Private()69     ~Private() { }
70 
setProperty(int key,const QVariant & value)71     void setProperty(int key, const QVariant &value) {
72         stylesPrivate.add(key, value);
73     }
propertyDouble(int key) const74     qreal propertyDouble(int key) const {
75         QVariant variant = stylesPrivate.value(key);
76         if (variant.isNull()) {
77             if (parentStyle)
78                 return parentStyle->d->propertyDouble(key);
79             else if (defaultStyle)
80                 return defaultStyle->d->propertyDouble(key);
81             return 0.0;
82         }
83         return variant.toDouble();
84     }
propertyInt(int key) const85     int propertyInt(int key) const {
86         QVariant variant = stylesPrivate.value(key);
87         if (variant.isNull()) {
88             if (parentStyle)
89                 return parentStyle->d->propertyInt(key);
90             else if (defaultStyle)
91                 return defaultStyle->d->propertyInt(key);
92             return 0;
93         }
94         return variant.toInt();
95     }
propertyString(int key) const96     QString propertyString(int key) const {
97         QVariant variant = stylesPrivate.value(key);
98         if (variant.isNull()) {
99             if (parentStyle)
100                 return parentStyle->d->propertyString(key);
101             else if (defaultStyle)
102                 return defaultStyle->d->propertyString(key);
103             return QString();
104         }
105         return qvariant_cast<QString>(variant);
106     }
propertyBoolean(int key) const107     bool propertyBoolean(int key) const {
108         QVariant variant = stylesPrivate.value(key);
109         if (variant.isNull()) {
110             if (parentStyle)
111                 return parentStyle->d->propertyBoolean(key);
112             else if (defaultStyle)
113                 return defaultStyle->d->propertyBoolean(key);
114             return false;
115         }
116         return variant.toBool();
117     }
propertyColor(int key) const118     QColor propertyColor(int key) const {
119         QVariant variant = stylesPrivate.value(key);
120         if (variant.isNull()) {
121             if (parentStyle)
122                 return parentStyle->d->propertyColor(key);
123             else if (defaultStyle)
124                 return defaultStyle->d->propertyColor(key);
125             return QColor();
126         }
127         return variant.value<QColor>();
128     }
129 
130     // problem with fonts in linux and windows is that true type fonts have more than one metric
131     // they have normal metric placed in font header table
132     //           microsoft metric placed in os2 table
133     //           apple metric placed in os2 table
134     // ms-word is probably using CreateFontIndirect and GetOutlineTextMetric function to calculate line height
135     // and this functions are using windows gdi environment which is using microsoft font metric placed in os2 table
136     // qt on linux is using normal font metric
137     // this two metrics are different and change from font to font
138     // this font stretch is needed if we want to have exact line height as in ms-word and oo
139     //
140     // font_size * font_stretch = windows_font_height
141     qreal calculateFontYStretch(const QString &fontFamily);
142 
143 
144     StylePrivate hardCodedDefaultStyle;
145 
146     QString name;
147     StylePrivate stylesPrivate;
148     KoCharacterStyle *parentStyle;
149     KoCharacterStyle *defaultStyle;
150     bool m_inUse;
151 };
152 
Private()153 KoCharacterStyle::Private::Private()
154     : parentStyle(0), defaultStyle(0), m_inUse(false)
155 {
156     //set the minimal default properties
157     hardCodedDefaultStyle.add(QTextFormat::FontFamily, QString("Sans Serif"));
158     hardCodedDefaultStyle.add(QTextFormat::FontPointSize, 12.0);
159     hardCodedDefaultStyle.add(QTextFormat::ForegroundBrush, QBrush(Qt::black));
160     hardCodedDefaultStyle.add(KoCharacterStyle::FontYStretch, 1);
161     hardCodedDefaultStyle.add(QTextFormat::FontHintingPreference, QFont::PreferNoHinting);
162 }
163 
164 
ensureMinimalProperties(QTextCharFormat & format) const165 void KoCharacterStyle::ensureMinimalProperties(QTextCharFormat &format) const
166 {
167     if (d->defaultStyle) {
168         QMap<int, QVariant> props = d->defaultStyle->d->stylesPrivate.properties();
169         QMap<int, QVariant>::const_iterator it = props.constBegin();
170         while (it != props.constEnd()) {
171             // in case there is already a foreground color don't apply the use window font color as then the foreground color
172             // should be used.
173             if (it.key() == KoCharacterStyle::UseWindowFontColor && format.hasProperty(QTextFormat::ForegroundBrush)) {
174                 ++it;
175                 continue;
176             }
177             // in case there is already a use window font color don't apply the foreground brush as this overwrite the foreground color
178             if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
179                 ++it;
180                 continue;
181             }
182 
183             if (!it.value().isNull() && !format.hasProperty(it.key())) {
184                 format.setProperty(it.key(), it.value());
185             }
186             ++it;
187         }
188     }
189     QMap<int, QVariant> props = d->hardCodedDefaultStyle.properties();
190     QMap<int, QVariant>::const_iterator it = props.constBegin();
191     while (it != props.constEnd()) {
192         if (!it.value().isNull() && !format.hasProperty(it.key())) {
193             if (it.key() == QTextFormat::ForegroundBrush && format.hasProperty(KoCharacterStyle::UseWindowFontColor)) {
194                 ++it;
195                 continue;
196             }
197 
198             format.setProperty(it.key(), it.value());
199         }
200         ++it;
201     }
202 }
203 
calculateFontYStretch(const QString & fontFamily)204 qreal KoCharacterStyle::Private::calculateFontYStretch(const QString &fontFamily)
205 {
206     qreal stretch = 1;
207 #ifdef SHOULD_BUILD_FONT_CONVERSION
208 
209     if (textScaleMap.contains(fontFamily)) {
210         return textScaleMap.value(fontFamily);
211     }
212 
213     FcResult result = FcResultMatch;
214     FT_Library  library;
215     FT_Face face;
216     int id = 0;
217     int error = 0;
218     QByteArray fontName = fontFamily.toLatin1();
219 
220     //TODO https://freedesktop.org/software/fontconfig/fontconfig-devel/x19.html
221     // we should specify slant and weight too
222     FcPattern *font = FcPatternBuild (0, FC_FAMILY, FcTypeString,fontName.data(), FC_SIZE, FcTypeDouble, (qreal)11, 0);
223     if (font == 0) {
224         return 1;
225     }
226 
227     // find font
228     FcPattern *matched = 0;
229     matched = FcFontMatch (0, font, &result);
230     if (matched == 0) {
231         FcPatternDestroy (font);
232         return 1;
233     }
234 
235     // get font family name
236     char * str = 0;
237     result = FcPatternGetString (matched, FC_FAMILY, 0,(FcChar8**) &str);
238     if (result != FcResultMatch || str == 0) {
239         FcPatternDestroy (font);
240         FcPatternDestroy (matched);
241         return 1;
242     }
243 
244     // check if right font was found
245     QByteArray foundFontFamily = QByteArray::fromRawData(str, strlen(str));
246     if (foundFontFamily != fontName) {
247         FcPatternDestroy (font);
248         FcPatternDestroy (matched);
249         return 1;
250     }
251 
252     // get path to font
253     str = 0;
254     result = FcPatternGetString (matched, FC_FILE, 0,(FcChar8**) &str);
255     if (result != FcResultMatch) {
256         FcPatternDestroy (font);
257         FcPatternDestroy (matched);
258         return 1;
259     }
260 
261     // get index of font inside the font file
262     result = FcPatternGetInteger (matched, FC_INDEX, 0, &id);
263     if (result != FcResultMatch) {
264         FcPatternDestroy (font);
265         FcPatternDestroy (matched);
266         return 1;
267     }
268 
269     // initialize freetype
270     error = FT_Init_FreeType( &library );
271     if (error) {
272         FcPatternDestroy (font);
273         FcPatternDestroy (matched);
274         return 1;
275     }
276 
277     // get font metric
278     error = FT_New_Face (library,(char *) str, id, &face);
279     if (error) {
280         FT_Done_FreeType(library);
281         FcPatternDestroy (font);
282         FcPatternDestroy (matched);
283         return 1;
284     }
285 
286     // get font metric os2 table
287     TT_OS2      *os2;
288     os2 = (TT_OS2 *) FT_Get_Sfnt_Table (face, ft_sfnt_os2);
289     if(os2 == 0) {
290         FT_Done_Face(face);
291         FT_Done_FreeType(library);
292         FcPatternDestroy (font);
293         FcPatternDestroy (matched);
294         return 1;
295     }
296 
297     // get font metric header table
298     TT_Header   *header;
299     header = (TT_Header *) FT_Get_Sfnt_Table (face, ft_sfnt_head);
300     if(header == 0) {
301         FT_Done_Face(face);
302         FT_Done_FreeType(library);
303         FcPatternDestroy (font);
304         FcPatternDestroy (matched);
305         return 1;
306     }
307 
308     // check if the data is valid
309     if (header->Units_Per_EM == 0 || (os2->usWinAscent + os2->usWinDescent) == 0) {
310         FT_Done_Face(face);
311         FT_Done_FreeType(library);
312         FcPatternDestroy (font);
313         FcPatternDestroy (matched);
314         return 1;
315     }
316 
317     // compute font height stretch
318     // font_size * font_stretch = windows_font_height
319     qreal height = os2->usWinAscent + os2->usWinDescent;
320     height = height * (2048 / header->Units_Per_EM);
321     stretch = (1.215 * height)/2500;
322     stretch = (1.15 * height)/2500; // seems a better guess but probably not right
323 
324     FT_Done_Face(face);
325     FT_Done_FreeType(library);
326     FcPatternDestroy (font);
327     FcPatternDestroy (matched);
328 
329     textScaleMap.insert(fontFamily, stretch);
330 #else
331     Q_UNUSED(fontFamily);
332 #endif //SHOULD_BUILD_FONT_CONVERSION
333 
334     return stretch;
335 }
KoCharacterStyle(QObject * parent)336 KoCharacterStyle::KoCharacterStyle(QObject *parent)
337         : QObject(parent), d(new Private())
338 {
339 }
340 
KoCharacterStyle(const QTextCharFormat & format,QObject * parent)341 KoCharacterStyle::KoCharacterStyle(const QTextCharFormat &format, QObject *parent)
342         : QObject(parent), d(new Private())
343 {
344     copyProperties(format);
345 }
346 
styleType() const347 KoCharacterStyle::Type KoCharacterStyle::styleType() const
348 {
349     return KoCharacterStyle::CharacterStyle;
350 }
351 
copyProperties(const KoCharacterStyle * style)352 void KoCharacterStyle::copyProperties(const KoCharacterStyle *style)
353 {
354     d->stylesPrivate = style->d->stylesPrivate;
355     setName(style->name()); // make sure we emit property change
356     d->parentStyle = style->d->parentStyle;
357     d->defaultStyle = style->d->defaultStyle;
358 }
359 
copyProperties(const QTextCharFormat & format)360 void KoCharacterStyle::copyProperties(const QTextCharFormat &format)
361 {
362     d->stylesPrivate = format.properties();
363 }
364 
clone(QObject * parent) const365 KoCharacterStyle *KoCharacterStyle::clone(QObject *parent) const
366 {
367     KoCharacterStyle *newStyle = new KoCharacterStyle(parent);
368     newStyle->copyProperties(this);
369     return newStyle;
370 }
371 
~KoCharacterStyle()372 KoCharacterStyle::~KoCharacterStyle()
373 {
374     delete d;
375 }
376 
setDefaultStyle(KoCharacterStyle * defaultStyle)377 void KoCharacterStyle::setDefaultStyle(KoCharacterStyle *defaultStyle)
378 {
379     d->defaultStyle = defaultStyle;
380 }
381 
setParentStyle(KoCharacterStyle * parent)382 void KoCharacterStyle::setParentStyle(KoCharacterStyle *parent)
383 {
384     d->parentStyle = parent;
385 }
386 
parentStyle() const387 KoCharacterStyle *KoCharacterStyle::parentStyle() const
388 {
389     return d->parentStyle;
390 }
391 
textOutline() const392 QPen KoCharacterStyle::textOutline() const
393 {
394     QVariant variant = value(QTextFormat::TextOutline);
395     if (variant.isNull()) {
396         return QPen(Qt::NoPen);
397     }
398     return qvariant_cast<QPen>(variant);
399 }
400 
background() const401 QBrush KoCharacterStyle::background() const
402 {
403     QVariant variant = value(QTextFormat::BackgroundBrush);
404 
405     if (variant.isNull()) {
406         return QBrush();
407     }
408     return qvariant_cast<QBrush>(variant);
409 }
410 
clearBackground()411 void KoCharacterStyle::clearBackground()
412 {
413     d->stylesPrivate.remove(QTextCharFormat::BackgroundBrush);
414 }
415 
foreground() const416 QBrush KoCharacterStyle::foreground() const
417 {
418     QVariant variant = value(QTextFormat::ForegroundBrush);
419     if (variant.isNull()) {
420         return QBrush();
421     }
422     return qvariant_cast<QBrush>(variant);
423 }
424 
clearForeground()425 void KoCharacterStyle::clearForeground()
426 {
427     d->stylesPrivate.remove(QTextCharFormat::ForegroundBrush);
428 }
429 
applyStyle(QTextCharFormat & format,bool emitSignal) const430 void KoCharacterStyle::applyStyle(QTextCharFormat &format, bool emitSignal) const
431 {
432     if (d->parentStyle) {
433         d->parentStyle->applyStyle(format);
434     }
435 
436     bool fontSizeSet = false; // if this style has already set size don't apply the relatives
437     const QMap<int, QVariant> props = d->stylesPrivate.properties();
438     QMap<int, QVariant>::const_iterator it = props.begin();
439     QList<int> clearProperty;
440     while (it != props.end()) {
441         if (!it.value().isNull()) {
442             if (it.key() == KoCharacterStyle::PercentageFontSize && !fontSizeSet) {
443                 qreal size = it.value().toDouble() / 100.0;
444                 if (format.hasProperty(QTextFormat::FontPointSize)) {
445                     size *= format.doubleProperty(QTextFormat::FontPointSize);
446                 } else {
447                     size *= 12.0;
448                 }
449                 format.setProperty(QTextFormat::FontPointSize, size);
450             }
451             else if (it.key() == KoCharacterStyle::AdditionalFontSize && !fontSizeSet) {
452                 qreal size = it.value().toDouble() / 100.0;
453                 if (format.hasProperty(QTextFormat::FontPointSize)) {
454                     size += format.doubleProperty(QTextFormat::FontPointSize);
455                 } else {
456                     size += 12.0;
457                 }
458                 format.setProperty(QTextFormat::FontPointSize, size);
459             }
460             else if (it.key() == QTextFormat::FontFamily) {
461                 if (!props.contains(QTextFormat::FontStyleHint)) {
462                     clearProperty.append(QTextFormat::FontStyleHint);
463                 }
464                 if (!props.contains(QTextFormat::FontFixedPitch)) {
465                     clearProperty.append(QTextFormat::FontFixedPitch);
466                 }
467                 if (!props.contains(KoCharacterStyle::FontCharset)) {
468                     clearProperty.append(KoCharacterStyle::FontCharset);
469                 }
470                 format.setProperty(it.key(), it.value());
471             }
472             else {
473                 debugText << "setProperty" << it.key() << it.value();
474                 format.setProperty(it.key(), it.value());
475             }
476 
477             if (it.key() == QTextFormat::FontPointSize) {
478                 fontSizeSet = true;
479             }
480 
481             if (it.key() == QTextFormat::ForegroundBrush) {
482                 clearProperty.append(KoCharacterStyle::UseWindowFontColor);
483             }
484             else if (it.key() == KoCharacterStyle::UseWindowFontColor) {
485                 clearProperty.append(QTextFormat::ForegroundBrush);
486             }
487         }
488         ++it;
489     }
490 
491     foreach (int property, clearProperty) {
492         debugText << "clearProperty" << property;
493         format.clearProperty(property);
494     }
495     if (emitSignal) {
496         emit styleApplied(this);
497         d->m_inUse = true;
498     }
499 }
500 
autoStyle(const QTextCharFormat & format,QTextCharFormat blockCharFormat) const501 KoCharacterStyle *KoCharacterStyle::autoStyle(const QTextCharFormat &format, QTextCharFormat blockCharFormat) const
502 {
503     KoCharacterStyle *autoStyle = new KoCharacterStyle(format);
504     applyStyle(blockCharFormat, false);
505     ensureMinimalProperties(blockCharFormat);
506     autoStyle->removeDuplicates(blockCharFormat);
507     autoStyle->setParentStyle(const_cast<KoCharacterStyle*>(this));
508     // remove StyleId if it is there as it is not a property of the style itself and will not be written out
509     // so it should not be part of the autostyle. As otherwise it can happen that the StyleId is the only
510     // property left and then we write out an empty style which is unneeded.
511     // we also need to remove the properties of links as they are saved differently
512     autoStyle->d->stylesPrivate.remove(StyleId);
513     autoStyle->d->stylesPrivate.remove(QTextFormat::IsAnchor);
514     autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorHref);
515     autoStyle->d->stylesPrivate.remove(QTextFormat::AnchorName);
516     return autoStyle;
517 }
518 
519 struct FragmentData
520 {
FragmentDataFragmentData521     FragmentData(const QTextCharFormat &format, int position, int length)
522     : format(format)
523     , position(position)
524     , length(length)
525     {}
526 
527     QTextCharFormat format;
528     int position;
529     int length;
530 };
531 
applyStyle(QTextBlock & block) const532 void KoCharacterStyle::applyStyle(QTextBlock &block) const
533 {
534     QTextCursor cursor(block);
535     QTextCharFormat cf = block.charFormat();
536 
537     if (!cf.isTableCellFormat()) {
538         cf = KoTextDocument(block.document()).frameCharFormat();
539     }
540 
541     applyStyle(cf);
542     ensureMinimalProperties(cf);
543     cursor.setBlockCharFormat(cf);
544 
545     // be sure that we keep the InlineInstanceId, anchor information and ChangeTrackerId when applying a style
546 
547     QList<FragmentData> fragments;
548     for (QTextBlock::iterator it = block.begin(); it != block.end(); ++it) {
549         QTextFragment currentFragment = it.fragment();
550         if (currentFragment.isValid()) {
551             QTextCharFormat format(cf);
552             QVariant v = currentFragment.charFormat().property(InlineInstanceId);
553             if (!v.isNull()) {
554                 format.setProperty(InlineInstanceId, v);
555             }
556 
557             v = currentFragment.charFormat().property(ChangeTrackerId);
558             if (!v.isNull()) {
559                 format.setProperty(ChangeTrackerId, v);
560             }
561 
562             if (currentFragment.charFormat().isAnchor()) {
563                 format.setAnchor(true);
564                 format.setAnchorHref(currentFragment.charFormat().anchorHref());
565             }
566             fragments.append(FragmentData(format, currentFragment.position(), currentFragment.length()));
567         }
568     }
569 
570     foreach (const FragmentData &fragment, fragments) {
571         cursor.setPosition(fragment.position);
572         cursor.setPosition(fragment.position + fragment.length, QTextCursor::KeepAnchor);
573         cursor.setCharFormat(fragment.format);
574     }
575 }
576 
applyStyle(QTextCursor * selection) const577 void KoCharacterStyle::applyStyle(QTextCursor *selection) const
578 {
579 // FIXME below should be done for each frament in the selection
580     QTextCharFormat cf = selection->charFormat();
581     applyStyle(cf);
582     ensureMinimalProperties(cf);
583     selection->setCharFormat(cf);
584 }
585 
unapplyStyle(QTextCharFormat & format) const586 void KoCharacterStyle::unapplyStyle(QTextCharFormat &format) const
587 {
588     if (d->parentStyle)
589         d->parentStyle->unapplyStyle(format);
590 
591     QMap<int, QVariant> props = d->stylesPrivate.properties();
592     QMap<int, QVariant>::const_iterator it = props.constBegin();
593     while (it != props.constEnd()) {
594         if (!it.value().isNull() && it.value() == format.property(it.key())) {
595            format.clearProperty(it.key());
596         }
597         ++it;
598     }
599 
600     props = d->hardCodedDefaultStyle.properties();
601     it = props.constBegin();
602     while (it != props.constEnd()) {
603         if (!it.value().isNull() && !format.hasProperty(it.key())) {
604             format.setProperty(it.key(), it.value());
605         }
606         ++it;
607     }
608 }
609 
isApplied() const610 bool KoCharacterStyle::isApplied() const
611 {
612     return d->m_inUse;
613 }
614 
unapplyStyle(QTextBlock & block) const615 void KoCharacterStyle::unapplyStyle(QTextBlock &block) const
616 {
617     QTextCursor cursor(block);
618     QTextCharFormat cf = cursor.blockCharFormat();
619     unapplyStyle(cf);
620     cursor.setBlockCharFormat(cf);
621 
622     if (block.length() == 1) // only the linefeed
623         return;
624     QTextBlock::iterator iter = block.end();
625     do {
626         --iter;
627         QTextFragment fragment = iter.fragment();
628         cursor.setPosition(fragment.position() + 1);
629         cf = cursor.charFormat();
630         unapplyStyle(cf);
631         cursor.setPosition(fragment.position());
632         cursor.setPosition(fragment.position() + fragment.length(), QTextCursor::KeepAnchor);
633         cursor.setCharFormat(cf);
634     } while (iter != block.begin());
635 }
636 
637 // OASIS 14.2.29
parseOdfLineWidth(const QString & width,KoCharacterStyle::LineWeight & lineWeight,qreal & lineWidth)638 static void parseOdfLineWidth(const QString &width, KoCharacterStyle::LineWeight &lineWeight, qreal &lineWidth)
639 {
640     lineWidth = 0;
641     lineWeight = KoCharacterStyle::AutoLineWeight;
642     if (width.isEmpty() || width == "auto")
643         lineWeight = KoCharacterStyle::AutoLineWeight;
644     else if (width == "normal")
645         lineWeight = KoCharacterStyle::NormalLineWeight;
646     else if (width == "bold")
647         lineWeight = KoCharacterStyle::BoldLineWeight;
648     else if (width == "thin")
649         lineWeight = KoCharacterStyle::ThinLineWeight;
650     else if (width == "dash")
651         lineWeight = KoCharacterStyle::DashLineWeight;
652     else if (width == "medium")
653         lineWeight = KoCharacterStyle::MediumLineWeight;
654     else if (width == "thick")
655         lineWeight = KoCharacterStyle::ThickLineWeight;
656     else if (width.endsWith('%')) {
657         lineWeight = KoCharacterStyle::PercentLineWeight;
658         lineWidth = width.mid(0, width.length() - 1).toDouble();
659     } else if (width[width.length()-1].isNumber()) {
660         lineWeight = KoCharacterStyle::LengthLineWeight;
661         lineWidth = width.toDouble();
662     } else {
663         lineWeight = KoCharacterStyle::LengthLineWeight;
664         lineWidth = KoUnit::parseValue(width);
665     }
666 }
667 
668 // OASIS 14.2.29
importOdfLine(const QString & type,const QString & style,KoCharacterStyle::LineStyle & lineStyle,KoCharacterStyle::LineType & lineType)669 static void importOdfLine(const QString &type, const QString &style, KoCharacterStyle::LineStyle &lineStyle, KoCharacterStyle::LineType &lineType)
670 {
671     lineStyle = KoCharacterStyle::NoLineStyle;
672     lineType = KoCharacterStyle::NoLineType;
673 
674     QString fixedType = type;
675     QString fixedStyle = style;
676     if (fixedStyle == "none")
677         fixedType.clear();
678     else if (fixedType.isEmpty() && !fixedStyle.isEmpty())
679         fixedType = "single";
680     else if (!fixedType.isEmpty() && fixedType != "none" && fixedStyle.isEmpty()) {
681         // don't set a style when the type is none
682         fixedStyle = "solid";
683     }
684 
685     if (fixedType == "single")
686         lineType = KoCharacterStyle::SingleLine;
687     else if (fixedType == "double")
688         lineType = KoCharacterStyle::DoubleLine;
689 
690     if (fixedStyle == "solid")
691         lineStyle = KoCharacterStyle::SolidLine;
692     else if (fixedStyle == "dotted")
693         lineStyle = KoCharacterStyle::DottedLine;
694     else if (fixedStyle == "dash")
695         lineStyle = KoCharacterStyle::DashLine;
696     else if (fixedStyle == "long-dash")
697         lineStyle = KoCharacterStyle::LongDashLine;
698     else if (fixedStyle == "dot-dash")
699         lineStyle = KoCharacterStyle::DotDashLine;
700     else if (fixedStyle == "dot-dot-dash")
701         lineStyle = KoCharacterStyle::DotDotDashLine;
702     else if (fixedStyle == "wave")
703         lineStyle = KoCharacterStyle::WaveLine;
704 }
705 
exportOdfLineType(KoCharacterStyle::LineType lineType)706 static QString exportOdfLineType(KoCharacterStyle::LineType lineType)
707 {
708     switch (lineType) {
709     case KoCharacterStyle::NoLineType:
710         return "none";
711     case KoCharacterStyle::SingleLine:
712         return "single";
713     case KoCharacterStyle::DoubleLine:
714         return "double";
715     default:
716         return "";
717     }
718 }
719 
exportOdfLineStyle(KoCharacterStyle::LineStyle lineStyle)720 static QString exportOdfLineStyle(KoCharacterStyle::LineStyle lineStyle)
721 {
722     switch (lineStyle) {
723     case KoCharacterStyle::NoLineStyle:
724         return "none";
725     case KoCharacterStyle::SolidLine:
726         return "solid";
727     case KoCharacterStyle::DottedLine:
728         return "dotted";
729     case KoCharacterStyle::DashLine:
730         return "dash";
731     case KoCharacterStyle::LongDashLine:
732         return "long-dash";
733     case KoCharacterStyle::DotDashLine:
734         return "dot-dash";
735     case KoCharacterStyle::DotDotDashLine:
736         return "dot-dot-dash";
737     case KoCharacterStyle::WaveLine:
738         return "wave";
739     default:
740         return "";
741     }
742 }
exportOdfLineMode(KoCharacterStyle::LineMode lineMode)743 static QString exportOdfLineMode(KoCharacterStyle::LineMode lineMode)
744 {
745     switch (lineMode) {
746     case KoCharacterStyle::ContinuousLineMode:
747         return "continuous";
748     case KoCharacterStyle::SkipWhiteSpaceLineMode:
749         return "skip-white-space";
750     default:
751         return "";
752     }
753 }
754 
exportOdfLineWidth(KoCharacterStyle::LineWeight lineWeight,qreal lineWidth)755 static QString exportOdfLineWidth(KoCharacterStyle::LineWeight lineWeight, qreal lineWidth)
756 {
757     switch (lineWeight) {
758     case KoCharacterStyle::AutoLineWeight:
759         return "auto";
760     case KoCharacterStyle::NormalLineWeight:
761         return "normal";
762     case KoCharacterStyle::BoldLineWeight:
763         return "bold";
764     case KoCharacterStyle::ThinLineWeight:
765         return "thin";
766     case KoCharacterStyle::DashLineWeight:
767         return "dash";
768     case KoCharacterStyle::MediumLineWeight:
769         return "medium";
770     case KoCharacterStyle::ThickLineWeight:
771         return "thick";
772     case KoCharacterStyle::PercentLineWeight:
773         return QString("%1%").arg(lineWidth);
774     case KoCharacterStyle::LengthLineWeight:
775         return QString("%1pt").arg(lineWidth);
776     default:
777         return QString();
778     }
779 }
780 
exportOdfFontStyleHint(QFont::StyleHint hint)781 static QString exportOdfFontStyleHint(QFont::StyleHint hint)
782 {
783     switch (hint) {
784     case QFont::Serif:
785         return "roman";
786     case QFont::SansSerif:
787         return "swiss";
788     case QFont::TypeWriter:
789         return "modern";
790     case QFont::Decorative:
791         return "decorative";
792     case QFont::System:
793         return "system";
794         /*case QFont::Script */
795     default:
796         return "";
797     }
798 }
799 
setFontFamily(const QString & family)800 void KoCharacterStyle::setFontFamily(const QString &family)
801 {
802     d->setProperty(QTextFormat::FontFamily, family);
803     setFontYStretch(d->calculateFontYStretch(family));
804 }
fontFamily() const805 QString KoCharacterStyle::fontFamily() const
806 {
807     return d->propertyString(QTextFormat::FontFamily);
808 }
setFontPointSize(qreal size)809 void KoCharacterStyle::setFontPointSize(qreal size)
810 {
811     d->setProperty(QTextFormat::FontPointSize, size);
812 }
clearFontPointSize()813 void KoCharacterStyle::clearFontPointSize() {
814     d->stylesPrivate.remove(QTextFormat::FontPointSize);
815 }
fontPointSize() const816 qreal KoCharacterStyle::fontPointSize() const
817 {
818     return d->propertyDouble(QTextFormat::FontPointSize);
819 }
setFontWeight(int weight)820 void KoCharacterStyle::setFontWeight(int weight)
821 {
822     d->setProperty(QTextFormat::FontWeight, weight);
823 }
fontWeight() const824 int KoCharacterStyle::fontWeight() const
825 {
826     return d->propertyInt(QTextFormat::FontWeight);
827 }
setFontItalic(bool italic)828 void KoCharacterStyle::setFontItalic(bool italic)
829 {
830     d->setProperty(QTextFormat::FontItalic, italic);
831 }
fontItalic() const832 bool KoCharacterStyle::fontItalic() const
833 {
834     return d->propertyBoolean(QTextFormat::FontItalic);
835 }
836 ///TODO Review legacy fontOverline functions and testing (consider removal)
837 /*
838 void KoCharacterStyle::setFontOverline(bool overline)
839 {
840     d->setProperty(QTextFormat::FontOverline, overline);
841 }
842 bool KoCharacterStyle::fontOverline() const
843 {
844     return d->propertyBoolean(QTextFormat::FontOverline);
845 }
846 */
setFontFixedPitch(bool fixedPitch)847 void KoCharacterStyle::setFontFixedPitch(bool fixedPitch)
848 {
849     d->setProperty(QTextFormat::FontFixedPitch, fixedPitch);
850 }
fontFixedPitch() const851 bool KoCharacterStyle::fontFixedPitch() const
852 {
853     return d->propertyBoolean(QTextFormat::FontFixedPitch);
854 }
setFontStyleHint(QFont::StyleHint styleHint)855 void KoCharacterStyle::setFontStyleHint(QFont::StyleHint styleHint)
856 {
857     d->setProperty(QTextFormat::FontStyleHint, styleHint);
858 }
fontStyleHint() const859 QFont::StyleHint KoCharacterStyle::fontStyleHint() const
860 {
861     return static_cast<QFont::StyleHint>(d->propertyInt(QTextFormat::FontStyleHint));
862 }
setFontKerning(bool enable)863 void KoCharacterStyle::setFontKerning(bool enable)
864 {
865     d->setProperty(QTextFormat::FontKerning, enable);
866 }
fontKerning() const867 bool KoCharacterStyle::fontKerning() const
868 {
869     return d->propertyBoolean(QTextFormat::FontKerning);
870 }
setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)871 void KoCharacterStyle::setVerticalAlignment(QTextCharFormat::VerticalAlignment alignment)
872 {
873     d->setProperty(QTextFormat::TextVerticalAlignment, alignment);
874 }
verticalAlignment() const875 QTextCharFormat::VerticalAlignment KoCharacterStyle::verticalAlignment() const
876 {
877     return static_cast<QTextCharFormat::VerticalAlignment>(d->propertyInt(QTextFormat::TextVerticalAlignment));
878 }
setTextOutline(const QPen & pen)879 void KoCharacterStyle::setTextOutline(const QPen &pen)
880 {
881     d->setProperty(QTextFormat::TextOutline, pen);
882 }
setBackground(const QBrush & brush)883 void KoCharacterStyle::setBackground(const QBrush &brush)
884 {
885     d->setProperty(QTextFormat::BackgroundBrush, brush);
886 }
setForeground(const QBrush & brush)887 void KoCharacterStyle::setForeground(const QBrush &brush)
888 {
889     d->setProperty(QTextFormat::ForegroundBrush, brush);
890 }
setFontAutoColor(bool use)891 void KoCharacterStyle::setFontAutoColor(bool use)
892 {
893     d->setProperty(KoCharacterStyle::UseWindowFontColor, use);
894 }
895 
name() const896 QString KoCharacterStyle::name() const
897 {
898     return d->name;
899 }
setName(const QString & name)900 void KoCharacterStyle::setName(const QString &name)
901 {
902     if (name == d->name)
903         return;
904     d->name = name;
905     emit nameChanged(name);
906 }
styleId() const907 int KoCharacterStyle::styleId() const
908 {
909     return d->propertyInt(StyleId);
910 }
setStyleId(int id)911 void KoCharacterStyle::setStyleId(int id)
912 {
913     d->setProperty(StyleId, id);
914 }
font() const915 QFont KoCharacterStyle::font() const
916 {
917     QFont font;
918     if (d->stylesPrivate.contains(QTextFormat::FontFamily))
919         font.setFamily(fontFamily());
920     if (d->stylesPrivate.contains(QTextFormat::FontPointSize))
921         font.setPointSizeF(fontPointSize());
922     if (d->stylesPrivate.contains(QTextFormat::FontWeight))
923         font.setWeight(fontWeight());
924     if (d->stylesPrivate.contains(QTextFormat::FontItalic))
925         font.setItalic(fontItalic());
926     return font;
927 }
setHasHyphenation(bool on)928 void KoCharacterStyle::setHasHyphenation(bool on)
929 {
930     d->setProperty(HasHyphenation, on);
931 }
hasHyphenation() const932 bool KoCharacterStyle::hasHyphenation() const
933 {
934     return d->propertyBoolean(HasHyphenation);
935 }
936 
setHyphenationPushCharCount(int count)937 void KoCharacterStyle::setHyphenationPushCharCount(int count)
938 {
939     if (count > 0)
940         d->setProperty(HyphenationPushCharCount, count);
941     else
942         d->stylesPrivate.remove(HyphenationPushCharCount);
943 }
944 
hyphenationPushCharCount() const945 int KoCharacterStyle::hyphenationPushCharCount() const
946 {
947     if (hasProperty(HyphenationPushCharCount))
948         return d->propertyInt(HyphenationPushCharCount);
949     return 0;
950 }
951 
setHyphenationRemainCharCount(int count)952 void KoCharacterStyle::setHyphenationRemainCharCount(int count)
953 {
954     if (count > 0)
955         d->setProperty(HyphenationRemainCharCount, count);
956     else
957         d->stylesPrivate.remove(HyphenationRemainCharCount);
958 }
959 
hyphenationRemainCharCount() const960 int KoCharacterStyle::hyphenationRemainCharCount() const
961 {
962     if (hasProperty(HyphenationRemainCharCount))
963         return d->propertyInt(HyphenationRemainCharCount);
964     return 0;
965 }
966 
setStrikeOutStyle(KoCharacterStyle::LineStyle strikeOut)967 void KoCharacterStyle::setStrikeOutStyle(KoCharacterStyle::LineStyle strikeOut)
968 {
969     d->setProperty(StrikeOutStyle, strikeOut);
970 }
971 
strikeOutStyle() const972 KoCharacterStyle::LineStyle KoCharacterStyle::strikeOutStyle() const
973 {
974     return (KoCharacterStyle::LineStyle) d->propertyInt(StrikeOutStyle);
975 }
976 
setStrikeOutType(LineType lineType)977 void KoCharacterStyle::setStrikeOutType(LineType lineType)
978 {
979     d->setProperty(StrikeOutType, lineType);
980 }
981 
strikeOutType() const982 KoCharacterStyle::LineType KoCharacterStyle::strikeOutType() const
983 {
984     return (KoCharacterStyle::LineType) d->propertyInt(StrikeOutType);
985 }
986 
setStrikeOutColor(const QColor & color)987 void KoCharacterStyle::setStrikeOutColor(const QColor &color)
988 {
989     d->setProperty(StrikeOutColor, color);
990 }
991 
strikeOutColor() const992 QColor KoCharacterStyle::strikeOutColor() const
993 {
994     return d->propertyColor(StrikeOutColor);
995 }
996 
setStrikeOutWidth(LineWeight weight,qreal width)997 void KoCharacterStyle::setStrikeOutWidth(LineWeight weight, qreal width)
998 {
999     d->setProperty(KoCharacterStyle::StrikeOutWeight, weight);
1000     d->setProperty(KoCharacterStyle::StrikeOutWidth, width);
1001 }
1002 
strikeOutWidth(LineWeight & weight,qreal & width) const1003 void KoCharacterStyle::strikeOutWidth(LineWeight &weight, qreal &width) const
1004 {
1005     weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::StrikeOutWeight);
1006     width = d->propertyDouble(KoCharacterStyle::StrikeOutWidth);
1007 }
setStrikeOutMode(LineMode lineMode)1008 void KoCharacterStyle::setStrikeOutMode(LineMode lineMode)
1009 {
1010     d->setProperty(StrikeOutMode, lineMode);
1011 }
1012 
setStrikeOutText(const QString & text)1013 void KoCharacterStyle::setStrikeOutText(const QString &text)
1014 {
1015     d->setProperty(StrikeOutText, text);
1016 }
strikeOutText() const1017 QString KoCharacterStyle::strikeOutText() const
1018 {
1019     return d->propertyString(StrikeOutText);
1020 }
strikeOutMode() const1021 KoCharacterStyle::LineMode KoCharacterStyle::strikeOutMode() const
1022 {
1023     return (KoCharacterStyle::LineMode) d->propertyInt(StrikeOutMode);
1024 }
1025 
setOverlineStyle(KoCharacterStyle::LineStyle overline)1026 void KoCharacterStyle::setOverlineStyle(KoCharacterStyle::LineStyle overline)
1027 {
1028     d->setProperty(OverlineStyle, overline);
1029 }
1030 
overlineStyle() const1031 KoCharacterStyle::LineStyle KoCharacterStyle::overlineStyle() const
1032 {
1033     return (KoCharacterStyle::LineStyle) d->propertyInt(OverlineStyle);
1034 }
1035 
setOverlineType(LineType lineType)1036 void KoCharacterStyle::setOverlineType(LineType lineType)
1037 {
1038     d->setProperty(OverlineType, lineType);
1039 }
1040 
overlineType() const1041 KoCharacterStyle::LineType KoCharacterStyle::overlineType() const
1042 {
1043     return (KoCharacterStyle::LineType) d->propertyInt(OverlineType);
1044 }
1045 
setOverlineColor(const QColor & color)1046 void KoCharacterStyle::setOverlineColor(const QColor &color)
1047 {
1048     d->setProperty(KoCharacterStyle::OverlineColor, color);
1049 }
1050 
overlineColor() const1051 QColor KoCharacterStyle::overlineColor() const
1052 {
1053     return d->propertyColor(KoCharacterStyle::OverlineColor);
1054 }
1055 
setOverlineWidth(LineWeight weight,qreal width)1056 void KoCharacterStyle::setOverlineWidth(LineWeight weight, qreal width)
1057 {
1058     d->setProperty(KoCharacterStyle::OverlineWeight, weight);
1059     d->setProperty(KoCharacterStyle::OverlineWidth, width);
1060 }
1061 
overlineWidth(LineWeight & weight,qreal & width) const1062 void KoCharacterStyle::overlineWidth(LineWeight &weight, qreal &width) const
1063 {
1064     weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::OverlineWeight);
1065     width = d->propertyDouble(KoCharacterStyle::OverlineWidth);
1066 }
1067 
setOverlineMode(LineMode mode)1068 void KoCharacterStyle::setOverlineMode(LineMode mode)
1069 {
1070     d->setProperty(KoCharacterStyle::OverlineMode, mode);
1071 }
1072 
overlineMode() const1073 KoCharacterStyle::LineMode KoCharacterStyle::overlineMode() const
1074 {
1075     return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::OverlineMode));
1076 }
1077 
setUnderlineStyle(KoCharacterStyle::LineStyle underline)1078 void KoCharacterStyle::setUnderlineStyle(KoCharacterStyle::LineStyle underline)
1079 {
1080     d->setProperty(UnderlineStyle, underline);
1081 }
1082 
underlineStyle() const1083 KoCharacterStyle::LineStyle KoCharacterStyle::underlineStyle() const
1084 {
1085     return (KoCharacterStyle::LineStyle) d->propertyInt(UnderlineStyle);
1086 }
1087 
setUnderlineType(LineType lineType)1088 void KoCharacterStyle::setUnderlineType(LineType lineType)
1089 {
1090     d->setProperty(UnderlineType, lineType);
1091 }
1092 
underlineType() const1093 KoCharacterStyle::LineType KoCharacterStyle::underlineType() const
1094 {
1095     return (KoCharacterStyle::LineType) d->propertyInt(UnderlineType);
1096 }
1097 
setUnderlineColor(const QColor & color)1098 void KoCharacterStyle::setUnderlineColor(const QColor &color)
1099 {
1100     d->setProperty(QTextFormat::TextUnderlineColor, color);
1101 }
1102 
underlineColor() const1103 QColor KoCharacterStyle::underlineColor() const
1104 {
1105     return d->propertyColor(QTextFormat::TextUnderlineColor);
1106 }
1107 
setUnderlineWidth(LineWeight weight,qreal width)1108 void KoCharacterStyle::setUnderlineWidth(LineWeight weight, qreal width)
1109 {
1110     d->setProperty(KoCharacterStyle::UnderlineWeight, weight);
1111     d->setProperty(KoCharacterStyle::UnderlineWidth, width);
1112 }
1113 
underlineWidth(LineWeight & weight,qreal & width) const1114 void KoCharacterStyle::underlineWidth(LineWeight &weight, qreal &width) const
1115 {
1116     weight = (KoCharacterStyle::LineWeight) d->propertyInt(KoCharacterStyle::UnderlineWeight);
1117     width = d->propertyDouble(KoCharacterStyle::UnderlineWidth);
1118 }
1119 
setUnderlineMode(LineMode mode)1120 void KoCharacterStyle::setUnderlineMode(LineMode mode)
1121 {
1122     d->setProperty(KoCharacterStyle::UnderlineMode, mode);
1123 }
1124 
underlineMode() const1125 KoCharacterStyle::LineMode KoCharacterStyle::underlineMode() const
1126 {
1127     return static_cast<KoCharacterStyle::LineMode>(d->propertyInt(KoCharacterStyle::UnderlineMode));
1128 }
1129 
setFontLetterSpacing(qreal spacing)1130 void KoCharacterStyle::setFontLetterSpacing(qreal spacing)
1131 {
1132     d->setProperty(KoCharacterStyle::FontLetterSpacing, spacing);
1133 }
1134 
fontLetterSpacing() const1135 qreal KoCharacterStyle::fontLetterSpacing() const
1136 {
1137     return d->propertyDouble(KoCharacterStyle::FontLetterSpacing);
1138 }
1139 
setFontWordSpacing(qreal spacing)1140 void KoCharacterStyle::setFontWordSpacing(qreal spacing)
1141 {
1142     d->setProperty(QTextCharFormat::FontWordSpacing, spacing);
1143 }
1144 
fontWordSpacing() const1145 qreal KoCharacterStyle::fontWordSpacing() const
1146 {
1147     return d->propertyDouble(QTextCharFormat::FontWordSpacing);
1148 }
1149 
1150 
setFontCapitalization(QFont::Capitalization capitalization)1151 void KoCharacterStyle::setFontCapitalization(QFont::Capitalization capitalization)
1152 {
1153     d->setProperty(QTextFormat::FontCapitalization, capitalization);
1154 }
1155 
fontCapitalization() const1156 QFont::Capitalization KoCharacterStyle::fontCapitalization() const
1157 {
1158     return (QFont::Capitalization) d->propertyInt(QTextFormat::FontCapitalization);
1159 }
1160 
1161 
setFontYStretch(qreal stretch)1162 void KoCharacterStyle::setFontYStretch(qreal stretch)
1163 {
1164     d->setProperty(KoCharacterStyle::FontYStretch, stretch);
1165 }
1166 
fontYStretch() const1167 qreal KoCharacterStyle::fontYStretch() const
1168 {
1169     return d->propertyDouble(KoCharacterStyle::FontYStretch);
1170 }
1171 
setCountry(const QString & country)1172 void KoCharacterStyle::setCountry(const QString &country)
1173 {
1174     if (country.isEmpty())
1175         d->stylesPrivate.remove(KoCharacterStyle::Country);
1176     else
1177         d->setProperty(KoCharacterStyle::Country, country);
1178 }
1179 
setLanguage(const QString & language)1180 void KoCharacterStyle::setLanguage(const QString &language)
1181 {
1182     if (language.isEmpty())
1183         d->stylesPrivate.remove(KoCharacterStyle::Language);
1184     else
1185         d->setProperty(KoCharacterStyle::Language, language);
1186 }
1187 
country() const1188 QString KoCharacterStyle::country() const
1189 {
1190     return value(KoCharacterStyle::Country).toString();
1191 }
1192 
language() const1193 QString KoCharacterStyle::language() const
1194 {
1195     return d->propertyString(KoCharacterStyle::Language);
1196 }
1197 
blinking() const1198 bool KoCharacterStyle::blinking() const
1199 {
1200     return d->propertyBoolean(Blink);
1201 }
1202 
setBlinking(bool blink)1203 void KoCharacterStyle::setBlinking(bool blink)
1204 {
1205     d->setProperty(KoCharacterStyle::Blink, blink);
1206 }
1207 
hasProperty(int key) const1208 bool KoCharacterStyle::hasProperty(int key) const
1209 {
1210     return d->stylesPrivate.contains(key);
1211 }
1212 
rotationScaleToString(KoCharacterStyle::RotationScale rotationScale)1213 static QString rotationScaleToString(KoCharacterStyle::RotationScale rotationScale)
1214 {
1215     QString scale = "line-height";
1216     if (rotationScale == KoCharacterStyle::Fixed) {
1217         scale = "fixed";
1218     }
1219     return scale;
1220 }
1221 
stringToRotationScale(const QString & scale)1222 static KoCharacterStyle::RotationScale stringToRotationScale(const QString &scale)
1223 {
1224     KoCharacterStyle::RotationScale rotationScale = KoCharacterStyle::LineHeight;
1225     if (scale == "fixed") {
1226         rotationScale = KoCharacterStyle::Fixed;
1227     }
1228     return rotationScale;
1229 }
1230 
setTextRotationAngle(qreal angle)1231 void KoCharacterStyle::setTextRotationAngle(qreal angle)
1232 {
1233     d->setProperty(TextRotationAngle, angle);
1234 }
1235 
textRotationAngle() const1236 qreal KoCharacterStyle::textRotationAngle() const
1237 {
1238     return d->propertyDouble(TextRotationAngle);
1239 }
1240 
setTextRotationScale(RotationScale scale)1241 void KoCharacterStyle::setTextRotationScale(RotationScale scale)
1242 {
1243     d->setProperty(TextRotationScale, rotationScaleToString(scale));
1244 }
1245 
textRotationScale() const1246 KoCharacterStyle::RotationScale KoCharacterStyle::textRotationScale() const
1247 {
1248     return stringToRotationScale(d->propertyString(TextRotationScale));
1249 }
1250 
setTextScale(int scale)1251 void KoCharacterStyle::setTextScale(int scale)
1252 {
1253     d->setProperty(TextScale, scale);
1254 }
1255 
textScale() const1256 int KoCharacterStyle::textScale() const
1257 {
1258     return d->propertyInt(TextScale);
1259 }
1260 
setTextShadow(const KoShadowStyle & shadow)1261 void KoCharacterStyle::setTextShadow(const KoShadowStyle& shadow)
1262 {
1263     d->setProperty(TextShadow, qVariantFromValue<KoShadowStyle>(shadow));
1264 }
1265 
textShadow() const1266 KoShadowStyle KoCharacterStyle::textShadow() const
1267 {
1268     if (hasProperty(TextShadow)) {
1269         QVariant shadow = value(TextShadow);
1270         if (shadow.canConvert<KoShadowStyle>())
1271             return shadow.value<KoShadowStyle>();
1272     }
1273     return KoShadowStyle();
1274 }
1275 
setTextCombine(KoCharacterStyle::TextCombineType type)1276 void KoCharacterStyle::setTextCombine(KoCharacterStyle::TextCombineType type)
1277 {
1278     d->setProperty(TextCombine, type);
1279 }
1280 
textCombine() const1281 KoCharacterStyle::TextCombineType KoCharacterStyle::textCombine() const
1282 {
1283     if (hasProperty(TextCombine)) {
1284         return (KoCharacterStyle::TextCombineType) d->propertyInt(TextCombine);
1285     }
1286     return NoTextCombine;
1287 }
1288 
textCombineEndChar() const1289 QChar KoCharacterStyle::textCombineEndChar() const
1290 {
1291     if (hasProperty(TextCombineEndChar)) {
1292         QString val = d->propertyString(TextCombineEndChar);
1293         if (val.length() > 0)
1294             return val.at(0);
1295     }
1296     return QChar();
1297 }
1298 
setTextCombineEndChar(const QChar & character)1299 void KoCharacterStyle::setTextCombineEndChar(const QChar& character)
1300 {
1301     d->setProperty(TextCombineEndChar, character);
1302 }
1303 
textCombineStartChar() const1304 QChar KoCharacterStyle::textCombineStartChar() const
1305 {
1306     if (hasProperty(TextCombineStartChar)) {
1307         QString val = d->propertyString(TextCombineStartChar);
1308         if (val.length() > 0)
1309             return val.at(0);
1310     }
1311     return QChar();
1312 }
1313 
setTextCombineStartChar(const QChar & character)1314 void KoCharacterStyle::setTextCombineStartChar(const QChar& character)
1315 {
1316     d->setProperty(TextCombineStartChar, character);
1317 }
1318 
setFontRelief(KoCharacterStyle::ReliefType relief)1319 void KoCharacterStyle::setFontRelief(KoCharacterStyle::ReliefType relief)
1320 {
1321     d->setProperty(FontRelief, relief);
1322 }
1323 
fontRelief() const1324 KoCharacterStyle::ReliefType KoCharacterStyle::fontRelief() const
1325 {
1326     if (hasProperty(FontRelief))
1327         return (KoCharacterStyle::ReliefType) d->propertyInt(FontRelief);
1328     return KoCharacterStyle::NoRelief;
1329 }
1330 
1331 
textEmphasizePosition() const1332 KoCharacterStyle::EmphasisPosition KoCharacterStyle::textEmphasizePosition() const
1333 {
1334     if (hasProperty(TextEmphasizePosition))
1335         return (KoCharacterStyle::EmphasisPosition) d->propertyInt(TextEmphasizePosition);
1336     return KoCharacterStyle::EmphasisAbove;
1337 }
1338 
setTextEmphasizePosition(KoCharacterStyle::EmphasisPosition position)1339 void KoCharacterStyle::setTextEmphasizePosition(KoCharacterStyle::EmphasisPosition position)
1340 {
1341     d->setProperty(TextEmphasizePosition, position);
1342 }
1343 
textEmphasizeStyle() const1344 KoCharacterStyle::EmphasisStyle KoCharacterStyle::textEmphasizeStyle() const
1345 {
1346     if (hasProperty(TextEmphasizeStyle))
1347         return (KoCharacterStyle::EmphasisStyle) d->propertyInt(TextEmphasizeStyle);
1348     return KoCharacterStyle::NoEmphasis;
1349 }
1350 
setTextEmphasizeStyle(KoCharacterStyle::EmphasisStyle emphasis)1351 void KoCharacterStyle::setTextEmphasizeStyle(KoCharacterStyle::EmphasisStyle emphasis)
1352 {
1353     d->setProperty(TextEmphasizeStyle, emphasis);
1354 }
1355 
setPercentageFontSize(qreal percent)1356 void KoCharacterStyle::setPercentageFontSize(qreal percent)
1357 {
1358     d->setProperty(KoCharacterStyle::PercentageFontSize, percent);
1359 }
1360 
percentageFontSize() const1361 qreal KoCharacterStyle::percentageFontSize() const
1362 {
1363     return d->propertyDouble(KoCharacterStyle::PercentageFontSize);
1364 }
1365 
setAdditionalFontSize(qreal percent)1366 void KoCharacterStyle::setAdditionalFontSize(qreal percent)
1367 {
1368     d->setProperty(KoCharacterStyle::AdditionalFontSize, percent);
1369 }
1370 
additionalFontSize() const1371 qreal KoCharacterStyle::additionalFontSize() const
1372 {
1373     return d->propertyDouble(KoCharacterStyle::AdditionalFontSize);
1374 }
1375 
loadOdf(const KoXmlElement * element,KoShapeLoadingContext & scontext,bool loadParents)1376 void KoCharacterStyle::loadOdf(const KoXmlElement *element, KoShapeLoadingContext &scontext,
1377     bool loadParents)
1378 {
1379     KoOdfLoadingContext &context = scontext.odfLoadingContext();
1380     const QString name(element->attributeNS(KoXmlNS::style, "display-name", QString()));
1381     if (!name.isEmpty()) {
1382         d->name = name;
1383     }
1384     else {
1385         d->name = element->attributeNS(KoXmlNS::style, "name", QString());
1386     }
1387 
1388     QString family = element->attributeNS(KoXmlNS::style, "family", "text");
1389 
1390     context.styleStack().save();
1391     if (loadParents) {
1392         context.addStyles(element, family.toLocal8Bit().constData());   // Load all parent
1393     } else {
1394         context.styleStack().push(*element);
1395     }
1396     context.styleStack().setTypeProperties("text");  // load the style:text-properties
1397     loadOdfProperties(scontext);
1398     context.styleStack().restore();
1399 }
1400 
loadOdfProperties(KoShapeLoadingContext & scontext)1401 void KoCharacterStyle::loadOdfProperties(KoShapeLoadingContext &scontext)
1402 {
1403     KoStyleStack &styleStack = scontext.odfLoadingContext().styleStack();
1404 
1405     d->stylesPrivate = StylePrivate();
1406 
1407     // The fo:color attribute specifies the foreground color of text.
1408     const QString color(styleStack.property(KoXmlNS::fo, "color"));
1409     if (!color.isEmpty()) {
1410         QColor c(color);
1411         if (c.isValid()) {     // 3.10.3
1412             setForeground(QBrush(c));
1413         }
1414     }
1415 
1416     QString fontName(styleStack.property(KoXmlNS::fo, "font-family"));
1417     if (!fontName.isEmpty()) {
1418         // Specify whether a font has a fixed or variable width.
1419         // These attributes are ignored if there is no corresponding fo:font-family attribute attached to the same formatting properties element.
1420         const QString fontPitch(styleStack.property(KoXmlNS::style, "font-pitch"));
1421         if (!fontPitch.isEmpty()) {
1422             setFontFixedPitch(fontPitch == "fixed");
1423         }
1424 
1425         const QString genericFamily(styleStack.property(KoXmlNS::style, "font-family-generic"));
1426         if (!genericFamily.isEmpty()) {
1427             if (genericFamily == "roman")
1428                 setFontStyleHint(QFont::Serif);
1429             else if (genericFamily == "swiss")
1430                 setFontStyleHint(QFont::SansSerif);
1431             else if (genericFamily == "modern")
1432                 setFontStyleHint(QFont::TypeWriter);
1433             else if (genericFamily == "decorative")
1434                 setFontStyleHint(QFont::Decorative);
1435             else if (genericFamily == "system")
1436                 setFontStyleHint(QFont::System);
1437             else if (genericFamily == "script") {
1438                 ; // TODO: no hint available in Qt yet, we should at least store it as a property internally!
1439             }
1440         }
1441 
1442         const QString fontCharset(styleStack.property(KoXmlNS::style, "font-charset"));
1443         if (!fontCharset.isEmpty()) {
1444             // this property is not required by Qt, since Qt auto selects the right font based on the text
1445             // The only charset of interest to us is x-symbol - this should disable spell checking
1446             d->setProperty(KoCharacterStyle::FontCharset, fontCharset);
1447         }
1448     }
1449 
1450     const QString fontFamily(styleStack.property(KoXmlNS::style, "font-family"));
1451     if (!fontFamily.isEmpty())
1452         fontName = fontFamily;
1453 
1454     if (styleStack.hasProperty(KoXmlNS::style, "font-name")) {
1455         // This font name is a reference to a font face declaration.
1456         KoOdfStylesReader &stylesReader = scontext.odfLoadingContext().stylesReader();
1457         const KoXmlElement *fontFace = stylesReader.findStyle(styleStack.property(KoXmlNS::style, "font-name"));
1458         if (fontFace != 0) {
1459             fontName = fontFace->attributeNS(KoXmlNS::svg, "font-family", "");
1460 
1461             KoXmlElement fontFaceElem;
1462             forEachElement(fontFaceElem, (*fontFace)) {
1463                 if (fontFaceElem.tagName() == "font-face-src") {
1464                     KoXmlElement fontUriElem;
1465                     forEachElement(fontUriElem, fontFaceElem) {
1466                         if (fontUriElem.tagName() == "font-face-uri") {
1467                             QString filename = fontUriElem.attributeNS(KoXmlNS::xlink, "href");
1468                             KoStore *store = scontext.odfLoadingContext().store();
1469                             if (store->open(filename)) {
1470                                 KoStoreDevice device(store);
1471                                 QByteArray data = device.readAll();
1472                                 if (device.open(QIODevice::ReadOnly)) {
1473                                     QFontDatabase::addApplicationFontFromData(data);
1474                                 }
1475                             }
1476                         }
1477                     }
1478                 }
1479             }
1480         }
1481      }
1482 
1483     if (!fontName.isEmpty()) {
1484         // Hmm, the remove "'" could break it's in the middle of the fontname...
1485         fontName = fontName.remove('\'');
1486 
1487         // 'Thorndale' is not known outside OpenOffice so we substitute it
1488         // with 'Times New Roman' that looks nearly the same.
1489         if (fontName == "Thorndale")
1490             fontName = "Times New Roman";
1491 
1492         // 'StarSymbol' is written by OpenOffice but they actually mean
1493         //  'OpenSymbol'.
1494         if (fontName == "StarSymbol")
1495             fontName = "OpenSymbol";
1496 
1497         fontName.remove(QRegExp("\\sCE$")); // Arial CE -> Arial
1498         setFontFamily(fontName);
1499     }
1500 
1501     // Specify the size of a font. The value of these attribute is either an absolute length or a percentage
1502     if (styleStack.hasProperty(KoXmlNS::fo, "font-size")) {
1503         const QString fontSize(styleStack.property(KoXmlNS::fo, "font-size"));
1504         if (!fontSize.isEmpty()) {
1505             if (fontSize.endsWith('%')) {
1506                 setPercentageFontSize(fontSize.left(fontSize.length() - 1).toDouble());
1507             } else {
1508                 setFontPointSize(KoUnit::parseValue(fontSize));
1509             }
1510         }
1511     }
1512     else {
1513         const QString fontSizeRel(styleStack.property(KoXmlNS::style, "font-size-rel"));
1514         if (!fontSizeRel.isEmpty()) {
1515             setAdditionalFontSize(KoUnit::parseValue(fontSizeRel));
1516         }
1517     }
1518 
1519     // Specify the weight of a font. The permitted values are normal, bold, and numeric values 100-900, in steps of 100. Unsupported numerical values are rounded off to the next supported value.
1520     const QString fontWeight(styleStack.property(KoXmlNS::fo, "font-weight"));
1521     if (!fontWeight.isEmpty()) {     // 3.10.24
1522         int boldness;
1523         if (fontWeight == "normal")
1524             boldness = 50;
1525         else if (fontWeight == "bold")
1526             boldness = 75;
1527         else
1528             // XSL/CSS has 100,200,300...900. Not the same scale as Qt!
1529             // See http://www.w3.org/TR/2001/REC-xsl-20011015/slice7.html#font-weight
1530             boldness = fontWeight.toInt() / 10;
1531         setFontWeight(boldness);
1532     }
1533 
1534     // Specify whether to use normal or italic font face.
1535     const QString fontStyle(styleStack.property(KoXmlNS::fo, "font-style" ));
1536     if (!fontStyle.isEmpty()) {     // 3.10.19
1537         if (fontStyle == "italic" || fontStyle == "oblique") {    // no difference in kotext
1538             setFontItalic(true);
1539         } else {
1540             setFontItalic(false);
1541         }
1542     }
1543 
1544 //TODO
1545 #if 0
1546     d->m_bWordByWord = styleStack.property(KoXmlNS::style, "text-underline-mode") == "skip-white-space";
1547     // TODO style:text-line-through-mode
1548 
1549     /*
1550     // OO compat code, to move to OO import filter
1551     d->m_bWordByWord = (styleStack.hasProperty( KoXmlNS::fo, "score-spaces")) // 3.10.25
1552                       && (styleStack.property( KoXmlNS::fo, "score-spaces") == "false");
1553     if( styleStack.hasProperty( KoXmlNS::style, "text-crossing-out" )) { // 3.10.6
1554         QString strikeOutType = styleStack.property( KoXmlNS::style, "text-crossing-out" );
1555         if( strikeOutType =="double-line")
1556             m_strikeOutType = S_DOUBLE;
1557         else if( strikeOutType =="single-line")
1558             m_strikeOutType = S_SIMPLE;
1559         else if( strikeOutType =="thick-line")
1560             m_strikeOutType = S_SIMPLE_BOLD;
1561         // not supported by Words: "slash" and "X"
1562         // not supported by OO: stylelines (solid, dash, dot, dashdot, dashdotdot)
1563     }
1564     */
1565 #endif
1566 
1567     // overline modes
1568     const QString textOverlineMode(styleStack.property( KoXmlNS::style, "text-overline-mode"));
1569     if (!textOverlineMode.isEmpty()) {
1570         if (textOverlineMode == "skip-white-space") {
1571             setOverlineMode(SkipWhiteSpaceLineMode);
1572         } else if (textOverlineMode == "continuous") {
1573             setOverlineMode(ContinuousLineMode);
1574         }
1575     }
1576 
1577     // Specifies whether text is overlined, and if so, whether a single or qreal line will be used for overlining.
1578     const QString textOverlineType(styleStack.property(KoXmlNS::style, "text-overline-type"));
1579     const QString textOverlineStyle(styleStack.property(KoXmlNS::style, "text-overline-style"));
1580     if (!textOverlineType.isEmpty() || !textOverlineStyle.isEmpty()) {    // OASIS 14.4.28
1581         LineStyle overlineStyle;
1582         LineType overlineType;
1583 
1584         importOdfLine(textOverlineType, textOverlineStyle,
1585                       overlineStyle, overlineType);
1586         setOverlineStyle(overlineStyle);
1587         setOverlineType(overlineType);
1588     }
1589 
1590     const QString textOverlineWidth(styleStack.property(KoXmlNS::style, "text-overline-width"));
1591     if (!textOverlineWidth.isEmpty()) {
1592         qreal overlineWidth;
1593         LineWeight overlineWeight;
1594         parseOdfLineWidth(textOverlineWidth, overlineWeight, overlineWidth);
1595         setOverlineWidth(overlineWeight, overlineWidth);
1596     }
1597 
1598     // Specifies the color that is used to overline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for overlining.
1599     QString overLineColor = styleStack.property(KoXmlNS::style, "text-overline-color");   // OO 3.10.23, OASIS 14.4.31
1600     if (!overLineColor.isEmpty() && overLineColor != "font-color") {
1601         setOverlineColor(QColor(overLineColor));
1602     } else if (overLineColor == "font-color") {
1603         setOverlineColor(QColor());
1604     }
1605 
1606     // underline modes
1607     const QString textUndelineMode(styleStack.property( KoXmlNS::style, "text-underline-mode"));
1608     if (!textUndelineMode.isEmpty()) {
1609         if (textUndelineMode == "skip-white-space") {
1610             setUnderlineMode(SkipWhiteSpaceLineMode);
1611         } else if (textUndelineMode == "continuous") {
1612             setUnderlineMode(ContinuousLineMode);
1613         }
1614     }
1615 
1616     // Specifies whether text is underlined, and if so, whether a single or qreal line will be used for underlining.
1617     const QString textUnderlineType(styleStack.property(KoXmlNS::style, "text-underline-type"));
1618     const QString textUnderlineStyle(styleStack.property(KoXmlNS::style, "text-underline-style"));
1619     if (!textUnderlineType.isEmpty() || !textUnderlineStyle.isEmpty()) {    // OASIS 14.4.28
1620         LineStyle underlineStyle;
1621         LineType underlineType;
1622 
1623         importOdfLine(textUnderlineType, textUnderlineStyle,
1624                       underlineStyle, underlineType);
1625         setUnderlineStyle(underlineStyle);
1626         setUnderlineType(underlineType);
1627     }
1628 
1629     const QString textUnderlineWidth(styleStack.property(KoXmlNS::style, "text-underline-width"));
1630     if (!textUnderlineWidth.isEmpty()) {
1631         qreal underlineWidth;
1632         LineWeight underlineWeight;
1633         parseOdfLineWidth(textUnderlineWidth, underlineWeight, underlineWidth);
1634         setUnderlineWidth(underlineWeight, underlineWidth);
1635     }
1636 
1637     // Specifies the color that is used to underline text. The value of this attribute is either font-color or a color. If the value is font-color, the current text color is used for underlining.
1638     QString underLineColor = styleStack.property(KoXmlNS::style, "text-underline-color");   // OO 3.10.23, OASIS 14.4.31
1639     if (!underLineColor.isEmpty() && underLineColor != "font-color") {
1640         setUnderlineColor(QColor(underLineColor));
1641     } else if (underLineColor == "font-color") {
1642         setUnderlineColor(QColor());
1643     }
1644 
1645 
1646     const QString textLineThroughType(styleStack.property(KoXmlNS::style, "text-line-through-type"));
1647     const QString textLineThroughStyle(styleStack.property(KoXmlNS::style, "text-line-through-style"));
1648     if (!textLineThroughType.isEmpty() || !textLineThroughStyle.isEmpty()) { // OASIS 14.4.7
1649         KoCharacterStyle::LineStyle throughStyle;
1650         LineType throughType;
1651 
1652         importOdfLine(textLineThroughType,textLineThroughStyle,
1653                       throughStyle, throughType);
1654 
1655         setStrikeOutStyle(throughStyle);
1656         setStrikeOutType(throughType);
1657         const QString textLineThroughText(styleStack.property(KoXmlNS::style, "text-line-through-text"));
1658         if (!textLineThroughText.isEmpty()) {
1659             setStrikeOutText(textLineThroughText);
1660         }
1661     }
1662 
1663     const QString textLineThroughWidth(styleStack.property(KoXmlNS::style, "text-line-through-width"));
1664     if (!textLineThroughWidth.isEmpty()) {
1665         qreal throughWidth;
1666         LineWeight throughWeight;
1667         parseOdfLineWidth(textLineThroughWidth, throughWeight, throughWidth);
1668         setStrikeOutWidth(throughWeight, throughWidth);
1669     }
1670 
1671     const QString lineThroughColor(styleStack.property(KoXmlNS::style, "text-line-through-color"));   // OO 3.10.23, OASIS 14.4.31
1672     if (!lineThroughColor.isEmpty() && lineThroughColor != "font-color") {
1673         setStrikeOutColor(QColor(lineThroughColor));
1674     }
1675 
1676     const QString lineThroughMode(styleStack.property(KoXmlNS::style, "text-line-through-mode"));
1677     if (lineThroughMode == "continuous") {
1678         setStrikeOutMode(ContinuousLineMode);
1679     }
1680     else if (lineThroughMode == "skip-white-space") {
1681         setStrikeOutMode(SkipWhiteSpaceLineMode);
1682     }
1683 
1684     const QString textPosition(styleStack.property(KoXmlNS::style, "text-position"));
1685     if (!textPosition.isEmpty()) {  // OO 3.10.7
1686         if (textPosition.startsWith("super"))
1687             setVerticalAlignment(QTextCharFormat::AlignSuperScript);
1688         else if (textPosition.startsWith("sub"))
1689             setVerticalAlignment(QTextCharFormat::AlignSubScript);
1690         else {
1691             QRegExp re("(-?[\\d.]+)%.*");
1692             if (re.exactMatch(textPosition)) {
1693                 int percent = re.capturedTexts()[1].toInt();
1694                 if (percent > 0)
1695                     setVerticalAlignment(QTextCharFormat::AlignSuperScript);
1696                 else if (percent < 0)
1697                     setVerticalAlignment(QTextCharFormat::AlignSubScript);
1698                 else // set explicit to overwrite inherited text-position's
1699                     setVerticalAlignment(QTextCharFormat::AlignNormal);
1700             }
1701         }
1702     }
1703 
1704     // The fo:font-variant attribute provides the option to display text as small capitalized letters.
1705     const QString textVariant(styleStack.property(KoXmlNS::fo, "font-variant"));
1706     if (!textVariant.isEmpty()) {
1707         if (textVariant == "small-caps")
1708             setFontCapitalization(QFont::SmallCaps);
1709         else if (textVariant == "normal")
1710             setFontCapitalization(QFont::MixedCase);
1711     }
1712     // The fo:text-transform attribute specifies text transformations to uppercase, lowercase, and capitalization.
1713     else {
1714         const QString textTransform(styleStack.property(KoXmlNS::fo, "text-transform"));
1715         if (!textTransform.isEmpty()) {
1716             if (textTransform == "uppercase")
1717                 setFontCapitalization(QFont::AllUppercase);
1718             else if (textTransform == "lowercase")
1719                 setFontCapitalization(QFont::AllLowercase);
1720             else if (textTransform == "capitalize")
1721                 setFontCapitalization(QFont::Capitalize);
1722             else if (textTransform == "none")
1723                 setFontCapitalization(QFont::MixedCase);
1724         }
1725     }
1726 
1727     const QString foLanguage(styleStack.property(KoXmlNS::fo, "language"));
1728     if (!foLanguage.isEmpty()) {
1729         setLanguage(foLanguage);
1730     }
1731 
1732     const QString foCountry(styleStack.property(KoXmlNS::fo, "country"));
1733     if (!foCountry.isEmpty()) {
1734         setCountry(foCountry);
1735     }
1736 
1737     // The fo:background-color attribute specifies the background color of a paragraph.
1738     const QString bgcolor(styleStack.property(KoXmlNS::fo, "background-color"));
1739     if (!bgcolor.isEmpty()) {
1740         QBrush brush = background();
1741         if (bgcolor == "transparent")
1742             brush.setStyle(Qt::NoBrush);
1743         else {
1744             if (brush.style() == Qt::NoBrush)
1745                 brush.setStyle(Qt::SolidPattern);
1746             brush.setColor(bgcolor); // #rrggbb format
1747         }
1748         setBackground(brush);
1749     }
1750 
1751     // The style:use-window-font-color attribute specifies whether or not the window foreground color should be as used as the foreground color for a light background color and white for a dark background color.
1752     const QString useWindowFont(styleStack.property(KoXmlNS::style, "use-window-font-color"));
1753     if (!useWindowFont.isEmpty()) {
1754         setFontAutoColor(useWindowFont == "true");
1755     }
1756 
1757     const QString letterKerning(styleStack.property( KoXmlNS::style, "letter-kerning"));
1758     if (!letterKerning.isEmpty()) {
1759         setFontKerning(letterKerning == "true");
1760     }
1761 
1762     const QString letterSpacing(styleStack.property(KoXmlNS::fo, "letter-spacing"));
1763     if ((!letterSpacing.isEmpty()) && (letterSpacing != "normal")) {
1764         qreal space = KoUnit::parseValue(letterSpacing);
1765         setFontLetterSpacing(space);
1766     }
1767 
1768     const QString textOutline(styleStack.property(KoXmlNS::style, "text-outline"));
1769     if (!textOutline.isEmpty()) {
1770         if (textOutline == "true") {
1771             setTextOutline(QPen((foreground().style() != Qt::NoBrush)?foreground():QBrush(Qt::black) , 0));
1772             setForeground(Qt::transparent);
1773         } else {
1774             setTextOutline(QPen(Qt::NoPen));
1775         }
1776     }
1777 
1778     const QString textRotationAngle(styleStack.property(KoXmlNS::style, "text-rotation-angle"));
1779     if (!textRotationAngle.isEmpty()) {
1780         setTextRotationAngle(KoUnit::parseAngle(textRotationAngle));
1781     }
1782 
1783     const QString textRotationScale(styleStack.property(KoXmlNS::style, "text-rotation-scale"));
1784     if (!textRotationScale.isEmpty()) {
1785         setTextRotationScale(stringToRotationScale(textRotationScale));
1786     }
1787 
1788     const QString textScale(styleStack.property(KoXmlNS::style, "text-scale"));
1789     if (!textScale.isEmpty()) {
1790         const int scale = (textScale.endsWith('%') ? textScale.left(textScale.length()-1) : textScale).toInt();
1791         setTextScale(scale);
1792     }
1793 
1794     const QString textShadow(styleStack.property(KoXmlNS::fo, "text-shadow"));
1795     if (!textShadow.isEmpty()) {
1796         KoShadowStyle shadow;
1797         if (shadow.loadOdf(textShadow))
1798             setTextShadow(shadow);
1799     }
1800 
1801     const QString textCombine(styleStack.property(KoXmlNS::style, "text-combine"));
1802     if (!textCombine.isEmpty()) {
1803         if (textCombine == "letters")
1804             setTextCombine(TextCombineLetters);
1805         else if (textCombine == "lines")
1806             setTextCombine(TextCombineLines);
1807         else if (textCombine == "none")
1808             setTextCombine(NoTextCombine);
1809     }
1810 
1811     const QString textCombineEndChar(styleStack.property(KoXmlNS::style, "text-combine-end-char"));
1812     if (!textCombineEndChar.isEmpty()) {
1813         setTextCombineEndChar(textCombineEndChar.at(0));
1814     }
1815     const QString textCombineStartChar(styleStack.property(KoXmlNS::style, "text-combine-start-char"));
1816     if (!textCombineStartChar.isEmpty()) {
1817         setTextCombineStartChar(textCombineStartChar.at(0));
1818     }
1819 
1820 
1821     const QString fontRelief(styleStack.property(KoXmlNS::style, "font-relief"));
1822     if (!fontRelief.isEmpty()) {
1823         if (fontRelief == "none")
1824             setFontRelief(KoCharacterStyle::NoRelief);
1825         else if (fontRelief == "embossed")
1826             setFontRelief(KoCharacterStyle::Embossed);
1827         else if (fontRelief == "engraved")
1828             setFontRelief(KoCharacterStyle::Engraved);
1829     }
1830 
1831     const QString fontEmphasize(styleStack.property(KoXmlNS::style, "text-emphasize"));
1832     if (!fontEmphasize.isEmpty()) {
1833         QString style, position;
1834         QStringList parts = fontEmphasize.split(' ');
1835         style = parts[0];
1836         if (parts.length() > 1)
1837             position = parts[1];
1838 
1839         if (style == "none") {
1840             setTextEmphasizeStyle(NoEmphasis);
1841         } else if (style == "accent") {
1842             setTextEmphasizeStyle(AccentEmphasis);
1843         } else if (style == "circle") {
1844             setTextEmphasizeStyle(CircleEmphasis);
1845         } else if (style == "disc") {
1846             setTextEmphasizeStyle(DiscEmphasis);
1847         } else if (style == "dot") {
1848             setTextEmphasizeStyle(DotEmphasis);
1849         }
1850 
1851         if (position == "below") {
1852             setTextEmphasizePosition(EmphasisBelow);
1853         } else if (position == "above") {
1854             setTextEmphasizePosition(EmphasisAbove);
1855         }
1856     }
1857 
1858     if (styleStack.hasProperty(KoXmlNS::fo, "hyphenate"))
1859         setHasHyphenation(styleStack.property(KoXmlNS::fo, "hyphenate") == "true");
1860 
1861     if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-remain-char-count")) {
1862         bool ok = false;
1863         int count = styleStack.property(KoXmlNS::fo, "hyphenation-remain-char-count").toInt(&ok);
1864         if (ok)
1865             setHyphenationRemainCharCount(count);
1866     }
1867     if (styleStack.hasProperty(KoXmlNS::fo, "hyphenation-push-char-count")) {
1868         bool ok = false;
1869         int count = styleStack.property(KoXmlNS::fo, "hyphenation-push-char-count").toInt(&ok);
1870         if (ok)
1871             setHyphenationPushCharCount(count);
1872     }
1873 
1874     if (styleStack.hasProperty(KoXmlNS::style, "text-blinking")) {
1875         setBlinking(styleStack.property(KoXmlNS::style, "text-blinking") == "true");
1876     }
1877 
1878 
1879 //TODO
1880 #if 0
1881     /*
1882       Missing properties:
1883       style:font-style-name, 3.10.11 - can be ignored, says DV, the other ways to specify a font are more precise
1884       fo:letter-spacing, 3.10.16 - not implemented in kotext
1885       style:text-relief, 3.10.20 - not implemented in kotext
1886       style:text-blinking, 3.10.27 - not implemented in kotext IIRC
1887       style:text-combine, 3.10.29/30 - not implemented, see http://www.w3.org/TR/WD-i18n-format/
1888       style:text-emphasis, 3.10.31 - not implemented in kotext
1889       style:text-scale, 3.10.33 - not implemented in kotext
1890       style:text-rotation-angle, 3.10.34 - not implemented in kotext (kpr rotates whole objects)
1891       style:text-rotation-scale, 3.10.35 - not implemented in kotext (kpr rotates whole objects)
1892       style:punctuation-wrap, 3.10.36 - not implemented in kotext
1893     */
1894 
1895     d->m_underLineWidth = 1.0;
1896 
1897     generateKey();
1898     addRef();
1899 #endif
1900 }
1901 
operator ==(const KoCharacterStyle & other) const1902 bool KoCharacterStyle::operator==(const KoCharacterStyle &other) const
1903 {
1904      return compareCharacterProperties(other);
1905 }
1906 
operator !=(const KoCharacterStyle & other) const1907 bool KoCharacterStyle::operator!=(const KoCharacterStyle &other) const
1908 {
1909      return !compareCharacterProperties(other);
1910 }
1911 
compareCharacterProperties(const KoCharacterStyle & other) const1912 bool KoCharacterStyle::compareCharacterProperties(const KoCharacterStyle &other) const
1913 {
1914     return other.d->stylesPrivate == d->stylesPrivate;
1915 }
1916 
removeDuplicates(const KoCharacterStyle & other)1917 void KoCharacterStyle::removeDuplicates(const KoCharacterStyle &other)
1918 {
1919     // In case the current style doesn't have the flag UseWindowFontColor set but the other has it set and they use the same color
1920     // remove duplicates will remove the color. However to make it work correctly we need to store the color with the style so it
1921     // will be loaded again. We don't store a use-window-font-color="false" as that is not compatible to the way OO/LO does work.
1922     // So save the color and restore it after the remove duplicates
1923     QBrush brush;
1924     if (other.d->propertyBoolean(KoCharacterStyle::UseWindowFontColor) && !d->propertyBoolean(KoCharacterStyle::UseWindowFontColor)) {
1925         brush = foreground();
1926     }
1927 
1928     // this properties should need to be kept if there is a font family defined as these are only evaluated if there is also a font family
1929     int keepProperties[] = { QTextFormat::FontStyleHint, QTextFormat::FontFixedPitch, KoCharacterStyle::FontCharset };
1930 
1931     QMap<int, QVariant> keep;
1932     for (unsigned int i = 0; i < sizeof(keepProperties)/sizeof(*keepProperties); ++i) {
1933         if (hasProperty(keepProperties[i])) {
1934             keep.insert(keepProperties[i], value(keepProperties[i]));
1935         }
1936     }
1937     this->d->stylesPrivate.removeDuplicates(other.d->stylesPrivate);
1938     if (brush.style() != Qt::NoBrush) {
1939         setForeground(brush);
1940     }
1941 
1942     // in case the char style has any of the following properties it also needs to have the fontFamily as otherwise
1943     // these values will be ignored when loading according to the odf spec
1944     if (!hasProperty(QTextFormat::FontFamily)) {
1945         if (hasProperty(QTextFormat::FontStyleHint) || hasProperty(QTextFormat::FontFixedPitch) || hasProperty(KoCharacterStyle::FontCharset)) {
1946             QString fontFamily = other.fontFamily();
1947             if (!fontFamily.isEmpty()) {
1948                 setFontFamily(fontFamily);
1949             }
1950         }
1951     }
1952     else {
1953         for (QMap<int, QVariant>::const_iterator it(keep.constBegin()); it != keep.constEnd(); ++it) {
1954             this->d->stylesPrivate.add(it.key(), it.value());
1955         }
1956     }
1957 }
1958 
removeDuplicates(const QTextCharFormat & otherFormat)1959 void KoCharacterStyle::removeDuplicates(const QTextCharFormat &otherFormat)
1960 {
1961     KoCharacterStyle other(otherFormat);
1962     removeDuplicates(other);
1963 }
1964 
remove(int key)1965 void KoCharacterStyle::remove(int key)
1966 {
1967     d->stylesPrivate.remove(key);
1968 }
1969 
isEmpty() const1970 bool KoCharacterStyle::isEmpty() const
1971 {
1972     return d->stylesPrivate.isEmpty();
1973 }
1974 
saveOdf(KoGenStyle & style) const1975 void KoCharacterStyle::saveOdf(KoGenStyle &style) const
1976 {
1977     if (!d->name.isEmpty() && !style.isDefaultStyle()) {
1978         style.addAttribute("style:display-name", d->name);
1979     }
1980     QList<int> keys = d->stylesPrivate.keys();
1981     Q_FOREACH (int key, keys) {
1982         if (key == QTextFormat::FontWeight) {
1983             bool ok = false;
1984             int boldness = d->stylesPrivate.value(key).toInt(&ok);
1985             if (ok) {
1986                 if (boldness == QFont::Normal) {
1987                     style.addProperty("fo:font-weight", "normal", KoGenStyle::TextType);
1988                 } else if (boldness == QFont::Bold) {
1989                     style.addProperty("fo:font-weight", "bold", KoGenStyle::TextType);
1990                 } else {
1991                     // Remember : Qt and CSS/XSL doesn't have the same scale. Its 100-900 instead of Qts 0-100
1992                     style.addProperty("fo:font-weight", qBound(10, boldness, 90) * 10, KoGenStyle::TextType);
1993                 }
1994             }
1995         } else if (key == QTextFormat::FontItalic) {
1996             if (d->stylesPrivate.value(key).toBool()) {
1997                 style.addProperty("fo:font-style", "italic", KoGenStyle::TextType);
1998             } else {
1999                 style.addProperty("fo:font-style", "normal", KoGenStyle::TextType);
2000             }
2001         } else if (key == QTextFormat::FontFamily) {
2002             QString fontFamily = d->stylesPrivate.value(key).toString();
2003             style.addProperty("fo:font-family", fontFamily, KoGenStyle::TextType);
2004         } else if (key == QTextFormat::FontFixedPitch) {
2005             bool fixedPitch = d->stylesPrivate.value(key).toBool();
2006             style.addProperty("style:font-pitch", fixedPitch ? "fixed" : "variable", KoGenStyle::TextType);
2007             // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2008             style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2009         } else if (key == QTextFormat::FontStyleHint) {
2010             bool ok = false;
2011             int styleHint = d->stylesPrivate.value(key).toInt(&ok);
2012             if (ok) {
2013                 QString generic = exportOdfFontStyleHint((QFont::StyleHint) styleHint);
2014                 if (!generic.isEmpty()) {
2015                     style.addProperty("style:font-family-generic", generic, KoGenStyle::TextType);
2016                 }
2017                 // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2018                 style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2019             }
2020         } else if (key == QTextFormat::FontKerning) {
2021             style.addProperty("style:letter-kerning", fontKerning() ? "true" : "false", KoGenStyle::TextType);
2022         } else if (key == QTextFormat::FontCapitalization) {
2023             switch (fontCapitalization()) {
2024             case QFont::SmallCaps:
2025                 style.addProperty("fo:font-variant", "small-caps", KoGenStyle::TextType);
2026                 break;
2027             case QFont::MixedCase:
2028                 style.addProperty("fo:font-variant", "normal", KoGenStyle::TextType);
2029                 style.addProperty("fo:text-transform", "none", KoGenStyle::TextType);
2030                 break;
2031             case QFont::AllUppercase:
2032                 style.addProperty("fo:text-transform", "uppercase", KoGenStyle::TextType);
2033                 break;
2034             case QFont::AllLowercase:
2035                 style.addProperty("fo:text-transform", "lowercase", KoGenStyle::TextType);
2036                 break;
2037             case QFont::Capitalize:
2038                 style.addProperty("fo:text-transform", "capitalize", KoGenStyle::TextType);
2039                 break;
2040             }
2041         } else if (key == OverlineStyle) {
2042             bool ok = false;
2043             int styleId = d->stylesPrivate.value(key).toInt(&ok);
2044             if (ok) {
2045                 style.addProperty("style:text-overline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2046         }
2047         } else if (key == OverlineType) {
2048             bool ok = false;
2049             int type = d->stylesPrivate.value(key).toInt(&ok);
2050             if (ok) {
2051                 style.addProperty("style:text-overline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2052         }
2053         } else if (key == OverlineColor) {
2054             QColor color = d->stylesPrivate.value(key).value<QColor>();
2055             if (color.isValid())
2056                 style.addProperty("style:text-overline-color", color.name(), KoGenStyle::TextType);
2057             else
2058                 style.addProperty("style:text-overline-color", "font-color", KoGenStyle::TextType);
2059         } else if (key == OverlineMode) {
2060             bool ok = false;
2061             int mode = d->stylesPrivate.value(key).toInt(&ok);
2062             if (ok) {
2063                 style.addProperty("style:text-overline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2064         }
2065         } else if (key == OverlineWidth) {
2066             KoCharacterStyle::LineWeight weight;
2067             qreal width;
2068             overlineWidth(weight, width);
2069             style.addProperty("style:text-overline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2070         } else if (key == UnderlineStyle) {
2071             bool ok = false;
2072             int styleId = d->stylesPrivate.value(key).toInt(&ok);
2073             if (ok)
2074                 style.addProperty("style:text-underline-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2075         } else if (key == UnderlineType) {
2076             bool ok = false;
2077             int type = d->stylesPrivate.value(key).toInt(&ok);
2078             if (ok)
2079                 style.addProperty("style:text-underline-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2080         } else if (key == QTextFormat::TextUnderlineColor) {
2081             QColor color = d->stylesPrivate.value(key).value<QColor>();
2082             if (color.isValid())
2083                 style.addProperty("style:text-underline-color", color.name(), KoGenStyle::TextType);
2084             else
2085                 style.addProperty("style:text-underline-color", "font-color", KoGenStyle::TextType);
2086         } else if (key == UnderlineMode) {
2087             bool ok = false;
2088             int mode = d->stylesPrivate.value(key).toInt(&ok);
2089             if (ok)
2090                 style.addProperty("style:text-underline-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2091         } else if (key == UnderlineWidth) {
2092             KoCharacterStyle::LineWeight weight;
2093             qreal width;
2094             underlineWidth(weight, width);
2095             style.addProperty("style:text-underline-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2096         } else if (key == StrikeOutStyle) {
2097             bool ok = false;
2098             int styleId = d->stylesPrivate.value(key).toInt(&ok);
2099             if (ok)
2100                 style.addProperty("style:text-line-through-style", exportOdfLineStyle((KoCharacterStyle::LineStyle) styleId), KoGenStyle::TextType);
2101         } else if (key == StrikeOutType) {
2102             bool ok = false;
2103             int type = d->stylesPrivate.value(key).toInt(&ok);
2104             if (ok)
2105                 style.addProperty("style:text-line-through-type", exportOdfLineType((KoCharacterStyle::LineType) type), KoGenStyle::TextType);
2106         } else if (key == StrikeOutText) {
2107             style.addProperty("style:text-line-through-text", d->stylesPrivate.value(key).toString(), KoGenStyle::TextType);
2108         } else if (key == StrikeOutColor) {
2109             QColor color = d->stylesPrivate.value(key).value<QColor>();
2110             if (color.isValid())
2111                 style.addProperty("style:text-line-through-color", color.name(), KoGenStyle::TextType);
2112         } else if (key == StrikeOutMode) {
2113             bool ok = false;
2114             int mode = d->stylesPrivate.value(key).toInt(&ok);
2115             if (ok)
2116                 style.addProperty("style:text-line-through-mode", exportOdfLineMode((KoCharacterStyle::LineMode) mode), KoGenStyle::TextType);
2117         } else if (key == StrikeOutWidth) {
2118             KoCharacterStyle::LineWeight weight;
2119             qreal width;
2120             strikeOutWidth(weight, width);
2121             style.addProperty("style:text-line-through-width", exportOdfLineWidth(weight, width), KoGenStyle::TextType);
2122         } else if (key == QTextFormat::BackgroundBrush) {
2123             QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
2124             if (brush.style() == Qt::NoBrush)
2125                 style.addProperty("fo:background-color", "transparent", KoGenStyle::TextType);
2126             else
2127                 style.addProperty("fo:background-color", brush.color().name(), KoGenStyle::TextType);
2128         } else if (key == QTextFormat::ForegroundBrush) {
2129             QBrush brush = d->stylesPrivate.value(key).value<QBrush>();
2130             if (brush.style() != Qt::NoBrush) {
2131                 style.addProperty("fo:color", brush.color().name(), KoGenStyle::TextType);
2132             }
2133         } else if (key == KoCharacterStyle::UseWindowFontColor) {
2134             bool use = d->stylesPrivate.value(key).toBool();
2135             style.addProperty("style:use-window-font-color", use ? "true" : "false", KoGenStyle::TextType);
2136         } else if (key == QTextFormat::TextVerticalAlignment) {
2137             if (verticalAlignment() == QTextCharFormat::AlignSuperScript)
2138                 style.addProperty("style:text-position", "super", KoGenStyle::TextType);
2139             else if (verticalAlignment() == QTextCharFormat::AlignSubScript)
2140                 style.addProperty("style:text-position", "sub", KoGenStyle::TextType);
2141             else if (d->stylesPrivate.contains(QTextFormat::TextVerticalAlignment)) // no superscript or subscript
2142                 style.addProperty("style:text-position", "0% 100%", KoGenStyle::TextType);
2143         } else if (key == QTextFormat::FontPointSize) {
2144             // when there is percentageFontSize!=100% property ignore the fontSize property and store the percentage property
2145             if ( (!hasProperty(KoCharacterStyle::PercentageFontSize)) || (percentageFontSize()==100))
2146                 style.addPropertyPt("fo:font-size", fontPointSize(), KoGenStyle::TextType);
2147         } else if (key == KoCharacterStyle::PercentageFontSize) {
2148             if(percentageFontSize()!=100) {
2149                 style.addProperty("fo:font-size", QString::number(percentageFontSize()) + '%', KoGenStyle::TextType);
2150             }
2151         } else if (key == KoCharacterStyle::Country) {
2152             style.addProperty("fo:country", d->stylesPrivate.value(KoCharacterStyle::Country).toString(), KoGenStyle::TextType);
2153         } else if (key == KoCharacterStyle::Language) {
2154             style.addProperty("fo:language", d->stylesPrivate.value(KoCharacterStyle::Language).toString(), KoGenStyle::TextType);
2155         } else if (key == KoCharacterStyle::FontLetterSpacing) {
2156             qreal space = fontLetterSpacing();
2157             style.addPropertyPt("fo:letter-spacing", space, KoGenStyle::TextType);
2158         } else if (key == QTextFormat::TextOutline) {
2159             QPen outline = textOutline();
2160             style.addProperty("style:text-outline", outline.style() == Qt::NoPen ? "false" : "true", KoGenStyle::TextType);
2161         } else if (key == KoCharacterStyle::FontCharset) {
2162             style.addProperty("style:font-charset", d->stylesPrivate.value(KoCharacterStyle::FontCharset).toString(), KoGenStyle::TextType);
2163             // if this property is saved we also need to save the fo:font-family attribute as otherwise it will be ignored on loading as defined in the spec
2164             style.addProperty("fo:font-family", fontFamily(), KoGenStyle::TextType);
2165         } else if (key == KoCharacterStyle::TextRotationAngle) {
2166             style.addProperty("style:text-rotation-angle", QString::number(textRotationAngle()), KoGenStyle::TextType);
2167         } else if (key == KoCharacterStyle::TextRotationScale) {
2168             RotationScale scale = textRotationScale();
2169             style.addProperty("style:text-rotation-scale", rotationScaleToString(scale), KoGenStyle::TextType);
2170         } else if (key == KoCharacterStyle::TextScale) {
2171             int scale = textScale();
2172             style.addProperty("style:text-scale", QString::number(scale) + '%', KoGenStyle::TextType);
2173         } else if (key == KoCharacterStyle::TextShadow) {
2174             KoShadowStyle shadow = textShadow();
2175             style.addProperty("fo:text-shadow", shadow.saveOdf(), KoGenStyle::TextType);
2176         } else if (key == KoCharacterStyle::TextCombine) {
2177             KoCharacterStyle::TextCombineType textCombineType = textCombine();
2178             switch (textCombineType)
2179             {
2180                 case KoCharacterStyle::NoTextCombine:
2181                     style.addProperty("style:text-combine", "none", KoGenStyle::TextType);
2182                     break;
2183                 case KoCharacterStyle::TextCombineLetters:
2184                     style.addProperty("style:text-combine", "letters", KoGenStyle::TextType);
2185                     break;
2186                 case KoCharacterStyle::TextCombineLines:
2187                     style.addProperty("style:text-combine", "lines", KoGenStyle::TextType);
2188                     break;
2189             }
2190         } else if (key == KoCharacterStyle::TextCombineEndChar) {
2191             style.addProperty("style:text-combine-end-char", textCombineEndChar(), KoGenStyle::TextType);
2192         } else if (key == KoCharacterStyle::TextCombineStartChar) {
2193             style.addProperty("style:text-combine-start-char", textCombineStartChar(), KoGenStyle::TextType);
2194         } else if (key == KoCharacterStyle::FontRelief) {
2195             KoCharacterStyle::ReliefType relief = fontRelief();
2196             switch (relief)
2197             {
2198                 case KoCharacterStyle::NoRelief:
2199                     style.addProperty("style:font-relief", "none", KoGenStyle::TextType);
2200                     break;
2201                 case KoCharacterStyle::Embossed:
2202                     style.addProperty("style:font-relief", "embossed", KoGenStyle::TextType);
2203                     break;
2204                 case KoCharacterStyle::Engraved:
2205                     style.addProperty("style:font-relief", "engraved", KoGenStyle::TextType);
2206                     break;
2207             }
2208         } else if (key == KoCharacterStyle::TextEmphasizeStyle) {
2209             KoCharacterStyle::EmphasisStyle emphasisStyle = textEmphasizeStyle();
2210             KoCharacterStyle::EmphasisPosition position = textEmphasizePosition();
2211             QString odfEmphasis;
2212             switch (emphasisStyle)
2213             {
2214                 case KoCharacterStyle::NoEmphasis:
2215                     odfEmphasis = "none";
2216                     break;
2217                 case KoCharacterStyle::AccentEmphasis:
2218                     odfEmphasis = "accent";
2219                     break;
2220                 case KoCharacterStyle::CircleEmphasis:
2221                     odfEmphasis = "circle";
2222                     break;
2223                 case KoCharacterStyle::DiscEmphasis:
2224                     odfEmphasis = "disc";
2225                     break;
2226                 case KoCharacterStyle::DotEmphasis:
2227                     odfEmphasis = "dot";
2228                     break;
2229             }
2230             if (hasProperty(KoCharacterStyle::TextEmphasizePosition)) {
2231                 if (position == KoCharacterStyle::EmphasisAbove)
2232                     odfEmphasis += " above";
2233                 else
2234                     odfEmphasis += " below";
2235             }
2236             style.addProperty("style:text-emphasize", odfEmphasis, KoGenStyle::TextType);
2237         } else if (key == KoCharacterStyle::HasHyphenation) {
2238             if (hasHyphenation())
2239                 style.addProperty("fo:hyphenate", "true", KoGenStyle::TextType);
2240             else
2241                 style.addProperty("fo:hyphenate", "false", KoGenStyle::TextType);
2242         } else if (key == KoCharacterStyle::HyphenationPushCharCount) {
2243             style.addProperty("fo:hyphenation-push-char-count", hyphenationPushCharCount(), KoGenStyle::TextType);
2244         } else if (key == KoCharacterStyle::HyphenationRemainCharCount) {
2245             style.addProperty("fo:hyphenation-remain-char-count", hyphenationRemainCharCount(), KoGenStyle::TextType);
2246         } else if (key == KoCharacterStyle::Blink) {
2247             style.addProperty("style:text-blinking", blinking(), KoGenStyle::TextType);
2248         }
2249     }
2250     //TODO: font name and family
2251 }
2252 
value(int key) const2253 QVariant KoCharacterStyle::value(int key) const
2254 {
2255     QVariant variant = d->stylesPrivate.value(key);
2256     if (variant.isNull()) {
2257         if (d->parentStyle)
2258             variant = d->parentStyle->value(key);
2259         else if (d->defaultStyle)
2260             variant = d->defaultStyle->value(key);
2261     }
2262     return variant;
2263 }
2264 
removeHardCodedDefaults()2265 void KoCharacterStyle::removeHardCodedDefaults()
2266 {
2267     d->hardCodedDefaultStyle.clearAll();
2268 }
2269