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 KoShape *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.
 
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)
 
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 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 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 451 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:135
QTransform transformation() const
Returns the shapes local transformation matrix.
Definition KoShape.cpp:383
virtual void updateAbsolute(const QRectF &rect) const
Definition KoShape.cpp:545
void setShapeId(const QString &id)
Definition KoShape.cpp:885
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:1026

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:1043
KoShapeManager * internalShapeManager() const
internalShapeManager

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

◆ ~Private()

KoSvgTextShape::~Private ( )
inline

Definition at line 496 of file KoSvgTextShape_p.h.

496 {
497
498 internalShapesPainter.reset();
499 Q_FOREACH(KoShape *shape, shapeGroup->shapes()) {
500 shapeGroup->removeShape(shape);
501 }
502 shapeGroup.reset();
503 qDeleteAll(shapesInside);
504 shapesInside.clear();
505 qDeleteAll(shapesSubtract);
506 shapesSubtract.clear();
507 qDeleteAll(textPaths);
508 textPaths.clear();
509 }
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 2336 of file KoSvgTextShape.cpp.

2337{
2338 Q_FOREACH(KoShape *shape, shapes) {
2339 if (d->textPaths.contains(shape)) {
2340 d->removeTextPathId(d->textData.childBegin(), shape->name());
2341 d->cleanUp(d->textData);
2342 d->textPaths.removeAll(shape);
2343 }
2344
2345 if (inside) {
2346 if (d->shapesSubtract.contains(shape)) {
2347 d->shapesSubtract.removeAll(shape);
2348 }
2349 d->shapesInside.append(shape);
2350 } else {
2351 if (d->shapesInside.contains(shape)) {
2352 d->shapesInside.removeAll(shape);
2353 }
2354 d->shapesSubtract.append(shape);
2355 }
2356 if (!d->shapeGroup->shapes().contains(shape)) {
2357 d->shapeGroup->addShape(shape);
2358 shape->addDependee(this);
2359 }
2360 }
2361
2362 notifyChanged(); // notify shape manager that our geometry has changed
2363
2364 if (!d->isLoading) {
2365 d->updateTextWrappingAreas();
2366 }
2367
2368 d->updateInternalShapesList();
2370 update();
2371}
virtual void update() const
Definition KoShape.cpp:534
void shapeChangedPriv(KoShape::ChangeType type)
Definition KoShape.cpp:104
@ 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:618
QString name() const
Definition KoShape.cpp:955

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 2525 of file KoSvgTextShape.cpp.

2526{
2527 auto root = d->textData.childBegin();
2528 if (root == d->textData.childEnd()) return;
2529 if (d->textPaths.contains(textPath)) return;
2530
2531 Private::makeTextPathNameUnique(d->textPaths, textPath);
2532 KoSvgTextContentElement textPathElement;
2533 textPathElement.textPathId = textPath->name();
2534 d->shapeGroup->addShape(textPath);
2535 d->textPaths.append(textPath);
2536 textPath->addDependee(this);
2537
2538 d->textData.insert(childEnd(root), textPathElement);
2539}
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 1057 of file KoSvgTextShape_p.h.

1057 {
1058 QString allText;
1059 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, allText, false);
1060
1061 auto end = std::make_reverse_iterator(tree.childBegin());
1062 auto begin = std::make_reverse_iterator(tree.childEnd());
1063
1064 for (; begin != end; begin++) {
1065 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1066 }
1067 if (convertToPreWrapped) {
1068 tree.childBegin()->properties.setProperty(KoSvgTextProperties::TextCollapseId, QVariant::fromValue(KoSvgText::Preserve));
1069 tree.childBegin()->properties.setProperty(KoSvgTextProperties::TextWrapId, QVariant::fromValue(KoSvgText::Wrap));
1070 }
1071 }
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 1073 of file KoSvgTextShape_p.h.

1073 {
1074 auto base = current.base();
1075 // It seems that .base() refers to the next entry instead of the pointer,
1076 // which is coherent with the template implementation of "operator*" here:
1077 // https://en.cppreference.com/w/cpp/iterator/reverse_iterator.html
1078 base--;
1079 if(base != siblingEnd(base)) {
1080 auto end = std::make_reverse_iterator(childBegin(base));
1081 auto begin = std::make_reverse_iterator(childEnd(base));
1082 for (; begin != end; begin++) {
1083 applyWhiteSpaceImpl(begin, collapsed, allText, convertToPreWrapped);
1084 }
1085 }
1086
1087 if (!current->text.isEmpty()) {
1088 const int total = current->text.size();
1089 QString currentText = allText.right(total);
1090
1091 for (int i = 0; i < total; i++) {
1092 const int j = total - (i+1);
1093 const bool col = collapsed.takeLast();
1094 if (col) {
1095 currentText.remove(j, 1);
1096 }
1097
1098 }
1099 current->text = currentText;
1100 allText.chop(total);
1101 }
1102 if (convertToPreWrapped) {
1103 current->properties.removeProperty(KoSvgTextProperties::TextCollapseId);
1104 current->properties.removeProperty(KoSvgTextProperties::TextWrapId);
1105 }
1106 }
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 1541 of file KoSvgTextShape.cpp.

1542{
1543 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1546 }
1548}
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().

◆ 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 2075 of file KoSvgTextShape.cpp.

2076{
2077 QRectF shapesRect;
2078 if (d->internalShapesPainter->contentRect().isValid()) {
2079 shapesRect = d->internalShapesPainter->contentRect();
2080 if (!(d->shapesInside.isEmpty() && d->shapesSubtract.isEmpty())) {
2081 return shapesRect;
2082 }
2083 }
2084 QRectF result;
2085
2086 QList<KoShapeStrokeModelSP> parentStrokes;
2087 for (auto it = d->textData.compositionBegin(); it != d->textData.compositionEnd(); it++) {
2088 if (it.state() == KisForestDetail::Enter) {
2089 if (it->properties.hasProperty(KoSvgTextProperties::StrokeId)) {
2090 parentStrokes.append(it->properties.property(KoSvgTextProperties::StrokeId).value<KoSvgText::StrokeProperty>().property);
2091 }
2092 } else {
2093 KoShapeStrokeModelSP stroke = parentStrokes.size() > 0? parentStrokes.last(): nullptr;
2094 QRectF bb = it->associatedOutline.boundingRect();
2095 QMap<KoSvgText::TextDecoration, QPainterPath> decorations = it->textDecorations;
2096 for (int i = 0; i < decorations.values().size(); ++i) {
2097 bb |= decorations.values().at(i).boundingRect();
2098 }
2099 if (!bb.isEmpty()) {
2100 if (stroke) {
2101 KoInsets insets;
2102 stroke->strokeInsets(this, insets);
2103 result |= bb.adjusted(-insets.left, -insets.top, insets.right, insets.bottom);
2104 } else {
2105 result |= bb;
2106 }
2107 }
2108 if (it->properties.hasProperty(KoSvgTextProperties::StrokeId)) {
2109 // reset stroke to use parent stroke.
2110 parentStrokes.pop_back();
2111 }
2112 }
2113 }
2114
2115 return (this->absoluteTransformation().mapRect(result) | shapesRect);
2116}
QTransform absoluteTransformation() const
Definition KoShape.cpp:335
@ 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 KoShape::absoluteTransformation(), KoInsets::bottom, d, KisForestDetail::Enter, KoInsets::left, result, KoInsets::right, stroke(), KoSvgTextProperties::StrokeId, and KoInsets::top.

◆ 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 706 of file KoSvgTextShape_p.h.

706 {
707 return std::distance(KisForestDetail::childBegin(it), KisForestDetail::childEnd(it));
708 }

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 1216 of file KoSvgTextShape.cpp.

1217{
1218 KoSvgTextShape::Private::cleanUp(d->textData);
1219 notifyChanged();
1221}

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 1266 of file KoSvgTextShape_p.h.

1266 {
1267 for (auto it = tree.depthFirstTailBegin(); it != tree.depthFirstTailEnd(); it++) {
1268 const int children = childCount(siblingCurrent(it));
1269 if (children == 0) {
1270
1271 // Remove empty leafs that are not the root or text paths.
1272 const int length = it->numChars(false);
1273 if (length == 0 && siblingCurrent(it) != tree.childBegin() && it->textPathId.isEmpty()) {
1274 tree.erase(siblingCurrent(it));
1275 } else {
1276 // check if siblings are similar.
1277 auto siblingPrev = siblingCurrent(it);
1279 QVariant(KoSvgText::BidiNormal)).toInt());
1280 siblingPrev--;
1281 if (!isEnd(siblingPrev)
1282 && siblingPrev != siblingCurrent(it)
1283 && (siblingPrev->localTransformations.isEmpty() && it->localTransformations.isEmpty())
1284 && (siblingPrev->textPathId.isEmpty() && it->textPathId.isEmpty())
1285 && (siblingPrev->textLength.isAuto && it->textLength.isAuto)
1286 && (siblingPrev->properties == it->properties)
1288 && childCount(siblingPrev) == 0) {
1289 // TODO: handle localtransforms better; annoyingly, this requires whitespace handling
1290 siblingPrev->text += it->text;
1291 tree.erase(siblingCurrent(it));
1292 }
1293 }
1294 } else if (children == 1) {
1295 // merge single children into parents if possible.
1296 auto child = childBegin(siblingCurrent(it));
1297 if ((child->localTransformations.isEmpty() && it->localTransformations.isEmpty())
1298 && (child->textPathId.isEmpty() && it->textPathId.isEmpty())
1299 && (child->textLength.isAuto && it->textLength.isAuto)
1300 && (!child->properties.hasNonInheritableProperties() || !it->properties.hasNonInheritableProperties())) {
1301 if (it->properties.hasNonInheritableProperties()) {
1302 KoSvgTextProperties props = it->properties;
1303 props.setAllButNonInheritableProperties(child->properties);
1304 child->properties = props;
1305 } else {
1306 child->properties.inheritFrom(it->properties);
1307 }
1308 tree.move(child, siblingCurrent(it));
1309 tree.erase(siblingCurrent(it));
1310 }
1311 }
1312 }
1313 }
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
depth_first_tail_iterator depthFirstTailEnd()
Definition KisForest.h:856
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
depth_first_tail_iterator depthFirstTailBegin()
Definition KisForest.h:852
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.
int toInt(const QString &str, bool *ok=nullptr)
bool isEnd(const ChildIterator< T, is_const > &it)
Definition KisForest.h:341
ChildIterator< value_type, is_const > siblingCurrent(ChildIterator< value_type, is_const > it)
Definition KisForest.h:240
@ 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 >::depthFirstTailBegin(), KisForestDetail::Forest< T >::depthFirstTailEnd(), KisForestDetail::Forest< T >::erase(), length(), KisForestDetail::Forest< T >::move(), 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 884 of file KoSvgTextShape_p.h.

884 {
885 QMap<int, KoSvgText::TextSpaceCollapse> collapseModes;
886
888 for (auto it = tree.compositionBegin(); it != tree.compositionEnd(); it++) {
889 if (it.state() == KisForestDetail::Enter) {
890 KoSvgTextProperties ownProperties = it->properties;
891 ownProperties.inheritFrom(parentProps.last());
892 parentProps.append(ownProperties);
893
894 const int children = childCount(siblingCurrent(it));
895 if (children == 0) {
896 QString text = it->text;
897 if (includeBidiControls) {
898 KoSvgText::UnicodeBidi bidi = KoSvgText::UnicodeBidi(parentProps.last().propertyOrDefault(KoSvgTextProperties::UnicodeBidiId).toInt());
899 KoSvgText::Direction direction = KoSvgText::Direction(parentProps.last().propertyOrDefault(KoSvgTextProperties::DirectionId).toInt());
900 QVector<QPair<int, int>> positions;
901 QString text = KoCssTextUtils::getBidiOpening(direction, bidi);
902 text += it->getTransformedString(positions, parentProps.last());
903 text += KoCssTextUtils::getBidiClosing(bidi);
904 }
905 KoSvgText::TextSpaceCollapse collapse = KoSvgText::TextSpaceCollapse(parentProps.last().propertyOrDefault(KoSvgTextProperties::TextCollapseId).toInt());
906 collapseModes.insert(allText.size(), collapse);
907 allText += text;
908 }
909 } else {
910 parentProps.pop_back();
911 }
912 }
913 QVector<bool> collapsed = KoCssTextUtils::collapseSpaces(&allText, collapseModes);
914
915 if (alsoCollapseLowSurrogate) {
916 for (int i = 0; i < allText.size(); i++) {
917 if (i > 0 && allText.at(i).isLowSurrogate() && allText.at(i-1).isHighSurrogate()) {
918 collapsed[i] = true;
919 }
920 }
921 }
922 return collapsed;
923 }
composition_iterator compositionBegin()
Definition KisForest.h:912
composition_iterator compositionEnd()
Definition KisForest.h:916
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)
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 KoShape * 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 1658 of file KoSvgTextShape.cpp.

1659{
1660 const int inlineSize = writingMode() == KoSvgText::HorizontalTB? outlineRect().width(): outlineRect().height();
1661 d->applyWhiteSpace(d->textData, true);
1662 d->insertNewLinesAtAnchors(d->textData, !d->shapesInside.isEmpty());
1663 d->cleanUp(d->textData);
1664
1665 KoSvgTextProperties props = this->propertiesForPos(-1);
1666 if (makeInlineSize) {
1668 // Using QCeil here because otherwise the text will layout too tight.
1669 val.customValue = qCeil(inlineSize);
1670 val.isAuto = false;
1672 props.setProperty(KoSvgTextProperties::InlineSizeId, QVariant::fromValue(val));
1673 }
1674 } else {
1676 }
1677 // NOTE: applyWhiteSpace and insertNewLines don't notify changes,
1678 // so setProperties is the only thing triggering relayout();
1679 setPropertiesAtPos(-1, props);
1680}
@ 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 1141 of file KoSvgTextShape.cpp.

1142{
1143 KoSvgTextShape *clone = new KoSvgTextShape(*this);
1144 int zero = 0;
1145 int endRange = index + length;
1146 int size = KoSvgTextShape::Private::numChars(clone->d->textData.childBegin(), false) - endRange;
1147 clone->removeText(endRange, size);
1148 clone->removeText(zero, index);
1149 KoSvgTextShape::Private::cleanUp(clone->d->textData);
1150 return std::unique_ptr<KoSvgTextShape>(clone);
1151}
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 623 of file KoSvgTextShape.cpp.

624{
625 if (d->result.isEmpty() || d->cursorPos.isEmpty() || pos < 0 || pos >= d->cursorPos.size()) {
626 return defaultCursorShape();
627 }
628 QPainterPath p;
629
630 CursorPos cursorPos = d->cursorPos.at(pos);
631
632 CharacterResult res = d->result.at(cursorPos.cluster);
633
634 const QTransform tf = res.finalTransform();
635 color = res.cursorInfo.color;
636 caret = res.cursorInfo.caret;
637 caret.translate(res.cursorInfo.offsets.value(cursorPos.offset, QPointF()));
638
639 p.moveTo(tf.map(caret.p1()));
640 p.lineTo(tf.map(caret.p2()));
641 if (d->isBidi && bidiFlagSize > 0) {
642 int sign = res.cursorInfo.rtl ? -1 : 1;
643 double bidiFlagHalf = bidiFlagSize * 0.5;
644 QPointF point3;
645 QPointF point4;
647 qreal slope = bidiFlagHalf * (caret.dx()/ caret.dy());
648 point3 = QPointF(caret.p2().x() + slope + (sign * bidiFlagHalf), caret.p2().y() + bidiFlagHalf);
649 point4 = QPointF(point3.x() + slope - (sign * bidiFlagHalf),point3.y() + bidiFlagHalf);
650 } else {
651 qreal slope = bidiFlagHalf * (caret.dy()/ caret.dx());
652 point3 = QPointF(caret.p2().x() - bidiFlagHalf, caret.p2().y() - slope + (sign * bidiFlagHalf));
653 point4 = QPointF(point3.x() - bidiFlagHalf, point3.y() - slope - (sign * bidiFlagHalf));
654 }
655 p.lineTo(tf.map(point3));
656 p.lineTo(tf.map(point4));
657 }
658 caret = tf.map(caret);
659
660 return p;
661}
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 1934 of file KoSvgTextShape.cpp.

1935{
1936 qDebug() << "Tree size:" << KisForestDetail::size(d->textData);
1937 QString spaces;
1938 for (auto it = compositionBegin(d->textData); it != compositionEnd(d->textData); it++) {
1939 if (it.state() == KisForestDetail::Enter) {
1940
1941 qDebug() << QString(spaces + "+") << it->text;
1942 qDebug() << QString(spaces + "|") << it->properties.convertToSvgTextAttributes();
1943 qDebug() << QString(spaces + "| PropertyType:") << it->properties.property(KoSvgTextProperties::KraTextStyleType).toString();
1944 qDebug() << QString(spaces + "| Fill set: ") << it->properties.hasProperty(KoSvgTextProperties::FillId);
1945 qDebug() << QString(spaces + "| Stroke set: ") << it->properties.hasProperty(KoSvgTextProperties::StrokeId);
1946 qDebug() << QString(spaces + "| Opacity: ") << it->properties.property(KoSvgTextProperties::Opacity);
1947 qDebug() << QString(spaces + "| PaintOrder: ") << it->properties.hasProperty(KoSvgTextProperties::PaintOrder);
1948 qDebug() << QString(spaces + "| Visibility set: ") << it->properties.hasProperty(KoSvgTextProperties::Visibility);
1949 qDebug() << QString(spaces + "| TextPath set: ") << it->textPathId;
1950 qDebug() << QString(spaces + "| Transforms set: ") << it->localTransformations;
1951 spaces.append(" ");
1952 }
1953
1954 if (it.state() == KisForestDetail::Leave) {
1955 spaces.chop(1);
1956 }
1957 }
1958}
@ 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 606 of file KoSvgTextShape.cpp.

607{
609 double fontSize = this->textProperties().fontSize().value;
610 QPainterPath p;
611 if (mode == KoSvgText::HorizontalTB) {
612 p.moveTo(0, fontSize*0.2);
613 p.lineTo(0, -fontSize);
614 } else {
615 p.moveTo(-fontSize * 0.5, 0);
616 p.lineTo(fontSize, 0);
617 }
618 p.translate(d->initialTextPosition);
619
620 return p;
621}
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}

◆ 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 1991 of file KoSvgTextShape.cpp.

1992{
1994
1995 QRectF updateRect;
1996
1997 if (d->bulkActionState->changed()) {
1998 if (d->bulkActionState->contourHasChanged) {
1999 d->updateTextWrappingAreas();
2000 } else if (d->bulkActionState->layoutHasChanged) {
2001 // updateTextWrappingAreas() already includes a call to relayout()
2002 relayout();
2003 }
2004
2005 updateRect = d->bulkActionState->originalBoundingRect | boundingRect();
2006 }
2007
2008 d->bulkActionState = std::nullopt;
2009 return updateRect;
2010}
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 1861 of file KoSvgTextShape.cpp.

1862{
1863
1864}

◆ 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 1473 of file KoSvgTextShape.cpp.

1474{
1475 for (auto it = d->textData.childBegin(); it != d->textData.childEnd(); it++) {
1476 if (it->properties.hasProperty(propertyId)) {
1477 return d->createTextNodeIndex(it);
1479 auto found = findNodeIndexForPropertyIdImpl(it, propertyId);
1480 if (found != it) {
1481 return d->createTextNodeIndex(found);
1482 }
1483 }
1484 }
1485 return d->createTextNodeIndex(d->textData.childBegin());
1486}
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 1488 of file KoSvgTextShape.cpp.

1489{
1490 int startIndex = 0;
1491 int endIndex = 0;
1492 for (auto child = d->textData.childBegin(); child != d->textData.childEnd(); child++) {
1493 // count children
1494 d->startIndexOfIterator(child, node.d->textElement, startIndex);
1495 endIndex = d->numChars(node.d->textElement) + startIndex;
1496 }
1497 return qMakePair(posForIndex(startIndex), posForIndex(endIndex));
1498}
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 723 of file KoSvgTextShape_p.h.

727 {
728 auto it = tree.depthFirstTailBegin();
729 for (; it != tree.depthFirstTailEnd(); it++) {
730 if (childCount(siblingCurrent(it)) > 0) {
731 continue;
732 }
733 int length = it->numChars(false);
734 if (length == 0 && skipZeroWidth) {
735 continue;
736 }
737
738 if (sought == currentIndex || (sought > currentIndex && sought < currentIndex + length)) {
739 break;
740 } else {
741 currentIndex += length;
742 }
743 }
744 return it;
745 }

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 859 of file KoSvgTextShape_p.h.

860 {
861 // An earlier version of the code used Hierarchy iterator,
862 // but that had too many exceptions when the child was not in the root.
863 if (!child.node()) return childEnd(root);
864 if (KisForestDetail::parent(child) == root) return child;
865 for (auto rootChild = childBegin(root); rootChild != childEnd(root); rootChild++) {
866 for (auto leaf = KisForestDetail::tailSubtreeBegin(rootChild);
867 leaf != KisForestDetail::tailSubtreeEnd(rootChild); leaf++) {
868 if (siblingCurrent(leaf) == child) {
869 return rootChild;
870 }
871 }
872 }
873 return childEnd(root);
874 }
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 1975 of file KoSvgTextShape.cpp.

1976{
1977 return d->disableFontMatching;
1978}

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 1980 of file KoSvgTextShape.cpp.

1981{
1982 return Private::generateShapes(shapesInside, shapesSubtract, props);
1983}

References shapesInside, and shapesSubtract.

◆ 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 1871 of file KoSvgTextShape.cpp.

1872{
1874 d->result,
1875 d->lineBoxes,
1876 d->cursorPos,
1877 d->logicalToVisualCursorPos,
1878 d->plainText,
1879 d->isBidi,
1880 d->initialTextPosition));
1881}
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 1416 of file KoSvgTextShape.cpp.

1417{
1419 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1420 return infos;
1421 }
1422 const int finalPos = d->cursorPos.size()-1;
1423 const int startIndex = d->cursorPos.at(qBound(0, qMin(startPos, endPos), finalPos)).index;
1424 const int endIndex = d->cursorPos.at(qBound(0, qMax(startPos, endPos), finalPos)).index;
1425
1426 for (int i = startIndex; i < endIndex; i++) {
1427 CharacterResult res = d->result.value(i);
1428 if (!res.addressable) continue;
1429 infos << infoFromCharacterResult(res, i);
1430 }
1431
1432 if (endIndex == startIndex) {
1433 bool final = qMax(startPos, endPos) == finalPos;
1434 CharacterResult resFinal = final? d->result.last(): d->result.value(startIndex);
1435 if (resFinal.addressable) {
1436 infos << infoFromCharacterResult(resFinal, startIndex);
1437 }
1438 }
1439
1440 return infos;
1441}
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 488 of file KoSvgTextShape_p.h.

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

◆ 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 878 of file KoSvgTextShape.cpp.

879{
880 if (d->cursorPos.isEmpty() || pos < 0) {
881 return -1;
882 }
883
884 return d->cursorPos.at(qMin(d->cursorPos.size()-1, pos)).index;
885}

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 1135 of file KoSvgTextShape_p.h.

1135 {
1137
1138 auto end = std::make_reverse_iterator(tree.childBegin());
1139 auto begin = std::make_reverse_iterator(tree.childEnd());
1140
1141 bool inTextPath = false;
1142 for (; begin != end; begin++) {
1143 insertNewLinesAtAnchorsImpl(begin, resolvedTransforms, inTextPath);
1144 }
1145 }
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 1147 of file KoSvgTextShape_p.h.

1149 {
1150
1151 inTextPath = (!current->textPathId.isEmpty());
1152 auto base = current.base();
1153 base--;
1154 if(base != siblingEnd(base)) {
1155 auto end = std::make_reverse_iterator(childBegin(base));
1156 auto begin = std::make_reverse_iterator(childEnd(base));
1157 for (; begin != end; begin++) {
1159 resolvedTransforms,
1160 inTextPath);
1161 }
1162 }
1163
1164 if (!current->text.isEmpty()) {
1165 const int total = current->text.size();
1166
1167 for (int i = 0; i < total; i++) {
1168 const int j = total - (i+1);
1169 KoSvgText::CharTransformation transform = resolvedTransforms.takeLast();
1176 bool startsNewChunk = transform.startsNewChunk() && j == 0;
1177
1178 if (inTextPath) {
1179 // First transform in path is always absolute, so we don't insert a newline.
1180 startsNewChunk = false;
1181 inTextPath = false;
1182 }
1183 // 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.
1184 if (startsNewChunk && !resolvedTransforms.isEmpty() && current->text.at(j) != QChar::LineFeed) {
1185 current->text.insert(j, "\n");
1186 }
1187 }
1188 }
1189 current->localTransformations.clear();
1190 }
QTransform transform() const
return the current matrix that contains the rotation/scale/position of this shape
Definition KoShape.cpp:950

◆ 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 1153 of file KoSvgTextShape.cpp.

1154{
1155 bool success = false;
1156 int currentIndex = 0;
1157 int elementIndex = 0;
1158 int insertionIndex = 0;
1159
1160 if (isEnd(richText->d->textData.childBegin())) {
1161 // rich text is empty.
1162 return success;
1163 }
1164
1165 if (pos > -1 && !d->cursorPos.isEmpty()) {
1166 CursorPos cursorPos = d->cursorPos.at(qMin(d->cursorPos.size()-1, pos));
1167 CharacterResult res = d->result.at(cursorPos.cluster);
1168 elementIndex = res.plaintTextIndex;
1169 insertionIndex = cursorPos.index;
1170 elementIndex = qMin(elementIndex, d->result.size()-1);
1171 }
1172
1173 KoSvgTextShape::Private::splitContentElement(this->d->textData, insertionIndex);
1174
1175 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, insertionIndex);
1176 auto richTextIt = d->textData.childEnd();
1177 if (it != d->textData.depthFirstTailEnd()) {
1178 richTextIt = d->textData.move(richText->d->textData.childBegin(), siblingCurrent(it));
1179 success = true;
1180 } else {
1181 currentIndex = 0;
1182 it = d->findTextContentElementForIndex(d->textData, currentIndex, elementIndex);
1183 if (it != d->textData.depthFirstTailEnd()) {
1184 richTextIt = d->textData.move(richText->d->textData.childBegin(), siblingEnd(siblingCurrent(it)));
1185 success = true;
1186 }
1187 }
1188
1189 if (richTextIt != d->textData.childEnd()) {
1190 Q_FOREACH (const KoSvgTextProperties::PropertyId p, richTextIt->properties.properties()) {
1192 richTextIt->properties.removeProperty(p);
1193 }
1194 }
1195 auto parentIt = KisForestDetail::hierarchyBegin(richTextIt);
1196 auto parentEnd = KisForestDetail::hierarchyEnd(richTextIt);
1197 if (parentIt != parentEnd) {
1198 parentIt++;
1199 if (inheritPropertiesIfPossible && parentIt != parentEnd) {
1200 Q_FOREACH (const KoSvgTextProperties::PropertyId p, richTextIt->properties.properties()) {
1201 if (richTextIt->properties.inheritsProperty(p, parentIt->properties)) {
1202 richTextIt->properties.removeProperty(p);
1203 }
1204 }
1205 }
1206 }
1207 }
1208
1209 if (success) {
1210 notifyChanged();
1212 }
1213 return success;
1214}
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 892 of file KoSvgTextShape.cpp.

893{
894 bool success = false;
895 int currentIndex = 0;
896
900 int elementIndex = 0;
901 int insertionIndex = 0;
902 if (pos > -1 && !d->cursorPos.isEmpty()) {
903 CursorPos cursorPos = d->cursorPos.at(pos);
904 CharacterResult res = d->result.at(cursorPos.cluster);
905 elementIndex = res.plaintTextIndex;
906 insertionIndex = cursorPos.index;
907 elementIndex = qMin(elementIndex, d->result.size()-1);
908 }
909 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, elementIndex);
910 if (it != d->textData.depthFirstTailEnd()) {
911 const int offset = insertionIndex - currentIndex;
912 it->insertText(offset, text);
913
914 d->insertTransforms(d->textData, insertionIndex, text.size(), (elementIndex == insertionIndex));
917 success = true;
918 }
919 return success;
920}

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 994 of file KoSvgTextShape_p.h.

994 {
995 QString all;
996 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all, true);
997
998 auto root = tree.childBegin();
999 insertTransformsImpl(root, 0, start, length, collapsedCharacters, allowSkipFirst);
1000 }
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 1006 of file KoSvgTextShape_p.h.

1006 {
1007 int currentLength = 0;
1008 auto it = childBegin(currentTextElement);
1009 if (it != childEnd(currentTextElement)) {
1010 for (; it != childEnd(currentTextElement); it++) {
1011 currentLength += insertTransformsImpl(it, globalIndex + currentLength, start, length, collapsedCharacters, allowSkipFirst);
1012 }
1013 } else {
1014 currentLength = currentTextElement->text.size();
1015 }
1016
1017 if (!currentTextElement->localTransformations.isEmpty()) {
1018 int transformOffset = 0;
1019 int transformOffsetEnd = 0;
1020
1021 for (int i = globalIndex; i < globalIndex + currentLength; i++) {
1022 if (i < start) {
1023 transformOffset += collapsedCharacters.at(i)? 0: 1;
1024 }
1025 if (i < start + length) {
1026 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
1027 } else {
1028 break;
1029 }
1030 }
1031
1032 // When at the start, skip the first transform.
1033 if (transformOffset == 0 && allowSkipFirst && currentTextElement->localTransformations.at(0).startsNewChunk()) {
1034 transformOffset += 1;
1035 }
1036
1037 if (transformOffset < currentTextElement->localTransformations.size()) {
1038 for (int i = transformOffset; i < transformOffsetEnd; i++) {
1039 currentTextElement->localTransformations.insert(i, KoSvgText::CharTransformation());
1040 }
1041 }
1042
1043 }
1044 return currentLength;
1045 }

References length().

◆ internalShapeManager()

KoShapeManager * KoSvgTextShape::internalShapeManager ( ) const

internalShapeManager

Returns
access the internal shapes manager for the contour shapes.

Definition at line 2562 of file KoSvgTextShape.cpp.

2563{
2564 return d->internalShapesPainter->internalShapeManager();
2565}

References d.

◆ internalShapes()

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

Definition at line 517 of file KoSvgTextShape_p.h.

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

◆ iteratorForTreeIndex()

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

Definition at line 1315 of file KoSvgTextShape_p.h.

1315 {
1316 if (treeIndex.isEmpty()) return parent;
1317 QVector<int> idx = treeIndex;
1318 int count = idx.takeFirst();
1319 for (auto child = KisForestDetail::childBegin(parent); child != KisForestDetail::childEnd(parent); child++) {
1320 if (count == 0) {
1322 return iteratorForTreeIndex(idx, child);
1323 } else {
1324 return child;
1325 }
1326 }
1327 count -= 1;
1328 }
1330 }
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 1866 of file KoSvgTextShape.cpp.

1867{
1868
1869}

◆ 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->cursorPos.at(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->cursorPos.at(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->cursorPos.at(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 1362 of file KoSvgTextShape_p.h.

1362 {
1363 bool textPathNameUnique = false;
1364 int textPathNumber = textPaths.size();
1365 QString newTextPathName = textPath->name();
1366 while(!textPathNameUnique) {
1367 textPathNameUnique = true;
1368 Q_FOREACH(KoShape *shape, textPaths) {
1369 if (shape->name() == newTextPathName) {
1370 textPathNameUnique = false;
1371 textPathNumber += 1;
1372 break;
1373 }
1374 }
1375 if (textPathNameUnique && !newTextPathName.isEmpty()) {
1376 textPath->setName(newTextPathName);
1377 } else {
1378 textPathNameUnique = false;
1379 }
1380 newTextPathName = QString("textPath"+QString::number(textPathNumber));
1381 }
1382 }
void setName(const QString &name)
Definition KoShape.cpp:960

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 1061 of file KoSvgTextShape.cpp.

1065{
1066 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1067 if (KisForestDetail::size(d->textData)) {
1068 Q_FOREACH(KoSvgTextProperties::PropertyId p, properties.properties()) {
1069 d->textData.childBegin()->properties.setProperty(p, properties.property(p));
1070 }
1071 Q_FOREACH(KoSvgTextProperties::PropertyId p, removeProperties) {
1072 d->textData.childBegin()->properties.removeProperty(p);
1073 }
1074 }
1075 notifyChanged();
1078 || removeProperties.contains(KoSvgTextProperties::ShapePaddingId)
1079 || removeProperties.contains(KoSvgTextProperties::ShapeMarginId)) {
1081 } else {
1083 }
1084 if (properties.hasProperty(KoSvgTextProperties::FillId)) {
1086 }
1089 }
1090 return;
1091 }
1092 const int startIndex = d->cursorPos.at(startPos).index;
1093 const int endIndex = d->cursorPos.at(endPos).index;
1094 if (startIndex != endIndex) {
1095 KoSvgTextShape::Private::splitContentElement(d->textData, startIndex);
1096 KoSvgTextShape::Private::splitContentElement(d->textData, endIndex);
1097 }
1098 bool changed = false;
1099 int currentIndex = 0;
1100 KoSvgText::AutoValue inlineSize = d->textData.childBegin()->properties.propertyOrDefault(KoSvgTextProperties::InlineSizeId).value<KoSvgText::AutoValue>();
1101 bool isWrapping = !d->shapesInside.isEmpty() || !inlineSize.isAuto;
1102 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
1103 if (KoSvgTextShape::Private::childCount(siblingCurrent(it)) > 0) {
1104 continue;
1105 }
1106
1107 if (currentIndex >= startIndex && currentIndex < endIndex) {
1108 Q_FOREACH(KoSvgTextProperties::PropertyId p, removeProperties) {
1110 d->textData.childBegin()->properties.removeProperty(p);
1111 } else {
1112 it->properties.removeProperty(p);
1113 }
1114 }
1115 Q_FOREACH(KoSvgTextProperties::PropertyId p, properties.properties()) {
1117 d->textData.childBegin()->properties.setProperty(p, properties.property(p));
1118 } else {
1119 it->properties.setProperty(p, properties.property(p));
1120 }
1121 }
1122
1123 changed = true;
1124 }
1125 currentIndex += it->numChars(false);
1126 }
1127
1128 if (changed){
1129 KoSvgTextShape::Private::cleanUp(d->textData);
1130 notifyChanged();
1132 if (properties.hasProperty(KoSvgTextProperties::FillId)) {
1134 }
1137 }
1138 }
1139}
@ 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 2405 of file KoSvgTextShape.cpp.

2406{
2407 const int oldIndex = d->shapesInside.indexOf(shapeInside);
2408 if (oldIndex < 0) return;
2409
2410 // Update.
2411 d->shapesInside.move(oldIndex, index);
2412 if (!d->isLoading) {
2413 d->updateTextWrappingAreas();
2414 }
2415 d->updateInternalShapesList();
2417 update();
2418}

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->cursorPos.at(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->cursorPos.at(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 1523 of file KoSvgTextShape.cpp.

1524{
1525 auto root = d->textData.childBegin();
1526 if (d->isLoading || d->cursorPos.isEmpty()) return d->createTextNodeIndex(root);
1527
1528 for (auto child = childBegin(root); child != childEnd(root); child++) {
1529 if (child->textPathId == textPath->name()) {
1530 return d->createTextNodeIndex(child);
1531 }
1532 }
1533 return d->createTextNodeIndex(root);
1534}

References d, and KoShape::name().

◆ notifyCursorPosChanged()

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

Notify that the cursor position has changed.

Definition at line 1632 of file KoSvgTextShape.cpp.

1633{
1634 if (d->isLoading) {
1635 return;
1636 }
1637 Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
1638 TextCursorChangeListener *cursorListener = dynamic_cast<TextCursorChangeListener*>(listener);
1639 if (cursorListener) {
1640 cursorListener->notifyCursorPosChanged(pos, anchor);
1641 }
1642 }
1643}
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 1645 of file KoSvgTextShape.cpp.

1646{
1647 if (d->isLoading) {
1648 return;
1649 }
1650 Q_FOREACH (KoShape::ShapeChangeListener *listener, listeners()) {
1651 TextCursorChangeListener *cursorListener = dynamic_cast<TextCursorChangeListener*>(listener);
1652 if (cursorListener) {
1653 cursorListener->notifyMarkupChanged();
1654 }
1655 }
1656}

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 695 of file KoSvgTextShape_p.h.

695 {
696 KoSvgTextProperties props = parent->properties;
697 props.inheritFrom(resolvedProps, true);
698 int count = parent->numChars(withControls, props);
700 count += numChars(it, withControls, props);
701 }
702 return count;
703 }
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 2051 of file KoSvgTextShape.cpp.

2051 {
2052 QPainterPath result;
2053 if (!d->internalShapes().isEmpty()) {
2054 Q_FOREACH(KoShape *shape, d->internalShapes()) {
2055 result.addPath(shape->transformation().map(shape->outline()));
2056 }
2057 }
2058
2059 if ((d->shapesInside.isEmpty() && d->shapesSubtract.isEmpty())) {
2060 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
2061 result.addPath(it->associatedOutline);
2062 for (int i = 0; i < it->textDecorations.values().size(); ++i) {
2063 result.addPath(it->textDecorations.values().at(i));
2064 }
2065 }
2066 }
2067
2068 return result;
2069}
virtual QPainterPath outline() const
Definition KoShape.cpp:559

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 2070 of file KoSvgTextShape.cpp.

2071{
2072 return outline().boundingRect();
2073}
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 2012 of file KoSvgTextShape.cpp.

2013{
2014 painter.save();
2015
2016 painter.setTransform(d->shapeGroup->absoluteTransformation().inverted()*painter.transform());
2017 d->internalShapesPainter->paint(painter);
2018 painter.restore();
2019
2020 painter.save();
2022 if (textRendering == KoSvgText::RenderingOptimizeSpeed || !painter.testRenderHint(QPainter::Antialiasing)) {
2023 // also apply antialiasing only if antialiasing is active on provided target QPainter
2024 painter.setRenderHint(QPainter::Antialiasing, false);
2025 painter.setRenderHint(QPainter::SmoothPixmapTransform, false);
2026 } else {
2027 painter.setRenderHint(QPainter::Antialiasing, true);
2028 painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
2029 }
2030
2031 QPainterPath chunk;
2032 int currentIndex = 0;
2033 if (!d->result.isEmpty()) {
2034 QPainterPath rootBounds;
2035 rootBounds.addRect(this->outline().boundingRect());
2036 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationUnderline, textRendering);
2037 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationOverline, textRendering);
2038 d->paintPaths(painter, rootBounds, this, d->result, textRendering, chunk, currentIndex);
2039 d->paintTextDecoration(painter, rootBounds, this, KoSvgText::DecorationLineThrough, textRendering);
2040 }
2041
2042 painter.restore();
2043}
@ DecorationOverline
Definition KoSvgText.h:260
@ DecorationLineThrough
Definition KoSvgText.h:261
@ DecorationUnderline
Definition KoSvgText.h:259
@ RenderingOptimizeSpeed
Definition KoSvgText.h:316

References boundingRect(), d, KoSvgText::DecorationLineThrough, KoSvgText::DecorationOverline, KoSvgText::DecorationUnderline, outline(), 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 2244 of file KoSvgTextShape.cpp.

2245{
2246 if (elements & DebugElement::CharBbox) {
2247 int currentIndex = 0;
2248 if (!d->result.isEmpty()) {
2249 QPainterPath rootBounds;
2250 rootBounds.addRect(this->outline().boundingRect());
2251 d->paintDebug(painter, d->result, currentIndex);
2252 }
2253
2254 //Debug shape outlines.
2255 Q_FOREACH (KoShape *shapeInside, d->shapesInside) {
2256 QPainterPath p = shapeInside->outline();
2257 p = shapeInside->transformation().map(p);
2258 painter.strokePath(p, QPen(Qt::green));
2259 }
2260 Q_FOREACH (KoShape *shapeInside, d->shapesSubtract) {
2261 QPainterPath p = shapeInside->outline();
2262 p = shapeInside->transformation().map(p);
2263 painter.strokePath(p, QPen(Qt::red));
2264 }
2265 }
2266
2267 if (elements & DebugElement::LineBox) {
2268 Q_FOREACH (LineBox lineBox, d->lineBoxes) {
2269 Q_FOREACH (const LineChunk &chunk, lineBox.chunks) {
2270 QPen pen;
2271 pen.setCosmetic(true);
2272 pen.setWidth(2);
2273 painter.setBrush(QBrush(Qt::transparent));
2274 pen.setColor(QColor(0, 128, 255, 128));
2275 painter.setPen(pen);
2276 painter.drawLine(chunk.length);
2277 pen.setColor(QColor(255, 128, 0, 128));
2278 painter.setPen(pen);
2279 painter.drawRect(chunk.boundingBox);
2280
2281 pen.setColor(QColor(255, 0, 0, 128));
2282 pen.setStyle(Qt::DashDotDotLine);
2283 painter.setPen(pen);
2284 painter.drawLine(chunk.length.translated(lineBox.baselineTop));
2285 pen.setColor(QColor(0, 128, 0, 128));
2286 pen.setStyle(Qt::DashDotLine);
2287 painter.setPen(pen);
2288 painter.drawLine(chunk.length.translated(lineBox.baselineBottom));
2289 }
2290 }
2291 }
2292}
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 1579 of file KoSvgTextShape.cpp.

1580{
1581 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1584 }
1585 return KoShape::paintOrder();
1586}
virtual QVector< PaintOrder > paintOrder() const
paintOrder
Definition KoShape.cpp:693

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 2045 of file KoSvgTextShape.cpp.

2046{
2047 Q_UNUSED(painter);
2048 // do nothing! everything is painted in paint()
2049}

◆ 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) {
313 if (direction == KoSvgText::DirectionRightToLeft) {
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 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 855 of file KoSvgTextShape.cpp.

856{
857 int pos = -1;
858 if (d->cursorPos.isEmpty() || index < 0) {
859 return pos;
860 }
861 for (int i = 0; i< d->cursorPos.size(); i++) {
862 if (skipSynthetic && d->cursorPos.at(i).synthetic) {
863 continue;
864 }
865 if (d->cursorPos.at(i).index <= index) {
866 pos = i;
867 if (d->cursorPos.at(i).index == index && firstIndex) {
868 break;
869 }
870 } else if (d->cursorPos.at(i).index > index) {
871 break;
872 }
873 }
874
875 return pos;
876}

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 784 of file KoSvgTextShape.cpp.

785{
786 int a = 0;
787 int b = d->cursorPos.size();
788 if (start >= 0 && end >= 0) {
789 a = qMax(start, a);
790 b = qMin(end, b);
791 }
792 double closest = std::numeric_limits<double>::max();
793 int candidate = 0;
794 for (int i = a; i < b; i++) {
795 CursorPos pos = d->cursorPos.at(i);
796 CharacterResult res = d->result.at(pos.cluster);
797 QPointF cursorStart = res.finalPosition;
798 cursorStart += res.cursorInfo.offsets.value(pos.offset, res.advance);
799 double distance = kisDistance(cursorStart, point);
800 if (distance < closest) {
801 candidate = i;
802 closest = distance;
803 if (overlaps) {
804 *overlaps = res.finalTransform().map(res.layoutBox()).containsPoint(point, Qt::WindingFill);
805 }
806 }
807 }
808 return candidate;
809}
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 811 of file KoSvgTextShape.cpp.

812{
813 bool overlaps = false;
814 int initialPos = posForPoint(point, -1, -1, &overlaps);
815
816 if (overlaps) {
817 return initialPos;
818 }
819
821
822 int candidateLineStart = 0;
823 double closest = std::numeric_limits<double>::max();
824 for (int i = 0; i < d->cursorPos.size(); i++) {
825 CursorPos pos = d->cursorPos.at(i);
826 CharacterResult res = d->result.at(pos.cluster);
827 if (res.anchored_chunk) {
828 QLineF caret = res.cursorInfo.caret;
829 caret.translate(res.finalPosition);
830 QPointF cursorStart = res.finalPosition;
831 cursorStart += res.cursorInfo.offsets.value(pos.offset, res.advance);
832 double distance = kisDistance(cursorStart, point);
833 if (mode == KoSvgText::HorizontalTB) {
834 if (caret.p1().y() > point.y() && caret.p2().y() <= point.y() && closest > distance) {
835 candidateLineStart = i;
836 closest = distance;
837 }
838 } else {
839 if (caret.p2().x() > point.x() && caret.p1().x() <= point.x() && closest > distance) {
840 candidateLineStart = i;
841 closest = distance;
842 }
843 }
844 }
845 }
846
847 if (candidateLineStart > -1) {
848 int end = lineEnd(candidateLineStart);
849 initialPos = posForPoint(point, candidateLineStart, qMin(end + 1, d->cursorPos.size()));
850 }
851
852 return initialPos;
853}
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 {
267 if (direction == KoSvgText::DirectionRightToLeft) {
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 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 {
285 if (direction == KoSvgText::DirectionRightToLeft) {
286 return previousPos(pos, visual);
287 } else {
288 return nextPos(pos, visual);
289 }
290 }
291}

References 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) {
298 if (direction == KoSvgText::DirectionRightToLeft) {
299 return nextPos(pos, visual);
300 } else {
301 return previousPos(pos, visual);
302 }
303 } else {
304 return previousLine(pos);
305 }
306}

References 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 int currentIndex = d->cursorPos.at(pos).index;
410
411 for (int i = pos; i >= 0; i--) {
412 if (d->cursorPos.at(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->cursorPos.at(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 444 of file KoSvgTextShape_p.h.

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

◆ Private() [2/2]

KoSvgTextShape::Private ( const Private & rhs)
inline

Definition at line 458 of file KoSvgTextShape_p.h.

460 , textData(rhs.textData)
461 {
462
463 KoShapeGroup *g = dynamic_cast<KoShapeGroup*>(rhs.shapeGroup.data()->cloneShape());
464 shapeGroup.reset(g);
466 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesInside, shapesInside);
467 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.shapesSubtract, shapesSubtract);
468 handleShapes(shapeGroup->shapes(), rhs.shapeGroup->shapes(), rhs.textPaths, textPaths);
470
471 yRes = rhs.yRes;
472 xRes = rhs.xRes;
473 result = rhs.result;
474 lineBoxes = rhs.lineBoxes;
475
476 cursorPos = rhs.cursorPos;
477 logicalToVisualCursorPos = rhs.logicalToVisualCursorPos;
478 plainText = rhs.plainText;
479 isBidi = rhs.isBidi;
480 initialTextPosition = rhs.initialTextPosition;
481
482 isLoading = rhs.isLoading;
483 disableFontMatching = rhs.disableFontMatching;
484
485 currentTextWrappingAreas = rhs.currentTextWrappingAreas;
486 }
void setSelectable(bool selectable)
Definition KoShape.cpp:832
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 961 of file KoSvgTextShape.cpp.

962{
963 return propertiesForRange(pos, pos, inherited).value(0, KoSvgTextProperties());
964}
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 982 of file KoSvgTextShape.cpp.

983{
985
987 if (d->isLoading) return props;
988
989 if (((startPos < 0 || startPos >= d->cursorPos.size()) && startPos == endPos) || d->cursorPos.isEmpty()) {
990 props = {KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties()};
991 return props;
992 }
993 const int finalPos = d->cursorPos.size() - 1;
994 const int startIndex = d->cursorPos.at(qBound(0, startPos, finalPos)).index;
995 const int endIndex = d->cursorPos.at(qBound(0, endPos, finalPos)).index;
996 int sought = startIndex;
997 if (startIndex == endIndex) {
998 int currentIndex = 0;
999 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, sought);
1000 if (it != d->textData.depthFirstTailEnd()) {
1001 if (inherited) {
1002 props.append(inheritProperties(it));
1003 } else {
1004 props.append(it->properties);
1005 }
1006 } else {
1007 currentIndex = 0;
1008 it = d->findTextContentElementForIndex(d->textData, currentIndex, sought - 1);
1009 if (it != d->textData.depthFirstTailEnd()) {
1010 if (inherited) {
1011 props.append(inheritProperties(it));
1012 } else {
1013 props.append(it->properties);
1014 }
1015 }
1016 }
1017 } else {
1018 while(sought < endIndex) {
1019 int currentIndex = 0;
1020 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, sought);
1021 if (KisForestDetail::siblingCurrent(it) == d->textData.childBegin()) {
1022 // If there's a selection and the search algorithm only returns the root, return empty.
1023 // The root text properties should be retrieved explicitly (either by using -1 as pos, or by calling textProperties()).
1024 props = {KoSvgTextProperties()};
1025 return props;
1026 } else if (it != d->textData.depthFirstTailEnd()) {
1027 if (inherited) {
1028 props.append(inheritProperties(it));
1029 } else {
1030 props.append(it->properties);
1031 }
1032 }
1033 sought = currentIndex + it->numChars(false);
1034 }
1035 }
1036
1037 return props;
1038}
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 2593 of file KoSvgTextShape.cpp.

2594{
2595 d->relayout();
2596}

References d.

◆ relayoutIsBlocked()

bool KoSvgTextShape::relayoutIsBlocked ( ) const

relayoutIsBlocked

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

Definition at line 1965 of file KoSvgTextShape.cpp.

1966{
1967 return d->isLoading;
1968}

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 2378 of file KoSvgTextShape.cpp.

2379{
2380 Q_FOREACH(KoShape *shape, shapes) {
2381 if (shape) {
2382 d->removeTextPathId(d->textData.childBegin(), shape->name());
2383 shape->removeDependee(this);
2384 d->shapesInside.removeAll(shape);
2385 d->shapesSubtract.removeAll(shape);
2386 d->textPaths.removeAll(shape);
2387
2388 }
2389 d->shapeGroup->removeShape(shape);
2390 }
2391 if (cleanup) {
2392 d->cleanUp(d->textData);
2393 }
2394 if (callUpdate) {
2395 notifyChanged(); // notify shape manager that our geometry has changed
2396 if (!d->isLoading) {
2397 d->updateTextWrappingAreas();
2398 }
2399 d->updateInternalShapesList();
2401 update();
2402 }
2403}

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 922 of file KoSvgTextShape.cpp.

923{
924 bool success = false;
925 if (index < -1) {
926 return success;
927 }
928 int currentLength = length;
929 int endLength = 0;
930 while (currentLength > 0) {
931 int currentIndex = 0;
932
933 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, index, true);
934 if (it != d->textData.depthFirstTailEnd()) {
935 int offset = index > currentIndex? index - currentIndex: 0;
936 int size = it->numChars(false);
937 it->removeText(offset, currentLength);
938 int diff = size - it->numChars(false);
939 currentLength -= diff;
940 endLength += diff;
941
942 if (index >= currentIndex) {
943 index = currentIndex + offset;
944 }
945
946 d->removeTransforms(d->textData, index, endLength);
947
948 success = true;
949 } else {
950 currentLength = -1;
951 }
952 }
953 if (success) {
954 length = endLength;
957 }
958 return success;
959}

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 1353 of file KoSvgTextShape_p.h.

1353 {
1354 for (auto it = childBegin(parent); it != childEnd(parent); it++) {
1355 if (it->textPathId == name) {
1356 it->textPathId = QString();
1357 break;
1358 }
1359 }
1360 }

◆ 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 936 of file KoSvgTextShape_p.h.

936 {
937 QString all;
938 QVector<bool> collapsedCharacters = collapsedWhiteSpacesForText(tree, all, true);
939
940 auto root = tree.childBegin();
941 removeTransformsImpl(root, 0, start, length, collapsedCharacters);
942 }
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 1443 of file KoSvgTextShape.cpp.

1444{
1445 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1446 return;
1447 }
1448 const int finalPos = d->cursorPos.size()-1;
1449 const int startIndex = d->cursorPos.at(qBound(0, qMin(startPos, endPos), finalPos)).index;
1450 const int endIndex = d->cursorPos.at(qBound(0, qMax(startPos, endPos), finalPos)).index;
1451
1452 d->removeTransforms(d->textData, startIndex, endIndex-startIndex);
1453
1454 KoSvgTextShape::Private::cleanUp(d->textData);
1455 notifyChanged();
1457}

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 949 of file KoSvgTextShape_p.h.

949 {
950 int currentLength = 0;
951 auto it = childBegin(currentTextElement);
952 if (it != childEnd(currentTextElement)) {
953 for (; it != childEnd(currentTextElement); it++) {
954 currentLength += removeTransformsImpl(it, globalIndex + currentLength, start, length, collapsedCharacters);
955 }
956 } else {
957 currentLength = currentTextElement->text.size();
958 }
959
960 if (!currentTextElement->localTransformations.isEmpty()) {
961 int transformOffset = 0;
962 int transformOffsetEnd = 0;
963
964 for (int i = globalIndex; i < globalIndex + currentLength; i++) {
965 if (i >= collapsedCharacters.size()) break;
966 if (i < start) {
967 transformOffset += collapsedCharacters.at(i)? 0: 1;
968 }
969 if (i < start + length) {
970 transformOffsetEnd += collapsedCharacters.at(i)? 0: 1;
971 } else {
972 break;
973 }
974 }
975 if (transformOffset < currentTextElement->localTransformations.size()) {
976 int length = qBound(0, transformOffsetEnd-transformOffset, qMax(0, currentTextElement->localTransformations.size()-transformOffset));
977 currentTextElement->localTransformations.remove(transformOffset,
978 length);
979 }
980
981 }
982 return currentLength;
983 }

References length().

◆ resolvedTransformsForTree()

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

Definition at line 1108 of file KoSvgTextShape_p.h.

1108 {
1109 QString all;
1110 QVector<bool> collapsed = collapsedWhiteSpacesForText(tree, all, false, includeBidiControls);
1111 QVector<CharacterResult> result(all.size());
1112 int globalIndex = 0;
1113 KoSvgTextProperties props = tree.childBegin()->properties;
1117 bool isHorizontal = mode == KoSvgText::HorizontalTB;
1118 bool isWrapped = (props.hasProperty(KoSvgTextProperties::InlineSizeId)
1119 || shapesInside);
1120 QVector<KoSvgText::CharTransformation> resolvedTransforms(all.size());
1121 resolveTransforms(tree.childBegin(), all, result, globalIndex,
1122 isHorizontal, isWrapped, false, resolvedTransforms,
1124 false);
1125 return resolvedTransforms;
1126 }
@ 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 1781 of file KoSvgTextShape.cpp.

1782{
1783 bool success = true;
1785 for (auto it = d->textData.compositionBegin(); it != d->textData.compositionEnd(); it++) {
1786 if (it.state() == KisForestDetail::Enter) {
1787 QMap<QString, QString> shapeSpecificStyles;
1788
1789 if (it == d->textData.compositionBegin()) {
1790 context.shapeWriter().startElement("p", false);
1791 } else {
1792 context.shapeWriter().startElement("span", false);
1793 }
1794 KoSvgTextProperties ownProperties = it->properties.ownProperties(parentProps.last(),
1795 it == d->textData.compositionBegin());
1796 parentProps.append(ownProperties);
1797 QMap<QString, QString> attributes = ownProperties.convertToSvgTextAttributes();
1798 if (it == d->textData.compositionBegin())
1799 attributes.insert(ownProperties.convertParagraphProperties());
1800 bool addedFill = false;
1801 if (attributes.size() > 0) {
1802 QString styleString;
1803 for (auto it = attributes.constBegin(); it != attributes.constEnd(); ++it) {
1804 if (QString(it.key().toLatin1().data()).contains("text-anchor")) {
1805 QString val = it.value();
1806 if (it.value()=="middle") {
1807 val = "center";
1808 } else if (it.value()=="end") {
1809 val = "right";
1810 } else {
1811 val = "left";
1812 }
1813 styleString.append("text-align")
1814 .append(": ")
1815 .append(val)
1816 .append(";" );
1817 } else if (QString(it.key().toLatin1().data()).contains("fill")) {
1818 styleString.append("color")
1819 .append(": ")
1820 .append(it.value())
1821 .append(";" );
1822 addedFill = true;
1823 } else if (QString(it.key().toLatin1().data()).contains("font-size")) {
1824 QString val = it.value();
1825 styleString.append(it.key().toLatin1().data())
1826 .append(": ")
1827 .append(val)
1828 .append(";" );
1829 } else {
1830 styleString.append(it.key().toLatin1().data())
1831 .append(": ")
1832 .append(it.value())
1833 .append(";" );
1834 }
1835 }
1836 if (ownProperties.hasProperty(KoSvgTextProperties::FillId) && !addedFill) {
1837 KoColorBackground *b = dynamic_cast<KoColorBackground *>(it->properties.background().data());
1838 if (b) {
1839 styleString.append("color")
1840 .append(": ")
1841 .append(b->color().name())
1842 .append(";" );
1843 }
1844 }
1845 context.shapeWriter().addAttribute("style", styleString);
1846
1847 if (d->childCount(siblingCurrent(it)) == 0) {
1848 debugFlake << "saveHTML" << this << it->text;
1849 // After adding all the styling to the <p> element, add the text
1850 context.shapeWriter().addTextNode(it->text);
1851 }
1852 }
1853 } else {
1854 parentProps.pop_back();
1855 context.shapeWriter().endElement();
1856 }
1857 }
1858 return success;
1859}
#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 1698 of file KoSvgTextShape.cpp.

1699{
1700 bool success = false;
1701
1702 QList<KoShape*> visibleShapes;
1703 Q_FOREACH(KoShape *shape, d->internalShapes()) {
1704 if (shape->isVisible(false)) {
1705 visibleShapes.append(shape);
1706 }
1707 }
1708 const bool writeGroup = !(visibleShapes.isEmpty() || context.strippedTextMode());
1709 if (writeGroup) {
1710 context.shapeWriter().startElement("g", false);
1711 context.shapeWriter().addAttribute("id", context.createUID("group"));
1712 context.shapeWriter().addAttribute(KoSvgTextShape_TEXTCONTOURGROUP, "true");
1713
1715 SvgWriter writer(visibleShapes);
1716 writer.saveDetached(context);
1717 }
1718 for (auto it = d->textData.compositionBegin(); it != d->textData.compositionEnd(); it++) {
1719 if (it.state() == KisForestDetail::Enter) {
1720 bool isTextPath = false;
1721 QMap<QString, QString> shapeSpecificStyles;
1722 if (!it->textPathId.isEmpty()) {
1723 isTextPath = true;
1724 }
1725 if (it == d->textData.compositionBegin()) {
1726 context.shapeWriter().startElement("text", false);
1727
1728 if (!context.strippedTextMode()) {
1729 context.shapeWriter().addAttribute("id", context.getID(this));
1730
1731 // save the version to distinguish from the buggy Krita version
1732 // 2: Wrong font-size.
1733 // 3: Wrong font-size-adjust.
1734 context.shapeWriter().addAttribute("krita:textVersion", 3);
1735
1736 if (visibleShapes.isEmpty()) {
1738 }
1739 SvgStyleWriter::saveSvgStyle(this, context);
1740 } else {
1741 SvgStyleWriter::saveSvgFill(this->background(), false, this->outlineRect(), this->size(), this->absoluteTransformation(), context);
1742 SvgStyleWriter::saveSvgStroke(this->stroke(), context);
1744 inheritPaintOrder(), context, true);
1745 }
1746 shapeSpecificStyles = this->shapeTypeSpecificStyles(context);
1747 } else {
1748 if (isTextPath) {
1749 context.shapeWriter().startElement("textPath", false);
1750 } else {
1751 context.shapeWriter().startElement("tspan", false);
1752 }
1753 SvgStyleWriter::saveSvgBasicStyle(it->properties.property(KoSvgTextProperties::Visibility, true).toBool(),
1754 it->properties.property(KoSvgTextProperties::Opacity, 0).toReal(),
1755 it->properties.property(KoSvgTextProperties::PaintOrder,
1756 QVariant::fromValue(paintOrder())
1758 !it->properties.hasProperty(KoSvgTextProperties::PaintOrder), context, true);
1759
1760 }
1761
1762 KoShape *textPath = KoSvgTextShape::Private::textPathByName(it->textPathId, d->textPaths);
1763 success = it->saveSvg(context,
1764 it == d->textData.compositionBegin(),
1765 d->childCount(siblingCurrent(it)) == 0,
1766 shapeSpecificStyles,
1767 textPath);
1768 } else {
1769 if (it == d->textData.compositionBegin()) {
1770 SvgStyleWriter::saveMetadata(this, context);
1771 }
1772 context.shapeWriter().endElement();
1773 }
1774 }
1775 if (writeGroup) {
1776 context.shapeWriter().endElement();
1777 }
1778 return success;
1779}
float value(const T *src, size_t ch)
#define KoSvgTextShape_TEXTCONTOURGROUP
bool inheritPaintOrder() const
inheritPaintOrder
Definition KoShape.cpp:715
bool isVisible(bool recursive=true) const
Definition KoShape.cpp:802
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 663 of file KoSvgTextShape.cpp.

664{
665 int start = qMin(pos, anchor);
666 int end = qMax(pos, anchor);
667 end = qMin(d->cursorPos.size()-1, end);
668
669 if (start == end || start < 0) {
670 return QPainterPath();
671 }
672
673 QPainterPath p;
674 p.setFillRule(Qt::WindingFill);
675 for (int i = start+1; i <= end; i++) {
676 CursorPos cursorPos = d->cursorPos.at(i);
677 CharacterResult res = d->result.at(cursorPos.cluster);
678 const QTransform tf = res.finalTransform();
679 QLineF first = res.cursorInfo.caret;
680 QLineF last = first;
681 if (res.cursorInfo.rtl) {
682 last.translate(res.cursorInfo.offsets.value(cursorPos.offset-1, res.advance));
683 first.translate(res.cursorInfo.offsets.value(cursorPos.offset, QPointF()));
684 } else {
685 first.translate(res.cursorInfo.offsets.value(cursorPos.offset-1, QPointF()));
686 last.translate(res.cursorInfo.offsets.value(cursorPos.offset, res.advance));
687 }
688 QPolygonF poly;
689 poly << first.p1() << first.p2() << last.p2() << last.p1() << first.p1();
690 p.addPolygon(tf.map(poly));
691 }
692
693 return p;
694}

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 1550 of file KoSvgTextShape.cpp.

1551{
1552 if (KisForestDetail::size(d->textData) == 0) {
1553 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1554 }
1555 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::FillId,
1556 QVariant::fromValue(KoSvgText::BackgroundProperty(background)));
1557
1559 notifyChanged();
1560}

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 1682 of file KoSvgTextShape.cpp.

1683{
1684 if (d->result.isEmpty()) return;
1685 d->setTransformsFromLayout(d->textData, d->result);
1686 d->cleanUp(d->textData);
1687 //d->applyWhiteSpace(d->textData, true);
1688 KoSvgTextProperties props = this->propertiesForPos(-1);
1692
1693 setPropertiesAtPos(-1, props);
1694}

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 1223 of file KoSvgTextShape.cpp.

1224{
1225 if ((startPos < 0 && startPos == endPos) || d->cursorPos.isEmpty()) {
1226 return false;
1227 }
1228 const int finalPos = d->cursorPos.size()-1;
1229 const int startIndex = d->cursorPos.at(qBound(0, qMin(startPos, endPos), finalPos)).index;
1230 int endIndex = d->cursorPos.at(qBound(0, qMax(startPos, endPos), finalPos)).index;
1231 if (startIndex == endIndex) {
1232 endIndex += 1;
1233 while(d->result.at(endIndex).middle) {
1234 endIndex += 1;
1235 if (endIndex > d->result.size()) break;
1236 }
1237 }
1238
1239 bool changed = false;
1240
1241 QVector<KoSvgText::CharTransformation> resolvedTransforms = Private::resolvedTransformsForTree(d->textData, !shapesInside().isEmpty(), true);
1242 Private::removeTransforms(d->textData, startIndex, endIndex-startIndex);
1243 QPointF totalStartDelta;
1244 QPointF anchorAbsolute;
1245 QPointF anchorCssPos;
1246
1249
1250 const CharacterResult startRes = d->result.value(startIndex);
1251 const QPointF startAdvance = startRes.cursorInfo.rtl? startRes.advance: QPointF();
1252
1253 if (deltaPosition) {
1254 for (int i = 0; i< startIndex; i++) {
1255 KoSvgText::CharTransformation tf = resolvedTransforms.value(i);
1256 if (tf.xPos) {
1257 totalStartDelta.setX(0);
1258 anchorAbsolute.setX(*tf.xPos);
1259 }
1260 if (tf.yPos) {
1261 totalStartDelta.setY(0);
1262 anchorAbsolute.setY(*tf.yPos);
1263 }
1264 if (tf.startsNewChunk()) {
1265 const CharacterResult res = d->result.value(i);
1266 anchorCssPos = res.cssPosition;
1267 }
1268 totalStartDelta += tf.relativeOffset();
1269 }
1270 } else {
1271 bool rtl = (dir == KoSvgText::DirectionRightToLeft);
1272 QPointF positionAtVisualEnd = (rtl? d->result.first(): d->result.last()).finalPosition;
1274 anchorAbsolute = positionAtVisualEnd;
1275 } else if (anchor == KoSvgText::AnchorMiddle) {
1276 anchorAbsolute = positionAtVisualEnd/2;
1277 }
1278 }
1279
1280 int currentIndex = 0;
1281 QPointF accumulatedOffset;
1282 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
1283 if (KoSvgTextShape::Private::childCount(siblingCurrent(it)) > 0 || !it->textPathId.isEmpty()) {
1284 continue;
1285 }
1286
1287 int endContentElement = it->finalResultIndex;
1288
1289 if (endContentElement >= startIndex && currentIndex <= endIndex) {
1290
1292 int addressableOffset = 0;
1293 for (int i = currentIndex; (i < endContentElement); i++) {
1294 const CharacterResult res = d->result.value(i);
1295 if (!res.addressable) {
1296 addressableOffset += 1;
1297 continue;
1298 }
1299
1300 const int transformIndex = (i - startIndex) - addressableOffset;
1301 KoSvgText::CharTransformation tf = resolvedTransforms.value(i, KoSvgText::CharTransformation());
1302
1303 // Function to get the delta position.
1304 auto getDelta = [res, totalStartDelta, accumulatedOffset, anchorAbsolute, anchorCssPos, startAdvance] (QPointF pos) -> QPointF {
1305 QPointF delta = pos - (res.textPathAndAnchoringOffset + anchorAbsolute + res.textLengthOffset);
1306 delta -= (totalStartDelta + accumulatedOffset + (res.cssPosition-anchorCssPos) + startAdvance);
1307 return delta;
1308 };
1309 // Function to get absolute position.
1310 auto getAbsolute = [res, tf, anchorAbsolute] (QPointF pos) -> QPointF {
1311 QPointF p = pos - (res.textPathAndAnchoringOffset - anchorAbsolute) - tf.relativeOffset();
1312 return p;
1313 };
1314
1315 if (i < startIndex) {
1316 if (!deltaPosition) {
1317 // Because we don't split the text content element, we need to set the absolute pos for every preceding transform.
1318 const QPointF p = getAbsolute(res.finalPosition);
1319 if (!tf.xPos) {
1320 tf.xPos = p.x();
1321 }
1322 if (!tf.yPos) {
1323 tf.yPos = p.y();
1324 }
1325 }
1326 transforms << tf;
1327 continue;
1328 }
1329
1330 if (i >= endIndex) {
1331 if (i == endIndex) {
1332 // Counter transform to keep unselected characters at the same pos.
1333 if (deltaPosition && !tf.startsNewChunk()) {
1334 QPointF delta = getDelta(res.finalPosition);
1335 tf.dxPos = delta.x();
1336 tf.dyPos = delta.y();
1337 } else {
1338 const QPointF p = getAbsolute(res.finalPosition) - anchorAbsolute;
1339 tf.xPos = p.x();
1340 tf.yPos = p.y();
1341 }
1342 if (!tf.rotate) {
1343 tf.rotate = 0.0;
1344 }
1345 }
1346 transforms << tf;
1347 continue;
1348 }
1349
1350 if (rotateDegrees.size()+startIndex > i) {
1351 tf.rotate = kisDegreesToRadians(rotateDegrees.value(transformIndex, tf.rotate? *tf.rotate: rotateDegrees.last()));
1352 }
1353 if (positions.size()+startIndex > i) {
1354 const QPointF pos = positions.value(transformIndex, QPointF());
1355
1356 if (deltaPosition) {
1357 if (tf.startsNewChunk()) {
1358 anchorAbsolute = tf.absolutePos();
1359 totalStartDelta = tf.relativeOffset();
1360 anchorCssPos = res.cssPosition;
1361 }
1362
1363 QPointF delta = getDelta(pos);
1364 tf.dxPos = delta.x();
1365 tf.dyPos = delta.y();
1366
1367 if (tf.startsNewChunk()) {
1368 accumulatedOffset = QPointF();
1369 totalStartDelta = tf.relativeOffset();
1370 } else {
1371 accumulatedOffset += tf.relativeOffset();
1372 }
1373 } else {
1374 const QPointF delta = getAbsolute(pos);
1375 tf.xPos = delta.x();
1376 tf.yPos = delta.y();
1377 accumulatedOffset = pos - res.finalPosition;
1378 }
1379
1380 }
1381
1382 transforms << tf;
1383 }
1384 it->localTransformations = transforms;
1385 changed = true;
1386 }
1387 currentIndex = it->finalResultIndex;
1388 if (currentIndex > endIndex) {
1389 break;
1390 }
1391 }
1392 const CharacterResult res = d->result.last();
1393
1394 if (changed) {
1395 KoSvgTextShape::Private::cleanUp(d->textData);
1396 notifyChanged();
1398 }
1399
1400 return changed;
1401}
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 1970 of file KoSvgTextShape.cpp.

1971{
1972 d->disableFontMatching = disable;
1973}

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 1913 of file KoSvgTextShape.cpp.

1914{
1915 setMementoImpl(memento);
1918}
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 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 1920 of file KoSvgTextShape.cpp.

1921{
1922 const bool shapeOffsetBefore = (textProperties().hasProperty(KoSvgTextProperties::ShapeMarginId)
1924 setMementoImpl(memento);
1925 const bool shapeOffsetAfter = (textProperties().hasProperty(KoSvgTextProperties::ShapeMarginId)
1927 if (shapeOffsetBefore || shapeOffsetAfter) {
1928 d->updateTextWrappingAreas();
1929 }
1932}

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

◆ setMementoImpl()

void KoSvgTextShape::setMementoImpl ( const KoSvgTextShapeMementoSP memento)
private

Definition at line 1883 of file KoSvgTextShape.cpp.

1884{
1885 // TODO: add an assert that all linked shpaes in memento are present in
1886 // the current state of d->textPaths. That is the responsibility of
1887 // KoSvgTextAddRemoveShapeCommandImpl to prepare the shapes for us
1888
1889 KoSvgTextShapeMementoImpl *impl = dynamic_cast<KoSvgTextShapeMementoImpl*>(memento.data());
1890 if (impl) {
1891 d->textData = impl->textData;
1892 d->result = impl->result;
1893 d->lineBoxes = impl->lineBoxes;
1894 d->cursorPos = impl->cursorPos;
1895 d->logicalToVisualCursorPos = impl->logicalToVisualCursorPos;
1896 d->plainText = impl->plainText;
1897 d->isBidi = impl->isBidi;
1898 d->initialTextPosition = impl->initialTextPosition;
1899
1900 // Ensure that any text paths exist.
1901 auto root = d->textData.childBegin();
1902 for (auto child = childBegin(root); child != childEnd(root); child++) {
1903 if (!child->textPathId.isEmpty()) {
1904 KIS_SAFE_ASSERT_RECOVER(Private::textPathByName(child->textPathId, d->textPaths)) {
1905 qDebug() << "missing path is" << child->textPathId;
1906 child->textPathId = QString();
1907 }
1908 }
1909 }
1910 }
1911}
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 1588 of file KoSvgTextShape.cpp.

1589{
1590 if (KisForestDetail::size(d->textData) == 0) {
1591 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1592 }
1593 KIS_SAFE_ASSERT_RECOVER_RETURN(first != second);
1595
1596 if (first != Fill) {
1597 if (order.at(1) == first) {
1598 order[1] = order[0];
1599 order[0] = first;
1600 } else if (order.at(2) == first) {
1601 order[2] = order[0];
1602 order[0] = first;
1603 }
1604 }
1605 if (second != first && second != Stroke) {
1606 if (order.at(2) == second) {
1607 order[2] = order[1];
1608 order[1] = second;
1609 }
1610 }
1611 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::PaintOrder,
1612 QVariant::fromValue(order));
1613 setInheritPaintOrder(false);
1614}
static QVector< PaintOrder > defaultPaintOrder()
default paint order as per SVG specification
Definition KoShape.cpp:704
void setInheritPaintOrder(bool value)
setInheritPaintOrder set inherit paint order.
Definition KoShape.cpp:710
#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 1040 of file KoSvgTextShape.cpp.

1041{
1042 if (pos < 0 || d->cursorPos.isEmpty()) {
1043 if (KisForestDetail::size(d->textData)) {
1044 d->textData.childBegin()->properties = properties;
1045 }
1046 notifyChanged();
1048 return;
1049 }
1050 CursorPos cursorPos = d->cursorPos.at(pos);
1051 CharacterResult res = d->result.at(cursorPos.cluster);
1052 int currentIndex = 0;
1053 auto it = d->findTextContentElementForIndex(d->textData, currentIndex, res.plaintTextIndex);
1054 if (it != d->textData.depthFirstTailEnd()) {
1055 it->properties = properties;
1056 notifyChanged();
1058 }
1059}

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

◆ setRelayoutBlocked()

void KoSvgTextShape::setRelayoutBlocked ( const bool disable)

Definition at line 1960 of file KoSvgTextShape.cpp.

1961{
1962 d->isLoading = disable;
1963}

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 2330 of file KoSvgTextShape.cpp.

2331{
2332 removeShapesFromContours(d->shapesInside, false);
2334}
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 2546 of file KoSvgTextShape.cpp.

2547{
2548 removeShapesFromContours(d->shapesSubtract, false);
2550}

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 2124 of file KoSvgTextShape.cpp.

2125{
2126 const QRectF oRect = this->outlineRect();
2127 const QSizeF oldSize = oRect.size();
2128
2129 if (size == oldSize) return;
2130
2131 // don't try to divide by zero
2132 if (oldSize.isEmpty()) return;
2133
2134 const qreal scaleX = size.width() / oldSize.width();
2135 const qreal scaleY = size.height() / oldSize.height();
2136
2137 if (d->internalShapes().isEmpty()) {
2143 const qreal scaleX = size.width() / oldSize.width();
2144 const qreal scaleY = size.height() / oldSize.height();
2145
2146 this->scale(scaleX, scaleY);
2147 // TODO: use scaling function for kosvgtextproperties when styles presets are merged.
2148 notifyChanged();
2150 } else {
2151 if (!d->textPaths.isEmpty()) return;
2152
2153 const bool allInternalShapeAreTranslatedOnly = [this] () {
2154 Q_FOREACH(KoShape *shape, d->internalShapes()) {
2155 if (shape->transformation().type() > QTransform::TxTranslate) {
2156 return false;
2157 }
2158 }
2159 return true;
2160 }();
2161
2162 if (allInternalShapeAreTranslatedOnly) {
2167 Q_FOREACH (KoShape *internalShape, d->internalShapes()) {
2174 const QPointF stillPoint = this->absoluteTransformation().map(QPointF());
2175 const bool useGlobalMode = false;
2176 const bool usePostScaling = false;
2177 KoFlake::resizeShapeCommon(internalShape,
2178 scaleX,
2179 scaleY,
2180 stillPoint,
2181 useGlobalMode,
2182 usePostScaling,
2183 QTransform());
2184 }
2185
2186 const QSizeF realNewSize = outlineRect().size();
2187 KoShape::setSize(realNewSize);
2188 } else {
2232 const QTransform scale = QTransform::fromScale(scaleX, scaleY);
2233
2234 Q_FOREACH (KoShape *shape, d->internalShapes()) {
2235 shape->setTransformation(shape->transformation() * scale);
2236 }
2237
2238 const QSizeF realNewSize = outlineRect().size();
2239 KoShape::setSize(realNewSize);
2240 }
2241 }
2242}
void setTransformation(const QTransform &matrix)
Definition KoShape.cpp:374
@ 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:209
virtual void setSize(const QSizeF &size)
Resize the shape.
Definition KoShape.cpp:248
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 1568 of file KoSvgTextShape.cpp.

1569{
1570 if (KisForestDetail::size(d->textData) == 0) {
1571 d->textData.insert(d->textData.childBegin(), KoSvgTextContentElement());
1572 }
1573 d->textData.childBegin()->properties.setProperty(KoSvgTextProperties::StrokeId,
1574 QVariant::fromValue(KoSvgText::StrokeProperty(stroke)));
1576 notifyChanged();
1577}

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 2420 of file KoSvgTextShape.cpp.

2421{
2422 const int finalPos = d->cursorPos.size() - 1;
2423 const int startIndex = (startPos == endPos && startPos < 0)? 0: d->cursorPos.at(qBound(0, startPos, finalPos)).index;
2424 const int endIndex = (startPos == endPos && startPos < 0)? finalPos: d->cursorPos.at(qBound(0, endPos, finalPos)).index;
2425
2426 Private::splitTree(d->textData, startIndex, false);
2427 Private::splitTree(d->textData, endIndex, true);
2428 int currentIndex = 0;
2429
2430 Private::makeTextPathNameUnique(d->textPaths, textPath);
2431 KoSvgTextContentElement textPathElement;
2432 textPathElement.textPathId = textPath->name();
2433 d->shapeGroup->addShape(textPath);
2434 d->textPaths.append(textPath);
2435 textPath->addDependee(this);
2436
2437
2438 if (KisForestDetail::depth(d->textData) == 1) {
2439 textPathElement.text = d->textData.childBegin()->text;
2443 Q_FOREACH(KoSvgTextProperties::PropertyId p, copyIds) {
2444 if (d->textData.childBegin()->properties.hasProperty(KoSvgTextProperties::TextDecorationLineId)) {
2445 textPathElement.properties.setProperty(p, d->textData.childBegin()->properties.property(p));
2446 d->textData.childBegin()->properties.removeProperty(p);
2447 }
2448 }
2449
2450 d->textData.childBegin()->text = QString();
2451 d->textData.insert(childEnd(d->textData.childBegin()), textPathElement);
2452 } else {
2453 // find nodes
2454 auto startElement = Private::findTextContentElementForIndex(d->textData, currentIndex, startIndex, true);
2455 currentIndex = 0;
2456 auto endElement = Private::findTextContentElementForIndex(d->textData, currentIndex, endIndex, true);
2457
2458 auto first = startElement.node()?Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(startElement))
2460 auto last = endElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(endElement))
2462
2463 // move children. we collect them before inserting the text path,
2464 // so we don't get iterator issues.
2466 auto textPathIt = textPathTree.insert(
2467 textPathTree.childEnd(),
2468 textPathElement);
2470 for (auto child = first;
2471 (child != last && child != childEnd(d->textData.childBegin()));
2472 child++) {
2473 if (!child->textPathId.isEmpty()) {
2474 Q_FOREACH(KoShape *shape, d->textPaths) {
2475 if (shape->name() == child->textPathId) {
2476 removeShapesFromContours({shape}, false, false);
2477 break;
2478 }
2479 }
2480 child->textPathId = QString();
2481 }
2482 movableChildren.append(child);
2483 }
2484 while (!movableChildren.isEmpty()) {
2485 auto child = movableChildren.takeLast();
2486 textPathTree.move(child, KisForestDetail::childBegin(textPathIt));
2487 }
2488 d->textData.move(textPathIt, last);
2489 }
2490 Private::cleanUp(d->textData);
2491
2492 d->updateInternalShapesList();
2493 notifyChanged();
2495 update();
2496 return true;
2497}
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
@ TextDecorationStyleId
KoSvgText::TextDecorationStyle.
@ TextDecorationLineId
Flags, KoSvgText::TextDecorations.
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 1192 of file KoSvgTextShape_p.h.

1192 {
1193 for (int i = 0; i< layout.size(); i++) {
1194 //split all anchored chunks, so we can set transforms on them.
1195 if (layout.at(i).anchored_chunk) {
1196 int plainTextIndex = layout.at(i).plaintTextIndex;
1197 splitContentElement(tree, plainTextIndex);
1198 }
1199 }
1200
1201 int globalIndex = 0;
1202 for (auto it = tree.childBegin(); it != tree.childEnd(); it++) {
1204 it->properties.propertyOrDefault(KoSvgTextProperties::WritingModeId).toInt());
1205 bool isHorizontal = mode == KoSvgText::HorizontalTB;
1206 setTransformsFromLayoutImpl(it, KoSvgTextProperties::defaultProperties(), layout, globalIndex, isHorizontal);
1207 }
1208 }
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 1210 of file KoSvgTextShape_p.h.

1212 {
1213 KoSvgTextProperties props = current->properties;
1214 props.inheritFrom(parentProps);
1215 if (!current->textPathId.isEmpty()) return; // When we're doing text-on-path, we're already in preformatted mode.
1216 for (auto it = childBegin(current); it!= childEnd(current); it++) {
1217 setTransformsFromLayoutImpl(it, props, layout, globalIndex, isHorizontal);
1218 }
1219
1220 if (current->text.isEmpty()) {
1221 current->localTransformations.clear();
1222 } else {
1224 const int length = current->numChars(true, props);
1225
1226 for (int i = globalIndex; i< globalIndex+length; i++) {
1227 CharacterResult result = layout.value(i);
1228
1229 if (!result.addressable) {
1230 continue;
1231 }
1233
1234 //TODO: Also split up content element if multiple anchored chunks.
1235 if (result.anchored_chunk) {
1236 int endIndex = 0;
1237 qreal shift = anchoredChunkShift(layout, isHorizontal, i, endIndex);
1238 QPointF offset = isHorizontal? QPointF(shift, 0): QPointF(0, shift);
1239 transform.xPos = result.finalPosition.x() - offset.x();
1240 transform.yPos = result.finalPosition.y() - offset.y();
1241 } else if (i > 0) {
1242 CharacterResult resultPrev = layout.value(i-1);
1243 QPointF offset = (result.finalPosition - result.cssPosition) - (resultPrev.finalPosition - resultPrev.cssPosition);
1244
1245 transform.dxPos = offset.x();
1246 transform.dyPos = offset.y();
1247 }
1248 transform.rotate = result.rotate;
1249
1250 transforms.append(transform);
1251 }
1252 current->localTransformations = transforms;
1253 current->text = current->text.split("\n").join(" ");
1254 globalIndex += length;
1255 }
1256 }
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:1059
@ 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 2373 of file KoSvgTextShape.cpp.

2374{
2375 return (shape->parent() == d->shapeGroup.data());
2376}
KoShapeContainer * parent() const
Definition KoShape.cpp:862

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 2567 of file KoSvgTextShape.cpp.

2568{
2569 QMap<QString, QString> map = this->textProperties().convertParagraphProperties();
2570 if (!d->shapesInside.isEmpty()) {
2571 QStringList shapesInsideList;
2572 Q_FOREACH(KoShape* shape, d->shapesInside) {
2573 QString id = (shape->isVisible(false) && !context.strippedTextMode())? context.getID(shape): SvgStyleWriter::embedShape(shape, context);
2574 shapesInsideList.append(QString("url(#%1)").arg(id));
2575 }
2576 map.insert("shape-inside", shapesInsideList.join(" "));
2579 map.insert("overflow", "clip");
2580 }
2581 if (!d->shapesSubtract.isEmpty()) {
2582 QStringList shapesInsideList;
2583 Q_FOREACH(KoShape* shape, d->shapesSubtract) {
2584 QString id = shape->isVisible(false)? context.getID(shape): SvgStyleWriter::embedShape(shape, context);
2585 shapesInsideList.append(QString("url(#%1)").arg(id));
2586 }
2587 map.insert("shape-subtract", shapesInsideList.join(" "));
2588 }
2589
2590 return map;
2591}
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 1626 of file KoSvgTextShape.cpp.

1627{
1628 if (d->textData.empty()) return false;
1629 return (KisForestDetail::size(d->textData) == 1);
1630}

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 2118 of file KoSvgTextShape.cpp.

2119{
2120 // TODO: check if KoShape::m_d->size is consistent, check cache in KoShapeGroup::size()
2121 return outlineRect().size();
2122}

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 755 of file KoSvgTextShape_p.h.

755 {
756 int currentIndex = 0;
757
758 // If there's only a single root element, don't bother searching.
759 auto contentElement = depth(tree) == 1? tree.depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index, true);
760 if (contentElement == tree.depthFirstTailEnd()) return false;
761
762 bool suitableStartIndex = siblingCurrent(contentElement) == tree.childBegin()? index >= currentIndex: index > currentIndex;
763 bool suitableEndIndex = siblingCurrent(contentElement) == tree.childBegin()? true: index < currentIndex + contentElement->numChars(false);
764
765 if (suitableStartIndex && suitableEndIndex) {
767 duplicate.text = contentElement->text;
768 int start = index - currentIndex;
769 int length = contentElement->numChars(false) - start;
770 int zero = 0;
771 duplicate.removeText(start, length);
772
773 if (!allowEmptyText && (duplicate.text.isEmpty() || length == 0)) {
774 return true;
775 }
776
777 // TODO: handle localtransforms better; annoyingly, this requires whitespace handling
778
779 if (siblingCurrent(contentElement) != tree.childBegin()
780 && contentElement->textPathId.isEmpty()
781 && contentElement->textLength.isAuto
782 && contentElement->localTransformations.isEmpty()) {
783 contentElement->removeText(zero, start);
784 duplicate.properties = contentElement->properties;
785 tree.insert(siblingCurrent(contentElement), duplicate);
786 } else {
788 duplicate2.text = contentElement->text;
789 duplicate2.removeText(zero, start);
790 contentElement->text.clear();
791 tree.insert(childBegin(contentElement), duplicate);
792 tree.insert(childEnd(contentElement), duplicate2);
793 }
794 return true;
795 }
796 return false;
797 }
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 806 of file KoSvgTextShape_p.h.

806 {
807 splitContentElement(tree, index, false);
808 int currentIndex = 0;
809 auto contentElement = depth(tree) == 1? tree.depthFirstTailBegin(): findTextContentElementForIndex(tree, currentIndex, index, true);
810
811 // We're either at the start or end.
812 if (contentElement == tree.depthFirstTailEnd()) return;
813 if (siblingCurrent(contentElement) == tree.childBegin()) return;
814
815 auto lastNode = siblingCurrent(contentElement);
816 for (auto parentIt = KisForestDetail::hierarchyBegin(siblingCurrent(contentElement));
817 parentIt != KisForestDetail::hierarchyEnd(siblingCurrent(contentElement)); parentIt++) {
818 if (lastNode == siblingCurrent(parentIt)) continue;
819 if (siblingCurrent(parentIt) == tree.childBegin()) {
820 break;
821 }
822
823 if (lastNode != childBegin(siblingCurrent(parentIt))) {
825 duplicate.properties = parentIt->properties;
826 if (textPathAfterSplit) {
827 duplicate.textPathId = parentIt->textPathId;
828 duplicate.textPathInfo = parentIt->textPathInfo;
829 parentIt->textPathId = QString();
830 parentIt->textPathInfo = KoSvgText::TextOnPathInfo();
831 }
832 auto insert = siblingCurrent(parentIt);
833 insert ++;
834 auto it = tree.insert(insert, duplicate);
835
837 for (auto child = lastNode; child != childEnd(siblingCurrent(parentIt)); child++) {
838 movableChildren.append(child);
839 }
840 while(!movableChildren.isEmpty()) {
841 auto child = movableChildren.takeLast();
842 tree.move(child, childBegin(it));
843 }
844 lastNode = it;
845 } else {
846 lastNode = siblingCurrent(parentIt);
847 }
848 }
849 }
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 1985 of file KoSvgTextShape.cpp.

1986{
1987 KIS_SAFE_ASSERT_RECOVER_RETURN(!d->bulkActionState);
1988 d->bulkActionState.emplace(boundingRect());
1989}

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 1332 of file KoSvgTextShape_p.h.

1332 {
1333 for (auto child = KisForestDetail::childBegin(parent); child != KisForestDetail::childEnd(parent); child++) {
1334 if (child == target) {
1335 return true;
1336 } else if ((KisForestDetail::childBegin(child) != KisForestDetail::childEnd(child))) {
1337 if (startIndexOfIterator(child, target, currentIndex)) {
1338 return true;
1339 }
1340 } else {
1341 currentIndex += numChars(child);
1342 }
1343 }
1344 return false;
1345 }
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 1562 of file KoSvgTextShape.cpp.

1563{
1564 KoSvgTextProperties props = KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1566}

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 2294 of file KoSvgTextShape.cpp.

2295{
2296 KoShape *shape = nullptr;
2297 int currentIndex = 0;
2298 if (!d->result.empty()) {
2299 shape = d->collectPaths(this, d->result, currentIndex);
2300 }
2301
2302 return shape;
2303}

References d.

◆ textPathByName()

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

Definition at line 571 of file KoSvgTextShape_p.h.

571 {
572 auto it = std::find_if(textPaths.begin(), textPaths.end(), [&name](const KoShape *s) -> bool {return s->name() == name;});
573 return it != textPaths.end()? *it: nullptr;
574 }
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 2499 of file KoSvgTextShape.cpp.

2500{
2501 const int finalPos = d->cursorPos.size() - 1;
2502 const int startIndex = (startPos == endPos && startPos < 0)? 0: d->cursorPos.at(qBound(0, startPos, finalPos)).index;
2503 const int endIndex = (startPos == endPos && startPos < 0)? finalPos: d->cursorPos.at(qBound(0, endPos, finalPos)).index;
2505 int currentIndex = 0;
2506 auto startElement = Private::findTextContentElementForIndex(d->textData, currentIndex, startIndex, true);
2507 currentIndex = 0;
2508 auto endElement = Private::findTextContentElementForIndex(d->textData, currentIndex, endIndex, true);
2509
2510 auto first = startElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(startElement))
2512 auto last = endElement.node()? Private::findTopLevelParent(d->textData.childBegin(), KisForestDetail::siblingCurrent(endElement))
2514 if (last != childEnd(d->textData.childBegin())) {
2515 last++;
2516 }
2517 for (auto child = first; (child != last && child != KisForestDetail::siblingEnd(first)); child++) {
2518 if (KoShape *path = Private::textPathByName(child->textPathId, d->textPaths)) {
2519 textPaths.append(path);
2520 }
2521 }
2522 return textPaths;
2523}

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

◆ textProperties()

KoSvgTextProperties KoSvgTextShape::textProperties ( ) const

Definition at line 1536 of file KoSvgTextShape.cpp.

1537{
1538 return KisForestDetail::size(d->textData)? d->textData.childBegin()->properties: KoSvgTextProperties();
1539}

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 2305 of file KoSvgTextShape.cpp.

2306{
2307 KoSvgText::AutoValue inlineSize = d->textData.childBegin()->properties.propertyOrDefault(KoSvgTextProperties::InlineSizeId).value<KoSvgText::AutoValue>();
2308 if (!d->shapesInside.isEmpty()) {
2309 return TextType::TextInShape;
2310 } else if (!inlineSize.isAuto) {
2311 return TextType::InlineWrap;
2312 } else {
2313 bool textSpaceCollapse = false;
2314 for (auto it = d->textData.depthFirstTailBegin(); it != d->textData.depthFirstTailEnd(); it++) {
2315 KoSvgText::TextSpaceCollapse collapse = KoSvgText::TextSpaceCollapse(it->properties.propertyOrDefault(KoSvgTextProperties::TextCollapseId).toInt());
2316 if (collapse == KoSvgText::Collapse || collapse == KoSvgText::PreserveSpaces) {
2317 textSpaceCollapse = true;
2318 break;
2319 }
2320 if (!it->localTransformations.isEmpty()) {
2321 textSpaceCollapse = true;
2322 break;
2323 }
2324 }
2326 }
2328}
@ 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::TextCollapseId, and TextInShape.

◆ 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 2552 of file KoSvgTextShape.cpp.

2553{
2554 return d->currentTextWrappingAreas;
2555}

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 1500 of file KoSvgTextShape.cpp.

1501{
1502 auto candidate = d->textData.childBegin();
1503 if (d->isLoading || d->cursorPos.isEmpty()) return d->createTextNodeIndex(candidate);
1504 if (childBegin(d->textData.childBegin()) != childEnd(d->textData.childBegin())) {
1505 candidate = childBegin(d->textData.childBegin());
1506 }
1507 const int finalPos = d->cursorPos.size() - 1;
1508 const int index = d->cursorPos.at(qBound(0, pos, finalPos)).index;
1509 int currentIndex = 0;
1510
1511 auto e = Private::findTextContentElementForIndex(d->textData, currentIndex, index, true);
1512 if (e == d->textData.depthFirstTailEnd()) {
1513 return d->createTextNodeIndex(candidate);
1514 }
1515
1516 auto element = KisForestDetail::siblingCurrent(e);
1517 auto parent = Private::findTopLevelParent(d->textData.childBegin(), element);
1518 if (parent == childEnd(d->textData.childBegin())) return d->createTextNodeIndex(candidate);
1519
1520 return d->createTextNodeIndex(parent);
1521}

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 696 of file KoSvgTextShape.cpp.

697{
698 int start = qMin(pos, anchor);
699 int end = qMax(pos, anchor);
700
701 if (start == end || start < 0 || end >= d->cursorPos.size()) {
702 return QPainterPath();
703 }
704 QPainterPathStroker stroker;
705
707 stroker.setCapStyle(Qt::FlatCap);
708 if (style == KoSvgText::Solid) {
709 stroker.setDashPattern(Qt::SolidLine);
710 } else if (style == KoSvgText::Dashed) {
711 stroker.setDashPattern(Qt::DashLine);
712 } else if (style == KoSvgText::Dotted) {
713 stroker.setDashPattern(Qt::DotLine);
714 } else {
715 stroker.setDashPattern(Qt::SolidLine);
716 }
717
718 QPainterPath underPath;
719 QPainterPath overPath;
720 QPainterPath middlePath;
721 qint32 strokeWidth = 0;
722 QPointF inset = mode == KoSvgText::HorizontalTB? QPointF(minimum*0.5, 0): QPointF(0, minimum*0.5);
723 for (int i = start+1; i <= end; i++) {
724 CursorPos pos = d->cursorPos.at(i);
725 CharacterResult res = d->result.at(pos.cluster);
726 strokeWidth += res.metrics.underlineThickness;
727 const QTransform tf = res.finalTransform();
728 QPointF first = res.cursorInfo.caret.p1();
729 QPointF last = first;
730 if (res.cursorInfo.rtl) {
731 last += res.cursorInfo.offsets.value(pos.offset-1, res.advance);
732 first += res.cursorInfo.offsets.value(pos.offset, QPointF());
733 if (i == start+1) {
734 first -= inset;
735 }
736 if (i == end) {
737 last += inset;
738 }
739 } else {
740 first += res.cursorInfo.offsets.value(pos.offset-1, QPointF());
741 last += res.cursorInfo.offsets.value(pos.offset, res.advance);
742 if (i == start+1) {
743 first += inset;
744 }
745 if (i == end) {
746 last -= inset;
747 }
748 }
749
750 if (decor.testFlag(KoSvgText::DecorationUnderline)){
751 underPath.moveTo(tf.map(first));
752 underPath.lineTo(tf.map(last));
753 }
754 QPointF diff = res.cursorInfo.caret.p2() - res.cursorInfo.caret.p1();
755 if (decor.testFlag(KoSvgText::DecorationOverline)){
756 overPath.moveTo(tf.map(first+diff));
757 overPath.lineTo(tf.map(last+diff));
758 }
759 if (decor.testFlag(KoSvgText::DecorationLineThrough)){
760 middlePath.moveTo(tf.map(first+(diff*0.5)));
761 middlePath.lineTo(tf.map(last+(diff*0.5)));
762 }
763 }
764
765 const qreal freetypePixelsToPt = (1.0 / 64.0) * (72. / qMin(d->xRes, d->yRes));
766 const qreal width = strokeWidth > 0 ? qMax(qreal(strokeWidth/qMax(1, end-(start+1)))*freetypePixelsToPt, minimum): minimum;
767
768 stroker.setWidth(thick? width*2: width);
769
770 QPainterPath final;
771 if (decor.testFlag(KoSvgText::DecorationUnderline)){
772 final.addPath(stroker.createStroke(underPath));
773 }
774 if (decor.testFlag(KoSvgText::DecorationOverline)){
775 final.addPath(stroker.createStroke(overPath));
776 }
777 if (decor.testFlag(KoSvgText::DecorationLineThrough)){
778 final.addPath(stroker.createStroke(middlePath));
779 }
780
781 return final;
782}
@ 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 537 of file KoSvgTextShape_p.h.

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

◆ updateShapeGroup()

void KoSvgTextShape::updateShapeGroup ( )
inline

Definition at line 521 of file KoSvgTextShape_p.h.

521 {
522 Q_FOREACH(KoShape *shape, shapeGroup->shapes()) {
523 shapeGroup->removeShape(shape);
524 }
525 Q_FOREACH(KoShape *shape, shapesInside) {
526 shapeGroup->addShape(shape);
527 }
528 Q_FOREACH(KoShape *shape, shapesSubtract) {
529 shapeGroup->addShape(shape);
530 }
531 Q_FOREACH(KoShape *shape, textPaths) {
532 shapeGroup->addShape(shape);
533 }
536 }
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 }
581
582 return wordEnd;
583}
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, CharacterResult::cursorInfo, cursorPos, d, 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 }
370 if (direction == KoSvgText::DirectionRightToLeft) {
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, 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 }
383 if (direction == KoSvgText::DirectionRightToLeft) {
384 return wordStart(pos);
385 }
386 return wordEnd(pos);
387}

References d, 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 585 of file KoSvgTextShape.cpp.

586{
587 if (pos <= 0 || pos > d->cursorPos.size() || d->result.isEmpty() || d->cursorPos.isEmpty()) {
588 return pos;
589 }
590
591 int wordStart = pos;
592 for (int i = pos; i >= 0; i--) {
593 wordStart = i;
594 CursorPos cursorPos = d->cursorPos.at(i);
595 const CharacterResult res = d->result.at(cursorPos.cluster);
597 && (cursorPos.offset == 0 || cursorPos.offset+1 == res.cursorInfo.offsets.size())
598 && i < pos) {
599 break;
600 }
601 }
602
603 return wordStart;
604}

References CharacterResult::breakType, CharacterResult::cursorInfo, cursorPos, d, 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 1621 of file KoSvgTextShape.cpp.

1622{
1624}

References textProperties(), and KoSvgTextProperties::WritingModeId.

Friends And Related Symbol Documentation

◆ KoSvgTextLoader

friend class KoSvgTextLoader
friend

Definition at line 677 of file KoSvgTextShape.h.

◆ TestSvgText

friend class TestSvgText
friend

Definition at line 676 of file KoSvgTextShape.h.

Member Data Documentation

◆ bulkActionState

std::optional<BulkActionState> KoSvgTextShape::bulkActionState

Definition at line 555 of file KoSvgTextShape_p.h.

◆ currentTextWrappingAreas

QList<QPainterPath> KoSvgTextShape::currentTextWrappingAreas

Definition at line 561 of file KoSvgTextShape_p.h.

◆ cursorPos

QVector<CursorPos> KoSvgTextShape::cursorPos

Definition at line 584 of file KoSvgTextShape_p.h.

◆ d

QScopedPointer<Private> KoSvgTextShape::d
private

Definition at line 704 of file KoSvgTextShape.h.

◆ disableFontMatching

bool KoSvgTextShape::disableFontMatching = false

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

Definition at line 579 of file KoSvgTextShape_p.h.

◆ initialTextPosition

QPointF KoSvgTextShape::initialTextPosition = QPointF()

Definition at line 589 of file KoSvgTextShape_p.h.

◆ internalShapesPainter

QScopedPointer<KoShapePainter> KoSvgTextShape::internalShapesPainter

Definition at line 514 of file KoSvgTextShape_p.h.

◆ isBidi

bool KoSvgTextShape::isBidi = false

Definition at line 588 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 577 of file KoSvgTextShape_p.h.

◆ lineBoxes

QVector<LineBox> KoSvgTextShape::lineBoxes

Definition at line 582 of file KoSvgTextShape_p.h.

◆ logicalToVisualCursorPos

QMap<int, int> KoSvgTextShape::logicalToVisualCursorPos

Definition at line 585 of file KoSvgTextShape_p.h.

◆ plainText

QString KoSvgTextShape::plainText

Definition at line 587 of file KoSvgTextShape_p.h.

◆ result

QVector<CharacterResult> KoSvgTextShape::result

Definition at line 581 of file KoSvgTextShape_p.h.

◆ shapeGroup

QScopedPointer<KoShapeGroup> KoSvgTextShape::shapeGroup

Definition at line 515 of file KoSvgTextShape_p.h.

◆ shapesInside

QList< KoShape * > KoSvgTextShape::shapesInside

Definition at line 557 of file KoSvgTextShape_p.h.

◆ shapesSubtract

QList< KoShape * > KoSvgTextShape::shapesSubtract

Definition at line 558 of file KoSvgTextShape_p.h.

◆ textData

KisForest<KoSvgTextContentElement> KoSvgTextShape::textData

Definition at line 576 of file KoSvgTextShape_p.h.

◆ textPaths

QList<KoShape*> KoSvgTextShape::textPaths

Definition at line 559 of file KoSvgTextShape_p.h.

◆ xRes

int KoSvgTextShape::xRes = 72

Definition at line 511 of file KoSvgTextShape_p.h.

◆ yRes

int KoSvgTextShape::yRes = 72

Definition at line 512 of file KoSvgTextShape_p.h.


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