8#ifndef KO_SVG_TEXT_SHAPE_P_H
9#define KO_SVG_TEXT_SHAPE_P_H
28#include <QPainterPath>
90using Variant = std::variant<std::monostate, Outline, Bitmap, ColorLayers>;
173 if (newOrigin == QPointF())
return;
175 outlineGlyph->path.translate(-newOrigin);
177 for (
int i = 0; i< bitmapGlyph->drawRects.size(); i++) {
178 bitmapGlyph->drawRects[i].translate(-newOrigin);
181 for (
int i = 0; i< colorGlyph->paths.size(); i++) {
182 colorGlyph->paths[i].translate(-newOrigin);
204 QTransform scale = QTransform::fromScale(xScale, yScale);
205 if (scale.isIdentity())
return;
206 const bool scaleToZero = !(xScale > 0 && yScale > 0);
209 if (!outlineGlyph->path.isEmpty()) {
211 outlineGlyph->path = QPainterPath();
213 outlineGlyph->path = scale.map(outlineGlyph->path);
218 bitmapGlyph->drawRects.clear();
219 bitmapGlyph->images.clear();
221 for (
int i = 0; i< bitmapGlyph->drawRects.size(); i++) {
222 bitmapGlyph->drawRects[i] = scale.mapRect(bitmapGlyph->drawRects[i]);
226 for (
int i = 0; i< colorGlyph->paths.size(); i++) {
228 colorGlyph->paths[i] = QPainterPath();
230 colorGlyph->paths[i] = scale.map(colorGlyph->paths[i]);
319 Q_FOREACH(QLineF line, lineWidths) {
326 Q_FOREACH(QLineF line, lineWidths) {
385 for (
int i=0; i<
chunks.size(); i++) {
390 if ((pos.x() < max) &&
398 if ((pos.y() < max) &&
408 if (
chunks.isEmpty())
return true;
409 for (
int i =0; i <
chunks.size(); i++) {
410 if (!
chunks.at(i).chunkIndices.isEmpty())
return false;
449 shapeGroup->setSelectable(
false);
461 , textData(rhs.textData)
467 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesInside, shapesInside);
468 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesSubtract, shapesSubtract);
469 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.textPaths, textPaths);
470 updateInternalShapesList();
475 lineBoxes = rhs.lineBoxes;
477 cursorPos = rhs.cursorPos;
478 logicalToVisualCursorPos = rhs.logicalToVisualCursorPos;
479 plainText = rhs.plainText;
481 initialTextPosition = rhs.initialTextPosition;
483 isLoading = rhs.isLoading;
484 disableFontMatching = rhs.disableFontMatching;
486 currentTextWrappingAreas = rhs.currentTextWrappingAreas;
490 for (
int i = 0; i<sourceShapeList.size(); i++) {
491 if (referenceShapeList.contains(referenceList2.at(i))) {
492 destinationShapeList.append(sourceShapeList.at(i));
499 internalShapesPainter.reset();
500 Q_FOREACH(
KoShape *shape, shapeGroup->shapes()) {
501 shapeGroup->removeShape(shape);
504 qDeleteAll(shapesInside);
505 shapesInside.clear();
506 qDeleteAll(shapesSubtract);
507 shapesSubtract.clear();
508 qDeleteAll(textPaths);
519 return internalShapesPainter->internalShapeManager()->shapes();
523 Q_FOREACH(
KoShape *shape, shapeGroup->shapes()) {
524 shapeGroup->removeShape(shape);
526 Q_FOREACH(
KoShape *shape, shapesInside) {
527 shapeGroup->addShape(shape);
529 Q_FOREACH(
KoShape *shape, shapesSubtract) {
530 shapeGroup->addShape(shape);
532 Q_FOREACH(
KoShape *shape, textPaths) {
533 shapeGroup->addShape(shape);
535 updateTextWrappingAreas();
536 updateInternalShapesList();
540 internalShapesPainter->setShapes(shapeGroup->shapes());
545 BulkActionState(QRectF originalBoundingRectArg) : originalBoundingRect(originalBoundingRectArg) {}
548 bool contourHasChanged =
false;
549 bool layoutHasChanged =
false;
550 bool layoutSetFromMemento =
false;
553 return contourHasChanged || layoutHasChanged || layoutSetFromMemento;
574 auto it = std::find_if(textPaths.begin(), textPaths.end(), [&name](
const KoShape *s) ->
bool {return s->name() == name;});
575 return it != textPaths.end()? *it:
nullptr;
580 return cursorPos.at(qBound(0, pos, cursorPos.size()-1));
584 bool isLoading =
false;
586 bool disableFontMatching =
false;
596 QPointF initialTextPosition = QPointF();
601 const FT_Int32 faceLoadFlags,
602 const bool isHorizontal,
603 const char32_t firstCodepoint,
605 raqm_glyph_t ¤tGlyph,
607 QPointF &totalAdvanceFTFontCoordinates);
610 const bool isHorizontal,
611 raqm_glyph_t ¤tGlyph);
614 FT_Int32 faceLoadFlags,
616 raqm_glyph_t ¤tGlyph,
632 const QPainterPath &path,
642 const bool isHorizontal,
643 const bool disableFontMatching);
650 const QMap<int, int>& logicalToVisual,
653 qreal textPathoffset,
663 const bool isHorizontal,
664 const KoSvgText::TextDecorations &decor,
666 const bool textDecorationSkipInset =
false,
668 const qreal currentTextPathOffset = 0.0,
669 const bool textPathSide =
false,
673 QPainterPath decorationPath,
674 const QPointF offset,
675 const QPainterPathStroker &stroker,
677 QMap<KoSvgText::TextDecoration, QPainterPath> &decorationPaths,
679 const bool isHorizontal,
680 const qreal currentTextPathOffset,
681 const bool textPathSide
685 const QPainterPath &outlineRect,
690 const QPainterPath &outlineRect,
705 int count = parent->numChars(withControls, props);
707 count += numChars(it, withControls, props);
733 bool skipZeroWidth =
false)
737 if (childCount(siblingCurrent(it)) > 0) {
740 int length = it->numChars(
false);
741 if (
length == 0 && skipZeroWidth) {
745 if (sought == currentIndex || (sought > currentIndex && sought < currentIndex +
length)) {
763 int currentIndex = 0;
766 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
769 bool suitableStartIndex = siblingCurrent(contentElement) == tree.
childBegin()? index >= currentIndex: index > currentIndex;
770 bool suitableEndIndex = siblingCurrent(contentElement) == tree.
childBegin()?
true: index < currentIndex + contentElement->numChars(
false);
772 if (suitableStartIndex && suitableEndIndex) {
774 duplicate.
text = contentElement->text;
775 int start = index - currentIndex;
776 int length = contentElement->numChars(
false) - start;
780 if (!allowEmptyText && (duplicate.
text.isEmpty() ||
length == 0)) {
786 if (siblingCurrent(contentElement) != tree.
childBegin()
787 && contentElement->textPathId.isEmpty()
788 && contentElement->textLength.isAuto
789 && contentElement->localTransformations.isEmpty()) {
790 contentElement->removeText(zero, start);
792 tree.
insert(siblingCurrent(contentElement), duplicate);
795 duplicate2.
text = contentElement->text;
797 contentElement->text.clear();
798 tree.
insert(childBegin(contentElement), duplicate);
799 tree.
insert(childEnd(contentElement), duplicate2);
814 splitContentElement(tree, index,
false);
815 int currentIndex = 0;
816 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
820 if (siblingCurrent(contentElement) == tree.
childBegin())
return;
822 auto lastNode = siblingCurrent(contentElement);
825 if (lastNode == siblingCurrent(parentIt))
continue;
826 if (siblingCurrent(parentIt) == tree.
childBegin()) {
830 if (lastNode != childBegin(siblingCurrent(parentIt))) {
833 if (textPathAfterSplit) {
836 parentIt->textPathId = QString();
839 auto insert = siblingCurrent(parentIt);
841 auto it = tree.
insert(insert, duplicate);
844 for (
auto child = lastNode; child != childEnd(siblingCurrent(parentIt)); child++) {
845 movableChildren.append(child);
847 while(!movableChildren.isEmpty()) {
848 auto child = movableChildren.takeLast();
849 tree.
move(child, childBegin(it));
853 lastNode = siblingCurrent(parentIt);
870 if (!child.
node())
return childEnd(root);
872 for (
auto rootChild = childBegin(root); rootChild != childEnd(root); rootChild++) {
875 if (siblingCurrent(leaf) == child) {
880 return childEnd(root);
892 QMap<int, KoSvgText::TextSpaceCollapse> collapseModes;
899 parentProps.append(ownProperties);
901 const int children = childCount(siblingCurrent(it));
903 QString text = it->text;
904 if (includeBidiControls) {
909 text += it->getTransformedString(positions, parentProps.last());
913 collapseModes.insert(allText.size(), collapse);
917 parentProps.pop_back();
922 if (alsoCollapseLowSurrogate) {
923 for (
int i = 0; i < allText.size(); i++) {
924 if (i > 0 && allText.at(i).isLowSurrogate() && allText.at(i-1).isHighSurrogate()) {
945 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
948 removeTransformsImpl(root, 0, start,
length, collapsedCharacters);
957 int currentLength = 0;
958 auto it = childBegin(currentTextElement);
959 if (it != childEnd(currentTextElement)) {
960 for (; it != childEnd(currentTextElement); it++) {
961 currentLength += removeTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters);
964 currentLength = currentTextElement->text.size();
967 if (!currentTextElement->localTransformations.isEmpty()) {
968 int transformOffset = 0;
969 int transformOffsetEnd = 0;
971 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
972 if (i >= collapsedCharacters.size())
break;
974 transformOffset += collapsedCharacters.at(i)? 0: 1;
977 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
982 if (transformOffset < currentTextElement->localTransformations.size()) {
983 int length = qBound(0, transformOffsetEnd-transformOffset, qMax(0, currentTextElement->localTransformations.size()-transformOffset));
984 currentTextElement->localTransformations.remove(transformOffset,
989 return currentLength;
1003 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
1006 insertTransformsImpl(root, 0, start,
length, collapsedCharacters, allowSkipFirst);
1014 int currentLength = 0;
1015 auto it = childBegin(currentTextElement);
1016 if (it != childEnd(currentTextElement)) {
1017 for (; it != childEnd(currentTextElement); it++) {
1018 currentLength += insertTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters, allowSkipFirst);
1021 currentLength = currentTextElement->text.size();
1024 if (!currentTextElement->localTransformations.isEmpty()) {
1025 int transformOffset = 0;
1026 int transformOffsetEnd = 0;
1028 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
1030 transformOffset += collapsedCharacters.at(i)? 0: 1;
1032 if (i < start +
length) {
1033 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
1040 if (transformOffset == 0 && allowSkipFirst && currentTextElement->localTransformations.at(0).startsNewChunk()) {
1041 transformOffset += 1;
1044 if (transformOffset < currentTextElement->localTransformations.size()) {
1045 for (
int i = transformOffset; i < transformOffsetEnd; i++) {
1051 return currentLength;
1066 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, allText,
false);
1068 auto end = std::make_reverse_iterator(tree.
childBegin());
1069 auto begin = std::make_reverse_iterator(tree.
childEnd());
1071 for (; begin != end; begin++) {
1072 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1074 if (convertToPreWrapped) {
1081 auto base = current.base();
1086 if(base != siblingEnd(base)) {
1087 auto end = std::make_reverse_iterator(childBegin(base));
1088 auto begin = std::make_reverse_iterator(childEnd(base));
1089 for (; begin != end; begin++) {
1090 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1094 if (!current->text.isEmpty()) {
1095 const int total = current->text.size();
1096 QString currentText = allText.right(total);
1098 for (
int i = 0; i < total; i++) {
1099 const int j = total - (i+1);
1100 const bool col = collapsed.takeLast();
1102 currentText.remove(j, 1);
1106 current->text = currentText;
1107 allText.chop(total);
1109 if (convertToPreWrapped) {
1117 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, all,
false, includeBidiControls);
1119 int globalIndex = 0;
1128 resolveTransforms(tree.
childBegin(), all, result, globalIndex,
1129 isHorizontal, isWrapped,
false, resolvedTransforms,
1132 return resolvedTransforms;
1145 auto end = std::make_reverse_iterator(tree.
childBegin());
1146 auto begin = std::make_reverse_iterator(tree.
childEnd());
1148 bool inTextPath =
false;
1149 for (; begin != end; begin++) {
1150 insertNewLinesAtAnchorsImpl(begin, resolvedTransforms, inTextPath);
1158 inTextPath = (!current->textPathId.isEmpty());
1159 auto base = current.base();
1161 if(base != siblingEnd(base)) {
1162 auto end = std::make_reverse_iterator(childBegin(base));
1163 auto begin = std::make_reverse_iterator(childEnd(base));
1164 for (; begin != end; begin++) {
1165 insertNewLinesAtAnchorsImpl(begin,
1171 if (!current->text.isEmpty()) {
1172 const int total = current->text.size();
1174 for (
int i = 0; i < total; i++) {
1175 const int j = total - (i+1);
1183 bool startsNewChunk = transform.startsNewChunk() && j == 0;
1187 startsNewChunk =
false;
1191 if (startsNewChunk && !resolvedTransforms.isEmpty() && current->text.at(j) != QChar::LineFeed) {
1192 current->text.insert(j,
"\n");
1196 current->localTransformations.clear();
1200 for (
int i = 0; i< layout.size(); i++) {
1202 if (layout.at(i).anchored_chunk) {
1203 int plainTextIndex = layout.at(i).plaintTextIndex;
1204 splitContentElement(tree, plainTextIndex);
1208 int globalIndex = 0;
1219 int &globalIndex,
bool isHorizontal) {
1222 if (!current->textPathId.isEmpty())
return;
1223 for (
auto it = childBegin(current); it!= childEnd(current); it++) {
1224 setTransformsFromLayoutImpl(it, props, layout, globalIndex, isHorizontal);
1227 if (current->text.isEmpty()) {
1228 current->localTransformations.clear();
1231 const int length = current->numChars(
true, props);
1233 for (
int i = globalIndex; i< globalIndex+
length; i++) {
1244 qreal shift = anchoredChunkShift(layout, isHorizontal, i, endIndex);
1245 QPointF offset = isHorizontal? QPointF(shift, 0): QPointF(0, shift);
1252 transform.
dxPos = offset.x();
1253 transform.
dyPos = offset.y();
1257 transforms.append(transform);
1259 current->localTransformations = transforms;
1260 current->text = current->text.split(
"\n").join(
" ");
1274 const int children = childCount(current);
1275 if (children == 0) {
1276 const int length = current->numChars(
false);
1277 if (
length == 0 && current != tree.
childBegin() && current->textPathId.isEmpty()) {
1281 auto siblingPrev = current;
1285 while (!isEnd(siblingPrev) && siblingPrev->text.isEmpty()) {
1290 if (!isEnd(siblingPrev)
1291 && siblingPrev != current
1292 && (siblingPrev->localTransformations.isEmpty() && current->localTransformations.isEmpty())
1293 && (siblingPrev->textPathId.isEmpty() && current->textPathId.isEmpty())
1294 && (siblingPrev->textLength.isAuto && current->textLength.isAuto)
1295 && (siblingPrev->properties == current->properties)
1297 && childCount(siblingPrev) == 0) {
1299 siblingPrev->text += current->text;
1300 current->text = QString();
1304 }
else if (children == 1) {
1306 auto child = childBegin(current);
1307 if ((child->localTransformations.isEmpty() && current->localTransformations.isEmpty())
1308 && (child->textPathId.isEmpty() && current->textPathId.isEmpty())
1309 && (child->textLength.isAuto && current->textLength.isAuto)
1310 && (!child->properties.hasNonInheritableProperties() || !current->properties.hasNonInheritableProperties())) {
1311 if (current->properties.hasNonInheritableProperties()) {
1314 child->properties = props;
1316 child->
properties.inheritFrom(current->properties);
1323 for (
auto child = childBegin(current); child != childEnd(current); child++) {
1324 if (cleanUpImpl(tree, child)) {
1325 deleteList.append(child);
1328 while (!deleteList.isEmpty()) {
1329 auto child = deleteList.takeFirst();
1333 if (childCount(current) <= 1) {
1335 return cleanUpImpl(tree, current);
1356 if (treeIndex.isEmpty())
return parent;
1358 int count = idx.takeFirst();
1362 return iteratorForTreeIndex(idx, child);
1377 if (startIndexOfIterator(child,
target, currentIndex)) {
1381 currentIndex += numChars(child);
1394 for (
auto it = childBegin(parent); it != childEnd(parent); it++) {
1395 if (it->textPathId == name) {
1396 it->textPathId = QString();
1403 bool textPathNameUnique =
false;
1404 int textPathNumber = textPaths.size();
1405 QString newTextPathName = textPath->
name();
1406 while(!textPathNameUnique) {
1407 textPathNameUnique =
true;
1408 Q_FOREACH(
KoShape *shape, textPaths) {
1409 if (shape->
name() == newTextPathName) {
1410 textPathNameUnique =
false;
1411 textPathNumber += 1;
1415 if (textPathNameUnique && !newTextPathName.isEmpty()) {
1416 textPath->
setName(newTextPathName);
1418 textPathNameUnique =
false;
1420 newTextPathName = QString(
"textPath"+QString::number(textPathNumber));
1443 QRectF bb = it->associatedOutline.boundingRect();
1444 QMap<KoSvgText::TextDecoration, QPainterPath> decorations = it->textDecorations;
1445 for (
int i = 0; i < decorations.values().size(); ++i) {
1446 bb |= decorations.values().at(i).boundingRect();
1448 if (!bb.isEmpty()) {
1449 if (stroke && includeStrokeInset) {
1451 stroke->strokeInsets(rootShape, insets);
1459 parentStrokes.pop_back();
qreal length(const QPointF &vec)
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
constexpr qreal SHAPE_PRECISION
Value that indicates the precision for testing coordinates for text-in-shape layout.
@ ConditionallyHang
Only hang if no space otherwise, only measured for justification if not hanging.
@ Collapse
Collapse if first or last in line.
@ ForceHang
Force hanging at the start or end of a line, never measured for justification.
@ NoChange
Do nothing special.
child_iterator childEnd()
child_iterator insert(child_iterator pos, X &&value)
Inserts element value into position pos. value becomes the child of the same parent as pos and is pla...
depth_first_tail_iterator depthFirstTailEnd()
child_iterator childBegin()
child_iterator move(child_iterator subtree, child_iterator newPos)
move a subtree to new position Moves subtree into a new position pointer by newPos....
composition_iterator compositionBegin()
composition_iterator compositionEnd()
depth_first_tail_iterator depthFirstTailBegin()
child_iterator erase(child_iterator pos)
Removes element at position pos. If pos is 'end', then result is undefined.
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 getBidiClosing(KoSvgText::UnicodeBidi bidi)
getBidiClosing Returns the bidi closing string associated with the given Css unicode-bidi value.
static QString getBidiOpening(bool ltr, KoSvgText::UnicodeBidi bidi)
getBidiOpening Get the bidi opening string associated with the given Css unicode-bidi value and direc...
The position of a path point within a path shape.
void setName(const QString &name)
void setSelectable(bool selectable)
The KoSvgTextNodeIndex class.
@ InlineSizeId
KoSvgText::AutoValue.
@ UnicodeBidiId
KoSvgText::UnicodeBidi.
@ TextCollapseId
KoSvgText::TextSpaceCollapse.
@ StrokeId
KoSvgText::StrokeProperty.
@ WritingModeId
KoSvgText::WritingMode.
@ DirectionId
KoSvgText::Direction.
@ TextWrapId
KoSvgText::TextWrap.
QList< PropertyId > properties() const
static const KoSvgTextProperties & defaultProperties()
bool hasProperty(PropertyId id) const
void inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve=false, bool onlyFontAndLineHeight=false)
void setAllButNonInheritableProperties(const KoSvgTextProperties &properties)
Used to merge child properties into parent properties.
QVariant propertyOrDefault(PropertyId id) const
void applyTextLength(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, QVector< CharacterResult > &result, int ¤tIndex, int &resolvedDescendentNodes, bool isHorizontal, const KoSvgTextProperties resolvedProps, const KoSvgText::ResolutionHandler &resHandler)
static qreal anchoredChunkShift(const QVector< CharacterResult > &result, const bool isHorizontal, const int start, int &end)
static int removeTransformsImpl(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, const int globalIndex, const int start, const int length, const QVector< bool > collapsedCharacters)
removeTransformsImpl recursive function that handles removing local transforms in a certain range....
QMap< KoSvgText::TextDecoration, QPainterPath > generateDecorationPaths(const int &start, const int &end, const KoSvgText::ResolutionHandler resHandler, const QVector< CharacterResult > &result, const bool isHorizontal, const KoSvgText::TextDecorations &decor, const KoSvgText::TextDecorationStyle style=KoSvgText::TextDecorationStyle::Solid, const bool textDecorationSkipInset=false, const KoPathShape *currentTextPath=nullptr, const qreal currentTextPathOffset=0.0, const bool textPathSide=false, const KoSvgText::TextDecorationUnderlinePosition underlinePosH=KoSvgText::TextDecorationUnderlinePosition::UnderlineAuto, const KoSvgText::TextDecorationUnderlinePosition underlinePosV=KoSvgText::TextDecorationUnderlinePosition::UnderlineAuto)
void paintDebug(QPainter &painter, const QVector< CharacterResult > &result, int ¤tIndex)
static bool cleanUpImpl(KisForest< KoSvgTextContentElement > &tree, KisForest< KoSvgTextContentElement >::child_iterator current)
cleanUpImpl implementation of recursive function for cleanup. This goes over a child and decides whet...
static void removeTransforms(KisForest< KoSvgTextContentElement > &tree, const int start, const int length)
removeTransforms Remove all local SVG character transforms in a certain range. Local transforms are i...
static void resolveTransforms(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, QString text, QVector< CharacterResult > &result, int ¤tIndex, bool isHorizontal, bool wrapped, bool textInPath, QVector< KoSvgText::CharTransformation > &resolved, QVector< bool > collapsedChars, const KoSvgTextProperties resolvedProps, bool withControls=true)
KisForest< KoSvgTextContentElement > textData
QVector< CursorPos > cursorPos
void updateTextWrappingAreas()
updateShapeContours The current shape contours can be slow to compute, so this function calls computi...
static qreal characterResultOnPath(CharacterResult &cr, qreal length, qreal offset, bool isHorizontal, bool isClosed)
void setTransformsFromLayoutImpl(KisForest< KoSvgTextContentElement >::child_iterator current, const KoSvgTextProperties parentProps, const QVector< CharacterResult > layout, int &globalIndex, bool isHorizontal)
static QVector< KoSvgText::CharTransformation > resolvedTransformsForTree(KisForest< KoSvgTextContentElement > &tree, bool shapesInside=false, bool includeBidiControls=false)
QVector< CharacterResult > result
static void finalizeDecoration(QPainterPath decorationPath, const QPointF offset, const QPainterPathStroker &stroker, const KoSvgText::TextDecoration type, QMap< KoSvgText::TextDecoration, QPainterPath > &decorationPaths, const KoPathShape *currentTextPath, const bool isHorizontal, const qreal currentTextPathOffset, const bool textPathSide)
QScopedPointer< KoShapeGroup > shapeGroup
void applyWhiteSpaceImpl(std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< bool > &collapsed, QString &allText, const bool convertToPreWrapped)
static KisForest< KoSvgTextContentElement >::depth_first_tail_iterator findTextContentElementForIndex(KisForest< KoSvgTextContentElement > &tree, int ¤tIndex, int sought, bool skipZeroWidth=false)
findTextContentElementForIndex Finds the given leaf of the current tree-wide string index.
static void computeFontMetrics(KisForest< KoSvgTextContentElement >::child_iterator parent, const KoSvgTextProperties &parentProps, const KoSvgText::FontMetrics &parentBaselineTable, const KoSvgText::Baseline parentBaseline, QVector< CharacterResult > &result, int ¤tIndex, const KoSvgText::ResolutionHandler resHandler, const bool isHorizontal, const bool disableFontMatching)
void paintPaths(QPainter &painter, const QPainterPath &outlineRect, const KoShape *rootShape, const QVector< CharacterResult > &result, const KoSvgText::TextRendering rendering, QPainterPath &chunk, int ¤tIndex)
QList< QPainterPath > currentTextWrappingAreas
static int insertTransformsImpl(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, const int globalIndex, const int start, const int length, const QVector< bool > collapsedCharacters, const bool allowSkipFirst)
insertTransformsImpl Recursive function that handles inserting empty transforms into a given range....
QList< KoShape * > internalShapes() const
void updateInternalShapesList()
QList< KoShape * > shapesInside
static KisForest< KoSvgTextContentElement >::child_iterator iteratorForTreeIndex(const QVector< int > treeIndex, KisForest< KoSvgTextContentElement >::child_iterator parent)
CursorPos getCursorPos(int pos)
static KoShape * textPathByName(QString name, QList< KoShape * > textPaths)
static int numChars(KisForest< KoSvgTextContentElement >::child_iterator parent, bool withControls=false, KoSvgTextProperties resolvedProps=KoSvgTextProperties::defaultProperties())
Get the number of characters for the whole subtree of this node.
QMap< int, int > logicalToVisualCursorPos
static void cleanUp(KisForest< KoSvgTextContentElement > &tree)
cleanUp This cleans up the tree by...
static void splitTree(KisForest< KoSvgTextContentElement > &tree, int index, bool textPathAfterSplit)
splitTree Split the whole hierarchy of nodes at the given index.
static void applyAnchoring(QVector< CharacterResult > &result, bool isHorizontal, const KoSvgText::ResolutionHandler resHandler)
void computeTextDecorations(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, const QVector< CharacterResult > &result, const QMap< int, int > &logicalToVisual, const KoSvgText::ResolutionHandler resHandler, KoPathShape *textPath, qreal textPathoffset, bool side, int ¤tIndex, bool isHorizontal, bool ltr, bool wrapping, const KoSvgTextProperties resolvedProps, QList< KoShape * > textPaths)
static void insertNewLinesAtAnchorsImpl(std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< KoSvgText::CharTransformation > &resolvedTransforms, bool &inTextPath)
KoSvgTextNodeIndex createTextNodeIndex(KisForest< KoSvgTextContentElement >::child_iterator textElement) const
static void applyTextPath(KisForest< KoSvgTextContentElement >::child_iterator parent, QVector< CharacterResult > &result, bool isHorizontal, QPointF &startPos, const KoSvgTextProperties resolvedProps, QList< KoShape * > textPaths)
void setTransformsFromLayout(KisForest< KoSvgTextContentElement > &tree, const QVector< CharacterResult > layout)
Private(const Private &rhs)
static int childCount(KisForest< KoSvgTextContentElement >::child_iterator it)
Get the child count of the current node. A node without children is a text node.
void paintTextDecoration(QPainter &painter, const QPainterPath &outlineRect, const KoShape *rootShape, const KoSvgText::TextDecoration type, const KoSvgText::TextRendering rendering)
static void makeTextPathNameUnique(QList< KoShape * > textPaths, KoShape *textPath)
static QRectF boundingBoxFromTree(KisForest< KoSvgTextContentElement > tree, const KoSvgTextShape *rootShape, bool includeStrokeInset)
boundingBoxFromTree get the bounding box of the current textdata tree. We need the bounding box for a...
static QVector< QPointF > getLigatureCarets(const KoSvgText::ResolutionHandler &resHandler, const bool isHorizontal, raqm_glyph_t ¤tGlyph)
static void insertNewLinesAtAnchors(KisForest< KoSvgTextContentElement > &tree, bool shapesInside=false)
insertNewLinesAtAnchors Resolves character transforms and then inserts new lines at each transform th...
static KisForest< KoSvgTextContentElement >::child_iterator findTopLevelParent(KisForest< KoSvgTextContentElement >::child_iterator root, KisForest< KoSvgTextContentElement >::child_iterator child)
findTopLevelParent Returns the toplevel parent of child that is not root.
static bool splitContentElement(KisForest< KoSvgTextContentElement > &tree, int index, bool allowEmptyText=true)
splitContentElement split the contentElement in tree at index into two nodes.
QScopedPointer< KoShapePainter > internalShapesPainter
std::optional< BulkActionState > bulkActionState
static std::pair< QTransform, qreal > loadGlyphOnly(const QTransform &ftTF, FT_Int32 faceLoadFlags, bool isHorizontal, raqm_glyph_t ¤tGlyph, CharacterResult &charResult, const KoSvgText::TextRendering rendering)
static void insertTransforms(KisForest< KoSvgTextContentElement > &tree, const int start, const int length, const bool allowSkipFirst)
insertTransforms Inserts empty transforms into tree recursively.
void handleShapes(const QList< KoShape * > &sourceShapeList, const QList< KoShape * > referenceList2, const QList< KoShape * > referenceShapeList, QList< KoShape * > &destinationShapeList)
static bool loadGlyph(const KoSvgText::ResolutionHandler &resHandler, const FT_Int32 faceLoadFlags, const bool isHorizontal, const char32_t firstCodepoint, const KoSvgText::TextRendering rendering, raqm_glyph_t ¤tGlyph, CharacterResult &charResult, QPointF &totalAdvanceFTFontCoordinates)
static QVector< bool > collapsedWhiteSpacesForText(KisForest< KoSvgTextContentElement > &tree, QString &allText, const bool alsoCollapseLowSurrogate=false, bool includeBidiControls=false)
collapsedWhiteSpacesForText This returns the collapsed spaces for a given piece of text,...
void clearAssociatedOutlines()
static QVector< SubChunk > collectSubChunks(KisForest< KoSvgTextContentElement >::child_iterator it, KoSvgTextProperties parent, bool textInPath, bool &firstTextInPath)
static QList< QPainterPath > generateShapes(const QList< KoShape * > shapesInside, const QList< KoShape * > shapesSubtract, const KoSvgTextProperties &properties)
QList< KoShape * > shapesSubtract
QVector< LineBox > lineBoxes
static QPainterPath stretchGlyphOnPath(const QPainterPath &glyph, const QPainterPath &path, bool isHorizontal, qreal offset, bool isClosed)
static bool startIndexOfIterator(KisForest< KoSvgTextContentElement >::child_iterator parent, KisForest< KoSvgTextContentElement >::child_iterator target, int ¤tIndex)
QList< KoShape * > textPaths
static void handleLineBoxAlignment(KisForest< KoSvgTextContentElement >::child_iterator parent, QVector< CharacterResult > &result, const QVector< LineBox > lineBoxes, int ¤tIndex, const bool isHorizontal, const KoSvgTextProperties resolvedProps)
KoShape * collectPaths(const KoSvgTextShape *rootShape, QVector< CharacterResult > &result, int ¤tIndex)
static void removeTextPathId(KisForest< KoSvgTextContentElement >::child_iterator parent, const QString &name)
removeTextPathId Remove the text path id with the given name from the toplevel elements.
void applyWhiteSpace(KisForest< KoSvgTextContentElement > &tree, const bool convertToPreWrapped=false)
applyWhiteSpace CSS Whitespace processes whitespaces so that duplicate white spaces and unnecessary h...
#define KIS_ASSERT_RECOVER_NOOP(cond)
std::variant< std::monostate, Outline, Bitmap, ColorLayers > Variant
ResultIterator hierarchyBegin(Iterator it)
ChildIterator< value_type, is_const > childBegin(const ChildIterator< value_type, is_const > &it)
ResultIterator hierarchyEnd(Iterator it)
ResultIterator tailSubtreeBegin(Iterator it)
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
ResultIterator tailSubtreeEnd(Iterator it)
ChildIterator< value_type, is_const > childEnd(const ChildIterator< value_type, is_const > &it)
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
@ AnchorStart
Anchor left for LTR, right for RTL.
TextDecorationStyle
Style of the text-decoration.
@ Solid
Draw a solid line.Ex: --—.
TextDecorationUnderlinePosition
Which location to choose for the underline.
@ UnderlineAuto
Use Font metrics.
TextDecoration
Flags for text-decoration, for underline, overline and strikethrough.
Direction
Base direction used by Bidi algorithm.
Baseline
Baseline values used by dominant-baseline and baseline-align.
@ BidiNormal
No new bidi-level is started.
@ BidiIsolate
Content is ordered as if in a separate paragraph.
@ Preserve
Do not collapse any space.
LineEdgeBehaviour lineStart
QPointF totalBaselineOffset() const
QRectF inkBoundingBox
The bounds of the drawn glyph. Different from the bounds the charresult takes up in the layout,...
KoSvgText::TextAnchor anchor
qreal scaledDescent
Descender, in pt.
QPointF finalPosition
the final position, taking into account both CSS and SVG positioning considerations.
KoSvgText::FontMetrics metrics
Fontmetrics for current font, in Freetype scanline coordinates.
bool justifyAfter
Justification Opportunity follows this character.
KoSvgText::Direction direction
bool justifyBefore
Justification Opportunity precedes this character.
std::optional< qreal > tabSize
If present, this is a tab and it should align to multiples of this tabSize value.
QRectF lineHeightBox() const
lineHeightBox
qreal extraFontScaling
Freetype doesn't allow us to scale below 1pt, so we need to do an extra transformation in these cases...
bool anchored_chunk
whether this is the start of a new chunk.
QPointF dominantBaselineOffset
LineEdgeBehaviour lineEnd
void scaleCharacterResult(qreal xScale, qreal yScale)
scaleCharacterResult convenience function to scale the whole character result.
qreal scaledAscent
Ascender, in pt.
void calculateAndApplyTabsize(QPointF currentPos, bool isHorizontal, const KoSvgText::ResolutionHandler &resHandler)
bool isHorizontal
Whether the current glyph lays out horizontal or vertical. Currently same as paragraph,...
QPointF textPathAndAnchoringOffset
Offset caused by textPath and anchoring.
QPointF cssPosition
the position in accordance with the CSS specs, as opossed to the SVG spec.
qreal scaledHalfLeading
Leading for both sides, can be either negative or positive, in pt.
qreal fontHalfLeading
Leading for both sides, can be either negative or positive.
QRectF layoutBox() const
layoutBox
void translateOrigin(QPointF newOrigin)
translateOrigin For dominant baseline, we want to move the glyph origin. This encompassed the glyph,...
QPointF textLengthOffset
offset caused by textLength
QTransform finalTransform() const
QLineF caret
Caret for this characterResult.
bool rtl
Whether the current glyph is right-to-left, as opposed to the markup.
QVector< int > graphemeIndices
The text-string indices of graphemes starting here, starting grapheme is not present.
QColor color
Which color the current position has.
QVector< QPointF > offsets
The advance offsets for each grapheme index.
int cluster
Which character result this position belongs in.
bool synthetic
Whether this position was inserted to have a visual indicator.
int index
Which grapheme this position belongs with.
int offset
Which offset this position belongs with.
QVector< QRectF > drawRects
QVector< bool > replaceWithForeGroundColor
QVector< QPainterPath > paths
qreal bottom
Bottom inset.
The KoSvgTextContentElement struct.
void removeText(int &start, int length)
removeText removes text,
KoSvgTextProperties properties
The textProperties. This includes.
QString textPathId
The textpath's name, if any.
QString text
Plain text of the current node. Use insertText and removeText to manipulate it.
KoSvgText::TextOnPathInfo textPathInfo
Text path info for the text-on-path algorithm.
QRectF originalBoundingRect
BulkActionState(QRectF originalBoundingRectArg)
boost::optional< qreal > yPos
boost::optional< qreal > dxPos
boost::optional< qreal > dyPos
boost::optional< qreal > rotate
boost::optional< qreal > xPos
The FontMetrics class A class to keep track of a variety of font metrics. Note that values are in Fre...
void scaleBaselines(const qreal multiplier)
The ResolutionHandler class.
QPointF adjustCeil(const QPointF point) const
Adjusts the point to ceiled pixel values.
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.
LineBox(QVector< QLineF > lineWidths, bool ltr, QPointF indent, const KoSvgText::ResolutionHandler &resHandler)
void setCurrentChunk(LineChunk chunk)
QPointF baselineTop
Used to identify the top of the line for baseline-alignment.
void setCurrentChunkForPos(QPointF pos, bool isHorizontal)
void clearAndAdjust(bool isHorizontal, QPointF current, QPointF indent)
qreal expectedLineTop
Because fonts can affect lineheight mid-line, and this affects wrapping, this estimates the line-heig...
QVector< LineChunk > chunks
QPointF baselineBottom
Used to identify the bottom of the line for baseline-alignment.
LineBox(QPointF start, QPointF end, const KoSvgText::ResolutionHandler &resHandler)
QPointF conditionalHangEnd
QVector< int > chunkIndices
charResult indices that belong to this chunk.
QLineF length
Used to measure how long the current line is allowed to be.
KisForest< KoSvgTextContentElement >::child_iterator associatedLeaf
SubChunk(KisForest< KoSvgTextContentElement >::child_iterator leaf)
QSharedPointer< KoShapeBackground > bg
KoSvgTextProperties inheritedProps
QVector< QPair< int, int > > newToOldPositions
For transformed strings, we need to know which.