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 <QRegExp>
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)
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);
125 }
126}
127
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 {
141 lineHeight.length.convertToAbsolute(this->metrics(false), usedSize);
142 }
143 setProperty(LineHeightId, QVariant::fromValue(lineHeight));
144 }
145
146 const KoSvgText::FontMetrics usedMetrics = this->metrics();
147
148 for (auto it = this->m_d->properties.begin(); it != this->m_d->properties.end(); it++) {
149
152
153 if (it.key() == LineHeightId) continue;
154 if (it.value().canConvert<KoSvgText::CssLengthPercentage>() && it.key() != KoSvgTextProperties::FontSizeId) {
156 length.convertToAbsolute(usedMetrics, usedSize, percentageUnit);
157 it.value() = QVariant::fromValue(length);
158 } else if (it.value().canConvert<KoSvgText::AutoLengthPercentage>()) {
160
161 if (!val.isAuto) {
162 val.length.convertToAbsolute(usedMetrics, usedSize, percentageUnit);
163 it.value() = QVariant::fromValue(val);
164 }
165 } else if (it.key() == KoSvgTextProperties::TabSizeId) {
167 if (!tabSize.isNumber) {
168 tabSize.length.convertToAbsolute(usedMetrics, usedSize);
169 it.value() = QVariant::fromValue(tabSize);
170 }
171 } else if (it.key() == KoSvgTextProperties::TextIndentId) {
172 KoSvgText::TextIndentInfo indent = it.value().value<KoSvgText::TextIndentInfo>();
174 indent.length.convertToAbsolute(usedMetrics, usedSize);
175 }
176 it.value() = QVariant::fromValue(indent);
177 }
178 }
179}
180
182{
183 return !hasProperty(id) || parentProperties.property(id) == property(id);
184}
185
187{
188 for (auto it = m_d->properties.constBegin(); it != m_d->properties.constEnd(); ++it) {
189 if (!m_d->isInheritable(it.key())) {
190 return true;
191 }
192 }
193 return false;
194}
195
197{
198 auto it = properties.m_d->properties.constBegin();
199 for (; it != properties.m_d->properties.constEnd(); ++it) {
200 if (m_d->isInheritable(it.key())) {
201 setProperty(it.key(), it.value());
202 }
203 }
204}
205
206void KoSvgTextProperties::scaleAbsoluteValues(const double scaleInline, const double scaleBlock)
207{
209
210 for (auto it = this->m_d->properties.begin(); it != this->m_d->properties.end(); ++it) {
211 if (it.value().canConvert<KoSvgText::CssLengthPercentage>()) {
213 if (length.unit != absoluteUnit) continue;
214 if (it.key() == FontSizeId || it.key() == BaselineShiftValueId) {
215 length.value *= scaleBlock;
216 } else {
217 length.value *= scaleInline;
218 }
219 it.value() = QVariant::fromValue(length);
220 } else if (it.value().canConvert<KoSvgText::LineHeightInfo>()) {
222 if (info.length.unit != absoluteUnit) continue;
223 info.length.value *= scaleBlock;
224 it.value() = QVariant::fromValue(info);
225 } else if (it.value().canConvert<KoSvgText::TabSizeInfo>()) {
227 if (info.length.unit != absoluteUnit) continue;
228 info.length.value *= scaleInline;
229 it.value() = QVariant::fromValue(info);
230 } else if (it.value().canConvert<KoSvgText::TextIndentInfo>()) {
231 KoSvgText::TextIndentInfo info = it.value().value<KoSvgText::TextIndentInfo>();
232 if (info.length.unit != absoluteUnit) continue;
233 info.length.value *= scaleInline;
234 it.value() = QVariant::fromValue(info);
235 } else if (it.value().canConvert<KoSvgText::AutoValue>()) {
236 KoSvgText::AutoValue info = it.value().value<KoSvgText::AutoValue>();
237 if (info.isAuto) continue;
238 if (it.key() != InlineSizeId) continue;
239 info.customValue *= scaleInline;
240 it.value() = QVariant::fromValue(info);
241 }
242 // TODO: Check shape padding and margin when they become editable.
243 }
244}
245
246KoSvgTextProperties KoSvgTextProperties::ownProperties(const KoSvgTextProperties &parentProperties, bool keepFontSize) const
247{
248 KoSvgTextProperties result;
249
250 auto it = m_d->properties.constBegin();
251 for (; it != m_d->properties.constEnd(); ++it) {
252 if ((keepFontSize && it.key() == FontSizeId) || !parentProperties.hasProperty(it.key())
253 || parentProperties.property(it.key()) != it.value()) {
254 result.setProperty(it.key(), it.value());
255 }
256 }
257
258 return result;
259}
260
261inline qreal roundToStraightAngle(qreal value)
262{
263 return normalizeAngle(int((value + M_PI_4) / M_PI_2) * M_PI_2);
264}
265
266QPair<QString, QString> parseTag(QString taggedValue) {
267 QPair<QString, QString> tag;
268 tag.first = taggedValue.mid(1, 4);
269 if (taggedValue.length() > 6) {
270 tag.second = taggedValue.remove(0, 6).trimmed();
271 }
272 return tag;
273}
274
275QVariantMap parseVariantStringList(const QStringList features) {
276 QVariantMap settings;
277 for (int i = 0; i < features.size(); i++) {
278 QString feature = features.at(i).trimmed();
279 if ((!feature.startsWith('\'') && !feature.startsWith('\"')) || feature.isEmpty()) {
280 continue;
281 }
282 QPair<QString, QString> tag = parseTag(feature);
283 bool ok = false;
284 double featureVal = tag.second.toDouble(&ok);
285
286 if (ok && !tag.first.isEmpty()) {
287 settings.insert(tag.first, QVariant(featureVal));
288 }
289 }
290 return settings;
291}
292
293QVariantMap parseFeatureSettingsStringList(const QStringList features) {
294 QVariantMap settings;
295 for (int i = 0; i < features.size(); i++) {
296 QString feature = features.at(i).trimmed();
297 if ((!feature.startsWith('\'') && !feature.startsWith('\"')) || feature.isEmpty()) {
298 continue;
299 }
300 QPair<QString, QString> tag = parseTag(feature);
301 if (tag.second.isEmpty()) {
302 settings.insert(tag.first, QVariant(1));
303 } else {
304 bool ok = false;
305 int featureVal = tag.second.toInt(&ok);
306 if (tag.second.toLower() == "on") {
307 featureVal = 1;
308 ok = true;
309 } else if (tag.second.toLower() == "off") {
310 featureVal = 0;
311 ok = true;
312 }
313 if (ok && !tag.first.isEmpty()) {
314 settings.insert(tag.first, QVariant(featureVal));
315 }
316 }
317 }
318 return settings;
319}
320
321void KoSvgTextProperties::parseSvgTextAttribute(const SvgLoadingContext &context, const QString &command, const QString &value)
322{
323 if (command == "writing-mode") {
325 } else if (command == "glyph-orientation-vertical") {
327 // glyph-orientation-vertical should only be converted for the 'auto', '0' and '90' cases,
328 // and treated as invalid otherwise.
329 QStringList acceptedOrientations;
330 acceptedOrientations << "auto"
331 << "0"
332 << "0deg"
333 << "90"
334 << "90deg";
335 if (acceptedOrientations.contains(value.toLower())) {
336 if (!autoValue.isAuto) {
338 }
340 setProperty(TextOrientationId, orientation);
341 }
342 } else if (command == "text-orientation") {
344 } else if (command == "direction") {
346 } else if (command == "unicode-bidi") {
348 } else if (command == "text-anchor") {
350 } else if (command == "dominant-baseline") {
352 } else if (command == "alignment-baseline") {
354 } else if (command == "baseline-shift") {
359 setProperty(BaselineShiftValueId, QVariant::fromValue(shift));
360 }
361 } else if (command == "vertical-align") {
362 QRegExp digits = QRegExp("\\d");
363 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
364#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
365 bool paramContains = param.contains(digits);
366#else
367 bool paramContains = (digits.indexIn(param) > 0);
368#endif
369
370
371 if (param == "sub" || param == "super" || param == "top" || param == "bottom" || paramContains) {
372 parseSvgTextAttribute(context, "baseline-shift", param);
373 } else {
374 parseSvgTextAttribute(context, "alignment-baseline", param);
375 }
376 }
377 } else if (command == "kerning" || command == "font-kerning") {
378 KoSvgText::AutoValue kerning;
379 if (value == "none") {
380 kerning.isAuto = false;
381 kerning.customValue = 0;
382 } else if (value == "normal") {
383 kerning.isAuto = false;
384 kerning.customValue = 1;
385 } else {
386 kerning = KoSvgText::parseAutoValueXY(value, context);
387 }
389 } else if (command == "letter-spacing") {
390 setProperty(LetterSpacingId, QVariant::fromValue(KoSvgText::parseAutoLengthPercentageXY(value, context, "normal", context.currentGC()->currentBoundingBox, true)));
391 } else if (command == "word-spacing") {
392 setProperty(WordSpacingId, QVariant::fromValue(KoSvgText::parseAutoLengthPercentageXY(value, context, "normal", context.currentGC()->currentBoundingBox, true)));
393 } else if (command == "font-family") {
394 QStringList familiesList;
395 Q_FOREACH (const QString &fam, value.split(',', Qt::SkipEmptyParts)) {
396 QString family = fam.trimmed();
397 if ((family.startsWith('\"') && family.endsWith('\"')) ||
398 (family.startsWith('\'') && family.endsWith('\''))) {
399
400 family = family.mid(1, family.size() - 2);
401 }
402 familiesList.append(family);
403 }
404 setProperty(FontFamiliesId, familiesList);
405
406 } else if (command == "font-style") {
408 } else if (command == "font-variant" || command == "font-variant-ligatures" || command == "font-variant-position" || command == "font-variant-caps"
409 || command == "font-variant-numeric" || command == "font-variant-east-asian" || command == "font-variant-alternates") {
410 const QStringList features = value.split(" ");
411 Q_FOREACH (const QString f, features) {
412 bool commandFontVariant = (command == "font-variant");
413 if (commandFontVariant || command == "font-variant-ligatures") {
416 setProperty(FontVariantLigatureId, QVariant::fromValue(liga));
417 }
418 if (commandFontVariant || command == "font-variant-position") {
421 setProperty(FontVariantPositionId, QVariant::fromValue(pos));
422 }
423 if (commandFontVariant || command == "font-variant-caps") {
425 caps = KoSvgText::parseFontFeatureCaps(f, caps);
426 setProperty(FontVariantCapsId, QVariant::fromValue(caps));
427 }
428 if (commandFontVariant || command == "font-variant-numeric") {
431 setProperty(FontVariantNumericId, QVariant::fromValue(num));
432 }
433 if (commandFontVariant || command == "font-variant-east-asian") {
436 setProperty(FontVariantEastAsianId, QVariant::fromValue(ea));
437 }
438 }
439
440 } else if (command == "font-feature-settings") {
442 } else if (command == "font-stretch") {
443 int newStretch = 100;
444
446
447 setProperty(FontStretchId, newStretch);
448
449 } else if (command == "font-weight") {
451
452 setProperty(FontWeightId, weight);
453
454 } else if (command == "font-size") {
456 if (pointSize.value > 0.0) {
457 setProperty(FontSizeId, QVariant::fromValue(pointSize));
458 }
459 } else if (command == "font-size-adjust") {
461
462 } else if (command == "font-optical-sizing") {
464 } else if (command == "font-variation-settings") {
466 } else if (command == "text-decoration" || command == "text-decoration-line" || command == "text-decoration-style" || command == "text-decoration-color"
467 || command == "text-decoration-position") {
468 using namespace KoSvgText;
469
470 TextDecorations deco = propertyOrDefault(TextDecorationLineId).value<KoSvgText::TextDecorations>();
471 if (command == "text-decoration" || command == "text-decoration-line") {
472 // reset deco when those values are being set..
474 }
475
478 QColor textDecorationColor = propertyOrDefault(TextDecorationStyleId).value<QColor>();
479 bool setPosition = false;
480
481 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
482 if (param == "line-through") {
483 deco |= DecorationLineThrough;
484 } else if (param == "underline") {
485 deco |= DecorationUnderline;
486 } else if (param == "overline") {
487 deco |= DecorationOverline;
488 } else if (param == "solid") {
489 style = Solid;
490 } else if (param == "double") {
491 style = Double;
492 } else if (param == "dotted") {
493 style = Dotted;
494 } else if (param == "dashed") {
495 style = Dashed;
496 } else if (param == "wavy") {
497 style = Wavy;
498 } else if (param == "auto") {
499 underlinePos.horizontalPosition = UnderlineAuto;
500 setPosition = true;
501 } else if (param == "under") {
502 underlinePos.horizontalPosition = UnderlineUnder;
503 setPosition = true;
504 } else if (param == "left") {
505 underlinePos.verticalPosition = UnderlineLeft;
506 setPosition = true;
507 } else if (param == "right") {
508 underlinePos.verticalPosition = UnderlineRight;
509 setPosition = true;
510 } else if (QColor::isValidColor(param)) {
511 // TODO: Convert to KoColor::fromSvg11.
512 textDecorationColor = QColor(param);
513 }
514 }
515
516 if (command == "text-decoration" || command == "text-decoration-line") {
517 setProperty(TextDecorationLineId, QVariant::fromValue(deco));
518 }
519 if (command == "text-decoration" || command == "text-decoration-style") {
521 }
522 if (command == "text-decoration" || command == "text-decoration-color") {
523 setProperty(TextDecorationColorId, QVariant::fromValue(textDecorationColor));
524 }
525 if ((command == "text-decoration" || command == "text-decoration-position") && setPosition) {
526 setProperty(TextDecorationPositionId, QVariant::fromValue(underlinePos));
527 }
528
529 } else if (command == "xml:lang") {
531 } else if (command == "text-transform") {
533 } else if (command == "white-space") {
534 KoSvgText::TextSpaceTrims trims = propertyOrDefault(TextTrimId).value<KoSvgText::TextSpaceTrims>();
537
538 KoSvgText::whiteSpaceValueToLongHands(value, collapse, wrap, trims);
539
540 setProperty(TextTrimId, QVariant::fromValue(trims));
541 setProperty(TextWrapId, wrap);
542 setProperty(TextCollapseId, collapse);
543
544 } else if (command == "xml:space") {
547 setProperty(TextCollapseId, collapse);
548 } else if (command == "word-break") {
550 } else if (command == "line-break") {
552 } else if (command == "text-align" || command == "text-align-all" || command == "text-align-last") {
553 QStringList params = value.split(' ', Qt::SkipEmptyParts);
554 if (command == "text-align" || command == "text-align-all") {
556 if (value == "justify-all") {
558 }
559 }
560 if (command == "text-align" && params.size() > 1) {
562 }
563 if (command == "text-align-last") {
565 }
566 } else if (command == "line-height") {
567 setProperty(LineHeightId, QVariant::fromValue(KoSvgText::parseLineHeight(value, context)));
568 } else if (command == "text-indent") {
569 setProperty(TextIndentId, QVariant::fromValue(KoSvgText::parseTextIndent(value, context)));
570 } else if (command == "hanging-punctuation") {
571 KoSvgText::HangingPunctuations hang;
572 Q_FOREACH (const QString &param, value.split(' ', Qt::SkipEmptyParts)) {
573 if (param == "first") {
574 hang.setFlag(KoSvgText::HangFirst, true);
575 } else if (param == "last") {
576 hang.setFlag(KoSvgText::HangLast, true);
577 } else if (param == "allow-end") {
578 hang.setFlag(KoSvgText::HangEnd, true);
579 hang.setFlag(KoSvgText::HangForce, false);
580 } else if (param == "force-end") {
581 hang.setFlag(KoSvgText::HangEnd, true);
582 hang.setFlag(KoSvgText::HangForce, true);
583 }
584 }
585 setProperty(HangingPunctuationId, QVariant::fromValue(hang));
586 } else if (command == "inline-size") {
588 } else if (command == "overflow") {
590 } else if (command == "text-overflow") {
592 } else if (command == "overflow-wrap" || command == "word-wrap") {
595 : value == "anywhere" ? KoSvgText::OverflowWrapAnywhere
597 } else if (command == "tab-size") {
598 setProperty(TabSizeId, QVariant::fromValue(KoSvgText::parseTabSize(value, context)));
599 } else if (command == "shape-padding") {
601 setProperty(ShapePaddingId, QVariant::fromValue(size));
602 } else if (command == "shape-margin") {
604 setProperty(ShapeMarginId, QVariant::fromValue(size));
605 } else if (command == "font-synthesis") {
610 if (value != "none") {
611 QStringList params = value.split(" ");
612 if (params.contains("position")) {
614 }
615 if (params.contains("weight")) {
617 }
618 if (params.contains("style")) {
620 }
621 if (params.contains("small-caps")) {
623 }
624 }
625 } else if (command == "font-synthesis-weight") {
627 } else if (command == "font-synthesis-style") {
629 } else if (command == "font-synthesis-small-caps") {
631 } else if (command == "font-synthesis-position") {
633 } else if (command == "text-rendering") {
635 } else {
636 qFatal("FATAL: Unknown SVG property: %s = %s", command.toUtf8().data(), value.toUtf8().data());
637 }
638}
639
641{
642 using namespace KoSvgText;
643
644 QMap<QString, QString> result;
645
646 bool svg1_1 = false;
647
649 result.insert("writing-mode", writeWritingMode(WritingMode(property(WritingModeId).toInt()), svg1_1));
650 }
651
653 if (svg1_1) {
655 QString value = "auto";
656 if (orientation == OrientationUpright) {
657 value = "0";
658 } else if (orientation == OrientationSideWays) {
659 value = "90";
660 }
661 result.insert("glyph-orientation-vertical", value);
662 } else {
663 result.insert("text-orientation", writeTextOrientation(TextOrientation(property(TextOrientationId).toInt())));
664 }
665 }
666
668 result.insert("direction", writeDirection(Direction(property(DirectionId).toInt())));
669 }
670
672 result.insert("unicode-bidi", writeUnicodeBidi(UnicodeBidi(property(UnicodeBidiId).toInt())));
673 }
674
676 result.insert("text-anchor", writeTextAnchor(TextAnchor(property(TextAnchorId).toInt())));
677 }
678
680 result.insert("dominant-baseline", writeDominantBaseline(Baseline(property(DominantBaselineId).toInt())));
681 }
682
683 bool writeSeparate = true;
684 if (hasProperty(BaselineShiftModeId) && !svg1_1) {
686 if (mode == ShiftLineTop || mode == ShiftLineBottom) {
687 writeSeparate = false;
688 }
689 }
690
691 if (writeSeparate) {
693 result.insert("alignment-baseline", writeAlignmentBaseline(Baseline(property(AlignmentBaselineId).toInt())));
694 }
695
698 result.insert("baseline-shift",
699 writeBaselineShiftMode(BaselineShiftMode(property(BaselineShiftModeId).toInt()), shift));
700 }
701 } else {
702 QStringList verticalAlign;
704 verticalAlign.append(writeAlignmentBaseline(Baseline(property(AlignmentBaselineId).toInt())));
705 }
706
709 verticalAlign.append(writeBaselineShiftMode(BaselineShiftMode(property(BaselineShiftModeId).toInt()), shift));
710 }
711 if (!verticalAlign.isEmpty()) {
712 result.insert("vertical-align", verticalAlign.join(" "));
713 }
714 }
715
716 if (hasProperty(KerningId)) {
717 if (svg1_1) {
718 result.insert("kerning", writeAutoValue(property(KerningId).value<AutoValue>()));
719 } else {
720 AutoValue kerning = property(KerningId).value<AutoValue>();
721 if (kerning.isAuto) {
722 result.insert("font-kerning", "auto");
723 } else if (kerning.customValue == 0) {
724 result.insert("font-kerning", "none");
725 } else {
726 result.insert("font-kerning", "normal");
727 }
728 }
729 }
730
731 // 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.
733 result.insert("letter-spacing", writeAutoLengthPercentage(property(LetterSpacingId).value<AutoLengthPercentage>(), "normal", true));
734 }
735
737 result.insert("word-spacing", writeAutoLengthPercentage(property(WordSpacingId).value<AutoLengthPercentage>(), "normal", true));
738 }
739
741 result.insert("font-family", property(FontFamiliesId).toStringList().join(','));
742 }
743
746 result.insert("font-style", KoSvgText::writeFontStyle(style));
747 }
748
751 result.insert("font-variant-ligatures", writeFontFeatureLigatures(feat));
752 }
755 result.insert("font-variant-position", writeFontFeaturePosition(feat));
756 }
759 result.insert("font-variant-caps", writeFontFeatureCaps(feat));
760 }
763 result.insert("font-variant-numeric", writeFontFeatureNumeric(feat));
764 }
767 result.insert("font-variant-east-asian", writeFontFeatureEastAsian(feat));
768 }
770 QStringList settings;
771 QVariantMap vals = property(FontFeatureSettingsId).toMap();
772 for(auto it = vals.begin(); it != vals.end(); it++) {
773 settings.append(QString("'%1' %2").arg(it.key()).arg(it.value().toDouble()));
774 }
775 result.insert("font-feature-settings", settings.join(", "));
776 }
777
779 if (!property(FontOpticalSizingId).toBool()) {
780 result.insert("font-optical-sizing", "none");
781 }
782 }
784 QStringList settings;
785 QVariantMap vals = property(FontVariationSettingsId).toMap();
786 for(auto it = vals.begin(); it != vals.end(); it++) {
787 settings.append(QString("'%1' %2").arg(it.key()).arg(it.value().toDouble()));
788 }
789 result.insert("font-variation-settings", settings.join(", "));
790 }
791
793 const int stretch = property(FontStretchId).toInt();
794 static constexpr std::array<int, 9> fontStretches = {50, 62, 75, 87, 100, 112, 125, 150, 200};
795 if (svg1_1 || std::find(fontStretches.begin(), fontStretches.end(), stretch) != fontStretches.end()) {
796 const auto it = std::lower_bound(fontStretches.begin(), fontStretches.end(), stretch);
797 if (it != fontStretches.end()) {
798 const auto index = std::distance(fontStretches.begin(), it);
799 KIS_ASSERT(index >= 0);
800 result.insert("font-stretch", KoSvgText::fontStretchNames.at(static_cast<size_t>(index)));
801 }
802 } else {
803 result.insert("font-stretch", KisDomUtils::toString(stretch));
804 }
805 }
806
808 result.insert("font-weight", KisDomUtils::toString(property(FontWeightId).toInt()));
809 }
810
811 if (hasProperty(FontSizeId)) {
812 result.insert("font-size", writeLengthPercentage(fontSize()));
813 }
814
816 result.insert("font-size-adjust", writeAutoValue(property(FontSizeAdjustId).value<AutoValue>(), "none"));
817 }
818
819 QStringList decoStrings;
821 TextDecorations deco = property(TextDecorationLineId).value<TextDecorations>();
822
823 if (deco.testFlag(DecorationUnderline)) {
824 decoStrings.append("underline");
825 }
826
827 if (deco.testFlag(DecorationOverline)) {
828 decoStrings.append("overline");
829 }
830
831 if (deco.testFlag(DecorationLineThrough)) {
832 decoStrings.append("line-through");
833 }
834
835 if (deco != DecorationNone) {
838
839 if (style == Solid) {
840 decoStrings.append("solid");
841 } else if (style == Double) {
842 decoStrings.append("double");
843 } else if (style == Dotted) {
844 decoStrings.append("dotted");
845 } else if (style == Dashed) {
846 decoStrings.append("dashed");
847 } else if (style == Wavy) {
848 decoStrings.append("wavy");
849 }
850 }
852 QColor color = property(TextDecorationColorId).value<QColor>();
853 if (color.isValid()) {
854 decoStrings.append(color.name());
855 }
856 }
857 }
858 if (!decoStrings.isEmpty()) {
859 result.insert("text-decoration", decoStrings.join(' '));
860 }
861 }
862
864 QStringList decoPositionStrings;
866 if (pos.horizontalPosition == UnderlineUnder) {
867 decoPositionStrings.append("under");
868 } else {
869 decoPositionStrings.append("auto");
870 }
871 if (pos.verticalPosition == UnderlineRight) {
872 decoPositionStrings.append("right");
873 } else {
874 decoPositionStrings.append("left");
875 }
876 if (!decoPositionStrings.isEmpty()) {
877 result.insert("text-decoration-position", decoPositionStrings.join(' '));
878 }
879 }
880
882 result.insert("xml:lang", property(TextLanguage).toString());
883 }
884
886 result.insert("text-transform", writeTextTransform(property(TextTransformId).value<TextTransformInfo>()));
887 }
889 result.insert("word-break", writeWordBreak(WordBreak(property(WordBreakId).toInt())));
890 }
892 result.insert("line-break", writeLineBreak(LineBreak(property(LineBreakId).toInt())));
893 }
895 KoSvgText::TextSpaceTrims trims = propertyOrDefault(TextTrimId).value<KoSvgText::TextSpaceTrims>();
898 if (collapse == KoSvgText::PreserveSpaces || svg1_1) {
899 result.insert("xml:space", writeXmlSpace(collapse));
900 } else {
901 result.insert("white-space", writeWhiteSpaceValue(collapse, wrap, trims));
902 }
903 }
906 result.insert("line-height", KoSvgText::writeLineHeight(lineHeight));
907 }
908 if (hasProperty(TabSizeId)) {
909 result.insert("tab-size", writeTabSize(propertyOrDefault(TabSizeId).value<TabSizeInfo>()));
910 }
912 HangingPunctuations hang = property(HangingPunctuationId).value<HangingPunctuations>();
914
915 if (hang.testFlag(HangFirst)) {
916 value.append("first");
917 }
918 if (hang.testFlag(HangLast)) {
919 value.append("last");
920 }
921 if (hang.testFlag(HangEnd)) {
922 if (hang.testFlag(HangForce)) {
923 value.append("force-end");
924 } else {
925 value.append("allow-end");
926 }
927 }
928
929 if (!value.isEmpty()) {
930 result.insert("hanging-punctuation", value.join(" "));
931 }
932 }
933
936 if (overflow == OverflowWrapAnywhere) {
937 result.insert("overflow-wrap", "anywhere");
938 } else if (overflow == OverflowWrapBreakWord) {
939 result.insert("overflow-wrap", "break-word");
940 }
941 }
944 if (overflow == OverFlowClip) {
945 result.insert("overflow", "clip");
946 result.insert("text-overflow", "clip");
947 } else if (overflow == OverFlowEllipse) {
948 result.insert("overflow", "visible");
949 result.insert("text-overflow", "ellipse");
950 } else {
951 result.insert("overflow", "visible");
952 result.insert("text-overflow", "clip");
953 }
954 }
955
958 bool weight = property(FontSynthesisBoldId).toBool();
959 bool italic = property(FontSynthesisItalicId).toBool();
960 bool caps = property(FontSynthesisSmallCapsId).toBool();
961 bool super = property(FontSynthesisSuperSubId).toBool();
962
963 if (!weight && !italic && !caps && !super) {
964 result.insert("font-synthesis", "none");
965 } else {
966 QStringList params;
967 if (weight) params.append("weight");
968 if (italic) params.append("style");
969 if (caps) params.append("small-caps");
970 if (super) params.append("position");
971 result.insert("font-synthesis", params.join(" "));
972 }
973 } else {
975 result.insert("font-synthesis-weight", property(FontSynthesisBoldId).toBool()? "auto": "none");
976 }
978 result.insert("font-synthesis-style", property(FontSynthesisItalicId).toBool()? "auto": "none");
979 }
981 result.insert("font-synthesis-small-caps", property(FontSynthesisSmallCapsId).toBool()? "auto": "none");
982 }
984 result.insert("font-synthesis-position", property(FontSynthesisSuperSubId).toBool()? "auto": "none");
985 }
986 }
987
989 result.insert("text-rendering", KoSvgText::writeTextRendering(TextRendering(property(TextRenderingId).toInt())));
990 }
991
992 return result;
993}
994
996{
997 using namespace KoSvgText;
998 QMap<QString, QString> result;
1000 result.insert("inline-size", writeAutoValue(property(InlineSizeId).value<AutoValue>(), "auto"));
1001 }
1003 result.insert("text-indent", writeTextIndent(propertyOrDefault(TextIndentId).value<TextIndentInfo>()));
1004 }
1007 result.insert("text-align", writeTextAlign(all));
1009 if (last != all || last != AlignLastAuto) {
1010 result.insert("text-align-last", writeTextAlign(last));
1011 }
1012 }
1014 result.insert("shape-padding", writeLengthPercentage(property(ShapePaddingId).value<CssLengthPercentage>()));
1015 }
1017 result.insert("shape-margin", writeLengthPercentage(property(ShapeMarginId).value<CssLengthPercentage>()));
1018 }
1019 return result;
1020}
1021
1023{
1024 QString fontFamily;
1025
1026 QStringList familiesList =
1028 if (!familiesList.isEmpty()) {
1029 fontFamily = familiesList.first();
1030 }
1031 const QFont::Style style =
1033
1035
1036 // for rounding see a comment below!
1037 QFont font(fontFamily
1038 , qMax(qRound(fontSize.value), 1)
1040 , style != QFont::StyleNormal);
1041 font.setStyle(style);
1042
1047 font.setPointSizeF(fontSize.value);
1048
1049 font.setStretch(propertyOrDefault(KoSvgTextProperties::FontStretchId).toInt());
1050
1051 using namespace KoSvgText;
1052
1053 TextDecorations deco = propertyOrDefault(KoSvgTextProperties::TextDecorationLineId).value<KoSvgText::TextDecorations>();
1054
1055 font.setStrikeOut(deco & DecorationLineThrough);
1056 font.setUnderline(deco & DecorationUnderline);
1057 font.setOverline(deco & DecorationOverline);
1058
1059 struct FakePaintDevice : public QPaintDevice
1060 {
1061 QPaintEngine *paintEngine() const override {
1062 return nullptr;
1063 }
1064
1065 int metric(QPaintDevice::PaintDeviceMetric metric) const override {
1066
1067 if (metric == QPaintDevice::PdmDpiX || metric == QPaintDevice::PdmDpiY) {
1068 return 72;
1069 }
1070
1071
1072 return QPaintDevice::metric(metric);
1073 }
1074 };
1075
1076 // paint device is used only to initialize DPI, so
1077 // we can delete it right after creation of the font
1078 FakePaintDevice fake72DpiPaintDevice;
1079 return QFont(font, &fake72DpiPaintDevice);
1080}
1081
1083{
1084 const KoSvgText::FontMetrics metrics = this->metrics(false);
1085
1086 const qreal fontSizeVal = fontSize().value;
1087 if (metrics.xHeight > 0 && metrics.fontSize > 0) {
1088 return metrics.xHeight * fontSizeVal / metrics.fontSize;
1089 }
1090 return fontSizeVal * 0.5;
1091}
1092
1093KoSvgText::FontMetrics KoSvgTextProperties::metrics(const bool withResolvedLineHeight, const bool offsetByBaseline) const
1094{
1095 const KoCSSFontInfo info = cssFontInfo();
1096
1097 const bool isHorizontal = propertyOrDefault(WritingModeId).toInt() == KoSvgText::HorizontalTB;
1100
1101 if (offsetByBaseline) {
1103 if (baseline == KoSvgText::BaselineAuto || baseline == KoSvgText::BaselineNoChange || baseline == KoSvgText::BaselineResetSize || baseline == KoSvgText::BaselineUseScript) {
1105 }
1107 }
1108
1109 return withResolvedLineHeight? applyLineHeight(metrics): metrics;
1110}
1111
1113{
1114 const qreal res = metrics.fontSize / this->fontSize().value;
1115
1117 if (!lineHeight.isNormal) {
1118 if (lineHeight.isNumber) {
1119 metrics.lineGap = (metrics.fontSize)*lineHeight.value;
1120 } else {
1121 metrics.lineGap = lineHeight.length.value * res;
1122 }
1124 }
1125 return metrics;
1126}
1127
1129{
1130 using namespace KoSvgText;
1131 QStringList fontFeatures;
1132
1134 fontFeatures.append(liga.fontFeatures(start, start+length));
1136 fontFeatures.append(KoSvgText::fontFeaturesPosition(pos, start, start+length));
1138 fontFeatures.append(KoSvgText::fontFeaturesCaps(caps, start, start+length));
1140 fontFeatures.append(numeric.fontFeatures(start, start+length));
1142 fontFeatures.append(eastasian.fontFeatures(start, start+length));
1143
1144 if (!property(KerningId).value<AutoValue>().isAuto && property(KerningId).value<AutoValue>().customValue == 0) {
1145 QString openTypeTag = "kern";
1146 openTypeTag += QString("[%1:%2]").arg(start).arg(start + length);
1147 openTypeTag += "=0";
1148 fontFeatures.append(openTypeTag);
1149 openTypeTag = "vkrn";
1150 openTypeTag += QString("[%1:%2]").arg(start).arg(start + length);
1151 openTypeTag += "=0";
1152 fontFeatures.append(openTypeTag);
1153 }
1154
1156 QVariantMap features = property(FontFeatureSettingsId).toMap();
1157 for (int i = 0; i < features.keys().size(); i++) {
1158 const QString key = features.keys().at(i);
1159 QString openTypeTag = QString("%1[%2:%3]=%4").arg(key).arg(start).arg(start + length).arg(features.value(key).toInt());
1160 fontFeatures.append(openTypeTag);
1161 }
1162 }
1163
1164 return fontFeatures;
1165}
1166
1168{
1169 KoCSSFontInfo info;
1170 info.weight = propertyOrDefault(FontWeightId).toInt();
1171 info.width = propertyOrDefault(FontStretchId).toInt();
1174 info.families = propertyOrDefault(FontFamiliesId).toStringList();
1176 if (property(KraTextVersionId).toInt() >= 3) {
1177 info.fontSizeAdjust = fontSizeAdjust.isAuto? 0.0: fontSizeAdjust.customValue;
1178 }
1179
1181 info.slantMode = style.style;
1182 info.autoSlant = style.slantValue.isAuto;
1183 info.slantValue = style.slantValue.customValue;
1184
1185 QVariantMap features = property(FontVariationSettingsId).toMap();
1186 for (auto it = features.begin(); it != features.end(); it++) {
1187 info.axisSettings.insert(it.key(), it.value().toDouble());
1188 }
1189
1190 return info;
1191}
1192
1197
1202
1207
1212
1214{
1215 QStringList attributes;
1216 attributes << "writing-mode"
1217 << "glyph-orientation-vertical"
1218 << "glyph-orientation-horizontal"
1219 << "direction"
1220 << "unicode-bidi"
1221 << "text-anchor"
1222 << "dominant-baseline"
1223 << "alignment-baseline"
1224 << "baseline-shift"
1225 << "kerning"
1226 << "letter-spacing"
1227 << "word-spacing"
1228 << "xml:space"
1229 << "xml:lang"
1230 << "text-rendering";
1231 return attributes;
1232}
1233
1234namespace {
1235Q_GLOBAL_STATIC(KoSvgTextProperties, s_defaultProperties)
1236}
1237
1239{
1240 if (!s_defaultProperties.exists()) {
1241 using namespace KoSvgText;
1242
1243 s_defaultProperties->setProperty(WritingModeId, HorizontalTB);
1244 s_defaultProperties->setProperty(DirectionId, DirectionLeftToRight);
1245 s_defaultProperties->setProperty(UnicodeBidiId, BidiNormal);
1246 s_defaultProperties->setProperty(TextAnchorId, AnchorStart);
1247 s_defaultProperties->setProperty(DominantBaselineId, BaselineAuto);
1248 s_defaultProperties->setProperty(AlignmentBaselineId, BaselineDominant);
1249 s_defaultProperties->setProperty(BaselineShiftModeId, ShiftNone);
1250 s_defaultProperties->setProperty(BaselineShiftValueId, QVariant::fromValue(KoSvgText::CssLengthPercentage()));
1251 s_defaultProperties->setProperty(KerningId, fromAutoValue(AutoValue()));
1252 s_defaultProperties->setProperty(TextOrientationId, OrientationMixed);
1253 s_defaultProperties->setProperty(LetterSpacingId, QVariant::fromValue(AutoLengthPercentage()));
1254 s_defaultProperties->setProperty(WordSpacingId, QVariant::fromValue(AutoLengthPercentage()));
1255
1256 s_defaultProperties->setProperty(FontFamiliesId, QStringLiteral("sans-serif"));
1257 s_defaultProperties->setProperty(FontStyleId, QVariant::fromValue(KoSvgText::CssFontStyleData()));
1258 s_defaultProperties->setProperty(FontStretchId, 100);
1259 s_defaultProperties->setProperty(FontWeightId, 400);
1260 s_defaultProperties->setProperty(FontSizeId, QVariant::fromValue(KoSvgText::CssLengthPercentage(12.0)));
1261 s_defaultProperties->setProperty(FontSizeAdjustId, fromAutoValue(AutoValue()));
1262
1263 s_defaultProperties->setProperty(FontSynthesisBoldId, true);
1264 s_defaultProperties->setProperty(FontSynthesisItalicId, true);
1265 s_defaultProperties->setProperty(FontSynthesisSmallCapsId, true);
1266 s_defaultProperties->setProperty(FontSynthesisSuperSubId, true);
1267
1268 s_defaultProperties->setProperty(FontOpticalSizingId, true);
1269 s_defaultProperties->setProperty(TextRenderingId, RenderingAuto);
1270 {
1271 using namespace KoSvgText;
1272 TextDecorations deco = DecorationNone;
1273
1274 s_defaultProperties->setProperty(TextDecorationLineId, QVariant::fromValue(deco));
1275 s_defaultProperties->setProperty(TextDecorationPositionId, QVariant::fromValue(KoSvgText::TextUnderlinePosition()));
1276 s_defaultProperties->setProperty(TextDecorationColorId, QVariant::fromValue(Qt::transparent));
1277 s_defaultProperties->setProperty(TextDecorationStyleId, Solid);
1278
1279 s_defaultProperties->setProperty(TextCollapseId, Collapse);
1280 s_defaultProperties->setProperty(TextWrapId, Wrap);
1281 TextSpaceTrims trim = TrimNone;
1282 s_defaultProperties->setProperty(TextTrimId, QVariant::fromValue(trim));
1283 s_defaultProperties->setProperty(LineBreakId, LineBreakAuto);
1284 s_defaultProperties->setProperty(WordBreakId, WordBreakNormal);
1285 s_defaultProperties->setProperty(TextAlignAllId, AlignStart);
1286 s_defaultProperties->setProperty(TextAlignLastId, AlignLastAuto);
1287 s_defaultProperties->setProperty(TextTransformId, TextTransformNone);
1288 s_defaultProperties->setProperty(LineHeightId, QVariant::fromValue(KoSvgText::LineHeightInfo()));
1289 s_defaultProperties->setProperty(TabSizeId, QVariant::fromValue(KoSvgText::TabSizeInfo()));
1290 HangingPunctuations hang = HangNone;
1291 s_defaultProperties->setProperty(HangingPunctuationId, QVariant::fromValue(hang));
1292 }
1293 }
1294 return *s_defaultProperties;
1295}
1296
1298{
1299 return id == WritingModeId ||
1300 id == TextAlignAllId ||
1301 id == TextAlignLastId ||
1302 id == TextIndentId ||
1303 id == HangingPunctuationId ||
1304 id == TextRenderingId;
1305}
1306
1308{
1309 return m_d->isInheritable(id);
1310}
1311
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 resolveRelativeValues(const KoSvgText::FontMetrics metrics=KoSvgText::FontMetrics(12.0, true), const qreal fontSize=12.0)
resolveRelativeValues resolve the font-relative values.
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.
KoSvgTextProperties ownProperties(const KoSvgTextProperties &parentProperties, bool keepFontSize=false) const
static QStringList supportedXmlAttributes()
QVariant propertyOrDefault(PropertyId id) const
KoSvgText::CssLengthPercentage fontSize() const
void inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve=false)
QRectF currentBoundingBox
the current bound box used for bounding box units
Contains data used for loading svg.
SvgGraphicsContext * currentGC() const
Returns the current graphics context.
KoSvgTextProperties resolvedProperties() const
These are the text properties, completely resolved, ensuring that everything is inherited and the siz...
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