File indexing completed on 2024-06-23 04:20:41

0001 /*
0002  *  SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef KOSVGTEXT_H
0008 #define KOSVGTEXT_H
0009 
0010 #include <QFont>
0011 #include <QList>
0012 #include <QPainterPath>
0013 #include <QTextCharFormat>
0014 #include <QVariant>
0015 #include <QVector>
0016 #include <array>
0017 #include <boost/operators.hpp>
0018 #include <boost/optional.hpp>
0019 
0020 #include <QSharedPointer>
0021 #include <KoShapeBackground.h>
0022 #include <KoShapeStrokeModel.h>
0023 
0024 #include <QDomDocument>
0025 
0026 #include <kritaflake_export.h>
0027 
0028 class SvgLoadingContext;
0029 class QDebug;
0030 
0031 #include <KoShape.h>
0032 class KoSvgTextChunkShape;
0033 
0034 namespace KoSvgText
0035 {
0036 enum WritingMode {
0037     HorizontalTB, ///< Left to right, lay out new lines bottom of previous. RTL
0038                   ///< scripts use this with BIDI reordering.
0039     VerticalRL, ///< Top to bottom, lay out new lines right of the previous.
0040                 ///< used for CJK scripts.
0041     VerticalLR ///< Top to bottom, lay out new lines left of the previous. Used
0042                ///< for Mongolian.
0043 };
0044 
0045 /// Base direction used by Bidi algorithm.
0046 enum Direction {
0047     DirectionLeftToRight,
0048     DirectionRightToLeft
0049 };
0050 
0051 /// These values control the type of bidi-controls we'll inject into the final
0052 /// text.
0053 enum UnicodeBidi {
0054     BidiNormal, ///< No new bidi-level is started.
0055     BidiEmbed, ///< Opens an additional Bidi-reordering level.
0056     BidiOverride, ///< Opens an additional Bidi-reordering level, implicit part
0057                   ///< of the algorithm is ignored.
0058     BidiIsolate, ///< Content is ordered as if in a seperate paragraph.
0059     BidiIsolateOverride, ///< Ordered like a directional override inside an
0060                          ///< isolated paragraph.
0061     BidiPlainText ///< Behaves like isolate, except using heuristics defined in
0062                   ///< P2 and P3 of the unicode bidirectional algorithm.
0063 };
0064 
0065 /// Orientation of the glyphs, used for vertical writing modes.
0066 enum TextOrientation {
0067     OrientationMixed, ///< Use UA50 to determine whether a character should be
0068                       ///< sideways.
0069     OrientationUpright, ///< Set all characters upright.
0070     OrientationSideWays ///< Set all characters sideways.
0071 };
0072 
0073 /// Where the text is anchored for SVG 1.1 text and 'inline-size'.
0074 enum TextAnchor {
0075     AnchorStart, ///< Anchor left for LTR, right for RTL.
0076     AnchorMiddle, ///< Anchor to the middle.
0077     AnchorEnd ///< Anchor right for LTR, left for RTL.
0078 };
0079 
0080 /*
0081  * CSS-Text-3 defines the white space property, and SVG 2 adopts this, except,
0082  * CSS-Text-3 doesn't have a concept of 'xml:space="preserve"'. CSS-Text-4
0083  * *does*, however, that works by splitting the white-space property into the
0084  * the following three enums. Officially the SVG2 spec says to use 'white-space'
0085  * of CSS-Text-4 because of this.
0086  */
0087 
0088 /// Part of "white-space", NOTE: white-space:break-spaces; is not really covered
0089 /// by this new method yet.
0090 enum TextSpaceCollapse {
0091     Collapse, ///< Collapse white space sequences into a single character.
0092     Discard, ///< Discard all Spaces
0093     Preserve, ///< Do not collapse any space
0094     PreserveBreaks, ///< Preserve segment breaks like /n, but otherwise collapse
0095                     ///< all whitespace.
0096     PreserveSpaces ///< Preserve spaces, convert tabs and linebreaks to spaces,
0097                    ///< required for 'xml:space="preserve"' emulation.
0098 };
0099 
0100 /// Part of "white-space", in practice we only support wrap and nowrap.
0101 enum TextWrap {
0102     Wrap, ///< Do any kind of text wrapping at soft wrapping opportunities,
0103           ///< typically greedy.
0104     NoWrap, ///< Do not do any text wrapping.
0105     Balance, ///< Select algorithm that tries to ensure white space is balanced
0106              ///< instead of as much text as possible on each line.
0107     Stable, ///< Select algorithm that doesn't change the text before the cursor
0108             ///< when adjusting text.
0109     Pretty ///< select algorithm that gives the best looking result, may require
0110            ///< looking ahead.
0111 };
0112 
0113 /// Part of "white-space"
0114 enum TextSpaceTrim {
0115     TrimNone = 0x0, ///< No trimming.
0116     TrimInner = 0x1, ///< Discard white space at the beginning and end of element.
0117     DiscardBefore = 0x2, ///< Trim white space before the start of the element.
0118     DiscardAfter = 0x4 ///< Trim white space after the end of the element.
0119 };
0120 
0121 /// Whether to break words.
0122 enum WordBreak {
0123     WordBreakNormal, ///< Set according to script. Also "break-word"
0124     WordBreakKeepAll, ///< Never break inside words.
0125     WordBreakBreakAll, ///< Always break inside words.
0126 };
0127 
0128 /// Line breaking strictness. A number of these values are values to be handed
0129 /// over to the line/word breaking algorithm.
0130 enum LineBreak {
0131     LineBreakAuto, ///< Use preferred method.
0132     LineBreakLoose, ///< Use loose method, language specific.
0133     LineBreakNormal, ///< Use normal method, language specific.
0134     LineBreakStrict, ///< Use strict method, language specific.
0135     LineBreakAnywhere ///< Break between any typographic clusters.
0136 };
0137 
0138 /// What to do with words that cannot be broken, but still overflow.
0139 enum OverflowWrap {
0140     OverflowWrapNormal, ///< Do nothing besides 'relaxing' the strictness of
0141                         ///< 'wordbreak'.
0142     OverflowWrapAnywhere, ///< Break anywhere as soon as overflow happens.
0143     OverflowWrapBreakWord ///< Break previous soft-break before breaking the
0144                           ///< word.
0145 };
0146 
0147 /// TextAlign values, see
0148 /// https://www.w3.org/TR/css-writing-modes-4/#logical-to-physical for
0149 /// interaction with writing mode and direction.
0150 enum TextAlign {
0151     AlignLastAuto, ///< TextAlignLast: same as text-align-all, unless that's
0152                    ///< justify, then this is AlignStart.
0153     AlignStart, ///< Align text to left side of line with LTR, right with RTL,
0154                 ///< top with the vertical writing modes.
0155     AlignEnd, ///< Align text to right side of line with LTR, left with RTL,
0156               ///< bottom with the vertical writing modes.
0157     AlignLeft, ///< Align text to left side of line. Top with the vertical
0158                ///< writing modes, bottom in sideways.
0159     AlignRight, ///< Align text to right side of line. Bottom with the vertical
0160                 ///< writing modes, top in sideways
0161     AlignCenter, ///< Center text in line.
0162     AlignJustify, ///< Justify text, so that the end and start both touch the
0163                   ///< end and start of the line.
0164     AlignMatchParent ///< Inherit, except Start and End are matched against the
0165                      ///< parent values... We don't support this.
0166 };
0167 
0168 /// Whether and how to transform text. Not strictly necessary according to SVG2.
0169 /// Fullwidth and FullSizeKana are inside the textTransform Struct.
0170 enum TextTransform {
0171     TextTransformNone = 0x0, ///< No transforms.
0172     TextTransformCapitalize = 0x1, ///< Convert first letter in word of bicarmel
0173                                    ///< text to upper-case, locale dependant.
0174     TextTransformUppercase = 0x2, ///< Convert all bicarmel text to upper-case, locale dependant.
0175     TextTransformLowercase = 0x4, ///< Convert all bicarmel text to lower-case, locale dependant.
0176 };
0177 
0178 /// How to handle overflow.
0179 enum TextOverflow {
0180     OverFlowVisible, ///< Determined by 'overflow' property, not by
0181                      ///< text-overflow. In svg all the non-visible values
0182                      ///< compute to 'clip'.
0183     OverFlowClip, ///< Clip the rendered content.
0184     OverFlowEllipse ///< Replace the last characters with "U+2026"
0185 };
0186 
0187 /// Flags. Whether and how to hang punctuation. Not strictly necessary according
0188 /// to SVG2, marked as 'at-risk' in CSS-Text-3, though this feature is useful
0189 /// for East-Asian text layout.
0190 enum HangingPunctuation {
0191     HangNone = 0x0, ///< Hang nothing.
0192     HangFirst = 0x1, ///< Hang opening brackets and quotes.
0193     HangLast = 0x2, ///< Hang closing brackets and quotes.
0194     HangEnd = 0x4, ///< Hang stops and commas. Force/Allow is a seperate boolean.
0195     HangForce = 0x8 ///< Whether to force hanging stops or commas.
0196 };
0197 
0198 /// Baseline values used by dominant-baseline and baseline-align.
0199 enum Baseline {
0200     BaselineAuto, ///< Use the preferred baseline for the writing-mode and
0201                   ///< text-orientation.
0202     BaselineUseScript, ///< SVG 1.1 feature, Deprecated in CSS-Inline-3. Use the
0203                        ///< preferred baseline for the given script.
0204     BaselineDominant, ///< alignment-baseline has the same value as
0205                       ///< dominant-baseline.
0206     BaselineNoChange, ///< Use parent baseline table.
0207     BaselineResetSize, ///< Use parent baseline table, but adjust to current
0208                        ///< fontsize.
0209     BaselineIdeographic, ///< Use 'ideo' or 'ideographic under/left' baselines.
0210                          ///< Used for CJK.
0211     BaselineAlphabetic, ///< Use 'romn' or the baseline for LCG scripts.
0212     BaselineHanging, ///< Use 'hang', or the baseline for scripts that hang like
0213                      ///< Tibetan and Devanagari.
0214     BaselineMathematical, ///< Use 'math' or the mathematical baseline, used for
0215                           ///< aligning numbers and mathematical symbols
0216                           ///< correctly.
0217     BaselineCentral, ///< Use the center between the ideographic over and under.
0218     BaselineMiddle, ///< Use the center between the alphabetical and x-height,
0219                     ///< or central in vertical.
0220     BaselineTextBottom, ///< Bottom side of the inline line-box.
0221     BaselineTextTop ///< Top side of the inline line-box.
0222 };
0223 
0224 /// Mode of the baseline shift.
0225 enum BaselineShiftMode {
0226     ShiftNone, ///< No shift.
0227     ShiftSub, ///< Use parent font metric for 'subscript'.
0228     ShiftSuper, ///< Use parent font metric for 'superscript'.
0229     ShiftPercentage ///< Percentage of the current fontsize.
0230     // note: we convert all the <length> values into the relative font values!
0231 };
0232 
0233 enum LengthAdjust {
0234     LengthAdjustSpacing, ///< Only stretch the spaces.
0235     LengthAdjustSpacingAndGlyphs ///< Stretches the glyphs as well.
0236 };
0237 
0238 /// Flags for text-decoration, for underline, overline and strikethrough.
0239 enum TextDecoration {
0240     DecorationNone = 0x0,
0241     DecorationUnderline = 0x1,
0242     DecorationOverline = 0x2,
0243     DecorationLineThrough = 0x4
0244 };
0245 
0246 /// Style of the text-decoration.
0247 enum TextDecorationStyle {
0248     Solid, ///< Draw a solid line.Ex: -----
0249     Double, ///< Draw two lines. Ex: =====
0250     Dotted, ///< Draw a dotted line. Ex: .....
0251     Dashed, ///< Draw a dashed line. Ex: - - - - -
0252     Wavy ///< Draw a wavy line. We currently make a zigzag, ex: ^^^^^
0253 };
0254 
0255 /// Which location to choose for the underline.
0256 enum TextDecorationUnderlinePosition {
0257     UnderlineAuto, ///< Use Font metrics.
0258     UnderlineUnder, ///< Use the bottom of the text decoration bounding box.
0259     UnderlineLeft, ///< Put the underline on the left of the text decoration
0260                    ///< bounding box, overline right.
0261     UnderlineRight ///< Put the underline on the right of the text decoration
0262                    ///< bounding box, overline left.
0263 };
0264 
0265 /// Whether to stretch the glyphs along a path.
0266 enum TextPathMethod {
0267     TextPathAlign, ///< Only align position and rotation of glyphs to the path.
0268     TextPathStretch ///< Align position and rotation and stretch glyphs' path
0269                     ///< points along the path as well.
0270 };
0271 
0272 /// Currently not used, this value suggest using either the default values or
0273 /// 'better' ones. Currently not used.
0274 enum TextPathSpacing {
0275     TextPathAuto,
0276     TextPathExact
0277 };
0278 
0279 /// Whether to reverse the path before laying out text.
0280 enum TextPathSide {
0281     TextPathSideRight,
0282     TextPathSideLeft
0283 };
0284 
0285 /// CSS defines a number of font features as CSS properties. Not all Opentype
0286 /// features are part of this.
0287 enum FontVariantFeature {
0288     FontVariantNormal, ///< Use default features.
0289     FontVariantNone, ///< All features are disabled.
0290     /// font-variant-ligatures, common and contextual are on by default.
0291     CommonLigatures,
0292     NoCommonLigatures,
0293     DiscretionaryLigatures,
0294     NoDiscretionaryLigatures,
0295     HistoricalLigatures,
0296     NoHistoricalLigatures,
0297     ContextualAlternates,
0298     NoContextualAlternates,
0299     /// font-variant-position, neither values are on by default.
0300     PositionSub,
0301     PositionSuper,
0302     /// font-variant-caps, none of the values applicable are on by default.
0303     SmallCaps,
0304     AllSmallCaps,
0305     PetiteCaps,
0306     AllPetiteCaps,
0307     Unicase,
0308     TitlingCaps,
0309     /// font-variant-numeric, none of the values applicable are on by default.
0310     LiningNums,
0311     OldStyleNums,
0312     ProportionalNums,
0313     TabularNums,
0314     DiagonalFractions,
0315     StackedFractions,
0316     Ordinal,
0317     SlashedZero,
0318     /// font-variant-alternates
0319     HistoricalForms,
0320     StylisticAlt,
0321     StyleSet,
0322     CharacterVariant,
0323     Swash,
0324     Ornaments,
0325     Annotation,
0326     /// font-variant-east-asian, none of the values applicable are on by
0327     /// default.
0328     EastAsianJis78,
0329     EastAsianJis83,
0330     EastAsianJis90,
0331     EastAsianJis04,
0332     EastAsianSimplified,
0333     EastAsianTraditional,
0334     EastAsianFullWidth,
0335     EastAsianProportionalWidth,
0336     EastAsianRuby
0337 };
0338 
0339 Q_DECLARE_FLAGS(TextDecorations, TextDecoration)
0340 Q_DECLARE_OPERATORS_FOR_FLAGS(TextDecorations)
0341 
0342 Q_DECLARE_FLAGS(TextSpaceTrims, TextSpaceTrim)
0343 Q_DECLARE_OPERATORS_FOR_FLAGS(TextSpaceTrims)
0344 
0345 Q_DECLARE_FLAGS(HangingPunctuations, HangingPunctuation)
0346 Q_DECLARE_OPERATORS_FOR_FLAGS(HangingPunctuations)
0347 
0348 /**
0349  * AutoValue represents the "auto-or-real" values used in SVG
0350  *
0351  * Some SVG attributes can be set to either "auto" or some floating point
0352  * value. E.g. 'kerning' attribute. If its value is "auto", the kerning is
0353  * defined by the kerning tables of the font. And if its value is a real
0354  * number, e.g. 0 or 5.5, the font kerning is set to this particular number.
0355  */
0356 struct AutoValue : public boost::equality_comparable<AutoValue>
0357 {
0358     AutoValue() {}
0359     AutoValue(qreal _customValue) : isAuto(false), customValue(_customValue) {}
0360 
0361     bool isAuto = true;
0362     qreal customValue = 0.0;
0363 
0364     bool operator==(const AutoValue & other) const {
0365         return isAuto == other.isAuto && (isAuto || customValue == other.customValue);
0366     }
0367 };
0368 
0369 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::AutoValue &value);
0370 
0371 inline QVariant fromAutoValue(const KoSvgText::AutoValue &value) {
0372     return QVariant::fromValue(value);
0373 }
0374 
0375 AutoValue parseAutoValueX(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword = "auto");
0376 AutoValue parseAutoValueY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword = "auto");
0377 AutoValue parseAutoValueXY(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword = "auto");
0378 AutoValue parseAutoValueAngular(const QString &value, const SvgLoadingContext &context, const QString &autoKeyword = "auto");
0379 
0380 WritingMode parseWritingMode(const QString &value);
0381 Direction parseDirection(const QString &value);
0382 UnicodeBidi parseUnicodeBidi(const QString &value);
0383 TextOrientation parseTextOrientation(const QString &value);
0384 TextOrientation parseTextOrientationFromGlyphOrientation(AutoValue value);
0385 TextAnchor parseTextAnchor(const QString &value);
0386 
0387 /**
0388  * @brief whiteSpaceValueToLongHands
0389  * CSS-Text-4 takes CSS-Text-3 whitespace values and treats them as a shorthand
0390  * for three more specific properties. This method sets the three properties
0391  * according to the white space value given.
0392  *
0393  * @return whether the value could be parsed.
0394  * Some CSS-Text-3 whitespace values ("break-spaces") have no CSS-Text-4
0395  * variants yet, and thus will be interpreted as "Normal" while this boolean
0396  * returns false.
0397  */
0398 bool whiteSpaceValueToLongHands(const QString &value, TextSpaceCollapse &collapseMethod, TextWrap &wrapMethod, TextSpaceTrims &trimMethod);
0399 /**
0400  * @brief xmlSpaceToLongHands
0401  * This takes xml:space values and converts them to CSS-Text-4 properties.
0402  * @see whiteSpaceValueToLongHands
0403  */
0404 bool xmlSpaceToLongHands(const QString &value, TextSpaceCollapse &collapseMethod);
0405 
0406 WordBreak parseWordBreak(const QString &value);
0407 LineBreak parseLineBreak(const QString &value);
0408 TextAlign parseTextAlign(const QString &value);
0409 
0410 Baseline parseBaseline(const QString &value);
0411 BaselineShiftMode parseBaselineShiftMode(const QString &value);
0412 
0413 LengthAdjust parseLengthAdjust(const QString &value);
0414 
0415 static const std::array<const char *, 9> fontStretchNames = {"ultra-condensed",
0416                                                              "extra-condensed",
0417                                                              "condensed",
0418                                                              "semi-condensed",
0419                                                              "normal",
0420                                                              "semi-expanded",
0421                                                              "expanded",
0422                                                              "extra-expanded",
0423                                                              "ultra-expanded"};
0424 static const std::array<const char *, 7> fontSizeNames =
0425     {"xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large"};
0426 /**
0427  * @brief parseCSSFontStretch
0428  * For CSS3, the font-stretches were only given as keywords. In Css 4 and above,
0429  * they also allow values, except in the "font"-shorthand. The css3 bool will
0430  * restrict parsing to this value for this reason.
0431  */
0432 int parseCSSFontStretch(const QString &value, int currentStretch);
0433 
0434 int parseCSSFontWeight(const QString &value, int currentWeight);
0435 
0436 QMap<QString, FontVariantFeature> fontVariantStrings();
0437 QStringList fontVariantOpentypeTags(FontVariantFeature feature);
0438 
0439 TextPathMethod parseTextPathMethod(const QString &value);
0440 TextPathSpacing parseTextPathSpacing(const QString &value);
0441 TextPathSide parseTextPathSide(const QString &value);
0442 
0443 QString writeAutoValue(const AutoValue &value, const QString &autoKeyword = "auto");
0444 
0445 QString writeWritingMode(WritingMode value, bool svg1_1 = false);
0446 QString writeDirection(Direction value);
0447 QString writeUnicodeBidi(UnicodeBidi value);
0448 QString writeTextOrientation(TextOrientation orientation);
0449 QString writeTextAnchor(TextAnchor value);
0450 QString writeDominantBaseline(Baseline value);
0451 QString writeAlignmentBaseline(Baseline value);
0452 QString writeBaselineShiftMode(BaselineShiftMode value, qreal portion);
0453 QString writeLengthAdjust(LengthAdjust value);
0454 
0455 QString writeTextPathMethod(TextPathMethod value);
0456 QString writeTextPathSpacing(TextPathSpacing value);
0457 QString writeTextPathSide(TextPathSide value);
0458 
0459 QString writeWordBreak(WordBreak value);
0460 QString writeLineBreak(LineBreak value);
0461 QString writeTextAlign(TextAlign value);
0462 
0463 /**
0464  * @brief writeWhiteSpaceValue
0465  * determine the CSS-3-Whitespace shorthand value.
0466  * @see whiteSpaceValueToLongHands
0467  */
0468 QString writeWhiteSpaceValue(TextSpaceCollapse collapseMethod, TextWrap wrapMethod, KoSvgText::TextSpaceTrims trimMethod);
0469 QString writeXmlSpace(TextSpaceCollapse collapseMethod);
0470 
0471 struct CharTransformation : public boost::equality_comparable<CharTransformation>
0472 {
0473     boost::optional<qreal> xPos;
0474     boost::optional<qreal> yPos;
0475     boost::optional<qreal> dxPos;
0476     boost::optional<qreal> dyPos;
0477     boost::optional<qreal> rotate;
0478 
0479     void mergeInParentTransformation(const CharTransformation &t);
0480     bool isNull() const;
0481     bool startsNewChunk() const;
0482     bool hasRelativeOffset() const;
0483 
0484     QPointF absolutePos() const;
0485     QPointF relativeOffset() const;
0486 
0487     bool operator==(const CharTransformation & other) const;
0488 };
0489 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::CharTransformation &t);
0490 
0491 struct TextOnPathInfo {
0492     qreal startOffset = 0.0;
0493     bool startOffsetIsPercentage = false;
0494     TextPathMethod method = TextPathAlign;
0495     TextPathSpacing spacing = TextPathAuto;
0496     TextPathSide side = TextPathSideLeft;
0497 };
0498 
0499 /// "This property transforms text for styling purposes.
0500 ///  It has no effect on the underlying content, and must not affect the content
0501 ///  of a plain text copy & paste operation."
0502 /// -- CSS-Text-3
0503 struct TextTransformInfo : public boost::equality_comparable<TextTransformInfo> {
0504     TextTransformInfo() = default;
0505     TextTransform capitals = TextTransformNone; ///< Text transform upper/lower/capitalize.
0506     bool fullWidth = false; ///< Convert proportional or half-width text to
0507                             ///< full-width text. 'at-risk'
0508     bool fullSizeKana = false; ///< Convert Japanese Katakana and Hiragana to
0509                                ///< their 'fullsize' equivelants. 'at-risk'
0510     bool operator==(const TextTransformInfo &rhs) const
0511     {
0512         return (capitals == rhs.capitals) && (fullWidth == rhs.fullWidth) && (fullSizeKana == rhs.fullSizeKana);
0513     }
0514 };
0515 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::TextTransformInfo &t);
0516 TextTransformInfo parseTextTransform(const QString &value);
0517 QString writeTextTransform(TextTransformInfo textTransform);
0518 
0519 /// "This property specifies the indentation applied to lines of inline content
0520 /// in a block.
0521 ///  The indent is treated as a margin applied to the start edge of the line
0522 ///  box." -- CSS-Text-3
0523 struct TextIndentInfo : public boost::equality_comparable<TextIndentInfo> {
0524     TextIndentInfo() = default;
0525 
0526     qreal value = 0.0; ///< The indentation length or percentage.
0527     bool isPercentage = false; ///< Interpret the value as a percentage of the
0528                                ///< total run length of a box.
0529     bool hanging = false; ///< Flip the lines to which text-indent is applied.
0530     bool eachLine = false; ///< Apply the text-indent to each line following a hardbreak.
0531     bool operator==(const TextIndentInfo &rhs) const
0532     {
0533         return (value == rhs.value) && (isPercentage == rhs.isPercentage) && (hanging == rhs.hanging) && (eachLine == rhs.eachLine);
0534     }
0535 };
0536 
0537 TextIndentInfo parseTextIndent(const QString &value, const SvgLoadingContext &context);
0538 QString writeTextIndent(TextIndentInfo textIndent);
0539 
0540 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::TextIndentInfo &value);
0541 
0542 /// "This property determines the tab size used to render preserved tab
0543 /// characters (U+0009)." -- CSS-Text-3
0544 struct TabSizeInfo : public boost::equality_comparable<TabSizeInfo> {
0545     qreal value = 8; ///< A length or a number. Length is currently marked 'at-risk'.
0546     bool isNumber = true; ///< Multiply by width of 'space' character, including
0547                           ///< word- and letter-spacing.
0548     qreal extraSpacing = 0.0; ///< Extra spacing due word or letter-spacing. Not
0549                               ///< written to css and only used during layout.
0550     bool operator==(const TabSizeInfo &rhs) const
0551     {
0552         return (value == rhs.value) && (isNumber == rhs.isNumber);
0553     }
0554 };
0555 TabSizeInfo parseTabSize(const QString &value, const SvgLoadingContext &context);
0556 QString writeTabSize(TabSizeInfo tabSize);
0557 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::TabSizeInfo &value);
0558 
0559 
0560 struct LineHeightInfo : public boost::equality_comparable<LineHeightInfo> {
0561     qreal value = 1.0; /// Length or number.
0562     bool isNumber = false; /// It's a number indicating the lineHeight;
0563     bool isNormal = true; /// The 'auto' value.
0564 
0565     bool operator==(const LineHeightInfo &rhs) const
0566     {
0567         return (value == rhs.value) && (isNumber == rhs.isNumber)  && (isNormal == rhs.isNormal);
0568     }
0569 };
0570 
0571 LineHeightInfo parseLineHeight(const QString &value, const SvgLoadingContext &context);
0572 QString writeLineHeight(LineHeightInfo lineHeight);
0573 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::LineHeightInfo &value);
0574 
0575 /**
0576  * @brief BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperties
0577  */
0578 struct BackgroundProperty : public boost::equality_comparable<BackgroundProperty>
0579 {
0580     BackgroundProperty() {}
0581     BackgroundProperty(QSharedPointer<KoShapeBackground> p) : property(p) {}
0582 
0583     bool operator==(const BackgroundProperty &rhs) const {
0584         return (!property && !rhs.property) ||
0585                 (property && rhs.property &&
0586                  property->compareTo(rhs.property.data()));
0587     }
0588 
0589     QSharedPointer<KoShapeBackground> property;
0590 };
0591 
0592 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::BackgroundProperty &prop);
0593 
0594 /**
0595  * @brief StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties
0596  */
0597 struct StrokeProperty : public boost::equality_comparable<StrokeProperty>
0598 {
0599     StrokeProperty() {}
0600     StrokeProperty(QSharedPointer<KoShapeStrokeModel> p) : property(p) {}
0601 
0602     bool operator==(const StrokeProperty &rhs) const {
0603         return (!property && !rhs.property) ||
0604                 (property && rhs.property &&
0605                  property->compareFillTo(rhs.property.data()) && property->compareStyleTo(rhs.property.data()));
0606     }
0607 
0608     QSharedPointer<KoShapeStrokeModel> property;
0609 };
0610 
0611 QDebug KRITAFLAKE_EXPORT operator<<(QDebug dbg, const KoSvgText::StrokeProperty &prop);
0612 
0613 } // namespace KoSvgText
0614 
0615 Q_DECLARE_METATYPE(KoSvgText::AutoValue)
0616 Q_DECLARE_METATYPE(KoSvgText::TextDecorations)
0617 Q_DECLARE_METATYPE(KoSvgText::HangingPunctuations)
0618 Q_DECLARE_METATYPE(KoSvgText::TextSpaceTrims)
0619 Q_DECLARE_METATYPE(KoSvgText::BackgroundProperty)
0620 Q_DECLARE_METATYPE(KoSvgText::StrokeProperty)
0621 Q_DECLARE_METATYPE(KoSvgText::TextTransformInfo)
0622 Q_DECLARE_METATYPE(KoSvgText::TextIndentInfo)
0623 Q_DECLARE_METATYPE(KoSvgText::TabSizeInfo)
0624 Q_DECLARE_METATYPE(KoSvgText::LineHeightInfo)
0625 
0626 #endif // KOSVGTEXT_H