Krita Source Code Documentation
Loading...
Searching...
No Matches
KoCssTextUtils.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2022 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6#include "KoCssTextUtils.h"
7#include "graphemebreak.h"
8#include <QChar>
9#include <kis_assert.h>
10
12 QVector<QPair<int, int>> positions;
13 if (a.isEmpty() && b.isEmpty()) return positions;
14
15 int countA = 0;
16 int countB = 0;
17 for (int i=0; i< a.size(); i++) {
18 QString textA = a.at(i);
19 QString textB = b.at(i);
20 if (textA.size() > textB.size()) {
21 for (int j=0; j < textA.size(); j++) {
22 int k = j < textB.size()? countB+j: -1;
23 positions.append(qMakePair(countA+j, k));
24 }
25 } else {
26 for (int j=0; j < textB.size(); j++) {
27 int k = j < textA.size()? countA+j: -1;
28 positions.append(qMakePair(k, countB+j));
29 }
30 }
31 countA += textA.size();
32 countB += textB.size();
33 }
34
35 return positions;
36}
37
38QString KoCssTextUtils::transformTextToUpperCase(const QString &text, const QString &langCode, QVector<QPair<int, int> > &positions)
39{
40 if (text.isEmpty()) return text;
41 QLocale locale(langCode.split("-").join("_"));
42 QString transformedText = locale.toUpper(text);
43 positions = positionDifference(textToUnicodeGraphemeClusters(text, langCode), textToUnicodeGraphemeClusters(transformedText, langCode));
44 return transformedText;
45}
46
47QString KoCssTextUtils::transformTextToLowerCase(const QString &text, const QString &langCode, QVector<QPair<int, int> > &positions)
48{
49 if (text.isEmpty()) return text;
50 QLocale locale(langCode.split("-").join("_"));
51 QString transformedText = locale.toLower(text);
52 positions = positionDifference(textToUnicodeGraphemeClusters(text, langCode), textToUnicodeGraphemeClusters(transformedText, langCode));
53 return transformedText;
54}
55
56QString KoCssTextUtils::transformTextCapitalize(const QString &text, const QString langCode, QVector<QPair<int, int>> &positions)
57{
58 if (text.isEmpty()) return text;
59 QLocale locale(langCode);
60
61 QStringList graphemes = textToUnicodeGraphemeClusters(text, langCode);
62 QStringList oldGraphemes = graphemes;
63 bool capitalizeGrapheme = true;
64 for (int i = 0; i < graphemes.size(); i++) {
65 QString grapheme = graphemes.at(i);
66 if (grapheme.isEmpty() || IsCssWordSeparator(grapheme)) {
67 capitalizeGrapheme = true;
68
69 } else if (capitalizeGrapheme) {
70 graphemes[i] = locale.toUpper(grapheme);
71 if (i + 1 < graphemes.size()) {
74 if (locale == QLocale::Dutch && grapheme.toLower().startsWith("i") && graphemes.at(i + 1).toLower().startsWith("j")) {
75 capitalizeGrapheme = true;
76 continue;
77 }
78 }
79 capitalizeGrapheme = false;
80 }
81 }
82
83 positions = positionDifference(oldGraphemes, graphemes);
84 return graphemes.join("");
85}
86
87static QChar findProportionalToFullWidth(const QChar &value, const QChar &defaultValue)
88{
89 static QMap<QChar, QChar> map = []() {
90 QMap<QChar, QChar> map;
91 // https://stackoverflow.com/questions/8326846/
92 for (int i = 0x0021; i < 0x007F; i++) {
93 map.insert(QChar(i), QChar(i + 0xFF00 - 0x0020));
94 }
95 map.insert(QChar(0x0020), QChar(0x3000)); // Ideographic space.
96
97 return map;
98 }();
99
100 return map.value(value, defaultValue);
101}
102
103QString KoCssTextUtils::transformTextFullWidth(const QString &text)
104{
105 if (text.isEmpty()) return text;
106 QString transformedText;
107 Q_FOREACH (const QChar &c, text) {
108 if (c.decompositionTag() == QChar::Narrow) {
109 transformedText.append(c.decomposition());
110 } else {
111 transformedText.append(findProportionalToFullWidth(c, c));
112 }
113 }
114
115 return transformedText;
116}
117
118static QChar findSmallKanaToBigKana(const QChar &value, const QChar &defaultValue)
119{
120 static QMap<QChar, QChar> map = {
121 // NOTE: these are not fully sequential!
122 // clang-format off
123 {QChar{0x3041}, QChar{0x3042}},
124 {QChar{0x3043}, QChar{0x3044}},
125 {QChar{0x3045}, QChar{0x3046}},
126 {QChar{0x3047}, QChar{0x3048}},
127 {QChar{0x3049}, QChar{0x304A}},
128 {QChar{0x3095}, QChar{0x304B}},
129 {QChar{0x3096}, QChar{0x3051}},
130 {QChar{0x1B132}, QChar{0x3053}},
131 {QChar{0x3063}, QChar{0x3064}},
132 {QChar{0x3083}, QChar{0x3084}},
133 {QChar{0x3085}, QChar{0x3086}},
134 {QChar{0x3087}, QChar{0x3088}},
135 {QChar{0x308E}, QChar{0x308F}},
136 {QChar{0x1B150}, QChar{0x3090}},
137 {QChar{0x1B151}, QChar{0x3091}},
138 {QChar{0x1B152}, QChar{0x3092}},
139
140 {QChar{0x30A1}, QChar{0x30A2}},
141 {QChar{0x30A3}, QChar{0x30A4}},
142 {QChar{0x30A5}, QChar{0x30A6}},
143 {QChar{0x30A7}, QChar{0x30A8}},
144 {QChar{0x30A9}, QChar{0x30AA}},
145 {QChar{0x30F5}, QChar{0x30AB}},
146 {QChar{0x31F0}, QChar{0x30AF}},
147 {QChar{0x30F6}, QChar{0x30B1}},
148 {QChar{0x1B155}, QChar{0x30B3}},
149 {QChar{0x31F1}, QChar{0x30B7}},
150 {QChar{0x31F2}, QChar{0x30B9}},
151 {QChar{0x30C3}, QChar{0x30C4}},
152 {QChar{0x31F3}, QChar{0x30C8}},
153 {QChar{0x31F4}, QChar{0x30CC}},
154 {QChar{0x31F5}, QChar{0x30CF}},
155 {QChar{0x31F6}, QChar{0x30D2}},
156 {QChar{0x31F7}, QChar{0x30D5}},
157 {QChar{0x31F8}, QChar{0x30D8}},
158 {QChar{0x31F9}, QChar{0x30DB}},
159 {QChar{0x31FA}, QChar{0x30E0}},
160 {QChar{0x30E3}, QChar{0x30E4}},
161 {QChar{0x30E5}, QChar{0x30E6}},
162 {QChar{0x30E7}, QChar{0x30E8}},
163 {QChar{0x31FB}, QChar{0x30E9}},
164 {QChar{0x31FC}, QChar{0x30EA}},
165 {QChar{0x31FD}, QChar{0x30EB}},
166 {QChar{0x31FE}, QChar{0x30EC}},
167 {QChar{0x31FF}, QChar{0x30ED}},
168 {QChar{0x30EE}, QChar{0x30EF}},
169 {QChar{0x1B164}, QChar{0x30F0}},
170 {QChar{0x1B165}, QChar{0x30F1}},
171 {QChar{0x1B166}, QChar{0x30F2}},
172 {QChar{0x1B167}, QChar{0x30F3}},
173
174 {QChar{0xFF67}, QChar{0xFF71}},
175 {QChar{0xFF68}, QChar{0xFF72}},
176 {QChar{0xFF69}, QChar{0xFF73}},
177 {QChar{0xFF6A}, QChar{0xFF74}},
178 {QChar{0xFF6B}, QChar{0xFF75}},
179 {QChar{0xFF6F}, QChar{0xFF82}},
180 {QChar{0xFF6C}, QChar{0xFF94}},
181 {QChar{0xFF6D}, QChar{0xFF95}},
182 {QChar{0xFF6E}, QChar{0xFF96}},
183 // clang-format on
184 };
185
186 return map.value(value, defaultValue);
187}
188
190{
191 QString transformedText;
192 Q_FOREACH (const QChar &c, text) {
193 transformedText.append(findSmallKanaToBigKana(c, c));
194 }
195
196 return transformedText;
197}
198
199QVector<bool> KoCssTextUtils::collapseSpaces(QString *text, QMap<int, KoSvgText::TextSpaceCollapse> collapseMethods)
200{
201
202 QString modifiedText = *text;
203 QVector<bool> collapseList(modifiedText.size());
204 collapseList.fill(false);
205 int spaceSequenceCount = 0;
206 KoSvgText::TextSpaceCollapse collapseMethod = collapseMethods.first();
207 for (int i = 0; i < modifiedText.size(); i++) {
208 bool firstOrLast = (i == 0 || i == modifiedText.size() - 1);
209 bool collapse = false;
210 if (collapseMethods.contains(i)) {
211 // If a whitespace:collapse sequence is inside a pre-wrap sequence, the first space needs to be left alone.
212 if (collapseMethods.value(i) != collapseMethod) spaceSequenceCount = 0;
213 collapseMethod = collapseMethods.value(i);
214 }
215 const QChar c = modifiedText.at(i);
216 if (c == QChar::LineFeed || c == QChar::Tabulation) {
217 if (collapseMethod == KoSvgText::Collapse ||
218 collapseMethod == KoSvgText::PreserveSpaces) {
219 modifiedText[i] = QChar::Space;
220 spaceSequenceCount += 1;
221 collapseList[i] = spaceSequenceCount > 1 || firstOrLast? true: false;
222 continue;
223 }
224 }
225 if (c.isSpace()) {
226 bool isSegmentBreak = c == QChar::LineFeed;
227 bool isTab = c == QChar::Tabulation;
228 spaceSequenceCount += 1;
229 if (spaceSequenceCount > 1 || firstOrLast) {
230 switch (collapseMethod) {
233 collapse = true;
234 break;
238 collapse = false;
239 break;
241 collapse = !isSegmentBreak;
242 if (isTab) {
243 modifiedText[i] = QChar::Space;
244 }
245 break;
246 }
247 }
248 } else {
249 spaceSequenceCount = 0;
250 }
251 collapseList[i] = collapse;
252 }
253 // go backward to ensure any dangling space characters are marked as collapsed.
254 for (int i = modifiedText.size()-1; i>=0; i--) {
255 if (collapseMethods.contains(i)) {
256 int pos = collapseMethods.keys().indexOf(i);
257 collapseMethod = collapseMethods.value(collapseMethods.keys().value(pos-1, 0), KoSvgText::Collapse);
258 if (collapseMethod != KoSvgText::Collapse) break;
259 }
260 if (modifiedText.at(i).isSpace()) {
261 if (collapseMethod == KoSvgText::Collapse) {
262 collapseList[i] = true;
263 }
264 } else {
265 break;
266 }
267 }
268 *text = modifiedText;
269 return collapseList;
270}
271
273{
274 bool collapse = false;
275 if (c == QChar::LineFeed) {
276 collapse = true;
277 } else if (c.isSpace()) {
278 switch (collapseMethod) {
281 collapse = true;
282 break;
285 collapse = false;
286 break;
288 collapse = true;
289 break;
291 collapse = false;
292 break;
293 }
294 }
295 return collapse;
296}
297
299 KoSvgText::TextSpaceCollapse collapseMethod,
300 KoSvgText::TextWrap wrapMethod,
301 bool &force,
302 bool nextCharIsHardBreak)
303{
304 if (c.isSpace()) {
305 if (collapseMethod == KoSvgText::Collapse || collapseMethod == KoSvgText::PreserveBreaks) {
306 // [css-text-3] white-space is set to normal, nowrap, or pre-line; or
307 // [css-text-4] white-space-collapse is collapse or preserve-breaks:
308 // hang unconditionally.
309 force = true;
310 return true;
311 } else if (collapseMethod == KoSvgText::Preserve && wrapMethod != KoSvgText::NoWrap) {
312 // [css-text-3] white-space is set to pre-wrap; or
313 // [css-text-4] white-space-collapse is preserve and text-wrap is not nowrap:
314 // hang unconditionally, unless followed by a force line break,
315 // in which case conditionally hang.
316
317 if (nextCharIsHardBreak) {
318 force = false;
319 } else {
320 force = true;
321 }
322 return true;
323 }
324 }
325
326 return false;
327}
328
329bool KoCssTextUtils::characterCanHang(const QChar c, KoSvgText::HangingPunctuations hangType)
330{
331 if (hangType.testFlag(KoSvgText::HangFirst)) {
332 if (c.category() == QChar::Punctuation_InitialQuote || // Pi
333 c.category() == QChar::Punctuation_Open || // Ps
334 c.category() == QChar::Punctuation_FinalQuote || // Pf
335 c == "\u0027" || // Apostrophe
336 c == "\uFF07" || // Fullwidth Apostrophe
337 c == "\u0022" || // Quotation Mark
338 c == "\uFF02") { // Fullwidth Quotation Mark
339 return true;
340 }
341 }
342 if (hangType.testFlag(KoSvgText::HangLast)) {
343 if (c.category() == QChar::Punctuation_InitialQuote || // Pi
344 c.category() == QChar::Punctuation_FinalQuote || // Pf
345 c.category() == QChar::Punctuation_Close || // Pe
346 c == "\u0027" || // Apostrophe
347 c == "\uFF07" || // Fullwidth Apostrophe
348 c == "\u0022" || // Quotation Mark
349 c == "\uFF02") { // Fullwidth Quotation Mark
350 return true;
351 }
352 }
353 if (hangType.testFlag(KoSvgText::HangEnd)) {
354 if (c == "\u002c" || // Comma
355 c == "\u002e" || // Full Stop
356 c == "\u060c" || // Arabic Comma
357 c == "\u06d4" || // Arabic Full Stop
358 c == "\u3001" || // Ideographic Comma
359 c == "\u3002" || // Ideographic Full Stop
360 c == "\uff0c" || // Fullwidth Comma
361 c == "\uff0e" || // Fullwidth full stop
362 c == "\ufe50" || // Small comma
363 c == "\ufe51" || // Small ideographic comma
364 c == "\ufe52" || // Small full stop
365 c == "\uff61" || // Halfwidth ideographic full stop
366 c == "\uff64" // halfwidth ideographic comma
367 ) {
368 return true;
369 }
370 }
371 return false;
372}
373
374bool KoCssTextUtils::IsCssWordSeparator(const QString grapheme)
375{
376 return (grapheme == "\u0020" || // Space
377 grapheme == "\u00A0" || // No Break Space
378 grapheme == "\u1361" || // Ethiopic Word Space
379 grapheme == "\u10100" || // Aegean Word Sepator Line
380 grapheme == "\u10101" || // Aegean Word Sepator Dot
381 grapheme == "\u1039F");
382}
383
384QStringList KoCssTextUtils::textToUnicodeGraphemeClusters(const QString &text, const QString &langCode)
385{
386 QVector<char> graphemeBreaks(text.size());
387 set_graphemebreaks_utf16(text.utf16(), static_cast<size_t>(text.size()), langCode.toUtf8().data(), graphemeBreaks.data());
388 QStringList graphemes;
389 int graphemeLength = 0;
390 int lastGrapheme = 0;
391 for (int i = 0; i < text.size(); i++) {
392 graphemeLength += 1;
393 bool breakGrapheme = lastGrapheme + graphemeLength < text.size() ? graphemeBreaks[i] == GRAPHEMEBREAK_BREAK : false;
394 if (breakGrapheme) {
395 graphemes.append(text.mid(lastGrapheme, graphemeLength));
396 lastGrapheme += graphemeLength;
397 graphemeLength = 0;
398 }
399 }
400 graphemes.append(text.mid(lastGrapheme, text.size() - lastGrapheme));
401 return graphemes;
402}
403
405 QChar::Script_Bopomofo,
406 QChar::Script_Han,
407 QChar::Script_Hangul,
408 QChar::Script_Hiragana,
409 QChar::Script_Katakana,
410 QChar::Script_Yi
411};
412
414 QChar::Script_Khmer,
415 QChar::Script_Lao,
416 QChar::Script_Myanmar,
417 QChar::Script_NewTaiLue,
418 QChar::Script_TaiLe,
419 QChar::Script_TaiTham,
420 QChar::Script_TaiViet,
421 QChar::Script_Thai
422};
423
425{
426 QVector<QPair<bool, bool>> opportunities(text.size());
427 opportunities.fill(QPair<bool, bool>(false, false));
428 QStringList graphemes = textToUnicodeGraphemeClusters(text, langCode);
429 for (int i = 0; i < graphemes.size(); i++) {
430 QString grapheme = graphemes.at(i);
431 if (IsCssWordSeparator(grapheme) || blockScript.contains(grapheme.at(0).script())
432 || clusterScript.contains(grapheme.at(0).script())) {
433 opportunities[i] = QPair<bool, bool>(true, true);
434 }
435 }
436 return opportunities;
437}
438
439const QString BIDI_CONTROL_LRE = "\u202a";
440const QString BIDI_CONTROL_RLE = "\u202b";
441const QString BIDI_CONTROL_PDF = "\u202c";
442const QString BIDI_CONTROL_LRO = "\u202d";
443const QString BIDI_CONTROL_RLO = "\u202e";
444const QString BIDI_CONTROL_LRI = "\u2066";
445const QString BIDI_CONTROL_RLI = "\u2067";
446const QString BIDI_CONTROL_FSI = "\u2068";
447const QString BIDI_CONTROL_PDI = "\u2069";
448const QString UNICODE_BIDI_ISOLATE_OVERRIDE_LR_START = "\u2068\u202d";
449const QString UNICODE_BIDI_ISOLATE_OVERRIDE_RL_START = "\u2068\u202e";
450const QString UNICODE_BIDI_ISOLATE_OVERRIDE_END = "\u202c\u2069";
451const QChar ZERO_WIDTH_JOINER = QChar{0x200d};
452
454{
455 using namespace KoSvgText;
456
457 QString result;
458
459 if (ltr) {
460 if (bidi == BidiEmbed) {
461 result = BIDI_CONTROL_LRE;
462 } else if (bidi == BidiOverride) {
463 result = BIDI_CONTROL_LRO;
464 } else if (bidi == BidiIsolate) {
465 result = BIDI_CONTROL_LRI;
466 } else if (bidi == BidiIsolateOverride) {
468 } else if (bidi == BidiPlainText) {
469 result = BIDI_CONTROL_FSI;
470 }
471 } else {
472 if (bidi == BidiEmbed) {
473 result = BIDI_CONTROL_RLE;
474 } else if (bidi == BidiOverride) {
475 result = BIDI_CONTROL_RLO;
476 } else if (bidi == BidiIsolate) {
477 result = BIDI_CONTROL_RLI;
478 } else if (bidi == BidiIsolateOverride) {
480 } else if (bidi == BidiPlainText) {
481 result = BIDI_CONTROL_FSI;
482 }
483 }
484
485 return result;
486}
487
489{
490 using namespace KoSvgText;
491
492 QString result;
493
494 if (bidi == BidiEmbed || bidi == BidiOverride) {
495 result = BIDI_CONTROL_PDF;
496 } else if (bidi == BidiIsolate || bidi == BidiPlainText) {
497 result = BIDI_CONTROL_PDI;
498 } else if (bidi == BidiIsolateOverride) {
500 }
501
502 return result;
503}
504
506 // Original set of VS
507 if (val == 0xfe00 || (val > 0xfe00 && val <= 0xfe0f)) {
508 return true;
509 }
510 // Extended set VS
511 if (val == 0xe0100 || (val > 0xe0100 && val <= 0xe01ef)) {
512 return true;
513 }
514 // Mongolian VS
515 if (val == 0x180b || (val > 0x180b && val <= 0x180f)) {
516 return true;
517 }
518 // Emoji skin tones
519 if (val == 0x1f3fb || (val > 0x1f3fb && val <= 0x1f3ff)) {
520 return true;
521 }
522 return false;
523}
524
526 if (val == 0x1f1e6 || (val > 0x1f1e6 && val <= 0x1f1ff)) {
527 return true;
528 }
529 return false;
530}
531
532void KoCssTextUtils::removeText(QString &text, int &start, int length)
533{
534 int end = start+length;
535 int j = 0;
536 int v = 0;
537 int lastCharZWJ = 0;
538 int lastVS = 0;
539 int vsClusterStart = 0;
540 int regionalIndicatorCount = 0;
541 bool startFound = false;
542 bool addToEnd = true;
543 Q_FOREACH(const uint i, text.toUcs4()) {
544 v = QChar::requiresSurrogates(i)? 2: 1;
545 int index = (j+v) -1;
546 bool ZWJ = text.at(index) == ZERO_WIDTH_JOINER;
547 if (isVariationSelector(i)) {
548 lastVS += v;
549 } else {
550 lastVS = 0;
551 vsClusterStart = j;
552 }
553 if (index >= start && !startFound) {
554 startFound = true;
555 if (v > 1) {
556 start = j;
557 }
558 if (regionalIndicatorCount > 0 && regionalIndicator(i)) {
559 start -= regionalIndicatorCount;
560 regionalIndicatorCount = 0;
561 }
562 // Always delete any zero-width-joiners as well.
563 if (ZWJ && index > start) {
564 start = -1;
565 }
566 if (lastCharZWJ > 0) {
567 start -= lastCharZWJ;
568 lastCharZWJ = 0;
569 }
570 // remove any clusters too.
571 if (lastVS > 0) {
572 start = vsClusterStart;
573 }
574 }
575
576
577 if (j >= end && addToEnd) {
578 end = j;
579 addToEnd = ZWJ || isVariationSelector(i)
580 || (regionalIndicatorCount < 3 && regionalIndicator(i));
581 if (addToEnd) {
582 end += v;
583 }
584 }
585 j += v;
586 lastCharZWJ = ZWJ? lastCharZWJ + v: 0;
587 regionalIndicatorCount = regionalIndicator(i)? regionalIndicatorCount + v: 0;
588 }
589 text.remove(start, end-start);
590}
591
592qreal KoCssTextUtils::cssSelectFontStyleValue(const QVector<qreal> &values, const qreal targetValue, const qreal defaultValue, const qreal defaultValueUpper, const bool shouldNotReturnDefault)
593{
594 if(values.isEmpty()) {
595 return targetValue;
596 }
597 // follow the CSS Fonts selection mechanism.
598 // See https://drafts.csswg.org/css-fonts-4/#font-style-matching
599 QVector<qreal> sortedValues = values;
600 std::sort(sortedValues.begin(), sortedValues.end());
601 qreal selectedValue = defaultValue;
602 auto upper = std::lower_bound(sortedValues.begin(), sortedValues.end(), targetValue);
603 if (upper == sortedValues.end()) {
604 upper--;
605 }
606 auto lower = upper;
607 if (lower != sortedValues.begin() && *lower > targetValue) {
608 lower--;
609 }
610
611 // ... Which wants to select the lower possible selection when the value is below the default.
612 if (targetValue < defaultValue) {
613 selectedValue = *lower;
614 // ... the higher closest value when the value is higher than the default (upper bound)
615 } else if (targetValue > defaultValueUpper) {
616 selectedValue = *upper;
617 } else {
618 // ... and if the value is between the lower and upper default bounds, first higher (within bounds)
619 // then lower, then higher.
620 if (*upper <= defaultValueUpper && *lower != targetValue) {
621 selectedValue = *upper;
622 } else {
623 selectedValue = *lower;
624 }
625 }
626 if (qFuzzyCompare(selectedValue, defaultValue) && shouldNotReturnDefault) {
627 return targetValue;
628 }
629 return selectedValue;
630}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
float value(const T *src, size_t ch)
qreal v
const QString BIDI_CONTROL_RLE
const QString BIDI_CONTROL_LRE
static QVector< QChar::Script > blockScript
const QString UNICODE_BIDI_ISOLATE_OVERRIDE_RL_START
const QString BIDI_CONTROL_RLO
const QString BIDI_CONTROL_LRI
const QString BIDI_CONTROL_PDF
static QVector< QChar::Script > clusterScript
const QString BIDI_CONTROL_LRO
static QChar findProportionalToFullWidth(const QChar &value, const QChar &defaultValue)
const QString UNICODE_BIDI_ISOLATE_OVERRIDE_END
bool isVariationSelector(uint val)
static QChar findSmallKanaToBigKana(const QChar &value, const QChar &defaultValue)
const QString BIDI_CONTROL_PDI
const QChar ZERO_WIDTH_JOINER
bool regionalIndicator(uint val)
const QString BIDI_CONTROL_FSI
const QString BIDI_CONTROL_RLI
const QString UNICODE_BIDI_ISOLATE_OVERRIDE_LR_START
QVector< QPair< int, int > > positionDifference(QStringList a, QStringList b)
unsigned int uint
static QVector< bool > collapseSpaces(QString *text, QMap< int, KoSvgText::TextSpaceCollapse > collapseMethods)
collapseSpaces Some versions of CSS-Text 'white-space' or 'text-space-collapse' will collapse or tran...
static QString transformTextFullSizeKana(const QString &text)
transformTextFullSizeKana This function will take 'small' Kana (Japanese phonetic script) and transfo...
static bool IsCssWordSeparator(QString grapheme)
IsCssWordSeparator CSS has a number of characters it considers word-separators, which are used in jus...
static QStringList textToUnicodeGraphemeClusters(const QString &text, const QString &langCode)
textToUnicodeGraphemes In letters like Å, the amount of unicode codpoints can be 1,...
static QString transformTextCapitalize(const QString &text, QString langCode, QVector< QPair< int, int > > &positions)
transformTextToUpperCase This function splits the text into graphemes, and then uses QLocale::toUpper...
static QString transformTextToUpperCase(const QString &text, const QString &langCode, QVector< QPair< int, int > > &positions)
transformTextToUpperCase convenience function that creates a QLocale and uses it's 'toUpper' function...
static QString transformTextToLowerCase(const QString &text, const QString &langCode, QVector< QPair< int, int > > &positions)
transformTextToUpperCase convenience function that creates a QLocale and uses it's 'toLower' function...
static bool characterCanHang(QChar c, KoSvgText::HangingPunctuations hangType)
characterCanHang The function returns whether the character qualifies for 'hanging-punctuation',...
static QString getBidiClosing(KoSvgText::UnicodeBidi bidi)
getBidiClosing Returns the bidi closing string associated with the given Css unicode-bidi value.
static void removeText(QString &text, int &start, int length)
removeText Special removal of text that takes a text, start and length and will modify these values s...
static qreal cssSelectFontStyleValue(const QVector< qreal > &values, const qreal targetValue, const qreal defaultValue, const qreal defaultValueUpper, const bool shouldNotReturnDefault)
cssSelectFontStyleValue Select the closest font style value from the list, following the CSS Fonts se...
static bool collapseLastSpace(QChar c, KoSvgText::TextSpaceCollapse collapseMethod)
collapseLastSpace Some versions of CSS-Text 'white-space' or 'text-space-collapse' will collapse the ...
static QString transformTextFullWidth(const QString &text)
transformTextFullWidth This function will transform 'narrow' or 'halfwidth' characters to their norma...
static bool hangLastSpace(const QChar c, KoSvgText::TextSpaceCollapse collapseMethod, KoSvgText::TextWrap wrapMethod, bool &force, bool nextCharIsHardBreak)
hangLastSpace Some versions of CSS-Text 'white-space' or 'text-space-collapse' will hang the final sp...
static QString getBidiOpening(bool ltr, KoSvgText::UnicodeBidi bidi)
getBidiOpening Get the bidi opening string associated with the given Css unicode-bidi value and direc...
static QVector< QPair< bool, bool > > justificationOpportunities(QString text, QString langCode)
justificationOpportunities mark justification opportunities in the text. Opportunities are between ch...
static bool qFuzzyCompare(half p1, half p2)
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
@ HangLast
Hang closing brackets and quotes.
Definition KoSvgText.h:207
@ HangFirst
Hang opening brackets and quotes.
Definition KoSvgText.h:206
@ HangEnd
Hang stops and commas. Force/Allow is a separate boolean.
Definition KoSvgText.h:208
TextSpaceCollapse
Definition KoSvgText.h:96
@ 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
@ Discard
Discard all Spaces.
Definition KoSvgText.h:98
@ PreserveSpaces
required for 'xml:space="preserve"' emulation.
Definition KoSvgText.h:102