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;
579 bool isLoading =
false;
581 bool disableFontMatching =
false;
591 QPointF initialTextPosition = QPointF();
596 const FT_Int32 faceLoadFlags,
597 const bool isHorizontal,
598 const char32_t firstCodepoint,
600 raqm_glyph_t ¤tGlyph,
602 QPointF &totalAdvanceFTFontCoordinates);
605 const bool isHorizontal,
606 raqm_glyph_t ¤tGlyph);
609 FT_Int32 faceLoadFlags,
611 raqm_glyph_t ¤tGlyph,
627 const QPainterPath &path,
637 const bool isHorizontal,
638 const bool disableFontMatching);
645 const QMap<int, int>& logicalToVisual,
648 qreal textPathoffset,
658 const bool isHorizontal,
659 const KoSvgText::TextDecorations &decor,
661 const bool textDecorationSkipInset =
false,
663 const qreal currentTextPathOffset = 0.0,
664 const bool textPathSide =
false,
668 QPainterPath decorationPath,
669 const QPointF offset,
670 const QPainterPathStroker &stroker,
672 QMap<KoSvgText::TextDecoration, QPainterPath> &decorationPaths,
674 const bool isHorizontal,
675 const qreal currentTextPathOffset,
676 const bool textPathSide
680 const QPainterPath &outlineRect,
685 const QPainterPath &outlineRect,
700 int count = parent->numChars(withControls, props);
702 count += numChars(it, withControls, props);
728 bool skipZeroWidth =
false)
732 if (childCount(siblingCurrent(it)) > 0) {
735 int length = it->numChars(
false);
736 if (
length == 0 && skipZeroWidth) {
740 if (sought == currentIndex || (sought > currentIndex && sought < currentIndex +
length)) {
758 int currentIndex = 0;
761 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
764 bool suitableStartIndex = siblingCurrent(contentElement) == tree.
childBegin()? index >= currentIndex: index > currentIndex;
765 bool suitableEndIndex = siblingCurrent(contentElement) == tree.
childBegin()?
true: index < currentIndex + contentElement->numChars(
false);
767 if (suitableStartIndex && suitableEndIndex) {
769 duplicate.
text = contentElement->text;
770 int start = index - currentIndex;
771 int length = contentElement->numChars(
false) - start;
775 if (!allowEmptyText && (duplicate.
text.isEmpty() ||
length == 0)) {
781 if (siblingCurrent(contentElement) != tree.
childBegin()
782 && contentElement->textPathId.isEmpty()
783 && contentElement->textLength.isAuto
784 && contentElement->localTransformations.isEmpty()) {
785 contentElement->removeText(zero, start);
787 tree.
insert(siblingCurrent(contentElement), duplicate);
790 duplicate2.
text = contentElement->text;
792 contentElement->text.clear();
793 tree.
insert(childBegin(contentElement), duplicate);
794 tree.
insert(childEnd(contentElement), duplicate2);
809 splitContentElement(tree, index,
false);
810 int currentIndex = 0;
811 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
815 if (siblingCurrent(contentElement) == tree.
childBegin())
return;
817 auto lastNode = siblingCurrent(contentElement);
820 if (lastNode == siblingCurrent(parentIt))
continue;
821 if (siblingCurrent(parentIt) == tree.
childBegin()) {
825 if (lastNode != childBegin(siblingCurrent(parentIt))) {
828 if (textPathAfterSplit) {
831 parentIt->textPathId = QString();
834 auto insert = siblingCurrent(parentIt);
836 auto it = tree.
insert(insert, duplicate);
839 for (
auto child = lastNode; child != childEnd(siblingCurrent(parentIt)); child++) {
840 movableChildren.append(child);
842 while(!movableChildren.isEmpty()) {
843 auto child = movableChildren.takeLast();
844 tree.
move(child, childBegin(it));
848 lastNode = siblingCurrent(parentIt);
865 if (!child.
node())
return childEnd(root);
867 for (
auto rootChild = childBegin(root); rootChild != childEnd(root); rootChild++) {
870 if (siblingCurrent(leaf) == child) {
875 return childEnd(root);
887 QMap<int, KoSvgText::TextSpaceCollapse> collapseModes;
894 parentProps.append(ownProperties);
896 const int children = childCount(siblingCurrent(it));
898 QString text = it->text;
899 if (includeBidiControls) {
904 text += it->getTransformedString(positions, parentProps.last());
908 collapseModes.insert(allText.size(), collapse);
912 parentProps.pop_back();
917 if (alsoCollapseLowSurrogate) {
918 for (
int i = 0; i < allText.size(); i++) {
919 if (i > 0 && allText.at(i).isLowSurrogate() && allText.at(i-1).isHighSurrogate()) {
940 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
943 removeTransformsImpl(root, 0, start,
length, collapsedCharacters);
952 int currentLength = 0;
953 auto it = childBegin(currentTextElement);
954 if (it != childEnd(currentTextElement)) {
955 for (; it != childEnd(currentTextElement); it++) {
956 currentLength += removeTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters);
959 currentLength = currentTextElement->text.size();
962 if (!currentTextElement->localTransformations.isEmpty()) {
963 int transformOffset = 0;
964 int transformOffsetEnd = 0;
966 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
967 if (i >= collapsedCharacters.size())
break;
969 transformOffset += collapsedCharacters.at(i)? 0: 1;
972 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
977 if (transformOffset < currentTextElement->localTransformations.size()) {
978 int length = qBound(0, transformOffsetEnd-transformOffset, qMax(0, currentTextElement->localTransformations.size()-transformOffset));
979 currentTextElement->localTransformations.remove(transformOffset,
984 return currentLength;
998 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
1001 insertTransformsImpl(root, 0, start,
length, collapsedCharacters, allowSkipFirst);
1009 int currentLength = 0;
1010 auto it = childBegin(currentTextElement);
1011 if (it != childEnd(currentTextElement)) {
1012 for (; it != childEnd(currentTextElement); it++) {
1013 currentLength += insertTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters, allowSkipFirst);
1016 currentLength = currentTextElement->text.size();
1019 if (!currentTextElement->localTransformations.isEmpty()) {
1020 int transformOffset = 0;
1021 int transformOffsetEnd = 0;
1023 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
1025 transformOffset += collapsedCharacters.at(i)? 0: 1;
1027 if (i < start +
length) {
1028 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
1035 if (transformOffset == 0 && allowSkipFirst && currentTextElement->localTransformations.at(0).startsNewChunk()) {
1036 transformOffset += 1;
1039 if (transformOffset < currentTextElement->localTransformations.size()) {
1040 for (
int i = transformOffset; i < transformOffsetEnd; i++) {
1046 return currentLength;
1061 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, allText,
false);
1063 auto end = std::make_reverse_iterator(tree.
childBegin());
1064 auto begin = std::make_reverse_iterator(tree.
childEnd());
1066 for (; begin != end; begin++) {
1067 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1069 if (convertToPreWrapped) {
1076 auto base = current.base();
1081 if(base != siblingEnd(base)) {
1082 auto end = std::make_reverse_iterator(childBegin(base));
1083 auto begin = std::make_reverse_iterator(childEnd(base));
1084 for (; begin != end; begin++) {
1085 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1089 if (!current->text.isEmpty()) {
1090 const int total = current->text.size();
1091 QString currentText = allText.right(total);
1093 for (
int i = 0; i < total; i++) {
1094 const int j = total - (i+1);
1095 const bool col = collapsed.takeLast();
1097 currentText.remove(j, 1);
1101 current->text = currentText;
1102 allText.chop(total);
1104 if (convertToPreWrapped) {
1112 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, all,
false, includeBidiControls);
1114 int globalIndex = 0;
1123 resolveTransforms(tree.
childBegin(), all, result, globalIndex,
1124 isHorizontal, isWrapped,
false, resolvedTransforms,
1127 return resolvedTransforms;
1140 auto end = std::make_reverse_iterator(tree.
childBegin());
1141 auto begin = std::make_reverse_iterator(tree.
childEnd());
1143 bool inTextPath =
false;
1144 for (; begin != end; begin++) {
1145 insertNewLinesAtAnchorsImpl(begin, resolvedTransforms, inTextPath);
1153 inTextPath = (!current->textPathId.isEmpty());
1154 auto base = current.base();
1156 if(base != siblingEnd(base)) {
1157 auto end = std::make_reverse_iterator(childBegin(base));
1158 auto begin = std::make_reverse_iterator(childEnd(base));
1159 for (; begin != end; begin++) {
1160 insertNewLinesAtAnchorsImpl(begin,
1166 if (!current->text.isEmpty()) {
1167 const int total = current->text.size();
1169 for (
int i = 0; i < total; i++) {
1170 const int j = total - (i+1);
1178 bool startsNewChunk = transform.startsNewChunk() && j == 0;
1182 startsNewChunk =
false;
1186 if (startsNewChunk && !resolvedTransforms.isEmpty() && current->text.at(j) != QChar::LineFeed) {
1187 current->text.insert(j,
"\n");
1191 current->localTransformations.clear();
1195 for (
int i = 0; i< layout.size(); i++) {
1197 if (layout.at(i).anchored_chunk) {
1198 int plainTextIndex = layout.at(i).plaintTextIndex;
1199 splitContentElement(tree, plainTextIndex);
1203 int globalIndex = 0;
1214 int &globalIndex,
bool isHorizontal) {
1217 if (!current->textPathId.isEmpty())
return;
1218 for (
auto it = childBegin(current); it!= childEnd(current); it++) {
1219 setTransformsFromLayoutImpl(it, props, layout, globalIndex, isHorizontal);
1222 if (current->text.isEmpty()) {
1223 current->localTransformations.clear();
1226 const int length = current->numChars(
true, props);
1228 for (
int i = globalIndex; i< globalIndex+
length; i++) {
1239 qreal shift = anchoredChunkShift(layout, isHorizontal, i, endIndex);
1240 QPointF offset = isHorizontal? QPointF(shift, 0): QPointF(0, shift);
1247 transform.
dxPos = offset.x();
1248 transform.
dyPos = offset.y();
1252 transforms.append(transform);
1254 current->localTransformations = transforms;
1255 current->text = current->text.split(
"\n").join(
" ");
1269 const int children = childCount(current);
1270 if (children == 0) {
1271 const int length = current->numChars(
false);
1272 if (
length == 0 && current != tree.
childBegin() && current->textPathId.isEmpty()) {
1276 auto siblingPrev = current;
1280 while (!isEnd(siblingPrev) && siblingPrev->text.isEmpty()) {
1285 if (!isEnd(siblingPrev)
1286 && siblingPrev != current
1287 && (siblingPrev->localTransformations.isEmpty() && current->localTransformations.isEmpty())
1288 && (siblingPrev->textPathId.isEmpty() && current->textPathId.isEmpty())
1289 && (siblingPrev->textLength.isAuto && current->textLength.isAuto)
1290 && (siblingPrev->properties == current->properties)
1292 && childCount(siblingPrev) == 0) {
1294 siblingPrev->text += current->text;
1295 current->text = QString();
1299 }
else if (children == 1) {
1301 auto child = childBegin(current);
1302 if ((child->localTransformations.isEmpty() && current->localTransformations.isEmpty())
1303 && (child->textPathId.isEmpty() && current->textPathId.isEmpty())
1304 && (child->textLength.isAuto && current->textLength.isAuto)
1305 && (!child->properties.hasNonInheritableProperties() || !current->properties.hasNonInheritableProperties())) {
1306 if (current->properties.hasNonInheritableProperties()) {
1309 child->properties = props;
1311 child->
properties.inheritFrom(current->properties);
1318 for (
auto child = childBegin(current); child != childEnd(current); child++) {
1319 if (cleanUpImpl(tree, child)) {
1320 deleteList.append(child);
1323 while (!deleteList.isEmpty()) {
1324 auto child = deleteList.takeFirst();
1328 if (childCount(current) <= 1) {
1330 return cleanUpImpl(tree, current);
1351 if (treeIndex.isEmpty())
return parent;
1353 int count = idx.takeFirst();
1357 return iteratorForTreeIndex(idx, child);
1372 if (startIndexOfIterator(child,
target, currentIndex)) {
1376 currentIndex += numChars(child);
1389 for (
auto it = childBegin(parent); it != childEnd(parent); it++) {
1390 if (it->textPathId == name) {
1391 it->textPathId = QString();
1398 bool textPathNameUnique =
false;
1399 int textPathNumber = textPaths.size();
1400 QString newTextPathName = textPath->
name();
1401 while(!textPathNameUnique) {
1402 textPathNameUnique =
true;
1403 Q_FOREACH(
KoShape *shape, textPaths) {
1404 if (shape->
name() == newTextPathName) {
1405 textPathNameUnique =
false;
1406 textPathNumber += 1;
1410 if (textPathNameUnique && !newTextPathName.isEmpty()) {
1411 textPath->
setName(newTextPathName);
1413 textPathNameUnique =
false;
1415 newTextPathName = QString(
"textPath"+QString::number(textPathNumber));
1438 QRectF bb = it->associatedOutline.boundingRect();
1439 QMap<KoSvgText::TextDecoration, QPainterPath> decorations = it->textDecorations;
1440 for (
int i = 0; i < decorations.values().size(); ++i) {
1441 bb |= decorations.values().at(i).boundingRect();
1443 if (!bb.isEmpty()) {
1444 if (stroke && includeStrokeInset) {
1446 stroke->strokeInsets(rootShape, insets);
1454 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)
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.