Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSvgTextProperties.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QFontMetrics>
10#include <QGlobalStatic>
11#include <QMap>
12#include <QRegularExpression>
13
14#include <fontconfig/fontconfig.h>
15
16#include <SvgGraphicContext.h>
17#include <SvgLoadingContext.h>
18#include <SvgUtil.h>
19#include <kis_dom_utils.h>
20#include <kis_global.h>
21
22#include "KoSvgText.h"
23#include "KoFontRegistry.h"
24
26{
27 QMap<PropertyId, QVariant> properties;
28
29 static bool isInheritable(PropertyId id);
30};
31
36
40
42 : m_d(new Private)
43{
44 m_d->properties = rhs.m_d->properties;
45}
46
48{
49 if (&rhs != this) {
50 m_d->properties = rhs.m_d->properties;
51 }
52 return *this;
53}
54
56 return m_d->properties == rhs.m_d->properties;
57}
58
60{
61 m_d->properties.insert(id, value);
62}
63
65{
66 return m_d->properties.contains(id);
67}
68
69QVariant KoSvgTextProperties::property(KoSvgTextProperties::PropertyId id, const QVariant &defaultValue) const
70{
71 return m_d->properties.value(id, defaultValue);
72}
73
78
80{
81 QVariant value = m_d->properties.value(id);
82 if (value.isNull()) {
84 }
85 return value;
86}
87
92
94{
95 return m_d->properties.isEmpty();
96}
97
98
103
105{
106 auto it = m_d->properties.begin();
107 for (; it != m_d->properties.end(); ++it) {
108 if (!m_d->isInheritable(it.key())) {
109 it.value() = defaultProperties().property(it.key());
110 }
111 }
112}
113
114void KoSvgTextProperties::inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve, bool onlyFontAndLineHeight)
115{
116 auto it = parentProperties.m_d->properties.constBegin();
117 for (; it != parentProperties.m_d->properties.constEnd(); ++it) {
118 if (!hasProperty(it.key()) && m_d->isInheritable(it.key())) {
119 setProperty(it.key(), it.value());
120 }
121 }
122
123 if (resolve) {
124 resolveRelativeValues(parentProperties.metrics(), parentProperties.fontSize().value, onlyFontAndLineHeight);
125 }
126}
127
128void KoSvgTextProperties::resolveRelativeValues(const KoSvgText::FontMetrics metrics, const qreal fontSize, bool onlyFontAndLineHeight)
129{
130 // First resolve 'font-*' properties.
131 // See https://www.w3.org/TR/css-values-4/#font-relative-lengths
134 this->setFontSize(size);
135 const qreal usedSize = size.value;
137 if (!lineHeight.isNormal && !lineHeight.isNumber) {
140 } else if (!onlyFontAndLineHeight) {
141 lineHeight.length.convertToAbsolute(this->metrics(false), usedSize);
142 }
143 setProperty(LineHeightId, QVariant::fromValue(lineHeight));
144 }
145
146 if (onlyFontAndLineHeight) return;
147
148 const KoSvgText::FontMetrics usedMetrics = this->metrics();
149
150
151 for (auto it = this->m_d->properties.begin(); it != this->m_d->properties.end(); it++) {
152
155
156 if (it.key() == LineHeightId) continue;
157 if (it.value().canConvert<KoSvgText::CssLengthPercentage>() && it.key() != KoSvgTextProperties::FontSizeId) {
159 length.convertToAbsolute(usedMetrics, usedSize, percentageUnit);
160 it.value() = QVariant::fromValue(length);
161 } else if (it.value().canConvert<KoSvgText::AutoLengthPercentage>()) {
163
164 if (!val.isAuto) {
165 val.length.convertToAbsolute(usedMetrics, usedSize, percentageUnit);
166 it.value() = QVariant::fromValue(val);
167 }
168 } else if (it.key() == KoSvgTextProperties::TabSizeId) {
170 if (!tabSize.isNumber) {
171 tabSize.length.convertToAbsolute(usedMetrics, usedSize);
172 it.value() = QVariant::fromValue(tabSize);
173 }
174 } else if (it.key() == KoSvgTextProperties::TextIndentId) {
175 KoSvgText::TextIndentInfo indent = it.value().value<KoSvgText::TextIndentInfo>();
177 indent.length.convertToAbsolute(usedMetrics, usedSize);
178 }
179 it.value() = QVariant::fromValue(indent);
180 }
181 }
182}
183
185{
186 return !hasProperty(id) || parentProperties.property(id) == property(id);
187}
188
190{
191 for (auto it = m_d->properties.constBegin(); it != m_d->properties.constEnd(); ++it) {
192 if (!m_d->isInheritable(it.key())) {
193 return true;
194 }
195 }
196 return false;
197}
198
200{
201 auto it = properties.m_d->properties.constBegin();
202 for (; it != properties.m_d->properties.constEnd(); ++it) {
203 if (m_d->isInheritable(it.key())) {
204 setProperty(it.key(), it.value());
205 }
206 }
207}
208
209void KoSvgTextProperties::scaleAbsoluteValues(const double scaleInline, const double scaleBlock)
210{
212
213 for (auto it = this->m_d->properties.begin(); it != this->m_d->properties.end(); ++it) {
214 if (it.value().canConvert<KoSvgText::CssLengthPercentage>()) {
216 if (length.unit != absoluteUnit) continue;
217 if (it.key() == FontSizeId || it.key() == BaselineShiftValueId) {
218 length.value *= scaleBlock;
219 } else {
220 length.value *= scaleInline;
221 }
222 it.value() = QVariant::fromValue(length);
223 } else if (it.value().canConvert<KoSvgText::LineHeightInfo>()) {
225 if (info.length.unit != absoluteUnit) continue;
226 info.length.value *= scaleBlock;
227 it.value() = QVariant::fromValue(info);
228 } else if (it.value().canConvert<KoSvgText::TabSizeInfo>()) {
230 if (info.length.unit != absoluteUnit) continue;
231 info.length.value *= scaleInline;
232 it.value() = QVariant::fromValue(info);
233 } else if (it.value().canConvert<KoSvgText::TextIndentInfo>()) {
234 KoSvgText::TextIndentInfo info = it.value().value<KoSvgText::TextIndentInfo>();
235 if (info.length.unit != absoluteUnit) continue;
236 info.length.value *= scaleInline;
237 it.value() = QVariant::fromValue(info);
238 } else if (it.value().canConvert<KoSvgText::AutoValue>()) {
239 KoSvgText::AutoValue info = it.value().value<KoSvgText::AutoValue>();
240 if (info.isAuto) continue;
241 if (it.key() != InlineSizeId) continue;
242 info.customValue *= scaleInline;
243 it.value() = QVariant::fromValue(info);
244 }
245 // TODO: Check shape padding and margin when they become editable.
246 }
247}
248
249KoSvgTextProperties KoSvgTextProperties::ownProperties(const KoSvgTextProperties &parentProperties, bool keepFontSize) const
250{
251 KoSvgTextProperties result;
252
253 auto it = m_d->properties.constBegin();
254 for (; it != m_d->properties.constEnd(); ++it) {
255 if ((keepFontSize && it.key() == FontSizeId) || !parentProperties.hasProperty(it.key())
256 || parentProperties.property(it.key()) != it.value()) {
257 result.setProperty(it.key(), it.value());
258 }
259 }
260
261 return result;
262}
263
264inline qreal roundToStraightAngle(qreal value)
265{
266 return normalizeAngle(int((value + M_PI_4) / M_PI_2) * M_PI_2);
267}
268
269QPair<QString, QString> parseTag(QString taggedValue) {
270 QPair<QString, QString> tag;
271 tag.first = taggedValue.mid(1, 4);
272 if (taggedValue.length() > 6) {
273 tag.second = taggedValue.remove(0, 6).trimmed();
274 }
275 return tag;
276}
277
278QVariantMap parseVariantStringList(const QStringList features) {
279 QVariantMap settings;
280 for (int i = 0; i < features.size(); i++) {
281 QString feature = features.at(i).trimmed();
282 if ((!feature.startsWith('\'') && !feature.startsWith('\"')) || feature.isEmpty()) {
283 continue;
284 }
285 QPair<QString, QString> tag = parseTag(feature);
286 bool ok = false;
287 double featureVal = tag.second.toDouble(&ok);
288
289 if (ok && !tag.first.isEmpty()) {
290 settings.insert(tag.first, QVariant(featureVal));
291 }
292 }
293 return settings;
294}
295
296QVariantMap parseFeatureSettingsStringList(const QStringList features) {
297 QVariantMap settings;
298 for (int i = 0; i < features.size(); i++) {
299 QString feature = features.at(i).trimmed();
300 if ((!feature.startsWith('\'') && !feature.startsWith('\"')) || feature.isEmpty()) {
301 continue;
302 }
303 QPair<QString, QString> tag = parseTag(feature);
304 if (tag.second.isEmpty()) {
305 settings.insert(tag.first, QVariant(1));
306 } else {
307 bool ok = false;
308 int featureVal = tag.second.toInt(&ok);
309 if (tag.second.toLower() == "on") {
310 featureVal = 1;
311 ok = true;
312 } else if (tag.second.toLower() == "off") {
313 featureVal = 0;
314 ok = true;
315 }
316 if (ok && !tag.first.isEmpty()) {
317 settings.insert(tag.first, QVariant(featureVal));
318 }
319 }
320 }
321 return settings;
322}
323
324void KoSvgTextProperties::parseSvgTextAttribute(const SvgLoadingContext &context, const QString &command, const QString &value)
325{
326 if (command == "writing-mode") {
328 } else if (command == "glyph-orientation-vertical") {
330 // glyph-orientation-vertical should only be converted for the 'auto', '0' and '90' cases,
331 // and treated as invalid otherwise.
332 QStringList acceptedOrientations;
333 acceptedOrientations << "auto"
334 << "0"
335 << "0deg"
336 << "90"
337 << "90deg";
338 if (acceptedOrientations.contains(value.toLower())) {
339 if (!autoValue.isAuto) {
341 }
343 setProperty(TextOrientationId, orientation);
344 }
345 } else if (command == "text-orientation") {
347 } else if (command == "direction") {
349 } else if (command == "unicode-bidi") {
351 } else if (command == "text-anchor") {
353 } else if (command == "dominant-baseline") {
355 } else if (command == "alignment-baseline") {
357 } else if (command == "baseline-shift") {
362 setProperty(BaselineShiftValueId, QVariant::fromValue(shift));
363 }
364 } else if (command == "vertical-align") {
365 QRegularExpression digits = QRegularExpression("\\d");
366 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
367 bool paramContains = param.contains(digits);
368
369 if (param == "sub" || param == "super" || param == "top" || param == "bottom" || paramContains) {
370 parseSvgTextAttribute(context, "baseline-shift", param);
371 } else {
372 parseSvgTextAttribute(context, "alignment-baseline", param);
373 }
374 }
375 } else if (command == "kerning" || command == "font-kerning") {
376 KoSvgText::AutoValue kerning;
377 if (value == "none") {
378 kerning.isAuto = false;
379 kerning.customValue = 0;
380 } else if (value == "normal") {
381 kerning.isAuto = false;
382 kerning.customValue = 1;
383 } else {
384 kerning = KoSvgText::parseAutoValueXY(value, context);
385 }
387 } else if (command == "letter-spacing") {
388 setProperty(LetterSpacingId, QVariant::fromValue(KoSvgText::parseAutoLengthPercentageXY(value, context, "normal", context.currentGC()->currentBoundingBox, true)));
389 } else if (command == "word-spacing") {
390 setProperty(WordSpacingId, QVariant::fromValue(KoSvgText::parseAutoLengthPercentageXY(value, context, "normal", context.currentGC()->currentBoundingBox, true)));
391 } else if (command == "font-family") {
392 QStringList familiesList;
393 Q_FOREACH (const QString &fam, value.split(',', Qt::SkipEmptyParts)) {
394 QString family = fam.trimmed();
395 if ((family.startsWith('\"') && family.endsWith('\"')) ||
396 (family.startsWith('\'') && family.endsWith('\''))) {
397
398 family = family.mid(1, family.size() - 2);
399 }
400 familiesList.append(family);
401 }
402 setProperty(FontFamiliesId, familiesList);
403
404 } else if (command == "font-style") {
406 } else if (command == "font-variant" || command == "font-variant-ligatures" || command == "font-variant-position" || command == "font-variant-caps"
407 || command == "font-variant-numeric" || command == "font-variant-east-asian" || command == "font-variant-alternates") {
408 const QStringList features = value.split(" ");
409 Q_FOREACH (const QString f, features) {
410 bool commandFontVariant = (command == "font-variant");
411 if (commandFontVariant || command == "font-variant-ligatures") {
414 setProperty(FontVariantLigatureId, QVariant::fromValue(liga));
415 }
416 if (commandFontVariant || command == "font-variant-position") {
419 setProperty(FontVariantPositionId, QVariant::fromValue(pos));
420 }
421 if (commandFontVariant || command == "font-variant-caps") {
423 caps = KoSvgText::parseFontFeatureCaps(f, caps);
424 setProperty(FontVariantCapsId, QVariant::fromValue(caps));
425 }
426 if (commandFontVariant || command == "font-variant-numeric") {
429 setProperty(FontVariantNumericId, QVariant::fromValue(num));
430 }
431 if (commandFontVariant || command == "font-variant-east-asian") {
434 setProperty(FontVariantEastAsianId, QVariant::fromValue(ea));
435 }
436 }
437
438 } else if (command == "font-feature-settings") {
440 } else if (command == "font-stretch") {
441 int newStretch = 100;
442
444
445 setProperty(FontStretchId, newStretch);
446
447 } else if (command == "font-weight") {
449
450 setProperty(FontWeightId, weight);
451
452 } else if (command == "font-size") {
454 if (pointSize.value > 0.0) {
455 setProperty(FontSizeId, QVariant::fromValue(pointSize));
456 }
457 } else if (command == "font-size-adjust") {
459
460 } else if (command == "font-optical-sizing") {
462 } else if (command == "font-variation-settings") {
464 } else if (command == "text-decoration" || command == "text-decoration-line" || command == "text-decoration-style" || command == "text-decoration-color"
465 || command == "text-decoration-position") {
466 using namespace KoSvgText;
467
468 TextDecorations deco = propertyOrDefault(TextDecorationLineId).value<KoSvgText::TextDecorations>();
469 if (command == "text-decoration" || command == "text-decoration-line") {
470 // reset deco when those values are being set..
472 }
473
476 QColor textDecorationColor = propertyOrDefault(TextDecorationStyleId).value<QColor>();
477 bool setPosition = false;
478
479 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
480 if (param == "line-through") {
481 deco |= DecorationLineThrough;
482 } else if (param == "underline") {
483 deco |= DecorationUnderline;
484 } else if (param == "overline") {
485 deco |= DecorationOverline;
486 } else if (param == "solid") {
487 style = Solid;
488 } else if (param == "double") {
489 style = Double;
490 } else if (param == "dotted") {
491 style = Dotted;
492 } else if (param == "dashed") {
493 style = Dashed;
494 } else if (param == "wavy") {
495 style = Wavy;
496 } else if (param == "auto") {
497 underlinePos.horizontalPosition = UnderlineAuto;
498 setPosition = true;
499 } else if (param == "under") {
500 underlinePos.horizontalPosition = UnderlineUnder;
501 setPosition = true;
502 } else if (param == "left") {
503 underlinePos.verticalPosition = UnderlineLeft;
504 setPosition = true;
505 } else if (param == "right") {
506 underlinePos.verticalPosition = UnderlineRight;
507 setPosition = true;
508#if QT_VERSION < QT_VERSION_CHECK(6, 6, 0)
509 } else if (QColor::isValidColor(param)) {
510#else
511 } else if (QColor::isValidColorName(param)) {
512#endif
513 // TODO: Convert to KoColor::fromSvg11.
514 textDecorationColor = QColor(param);
515 }
516 }
517
518 if (command == "text-decoration" || command == "text-decoration-line") {
519 setProperty(TextDecorationLineId, QVariant::fromValue(deco));
520 }
521 if (command == "text-decoration" || command == "text-decoration-style") {
523 }
524 if (command == "text-decoration" || command == "text-decoration-color") {
525 setProperty(TextDecorationColorId, QVariant::fromValue(textDecorationColor));
526 }
527 if ((command == "text-decoration" || command == "text-decoration-position") && setPosition) {
528 setProperty(TextDecorationPositionId, QVariant::fromValue(underlinePos));
529 }
530
531 } else if (command == "xml:lang") {
533 } else if (command == "text-transform") {
535 } else if (command == "white-space") {
536 KoSvgText::TextSpaceTrims trims = propertyOrDefault(TextTrimId).value<KoSvgText::TextSpaceTrims>();
539
540 KoSvgText::whiteSpaceValueToLongHands(value, collapse, wrap, trims);
541
542 setProperty(TextTrimId, QVariant::fromValue(trims));
543 setProperty(TextWrapId, wrap);
544 setProperty(TextCollapseId, collapse);
545
546 } else if (command == "xml:space") {
549 setProperty(TextCollapseId, collapse);
550 } else if (command == "word-break") {
552 } else if (command == "line-break") {
554 } else if (command == "text-align" || command == "text-align-all" || command == "text-align-last") {
555 QStringList params = value.split(' ', Qt::SkipEmptyParts);
556 if (command == "text-align" || command == "text-align-all") {
558 if (value == "justify-all") {
560 }
561 }
562 if (command == "text-align" && params.size() > 1) {
564 }
565 if (command == "text-align-last") {
567 }
568 } else if (command == "line-height") {
569 setProperty(LineHeightId, QVariant::fromValue(KoSvgText::parseLineHeight(value, context)));
570 } else if (command == "text-indent") {
571 setProperty(TextIndentId, QVariant::fromValue(KoSvgText::parseTextIndent(value, context)));
572 } else if (command == "hanging-punctuation") {
573 KoSvgText::HangingPunctuations hang;
574 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
575 if (param == "first") {
576 hang.setFlag(KoSvgText::HangFirst, true);
577 } else if (param == "last") {
578 hang.setFlag(KoSvgText::HangLast, true);
579 } else if (param == "allow-end") {
580 hang.setFlag(KoSvgText::HangEnd, true);
581 hang.setFlag(KoSvgText::HangForce, false);
582 } else if (param == "force-end") {
583 hang.setFlag(KoSvgText::HangEnd, true);
584 hang.setFlag(KoSvgText::HangForce, true);
585 }
586 }
587 setProperty(HangingPunctuationId, QVariant::fromValue(hang));
588 } else if (command == "inline-size") {
590 } else if (command == "overflow") {
592 } else if (command == "text-overflow") {
594 } else if (command == "overflow-wrap" || command == "word-wrap") {
597 : value == "anywhere" ? KoSvgText::OverflowWrapAnywhere
599 } else if (command == "tab-size") {
600 setProperty(TabSizeId, QVariant::fromValue(KoSvgText::parseTabSize(value, context)));
601 } else if (command == "shape-padding") {
603 setProperty(ShapePaddingId, QVariant::fromValue(size));
604 } else if (command == "shape-margin") {
606 setProperty(ShapeMarginId, QVariant::fromValue(size));
607 } else if (command == "font-synthesis") {
612 if (value != "none") {
613 QStringList params = value.split(" ");
614 if (params.contains("position")) {
616 }
617 if (params.contains("weight")) {
619 }
620 if (params.contains("style")) {
622 }
623 if (params.contains("small-caps")) {
625 }
626 }
627 } else if (command == "font-synthesis-weight") {
629 } else if (command == "font-synthesis-style") {
631 } else if (command == "font-synthesis-small-caps") {
633 } else if (command == "font-synthesis-position") {
635 } else if (command == "text-rendering") {
637 } else {
638 qFatal("FATAL: Unknown SVG property: %s = %s", command.toUtf8().data(), value.toUtf8().data());
639 }
640}
641
643{
644 using namespace KoSvgText;
645
646 QMap<QString, QString> result;
647
648 bool svg1_1 = false;
649
651 result.insert("writing-mode", writeWritingMode(WritingMode(property(WritingModeId).toInt()), svg1_1));
652 }
653
655 if (svg1_1) {
657 QString value = "auto";
658 if (orientation == OrientationUpright) {
659 value = "0";
660 } else if (orientation == OrientationSideWays) {
661 value = "90";
662 }
663 result.insert("glyph-orientation-vertical", value);
664 } else {
665 result.insert("text-orientation", writeTextOrientation(TextOrientation(property(TextOrientationId).toInt())));
666 }
667 }
668
670 result.insert("direction", writeDirection(Direction(property(DirectionId).toInt())));
671 }
672
674 result.insert("unicode-bidi", writeUnicodeBidi(UnicodeBidi(property(UnicodeBidiId).toInt())));
675 }
676
678 result.insert("text-anchor", writeTextAnchor(TextAnchor(property(TextAnchorId).toInt())));
679 }
680
682 result.insert("dominant-baseline", writeDominantBaseline(Baseline(property(DominantBaselineId).toInt())));
683 }
684
685 bool writeSeparate = true;
686 if (hasProperty(BaselineShiftModeId) && !svg1_1) {
688 if (mode == ShiftLineTop || mode == ShiftLineBottom) {
689 writeSeparate = false;
690 }
691 }
692
693 if (writeSeparate) {
695 result.insert("alignment-baseline", writeAlignmentBaseline(Baseline(property(AlignmentBaselineId).toInt())));
696 }
697
700 result.insert("baseline-shift",
701 writeBaselineShiftMode(BaselineShiftMode(property(BaselineShiftModeId).toInt()), shift));
702 }
703 } else {
704 QStringList verticalAlign;
706 verticalAlign.append(writeAlignmentBaseline(Baseline(property(AlignmentBaselineId).toInt())));
707 }
708
711 verticalAlign.append(writeBaselineShiftMode(BaselineShiftMode(property(BaselineShiftModeId).toInt()), shift));
712 }
713 if (!verticalAlign.isEmpty()) {
714 result.insert("vertical-align", verticalAlign.join(" "));
715 }
716 }
717
718 if (hasProperty(KerningId)) {
719 if (svg1_1) {
720 result.insert("kerning", writeAutoValue(property(KerningId).value<AutoValue>()));
721 } else {
722 AutoValue kerning = property(KerningId).value<AutoValue>();
723 if (kerning.isAuto) {
724 result.insert("font-kerning", "auto");
725 } else if (kerning.customValue == 0) {
726 result.insert("font-kerning", "none");
727 } else {
728 result.insert("font-kerning", "normal");
729 }
730 }
731 }
732
733 // Word-spacing and letter-spacing don't support % until css-text-4, and in svg 1.1, % were viewport, so save % as em for now.
735 result.insert("letter-spacing", writeAutoLengthPercentage(property(LetterSpacingId).value<AutoLengthPercentage>(), "normal", true));
736 }
737
739 result.insert("word-spacing", writeAutoLengthPercentage(property(WordSpacingId).value<AutoLengthPercentage>(), "normal", true));
740 }
741
743 result.insert("font-family", property(FontFamiliesId).toStringList().join(','));
744 }
745
748 result.insert("font-style", KoSvgText::writeFontStyle(style));
749 }
750
753 result.insert("font-variant-ligatures", writeFontFeatureLigatures(feat));
754 }
757 result.insert("font-variant-position", writeFontFeaturePosition(feat));
758 }
761 result.insert("font-variant-caps", writeFontFeatureCaps(feat));
762 }
765 result.insert("font-variant-numeric", writeFontFeatureNumeric(feat));
766 }
769 result.insert("font-variant-east-asian", writeFontFeatureEastAsian(feat));
770 }
772 QStringList settings;
773 QVariantMap vals = property(FontFeatureSettingsId).toMap();
774 for(auto it = vals.begin(); it != vals.end(); it++) {
775 settings.append(QString("'%1' %2").arg(it.key()).arg(it.value().toDouble()));
776 }
777 result.insert("font-feature-settings", settings.join(", "));
778 }
779
781 if (!property(FontOpticalSizingId).toBool()) {
782 result.insert("font-optical-sizing", "none");
783 }
784 }
786 QStringList settings;
787 QVariantMap vals = property(FontVariationSettingsId).toMap();
788 for(auto it = vals.begin(); it != vals.end(); it++) {
789 settings.append(QString("'%1' %2").arg(it.key()).arg(it.value().toDouble()));
790 }
791 result.insert("font-variation-settings", settings.join(", "));
792 }
793
795 const int stretch = property(FontStretchId).toInt();
796 static constexpr std::array<int, 9> fontStretches = {50, 62, 75, 87, 100, 112, 125, 150, 200};
797 if (svg1_1 || std::find(fontStretches.begin(), fontStretches.end(), stretch) != fontStretches.end()) {
798 const auto it = std::lower_bound(fontStretches.begin(), fontStretches.end(), stretch);
799 if (it != fontStretches.end()) {
800 const auto index = std::distance(fontStretches.begin(), it);
801 KIS_ASSERT(index >= 0);
802 result.insert("font-stretch", KoSvgText::fontStretchNames.at(static_cast<size_t>(index)));
803 }
804 } else {
805 result.insert("font-stretch", KisDomUtils::toString(stretch));
806 }
807 }
808
810 result.insert("font-weight", KisDomUtils::toString(property(FontWeightId).toInt()));
811 }
812
813 if (hasProperty(FontSizeId)) {
814 result.insert("font-size", writeLengthPercentage(fontSize()));
815 }
816
818 result.insert("font-size-adjust", writeAutoValue(property(FontSizeAdjustId).value<AutoValue>(), "none"));
819 }
820
821 QStringList decoStrings;
823 TextDecorations deco = property(TextDecorationLineId).value<TextDecorations>();
824
825 if (deco.testFlag(DecorationUnderline)) {
826 decoStrings.append("underline");
827 }
828
829 if (deco.testFlag(DecorationOverline)) {
830 decoStrings.append("overline");
831 }
832
833 if (deco.testFlag(DecorationLineThrough)) {
834 decoStrings.append("line-through");
835 }
836
837 if (deco != DecorationNone) {
840
841 if (style == Solid) {
842 decoStrings.append("solid");
843 } else if (style == Double) {
844 decoStrings.append("double");
845 } else if (style == Dotted) {
846 decoStrings.append("dotted");
847 } else if (style == Dashed) {
848 decoStrings.append("dashed");
849 } else if (style == Wavy) {
850 decoStrings.append("wavy");
851 }
852 }
854 QColor color = property(TextDecorationColorId).value<QColor>();
855 if (color.isValid()) {
856 decoStrings.append(color.name());
857 }
858 }
859 }
860 if (!decoStrings.isEmpty()) {
861 result.insert("text-decoration", decoStrings.join(' '));
862 }
863 }
864
866 QStringList decoPositionStrings;
868 if (pos.horizontalPosition == UnderlineUnder) {
869 decoPositionStrings.append("under");
870 } else {
871 decoPositionStrings.append("auto");
872 }
873 if (pos.verticalPosition == UnderlineRight) {
874 decoPositionStrings.append("right");
875 } else {
876 decoPositionStrings.append("left");
877 }
878 if (!decoPositionStrings.isEmpty()) {
879 result.insert("text-decoration-position", decoPositionStrings.join(' '));
880 }
881 }
882
884 result.insert("xml:lang", property(TextLanguage).toString());
885 }
886
888 result.insert("text-transform", writeTextTransform(property(TextTransformId).value<TextTransformInfo>()));
889 }
891 result.insert("word-break", writeWordBreak(WordBreak(property(WordBreakId).toInt())));
892 }
894 result.insert("line-break", writeLineBreak(LineBreak(property(LineBreakId).toInt())));
895 }
897 KoSvgText::TextSpaceTrims trims = propertyOrDefault(TextTrimId).value<KoSvgText::TextSpaceTrims>();
900 if (collapse == KoSvgText::PreserveSpaces || svg1_1) {
901 result.insert("xml:space", writeXmlSpace(collapse));
902 } else {
903 result.insert("white-space", writeWhiteSpaceValue(collapse, wrap, trims));
904 }
905 }
908 result.insert("line-height", KoSvgText::writeLineHeight(lineHeight));
909 }
910 if (hasProperty(TabSizeId)) {
911 result.insert("tab-size", writeTabSize(propertyOrDefault(TabSizeId).value<TabSizeInfo>()));
912 }
914 HangingPunctuations hang = property(HangingPunctuationId).value<HangingPunctuations>();
916
917 if (hang.testFlag(HangFirst)) {
918 value.append("first");
919 }
920 if (hang.testFlag(HangLast)) {
921 value.append("last");
922 }
923 if (hang.testFlag(HangEnd)) {
924 if (hang.testFlag(HangForce)) {
925 value.append("force-end");
926 } else {
927 value.append("allow-end");
928 }
929 }
930
931 if (!value.isEmpty()) {
932 result.insert("hanging-punctuation", value.join(" "));
933 }
934 }
935
938 if (overflow == OverflowWrapAnywhere) {
939 result.insert("overflow-wrap", "anywhere");
940 } else if (overflow == OverflowWrapBreakWord) {
941 result.insert("overflow-wrap", "break-word");
942 }
943 }
946 if (overflow == OverFlowClip) {
947 result.insert("overflow", "clip");
948 result.insert("text-overflow", "clip");
949 } else if (overflow == OverFlowEllipse) {
950 result.insert("overflow", "visible");
951 result.insert("text-overflow", "ellipse");
952 } else {
953 result.insert("overflow", "visible");
954 result.insert("text-overflow", "clip");
955 }
956 }
957
960 bool weight = property(FontSynthesisBoldId).toBool();
961 bool italic = property(FontSynthesisItalicId).toBool();
962 bool caps = property(FontSynthesisSmallCapsId).toBool();
963 bool super = property(FontSynthesisSuperSubId).toBool();
964
965 if (!weight && !italic && !caps && !super) {
966 result.insert("font-synthesis", "none");
967 } else {
968 QStringList params;
969 if (weight) params.append("weight");
970 if (italic) params.append("style");
971 if (caps) params.append("small-caps");
972 if (super) params.append("position");
973 result.insert("font-synthesis", params.join(" "));
974 }
975 } else {
977 result.insert("font-synthesis-weight", property(FontSynthesisBoldId).toBool()? "auto": "none");
978 }
980 result.insert("font-synthesis-style", property(FontSynthesisItalicId).toBool()? "auto": "none");
981 }
983 result.insert("font-synthesis-small-caps", property(FontSynthesisSmallCapsId).toBool()? "auto": "none");
984 }
986 result.insert("font-synthesis-position", property(FontSynthesisSuperSubId).toBool()? "auto": "none");
987 }
988 }
989
991 result.insert("text-rendering", KoSvgText::writeTextRendering(TextRendering(property(TextRenderingId).toInt())));
992 }
993
994 return result;
995}
996
998{
999 using namespace KoSvgText;
1000 QMap<QString, QString> result;
1002 result.insert("inline-size", writeAutoValue(property(InlineSizeId).value<AutoValue>(), "auto"));
1003 }
1005 result.insert("text-indent", writeTextIndent(propertyOrDefault(TextIndentId).value<TextIndentInfo>()));
1006 }
1009 result.insert("text-align", writeTextAlign(all));
1011 if (last != all || last != AlignLastAuto) {
1012 result.insert("text-align-last", writeTextAlign(last));
1013 }
1014 }
1016 result.insert("shape-padding", writeLengthPercentage(property(ShapePaddingId).value<CssLengthPercentage>()));
1017 }
1019 result.insert("shape-margin", writeLengthPercentage(property(ShapeMarginId).value<CssLengthPercentage>()));
1020 }
1021 return result;
1022}
1023
1025{
1026 QString fontFamily;
1027
1028 QStringList familiesList =
1030 if (!familiesList.isEmpty()) {
1031 fontFamily = familiesList.first();
1032 }
1033 const QFont::Style style =
1035
1037
1038 // for rounding see a comment below!
1039 QFont font(fontFamily
1040 , qMax(qRound(fontSize.value), 1)
1042 , style != QFont::StyleNormal);
1043 font.setStyle(style);
1044
1049 font.setPointSizeF(fontSize.value);
1050
1051 font.setStretch(propertyOrDefault(KoSvgTextProperties::FontStretchId).toInt());
1052
1053 using namespace KoSvgText;
1054
1055 TextDecorations deco = propertyOrDefault(KoSvgTextProperties::TextDecorationLineId).value<KoSvgText::TextDecorations>();
1056
1057 font.setStrikeOut(deco & DecorationLineThrough);
1058 font.setUnderline(deco & DecorationUnderline);
1059 font.setOverline(deco & DecorationOverline);
1060
1061 struct FakePaintDevice : public QPaintDevice
1062 {
1063 QPaintEngine *paintEngine() const override {
1064 return nullptr;
1065 }
1066
1067 int metric(QPaintDevice::PaintDeviceMetric metric) const override {
1068
1069 if (metric == QPaintDevice::PdmDpiX || metric == QPaintDevice::PdmDpiY) {
1070 return 72;
1071 }
1072
1073
1074 return QPaintDevice::metric(metric);
1075 }
1076 };
1077
1078 // paint device is used only to initialize DPI, so
1079 // we can delete it right after creation of the font
1080 FakePaintDevice fake72DpiPaintDevice;
1081 return QFont(font, &fake72DpiPaintDevice);
1082}
1083
1085{
1086 const KoSvgText::FontMetrics metrics = this->metrics(false);
1087
1088 const qreal fontSizeVal = fontSize().value;
1089 if (metrics.xHeight > 0 && metrics.fontSize > 0) {
1090 return metrics.xHeight * fontSizeVal / metrics.fontSize;
1091 }
1092 return fontSizeVal * 0.5;
1093}
1094
1095KoSvgText::FontMetrics KoSvgTextProperties::metrics(const bool withResolvedLineHeight, const bool offsetByBaseline) const
1096{
1097 const KoCSSFontInfo info = cssFontInfo();
1098
1099 const bool isHorizontal = propertyOrDefault(WritingModeId).toInt() == KoSvgText::HorizontalTB;
1102
1103 if (offsetByBaseline) {
1105 if (baseline == KoSvgText::BaselineAuto || baseline == KoSvgText::BaselineNoChange || baseline == KoSvgText::BaselineResetSize || baseline == KoSvgText::BaselineUseScript) {
1107 }
1109 }
1110
1111 return withResolvedLineHeight? applyLineHeight(metrics): metrics;
1112}
1113
1115{
1116 const qreal res = metrics.fontSize / this->fontSize().value;
1117
1119 if (!lineHeight.isNormal) {
1120 if (lineHeight.isNumber) {
1121 metrics.lineGap = (metrics.fontSize)*lineHeight.value;
1122 } else {
1123 metrics.lineGap = lineHeight.length.value * res;
1124 }
1126 }
1127 return metrics;
1128}
1129
1131{
1132 using namespace KoSvgText;
1133 QStringList fontFeatures;
1134
1136 fontFeatures.append(liga.fontFeatures(start, start+length));
1138 fontFeatures.append(KoSvgText::fontFeaturesPosition(pos, start, start+length));
1140 fontFeatures.append(KoSvgText::fontFeaturesCaps(caps, start, start+length));
1142 fontFeatures.append(numeric.fontFeatures(start, start+length));
1144 fontFeatures.append(eastasian.fontFeatures(start, start+length));
1145
1146 if (!property(KerningId).value<AutoValue>().isAuto && property(KerningId).value<AutoValue>().customValue == 0) {
1147 QString openTypeTag = "kern";
1148 openTypeTag += QString("[%1:%2]").arg(start).arg(start + length);
1149 openTypeTag += "=0";
1150 fontFeatures.append(openTypeTag);
1151 openTypeTag = "vkrn";
1152 openTypeTag += QString("[%1:%2]").arg(start).arg(start + length);
1153 openTypeTag += "=0";
1154 fontFeatures.append(openTypeTag);
1155 }
1156
1158 QVariantMap features = property(FontFeatureSettingsId).toMap();
1159 for (int i = 0; i < features.keys().size(); i++) {
1160 const QString key = features.keys().at(i);
1161 QString openTypeTag = QString("%1[%2:%3]=%4").arg(key).arg(start).arg(start + length).arg(features.value(key).toInt());
1162 fontFeatures.append(openTypeTag);
1163 }
1164 }
1165
1166 return fontFeatures;
1167}
1168
1170{
1171 KoCSSFontInfo info;
1172 info.weight = propertyOrDefault(FontWeightId).toInt();
1173 info.width = propertyOrDefault(FontStretchId).toInt();
1176 info.families = propertyOrDefault(FontFamiliesId).toStringList();
1178 if (property(KraTextVersionId).toInt() >= 3) {
1179 info.fontSizeAdjust = fontSizeAdjust.isAuto? 0.0: fontSizeAdjust.customValue;
1180 }
1181
1183 info.slantMode = style.style;
1184 info.autoSlant = style.slantValue.isAuto;
1185 info.slantValue = style.slantValue.customValue;
1186
1187 QVariantMap features = property(FontVariationSettingsId).toMap();
1188 for (auto it = features.begin(); it != features.end(); it++) {
1189 info.axisSettings.insert(it.key(), it.value().toDouble());
1190 }
1191
1192 return info;
1193}
1194
1199
1204
1209
1214
1216{
1217 QStringList attributes;
1218 attributes << "writing-mode"
1219 << "glyph-orientation-vertical"
1220 << "glyph-orientation-horizontal"
1221 << "direction"
1222 << "unicode-bidi"
1223 << "text-anchor"
1224 << "dominant-baseline"
1225 << "alignment-baseline"
1226 << "baseline-shift"
1227 << "kerning"
1228 << "letter-spacing"
1229 << "word-spacing"
1230 << "xml:space"
1231 << "xml:lang"
1232 << "text-rendering";
1233 return attributes;
1234}
1235
1236namespace {
1237Q_GLOBAL_STATIC(KoSvgTextProperties, s_defaultProperties)
1238}
1239
1241{
1242 if (!s_defaultProperties.exists()) {
1243 using namespace KoSvgText;
1244
1245 s_defaultProperties->setProperty(WritingModeId, HorizontalTB);
1246 s_defaultProperties->setProperty(DirectionId, DirectionLeftToRight);
1247 s_defaultProperties->setProperty(UnicodeBidiId, BidiNormal);
1248 s_defaultProperties->setProperty(TextAnchorId, AnchorStart);
1249 s_defaultProperties->setProperty(DominantBaselineId, BaselineAuto);
1250 s_defaultProperties->setProperty(AlignmentBaselineId, BaselineDominant);
1251 s_defaultProperties->setProperty(BaselineShiftModeId, ShiftNone);
1252 s_defaultProperties->setProperty(BaselineShiftValueId, QVariant::fromValue(KoSvgText::CssLengthPercentage()));
1253 s_defaultProperties->setProperty(KerningId, fromAutoValue(AutoValue()));
1254 s_defaultProperties->setProperty(TextOrientationId, OrientationMixed);
1255 s_defaultProperties->setProperty(LetterSpacingId, QVariant::fromValue(AutoLengthPercentage()));
1256 s_defaultProperties->setProperty(WordSpacingId, QVariant::fromValue(AutoLengthPercentage()));
1257
1258 s_defaultProperties->setProperty(FontFamiliesId, QStringLiteral("sans-serif"));
1259 s_defaultProperties->setProperty(FontStyleId, QVariant::fromValue(KoSvgText::CssFontStyleData()));
1260 s_defaultProperties->setProperty(FontStretchId, 100);
1261 s_defaultProperties->setProperty(FontWeightId, 400);
1262 s_defaultProperties->setProperty(FontSizeId, QVariant::fromValue(KoSvgText::CssLengthPercentage(12.0)));
1263 s_defaultProperties->setProperty(FontSizeAdjustId, fromAutoValue(AutoValue()));
1264
1265 s_defaultProperties->setProperty(FontSynthesisBoldId, true);
1266 s_defaultProperties->setProperty(FontSynthesisItalicId, true);
1267 s_defaultProperties->setProperty(FontSynthesisSmallCapsId, true);
1268 s_defaultProperties->setProperty(FontSynthesisSuperSubId, true);
1269
1270 s_defaultProperties->setProperty(FontOpticalSizingId, true);
1271 s_defaultProperties->setProperty(TextRenderingId, RenderingAuto);
1272 {
1273 using namespace KoSvgText;
1274 TextDecorations deco = DecorationNone;
1275
1276 s_defaultProperties->setProperty(TextDecorationLineId, QVariant::fromValue(deco));
1277 s_defaultProperties->setProperty(TextDecorationPositionId, QVariant::fromValue(KoSvgText::TextUnderlinePosition()));
1278 s_defaultProperties->setProperty(TextDecorationColorId, QVariant::fromValue(Qt::transparent));
1279 s_defaultProperties->setProperty(TextDecorationStyleId, Solid);
1280
1281 s_defaultProperties->setProperty(TextCollapseId, Collapse);
1282 s_defaultProperties->setProperty(TextWrapId, Wrap);
1283 TextSpaceTrims trim = TrimNone;
1284 s_defaultProperties->setProperty(TextTrimId, QVariant::fromValue(trim));
1285 s_defaultProperties->setProperty(LineBreakId, LineBreakAuto);
1286 s_defaultProperties->setProperty(WordBreakId, WordBreakNormal);
1287 s_defaultProperties->setProperty(TextAlignAllId, AlignStart);
1288 s_defaultProperties->setProperty(TextAlignLastId, AlignLastAuto);
1289 s_defaultProperties->setProperty(TextTransformId, TextTransformNone);
1290 s_defaultProperties->setProperty(LineHeightId, QVariant::fromValue(KoSvgText::LineHeightInfo()));
1291 s_defaultProperties->setProperty(TabSizeId, QVariant::fromValue(KoSvgText::TabSizeInfo()));
1292 HangingPunctuations hang = HangNone;
1293 s_defaultProperties->setProperty(HangingPunctuationId, QVariant::fromValue(hang));
1294 }
1295 }
1296 return *s_defaultProperties;
1297}
1298
1300{
1301 return id == WritingModeId ||
1302 id == TextAlignAllId ||
1303 id == TextAlignLastId ||
1304 id == TextIndentId ||
1305 id == HangingPunctuationId ||
1306 id == TextRenderingId;
1307}
1308
1310{
1311 return m_d->isInheritable(id);
1312}
1313
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
QPair< QString, QString > parseTag(QString taggedValue)
qreal roundToStraightAngle(qreal value)
QVariantMap parseFeatureSettingsStringList(const QStringList features)
QVariantMap parseVariantStringList(const QStringList features)
@ Collapse
Collapse if first or last in line.
KoSvgText::FontMetrics fontMetricsForCSSValues(KoCSSFontInfo info=KoCSSFontInfo(), const bool isHorizontal=true, const KoSvgText::TextRendering rendering=KoSvgText::RenderingAuto, const QString &text="", quint32 xRes=72, quint32 yRes=72, bool disableFontMatching=false, const QString &language=QString())
static KoFontRegistry * instance()
bool hasNonInheritableProperties() const
Test whether it has non-inheritable properties set.
@ TextAnchorId
KoSvgText::TextAnchor.
@ InlineSizeId
KoSvgText::AutoValue.
@ UnicodeBidiId
KoSvgText::UnicodeBidi.
@ KraTextVersionId
Int, used for handling incorrectly saved files.
@ DominantBaselineId
KoSvgText::Baseline.
@ TextTrimId
Flags, KoSvgText::TextSpaceTrims.
@ AlignmentBaselineId
KoSvgText::Baseline.
@ LineHeightId
KoSvgText::AutoValue.
@ WordSpacingId
KoSvgText::AutoLengthPercentage.
@ LineBreakId
KoSvgText::LineBreak.
@ FontSizeAdjustId
KoSvgText::AutoValue.
@ LetterSpacingId
KoSvgText::AutoLengthPercentage.
@ TextOrientationId
KoSvgText::TextOrientation.
@ TextAlignAllId
KoSvgText::TextAlign.
@ TextCollapseId
KoSvgText::TextSpaceCollapse.
@ StrokeId
KoSvgText::StrokeProperty.
@ TextDecorationStyleId
KoSvgText::TextDecorationStyle.
@ TextOverFlowId
KoSvgText::WordBreak.
@ TextTransformId
KoSvgText::TextTransformInfo Struct.
@ FillId
KoSvgText::BackgroundProperty.
@ FontStyleId
KoSvgText::CssSlantData.
@ FontFeatureSettingsId
QStringList.
@ WritingModeId
KoSvgText::WritingMode.
@ DirectionId
KoSvgText::Direction.
@ TextWrapId
KoSvgText::TextWrap.
@ HangingPunctuationId
Flags, KoSvgText::HangingPunctuations.
@ BaselineShiftModeId
KoSvgText::BaselineShiftMode.
@ TextAlignLastId
KoSvgText::TextAlign.
@ FontVariantLigatureId
KoSvgText::FontVariantFeature.
@ TextDecorationPositionId
KoSvgText::TextDecorationUnderlinePosition.
@ TextIndentId
KoSvgText::TextIndentInfo Struct.
@ FontVariationSettingsId
QStringList.
@ WordBreakId
KoSvgText::WordBreak.
@ TextLanguage
a language string.
@ TextDecorationLineId
Flags, KoSvgText::TextDecorations.
@ KerningId
KoSvgText::AutoValue.
QSharedPointer< KoShapeBackground > background() const
void removeProperty(PropertyId id)
KoShapeStrokeModelSP stroke() const
bool propertyIsInheritable(KoSvgTextProperties::PropertyId id) const
QList< PropertyId > properties() const
static bool propertyIsBlockOnly(KoSvgTextProperties::PropertyId id)
KoSvgText::FontMetrics metrics(const bool withResolvedLineHeight=true, const bool offsetByBaseline=false) const
metrics Return the metrics of the first available font.
QMap< QString, QString > convertToSvgTextAttributes() const
KoSvgTextProperties & operator=(const KoSvgTextProperties &rhs)
QVariant property(PropertyId id, const QVariant &defaultValue=QVariant()) const
QMap< QString, QString > convertParagraphProperties() const
convertParagraphProperties some properties only apply to the root shape, so we write those separately...
const QScopedPointer< Private > m_d
static const KoSvgTextProperties & defaultProperties()
QStringList fontFeaturesForText(int start, int length) const
fontFeaturesForText Returns a harfbuzz friendly list of opentype font-feature settings using the vari...
bool operator==(const KoSvgTextProperties &rhs) const
void scaleAbsoluteValues(const double scaleInline=1.0, const double scaleBlock=1.0)
scaleAbsoluteValues This scales all absolute values stored in these text properties....
bool inheritsProperty(PropertyId id, const KoSvgTextProperties &parentProperties) const
KoCSSFontInfo cssFontInfo() const
cssFontInfo
bool hasProperty(PropertyId id) const
void inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve=false, bool onlyFontAndLineHeight=false)
void setAllButNonInheritableProperties(const KoSvgTextProperties &properties)
Used to merge child properties into parent properties.
void setFontSize(const KoSvgText::CssLengthPercentage length)
void parseSvgTextAttribute(const SvgLoadingContext &context, const QString &command, const QString &value)
parseSvgTextAttribute add a property according to an XML attribute value.
void setProperty(PropertyId id, const QVariant &value)
KoSvgText::FontMetrics applyLineHeight(KoSvgText::FontMetrics metrics) const
applyLineHeight Calculate the linegap for the current linegap property.
void resolveRelativeValues(const KoSvgText::FontMetrics metrics=KoSvgText::FontMetrics(12.0, true), const qreal fontSize=12.0, bool onlyFontAndLineHeight=false)
resolveRelativeValues resolve the font-relative values.
KoSvgTextProperties ownProperties(const KoSvgTextProperties &parentProperties, bool keepFontSize=false) const
static QStringList supportedXmlAttributes()
QVariant propertyOrDefault(PropertyId id) const
KoSvgText::CssLengthPercentage fontSize() const
QRectF currentBoundingBox
the current bound box used for bounding box units
Contains data used for loading svg.
KoSvgTextProperties resolvedProperties(bool onlyFontAndLineHeight=false) const
SvgGraphicsContext * currentGC() const
Returns the current graphics context.
static KoSvgText::CssLengthPercentage parseTextUnitStruct(SvgGraphicsContext *gc, QStringView unit)
Unit structs for text do not need the percentage to be resolved to viewport in most cases.
Definition SvgUtil.cpp:239
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
T kisRadiansToDegrees(T radians)
Definition kis_global.h:181
std::enable_if< std::is_floating_point< T >::value, T >::type normalizeAngle(T a)
Definition kis_global.h:121
QString toString(const QString &value)
BaselineShiftMode parseBaselineShiftMode(const QString &value)
BaselineShiftMode
Mode of the baseline shift.
Definition KoSvgText.h:240
@ ShiftLengthPercentage
Css Length Percentage, percentage is lh.
Definition KoSvgText.h:244
FontFeatureCaps
Represents font-feature-caps.
Definition KoSvgText.h:897
bool xmlSpaceToLongHands(const QString &value, TextSpaceCollapse &collapseMethod)
xmlSpaceToLongHands This takes xml:space values and converts them to CSS-Text-4 properties.
AutoValue parseAutoValueY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
Definition KoSvgText.h:79
FontFeaturePosition
The FontFeatureLigatures class This enum represents css font-variant-position.
Definition KoSvgText.h:886
TabSizeInfo parseTabSize(const QString &value, const SvgLoadingContext &context)
Baseline parseBaseline(const QString &value)
TextDecorationStyle
Style of the text-decoration.
Definition KoSvgText.h:265
FontFeatureEastAsian parseFontFeatureEastAsian(const QString &value, FontFeatureEastAsian features)
TextAnchor parseTextAnchor(const QString &value)
OverflowWrap
What to do with words that cannot be broken, but still overflow.
Definition KoSvgText.h:151
@ OverflowWrapBreakWord
Definition KoSvgText.h:155
@ OverflowWrapNormal
Definition KoSvgText.h:152
@ OverflowWrapAnywhere
Break anywhere as soon as overflow happens.
Definition KoSvgText.h:154
TextOrientation parseTextOrientation(const QString &value)
WordBreak
Whether to break words.
Definition KoSvgText.h:132
UnicodeBidi parseUnicodeBidi(const QString &value)
WritingMode parseWritingMode(const QString &value)
TextWrap
Part of "white-space", in practice we only support wrap and nowrap.
Definition KoSvgText.h:109
QString writeLineHeight(LineHeightInfo lineHeight)
@ DecorationNone
Definition KoSvgText.h:258
bool whiteSpaceValueToLongHands(const QString &value, TextSpaceCollapse &collapseMethod, TextWrap &wrapMethod, TextSpaceTrims &trimMethod)
whiteSpaceValueToLongHands CSS-Text-4 takes CSS-Text-3 whitespace values and treats them as a shortha...
CssFontStyleData parseFontStyle(const QString &value)
TextRendering parseTextRendering(const QString &value)
Baseline
Baseline values used by dominant-baseline and baseline-align.
Definition KoSvgText.h:213
@ BaselineAlphabetic
Use 'romn' or the baseline for LCG scripts.
Definition KoSvgText.h:225
@ BaselineUseScript
Definition KoSvgText.h:216
@ BaselineResetSize
Definition KoSvgText.h:221
@ BaselineNoChange
Use parent baseline table.
Definition KoSvgText.h:220
@ BaselineCentral
Use the center between the ideographic over and under.
Definition KoSvgText.h:231
AutoValue parseAutoValueAngular(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
TextOverflow
How to handle overflow.
Definition KoSvgText.h:193
@ OverFlowVisible
Definition KoSvgText.h:194
@ OverFlowEllipse
Replace the last characters with "U+2026".
Definition KoSvgText.h:198
@ OverFlowClip
Clip the rendered content.
Definition KoSvgText.h:197
TextIndentInfo parseTextIndent(const QString &value, const SvgLoadingContext &context)
QString writeTextRendering(TextRendering value)
TextAlign parseTextAlign(const QString &value)
Direction parseDirection(const QString &value)
LineHeightInfo parseLineHeight(const QString &value, const SvgLoadingContext &context)
@ HorizontalTB
Definition KoSvgText.h:38
QVariant fromAutoValue(const KoSvgText::AutoValue &value)
Definition KoSvgText.h:493
AutoValue parseAutoValueXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
FontFeaturePosition parseFontFeaturePosition(const QString &value, FontFeaturePosition feature)
QString writeFontStyle(CssFontStyleData value)
LineBreak parseLineBreak(const QString &value)
QStringList fontFeaturesPosition(const FontFeaturePosition &feature, const int start, const int end)
int parseCSSFontWeight(const QString &value, int currentWeight)
TextOrientation parseTextOrientationFromGlyphOrientation(AutoValue value)
static const std::array< const char *, 9 > fontStretchNames
Definition KoSvgText.h:543
AutoLengthPercentage parseAutoLengthPercentageXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword, QRectF bbox, bool percentageIsViewPort)
FontFeatureCaps parseFontFeatureCaps(const QString &value, FontFeatureCaps feature)
FontFeatureLigatures parseFontFeatureLigatures(const QString &value, FontFeatureLigatures features)
int parseCSSFontStretch(const QString &value, int currentStretch)
parseCSSFontStretch For CSS3, the font-stretches were only given as keywords. In Css 4 and above,...
TextOrientation
Orientation of the glyphs, used for vertical writing modes.
Definition KoSvgText.h:70
TextTransformInfo parseTextTransform(const QString &value)
@ HangForce
Whether to force hanging stops or commas.
Definition KoSvgText.h:209
@ HangLast
Hang closing brackets and quotes.
Definition KoSvgText.h:207
@ HangFirst
Hang opening brackets and quotes.
Definition KoSvgText.h:206
@ HangEnd
Hang stops and commas. Force/Allow is a separate boolean.
Definition KoSvgText.h:208
TextSpaceCollapse
Definition KoSvgText.h:96
@ PreserveSpaces
required for 'xml:space="preserve"' emulation.
Definition KoSvgText.h:102
WordBreak parseWordBreak(const QString &value)
FontFeatureNumeric parseFontFeatureNumeric(const QString &value, FontFeatureNumeric features)
QStringList fontFeaturesCaps(const FontFeatureCaps &feature, const int start, const int end)
The KoCSSFontInfo class Convenience struct to make it easier to use KoFontRegistry....
QStringList families
double fontSizeAdjust
bool automaticOpticalSizing
< Size in Pt.
QMap< QString, double > axisSettings
QFont::Style slantMode
static bool isInheritable(PropertyId id)
QMap< PropertyId, QVariant > properties
CssLengthPercentage length
Definition KoSvgText.h:466
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
Definition KoSvgText.h:714
When style is oblique, a custom slant value can be specified for variable fonts.
Definition KoSvgText.h:475
KoSvgText::AutoValue slantValue
Definition KoSvgText.h:479
@ Absolute
Pt, everything needs to be converted to pt for this to work.
Definition KoSvgText.h:408
@ Lh
multiply by width of "U+6C34", represents average full width script advance.
Definition KoSvgText.h:415
void convertToAbsolute(const KoSvgText::FontMetrics metrics, const qreal fontSize, const UnitType percentageUnit=Em)
QStringList fontFeatures(const int start, const int end)
Definition KoSvgText.h:1023
The FontFeatureLigatures class This struct represents css font-variant-ligatures.
Definition KoSvgText.h:847
QStringList fontFeatures(const int start, const int end)
Definition KoSvgText.h:860
The FontFeatureLigatures class This struct represents css font-variant-numeric.
Definition KoSvgText.h:935
QStringList fontFeatures(const int start, const int end)
Definition KoSvgText.h:951
The FontMetrics class A class to keep track of a variety of font metrics. Note that values are in Fre...
Definition KoSvgText.h:327
qint32 xHeight
height of X, defaults to 0.5 fontsize.
Definition KoSvgText.h:334
qint32 lineGap
additional linegap between consecutive lines.
Definition KoSvgText.h:341
qint32 fontSize
Currently set size, CSS unit 'em'.
Definition KoSvgText.h:329
qint32 descender
distance for origin to bottom.
Definition KoSvgText.h:340
qint32 ascender
distance from origin to top.
Definition KoSvgText.h:339
void offsetMetricsToNewOrigin(const Baseline baseline)
bool isNumber
Length or number.
Definition KoSvgText.h:695
CssLengthPercentage length
Definition KoSvgText.h:693
bool isNormal
It's a number indicating the lineHeight;.
Definition KoSvgText.h:696
StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties.
Definition KoSvgText.h:733
qreal value
A length or a number. Length is currently marked 'at-risk'.
Definition KoSvgText.h:675
CssLengthPercentage length
Definition KoSvgText.h:678
CssLengthPercentage length
Definition KoSvgText.h:658
TextDecorationUnderlinePosition verticalPosition
Definition KoSvgText.h:1070
TextDecorationUnderlinePosition horizontalPosition
Definition KoSvgText.h:1069