cui/source/inc/paragrph.hxx | 2 cui/source/tabpages/paragrph.cxx | 100 +++-- cui/uiconfig/ui/paragalignpage.ui | 49 ++ editeng/source/editeng/impedit2.cxx | 25 + editeng/source/items/paraitem.cxx | 10 editeng/source/uno/unonrule.cxx | 2 include/editeng/adjustitem.hxx | 8 include/editeng/editrids.hrc | 2 include/editeng/svxenum.hxx | 2 include/xmloff/xmlimp.hxx | 3 offapi/com/sun/star/style/ParagraphAdjust.idl | 13 offapi/type_reference/offapi.idl | 4 sw/qa/extras/odfexport/data/tdf118350-start-end-preserved.fodt | 150 +++++++ sw/qa/extras/odfexport/odfexport4.cxx | 31 + sw/qa/extras/uiwriter/data/tdf143176.fodt | 2 sw/source/core/text/itrcrsr.cxx | 26 + sw/source/core/unocore/unosett.cxx | 2 vcl/qa/cppunit/pdfexport/data/tdf118350-start-end-para-align.fodt | 192 ++++++++++ vcl/qa/cppunit/pdfexport/pdfexport2.cxx | 91 ++++ xmloff/qa/unit/uxmloff.cxx | 5 xmloff/source/core/xmlimp.cxx | 12 xmloff/source/style/adjushdl.cxx | 4 xmloff/source/style/xmlimppr.cxx | 29 + 23 files changed, 705 insertions(+), 59 deletions(-)
New commits: commit 5d1b2baaa96fce2cc283e4d383bcfca70651b2da Author: Jonathan Clark <[email protected]> AuthorDate: Tue Oct 21 02:14:26 2025 -0600 Commit: Jonathan Clark <[email protected]> CommitDate: Fri Oct 24 13:07:10 2025 +0200 tdf#118350 [API CHANGE] Implement start and end paragraph alignment Implements support for ODF fo:text-align start and end in paragraph styles. The new alignment options can be selected in the paragraph dialog. Further user interface changes are tracked as separate bugs. This change also adds START and END to css.style.ParagraphAdjust, which is flagged as an incompatible UNO API change. Change-Id: I2ee57f0029de7b794bc1ecd3eddbbd90af5dfdb9 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/192932 Tested-by: Jenkins Reviewed-by: Jonathan Clark <[email protected]> diff --git a/cui/source/inc/paragrph.hxx b/cui/source/inc/paragrph.hxx index 856daffcf776..ff6482526ed3 100644 --- a/cui/source/inc/paragrph.hxx +++ b/cui/source/inc/paragrph.hxx @@ -128,7 +128,9 @@ class SvxParaAlignTabPage : public SfxTabPage // alignment std::unique_ptr<weld::RadioButton> m_xLeft; + std::unique_ptr<weld::RadioButton> m_xStart; std::unique_ptr<weld::RadioButton> m_xRight; + std::unique_ptr<weld::RadioButton> m_xEnd; std::unique_ptr<weld::RadioButton> m_xCenter; std::unique_ptr<weld::RadioButton> m_xJustify; std::unique_ptr<weld::Label> m_xLeftBottom; diff --git a/cui/source/tabpages/paragrph.cxx b/cui/source/tabpages/paragrph.cxx index 3d285f514e84..978c4811b8cf 100644 --- a/cui/source/tabpages/paragrph.cxx +++ b/cui/source/tabpages/paragrph.cxx @@ -1265,7 +1265,9 @@ SvxParaAlignTabPage::SvxParaAlignTabPage(weld::Container* pPage, weld::DialogCon : SfxTabPage(pPage, pController, u"cui/ui/paragalignpage.ui"_ustr, u"ParaAlignPage"_ustr, &rSet) , m_bSdrVertAlign(false) , m_xLeft(m_xBuilder->weld_radio_button(u"radioBTN_LEFTALIGN"_ustr)) + , m_xStart(m_xBuilder->weld_radio_button(u"radioBTN_STARTALIGN"_ustr)) , m_xRight(m_xBuilder->weld_radio_button(u"radioBTN_RIGHTALIGN"_ustr)) + , m_xEnd(m_xBuilder->weld_radio_button(u"radioBTN_ENDALIGN"_ustr)) , m_xCenter(m_xBuilder->weld_radio_button(u"radioBTN_CENTERALIGN"_ustr)) , m_xJustify(m_xBuilder->weld_radio_button(u"radioBTN_JUSTIFYALIGN"_ustr)) , m_xLeftBottom(m_xBuilder->weld_label(u"labelST_LEFTALIGN_ASIAN"_ustr)) @@ -1321,7 +1323,9 @@ SvxParaAlignTabPage::SvxParaAlignTabPage(weld::Container* pPage, weld::DialogCon Link<weld::Toggleable&, void> aLink = LINK( this, SvxParaAlignTabPage, AlignHdl_Impl ); m_xLeft->connect_toggled(aLink); + m_xStart->connect_toggled(aLink); m_xRight->connect_toggled(aLink); + m_xEnd->connect_toggled(aLink); m_xCenter->connect_toggled(aLink); m_xJustify->connect_toggled(aLink); m_xLastLineLB->connect_changed(LINK(this, SvxParaAlignTabPage, LastLineHdl_Impl)); @@ -1366,11 +1370,21 @@ bool SvxParaAlignTabPage::FillItemSet( SfxItemSet* rOutSet ) eAdjust = SvxAdjust::Left; bAdj = m_xLeft->get_saved_state() == TRISTATE_FALSE; } + else if (m_xStart->get_active()) + { + eAdjust = SvxAdjust::ParaStart; + bAdj = m_xStart->get_saved_state() == TRISTATE_FALSE; + } else if (m_xRight->get_active()) { eAdjust = SvxAdjust::Right; bAdj = m_xRight->get_saved_state() == TRISTATE_FALSE; } + else if (m_xEnd->get_active()) + { + eAdjust = SvxAdjust::ParaEnd; + bAdj = m_xEnd->get_saved_state() == TRISTATE_FALSE; + } else if (m_xCenter->get_active()) { eAdjust = SvxAdjust::Center; @@ -1466,8 +1480,12 @@ void SvxParaAlignTabPage::Reset( const SfxItemSet* rSet ) { case SvxAdjust::Left: m_xLeft->set_active(true); break; + case SvxAdjust::ParaStart: m_xStart->set_active(true); break; + case SvxAdjust::Right: m_xRight->set_active(true); break; + case SvxAdjust::ParaEnd: m_xEnd->set_active(true); break; + case SvxAdjust::Center: m_xCenter->set_active(true); break; case SvxAdjust::Block: m_xJustify->set_active(true); break; @@ -1533,7 +1551,9 @@ void SvxParaAlignTabPage::Reset( const SfxItemSet* rSet ) else { m_xLeft->set_active(false); + m_xStart->set_active(false); m_xRight->set_active(false); + m_xEnd->set_active(false); m_xCenter->set_active(false); m_xJustify->set_active(false); m_xLabelWordSpacing->set_sensitive(false); @@ -1601,7 +1621,9 @@ void SvxParaAlignTabPage::Reset( const SfxItemSet* rSet ) m_xSnapToGridCB->save_state(); m_xVertAlignLB->save_value(); m_xLeft->save_state(); + m_xStart->save_state(); m_xRight->save_state(); + m_xEnd->save_state(); m_xCenter->save_state(); m_xJustify->save_state(); m_xLastLineLB->save_value(); @@ -1623,7 +1645,9 @@ void SvxParaAlignTabPage::ChangesApplied() m_xSnapToGridCB->save_state(); m_xVertAlignLB->save_value(); m_xLeft->save_state(); + m_xStart->save_state(); m_xRight->save_state(); + m_xEnd->save_state(); m_xCenter->save_state(); m_xJustify->save_state(); m_xLastLineLB->save_value(); @@ -1714,50 +1738,64 @@ IMPL_LINK_NOARG(SvxParaAlignTabPage, WordSpacingMaximumHdl_Impl, weld::MetricSpi void SvxParaAlignTabPage::UpdateExample_Impl() { + bool bParaIsRtl = [&] + { + SvxFrameDirection eDir = m_xTextDirectionLB->get_active_id(); + switch (eDir) + { + case SvxFrameDirection::Environment: + return AllSettings::GetLayoutRTL(); + + case SvxFrameDirection::Horizontal_RL_TB: + return true; + + default: + case SvxFrameDirection::Horizontal_LR_TB: + return false; + } + }(); + if (m_xLeft->get_active()) { m_aExampleWin.EnableRTL(false); m_aExampleWin.SetAdjust(SvxAdjust::Left); m_aExampleWin.SetLastLine(SvxAdjust::Left); } + else if (m_xStart->get_active()) + { + m_aExampleWin.EnableRTL(bParaIsRtl); + m_aExampleWin.SetAdjust(SvxAdjust::Left); + m_aExampleWin.SetLastLine(SvxAdjust::Left); + } else if (m_xRight->get_active()) { m_aExampleWin.EnableRTL(true); m_aExampleWin.SetAdjust(SvxAdjust::Left); m_aExampleWin.SetLastLine(SvxAdjust::Left); } - else + else if (m_xEnd->get_active()) { - SvxFrameDirection eDir = m_xTextDirectionLB->get_active_id(); - switch ( eDir ) - { - case SvxFrameDirection::Environment : - if ( !m_xRight->get_active() ) - m_aExampleWin.EnableRTL( AllSettings::GetLayoutRTL() ); - break; - case SvxFrameDirection::Horizontal_RL_TB : - if ( !m_xLeft->get_active() ) - m_aExampleWin.EnableRTL( true ); - break; - case SvxFrameDirection::Horizontal_LR_TB : - if ( !m_xRight->get_active() ) - m_aExampleWin.EnableRTL( false ); - break; - default: ; //prevent warning - } - if (m_xCenter->get_active()) - m_aExampleWin.SetAdjust( SvxAdjust::Center ); - else if (m_xJustify->get_active()) - { - m_aExampleWin.SetAdjust( SvxAdjust::Block ); - int nLBPos = m_xLastLineLB->get_active(); - if (nLBPos == 0) - m_aExampleWin.SetLastLine(SvxAdjust::Left); - else if (nLBPos == 1) - m_aExampleWin.SetLastLine(SvxAdjust::Center); - else if (nLBPos == 2) - m_aExampleWin.SetLastLine(SvxAdjust::Block); - } + m_aExampleWin.EnableRTL(!bParaIsRtl); + m_aExampleWin.SetAdjust(SvxAdjust::Left); + m_aExampleWin.SetLastLine(SvxAdjust::Left); + } + else if (m_xCenter->get_active()) + { + m_aExampleWin.EnableRTL(bParaIsRtl); + m_aExampleWin.SetAdjust(SvxAdjust::Center); + } + else if (m_xJustify->get_active()) + { + m_aExampleWin.EnableRTL(bParaIsRtl); + m_aExampleWin.SetAdjust(SvxAdjust::Block); + + int nLBPos = m_xLastLineLB->get_active(); + if (nLBPos == 0) + m_aExampleWin.SetLastLine(SvxAdjust::Left); + else if (nLBPos == 1) + m_aExampleWin.SetLastLine(SvxAdjust::Center); + else if (nLBPos == 2) + m_aExampleWin.SetLastLine(SvxAdjust::Block); } m_aExampleWin.Invalidate(); diff --git a/cui/uiconfig/ui/paragalignpage.ui b/cui/uiconfig/ui/paragalignpage.ui index 92824780cf41..58da274533f8 100644 --- a/cui/uiconfig/ui/paragalignpage.ui +++ b/cui/uiconfig/ui/paragalignpage.ui @@ -110,7 +110,7 @@ <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <!-- n-columns=1 n-rows=8 --> + <!-- n-columns=1 n-rows=10 --> <object class="GtkGrid" id="grid2"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -174,7 +174,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">3</property> + <property name="top-attach">5</property> </packing> </child> <child> @@ -189,7 +189,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">5</property> + <property name="top-attach">7</property> </packing> </child> <child> @@ -204,7 +204,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">6</property> + <property name="top-attach">8</property> </packing> </child> <child> @@ -250,7 +250,7 @@ </object> <packing> <property name="left-attach">0</property> - <property name="top-attach">7</property> + <property name="top-attach">9</property> </packing> </child> <child> @@ -293,11 +293,41 @@ </packing> </child> </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">6</property> + </packing> + </child> + <child> + <object class="GtkRadioButton" id="radioBTN_ENDALIGN"> + <property name="label" translatable="yes" context="paragalignpage|radioBTN_ENDALIGN">_End</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> + <property name="group">radioBTN_LEFTALIGN</property> + </object> <packing> <property name="left-attach">0</property> <property name="top-attach">4</property> </packing> </child> + <child> + <object class="GtkRadioButton" id="radioBTN_STARTALIGN"> + <property name="label" translatable="yes" context="paragalignpage|radioBTN_STARTALIGN">S_tart</property> + <property name="visible">True</property> + <property name="can-focus">True</property> + <property name="receives-default">False</property> + <property name="use-underline">True</property> + <property name="draw-indicator">True</property> + <property name="group">radioBTN_LEFTALIGN</property> + </object> + <packing> + <property name="left-attach">0</property> + <property name="top-attach">3</property> + </packing> + </child> </object> </child> <child type="label"> @@ -445,7 +475,7 @@ <property name="label-xalign">0</property> <property name="shadow-type">none</property> <child> - <!-- n-columns=4 n-rows=2 --> + <!-- n-columns=4 n-rows=4 --> <object class="GtkGrid" id="gridJustification"> <property name="visible">True</property> <property name="can-focus">False</property> @@ -657,7 +687,12 @@ <property name="top-attach">3</property> </packing> </child> - + <child> + <placeholder/> + </child> + <child> + <placeholder/> + </child> <child> <placeholder/> </child> diff --git a/editeng/source/editeng/impedit2.cxx b/editeng/source/editeng/impedit2.cxx index 5a617b0e6146..c72239dedc11 100644 --- a/editeng/source/editeng/impedit2.cxx +++ b/editeng/source/editeng/impedit2.cxx @@ -2070,12 +2070,29 @@ SvxAdjust ImpEditEngine::GetJustification( sal_Int32 nPara ) const { eJustification = GetParaAttrib( nPara, EE_PARA_JUST ).GetAdjust(); - if ( IsRightToLeft( nPara ) ) + // Convert paragraph adjustment into an internal start/end value. + switch (eJustification) { - if ( eJustification == SvxAdjust::Left ) - eJustification = SvxAdjust::Right; - else if ( eJustification == SvxAdjust::Right ) + case SvxAdjust::ParaStart: + // Internally, the paragraph start is always the left margin: eJustification = SvxAdjust::Left; + break; + + case SvxAdjust::ParaEnd: + // Internally, the paragraph end is always the right margin: + eJustification = SvxAdjust::Right; + break; + + case SvxAdjust::Left: + eJustification = IsRightToLeft(nPara) ? SvxAdjust::Right : SvxAdjust::Left; + break; + + case SvxAdjust::Right: + eJustification = IsRightToLeft(nPara) ? SvxAdjust::Left : SvxAdjust::Right; + break; + + default: + break; } } return eJustification; diff --git a/editeng/source/items/paraitem.cxx b/editeng/source/items/paraitem.cxx index 58fd5be3cc60..9c16c3f78dca 100644 --- a/editeng/source/items/paraitem.cxx +++ b/editeng/source/items/paraitem.cxx @@ -409,7 +409,7 @@ bool SvxAdjustItem::PutValue( const uno::Any& rVal, sal_uInt8 nMemberId ) { sal_Int32 eVal = - 1; ::cppu::enum2int(eVal,rVal); - if(eVal >= 0 && eVal <= 4) + if(eVal >= 0 && eVal <= 6) { SvxAdjust eAdjust = static_cast<SvxAdjust>(eVal); if(MID_LAST_LINE_ADJUST == nMemberId && @@ -512,10 +512,12 @@ OUString SvxAdjustItem::GetValueTextByPos( sal_uInt16 nPos ) RID_SVXITEMS_ADJUST_RIGHT, RID_SVXITEMS_ADJUST_BLOCK, RID_SVXITEMS_ADJUST_CENTER, - RID_SVXITEMS_ADJUST_BLOCKLINE + RID_SVXITEMS_ADJUST_BLOCKLINE, + RID_SVXITEMS_ADJUST_PARASTART, + RID_SVXITEMS_ADJUST_PARAEND }; - static_assert(std::size(RID_SVXITEMS_ADJUST) - 1 == static_cast<size_t>(SvxAdjust::BlockLine), "unexpected size"); - assert(nPos <= sal_uInt16(SvxAdjust::BlockLine) && "enum overflow!"); + static_assert(std::size(RID_SVXITEMS_ADJUST) - 1 == static_cast<size_t>(SvxAdjust::ParaEnd), "unexpected size"); + assert(nPos <= sal_uInt16(SvxAdjust::ParaEnd) && "enum overflow!"); return EditResId(RID_SVXITEMS_ADJUST[nPos]); } diff --git a/editeng/source/uno/unonrule.cxx b/editeng/source/uno/unonrule.cxx index c3ba8276551c..a508d6a7544c 100644 --- a/editeng/source/uno/unonrule.cxx +++ b/editeng/source/uno/unonrule.cxx @@ -72,6 +72,8 @@ const o3tl::enumarray<SvxAdjust, sal_Int16> aSvxToUnoAdjust text::HoriOrientation::FULL, text::HoriOrientation::CENTER, text::HoriOrientation::FULL, + text::HoriOrientation::LEFT, + text::HoriOrientation::RIGHT, text::HoriOrientation::LEFT }; diff --git a/include/editeng/adjustitem.hxx b/include/editeng/adjustitem.hxx index c1acd36a4113..0a57417bc073 100644 --- a/include/editeng/adjustitem.hxx +++ b/include/editeng/adjustitem.hxx @@ -37,6 +37,8 @@ class EDITENG_DLLPUBLIC SvxAdjustItem final : public SfxPoolItem bool bRight : 1; bool bCenter : 1; bool bBlock : 1; + bool bStart : 1; + bool bEnd : 1; // only active when bBlock bool bOneBlock : 1; @@ -103,6 +105,8 @@ public: bRight = eType == SvxAdjust::Right; bCenter = eType == SvxAdjust::Center; bBlock = eType == SvxAdjust::Block; + bStart = eType == SvxAdjust::ParaStart; + bEnd = eType == SvxAdjust::ParaEnd; } SvxAdjust GetLastBlock() const @@ -135,6 +139,10 @@ public: eRet = SvxAdjust::Center; else if ( bBlock ) eRet = SvxAdjust::Block; + else if ( bStart ) + eRet = SvxAdjust::ParaStart; + else if ( bEnd ) + eRet = SvxAdjust::ParaEnd; return eRet; } diff --git a/include/editeng/editrids.hrc b/include/editeng/editrids.hrc index 23c8ec932fd0..fa82e0d90f33 100644 --- a/include/editeng/editrids.hrc +++ b/include/editeng/editrids.hrc @@ -151,6 +151,8 @@ #define RID_SVXITEMS_ADJUST_BLOCK NC_("RID_SVXITEMS_ADJUST_BLOCK", "Justify") #define RID_SVXITEMS_ADJUST_CENTER NC_("RID_SVXITEMS_ADJUST_CENTER", "Centered") #define RID_SVXITEMS_ADJUST_BLOCKLINE NC_("RID_SVXITEMS_ADJUST_BLOCKLINE", "Justify") +#define RID_SVXITEMS_ADJUST_PARASTART NC_("RID_SVXITEMS_ADJUST_PARASTART", "Start") +#define RID_SVXITEMS_ADJUST_PARAEND NC_("RID_SVXITEMS_ADJUST_PARAEND", "End") #define RID_SOLID NC_("RID_SOLID", "Single, solid") #define RID_DOTTED NC_("RID_DOTTED", "Single, dotted") #define RID_DASHED NC_("RID_DASHED", "Single, dashed") diff --git a/include/editeng/svxenum.hxx b/include/editeng/svxenum.hxx index ba77a2a3c65a..84362e18c975 100644 --- a/include/editeng/svxenum.hxx +++ b/include/editeng/svxenum.hxx @@ -83,6 +83,8 @@ enum class SvxAdjust Block, Center, BlockLine, + ParaStart, + ParaEnd, End, LAST = End }; diff --git a/include/xmloff/xmlimp.hxx b/include/xmloff/xmlimp.hxx index 352c61224f74..2a0660272250 100644 --- a/include/xmloff/xmlimp.hxx +++ b/include/xmloff/xmlimp.hxx @@ -555,6 +555,9 @@ public: static const sal_uInt16 LO_76 = 76 | LO_flag; static const sal_uInt16 LO_242 = 80 | LO_flag; static const sal_uInt16 LO_248 = 81 | LO_flag; + static const sal_uInt16 LO_252 = 82 | LO_flag; + static const sal_uInt16 LO_258 = 83 | LO_flag; + static const sal_uInt16 LO_262 = 84 | LO_flag; static const sal_uInt16 LO_New = 100 | LO_flag; static const sal_uInt16 ProductVersionUnknown = SAL_MAX_UINT16; diff --git a/offapi/com/sun/star/style/ParagraphAdjust.idl b/offapi/com/sun/star/style/ParagraphAdjust.idl index 367202bfa87a..248eec51dca3 100644 --- a/offapi/com/sun/star/style/ParagraphAdjust.idl +++ b/offapi/com/sun/star/style/ParagraphAdjust.idl @@ -43,8 +43,19 @@ published enum ParagraphAdjust /** adjusted to both borders / stretched, including last line */ - STRETCH + STRETCH, + /** equivalent to LEFT for LTR paragraphs, RIGHT for RTL paragraphs + + @since LibreOffice 26.2 + */ + START, + + /** equivalent to RIGHT for LTR paragraphs, LEFT for RTL paragraphs + + @since LibreOffice 26.2 + */ + END }; diff --git a/offapi/type_reference/offapi.idl b/offapi/type_reference/offapi.idl index 471183f20005..369ca0550221 100644 --- a/offapi/type_reference/offapi.idl +++ b/offapi/type_reference/offapi.idl @@ -3585,7 +3585,9 @@ module com { RIGHT = 1, BLOCK = 2, CENTER = 3, - STRETCH = 4 + STRETCH = 4, + START = 5, + END = 6 }; published enum TabAlign { LEFT = 0, diff --git a/sw/qa/extras/odfexport/data/tdf118350-start-end-preserved.fodt b/sw/qa/extras/odfexport/data/tdf118350-start-end-preserved.fodt new file mode 100644 index 000000000000..2859bf0cddae --- /dev/null +++ b/sw/qa/extras/odfexport/data/tdf118350-start-end-preserved.fodt @@ -0,0 +1,150 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2025-10-22T05:31:47.251184918</meta:creation-date><meta:generator>LibreOfficeDev/26.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/d7e24df067ba6af0043e70750ad2b97e21201fa9</meta:generator><dc:date>2025-10-22T05:36:27.933616336</dc:date><meta:editing-duration>PT4M39S</meta:editing-duration><meta:editing-cycles>3</meta:editing-cycles><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="8" meta:word-count="48" meta:character-count="282" meta:non-whitespace-character-count="242"/></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans Devanagari1" svg:font-family="'Noto Sans Devanagari'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Serif CJK JP" svg:font-family="'Noto Serif CJK JP'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:writing-mode="lr-tb" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="CA" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK JP" style:font-size-asian="10.5pt" style:language-asian="ja" style:country-asian="JP" style:font-name-complex="Noto Sans Devanagari1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="CA" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK JP" style:font-size-asian="10.5pt" style:language-asian="ja" style:country-asian="JP" style:font-name-complex="Noto Sans Devanagari1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <style:style style:name="LTRLeft" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="left"/> + </style:style> + <style:style style:name="LTRStart" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="start"/> + </style:style> + <style:style style:name="LTRRight" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="right"/> + </style:style> + <style:style style:name="LTREnd" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="end"/> + </style:style> + <style:style style:name="RTLLeft" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="left" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="RTLStart" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="start" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="RTLRight" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="right" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="RTLEnd" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="end" style:writing-mode="rl-tb"/> + </style:style> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:text-properties/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.59cm" fo:page-height="27.94cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="LTRLeft">This paragraph is LTR aligned left.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="LTRStart">This paragraph is LTR aligned start.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="LTRRight">This paragraph is LTR aligned right.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="LTREnd">This paragraph is LTR aligned end.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="RTLLeft">This paragraph is RTL aligned left.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="RTLStart">This paragraph is RTL aligned start.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="RTLRight">This paragraph is RTL aligned right.</text:p> + <text:p text:style-name="P1"/> + <text:p text:style-name="RTLEnd">This paragraph is RTL aligned end.</text:p> + <text:p text:style-name="RTLEnd"/> + </office:text> + </office:body> +</office:document> diff --git a/sw/qa/extras/odfexport/odfexport4.cxx b/sw/qa/extras/odfexport/odfexport4.cxx index d75937da016c..087e19731391 100644 --- a/sw/qa/extras/odfexport/odfexport4.cxx +++ b/sw/qa/extras/odfexport/odfexport4.cxx @@ -1645,8 +1645,9 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf168980) CPPUNIT_TEST_FIXTURE(Test, testTdf37128ConvertStartEndOnResave) { - // LO doesn't support start/end fo:text-align. These are always loaded as - // left/right, respectively. They should be resaved as left/right, too. + // Older versions of LO always stored fo:text-align left/right as + // start/end, respectively. Make sure documents produced by older + // versions of LO convert these values to left/right. loadAndReload("tdf37128-start-end-to-left-right.fodt"); CPPUNIT_ASSERT_EQUAL(1, getPages()); xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr); @@ -1669,6 +1670,32 @@ CPPUNIT_TEST_FIXTURE(Test, testTdf37128ConvertStartEndOnResave) "text-align", u"right"); } +CPPUNIT_TEST_FIXTURE(Test, testTdf118350StartEndPreserved) +{ + // Check that fo:text-align start/end round-trip correctly for + // documents made by newer versions of LO. + loadAndReload("tdf118350-start-end-preserved.fodt"); + CPPUNIT_ASSERT_EQUAL(1, getPages()); + xmlDocUniquePtr pXmlDoc = parseExport(u"styles.xml"_ustr); + + assertXPath(pXmlDoc, "//style:style[@style:name='LTRLeft']/style:paragraph-properties", + "text-align", u"left"); + assertXPath(pXmlDoc, "//style:style[@style:name='LTRStart']/style:paragraph-properties", + "text-align", u"start"); + assertXPath(pXmlDoc, "//style:style[@style:name='LTRRight']/style:paragraph-properties", + "text-align", u"right"); + assertXPath(pXmlDoc, "//style:style[@style:name='LTREnd']/style:paragraph-properties", + "text-align", u"end"); + assertXPath(pXmlDoc, "//style:style[@style:name='RTLLeft']/style:paragraph-properties", + "text-align", u"left"); + assertXPath(pXmlDoc, "//style:style[@style:name='RTLStart']/style:paragraph-properties", + "text-align", u"start"); + assertXPath(pXmlDoc, "//style:style[@style:name='RTLRight']/style:paragraph-properties", + "text-align", u"right"); + assertXPath(pXmlDoc, "//style:style[@style:name='RTLEnd']/style:paragraph-properties", + "text-align", u"end"); +} + } // end of anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/sw/qa/extras/uiwriter/data/tdf143176.fodt b/sw/qa/extras/uiwriter/data/tdf143176.fodt index fdd89c38da3c..994f133447d4 100644 --- a/sw/qa/extras/uiwriter/data/tdf143176.fodt +++ b/sw/qa/extras/uiwriter/data/tdf143176.fodt @@ -8,7 +8,7 @@ </office:styles> <office:automatic-styles> <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> - <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" style:writing-mode="rl-tb"/> + <style:paragraph-properties fo:text-align="start" style:justify-single-word="false" style:writing-mode="rl-tb"/> </style:style> </office:automatic-styles> <office:body> diff --git a/sw/source/core/text/itrcrsr.cxx b/sw/source/core/text/itrcrsr.cxx index 1a8c500ef92f..bff160bffba8 100644 --- a/sw/source/core/text/itrcrsr.cxx +++ b/sw/source/core/text/itrcrsr.cxx @@ -348,13 +348,29 @@ void SwTextMargin::CtorInitTextMargin( SwTextFrame *pNewFrame, SwTextSizeInfo *p const SvxAdjustItem& rAdjust = m_pFrame->GetTextNodeForParaProps()->GetSwAttrSet().GetAdjust(); mnAdjust = rAdjust.GetAdjust(); - // left is left and right is right - if ( m_pFrame->IsRightToLeft() ) + // Convert paragraph adjustment into an internal start/end value. + switch (mnAdjust) { - if ( SvxAdjust::Left == mnAdjust ) - mnAdjust = SvxAdjust::Right; - else if ( SvxAdjust::Right == mnAdjust ) + case SvxAdjust::ParaStart: + // Internally, the paragraph start is always the left margin: mnAdjust = SvxAdjust::Left; + break; + + case SvxAdjust::ParaEnd: + // Internally, the paragraph end is always the right margin: + mnAdjust = SvxAdjust::Right; + break; + + case SvxAdjust::Left: + mnAdjust = m_pFrame->IsRightToLeft() ? SvxAdjust::Right : SvxAdjust::Left; + break; + + case SvxAdjust::Right: + mnAdjust = m_pFrame->IsRightToLeft() ? SvxAdjust::Left : SvxAdjust::Right; + break; + + default: + break; } m_bOneBlock = rAdjust.GetOneWord() == SvxAdjust::Block; diff --git a/sw/source/core/unocore/unosett.cxx b/sw/source/core/unocore/unosett.cxx index cce13036c8d5..cd4d5020f13f 100644 --- a/sw/source/core/unocore/unosett.cxx +++ b/sw/source/core/unocore/unosett.cxx @@ -244,6 +244,8 @@ const o3tl::enumarray<SvxAdjust, sal_Int16> aSvxToUnoAdjust sal_Int16(-1), text::HoriOrientation::CENTER, //2 sal_Int16(-1), + sal_Int16(-1), + sal_Int16(-1), sal_Int16(-1) }; diff --git a/vcl/qa/cppunit/pdfexport/data/tdf118350-start-end-para-align.fodt b/vcl/qa/cppunit/pdfexport/data/tdf118350-start-end-para-align.fodt new file mode 100644 index 000000000000..ad0b5e132659 --- /dev/null +++ b/vcl/qa/cppunit/pdfexport/data/tdf118350-start-end-para-align.fodt @@ -0,0 +1,192 @@ +<?xml version='1.0' encoding='UTF-8'?> +<office:document xmlns:css3t="http://www.w3.org/TR/css3-text/" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:c alcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:rpt="http://openoffice.org/2005/report" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:officeooo="http://openoffice.org/2009/office" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns: meta:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" office:version="1.4" office:mimetype="application/vnd.oasis.opendocument.text"> + <office:meta><meta:creation-date>2025-10-23T06:15:16.537082542</meta:creation-date><dc:date>2025-10-23T06:21:45.657634279</dc:date><meta:editing-duration>PT4M33S</meta:editing-duration><meta:editing-cycles>5</meta:editing-cycles><meta:generator>LibreOfficeDev/26.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/faccef0e7b37c40cb2efc276ea5d914f9496665e</meta:generator><meta:document-statistic meta:table-count="0" meta:image-count="0" meta:object-count="0" meta:page-count="1" meta:paragraph-count="8" meta:word-count="48" meta:character-count="282" meta:non-whitespace-character-count="242"/></office:meta> + <office:font-face-decls> + <style:font-face style:name="Liberation Serif" svg:font-family="'Liberation Serif'" style:font-family-generic="roman" style:font-pitch="variable"/> + <style:font-face style:name="Noto Sans1" svg:font-family="'Noto Sans'" style:font-family-generic="system" style:font-pitch="variable"/> + <style:font-face style:name="Noto Serif CJK SC" svg:font-family="'Noto Serif CJK SC'" style:font-family-generic="system" style:font-pitch="variable"/> + </office:font-face-decls> + <office:styles> + <style:default-style style:family="graphic"> + <style:graphic-properties svg:stroke-color="#3465a4" draw:fill-color="#729fcf" fo:wrap-option="no-wrap" draw:shadow-offset-x="0.3cm" draw:shadow-offset-y="0.3cm" draw:start-line-spacing-horizontal="0.283cm" draw:start-line-spacing-vertical="0.283cm" draw:end-line-spacing-horizontal="0.283cm" draw:end-line-spacing-vertical="0.283cm" style:writing-mode="lr-tb" style:flow-with-text="false"/> + <style:paragraph-properties style:text-autospace="ideograph-alpha" style:line-break="strict" loext:tab-stop-distance="0cm" style:font-independent-line-spacing="false"> + <style:tab-stops/> + </style:paragraph-properties> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="CA" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN"/> + </style:default-style> + <style:default-style style:family="paragraph"> + <style:paragraph-properties fo:orphans="2" fo:widows="2" fo:hyphenation-ladder-count="no-limit" fo:hyphenation-keep="auto" loext:hyphenation-keep-type="column" loext:hyphenation-keep-line="false" style:text-autospace="ideograph-alpha" style:punctuation-wrap="hanging" style:line-break="strict" style:tab-stop-distance="1.251cm" style:writing-mode="page"/> + <style:text-properties style:use-window-font-color="true" loext:opacity="0%" style:font-name="Liberation Serif" fo:font-size="12pt" fo:language="en" fo:country="CA" style:letter-kerning="true" style:font-name-asian="Noto Serif CJK SC" style:font-size-asian="10.5pt" style:language-asian="zh" style:country-asian="CN" style:font-name-complex="Noto Sans1" style:font-size-complex="12pt" style:language-complex="hi" style:country-complex="IN" fo:hyphenate="false" fo:hyphenation-remain-char-count="2" fo:hyphenation-push-char-count="2" loext:hyphenation-no-caps="false" loext:hyphenation-no-last-word="false" loext:hyphenation-word-char-count="5" loext:hyphenation-zone="no-limit"/> + </style:default-style> + <style:default-style style:family="table"> + <style:table-properties table:border-model="collapsing"/> + </style:default-style> + <style:default-style style:family="table-row"> + <style:table-row-properties fo:keep-together="auto"/> + </style:default-style> + <style:style style:name="Standard" style:family="paragraph" style:class="text"/> + <text:outline-style style:name="Outline"> + <text:outline-level-style text:level="1" loext:num-list-format="%1%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="2" loext:num-list-format="%2%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="3" loext:num-list-format="%3%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="4" loext:num-list-format="%4%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="5" loext:num-list-format="%5%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="6" loext:num-list-format="%6%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="7" loext:num-list-format="%7%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="8" loext:num-list-format="%8%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="9" loext:num-list-format="%9%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + <text:outline-level-style text:level="10" loext:num-list-format="%10%" style:num-format=""> + <style:list-level-properties text:list-level-position-and-space-mode="label-alignment"> + <style:list-level-label-alignment text:label-followed-by="listtab"/> + </style:list-level-properties> + </text:outline-level-style> + </text:outline-style> + <text:notes-configuration text:note-class="footnote" style:num-format="1" text:start-value="0" text:footnotes-position="page" text:start-numbering-at="document"/> + <text:notes-configuration text:note-class="endnote" style:num-format="i" text:start-value="0"/> + <text:linenumbering-configuration text:number-lines="false" text:offset="0.499cm" style:num-format="1" text:number-position="left" text:increment="5"/> + </office:styles> + <office:automatic-styles> + <style:style style:name="P1" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="start" style:justify-single-word="false"/> + </style:style> + <style:style style:name="P2" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="right" style:justify-single-word="false"/> + </style:style> + <style:style style:name="P3" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="end" style:justify-single-word="false"/> + </style:style> + <style:style style:name="P4" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P5" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="start" style:justify-single-word="false" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P6" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="right" style:justify-single-word="false" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P7" style:family="paragraph" style:parent-style-name="Standard"> + <style:paragraph-properties fo:text-align="end" style:justify-single-word="false" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P8" style:family="paragraph"> + <style:paragraph-properties fo:text-align="start"/> + </style:style> + <style:style style:name="P9" style:family="paragraph"> + <style:paragraph-properties fo:text-align="right"/> + </style:style> + <style:style style:name="P10" style:family="paragraph"> + <style:paragraph-properties fo:text-align="end"/> + </style:style> + <style:style style:name="P11" style:family="paragraph"> + <style:paragraph-properties fo:text-align="end" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P12" style:family="paragraph"> + <style:paragraph-properties fo:text-align="start" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P13" style:family="paragraph"> + <style:paragraph-properties fo:text-align="right" style:writing-mode="rl-tb"/> + </style:style> + <style:style style:name="P14" style:family="paragraph"> + <loext:graphic-properties draw:fill="none" draw:fill-color="#ffffff"/> + </style:style> + <style:style style:name="gr1" style:family="graphic"> + <style:graphic-properties draw:stroke="none" svg:stroke-color="#000000" draw:fill="none" draw:fill-color="#ffffff" fo:min-height="11.748cm" loext:decorative="false" style:run-through="foreground" style:wrap="run-through" style:number-wrapped-paragraphs="no-limit" style:vertical-pos="from-top" style:vertical-rel="paragraph" style:horizontal-pos="from-left" style:horizontal-rel="paragraph" draw:wrap-influence-on-position="once-concurrent" loext:allow-overlap="true" style:flow-with-text="false"/> + <style:paragraph-properties style:writing-mode="lr-tb"/> + </style:style> + <style:page-layout style:name="pm1"> + <style:page-layout-properties fo:page-width="21.59cm" fo:page-height="27.94cm" style:num-format="1" style:print-orientation="portrait" fo:margin-top="2cm" fo:margin-bottom="2cm" fo:margin-left="2cm" fo:margin-right="2cm" style:writing-mode="lr-tb" style:layout-grid-color="#c0c0c0" style:layout-grid-lines="20" style:layout-grid-base-height="0.706cm" style:layout-grid-ruby-height="0.353cm" style:layout-grid-mode="none" style:layout-grid-ruby-below="false" style:layout-grid-print="false" style:layout-grid-display="false" style:footnote-max-height="0cm" loext:margin-gutter="0cm"> + <style:footnote-sep style:width="0.018cm" style:distance-before-sep="0.101cm" style:distance-after-sep="0.101cm" style:line-style="solid" style:adjustment="left" style:rel-width="25%" style:color="#000000"/> + </style:page-layout-properties> + <style:header-style/> + <style:footer-style/> + </style:page-layout> + <style:style style:name="dp1" style:family="drawing-page"> + <style:drawing-page-properties draw:background-size="full"/> + </style:style> + </office:automatic-styles> + <office:master-styles> + <style:master-page style:name="Standard" style:page-layout-name="pm1" draw:style-name="dp1"/> + </office:master-styles> + <office:body> + <office:text> + <text:sequence-decls> + <text:sequence-decl text:display-outline-level="0" text:name="Illustration"/> + <text:sequence-decl text:display-outline-level="0" text:name="Table"/> + <text:sequence-decl text:display-outline-level="0" text:name="Text"/> + <text:sequence-decl text:display-outline-level="0" text:name="Drawing"/> + <text:sequence-decl text:display-outline-level="0" text:name="Figure"/> + </text:sequence-decls> + <text:p text:style-name="Standard">This paragraph is LTR aligned left.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P1">This paragraph is LTR aligned start.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P2">This paragraph is LTR aligned right.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P3">This paragraph is LTR aligned end.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P4">This paragraph is RTL aligned left.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P5">This paragraph is RTL aligned start.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P6">This paragraph is RTL aligned right.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="P7">This paragraph is RTL aligned end.</text:p> + <text:p text:style-name="Standard"/> + <text:p text:style-name="Standard"><draw:frame text:anchor-type="paragraph" draw:z-index="0" draw:name="Text Frame 1" draw:style-name="gr1" draw:text-style-name="P14" svg:width="15.505cm" svg:height="11.748cm" svg:x="1.478cm" svg:y="1.986cm"> + <draw:text-box> + <text:p>This paragraph is LTR aligned left.</text:p> + <text:p/> + <text:p text:style-name="P8">This paragraph is LTR aligned start.</text:p> + <text:p/> + <text:p text:style-name="P9">This paragraph is LTR aligned right.</text:p> + <text:p/> + <text:p text:style-name="P10">This paragraph is LTR aligned end.</text:p> + <text:p/> + <text:p text:style-name="P11">This paragraph is RTL aligned left.</text:p> + <text:p/> + <text:p text:style-name="P12">This paragraph is RTL aligned start.</text:p> + <text:p/> + <text:p text:style-name="P13">This paragraph is RTL aligned right.</text:p> + <text:p/> + <text:p text:style-name="P11">This paragraph is RTL aligned end.</text:p> + <text:p/> + </draw:text-box> + </draw:frame></text:p> + </office:text> + </office:body> +</office:document> \ No newline at end of file diff --git a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx index b160e67b0ab0..61075c4d3bf9 100644 --- a/vcl/qa/cppunit/pdfexport/pdfexport2.cxx +++ b/vcl/qa/cppunit/pdfexport/pdfexport2.cxx @@ -6348,6 +6348,97 @@ CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf166044ContFootnoteOnlyOnePgNum) CPPUNIT_ASSERT_EQUAL(u"2"_ustr, pPgNumObject->getText(pTextPage)); } +CPPUNIT_TEST_FIXTURE(PdfExportTest2, testTdf118350StartEndParaAlign) +{ + saveAsPDF(u"tdf118350-start-end-para-align.fodt"); + + auto pPdfDocument = parsePDFExport(); + CPPUNIT_ASSERT_EQUAL(1, pPdfDocument->getPageCount()); + + auto pPdfPage = pPdfDocument->openPage(/*nIndex*/ 0); + CPPUNIT_ASSERT(pPdfPage); + auto pTextPage = pPdfPage->getTextPage(); + CPPUNIT_ASSERT(pTextPage); + + int nPageObjectCount = pPdfPage->getObjectCount(); + + CPPUNIT_ASSERT_EQUAL(24, nPageObjectCount); + + std::vector<OUString> aText; + std::vector<basegfx::B2DRectangle> aRect; + + for (int i = 0; i < nPageObjectCount; ++i) + { + auto pPageObject = pPdfPage->getObject(i); + CPPUNIT_ASSERT_MESSAGE("no object", pPageObject != nullptr); + if (pPageObject->getType() == vcl::pdf::PDFPageObjectType::Text) + { + aText.push_back(pPageObject->getText(pTextPage)); + aRect.push_back(pPageObject->getBounds()); + } + } + + CPPUNIT_ASSERT_EQUAL(size_t(24), aText.size()); + + // Lines from the Writer portion + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned left."_ustr, aText.at(0).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(57.0, aRect.at(0).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned start."_ustr, aText.at(1).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(57.0, aRect.at(1).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned right."_ustr, aText.at(2).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(550.0, aRect.at(2).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned end."_ustr, aText.at(3).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(550.0, aRect.at(3).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned left"_ustr, aText.at(4).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(5).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(57.0, aRect.at(5).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned start"_ustr, aText.at(6).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(7).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(550.0, aRect.at(6).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned right"_ustr, aText.at(8).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(9).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(550.0, aRect.at(8).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned end"_ustr, aText.at(10).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(11).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(57.0, aRect.at(11).getMinX(), /*delta*/ 10.0); + + // Lines from the Edit Engine portion + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned left."_ustr, aText.at(12).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(99.0, aRect.at(12).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned start."_ustr, aText.at(13).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(99.0, aRect.at(13).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned right."_ustr, aText.at(14).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(537.0, aRect.at(14).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is LTR aligned end."_ustr, aText.at(15).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(537.0, aRect.at(15).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned left"_ustr, aText.at(16).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(17).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(99.0, aRect.at(17).getMinX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned start"_ustr, aText.at(18).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(19).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(537.0, aRect.at(18).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned right"_ustr, aText.at(20).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(21).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(537.0, aRect.at(20).getMaxX(), /*delta*/ 10.0); + + CPPUNIT_ASSERT_EQUAL(u"This paragraph is RTL aligned end"_ustr, aText.at(22).trim()); + CPPUNIT_ASSERT_EQUAL(u"."_ustr, aText.at(23).trim()); + CPPUNIT_ASSERT_DOUBLES_EQUAL(99.0, aRect.at(23).getMinX(), /*delta*/ 10.0); +} + } // end anonymous namespace CPPUNIT_PLUGIN_IMPLEMENT(); diff --git a/xmloff/qa/unit/uxmloff.cxx b/xmloff/qa/unit/uxmloff.cxx index cf888baa93fd..7f51e193f284 100644 --- a/xmloff/qa/unit/uxmloff.cxx +++ b/xmloff/qa/unit/uxmloff.cxx @@ -201,7 +201,10 @@ void Test::testMetaGenerator() { "CIB_OfficeDev/6.4.0.19$Linux_X86_64 LibreOffice_project/2e04f804b5f82770435f250873f07b3384d95504", ";6.4.0.19", SvXMLImport::LO_63x }, { "LibreOfficeDev/24.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/b81e7b6f3c71fb3ade1cb665444ac730dac0a9a9", ";24.2.0.0.", SvXMLImport::LO_242 }, { "LibreOfficeDev/24.8.6.2$Linux_X86_64 LibreOffice_project/dc6216c3d2b4ec3bcdba950f1e6ee1d013adb2d6", ";24.8.6.2", SvXMLImport::LO_248 }, - { "LibreOfficeDev/25.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/308705574842e0c36f7385f73fc47da9a4542367", ";25.8.0.0.", SvXMLImport::LO_New } + { "LibreOffice/25.2.6.2$Linux_X86_64 LibreOffice_project/520$Build-2", ";25.2.6.2", SvXMLImport::LO_252 }, + { "LibreOfficeDev/25.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/308705574842e0c36f7385f73fc47da9a4542367", ";25.8.0.0.", SvXMLImport::LO_258 }, + { "LibreOfficeDev/26.2.0.0.alpha0$Linux_X86_64 LibreOffice_project/d7e24df067ba6af0043e70750ad2b97e21201fa9", ";26.2.0.0.", SvXMLImport::LO_262 }, + { "LibreOfficeDev/26.8.0.0.alpha0$Linux_X86_64 LibreOffice_project/d7e24df067ba6af0043e70750ad2b97e21201fa9", ";26.8.0.0.", SvXMLImport::LO_New } }; for (auto const[pGenerator, pBuildId, nResult] : tests) diff --git a/xmloff/source/core/xmlimp.cxx b/xmloff/source/core/xmlimp.cxx index 3e1c26fced76..36aae86dc200 100644 --- a/xmloff/source/core/xmlimp.cxx +++ b/xmloff/source/core/xmlimp.cxx @@ -243,6 +243,18 @@ public: { mnGeneratorVersion = SvXMLImport::LO_248; } + else if (25 == year && month == 2) + { + mnGeneratorVersion = SvXMLImport::LO_252; + } + else if (25 == year && month == 8) + { + mnGeneratorVersion = SvXMLImport::LO_258; + } + else if (26 == year && month == 2) + { + mnGeneratorVersion = SvXMLImport::LO_262; + } else if (0 < year) { mnGeneratorVersion = SvXMLImport::LO_New; diff --git a/xmloff/source/style/adjushdl.cxx b/xmloff/source/style/adjushdl.cxx index 61878c720504..a37243c5e052 100644 --- a/xmloff/source/style/adjushdl.cxx +++ b/xmloff/source/style/adjushdl.cxx @@ -33,8 +33,8 @@ SvXMLEnumMapEntry<style::ParagraphAdjust> const pXML_Para_Adjust_Enum[] = { { XML_LEFT, style::ParagraphAdjust_LEFT }, { XML_RIGHT, style::ParagraphAdjust_RIGHT }, - { XML_START, style::ParagraphAdjust_LEFT }, - { XML_END, style::ParagraphAdjust_RIGHT }, + { XML_START, style::ParagraphAdjust_START }, + { XML_END, style::ParagraphAdjust_END }, { XML_CENTER, style::ParagraphAdjust_CENTER }, { XML_JUSTIFY, style::ParagraphAdjust_BLOCK }, { XML_JUSTIFIED, style::ParagraphAdjust_BLOCK }, // obsolete diff --git a/xmloff/source/style/xmlimppr.cxx b/xmloff/source/style/xmlimppr.cxx index ef4b2bb24513..5626da2e3c99 100644 --- a/xmloff/source/style/xmlimppr.cxx +++ b/xmloff/source/style/xmlimppr.cxx @@ -26,6 +26,7 @@ #include <com/sun/star/beans/TolerantPropertySetResultType.hpp> #include <com/sun/star/beans/XTolerantMultiPropertySet.hpp> #include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/style/ParagraphAdjust.hpp> #include <sal/log.hxx> #include <osl/diagnose.h> #include <utility> @@ -231,6 +232,34 @@ void SvXMLImportPropertyMapper::importXMLAttribute( // let the XMLPropertySetMapper decide how to import the value bSet = maPropMapper->importXML( sValue, aNewProperty, rUnitConverter ); + + // tdf#37128: Older versions of LO stored fo:text-align incorrectly. + // Remap the buggy values during parsing. + if (bSet + && GetImport().isGeneratorVersionOlderThan(SvXMLImport::AOO_4x, + SvXMLImport::LO_262) + && rAttrName == u"fo:text-align"_ustr) + { + if (sal_Int16 nTmp; aNewProperty.maValue >>= nTmp) + { + css::style::ParagraphAdjust eAdjust{ nTmp }; + switch (eAdjust) + { + case css::style::ParagraphAdjust_START: + eAdjust = css::style::ParagraphAdjust_LEFT; + break; + + case css::style::ParagraphAdjust_END: + eAdjust = css::style::ParagraphAdjust_RIGHT; + break; + + default: + break; + } + + aNewProperty.maValue <<= static_cast<sal_Int16>(eAdjust); + } + } } else {
