summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--editeng/source/items/frmitems.cxx9
-rw-r--r--include/editeng/editrids.hrc1
-rw-r--r--include/editeng/frmdir.hxx5
-rw-r--r--include/editeng/frmdiritem.hxx2
-rw-r--r--include/svx/svddef.hxx7
-rw-r--r--include/svx/unoshprp.hxx3
-rw-r--r--include/xmloff/xmltoken.hxx1
-rw-r--r--offapi/com/sun/star/text/WritingMode2.idl10
-rw-r--r--oox/inc/drawingml/customshapeproperties.hxx4
-rw-r--r--oox/inc/drawingml/textbodyproperties.hxx2
-rw-r--r--oox/source/drawingml/customshapeproperties.cxx8
-rw-r--r--oox/source/drawingml/shape.cxx9
-rw-r--r--oox/source/drawingml/textbodyproperties.cxx4
-rw-r--r--oox/source/drawingml/textbodypropertiescontext.cxx22
-rw-r--r--oox/source/export/drawingml.cxx89
-rw-r--r--oox/source/export/vmlexport.cxx12
-rw-r--r--oox/source/shape/WpsContext.cxx45
-rw-r--r--sc/qa/unit/subsequent_filters_test2.cxx22
-rw-r--r--schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng1
-rw-r--r--sd/qa/unit/data/xml/n902652_0.xml4
-rw-r--r--sd/qa/unit/export-tests.cxx63
-rw-r--r--sd/qa/unit/import-tests2.cxx26
-rw-r--r--svx/source/sdr/properties/customshapeproperties.cxx1
-rw-r--r--svx/source/svdraw/svdattr.cxx5
-rw-r--r--svx/source/svdraw/svdoashp.cxx31
-rw-r--r--svx/source/unodraw/unoshape.cxx10
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport13.cxx12
-rw-r--r--sw/qa/extras/ooxmlexport/ooxmlexport8.cxx4
-rw-r--r--sw/source/core/doc/textboxhelper.cxx11
-rw-r--r--sw/source/core/layout/wsfrm.cxx6
-rw-r--r--sw/source/filter/ww8/docxattributeoutput.cxx12
-rw-r--r--sw/source/filter/ww8/docxsdrexport.cxx5
-rw-r--r--sw/source/filter/xml/xmlexpit.cxx13
-rw-r--r--sw/source/filter/xml/xmlimpit.cxx7
-rw-r--r--writerfilter/source/dmapper/DomainMapper.cxx37
-rw-r--r--xmloff/inc/xmlsdtypes.hxx2
-rw-r--r--xmloff/source/core/xmltoken.cxx1
-rw-r--r--xmloff/source/draw/sdpropls.cxx37
-rw-r--r--xmloff/source/draw/shapeexport.cxx30
-rw-r--r--xmloff/source/style/prhdlfac.cxx3
-rw-r--r--xmloff/source/style/xmlexppr.cxx3
-rw-r--r--xmloff/source/token/tokens.txt1
42 files changed, 436 insertions, 144 deletions
diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx
index 35e1be7b094c..890d74a75510 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -3411,7 +3411,8 @@ TranslateId getFrmDirResId(size_t nIndex)
RID_SVXITEMS_FRMDIR_VERT_TOP_RIGHT,
RID_SVXITEMS_FRMDIR_VERT_TOP_LEFT,
RID_SVXITEMS_FRMDIR_ENVIRONMENT,
- RID_SVXITEMS_FRMDIR_VERT_BOT_LEFT
+ RID_SVXITEMS_FRMDIR_VERT_BOT_LEFT,
+ RID_SVXITEMS_FRMDIR_VERT_TOP_RIGHT90
};
return RID_SVXITEMS_FRMDIR[nIndex];
}
@@ -3451,6 +3452,9 @@ bool SvxFrameDirectionItem::PutValue( const css::uno::Any& rVal,
case text::WritingMode2::BT_LR:
SetValue( SvxFrameDirection::Vertical_LR_BT );
break;
+ case text::WritingMode2::TB_RL90:
+ SetValue(SvxFrameDirection::Vertical_RL_TB90);
+ break;
case text::WritingMode2::PAGE:
SetValue( SvxFrameDirection::Environment );
break;
@@ -3487,6 +3491,9 @@ bool SvxFrameDirectionItem::QueryValue( css::uno::Any& rVal,
case SvxFrameDirection::Vertical_LR_BT:
nVal = text::WritingMode2::BT_LR;
break;
+ case SvxFrameDirection::Vertical_RL_TB90:
+ nVal = text::WritingMode2::TB_RL90;
+ break;
case SvxFrameDirection::Environment:
nVal = text::WritingMode2::PAGE;
break;
diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc
index 31ac07a1d22b..850641d5ce9f 100644
--- a/include/editeng/editrids.hrc
+++ b/include/editeng/editrids.hrc
@@ -276,6 +276,7 @@
#define RID_SVXITEMS_FRMDIR_VERT_TOP_LEFT NC_("RID_SVXITEMS_FRMDIR_VERT_TOP_LEFT", "Text direction left-to-right (vertical)")
#define RID_SVXITEMS_FRMDIR_ENVIRONMENT NC_("RID_SVXITEMS_FRMDIR_ENVIRONMENT", "Use superordinate object text direction setting")
#define RID_SVXITEMS_FRMDIR_VERT_BOT_LEFT NC_("RID_SVXITEMS_FRMDIR_VERT_BOT_LEFT", "Text direction left-to-right (vertical from bottom)")
+#define RID_SVXITEMS_FRMDIR_VERT_TOP_RIGHT90 NC_("RID_SVXITEMS_FRMDIR_Vert_TOP_RIGHT90", "Text direction right-to-left (vertical all characters rotated)")
#define RID_SVXITEMS_PARASNAPTOGRID_ON NC_("RID_SVXITEMS_PARASNAPTOGRID_ON", "Paragraph snaps to text grid (if active)")
#define RID_SVXITEMS_PARASNAPTOGRID_OFF NC_("RID_SVXITEMS_PARASNAPTOGRID_OFF", "Paragraph does not snap to text grid")
#define RID_SVXITEMS_CHARHIDDEN_FALSE NC_("RID_SVXITEMS_CHARHIDDEN_FALSE", "Not hidden")
diff --git a/include/editeng/frmdir.hxx b/include/editeng/frmdir.hxx
index ef5275d26a7d..270ab62c626d 100644
--- a/include/editeng/frmdir.hxx
+++ b/include/editeng/frmdir.hxx
@@ -51,8 +51,11 @@ enum class SvxFrameDirection
/** Use the value from the environment, can only be used in frames. */
Environment = css::text::WritingMode2::CONTEXT,
- /** Vertical, from bottom to top, from left to right. */
+ /** Vertical, from bottom to top, from left to right (vert="vert270"). */
Vertical_LR_BT = css::text::WritingMode2::BT_LR,
+
+ /** Vertical, from top to bottom, from right to left (vert="vert"). */
+ Vertical_RL_TB90 = css::text::WritingMode2::TB_RL90,
};
TranslateId getFrmDirResId(size_t nIndex);
diff --git a/include/editeng/frmdiritem.hxx b/include/editeng/frmdiritem.hxx
index 2a439aa50ca7..7bb6dc09950d 100644
--- a/include/editeng/frmdiritem.hxx
+++ b/include/editeng/frmdiritem.hxx
@@ -52,7 +52,7 @@ public:
virtual sal_uInt16 GetValueCount() const override
{
- return sal_uInt16(SvxFrameDirection::Vertical_LR_BT) + 1;
+ return sal_uInt16(SvxFrameDirection::Vertical_RL_TB90) + 1;
}
// SfxPoolItem copy function dichotomy
diff --git a/include/svx/svddef.hxx b/include/svx/svddef.hxx
index 9332dc65a59f..059c461721b4 100644
--- a/include/svx/svddef.hxx
+++ b/include/svx/svddef.hxx
@@ -175,6 +175,7 @@ class SdrRotateAllItem;
class Svx3DTextureKindItem;
class Svx3DTextureModeItem;
class SvXMLAttrContainerItem;
+class SvxFrameDirectionItem;
constexpr sal_uInt16 SDRATTR_START (XATTR_START); /* 1000 */
/* Pool V4*/ /* Pool V3*/ /* Pool V2*/
@@ -432,7 +433,11 @@ constexpr TypedWhichId<SfxInt16Item> SDRATTR_TEXTCOLUMNS_NUMBER(SDRATTR_TEXTCOLU
constexpr TypedWhichId<SdrMetricItem> SDRATTR_TEXTCOLUMNS_SPACING(SDRATTR_TEXTCOLUMNS_FIRST + 1);
constexpr sal_uInt16 SDRATTR_TEXTCOLUMNS_LAST(SDRATTR_TEXTCOLUMNS_SPACING);
-constexpr sal_uInt16 SDRATTR_END (SDRATTR_TEXTCOLUMNS_LAST); /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/ /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
+constexpr sal_uInt16 SDRATTR_WRITINGMODE2_FIRST(SDRATTR_TEXTCOLUMNS_LAST + 1);
+constexpr TypedWhichId<SvxFrameDirectionItem> SDRATTR_WRITINGMODE2(SDRATTR_WRITINGMODE2_FIRST + 0);
+constexpr sal_uInt16 SDRATTR_WRITINGMODE2_LAST(SDRATTR_WRITINGMODE2);
+
+constexpr sal_uInt16 SDRATTR_END (SDRATTR_WRITINGMODE2_LAST); /* 1357 */ /* 1333 V4+++*/ /* 1243 V4+++*/ /*1213*/ /*1085*/ /*1040*/ /*Pool V2: 1123,V1: 1065 */
#endif // INCLUDED_SVX_SVDDEF_HXX
diff --git a/include/svx/unoshprp.hxx b/include/svx/unoshprp.hxx
index b32b8672c77c..010cbbcd4b36 100644
--- a/include/svx/unoshprp.hxx
+++ b/include/svx/unoshprp.hxx
@@ -365,7 +365,8 @@
/* #i68101# */ \
{ UNO_NAME_MISC_OBJ_TITLE, OWN_ATTR_MISC_OBJ_TITLE , ::cppu::UnoType<OUString>::get(), 0, 0}, \
{ UNO_NAME_MISC_OBJ_DESCRIPTION, OWN_ATTR_MISC_OBJ_DESCRIPTION , ::cppu::UnoType<OUString>::get(), 0, 0}, \
- { UNO_NAME_HYPERLINK, OWN_ATTR_HYPERLINK, ::cppu::UnoType<OUString>::get(), 0, 0},
+ { UNO_NAME_HYPERLINK, OWN_ATTR_HYPERLINK, ::cppu::UnoType<OUString>::get(), 0, 0}, \
+ { u"WritingMode", SDRATTR_WRITINGMODE2, ::cppu::UnoType<sal_Int16>::get(), 0, 0},
#define LINKTARGET_PROPERTIES \
{ UNO_NAME_LINKDISPLAYNAME, OWN_ATTR_LDNAME , ::cppu::UnoType<OUString>::get(), css::beans::PropertyAttribute::READONLY, 0}, \
diff --git a/include/xmloff/xmltoken.hxx b/include/xmloff/xmltoken.hxx
index da0e0b83c879..93f00d81db2a 100644
--- a/include/xmloff/xmltoken.hxx
+++ b/include/xmloff/xmltoken.hxx
@@ -2284,6 +2284,7 @@ namespace xmloff::token {
XML_LR,
XML_RL,
XML_TB,
+ XML_TB_RL90,
XML_LAYOUT_GRID_COLOR,
XML_LAYOUT_GRID_LINES,
diff --git a/offapi/com/sun/star/text/WritingMode2.idl b/offapi/com/sun/star/text/WritingMode2.idl
index 3d5d1badc6f2..f75108337a69 100644
--- a/offapi/com/sun/star/text/WritingMode2.idl
+++ b/offapi/com/sun/star/text/WritingMode2.idl
@@ -81,6 +81,16 @@ published constants WritingMode2
@since LibreOffice 6.3
*/
const short BT_LR = 5;
+
+ /** text within a line is written top-to-bottom so as if a horizontal
+ left-to-right line is clockwise rotated by 90deg. Lines and blocks
+ are placed right-to-left. This corresponds to OOXML attribute
+ vert="vert" for shapes and ECMA w:val="tbRl" attribute in
+ <w:textDirection> element.
+
+ @since LibreOffice 7.5
+ */
+ const short TB_RL90 = 6;
};
diff --git a/oox/inc/drawingml/customshapeproperties.hxx b/oox/inc/drawingml/customshapeproperties.hxx
index 2a6baad662ad..c009a0fb7db0 100644
--- a/oox/inc/drawingml/customshapeproperties.hxx
+++ b/oox/inc/drawingml/customshapeproperties.hxx
@@ -115,7 +115,7 @@ public:
std::vector< css::drawing::EnhancedCustomShapeSegment >& getSegments(){ return maSegments; };
void setMirroredX( bool bMirroredX ) { mbMirroredX = bMirroredX; };
void setMirroredY( bool bMirroredY ) { mbMirroredY = bMirroredY; };
- void setTextRotateAngle( sal_Int32 nAngle ) { mnTextRotateAngle = nAngle; };
+ void setTextPreRotateAngle( sal_Int32 nAngle ) { mnTextPreRotateAngle = nAngle; };
void setTextCameraZRotateAngle( sal_Int32 nAngle ) { mnTextCameraZRotateAngle = nAngle; };
void setTextAreaRotateAngle(sal_Int32 nAngle) { moTextAreaRotateAngle = nAngle; };
@@ -145,7 +145,7 @@ private:
maSegments;
bool mbMirroredX;
bool mbMirroredY;
- sal_Int32 mnTextRotateAngle; // TextPreRotateAngle
+ sal_Int32 mnTextPreRotateAngle; // TextPreRotateAngle
sal_Int32 mnTextCameraZRotateAngle;
std::optional< sal_Int32 > moTextAreaRotateAngle; // TextRotateAngle
diff --git a/oox/inc/drawingml/textbodyproperties.hxx b/oox/inc/drawingml/textbodyproperties.hxx
index bc1d9508daea..1daa5d592a30 100644
--- a/oox/inc/drawingml/textbodyproperties.hxx
+++ b/oox/inc/drawingml/textbodyproperties.hxx
@@ -34,7 +34,7 @@ namespace oox::drawingml {
struct TextBodyProperties
{
PropertyMap maPropertyMap;
- // TextPreRotateAngle. Used for simulating writing modes.
+ // TextPreRotateAngle. Used in diagram (SmartArt) import.
std::optional< sal_Int32 > moTextPreRotation;
// TextRotateAngle. ODF draw:text-rotate-angle, OOXML 'rot' attribute in <bodyPr> element
std::optional< sal_Int32 > moTextAreaRotation;
diff --git a/oox/source/drawingml/customshapeproperties.cxx b/oox/source/drawingml/customshapeproperties.cxx
index 2c3204405c2b..ef164194e7f0 100644
--- a/oox/source/drawingml/customshapeproperties.cxx
+++ b/oox/source/drawingml/customshapeproperties.cxx
@@ -48,7 +48,7 @@ CustomShapeProperties::CustomShapeProperties()
, mbShapeTypeOverride(false)
, mbMirroredX ( false )
, mbMirroredY ( false )
-, mnTextRotateAngle ( 0 )
+, mnTextPreRotateAngle ( 0 )
, mnTextCameraZRotateAngle ( 0 )
, mnArcNum ( 0 )
{
@@ -125,7 +125,7 @@ void CustomShapeProperties::pushToPropSet(
aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
- aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
+ aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextPreRotateAngle );
aPropertyMap.setProperty( PROP_TextCameraZRotateAngle, mnTextCameraZRotateAngle );
if (moTextAreaRotateAngle.has_value())
aPropertyMap.setProperty(PROP_TextRotateAngle, moTextAreaRotateAngle.value());
@@ -189,8 +189,8 @@ void CustomShapeProperties::pushToPropSet(
aPropertyMap.setProperty( PROP_Type, OUString( "ooxml-non-primitive" ));
aPropertyMap.setProperty( PROP_MirroredX, mbMirroredX );
aPropertyMap.setProperty( PROP_MirroredY, mbMirroredY );
- if( mnTextRotateAngle )
- aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextRotateAngle );
+ if( mnTextPreRotateAngle )
+ aPropertyMap.setProperty( PROP_TextPreRotateAngle, mnTextPreRotateAngle );
if (moTextAreaRotateAngle.has_value())
aPropertyMap.setProperty(PROP_TextRotateAngle, moTextAreaRotateAngle.value());
// Note 1: If Equations are defined - they are processed using internal div by 360 coordinates
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index be9e8df456b2..cfe1ea29dc95 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -1447,7 +1447,8 @@ Reference< XShape > const & Shape::createAndInsert(
}
else if (mbTextBox)
{
- // ToDo: TextBox has no rotated text, so introduce it only if really needed. tdf#82627
+ // This introduces a TextBox in a shape in Writer. ToDo: Can we restrict it to cases
+ // where the TextBox edit engine is really needed? tdf#82627
aShapeProps.setProperty(PROP_TextBox, true);
}
@@ -1714,10 +1715,10 @@ Reference< XShape > const & Shape::createAndInsert(
sal_Int32 nTextCameraZRotation = getTextBody()->get3DProperties().maCameraRotation.mnRevolution.value_or(0);
mpCustomShapePropertiesPtr->setTextCameraZRotateAngle( nTextCameraZRotation / 60000 );
- // TextPreRotateAngle. Text rotates inside the text area.
+ // TextPreRotateAngle. Text rotates inside the text area. Might be used for diagram layout 'upr' and 'grav'.
sal_Int32 nTextPreRotateAngle = static_cast< sal_Int32 >( getTextBody()->getTextProperties().moTextPreRotation.value_or( 0 ) );
- nTextPreRotateAngle -= mnDiagramRotation;
+ nTextPreRotateAngle -= mnDiagramRotation; // Use of mnDiagramRotation is unclear. It seems to be always 0 here.
// TextRotateAngle. The text area rotates.
sal_Int32 nTextAreaRotateAngle = getTextBody()->getTextProperties().moTextAreaRotation.value_or(0);
@@ -1740,7 +1741,7 @@ Reference< XShape > const & Shape::createAndInsert(
}
/* OOX measures text rotation clockwise in 1/60000th degrees,
relative to the containing shape. set*Angle wants degrees counter-clockwise. */
- mpCustomShapePropertiesPtr->setTextRotateAngle(-nTextPreRotateAngle / 60000);
+ mpCustomShapePropertiesPtr->setTextPreRotateAngle(-nTextPreRotateAngle / 60000);
if (nTextAreaRotateAngle != 0)
mpCustomShapePropertiesPtr->setTextAreaRotateAngle(-nTextAreaRotateAngle / 60000);
diff --git a/oox/source/drawingml/textbodyproperties.cxx b/oox/source/drawingml/textbodyproperties.cxx
index 5cea05256462..ff501e40c413 100644
--- a/oox/source/drawingml/textbodyproperties.cxx
+++ b/oox/source/drawingml/textbodyproperties.cxx
@@ -87,8 +87,10 @@ void TextBodyProperties::pushTextDistances(Size const& rTextAreaSize)
default: break;
}
- if (moVert && moVert.value() == XML_eaVert)
+ if (moVert && (moVert.value() == XML_eaVert || moVert.value() == XML_vert))
nOff = (nOff + 3) % aProps.size();
+ else if (moVert && moVert.value() == XML_vert270)
+ nOff = (nOff + 1) % aProps.size();
for (size_t i = 0; i < aProps.size(); i++)
{
diff --git a/oox/source/drawingml/textbodypropertiescontext.cxx b/oox/source/drawingml/textbodypropertiescontext.cxx
index 8b1c6db6a791..9d221a18ffbe 100644
--- a/oox/source/drawingml/textbodypropertiescontext.cxx
+++ b/oox/source/drawingml/textbodypropertiescontext.cxx
@@ -20,9 +20,11 @@
#include <drawingml/textbodypropertiescontext.hxx>
#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/drawing/TextFitToSizeType.hpp>
#include <com/sun/star/drawing/TextHorizontalAdjust.hpp>
#include <com/sun/star/text/XTextColumns.hpp>
+
#include <drawingml/textbodyproperties.hxx>
#include <drawingml/textbody.hxx>
#include <drawingml/customshapegeometry.hxx>
@@ -119,15 +121,29 @@ TextBodyPropertiesContext::TextBodyPropertiesContext( ContextHandler2Helper cons
mrTextBodyProp.moVert = rAttribs.getToken( XML_vert );
sal_Int32 tVert = mrTextBodyProp.moVert.value_or( XML_horz );
if (tVert == XML_eaVert)
+ {
mrTextBodyProp.maPropertyMap.setProperty(PROP_TextWritingMode, WritingMode_TB_RL);
- else if (tVert == XML_vert || tVert == XML_mongolianVert)
- mrTextBodyProp.moTextPreRotation = 5400000;
+ mrTextBodyProp.maPropertyMap.setProperty(PROP_WritingMode, text::WritingMode2::TB_RL);
+ }
+ else if (tVert == XML_vert)
+ {
+ mrTextBodyProp.maPropertyMap.setProperty(PROP_WritingMode, text::WritingMode2::TB_RL90);
+ }
+ else if (tVert == XML_mongolianVert)
+ {
+ // rendering not yet implemented for shape text, only for frames
+ mrTextBodyProp.maPropertyMap.setProperty(PROP_WritingMode, text::WritingMode2::TB_LR);
+ }
else if (tVert == XML_vert270)
- mrTextBodyProp.moTextPreRotation = 5400000 * 3;
+ {
+ mrTextBodyProp.maPropertyMap.setProperty(PROP_WritingMode, text::WritingMode2::BT_LR);
+ }
else {
bool bRtl = rAttribs.getBool( XML_rtl, false );
mrTextBodyProp.maPropertyMap.setProperty( PROP_TextWritingMode,
( bRtl ? WritingMode_RL_TB : WritingMode_LR_TB ));
+ mrTextBodyProp.maPropertyMap.setProperty(PROP_WritingMode,
+ ( bRtl ? text::WritingMode2::RL_TB : text::WritingMode2::LR_TB));
}
}
diff --git a/oox/source/export/drawingml.cxx b/oox/source/export/drawingml.cxx
index 51ac5f660237..42aa3eb04700 100644
--- a/oox/source/export/drawingml.cxx
+++ b/oox/source/export/drawingml.cxx
@@ -3335,6 +3335,33 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
bVertical = true;
}
}
+ if (GetProperty(rXPropSet, "WritingMode"))
+ {
+ sal_Int16 nWritingMode;
+ if (mAny >>= nWritingMode)
+ {
+ if (nWritingMode == text::WritingMode2::TB_RL)
+ {
+ sWritingMode = "eaVert";
+ bVertical = true;
+ }
+ else if (nWritingMode == text::WritingMode2::BT_LR)
+ {
+ sWritingMode = "vert270";
+ bVertical = true;
+ }
+ else if (nWritingMode == text::WritingMode2::TB_RL90)
+ {
+ sWritingMode = "vert";
+ bVertical = true;
+ }
+ else if (nWritingMode == text::WritingMode2::TB_LR)
+ {
+ sWritingMode = "mongolianVert";
+ bVertical = true;
+ }
+ }
+ }
// read values from CustomShapeGeometry
Sequence<drawing::EnhancedCustomShapeAdjustmentValue> aAdjustmentSeq;
@@ -3395,13 +3422,21 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
switch (nWritingMode)
{
case WritingMode2::TB_RL:
- sWritingMode = "vert";
+ sWritingMode = "eaVert";
bVertical = true;
break;
case WritingMode2::BT_LR:
sWritingMode = "vert270";
bVertical = true;
break;
+ case WritingMode2::TB_RL90:
+ sWritingMode = "vert";
+ bVertical = true;
+ break;
+ case WritingMode2::TB_LR:
+ sWritingMode = "mongolianVert";
+ bVertical = true;
+ break;
default:
break;
}
@@ -3489,30 +3524,19 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
}
}
- // Evaluate "TextPreRotateAngle". It is used to simulate not yet implemented writing modes.
+ // ToDo: Unsure about this. Need to investigate shapes from diagram import, especially digrams
+ // with vertical text directions.
if (nTextPreRotateAngle != 0 && !sWritingMode)
{
if (nTextPreRotateAngle == -90 || nTextPreRotateAngle == 270)
{
sWritingMode = "vert";
bVertical = true;
- // Our TextPreRotation includes padding, MSO vert does not include padding. Therefore set
- // padding so, that is looks the same in MSO as in LO.
- sal_Int32 nHelp = nLeft;
- nLeft = nBottom;
- nBottom = nRight;
- nRight = nTop;
- nTop = nHelp;
}
else if (nTextPreRotateAngle == -270 || nTextPreRotateAngle == 90)
{
sWritingMode = "vert270";
bVertical = true;
- sal_Int32 nHelp = nLeft;
- nLeft = nTop;
- nTop = nRight;
- nRight = nBottom;
- nBottom = nHelp;
}
else if (nTextPreRotateAngle == -180 || nTextPreRotateAngle == 180)
{
@@ -3525,19 +3549,11 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12
#pragma GCC diagnostic pop
#endif
- // ToDo: Examine insets. They might need rotation too.
+ // ToDo: Examine insets. They might need rotation too. Check diagrams (SmartArt).
}
else
SAL_WARN("oox", "unsuitable value for TextPreRotateAngle:" << nTextPreRotateAngle);
}
- else if (nTextPreRotateAngle == 0 && sWritingMode && sWritingMode.value() == "eaVert")
- {
- sal_Int32 nHelp = nLeft;
- nLeft = nBottom;
- nBottom = nRight;
- nRight = nTop;
- nTop = nHelp;
- }
else if (nTextPreRotateAngle != 0 && sWritingMode && sWritingMode.value() == "eaVert")
{
// ToDo: eaVert plus 270deg clockwise rotation has to be written with vert="horz"
@@ -3545,6 +3561,33 @@ void DrawingML::WriteText(const Reference<XInterface>& rXIface, bool bBodyPr, bo
}
// else nothing to do
+ // Our WritingMode introduces text pre rotation which includes padding, MSO vert does not include
+ // padding. Therefore set padding so, that is looks the same in MSO as in LO.
+ if (sWritingMode)
+ {
+ if (sWritingMode.value() == "vert" || sWritingMode.value() == "eaVert")
+ {
+ sal_Int32 nHelp = nLeft;
+ nLeft = nBottom;
+ nBottom = nRight;
+ nRight = nTop;
+ nTop = nHelp;
+ }
+ else if (sWritingMode.value() == "vert270")
+ {
+ sal_Int32 nHelp = nLeft;
+ nLeft = nTop;
+ nTop = nRight;
+ nRight = nBottom;
+ nBottom = nHelp;
+ }
+ else if (sWritingMode.value() == "mongolianVert")
+ {
+ // ToDo: Examine padding
+ }
+ }
+
+
std::optional<OString> sTextRotateAngleMSUnit;
if (nTextRotateAngleDeg100.has_value())
#if defined __GNUC__ && !defined __clang__ && __GNUC__ == 12
diff --git a/oox/source/export/vmlexport.cxx b/oox/source/export/vmlexport.cxx
index 5d6f244bb42f..bda301201ad2 100644
--- a/oox/source/export/vmlexport.cxx
+++ b/oox/source/export/vmlexport.cxx
@@ -1440,14 +1440,10 @@ void VMLExport::EndShape( sal_Int32 nShapeElement )
if (xPropertySetInfo->hasPropertyByName("CustomShapeGeometry"))
{
// In this case a DrawingML DOCX was imported.
- comphelper::SequenceAsHashMap aCustomShapeProperties(
- xPropertySet->getPropertyValue("CustomShapeGeometry"));
- if (aCustomShapeProperties.find("TextPreRotateAngle") != aCustomShapeProperties.end())
- {
- sal_Int32 nTextRotateAngle = aCustomShapeProperties["TextPreRotateAngle"].get<sal_Int32>();
- if (nTextRotateAngle == -270)
- bBottomToTop = true;
- }
+ auto aAny = xPropertySet->getPropertyValue("WritingMode");
+ sal_Int16 nWritingMode;
+ if ((aAny >>= nWritingMode) && nWritingMode == text::WritingMode2::BT_LR)
+ bBottomToTop = true;
}
else
{
diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx
index 79fcf1c9dc81..5b0e75617215 100644
--- a/oox/source/shape/WpsContext.cxx
+++ b/oox/source/shape/WpsContext.cxx
@@ -21,6 +21,7 @@
#include <com/sun/star/text/XText.hpp>
#include <com/sun/star/text/XTextCursor.hpp>
#include <com/sun/star/text/WritingMode.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <svx/svdtrans.hxx>
#include <oox/helper/attributelist.hxx>
#include <oox/token/namespaces.hxx>
@@ -69,20 +70,27 @@ oox::core::ContextHandlerRef WpsContext::onCreateContext(sal_Int32 nElementToken
uno::Reference<lang::XServiceInfo> xServiceInfo(mxShape, uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xPropertySet(mxShape, uno::UNO_QUERY);
sal_Int32 nVert = rAttribs.getToken(XML_vert, XML_horz);
- if (nVert == XML_eaVert)
+ // Values 'wordArtVert' and 'wordArtVertRtl' are not implemented.
+ // Map them to other vert values.
+ if (nVert == XML_eaVert || nVert == XML_wordArtVertRtl)
{
xPropertySet->setPropertyValue("TextWritingMode",
uno::Any(text::WritingMode_TB_RL));
+ xPropertySet->setPropertyValue("WritingMode",
+ uno::Any(text::WritingMode2::TB_RL));
}
- else if (nVert != XML_horz)
+ else if (nVert == XML_mongolianVert || nVert == XML_wordArtVert)
{
- // The UI of Word has only 'vert' and 'vert270'. Further values would be
- // 'mongolianVert', 'wordArtVert' and 'wordArtVertRtl'.
- const sal_Int32 nRotation = nVert == XML_vert270 ? -270 : -90;
+ xPropertySet->setPropertyValue("WritingMode",
+ uno::Any(text::WritingMode2::TB_LR));
+ }
+ else if (nVert != XML_horz) // cases XML_vert and XML_vert270
+ {
+ // Hack to get same rendering as after the fix for tdf#87924. If shape rotation
+ // plus text direction results in upright text, use horizontal text direction.
+ // Remove hack when frame is able to rotate.
- // Workaround for tdf#87924, produces bug tdf#149809 as of 2022-07
- // If the text is not rotated the way the shape wants it already, set the angle.
- // Get the existing rotation of the shape.
+ // Need transformation matrix since RotateAngle does not contain flip.
drawing::HomogenMatrix3 aMatrix;
xPropertySet->getPropertyValue("Transformation") >>= aMatrix;
basegfx::B2DHomMatrix aTransformation;
@@ -100,17 +108,20 @@ oox::core::ContextHandlerRef WpsContext::onCreateContext(sal_Int32 nElementToken
double fRotate = 0;
double fShearX = 0;
aTransformation.decompose(aScale, aTranslate, fRotate, fShearX);
-
- if (static_cast<sal_Int32>(basegfx::rad2deg(fRotate))
- != NormAngle36000(Degree100(nRotation * 100)).get() / 100)
+ auto nRotate(static_cast<sal_uInt16>(NormAngle360(basegfx::rad2deg(fRotate))));
+ if ((nVert == XML_vert && nRotate == 270)
+ || (nVert == XML_vert270 && nRotate == 90))
{
- comphelper::SequenceAsHashMap aCustomShapeGeometry(
- xPropertySet->getPropertyValue("CustomShapeGeometry"));
- aCustomShapeGeometry["TextPreRotateAngle"] <<= nRotation;
- xPropertySet->setPropertyValue(
- "CustomShapeGeometry",
- uno::Any(aCustomShapeGeometry.getAsConstPropertyValueList()));
+ xPropertySet->setPropertyValue("WritingMode",
+ uno::Any(text::WritingMode2::LR_TB));
+ // ToDo: Rembember original vert value and remove hack on export.
}
+ else if (nVert == XML_vert)
+ xPropertySet->setPropertyValue("WritingMode",
+ uno::Any(text::WritingMode2::TB_RL90));
+ else // nVert == XML_vert270
+ xPropertySet->setPropertyValue("WritingMode",
+ uno::Any(text::WritingMode2::BT_LR));
}
if (bool bUpright = rAttribs.getBool(XML_upright, false))
diff --git a/sc/qa/unit/subsequent_filters_test2.cxx b/sc/qa/unit/subsequent_filters_test2.cxx
index 1dd93e55ad95..37f177d48297 100644
--- a/sc/qa/unit/subsequent_filters_test2.cxx
+++ b/sc/qa/unit/subsequent_filters_test2.cxx
@@ -54,6 +54,7 @@
#include <com/sun/star/drawing/XControlShape.hpp>
#include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
#include <com/sun/star/container/XIndexAccess.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <comphelper/scopeguard.hxx>
#include <tools/UnitConversion.hxx>
@@ -2582,7 +2583,8 @@ void ScFiltersTest2::testTextBoxBodyUpright()
}
CPPUNIT_ASSERT_EQUAL(true, isUpright);
- // Check the new textRotateAngle.
+ // Check the TextPreRotateAngle has the compensation for the additional 90deg area rotation,
+ // which is added in Shape::createAndInsert to get the same rendering as in MS Office.
sal_Int32 nAngle;
uno::Any aGeom = xShapeProperties->getPropertyValue("CustomShapeGeometry");
auto aGeomSeq = aGeom.get<Sequence<beans::PropertyValue>>();
@@ -2607,19 +2609,11 @@ void ScFiltersTest2::testTextBoxBodyRotateAngle()
uno::Reference<drawing::XShape> xShape(xPage->getByIndex(0), uno::UNO_QUERY_THROW);
uno::Reference<beans::XPropertySet> xShapeProperties(xShape, uno::UNO_QUERY_THROW);
- // Check the new textRotateAngle.
- sal_Int32 nAngle;
- uno::Any aGeom = xShapeProperties->getPropertyValue("CustomShapeGeometry");
- auto aGeomSeq = aGeom.get<Sequence<beans::PropertyValue>>();
- for (const auto& aProp : std::as_const(aGeomSeq))
- {
- if (aProp.Name == "TextPreRotateAngle")
- {
- aProp.Value >>= nAngle;
- break;
- }
- }
- CPPUNIT_ASSERT_EQUAL(sal_Int32(-270), nAngle);
+ // Check the text direction.
+ sal_Int16 eWritingMode = text::WritingMode2::LR_TB;
+ if (xShapeProperties->getPropertySetInfo()->hasPropertyByName("WritingMode"))
+ xShapeProperties->getPropertyValue("WritingMode") >>= eWritingMode;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(text::WritingMode2::BT_LR), eWritingMode);
}
void ScFiltersTest2::testTextLengthDataValidityXLSX()
diff --git a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
index 5109a13687d6..cd0c8fb04244 100644
--- a/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
+++ b/schema/libreoffice/OpenDocument-v1.3+libreoffice-schema.rng
@@ -2719,6 +2719,7 @@ xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.
<rng:attribute name="loext:writing-mode">
<rng:choice>
<rng:value>bt-lr</rng:value>
+ <rng:value>tb-rl90</rng:value>
</rng:choice>
</rng:attribute>
</rng:optional>
diff --git a/sd/qa/unit/data/xml/n902652_0.xml b/sd/qa/unit/data/xml/n902652_0.xml
index b5fd7740ef47..34a18af57fba 100644
--- a/sd/qa/unit/data/xml/n902652_0.xml
+++ b/sd/qa/unit/data/xml/n902652_0.xml
@@ -197,7 +197,7 @@
</Path>
</PropertyValue>
<PropertyValue name="TextCameraZRotateAngle" value="0" handle="0" propertyState="DIRECT_VALUE"/>
- <PropertyValue name="TextPreRotateAngle" value="-90" handle="0" propertyState="DIRECT_VALUE"/>
+ <PropertyValue name="TextPreRotateAngle" value="0" handle="0" propertyState="DIRECT_VALUE"/>
<PropertyValue name="Type" value="ooxml-roundRect" handle="0" propertyState="DIRECT_VALUE"/>
<PropertyValue name="ViewBox">
<ViewBox x="0" y="0" width="0" height="0"/>
@@ -299,7 +299,7 @@
</Path>
</PropertyValue>
<PropertyValue name="TextCameraZRotateAngle" value="0" handle="0" propertyState="DIRECT_VALUE"/>
- <PropertyValue name="TextPreRotateAngle" value="-270" handle="0" propertyState="DIRECT_VALUE"/>
+ <PropertyValue name="TextPreRotateAngle" value="0" handle="0" propertyState="DIRECT_VALUE"/>
<PropertyValue name="Type" value="ooxml-roundRect" handle="0" propertyState="DIRECT_VALUE"/>
<PropertyValue name="ViewBox">
<ViewBox x="0" y="0" width="0" height="0"/>
diff --git a/sd/qa/unit/export-tests.cxx b/sd/qa/unit/export-tests.cxx
index 2e1a3ad5ec30..97167d219ff3 100644
--- a/sd/qa/unit/export-tests.cxx
+++ b/sd/qa/unit/export-tests.cxx
@@ -1096,24 +1096,63 @@ void SdExportTest::testPageWithTransparentBackground()
void SdExportTest::testTextRotation()
{
- ::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/shape-text-rotate.pptx"), PPTX);
- utl::TempFile tempFile;
- xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile);
+ // Save behavior depends on whether ODF strict or extended is used.
+ Resetter _([]() {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch);
+ return pBatch->commit();
+ });
+
+ // The contained shape has a text rotation vert="vert" which corresponds to
+ // loext:writing-mode="tb-rl90" in the graphic-properties of the style of the shape in ODF 1.3
+ // extended.
+ // Save to ODF 1.3 extended. Adapt 3 (=ODFVER_LATEST) to a to be ODFVER_013_EXTENDED when
+ // attribute value "tb-rl90" is included in ODF strict.
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(3, pBatch);
+ pBatch->commit();
- uno::Reference<drawing::XDrawPage> xPage(getPage(0, xDocShRef));
- uno::Reference<beans::XPropertySet> xPropSet(getShape(0, xPage));
+ ::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/shape-text-rotate.pptx"), PPTX);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile);
+
+ uno::Reference<drawing::XDrawPage> xPage(getPage(0, xDocShRef));
+ uno::Reference<beans::XPropertySet> xPropSet(getShape(0, xPage));
+ CPPUNIT_ASSERT(xPropSet.is());
+
+ auto aWritingMode = xPropSet->getPropertyValue("WritingMode").get<sal_Int16>();
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(text::WritingMode2::TB_RL90), aWritingMode);
+
+ xDocShRef->DoClose();
+ }
+ // In ODF 1.3 strict the workaround to use the TextRotateAngle is used instead.
+ {
+ std::shared_ptr<comphelper::ConfigurationChanges> pBatch(
+ comphelper::ConfigurationChanges::create());
+ officecfg::Office::Common::Save::ODF::DefaultVersion::set(10, pBatch);
+ pBatch->commit();
+
+ ::sd::DrawDocShellRef xDocShRef = loadURL(m_directories.getURLFromSrc(u"sd/qa/unit/data/pptx/shape-text-rotate.pptx"), PPTX);
+ utl::TempFile tempFile;
+ xDocShRef = saveAndReload(xDocShRef.get(), ODP, &tempFile);
- CPPUNIT_ASSERT(xPropSet.is());
+ uno::Reference<drawing::XDrawPage> xPage(getPage(0, xDocShRef));
+ uno::Reference<beans::XPropertySet> xPropSet(getShape(0, xPage));
- auto aGeomPropSeq = xPropSet->getPropertyValue("CustomShapeGeometry").get<uno::Sequence<beans::PropertyValue>>();
- comphelper::SequenceAsHashMap aCustomShapeGeometry(aGeomPropSeq);
+ CPPUNIT_ASSERT(xPropSet.is());
+ auto aGeomPropSeq = xPropSet->getPropertyValue("CustomShapeGeometry").get<uno::Sequence<beans::PropertyValue>>();
+ comphelper::SequenceAsHashMap aCustomShapeGeometry(aGeomPropSeq);
- auto it = aCustomShapeGeometry.find("TextRotateAngle");
- CPPUNIT_ASSERT(it != aCustomShapeGeometry.end());
+ auto it = aCustomShapeGeometry.find("TextRotateAngle");
+ CPPUNIT_ASSERT(it != aCustomShapeGeometry.end());
- CPPUNIT_ASSERT_EQUAL(double(-90), aCustomShapeGeometry["TextRotateAngle"].get<double>());
+ CPPUNIT_ASSERT_EQUAL(double(-90), aCustomShapeGeometry["TextRotateAngle"].get<double>());
- xDocShRef->DoClose();
+ xDocShRef->DoClose();
+ }
}
void SdExportTest::testTdf115394PPT()
diff --git a/sd/qa/unit/import-tests2.cxx b/sd/qa/unit/import-tests2.cxx
index 23e92530b479..17c793d08ab8 100644
--- a/sd/qa/unit/import-tests2.cxx
+++ b/sd/qa/unit/import-tests2.cxx
@@ -50,6 +50,7 @@
#include <com/sun/star/style/LineSpacingMode.hpp>
#include <com/sun/star/frame/Desktop.hpp>
#include <com/sun/star/text/GraphicCrop.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/text/XTextColumns.hpp>
#include <com/sun/star/xml/dom/XDocument.hpp>
@@ -1843,21 +1844,18 @@ void SdImportTest2::testTdf128684()
CPPUNIT_ASSERT(xDoc.is());
uno::Reference<drawing::XDrawPage> xPage(xDoc->getDrawPages()->getByIndex(0), uno::UNO_QUERY);
CPPUNIT_ASSERT(xPage.is());
- uno::Reference<beans::XPropertySet> xShape(getShape(0, xPage));
- CPPUNIT_ASSERT(xShape.is());
- uno::Any aAny = xShape->getPropertyValue("CustomShapeGeometry");
- CPPUNIT_ASSERT(aAny.hasValue());
- uno::Sequence<beans::PropertyValue> aProps;
- CPPUNIT_ASSERT(aAny >>= aProps);
+ uno::Reference<beans::XPropertySet> xShapeProperties(getShape(0, xPage));
+ CPPUNIT_ASSERT(xShapeProperties.is());
+ // Check text direction.
+ sal_Int16 eWritingMode(text::WritingMode2::LR_TB);
+ if (xShapeProperties->getPropertySetInfo()->hasPropertyByName("WritingMode"))
+ xShapeProperties->getPropertyValue("WritingMode") >>= eWritingMode;
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(text::WritingMode2::TB_RL90), eWritingMode);
+ // Check shape rotation
sal_Int32 nRotateAngle = 0;
- for (const auto& rProp : std::as_const(aProps))
- {
- if (rProp.Name == "TextPreRotateAngle")
- {
- rProp.Value >>= nRotateAngle;
- }
- }
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-90), nRotateAngle);
+ if (xShapeProperties->getPropertySetInfo()->hasPropertyByName("RotateAngle"))
+ xShapeProperties->getPropertyValue("RotateAngle") >>= nRotateAngle;
+ CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(9000), nRotateAngle);
}
void SdImportTest2::testTdf113198()
diff --git a/svx/source/sdr/properties/customshapeproperties.cxx b/svx/source/sdr/properties/customshapeproperties.cxx
index 59135cde1d55..cf79f77830c3 100644
--- a/svx/source/sdr/properties/customshapeproperties.cxx
+++ b/svx/source/sdr/properties/customshapeproperties.cxx
@@ -73,6 +73,7 @@ namespace sdr::properties
SDRATTR_GRAF_FIRST, SDRATTR_CUSTOMSHAPE_LAST,
SDRATTR_GLOW_FIRST, SDRATTR_SOFTEDGE_LAST,
SDRATTR_TEXTCOLUMNS_FIRST, SDRATTR_TEXTCOLUMNS_LAST,
+ SDRATTR_WRITINGMODE2, SDRATTR_WRITINGMODE2,
// Range from SdrTextObj:
EE_ITEMS_START, EE_ITEMS_END>);
}
diff --git a/svx/source/svdraw/svdattr.cxx b/svx/source/svdraw/svdattr.cxx
index c0057b6aee70..86794dc92bfe 100644
--- a/svx/source/svdraw/svdattr.cxx
+++ b/svx/source/svdraw/svdattr.cxx
@@ -104,6 +104,7 @@
#include <sxsiitm.hxx>
#include <sxsoitm.hxx>
#include <sxtraitm.hxx>
+#include <editeng/frmdiritem.hxx>
#include <libxml/xmlwriter.h>
using namespace ::com::sun::star;
@@ -335,6 +336,8 @@ SdrItemPool::SdrItemPool(
rPoolDefaults[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START] = new SfxInt16Item(SDRATTR_TEXTCOLUMNS_NUMBER, 1);
rPoolDefaults[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START] = new SdrMetricItem(SDRATTR_TEXTCOLUMNS_SPACING, 0);
+ rPoolDefaults[SDRATTR_WRITINGMODE2 - SDRATTR_START] = new SvxFrameDirectionItem(SvxFrameDirection::Horizontal_LR_TB, SDRATTR_WRITINGMODE2);
+
// set own ItemInfos
mpLocalItemInfos[SDRATTR_SHADOW-SDRATTR_START]._nSID=SID_ATTR_FILL_SHADOW;
mpLocalItemInfos[SDRATTR_SHADOWCOLOR-SDRATTR_START]._nSID=SID_ATTR_SHADOW_COLOR;
@@ -359,6 +362,8 @@ SdrItemPool::SdrItemPool(
mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_NUMBER - SDRATTR_START]._nSID = 0 /*TODO*/;
mpLocalItemInfos[SDRATTR_TEXTCOLUMNS_SPACING - SDRATTR_START]._nSID = 0 /*TODO*/;
+ mpLocalItemInfos[SDRATTR_WRITINGMODE2 - SDRATTR_START]._nSID = 0 /*TODO*/;
+
// it's my own creation level, set Defaults and ItemInfos
SetDefaults(mpLocalPoolDefaults);
SetItemInfos(mpLocalItemInfos.get());
diff --git a/svx/source/svdraw/svdoashp.cxx b/svx/source/svdraw/svdoashp.cxx
index 5993781186a7..30d959b865e9 100644
--- a/svx/source/svdraw/svdoashp.cxx
+++ b/svx/source/svdraw/svdoashp.cxx
@@ -86,6 +86,7 @@
#include <sal/log.hxx>
#include <o3tl/string_view.hxx>
#include "presetooxhandleadjustmentrelations.hxx"
+#include <editeng/frmdiritem.hxx>
using namespace ::com::sun::star;
@@ -503,12 +504,32 @@ void SdrObjCustomShape::SetMirroredY( const bool bMirrorY )
double SdrObjCustomShape::GetExtraTextRotation( const bool bPreRotation ) const
{
- const uno::Any* pAny;
- const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
- pAny = rGeometryItem.GetPropertyValueByName( bPreRotation ? OUString( "TextPreRotateAngle" ) : OUString( "TextRotateAngle" ) );
double fExtraTextRotateAngle = 0.0;
- if ( pAny )
- *pAny >>= fExtraTextRotateAngle;
+ if (bPreRotation)
+ {
+ // textPreRotateAngle might be set by macro or diagram (SmartArt) import
+ const uno::Any* pAny;
+ const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ pAny = rGeometryItem.GetPropertyValueByName(u"TextPreRotateAngle");
+ if ( pAny )
+ *pAny >>= fExtraTextRotateAngle;
+
+ // As long as the edit engine is not able to rendere these text directions we
+ // emulate them by setting a suitable text pre-rotation.
+ const SvxFrameDirectionItem& rDirectionItem = GetMergedItem(SDRATTR_WRITINGMODE2);
+ if (rDirectionItem.GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ fExtraTextRotateAngle -= 90;
+ else if (rDirectionItem.GetValue() == SvxFrameDirection::Vertical_LR_BT)
+ fExtraTextRotateAngle -=270;
+ }
+ else
+ {
+ const uno::Any* pAny;
+ const SdrCustomShapeGeometryItem& rGeometryItem = GetMergedItem( SDRATTR_CUSTOMSHAPE_GEOMETRY );
+ pAny = rGeometryItem.GetPropertyValueByName(u"TextRotateAngle");
+ if ( pAny )
+ *pAny >>= fExtraTextRotateAngle;
+ }
return fExtraTextRotateAngle;
}
diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx
index 9ab5ef495f69..a37e6ef4c65c 100644
--- a/svx/source/unodraw/unoshape.cxx
+++ b/svx/source/unodraw/unoshape.cxx
@@ -90,6 +90,7 @@
#include <svx/svdopath.hxx>
#include <svx/SvxXTextColumns.hxx>
#include <svx/xflclit.hxx>
+#include <editeng/frmdiritem.hxx>
#include <memory>
#include <optional>
@@ -2464,6 +2465,15 @@ bool SvxShape::setPropertyValueImpl( const OUString&, const SfxItemPropertyMapEn
break;
}
+ case SDRATTR_WRITINGMODE2:
+ {
+ SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, SDRATTR_WRITINGMODE2);
+ aItem.PutValue(rValue, 0);
+ GetSdrObject()->SetMergedItem(aItem);
+ return true;
+ break;
+ }
+
default:
{
return false;
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
index 751ebdcf8167..0b7953bcb54e 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport13.cxx
@@ -312,11 +312,11 @@ DECLARE_OOXMLEXPORT_TEST(testendingSectionProps, "endingSectionProps.docx")
DECLARE_OOXMLEXPORT_TEST(testTbrlTextbox, "tbrl-textbox.docx")
{
uno::Reference<beans::XPropertySet> xPropertySet(getShape(1), uno::UNO_QUERY);
- comphelper::SequenceAsHashMap aGeometry(xPropertySet->getPropertyValue("CustomShapeGeometry"));
// Without the accompanying fix in place, this test would have failed with 'Expected: -90;
// Actual: 0', i.e. tbRl writing direction was imported as lrTb.
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-90),
- aGeometry["TextPreRotateAngle"].get<sal_Int32>());
+ // Note: Implementation was changed to use WritingMode property instead of TextPreRotateAngle.
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::TB_RL90,
+ getProperty<sal_Int16>(xPropertySet, "WritingMode"));
}
DECLARE_OOXMLEXPORT_TEST(testBtlrShape, "btlr-textbox.docx")
@@ -949,11 +949,11 @@ CPPUNIT_TEST_FIXTURE(Test, testBtlrFrame)
CPPUNIT_ASSERT_EQUAL(1, getShapes());
CPPUNIT_ASSERT_EQUAL(1, getPages());
uno::Reference<beans::XPropertySet> xPropertySet(getShape(1), uno::UNO_QUERY);
- comphelper::SequenceAsHashMap aGeometry(xPropertySet->getPropertyValue("CustomShapeGeometry"));
// Without the accompanying fix in place, this test would have failed with 'Expected:
// -270; Actual: 0', i.e. the writing direction of the frame was lost.
- CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(-270),
- aGeometry["TextPreRotateAngle"].get<sal_Int32>());
+ // Note: Implementation was changed to use WritingMode property instead of TextPreRotateAngle.
+ CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR,
+ getProperty<sal_Int16>(xPropertySet, "WritingMode"));
}
CPPUNIT_TEST_FIXTURE(Test, testTdf125518)
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
index 62c754af3d0f..50c98590e765 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport8.cxx
@@ -1207,9 +1207,9 @@ DECLARE_OOXMLEXPORT_TEST(testVmlTextVerticalAdjust, "vml-text-vertical-adjust.do
DECLARE_OOXMLEXPORT_TEST(testFdo69636, "fdo69636.docx")
{
// The problem was that the mso-layout-flow-alt:bottom-to-top VML shape property wasn't handled for sw text frames.
+ // Note: VML is no longer used on import. OOXML import uses WritingMode2::BT_LR now.
uno::Reference<beans::XPropertySet> xPropertySet(getShape(1), uno::UNO_QUERY);
- comphelper::SequenceAsHashMap aCustomShapeGeometry(xPropertySet->getPropertyValue("CustomShapeGeometry"));
- CPPUNIT_ASSERT_EQUAL(sal_Int32(-270), aCustomShapeGeometry["TextPreRotateAngle"].get<sal_Int32>());
+ CPPUNIT_ASSERT_EQUAL(sal_Int16(text::WritingMode2::BT_LR), getProperty<sal_Int16>(xPropertySet, "WritingMode"));
}
DECLARE_OOXMLEXPORT_TEST(testChartProp, "chart-prop.docx")
diff --git a/sw/source/core/doc/textboxhelper.cxx b/sw/source/core/doc/textboxhelper.cxx
index 909d818c54cd..5658d1075862 100644
--- a/sw/source/core/doc/textboxhelper.cxx
+++ b/sw/source/core/doc/textboxhelper.cxx
@@ -605,6 +605,9 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP
if (!pFormat)
return;
+ // Older documents or documents in ODF strict do not have WritingMode, but have used the
+ // TextRotateAngle values -90 and -270 to emulate these text directions of frames.
+ // ToDo: Is TextPreRotateAngle needed for diagrams or can it be removed?
comphelper::SequenceAsHashMap aCustomShapeGeometry(rValue);
auto it = aCustomShapeGeometry.find("TextPreRotateAngle");
if (it == aCustomShapeGeometry.end())
@@ -624,7 +627,7 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP
switch (nAngle)
{
case -90:
- nDirection = text::WritingMode2::TB_RL;
+ nDirection = text::WritingMode2::TB_RL90;
break;
case -270:
nDirection = text::WritingMode2::BT_LR;
@@ -663,6 +666,12 @@ void SwTextBoxHelper::syncProperty(SwFrameFormat* pShape, std::u16string_view rP
else if (rValue >>= eMode2)
syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(eMode2), pObj);
}
+ else if (rPropertyName == u"WritingMode")
+ {
+ sal_Int16 eMode2;
+ if (rValue >>= eMode2)
+ syncProperty(pShape, RES_FRAMEDIR, 0, uno::Any(eMode2), pObj);
+ }
else
SAL_INFO("sw.core", "SwTextBoxHelper::syncProperty: unhandled property: "
<< static_cast<OUString>(rPropertyName));
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index d6982d40bdee..2d59a1c7ea73 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -375,6 +375,12 @@ void SwFrame::CheckDir( SvxFrameDirection nDir, bool bVert, bool bOnlyBiDi, bool
mbVertLR = true;
mbVertLRBT = true;
}
+ else if (nDir == SvxFrameDirection::Vertical_RL_TB90)
+ {
+ // not yet implemented, render as RL_TB
+ mbVertLR = false;
+ mbVertLRBT = false;
+ }
}
}
else
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx b/sw/source/filter/ww8/docxattributeoutput.cxx
index de5bd79bcc4b..49ac7c64a9cf 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -10182,10 +10182,18 @@ void DocxAttributeOutput::FormatFrameDirection( const SvxFrameDirectionItem& rDi
sTextFlow = OString( "lrTb" );
bBiDi = true;
break;
- case SvxFrameDirection::Vertical_LR_TB: // many things but not this one
- case SvxFrameDirection::Vertical_RL_TB:
+ case SvxFrameDirection::Vertical_LR_TB: // ~ vert="mongolianVert"
+ sTextFlow = OString("tbLrV");
+ break;
+ case SvxFrameDirection::Vertical_RL_TB: // ~ vert="eaVert"
sTextFlow = OString( "tbRl" );
break;
+ case SvxFrameDirection::Vertical_LR_BT: // ~ vert="vert270"
+ sTextFlow = OString("btLr");
+ break;
+ case SvxFrameDirection::Vertical_RL_TB90: // ~ vert="vert"
+ sTextFlow = OString("tbRlV");
+ break;
}
if ( m_rExport.m_bOutPageDescs )
diff --git a/sw/source/filter/ww8/docxsdrexport.cxx b/sw/source/filter/ww8/docxsdrexport.cxx
index 3a0ff11b3962..c73418df7254 100644
--- a/sw/source/filter/ww8/docxsdrexport.cxx
+++ b/sw/source/filter/ww8/docxsdrexport.cxx
@@ -1965,7 +1965,10 @@ void DocxSdrExport::writeDMLTextFrame(ww8::Frame const* pParentFrame, int nAncho
m_pImpl->getBodyPrAttrList()->add(XML_vert, "eaVert");
else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_BT)
m_pImpl->getBodyPrAttrList()->add(XML_vert, "vert270");
-
+ else if (rDirection.GetValue() == SvxFrameDirection::Vertical_LR_TB)
+ m_pImpl->getBodyPrAttrList()->add(XML_vert, "mongolianVert");
+ else if (rDirection.GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ m_pImpl->getBodyPrAttrList()->add(XML_vert, "vert");
{
::comphelper::FlagRestorationGuard const g(m_pImpl->m_bFlyFrameGraphic, true);
comphelper::ValueRestorationGuard vg(m_pImpl->getExport().m_nTextTyp, TXT_TXTBOX);
diff --git a/sw/source/filter/xml/xmlexpit.cxx b/sw/source/filter/xml/xmlexpit.cxx
index c2d0dd76c659..3be82886d11a 100644
--- a/sw/source/filter/xml/xmlexpit.cxx
+++ b/sw/source/filter/xml/xmlexpit.cxx
@@ -194,7 +194,7 @@ void SvXMLExportItemMapper::exportXML(const SvXMLExport&,
{
case RES_FRAMEDIR:
{
- // Write bt-lr to the extension namespace, handle other values
+ // Write bt-lr and tb-rl90 to the extension namespace, handle other values
// below.
auto pDirection = static_cast<const SvxFrameDirectionItem*>(&rItem);
if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
@@ -207,6 +207,17 @@ void SvXMLExportItemMapper::exportXML(const SvXMLExport&,
if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
|| pDirection->GetValue() == SvxFrameDirection::Vertical_LR_BT)
bDone = true;
+
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ && pDirection->GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ {
+ const OUString sName(rNamespaceMap.GetQNameByKey(
+ XML_NAMESPACE_LO_EXT, GetXMLToken(XML_WRITING_MODE)));
+ rAttrList.AddAttribute(sName, GetXMLToken(XML_TB_RL90));
+ }
+ if (rEntry.nNameSpace == XML_NAMESPACE_LO_EXT
+ || pDirection->GetValue() == SvxFrameDirection::Vertical_RL_TB90)
+ bDone = true;
break;
}
}
diff --git a/sw/source/filter/xml/xmlimpit.cxx b/sw/source/filter/xml/xmlimpit.cxx
index 067ebc41fb90..b092fe85f8af 100644
--- a/sw/source/filter/xml/xmlimpit.cxx
+++ b/sw/source/filter/xml/xmlimpit.cxx
@@ -997,6 +997,13 @@ bool SvXMLImportItemMapper::PutXMLValue(
aAny <<= static_cast<sal_uInt16>(SvxFrameDirection::Vertical_LR_BT);
bOk = rItem.PutValue(aAny, 0);
}
+ else if (IsXMLToken(rValue, XML_TB_RL90))
+ {
+ // Read tb-rl90 from the extension namespace.
+ Any aAny;
+ aAny <<= static_cast<sal_uInt16>(SvxFrameDirection::Vertical_RL_TB90);
+ bOk = rItem.PutValue(aAny, 0);
+ }
else
{
std::unique_ptr<XMLPropertyHandler> pWritingModeHandler =
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index befaa122c705..9fa547675c8a 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1618,28 +1618,35 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
{
switch (nIntValue)
{
- case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRl: // ~ vert="eaVert"
{
m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
break;
}
- case NS_ooxml::LN_Value_ST_TextDirection_btLr:
+ case NS_ooxml::LN_Value_ST_TextDirection_btLr: // ~ vert="vert270"
{
m_pImpl->SetFrameDirection(text::WritingMode2::BT_LR);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
{
+ // East Asian character rotation is not implemented in LO, use ordinary LR_TB instead.
m_pImpl->SetFrameDirection(text::WritingMode2::LR_TB);
break;
}
- case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV: // ~ vert="vert"
{
- m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL90);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
- case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ // default in LO. Do not overwrite RL_TB set by bidi.
+ break;
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV: // ~ vert="mongolianVert"
+ {
+ m_pImpl->SetFrameDirection(text::WritingMode2::TB_LR);
+ break;
+ }
default:
SAL_WARN("writerfilter", "DomainMapper::sprmWithProps: unhandled textDirection");
}
@@ -2038,19 +2045,27 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
break;
case NS_ooxml::LN_EG_SectPrContents_textDirection:
{
- /* 0 HoriLR 1 Vert TR 2 Vert TR 3 Vert TT 4 HoriLT
- only 0 and 1 can be imported correctly
- */
- text::WritingMode nDirection = text::WritingMode_LR_TB;
+ sal_Int16 nDirection = text::WritingMode2::LR_TB;
switch( nIntValue )
{
+ // East Asian 270deg rotation in lrTbV is not implemented in LO
case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
- nDirection = text::WritingMode_LR_TB;
+ nDirection = text::WritingMode2::LR_TB; // =0
break;
case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
+ nDirection = text::WritingMode2::TB_RL; // =2
+ break;
+ // Word does not write btLr in sections, but LO would be able to use it.
case NS_ooxml::LN_Value_ST_TextDirection_btLr:
- nDirection = text::WritingMode_TB_RL;
+ nDirection = text::WritingMode2::BT_LR; // =5
+ break;
+ // Word maps mongolian direction to tbRlV in sections in file save, as of Aug 2022.
+ // From point of OOXML standard it would be tbLrV. Since tbRlV is currently not
+ // implemented in LO for text direction in page styles, we follow Word here.
+ case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
+ case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
+ nDirection = text::WritingMode2::TB_LR; // =3
break;
default:;
}
diff --git a/xmloff/inc/xmlsdtypes.hxx b/xmloff/inc/xmlsdtypes.hxx
index 898c475bd7ef..c6e0ad315e22 100644
--- a/xmloff/inc/xmlsdtypes.hxx
+++ b/xmloff/inc/xmlsdtypes.hxx
@@ -118,6 +118,7 @@
//////////////////////////////////////////////////////////////////////////////
#define XML_SD_TYPE_CELL_ROTATION_ANGLE (XML_SD_TYPES_START + 79 )
+#define XML_SD_TYPE_WRITINGMODE2 (XML_SD_TYPES_START + 80 )
#define CTF_NUMBERINGRULES 1000
#define CTF_CONTROLWRITINGMODE 1001
@@ -200,5 +201,6 @@
#define CTF_SD_OLE_VIS_AREA_EXPORT_HEIGHT 1063
//////////////////////////////////////////////////////////////////////////////
+#define CTF_WRITINGMODE2 1064
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/xmloff/source/core/xmltoken.cxx b/xmloff/source/core/xmltoken.cxx
index 30158b20660e..ca5c7ec21b08 100644
--- a/xmloff/source/core/xmltoken.cxx
+++ b/xmloff/source/core/xmltoken.cxx
@@ -2299,6 +2299,7 @@ namespace xmloff::token {
TOKEN( "lr", XML_LR ),
TOKEN( "rl", XML_RL ),
TOKEN( "tb", XML_TB ),
+ TOKEN( "tb-rl90", XML_TB_RL90 ),
TOKEN( "layout-grid-color", XML_LAYOUT_GRID_COLOR ),
TOKEN( "layout-grid-lines", XML_LAYOUT_GRID_LINES ),
diff --git a/xmloff/source/draw/sdpropls.cxx b/xmloff/source/draw/sdpropls.cxx
index a72a57261b58..3490625e1e8b 100644
--- a/xmloff/source/draw/sdpropls.cxx
+++ b/xmloff/source/draw/sdpropls.cxx
@@ -317,6 +317,9 @@ const XMLPropertyMapEntry aXMLSDProperties[] =
// misc object properties
GMAP( "MoveProtect", XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_MOVE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_MOVE_PROTECT ),
GMAP( "SizeProtect", XML_NAMESPACE_STYLE, XML_PROTECT, XML_SD_TYPE_SIZE_PROTECT|MID_FLAG_MULTI_PROPERTY|MID_FLAG_MERGE_ATTRIBUTE, CTF_SD_SIZE_PROTECT ),
+ GMAP( "WritingMode", XML_NAMESPACE_STYLE, XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE2, CTF_WRITINGMODE2 ),
+ {"WritingMode", XML_NAMESPACE_LO_EXT, XML_WRITING_MODE, XML_SD_TYPE_WRITINGMODE2|XML_TYPE_PROP_GRAPHIC, 0, SvtSaveOptions::ODFSVER_FUTURE_EXTENDED, true},
+
MAP_END()
};
@@ -589,6 +592,18 @@ SvXMLEnumMapEntry<text::WritingMode> const aXML_WritingMode_EnumMap[] =
{ XML_TOKEN_INVALID, text::WritingMode(0) }
};
+SvXMLEnumMapEntry<sal_Int16> const aXML_WritingMode2_EnumMap[] =
+{
+ { XML_LR_TB, text::WritingMode2::LR_TB },
+ { XML_RL_TB, text::WritingMode2::RL_TB },
+ { XML_TB_RL, text::WritingMode2::TB_RL },
+ { XML_TB_LR, text::WritingMode2::TB_LR },
+ { XML_PAGE, text::WritingMode2::CONTEXT },
+ { XML_BT_LR, text::WritingMode2::BT_LR },
+ { XML_TB_RL90, text::WritingMode2::TB_RL90 },
+ { XML_TOKEN_INVALID, text::WritingMode2::LR_TB }
+};
+
SvXMLEnumMapEntry<drawing::TextAnimationKind> const pXML_TextAnimation_Enum[] =
{
{ XML_NONE, drawing::TextAnimationKind_NONE },
@@ -1061,6 +1076,11 @@ const XMLPropertyHandler* XMLSdPropHdlFactory::GetPropertyHandler( sal_Int32 nTy
pHdl = new XMLEnumPropertyHdl( aXML_WritingMode_EnumMap );
break;
}
+ case XML_SD_TYPE_WRITINGMODE2 :
+ {
+ pHdl = new XMLConstantsPropertyHandler ( aXML_WritingMode2_EnumMap, XML_LR_TB );
+ break;
+ }
case XML_SD_TYPE_PRESPAGE_VISIBILITY :
{
pHdl = new XMLNamedBoolPropertyHdl( GetXMLToken(XML_VISIBLE), GetXMLToken(XML_HIDDEN) );
@@ -1360,6 +1380,7 @@ void XMLShapeExportPropertyMapper::ContextFilter(
XMLPropertyState* pClip11State = nullptr;
XMLPropertyState* pClipState = nullptr;
+ XMLPropertyState* pGraphicWritingMode2 = nullptr;
XMLPropertyState* pShapeWritingMode = nullptr;
XMLPropertyState* pTextWritingMode = nullptr;
XMLPropertyState* pControlWritingMode = nullptr;
@@ -1391,6 +1412,9 @@ void XMLShapeExportPropertyMapper::ContextFilter(
property->mnIndex = -1;
}
break;
+ case CTF_WRITINGMODE2:
+ pGraphicWritingMode2 = property;
+ break;
case CTF_WRITINGMODE:
pShapeWritingMode = property;
break;
@@ -1484,6 +1508,19 @@ void XMLShapeExportPropertyMapper::ContextFilter(
}
}
+ if (pGraphicWritingMode2)
+ {
+ // A style:writing-mode attribute G in graphic-properties is only evaluated if there is no
+ // style:writing-mode attribute P in the paragraph-properties of the same graphic style.
+ // Otherwise the value of P is used. For values lr-tb, rl-tb and tb-rl the values G and P
+ // should be the same. But other values in G cannot be expressed in P and would produce default
+ // 0 value in P, preventing evaluation of G.
+ sal_Int16 eGraphicWritingMode;
+ if ((pGraphicWritingMode2->maValue >>= eGraphicWritingMode)
+ && eGraphicWritingMode >= text::WritingMode2::TB_LR && pShapeWritingMode)
+ pShapeWritingMode->mnIndex = -1;
+ }
+
// check for duplicate writing mode
if( pShapeWritingMode && (pTextWritingMode || pControlWritingMode) )
{
diff --git a/xmloff/source/draw/shapeexport.cxx b/xmloff/source/draw/shapeexport.cxx
index c44349184770..a9f0291a53b8 100644
--- a/xmloff/source/draw/shapeexport.cxx
+++ b/xmloff/source/draw/shapeexport.cxx
@@ -80,6 +80,7 @@
#include <com/sun/star/presentation/ClickAction.hpp>
#include <com/sun/star/style/XStyle.hpp>
#include <com/sun/star/table/XColumnRowRange.hpp>
+#include <com/sun/star/text/WritingMode2.hpp>
#include <com/sun/star/text/XText.hpp>
#include <comphelper/classids.hxx>
@@ -4313,7 +4314,8 @@ static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Referenc
OUString aStr;
OUStringBuffer aStrBuffer;
- double fTextRotateAngle(0.0); // sum TextRotateAngle and TextPreRotateAngle
+ double fTextRotateAngle(0.0);
+ double fTextPreRotateAngle(0.0); // will be consolidated with fTextRotateAngle at the end
SvXMLUnitConverter& rUnitConverter = rExport.GetMM100UnitConverter();
uno::Reference< beans::XPropertySetInfo > xPropSetInfo( xPropSet->getPropertySetInfo() );
@@ -4366,11 +4368,13 @@ static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Referenc
}
break;
case EAS_TextPreRotateAngle :
+ {
+ rGeoProp.Value >>= fTextPreRotateAngle;
+ }
+ break;
case EAS_TextRotateAngle :
{
- double fAngle = 0.0;
- rGeoProp.Value >>= fAngle;
- fTextRotateAngle += fAngle;
+ rGeoProp.Value >>= fTextRotateAngle;
}
break;
case EAS_Extrusion :
@@ -4947,12 +4951,30 @@ static void ImpExportEnhancedGeometry( SvXMLExport& rExport, const uno::Referenc
break;
}
} // for
+
+ // ToDo: Where is TextPreRotateAngle still used? We cannot save it in ODF.
+ fTextRotateAngle += fTextPreRotateAngle;
+ // Workaround for writing-mode bt-lr and tb-rl90 in ODF strict,
+ // otherwise loext:writing-mode is used in style export.
+ if (!(rExport.getSaneDefaultVersion() & SvtSaveOptions::ODFSVER_EXTENDED))
+ {
+ if (xPropSetInfo->hasPropertyByName(u"WritingMode"))
+ {
+ sal_Int16 nDirection;
+ xPropSet->getPropertyValue(u"WritingMode") >>= nDirection;
+ if (nDirection == text::WritingMode2::TB_RL90)
+ fTextRotateAngle -= 90;
+ else if (nDirection == text::WritingMode2::BT_LR)
+ fTextRotateAngle -= 270;
+ }
+ }
if (fTextRotateAngle != 0)
{
::sax::Converter::convertDouble( aStrBuffer, fTextRotateAngle );
aStr = aStrBuffer.makeStringAndClear();
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TEXT_ROTATE_ANGLE, aStr );
}
+
rExport.AddAttribute( XML_NAMESPACE_DRAW, XML_TYPE, aCustomShapeType );
// adjustments
diff --git a/xmloff/source/style/prhdlfac.cxx b/xmloff/source/style/prhdlfac.cxx
index ca96e0421552..3b8cbe371000 100644
--- a/xmloff/source/style/prhdlfac.cxx
+++ b/xmloff/source/style/prhdlfac.cxx
@@ -99,6 +99,9 @@ SvXMLEnumMapEntry<sal_uInt16> const aXML_WritingDirection_Enum[] =
{ XML_RL, text::WritingMode2::RL_TB },
{ XML_TB, text::WritingMode2::TB_RL },
+ // vertical as clockwise 90deg rotation, for OOXML vert="vert"
+ { XML_TB_RL90, text::WritingMode2::TB_RL90 },
+
{ XML_TOKEN_INVALID, 0 }
};
diff --git a/xmloff/source/style/xmlexppr.cxx b/xmloff/source/style/xmlexppr.cxx
index 412b578c42a9..d2088cfea601 100644
--- a/xmloff/source/style/xmlexppr.cxx
+++ b/xmloff/source/style/xmlexppr.cxx
@@ -938,7 +938,8 @@ namespace
sal_Int8 CheckExtendedNamespace(std::u16string_view sXMLAttributeName, std::u16string_view sValue,
const SvtSaveOptions::ODFSaneDefaultVersion nODFVersion)
{
- if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE) && IsXMLToken(sValue, XML_BT_LR))
+ if (IsXMLToken(sXMLAttributeName, XML_WRITING_MODE)
+ && (IsXMLToken(sValue, XML_BT_LR) || IsXMLToken(sValue, XML_TB_RL90)))
return nODFVersion & SvtSaveOptions::ODFSVER_EXTENDED ? 1 : -1;
else if (IsXMLToken(sXMLAttributeName, XML_VERTICAL_REL)
&& (IsXMLToken(sValue, XML_PAGE_CONTENT_BOTTOM)
diff --git a/xmloff/source/token/tokens.txt b/xmloff/source/token/tokens.txt
index 918ab44981c4..506b9a4cb0e4 100644
--- a/xmloff/source/token/tokens.txt
+++ b/xmloff/source/token/tokens.txt
@@ -2183,6 +2183,7 @@ bt-lr
lr
rl
tb
+tb-rl90
layout-grid-color
layout-grid-lines
layout-grid-base-height