Krita Source Code Documentation
Loading...
Searching...
No Matches
KoSvgTextShape Class Reference

#include <KoSvgTextShape.h>

+ Inheritance diagram for KoSvgTextShape:

Classes

struct  BulkActionState
 
struct  TextCursorChangeListener
 ShapeChangeListener so we can inform any text cursors that the cursor needs updating. More...
 

Public Types

enum class  DebugElement { CharBbox = 1 << 0 , LineBox = 1 << 1 }
 
enum  InternalShapeState { Decorative , ShapeInside , ShapeSubtract , TextPath }
 
enum  TextType { PrePositionedText = 0 , PreformattedText , InlineWrap , TextInShape }
 
- Public Types inherited from KoShape
enum  ChangeType {
  PositionChanged , RotationChanged , ScaleChanged , ShearChanged ,
  SizeChanged , GenericMatrixChange , KeepAspectRatioChange , ParentChanged ,
  Deleted , StrokeChanged , BackgroundChanged , BorderChanged ,
  ParameterChanged , ContentChanged , TextContourMarginChanged , ChildChanged ,
  ConnectionPointChanged , ClipPathChanged , ClipMaskChanged , TransparencyChanged
}
 Used by shapeChanged() to select which change was made. More...
 
enum  ChildZOrderPolicy { ChildZDefault , ChildZParentChild = ChildZDefault , ChildZPassThrough }
 Used by compareShapeZIndex() to order shapes. More...
 
enum  PaintOrder { Fill , Stroke , Markers }
 

Public Member Functions

void addShapeContours (QList< KoShape * > shapes, const bool inside=true)
 addShapesContours Add shapes to the contours that make up the wrapping area.
 
void addTextPathAtEnd (KoShape *textPath)
 addTextPathAtEnd add a textpath node at the end of the text.
 
void applyTextLength (KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, QVector< CharacterResult > &result, int &currentIndex, int &resolvedDescendentNodes, bool isHorizontal, const KoSvgTextProperties resolvedProps, const KoSvgText::ResolutionHandler &resHandler)
 
void applyWhiteSpace (KisForest< KoSvgTextContentElement > &tree, const bool convertToPreWrapped=false)
 applyWhiteSpace CSS Whitespace processes whitespaces so that duplicate white spaces and unnecessary hard breaks get removed from the text. Within the text layout we avoid removing the white spaces. However, when converting between text types it can be useful to remove these spaces. This function actually applies the white space rule to the active text.
 
void applyWhiteSpaceImpl (std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< bool > &collapsed, QString &allText, const bool convertToPreWrapped)
 
QSharedPointer< KoShapeBackgroundbackground () const override
 
QRectF boundingRect () const override
 Get the bounding box of the shape.
 
void cleanUp ()
 Cleans up the internal text data. Used by undo commands.
 
void clearAssociatedOutlines ()
 
KoShapecloneShape () const override
 creates a deep copy of the shape or shape's subtree
 
KoShapecollectPaths (const KoSvgTextShape *rootShape, QVector< CharacterResult > &result, int &currentIndex)
 
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 &currentIndex, bool isHorizontal, bool ltr, bool wrapping, const KoSvgTextProperties resolvedProps, QList< KoShape * > textPaths)
 
void convertCharTransformsToPreformatted (bool makeInlineSize=false)
 convertCharTransformsToPreformatted Converts the text to a preformatted SVG 2.0 text. This changes the textType();
 
std::unique_ptr< KoSvgTextShapecopyRange (int index, int length) const
 copyRange Copy the rich text for the given range.
 
KoSvgTextNodeIndex createTextNodeIndex (KisForest< KoSvgTextContentElement >::child_iterator textElement) const
 
QPainterPath cursorForPos (int pos, QLineF &caret, QColor &color, double bidiFlagSize=1.0)
 cursorForPos returns the QPainterPath associated with this cursorPosition.
 
void debugParsing ()
 Outputs debug with the current textData tree.
 
KoSvgText::Direction direction () const
 direction Whether the text is left to right or right to left.
 
QRectF endBulkAction () override
 
void enterNodeSubtree ()
 Set the current node to its first child, entering the subtree.
 
KoSvgTextNodeIndex findNodeIndexForPropertyId (KoSvgTextProperties::PropertyId propertyId)
 findNodeIndexForPropertyId
 
QPair< int, int > findRangeForNodeIndex (const KoSvgTextNodeIndex &node) const
 findRangeForNodeIndex Find the start and end cursor position for a given nodeIndex.
 
bool fontMatchingDisabled () const
 fontMatchingDisabled
 
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)
 
CursorPos getCursorPos (int pos)
 
KoSvgTextShapeMementoSP getMemento ()
 Get a memento holding the current textdata and layout info.
 
QList< KoSvgTextCharacterInfogetPositionsAndRotationsForRange (const int startPos, const int endPos) const
 getPositionsAndRotationsForRange
 
void handleShapes (const QList< KoShape * > &sourceShapeList, const QList< KoShape * > referenceList2, const QList< KoShape * > referenceShapeList, QList< KoShape * > &destinationShapeList)
 
int indexForPos (int pos) const
 indexForPos get the string index for a given cursor position.
 
QPointF initialTextPosition () const
 initialTextPosition Returns the initial text position as per SVG algorithm. The eventual result of this can include transforms or repositioning due to text shapes.
 
bool insertRichText (int pos, const KoSvgTextShape *richText, bool inheritPropertiesIfPossible=false)
 insertRichText Insert rich text at the given cursor pos. This will first split contents at the given pos before inserting the new rich text.
 
bool insertText (int pos, QString text)
 insertText Insert a text somewhere in the KoTextShape.
 
KoShapeManagerinternalShapeManager () const
 internalShapeManager
 
QList< KoShape * > internalShapes () const
 
 KoSvgTextShape ()
 
 KoSvgTextShape (const KoSvgTextShape &rhs)
 
void leaveNodeSubtree ()
 Set the current node to its parent, leaving the subtree.
 
int lineEnd (int pos)
 lineEnd return the 'line end' for this pos. This uses anchored chunks, so each absolute x, y posititioning will be considered a line-start.
 
int lineStart (int pos)
 lineStart return the 'line start' for this pos. This uses anchored chunks, so each absolute x, y posititioning will be considered a line-start.
 
void mergePropertiesIntoRange (const int startPos, const int endPos, const KoSvgTextProperties properties, const QSet< KoSvgTextProperties::PropertyId > removeProperties=QSet< KoSvgTextProperties::PropertyId >())
 mergePropertiesIntoRange Merge given properties into the given range. This will first split the nodes at the two range ends, and then merge in the properties into each leaf node. Won't do anything when startPos == endPos
 
void moveShapeInsideToIndex (KoShape *shapeInside, const int index)
 moveShapeInsideToIndex Because the order of shapes inside shape-inside affects the text layout, it can be useful to be able to reorder them.
 
int nextIndex (int pos)
 nextIndex Return the first cursor position with a higher string index.
 
int nextLine (int pos)
 nextLine get a position on the next line for this position.
 
KoSvgTextNodeIndex nodeForTextPath (KoShape *textPath) const
 nodeForTextPath TextPaths are set on toplevel content elements. This function allows for searching which node has said textPath, which should be less clunky than running topLevelNodeForPos for every pos.
 
void notifyCursorPosChanged (int pos, int anchor)
 Notify that the cursor position has changed.
 
void notifyMarkupChanged ()
 Notify that the markup has changed.
 
QPainterPath outline () const override
 
QRectF outlineRect () const override
 
void paint (QPainter &painter) const override
 Paint the shape fill The class extending this one is responsible for painting itself. painter is expected to be preconfigured to work in "document" pixels.
 
void paintDebug (QPainter &painter, const QVector< CharacterResult > &result, int &currentIndex)
 
void paintDebug (QPainter &painter, DebugElements elements) const
 
QVector< PaintOrderpaintOrder () const override
 paintOrder
 
void paintPaths (QPainter &painter, const QPainterPath &outlineRect, const KoShape *rootShape, const QVector< CharacterResult > &result, const KoSvgText::TextRendering rendering, QPainterPath &chunk, int &currentIndex)
 
void paintStroke (QPainter &painter) const override
 paintStroke paints the shape's stroked outline
 
void paintTextDecoration (QPainter &painter, const QPainterPath &outlineRect, const KoShape *rootShape, const KoSvgText::TextDecoration type, const KoSvgText::TextRendering rendering)
 
QString plainText ()
 plainText plain text of all text inside this text shape, without the bidi controls or any transforms.
 
int posDown (int pos, bool visual=false)
 return position below.
 
int posForIndex (int index, bool firstIndex=false, bool skipSynthetic=false) const
 posForIndex Get the cursor position for a given index in a string.
 
int posForPoint (QPointF point, int start=-1, int end=-1, bool *overlaps=nullptr)
 posForPoint Finds the closest cursor position for the given point in shape coordinates.
 
int posForPointLineSensitive (QPointF point)
 posForPointLineSensitive When clicking on an empty space in a wrapped text, it is preferable to have the caret be at the end of the line visually associated with that empty space than the positions above or below that might be closer.
 
int posLeft (int pos, bool visual=false)
 
int posRight (int pos, bool visual=false)
 
int posUp (int pos, bool visual=false)
 return position above.
 
int previousIndex (int pos)
 previousIndex Return the first pos which has a lower string index.
 
int previousLine (int pos)
 previousLine get a position on the previous line for this position.
 
 Private ()
 
 Private (const Private &rhs)
 
KoSvgTextProperties propertiesForPos (const int pos, bool inherited=false) const
 Return the properties at a given position.
 
QList< KoSvgTextPropertiespropertiesForRange (const int startPos, const int endPos, bool inherited=false) const
 propertiesForRange get the properties for a range.
 
 Q_DECLARE_FLAGS (DebugElements, DebugElement)
 
void relayout ()
 
void relayout () const
 
bool relayoutIsBlocked () const
 relayoutIsBlocked
 
void removeShapesFromContours (QList< KoShape * > shapes, bool callUpdate=true, bool cleanup=true)
 removeShapesFromContours Remove list of shapes from any of the internal lists.
 
bool removeText (int &index, int &length)
 removeText Where insert text explicitly uses a cursorposition, remove text uses a string index. It will modify these values so that...
 
void removeTransformsFromRange (const int startPos, const int endPos)
 
bool saveHtml (HtmlSavingContext &context)
 
bool saveSvg (SvgSavingContext &context) override
 Saves SVG data.
 
QPainterPath selectionBoxes (int pos, int anchor)
 selectionBoxes returns all selection boxes for a given range. Range will be normalized internally.
 
void setBackground (QSharedPointer< KoShapeBackground > background) override
 
void setCharacterTransformsFromLayout ()
 setCharacterTransformsFromLayout Converts the text to a prepositioned SVG 1.1 text. This changes the textType();
 
bool setCharacterTransformsOnRange (const int startPos, const int endPos, const QVector< QPointF > positions, const QVector< qreal > rotateDegrees, const bool deltaPosition=true)
 setCharacterTransformsOnRange Set SVG 1.1 style character transforms on the given range. Will not work when the shape is auto wrapping.
 
void setFontMatchingDisabled (const bool disable)
 setDisableFontMatching
 
void setMemento (const KoSvgTextShapeMementoSP memento)
 Set the text data and layout info, reset listening cursors to 0.
 
void setMemento (const KoSvgTextShapeMementoSP memento, int pos, int anchor)
 Set the text data, layout info and also adjust any listening cursors.
 
void setPaintOrder (PaintOrder first, PaintOrder second) override
 setPaintOrder set the paint order. As there's only three entries in any given paintorder, you only need to have the first and second entry to set it.
 
void setPropertiesAtPos (int pos, KoSvgTextProperties properties)
 setPropertiesAtPos will set the properties at pos.
 
void setRelayoutBlocked (const bool disable)
 
void setResolution (qreal xRes, qreal yRes) override
 
void setShapesInside (QList< KoShape * > shapesInside)
 setShapesInside
 
void setShapesSubtract (QList< KoShape * > shapesSubtract)
 setShapesSubtract
 
void setSize (const QSizeF &size) override
 Resize the shape.
 
void setStroke (KoShapeStrokeModelSP stroke) override
 
bool setTextPathOnRange (KoShape *textPath, const int startPos=-1, const int endPos=-1)
 setTextPathOnRange Set a text path on the specified range. In SVG text paths are always at the first child.
 
void setTransformsFromLayout (KisForest< KoSvgTextContentElement > &tree, const QVector< CharacterResult > layout)
 
void setTransformsFromLayoutImpl (KisForest< KoSvgTextContentElement >::child_iterator current, const KoSvgTextProperties parentProps, const QVector< CharacterResult > layout, int &globalIndex, bool isHorizontal)
 
bool shapeInContours (KoShape *shape)
 shapeInContours
 
QList< KoShape * > shapesInside () const
 shapesInside
 
QList< KoShape * > shapesSubtract () const
 shapesSubtract
 
QMap< QString, QString > shapeTypeSpecificStyles (SvgSavingContext &context) const
 
bool singleNode () const
 singleNode Sometimes it is useful to know whether there's only a single text node for UX purposes.
 
QSizeF size () const override
 Get the size of the shape in pt.
 
void startBulkAction () override
 
KoShapeStrokeModelSP stroke () const override
 
KoShapetextOutline () const
 textOutline This turns the text object into non-text KoShape(s) to the best of its abilities.
 
QList< KoShape * > textPathsAtRange (const int startPos=-1, const int endPos=-1)
 textPathsAtRange Get a list of textPaths at the given range. This includes textPaths whose node is only partially overlapped by the range.
 
KoSvgTextProperties textProperties () const
 
TextType textType () const
 textType This enum gives an indication of what kind of text this shape is. The different text types are a bit blurry as SVG allows a mixutre to provide fallback information. When such fallback is in place, this will only return the primary text type, that is, TextInShape before InlineWrap and InlineWrap before PrePositioned/Preformatted. This primarily exists to give UI feedback.
 
QList< QPainterPath > textWrappingAreas () const
 textWrappingAreas The text wrapping areas are computed from shapesInside() and shapesSubtract(), as well as the text properties ShapeMargin and ShapePadding. This returns the computed wrapping areas, in the local coordinates of the shape.
 
KoSvgTextNodeIndex topLevelNodeForPos (int pos) const
 topLevelNodeForPos Get, if possible, an index for the child element of the root at pos. If not possible, returns an index for the root. This is used primarily for text-on-path.
 
QPainterPath underlines (int pos, int anchor, KoSvgText::TextDecorations decor, KoSvgText::TextDecorationStyle style, qreal minimum, bool thick)
 
void updateInternalShapesList ()
 
void updateShapeGroup ()
 
void updateTextWrappingAreas ()
 updateShapeContours The current shape contours can be slow to compute, so this function calls computing them, and then calls relayout();
 
int wordEnd (int pos)
 wordEnd return the pos of the first wordbreak.
 
int wordLeft (int pos, bool visual=false)
 wordLeft return the cursorpos for the word left or the extreme of the line.
 
int wordRight (int pos, bool visual=false)
 wordRight return the cursorpos for the word right or the extreme of the line.
 
int wordStart (int pos)
 wordStart return the first pos before a wordbreak in the start direction.
 
KoSvgText::WritingMode writingMode () const
 writingMode There's a number of places we need to check the writing mode to provide proper controls.
 
 ~KoSvgTextShape () override
 
 ~Private ()
 
- Public Member Functions inherited from KoShape
QRectF absoluteOutlineRect () const
 
QPointF absolutePosition (KoFlake::AnchorPosition anchor=KoFlake::Center) const
 
QTransform absoluteTransformation () const
 
bool addDependee (KoShape *shape)
 
QString additionalAttribute (const QString &name) const
 
void addShapeChangeListener (ShapeChangeListener *listener)
 
KoShapeAnchoranchor () const
 
void applyAbsoluteTransformation (const QTransform &matrix)
 
void applyTransformation (const QTransform &matrix)
 
virtual ChildZOrderPolicy childZOrderPolicy ()
 
KoClipMaskclipMask () const
 Returns the currently set clip mask or 0 if there is no clip mask set.
 
KoClipPathclipPath () const
 Returns the currently set clip path or 0 if there is no clip path set.
 
KoShapecloneShapeAndBakeAbsoluteTransform () const
 creates a deep copy of the shape/shapes tree and bakes the absolute transform of this into the resulting shape.
 
void copySettings (const KoShape *shape)
 
QList< KoShape * > dependees () const
 Returns list of shapes depending on this shape.
 
QPointF documentToShape (const QPointF &point) const
 Transforms point from document coordinates to shape coordinates.
 
QRectF documentToShape (const QRectF &rect) const
 Transform rect from document coordinates to shape coordinates.
 
bool hasAdditionalAttribute (const QString &name) const
 
bool hasCommonParent (const KoShape *shape) const
 
bool hasDependee (KoShape *shape) const
 Returns if the given shape is dependent on this shape.
 
virtual bool hasTransparency () const
 
virtual bool hitTest (const QPointF &position) const
 Check if the shape is hit on position.
 
QString hyperLink () const
 
bool inheritBackground () const
 inheritBackground shows if the shape inherits background from its parent
 
bool inheritPaintOrder () const
 inheritPaintOrder
 
bool inheritsTransformFromAny (const QList< KoShape * > ancestorsInQuestion) const
 inheritsTransformFromAny checks if the shape inherits transformation from any of the shapes listed in ancestorsInQuestion. The inheritance is checked in recursive way.
 
bool inheritStroke () const
 inheritStroke shows if the shape inherits the stroke from its parent
 
bool isContentProtected () const
 
bool isGeometryProtected () const
 
bool isPrintable () const
 
bool isSelectable () const
 
virtual bool isShapeEditable (bool recursive=true) const
 checks recursively if the shape or one of its parents is not visible or locked
 
bool isVisible (bool recursive=true) const
 
bool keepAspectRatio () const
 
 KoShape ()
 Constructor.
 
qreal minimumHeight () const
 
QString name () const
 
void notifyChanged ()
 
virtual void paintMarkers (QPainter &painter) const
 paintStroke paints the shape's markers
 
KoShapeContainerparent () const
 
QPointF position () const
 Get the position of the shape in pt.
 
void removeAdditionalAttribute (const QString &name)
 
void removeAdditionalStyleAttribute (const char *name)
 
void removeDependee (KoShape *shape)
 
void removeShapeChangeListener (ShapeChangeListener *listener)
 
void rotate (qreal angle)
 Rotate the shape (relative)
 
qreal rotation () const
 
void scale (qreal sx, qreal sy)
 Scale the shape using the zero-point which is the top-left corner.
 
void setAbsolutePosition (const QPointF &newPosition, KoFlake::AnchorPosition anchor=KoFlake::Center)
 
void setAdditionalAttribute (const QString &name, const QString &value)
 
void setAdditionalStyleAttribute (const char *name, const QString &value)
 
void setAnchor (KoShapeAnchor *anchor)
 
void setClipMask (KoClipMask *clipMask)
 Sets a new clip mask, removing the old one. The mask is owned by the shape.
 
void setClipPath (KoClipPath *clipPath)
 Sets a new clip path, removing the old one.
 
void setContentProtected (bool protect)
 
void setGeometryProtected (bool on)
 
void setHyperLink (const QString &hyperLink)
 
void setInheritBackground (bool value)
 setInheritBackground marks a shape as inheriting the background from the parent shape. NOTE: The currently selected background is destroyed.
 
void setInheritPaintOrder (bool value)
 setInheritPaintOrder set inherit paint order.
 
void setInheritStroke (bool value)
 setInheritStroke marks a shape as inheriting the stroke from the parent shape. NOTE: The currently selected stroke is destroyed.
 
void setKeepAspectRatio (bool keepAspect)
 
void setMinimumHeight (qreal height)
 
void setName (const QString &name)
 
void setParent (KoShapeContainer *parent)
 
virtual void setPosition (const QPointF &position)
 Set the position of the shape in pt.
 
void setPrintable (bool on)
 
void setSelectable (bool selectable)
 
void setShapeId (const QString &id)
 
void setToolDelegates (const QSet< KoShape * > &delegates)
 
void setTransformation (const QTransform &matrix)
 
void setTransparency (qreal transparency)
 
void setUserData (KoShapeUserData *userData)
 
void setVisible (bool on)
 
void setZIndex (qint16 zIndex)
 
QString shapeId () const
 
QPointF shapeToDocument (const QPointF &point) const
 Transforms point from shape coordinates to document coordinates.
 
QRectF shapeToDocument (const QRectF &rect) const
 Transforms rect from shape coordinates to document coordinates.
 
void shear (qreal sx, qreal sy)
 Shear the shape The shape will be sheared using the zero-point which is the top-left corner.
 
virtual KoSnapData snapData () const
 Returns additional snap data the shape wants to have snapping to.
 
KoInsets strokeInsets () const
 
QSet< KoShape * > toolDelegates () const
 
QTransform transformation () const
 Returns the shapes local transformation matrix.
 
qreal transparency (bool recursive=false) const
 
virtual void update () const
 
virtual void updateAbsolute (const QRectF &rect) const
 
KoShapeUserDatauserData () const
 
virtual void waitUntilReady (bool asynchronous=true) const
 
qint16 zIndex () const
 
virtual ~KoShape ()
 Destructor.
 
- Public Member Functions inherited from SvgShape
virtual bool loadSvg (const QDomElement &element, SvgLoadingContext &context)
 Loads data from specified svg element.
 
void saveMetadata (SvgSavingContext &context)
 
virtual ~SvgShape ()
 
- Public Member Functions inherited from KoShapeBulkActionInterface
virtual ~KoShapeBulkActionInterface ()=default
 

Static Public Member Functions

static qreal anchoredChunkShift (const QVector< CharacterResult > &result, const bool isHorizontal, const int start, int &end)
 
static void applyAnchoring (QVector< CharacterResult > &result, bool isHorizontal, const KoSvgText::ResolutionHandler resHandler)
 
static void applyTextPath (KisForest< KoSvgTextContentElement >::child_iterator parent, QVector< CharacterResult > &result, bool isHorizontal, QPointF &startPos, const KoSvgTextProperties resolvedProps, QList< KoShape * > textPaths)
 
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 variety of things, primarily KoShape::boundingRect(), but also the calculation of the gradient painting rect.
 
static qreal characterResultOnPath (CharacterResult &cr, qreal length, qreal offset, bool isHorizontal, bool isClosed)
 
static int childCount (KisForest< KoSvgTextContentElement >::child_iterator it)
 Get the child count of the current node. A node without children is a text node.
 
static void cleanUp (KisForest< KoSvgTextContentElement > &tree)
 cleanUp This cleans up the tree by...
 
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 whether it should be removed. If the child has more than one child of its own, it'll call this function over the children, and then handle the removal of children marked as deletable.
 
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, without transforms.
 
static QVector< SubChunkcollectSubChunks (KisForest< KoSvgTextContentElement >::child_iterator it, KoSvgTextProperties parent, bool textInPath, bool &firstTextInPath)
 
static void computeFontMetrics (KisForest< KoSvgTextContentElement >::child_iterator parent, const KoSvgTextProperties &parentProps, const KoSvgText::FontMetrics &parentBaselineTable, const KoSvgText::Baseline parentBaseline, QVector< CharacterResult > &result, int &currentIndex, const KoSvgText::ResolutionHandler resHandler, const bool isHorizontal, const bool disableFontMatching)
 
static const QString & defaultPlaceholderText ()
 
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)
 
static KisForest< KoSvgTextContentElement >::depth_first_tail_iterator findTextContentElementForIndex (KisForest< KoSvgTextContentElement > &tree, int &currentIndex, int sought, bool skipZeroWidth=false)
 findTextContentElementForIndex Finds the given leaf of the current tree-wide string index.
 
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 QList< QPainterPath > generateShapes (const QList< KoShape * > shapesInside, const QList< KoShape * > shapesSubtract, const KoSvgTextProperties &properties)
 
static QList< QPainterPath > generateTextAreas (const QList< KoShape * > shapesInside, const QList< KoShape * > shapesSubtract, const KoSvgTextProperties &props)
 generateTextAreas Generates text areas with the given shapes and properties. This is used to paint previews in the PaddingMargin strategy.
 
static QVector< QPointF > getLigatureCarets (const KoSvgText::ResolutionHandler &resHandler, const bool isHorizontal, raqm_glyph_t &currentGlyph)
 
static void handleLineBoxAlignment (KisForest< KoSvgTextContentElement >::child_iterator parent, QVector< CharacterResult > &result, const QVector< LineBox > lineBoxes, int &currentIndex, const bool isHorizontal, const KoSvgTextProperties resolvedProps)
 
static void insertNewLinesAtAnchors (KisForest< KoSvgTextContentElement > &tree, bool shapesInside=false)
 insertNewLinesAtAnchors Resolves character transforms and then inserts new lines at each transform that creates a new chunk.
 
static void insertNewLinesAtAnchorsImpl (std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< KoSvgText::CharTransformation > &resolvedTransforms, bool &inTextPath)
 
static void insertTransforms (KisForest< KoSvgTextContentElement > &tree, const int start, const int length, const bool allowSkipFirst)
 insertTransforms Inserts empty transforms into tree recursively.
 
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. Used by insertTransforms.
 
static KisForest< KoSvgTextContentElement >::child_iterator iteratorForTreeIndex (const QVector< int > treeIndex, KisForest< KoSvgTextContentElement >::child_iterator parent)
 
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 &currentGlyph, CharacterResult &charResult, QPointF &totalAdvanceFTFontCoordinates)
 
static std::pair< QTransform, qreal > loadGlyphOnly (const QTransform &ftTF, FT_Int32 faceLoadFlags, bool isHorizontal, raqm_glyph_t &currentGlyph, CharacterResult &charResult, const KoSvgText::TextRendering rendering)
 
static void makeTextPathNameUnique (QList< KoShape * > textPaths, KoShape *textPath)
 
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.
 
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.
 
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 influenced by whitespace collapse and whether they are set to unicode codepoints, and they also accumulate from parent to child. This function removes all local transforms in a certain section.
 
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. Used by removeTransform.
 
static QVector< KoSvgText::CharTransformationresolvedTransformsForTree (KisForest< KoSvgTextContentElement > &tree, bool shapesInside=false, bool includeBidiControls=false)
 
static void resolveTransforms (KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, QString text, QVector< CharacterResult > &result, int &currentIndex, bool isHorizontal, bool wrapped, bool textInPath, QVector< KoSvgText::CharTransformation > &resolved, QVector< bool > collapsedChars, const KoSvgTextProperties resolvedProps, bool withControls=true)
 
static bool splitContentElement (KisForest< KoSvgTextContentElement > &tree, int index, bool allowEmptyText=true)
 splitContentElement split the contentElement in tree at index into two nodes.
 
static void splitTree (KisForest< KoSvgTextContentElement > &tree, int index, bool textPathAfterSplit)
 splitTree Split the whole hierarchy of nodes at the given index.
 
static bool startIndexOfIterator (KisForest< KoSvgTextContentElement >::child_iterator parent, KisForest< KoSvgTextContentElement >::child_iterator target, int &currentIndex)
 
static QPainterPath stretchGlyphOnPath (const QPainterPath &glyph, const QPainterPath &path, bool isHorizontal, qreal offset, bool isClosed)
 
static KoShapetextPathByName (QString name, QList< KoShape * > textPaths)
 
- Static Public Member Functions inherited from KoShape
static QRectF absoluteOutlineRect (const QList< KoShape * > &shapes)
 
static QRectF boundingRect (const QList< KoShape * > &shapes)
 
static bool compareShapeZIndex (KoShape *s1, KoShape *s2)
 
static KisHandlePainterHelper createHandlePainterHelperDocument (QPainter *painter, KoShape *shape, qreal handleRadius, int decorationThickness)
 
static KisHandlePainterHelper createHandlePainterHelperView (QPainter *painter, KoShape *shape, const KoViewConverter &converter, qreal handleRadius=0.0, int decorationThickness=1)
 
static QVector< PaintOrderdefaultPaintOrder ()
 default paint order as per SVG specification
 
static QList< KoShape * > linearizeSubtree (const QList< KoShape * > &shapes)
 
static QList< KoShape * > linearizeSubtreeSorted (const QList< KoShape * > &shapes)
 

Public Attributes

std::optional< BulkActionStatebulkActionState
 
QList< QPainterPath > currentTextWrappingAreas
 
QVector< CursorPoscursorPos
 
bool disableFontMatching = false
 Turn off font matching, which should speed up relayout slightly.
 
QPointF initialTextPosition = QPointF()
 
QScopedPointer< KoShapePainterinternalShapesPainter
 
bool isBidi = false
 
bool isLoading = false
 Turned on when loading in text data, blocks updates to shape listeners.
 
QVector< LineBoxlineBoxes
 
QMap< int, int > logicalToVisualCursorPos
 
QString plainText
 
QVector< CharacterResultresult
 
QScopedPointer< KoShapeGroupshapeGroup
 
QList< KoShape * > shapesInside
 
QList< KoShape * > shapesSubtract
 
KisForest< KoSvgTextContentElementtextData
 
QList< KoShape * > textPaths
 
int xRes = 72
 
int yRes = 72
 

Protected Member Functions

void shapeChanged (ChangeType type, KoShape *shape) override
 
- Protected Member Functions inherited from KoShape
 KoShape (const KoShape &rhs)
 
QList< ShapeChangeListener * > listeners () const
 
void setSizeImpl (const QSizeF &size) const
 
void shapeChangedPriv (KoShape::ChangeType type)
 
QTransform transform () const
 return the current matrix that contains the rotation/scale/position of this shape
 

Private Member Functions

QPainterPath defaultCursorShape ()
 defaultCursorShape This returns a default cursor shape for when there's no text inside the text shape.
 
int nextPos (int pos, bool visual)
 nextPos get the next position.
 
int previousPos (int pos, bool visual)
 previousPos get the previous position.
 
void setMementoImpl (const KoSvgTextShapeMementoSP memento)
 
- Private Member Functions inherited from KoShape::Private
 Private ()
 
 Private (const Private &rhs)=delete
 

Private Attributes

QScopedPointer< Privated
 
- Private Attributes inherited from KoShape::Private
QList< KoShape * > dependees
 list of shape dependent on this shape
 
DependeesLifetimeListener dependeesLifetimeListener
 
QList< KoShape::ShapeChangeListener * > listeners
 
KoShapeContainerparent = nullptr
 
QSet< KoShapeManager * > shapeManagers
 
QSet< KoShape * > toolDelegates
 

Friends

class KoSvgTextLoader
 
class TestSvgText
 

Additional Inherited Members

- Static Public Attributes inherited from KoShape
static const qint16 maxZIndex = std::numeric_limits<qint16>::max()
 
static const qint16 minZIndex = std::numeric_limits<qint16>::min()
 

Detailed Description

KoSvgTextShape is a root chunk of the <text> element subtree.

Definition at line 32 of file KoSvgTextShape.h.

Member Enumeration Documentation

◆ DebugElement

enum class KoSvgTextShape::DebugElement
strong
Enumerator
CharBbox 
LineBox 

Definition at line 53 of file KoSvgTextShape.h.

53 {
54 CharBbox = 1 << 0,
55 LineBox = 1 << 1,
56 };
The LineBox struct.

◆ InternalShapeState

Enumerator
Decorative 
ShapeInside 
ShapeSubtract 
TextPath 

Definition at line 452 of file KoSvgTextShape_p.h.

◆ TextType

Enumerator
PrePositionedText 

SVG 1.1 text, white spaces are collapsed or only spaces are preserved. Identical to PreformattedText otherwise.

PreformattedText 

Text-on-Path falls under this or PrePositionedText depending on collapse of lines.

No wrapping, but preserves spaces and linebreaks.

InlineWrap 

Uses inline size to wrap and preserves spaces.

TextInShape 

Uses shape-inside to wrap and preserves spaces.

Definition at line 76 of file KoSvgTextShape.h.

76 {
83 };
@ PreformattedText
Text-on-Path falls under this or PrePositionedText depending on collapse of lines.
@ TextInShape
Uses shape-inside to wrap and preserves spaces.
@ InlineWrap
Uses inline size to wrap and preserves spaces.

Constructor & Destructor Documentation

◆ KoSvgTextShape() [1/2]

KoSvgTextShape::KoSvgTextShape ( )

Definition at line 138 of file KoSvgTextShape.cpp.

139 : KoShape()
140 , d(new Private)
141{
143 d->shapeGroup->setTransformation(this->transformation());
144 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
145 d->internalShapesPainter->setUpdateFunction(std::bind(&KoSvgTextShape::updateAbsolute, this, std::placeholders::_1));
146}
#define KoSvgTextShape_SHAPEID
KoShape()
Constructor.
Definition KoShape.cpp:136
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:378
virtual void updateAbsolute(const QRectF &rect) const
Definition KoShape.cpp:540
void setShapeId(const QString &id)
Definition KoShape.cpp:880
QScopedPointer< Private > d
The KoSvgTextContentElement struct.

References d, KoSvgTextShape_SHAPEID, KoShape::setShapeId(), KoShape::transformation(), and KoShape::updateAbsolute().

◆ KoSvgTextShape() [2/2]

KoSvgTextShape::KoSvgTextShape ( const KoSvgTextShape & rhs)

Definition at line 148 of file KoSvgTextShape.cpp.

149 : KoShape(rhs)
150 , d(new Private(*rhs.d))
151{
153 d->shapeGroup->setTransformation(this->transformation());
154 d->internalShapesPainter->setUpdateFunction(std::bind(&KoSvgTextShape::updateAbsolute, this, std::placeholders::_1));
155 Q_FOREACH(KoShape *shape, d->shapeGroup->shapes()) {
156 shape->addDependee(this);
157 }
158}
bool addDependee(KoShape *shape)
Definition KoShape.cpp:1021

References KoShape::addDependee(), d, KoSvgTextShape_SHAPEID, KoShape::setShapeId(), KoShape::transformation(), and KoShape::updateAbsolute().

◆ ~KoSvgTextShape()

KoSvgTextShape::~KoSvgTextShape ( )
override

Definition at line 160 of file KoSvgTextShape.cpp.

161{
162 Q_FOREACH(KoShape *shape, internalShapeManager()->shapes()) {
163 shape->removeDependee(this);
164 }
165}
void removeDependee(KoShape *shape)
Definition KoShape.cpp:1038
KoShapeManager * internalShapeManager() const
internalShapeManager

References internalShapeManager(), and KoShape::removeDependee().

◆ ~Private()

KoSvgTextShape::~Private ( )
inline

Definition at line 497 of file KoSvgTextShape_p.h.

497 {
498
499 internalShapesPainter.reset();
500 Q_FOREACH(KoShape *shape, shapeGroup->shapes()) {
501 shapeGroup->removeShape(shape);
502 }
503 shapeGroup.reset();
504 qDeleteAll(shapesInside);
505 shapesInside.clear();
506 qDeleteAll(shapesSubtract);
507 shapesSubtract.clear();
508 qDeleteAll(textPaths);
509 textPaths.clear();
510 }
QScopedPointer< KoShapeGroup > shapeGroup
QList< KoShape * > shapesInside
QScopedPointer< KoShapePainter > internalShapesPainter
QList< KoShape * > shapesSubtract
QList< KoShape * > textPaths

Member Function Documentation

◆ addShapeContours()

void KoSvgTextShape::addShapeContours ( QList< KoShape * > shapes,
const bool inside = true )

addShapesContours Add shapes to the contours that make up the wrapping area.

Parameters
shapes– shapes to add.
inside– whether to add to shapesInside or shapesSubtract. If a shape is already in one list, adding them will cause them to be moved to the other list.

Definition at line 2352 of file KoSvgTextShape.cpp.

2353{
2354 Q_FOREACH(KoShape *shape, shapes) {
2355 if (d->textPaths.contains(shape)) {
2356 d->removeTextPathId(d->textData.childBegin(), shape->name());
2357 d->cleanUp(d->textData);
2358 d->textPaths.removeAll(shape);
2359 }
2360
2361 if (inside) {
2362 if (d->shapesSubtract.contains(shape)) {
2363 d->shapesSubtract.removeAll(shape);
2364 }
2365 d->shapesInside.append(shape);
2366 } else {
2367 if (d->shapesInside.contains(shape)) {
2368 d->shapesInside.removeAll(shape);
2369 }
2370 d->shapesSubtract.append(shape);
2371 }
2372 if (!d->shapeGroup->shapes().contains(shape)) {
2373 d->shapeGroup->addShape(shape);
2374 shape->addDependee(this);
2375 }
2376 }
2377
2378 notifyChanged(); // notify shape manager that our geometry has changed
2379
2380 if (!d->isLoading) {
2381 d->updateTextWrappingAreas();
2382 }
2383
2384 d->updateInternalShapesList();
2386 update();
2387}
virtual void update() const
Definition KoShape.cpp:529
void shapeChangedPriv(KoShape::ChangeType type)
Definition KoShape.cpp:105
@ ContentChanged
the content of the shape changed e.g. a new image inside a pixmap/text change inside a textshape
Definition KoShape.h:106
void notifyChanged()
Definition KoShape.cpp:613
QString name() const
Definition KoShape.cpp:950

References KoShape::addDependee(), KoShape::ContentChanged, d, KoShape::name(), KoShape::notifyChanged(), KoShape::shapeChangedPriv(), and KoShape::update().

◆ addTextPathAtEnd()

void KoSvgTextShape::addTextPathAtEnd ( KoShape * textPath)

addTextPathAtEnd add a textpath node at the end of the text.

Parameters
textPath– text path to add.

Definition at line 2541 of file KoSvgTextShape.cpp.

2542{
2543 auto root = d->textData.childBegin();
2544 if (root == d->textData.childEnd()) return;
2545 if (d->textPaths.contains(textPath)) return;
2546
2547 Private::makeTextPathNameUnique(d->textPaths, textPath);
2548 KoSvgTextContentElement textPathElement;
2549 textPathElement.textPathId = textPath->name();
2550 d->shapeGroup->addShape(textPath);
2551 d->textPaths.append(textPath);
2552 textPath->addDependee(this);
2553
2554 d->textData.insert(childEnd(root), textPathElement);
2555}
ChildIterator< value_type, is_const > childEnd(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:300
QString textPathId
The textpath's name, if any.

References KoShape::addDependee(), d, KoShape::name(), and KoSvgTextContentElement::textPathId.

◆ anchoredChunkShift()

static qreal KoSvgTextShape::anchoredChunkShift ( const QVector< CharacterResult > & result,
const bool isHorizontal,
const int start,
int & end )
static

◆ applyAnchoring()

static void KoSvgTextShape::applyAnchoring ( QVector< CharacterResult > & result,
bool isHorizontal,
const KoSvgText::ResolutionHandler resHandler )
static

◆ applyTextLength()

void KoSvgTextShape::applyTextLength ( KisForest< KoSvgTextContentElement >::child_iterator currentTextElement,
QVector< CharacterResult > & result,
int & currentIndex,
int & resolvedDescendentNodes,
bool isHorizontal,
const KoSvgTextProperties resolvedProps,
const KoSvgText::ResolutionHandler & resHandler )

◆ applyTextPath()

static void KoSvgTextShape::applyTextPath ( KisForest< KoSvgTextContentElement >::child_iterator parent,
QVector< CharacterResult > & result,
bool isHorizontal,
QPointF & startPos,
const KoSvgTextProperties resolvedProps,
QList< KoShape * > textPaths )
static

◆ applyWhiteSpace()

void KoSvgTextShape::applyWhiteSpace ( KisForest< KoSvgTextContentElement > & tree,
const bool convertToPreWrapped = false )
inline

applyWhiteSpace CSS Whitespace processes whitespaces so that duplicate white spaces and unnecessary hard breaks get removed from the text. Within the text layout we avoid removing the white spaces. However, when converting between text types it can be useful to remove these spaces. This function actually applies the white space rule to the active text.

Parameters
tree– tree to apply the whitespace rule onto.
convertToPreWrapped– switch all whitespace rules to pre-wrapped.

Definition at line 1064 of file KoSvgTextShape_p.h.

1064 {
1065 QString allText;
1066 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, allText, false);
1067
1068 auto end = std::make_reverse_iterator(tree.childBegin());
1069 auto begin = std::make_reverse_iterator(tree.childEnd());
1070
1071 for (; begin != end; begin++) {
1072 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1073 }
1074 if (convertToPreWrapped) {
1075 tree.childBegin()->properties.setProperty(KoSvgTextProperties::TextCollapseId, QVariant::fromValue(KoSvgText::Preserve));
1076 tree.childBegin()->properties.setProperty(KoSvgTextProperties::TextWrapId, QVariant::fromValue(KoSvgText::Wrap));
1077 }
1078 }
child_iterator childEnd()
Definition KisForest.h:880
child_iterator childBegin()
Definition KisForest.h:876
@ TextCollapseId
KoSvgText::TextSpaceCollapse.
@ TextWrapId
KoSvgText::TextWrap.
void applyWhiteSpaceImpl(std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< bool > &collapsed, QString &allText, const bool convertToPreWrapped)
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,...
@ Preserve
Do not collapse any space.
Definition KoSvgText.h:99

References KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::childEnd(), KoSvgText::Preserve, KoSvgTextProperties::TextCollapseId, KoSvgTextProperties::TextWrapId, and KoSvgText::Wrap.

◆ applyWhiteSpaceImpl()

void KoSvgTextShape::applyWhiteSpaceImpl ( std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current,
QVector< bool > & collapsed,
QString & allText,
const bool convertToPreWrapped )
inline

Definition at line 1080 of file KoSvgTextShape_p.h.

1080 {
1081 auto base = current.base();
1082 // It seems that .base() refers to the next entry instead of the pointer,
1083 // which is coherent with the template implementation of "operator*" here:
1084 // https://en.cppreference.com/w/cpp/iterator/reverse_iterator.html
1085 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);
1091 }
1092 }
1093
1094 if (!current->text.isEmpty()) {
1095 const int total = current->text.size();
1096 QString currentText = allText.right(total);
1097
1098 for (int i = 0; i < total; i++) {
1099 const int j = total - (i+1);
1100 const bool col = collapsed.takeLast();
1101 if (col) {
1102 currentText.remove(j, 1);
1103 }
1104
1105 }
1106 current->text = currentText;
1107 allText.chop(total);
1108 }
1109 if (convertToPreWrapped) {
1110 current->properties.removeProperty(KoSvgTextProperties::TextCollapseId);
1111 current->properties.removeProperty(KoSvgTextProperties::TextWrapId);
1112 }
1113 }
ChildIterator< value_type, is_const > childBegin(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:290
ChildIterator< value_type, is_const > siblingEnd(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:255

References KoSvgTextProperties::TextCollapseId, and KoSvgTextProperties::TextWrapId.

◆ background()

QSharedPointer< KoShapeBackground > KoSvgTextShape::background ( ) const
overridevirtual

Return the brush used to paint the background of this shape with. A QBrush can have a plain color, be fully transparent or have a complex fill. setting such a brush will allow the shape to fill itself using that brush and will be able to tell if its transparent or not.

Returns
the background-brush

Reimplemented from KoShape.

Definition at line 1567 of file KoSvgTextShape.cpp.

1568{
1569 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1572 }
1574}
A simple solid color shape background.
@ FillId
KoSvgText::BackgroundProperty.
QList< PropertyId > properties() const
QVariant property(PropertyId id, const QVariant &defaultValue=QVariant()) const
bool hasProperty(PropertyId id) const
int size(const Forest< T > &forest)
Definition KisForest.h:1232
BackgroundProperty is a special wrapper around KoShapeBackground for managing it in KoSvgTextProperti...
Definition KoSvgText.h:714

References d, KoSvgTextProperties::FillId, KoSvgTextProperties::hasProperty(), KoSvgTextProperties::properties(), KoSvgTextProperties::property(), and KisForestDetail::size().

◆ boundingBoxFromTree()

static QRectF KoSvgTextShape::boundingBoxFromTree ( KisForest< KoSvgTextContentElement > tree,
const KoSvgTextShape * rootShape,
bool includeStrokeInset )
inlinestatic

boundingBoxFromTree get the bounding box of the current textdata tree. We need the bounding box for a variety of things, primarily KoShape::boundingRect(), but also the calculation of the gradient painting rect.

Parameters
tree– tree to perform this on.
includeStrokeInset– whether to include stroke insets.
Returns
a bounding rect.

Definition at line 1433 of file KoSvgTextShape_p.h.

1433 {
1434 QRectF result;
1435 QList<KoShapeStrokeModelSP> parentStrokes;
1436 for (auto it = tree.compositionBegin(); it != tree.compositionEnd(); it++) {
1437 if (it.state() == KisForestDetail::Enter) {
1438 if (it->properties.hasProperty(KoSvgTextProperties::StrokeId)) {
1439 parentStrokes.append(it->properties.property(KoSvgTextProperties::StrokeId).value<KoSvgText::StrokeProperty>().property);
1440 }
1441 } else {
1442 KoShapeStrokeModelSP stroke = parentStrokes.size() > 0? parentStrokes.last(): nullptr;
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();
1447 }
1448 if (!bb.isEmpty()) {
1449 if (stroke && includeStrokeInset) {
1450 KoInsets insets;
1451 stroke->strokeInsets(rootShape, insets);
1452 result |= bb.adjusted(-insets.left, -insets.top, insets.right, insets.bottom);
1453 } else {
1454 result |= bb;
1455 }
1456 }
1457 if (it->properties.hasProperty(KoSvgTextProperties::StrokeId)) {
1458 // reset stroke to use parent stroke.
1459 parentStrokes.pop_back();
1460 }
1461 }
1462 }
1463 return result;
1464 }
composition_iterator compositionBegin()
Definition KisForest.h:912
composition_iterator compositionEnd()
Definition KisForest.h:916
@ StrokeId
KoSvgText::StrokeProperty.
KoShapeStrokeModelSP stroke() const override
QVector< CharacterResult > result
qreal bottom
Bottom inset.
Definition KoInsets.h:50
qreal right
Right inset.
Definition KoInsets.h:52
qreal top
Top inset.
Definition KoInsets.h:49
qreal left
Left inset.
Definition KoInsets.h:51
StrokeProperty is a special wrapper around KoShapeStrokeModel for managing it in KoSvgTextProperties.
Definition KoSvgText.h:733

References KoInsets::bottom, KisForestDetail::Forest< T >::compositionBegin(), KisForestDetail::Forest< T >::compositionEnd(), KisForestDetail::Enter, KoInsets::left, KoInsets::right, KoSvgTextProperties::StrokeId, and KoInsets::top.

◆ boundingRect()

QRectF KoSvgTextShape::boundingRect ( ) const
overridevirtual

Get the bounding box of the shape.

This includes the line width of the shape

Returns
the bounding box of the shape

Reimplemented from KoShape.

Definition at line 2120 of file KoSvgTextShape.cpp.

2121{
2122 QRectF shapesRect;
2123 if (d->internalShapesPainter->contentRect().isValid()) {
2124 shapesRect = d->internalShapesPainter->contentRect();
2125 if (!(d->shapesInside.isEmpty() && d->shapesSubtract.isEmpty())) {
2126 return shapesRect;
2127 }
2128 }
2129 QRectF result = Private::boundingBoxFromTree(d->textData, this, true);
2130
2131 return (this->absoluteTransformation().mapRect(result) | shapesRect);
2132}
QTransform absoluteTransformation() const
Definition KoShape.cpp:330

References KoShape::absoluteTransformation(), d, and result.

◆ characterResultOnPath()

static qreal KoSvgTextShape::characterResultOnPath ( CharacterResult & cr,
qreal length,
qreal offset,
bool isHorizontal,
bool isClosed )
static

◆ childCount()

static int KoSvgTextShape::childCount ( KisForest< KoSvgTextContentElement >::child_iterator it)
inlinestatic

Get the child count of the current node. A node without children is a text node.

Definition at line 713 of file KoSvgTextShape_p.h.

713 {
714 return std::distance(KisForestDetail::childBegin(it), KisForestDetail::childEnd(it));
715 }

References KisForestDetail::childBegin(), and KisForestDetail::childEnd().

◆ cleanUp() [1/2]

void KoSvgTextShape::cleanUp ( )

Cleans up the internal text data. Used by undo commands.

Definition at line 1245 of file KoSvgTextShape.cpp.

1246{
1247 KoSvgTextShape::Private::cleanUp(d->textData);
1248 notifyChanged();
1250}

References KoShape::ContentChanged, d, KoShape::notifyChanged(), and KoShape::shapeChangedPriv().

◆ cleanUp() [2/2]

static void KoSvgTextShape::cleanUp ( KisForest< KoSvgTextContentElement > & tree)
inlinestatic

cleanUp This cleans up the tree by...

  • Removing empty text elements that are not the root or text paths.
  • Merging sibling elements with similar properties.
  • Merging single children with parent if possible.
    Parameters
    tree– tree to clean up

Definition at line 1349 of file KoSvgTextShape_p.h.

1349 {
1350 if (tree.childBegin() != tree.childEnd()) {
1351 cleanUpImpl(tree, tree.childBegin());
1352 }
1353 }
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...

References KisForestDetail::Forest< T >::childBegin(), and KisForestDetail::Forest< T >::childEnd().

◆ cleanUpImpl()

static bool KoSvgTextShape::cleanUpImpl ( KisForest< KoSvgTextContentElement > & tree,
KisForest< KoSvgTextContentElement >::child_iterator current )
inlinestatic

cleanUpImpl implementation of recursive function for cleanup. This goes over a child and decides whether it should be removed. If the child has more than one child of its own, it'll call this function over the children, and then handle the removal of children marked as deletable.

Returns
whether the given child should be removed from the tree.

Definition at line 1273 of file KoSvgTextShape_p.h.

1273 {
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()) {
1278 return true;
1279 } else {
1280 // check if siblings are similar.
1281 auto siblingPrev = current;
1283 QVariant(KoSvgText::BidiNormal)).toInt());
1284 siblingPrev--;
1285 while (!isEnd(siblingPrev) && siblingPrev->text.isEmpty()) {
1286 // By checking whether the text is empty, we can skip previous
1287 // siblings that are already marked for deletion.
1288 siblingPrev--;
1289 }
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) {
1298 // TODO: handle localtransforms better; annoyingly, this requires whitespace handling
1299 siblingPrev->text += current->text;
1300 current->text = QString();
1301 return true;
1302 }
1303 }
1304 } else if (children == 1) {
1305 // merge single children into parents if possible.
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()) {
1312 KoSvgTextProperties props = current->properties;
1313 props.setAllButNonInheritableProperties(child->properties);
1314 child->properties = props;
1315 } else {
1316 child->properties.inheritFrom(current->properties);
1317 }
1318 *current = *child;
1319 tree.erase(child);
1320 }
1321 } else {
1323 for (auto child = childBegin(current); child != childEnd(current); child++) {
1324 if (cleanUpImpl(tree, child)) {
1325 deleteList.append(child);
1326 }
1327 }
1328 while (!deleteList.isEmpty()) {
1329 auto child = deleteList.takeFirst();
1331 tree.erase(child);
1332 }
1333 if (childCount(current) <= 1) {
1334 // This checks if, when there's only 0 or 1 children, this node can be cleaned up as well.
1335 return cleanUpImpl(tree, current);
1336 }
1337 }
1338 return false;
1339 }
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
child_iterator erase(child_iterator pos)
Removes element at position pos. If pos is 'end', then result is undefined.
Definition KisForest.h:956
@ UnicodeBidiId
KoSvgText::UnicodeBidi.
void setAllButNonInheritableProperties(const KoSvgTextProperties &properties)
Used to merge child properties into parent properties.
static int childCount(KisForest< KoSvgTextContentElement >::child_iterator it)
Get the child count of the current node. A node without children is a text node.
#define KIS_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:97
int toInt(const QString &str, bool *ok=nullptr)
bool isEnd(const ChildIterator< T, is_const > &it)
Definition KisForest.h:341
@ BidiNormal
No new bidi-level is started.
Definition KoSvgText.h:57
@ BidiIsolate
Content is ordered as if in a separate paragraph.
Definition KoSvgText.h:61
@ BidiIsolateOverride
Definition KoSvgText.h:62

References KoSvgText::BidiIsolate, KoSvgText::BidiIsolateOverride, KoSvgText::BidiNormal, KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::erase(), KIS_ASSERT_RECOVER_NOOP, length(), KoSvgTextProperties::properties(), KoSvgTextProperties::setAllButNonInheritableProperties(), and KoSvgTextProperties::UnicodeBidiId.

◆ clearAssociatedOutlines()

void KoSvgTextShape::clearAssociatedOutlines ( )

◆ cloneShape()

KoShape * KoSvgTextShape::cloneShape ( ) const
overridevirtual

creates a deep copy of the shape or shape's subtree

Returns
a cloned shape

Reimplemented from KoShape.

Definition at line 173 of file KoSvgTextShape.cpp.

174{
175 return new KoSvgTextShape(*this);
176}

References KoSvgTextShape().

◆ collapsedWhiteSpacesForText()

static QVector< bool > KoSvgTextShape::collapsedWhiteSpacesForText ( KisForest< KoSvgTextContentElement > & tree,
QString & allText,
const bool alsoCollapseLowSurrogate = false,
bool includeBidiControls = false )
inlinestatic

collapsedWhiteSpacesForText This returns the collapsed spaces for a given piece of text, without transforms.

Parameters
tree– text data tree.
allText– some collapseMethods modify the text. This is a pointer that sets the modified text.
alsoCollapseLowSurrogate– whether to mark utf16 surrogates as collapsed too.
Returns
list of collapsed characters

Definition at line 891 of file KoSvgTextShape_p.h.

891 {
892 QMap<int, KoSvgText::TextSpaceCollapse> collapseModes;
893
895 for (auto it = tree.compositionBegin(); it != tree.compositionEnd(); it++) {
896 if (it.state() == KisForestDetail::Enter) {
897 KoSvgTextProperties ownProperties = it->properties;
898 ownProperties.inheritFrom(parentProps.last());
899 parentProps.append(ownProperties);
900
901 const int children = childCount(siblingCurrent(it));
902 if (children == 0) {
903 QString text = it->text;
904 if (includeBidiControls) {
905 KoSvgText::UnicodeBidi bidi = KoSvgText::UnicodeBidi(parentProps.last().propertyOrDefault(KoSvgTextProperties::UnicodeBidiId).toInt());
906 KoSvgText::Direction direction = KoSvgText::Direction(parentProps.last().propertyOrDefault(KoSvgTextProperties::DirectionId).toInt());
907 QVector<QPair<int, int>> positions;
908 QString text = KoCssTextUtils::getBidiOpening(direction, bidi);
909 text += it->getTransformedString(positions, parentProps.last());
910 text += KoCssTextUtils::getBidiClosing(bidi);
911 }
912 KoSvgText::TextSpaceCollapse collapse = KoSvgText::TextSpaceCollapse(parentProps.last().propertyOrDefault(KoSvgTextProperties::TextCollapseId).toInt());
913 collapseModes.insert(allText.size(), collapse);
914 allText += text;
915 }
916 } else {
917 parentProps.pop_back();
918 }
919 }
920 QVector<bool> collapsed = KoCssTextUtils::collapseSpaces(&allText, collapseModes);
921
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()) {
925 collapsed[i] = true;
926 }
927 }
928 }
929 return collapsed;
930 }
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...
@ DirectionId
KoSvgText::Direction.
static const KoSvgTextProperties & defaultProperties()
void inheritFrom(const KoSvgTextProperties &parentProperties, bool resolve=false, bool onlyFontAndLineHeight=false)
KoSvgText::Direction direction() const
direction Whether the text is left to right or right to left.
ChildIterator< value_type, is_const > siblingCurrent(ChildIterator< value_type, is_const > it)
Definition KisForest.h:240
Direction
Base direction used by Bidi algorithm.
Definition KoSvgText.h:48
TextSpaceCollapse
Definition KoSvgText.h:96

References KoCssTextUtils::collapseSpaces(), KisForestDetail::Forest< T >::compositionBegin(), KisForestDetail::Forest< T >::compositionEnd(), KoSvgTextProperties::defaultProperties(), KoSvgTextProperties::DirectionId, KisForestDetail::Enter, KoCssTextUtils::getBidiClosing(), KoCssTextUtils::getBidiOpening(), KoSvgTextProperties::inheritFrom(), KoSvgTextProperties::properties(), KoSvgTextProperties::TextCollapseId, and KoSvgTextProperties::UnicodeBidiId.

◆ collectPaths()

KoShape * KoSvgTextShape::collectPaths ( const KoSvgTextShape * rootShape,
QVector< CharacterResult > & result,
int & currentIndex )

◆ collectSubChunks()

static QVector< SubChunk > KoSvgTextShape::collectSubChunks ( KisForest< KoSvgTextContentElement >::child_iterator it,
KoSvgTextProperties parent,
bool textInPath,
bool & firstTextInPath )
static

Return a linearized representation of a subtree of text "subchunks".

◆ computeFontMetrics()

static void KoSvgTextShape::computeFontMetrics ( KisForest< KoSvgTextContentElement >::child_iterator parent,
const KoSvgTextProperties & parentProps,
const KoSvgText::FontMetrics & parentBaselineTable,
const KoSvgText::Baseline parentBaseline,
QVector< CharacterResult > & result,
int & currentIndex,
const KoSvgText::ResolutionHandler resHandler,
const bool isHorizontal,
const bool disableFontMatching )
static

◆ computeTextDecorations()

void KoSvgTextShape::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 & currentIndex,
bool isHorizontal,
bool ltr,
bool wrapping,
const KoSvgTextProperties resolvedProps,
QList< KoShape * > textPaths )

◆ convertCharTransformsToPreformatted()

void KoSvgTextShape::convertCharTransformsToPreformatted ( bool makeInlineSize = false)

convertCharTransformsToPreformatted Converts the text to a preformatted SVG 2.0 text. This changes the textType();

Parameters
makeInlineSize– whether to have inline size applied.

Definition at line 1689 of file KoSvgTextShape.cpp.

1690{
1691 const int inlineSize = writingMode() == KoSvgText::HorizontalTB? outlineRect().width(): outlineRect().height();
1692 d->applyWhiteSpace(d->textData, true);
1693 d->insertNewLinesAtAnchors(d->textData, !d->shapesInside.isEmpty());
1694 d->cleanUp(d->textData);
1695
1696 KoSvgTextProperties props = this->propertiesForPos(-1);
1697 if (makeInlineSize) {
1699 // Using QCeil here because otherwise the text will layout too tight.
1700 val.customValue = qCeil(inlineSize);
1701 val.isAuto = false;
1703 props.setProperty(KoSvgTextProperties::InlineSizeId, QVariant::fromValue(val));
1704 }
1705 } else {
1707 }
1708 // NOTE: applyWhiteSpace and insertNewLines don't notify changes,
1709 // so setProperties is the only thing triggering relayout();
1710 setPropertiesAtPos(-1, props);
1711}
@ InlineSizeId
KoSvgText::AutoValue.
void removeProperty(PropertyId id)
void setProperty(PropertyId id, const QVariant &value)
KoSvgTextProperties propertiesForPos(const int pos, bool inherited=false) const
Return the properties at a given position.
void setPropertiesAtPos(int pos, KoSvgTextProperties properties)
setPropertiesAtPos will set the properties at pos.
KoSvgText::WritingMode writingMode() const
writingMode There's a number of places we need to check the writing mode to provide proper controls.
QRectF outlineRect() const override
@ HorizontalTB
Definition KoSvgText.h:38

References KoSvgText::AutoValue::customValue, d, KoSvgTextProperties::hasProperty(), KoSvgText::HorizontalTB, KoSvgTextProperties::InlineSizeId, KoSvgText::AutoValue::isAuto, outlineRect(), propertiesForPos(), KoSvgTextProperties::removeProperty(), setPropertiesAtPos(), KoSvgTextProperties::setProperty(), and writingMode().

◆ copyRange()

std::unique_ptr< KoSvgTextShape > KoSvgTextShape::copyRange ( int index,
int length ) const

copyRange Copy the rich text for the given range.

Parameters
index– start string index of the range.
length– length of the range.
Returns
a KoSvgTextShape with only the content elements inside the range.

Definition at line 1170 of file KoSvgTextShape.cpp.

1171{
1172 KoSvgTextShape *clone = new KoSvgTextShape(*this);
1173 int zero = 0;
1174 int endRange = index + length;
1175 int size = KoSvgTextShape::Private::numChars(clone->d->textData.childBegin(), false) - endRange;
1176 clone->removeText(endRange, size);
1177 clone->removeText(zero, index);
1178 KoSvgTextShape::Private::cleanUp(clone->d->textData);
1179 return std::unique_ptr<KoSvgTextShape>(clone);
1180}
QSizeF size() const override
Get the size of the shape in pt.
bool removeText(int &index, int &length)
removeText Where insert text explicitly uses a cursorposition, remove text uses a string index....

References d, KoSvgTextShape(), length(), removeText(), and size().

◆ createTextNodeIndex()

KoSvgTextNodeIndex KoSvgTextShape::createTextNodeIndex ( KisForest< KoSvgTextContentElement >::child_iterator textElement) const

◆ cursorForPos()

QPainterPath KoSvgTextShape::cursorForPos ( int pos,
QLineF & caret,
QColor & color,
double bidiFlagSize = 1.0 )

cursorForPos returns the QPainterPath associated with this cursorPosition.

Parameters
posthe cursor Position
bidiFlagSize– size of the bidirectional indicator.
Returns
a path to draw a cursor with.

Definition at line 653 of file KoSvgTextShape.cpp.

654{
655 if (d->result.isEmpty() || d->cursorPos.isEmpty() || pos < 0 || pos >= d->cursorPos.size()) {
656 return defaultCursorShape();
657 }
658 QPainterPath p;
659
660 CursorPos cursorPos = d->getCursorPos(pos);
661
662 CharacterResult res = d->result.at(cursorPos.cluster);
663
664 const QTransform tf = res.finalTransform();
665 color = res.cursorInfo.color;
666 caret = res.cursorInfo.caret;
667 caret.translate(res.cursorInfo.offsets.value(cursorPos.offset, QPointF()));
668
669 p.moveTo(tf.map(caret.p1()));
670 p.lineTo(tf.map(caret.p2()));
671 if (d->isBidi && bidiFlagSize > 0) {
672 int sign = res.cursorInfo.rtl ? -1 : 1;
673 double bidiFlagHalf = bidiFlagSize * 0.5;
674 QPointF point3;
675 QPointF point4;
677 qreal slope = bidiFlagHalf * (caret.dx()/ caret.dy());
678 point3 = QPointF(caret.p2().x() + slope + (sign * bidiFlagHalf), caret.p2().y() + bidiFlagHalf);
679 point4 = QPointF(point3.x() + slope - (sign * bidiFlagHalf),point3.y() + bidiFlagHalf);
680 } else {
681 qreal slope = bidiFlagHalf * (caret.dy()/ caret.dx());
682 point3 = QPointF(caret.p2().x() - bidiFlagHalf, caret.p2().y() - slope + (sign * bidiFlagHalf));
683 point4 = QPointF(point3.x() - bidiFlagHalf, point3.y() - slope - (sign * bidiFlagHalf));
684 }
685 p.lineTo(tf.map(point3));
686 p.lineTo(tf.map(point4));
687 }
688 caret = tf.map(caret);
689
690 return p;
691}
const Params2D p
QVector< CursorPos > cursorPos
QPainterPath defaultCursorShape()
defaultCursorShape This returns a default cursor shape for when there's no text inside the text shape...
QTransform finalTransform() const
QLineF caret
Caret for this characterResult.
bool rtl
Whether the current glyph is right-to-left, as opposed to the markup.
QColor color
Which color the current position has.
QVector< QPointF > offsets
The advance offsets for each grapheme index.

References CursorInfo::caret, CursorInfo::color, CharacterResult::cursorInfo, cursorPos, d, defaultCursorShape(), CharacterResult::finalTransform(), KoSvgText::HorizontalTB, CursorInfo::offsets, p, CursorInfo::rtl, sign(), and writingMode().

◆ debugParsing()

void KoSvgTextShape::debugParsing ( )

Outputs debug with the current textData tree.

Definition at line 1978 of file KoSvgTextShape.cpp.

1979{
1980 qDebug() << "Tree size:" << KisForestDetail::size(d->textData);
1981 QString spaces;
1982 for (auto it = compositionBegin(d->textData); it != compositionEnd(d->textData); it++) {
1983 if (it.state() == KisForestDetail::Enter) {
1984
1985 qDebug() << QString(spaces + "+") << it->text;
1986 qDebug() << QString(spaces + "|") << it->properties.convertToSvgTextAttributes();
1987 qDebug() << QString(spaces + "| PropertyType:") << it->properties.property(KoSvgTextProperties::KraTextStyleType).toString();
1988 qDebug() << QString(spaces + "| Fill set: ") << it->properties.hasProperty(KoSvgTextProperties::FillId);
1989 qDebug() << QString(spaces + "| Stroke set: ") << it->properties.hasProperty(KoSvgTextProperties::StrokeId);
1990 qDebug() << QString(spaces + "| Opacity: ") << it->properties.property(KoSvgTextProperties::Opacity);
1991 qDebug() << QString(spaces + "| PaintOrder: ") << it->properties.hasProperty(KoSvgTextProperties::PaintOrder);
1992 qDebug() << QString(spaces + "| Visibility set: ") << it->properties.hasProperty(KoSvgTextProperties::Visibility);
1993 qDebug() << QString(spaces + "| TextPath set: ") << it->textPathId;
1994 qDebug() << QString(spaces + "| Transforms set: ") << it->localTransformations;
1995 spaces.append(" ");
1996 }
1997
1998 if (it.state() == KisForestDetail::Leave) {
1999 spaces.chop(1);
2000 }
2001 }
2002}
@ PaintOrder
QVector<KoShape::PaintOrder>
@ Opacity
Double, SVG shape opacity.
@ KraTextStyleType
string, used to identify the style preset type (character or paragraph).
@ Visibility
Bool, CSS visibility.
ResultIterator compositionEnd(Iterator it)
Definition KisForest.h:570
ResultIterator compositionBegin(Iterator it)
Definition KisForest.h:562

References d, KisForestDetail::Enter, KoSvgTextProperties::FillId, KoSvgTextProperties::KraTextStyleType, KisForestDetail::Leave, KoSvgTextProperties::Opacity, KoSvgTextProperties::PaintOrder, KisForestDetail::size(), KoSvgTextProperties::StrokeId, and KoSvgTextProperties::Visibility.

◆ defaultCursorShape()

QPainterPath KoSvgTextShape::defaultCursorShape ( )
private

defaultCursorShape This returns a default cursor shape for when there's no text inside the text shape.

Returns
a QPainterPath for a cursor.

Definition at line 636 of file KoSvgTextShape.cpp.

637{
639 double fontSize = this->textProperties().fontSize().value;
640 QPainterPath p;
641 if (mode == KoSvgText::HorizontalTB) {
642 p.moveTo(0, fontSize*0.2);
643 p.lineTo(0, -fontSize);
644 } else {
645 p.moveTo(-fontSize * 0.5, 0);
646 p.lineTo(fontSize, 0);
647 }
648 p.translate(d->initialTextPosition);
649
650 return p;
651}
KoSvgText::CssLengthPercentage fontSize() const
KoSvgTextProperties textProperties() const

References d, KoSvgTextProperties::fontSize(), KoSvgText::HorizontalTB, p, textProperties(), KoSvgText::CssLengthPercentage::value, and writingMode().

◆ defaultPlaceholderText()

const QString & KoSvgTextShape::defaultPlaceholderText ( )
static

Definition at line 167 of file KoSvgTextShape.cpp.

168{
169 static const QString s_placeholderText = i18nc("Default text for the text shape", "Placeholder Text");
170 return s_placeholderText;
171}

◆ direction()

KoSvgText::Direction KoSvgTextShape::direction ( ) const

direction Whether the text is left to right or right to left.

Returns
the paragraph-direction of this text.

Definition at line 1652 of file KoSvgTextShape.cpp.

1653{
1655}

References KoSvgTextProperties::DirectionId, and textProperties().

◆ endBulkAction()

QRectF KoSvgTextShape::endBulkAction ( )
overridevirtual

Ends bulk action state and performs all calculation-heavy operations over the new state. Returns a rectangle in absolute coordinates that should be updated to make these changes visible to the user.

Implements KoShapeBulkActionInterface.

Definition at line 2035 of file KoSvgTextShape.cpp.

2036{
2038
2039 QRectF updateRect;
2040
2041 if (d->bulkActionState->changed()) {
2042 if (d->bulkActionState->contourHasChanged) {
2043 d->updateTextWrappingAreas();
2044 } else if (d->bulkActionState->layoutHasChanged) {
2045 // updateTextWrappingAreas() already includes a call to relayout()
2046 relayout();
2047 }
2048 // otherwise, it's an update from a memento.
2049
2050 updateRect = d->bulkActionState->originalBoundingRect | boundingRect();
2051 }
2052
2053 d->bulkActionState = std::nullopt;
2054 return updateRect;
2055}
QRectF boundingRect() const override
Get the bounding box of the shape.
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129

References boundingRect(), d, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, and relayout().

◆ enterNodeSubtree()

void KoSvgTextShape::enterNodeSubtree ( )

Set the current node to its first child, entering the subtree.

Definition at line 1892 of file KoSvgTextShape.cpp.

1893{
1894
1895}

◆ finalizeDecoration()

static void KoSvgTextShape::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 )
static

◆ findNodeIndexForPropertyId()

KoSvgTextNodeIndex KoSvgTextShape::findNodeIndexForPropertyId ( KoSvgTextProperties::PropertyId propertyId)

findNodeIndexForPropertyId

Returns
the nodeIndex of the first content element found with a given property id. @propertyId -- id to search for.

Definition at line 1500 of file KoSvgTextShape.cpp.

1501{
1502 for (auto it = d->textData.childBegin(); it != d->textData.childEnd(); it++) {
1503 if (it->properties.hasProperty(propertyId)) {
1504 return d->createTextNodeIndex(it);
1506 auto found = findNodeIndexForPropertyIdImpl(it, propertyId);
1507 if (found != it) {
1508 return d->createTextNodeIndex(found);
1509 }
1510 }
1511 }
1512 return d->createTextNodeIndex(d->textData.childBegin());
1513}
KisForest< KoSvgTextContentElement >::child_iterator findNodeIndexForPropertyIdImpl(KisForest< KoSvgTextContentElement >::child_iterator parent, KoSvgTextProperties::PropertyId propertyId)

References KisForestDetail::childBegin(), KisForestDetail::childEnd(), d, and findNodeIndexForPropertyIdImpl().

◆ findRangeForNodeIndex()

QPair< int, int > KoSvgTextShape::findRangeForNodeIndex ( const KoSvgTextNodeIndex & node) const

findRangeForNodeIndex Find the start and end cursor position for a given nodeIndex.

Parameters
nodethe tree index to find the range for.
Returns
A QPair<int,int> describing cursor position range encompassed by the tree index and it's children. Will return {-1, -1} when the tree index is invalid.

Definition at line 1515 of file KoSvgTextShape.cpp.

1516{
1517 int startIndex = 0;
1518 int endIndex = 0;
1519 for (auto child = d->textData.childBegin(); child != d->textData.childEnd(); child++) {
1520 // count children
1521 d->startIndexOfIterator(child, node.d->textElement, startIndex);
1522 endIndex = d->numChars(node.d->textElement) + startIndex;
1523 }
1524 return qMakePair(posForIndex(startIndex), posForIndex(endIndex));
1525}
QScopedPointer< Private > d
int posForIndex(int index, bool firstIndex=false, bool skipSynthetic=false) const
posForIndex Get the cursor position for a given index in a string.

References d, KoSvgTextNodeIndex::d, and posForIndex().

◆ findTextContentElementForIndex()

static KisForest< KoSvgTextContentElement >::depth_first_tail_iterator KoSvgTextShape::findTextContentElementForIndex ( KisForest< KoSvgTextContentElement > & tree,
int & currentIndex,
int sought,
bool skipZeroWidth = false )
inlinestatic

findTextContentElementForIndex Finds the given leaf of the current tree-wide string index.

Parameters
tree– tree to search in.
currentIndex– currentIndex, will always be set to the start index of the found element.
sought– index sought.
skipZeroWidth– whether to explicitly skip zero-width chunks. Remove text may set this to true, while inserting text into empty chunks requires this to be false.
Returns
iterator – found iterator. Will default to tree end if nothing is found.

Definition at line 730 of file KoSvgTextShape_p.h.

734 {
735 auto it = tree.depthFirstTailBegin();
736 for (; it != tree.depthFirstTailEnd(); it++) {
737 if (childCount(siblingCurrent(it)) > 0) {
738 continue;
739 }
740 int length = it->numChars(false);
741 if (length == 0 && skipZeroWidth) {
742 continue;
743 }
744
745 if (sought == currentIndex || (sought > currentIndex && sought < currentIndex + length)) {
746 break;
747 } else {
748 currentIndex += length;
749 }
750 }
751 return it;
752 }
depth_first_tail_iterator depthFirstTailEnd()
Definition KisForest.h:856
depth_first_tail_iterator depthFirstTailBegin()
Definition KisForest.h:852

References KisForestDetail::Forest< T >::depthFirstTailBegin(), KisForestDetail::Forest< T >::depthFirstTailEnd(), and length().

◆ findTopLevelParent()

static KisForest< KoSvgTextContentElement >::child_iterator KoSvgTextShape::findTopLevelParent ( KisForest< KoSvgTextContentElement >::child_iterator root,
KisForest< KoSvgTextContentElement >::child_iterator child )
inlinestatic

findTopLevelParent Returns the toplevel parent of child that is not root.

Parameters
root– root under which the toplevel item is.
child– child for which to search the parent for.
Returns
toplevel parent of child that is itself a child of root, will return childEnd(root) if the child isn't inside root.

Definition at line 866 of file KoSvgTextShape_p.h.

867 {
868 // An earlier version of the code used Hierarchy iterator,
869 // but that had too many exceptions when the child was not in the root.
870 if (!child.node()) return childEnd(root);
871 if (KisForestDetail::parent(child) == root) return child;
872 for (auto rootChild = childBegin(root); rootChild != childEnd(root); rootChild++) {
873 for (auto leaf = KisForestDetail::tailSubtreeBegin(rootChild);
874 leaf != KisForestDetail::tailSubtreeEnd(rootChild); leaf++) {
875 if (siblingCurrent(leaf) == child) {
876 return rootChild;
877 }
878 }
879 }
880 return childEnd(root);
881 }
NodeType * node() const
Definition KisForest.h:78
ResultIterator tailSubtreeBegin(Iterator it)
Definition KisForest.h:706
ChildIterator< value_type, is_const > parent(const ChildIterator< value_type, is_const > &it)
Definition KisForest.h:327
ResultIterator tailSubtreeEnd(Iterator it)
Definition KisForest.h:714

References KisForestDetail::BaseIterator< BaseClass, T, Tag, is_const >::node(), KisForestDetail::parent(), KisForestDetail::tailSubtreeBegin(), and KisForestDetail::tailSubtreeEnd().

◆ fontMatchingDisabled()

bool KoSvgTextShape::fontMatchingDisabled ( ) const

fontMatchingDisabled

Returns
whether font matching is disabled for this shape.

Definition at line 2019 of file KoSvgTextShape.cpp.

2020{
2021 return d->disableFontMatching;
2022}

References d.

◆ generateDecorationPaths()

QMap< KoSvgText::TextDecoration, QPainterPath > KoSvgTextShape::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 )

◆ generateShapes()

static QList< QPainterPath > KoSvgTextShape::generateShapes ( const QList< KoShape * > shapesInside,
const QList< KoShape * > shapesSubtract,
const KoSvgTextProperties & properties )
static

◆ generateTextAreas()

QList< QPainterPath > KoSvgTextShape::generateTextAreas ( const QList< KoShape * > shapesInside,
const QList< KoShape * > shapesSubtract,
const KoSvgTextProperties & props )
static

generateTextAreas Generates text areas with the given shapes and properties. This is used to paint previews in the PaddingMargin strategy.

Parameters
shapesInside– the shapes inside to compute the text areas from.
shapesSubtract– the subtract shapes to remove from the text areas.
props– the properties to use. ShapePadding and ShapeMargin id will be taken from this.
Returns
list of QPainterPaths.

Definition at line 2024 of file KoSvgTextShape.cpp.

2025{
2026 return Private::generateShapes(shapesInside, shapesSubtract, props);
2027}

References shapesInside, and shapesSubtract.

◆ getCursorPos()

CursorPos KoSvgTextShape::getCursorPos ( int pos)
inline

Definition at line 579 of file KoSvgTextShape_p.h.

579 {
580 return cursorPos.at(qBound(0, pos, cursorPos.size()-1));
581 }

◆ getLigatureCarets()

static QVector< QPointF > KoSvgTextShape::getLigatureCarets ( const KoSvgText::ResolutionHandler & resHandler,
const bool isHorizontal,
raqm_glyph_t & currentGlyph )
static

◆ getMemento()

KoSvgTextShapeMementoSP KoSvgTextShape::getMemento ( )

Get a memento holding the current textdata and layout info.

Definition at line 1902 of file KoSvgTextShape.cpp.

1903{
1905 d->result,
1906 d->lineBoxes,
1907 d->cursorPos,
1908 d->logicalToVisualCursorPos,
1909 d->plainText,
1910 d->isBidi,
1911 d->initialTextPosition));
1912}
QSharedPointer< KoSvgTextShapeMemento > KoSvgTextShapeMementoSP

References d.

◆ getPositionsAndRotationsForRange()

QList< KoSvgTextCharacterInfo > KoSvgTextShape::getPositionsAndRotationsForRange ( const int startPos,
const int endPos ) const

getPositionsAndRotationsForRange

Parameters
startPos– start of range.
endPos– end of range, not inclusive.
includeLastAdvance– include a transform at the end that represents the last transform+advance.
Returns
list of qpairs, with the first value being the final position, and the second the final rotation.

Definition at line 1444 of file KoSvgTextShape.cpp.

1445{
1447 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1448 return infos;
1449 }
1450 const int finalPos = d->cursorPos.size()-1;
1451 const int startIndex = d->getCursorPos(qMin(startPos, endPos)).index;
1452 const int endIndex = d->getCursorPos(qMax(startPos, endPos)).index;
1453
1454 for (int i = startIndex; i < endIndex; i++) {
1455 CharacterResult res = d->result.value(i);
1456 if (!res.addressable) continue;
1457 infos << infoFromCharacterResult(res, i);
1458 }
1459
1460 if (endIndex == startIndex) {
1461 bool final = qMax(startPos, endPos) == finalPos;
1462 CharacterResult resFinal = final? d->result.last(): d->result.value(startIndex);
1463 if (resFinal.addressable) {
1464 infos << infoFromCharacterResult(resFinal, startIndex);
1465 }
1466 }
1467
1468 return infos;
1469}
KoSvgTextCharacterInfo infoFromCharacterResult(const CharacterResult &res, const int index)

References CharacterResult::addressable, d, and infoFromCharacterResult().

◆ handleLineBoxAlignment()

static void KoSvgTextShape::handleLineBoxAlignment ( KisForest< KoSvgTextContentElement >::child_iterator parent,
QVector< CharacterResult > & result,
const QVector< LineBox > lineBoxes,
int & currentIndex,
const bool isHorizontal,
const KoSvgTextProperties resolvedProps )
static

◆ handleShapes()

void KoSvgTextShape::handleShapes ( const QList< KoShape * > & sourceShapeList,
const QList< KoShape * > referenceList2,
const QList< KoShape * > referenceShapeList,
QList< KoShape * > & destinationShapeList )
inline

Definition at line 489 of file KoSvgTextShape_p.h.

489 {
490 for (int i = 0; i<sourceShapeList.size(); i++) {
491 if (referenceShapeList.contains(referenceList2.at(i))) {
492 destinationShapeList.append(sourceShapeList.at(i));
493 }
494 }
495 }

◆ indexForPos()

int KoSvgTextShape::indexForPos ( int pos) const

indexForPos get the string index for a given cursor position.

Parameters
posthe cursor position.
Returns
the index in the string.

Definition at line 908 of file KoSvgTextShape.cpp.

909{
910 if (d->cursorPos.isEmpty() || pos < 0) {
911 return -1;
912 }
913
914 return d->getCursorPos(pos).index;
915}

References d.

◆ initialTextPosition()

QPointF KoSvgTextShape::initialTextPosition ( ) const

initialTextPosition Returns the initial text position as per SVG algorithm. The eventual result of this can include transforms or repositioning due to text shapes.

Returns
the initial text position in shape coordinates.

◆ insertNewLinesAtAnchors()

static void KoSvgTextShape::insertNewLinesAtAnchors ( KisForest< KoSvgTextContentElement > & tree,
bool shapesInside = false )
inlinestatic

insertNewLinesAtAnchors Resolves character transforms and then inserts new lines at each transform that creates a new chunk.

Parameters
tree– tree to apply to.
shapesInside– whether we're wrapping in shape.

Definition at line 1142 of file KoSvgTextShape_p.h.

1142 {
1144
1145 auto end = std::make_reverse_iterator(tree.childBegin());
1146 auto begin = std::make_reverse_iterator(tree.childEnd());
1147
1148 bool inTextPath = false;
1149 for (; begin != end; begin++) {
1150 insertNewLinesAtAnchorsImpl(begin, resolvedTransforms, inTextPath);
1151 }
1152 }
static QVector< KoSvgText::CharTransformation > resolvedTransformsForTree(KisForest< KoSvgTextContentElement > &tree, bool shapesInside=false, bool includeBidiControls=false)
static void insertNewLinesAtAnchorsImpl(std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current, QVector< KoSvgText::CharTransformation > &resolvedTransforms, bool &inTextPath)

References KisForestDetail::Forest< T >::childBegin(), and KisForestDetail::Forest< T >::childEnd().

◆ insertNewLinesAtAnchorsImpl()

static void KoSvgTextShape::insertNewLinesAtAnchorsImpl ( std::reverse_iterator< KisForest< KoSvgTextContentElement >::child_iterator > current,
QVector< KoSvgText::CharTransformation > & resolvedTransforms,
bool & inTextPath )
inlinestatic

Because sometimes we have to deal with multiple transforms on a span we only really want to insert newlines when at a content element start. In theory the other transforms can be tested, but this is hard, and semantically it doesn't make sense if a svg text does this.

Definition at line 1154 of file KoSvgTextShape_p.h.

1156 {
1157
1158 inTextPath = (!current->textPathId.isEmpty());
1159 auto base = current.base();
1160 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++) {
1166 resolvedTransforms,
1167 inTextPath);
1168 }
1169 }
1170
1171 if (!current->text.isEmpty()) {
1172 const int total = current->text.size();
1173
1174 for (int i = 0; i < total; i++) {
1175 const int j = total - (i+1);
1176 KoSvgText::CharTransformation transform = resolvedTransforms.takeLast();
1183 bool startsNewChunk = transform.startsNewChunk() && j == 0;
1184
1185 if (inTextPath) {
1186 // First transform in path is always absolute, so we don't insert a newline.
1187 startsNewChunk = false;
1188 inTextPath = false;
1189 }
1190 // When there's no new chunk, we're not at the start of the text and there isn't already a line feed, insert a line feed.
1191 if (startsNewChunk && !resolvedTransforms.isEmpty() && current->text.at(j) != QChar::LineFeed) {
1192 current->text.insert(j, "\n");
1193 }
1194 }
1195 }
1196 current->localTransformations.clear();
1197 }
QTransform transform() const
return the current matrix that contains the rotation/scale/position of this shape
Definition KoShape.cpp:945

◆ insertRichText()

bool KoSvgTextShape::insertRichText ( int pos,
const KoSvgTextShape * richText,
bool inheritPropertiesIfPossible = false )

insertRichText Insert rich text at the given cursor pos. This will first split contents at the given pos before inserting the new rich text.

Parameters
pos– cursor pos to insert at.
richTextKoSvgTextShape with rich text data.
inheritPropertiesIfPossible– toggle whether to inherit rich text if possible.
Returns
whether insertion happened successfully.

Definition at line 1182 of file KoSvgTextShape.cpp.

1183{
1184 bool success = false;
1185 int currentIndex = 0;
1186 int elementIndex = 0;
1187 int insertionIndex = 0;
1188
1189 if (isEnd(richText->d->textData.childBegin())) {
1190 // rich text is empty.
1191 return success;
1192 }
1193
1194 if (pos > -1 && !d->cursorPos.isEmpty()) {
1195 CursorPos cursorPos = d->getCursorPos(pos);
1196 CharacterResult res = d->result.at(cursorPos.cluster);
1197 elementIndex = res.plaintTextIndex;
1198 insertionIndex = cursorPos.index;
1199 elementIndex = qMin(elementIndex, d->result.size()-1);
1200 }
1201
1202 KoSvgTextShape::Private::splitContentElement(this->d->textData, insertionIndex);
1203
1204 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, insertionIndex);
1205 auto richTextIt = d->textData.childEnd();
1206 if (it != d->textData.depthFirstTailEnd()) {
1207 richTextIt = d->textData.move(richText->d->textData.childBegin(), siblingCurrent(it));
1208 success = true;
1209 } else {
1210 currentIndex = 0;
1211 it = d->findTextContentElementForIndex(d->textData, currentIndex, elementIndex);
1212 if (it != d->textData.depthFirstTailEnd()) {
1213 richTextIt = d->textData.move(richText->d->textData.childBegin(), siblingEnd(siblingCurrent(it)));
1214 success = true;
1215 }
1216 }
1217
1218 if (richTextIt != d->textData.childEnd()) {
1219 Q_FOREACH (const KoSvgTextProperties::PropertyId p, richTextIt->properties.properties()) {
1221 richTextIt->properties.removeProperty(p);
1222 }
1223 }
1224 auto parentIt = KisForestDetail::hierarchyBegin(richTextIt);
1225 auto parentEnd = KisForestDetail::hierarchyEnd(richTextIt);
1226 if (parentIt != parentEnd) {
1227 parentIt++;
1228 if (inheritPropertiesIfPossible && parentIt != parentEnd) {
1229 Q_FOREACH (const KoSvgTextProperties::PropertyId p, richTextIt->properties.properties()) {
1230 if (richTextIt->properties.inheritsProperty(p, parentIt->properties)) {
1231 richTextIt->properties.removeProperty(p);
1232 }
1233 }
1234 }
1235 }
1236 }
1237
1238 if (success) {
1239 notifyChanged();
1241 }
1242 return success;
1243}
static bool propertyIsBlockOnly(KoSvgTextProperties::PropertyId id)
ResultIterator hierarchyBegin(Iterator it)
Definition KisForest.h:419
ResultIterator hierarchyEnd(Iterator it)
Definition KisForest.h:427

References KoShape::ContentChanged, cursorPos, d, KisForestDetail::hierarchyBegin(), KisForestDetail::hierarchyEnd(), KoShape::notifyChanged(), p, CharacterResult::plaintTextIndex, KoSvgTextProperties::propertyIsBlockOnly(), and KoShape::shapeChangedPriv().

◆ insertText()

bool KoSvgTextShape::insertText ( int pos,
QString text )

insertText Insert a text somewhere in the KoTextShape.

Parameters
posthe cursor position.
textthe text to insert.
Returns
whether it was successful in inserting text.

< Current position of the search.

The distinction between element and insertion index allows us to insert text at the start or end of a content element, without ambiguity on whether we're inserting into the next element.

Definition at line 922 of file KoSvgTextShape.cpp.

923{
924 bool success = false;
925 int currentIndex = 0;
926
930 int elementIndex = 0;
931 int insertionIndex = 0;
932 if (pos > -1 && !d->cursorPos.isEmpty()) {
933 CursorPos cursorPos = d->getCursorPos(pos);
934 CharacterResult res = d->result.at(cursorPos.cluster);
935 elementIndex = res.plaintTextIndex;
936 insertionIndex = cursorPos.index;
937 elementIndex = qMin(elementIndex, d->result.size()-1);
938 }
939 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, elementIndex);
940 if (it != d->textData.depthFirstTailEnd()) {
941 const int offset = insertionIndex - currentIndex;
942 it->insertText(offset, text);
943
944 d->insertTransforms(d->textData, insertionIndex, text.size(), (elementIndex == insertionIndex));
947 success = true;
948 }
949 return success;
950}

References KoShape::ContentChanged, cursorPos, d, KoShape::notifyChanged(), CharacterResult::plaintTextIndex, and KoShape::shapeChangedPriv().

◆ insertTransforms()

static void KoSvgTextShape::insertTransforms ( KisForest< KoSvgTextContentElement > & tree,
const int start,
const int length,
const bool allowSkipFirst )
inlinestatic

insertTransforms Inserts empty transforms into tree recursively.

Parameters
tree– tree to insert transforms on.
start– start index.
length– amount of transforms to insert.
allowSkipFirst– whether we're allowed to skip the first transform because it is at the start of a text element.

Definition at line 1001 of file KoSvgTextShape_p.h.

1001 {
1002 QString all;
1003 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all, true);
1004
1005 auto root = tree.childBegin();
1006 insertTransformsImpl(root, 0, start, length, collapsedCharacters, allowSkipFirst);
1007 }
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....

References KisForestDetail::Forest< T >::childBegin(), and length().

◆ insertTransformsImpl()

static int KoSvgTextShape::insertTransformsImpl ( KisForest< KoSvgTextContentElement >::child_iterator currentTextElement,
const int globalIndex,
const int start,
const int length,
const QVector< bool > collapsedCharacters,
const bool allowSkipFirst )
inlinestatic

insertTransformsImpl Recursive function that handles inserting empty transforms into a given range. Used by insertTransforms.

Definition at line 1013 of file KoSvgTextShape_p.h.

1013 {
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);
1019 }
1020 } else {
1021 currentLength = currentTextElement->text.size();
1022 }
1023
1024 if (!currentTextElement->localTransformations.isEmpty()) {
1025 int transformOffset = 0;
1026 int transformOffsetEnd = 0;
1027
1028 for (int i = globalIndex; i < globalIndex + currentLength; i++) {
1029 if (i < start) {
1030 transformOffset += collapsedCharacters.at(i)? 0: 1;
1031 }
1032 if (i < start + length) {
1033 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
1034 } else {
1035 break;
1036 }
1037 }
1038
1039 // When at the start, skip the first transform.
1040 if (transformOffset == 0 && allowSkipFirst && currentTextElement->localTransformations.at(0).startsNewChunk()) {
1041 transformOffset += 1;
1042 }
1043
1044 if (transformOffset < currentTextElement->localTransformations.size()) {
1045 for (int i = transformOffset; i < transformOffsetEnd; i++) {
1046 currentTextElement->localTransformations.insert(i, KoSvgText::CharTransformation());
1047 }
1048 }
1049
1050 }
1051 return currentLength;
1052 }

References length().

◆ internalShapeManager()

KoShapeManager * KoSvgTextShape::internalShapeManager ( ) const

internalShapeManager

Returns
access the internal shapes manager for the contour shapes.

Definition at line 2578 of file KoSvgTextShape.cpp.

2579{
2580 return d->internalShapesPainter->internalShapeManager();
2581}

References d.

◆ internalShapes()

QList< KoShape * > KoSvgTextShape::internalShapes ( ) const
inline

Definition at line 518 of file KoSvgTextShape_p.h.

518 {
519 return internalShapesPainter->internalShapeManager()->shapes();
520 }

◆ iteratorForTreeIndex()

static KisForest< KoSvgTextContentElement >::child_iterator KoSvgTextShape::iteratorForTreeIndex ( const QVector< int > treeIndex,
KisForest< KoSvgTextContentElement >::child_iterator parent )
inlinestatic

Definition at line 1355 of file KoSvgTextShape_p.h.

1355 {
1356 if (treeIndex.isEmpty()) return parent;
1357 QVector<int> idx = treeIndex;
1358 int count = idx.takeFirst();
1359 for (auto child = KisForestDetail::childBegin(parent); child != KisForestDetail::childEnd(parent); child++) {
1360 if (count == 0) {
1362 return iteratorForTreeIndex(idx, child);
1363 } else {
1364 return child;
1365 }
1366 }
1367 count -= 1;
1368 }
1370 }
KoShapeContainer * parent
Definition KoShape_p.h:95
static KisForest< KoSvgTextContentElement >::child_iterator iteratorForTreeIndex(const QVector< int > treeIndex, KisForest< KoSvgTextContentElement >::child_iterator parent)

References KisForestDetail::childBegin(), and KisForestDetail::childEnd().

◆ leaveNodeSubtree()

void KoSvgTextShape::leaveNodeSubtree ( )

Set the current node to its parent, leaving the subtree.

Definition at line 1897 of file KoSvgTextShape.cpp.

1898{
1899
1900}

◆ lineEnd()

int KoSvgTextShape::lineEnd ( int pos)

lineEnd return the 'line end' for this pos. This uses anchored chunks, so each absolute x, y posititioning will be considered a line-start.

Parameters
pos– the cursor pos for which to find the line end.
Returns
the line end.

Definition at line 342 of file KoSvgTextShape.cpp.

343{
344 if (pos < 0 || d->cursorPos.isEmpty() || d->result.isEmpty()) {
345 return pos;
346 }
347 if (pos > d->cursorPos.size() - 1) {
348 return d->cursorPos.size() - 1;
349 }
350 int candidate = 0;
351 int posCluster = d->getCursorPos(pos).cluster;
352 for (int i = pos; i < d->cursorPos.size(); i++) {
353 CursorPos p = d->cursorPos.at(i);
354 if (d->result.at(p.cluster).anchored_chunk && i > pos && posCluster != p.cluster) {
355 break;
356 }
357 candidate = i;
358 }
359 return candidate;
360}

References cursorPos, d, and p.

◆ lineStart()

int KoSvgTextShape::lineStart ( int pos)

lineStart return the 'line start' for this pos. This uses anchored chunks, so each absolute x, y posititioning will be considered a line-start.

Parameters
pos– the cursor pos for which to find the line start.
Returns
the line start.

Definition at line 323 of file KoSvgTextShape.cpp.

324{
325 if (pos < 0 || d->cursorPos.isEmpty() || d->result.isEmpty()) {
326 return pos;
327 }
328 CursorPos p = d->getCursorPos(pos);
329 if (d->result.at(p.cluster).anchored_chunk && p.offset == 0) {
330 return pos;
331 }
332 int candidate = 0;
333 for (int i = 0; i < pos; i++) {
334 CursorPos p2 = d->getCursorPos(i);
335 if (d->result.at(p2.cluster).anchored_chunk && p2.offset == 0) {
336 candidate = i;
337 }
338 }
339 return candidate;
340}
QPointF p2

References cursorPos, d, p, and p2.

◆ loadGlyph()

static bool KoSvgTextShape::loadGlyph ( const KoSvgText::ResolutionHandler & resHandler,
const FT_Int32 faceLoadFlags,
const bool isHorizontal,
const char32_t firstCodepoint,
const KoSvgText::TextRendering rendering,
raqm_glyph_t & currentGlyph,
CharacterResult & charResult,
QPointF & totalAdvanceFTFontCoordinates )
static

◆ loadGlyphOnly()

static std::pair< QTransform, qreal > KoSvgTextShape::loadGlyphOnly ( const QTransform & ftTF,
FT_Int32 faceLoadFlags,
bool isHorizontal,
raqm_glyph_t & currentGlyph,
CharacterResult & charResult,
const KoSvgText::TextRendering rendering )
static

◆ makeTextPathNameUnique()

static void KoSvgTextShape::makeTextPathNameUnique ( QList< KoShape * > textPaths,
KoShape * textPath )
inlinestatic

Definition at line 1402 of file KoSvgTextShape_p.h.

1402 {
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;
1412 break;
1413 }
1414 }
1415 if (textPathNameUnique && !newTextPathName.isEmpty()) {
1416 textPath->setName(newTextPathName);
1417 } else {
1418 textPathNameUnique = false;
1419 }
1420 newTextPathName = QString("textPath"+QString::number(textPathNumber));
1421 }
1422 }
void setName(const QString &name)
Definition KoShape.cpp:955

References KoShape::name(), and KoShape::setName().

◆ mergePropertiesIntoRange()

void KoSvgTextShape::mergePropertiesIntoRange ( const int startPos,
const int endPos,
const KoSvgTextProperties properties,
const QSet< KoSvgTextProperties::PropertyId > removeProperties = QSet<KoSvgTextProperties::PropertyId>() )

mergePropertiesIntoRange Merge given properties into the given range. This will first split the nodes at the two range ends, and then merge in the properties into each leaf node. Won't do anything when startPos == endPos

First, the properties in removeProperties list will be removed, then properties in properties will be applied. If the property is present in both lists, then the value from properties will be used.

Parameters
startPos– cursor pos start.
endPos– cursor pos end.
properties– properties to merge in.
removeProperties– optional list of properties to remove, these will always apply after merging.

Definition at line 1090 of file KoSvgTextShape.cpp.

1094{
1095 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1096 if (KisForestDetail::size(d->textData)) {
1097 Q_FOREACH(KoSvgTextProperties::PropertyId p, properties.properties()) {
1098 d->textData.childBegin()->properties.setProperty(p, properties.property(p));
1099 }
1100 Q_FOREACH(KoSvgTextProperties::PropertyId p, removeProperties) {
1101 d->textData.childBegin()->properties.removeProperty(p);
1102 }
1103 }
1104 notifyChanged();
1107 || removeProperties.contains(KoSvgTextProperties::ShapePaddingId)
1108 || removeProperties.contains(KoSvgTextProperties::ShapeMarginId)) {
1110 } else {
1112 }
1113 if (properties.hasProperty(KoSvgTextProperties::FillId)) {
1115 }
1118 }
1119 return;
1120 }
1121 const int startIndex =d->getCursorPos(startPos).index;
1122 const int endIndex = d->getCursorPos(endPos).index;
1123 if (startIndex != endIndex) {
1124 KoSvgTextShape::Private::splitContentElement(d->textData, startIndex);
1125 KoSvgTextShape::Private::splitContentElement(d->textData, endIndex);
1126 }
1127 bool changed = false;
1128 int currentIndex = 0;
1129 KoSvgText::AutoValue inlineSize = d->textData.childBegin()->properties.propertyOrDefault(KoSvgTextProperties::InlineSizeId).value<KoSvgText::AutoValue>();
1130 bool isWrapping = !d->shapesInside.isEmpty() || !inlineSize.isAuto;
1131 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
1132 if (KoSvgTextShape::Private::childCount(siblingCurrent(it)) > 0) {
1133 continue;
1134 }
1135
1136 if (currentIndex >= startIndex && currentIndex < endIndex) {
1137 Q_FOREACH(KoSvgTextProperties::PropertyId p, removeProperties) {
1139 d->textData.childBegin()->properties.removeProperty(p);
1140 } else {
1141 it->properties.removeProperty(p);
1142 }
1143 }
1144 Q_FOREACH(KoSvgTextProperties::PropertyId p, properties.properties()) {
1146 d->textData.childBegin()->properties.setProperty(p, properties.property(p));
1147 } else {
1148 it->properties.setProperty(p, properties.property(p));
1149 }
1150 }
1151
1152 changed = true;
1153 }
1154 currentIndex += it->numChars(false);
1155 }
1156
1157 if (changed){
1158 KoSvgTextShape::Private::cleanUp(d->textData);
1159 notifyChanged();
1161 if (properties.hasProperty(KoSvgTextProperties::FillId)) {
1163 }
1166 }
1167 }
1168}
@ StrokeChanged
the shapes stroke has changed
Definition KoShape.h:102
@ BackgroundChanged
the shapes background has changed
Definition KoShape.h:103
@ TextContourMarginChanged
used after text properties changed and modified the contour margin in the text shape
Definition KoShape.h:107
@ TextAnchorId
KoSvgText::TextAnchor.

References KoShape::BackgroundChanged, KoShape::ContentChanged, d, KoSvgTextProperties::FillId, KoSvgTextProperties::hasProperty(), KoSvgTextProperties::InlineSizeId, KoSvgText::AutoValue::isAuto, KoShape::notifyChanged(), p, KoSvgTextProperties::properties(), KoSvgTextProperties::property(), KoSvgTextProperties::propertyIsBlockOnly(), KoShape::shapeChangedPriv(), KoSvgTextProperties::ShapeMarginId, KoSvgTextProperties::ShapePaddingId, KisForestDetail::size(), KoShape::StrokeChanged, KoSvgTextProperties::StrokeId, KoSvgTextProperties::TextAnchorId, and KoShape::TextContourMarginChanged.

◆ moveShapeInsideToIndex()

void KoSvgTextShape::moveShapeInsideToIndex ( KoShape * shapeInside,
const int index )

moveShapeInsideToIndex Because the order of shapes inside shape-inside affects the text layout, it can be useful to be able to reorder them.

Parameters
shapeInside– shape from the shapesInside list. This function will do nothing
index– new index to move the shape inside to. Will be bound to the list size.

@seealso shapesInside();

Definition at line 2421 of file KoSvgTextShape.cpp.

2422{
2423 const int oldIndex = d->shapesInside.indexOf(shapeInside);
2424 if (oldIndex < 0) return;
2425
2426 // Update.
2427 d->shapesInside.move(oldIndex, index);
2428 if (!d->isLoading) {
2429 d->updateTextWrappingAreas();
2430 }
2431 d->updateInternalShapesList();
2433 update();
2434}

References KoShape::ContentChanged, d, KoShape::shapeChangedPriv(), and KoShape::update().

◆ nextIndex()

int KoSvgTextShape::nextIndex ( int pos)

nextIndex Return the first cursor position with a higher string index.

Parameters
posthe cursor position.
Returns
the first pos with a higher cluster or same cluster and higher offset.

Definition at line 389 of file KoSvgTextShape.cpp.

390{
391 if (d->cursorPos.isEmpty()) {
392 return pos;
393 }
394 int currentIndex = d->getCursorPos(pos).index;
395
396 for (int i = pos; i < d->cursorPos.size(); i++) {
397 if (d->cursorPos.at(i).index > currentIndex) {
398 return i;
399 }
400 }
401 return pos;
402}

References d.

◆ nextLine()

int KoSvgTextShape::nextLine ( int pos)

nextLine get a position on the next line for this position.

Parameters
pos– cursor position.
Returns
the pos on the next line;

Definition at line 447 of file KoSvgTextShape.cpp.

448{
449 if (pos < 0 || pos > d->cursorPos.size()-1 || d->result.isEmpty() || d->cursorPos.isEmpty()) {
450 return pos;
451 }
452
453 int nextLineStart = lineEnd(pos)+1;
454 int nextLineEnd = lineEnd(nextLineStart);
455 CursorPos cursorPos = d->getCursorPos(pos);
456 if (!this->shapesInside().isEmpty()) {
457 LineBox nextLineBox;
458 for (int i = 0; i < d->lineBoxes.size(); ++i) {
459 for (int j = 0; j < d->lineBoxes.at(i).chunks.size(); ++j) {
460 if (d->lineBoxes.at(i).chunks.at(j).chunkIndices.contains(cursorPos.cluster)) {
461 nextLineBox = d->lineBoxes.at(qMin(i + 1, d->lineBoxes.size()-1));
462 }
463 }
464 }
465 if (nextLineBox.chunks.size()>0) {
466 int first = -1;
467 int last = -1;
468 Q_FOREACH(LineChunk chunk, nextLineBox.chunks) {
469 Q_FOREACH (int i, chunk.chunkIndices) {
470 if (d->result.at(i).addressable) {
471 if (first < 0) {
472 first = d->result.at(i).cursorInfo.graphemeIndices.first();
473 }
474 last = d->result.at(i).cursorInfo.graphemeIndices.last();
475 }
476 }
477 }
478 if (first > -1 && last > -1) {
479 nextLineStart = posForIndex(first);
480 nextLineEnd = posForIndex(last);
481 }
482 }
483 }
484
485
486 if (nextLineStart > d->cursorPos.size()-1) {
487 return d->cursorPos.size()-1;
488 }
489
490 CharacterResult res = d->result.at(cursorPos.cluster);
491 QPointF currentPoint = res.finalPosition;
492 currentPoint += res.cursorInfo.offsets.value(cursorPos.offset, res.advance);
493 int candidate = posForPoint(currentPoint, nextLineStart, nextLineEnd+1);
494 if (candidate < 0) {
495 return pos;
496 }
497
498 return candidate;
499}
int posForPoint(QPointF point, int start=-1, int end=-1, bool *overlaps=nullptr)
posForPoint Finds the closest cursor position for the given point in shape coordinates.
int lineEnd(int pos)
lineEnd return the 'line end' for this pos. This uses anchored chunks, so each absolute x,...
QPointF finalPosition
the final position, taking into account both CSS and SVG positioning considerations.
QVector< LineChunk > chunks
QVector< int > chunkIndices
charResult indices that belong to this chunk.

References CharacterResult::advance, LineChunk::chunkIndices, LineBox::chunks, CharacterResult::cursorInfo, cursorPos, d, CharacterResult::finalPosition, lineEnd(), CursorInfo::offsets, posForIndex(), posForPoint(), and shapesInside.

◆ nextPos()

int KoSvgTextShape::nextPos ( int pos,
bool visual )
private

nextPos get the next position.

Parameters
pos– cursor position.
Returns
the next pos;

Definition at line 419 of file KoSvgTextShape.cpp.

420{
421 if (d->cursorPos.isEmpty()) {
422 return -1;
423 }
424
425 if(visual) {
426 int visualIndex = d->logicalToVisualCursorPos.value(pos);
427 return d->logicalToVisualCursorPos.key(qMin(visualIndex + 1, d->cursorPos.size() - 1), d->cursorPos.size() - 1);
428 }
429
430 return qMin(pos + 1, d->cursorPos.size() - 1);
431}

References d.

◆ nodeForTextPath()

KoSvgTextNodeIndex KoSvgTextShape::nodeForTextPath ( KoShape * textPath) const

nodeForTextPath TextPaths are set on toplevel content elements. This function allows for searching which node has said textPath, which should be less clunky than running topLevelNodeForPos for every pos.

Parameters
textPath– the text path to find the node for.
Returns
toplevel node that has the given shape set at it's text path. Returns the root node when none is found.

Definition at line 1549 of file KoSvgTextShape.cpp.

1550{
1551 auto root = d->textData.childBegin();
1552 if (d->isLoading || d->cursorPos.isEmpty()) return d->createTextNodeIndex(root);
1553
1554 for (auto child = childBegin(root); child != childEnd(root); child++) {
1555 if (child->textPathId == textPath->name()) {
1556 return d->createTextNodeIndex(child);
1557 }
1558 }
1559 return d->createTextNodeIndex(root);
1560}

References d, and KoShape::name().

◆ notifyCursorPosChanged()

void KoSvgTextShape::notifyCursorPosChanged ( int pos,
int anchor )

Notify that the cursor position has changed.

Definition at line 1663 of file KoSvgTextShape.cpp.

1664{
1665 if (d->isLoading) {
1666 return;
1667 }
1668 Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
1669 TextCursorChangeListener *cursorListener = dynamic_cast<TextCursorChangeListener*>(listener);
1670 if (cursorListener) {
1671 cursorListener->notifyCursorPosChanged(pos, anchor);
1672 }
1673 }
1674}
QList< KoShape::ShapeChangeListener * > listeners
Definition KoShape_p.h:99
KoShapeAnchor * anchor() const

References KoShape::anchor(), d, KoShape::Private::listeners, and KoSvgTextShape::TextCursorChangeListener::notifyCursorPosChanged().

◆ notifyMarkupChanged()

void KoSvgTextShape::notifyMarkupChanged ( )

Notify that the markup has changed.

Definition at line 1676 of file KoSvgTextShape.cpp.

1677{
1678 if (d->isLoading) {
1679 return;
1680 }
1681 Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
1682 TextCursorChangeListener *cursorListener = dynamic_cast<TextCursorChangeListener*>(listener);
1683 if (cursorListener) {
1684 cursorListener->notifyMarkupChanged();
1685 }
1686 }
1687}

References d, KoShape::Private::listeners, and KoSvgTextShape::TextCursorChangeListener::notifyMarkupChanged().

◆ numChars()

static int KoSvgTextShape::numChars ( KisForest< KoSvgTextContentElement >::child_iterator parent,
bool withControls = false,
KoSvgTextProperties resolvedProps = KoSvgTextProperties::defaultProperties() )
inlinestatic

Get the number of characters for the whole subtree of this node.

Definition at line 702 of file KoSvgTextShape_p.h.

702 {
703 KoSvgTextProperties props = parent->properties;
704 props.inheritFrom(resolvedProps, true);
705 int count = parent->numChars(withControls, props);
707 count += numChars(it, withControls, props);
708 }
709 return count;
710 }
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.

References KisForestDetail::childBegin(), KisForestDetail::childEnd(), and KoSvgTextProperties::inheritFrom().

◆ outline()

QPainterPath KoSvgTextShape::outline ( ) const
overridevirtual

returns the outline of the shape in the form of a path. The outline returned will always be relative to the position() of the shape, so moving the shape will not alter the result. The outline is used to draw the stroke on, for example.

Returns
the outline of the shape in the form of a path.

Reimplemented from KoShape.

Definition at line 2096 of file KoSvgTextShape.cpp.

2096 {
2097 QPainterPath result;
2098 if (!d->internalShapes().isEmpty()) {
2099 Q_FOREACH(KoShape *shape, d->internalShapes()) {
2100 result.addPath(shape->transformation().map(shape->outline()));
2101 }
2102 }
2103
2104 if ((d->shapesInside.isEmpty() && d->shapesSubtract.isEmpty())) {
2105 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
2106 result.addPath(it->associatedOutline);
2107 for (int i = 0; i < it->textDecorations.values().size(); ++i) {
2108 result.addPath(it->textDecorations.values().at(i));
2109 }
2110 }
2111 }
2112
2113 return result;
2114}
virtual QPainterPath outline() const
Definition KoShape.cpp:554

References d, KoShape::outline(), result, and KoShape::transformation().

◆ outlineRect()

QRectF KoSvgTextShape::outlineRect ( ) const
overridevirtual

returns the outline of the shape in the form of a rect. The outlineRect returned will always be relative to the position() of the shape, so moving the shape will not alter the result. The outline is used to calculate the boundingRect.

Returns
the outline of the shape in the form of a rect.

Reimplemented from KoShape.

Definition at line 2115 of file KoSvgTextShape.cpp.

2116{
2117 return outline().boundingRect();
2118}
QPainterPath outline() const override

References outline().

◆ paint()

void KoSvgTextShape::paint ( QPainter & painter) const
overridevirtual

Paint the shape fill The class extending this one is responsible for painting itself. painter is expected to be preconfigured to work in "document" pixels.

Parameters
painterused for painting the shape

Implements KoShape.

Definition at line 2057 of file KoSvgTextShape.cpp.

2058{
2059 painter.save();
2060
2061 painter.setTransform(d->shapeGroup->absoluteTransformation().inverted()*painter.transform());
2062 d->internalShapesPainter->paint(painter);
2063 painter.restore();
2064
2065 painter.save();
2067 if (textRendering == KoSvgText::RenderingOptimizeSpeed || !painter.testRenderHint(QPainter::Antialiasing)) {
2068 // also apply antialiasing only if antialiasing is active on provided target QPainter
2069 painter.setRenderHint(QPainter::Antialiasing, false);
2070 painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
2071 } else {
2072 painter.setRenderHint(QPainter::Antialiasing, true);
2073 painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
2074 }
2075
2076 QPainterPath chunk;
2077 int currentIndex = 0;
2078 if (!d->result.isEmpty()) {
2079 QPainterPath rootBounds;
2080 rootBounds.addRect(Private::boundingBoxFromTree(d->textData, this, false));
2081 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationUnderline, textRendering);
2082 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationOverline, textRendering);
2083 d->paintPaths(painter, rootBounds, this, d->result, textRendering, chunk, currentIndex);
2084 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationLineThrough, textRendering);
2085 }
2086
2087 painter.restore();
2088}
@ DecorationOverline
Definition KoSvgText.h:260
@ DecorationLineThrough
Definition KoSvgText.h:261
@ DecorationUnderline
Definition KoSvgText.h:259
@ RenderingOptimizeSpeed
Definition KoSvgText.h:316

References d, KoSvgText::DecorationLineThrough, KoSvgText::DecorationOverline, KoSvgText::DecorationUnderline, KoSvgText::RenderingOptimizeSpeed, textProperties(), and KoSvgTextProperties::TextRenderingId.

◆ paintDebug() [1/2]

void KoSvgTextShape::paintDebug ( QPainter & painter,
const QVector< CharacterResult > & result,
int & currentIndex )

◆ paintDebug() [2/2]

void KoSvgTextShape::paintDebug ( QPainter & painter,
DebugElements elements ) const

Definition at line 2260 of file KoSvgTextShape.cpp.

2261{
2262 if (elements & DebugElement::CharBbox) {
2263 int currentIndex = 0;
2264 if (!d->result.isEmpty()) {
2265 QPainterPath rootBounds;
2266 rootBounds.addRect(this->outline().boundingRect());
2267 d->paintDebug(painter, d->result, currentIndex);
2268 }
2269
2270 //Debug shape outlines.
2271 Q_FOREACH (KoShape *shapeInside, d->shapesInside) {
2272 QPainterPath p = shapeInside->outline();
2273 p = shapeInside->transformation().map(p);
2274 painter.strokePath(p, QPen(Qt::green));
2275 }
2276 Q_FOREACH (KoShape *shapeInside, d->shapesSubtract) {
2277 QPainterPath p = shapeInside->outline();
2278 p = shapeInside->transformation().map(p);
2279 painter.strokePath(p, QPen(Qt::red));
2280 }
2281 }
2282
2283 if (elements & DebugElement::LineBox) {
2284 Q_FOREACH (LineBox lineBox, d->lineBoxes) {
2285 Q_FOREACH (const LineChunk &chunk, lineBox.chunks) {
2286 QPen pen;
2287 pen.setCosmetic(true);
2288 pen.setWidth(2);
2289 painter.setBrush(QBrush(Qt::transparent));
2290 pen.setColor(QColor(0, 128, 255, 128));
2291 painter.setPen(pen);
2292 painter.drawLine(chunk.length);
2293 pen.setColor(QColor(255, 128, 0, 128));
2294 painter.setPen(pen);
2295 painter.drawRect(chunk.boundingBox);
2296
2297 pen.setColor(QColor(255, 0, 0, 128));
2298 pen.setStyle(Qt::DashDotDotLine);
2299 painter.setPen(pen);
2300 painter.drawLine(chunk.length.translated(lineBox.baselineTop));
2301 pen.setColor(QColor(0, 128, 0, 128));
2302 pen.setStyle(Qt::DashDotLine);
2303 painter.setPen(pen);
2304 painter.drawLine(chunk.length.translated(lineBox.baselineBottom));
2305 }
2306 }
2307 }
2308}
QPointF baselineTop
Used to identify the top of the line for baseline-alignment.
QPointF baselineBottom
Used to identify the bottom of the line for baseline-alignment.
QLineF length
Used to measure how long the current line is allowed to be.

References LineBox::baselineBottom, LineBox::baselineTop, LineChunk::boundingBox, boundingRect(), CharBbox, LineBox::chunks, d, LineChunk::length, LineBox, KoShape::outline(), outline(), p, and KoShape::transformation().

◆ paintOrder()

QVector< KoShape::PaintOrder > KoSvgTextShape::paintOrder ( ) const
overridevirtual

paintOrder

Returns
vector of paint orders, will always be 3 big and contain a fill, stroke and marker entry.

Reimplemented from KoShape.

Definition at line 1605 of file KoSvgTextShape.cpp.

1606{
1607 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1610 }
1611 return KoShape::paintOrder();
1612}
virtual QVector< PaintOrder > paintOrder() const
paintOrder
Definition KoShape.cpp:688

References d, KoSvgTextProperties::hasProperty(), KoShape::paintOrder(), KoSvgTextProperties::PaintOrder, KoSvgTextProperties::properties(), KoSvgTextProperties::property(), and KisForestDetail::size().

◆ paintPaths()

void KoSvgTextShape::paintPaths ( QPainter & painter,
const QPainterPath & outlineRect,
const KoShape * rootShape,
const QVector< CharacterResult > & result,
const KoSvgText::TextRendering rendering,
QPainterPath & chunk,
int & currentIndex )

◆ paintStroke()

void KoSvgTextShape::paintStroke ( QPainter & painter) const
overridevirtual

paintStroke paints the shape's stroked outline

Parameters
painterused for painting the shape
See also
applyConversion()

Reimplemented from KoShape.

Definition at line 2090 of file KoSvgTextShape.cpp.

2091{
2092 Q_UNUSED(painter);
2093 // do nothing! everything is painted in paint()
2094}

◆ paintTextDecoration()

void KoSvgTextShape::paintTextDecoration ( QPainter & painter,
const QPainterPath & outlineRect,
const KoShape * rootShape,
const KoSvgText::TextDecoration type,
const KoSvgText::TextRendering rendering )

◆ plainText()

QString KoSvgTextShape::plainText ( )

plainText plain text of all text inside this text shape, without the bidi controls or any transforms.

Returns
a string of plain text.

◆ posDown()

int KoSvgTextShape::posDown ( int pos,
bool visual = false )

return position below.

Definition at line 308 of file KoSvgTextShape.cpp.

309{
312 if (mode == KoSvgText::VerticalRL || mode == KoSvgText::VerticalLR) {
314 return previousPos(pos, visual);
315 } else {
316 return nextPos(pos, visual);
317 }
318 } else {
319 return nextLine(pos);
320 }
321}
int nextLine(int pos)
nextLine get a position on the next line for this position.
int nextPos(int pos, bool visual)
nextPos get the next position.
int previousPos(int pos, bool visual)
previousPos get the previous position.
@ DirectionRightToLeft
Definition KoSvgText.h:50

References direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, nextLine(), nextPos(), previousPos(), textProperties(), KoSvgText::VerticalLR, KoSvgText::VerticalRL, and writingMode().

◆ posForIndex()

int KoSvgTextShape::posForIndex ( int index,
bool firstIndex = false,
bool skipSynthetic = false ) const

posForIndex Get the cursor position for a given index in a string.

Parameters
index– index in the string.
firstIndex– whether to return for the first instance of the index.
skipSynthetic– whether to skip over synthetic cursorPositions.
Returns
the cursor – position for an index.

Definition at line 885 of file KoSvgTextShape.cpp.

886{
887 int pos = -1;
888 if (d->cursorPos.isEmpty() || index < 0) {
889 return pos;
890 }
891 for (int i = 0; i< d->cursorPos.size(); i++) {
892 if (skipSynthetic && d->cursorPos.at(i).synthetic) {
893 continue;
894 }
895 if (d->cursorPos.at(i).index <= index) {
896 pos = i;
897 if (d->cursorPos.at(i).index == index && firstIndex) {
898 break;
899 }
900 } else if (d->cursorPos.at(i).index > index) {
901 break;
902 }
903 }
904
905 return pos;
906}

References d.

◆ posForPoint()

int KoSvgTextShape::posForPoint ( QPointF point,
int start = -1,
int end = -1,
bool * overlaps = nullptr )

posForPoint Finds the closest cursor position for the given point in shape coordinates.

Parameters
point
start– optional start position;
end– optional end position;
overlaps– optional bool that is set if the point overlaps any glyph box.
Returns
the closest cursor position.

Definition at line 814 of file KoSvgTextShape.cpp.

815{
816 int a = 0;
817 int b = d->cursorPos.size();
818 if (start >= 0 && end >= 0) {
819 a = qMax(start, a);
820 b = qMin(end, b);
821 }
822 double closest = std::numeric_limits<double>::max();
823 int candidate = 0;
824 for (int i = a; i < b; i++) {
825 CursorPos pos = d->getCursorPos(i);
826 CharacterResult res = d->result.at(pos.cluster);
827 QPointF cursorStart = res.finalPosition;
828 cursorStart += res.cursorInfo.offsets.value(pos.offset, res.advance);
829 double distance = kisDistance(cursorStart, point);
830 if (distance < closest) {
831 candidate = i;
832 closest = distance;
833 if (overlaps) {
834 *overlaps = res.finalTransform().map(res.layoutBox()).containsPoint(point, Qt::WindingFill);
835 }
836 }
837 }
838 return candidate;
839}
qreal distance(const QPointF &p1, const QPointF &p2)
qreal kisDistance(const QPointF &pt1, const QPointF &pt2)
Definition kis_global.h:190
QRectF layoutBox() const
layoutBox
int cluster
Which character result this position belongs in.
int offset
Which offset this position belongs with.

References CharacterResult::advance, CursorPos::cluster, CharacterResult::cursorInfo, d, distance(), CharacterResult::finalPosition, CharacterResult::finalTransform(), kisDistance(), CharacterResult::layoutBox(), CursorPos::offset, and CursorInfo::offsets.

◆ posForPointLineSensitive()

int KoSvgTextShape::posForPointLineSensitive ( QPointF point)

posForPointLineSensitive When clicking on an empty space in a wrapped text, it is preferable to have the caret be at the end of the line visually associated with that empty space than the positions above or below that might be closer.

Because SVG has several situations where there's no real lines, we first test for the closest cursorpos and also whether there's an actual overlap with a glyph. If there's no such overlap, we test against whether there's an anchored chunk in the inline direction, and if so search the line resulting from that. If not, we return the closest pos.

Parameters
pointthe point in shape coordinates.
Returns
the closest pos, taking into account any line starts or ends.

Definition at line 841 of file KoSvgTextShape.cpp.

842{
843 bool overlaps = false;
844 int initialPos = posForPoint(point, -1, -1, &overlaps);
845
846 if (overlaps) {
847 return initialPos;
848 }
849
851
852 int candidateLineStart = 0;
853 double closest = std::numeric_limits<double>::max();
854 for (int i = 0; i < d->cursorPos.size(); i++) {
855 CursorPos pos = d->cursorPos.at(i);
856 CharacterResult res = d->result.at(pos.cluster);
857 if (res.anchored_chunk) {
858 QLineF caret = res.cursorInfo.caret;
859 caret.translate(res.finalPosition);
860 QPointF cursorStart = res.finalPosition;
861 cursorStart += res.cursorInfo.offsets.value(pos.offset, res.advance);
862 double distance = kisDistance(cursorStart, point);
863 if (mode == KoSvgText::HorizontalTB) {
864 if (caret.p1().y() > point.y() && caret.p2().y() <= point.y() && closest > distance) {
865 candidateLineStart = i;
866 closest = distance;
867 }
868 } else {
869 if (caret.p2().x() > point.x() && caret.p1().x() <= point.x() && closest > distance) {
870 candidateLineStart = i;
871 closest = distance;
872 }
873 }
874 }
875 }
876
877 if (candidateLineStart > -1) {
878 int end = lineEnd(candidateLineStart);
879 initialPos = posForPoint(point, candidateLineStart, qMin(end + 1, d->cursorPos.size()));
880 }
881
882 return initialPos;
883}
bool anchored_chunk
whether this is the start of a new chunk.

References CharacterResult::advance, CharacterResult::anchored_chunk, CursorInfo::caret, CursorPos::cluster, CharacterResult::cursorInfo, d, distance(), CharacterResult::finalPosition, KoSvgText::HorizontalTB, kisDistance(), lineEnd(), CursorPos::offset, CursorInfo::offsets, posForPoint(), and writingMode().

◆ posLeft()

int KoSvgTextShape::posLeft ( int pos,
bool visual = false )

return position to the left; visual indicates whether to use logical ('previous') or visual left (depending on direction).

Definition at line 258 of file KoSvgTextShape.cpp.

259{
262 if (mode == KoSvgText::VerticalRL) {
263 return nextLine(pos);
264 } else if (mode == KoSvgText::VerticalLR) {
265 return previousLine(pos);
266 } else {
268 return nextPos(pos, visual);
269 } else {
270 return previousPos(pos, visual);
271 }
272 }
273}
int previousLine(int pos)
previousLine get a position on the previous line for this position.

References direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, nextLine(), nextPos(), previousLine(), previousPos(), textProperties(), KoSvgText::VerticalLR, KoSvgText::VerticalRL, and writingMode().

◆ posRight()

int KoSvgTextShape::posRight ( int pos,
bool visual = false )

return position to the right; visual indicates whether to use logical ('next') or visual right (depending on direction).

Definition at line 275 of file KoSvgTextShape.cpp.

276{
279
280 if (mode == KoSvgText::VerticalRL) {
281 return previousLine(pos);
282 } else if (mode == KoSvgText::VerticalLR) {
283 return nextLine(pos);
284 } else {
286 return previousPos(pos, visual);
287 } else {
288 return nextPos(pos, visual);
289 }
290 }
291}

References direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, nextLine(), nextPos(), previousLine(), previousPos(), textProperties(), KoSvgText::VerticalLR, KoSvgText::VerticalRL, and writingMode().

◆ posUp()

int KoSvgTextShape::posUp ( int pos,
bool visual = false )

return position above.

Definition at line 293 of file KoSvgTextShape.cpp.

294{
297 if (mode == KoSvgText::VerticalRL || mode == KoSvgText::VerticalLR) {
299 return nextPos(pos, visual);
300 } else {
301 return previousPos(pos, visual);
302 }
303 } else {
304 return previousLine(pos);
305 }
306}

References direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, nextPos(), previousLine(), previousPos(), textProperties(), KoSvgText::VerticalLR, KoSvgText::VerticalRL, and writingMode().

◆ previousIndex()

int KoSvgTextShape::previousIndex ( int pos)

previousIndex Return the first pos which has a lower string index.

Parameters
posthe cursor position.
Returns
the first cursor position with a lower index.

Definition at line 404 of file KoSvgTextShape.cpp.

405{
406 if (d->cursorPos.isEmpty()) {
407 return pos;
408 }
409 const int currentIndex = d->getCursorPos(pos).index;
410
411 for (int i = pos; i >= 0; i--) {
412 if (d->getCursorPos(i).index < currentIndex) {
413 return i;
414 }
415 }
416 return pos;
417}

References d.

◆ previousLine()

int KoSvgTextShape::previousLine ( int pos)

previousLine get a position on the previous line for this position.

Parameters
pos– cursor position.
Returns
the pos on the previous line;

Definition at line 501 of file KoSvgTextShape.cpp.

502{
503 if (pos < 0 || pos > d->cursorPos.size()-1 || d->result.isEmpty() || d->cursorPos.isEmpty()) {
504 return pos;
505 }
506 int currentLineStart = lineStart(pos);
507 if (currentLineStart - 1 < 0) {
508 return 0;
509 }
510 int previousLineStart = lineStart(currentLineStart-1);
511
512 CursorPos cursorPos = d->getCursorPos(pos);
513 if (!this->shapesInside().isEmpty()) {
514 LineBox previousLineBox;
515 for (int i = 0; i < d->lineBoxes.size(); ++i) {
516 for (int j = 0; j < d->lineBoxes.at(i).chunks.size(); ++j) {
517 if (d->lineBoxes.at(i).chunks.at(j).chunkIndices.contains(cursorPos.cluster)) {
518 previousLineBox = d->lineBoxes.at(qMax(i - 1, 0));
519 }
520 }
521 }
522 if (previousLineBox.chunks.size()>0) {
523 int first = -1;
524 int last = -1;
525 Q_FOREACH(LineChunk chunk, previousLineBox.chunks) {
526 Q_FOREACH (int i, chunk.chunkIndices) {
527 if (d->result.at(i).addressable) {
528 if (first < 0) {
529 first = d->result.at(i).cursorInfo.graphemeIndices.first();
530 }
531 last = d->result.at(i).cursorInfo.graphemeIndices.last();
532 }
533 }
534 }
535 if (first > -1 && last > -1) {
536 previousLineStart = posForIndex(first);
537 currentLineStart = posForIndex(last);
538 }
539 }
540 }
541
542 CharacterResult res = d->result.at(cursorPos.cluster);
543 QPointF currentPoint = res.finalPosition;
544 currentPoint += res.cursorInfo.offsets.value(cursorPos.offset, res.advance);
545 int candidate = posForPoint(currentPoint, previousLineStart, currentLineStart);
546 if (candidate < 0) {
547 return pos;
548 }
549
550 return candidate;
551}
int lineStart(int pos)
lineStart return the 'line start' for this pos. This uses anchored chunks, so each absolute x,...

References CharacterResult::advance, LineChunk::chunkIndices, LineBox::chunks, CharacterResult::cursorInfo, cursorPos, d, CharacterResult::finalPosition, lineStart(), CursorInfo::offsets, posForIndex(), posForPoint(), and shapesInside.

◆ previousPos()

int KoSvgTextShape::previousPos ( int pos,
bool visual )
private

previousPos get the previous position.

Parameters
pos– cursor position.
Returns
the previous pos;

Definition at line 433 of file KoSvgTextShape.cpp.

434{
435 if (d->cursorPos.isEmpty()) {
436 return -1;
437 }
438
439 if(visual) {
440 int visualIndex = d->logicalToVisualCursorPos.value(pos);
441 return d->logicalToVisualCursorPos.key(qMax(visualIndex - 1, 0), 0);
442 }
443
444 return qMax(pos - 1, 0);
445}

References d.

◆ Private() [1/2]

Definition at line 445 of file KoSvgTextShape_p.h.

448 {
449 shapeGroup->setSelectable(false);
450 }

◆ Private() [2/2]

KoSvgTextShape::Private ( const Private & rhs)
inline

Definition at line 459 of file KoSvgTextShape_p.h.

461 , textData(rhs.textData)
462 {
463
464 KoShapeGroup *g = dynamic_cast<KoShapeGroup*>(rhs.shapeGroup.data()->cloneShape());
465 shapeGroup.reset(g);
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);
471
472 yRes = rhs.yRes;
473 xRes = rhs.xRes;
474 result = rhs.result;
475 lineBoxes = rhs.lineBoxes;
476
477 cursorPos = rhs.cursorPos;
478 logicalToVisualCursorPos = rhs.logicalToVisualCursorPos;
479 plainText = rhs.plainText;
480 isBidi = rhs.isBidi;
481 initialTextPosition = rhs.initialTextPosition;
482
483 isLoading = rhs.isLoading;
484 disableFontMatching = rhs.disableFontMatching;
485
486 currentTextWrappingAreas = rhs.currentTextWrappingAreas;
487 }
void setSelectable(bool selectable)
Definition KoShape.cpp:827
KisForest< KoSvgTextContentElement > textData
QList< QPainterPath > currentTextWrappingAreas
void updateInternalShapesList()
QPointF initialTextPosition
QMap< int, int > logicalToVisualCursorPos
bool isLoading
Turned on when loading in text data, blocks updates to shape listeners.
void handleShapes(const QList< KoShape * > &sourceShapeList, const QList< KoShape * > referenceList2, const QList< KoShape * > referenceShapeList, QList< KoShape * > &destinationShapeList)
QVector< LineBox > lineBoxes
bool disableFontMatching
Turn off font matching, which should speed up relayout slightly.

References KoShape::setSelectable().

◆ propertiesForPos()

KoSvgTextProperties KoSvgTextShape::propertiesForPos ( const int pos,
bool inherited = false ) const

Return the properties at a given position.

Definition at line 991 of file KoSvgTextShape.cpp.

992{
993 return propertiesForRange(pos, pos, inherited).value(0, KoSvgTextProperties());
994}
QList< KoSvgTextProperties > propertiesForRange(const int startPos, const int endPos, bool inherited=false) const
propertiesForRange get the properties for a range.

References propertiesForRange().

◆ propertiesForRange()

QList< KoSvgTextProperties > KoSvgTextShape::propertiesForRange ( const int startPos,
const int endPos,
bool inherited = false ) const

propertiesForRange get the properties for a range.

Parameters
startPos– range start.
endPos– range end.
Returns
list of properties.

Sometimes this gets called when xml data is uploaded into the shape, at which point the tree is empty.

Definition at line 1012 of file KoSvgTextShape.cpp.

1013{
1015
1017 if (d->isLoading) return props;
1018
1019 if (((startPos < 0 || startPos >= d->cursorPos.size()) && startPos == endPos) || d->cursorPos.isEmpty()) {
1020 props = {KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties()};
1021 return props;
1022 }
1023 const int startIndex = d->getCursorPos(startPos).index;
1024 const int endIndex = d->getCursorPos(endPos).index;
1025 int sought = startIndex;
1026 if (startIndex == endIndex) {
1027 int currentIndex = 0;
1028 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, sought);
1029 if (it != d->textData.depthFirstTailEnd()) {
1030 if (inherited) {
1031 props.append(inheritProperties(it));
1032 } else {
1033 props.append(it->properties);
1034 }
1035 } else {
1036 currentIndex = 0;
1037 it = d->findTextContentElementForIndex(d->textData, currentIndex, sought - 1);
1038 if (it != d->textData.depthFirstTailEnd()) {
1039 if (inherited) {
1040 props.append(inheritProperties(it));
1041 } else {
1042 props.append(it->properties);
1043 }
1044 }
1045 }
1046 } else {
1047 while(sought < endIndex) {
1048 int currentIndex = 0;
1049 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, sought);
1050 if (KisForestDetail::siblingCurrent(it) == d->textData.childBegin()) {
1051 // If there's a selection and the search algorithm only returns the root, return empty.
1052 // The root text properties should be retrieved explicitly (either by using -1 as pos, or by calling textProperties()).
1053 props = {KoSvgTextProperties()};
1054 return props;
1055 } else if (it != d->textData.depthFirstTailEnd()) {
1056 if (inherited) {
1057 props.append(inheritProperties(it));
1058 } else {
1059 props.append(it->properties);
1060 }
1061 }
1062 sought = currentIndex + it->numChars(false);
1063 }
1064 }
1065
1066 return props;
1067}
KoSvgTextProperties inheritProperties(KisForest< KoSvgTextContentElement >::depth_first_tail_iterator it)

References d, inheritProperties(), KisForestDetail::siblingCurrent(), and KisForestDetail::size().

◆ Q_DECLARE_FLAGS()

KoSvgTextShape::Q_DECLARE_FLAGS ( DebugElements ,
DebugElement  )

◆ relayout() [1/2]

void KoSvgTextShape::relayout ( )

◆ relayout() [2/2]

void KoSvgTextShape::relayout ( ) const

Create a new text layout for the current content of the text shape chunks tree. The user should always call relayout() after every change in the text shapes hierarchy.

Definition at line 2609 of file KoSvgTextShape.cpp.

2610{
2611 d->relayout();
2612}

References d.

◆ relayoutIsBlocked()

bool KoSvgTextShape::relayoutIsBlocked ( ) const

relayoutIsBlocked

Returns
whether automatic relayout is blocked, as are updates to shape listeners.

Definition at line 2009 of file KoSvgTextShape.cpp.

2010{
2011 return d->isLoading;
2012}

References d.

◆ removeShapesFromContours()

void KoSvgTextShape::removeShapesFromContours ( QList< KoShape * > shapes,
bool callUpdate = true,
bool cleanup = true )

removeShapesFromContours Remove list of shapes from any of the internal lists.

Parameters
shapes– shapes to remove.
update– whether to call an update.
cleanup– whether to cleanup the textdata.

Definition at line 2394 of file KoSvgTextShape.cpp.

2395{
2396 Q_FOREACH(KoShape *shape, shapes) {
2397 if (shape) {
2398 d->removeTextPathId(d->textData.childBegin(), shape->name());
2399 shape->removeDependee(this);
2400 d->shapesInside.removeAll(shape);
2401 d->shapesSubtract.removeAll(shape);
2402 d->textPaths.removeAll(shape);
2403
2404 }
2405 d->shapeGroup->removeShape(shape);
2406 }
2407 if (cleanup) {
2408 d->cleanUp(d->textData);
2409 }
2410 if (callUpdate) {
2411 notifyChanged(); // notify shape manager that our geometry has changed
2412 if (!d->isLoading) {
2413 d->updateTextWrappingAreas();
2414 }
2415 d->updateInternalShapesList();
2417 update();
2418 }
2419}

References KoShape::ContentChanged, d, KoShape::name(), KoShape::notifyChanged(), KoShape::removeDependee(), KoShape::shapeChangedPriv(), and KoShape::update().

◆ removeText()

bool KoSvgTextShape::removeText ( int & index,
int & length )

removeText Where insert text explicitly uses a cursorposition, remove text uses a string index. It will modify these values so that...

  • Whole code points are deleted at any time, avoiding no dangling surrogates.
  • Graphemes don't end with Zero-width-joiners, as that can lead to the grapheme merging with the next.
  • Variation selectors are deleted along their base.
  • regional sequences are deleted in pairs.
    Parameters
    index- index (not cursorpos!) of the start position.
    length- total length of text to remove.
    Returns
    whether it was successful.

Definition at line 952 of file KoSvgTextShape.cpp.

953{
954 bool success = false;
955 if (index < -1) {
956 return success;
957 }
958 int currentLength = length;
959 int endLength = 0;
960 while (currentLength > 0) {
961 int currentIndex = 0;
962
963 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, index, true);
964 if (it != d->textData.depthFirstTailEnd()) {
965 int offset = index > currentIndex? index - currentIndex: 0;
966 int size = it->numChars(false);
967 it->removeText(offset, currentLength);
968 int diff = size - it->numChars(false);
969 currentLength -= diff;
970 endLength += diff;
971
972 if (index >= currentIndex) {
973 index = currentIndex + offset;
974 }
975
976 d->removeTransforms(d->textData, index, endLength);
977
978 success = true;
979 } else {
980 currentLength = -1;
981 }
982 }
983 if (success) {
984 length = endLength;
987 }
988 return success;
989}

References KoShape::ContentChanged, d, length(), KoShape::notifyChanged(), KoShape::shapeChangedPriv(), and size().

◆ removeTextPathId()

static void KoSvgTextShape::removeTextPathId ( KisForest< KoSvgTextContentElement >::child_iterator parent,
const QString & name )
inlinestatic

removeTextPathId Remove the text path id with the given name from the toplevel elements.

Definition at line 1393 of file KoSvgTextShape_p.h.

1393 {
1394 for (auto it = childBegin(parent); it != childEnd(parent); it++) {
1395 if (it->textPathId == name) {
1396 it->textPathId = QString();
1397 break;
1398 }
1399 }
1400 }

◆ removeTransforms()

static void KoSvgTextShape::removeTransforms ( KisForest< KoSvgTextContentElement > & tree,
const int start,
const int length )
inlinestatic

removeTransforms Remove all local SVG character transforms in a certain range. Local transforms are influenced by whitespace collapse and whether they are set to unicode codepoints, and they also accumulate from parent to child. This function removes all local transforms in a certain section.

Parameters
tree– tree to remove transforms from.
start– start at which to remove transforms.
length– end to remove from.

Definition at line 943 of file KoSvgTextShape_p.h.

943 {
944 QString all;
945 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all, true);
946
947 auto root = tree.childBegin();
948 removeTransformsImpl(root, 0, start, length, collapsedCharacters);
949 }
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....

References KisForestDetail::Forest< T >::childBegin(), and length().

◆ removeTransformsFromRange()

void KoSvgTextShape::removeTransformsFromRange ( const int startPos,
const int endPos )

Remove local transforms from the given range.

Definition at line 1471 of file KoSvgTextShape.cpp.

1472{
1473 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1474 return;
1475 }
1476 const int startIndex = d->getCursorPos(qMin(startPos, endPos)).index;
1477 const int endIndex = d->getCursorPos(qMax(startPos, endPos)).index;
1478
1479 d->removeTransforms(d->textData, startIndex, endIndex-startIndex);
1480
1481 KoSvgTextShape::Private::cleanUp(d->textData);
1482 notifyChanged();
1484}

References KoShape::ContentChanged, d, KoShape::notifyChanged(), and KoShape::shapeChangedPriv().

◆ removeTransformsImpl()

static int KoSvgTextShape::removeTransformsImpl ( KisForest< KoSvgTextContentElement >::child_iterator currentTextElement,
const int globalIndex,
const int start,
const int length,
const QVector< bool > collapsedCharacters )
inlinestatic

removeTransformsImpl recursive function that handles removing local transforms in a certain range. Used by removeTransform.

Definition at line 956 of file KoSvgTextShape_p.h.

956 {
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);
962 }
963 } else {
964 currentLength = currentTextElement->text.size();
965 }
966
967 if (!currentTextElement->localTransformations.isEmpty()) {
968 int transformOffset = 0;
969 int transformOffsetEnd = 0;
970
971 for (int i = globalIndex; i < globalIndex + currentLength; i++) {
972 if (i >= collapsedCharacters.size()) break;
973 if (i < start) {
974 transformOffset += collapsedCharacters.at(i)? 0: 1;
975 }
976 if (i < start + length) {
977 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
978 } else {
979 break;
980 }
981 }
982 if (transformOffset < currentTextElement->localTransformations.size()) {
983 int length = qBound(0, transformOffsetEnd-transformOffset, qMax(0, currentTextElement->localTransformations.size()-transformOffset));
984 currentTextElement->localTransformations.remove(transformOffset,
985 length);
986 }
987
988 }
989 return currentLength;
990 }

References length().

◆ resolvedTransformsForTree()

static QVector< KoSvgText::CharTransformation > KoSvgTextShape::resolvedTransformsForTree ( KisForest< KoSvgTextContentElement > & tree,
bool shapesInside = false,
bool includeBidiControls = false )
inlinestatic

Definition at line 1115 of file KoSvgTextShape_p.h.

1115 {
1116 QString all;
1117 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, all, false, includeBidiControls);
1118 QVector<CharacterResult> result(all.size());
1119 int globalIndex = 0;
1120 KoSvgTextProperties props = tree.childBegin()->properties;
1124 bool isHorizontal = mode == KoSvgText::HorizontalTB;
1125 bool isWrapped = (props.hasProperty(KoSvgTextProperties::InlineSizeId)
1126 || shapesInside);
1127 QVector<KoSvgText::CharTransformation> resolvedTransforms(all.size());
1128 resolveTransforms(tree.childBegin(), all, result, globalIndex,
1129 isHorizontal, isWrapped, false, resolvedTransforms,
1131 false);
1132 return resolvedTransforms;
1133 }
@ WritingModeId
KoSvgText::WritingMode.
QVariant propertyOrDefault(PropertyId id) const
static void resolveTransforms(KisForest< KoSvgTextContentElement >::child_iterator currentTextElement, QString text, QVector< CharacterResult > &result, int &currentIndex, bool isHorizontal, bool wrapped, bool textInPath, QVector< KoSvgText::CharTransformation > &resolved, QVector< bool > collapsedChars, const KoSvgTextProperties resolvedProps, bool withControls=true)

References KisForestDetail::Forest< T >::childBegin(), KoSvgTextProperties::defaultProperties(), KoSvgTextProperties::hasProperty(), KoSvgText::HorizontalTB, KoSvgTextProperties::inheritFrom(), KoSvgTextProperties::InlineSizeId, KoSvgTextProperties::propertyOrDefault(), and KoSvgTextProperties::WritingModeId.

◆ resolveTransforms()

static void KoSvgTextShape::resolveTransforms ( KisForest< KoSvgTextContentElement >::child_iterator currentTextElement,
QString text,
QVector< CharacterResult > & result,
int & currentIndex,
bool isHorizontal,
bool wrapped,
bool textInPath,
QVector< KoSvgText::CharTransformation > & resolved,
QVector< bool > collapsedChars,
const KoSvgTextProperties resolvedProps,
bool withControls = true )
static

◆ saveHtml()

bool KoSvgTextShape::saveHtml ( HtmlSavingContext & context)

Definition at line 1812 of file KoSvgTextShape.cpp.

1813{
1814 bool success = true;
1816 for (auto it = d->textData.compositionBegin(); it != d->textData.compositionEnd(); it++) {
1817 if (it.state() == KisForestDetail::Enter) {
1818 QMap<QString, QString> shapeSpecificStyles;
1819
1820 if (it == d->textData.compositionBegin()) {
1821 context.shapeWriter().startElement("p", false);
1822 } else {
1823 context.shapeWriter().startElement("span", false);
1824 }
1825 KoSvgTextProperties ownProperties = it->properties.ownProperties(parentProps.last(),
1826 it == d->textData.compositionBegin());
1827 parentProps.append(ownProperties);
1828 QMap<QString, QString> attributes = ownProperties.convertToSvgTextAttributes();
1829 if (it == d->textData.compositionBegin())
1830 attributes.insert(ownProperties.convertParagraphProperties());
1831 bool addedFill = false;
1832 if (attributes.size() > 0) {
1833 QString styleString;
1834 for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
1835 if (QString(it.key().toLatin1().data()).contains("text-anchor")) {
1836 QString val = it.value();
1837 if (it.value()=="middle") {
1838 val = "center";
1839 } else if (it.value()=="end") {
1840 val = "right";
1841 } else {
1842 val = "left";
1843 }
1844 styleString.append("text-align")
1845 .append(": ")
1846 .append(val)
1847 .append(";" );
1848 } else if (QString(it.key().toLatin1().data()).contains("fill")) {
1849 styleString.append("color")
1850 .append(": ")
1851 .append(it.value())
1852 .append(";" );
1853 addedFill = true;
1854 } else if (QString(it.key().toLatin1().data()).contains("font-size")) {
1855 QString val = it.value();
1856 styleString.append(it.key().toLatin1().data())
1857 .append(": ")
1858 .append(val)
1859 .append(";" );
1860 } else {
1861 styleString.append(it.key().toLatin1().data())
1862 .append(": ")
1863 .append(it.value())
1864 .append(";" );
1865 }
1866 }
1867 if (ownProperties.hasProperty(KoSvgTextProperties::FillId) && !addedFill) {
1868 KoColorBackground *b = dynamic_cast<KoColorBackground *>(it->properties.background().data());
1869 if (b) {
1870 styleString.append("color")
1871 .append(": ")
1872 .append(b->color().name())
1873 .append(";" );
1874 }
1875 }
1876 context.shapeWriter().addAttribute("style", styleString);
1877
1878 if (d->childCount(siblingCurrent(it)) == 0) {
1879 debugFlake << "saveHTML" << this << it->text;
1880 // After adding all the styling to the <p> element, add the text
1881 context.shapeWriter().addTextNode(it->text);
1882 }
1883 }
1884 } else {
1885 parentProps.pop_back();
1886 context.shapeWriter().endElement();
1887 }
1888 }
1889 return success;
1890}
#define debugFlake
Definition FlakeDebug.h:15
KoXmlWriter & shapeWriter()
Provides access to the shape writer.
QMap< QString, QString > convertToSvgTextAttributes() const
QMap< QString, QString > convertParagraphProperties() const
convertParagraphProperties some properties only apply to the root shape, so we write those separately...
void startElement(const char *tagName, bool indentInside=true)
void addTextNode(const QString &str)
void endElement()
void addAttribute(const char *attrName, const QString &value)
Definition KoXmlWriter.h:61

References KoXmlWriter::addAttribute(), KoXmlWriter::addTextNode(), KoSvgTextProperties::convertParagraphProperties(), KoSvgTextProperties::convertToSvgTextAttributes(), d, debugFlake, KoSvgTextProperties::defaultProperties(), KoXmlWriter::endElement(), KisForestDetail::Enter, KoSvgTextProperties::FillId, KoSvgTextProperties::hasProperty(), KoSvgTextProperties::properties(), HtmlSavingContext::shapeWriter(), and KoXmlWriter::startElement().

◆ saveSvg()

bool KoSvgTextShape::saveSvg ( SvgSavingContext & context)
overridevirtual

Saves SVG data.

Reimplemented from SvgShape.

Definition at line 1729 of file KoSvgTextShape.cpp.

1730{
1731 bool success = false;
1732
1733 QList<KoShape*> visibleShapes;
1734 Q_FOREACH(KoShape *shape, d->internalShapes()) {
1735 if (shape->isVisible(false)) {
1736 visibleShapes.append(shape);
1737 }
1738 }
1739 const bool writeGroup = !(visibleShapes.isEmpty() || context.strippedTextMode());
1740 if (writeGroup) {
1741 context.shapeWriter().startElement("g", false);
1742 context.shapeWriter().addAttribute("id", context.createUID("group"));
1743 context.shapeWriter().addAttribute(KoSvgTextShape_TEXTCONTOURGROUP, "true");
1744
1746 SvgWriter writer(visibleShapes);
1747 writer.saveDetached(context);
1748 }
1749 for (auto it = d->textData.compositionBegin(); it != d->textData.compositionEnd(); it++) {
1750 if (it.state() == KisForestDetail::Enter) {
1751 bool isTextPath = false;
1752 QMap<QString, QString> shapeSpecificStyles;
1753 if (!it->textPathId.isEmpty()) {
1754 isTextPath = true;
1755 }
1756 if (it == d->textData.compositionBegin()) {
1757 context.shapeWriter().startElement("text", false);
1758
1759 if (!context.strippedTextMode()) {
1760 context.shapeWriter().addAttribute("id", context.getID(this));
1761
1762 // save the version to distinguish from the buggy Krita version
1763 // 2: Wrong font-size.
1764 // 3: Wrong font-size-adjust.
1765 context.shapeWriter().addAttribute("krita:textVersion", 3);
1766
1767 if (visibleShapes.isEmpty()) {
1769 }
1770 SvgStyleWriter::saveSvgStyle(this, context);
1771 } else {
1772 SvgStyleWriter::saveSvgFill(this->background(), false, this->outlineRect(), this->size(), this->absoluteTransformation(), context);
1773 SvgStyleWriter::saveSvgStroke(this->stroke(), context);
1775 inheritPaintOrder(), context, true);
1776 }
1777 shapeSpecificStyles = this->shapeTypeSpecificStyles(context);
1778 } else {
1779 if (isTextPath) {
1780 context.shapeWriter().startElement("textPath", false);
1781 } else {
1782 context.shapeWriter().startElement("tspan", false);
1783 }
1784 SvgStyleWriter::saveSvgBasicStyle(it->properties.property(KoSvgTextProperties::Visibility, true).toBool(),
1785 it->properties.property(KoSvgTextProperties::Opacity, 0).toReal(),
1786 it->properties.property(KoSvgTextProperties::PaintOrder,
1787 QVariant::fromValue(paintOrder())
1789 !it->properties.hasProperty(KoSvgTextProperties::PaintOrder), context, true);
1790
1791 }
1792
1793 KoShape *textPath = KoSvgTextShape::Private::textPathByName(it->textPathId, d->textPaths);
1794 success = it->saveSvg(context,
1795 it == d->textData.compositionBegin(),
1796 d->childCount(siblingCurrent(it)) == 0,
1797 shapeSpecificStyles,
1798 textPath);
1799 } else {
1800 if (it == d->textData.compositionBegin()) {
1801 SvgStyleWriter::saveMetadata(this, context);
1802 }
1803 context.shapeWriter().endElement();
1804 }
1805 }
1806 if (writeGroup) {
1807 context.shapeWriter().endElement();
1808 }
1809 return success;
1810}
float value(const T *src, size_t ch)
#define KoSvgTextShape_TEXTCONTOURGROUP
bool inheritPaintOrder() const
inheritPaintOrder
Definition KoShape.cpp:710
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:797
QSharedPointer< KoShapeBackground > background() const override
QVector< PaintOrder > paintOrder() const override
paintOrder
QMap< QString, QString > shapeTypeSpecificStyles(SvgSavingContext &context) const
QString createUID(const QString &base)
Create a unique id from the specified base text.
QScopedPointer< KoXmlWriter > shapeWriter
QString getID(const KoShape *obj)
Returns the unique id for the given shape.
static void saveSvgFill(QSharedPointer< KoShapeBackground > background, const bool fillRuleEvenOdd, const QRectF outlineRect, const QSizeF size, const QTransform absoluteTransform, SvgSavingContext &context)
Saves fill style of specified shape.
static void saveSvgBasicStyle(const bool isVisible, const qreal transparency, const QVector< KoShape::PaintOrder > paintOrder, bool inheritPaintorder, SvgSavingContext &context, bool textShape=false)
Saves only stroke, fill and transparency of the shape.
static void saveSvgStyle(KoShape *shape, SvgSavingContext &context)
Saves the style of the specified shape.
static void saveMetadata(const KoShape *shape, SvgSavingContext &context)
static void saveSvgStroke(KoShapeStrokeModelSP, SvgSavingContext &context)
Saves stroke style of specified shape.
static void writeTransformAttributeLazy(const QString &name, const QTransform &transform, KoXmlWriter &shapeWriter)
Writes a transform as an attribute name iff the transform is not empty.
Definition SvgUtil.cpp:124
Implements exporting shapes to SVG.
Definition SvgWriter.h:33

References KoShape::absoluteTransformation(), background(), SvgSavingContext::createUID(), d, KisForestDetail::Enter, SvgSavingContext::getID(), KoShape::inheritPaintOrder(), KoShape::isVisible(), KoSvgTextShape_TEXTCONTOURGROUP, KoSvgTextProperties::Opacity, outlineRect(), KoSvgTextProperties::PaintOrder, paintOrder(), SvgWriter::saveDetached(), SvgStyleWriter::saveMetadata(), SvgStyleWriter::saveSvgBasicStyle(), SvgStyleWriter::saveSvgFill(), SvgStyleWriter::saveSvgStroke(), SvgStyleWriter::saveSvgStyle(), shapeTypeSpecificStyles(), SvgSavingContext::shapeWriter, size(), SvgSavingContext::strippedTextMode, stroke(), KoShape::transformation(), value(), KoSvgTextProperties::Visibility, and SvgUtil::writeTransformAttributeLazy().

◆ selectionBoxes()

QPainterPath KoSvgTextShape::selectionBoxes ( int pos,
int anchor )

selectionBoxes returns all selection boxes for a given range. Range will be normalized internally.

Parameters
pos– the main cursor pos.
anchor– the anchor from which the selection is calculated.
Returns
a winding-fill style QPainterPath will all boxes added as subpaths.

Definition at line 693 of file KoSvgTextShape.cpp.

694{
695 int start = qMin(pos, anchor);
696 int end = qMax(pos, anchor);
697 end = qMin(d->cursorPos.size()-1, end);
698
699 if (start == end || start < 0) {
700 return QPainterPath();
701 }
702
703 QPainterPath p;
704 p.setFillRule(Qt::WindingFill);
705 for (int i = start+1; i <= end; i++) {
706 CursorPos cursorPos = d->getCursorPos(i);
707 CharacterResult res = d->result.at(cursorPos.cluster);
708 const QTransform tf = res.finalTransform();
709 QLineF first = res.cursorInfo.caret;
710 QLineF last = first;
711 if (res.cursorInfo.rtl) {
712 last.translate(res.cursorInfo.offsets.value(cursorPos.offset-1, res.advance));
713 first.translate(res.cursorInfo.offsets.value(cursorPos.offset, QPointF()));
714 } else {
715 first.translate(res.cursorInfo.offsets.value(cursorPos.offset-1, QPointF()));
716 last.translate(res.cursorInfo.offsets.value(cursorPos.offset, res.advance));
717 }
718 QPolygonF poly;
719 poly << first.p1() << first.p2() << last.p2() << last.p1() << first.p1();
720 p.addPolygon(tf.map(poly));
721 }
722
723 return p;
724}

References CharacterResult::advance, KoShape::anchor(), CursorInfo::caret, CharacterResult::cursorInfo, cursorPos, d, CharacterResult::finalTransform(), CursorInfo::offsets, p, and CursorInfo::rtl.

◆ setBackground()

void KoSvgTextShape::setBackground ( QSharedPointer< KoShapeBackground > background)
overridevirtual

Set the background of the shape. A shape background can be a plain color, a gradient, a pattern, be fully transparent or have a complex fill. Setting such a background will allow the shape to be filled and will be able to tell if it is transparent or not.

If the shape inherited the background from its parent, its stops inheriting it, that is inheritBackground property resets to false.

Parameters
backgroundthe new shape background.

Reimplemented from KoShape.

Definition at line 1576 of file KoSvgTextShape.cpp.

1577{
1578 if (KisForestDetail::size(d->textData) == 0) {
1579 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1580 }
1581 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::FillId,
1582 QVariant::fromValue(KoSvgText::BackgroundProperty(background)));
1583
1585 notifyChanged();
1586}

References background(), KoShape::BackgroundChanged, d, KoSvgTextProperties::FillId, KoShape::notifyChanged(), KoShape::shapeChangedPriv(), and KisForestDetail::size().

◆ setCharacterTransformsFromLayout()

void KoSvgTextShape::setCharacterTransformsFromLayout ( )

setCharacterTransformsFromLayout Converts the text to a prepositioned SVG 1.1 text. This changes the textType();

Definition at line 1713 of file KoSvgTextShape.cpp.

1714{
1715 if (d->result.isEmpty()) return;
1716 d->setTransformsFromLayout(d->textData, d->result);
1717 d->cleanUp(d->textData);
1718 //d->applyWhiteSpace(d->textData, true);
1719 KoSvgTextProperties props = this->propertiesForPos(-1);
1723
1724 setPropertiesAtPos(-1, props);
1725}

References d, KoSvgTextProperties::InlineSizeId, propertiesForPos(), KoSvgTextProperties::removeProperty(), setPropertiesAtPos(), KoSvgTextProperties::TextCollapseId, and KoSvgTextProperties::TextWrapId.

◆ setCharacterTransformsOnRange()

bool KoSvgTextShape::setCharacterTransformsOnRange ( const int startPos,
const int endPos,
const QVector< QPointF > positions,
const QVector< qreal > rotateDegrees,
const bool deltaPosition = true )

setCharacterTransformsOnRange Set SVG 1.1 style character transforms on the given range. Will not work when the shape is auto wrapping.

Parameters
startPos– start of range
endPos– end of range
positions– positions, in shape coordinates.
rotations– rotations, in degrees.
deltaPosition– whether to calculate and set the delta positions.
Returns
whether successful.

Definition at line 1252 of file KoSvgTextShape.cpp.

1253{
1254 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1255 return false;
1256 }
1257 const int startIndex = d->getCursorPos(qMin(startPos, endPos)).index;
1258 int endIndex = d->getCursorPos(qMax(startPos, endPos)).index;
1259 if (startIndex == endIndex) {
1260 endIndex += 1;
1261 while(d->result.at(endIndex).middle) {
1262 endIndex += 1;
1263 if (endIndex > d->result.size()) break;
1264 }
1265 }
1266
1267 bool changed = false;
1268
1269 QVector<KoSvgText::CharTransformation> resolvedTransforms = Private::resolvedTransformsForTree(d->textData, !shapesInside().isEmpty(), true);
1270 Private::removeTransforms(d->textData, startIndex, endIndex-startIndex);
1271 QPointF totalStartDelta;
1272 QPointF anchorAbsolute;
1273 QPointF anchorCssPos;
1274
1277
1278 const CharacterResult startRes = d->result.value(startIndex);
1279 const QPointF startAdvance = startRes.cursorInfo.rtl? startRes.advance: QPointF();
1280
1281 if (deltaPosition) {
1282 for (int i = 0; i< startIndex; i++) {
1283 KoSvgText::CharTransformation tf = resolvedTransforms.value(i);
1284 if (tf.xPos) {
1285 totalStartDelta.setX(0);
1286 anchorAbsolute.setX(*tf.xPos);
1287 }
1288 if (tf.yPos) {
1289 totalStartDelta.setY(0);
1290 anchorAbsolute.setY(*tf.yPos);
1291 }
1292 if (tf.startsNewChunk()) {
1293 const CharacterResult res = d->result.value(i);
1294 anchorCssPos = res.cssPosition;
1295 }
1296 totalStartDelta += tf.relativeOffset();
1297 }
1298 } else {
1299 bool rtl = (dir == KoSvgText::DirectionRightToLeft);
1300 QPointF positionAtVisualEnd = (rtl? d->result.first(): d->result.last()).finalPosition;
1302 anchorAbsolute = positionAtVisualEnd;
1303 } else if (anchor == KoSvgText::AnchorMiddle) {
1304 anchorAbsolute = positionAtVisualEnd/2;
1305 }
1306 }
1307
1308 int currentIndex = 0;
1309 QPointF accumulatedOffset;
1310 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
1311 if (KoSvgTextShape::Private::childCount(siblingCurrent(it)) > 0 || !it->textPathId.isEmpty()) {
1312 continue;
1313 }
1314
1315 int endContentElement = it->finalResultIndex;
1316
1317 if (endContentElement >= startIndex && currentIndex <= endIndex) {
1318
1320 int addressableOffset = 0;
1321 for (int i = currentIndex; (i < endContentElement); i++) {
1322 const CharacterResult res = d->result.value(i);
1323 if (!res.addressable) {
1324 addressableOffset += 1;
1325 continue;
1326 }
1327
1328 const int transformIndex = (i - startIndex) - addressableOffset;
1329 KoSvgText::CharTransformation tf = resolvedTransforms.value(i, KoSvgText::CharTransformation());
1330
1331 // Function to get the delta position.
1332 auto getDelta = [res, totalStartDelta, accumulatedOffset, anchorAbsolute, anchorCssPos, startAdvance] (QPointF pos) -> QPointF {
1333 QPointF delta = pos - (res.textPathAndAnchoringOffset + anchorAbsolute + res.textLengthOffset);
1334 delta -= (totalStartDelta + accumulatedOffset + (res.cssPosition-anchorCssPos) + startAdvance);
1335 return delta;
1336 };
1337 // Function to get absolute position.
1338 auto getAbsolute = [res, tf, anchorAbsolute] (QPointF pos) -> QPointF {
1339 QPointF p = pos - (res.textPathAndAnchoringOffset - anchorAbsolute) - tf.relativeOffset();
1340 return p;
1341 };
1342
1343 if (i < startIndex) {
1344 if (!deltaPosition) {
1345 // Because we don't split the text content element, we need to set the absolute pos for every preceding transform.
1346 const QPointF p = getAbsolute(res.finalPosition);
1347 if (!tf.xPos) {
1348 tf.xPos = p.x();
1349 }
1350 if (!tf.yPos) {
1351 tf.yPos = p.y();
1352 }
1353 }
1354 transforms << tf;
1355 continue;
1356 }
1357
1358 if (i >= endIndex) {
1359 if (i == endIndex) {
1360 // Counter transform to keep unselected characters at the same pos.
1361 if (deltaPosition && !tf.startsNewChunk()) {
1362 QPointF delta = getDelta(res.finalPosition);
1363 tf.dxPos = delta.x();
1364 tf.dyPos = delta.y();
1365 } else {
1366 const QPointF p = getAbsolute(res.finalPosition) - anchorAbsolute;
1367 tf.xPos = p.x();
1368 tf.yPos = p.y();
1369 }
1370 if (!tf.rotate) {
1371 tf.rotate = 0.0;
1372 }
1373 }
1374 transforms << tf;
1375 continue;
1376 }
1377
1378 if (rotateDegrees.size()+startIndex > i) {
1379 tf.rotate = kisDegreesToRadians(rotateDegrees.value(transformIndex, tf.rotate? *tf.rotate: rotateDegrees.last()));
1380 }
1381 if (positions.size()+startIndex > i) {
1382 const QPointF pos = positions.value(transformIndex, QPointF());
1383
1384 if (deltaPosition) {
1385 if (tf.startsNewChunk()) {
1386 anchorAbsolute = tf.absolutePos();
1387 totalStartDelta = tf.relativeOffset();
1388 anchorCssPos = res.cssPosition;
1389 }
1390
1391 QPointF delta = getDelta(pos);
1392 tf.dxPos = delta.x();
1393 tf.dyPos = delta.y();
1394
1395 if (tf.startsNewChunk()) {
1396 accumulatedOffset = QPointF();
1397 totalStartDelta = tf.relativeOffset();
1398 } else {
1399 accumulatedOffset += tf.relativeOffset();
1400 }
1401 } else {
1402 const QPointF delta = getAbsolute(pos);
1403 tf.xPos = delta.x();
1404 tf.yPos = delta.y();
1405 accumulatedOffset = pos - res.finalPosition;
1406 }
1407
1408 }
1409
1410 transforms << tf;
1411 }
1412 it->localTransformations = transforms;
1413 changed = true;
1414 }
1415 currentIndex = it->finalResultIndex;
1416 if (currentIndex > endIndex) {
1417 break;
1418 }
1419 }
1420 const CharacterResult res = d->result.last();
1421
1422 if (changed) {
1423 KoSvgTextShape::Private::cleanUp(d->textData);
1424 notifyChanged();
1426 }
1427
1428 return changed;
1429}
T kisDegreesToRadians(T degrees)
Definition kis_global.h:176
TextAnchor
Where the text is anchored for SVG 1.1 text and 'inline-size'.
Definition KoSvgText.h:79
@ AnchorEnd
Anchor right for LTR, left for RTL.
Definition KoSvgText.h:82
@ AnchorMiddle
Anchor to the middle.
Definition KoSvgText.h:81
QPointF textPathAndAnchoringOffset
Offset caused by textPath and anchoring.
QPointF cssPosition
the position in accordance with the CSS specs, as opossed to the SVG spec.
QPointF textLengthOffset
offset caused by textLength
boost::optional< qreal > yPos
Definition KoSvgText.h:606
boost::optional< qreal > xPos
Definition KoSvgText.h:605

References KoSvgText::CharTransformation::absolutePos(), CharacterResult::addressable, CharacterResult::advance, KoShape::anchor(), KoSvgText::AnchorEnd, KoSvgText::AnchorMiddle, KoShape::ContentChanged, CharacterResult::cssPosition, CharacterResult::cursorInfo, d, KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, KoSvgText::CharTransformation::dxPos, KoSvgText::CharTransformation::dyPos, CharacterResult::finalPosition, kisDegreesToRadians(), KoShape::notifyChanged(), p, KoSvgText::CharTransformation::relativeOffset(), KoSvgText::CharTransformation::rotate, CursorInfo::rtl, KoShape::shapeChangedPriv(), shapesInside, KoSvgText::CharTransformation::startsNewChunk(), KoSvgTextProperties::TextAnchorId, CharacterResult::textLengthOffset, CharacterResult::textPathAndAnchoringOffset, textProperties(), KoSvgText::CharTransformation::xPos, and KoSvgText::CharTransformation::yPos.

◆ setFontMatchingDisabled()

void KoSvgTextShape::setFontMatchingDisabled ( const bool disable)

setDisableFontMatching

Parameters
disablefont matching when retrieving fonts for text layout (if possible). This speeds up text layout, but should only be done if there's only one font necessary and it can be found with the KoFFWWSconverter.

Definition at line 2014 of file KoSvgTextShape.cpp.

2015{
2016 d->disableFontMatching = disable;
2017}

References d.

◆ setMemento() [1/2]

void KoSvgTextShape::setMemento ( const KoSvgTextShapeMementoSP memento)

Set the text data and layout info, reset listening cursors to 0.

Definition at line 1944 of file KoSvgTextShape.cpp.

1945{
1946 setMementoImpl(memento);
1947 if (d->bulkActionState) {
1948 d->bulkActionState->layoutSetFromMemento = true;
1949 }
1950 notifyChanged();
1953}
void notifyCursorPosChanged(int pos, int anchor)
Notify that the cursor position has changed.
void notifyMarkupChanged()
Notify that the markup has changed.
void setMementoImpl(const KoSvgTextShapeMementoSP memento)

References d, KoShape::notifyChanged(), notifyCursorPosChanged(), notifyMarkupChanged(), and setMementoImpl().

◆ setMemento() [2/2]

void KoSvgTextShape::setMemento ( const KoSvgTextShapeMementoSP memento,
int pos,
int anchor )

Set the text data, layout info and also adjust any listening cursors.

Definition at line 1955 of file KoSvgTextShape.cpp.

1956{
1957 const bool shapeOffsetBefore = (textProperties().hasProperty(KoSvgTextProperties::ShapeMarginId)
1959 setMementoImpl(memento);
1960 const bool shapeOffsetAfter = (textProperties().hasProperty(KoSvgTextProperties::ShapeMarginId)
1962 if (shapeOffsetBefore || shapeOffsetAfter) {
1963 if (d->bulkActionState) {
1964 d->bulkActionState->contourHasChanged = true;
1965 } else {
1966 d->updateTextWrappingAreas();
1967 }
1968 } else {
1969 if (d->bulkActionState) {
1970 d->bulkActionState->layoutSetFromMemento = true;
1971 }
1972 }
1973 notifyChanged();
1976}

References KoShape::anchor(), d, KoSvgTextProperties::hasProperty(), KoShape::notifyChanged(), notifyCursorPosChanged(), notifyMarkupChanged(), setMementoImpl(), KoSvgTextProperties::ShapeMarginId, KoSvgTextProperties::ShapePaddingId, and textProperties().

◆ setMementoImpl()

void KoSvgTextShape::setMementoImpl ( const KoSvgTextShapeMementoSP memento)
private

Definition at line 1914 of file KoSvgTextShape.cpp.

1915{
1916 // TODO: add an assert that all linked shpaes in memento are present in
1917 // the current state of d->textPaths. That is the responsibility of
1918 // KoSvgTextAddRemoveShapeCommandImpl to prepare the shapes for us
1919
1920 KoSvgTextShapeMementoImpl *impl = dynamic_cast<KoSvgTextShapeMementoImpl*>(memento.data());
1921 if (impl) {
1922 d->textData = impl->textData;
1923 d->result = impl->result;
1924 d->lineBoxes = impl->lineBoxes;
1925 d->cursorPos = impl->cursorPos;
1926 d->logicalToVisualCursorPos = impl->logicalToVisualCursorPos;
1927 d->plainText = impl->plainText;
1928 d->isBidi = impl->isBidi;
1929 d->initialTextPosition = impl->initialTextPosition;
1930
1931 // Ensure that any text paths exist.
1932 auto root = d->textData.childBegin();
1933 for (auto child = childBegin(root); child != childEnd(root); child++) {
1934 if (!child->textPathId.isEmpty()) {
1935 KIS_SAFE_ASSERT_RECOVER(Private::textPathByName(child->textPathId, d->textPaths)) {
1936 qDebug() << "missing path is" << child->textPathId;
1937 child->textPathId = QString();
1938 }
1939 }
1940 }
1941 }
1942}
QVector< LineBox > lineBoxes
QMap< int, int > logicalToVisualCursorPos
KisForest< KoSvgTextContentElement > textData
QVector< CharacterResult > result
QVector< CursorPos > cursorPos
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126

References KoSvgTextShapeMementoImpl::cursorPos, d, KoSvgTextShapeMementoImpl::initialTextPosition, KoSvgTextShapeMementoImpl::isBidi, KIS_SAFE_ASSERT_RECOVER, KoSvgTextShapeMementoImpl::lineBoxes, KoSvgTextShapeMementoImpl::logicalToVisualCursorPos, KoSvgTextShapeMementoImpl::plainText, KoSvgTextShapeMementoImpl::result, and KoSvgTextShapeMementoImpl::textData.

◆ setPaintOrder()

void KoSvgTextShape::setPaintOrder ( KoShape::PaintOrder first,
KoShape::PaintOrder second )
overridevirtual

setPaintOrder set the paint order. As there's only three entries in any given paintorder, you only need to have the first and second entry to set it.

Parameters
firstfirst thing to paint
secondsecond thing to paint.

Reimplemented from KoShape.

Definition at line 1614 of file KoSvgTextShape.cpp.

1615{
1616 if (KisForestDetail::size(d->textData) == 0) {
1617 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1618 }
1619 KIS_SAFE_ASSERT_RECOVER_RETURN(first != second);
1621
1622 if (first != Fill) {
1623 if (order.at(1) == first) {
1624 order[1] = order[0];
1625 order[0] = first;
1626 } else if (order.at(2) == first) {
1627 order[2] = order[0];
1628 order[0] = first;
1629 }
1630 }
1631 if (second != first && second != Stroke) {
1632 if (order.at(2) == second) {
1633 order[2] = order[1];
1634 order[1] = second;
1635 }
1636 }
1637 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::PaintOrder,
1638 QVariant::fromValue(order));
1639 setInheritPaintOrder(false);
1640}
static QVector< PaintOrder > defaultPaintOrder()
default paint order as per SVG specification
Definition KoShape.cpp:699
void setInheritPaintOrder(bool value)
setInheritPaintOrder set inherit paint order.
Definition KoShape.cpp:705
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References d, KoShape::defaultPaintOrder(), KoShape::Fill, KIS_SAFE_ASSERT_RECOVER_RETURN, KoSvgTextProperties::PaintOrder, KoShape::setInheritPaintOrder(), and KisForestDetail::size().

◆ setPropertiesAtPos()

void KoSvgTextShape::setPropertiesAtPos ( int pos,
KoSvgTextProperties properties )

setPropertiesAtPos will set the properties at pos.

Parameters
pos
properties

Definition at line 1069 of file KoSvgTextShape.cpp.

1070{
1071 if (pos < 0 || d->cursorPos.isEmpty()) {
1072 if (KisForestDetail::size(d->textData)) {
1073 d->textData.childBegin()->properties = properties;
1074 }
1075 notifyChanged();
1077 return;
1078 }
1079 CursorPos cursorPos = d->getCursorPos(pos);
1080 CharacterResult res = d->result.at(cursorPos.cluster);
1081 int currentIndex = 0;
1082 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, res.plaintTextIndex);
1083 if (it != d->textData.depthFirstTailEnd()) {
1084 it->properties = properties;
1085 notifyChanged();
1087 }
1088}

References KoShape::ContentChanged, cursorPos, d, KoShape::notifyChanged(), CharacterResult::plaintTextIndex, KoShape::shapeChangedPriv(), and KisForestDetail::size().

◆ setRelayoutBlocked()

void KoSvgTextShape::setRelayoutBlocked ( const bool disable)

Definition at line 2004 of file KoSvgTextShape.cpp.

2005{
2006 d->isLoading = disable;
2007}

References d.

◆ setResolution()

void KoSvgTextShape::setResolution ( qreal xRes,
qreal yRes )
overridevirtual

Update the image resolution in pixels per inch. Shapes should override this if they need to know the image resolution.

Parameters
xRes
yRes

Reimplemented from KoShape.

Definition at line 247 of file KoSvgTextShape.cpp.

248{
249 int roundedX = qRound(xRes);
250 int roundedY = qRound(yRes);
251 if (roundedX != d->xRes || roundedY != d->yRes) {
252 d->xRes = roundedX;
253 d->yRes = roundedY;
254 relayout();
255 }
256}

References d, relayout(), xRes, and yRes.

◆ setShapesInside()

void KoSvgTextShape::setShapesInside ( QList< KoShape * > shapesInside)

setShapesInside

Parameters
shapesInsidethe list of shapes to make up the content area.

Definition at line 2346 of file KoSvgTextShape.cpp.

2347{
2348 removeShapesFromContours(d->shapesInside, false);
2350}
void addShapeContours(QList< KoShape * > shapes, const bool inside=true)
addShapesContours Add shapes to the contours that make up the wrapping area.
void removeShapesFromContours(QList< KoShape * > shapes, bool callUpdate=true, bool cleanup=true)
removeShapesFromContours Remove list of shapes from any of the internal lists.

References addShapeContours(), d, removeShapesFromContours(), and shapesInside.

◆ setShapesSubtract()

void KoSvgTextShape::setShapesSubtract ( QList< KoShape * > shapesSubtract)

setShapesSubtract

Parameters
shapesSubtractthe list of shapes that subtract from the wrapping area.

Definition at line 2562 of file KoSvgTextShape.cpp.

2563{
2564 removeShapesFromContours(d->shapesSubtract, false);
2566}

References addShapeContours(), d, removeShapesFromContours(), and shapesSubtract.

◆ setSize()

void KoSvgTextShape::setSize ( const QSizeF & size)
overridevirtual

Resize the shape.

Parameters
sizethe new size of the shape. This is different from scaling as scaling is a so called secondary operation which is comparable to zooming in instead of changing the size of the basic shape. Easiest example of this difference is that using this method will not distort the size of pattern-fills and strokes.

We don't have any contours, just scale (and distort) the text, as if "Scale Styles" were activated

We have only one contour that has no transformations, so we can just pass the resize to it and preserve all the contours intact

When resizing the shapes via setSize() we expect the method to scale the shapes bluntly in the parent's coordinate system. So, when resizing embedded shapes we should just anchor them to the origin of the text-shape's coordinate system.

When we have transformed (scaled, rotated and etc.) shapes internally, we cannot pass resize action to them, because it is impossible to mimic the parent resize by mere resizing the child shapes. We would have to add shear to them [1].

That is why we just add a scaling transform to every contour shape while keeping the text unscaled. Keeping the text unscaled covers the case when the user want to simply transform a text balloon without contours.

[1] Proof of the "impossible to pass the resize" claim

That comes from the matrix equation to the child-parent transformation. Here is an example for a rotated child:

Original transformation is:

parentPoint = childPoint * ChildRotate,

now apply Scale to both sides, to simulate scale in the parent's coordinate system:

parentPoint * Scale = childPoint * ChildRotate * Scale,

now we need to preserve the original child's transformation to be intact, which was ChildRotate. To achieve that, add (ChildRotate.inverted() * ChildRotate) at the end of the equation:

parentPoint * Scale = childPoint * ChildRotate * Scale * (ChildRotate.inverted() * ChildRotate),

now regroup the matrices:

parentPoint * Scale = childPoint * (ChildRotate * Scale * ChildRotate.inverted()) * ChildRotate,

notice matrix (ChildRotate * Scale * ChildRotate.inverted()) is the one that we should apply to the child shape in setSize() to preserve its transform. This matrix can not be a scale matrix, it will always recieve shear components for any non-trivial ChildRotate values.

Reimplemented from KoShape.

Definition at line 2140 of file KoSvgTextShape.cpp.

2141{
2142 const QRectF oRect = this->outlineRect();
2143 const QSizeF oldSize = oRect.size();
2144
2145 if (size == oldSize) return;
2146
2147 // don't try to divide by zero
2148 if (oldSize.isEmpty()) return;
2149
2150 const qreal scaleX = size.width() / oldSize.width();
2151 const qreal scaleY = size.height() / oldSize.height();
2152
2153 if (d->internalShapes().isEmpty()) {
2159 const qreal scaleX = size.width() / oldSize.width();
2160 const qreal scaleY = size.height() / oldSize.height();
2161
2162 this->scale(scaleX, scaleY);
2163 // TODO: use scaling function for kosvgtextproperties when styles presets are merged.
2164 notifyChanged();
2166 } else {
2167 if (!d->textPaths.isEmpty()) return;
2168
2169 const bool allInternalShapeAreTranslatedOnly = [this] () {
2170 Q_FOREACH(KoShape *shape, d->internalShapes()) {
2171 if (shape->transformation().type() > QTransform::TxTranslate) {
2172 return false;
2173 }
2174 }
2175 return true;
2176 }();
2177
2178 if (allInternalShapeAreTranslatedOnly) {
2183 Q_FOREACH (KoShape *internalShape, d->internalShapes()) {
2190 const QPointF stillPoint = this->absoluteTransformation().map(QPointF());
2191 const bool useGlobalMode = false;
2192 const bool usePostScaling = false;
2193 KoFlake::resizeShapeCommon(internalShape,
2194 scaleX,
2195 scaleY,
2196 stillPoint,
2197 useGlobalMode,
2198 usePostScaling,
2199 QTransform());
2200 }
2201
2202 const QSizeF realNewSize = outlineRect().size();
2203 KoShape::setSize(realNewSize);
2204 } else {
2248 const QTransform scale = QTransform::fromScale(scaleX, scaleY);
2249
2250 Q_FOREACH (KoShape *shape, d->internalShapes()) {
2251 shape->setTransformation(shape->transformation() * scale);
2252 }
2253
2254 const QSizeF realNewSize = outlineRect().size();
2255 KoShape::setSize(realNewSize);
2256 }
2257 }
2258}
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:369
@ ScaleChanged
used after a scale()
Definition KoShape.h:95
void scale(qreal sx, qreal sy)
Scale the shape using the zero-point which is the top-left corner.
Definition KoShape.cpp:210
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:249
KRITAFLAKE_EXPORT void resizeShapeCommon(KoShape *shape, qreal scaleX, qreal scaleY, const QPointF &absoluteStillPoint, bool useGlobalMode, bool usePostScaling, const QTransform &postScalingCoveringTransform)
Definition KoFlake.cpp:313

References KoShape::absoluteTransformation(), d, KoShape::notifyChanged(), outlineRect(), KoFlake::resizeShapeCommon(), KoShape::scale(), KoShape::ScaleChanged, KoShape::setSize(), KoShape::setTransformation(), KoShape::shapeChangedPriv(), size(), and KoShape::transformation().

◆ setStroke()

void KoSvgTextShape::setStroke ( KoShapeStrokeModelSP stroke)
overridevirtual

Set a new stroke, removing the old one. The stroke inheritance becomes disabled.

Parameters
strokethe new stroke, or 0 if there should be no stroke.

Reimplemented from KoShape.

Definition at line 1594 of file KoSvgTextShape.cpp.

1595{
1596 if (KisForestDetail::size(d->textData) == 0) {
1597 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1598 }
1599 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::StrokeId,
1600 QVariant::fromValue(KoSvgText::StrokeProperty(stroke)));
1602 notifyChanged();
1603}

References d, KoShape::notifyChanged(), KoShape::shapeChangedPriv(), KisForestDetail::size(), stroke(), KoShape::StrokeChanged, and KoSvgTextProperties::StrokeId.

◆ setTextPathOnRange()

bool KoSvgTextShape::setTextPathOnRange ( KoShape * textPath,
const int startPos = -1,
const int endPos = -1 )

setTextPathOnRange Set a text path on the specified range. In SVG text paths are always at the first child.

Parameters
textPath– TextPath to set.
posStart– Start of the range, as cursor pos.
posEnd– End of the range, as cursor pos.
Returns
whether successfull.

Definition at line 2436 of file KoSvgTextShape.cpp.

2437{
2438 const int finalPos = d->cursorPos.size() - 1;
2439 const int startIndex = (startPos == endPos && startPos < 0)? 0: d->getCursorPos(startPos).index;
2440 const int endIndex = (startPos == endPos && startPos < 0)? finalPos: d->getCursorPos(endPos).index;
2441
2442 Private::splitTree(d->textData, startIndex, false);
2443 Private::splitTree(d->textData, endIndex, true);
2444 int currentIndex = 0;
2445
2446 Private::makeTextPathNameUnique(d->textPaths, textPath);
2447 KoSvgTextContentElement textPathElement;
2448 textPathElement.textPathId = textPath->name();
2449 d->shapeGroup->addShape(textPath);
2450 d->textPaths.append(textPath);
2451 textPath->addDependee(this);
2452
2453
2454 if (KisForestDetail::depth(d->textData) == 1) {
2455 textPathElement.text = d->textData.childBegin()->text;
2459 Q_FOREACH(KoSvgTextProperties::PropertyId p, copyIds) {
2460 if (d->textData.childBegin()->properties.hasProperty(KoSvgTextProperties::TextDecorationLineId)) {
2461 textPathElement.properties.setProperty(p, d->textData.childBegin()->properties.property(p));
2462 d->textData.childBegin()->properties.removeProperty(p);
2463 }
2464 }
2465
2466 d->textData.childBegin()->text = QString();
2467 d->textData.insert(childEnd(d->textData.childBegin()), textPathElement);
2468 } else {
2469 // find nodes
2470 auto startElement = Private::findTextContentElementForIndex(d->textData, currentIndex, startIndex, true);
2471 currentIndex = 0;
2472 auto endElement = Private::findTextContentElementForIndex(d->textData, currentIndex, endIndex, true);
2473
2474 auto first = startElement.node()?Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(startElement))
2476 auto last = endElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(endElement))
2478
2479 // move children. we collect them before inserting the text path,
2480 // so we don't get iterator issues.
2482 auto textPathIt = textPathTree.insert(
2483 textPathTree.childEnd(),
2484 textPathElement);
2486 for (auto child = first;
2487 (child != last && child != childEnd(d->textData.childBegin()));
2488 child++) {
2489 if (!child->textPathId.isEmpty()) {
2490 Q_FOREACH(KoShape *shape, d->textPaths) {
2491 if (shape->name() == child->textPathId) {
2492 removeShapesFromContours({shape}, false, false);
2493 break;
2494 }
2495 }
2496 child->textPathId = QString();
2497 }
2498 movableChildren.append(child);
2499 }
2500 while (!movableChildren.isEmpty()) {
2501 auto child = movableChildren.takeLast();
2502 textPathTree.move(child, KisForestDetail::childBegin(textPathIt));
2503 }
2504 d->textData.move(textPathIt, last);
2505 }
2506 Private::cleanUp(d->textData);
2507
2508 d->updateInternalShapesList();
2509 notifyChanged();
2511 update();
2512 return true;
2513}
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...
Definition KisForest.h:943
child_iterator move(child_iterator subtree, child_iterator newPos)
move a subtree to new position Moves subtree into a new position pointer by newPos....
Definition KisForest.h:994
@ TextDecorationStyleId
KoSvgText::TextDecorationStyle.
@ TextDecorationLineId
Flags, KoSvgText::TextDecorations.
CursorPos getCursorPos(int pos)
int depth(typename Forest< T >::const_child_iterator beginIt, typename Forest< T >::const_child_iterator endIt)
Definition KisForest.h:1213
KoSvgTextProperties properties
The textProperties. This includes.
QString text
Plain text of the current node. Use insertText and removeText to manipulate it.

References KoShape::addDependee(), KisForestDetail::childBegin(), KisForestDetail::Forest< T >::childEnd(), KoShape::ContentChanged, d, KisForestDetail::depth(), KisForestDetail::Forest< T >::insert(), KisForestDetail::Forest< T >::move(), KoShape::name(), KoShape::notifyChanged(), p, KoSvgTextContentElement::properties, removeShapesFromContours(), KoSvgTextProperties::setProperty(), KoShape::shapeChangedPriv(), KisForestDetail::siblingCurrent(), KoSvgTextContentElement::text, KoSvgTextProperties::TextDecorationColorId, KoSvgTextProperties::TextDecorationLineId, KoSvgTextProperties::TextDecorationStyleId, KoSvgTextContentElement::textPathId, and KoShape::update().

◆ setTransformsFromLayout()

void KoSvgTextShape::setTransformsFromLayout ( KisForest< KoSvgTextContentElement > & tree,
const QVector< CharacterResult > layout )
inline

Definition at line 1199 of file KoSvgTextShape_p.h.

1199 {
1200 for (int i = 0; i< layout.size(); i++) {
1201 //split all anchored chunks, so we can set transforms on them.
1202 if (layout.at(i).anchored_chunk) {
1203 int plainTextIndex = layout.at(i).plaintTextIndex;
1204 splitContentElement(tree, plainTextIndex);
1205 }
1206 }
1207
1208 int globalIndex = 0;
1209 for (auto it = tree.childBegin(); it != tree.childEnd(); it++) {
1211 it->properties.propertyOrDefault(KoSvgTextProperties::WritingModeId).toInt());
1212 bool isHorizontal = mode == KoSvgText::HorizontalTB;
1213 setTransformsFromLayoutImpl(it, KoSvgTextProperties::defaultProperties(), layout, globalIndex, isHorizontal);
1214 }
1215 }
void setTransformsFromLayoutImpl(KisForest< KoSvgTextContentElement >::child_iterator current, const KoSvgTextProperties parentProps, const QVector< CharacterResult > layout, int &globalIndex, bool isHorizontal)
static bool splitContentElement(KisForest< KoSvgTextContentElement > &tree, int index, bool allowEmptyText=true)
splitContentElement split the contentElement in tree at index into two nodes.

References KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::childEnd(), KoSvgTextProperties::defaultProperties(), KoSvgText::HorizontalTB, and KoSvgTextProperties::WritingModeId.

◆ setTransformsFromLayoutImpl()

void KoSvgTextShape::setTransformsFromLayoutImpl ( KisForest< KoSvgTextContentElement >::child_iterator current,
const KoSvgTextProperties parentProps,
const QVector< CharacterResult > layout,
int & globalIndex,
bool isHorizontal )
inline

Definition at line 1217 of file KoSvgTextShape_p.h.

1219 {
1220 KoSvgTextProperties props = current->properties;
1221 props.inheritFrom(parentProps);
1222 if (!current->textPathId.isEmpty()) return; // When we're doing text-on-path, we're already in preformatted mode.
1223 for (auto it = childBegin(current); it!= childEnd(current); it++) {
1224 setTransformsFromLayoutImpl(it, props, layout, globalIndex, isHorizontal);
1225 }
1226
1227 if (current->text.isEmpty()) {
1228 current->localTransformations.clear();
1229 } else {
1231 const int length = current->numChars(true, props);
1232
1233 for (int i = globalIndex; i< globalIndex+length; i++) {
1234 CharacterResult result = layout.value(i);
1235
1236 if (!result.addressable) {
1237 continue;
1238 }
1240
1241 //TODO: Also split up content element if multiple anchored chunks.
1242 if (result.anchored_chunk) {
1243 int endIndex = 0;
1244 qreal shift = anchoredChunkShift(layout, isHorizontal, i, endIndex);
1245 QPointF offset = isHorizontal? QPointF(shift, 0): QPointF(0, shift);
1246 transform.xPos = result.finalPosition.x() - offset.x();
1247 transform.yPos = result.finalPosition.y() - offset.y();
1248 } else if (i > 0) {
1249 CharacterResult resultPrev = layout.value(i-1);
1250 QPointF offset = (result.finalPosition - result.cssPosition) - (resultPrev.finalPosition - resultPrev.cssPosition);
1251
1252 transform.dxPos = offset.x();
1253 transform.dyPos = offset.y();
1254 }
1255 transform.rotate = result.rotate;
1256
1257 transforms.append(transform);
1258 }
1259 current->localTransformations = transforms;
1260 current->text = current->text.split("\n").join(" ");
1261 globalIndex += length;
1262 }
1263 }
static qreal anchoredChunkShift(const QVector< CharacterResult > &result, const bool isHorizontal, const int start, int &end)

References CharacterResult::addressable, CharacterResult::anchored_chunk, CharacterResult::cssPosition, KoSvgText::CharTransformation::dxPos, KoSvgText::CharTransformation::dyPos, CharacterResult::finalPosition, KoSvgTextProperties::inheritFrom(), length(), KoSvgText::CharTransformation::rotate, CharacterResult::rotate, KoSvgText::CharTransformation::xPos, and KoSvgText::CharTransformation::yPos.

◆ shapeChanged()

void KoSvgTextShape::shapeChanged ( ChangeType type,
KoShape * shape )
overrideprotectedvirtual

A hook that allows inheriting classes to do something after a KoShape property changed This is called whenever the shape, position rotation or scale properties were altered.

Parameters
typean indicator which type was changed.
shapethe shape.

NOTE: we don't need to handle Deleted type for the shapes in d->dependees list here, becasue this function is called on the other side of the relation, i.e. in the actual "dependee". We handle that in Private::DependeesLifetimeListener.

Reimplemented from KoShape.

Definition at line 178 of file KoSvgTextShape.cpp.

179{
180 KoShape::shapeChanged(type, shape);
181
182 if (d->isLoading) {
183 return;
184 }
185
187
188 if ((d->shapesInside.contains(shape) || d->shapesSubtract.contains(shape) || d->textPaths.contains(shape))
189 && (transformationTypes.contains(type)
190 || type == ParameterChanged
191 || type == ParentChanged
192 || type == ContentChanged // for KoPathShape modifications
193 || type == Deleted)) {
194 if (type == Deleted) {
195 if (d->shapesInside.contains(shape)) {
196 d->shapesInside.removeAll(shape);
197 }
198 if (d->shapesSubtract.contains(shape)) {
199 d->shapesSubtract.removeAll(shape);
200 }
201 if (d->textPaths.contains(shape)) {
202 d->textPaths.removeAll(shape);
203 // TODO: remove ID from relevant text content element.
204 }
205 if (d->shapeGroup && d->shapeGroup->shapes().contains(shape)) {
206 d->shapeGroup->removeShape(shape);
207 }
208 d->updateInternalShapesList();
209 }
210
211 // Updates the contours and calls relayout.
212 // Would be great if we could compress the updates here somehow...
213 if (d->bulkActionState) {
214 d->bulkActionState->contourHasChanged = true;
215 } else {
216 d->updateTextWrappingAreas();
217 }
218
219 // NotifyChanged ensures that boundingRect() is called on this shape;
220 // it is NOT compressed by the bulk action, since boundingRect() is
221 // guaranteed to be valid during the whole bulk action
222 this->notifyChanged();
223 }
224 if ((!shape || shape == this)) {
225 if (type == ContentChanged) {
226 if (d->bulkActionState) {
227 d->bulkActionState->layoutHasChanged = true;
228 } else {
229 relayout();
230 }
231 } else if (transformationTypes.contains(type) || type == ParentChanged) {
232 d->shapeGroup->setTransformation(this->absoluteTransformation());
233 } else if (type == TextContourMarginChanged) {
234 if (d->bulkActionState) {
235 d->bulkActionState->contourHasChanged = true;
236 } else {
237 d->updateTextWrappingAreas();
238 }
239 }
240
241 // when calling shapeChangedImpl() on `this` shape, we call
242 // notifyChanged() manually at the calling site, so we shouldn't
243 // do that again here
244 }
245}
virtual void shapeChanged(ChangeType type, KoShape *shape=0)
Definition KoShape.cpp:1054
@ RotationChanged
used after a setRotation()
Definition KoShape.h:94
@ PositionChanged
used after a setPosition()
Definition KoShape.h:93
@ Deleted
the shape was deleted
Definition KoShape.h:101
@ ShearChanged
used after a shear()
Definition KoShape.h:96
@ ParentChanged
used after a setParent()
Definition KoShape.h:100
@ ParameterChanged
the shapes parameter has changed (KoParameterShape only)
Definition KoShape.h:105
@ SizeChanged
used after a setSize()
Definition KoShape.h:97
@ GenericMatrixChange
used after the matrix was changed without knowing which property explicitly changed
Definition KoShape.h:98

References KoShape::absoluteTransformation(), KoShape::ContentChanged, d, KoShape::Deleted, KoShape::GenericMatrixChange, KoShape::notifyChanged(), KoShape::ParameterChanged, KoShape::ParentChanged, KoShape::PositionChanged, relayout(), KoShape::RotationChanged, KoShape::ScaleChanged, KoShape::shapeChanged(), KoShape::ShearChanged, KoShape::SizeChanged, and KoShape::TextContourMarginChanged.

◆ shapeInContours()

bool KoSvgTextShape::shapeInContours ( KoShape * shape)

shapeInContours

Parameters
shape
Returns
whether a shape is in any contour.

Definition at line 2389 of file KoSvgTextShape.cpp.

2390{
2391 return (shape->parent() == d->shapeGroup.data());
2392}
KoShapeContainer * parent() const
Definition KoShape.cpp:857

References d, and KoShape::parent().

◆ shapesInside()

QList< KoShape * > KoSvgTextShape::shapesInside ( ) const

shapesInside

Returns
the list of shapes that make up the content area.

◆ shapesSubtract()

QList< KoShape * > KoSvgTextShape::shapesSubtract ( ) const

shapesSubtract

Returns
list of subtract shapes.

◆ shapeTypeSpecificStyles()

QMap< QString, QString > KoSvgTextShape::shapeTypeSpecificStyles ( SvgSavingContext & context) const

Right now we don't support showing glyphs outside the shape. Nor does Inkscape. Therefore being excplit about clipping these glyphs is preferable.

Definition at line 2583 of file KoSvgTextShape.cpp.

2584{
2585 QMap<QString, QString> map = this->textProperties().convertParagraphProperties();
2586 if (!d->shapesInside.isEmpty()) {
2587 QStringList shapesInsideList;
2588 Q_FOREACH(KoShape* shape, d->shapesInside) {
2589 QString id = (shape->isVisible(false) && !context.strippedTextMode())? context.getID(shape): SvgStyleWriter::embedShape(shape, context);
2590 shapesInsideList.append(QString("url(#%1)").arg(id));
2591 }
2592 map.insert("shape-inside", shapesInsideList.join(" "));
2595 map.insert("overflow", "clip");
2596 }
2597 if (!d->shapesSubtract.isEmpty()) {
2598 QStringList shapesInsideList;
2599 Q_FOREACH(KoShape* shape, d->shapesSubtract) {
2600 QString id = shape->isVisible(false)? context.getID(shape): SvgStyleWriter::embedShape(shape, context);
2601 shapesInsideList.append(QString("url(#%1)").arg(id));
2602 }
2603 map.insert("shape-subtract", shapesInsideList.join(" "));
2604 }
2605
2606 return map;
2607}
static QString embedShape(const KoShape *shape, SvgSavingContext &context)

References KoSvgTextProperties::convertParagraphProperties(), d, SvgStyleWriter::embedShape(), SvgSavingContext::getID(), KoShape::isVisible(), SvgSavingContext::strippedTextMode, and textProperties().

◆ singleNode()

bool KoSvgTextShape::singleNode ( ) const

singleNode Sometimes it is useful to know whether there's only a single text node for UX purposes.

Returns
whether there's only a single root node, or there's a full fledged tree.

Definition at line 1657 of file KoSvgTextShape.cpp.

1658{
1659 if (d->textData.empty()) return false;
1660 return (KisForestDetail::size(d->textData) == 1);
1661}

References d, and KisForestDetail::size().

◆ size()

QSizeF KoSvgTextShape::size ( ) const
overridevirtual

Get the size of the shape in pt.

The size is in shape coordinates.

Returns
the size of the shape as set by setSize()

Reimplemented from KoShape.

Definition at line 2134 of file KoSvgTextShape.cpp.

2135{
2136 // TODO: check if KoShape::m_d->size is consistent, check cache in KoShapeGroup::size()
2137 return outlineRect().size();
2138}

References outlineRect().

◆ splitContentElement()

static bool KoSvgTextShape::splitContentElement ( KisForest< KoSvgTextContentElement > & tree,
int index,
bool allowEmptyText = true )
inlinestatic

splitContentElement split the contentElement in tree at index into two nodes.

Parameters
tree– tree to work on.
index– index
allowEmptyText– when false, will return true without splitting the text content element, if the split text would be empty.
Returns
whether it was successful.

Definition at line 762 of file KoSvgTextShape_p.h.

762 {
763 int currentIndex = 0;
764
765 // If there's only a single root element, don't bother searching.
766 auto contentElement = depth(tree) == 1? tree.depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index, true);
767 if (contentElement == tree.depthFirstTailEnd()) return false;
768
769 bool suitableStartIndex = siblingCurrent(contentElement) == tree.childBegin()? index >= currentIndex: index > currentIndex;
770 bool suitableEndIndex = siblingCurrent(contentElement) == tree.childBegin()? true: index < currentIndex + contentElement->numChars(false);
771
772 if (suitableStartIndex && suitableEndIndex) {
774 duplicate.text = contentElement->text;
775 int start = index - currentIndex;
776 int length = contentElement->numChars(false) - start;
777 int zero = 0;
778 duplicate.removeText(start, length);
779
780 if (!allowEmptyText && (duplicate.text.isEmpty() || length == 0)) {
781 return true;
782 }
783
784 // TODO: handle localtransforms better; annoyingly, this requires whitespace handling
785
786 if (siblingCurrent(contentElement) != tree.childBegin()
787 && contentElement->textPathId.isEmpty()
788 && contentElement->textLength.isAuto
789 && contentElement->localTransformations.isEmpty()) {
790 contentElement->removeText(zero, start);
791 duplicate.properties = contentElement->properties;
792 tree.insert(siblingCurrent(contentElement), duplicate);
793 } else {
795 duplicate2.text = contentElement->text;
796 duplicate2.removeText(zero, start);
797 contentElement->text.clear();
798 tree.insert(childBegin(contentElement), duplicate);
799 tree.insert(childEnd(contentElement), duplicate2);
800 }
801 return true;
802 }
803 return false;
804 }
static KisForest< KoSvgTextContentElement >::depth_first_tail_iterator findTextContentElementForIndex(KisForest< KoSvgTextContentElement > &tree, int &currentIndex, int sought, bool skipZeroWidth=false)
findTextContentElementForIndex Finds the given leaf of the current tree-wide string index.
void removeText(int &start, int length)
removeText removes text,

References KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::depthFirstTailBegin(), KisForestDetail::Forest< T >::depthFirstTailEnd(), KisForestDetail::Forest< T >::insert(), length(), KoSvgTextContentElement::properties, KoSvgTextProperties::properties(), KoSvgTextContentElement::removeText(), and KoSvgTextContentElement::text.

◆ splitTree()

static void KoSvgTextShape::splitTree ( KisForest< KoSvgTextContentElement > & tree,
int index,
bool textPathAfterSplit )
inlinestatic

splitTree Split the whole hierarchy of nodes at the given index.

Parameters
tree- tree to split.
index- index to split at.
textPathAfterSplit- whether to put any found textPaths before or after the split.

Definition at line 813 of file KoSvgTextShape_p.h.

813 {
814 splitContentElement(tree, index, false);
815 int currentIndex = 0;
816 auto contentElement = depth(tree) == 1? tree.depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index, true);
817
818 // We're either at the start or end.
819 if (contentElement == tree.depthFirstTailEnd()) return;
820 if (siblingCurrent(contentElement) == tree.childBegin()) return;
821
822 auto lastNode = siblingCurrent(contentElement);
823 for (auto parentIt = KisForestDetail::hierarchyBegin(siblingCurrent(contentElement));
824 parentIt != KisForestDetail::hierarchyEnd(siblingCurrent(contentElement)); parentIt++) {
825 if (lastNode == siblingCurrent(parentIt)) continue;
826 if (siblingCurrent(parentIt) == tree.childBegin()) {
827 break;
828 }
829
830 if (lastNode != childBegin(siblingCurrent(parentIt))) {
832 duplicate.properties = parentIt->properties;
833 if (textPathAfterSplit) {
834 duplicate.textPathId = parentIt->textPathId;
835 duplicate.textPathInfo = parentIt->textPathInfo;
836 parentIt->textPathId = QString();
837 parentIt->textPathInfo = KoSvgText::TextOnPathInfo();
838 }
839 auto insert = siblingCurrent(parentIt);
840 insert ++;
841 auto it = tree.insert(insert, duplicate);
842
844 for (auto child = lastNode; child != childEnd(siblingCurrent(parentIt)); child++) {
845 movableChildren.append(child);
846 }
847 while(!movableChildren.isEmpty()) {
848 auto child = movableChildren.takeLast();
849 tree.move(child, childBegin(it));
850 }
851 lastNode = it;
852 } else {
853 lastNode = siblingCurrent(parentIt);
854 }
855 }
856 }
KoSvgText::TextOnPathInfo textPathInfo
Text path info for the text-on-path algorithm.

References KisForestDetail::Forest< T >::childBegin(), KisForestDetail::Forest< T >::depthFirstTailBegin(), KisForestDetail::Forest< T >::depthFirstTailEnd(), KisForestDetail::hierarchyBegin(), KisForestDetail::hierarchyEnd(), KisForestDetail::Forest< T >::insert(), KisForestDetail::Forest< T >::move(), KoSvgTextContentElement::properties, KoSvgTextProperties::properties(), KoSvgTextContentElement::textPathId, and KoSvgTextContentElement::textPathInfo.

◆ startBulkAction()

void KoSvgTextShape::startBulkAction ( )
overridevirtual

Called by the GUI code when it wants to execute some kind of a long action, which will result in multiple shapeChanged() callbacks to be delivered.

When started, the shape enters into an "bulk action" state as described in the class documentation.

Implements KoShapeBulkActionInterface.

Definition at line 2029 of file KoSvgTextShape.cpp.

2030{
2031 KIS_SAFE_ASSERT_RECOVER_RETURN(!d->bulkActionState);
2032 d->bulkActionState.emplace(boundingRect());
2033}

References boundingRect(), d, and KIS_SAFE_ASSERT_RECOVER_RETURN.

◆ startIndexOfIterator()

static bool KoSvgTextShape::startIndexOfIterator ( KisForest< KoSvgTextContentElement >::child_iterator parent,
KisForest< KoSvgTextContentElement >::child_iterator target,
int & currentIndex )
inlinestatic

Definition at line 1372 of file KoSvgTextShape_p.h.

1372 {
1373 for (auto child = KisForestDetail::childBegin(parent); child != KisForestDetail::childEnd(parent); child++) {
1374 if (child == target) {
1375 return true;
1376 } else if ((KisForestDetail::childBegin(child) != KisForestDetail::childEnd(child))) {
1377 if (startIndexOfIterator(child, target, currentIndex)) {
1378 return true;
1379 }
1380 } else {
1381 currentIndex += numChars(child);
1382 }
1383 }
1384 return false;
1385 }
KisMagneticGraph::vertex_descriptor target(typename KisMagneticGraph::edge_descriptor e, KisMagneticGraph g)
static bool startIndexOfIterator(KisForest< KoSvgTextContentElement >::child_iterator parent, KisForest< KoSvgTextContentElement >::child_iterator target, int &currentIndex)

References KisForestDetail::childBegin(), KisForestDetail::childEnd(), and target().

◆ stretchGlyphOnPath()

static QPainterPath KoSvgTextShape::stretchGlyphOnPath ( const QPainterPath & glyph,
const QPainterPath & path,
bool isHorizontal,
qreal offset,
bool isClosed )
static

◆ stroke()

KoShapeStrokeModelSP KoSvgTextShape::stroke ( ) const
overridevirtual

Returns the currently set stroke, or 0 if there is no stroke.

Returns
the currently set stroke, or 0 if there is no stroke.

Reimplemented from KoShape.

Definition at line 1588 of file KoSvgTextShape.cpp.

1589{
1590 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1592}

References d, KoSvgTextProperties::properties(), KoSvgTextProperties::property(), KisForestDetail::size(), and KoSvgTextProperties::StrokeId.

◆ textOutline()

KoShape * KoSvgTextShape::textOutline ( ) const

textOutline This turns the text object into non-text KoShape(s) to the best of its abilities.

Returns
a single KoPathShape if only a single path is necessary, or multiple KoShapes (Paths, Images, and Rectangles with Masks are all possible) inside a KoShapeGroup.

Definition at line 2310 of file KoSvgTextShape.cpp.

2311{
2312 KoShape *shape = nullptr;
2313 int currentIndex = 0;
2314 if (!d->result.empty()) {
2315 shape = d->collectPaths(this, d->result, currentIndex);
2316 }
2317
2318 return shape;
2319}

References d.

◆ textPathByName()

static KoShape * KoSvgTextShape::textPathByName ( QString name,
QList< KoShape * > textPaths )
inlinestatic

Definition at line 573 of file KoSvgTextShape_p.h.

573 {
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;
576 }
QSharedDataPointer< SharedData > s
Definition KoShape.h:977

◆ textPathsAtRange()

QList< KoShape * > KoSvgTextShape::textPathsAtRange ( const int startPos = -1,
const int endPos = -1 )

textPathsAtRange Get a list of textPaths at the given range. This includes textPaths whose node is only partially overlapped by the range.

Parameters
posStart– Start of the range, as cursor pos.
posEnd– End of the range, as cursor pos.
Returns
list of KoShapes that are text paths.

Definition at line 2515 of file KoSvgTextShape.cpp.

2516{
2517 const int finalPos = d->cursorPos.size() - 1;
2518 const int startIndex = (startPos == endPos && startPos < 0)? 0: d->getCursorPos(startPos).index;
2519 const int endIndex = (startPos == endPos && startPos < 0)? finalPos: d->getCursorPos(endPos).index;
2521 int currentIndex = 0;
2522 auto startElement = Private::findTextContentElementForIndex(d->textData, currentIndex, startIndex, true);
2523 currentIndex = 0;
2524 auto endElement = Private::findTextContentElementForIndex(d->textData, currentIndex, endIndex, true);
2525
2526 auto first = startElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(startElement))
2528 auto last = endElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(endElement))
2530 if (last != childEnd(d->textData.childBegin())) {
2531 last++;
2532 }
2533 for (auto child = first; (child != last && child != KisForestDetail::siblingEnd(first)); child++) {
2534 if (KoShape *path = Private::textPathByName(child->textPathId, d->textPaths)) {
2535 textPaths.append(path);
2536 }
2537 }
2538 return textPaths;
2539}

References d, KisForestDetail::siblingCurrent(), KisForestDetail::siblingEnd(), and textPaths.

◆ textProperties()

KoSvgTextProperties KoSvgTextShape::textProperties ( ) const

Definition at line 1562 of file KoSvgTextShape.cpp.

1563{
1564 return KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1565}

References d, KoSvgTextProperties::properties(), and KisForestDetail::size().

◆ textType()

KoSvgTextShape::TextType KoSvgTextShape::textType ( ) const

textType This enum gives an indication of what kind of text this shape is. The different text types are a bit blurry as SVG allows a mixutre to provide fallback information. When such fallback is in place, this will only return the primary text type, that is, TextInShape before InlineWrap and InlineWrap before PrePositioned/Preformatted. This primarily exists to give UI feedback.

Returns
estimated TextType

Definition at line 2321 of file KoSvgTextShape.cpp.

2322{
2324 if (!d->shapesInside.isEmpty()) {
2325 return TextType::TextInShape;
2326 } else if (!inlineSize.isAuto) {
2327 return TextType::InlineWrap;
2328 } else {
2329 bool textSpaceCollapse = false;
2330 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
2331 KoSvgText::TextSpaceCollapse collapse = KoSvgText::TextSpaceCollapse(it->properties.propertyOrDefault(KoSvgTextProperties::TextCollapseId).toInt());
2332 if (collapse == KoSvgText::Collapse || collapse == KoSvgText::PreserveSpaces) {
2333 textSpaceCollapse = true;
2334 break;
2335 }
2336 if (!it->localTransformations.isEmpty()) {
2337 textSpaceCollapse = true;
2338 break;
2339 }
2340 }
2342 }
2344}
@ Collapse
Collapse white space sequences into a single character.
Definition KoSvgText.h:97
@ PreserveSpaces
required for 'xml:space="preserve"' emulation.
Definition KoSvgText.h:102

References KoSvgText::Collapse, d, KoSvgTextProperties::InlineSizeId, InlineWrap, KoSvgText::AutoValue::isAuto, PreformattedText, PrePositionedText, KoSvgText::PreserveSpaces, KoSvgTextProperties::propertyOrDefault(), KoSvgTextProperties::TextCollapseId, TextInShape, and textProperties().

◆ textWrappingAreas()

QList< QPainterPath > KoSvgTextShape::textWrappingAreas ( ) const

textWrappingAreas The text wrapping areas are computed from shapesInside() and shapesSubtract(), as well as the text properties ShapeMargin and ShapePadding. This returns the computed wrapping areas, in the local coordinates of the shape.

@seealso outline()

Returns
a list of computed text wrapping areas.

Definition at line 2568 of file KoSvgTextShape.cpp.

2569{
2570 return d->currentTextWrappingAreas;
2571}

References d.

◆ topLevelNodeForPos()

KoSvgTextNodeIndex KoSvgTextShape::topLevelNodeForPos ( int pos) const

topLevelNodeForPos Get, if possible, an index for the child element of the root at pos. If not possible, returns an index for the root. This is used primarily for text-on-path.

Parameters
pos– cursor position at which to find the index.
Returns
if the text only has a root, it will still return the index for the root, but otherwise it will return a child element of root at pos.

Definition at line 1527 of file KoSvgTextShape.cpp.

1528{
1529 auto candidate = d->textData.childBegin();
1530 if (d->isLoading || d->cursorPos.isEmpty()) return d->createTextNodeIndex(candidate);
1531 if (childBegin(d->textData.childBegin()) != childEnd(d->textData.childBegin())) {
1532 candidate = childBegin(d->textData.childBegin());
1533 }
1534 const int index = d->getCursorPos(pos).index;
1535 int currentIndex = 0;
1536
1537 auto e = Private::findTextContentElementForIndex(d->textData, currentIndex, index, true);
1538 if (e == d->textData.depthFirstTailEnd()) {
1539 return d->createTextNodeIndex(candidate);
1540 }
1541
1542 auto element = KisForestDetail::siblingCurrent(e);
1543 auto parent = Private::findTopLevelParent(d->textData.childBegin(), element);
1544 if (parent == childEnd(d->textData.childBegin())) return d->createTextNodeIndex(candidate);
1545
1546 return d->createTextNodeIndex(parent);
1547}

References d, KoShape::Private::parent, and KisForestDetail::siblingCurrent().

◆ underlines()

QPainterPath KoSvgTextShape::underlines ( int pos,
int anchor,
KoSvgText::TextDecorations decor,
KoSvgText::TextDecorationStyle style,
qreal minimum,
bool thick )

Definition at line 726 of file KoSvgTextShape.cpp.

727{
728 int start = qMin(pos, anchor);
729 int end = qMax(pos, anchor);
730
731 if (start == end || start < 0 || end >= d->cursorPos.size()) {
732 return QPainterPath();
733 }
734 QPainterPathStroker stroker;
735
737 stroker.setCapStyle(Qt::FlatCap);
738 if (style == KoSvgText::Solid) {
739 stroker.setDashPattern(Qt::SolidLine);
740 } else if (style == KoSvgText::Dashed) {
741 stroker.setDashPattern(Qt::DashLine);
742 } else if (style == KoSvgText::Dotted) {
743 stroker.setDashPattern(Qt::DotLine);
744 } else {
745 stroker.setDashPattern(Qt::SolidLine);
746 }
747
748 QPainterPath underPath;
749 QPainterPath overPath;
750 QPainterPath middlePath;
751 qint32 strokeWidth = 0;
752 QPointF inset = mode == KoSvgText::HorizontalTB? QPointF(minimum*0.5, 0): QPointF(0, minimum*0.5);
753 for (int i = start+1; i <= end; i++) {
754 CursorPos pos = d->getCursorPos(i);
755 CharacterResult res = d->result.at(pos.cluster);
756 strokeWidth += res.metrics.underlineThickness;
757 const QTransform tf = res.finalTransform();
758 QPointF first = res.cursorInfo.caret.p1();
759 QPointF last = first;
760 if (res.cursorInfo.rtl) {
761 last += res.cursorInfo.offsets.value(pos.offset-1, res.advance);
762 first += res.cursorInfo.offsets.value(pos.offset, QPointF());
763 if (i == start+1) {
764 first -= inset;
765 }
766 if (i == end) {
767 last += inset;
768 }
769 } else {
770 first += res.cursorInfo.offsets.value(pos.offset-1, QPointF());
771 last += res.cursorInfo.offsets.value(pos.offset, res.advance);
772 if (i == start+1) {
773 first += inset;
774 }
775 if (i == end) {
776 last -= inset;
777 }
778 }
779
780 if (decor.testFlag(KoSvgText::DecorationUnderline)){
781 underPath.moveTo(tf.map(first));
782 underPath.lineTo(tf.map(last));
783 }
784 QPointF diff = res.cursorInfo.caret.p2() - res.cursorInfo.caret.p1();
785 if (decor.testFlag(KoSvgText::DecorationOverline)){
786 overPath.moveTo(tf.map(first+diff));
787 overPath.lineTo(tf.map(last+diff));
788 }
789 if (decor.testFlag(KoSvgText::DecorationLineThrough)){
790 middlePath.moveTo(tf.map(first+(diff*0.5)));
791 middlePath.lineTo(tf.map(last+(diff*0.5)));
792 }
793 }
794
795 const qreal freetypePixelsToPt = (1.0 / 64.0) * (72. / qMin(d->xRes, d->yRes));
796 const qreal width = strokeWidth > 0 ? qMax(qreal(strokeWidth/qMax(1, end-(start+1)))*freetypePixelsToPt, minimum): minimum;
797
798 stroker.setWidth(thick? width*2: width);
799
800 QPainterPath final;
801 if (decor.testFlag(KoSvgText::DecorationUnderline)){
802 final.addPath(stroker.createStroke(underPath));
803 }
804 if (decor.testFlag(KoSvgText::DecorationOverline)){
805 final.addPath(stroker.createStroke(overPath));
806 }
807 if (decor.testFlag(KoSvgText::DecorationLineThrough)){
808 final.addPath(stroker.createStroke(middlePath));
809 }
810
811 return final;
812}
@ Solid
Draw a solid line.Ex: --—.
Definition KoSvgText.h:266
@ Dashed
Draw a dashed line. Ex: - - - - -.
Definition KoSvgText.h:269
@ Dotted
Draw a dotted line. Ex: .....
Definition KoSvgText.h:268
KoSvgText::FontMetrics metrics
Fontmetrics for current font, in Freetype scanline coordinates.
qint32 underlineThickness
underline thickness from font.
Definition KoSvgText.h:357

References CharacterResult::advance, KoShape::anchor(), CursorInfo::caret, CursorPos::cluster, CharacterResult::cursorInfo, d, KoSvgText::Dashed, KoSvgText::DecorationLineThrough, KoSvgText::DecorationOverline, KoSvgText::DecorationUnderline, KoSvgText::Dotted, CharacterResult::finalTransform(), KoSvgText::HorizontalTB, CharacterResult::metrics, CursorPos::offset, CursorInfo::offsets, CursorInfo::rtl, KoSvgText::Solid, textProperties(), KoSvgText::FontMetrics::underlineThickness, and KoSvgTextProperties::WritingModeId.

◆ updateInternalShapesList()

void KoSvgTextShape::updateInternalShapesList ( )
inline

Definition at line 538 of file KoSvgTextShape_p.h.

538 {
539 if (shapeGroup) {
540 internalShapesPainter->setShapes(shapeGroup->shapes());
541 }
542 }

◆ updateShapeGroup()

void KoSvgTextShape::updateShapeGroup ( )
inline

Definition at line 522 of file KoSvgTextShape_p.h.

522 {
523 Q_FOREACH(KoShape *shape, shapeGroup->shapes()) {
524 shapeGroup->removeShape(shape);
525 }
526 Q_FOREACH(KoShape *shape, shapesInside) {
527 shapeGroup->addShape(shape);
528 }
529 Q_FOREACH(KoShape *shape, shapesSubtract) {
530 shapeGroup->addShape(shape);
531 }
532 Q_FOREACH(KoShape *shape, textPaths) {
533 shapeGroup->addShape(shape);
534 }
537 }
void updateTextWrappingAreas()
updateShapeContours The current shape contours can be slow to compute, so this function calls computi...

◆ updateTextWrappingAreas()

void KoSvgTextShape::updateTextWrappingAreas ( )

updateShapeContours The current shape contours can be slow to compute, so this function calls computing them, and then calls relayout();

◆ wordEnd()

int KoSvgTextShape::wordEnd ( int pos)

wordEnd return the pos of the first wordbreak.

Parameters
pos– cursor position.
Returns
the first wordbreak or line end.

Definition at line 553 of file KoSvgTextShape.cpp.

554{
555 if (pos < 0 || pos >= d->cursorPos.size() || d->result.isEmpty() || d->cursorPos.isEmpty()) {
556 return pos;
557 }
558
559 int wordEnd = pos;
560 for (int i = pos; i < d->cursorPos.size(); i++) {
561 wordEnd = i;
562 CursorPos cursorPos = d->cursorPos.at(i);
563 bool isWhiteSpace = false;
564 const CharacterResult res = d->result.at(cursorPos.cluster);
565 const int pIndex = res.plaintTextIndex;
566 if (pIndex >= 0 && pIndex < d->plainText.size()) {
567 QChar c = d->plainText.at(pIndex);
568 isWhiteSpace = KoCssTextUtils::IsCssWordSeparator(QString(c)) || c.isSpace();
569 }
571 && (cursorPos.offset == 0 || cursorPos.offset+1 == res.cursorInfo.offsets.size())
572 && i > pos) {
573
574 if (isWhiteSpace) {
575 wordEnd = qMax(pos, wordEnd-1);
576 }
577 break;
578 }
579
580 // Also test the next cluster on whether it is a hardbreak. This is because hardbreaks by default get hidden.
581 if (i < d->cursorPos.size()-1 && i > pos) {
582 const CursorPos nextCursorPos = d->cursorPos.at(i+1);
583 bool found = false;
584 for (int j = cursorPos.cluster; j < nextCursorPos.cluster; j++) {
585 if (d->result.at(j).breakType == BreakType::HardBreak && d->result.at(j).addressable) {
586 wordEnd = qMax(pos, wordEnd);
587 found = true;
588 break;
589 }
590 }
591 if (found) {
592 break;
593 }
594 }
595 }
596
597 return wordEnd;
598}
static bool IsCssWordSeparator(QString grapheme)
IsCssWordSeparator CSS has a number of characters it considers word-separators, which are used in jus...
int wordEnd(int pos)
wordEnd return the pos of the first wordbreak.
bool isWhiteSpace(char c)

References CharacterResult::breakType, CursorPos::cluster, CharacterResult::cursorInfo, cursorPos, d, HardBreak, KoCssTextUtils::IsCssWordSeparator(), isWhiteSpace(), NoBreak, CursorInfo::offsets, plainText, CharacterResult::plaintTextIndex, and wordEnd().

◆ wordLeft()

int KoSvgTextShape::wordLeft ( int pos,
bool visual = false )

wordLeft return the cursorpos for the word left or the extreme of the line.

Parameters
posthe position.
visualwhether to flip for rtl.
Returns
the first pos before a wordbreak at the left.

Definition at line 362 of file KoSvgTextShape.cpp.

363{
364 //TODO: figure out preferred behaviour for wordLeft in RTL && visual.
365 Q_UNUSED(visual)
366 if (pos < 0 || pos > d->cursorPos.size()-1 || d->result.isEmpty() || d->cursorPos.isEmpty()) {
367 return pos;
368 }
371 return wordEnd(pos);
372 }
373 return wordStart(pos);
374}
int wordStart(int pos)
wordStart return the first pos before a wordbreak in the start direction.

References d, direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, textProperties(), wordEnd(), and wordStart().

◆ wordRight()

int KoSvgTextShape::wordRight ( int pos,
bool visual = false )

wordRight return the cursorpos for the word right or the extreme of the line.

Parameters
posthe position.
visualwhether to flip for rtl.
Returns
the first word break at the right.

Definition at line 376 of file KoSvgTextShape.cpp.

377{
378 Q_UNUSED(visual)
379 if (pos < 0 || pos > d->cursorPos.size()-1 || d->result.isEmpty() || d->cursorPos.isEmpty()) {
380 return pos;
381 }
384 return wordStart(pos);
385 }
386 return wordEnd(pos);
387}

References d, direction(), KoSvgTextProperties::DirectionId, KoSvgText::DirectionRightToLeft, textProperties(), wordEnd(), and wordStart().

◆ wordStart()

int KoSvgTextShape::wordStart ( int pos)

wordStart return the first pos before a wordbreak in the start direction.

Parameters
pos– cursor position
Returns
the first position before a wordbreak or the line start.

Definition at line 600 of file KoSvgTextShape.cpp.

601{
602 if (pos <= 0 || pos > d->cursorPos.size() || d->result.isEmpty() || d->cursorPos.isEmpty()) {
603 return pos;
604 }
605
606 int wordStart = pos;
607 for (int i = pos; i >= 0; i--) {
608 wordStart = i;
609 CursorPos cursorPos = d->getCursorPos(i);
610 const CharacterResult res = d->result.at(cursorPos.cluster);
612 && (cursorPos.offset == 0 || cursorPos.offset+1 == res.cursorInfo.offsets.size())
613 && i < pos) {
614 break;
615 }
616 // Also test the previous cluster on whether it is a hardbreak. This is because hardbreaks by default get hidden.
617 if (i > 1 && i < pos) {
618 const CursorPos prevCursorPos = d->getCursorPos(i-1);
619 bool found = false;
620 for (int j = cursorPos.cluster; j > prevCursorPos.cluster; j--) {
621 if (d->result.at(j).breakType == BreakType::HardBreak && d->result.at(j).addressable) {
622 wordStart = qMin(pos, i-1);
623 found = true;
624 break;
625 }
626 }
627 if (found) {
628 break;
629 }
630 }
631 }
632
633 return wordStart;
634}

References CharacterResult::breakType, CursorPos::cluster, CharacterResult::cursorInfo, cursorPos, d, HardBreak, NoBreak, CursorInfo::offsets, and wordStart().

◆ writingMode()

KoSvgText::WritingMode KoSvgTextShape::writingMode ( ) const

writingMode There's a number of places we need to check the writing mode to provide proper controls.

Returns
the writing mode of this text.

Definition at line 1647 of file KoSvgTextShape.cpp.

1648{
1650}

References textProperties(), and KoSvgTextProperties::WritingModeId.

Friends And Related Symbol Documentation

◆ KoSvgTextLoader

friend class KoSvgTextLoader
friend

Definition at line 684 of file KoSvgTextShape.h.

◆ TestSvgText

friend class TestSvgText
friend

Definition at line 683 of file KoSvgTextShape.h.

Member Data Documentation

◆ bulkActionState

std::optional<BulkActionState> KoSvgTextShape::bulkActionState

Definition at line 557 of file KoSvgTextShape_p.h.

◆ currentTextWrappingAreas

QList<QPainterPath> KoSvgTextShape::currentTextWrappingAreas

Definition at line 563 of file KoSvgTextShape_p.h.

◆ cursorPos

QVector<CursorPos> KoSvgTextShape::cursorPos

Definition at line 591 of file KoSvgTextShape_p.h.

◆ d

QScopedPointer<Private> KoSvgTextShape::d
private

Definition at line 711 of file KoSvgTextShape.h.

◆ disableFontMatching

bool KoSvgTextShape::disableFontMatching = false

Turn off font matching, which should speed up relayout slightly.

Definition at line 586 of file KoSvgTextShape_p.h.

◆ initialTextPosition

QPointF KoSvgTextShape::initialTextPosition = QPointF()

Definition at line 596 of file KoSvgTextShape_p.h.

◆ internalShapesPainter

QScopedPointer<KoShapePainter> KoSvgTextShape::internalShapesPainter

Definition at line 515 of file KoSvgTextShape_p.h.

◆ isBidi

bool KoSvgTextShape::isBidi = false

Definition at line 595 of file KoSvgTextShape_p.h.

◆ isLoading

bool KoSvgTextShape::isLoading = false

Turned on when loading in text data, blocks updates to shape listeners.

Definition at line 584 of file KoSvgTextShape_p.h.

◆ lineBoxes

QVector<LineBox> KoSvgTextShape::lineBoxes

Definition at line 589 of file KoSvgTextShape_p.h.

◆ logicalToVisualCursorPos

QMap<int, int> KoSvgTextShape::logicalToVisualCursorPos

Definition at line 592 of file KoSvgTextShape_p.h.

◆ plainText

QString KoSvgTextShape::plainText

Definition at line 594 of file KoSvgTextShape_p.h.

◆ result

QVector<CharacterResult> KoSvgTextShape::result

Definition at line 588 of file KoSvgTextShape_p.h.

◆ shapeGroup

QScopedPointer<KoShapeGroup> KoSvgTextShape::shapeGroup

Definition at line 516 of file KoSvgTextShape_p.h.

◆ shapesInside

QList< KoShape * > KoSvgTextShape::shapesInside

Definition at line 559 of file KoSvgTextShape_p.h.

◆ shapesSubtract

QList< KoShape * > KoSvgTextShape::shapesSubtract

Definition at line 560 of file KoSvgTextShape_p.h.

◆ textData

KisForest<KoSvgTextContentElement> KoSvgTextShape::textData

Definition at line 583 of file KoSvgTextShape_p.h.

◆ textPaths

QList<KoShape*> KoSvgTextShape::textPaths

Definition at line 561 of file KoSvgTextShape_p.h.

◆ xRes

int KoSvgTextShape::xRes = 72

Definition at line 512 of file KoSvgTextShape_p.h.

◆ yRes

int KoSvgTextShape::yRes = 72

Definition at line 513 of file KoSvgTextShape_p.h.


The documentation for this class was generated from the following files: