8#ifndef KO_SVG_TEXT_SHAPE_P_H
9#define KO_SVG_TEXT_SHAPE_P_H
27#include <QPainterPath>
89using Variant = std::variant<std::monostate, Outline, Bitmap, ColorLayers>;
172 if (newOrigin == QPointF())
return;
174 outlineGlyph->path.translate(-newOrigin);
176 for (
int i = 0; i< bitmapGlyph->drawRects.size(); i++) {
177 bitmapGlyph->drawRects[i].translate(-newOrigin);
180 for (
int i = 0; i< colorGlyph->paths.size(); i++) {
181 colorGlyph->paths[i].translate(-newOrigin);
203 QTransform scale = QTransform::fromScale(xScale, yScale);
204 if (scale.isIdentity())
return;
205 const bool scaleToZero = !(xScale > 0 && yScale > 0);
208 if (!outlineGlyph->path.isEmpty()) {
210 outlineGlyph->path = QPainterPath();
212 outlineGlyph->path = scale.map(outlineGlyph->path);
217 bitmapGlyph->drawRects.clear();
218 bitmapGlyph->images.clear();
220 for (
int i = 0; i< bitmapGlyph->drawRects.size(); i++) {
221 bitmapGlyph->drawRects[i] = scale.mapRect(bitmapGlyph->drawRects[i]);
225 for (
int i = 0; i< colorGlyph->paths.size(); i++) {
227 colorGlyph->paths[i] = QPainterPath();
229 colorGlyph->paths[i] = scale.map(colorGlyph->paths[i]);
318 Q_FOREACH(QLineF line, lineWidths) {
325 Q_FOREACH(QLineF line, lineWidths) {
384 for (
int i=0; i<
chunks.size(); i++) {
389 if ((pos.x() < max) &&
397 if ((pos.y() < max) &&
407 if (
chunks.isEmpty())
return true;
408 for (
int i =0; i <
chunks.size(); i++) {
409 if (!
chunks.at(i).chunkIndices.isEmpty())
return false;
448 shapeGroup->setSelectable(
false);
460 , textData(rhs.textData)
466 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesInside, shapesInside);
467 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesSubtract, shapesSubtract);
468 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.textPaths, textPaths);
469 updateInternalShapesList();
474 lineBoxes = rhs.lineBoxes;
476 cursorPos = rhs.cursorPos;
477 logicalToVisualCursorPos = rhs.logicalToVisualCursorPos;
478 plainText = rhs.plainText;
480 initialTextPosition = rhs.initialTextPosition;
482 isLoading = rhs.isLoading;
483 disableFontMatching = rhs.disableFontMatching;
485 currentTextWrappingAreas = rhs.currentTextWrappingAreas;
489 for (
int i = 0; i<sourceShapeList.size(); i++) {
490 if (referenceShapeList.contains(referenceList2.at(i))) {
491 destinationShapeList.append(sourceShapeList.at(i));
498 internalShapesPainter.reset();
499 Q_FOREACH(
KoShape *shape, shapeGroup->shapes()) {
500 shapeGroup->removeShape(shape);
503 qDeleteAll(shapesInside);
504 shapesInside.clear();
505 qDeleteAll(shapesSubtract);
506 shapesSubtract.clear();
507 qDeleteAll(textPaths);
518 return internalShapesPainter->internalShapeManager()->shapes();
522 Q_FOREACH(
KoShape *shape, shapeGroup->shapes()) {
523 shapeGroup->removeShape(shape);
525 Q_FOREACH(
KoShape *shape, shapesInside) {
526 shapeGroup->addShape(shape);
528 Q_FOREACH(
KoShape *shape, shapesSubtract) {
529 shapeGroup->addShape(shape);
531 Q_FOREACH(
KoShape *shape, textPaths) {
532 shapeGroup->addShape(shape);
534 updateTextWrappingAreas();
535 updateInternalShapesList();
539 internalShapesPainter->setShapes(shapeGroup->shapes());
544 BulkActionState(QRectF originalBoundingRectArg) : originalBoundingRect(originalBoundingRectArg) {}
547 bool contourHasChanged =
false;
548 bool layoutHasChanged =
false;
551 return contourHasChanged || layoutHasChanged;
572 auto it = std::find_if(textPaths.begin(), textPaths.end(), [&name](
const KoShape *s) ->
bool {return s->name() == name;});
573 return it != textPaths.end()? *it:
nullptr;
577 bool isLoading =
false;
579 bool disableFontMatching =
false;
589 QPointF initialTextPosition = QPointF();
594 const FT_Int32 faceLoadFlags,
595 const bool isHorizontal,
596 const char32_t firstCodepoint,
598 raqm_glyph_t ¤tGlyph,
600 QPointF &totalAdvanceFTFontCoordinates);
603 const bool isHorizontal,
604 raqm_glyph_t ¤tGlyph);
607 FT_Int32 faceLoadFlags,
609 raqm_glyph_t ¤tGlyph,
625 const QPainterPath &path,
635 const bool isHorizontal,
636 const bool disableFontMatching);
643 const QMap<int, int>& logicalToVisual,
646 qreal textPathoffset,
656 const bool isHorizontal,
657 const KoSvgText::TextDecorations &decor,
659 const bool textDecorationSkipInset =
false,
661 const qreal currentTextPathOffset = 0.0,
662 const bool textPathSide =
false,
666 QPainterPath decorationPath,
667 const QPointF offset,
668 const QPainterPathStroker &stroker,
670 QMap<KoSvgText::TextDecoration, QPainterPath> &decorationPaths,
672 const bool isHorizontal,
673 const qreal currentTextPathOffset,
674 const bool textPathSide
678 const QPainterPath &outlineRect,
683 const QPainterPath &outlineRect,
698 int count = parent->numChars(withControls, props);
700 count += numChars(it, withControls, props);
726 bool skipZeroWidth =
false)
730 if (childCount(siblingCurrent(it)) > 0) {
733 int length = it->numChars(
false);
734 if (
length == 0 && skipZeroWidth) {
738 if (sought == currentIndex || (sought > currentIndex && sought < currentIndex +
length)) {
756 int currentIndex = 0;
759 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
762 bool suitableStartIndex = siblingCurrent(contentElement) == tree.
childBegin()? index >= currentIndex: index > currentIndex;
763 bool suitableEndIndex = siblingCurrent(contentElement) == tree.
childBegin()?
true: index < currentIndex + contentElement->numChars(
false);
765 if (suitableStartIndex && suitableEndIndex) {
767 duplicate.
text = contentElement->text;
768 int start = index - currentIndex;
769 int length = contentElement->numChars(
false) - start;
773 if (!allowEmptyText && (duplicate.
text.isEmpty() ||
length == 0)) {
779 if (siblingCurrent(contentElement) != tree.
childBegin()
780 && contentElement->textPathId.isEmpty()
781 && contentElement->textLength.isAuto
782 && contentElement->localTransformations.isEmpty()) {
783 contentElement->removeText(zero, start);
785 tree.
insert(siblingCurrent(contentElement), duplicate);
788 duplicate2.
text = contentElement->text;
790 contentElement->text.clear();
791 tree.
insert(childBegin(contentElement), duplicate);
792 tree.
insert(childEnd(contentElement), duplicate2);
807 splitContentElement(tree, index,
false);
808 int currentIndex = 0;
809 auto contentElement = depth(tree) == 1? tree.
depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index,
true);
813 if (siblingCurrent(contentElement) == tree.
childBegin())
return;
815 auto lastNode = siblingCurrent(contentElement);
818 if (lastNode == siblingCurrent(parentIt))
continue;
819 if (siblingCurrent(parentIt) == tree.
childBegin()) {
823 if (lastNode != childBegin(siblingCurrent(parentIt))) {
826 if (textPathAfterSplit) {
829 parentIt->textPathId = QString();
832 auto insert = siblingCurrent(parentIt);
834 auto it = tree.
insert(insert, duplicate);
837 for (
auto child = lastNode; child != childEnd(siblingCurrent(parentIt)); child++) {
838 movableChildren.append(child);
840 while(!movableChildren.isEmpty()) {
841 auto child = movableChildren.takeLast();
842 tree.
move(child, childBegin(it));
846 lastNode = siblingCurrent(parentIt);
863 if (!child.
node())
return childEnd(root);
865 for (
auto rootChild = childBegin(root); rootChild != childEnd(root); rootChild++) {
868 if (siblingCurrent(leaf) == child) {
873 return childEnd(root);
885 QMap<int, KoSvgText::TextSpaceCollapse> collapseModes;
892 parentProps.append(ownProperties);
894 const int children = childCount(siblingCurrent(it));
896 QString text = it->text;
897 if (includeBidiControls) {
902 text += it->getTransformedString(positions, parentProps.last());
906 collapseModes.insert(allText.size(), collapse);
910 parentProps.pop_back();
915 if (alsoCollapseLowSurrogate) {
916 for (
int i = 0; i < allText.size(); i++) {
917 if (i > 0 && allText.at(i).isLowSurrogate() && allText.at(i-1).isHighSurrogate()) {
938 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
941 removeTransformsImpl(root, 0, start,
length, collapsedCharacters);
950 int currentLength = 0;
951 auto it = childBegin(currentTextElement);
952 if (it != childEnd(currentTextElement)) {
953 for (; it != childEnd(currentTextElement); it++) {
954 currentLength += removeTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters);
957 currentLength = currentTextElement->text.size();
960 if (!currentTextElement->localTransformations.isEmpty()) {
961 int transformOffset = 0;
962 int transformOffsetEnd = 0;
964 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
965 if (i >= collapsedCharacters.size())
break;
967 transformOffset += collapsedCharacters.at(i)? 0: 1;
970 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
975 if (transformOffset < currentTextElement->localTransformations.size()) {
976 int length = qBound(0, transformOffsetEnd-transformOffset, qMax(0, currentTextElement->localTransformations.size()-transformOffset));
977 currentTextElement->localTransformations.remove(transformOffset,
982 return currentLength;
996 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all,
true);
999 insertTransformsImpl(root, 0, start,
length, collapsedCharacters, allowSkipFirst);
1007 int currentLength = 0;
1008 auto it = childBegin(currentTextElement);
1009 if (it != childEnd(currentTextElement)) {
1010 for (; it != childEnd(currentTextElement); it++) {
1011 currentLength += insertTransformsImpl(it, globalIndex + currentLength, start,
length, collapsedCharacters, allowSkipFirst);
1014 currentLength = currentTextElement->text.size();
1017 if (!currentTextElement->localTransformations.isEmpty()) {
1018 int transformOffset = 0;
1019 int transformOffsetEnd = 0;
1021 for (
int i = globalIndex; i < globalIndex + currentLength; i++) {
1023 transformOffset += collapsedCharacters.at(i)? 0: 1;
1025 if (i < start +
length) {
1026 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
1033 if (transformOffset == 0 && allowSkipFirst && currentTextElement->localTransformations.at(0).startsNewChunk()) {
1034 transformOffset += 1;
1037 if (transformOffset < currentTextElement->localTransformations.size()) {
1038 for (
int i = transformOffset; i < transformOffsetEnd; i++) {
1044 return currentLength;
1059 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, allText,
false);
1061 auto end = std::make_reverse_iterator(tree.
childBegin());
1062 auto begin = std::make_reverse_iterator(tree.
childEnd());
1064 for (; begin != end; begin++) {
1065 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1067 if (convertToPreWrapped) {
1074 auto base = current.base();
1079 if(base != siblingEnd(base)) {
1080 auto end = std::make_reverse_iterator(childBegin(base));
1081 auto begin = std::make_reverse_iterator(childEnd(base));
1082 for (; begin != end; begin++) {
1083 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1087 if (!current->text.isEmpty()) {
1088 const int total = current->text.size();
1089 QString currentText = allText.right(total);
1091 for (
int i = 0; i < total; i++) {
1092 const int j = total - (i+1);
1093 const bool col = collapsed.takeLast();
1095 currentText.remove(j, 1);
1099 current->text = currentText;
1100 allText.chop(total);
1102 if (convertToPreWrapped) {
1110 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, all,
false, includeBidiControls);
1112 int globalIndex = 0;
1121 resolveTransforms(tree.
childBegin(), all, result, globalIndex,
1122 isHorizontal, isWrapped,
false, resolvedTransforms,
1125 return resolvedTransforms;
1138 auto end = std::make_reverse_iterator(tree.
childBegin());
1139 auto begin = std::make_reverse_iterator(tree.
childEnd());
1141 bool inTextPath =
false;
1142 for (; begin != end; begin++) {
1143 insertNewLinesAtAnchorsImpl(begin, resolvedTransforms, inTextPath);
1151 inTextPath = (!current->textPathId.isEmpty());
1152 auto base = current.base();
1154 if(base != siblingEnd(base)) {
1155 auto end = std::make_reverse_iterator(childBegin(base));
1156 auto begin = std::make_reverse_iterator(childEnd(base));
1157 for (; begin != end; begin++) {
1158 insertNewLinesAtAnchorsImpl(begin,
1164 if (!current->text.isEmpty()) {
1165 const int total = current->text.size();
1167 for (
int i = 0; i < total; i++) {
1168 const int j = total - (i+1);
1176 bool startsNewChunk = transform.startsNewChunk() && j == 0;
1180 startsNewChunk =
false;
1184 if (startsNewChunk && !resolvedTransforms.isEmpty() && current->text.at(j) != QChar::LineFeed) {
1185 current->text.insert(j,
"\n");
1189 current->localTransformations.clear();
1193 for (
int i = 0; i< layout.size(); i++) {
1195 if (layout.at(i).anchored_chunk) {
1196 int plainTextIndex = layout.at(i).plaintTextIndex;
1197 splitContentElement(tree, plainTextIndex);
1201 int globalIndex = 0;
1212 int &globalIndex,
bool isHorizontal) {
1215 if (!current->textPathId.isEmpty())
return;
1216 for (
auto it = childBegin(current); it!= childEnd(current); it++) {
1217 setTransformsFromLayoutImpl(it, props, layout, globalIndex, isHorizontal);
1220 if (current->text.isEmpty()) {
1221 current->localTransformations.clear();
1224 const int length = current->numChars(
true, props);
1226 for (
int i = globalIndex; i< globalIndex+
length; i++) {
1237 qreal shift = anchoredChunkShift(layout, isHorizontal, i, endIndex);
1238 QPointF offset = isHorizontal? QPointF(shift, 0): QPointF(0, shift);
1245 transform.
dxPos = offset.x();
1246 transform.
dyPos = offset.y();
1250 transforms.append(transform);
1252 current->localTransformations = transforms;
1253 current->text = current->text.split(
"\n").join(
" ");
1268 const int children = childCount(siblingCurrent(it));
1269 if (children == 0) {
1272 const int length = it->numChars(
false);
1273 if (
length == 0 && siblingCurrent(it) != tree.
childBegin() && it->textPathId.isEmpty()) {
1274 tree.
erase(siblingCurrent(it));
1277 auto siblingPrev = siblingCurrent(it);
1281 if (!isEnd(siblingPrev)
1282 && siblingPrev != siblingCurrent(it)
1283 && (siblingPrev->localTransformations.isEmpty() && it->localTransformations.isEmpty())
1284 && (siblingPrev->textPathId.isEmpty() && it->textPathId.isEmpty())
1285 && (siblingPrev->textLength.isAuto && it->textLength.isAuto)
1286 && (siblingPrev->properties == it->properties)
1288 && childCount(siblingPrev) == 0) {
1290 siblingPrev->text += it->text;
1291 tree.
erase(siblingCurrent(it));
1294 }
else if (children == 1) {
1296 auto child = childBegin(siblingCurrent(it));
1297 if ((child->localTransformations.isEmpty() && it->localTransformations.isEmpty())
1298 && (child->textPathId.isEmpty() && it->textPathId.isEmpty())
1299 && (child->textLength.isAuto && it->textLength.isAuto)
1300 && (!child->properties.hasNonInheritableProperties() || !it->properties.hasNonInheritableProperties())) {
1301 if (it->properties.hasNonInheritableProperties()) {
1304 child->properties = props;
1306 child->
properties.inheritFrom(it->properties);
1308 tree.
move(child, siblingCurrent(it));
1309 tree.
erase(siblingCurrent(it));
1316 if (treeIndex.isEmpty())
return parent;
1318 int count = idx.takeFirst();
1322 return iteratorForTreeIndex(idx, child);
1337 if (startIndexOfIterator(child,
target, currentIndex)) {
1341 currentIndex += numChars(child);
1354 for (
auto it = childBegin(parent); it != childEnd(parent); it++) {
1355 if (it->textPathId == name) {
1356 it->textPathId = QString();
1363 bool textPathNameUnique =
false;
1364 int textPathNumber = textPaths.size();
1365 QString newTextPathName = textPath->
name();
1366 while(!textPathNameUnique) {
1367 textPathNameUnique =
true;
1368 Q_FOREACH(
KoShape *shape, textPaths) {
1369 if (shape->
name() == newTextPathName) {
1370 textPathNameUnique =
false;
1371 textPathNumber += 1;
1375 if (textPathNameUnique && !newTextPathName.isEmpty()) {
1376 textPath->
setName(newTextPathName);
1378 textPathNameUnique =
false;
1380 newTextPathName = QString(
"textPath"+QString::number(textPathNumber));
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.
@ WritingModeId
KoSvgText::WritingMode.
@ DirectionId
KoSvgText::Direction.
@ TextWrapId
KoSvgText::TextWrap.
QList< PropertyId > properties() const
static const KoSvgTextProperties & defaultProperties()
bool hasProperty(PropertyId id) const
void setAllButNonInheritableProperties(const KoSvgTextProperties &properties)
Used to merge child properties into parent properties.
QVariant propertyOrDefault(PropertyId id) const
void inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve=false)
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 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)
KoShape * collectPaths(const KoShape *rootShape, QVector< CharacterResult > &result, int ¤tIndex)
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 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)
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...
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
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...
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.