Development/Custom Shape Orientation Guide

This article is an orientation guide about custom shapes and is intended for developers. It points to relevant specifications, points to relevant parts of the code and tries to show relationships in regard to file formats.

Please use the “Discussion” page for your comments, questions and proposals. In case you find errors, simple correct them.

What is “custom shape”?
custom shape is a technical term and does not mean user made shape, but custom shape is the generic term for the shapes that have an enhanced geometry. Strictly speaking, the spelling “custom shape”-shape should be used. However, this article uses the simpler spelling custom shape. These shapes are written as element    in the file markup in ODF. These kind of shapes are identified by SdrObjKind::CustomShape and support the service com.sun.star.drawing.CustomShape.

Many of these shapes have handles and shape specific glue points. For all of these shapes and only for them the tool “Toggle Extrusion” is active in the UI. Looking at it allows to quickly distinguish a custom shape from other kind of shapes.

Starting with OOo2.0, custom shapes were implemented to work with shapes from binary MS Office format and related RTF and VML formats. Import and export filter for shapes defined in OOXML were added a few years later. Work on improving the filters is ongoing.

A custom shape is an object of SdrObjCustomShape class and belongs to the hierarchy of SdrObject class. In particular, many aspects of its text content are inherited from SdrTextObj class. Object methods of custom shapes, such as move and rotate, are located in the svdoashp.hxx/cxx files. Methods for preparing rendering are located in the customshapes</tt> folder in the svx module.

Custom shapes in a Writer document are special as they can have an attached text frame. The relevant class is SwTextBoxHelper</tt>. This text frame is mainly used for round-trip with OOXML. It has been introduced in 2014, read blog post. It still needs some improvements.

Specifications
When working on filters, you surely need the specifications. They are also useful for understanding the code, since identifiers often have a direct relationship to terms in the specifications. The “Relevant Specifications” section at the end of the article contains some links to them. References such as “[RTF page nn]” refer to this list.

API/UNO
Many properties of custom shapes are not represented by class members but by properties. They are used via services and interfaces. Most constants and properties for custom shapes are prefixed with EnhancedCustomShape</tt>. For to get a local copy install the SDK for your installed LibreOffice or build LibreOffice with configure option -–⁠enable-odk</tt> which will put the SDK into folder /core/instdir/sdk</tt>. To take a look at a custom shape from an API point of view, use the “Development Tools”. Look at property “CustomShapeGeometry”, which is essential for custom shapes. It is a sequence of properties. They are explained in the “CustomShapeGeometry” and “Path” sections in alphabetical order.

Predefined Shapes
The MS binary file format and OOXML each define a set of predefined shapes. “Predefined” means that the geometry of the shapes is not contained in the file, but defined in the file format specification. ODF has no such concept; all shapes must be entirely defined in the file itself. The predefined shapes of MS binary file formats are described in “Appendix D: AutoShapes” in the specification [MS97]. The predefined shapes of OOXML are provided in separate xml-files [OOXML].

The translation of the OOXML preset shapes into our properties is located in CustomShapeProperties::initializePresetDataMap</tt>. Since the result is independent of individual documents, it is located in the repository. To translate AutoShapes of MS binar format to our properties, their geometry is described in structs of type mso_CustomShape</tt>.

struct mso_CustomShape
struct mso_CustomShape {   SvxMSDffVertPair*                       pVertices; sal_uInt32                             nVertices; sal_uInt16*                            pElements; sal_uInt32                             nElements; SvxMSDffCalculationData*               pCalculation; sal_uInt32                             nCalculation; sal_Int32*                             pDefData; SvxMSDffTextRectangles*                pTextRect; sal_uInt32                             nTextRect; sal_Int32                              nCoordWidth; sal_Int32                              nCoordHeight; sal_Int32                              nXRef; sal_Int32                              nYRef; SvxMSDffVertPair*                      pGluePoints; sal_uInt32                             nGluePoints; SvxMSDffHandle*                        pHandles; sal_uInt32                             nHandles; }; The mso_CustomShape</tt> struct is defined in EnhancedCustomShapeGeometry.hxx</tt> and used in EnhancedCustomShapeGeometry.cxx</tt> to describe the preset shapes of MS binary format in a way, that they can be expressed as custom shapes. Translating such description to the syntax used in custom shapes is located at start of file EnhancedCustomShape2d.cxx</tt>. Method SdrObjCustomShape::MergeDefaultAttributes</tt> sets the properties to the individual custom shape.

The structures in the EnhancedCustomShapeGeometry</tt> file use values that have flags incorporated, as well as special constants. Their meanings are explained later in the affected sections.

Shape definitions are not translated 1:1 from AutoShape definitions [MS97 Appendix D] in all cases. Custom shapes in LO are rendered using polygons. A fill is only possible for a closed polygon. However, the original definition may contain only a polyline. In such cases, the definition was adapted to the needs of our rendering engine. This was especially necessary for shapes rendered with lightened and darkened parts in MS Office. The description in MS binary format does not take into account such shading.

AdjustmentValues
The corresponding attribute in ODF is draw:modifiers</tt> [ODF 19.196]. It is a space-separated list of numbers. The numbers can be used in formulas, point coordinates, and handle positions by using a modifier reference $0</tt>, $1</tt>,&hellip;. The other specifications use the term "adjustment value".

RTF has the array pAdjustHandles</tt> [RTF page 173] for this purpose.

The MS binary format has individual attributes <tt>adjustValue</tt>, <tt>adjust2Value</tt>, &hellip;, <tt>adjust10Value</tt> [MS97 page 30]. A reference to such a value is written as <tt>DFF_Prop_adjustValue</tt>, <tt>DFF_Prop_adjust2Value</tt>, &hellip; in structs of type <tt>mso_CustomShape</tt> in the file <tt>EnhancedCustomShapeGeometry.cxx</tt>.

OOXML and VML use the <tt> <avLst> </tt> element (List of Shape Adjust Values) [OOXML 20.1.9.5] with <tt> <gd> </tt> child elements (Shape Guide) [OOXML 20.1.9.11]. Such <tt> <gd> </tt> element has a <tt>name</tt> attribute and a <tt>fmla</tt> attribute. The values are referenced by using the value of the <tt>name</tt> attribute. Although formally arbitrary formulas are allowed, in practice constant numbers are used in case of adjustment values. Therefore translation to ODF is possible.

The <tt>AdjustmentValues</tt> property is a sequence of items of struct <tt>css.drawing.EnhanceCustomShapeAdjustmentValue</tt>. For ODF, a simple vector of numbers would suffice, but round-trip with OOXML additionally requires the <tt>name</tt> component. It is empty in case of ODF.

ODF
The <tt>Equations</tt> property is a sequence of strings. Each string holds an expression formed according to the formula language specified in ODF [ODF 19.171]. It is a complex language that allows nested expressions. The language provides the usual operators, expect <tt>^</tt>, and functions <tt>abs</tt>, <tt>sqrt</tt>, <tt>sin</tt>, <tt>cos</tt>, <tt>tan</tt>, <tt>atan</tt>, <tt>min</tt>, <tt>max</tt>, <tt>atan2</tt>, and <tt>if</tt>. In addition it has the identifiers <tt>left</tt>, <tt>top</tt>, <tt>right</tt>, <tt>bottom</tt> (values of <tt>svg:viewBox</tt>), <tt>logwidth</tt>, <tt>logheight</tt> (values of <tt>svg:width</tt> and <tt>svg:height</tt> in hundredths of millimeters), <tt>hasfill</tt>, <tt>hasstroke</tt>, <tt>xstretch</tt>, <tt>ystretch</tt> and the identifier <tt>pi</tt>. The identifiers <tt>logwidth</tt> and <tt>logheight</tt> are often used when translating from OOXML, as they allow the current size of the shape to be used in equations instead of values from <tt>viewBox</tt> attribute.

The other file formats have a similar principle. However, their formula language has only a limited number of expression types [VML page 352] and [OOXML 20.1.9.11 and 20.1.10.56]. The translation of their formulas to ODF is implemented in LibreOffice, but the translation from ODF to their restricted format is not yet solved in LibreOffice (as of May 2022).

The corresponding element in ODF is <tt> <draw:equation> </tt> [ODF 10.2.5]. It has an attribute <tt>draw:name</tt> and an attribute <tt>draw:formula</tt> [ODF 19.171]. LibreOffice discards the names when opening an ODF file and uses the zero-based index of the equation in the sequence instead. For example, a reference to an equation with index <tt>7</tt> is then written as <tt>?7</tt>. LibreOffice generates the names <tt>f0</tt>, <tt>f1</tt>, … and changes the references to <tt>?f7</tt>, for example, when the ODF markup is written to the file.

MS binary format
The struct <tt>mso_CustomShape</tt> (used for the description of AutoShapes) contains the formulas in member <tt>pCalculation</tt>. This is an array of items of type struct <tt>SvxMSDffCalculationData</tt>. This struct has the members <tt>nFlags</tt> and <tt>nVal[3]</tt>. The member <tt>nFlags</tt> contains in its last byte coded which expression type has to be used. The member <tt>nVal[3]</tt> contains three parameters for the expression. Parameters not needed for an expression type are ignored.

Evaluating the expression type is located in <tt>EnhancedCustomShape2d::GetEquation</tt> The expression type enumeration follows the expression type order in [VML page 352] and the enumeration “Shape Guide Formula” [MS97 page 171] or in [MS 2.2.58 SG]. The case <tt>0</tt> includes evaluation of the expression type <tt>val</tt>, which specifies a constant number.

Formulas can use references to other formulas that have a lower index and to adjustment values. The first byte of the member <tt>nFlags</tt> contains encoded which of the three parameters is not a simple number.

In a parameter from <tt>nVal[3]</tt> in a <tt>SvxMSDffCalculationData</tt> struct, a reference to a formula is written as <tt>0x4</tt>nm. The <tt>0x4</tt> part is a flag evaluated in method <tt>EnhancedCustomShape2d::AppendEnhancedCustomShapeEquationParameter</tt> to distinguish a reference to a formula from references to adjustment values and from other identifiers.

OOXML
The set of possible expression types for OOXML is listed in attribute <tt>fmls</tt> [OOXML 2.1.9.11]. Compared to MS binary format the types <tt>sumangle</tt> and <tt>ellipse</tt> have been removed, type <tt>pin</tt> (clamp) is added, type <tt>val</tt> for constant number is added and the type <tt>mid</tt> has been replaced by the more general expression type <tt>+/</tt> (Add Divide). The standard defines 38 predefined constants and expressions that can be used as parameter [OOXML 20.1.10.56]. Such are <tt>hc</tt> for <tt>*/ w 1.0 2.0</tt> or <tt>ss</tt> for <tt>min w h</tt>, for example. These allow a shorter list of equations needed.

The translation in LibreOffice is located in static method <tt>convertToOOEquation</tt> in file <tt>customshapegeometry.cxx</tt>.

Extrusion
This is a sequence of properties. It serves as container for attributes from the 24 extrusion related attributes of the ODF element <tt> <draw:enhanced-geometry> </tt> [ODF 10.6.2]. The chapter “Custom Shapes in 3D” in the book “Custom Shape Tutorial” provides an overview of the meaning of these attributes. There are similar attributes in MS binary format [MS 2.3.15 and 2.3.16], RTF [RTF page 182] and VML [VML 19.2.2.11]. Only import from MS binary format works well.

OOXML has extrusion as part of its “3D” [OOXML 20.1.5]. Extrusion is not handled when exporting from ODF to OOXML, and in round-tripping from OOXML it is only preserved via the <tt>InteropGrabBag</tt> property, but not evaluated (as of May 2022).

LO uses the same rendering engine for extruded custom shapes as for 3D-scenes. The creation of a corresponding 3D-scene is done in the method EnhancedCustomShape3d::Create3DObject, which is called by the method EnhancedCustomShapeEngine::render.

Handles
The <tt>Handles</tt> property is a sequence of handles. The API reference has a handle therein as service <tt>EnhancedCustomShapeHandle</tt>.

The <tt>Handles</tt> property corresponds to array <tt>pAdjustHandles</tt> in RTF [RTF page 173] and MS binary format [MS 2.3.6.24][MS97 page 31] and to <tt> </tt> element in VML [VML 19.1.2.9]. The struct <tt>mso_CustomShape</tt> has this sequence of handles in its member <tt>pHandles</tt>. That is a sequence of items of type <tt>SvxMSDffHandle</tt>.

OOXML has the sequence of handles as element <tt> <ahLst> </tt> [OOXML 20.1.9.1] with child elements <tt> <ahPolar> </tt> [OOXML 20.1.9.2] and <tt> <ahXY> </tt> [OOXML 20.1.9.3].

ODF has no such container element but the elements for the individual handles are written directly after the elements for equations, which results in an order of the elements too. A handle is specified as <tt> <draw:handle> </tt> [ODF 10.6.3].

All specification know a “handle” but the details vary.

MS binary format
A handle is described by an <tt>ADJH</tt> struct in MS binary format [MS97 page 171][MS 2.2.57]. It consists of flags and attributes. The above mentioned struct <tt>SvxMSDffHandle</tt> reflects this; it has a component <tt>nFlags</tt> of type <tt>SvxMSDffHandleFlags</tt> and several components for attributes. The description of these flags in [MS] specfication is quite informative.

The components in struct <tt>mso_CustomShape</tt> have the same meaning as the attributes in [MS] specification. The method <tt>EnhancedCustomShape2d::SetEnhancedCustomShapeHandleParameter</tt> converts these values into values of type <tt>EnhancedCustomShapeParameter</tt>, which has a <tt>Type</tt> component and a <tt>Value</tt> component. That is used by method lcl_ShapePropertiesFromDFF in file <tt>svdoashp.cxx</tt>, which converts all handle data into the corresponding UNO properties.

OOXML, VML, RTF, ODF
RTF and VML use the same <tt> <h> </tt> element [VML 19.1.2.8] to specify a handle. Its attributes have counterparts in OOXML and ODF. OOXML has separate elements <tt> <ahPolar> </tt> [OOXML 20.1.9.2] for polar handles and <tt> ahXY </tt> [OOXML 20.1.9.3] for Cartesian handles. The attributes are nevertheless comparable. Service <tt>EnhancedCustomShapeHandle</tt> covers most of them. Therefore they are put together into one table to make the relationships visible.

Comments to “Position”
The coordinates of a handle position need to directly or indirectly refer adjustment values. When the user changes the handle position, the application will determine the adjustment values so, that when using these values in the calculation of the coordinates of the position attribute. the position determined by the user is generated.

OOXML: The coordinates in the <tt>pos</tt> element are in unit EMU and not relative to the local coordinate system of the shape according to [OI29500 2.1.1310]. They are Cartesian coordinates even if the handle is a polar handle. It is yet not solved in general to calculate the needed adjustment values when a user moves a handle. But it already works for most of the predefined shapes. The calculation is located in method EnhancedCustomShape2d::SetHandleControllerPosition and page “Improve handles of DrawingML shapes” has details about it.

ODF, VML/RTF: If the handle is set as polar handle, that is if <tt>draw:handle-polar</tt> attribute or <tt>Polar</tt> or <tt>polar</tt> flag, respectively, is set, then the position attribute contains polar coordinates (Radius,Angle) else Cartesian coordinates (x,y). Caution, the ODF specification text has erroneously order (Angle,Radius).

ODF (and UNO): In coordinates are not only numbers and references allowed but all identifiers as listed in section “Equations” as well, except for <tt>pi</tt>.

VML/RTF: Besides numbers and references to equations the identifiers <tt>center</tt>, <tt>topleft</tt> and <tt>bottomright</tt> are allowed for Cartesian handles.

MirroredX, MirroredY
The corresponding attributes in ODF are <tt>draw:mirror-horizontal</tt> [ODF 19.192] and <tt>draw:mirror-vertical</tt> [ODF 19.193].

When the user mirrors a custom shape, this does not change the defining points in the path of the shape, but mirroring is stored as property of the shape. This is different from, for example, polygons, where the reflection is directly applied to the coordinates of the path points. You will find a lot of code where this different handling of mirroring is addressed by a case distinction.

The mirroring is always done at the center point of the shape. Mirroring is handled by object methods.

The corresponding attributes in MS binary format and RTF are <tt>fFlipH</tt> and <tt>fFlipV</tt>, in VML and OOXML they are <tt>flipH</tt> and <tt>flipV</tt>.

Path
The <tt>Path</tt> property is actually a sequence of properties. They are discussed below in a separate section “Path”.

TextCameraZRotateAngle
OOXML provides full 3D transformation of shapes. Users often use its z-rotation to rotate a shape instead of using the 2D shape rotation. LibreOffice uses this property to track such rotation. ODF has nothing equivalent to this property, so the rotation is converted to 2D object rotation when in ODF. The property is not published.

TextPath
The <tt>TextPath</tt> property is a sequence of properties. It serves as container for attributes used to describe shapes called “FontWork” in the LibreOffice user interface. It corresponds to the service <tt>EnhancedCustomShapeTextPath</tt> in the API reference. Older MS Office versions called it “WordArt”, newer versions use the term “abc Transformation”. And you may also come across the term “text warp”.

The property <tt>IsFontwork</tt> and the properties starting with <tt>FontWork</tt>, which you might see when using the “Development Tools”, do not belong to custom shapes but to the "Formtext"-feature of curves and polygons.

OOXML has 40 predefined shapes in <tt>presetTextWarpDefinitons.xml</tt> file in the zip archive “Electronic inserts” belonging to Part 1. There exists no way to extend this set. In MS binary format these shape types are available too, integrated in the shape type's table used for all AutoShapes [MS97 page 57][MS 2.4.24 MSOSPT], similar for RTF with values 136 to 175 of <tt>ShapeType</tt> attribute [RTF page 190]. VML has no set of predefined shapes. It has a <tt>textpath</tt> element with several attributes which can be added to any <tt>shape</tt> element [VML 19.1.2.23] to get this artistic form of text data. Examples are shown in the specification. If Word detects or knows, that the shape geometry equals a predefined one, it writes the attribute <tt>o:spt</tt> with type index in the docx markup. If such attribute is missing LO imports the shape with errors (as of June 2022).

The struct <tt>mso_CustomShape</tt> defines only the geometry of the shape and has no information about a text path. The fact, that it is a “WordArt” shape, is given by its type. All properties belonging to <tt>TextPath</tt> are already included in the predefined shapes from the “Fontwork Gallery” or they are imported along with the shape when a document is opened that contains a “Fontwork”-shape.

The article “Remarks on Fontwork and TextWarp” contains more information about this special state of custom shapes. The chapter “Text Path” in the book “Custom Shape Tutorial” provides examples of “Fontwork”-shapes beyond the predefined ones.

TextPreRotateAngle
This has been introduced for round-trip with OOXML Use and relationship to property TextRotateAngle is unclear. It needs improvements. The property is not published.

TextRotateAngle
The corresponding attribute in ODF is <tt>draw:text-rotate-angle</tt> [ODF 19.226] The text area of a custom shape can be rotated independent from the shape rotation. So it is possible to have an upright text in a rotated shape. The property is evaluated and correctly rendered but has no UI.

ToDo: Other file formats?

Type
The corresponding attribute in ODF is <tt>draw:type</tt> [ODF 19.229.3] with the default value <tt>non-primitive</tt>. LibreOffice uses this property in a very special way.

LibreOffice needs to know whether a shape was generated from a predefined shape on import for to be able to use this definition on export. LibreOffice tracks this in the <tt>Type</tt> property.

OOXML
The import of shapes in documents in OOXML format distinguishes three cases:

a) The shape markup has an element <tt> <custGeom> </tt>. Then <tt>Type="ooxml-non-primitive"</tt> is used. The file contains the complete shape definition.

b) The shape markup has an element <tt> <prstGeom> </tt> and no element <tt> <prstTxWarp> </tt>. Then it is a shape predefined in file <tt>presetShapeDefinitions.xml</tt> and the value of attribute <tt>prst</tt> of the <tt> <prstGeom> </tt> element is used with prefix “ooxml-”. The markup <tt>prst="noSmoking"</tt> results in value <tt>ooxml-noSmoking</tt> for the <tt>Type</tt> property, for example.

c) The shape markup has an element <tt> <prstGeom> </tt> with attribute <tt>prst="rect"</tt> and it has an element <tt> <prstTxWarp> </tt>. Then it is a shape predefined in file <tt>presetTextWarpDefinitions.xml</tt>. Those shapes are mapped to the corresponding shape type of MS binary format.

MS binary format
The import of shapes in documents in MS binary format uses the enum <tt>MSO_SPT</tt> in file msdffdef.hxx. The numbering is the same as defined in the specification [MS97 page 57]. These numbers are used with same meaning in attribute <tt>ShapeType</tt> in [RTF] too. This enum values are mapped to strings in <tt>pNameTypeTableArray</tt> in EnhancedCustomShapeTypeNames.cxx.

The value of property <tt>Type</tt> is used as parameter in method <tt>createCustomDefaults</tt> of interface <tt>XEnhancedCustomShapeDefaulter</tt>. That is implemented in <tt>SvxCustomShape::createCustomShapeDefaults</tt>. It covers shape types from MS binary format.

On export to OOXML the implementation tries to export the shape types from MS binary format to suitable OOXML shape types. That is located in <tt>ShapeExport::WriteCustomShape</tt>. If that is not possible a shape of kind <tt> <custGeom> </tt> which has the shape outline in its <tt> </tt> elements is used. Improving the export filter is ongoing work.

OpenOffice.org
Last to mention are shapes with values structure <tt>col-nxxxxxxx</tt> of the <tt>Type</tt> attribute. We have two of such shapes in the UI, “Octagon Bevel” with <tt>Type="col-60da8460"</tt> and “Diamond Bevel” with <tt>Type="col-⁠502ad400"</tt>. Because ODF has no way to express to lighten or darken a part of a shape, OOo has introduces this special kind of value of the <tt>Type</tt> attribute. The value is decoded into member <tt>nColorData</tt> of an object of class <tt>EnhancedCustomShape2d</tt>. This member <tt>nColorData</tt> is used too to express lighten and darken for shaped types from MS binary format. The needed value is individually set for such shapes in the object ctor.

ViewBox
The corresponding attribute in ODF is <tt>svg:viewBox</tt> [ODF 19.574] and it has the same meaning as in SVG. It defines a local coordinate system for the coordinates used inside the enhanced geometry of the custom shape. The rectangle given by the <tt>svg:viewBox</tt> attribute is scaled to the world coordinate rectangle given by the <tt>svg:x</tt>, <tt>svg:y</tt>, <tt>svg:width</tt> and <tt>svg:height</tt> attributes. Using coordinates outside the rectangle given by the <tt>svg:viewBox</tt> attribute is possible, used in the shape “Rectangular Callout” for example.

The attribute <tt>svg:viewBox</tt> may be omitted in ODF. LibreOffice renders the shape then (not ODF conform) as if <tt>svg:viewBox="0 0 21600 21600"</tt> was set. That happens in ctor of <tt>EnhancedCustomShape2d</tt> via members <tt>nCoordWidthG</tt> and <tt>nCoordHeightG</tt>.

MS binary format and RTF use the individual attributes <tt>geoLeft</tt>, <tt>geoTop</tt>, <tt>geoRight</tt> and <tt>geoBottom</tt> to define a local coordinate system. The default values are <tt>0</tt>, <tt>0</tt>, <tt>21600</tt> and <tt>21600</tt>. Using other values than <tt>0</tt> for attributes <tt>geoLeft</tt> and <tt>geoTop</tt> is neither implemented in MS Office nor in LibreOffice. The values from attributes <tt>geoRight</tt> and <tt>geoBottom</tt> are represented as members <tt>nCoordWidth</tt> and <tt>nCoordHeight</tt> in struct <tt>mso_CustomShape</tt>. All shape description in file <tt>EnhancedCustomShapeGeometry.cxx</tt> use the default values, only descriptions for shapes “can” and “heart” are different.

svg:viewBox="0 0 0 0"
OOXML has something similar in attributes <tt>w</tt> and <tt>h</tt> of the <tt> </tt> element [OOXML 20.1.9.15]. OOXML can set these attributes individually for each <tt> </tt> element. ODF can set attribute <tt>svg:viewBox</tt> only globally for the entire shape geometry.

On the other hand the attributes <tt>w</tt> and <tt>h</tt> may be omitted and so a viewBox does not exist. In that case the current width and height of the shape is used, which have unit EMU. But a missing viewBox is treated as <tt>svg:viewBox="0 0 21600 21600"</tt> in LibreOffice.

Therefore LibreOffice uses <tt>svg:viewBox="0 0 0 0"</tt> to indicate these situations. As of June 2022 it is set for all shapes on import from OOXML format, expect shapes “chartPlus”, “chartStar” and “chartX”. You find this in file <tt>oox-drawingml-cs-presets</tt> and in method <tt>CustomShapeProperties::pushToPropSet</tt>. (I don’t know why the “ChartFoo” shapes use “0 0 4000000 400000” and whether these different values are actually used somewhere.)

The use of <tt>svg:viewBox="0 0 0 0"</tt> is problematic in regard to interoperability. As attribute in SVG it means, that the shape is not rendered, and thus MS Office will not render the shape, when it opens an ODF document with such a shape.

Path
The <tt>Path</tt> property in <tt>CustomShapeGeometry</tt> is a sequence of properties and serves as container. It has no direct corresponding attribute or element in any of the mentioned file format specifications. It corresponds to service <tt>EnhancedCustomShapePath</tt> in the API reference.

ConcentricGrandientFillAllowed
The corresponding attribute in ODF is <tt>draw:concentric-gradient-fill-allowed</tt> [ODF 19.124]. Concentric gradient fill is not implemented in LibreOffice, although the property is mentioned in the API reference.

ToDo: Other file formats?

Coordinates
There is no directly corresponding attribute in ODF. But the information in <tt>draw:enhanced-path</tt> attribute is divided into a sequence of the pure coordinates (<tt>Coordinates</tt> property ) and a sequence of commands (<tt>Segments</tt> property). For example <tt>draw:enhanced-path="M 0 10 Y 20 0 L 30 40 N Z"</tt> will become (not literally but in content) Coordinates=”0|10 20|0 30|40” and Segments=”M Y L N Z”.

Shapes in OOXML and VML too have no separation in coordinates and commands. But such separation exists in RTF and in MS binary format as arrays <tt>pSegmentInfo</tt> and <tt>pVertices</tt>.

The <tt>Coordinates</tt> property is a sequence of items of type <tt>css.drawing.EnhancedCustomShapeParameterPair</tt>. Such item has the components <tt>First</tt> and <tt>Second</tt>, not “X” and “Y”. The components <tt>First</tt> and <tt>Second</tt> themselves have type <tt>css.drawing.EnhancedCustomShapeParameter</tt>. That has the components <tt>Value</tt> and <tt>Type</tt>. <tt>Value</tt> can contain any number. <tt>Type</tt> is a constant from <tt>css.drawing.EnhancedCustomShapeParameterType</tt>. In the context of coordinates only the constants <tt>Normal</tt> = 0, <tt>Equation</tt> = 1 and <tt>Adjustment</tt> = 2 are allowed. So if the shape path needs the constant <tt>Right</tt>, an equation has to be introduced for that value. A reference to an equation is written with <tt>?</tt> prefix in ODF file markup, to an adjustment value with <tt>$</tt> prefix.

The <tt>mso_CustomShape</tt> struct (used for the description for predefined shape of MS binary format) has this sequence of coordinates in its member <tt>pVertices</tt>. A coordinate pair is a struct <tt>SvxMSDffVertPair</tt> with component <tt>nValA</tt> and <tt>nValB</tt>, both type <tt>sal_Int32</tt>. To be able to use a reference to an equation the flag <tt>MSO_I</tt> is used, which sets the first bit. A reference to an adjustment value is here not possible. Such reference needs to be used indirectly via equation.

ExtrusionAllowed
The corresponding attribute in ODF is <tt>draw:extrusion-allowed</tt> [ODF 19.149]. It is attribute <tt>f3DOK</tt> in MS binary format [MS97 page 31] and RTF [RTF page 184]. It is attribute <tt>extrusionok</tt> in VML [VML 19.1.2.14] and attribute <tt>extrusionOk</tt> in OOXML [OOXML 20.1.9.15]. Default value is <tt>true</tt>, for OOXML search for “extrusionOk” in [OI29599].

Lot of OOXML preset shapes have <tt>extrusionOk="false"</tt> in their path elements, “rightBrace”, smileyFace” or “verticalScoll” for example. The property is not evaluated in LibreOffice as of version 7.4. All custom shapes are able to extrude.

GluePoints
The corresponding attribute in ODF is <tt>draw:glue-points</tt> [ODF 19.175]. It is array <tt>pConnectionSites</tt> in RTF [RTF page 173] and MS binary format [MS97 page 31][MS 2.3.6.18]. It is attribute <tt>connectlocs</tt> in VML [VML 19.1.2.14]. In OOXML it is element <tt>cxnLst</tt> as child element of element <tt>custGeom</tt> and accordingly in the predefined OOXML shapes[OOXML 20.1.9.10].

The struct <tt>mso_CustomShape</tt> has the glue points in array <tt>pGluePoints</tt>, with items of type <tt>SvxMSDffVertPair</tt>. That is the same structure as used for property <tt>Coordinates</tt>.

OOXML has only one kind of glue points. ODF has the four default glue points at the middle of the edges of the maybe transformed snap rectangle, the object specific glue points defined in the path property of the enhanced-geometry (where this section is about) and glue points defined by the user according elements <tt> <draw:glue-point> </tt> [ODF 10.3.16].

In case of export from ODF to OOXML using a <tt>custGeom</tt> element, all glue points need to be exported. The method <tt>getGluePoints</tt> of interface <tt>XGluePointsSupplier</tt> returns a read-only container which contains all glue points. OOXML uses world coordinates, ODF uses local coordinates. But export of glue points in this case is not yet implemented (as of June 2020).

GluePointLeavingDirections
The corresponding attribute in ODF is <tt>draw:glue-point-leaving-directions</tt> [ODF 19.173]. It is array <tt>pConnectionSitesDir</tt> in RTF [RTF page 173] and MS binary format [MS97 page 31][MS 2.3.6.20]. It is attribute <tt>connectangles</tt> of element <tt> </tt> in VML [VML 19.1.2.14] and attribute <tt>ang</tt> of element <tt>cxn</tt> in OOXML [20.1.9.9].

This attribute is not implemented in LibreOffice although mentioned in the API reference.

GluePointType
The corresponding attribute in ODF is <tt>draw:glue-point-type</tt> [ODF 19.174] with values <tt>none</tt>, <tt>rectangle</tt> and <tt>segments</tt>. The values for the <tt>GluePointType</tt> property are given in <tt>EnhancedCustomShapeGluePointType</tt> as NONE, SEGMENTS, CUSTOM and RECT. That corresponds to attribute <tt>cxk</tt> in MS binary format and RTF [RTF page 186] and attribute <tt>connecttype</tt> in VML [VML 19.2.3.8].

Although the property is mentioned in the API reference, it is not really implemented for ODF documents but only rudimentary used in filters for MS binary format.

Segments
There is no directly corresponding attribute in ODF. But the information in attribute <tt>draw:enhanced-path</tt> is divided into a sequence of the pure coordinates (<tt>Coordinates</tt> property) and a sequence of commands (<tt>Segments</tt> property).

The <tt>Segments</tt> property is a sequence of items of type <tt>css.drawing.EnhancedCustomShapeSegment</tt>. That is a struct of components <tt>Command</tt> and <tt>Count</tt>. The component <tt>Command</tt> is one of the values listed in <tt>css.drawing.EnhancedCustomShapeCommand</tt> in the API reference. Values 1 to 16 have counterparts in ODF [ODF 19.145], the commands 17 to 21 are extensions by LibreOffice introduced for compatibility with OOXML. If one of the commands 17 to 21 occurs and extended ODF is used, the path is not only saved as element <tt> <draw:enhanced-path> </tt> without these commands but a second time as element<tt> <drawooo:enhanced-path> </tt> including these commands.

If the same command would follow several times in direct succession, this is combined into one item. The component <tt>Count</tt> tells how many sets of parameter values are needed, but the item has no information about the size of such set. The property <tt>Segments</tt> does not directly record how many parameters a command needs, but the program code needs to set it itself depending on the command.

The commands 1 to 16 are similar to those used by MS binary format, RTF and VML. OOXML has the commands as child elements of element <tt>path</tt> [OOXML 20.1.9.15]. It has only the commands <tt>arcTo</tt> [OOXML 20.1.9.4], <tt>close</tt> [OOXML 20.1.9.6], <tt>cubicBezTo</tt> [OOXML 21.1.9.7], <tt>lnTo</tt> [OOXML 20.1.9.13], <tt>moveTo</tt> [OOXML 20.1.9.14] and <tt>quadBezTo</tt> [OOXML 20.1.9.21].

The <tt>mso_CustomShape</tt> struct for the description for predefined shapes of MS binary format has this sequence of commands in its member <tt>pElements</tt> which is a sequence of items of type <tt>sal_Int16</tt>. Such item has in its first byte the command encoded and in its second byte information which is needed to calculate the above mentioned value for component <tt>Count</tt> (see table). The conversion of this description to <tt>Segments</tt> property is located in method <tt>lcl_ShapeSegmentFromBinary</tt>.

StretchX, StretchY
The corresponding attributes in ODF are <tt>draw:path-stretchpoint-x</tt> [ODF 19.204] and <tt>draw:path-stretchpoint-y</tt> [ODF 19.205]. MS binary format and RTF have these as attributes <tt>xLimo</tt> and <tt>yLimo</tt> [MS page 31], [RTF page 169]. VML has attribute <tt>limo</tt> of the <tt> </tt> element [VML page 487]. The standard OOXML has nothing comparable. Authors of OOXML shapes have to use formulas to calculate the suitable point coordinates to get the same effect. Look at preset shape “flowChartAlternateProcess” to learn how it can be done in OOXML.

limo-stretch
The descriptions in [VML page 487] or in [MS97 page 31] are not helpful, but the newer version of the specification has useful illustrations of the intended behavior [MS 2.3.6.22 and 2.3.6.23]. The ODF specification describes clearer what these values mean. For attribute <tt>draw:path-stretchpoint-x</tt> [ODF 19.204] it is,


 * “If specified, and if the x/y aspect ratio of the <tt>svg:viewBox</tt> 19.574 is lower than the x/y aspect ratio of the shape size then the whole path is stretched horizontally at <tt>draw:path-stretchpoint-x</tt>.


 * Stretching is done by:


 * 1) intersecting the path vertically at <tt>draw:path-stretchpoint-x</tt>.


 * 2) moving the right path fragments to the right border of the drawing shape, using its original aspect ratio. The left path fragment remains unmodified at the left border of drawing the shape.“

LibreOffice
LibreOffice does not behave exactly as specified in ODF as it does not evaluate the number in the attribute but evaluates only whether the attribute exists or not. However, it preserves the values. And LibreOffice requires a square viewBox to produce a correct limo-stretch. The ODF specification considers non-square viewBox rectangles too, so here a fix is needed, see bug. Microsoft Office interprets the properties <tt>StretchX</tt> and<tt> StretchY</tt> in documents in ODF in case of a square viewBox the same way as LibreOffice.

To understand how LibreOffice uses the properties <tt>StretchX</tt> and <tt>StretchY</tt>, let’s calculate an example manually.


 * Assume there is a shape with <tt>svg:viewBox="0 0 21600 21600"</tt> and <tt>svg:width="12cm"</tt> and <tt>svg:height="3cm"</tt>. We want to get the world coordinates for a point on the right edge and for a point inside the shape, for example the center point. In the example we use constant values and only look at the x-coordinates. The behavior for <tt>StretchY</tt> is analogous.


 * We call EnhancedCustomShape2d::GetPointAsB2DPoint with


 * <tt>true</tt> in <tt>bScale</tt> to get world coordinates.


 * <tt>true</tt> in <tt>bReplaceGeoSize</tt> to indicate that properties <tt>StretchX</tt> and <tt>StretchY</tt> have to be considered in case they are set.


 * <tt>EnhancedCustomShapeParameterType::NORMAL</tt> in <tt>rPair.First.Type</tt> and <tt>rPair.Second.Type</tt> because we use constant values.


 * <tt>rPair.First.Value=21600</tt> for a point on right edge or <tt>rPair.First.Value=10800</tt> for center point; <tt>rPair.Second.Value</tt> does not matter here.


 * Method <tt>GetPointAsB2DPoint</tt> calls <tt>EnhancedCustomShape2d::GetParameter(fValX, rPair.First, bReplaceGeoSize, false)</tt>. The main purpose of that method is to resolve modifier references and function references to values.


 * Case „StretchX is not set“
 * In that case method <tt>GetParameter</tt> simply returns a given constant value. So we get <tt>fValX=21600</tt> for a point on the right edge or <tt>fValX=10800</tt> for center point respectively. These values are then scaled with variable <tt>fScaleX</tt>.


 * The variable <tt>fXScale</tt> is a member in class <tt>EnhancedCustomShape2d</tt>. It has been initialized with <tt>fXScale=aLogicRect.GetWidth/nCoordWidth</tt> in method <tt>EnhancedCustomShape2d::SetPathSize</tt>. It contains the factor to be used to get world coordinates from local coordinates. In case of the example it is <tt>fXScale=12cm/21600</tt>. In reality, it is not „12cm“, but the value in hundredths of a millimeter. But I use the unit here to easily distinguish local coordinates and world coordinates.


 * So the final return value of <tt>GetPointAsB2DPoint</tt> is then <tt>fValX=21600*12cm/21600=12cm</tt> or <tt>fValX=10800*12cm/21600=6cm</tt> respectively.


 * Summary: In case „StretchX is not set“, the relationship of the points to each other is preserved, but the entire geometry is scaled to the world size of the shape.


 * Case „StretchX is set“


 * Here we need to take a deeper look at method <tt>GetParameter</tt>. The call from <tt>GetPointAsB2DPoint</tt> gives the parameters


 * <tt>rRetValue = fValX</tt>,
 * <tt>rParameter = {NORMAL,21600}</tt> or <tt>rParameter = {NORMAL,10800)</tt> respectively,
 * <tt>bRepalceGeoWidth=true</tt> and
 * <tt>bReplaceGeoHeight=false</tt>.


 * The switch case NORMAL is used and because the TypeClass of 21600 or 10800 is not DOUBLE it goes to the else branch therein. There we find, that in case the value is at the right edge the return value is multiplied with variable <tt>fXRatio</tt>.


 * The variable <tt>fXRatio</tt> is a member in class <tt>EnhancedCustomShape2d</tt>. It has been set in method <tt>EnhancedCustomShape2d::SetPathSize</tt>. There it is set to <tt>fXRatio=1.0</tt> for normal cases, but has a special handling in case <tt>nXRef!=0x8000000</tt>. That condition is the same as „StretchX is set“. In this special case it determines the ratio of width/height of the shape in world coordinates, in the example it sets <tt>fXRatio=12cm/3cm=4.0</tt>. But it uses that value only if <tt>fXRatio>1</tt> (as of Jun 2022, see bug ) and otherwise the normal value <tt>1.0</tt>. The condition means, that a shape with a square viewBox rectangle is horizontally stretched.


 * In that case it changes <tt>fXScale</tt> too; it becomes <tt>fXScale=12cm/21600 / 4.0 = 3cm/21600</tt>. So for a point on the right edge we have <tt>fXRatio=4.0</tt> and <tt>fXScale=3cm/21600</tt> and for all other points we have <tt>fXRatio=1.0</tt> and <tt>fXScale=12cm/21600</tt>.


 * Back to method <tt>GetParameter</tt> we get <tt>fRetValue=21600*4.0=86400.0</tt> for the point on the edge and <tt>fRetValue=10800.0</tt> for the center point.


 * And back to method <tt>GetPointAsB2DPoint</tt> we get <tt>fValX=86400*3cm/21600=12cm</tt> for the point on the edge and <tt>fValX=10800*3cm/21600=1.5cm</tt> for the center point.


 * Summary: In case „StretchX is set“, the world coordinates are so as if the shape is square with minimum of <tt>svg:Width</tt> and <tt>svg:Height</tt> as size. That is done by manipulating the scaling factor <tt>fXScale</tt>. Only for a point on the right edge we get the „original“ world coordinates, because the return value from <tt>GetParameter</tt> was changed to compensate the manipulated scaling factor.

For to keep the ratio of points, but move them to the right side of the shape (as described in the ODF specification cited above), their coordinates need to be defined relative to the right edge of the shape and not to the left edge as it is usually done. In formulas not the constant number 21600 but the identifier <tt>right</tt> has to be used.

The corresponding members in <tt>mso_CustomShapes</tt> struct are <tt>nXRef</tt> and <tt>nYRef</tt>. The same identifiers, with same meaning are used as members of class EnhancedCustomShape2d. There they are initialized with value <tt>0x80000000</tt> in the ctor. That is interpreted as “property is not set”. The <tt>mso_CustomShapes</tt> structs in the descriptions of AutoShapes use the constant <tt> MIN_INT32 = std::numeric_limits<sal_Int32>::min </tt> for the same purpose.

SubViewSize
If a shape is rendered, that was imported from OOXML, the <tt>SubViewSize</tt> property is evaluated. It is a sequence of items of type <tt>css.awt.Size</tt>. For each sub-path in the <tt>draw:enhanced-path</tt> attribute the item sets the width and height of the used <tt>viewBox</tt>. Values for left and top are <tt>0</tt> in that case.

It is a proprietary attribute of LibreOffice. Therefore it can only be used in proprietary namespace in “extended” ODF, here written as <tt>drawooo:sub-view-size</tt> attribute. An overview of extensions to ODF by LibreOffice is in List of LibreOffice_ODF_Extensions.

TextFrames
The corresponding attribute in ODF is <tt>draw:text-areas</tt> [ODF 19.220]. It determines the rectangle into which the text content of the shape is written. It has one or two sets of four parameters. If a second set is given, it is only used for vertical writing directions. The parameters in the set mean position of left, top, right and bottom edge of the area. The positions may not only use constant values but references to modifiers or to equationa as well. If a definition for a text area is omitted, the entire area of the shape is used.

OOXML has such rectangle as element <tt> </tt> [OOXML 20.1.9.22] with attributes <tt>l</tt>, <tt>t</tt>, <tt>r</tt> and <tt>b</tt>. The values of these attributes may be guide references. There exists only one element for all writing directions. The import and export filter in module <tt>oox</tt> should handle it correctly, only a second text-area rectangle will be lost on export.

VML has such rectangle as <tt>textboxrect</tt> attribute of the element <tt>path</tt>. If MS Office opens a RTF or DOC document and saves it in DOCX format in “Compatible” mode, then it uses VML for a shape. When older version of LibreOffice open such DOCX document, they generate a path object; and that has no text-area rectangle at all. Current LO 7.4 generates a custom shape on opening, but does not interpret the <tt>textboxrect</tt> attribute.

MS binary format and RTL have such text areas as attribute <tt>pInscribe</tt>. The import and export filter for MS binary format have it as property <tt>DFF_Prop_textRectangles</tt> and it works well. Export is in file escherex.cxx, import in file msdffimp.cxx.

The corresponding member in <tt>mso_CustomShapes</tt> struct, which is used for the description of AutoShapes, is <tt>pTextRect</tt>. That is a sequence of items of type <tt>SvxMSDffTextRectangles</tt>, which is a struct with components <tt>nPairA</tt> and <tt>nPairB</tt> of type <tt>SVxMSDffVertPair</tt>. <tt>nPairA</tt> has the top-left vertex and <tt>nPairB</tt> the bottom-right vertex. <tt>SvxMSDffVertPair</tt> is a struct with component <tt>nValA</tt> for the x-coordinate and <tt>nValB</tt> for the y-coordinate. Because of this nesting of structs it is written with nested brackets, for example const SvxMSDffTextRectangles mso_sptHexagonTextRect[] = {   { { 3 MSO_I, 3 MSO_I }, { 4 MSO_I, 4 MSO_I } } };

Same as with <tt>Coordinates</tt> property a reference to an equation is possible with the flag <tt>MSO_I</tt>, a reference to a modifier is not possible.

The method <tt>SdrObjCustomShape::MergeDefaultAttributes</tt> converts such value correctly to the <tt>TextFrames</tt> property.

TextPathAllowed
The corresponding attribute in ODF is <tt>draw:text-path-allowed</tt> [ODF 19.222]. LibreOffice does not evaluate this attribute. It has no UI to allow the user to switch the text-path of an custom shape on or off. That corresponds to the fact, that the default value for this attribute is <tt>false</tt>. But nevertheless the value of attribute <tt>TextPath</tt> can be toggled via macro.

ToDo: Other file formats?

Relevant Specifications

 * [MS]
 * [MS-ODRAW] Office Drawing Binary File Format
 * References in this article use the version 10.0 2022-05-17.
 * https://docs.microsoft.com/en-us/openspecs/office_file_formats/ms-odraw/8560795e-7759-4745-838f-f7f2ef2f1872 [last visited 2022-05-28]


 * [MS97]
 * Microsoft Office Drawing 97-2007 Binary Format Specification
 * Some information is easier to get from the old version, e.g. the geometry definition of the AutoShapes.
 * https://download.microsoft.com/download/0/B/E/0BE8BDD7-E5E8-422A-ABFD-4342ED7AD886/OfficeDrawing97-2007BinaryFormatSpecification.pdf [last visited 2022-06-07]


 * [RTF] Rich Text Format.
 * The specification is no longer directly available from Microsoft. The article “Rich Text Format” on en.wikipedia.org lists two download links. The first one is a pdf-file with images, so not search-able. The second one is a better suitable pdf-file. References on this page use the version RTF 1.9.1.
 * https://web.archive.org/web/20190708132914/http://www.kleinlercher.at/tools/Windows_Protocols/Word2007RTFSpec9.pdf [last visited 2022-05-27]


 * [VML] Vector Markup Language.
 * This file format is deprecated, but the markup is still used in docx-files in ‘compatibility mode’. VML is related to the MS binary format. The latest version of the specification is given in chapter 19 “VML Reference Material” in part 4 of the OOXML standard. Look for “ISO/IEC 29500-4:2016” on https://standards.iso.org/ittf/PubliclyAvailableStandards/index.html
 * The version as of 2011 is in the archive of Microsoft https://docs.microsoft.com/en-us/windows/win32/vml/msdn-online-vector-markup-language-object-model-reference.
 * The initial version can be found at https://www.w3.org/TR/NOTE-VML [last visited 2022-05-28]


 * [OOXML] Office Open XML
 * Part 1 is relevant here. Look for “ISO/IEC 29500-1:2016” on https://standards.iso.org/ittf/PubliclyAvailableStandards/index.html
 * The zip archive “Electronic inserts” belonging to Part 1 contains files <tt>presetShapeDefinitions.xml</tt> and <tt>presertTextWarpDefinitions.xml</tt>, which have the markup equivalents for the preset shapes.


 * [OI29500]
 * Microsoft publishes “Office Implementation Information for ISO/IEC 29500 Standards Support” which documents errors in the standard and deviations from the standard in MS Office.
 * https://docs.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/1fd4a662-8623-49c0-82f0-18fa91b413b8 [last visited 2022-06-01]


 * [ECMA]
 * Office Open XML File Formats – Part 1 ECMA-376 Part 1 3rd Edition / June 2011
 * This is a predecessor of the standard at ISO. It is the last edition, which has a list of parent and child elements. The current ISO version lists only attributes in the text. So it might be useful for searching element names.
 * https://www.ecma-international.org/wp-content/uploads/ecma-376_third_edition_june_2011.zip [last visited 2022-05-28].


 * [ODF] Open Document Format
 * Open Document Format for Office Applications (OpenDocument) Version 1.3. Part 3: OpenDocument Schema. OASIS Standard 27 April 2021
 * This is available in odt, html and pdf format.
 * https://docs.oasis-open.org/office/OpenDocument/v1.3/os/part3-schema/ [last visited 2022-05-28].