Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSvgText.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
7#include "KoSvgText.h"
8
9#include <QDebug>
10#include <array>
11
12#include <kis_dom_utils.h>
13
14#include <KoColorBackground.h>
17#include <KoShapeStroke.h>
18
19#include <SvgLoadingContext.h>
20#include <SvgUtil.h>
21
23
25 qRegisterMetaType<KoSvgText::CssLengthPercentage>("KoSvgText::CssLengthPercentage");
26 qRegisterMetaType<KoSvgText::AutoValue>("KoSvgText::AutoValue");
27 qRegisterMetaType<KoSvgText::AutoLengthPercentage>("KoSvgText::AutoLengthPercentage");
28 qRegisterMetaType<KoSvgText::StrokeProperty>("KoSvgText::StrokeProperty");
29 qRegisterMetaType<KoSvgText::TextTransformInfo>("KoSvgText::TextTransformInfo");
30 qRegisterMetaType<KoSvgText::TextIndentInfo>("KoSvgText::TextIndentInfo");
31 qRegisterMetaType<KoSvgText::TabSizeInfo>("KoSvgText::TabSizeInfo");
32 qRegisterMetaType<KoSvgText::LineHeightInfo>("KoSvgText::LineHeightInfo");
33 qRegisterMetaType<KoSvgText::FontFamilyAxis>("KoSvgText::FontFamilyAxis");
34 qRegisterMetaType<KoSvgText::FontFamilyStyleInfo>("KoSvgText::FontFamilyStyleInfo");
35 qRegisterMetaType<KoSvgText::CssFontStyleData>("KoSvgText::CssSlantData");
36 qRegisterMetaType<KoSvgText::BackgroundProperty>("KoSvgText::BackgroundProperty");
37 qRegisterMetaType<KoSvgText::FontFeatureLigatures>("KoSvgText::FontFeatureLigatures");
38 qRegisterMetaType<KoSvgText::FontFeatureNumeric>("KoSvgText::FontFeatureNumeric");
39 qRegisterMetaType<KoSvgText::FontFeatureEastAsian>("KoSvgText::FontFeatureEastAsian");
40 qRegisterMetaType<KoSvgText::FontMetrics>("KoSvgText::FontMetrics");
41 qRegisterMetaType<KoSvgText::TextUnderlinePosition>("KoSvgText::TextUnderlinePosition");
42
43#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
44 qRegisterMetaTypeStreamOperators<KoSvgText::FontFamilyAxis>("KoSvgText::FontFamilyAxis");
45 qRegisterMetaTypeStreamOperators<KoSvgText::FontFamilyStyleInfo>("KoSvgText::FontFamilyStyleInfo");
46
47 QMetaType::registerEqualsComparator<KoSvgText::CssLengthPercentage>();
48 QMetaType::registerDebugStreamOperator<KoSvgText::CssLengthPercentage>();
49
50 QMetaType::registerEqualsComparator<KoSvgText::AutoValue>();
51 QMetaType::registerDebugStreamOperator<KoSvgText::AutoValue>();
52
53
54 QMetaType::registerEqualsComparator<KoSvgText::AutoLengthPercentage>();
55 QMetaType::registerDebugStreamOperator<KoSvgText::AutoLengthPercentage>();
56
57 QMetaType::registerEqualsComparator<KoSvgText::CssFontStyleData>();
58 QMetaType::registerDebugStreamOperator<KoSvgText::CssFontStyleData>();
59
60 QMetaType::registerEqualsComparator<KoSvgText::BackgroundProperty>();
61 QMetaType::registerDebugStreamOperator<KoSvgText::BackgroundProperty>();
62
63
64 QMetaType::registerEqualsComparator<KoSvgText::StrokeProperty>();
65 QMetaType::registerDebugStreamOperator<KoSvgText::StrokeProperty>();
66
67
68 QMetaType::registerEqualsComparator<KoSvgText::TextTransformInfo>();
69 QMetaType::registerDebugStreamOperator<KoSvgText::TextTransformInfo>();
70
71
72 QMetaType::registerEqualsComparator<KoSvgText::TextIndentInfo>();
73 QMetaType::registerDebugStreamOperator<KoSvgText::TextIndentInfo>();
74
75
76 QMetaType::registerEqualsComparator<KoSvgText::TabSizeInfo>();
77 QMetaType::registerDebugStreamOperator<KoSvgText::TabSizeInfo>();
78
79 QMetaType::registerEqualsComparator<KoSvgText::LineHeightInfo>();
80 QMetaType::registerDebugStreamOperator<KoSvgText::LineHeightInfo>();
81
82 QMetaType::registerEqualsComparator<KoSvgText::FontFamilyAxis>();
83 QMetaType::registerDebugStreamOperator<KoSvgText::FontFamilyAxis>();
84
85 QMetaType::registerEqualsComparator<KoSvgText::FontFamilyStyleInfo>();
86 QMetaType::registerDebugStreamOperator<KoSvgText::FontFamilyStyleInfo>();
87
88 QMetaType::registerEqualsComparator<KoSvgText::FontFeatureLigatures>();
89 QMetaType::registerDebugStreamOperator<KoSvgText::FontFeatureLigatures>();
90
91 QMetaType::registerEqualsComparator<KoSvgText::FontFeatureNumeric>();
92 QMetaType::registerDebugStreamOperator<KoSvgText::FontFeatureNumeric>();
93
94 QMetaType::registerEqualsComparator<KoSvgText::FontFeatureEastAsian>();
95 QMetaType::registerDebugStreamOperator<KoSvgText::FontFeatureEastAsian>();
96
97 QMetaType::registerEqualsComparator<KoSvgText::FontMetrics>();
98 QMetaType::registerDebugStreamOperator<KoSvgText::FontMetrics>();
99
100 QMetaType::registerEqualsComparator<KoSvgText::TextUnderlinePosition>();
101 QMetaType::registerDebugStreamOperator<KoSvgText::TextUnderlinePosition>();
102#endif
103}
104
105namespace KoSvgText {
106
107AutoValue parseAutoValueX(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
108{
109 return value == autoKeyword ? AutoValue() : SvgUtil::parseUnitX(context.currentGC(), context.resolvedProperties(), value);
110}
111
112AutoValue parseAutoValueY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
113{
114 return value == autoKeyword ? AutoValue() : SvgUtil::parseUnitY(context.currentGC(), context.resolvedProperties(), value);
115}
116
117AutoValue parseAutoValueXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
118{
119 return value == autoKeyword ? AutoValue() : SvgUtil::parseUnitXY(context.currentGC(), context.resolvedProperties(), value);
120}
121
122AutoValue parseAutoValueAngular(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
123{
124 return value == autoKeyword ? AutoValue() : SvgUtil::parseUnitAngular(context.currentGC(), value);
125}
126
128 return (value == "tb-rl" || value == "tb" || value == "vertical-rl") ? VerticalRL : (value == "vertical-lr") ? VerticalLR : HorizontalTB;
129}
130
133}
134
136{
137 return value == "embed" ? BidiEmbed
138 : value == "bidi-override" ? BidiOverride
139 : value == "isolate" ? BidiIsolate
140 : value == "isolate-override" ? BidiIsolateOverride
141 : value == "plaintext" ? BidiPlainText
142 : BidiNormal;
143}
144
146{
147 return value == "upright" ? OrientationUpright : value == "sideways" ? OrientationSideWays : OrientationMixed;
148}
150{
151 if (value.isAuto) {
152 return OrientationMixed;
153 } else if (value.customValue == 0) {
154 return OrientationUpright;
155 } else if (value.customValue == 90) {
156 return OrientationSideWays;
157 } else {
158 return OrientationMixed;
159 }
160}
161
163{
164 return value == "middle" ? AnchorMiddle :
165 value == "end" ? AnchorEnd :
167}
168
170{
171 return value == "use-script" ? BaselineUseScript
172 : value == "no-change" ? BaselineNoChange
173 : value == "reset-size" ? BaselineResetSize
174 : value == "ideographic" ? BaselineIdeographic
175 : value == "alphabetic" ? BaselineAlphabetic
176 : value == "hanging" ? BaselineHanging
177 : value == "mathematical" ? BaselineMathematical
178 : value == "central" ? BaselineCentral
179 : value == "middle" ? BaselineMiddle
180 : value == "baseline" ? BaselineDominant
181 : (value == "text-after-edge" || value == "after-edge" || value == "text-bottom") ? BaselineTextBottom
182 : (value == "text-before-edge" || value == "before-edge" || value == "text-top") ? BaselineTextTop
183 : BaselineAuto;
184}
185
187{
188 return value == "baseline" ? ShiftNone :
189 value == "sub" ? ShiftSub :
190 value == "super" ? ShiftSuper :
191 value == "top" ? ShiftLineTop :
192 value == "bottom" ? ShiftLineBottom :
194}
195
197{
198 return value == "spacingAndGlyphs" ? LengthAdjustSpacingAndGlyphs : LengthAdjustSpacing;
199}
200
201QString writeAutoValue(const AutoValue &value, const QString &autoKeyword)
202{
203 return value.isAuto ? autoKeyword : KisDomUtils::toString(value.customValue);
204}
205
206QString writeWritingMode(WritingMode value, bool svg1_1)
207{
208 if (svg1_1) {
209 return value == VerticalRL ? "tb" : "lr";
210 } else {
211 return value == VerticalRL ? "vertical-rl" : value == VerticalLR ? "vertical-lr" : "horizontal-tb";
212 }
213}
214
216{
217 return value == DirectionRightToLeft ? "rtl" : "ltr";
218}
219
221{
222 return value == BidiEmbed ? "embed"
223 : value == BidiOverride ? "bidi-override"
224 : value == BidiIsolate ? "isolate"
225 : value == BidiIsolateOverride ? "isolate-override"
226 : value == BidiPlainText ? "plaintext"
227 : "normal";
228}
229
231{
232 return orientation == OrientationUpright ? "upright" : orientation == OrientationSideWays ? "sideways" : "mixed";
233}
234
236{
237 return value == AnchorEnd ? "end" : value == AnchorMiddle ? "middle" : "start";
238}
239
241{
242 return value == BaselineUseScript ? "use-script"
243 : value == BaselineNoChange ? "no-change"
244 : value == BaselineResetSize ? "reset-size"
245 : value == BaselineIdeographic ? "ideographic"
246 : value == BaselineAlphabetic ? "alphabetic"
247 : value == BaselineHanging ? "hanging"
248 : value == BaselineMathematical ? "mathematical"
249 : value == BaselineCentral ? "central"
250 : value == BaselineMiddle ? "middle"
251 : value == BaselineTextBottom ? "text-bottom"
252 : // text-after-edge in svg 1.1
253 value == BaselineTextTop ? "text-top"
254 : // text-before-edge in svg 1.1
255 "auto";
256}
257
259{
260 return value == BaselineDominant ? "baseline"
261 : value == BaselineIdeographic ? "ideographic"
262 : value == BaselineAlphabetic ? "alphabetic"
263 : value == BaselineHanging ? "hanging"
264 : value == BaselineMathematical ? "mathematical"
265 : value == BaselineCentral ? "central"
266 : value == BaselineMiddle ? "middle"
267 : value == BaselineTextBottom ? "text-bottom"
268 : // text-after-edge in svg 1.1
269 value == BaselineTextTop ? "text-top"
270 : // text-before-edge in svg 1.1
271 "auto";
272}
273
275{
276 return value == ShiftNone ? "baseline" :
277 value == ShiftSub ? "sub" :
278 value == ShiftSuper ? "super" :
279 value == ShiftLineTop ? "top" :
280 value == ShiftLineBottom ? "bottom" :
282}
283
285{
286 return value == LengthAdjustSpacingAndGlyphs ? "spacingAndGlyphs" : "spacing";
287}
288
289QDebug operator<<(QDebug dbg, const KoSvgText::AutoValue &value)
290{
291 dbg.nospace() << (value.isAuto ? "auto" : QString::number(value.customValue));
292 return dbg.space();
293}
294
296{
297 if (value.style == QFont::StyleOblique) {
298 dbg.nospace() << "oblique ";
299 dbg.nospace() << value.slantValue;
300 } else {
301 dbg.nospace() << (value.style == QFont::StyleItalic? "italic": "roman");
302 }
303
304
305 return dbg.space();
306}
307
309{
310 if (!xPos && t.xPos) {
311 xPos = *t.xPos;
312 }
313
314 if (!yPos && t.yPos) {
315 yPos = *t.yPos;
316 }
317
318 if (!dxPos && t.dxPos) {
319 dxPos = *t.dxPos;
320 }
321
322 if (!dyPos && t.dyPos) {
323 dyPos = *t.dyPos;
324 }
325
326 if (!rotate && t.rotate) {
327 rotate = *t.rotate;
328 }
329}
330
332{
333 return !xPos && !yPos && !dxPos && !dyPos && !rotate;
334}
335
337{
338 return xPos || yPos;
339}
340
342{
343 return dxPos || dyPos;
344}
345
347{
348 QPointF result;
349
350 if (xPos) {
351 result.rx() = *xPos;
352 }
353
354 if (yPos) {
355 result.ry() = *yPos;
356 }
357
358 return result;
359}
360
362{
363 QPointF result;
364
365 if (dxPos) {
366 result.rx() = *dxPos;
367 }
368
369 if (dyPos) {
370 result.ry() = *dyPos;
371 }
372
373 return result;
374}
375
377 return
378 xPos == other.xPos && yPos == other.yPos &&
379 dxPos == other.dxPos && dyPos == other.dyPos &&
380 rotate == other.rotate;
381}
382
383namespace {
384QDebug addSeparator(QDebug dbg, bool hasPreviousContent) {
385 return hasPreviousContent ? (dbg.nospace() << "; ") : dbg;
386}
387}
388
389QDebug operator<<(QDebug dbg, const CharTransformation &t)
390{
391 dbg.nospace() << "CharTransformation(";
392
393 bool hasContent = false;
394
395 if (t.xPos) {
396 dbg.nospace() << "xPos = " << *t.xPos;
397 hasContent = true;
398 }
399
400 if (t.yPos) {
401 dbg = addSeparator(dbg, hasContent);
402 dbg.nospace() << "yPos = " << *t.yPos;
403 hasContent = true;
404 }
405
406 if (t.dxPos) {
407 dbg = addSeparator(dbg, hasContent);
408 dbg.nospace() << "dxPos = " << *t.dxPos;
409 hasContent = true;
410 }
411
412 if (t.dyPos) {
413 dbg = addSeparator(dbg, hasContent);
414 dbg.nospace() << "dyPos = " << *t.dyPos;
415 hasContent = true;
416 }
417
418 if (t.rotate) {
419 dbg = addSeparator(dbg, hasContent);
420 dbg.nospace() << "rotate = " << *t.rotate;
421 hasContent = true;
422 }
423
424 dbg.nospace() << ")";
425 return dbg.space();
426}
427
428QDebug operator<<(QDebug dbg, const TextTransformInfo &t)
429{
430 dbg.nospace() << "TextTransformInfo(";
431 dbg.nospace() << writeTextTransform(t);
432 dbg.nospace() << ")";
433 return dbg.space();
434}
435QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::TextIndentInfo &value)
436{
437 dbg.nospace() << "TextIndentInfo(";
438 dbg.nospace() << writeTextIndent(value);
439 dbg.nospace() << ")";
440 return dbg.space();
441}
442
443QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::TabSizeInfo &value)
444{
445 dbg.nospace() << "TextIndentInfo(";
446 dbg.nospace() << writeTabSize(value);
447 if (value.isNumber) {
448 dbg.nospace() << "x Spaces";
449 }
450 dbg.nospace() << ")";
451 return dbg.space();
452}
453
454QDebug operator<<(QDebug dbg, const BackgroundProperty &prop)
455{
456 dbg.nospace() << "BackgroundProperty(";
457
458 dbg.nospace() << prop.property.data();
459
460 if (KoColorBackground *fill = dynamic_cast<KoColorBackground*>(prop.property.data())) {
461 dbg.nospace() << ", color, " << fill->color();
462 }
463
464 if (KoGradientBackground *fill = dynamic_cast<KoGradientBackground*>(prop.property.data())) {
465 dbg.nospace() << ", gradient, " << fill->gradient();
466 }
467
468 if (KoVectorPatternBackground *fill = dynamic_cast<KoVectorPatternBackground*>(prop.property.data())) {
469 dbg.nospace() << ", pattern, num shapes: " << fill->shapes().size();
470 }
471
472 dbg.nospace() << ")";
473 return dbg.space();
474}
475
476QDebug operator<<(QDebug dbg, const StrokeProperty &prop)
477{
478 dbg.nospace() << "StrokeProperty(";
479
480 dbg.nospace() << prop.property.data();
481
482 if (KoShapeStroke *stroke = dynamic_cast<KoShapeStroke*>(prop.property.data())) {
483 dbg.nospace() << ", " << stroke->resultLinePen();
484 }
485
486 dbg.nospace() << ")";
487 return dbg.space();
488}
489
491{
492 return value == "stretch" ? TextPathStretch : TextPathAlign;
493}
494
496{
497 return value == "auto" ? TextPathAuto : TextPathExact;
498}
499
501{
502 return value == "left" ? TextPathSideLeft : TextPathSideRight;
503}
504
506{
507 return value == TextPathAlign ? "align" : "stretch";
508}
509
511{
512 return value == TextPathAuto ? "auto" : "exact";
513}
514
516{
517 return value == TextPathSideLeft ? "left" : "right";
518}
519
520bool whiteSpaceValueToLongHands(const QString &value, TextSpaceCollapse &collapseMethod, TextWrap &wrapMethod, TextSpaceTrims &trimMethod)
521{
522 bool result = true;
523 if (value == "pre") {
524 collapseMethod = Preserve;
525 wrapMethod = NoWrap;
526 trimMethod = TrimNone;
527 } else if (value == "nowrap") {
528 collapseMethod = Collapse;
529 wrapMethod = NoWrap;
530 trimMethod = TrimNone;
531 } else if (value == "pre-wrap") {
532 collapseMethod = Preserve;
533 wrapMethod = Wrap;
534 trimMethod = TrimNone;
535 } else if (value == "pre-wrap") {
536 collapseMethod = BreakSpaces;
537 wrapMethod = Wrap;
538 trimMethod = TrimNone;
539 } else if (value == "pre-line") {
540 collapseMethod = PreserveBreaks;
541 wrapMethod = Wrap;
542 trimMethod = TrimNone;
543 } else { // "normal"
544 if (value != "normal") {
545 result = false;
546 }
547 collapseMethod = Collapse;
548 wrapMethod = Wrap;
549 trimMethod = TrimNone;
550 }
551 return result;
552}
553
554bool xmlSpaceToLongHands(const QString &value, TextSpaceCollapse &collapseMethod)
555{
556 bool result = true;
557
558 if (value == "preserve") {
559 /*
560 * "When xml:space="preserve", the SVG user agent will do the following
561 * using a copy of the original character data content. It will convert
562 * all newline and tab characters into space characters. Then, it will
563 * draw all space characters, including leading, trailing and multiple
564 * contiguous space characters."
565 */
566 collapseMethod = PreserveSpaces;
567 } else {
568 /*
569 * "When xml:space="default", the SVG user agent will do the following
570 * using a copy of the original character data content. First, it will
571 * remove all newline characters. Then it will convert all tab
572 * characters into space characters. Then, it will strip off all leading
573 * and trailing space characters. Then, all contiguous space characters
574 * will be consolidated."
575 */
576 if (value != "default") {
577 result = false;
578 }
579 collapseMethod = Collapse;
580 }
581
582 return result;
583}
584
585QString writeWhiteSpaceValue(TextSpaceCollapse collapseMethod, TextWrap wrapMethod, TextSpaceTrims trimMethod)
586{
587 Q_UNUSED(trimMethod);
588 if (wrapMethod != NoWrap) {
589 if (collapseMethod == Preserve) {
590 return "pre-wrap";
591 } else if (collapseMethod == PreserveBreaks) {
592 return "pre-line";
593 } else if (collapseMethod == BreakSpaces) {
594 return "break-spaces";
595 } else {
596 return "normal";
597 }
598
599 } else {
600 if (collapseMethod == Preserve) {
601 return "pre";
602 } else {
603 return "nowrap";
604 }
605 }
606}
607
608QString writeXmlSpace(TextSpaceCollapse collapseMethod)
609{
610 return collapseMethod == PreserveSpaces ? "preserve" : "default";
611}
612
614{
615 return value == "keep-all" ? WordBreakKeepAll : value == "break-all" ? WordBreakBreakAll : WordBreakNormal;
616}
617
619{
620 return value == "loose" ? LineBreakLoose
621 : value == "normal" ? LineBreakNormal
622 : value == "strict" ? LineBreakStrict
623 : value == "anywhere" ? LineBreakAnywhere
625}
626
628{
629 return value == "end" ? AlignEnd
630 : value == "left" ? AlignLeft
631 : value == "right" ? AlignRight
632 : value == "center" ? AlignCenter
633 : value == "justify" ? AlignJustify
634 : value == "justify-all" ? AlignJustify
635 : value == "match-parent" ? AlignMatchParent
636 : value == "auto" ? AlignLastAuto
637 : // only for text-align-last
639}
640
642{
643 return value == WordBreakKeepAll ? "keep-all" : value == WordBreakBreakAll ? "break-all" : "normal";
644}
645
647{
648 return value == LineBreakLoose ? "loose"
649 : value == LineBreakNormal ? "normal"
650 : value == LineBreakStrict ? "strict"
651 : value == LineBreakAnywhere ? "anywhere"
652 : "auto";
653}
654
656{
657 return value == AlignEnd ? "end"
658 : value == AlignLeft ? "left"
659 : value == AlignRight ? "right"
660 : value == AlignCenter ? "center"
661 : value == AlignJustify ? "justify"
662 : value == AlignMatchParent ? "match-parent"
663 : value == AlignLastAuto ? "auto"
664 : // only for text-align-last
665 "start";
666}
667
669{
670 TextTransformInfo textTransform;
671 const QStringList values = value.toLower().split(" ");
672 Q_FOREACH (const QString &param, values) {
673 if (param == "capitalize") {
674 textTransform.capitals = TextTransformCapitalize;
675 } else if (param == "uppercase") {
676 textTransform.capitals = TextTransformUppercase;
677 } else if (param == "lowercase") {
678 textTransform.capitals = TextTransformLowercase;
679 } else if (param == "full-width") {
680 textTransform.fullWidth = true;
681 } else if (param == "full-size-kana") {
682 textTransform.fullSizeKana = true;
683 } else if (param == "none") {
684 textTransform.capitals = TextTransformNone;
685 textTransform.fullWidth = false;
686 textTransform.fullSizeKana = false;
687 } else {
688 qWarning() << "Unknown parameter in text-transform" << param;
689 }
690 }
691 return textTransform;
692}
693
694QString writeTextTransform(const TextTransformInfo textTransform)
695{
696 QStringList values;
697 if (textTransform.capitals == TextTransformNone && !textTransform.fullWidth && !textTransform.fullSizeKana) {
698 values.append("none");
699 } else {
700 if (textTransform.capitals == TextTransformLowercase) {
701 values.append("lowercase");
702 } else if (textTransform.capitals == TextTransformUppercase) {
703 values.append("uppercase");
704 } else if (textTransform.capitals == TextTransformCapitalize) {
705 values.append("capitalize");
706 }
707 if (textTransform.fullWidth) {
708 values.append("full-width");
709 }
710 if (textTransform.fullSizeKana) {
711 values.append("full-size-kana");
712 }
713 }
714 return values.join(" ");
715}
716
718{
719 const QStringList values = value.toLower().split(" ");
720 TextIndentInfo textIndent;
721 Q_FOREACH (const QString &param, values) {
722 if (param == "hanging") {
723 textIndent.hanging = true;
724 } else if (param == "each-line") {
725 textIndent.eachLine = true;
726 } else {
727 textIndent.length = SvgUtil::parseTextUnitStruct(context.currentGC(), param);
728 //ToDo: figure out how to detect value is number.
729 //qWarning() << "Unknown parameter in text-indent" << param;
730 }
731 }
732 return textIndent;
733}
734
735QString writeTextIndent(const TextIndentInfo textIndent)
736{
737 QStringList values;
738 values.append(writeLengthPercentage(textIndent.length));
739 if (textIndent.hanging) {
740 values.append("hanging");
741 }
742 if (textIndent.eachLine) {
743 values.append("each-line");
744 }
745 return values.join(" ");
746}
747
748TabSizeInfo parseTabSize(const QString &value, const SvgLoadingContext &context)
749{
750 TabSizeInfo tabSizeInfo;
751 qreal val = KisDomUtils::toDouble(value, &tabSizeInfo.isNumber);
752 if (tabSizeInfo.isNumber) {
753 tabSizeInfo.value = qMax(0.0, val);
754 } else {
755 tabSizeInfo.length = SvgUtil::parseTextUnitStruct(context.currentGC(), value);
756 }
757 if ((tabSizeInfo.isNumber && tabSizeInfo.value < 0) || tabSizeInfo.length.value < 0) {
758 tabSizeInfo.isNumber = true;
759 tabSizeInfo.value = 0;
760 tabSizeInfo.length.value = 0;
761 }
762 return tabSizeInfo;
763}
764
765QString writeTabSize(const TabSizeInfo tabSize)
766{
767 QString val = KisDomUtils::toString(tabSize.value);
768 if (!tabSize.isNumber) {
769
770 // Tabsize does not support percentage, so if we accidentally set it somewhere, convert to em.
771 val = writeLengthPercentage(tabSize.length, true);
772 if (tabSize.length == CssLengthPercentage::Absolute) {
773 val += "px"; // In SVG, due to browsers, the default unit is css px. Krita scales these to pt.
774 }
775 }
776 return val;
777}
778
779int parseCSSFontStretch(const QString &value, int currentStretch)
780{
781 int newStretch = 100;
782
783 static constexpr std::array<int, 9> fontStretches = {50, 62, 75, 87, 100, 112, 125, 150, 200};
784
785 if (value == "wider") {
786 const auto it = std::upper_bound(fontStretches.begin(), fontStretches.end(), currentStretch);
787
788 newStretch = it != fontStretches.end() ? *it : fontStretches.back();
789 } else if (value == "narrower") {
790 const auto it =
791 std::upper_bound(fontStretches.rbegin(), fontStretches.rend(), currentStretch, std::greater<int>());
792
793 newStretch = it != fontStretches.rend() ? *it : fontStretches.front();
794 } else {
795 // try to read numerical stretch value
796 bool ok = false;
797 newStretch = value.toInt(&ok, 10);
798
799 if (!ok) {
800 auto it = std::find(fontStretchNames.begin(), fontStretchNames.end(), value);
801 if (it != fontStretchNames.end()) {
802 const auto index = std::distance(fontStretchNames.begin(), it);
803 KIS_ASSERT(index >= 0);
804 newStretch = fontStretches.at(static_cast<size_t>(index));
805 }
806 }
807 }
808 return newStretch;
809}
810
811int parseCSSFontWeight(const QString &value, int currentWeight)
812{
813 int weight = 400;
814
815 // map svg weight to qt weight
816 // svg value qt value
817 // 100,200,300 1, 17, 33
818 // 400 50 (normal)
819 // 500,600 58,66
820 // 700 75 (bold)
821 // 800,900 87,99
822 static constexpr std::array<int, 9> svgFontWeights = {100, 200, 300, 400, 500, 600, 700, 800, 900};
823
824 if (value == "bold")
825 weight = 700;
826 else if (value == "bolder") {
827 const auto it = std::upper_bound(svgFontWeights.begin(), svgFontWeights.end(), currentWeight);
828
829 weight = it != svgFontWeights.end() ? *it : svgFontWeights.back();
830 } else if (value == "lighter") {
831 const auto it =
832 std::upper_bound(svgFontWeights.rbegin(), svgFontWeights.rend(), currentWeight, std::greater<int>());
833
834 weight = it != svgFontWeights.rend() ? *it : svgFontWeights.front();
835 } else {
836 bool ok = false;
837
838 // try to read numerical weight value
839 const int parsed = value.toInt(&ok, 10);
840 if (ok) {
841 weight = qBound(0, parsed, 1000);
842 }
843 }
844 return weight;
845}
846
848{
849 LineHeightInfo lineHeight;
850 lineHeight.isNormal = value == "normal";
851 qreal parsed = value.toDouble(&lineHeight.isNumber);
852
853 if (lineHeight.isNumber) {
854 lineHeight.value = parsed;
855 } else {
856 lineHeight.length = SvgUtil::parseTextUnitStruct(context.currentGC(), value);
857 }
858
859 // Negative line-height is invalid
860 if (!lineHeight.isNormal && (lineHeight.value < 0 || lineHeight.length.value < 0)) {
861 lineHeight.isNormal = true;
862 lineHeight.isNumber = false;
863 lineHeight.value = 0;
864 lineHeight.length.value = 0;
865 }
866
867 return lineHeight;
868}
869
871{
872 if (lineHeight.isNormal) return QString("normal");
873 QString val = KisDomUtils::toString(lineHeight.value);
874 if (!lineHeight.isNumber) {
875 val = writeLengthPercentage(lineHeight.length);
876 if (lineHeight.length.unit == CssLengthPercentage::Absolute) {
877 val += "px"; // In SVG, due to browsers, the default unit is css px. Krita scales these to pt.
878 }
879 }
880 return val;
881}
882
883QDebug operator<<(QDebug dbg, const LineHeightInfo &value)
884{
885 dbg.nospace() << "LineHeightInfo(";
886
887 if (value.isNormal) {
888 dbg.nospace() << "normal";
889 } else if (!value.isNumber) {
890 dbg.nospace() << value.value << "pt";
891 } else {
892 dbg.nospace() << value.value;
893 }
894
895 dbg.nospace() << ")";
896 return dbg.space();
897}
898
899QDebug operator<<(QDebug dbg, const CssLengthPercentage &value)
900{
901 dbg.nospace() << "Length(";
902
904 dbg.nospace() << value.value << "%";
905 } else if (value.unit == CssLengthPercentage::Em) {
906 dbg.nospace() << value.value << "em";
907 } else if (value.unit == CssLengthPercentage::Ex) {
908 dbg.nospace() << value.value << "ex";
909 } else if (value.unit == CssLengthPercentage::Cap) {
910 dbg.nospace() << value.value << "cap";
911 } else if (value.unit == CssLengthPercentage::Ch) {
912 dbg.nospace() << value.value << "ch";
913 } else if (value.unit == CssLengthPercentage::Ic) {
914 dbg.nospace() << value.value << "ic";
915 } else if (value.unit == CssLengthPercentage::Lh) {
916 dbg.nospace() << value.value << "lh";
917 } else {
918 dbg.nospace() << value.value << "(pt)";
919 }
920
921 dbg.nospace() << ")";
922 return dbg.space();
923}
924
925QString writeLengthPercentage(const CssLengthPercentage &length, bool percentageAsEm)
926{
927 QString val;
928 if (length.unit == CssLengthPercentage::Percentage && !percentageAsEm) {
929 val = KisDomUtils::toString(length.value*100.0) + "%";
930 } else {
931 val = KisDomUtils::toString(length.value);
933 val += "em";
934 } else if (length.unit == CssLengthPercentage::Ex) {
935 val += "ex";
936 } else if (length.unit == CssLengthPercentage::Cap) {
937 val += "cap";
938 } else if (length.unit == CssLengthPercentage::Ch) {
939 val += "ch";
940 } else if (length.unit == CssLengthPercentage::Ic) {
941 val += "ic";
942 } else if (length.unit == CssLengthPercentage::Lh) {
943 val += "lh";
944 }
945 }
946 return val;
947}
948
949void CssLengthPercentage::convertToAbsolute(const KoSvgText::FontMetrics metrics, const qreal fontSize, const CssLengthPercentage::UnitType percentageUnit) {
950 UnitType u = unit;
951 if (u == Percentage) {
952 u = percentageUnit;
953 }
954
955 const qreal ftMultiplier = fontSize / metrics.fontSize;
956 if (u == Em) {
957 value = value * fontSize;
958 } else if (u == Ex) {
959 value = value * metrics.xHeight * ftMultiplier;
960 } else if (u == Cap) {
961 value = value * metrics.capHeight * ftMultiplier;
962 } else if (u == Ch) {
963 value = value * metrics.zeroAdvance * ftMultiplier;
964 } else if (u == Ic) {
965 value = value * metrics.ideographicAdvance * ftMultiplier;
966 } else if (u == Lh) {
967 value = value * (metrics.ascender - metrics.descender + metrics.lineGap) * ftMultiplier;
968 }
969 unit = Absolute;
970}
971
972AutoLengthPercentage parseAutoLengthPercentageXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword, QRectF bbox, bool percentageIsViewPort)
973{
974 return value == autoKeyword ? AutoLengthPercentage()
975 : percentageIsViewPort? AutoLengthPercentage(SvgUtil::parseUnitStruct(context.currentGC(), value, true, true, bbox))
977}
978
979QString writeAutoLengthPercentage(const AutoLengthPercentage &value, const QString &autoKeyword, bool percentageToEm)
980{
981 return value.isAuto ? autoKeyword : writeLengthPercentage(value.length, percentageToEm);
982}
983
985{
986 if (value.isAuto) {
987 dbg.nospace() << "auto";
988 } else {
989 dbg.nospace() << value.length;
990 }
991 return dbg.space();
992}
993
994
995QDebug operator<<(QDebug dbg, const KoSvgText::FontFamilyAxis &axis)
996{
997 dbg.nospace() << axis.debugInfo();
998 return dbg.space();
999}
1000
1001QDataStream &operator<<(QDataStream &out, const KoSvgText::FontFamilyAxis &axis) {
1002
1003 QDomDocument doc;
1004 QDomElement root = doc.createElement("axis");
1005 root.setAttribute("tagName", axis.tag);
1006 root.setAttribute("min", axis.min);
1007 root.setAttribute("max", axis.max);
1008 root.setAttribute("default", axis.defaultValue);
1009 root.setAttribute("hidden", axis.axisHidden? "true": "false");
1010 root.setAttribute("variable", axis.variableAxis? "true": "false");
1011 for(auto it = axis.localizedLabels.begin(); it != axis.localizedLabels.end(); it++) {
1012 QDomElement name = doc.createElement("name");
1013 name.setAttribute("lang", it.key().bcp47Name());
1014 name.setAttribute("value", it.value());
1015 root.appendChild(name);
1016 }
1017 doc.appendChild(root);
1018 out << doc.toString(0);
1019 return out;
1020}
1021QDataStream &operator>>(QDataStream &in, KoSvgText::FontFamilyAxis &axis) {
1022
1023 QString xml;
1024 in >> xml;
1025
1026 QDomDocument doc;
1027 doc.setContent(xml);
1028 QDomElement root = doc.childNodes().at(0).toElement();
1029 axis.tag = root.attribute("tagName");
1030 axis.min = root.attribute("min").toDouble();
1031 axis.max = root.attribute("max").toDouble();
1032 axis.defaultValue = root.attribute("default").toDouble();
1033 axis.axisHidden = root.attribute("hidden") == "true"? true: false;
1034 axis.variableAxis = root.attribute("variable") == "true"? true: false;
1035 QDomNodeList names = root.elementsByTagName("name");
1036 for(int i = 0; i < names.size(); i++) {
1037 QDomElement name = names.at(i).toElement();
1038 QString lang = name.attribute("lang");
1039 QString value = name.attribute("value");
1040 axis.localizedLabels.insert(QLocale(lang), value);
1041 }
1042
1043 return in;
1044}
1045
1046QDebug operator<<(QDebug dbg, const KoSvgText::FontFamilyStyleInfo &style)
1047{
1048 dbg.nospace() << style.debugInfo();
1049 return dbg.space();
1050}
1051
1052QDataStream &operator<<(QDataStream &out, const KoSvgText::FontFamilyStyleInfo &style) {
1053
1054 QDomDocument doc;
1055 QDomElement root = doc.createElement("style");
1056 root.setAttribute("italic", style.isItalic? "true": "false");
1057 root.setAttribute("oblique", style.isOblique? "true": "false");
1058 for(auto it = style.instanceCoords.begin(); it != style.instanceCoords.end(); it++) {
1059 QDomElement coord = doc.createElement("coord");
1060 coord.setAttribute("tag", it.key());
1061 coord.setAttribute("value", it.value());
1062 root.appendChild(coord);
1063 }
1064 for(auto it = style.localizedLabels.begin(); it != style.localizedLabels.end(); it++) {
1065 QDomElement name = doc.createElement("name");
1066 name.setAttribute("lang", it.key().bcp47Name());
1067 name.setAttribute("value", it.value());
1068 root.appendChild(name);
1069 }
1070 doc.appendChild(root);
1071 out << doc.toString(0);
1072 return out;
1073}
1074QDataStream &operator>>(QDataStream &in, KoSvgText::FontFamilyStyleInfo &style) {
1075 QString xml;
1076 in >> xml;
1077
1078 QDomDocument doc;
1079 doc.setContent(xml);
1080 QDomElement root = doc.childNodes().at(0).toElement();
1081 style.isItalic = root.attribute("italic") == "true"? true: false;
1082 style.isOblique = root.attribute("oblique") == "true"? true: false;
1083 QDomNodeList names = root.elementsByTagName("name");
1084 for(int i = 0; i < names.size(); i++) {
1085 QDomElement name = names.at(i).toElement();
1086 QString lang = name.attribute("lang");
1087 QString value = name.attribute("value");
1088 style.localizedLabels.insert(QLocale(lang), value);
1089 }
1090 QDomNodeList coords = root.elementsByTagName("coord");
1091 for(int i = 0; i < coords.size(); i++) {
1092 QDomElement coord = coords.at(i).toElement();
1093 QString tag = coord.attribute("tag");
1094 double value = coord.attribute("value").toDouble();
1095 style.instanceCoords.insert(tag, value);
1096 }
1097
1098 return in;
1099}
1100
1102{
1103 CssFontStyleData slant;
1104 QStringList params = value.split(" ");
1105 if (!params.isEmpty()) {
1106 QString style = params.first();
1107 slant.style = style == "italic"? QFont::StyleItalic: style == "oblique"? QFont::StyleOblique: QFont::StyleNormal;
1108 }
1109 if (params.size() > 1) {
1110 QString angle = params.last();
1111 if (angle.endsWith("deg")) {
1112 angle.chop(3);
1113 slant.slantValue.isAuto = false;
1114 slant.slantValue.customValue = angle.toDouble();
1115 }
1116 }
1117 return slant;
1118}
1119
1121{
1122 QString style =
1123 value.style == QFont::StyleItalic ? "italic" :
1124 value.style == QFont::StyleOblique ? "oblique" : "normal";
1125 if (value.style == QFont::StyleOblique && !value.slantValue.isAuto) {
1126 style.append(QString(" ")+QString::number(value.slantValue.customValue)+QString("deg"));
1127 }
1128 return style;
1129}
1130
1132{
1133 if (value == "common-ligatures") {
1134 features.commonLigatures = true;
1135 } else if (value == "no-common-ligatures") {
1136 features.commonLigatures = false;
1137 } else if (value == "discretionary-ligatures") {
1138 features.discretionaryLigatures = true;
1139 } else if (value == "no-discretionary-ligatures") {
1140 features.discretionaryLigatures = false;
1141 } else if (value == "historical-ligatures") {
1142 features.historicalLigatures = true;
1143 } else if (value == "no-historical-ligatures") {
1144 features.historicalLigatures = false;
1145 } else if (value == "contextual") {
1146 features.contextualAlternates = true;
1147 } else if (value == "no-contextual") {
1148 features.contextualAlternates = false;
1149 } else if (value == "none") {
1150 features.commonLigatures = false;
1151 features.discretionaryLigatures = false;
1152 features.historicalLigatures = false;
1153 features.contextualAlternates = false;
1154 }
1155 return features;
1156}
1157
1159{
1160 if (feature.commonLigatures && !feature.discretionaryLigatures
1161 && !feature.historicalLigatures && feature.commonLigatures) {
1162 return "normal";
1163 }
1164 if (!feature.commonLigatures && !feature.discretionaryLigatures
1165 && !feature.historicalLigatures && !feature.commonLigatures) {
1166 return "none";
1167 }
1168 QStringList list;
1169 if (!feature.commonLigatures) {
1170 list << "no-common-ligatures";
1171 }
1172 if (feature.discretionaryLigatures) {
1173 list << "discretionary-ligatures";
1174 }
1175 if (feature.historicalLigatures) {
1176 list << "historical-ligatures";
1177 }
1178 if (!feature.contextualAlternates) {
1179 list << "no-contextual";
1180 }
1181 return list.join(" ");
1182}
1183
1184QDebug operator<<(QDebug dbg, const KoSvgText::FontFeatureLigatures &feature)
1185{
1186 dbg.nospace() << "Ligatures("<< writeFontFeatureLigatures(feature) <<")";
1187 return dbg.space();
1188}
1189
1191{
1192 if (value == "lining-nums") {
1194 } else if (value == "oldstyle-nums") {
1195 features.style = NumericFigureStyleOld;
1196 } else if (value == "proportional-nums") {
1198 } else if (value == "tabular-nums") {
1200 } else if (value == "diagonal-fractions") {
1202 } else if (value == "stacked-fractions") {
1204 } else if (value == "ordinal") {
1205 features.ordinals = true;
1206 } else if (value == "slashed-zero") {
1207 features.slashedZero = true;
1208 } else {
1209 features = FontFeatureNumeric();
1210 }
1211 return features;
1212}
1213
1215{
1216 if (feature == FontFeatureNumeric()) {
1217 return "normal";
1218 }
1219 QStringList list;
1220
1221 if (feature.style == NumericFigureStyleLining) {
1222 list << "lining-nums";
1223 } else if (feature.style == NumericFigureStyleOld) {
1224 list << "oldstyle-nums";
1225 }
1226
1228 list << "proportional-nums";
1229 } else if (feature.spacing == NumericFigureSpacingTabular) {
1230 list << "tabular-nums";
1231 }
1232
1233 if (feature.fractions == NumericFractionsDiagonal) {
1234 list << "diagonal-fractions";
1235 } else if (feature.fractions == NumericFractionsStacked) {
1236 list << "stacked-fractions";
1237 }
1238
1239 if (feature.ordinals) {
1240 list << "ordinal";
1241 }
1242
1243 if (feature.slashedZero) {
1244 list << "slashed-zero";
1245 }
1246
1247 return list.join(" ");
1248}
1249
1250QDebug operator<<(QDebug dbg, const KoSvgText::FontFeatureNumeric &feature)
1251{
1252 dbg.nospace() << "NumericFeatures("<< writeFontFeatureNumeric(feature) <<")";
1253 return dbg.space();
1254}
1255
1257{
1258 if (value == "jis78") {
1259 features.variant = EastAsianJis78;
1260 } else if (value == "jis83") {
1261 features.variant = EastAsianJis83;
1262 } else if (value == "jis90") {
1263 features.variant = EastAsianJis90;
1264 } else if (value == "jis04") {
1265 features.variant = EastAsianJis04;
1266 } else if (value == "simplified") {
1267 features.variant = EastAsianSimplified;
1268 } else if (value == "traditional") {
1269 features.variant = EastAsianTraditional;
1270 } else if (value == "full-width") {
1271 features.width = EastAsianFullWidth;
1272 } else if (value == "proportional-width") {
1274 } else if (value == "ruby") {
1275 features.ruby = true;
1276 } else {
1277 features = FontFeatureEastAsian();
1278 }
1279 return features;
1280}
1281
1283{
1284 if (feature == FontFeatureEastAsian()) {
1285 return "normal";
1286 }
1287 QStringList list;
1288
1289 if (feature.variant == EastAsianJis78) {
1290 list << "jis78";
1291 } else if (feature.variant == EastAsianJis83) {
1292 list << "jis83";
1293 } else if (feature.variant == EastAsianJis90) {
1294 list << "jis90";
1295 } else if (feature.variant == EastAsianJis04) {
1296 list << "jis04";
1297 } else if (feature.variant == EastAsianSimplified) {
1298 list << "simplified";
1299 } else if (feature.variant == EastAsianTraditional) {
1300 list << "traditional";
1301 }
1302
1303 if (feature.width == EastAsianFullWidth) {
1304 list << "full-width";
1305 } else if (feature.width == EastAsianProportionalWidth) {
1306 list << "proportional-width";
1307 }
1308
1309 if (feature.ruby) {
1310 list << "ruby";
1311 }
1312
1313 return list.join(" ");
1314}
1315
1316QDebug operator<<(QDebug dbg, const KoSvgText::FontFeatureEastAsian &feature)
1317{
1318 dbg.nospace() << "EastAsianFeatures("<< writeFontFeatureEastAsian(feature) <<")";
1319 return dbg.space();
1320}
1321
1323{
1324 return value == "super"? PositionSuper : value == "sub"? PositionSub : value == "normal"? PositionNormal: feature;
1325}
1326
1328{
1329 return value == PositionSuper ? "super"
1330 : value == PositionSub? "sub" : "normal";
1331}
1332
1334{
1335 return value == "small-caps" ? CapsSmall
1336 : value == "all-small-caps" ? CapsAllSmall
1337 : value == "petite-caps" ? CapsPetite
1338 : value == "all-petite-caps" ? CapsAllPetite
1339 : value == "unicase" ? CapsUnicase
1340 : value == "titling-caps" ? CapsTitling
1341 : value == "normal" ? CapsNormal: feature;
1342}
1343
1345{
1346 return value == CapsSmall ? "small-caps"
1347 : value == CapsAllSmall ? "all-small-caps"
1348 : value == CapsPetite ? "petite-caps"
1349 : value == CapsAllPetite ? "all-petite-caps"
1350 : value == CapsUnicase ? "unicase"
1351 : value == CapsTitling ? "titling-caps"
1352 : "normal";
1353}
1354
1355QStringList fontFeaturesPosition(const FontFeaturePosition &feature, const int start, const int end)
1356{
1357 const QString length = QString("[%1:%2]").arg(start).arg(end);
1358 QString tag = feature == PositionSuper? "sups" : feature == PositionSub? "subs": QString();
1359 if (!tag.isEmpty()) {
1360 tag += length;
1361 tag += "=1";
1362 }
1363 return tag.isEmpty()? QStringList(): QStringList(tag);
1364}
1365
1366QStringList fontFeaturesCaps(const FontFeatureCaps &feature, const int start, const int end)
1367{
1368 QStringList list;
1369 const QString length = QString("[%1:%2]").arg(start).arg(end);
1370
1371 switch (feature) {
1372 case CapsSmall:
1373 list << "smcp" + length + "=1";
1374 break;
1375 case CapsAllSmall:
1376 list << "smcp" + length + "=1";
1377 list << "c2sc" + length + "=1";
1378 break;
1379 case CapsPetite:
1380 list << "pcap" + length + "=1";
1381 break;
1382 case CapsAllPetite:
1383 list << "pcap" + length + "=1";
1384 list << "c2pc" + length + "=1";
1385 break;
1386 case CapsUnicase:
1387 list << "unic" + length + "=1";
1388 break;
1389 case CapsTitling:
1390 list << "titl" + length + "=1";
1391 break;
1392 default:
1393 break;
1394 }
1395
1396 return list;
1397}
1398
1399FontMetrics::FontMetrics(qreal fontSizeInPt, bool isHorizontal)
1400 : isVertical(!isHorizontal)
1401 , fontSize(fontSizeInPt * 64.0)
1402{
1404 xHeight = fontSize/2;
1405 capHeight = (fontSize / 5) * 4;
1406
1407 subScriptOffset.second = -(fontSize / 5);
1408 superScriptOffset.second = (fontSize / 3);
1409 if (isHorizontal) {
1412
1413 ascender = (fontSize / 5) * 4;
1415
1417
1421
1422 hangingBaseline = (fontSize / 5) * 3;
1423
1424 caretRun = 0;
1425 caretRise = 1;
1426 caretOffset = 0;
1427
1428 } else {
1431
1432 ascender = fontSize /2;
1434
1438
1440
1441 alphabeticBaseline = ascender - (fontSize / 5) * 4;
1442
1444
1445 caretRun = 1;
1446 caretRise = 0;
1447 caretOffset = 0;
1448 }
1449
1453}
1454
1484
1486 qint32 baselineVal = 0;
1487 switch(baseline) {
1489 baselineVal = ideographicUnderBaseline;
1490 break;
1491 case BaselineAlphabetic:
1492 baselineVal = alphabeticBaseline;
1493 break;
1494 case BaselineHanging:
1495 baselineVal = hangingBaseline;
1496 break;
1498 baselineVal = mathematicalBaseline;
1499 break;
1500 case BaselineCentral:
1501 baselineVal = ideographicCenterBaseline;
1502 break;
1503 case BaselineMiddle:
1505 break;
1506 case BaselineTextBottom:
1507 baselineVal = descender;
1508 break;
1509 case BaselineTextTop:
1510 baselineVal = ascender;
1511 break;
1512 default:
1513 break;
1514 }
1515 return baselineVal;
1516}
1517
1518void FontMetrics::setBaselineValueByTag(const QString &tag, int32_t value) {
1519 if (tag == "romn") {
1521 } else if (tag == "hang") {
1523 } else if (tag == "icfb") {
1525 } else if (tag == "icft") {
1527 } else if (tag == "ideo") {
1529 } else if (tag == "idtp") {
1531 } else if (tag == "Idce") {
1533 } else if (tag == "math") {
1535 }
1536}
1537
1538void FontMetrics::setMetricsValueByTag(const QLatin1String &tag, int32_t value) {
1539 if (tag == "xhgt") {
1540 xHeight = value;
1541 } else if (tag == "cpht") {
1542 capHeight = value;
1543 } else if (tag == "sbxo") {
1544 subScriptOffset.first = value;
1545 } else if (tag == "sbyo") {
1546 subScriptOffset.second = value;
1547 } else if (tag == "spxo") {
1548 superScriptOffset.first = value;
1549 } else if (tag == "spyo") {
1550 superScriptOffset.second = value;
1551 } else if (tag == "strs") {
1553 } else if (tag == "stro") {
1555 } else if (tag == "unds") {
1557 } else if (tag == "undo") {
1559 } else if (tag == "hcrs") {
1560 caretRise = value;
1561 } else if (tag == "hcrn") {
1562 caretRun = value;
1563 } else if (tag == "hcof") {
1565 } else if (tag == "vcrs") {
1566 caretRise = value;
1567 } else if (tag == "vcrn") {
1568 caretRun = value;
1569 } else if (tag == "vcof") {
1571 }
1572}
1573
1574void FontMetrics::scaleBaselines(const qreal multiplier)
1575{
1576 alphabeticBaseline *= multiplier;
1577 hangingBaseline *= multiplier;
1578 mathematicalBaseline *= multiplier;
1579 ideographicFaceUnderBaseline *= multiplier;
1580 ideographicFaceOverBaseline *= multiplier;
1581 ideographicOverBaseline *= multiplier;
1582 ideographicCenterBaseline *= multiplier;
1583 ideographicUnderBaseline *= multiplier;
1584 xHeight *= multiplier;
1585 capHeight *= multiplier;
1586 subScriptOffset.first *= multiplier;
1587 subScriptOffset.second *= multiplier;
1588 superScriptOffset.first *= multiplier;
1589 superScriptOffset.second *= multiplier;
1590 fontSize *= multiplier;
1591 ascender *= multiplier;
1592 descender *= multiplier;
1593 lineGap *= multiplier;
1594
1595 zeroAdvance *= multiplier;
1596 spaceAdvance *= multiplier;
1597 ideographicAdvance *= multiplier;
1598
1599 underlineOffset *= multiplier;
1600 underlineThickness *= multiplier;
1601 lineThroughOffset *= multiplier;
1602 lineThroughThickness *= multiplier;
1603}
1604
1606{
1607 qint32 offset = valueForBaselineValue(baseline);
1608 if (offset == 0) return;
1609
1610 alphabeticBaseline -= offset;
1611 hangingBaseline -= offset;
1612 mathematicalBaseline -= offset;
1615 ideographicOverBaseline -= offset;
1616 ideographicCenterBaseline -= offset;
1617 ideographicUnderBaseline -= offset;
1618
1619 ascender -= offset;
1620 descender -= offset;
1621}
1622
1623QDebug operator<<(QDebug dbg, const FontMetrics &metrics)
1624{
1625 const double ftPixel = 1.0;
1626 dbg.nospace() << "FontMetrics(";
1627 dbg.nospace() << "Direction: " << (metrics.isVertical? "Top to bottom. ": "Left to right. ");
1628 dbg.nospace() << "FontSize: " << QString::number(metrics.fontSize*ftPixel) << "px. ";
1629 dbg.nospace() << "Number width: " << QString::number(metrics.zeroAdvance*ftPixel) << "px. ";
1630 dbg.nospace() << "Space width: " << QString::number(metrics.spaceAdvance*ftPixel) << "px. ";
1631 dbg.nospace() << "Ideographic width: " << QString::number(metrics.ideographicAdvance*ftPixel) << "px. ";
1632
1633 dbg.nospace() << "xHeight: " << QString::number(metrics.xHeight*ftPixel) << "px. ";
1634 dbg.nospace() << "cap height: " << QString::number(metrics.capHeight*ftPixel) << "px. ";
1635 dbg.nospace() << "Subscripts: " << QString::number(metrics.subScriptOffset.second*ftPixel) << "px. ";
1636 dbg.nospace() << "Superscripts: " << QString::number(metrics.superScriptOffset.second*ftPixel) << "px. ";
1637 dbg.nospace() << "Ascender: " << QString::number(metrics.ascender*ftPixel) << "px. ";
1638 dbg.nospace() << "Descender: " << QString::number(metrics.descender*ftPixel) << "px. ";
1639 dbg.nospace() << "Linegap: " << QString::number(metrics.lineGap*ftPixel) << "px. ";
1640
1641 dbg.nospace() << "Alphabetic: " << QString::number(metrics.alphabeticBaseline*ftPixel) << "px. ";
1642 dbg.nospace() << "Middle: " << QString::number((metrics.xHeight/2)*ftPixel) << "px. ";
1643 dbg.nospace() << "Mathematical: " << QString::number(metrics.mathematicalBaseline*ftPixel) << "px. ";
1644
1645 dbg.nospace() << "Ideo Over: " << QString::number(metrics.ideographicOverBaseline*ftPixel) << "px. ";
1646 dbg.nospace() << "Central: " << QString::number(metrics.ideographicCenterBaseline*ftPixel) << "px. ";
1647 dbg.nospace() << "Ideo Under: " << QString::number(metrics.ideographicUnderBaseline*ftPixel) << "px. ";
1648
1649 dbg.nospace() << "Ideo Face Over: " << QString::number(metrics.ideographicFaceOverBaseline*ftPixel) << "px. ";
1650 dbg.nospace() << "Ideo Face Under: " << QString::number(metrics.ideographicFaceUnderBaseline*ftPixel) << "px. ";
1651 dbg.nospace() << "Hanging: " << QString::number(metrics.hangingBaseline*ftPixel) << "px. ";
1652 dbg.nospace() << ")";
1653 return dbg.space();
1654}
1655
1657{
1658 dbg.nospace() << "Underline position( horizontal:" << value.horizontalPosition << ", vertical:" << value.verticalPosition << ")";
1659 return dbg.space();
1660}
1661
1663{
1664 if (value == "optimizeSpeed") {
1666 } else if (value == "optimizeLegibility") {
1668 } else if (value == "geometricPrecision") {
1670 }
1671 return RenderingAuto;
1672}
1673
1675{
1677 return "optimizeSpeed";
1678 } else if (value == RenderingOptimizeLegibility) {
1679 return "optimizeLegibility";
1680 } else if (value == RenderingGeometricPrecision) {
1681 return "geometricPrecision";
1682 } else {
1683 return "auto";
1684 }
1685}
1686
1688 return (1.0/freeTypePixel) * pixelToPointFactor(x);
1689}
1690
1692 return QTransform::fromScale(1/freeTypePixel, -1/freeTypePixel);
1693}
1694
1699
1701 return QTransform::fromScale(pointInInch / xRes, pointInInch / yRes);
1702}
1703
1704QPointF ResolutionHandler::adjust(const QPointF point) const {
1705 if (!roundToPixelHorizontal && !roundToPixelVertical) return point;
1706 QPointF pix = pointToPixel().map(point);
1708 pix.setX(qRound(pix.x()));
1709 }
1711 pix.setY(qRound(pix.y()));
1712 }
1713 return pixelToPoint().map(pix);
1714}
1715
1716QPointF ResolutionHandler::adjustFloor(const QPointF point) const
1717{
1718 if (!roundToPixelHorizontal && !roundToPixelVertical) return point;
1719 QPointF pix = pointToPixel().map(point);
1721 pix.setX(floor(pix.x()));
1722 }
1724 pix.setY(floor(pix.y()));
1725 }
1726 return pixelToPoint().map(pix);
1727}
1728
1729QPointF ResolutionHandler::adjustCeil(const QPointF point) const
1730{
1731 if (!roundToPixelHorizontal && !roundToPixelVertical) return point;
1732 QPointF pix = pointToPixel().map(point);
1734 pix.setX(ceil(pix.x()));
1735 }
1737 pix.setY(ceil(pix.y()));
1738 }
1739 return pixelToPoint().map(pix);
1740}
1741
1742QPointF ResolutionHandler::adjustWithOffset(const QPointF point, const QPointF offset) const
1743{
1744 if (!roundToPixelHorizontal && !roundToPixelVertical) return point;
1745 return adjust(point+offset)-offset;
1746}
1747
1748QRectF ResolutionHandler::adjust(const QRectF rect) const {
1749 return QRectF(adjust(rect.topLeft()), adjust(rect.bottomRight()));
1750}
1751
1752qreal ResolutionHandler::pointToPixelFactor(const bool x) const {
1753 return x? xRes/pointInInch: yRes/pointInInch;
1754}
1755
1757 return QTransform::fromScale(xRes/pointInInch, yRes/pointInInch);
1758}
1759
1760qreal ResolutionHandler::pixelToPointFactor(const bool x) const {
1761 return x? pointInInch/xRes: pointInInch/yRes;
1762}
1763
1764} // namespace KoSvgText
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
qreal u
QList< QString > QStringList
qRegisterMetaType< KoSvgText::FontFeatureLigatures >("KoSvgText::FontFeatureLigatures")
qRegisterMetaType< KoSvgText::TextTransformInfo >("KoSvgText::TextTransformInfo")
qRegisterMetaType< KoSvgText::FontFamilyStyleInfo >("KoSvgText::FontFamilyStyleInfo")
qRegisterMetaType< KoSvgText::FontMetrics >("KoSvgText::FontMetrics")
qRegisterMetaType< KoSvgText::FontFeatureNumeric >("KoSvgText::FontFeatureNumeric")
qRegisterMetaType< KoSvgText::BackgroundProperty >("KoSvgText::BackgroundProperty")
qRegisterMetaType< KoSvgText::StrokeProperty >("KoSvgText::StrokeProperty")
qRegisterMetaType< KoSvgText::FontFeatureEastAsian >("KoSvgText::FontFeatureEastAsian")
KIS_DECLARE_STATIC_INITIALIZER
Definition KoSvgText.cpp:24
qRegisterMetaType< KoSvgText::CssFontStyleData >("KoSvgText::CssSlantData")
qRegisterMetaType< KoSvgText::AutoLengthPercentage >("KoSvgText::AutoLengthPercentage")
qRegisterMetaType< KoSvgText::TextUnderlinePosition >("KoSvgText::TextUnderlinePosition")
qRegisterMetaType< KoSvgText::AutoValue >("KoSvgText::AutoValue")
qRegisterMetaType< KoSvgText::FontFamilyAxis >("KoSvgText::FontFamilyAxis")
qRegisterMetaType< KoSvgText::TabSizeInfo >("KoSvgText::TabSizeInfo")
qRegisterMetaType< KoSvgText::TextIndentInfo >("KoSvgText::TextIndentInfo")
qRegisterMetaType< KoSvgText::LineHeightInfo >("KoSvgText::LineHeightInfo")
A simple solid color shape background.
A gradient shape background.
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 qreal parseUnitX(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in x-direction
Definition SvgUtil.cpp:304
static qreal parseUnitAngular(SvgGraphicsContext *gc, const QString &unit)
parses angle, result in radians!
Definition SvgUtil.cpp:332
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
static qreal parseUnitXY(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in xy-direction
Definition SvgUtil.cpp:322
static KoSvgText::CssLengthPercentage parseUnitStruct(SvgGraphicsContext *gc, QStringView unit, bool horiz=false, bool vert=false, const QRectF &bbox=QRectF())
Parse length attribute into a struct, always resolving the percentage to viewport.
Definition SvgUtil.cpp:234
static qreal parseUnitY(SvgGraphicsContext *gc, const KoSvgTextProperties &resolved, const QString &unit)
parses a length attribute in y-direction
Definition SvgUtil.cpp:313
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
double toDouble(const QString &str, bool *ok=nullptr)
QString toString(const QString &value)
@ AlignCenter
Center text in line.
Definition KoSvgText.h:173
@ AlignLastAuto
Definition KoSvgText.h:163
@ AlignMatchParent
Definition KoSvgText.h:176
QString writeTextPathSide(TextPathSide value)
BaselineShiftMode parseBaselineShiftMode(const QString &value)
BaselineShiftMode
Mode of the baseline shift.
Definition KoSvgText.h:240
@ ShiftLineBottom
this handles css-inline-3 vertical-align:bottom. Not exposed to ui
Definition KoSvgText.h:246
@ ShiftSuper
Use parent font metric for 'superscript'.
Definition KoSvgText.h:243
@ ShiftLineTop
this handles css-inline-3 vertical-align:top. Not exposed to ui
Definition KoSvgText.h:245
@ ShiftLengthPercentage
Css Length Percentage, percentage is lh.
Definition KoSvgText.h:244
@ ShiftNone
No shift.
Definition KoSvgText.h:241
@ ShiftSub
Use parent font metric for 'subscript'.
Definition KoSvgText.h:242
@ EastAsianJis78
Definition KoSvgText.h:999
@ EastAsianSimplified
Definition KoSvgText.h:1003
@ EastAsianTraditional
Definition KoSvgText.h:1004
@ TextPathExact
Definition KoSvgText.h:296
FontFeatureCaps
Represents font-feature-caps.
Definition KoSvgText.h:897
@ CapsAllPetite
Definition KoSvgText.h:902
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)
@ LineBreakStrict
Use strict method, language specific.
Definition KoSvgText.h:145
@ LineBreakLoose
Use loose method, language specific.
Definition KoSvgText.h:143
@ LineBreakAnywhere
Break between any typographic clusters.
Definition KoSvgText.h:146
@ LineBreakAuto
Use preferred method.
Definition KoSvgText.h:142
@ LineBreakNormal
Use normal method, language specific.
Definition KoSvgText.h:144
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
Definition KoSvgText.h:79
@ AnchorEnd
Anchor right for LTR, left for RTL.
Definition KoSvgText.h:82
@ AnchorStart
Anchor left for LTR, right for RTL.
Definition KoSvgText.h:80
@ AnchorMiddle
Anchor to the middle.
Definition KoSvgText.h:81
QString writeWordBreak(WordBreak value)
FontFeaturePosition
The FontFeatureLigatures class This enum represents css font-variant-position.
Definition KoSvgText.h:886
@ PositionSuper
Definition KoSvgText.h:888
@ PositionNormal
Definition KoSvgText.h:887
TabSizeInfo parseTabSize(const QString &value, const SvgLoadingContext &context)
TextPathSide parseTextPathSide(const QString &value)
QDebug operator<<(QDebug dbg, const KoSvgText::AutoValue &value)
Baseline parseBaseline(const QString &value)
@ NumericFigureSpacingProportional
Definition KoSvgText.h:921
@ NumericFigureSpacingTabular
Definition KoSvgText.h:922
FontFeatureEastAsian parseFontFeatureEastAsian(const QString &value, FontFeatureEastAsian features)
TextAnchor parseTextAnchor(const QString &value)
TextOrientation parseTextOrientation(const QString &value)
TextPathSpacing parseTextPathSpacing(const QString &value)
WordBreak
Whether to break words.
Definition KoSvgText.h:132
@ WordBreakNormal
Set according to script. Also "break-word".
Definition KoSvgText.h:133
@ WordBreakBreakAll
Always break inside words.
Definition KoSvgText.h:135
@ WordBreakKeepAll
Never break inside words.
Definition KoSvgText.h:134
QString writeBaselineShiftMode(BaselineShiftMode value, CssLengthPercentage shift)
UnicodeBidi parseUnicodeBidi(const QString &value)
@ LengthAdjustSpacing
Only stretch the spaces.
Definition KoSvgText.h:251
@ LengthAdjustSpacingAndGlyphs
Stretches the glyphs as well.
Definition KoSvgText.h:252
WritingMode parseWritingMode(const QString &value)
QString writeTabSize(const TabSizeInfo tabSize)
LengthAdjust parseLengthAdjust(const QString &value)
TextWrap
Part of "white-space", in practice we only support wrap and nowrap.
Definition KoSvgText.h:109
@ NoWrap
Do not do any text wrapping.
Definition KoSvgText.h:112
AutoValue parseAutoValueX(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
QString writeLineHeight(LineHeightInfo lineHeight)
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)
Direction
Base direction used by Bidi algorithm.
Definition KoSvgText.h:48
@ DirectionLeftToRight
Definition KoSvgText.h:49
@ DirectionRightToLeft
Definition KoSvgText.h:50
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
@ BaselineDominant
Definition KoSvgText.h:218
@ BaselineHanging
Definition KoSvgText.h:226
@ BaselineMiddle
Definition KoSvgText.h:232
@ BaselineUseScript
Definition KoSvgText.h:216
@ BaselineTextBottom
Bottom side of the inline line-box.
Definition KoSvgText.h:234
@ BaselineResetSize
Definition KoSvgText.h:221
@ BaselineNoChange
Use parent baseline table.
Definition KoSvgText.h:220
@ BaselineIdeographic
Definition KoSvgText.h:223
@ BaselineMathematical
Definition KoSvgText.h:228
@ BaselineTextTop
Top side of the inline line-box.
Definition KoSvgText.h:235
@ BaselineCentral
Use the center between the ideographic over and under.
Definition KoSvgText.h:231
QString writeFontFeatureLigatures(const FontFeatureLigatures &feature)
QString writeUnicodeBidi(UnicodeBidi value)
@ EastAsianProportionalWidth
Definition KoSvgText.h:1010
@ EastAsianFullWidth
Definition KoSvgText.h:1009
AutoValue parseAutoValueAngular(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
TextIndentInfo parseTextIndent(const QString &value, const SvgLoadingContext &context)
QString writeTextRendering(TextRendering value)
TextAlign parseTextAlign(const QString &value)
QString writeTextPathMethod(TextPathMethod value)
TextPathSide
Whether to reverse the path before laying out text.
Definition KoSvgText.h:300
@ TextPathSideRight
Definition KoSvgText.h:301
@ TextPathSideLeft
Definition KoSvgText.h:302
Direction parseDirection(const QString &value)
LineHeightInfo parseLineHeight(const QString &value, const SvgLoadingContext &context)
QString writeLineBreak(LineBreak value)
QString writeLengthPercentage(const CssLengthPercentage &length, bool percentageAsEm)
@ HorizontalTB
Definition KoSvgText.h:38
@ NumericFractionsDiagonal
Definition KoSvgText.h:927
@ NumericFractionsStacked
Definition KoSvgText.h:928
QString writeAutoLengthPercentage(const AutoLengthPercentage &value, const QString &autoKeyword, bool percentageToEm)
AutoValue parseAutoValueXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword)
@ BidiNormal
No new bidi-level is started.
Definition KoSvgText.h:57
@ BidiPlainText
Definition KoSvgText.h:64
@ BidiIsolate
Content is ordered as if in a separate paragraph.
Definition KoSvgText.h:61
@ BidiOverride
Definition KoSvgText.h:59
@ BidiEmbed
Opens an additional Bidi-reordering level.
Definition KoSvgText.h:58
@ BidiIsolateOverride
Definition KoSvgText.h:62
QString writeFontFeatureCaps(const FontFeatureCaps &value)
QDataStream & operator>>(QDataStream &in, KoSvgText::FontFamilyAxis &axis)
FontFeaturePosition parseFontFeaturePosition(const QString &value, FontFeaturePosition feature)
QString writeFontFeatureEastAsian(const FontFeatureEastAsian &feature)
QString writeFontStyle(CssFontStyleData value)
QString writeTextAlign(TextAlign value)
LineBreak parseLineBreak(const QString &value)
QStringList fontFeaturesPosition(const FontFeaturePosition &feature, const int start, const int end)
QString writeFontFeatureNumeric(const FontFeatureNumeric &feature)
QString writeLengthAdjust(LengthAdjust value)
QString writeAlignmentBaseline(Baseline value)
@ TrimNone
No trimming.
Definition KoSvgText.h:124
@ RenderingGeometricPrecision
Definition KoSvgText.h:318
@ RenderingAuto
Definition KoSvgText.h:315
@ RenderingOptimizeLegibility
Definition KoSvgText.h:317
@ RenderingOptimizeSpeed
Definition KoSvgText.h:316
int parseCSSFontWeight(const QString &value, int currentWeight)
TextOrientation parseTextOrientationFromGlyphOrientation(AutoValue value)
QString writeFontFeaturePosition(const FontFeaturePosition &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)
QString writeTextOrientation(TextOrientation orientation)
FontFeatureLigatures parseFontFeatureLigatures(const QString &value, FontFeatureLigatures features)
QString writeXmlSpace(TextSpaceCollapse collapseMethod)
QString writeTextPathSpacing(TextPathSpacing value)
TextPathMethod parseTextPathMethod(const QString &value)
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
@ OrientationUpright
Set all characters upright.
Definition KoSvgText.h:73
@ OrientationMixed
Definition KoSvgText.h:71
@ OrientationSideWays
Set all characters sideways.
Definition KoSvgText.h:74
@ TextTransformCapitalize
Definition KoSvgText.h:185
@ TextTransformUppercase
Convert all bicarmel text to upper-case, locale dependant.
Definition KoSvgText.h:187
@ TextTransformLowercase
Convert all bicarmel text to lower-case, locale dependant.
Definition KoSvgText.h:188
@ TextTransformNone
No transforms.
Definition KoSvgText.h:184
QString writeTextAnchor(TextAnchor value)
QString writeWritingMode(WritingMode value, bool svg1_1)
TextTransformInfo parseTextTransform(const QString &value)
QString writeAutoValue(const AutoValue &value, const QString &autoKeyword)
QString writeDominantBaseline(Baseline value)
@ NumericFigureStyleOld
Definition KoSvgText.h:915
@ NumericFigureStyleLining
Definition KoSvgText.h:914
TextSpaceCollapse
Definition KoSvgText.h:96
@ Preserve
Do not collapse any space.
Definition KoSvgText.h:99
@ BreakSpaces
Same as preserve, except each white space and wordseperate is breakable.
Definition KoSvgText.h:104
@ Collapse
Collapse white space sequences into a single character.
Definition KoSvgText.h:97
@ PreserveBreaks
Definition KoSvgText.h:100
@ PreserveSpaces
required for 'xml:space="preserve"' emulation.
Definition KoSvgText.h:102
QString writeTextTransform(const TextTransformInfo textTransform)
WordBreak parseWordBreak(const QString &value)
FontFeatureNumeric parseFontFeatureNumeric(const QString &value, FontFeatureNumeric features)
QString writeDirection(Direction value)
TextPathMethod
Whether to stretch the glyphs along a path.
Definition KoSvgText.h:286
@ TextPathAlign
Only align position and rotation of glyphs to the path.
Definition KoSvgText.h:287
@ TextPathStretch
Definition KoSvgText.h:288
QString writeWhiteSpaceValue(TextSpaceCollapse collapseMethod, TextWrap wrapMethod, TextSpaceTrims trimMethod)
QStringList fontFeaturesCaps(const FontFeatureCaps &feature, const int start, const int end)
QString writeTextIndent(const TextIndentInfo textIndent)
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
Definition KoSvgText.h:714
QSharedPointer< KoShapeBackground > property
Definition KoSvgText.h:724
boost::optional< qreal > yPos
Definition KoSvgText.h:606
bool operator==(const CharTransformation &other) const
boost::optional< qreal > dxPos
Definition KoSvgText.h:607
boost::optional< qreal > dyPos
Definition KoSvgText.h:608
boost::optional< qreal > rotate
Definition KoSvgText.h:609
void mergeInParentTransformation(const CharTransformation &t)
boost::optional< qreal > xPos
Definition KoSvgText.h:605
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
@ Cap
multiply by font-x-height.
Definition KoSvgText.h:412
@ Ch
multiply by font cap height
Definition KoSvgText.h:413
@ 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
@ Ex
multiply by Font-size
Definition KoSvgText.h:411
@ Ic
multiply by width of "0", represents average proportional script advance.
Definition KoSvgText.h:414
void convertToAbsolute(const KoSvgText::FontMetrics metrics, const qreal fontSize, const UnitType percentageUnit=Em)
QString debugInfo() const
Some variable fonts have axes that are not really supposed to be shown to the user.
Definition KoSvgText.h:785
QHash< QLocale, QString > localizedLabels
Definition KoSvgText.h:777
QHash< QString, float > instanceCoords
Definition KoSvgText.h:816
QHash< QLocale, QString > localizedLabels
Definition KoSvgText.h:815
The FontFeatureLigatures class This struct represents css font-variant-ligatures.
Definition KoSvgText.h:847
bool commonLigatures
'clig' and 'liga'
Definition KoSvgText.h:848
The FontFeatureLigatures class This struct represents css font-variant-numeric.
Definition KoSvgText.h:935
NumericFractions fractions
Definition KoSvgText.h:940
NumericFigureStyle style
Definition KoSvgText.h:938
NumericFigureSpacing spacing
Definition KoSvgText.h:939
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 ideographicCenterBaseline
default baseline for vertical, centered between over and under.
Definition KoSvgText.h:347
qint32 ideographicUnderBaseline
location of ideographic under baseline from origin, may fall back to descender.
Definition KoSvgText.h:346
QPair< qint32, qint32 > subScriptOffset
subscript baseline height, defaults to 1/5th em below alphabetic.
Definition KoSvgText.h:336
qint32 xHeight
height of X, defaults to 0.5 fontsize.
Definition KoSvgText.h:334
void setBaselineValueByTag(const QString &tag, int32_t value)
qint32 lineThroughThickness
strikethrough thickness, from font.
Definition KoSvgText.h:359
qint32 underlineThickness
underline thickness from font.
Definition KoSvgText.h:357
qint32 lineThroughOffset
offset of strike-through from alphabetic baseline.
Definition KoSvgText.h:358
qint32 lineGap
additional linegap between consecutive lines.
Definition KoSvgText.h:341
qint32 zeroAdvance
Advance of the character '0', CSS Unit 'ch', defaults to 0.5 em in horizontal and 1....
Definition KoSvgText.h:330
qint32 underlineOffset
underline offset from alphabetic, positive.
Definition KoSvgText.h:356
qint32 ideographicAdvance
Advance of the character '水' (U+6C34), CSS Unit ic, defaults to 1 em.
Definition KoSvgText.h:332
qint32 ideographicFaceOverBaseline
location of ideographic face over baseline, that is, the top of the glyphs.
Definition KoSvgText.h:352
void scaleBaselines(const qreal multiplier)
qint32 ideographicOverBaseline
location of ideographic over baseline from origin.
Definition KoSvgText.h:349
void setMetricsValueByTag(const QLatin1String &tag, int32_t value)
qint32 fontSize
Currently set size, CSS unit 'em'.
Definition KoSvgText.h:329
int valueForBaselineValue(Baseline baseline) const
qint32 ideographicFaceUnderBaseline
location of ideographic face under baseline, that is, the bottom of the glyphs.
Definition KoSvgText.h:351
qint32 caretRun
These are only used to determine the caret slant proportion.
Definition KoSvgText.h:362
qint32 alphabeticBaseline
location of alphabetic baseline from origin.
Definition KoSvgText.h:343
qint32 descender
distance for origin to bottom.
Definition KoSvgText.h:340
qint32 ascender
distance from origin to top.
Definition KoSvgText.h:339
qint32 mathematicalBaseline
location of mathematical baseline from origin.
Definition KoSvgText.h:344
bool operator==(const FontMetrics &other) const
qint32 capHeight
Height of capital letters, defaults to ascender.
Definition KoSvgText.h:335
void offsetMetricsToNewOrigin(const Baseline baseline)
bool isVertical
Different fontMetrics count between vertical and horizontal.
Definition KoSvgText.h:328
qint32 hangingBaseline
location of the hanging baseline used in north brahmic scripts.
Definition KoSvgText.h:354
qint32 spaceAdvance
Advance of the character ' ', used by tabs.
Definition KoSvgText.h:331
QPair< qint32, qint32 > superScriptOffset
superscript baseline height, defaults to 2/3rd above alphabetic.
Definition KoSvgText.h:337
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
qreal freeTypePixelToPointFactor(const bool x=true) const
qreal pointToPixelFactor(const bool x=true) const
qreal pixelToPointFactor(const bool x=true) const
QTransform pixelToPoint() const
QTransform pointToPixel() const
QPointF adjustCeil(const QPointF point) const
Adjusts the point to ceiled pixel values.
QTransform freeTypeToPixelTransform() const
QTransform freeTypeToPointTransform() const
QPointF adjustWithOffset(const QPointF point, const QPointF offset) const
QPointF adjustFloor(const QPointF point) const
Adjusts the point to floored pixel values.
QPointF adjust(const QPointF point) const
Adjusts the point to rounded pixel values, based on whether roundToPixelHorizontal or roundToPixelVer...
StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties.
Definition KoSvgText.h:733
QSharedPointer< KoShapeStrokeModel > property
Definition KoSvgText.h:743
qreal value
A length or a number. Length is currently marked 'at-risk'.
Definition KoSvgText.h:675
CssLengthPercentage length
Definition KoSvgText.h:678
bool hanging
Flip the lines to which text-indent is applied.
Definition KoSvgText.h:659
bool eachLine
Apply the text-indent to each line following a hardbreak.
Definition KoSvgText.h:660
CssLengthPercentage length
Definition KoSvgText.h:658
TextTransform capitals
Text transform upper/lower/capitalize.
Definition KoSvgText.h:637