sw/qa/extras/ooxmlexport/data/tdf155707.docx    |binary
 sw/qa/extras/ooxmlexport/ooxmlexport14.cxx      |   12 ++++++++++++
 sw/source/core/text/portxt.cxx                  |    6 +++++-
 sw/source/filter/ww8/docxattributeoutput.cxx    |   19 +++++++++++++++++++
 sw/source/writerfilter/dmapper/DomainMapper.cxx |   22 ++++++++++++++++++++++
 sw/source/writerfilter/dmapper/PropertyIds.cxx  |    3 +++
 sw/source/writerfilter/dmapper/PropertyIds.hxx  |    3 +++
 7 files changed, 64 insertions(+), 1 deletion(-)

New commits:
commit 7d4ad3fa74674fff06f52eec0abc8dc7691a89b4
Author:     László Németh <nem...@numbertext.org>
AuthorDate: Mon May 12 20:29:47 2025 +0200
Commit:     László Németh <nem...@numbertext.org>
CommitDate: Tue May 13 09:45:26 2025 +0200

    tdf#155707 sw DOCX: fix Kashida justification import/export/layout
    
    Fix missing import/export of DOCX w:jc=lowKashida/mediumKashida/
    highKashida justification settings. Add visualization support
    using 133%, 200% and 300% word spacing for them.
    
    Kashida justification allows typesetting less compressed Arabic text,
    but this layout lost in Writer, also lost in DOCX/Word completely at
    DOCX export of Writer (the settings weren't grab-bagged).
    
    Note: instead of grab-bagging (which applied only at table properties
    yet in the case of w:jc), these minimum = desired = maximum word spacing
    values carry the Kashida justification setting. (DOCX cannot support
    custom word spacing, so this doesn't interfere with the other settings.)
    
    Follow-up to commit 5a48070f5904c51dc9e7bbad4213d802fd4bc89b
    "tdf#126154 sw offapi xmloff cui: add min/max word spacing",
    and commit 7d6696757dcdfa3cee481ac7795a91b2b47da363
    "tdf#159923 sw cui offapi xmloff: add custom word spacing".
    
    Change-Id: Icc41a69742ae604d091c6429441261742fe6f763
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/185233
    Reviewed-by: László Németh <nem...@numbertext.org>
    Tested-by: Jenkins

diff --git a/sw/qa/extras/ooxmlexport/data/tdf155707.docx 
b/sw/qa/extras/ooxmlexport/data/tdf155707.docx
new file mode 100644
index 000000000000..47c4d4664c56
Binary files /dev/null and b/sw/qa/extras/ooxmlexport/data/tdf155707.docx differ
diff --git a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx 
b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
index f8293de0e2c5..3f0b7fb53d54 100644
--- a/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
+++ b/sw/qa/extras/ooxmlexport/ooxmlexport14.cxx
@@ -757,6 +757,18 @@ DECLARE_OOXMLEXPORT_TEST(testTdf161628, 
"tdf132599_frames_on_right_pages_no_hyph
     CPPUNIT_ASSERT_EQUAL( static_cast<sal_Int16>(0), 
getProperty<sal_Int16>(xStyle, u"ParaHyphenationZone"_ustr));
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testTdf155707)
+{
+    loadAndSave("tdf155707.docx");
+
+    xmlDocUniquePtr pXmlDoc = parseExport(u"word/document.xml"_ustr);
+    CPPUNIT_ASSERT(pXmlDoc);
+    // Without the accompanying fix in place, this test would have failed
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p[13]/w:pPr/w:jc", "val", 
u"lowKashida");
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p[15]/w:pPr/w:jc", "val", 
u"mediumKashida");
+    assertXPath(pXmlDoc, "/w:document/w:body/w:p[17]/w:pPr/w:jc", "val", 
u"highKashida");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf161643)
 {
     loadAndSave("fdo76163.docx");
diff --git a/sw/source/core/text/portxt.cxx b/sw/source/core/text/portxt.cxx
index 7ee01437ebf3..be365fef2d64 100644
--- a/sw/source/core/text/portxt.cxx
+++ b/sw/source/core/text/portxt.cxx
@@ -369,7 +369,11 @@ bool SwTextPortion::Format_( SwTextFormatInfo &rInf )
          pGuess->BreakPos() != TextFrameIndex(COMPLETE_STRING);
     bool bInteropSmartJustify = bFullJustified &&
             rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
-                    DocumentSettingId::JUSTIFY_LINES_WITH_SHRINKING);
+                    DocumentSettingId::JUSTIFY_LINES_WITH_SHRINKING) &&
+                    // support different Kashida etc. values
+                    aAdjustItem.GetPropWordSpacing() == 100 &&
+                    aAdjustItem.GetPropWordSpacingMinimum() == 100 &&
+                    aAdjustItem.GetPropWordSpacingMaximum() == 100;
     bool bWordSpacing = bFullJustified && !bInteropSmartJustify &&
            aAdjustItem.GetPropWordSpacing() != 100;
     bool bWordSpacingMaximum = bFullJustified && !bInteropSmartJustify &&
diff --git a/sw/source/filter/ww8/docxattributeoutput.cxx 
b/sw/source/filter/ww8/docxattributeoutput.cxx
index 899d6fdbf5dc..8e9177170c7f 100644
--- a/sw/source/filter/ww8/docxattributeoutput.cxx
+++ b/sw/source/filter/ww8/docxattributeoutput.cxx
@@ -9076,11 +9076,30 @@ void DocxAttributeOutput::ParaAdjust( const 
SvxAdjustItem& rAdjust )
             break;
         case SvxAdjust::BlockLine:
         case SvxAdjust::Block:
+        {
             if (rAdjust.GetLastBlock() == SvxAdjust::Block)
                 pAdjustString = "distribute";
             else
                 pAdjustString = "both";
+            switch ( rAdjust.GetPropWordSpacingMinimum() )
+            {
+                case 133:
+                    if ( rAdjust.GetPropWordSpacingMaximum() == 133 )
+                        pAdjustString = "lowKashida";
+                    break;
+                case 200:
+                    if ( rAdjust.GetPropWordSpacingMaximum() == 200 )
+                        pAdjustString = "mediumKashida";
+                    break;
+                case 300:
+                    if ( rAdjust.GetPropWordSpacingMaximum() == 300 )
+                        pAdjustString = "highKashida";
+                    break;
+                default:
+                    break;
+            }
             break;
+        }
         case SvxAdjust::Center:
             pAdjustString = "center";
             break;
diff --git a/sw/source/writerfilter/dmapper/DomainMapper.cxx 
b/sw/source/writerfilter/dmapper/DomainMapper.cxx
index a1018b9c65c1..fc8cc458a262 100644
--- a/sw/source/writerfilter/dmapper/DomainMapper.cxx
+++ b/sw/source/writerfilter/dmapper/DomainMapper.cxx
@@ -4880,6 +4880,7 @@ void DomainMapper::handleParaJustification(const 
sal_Int32 nIntValue, const ::to
     style::ParagraphAdjust nAdjust = style::ParagraphAdjust_LEFT;
     style::ParagraphAdjust nLastLineAdjust = style::ParagraphAdjust_LEFT;
     OUString aStringValue = u"left"_ustr;
+    sal_uInt16 nWordSpacing = 100;
     switch(nIntValue)
     {
     case NS_ooxml::LN_Value_ST_Jc_center:
@@ -4898,6 +4899,21 @@ void DomainMapper::handleParaJustification(const 
sal_Int32 nIntValue, const ::to
         nAdjust = style::ParagraphAdjust_BLOCK;
         aStringValue = "both";
         break;
+    case NS_ooxml::LN_Value_ST_Jc_lowKashida:
+        nAdjust = style::ParagraphAdjust_BLOCK;
+        // modify this value also in 
sw/source/filter/ww8/docxattributeoutput.cxx
+        nWordSpacing = 133;
+        break;
+    case NS_ooxml::LN_Value_ST_Jc_mediumKashida:
+        nAdjust = style::ParagraphAdjust_BLOCK;
+        // modify this value also in 
sw/source/filter/ww8/docxattributeoutput.cxx
+        nWordSpacing = 200;
+        break;
+    case NS_ooxml::LN_Value_ST_Jc_highKashida:
+        nAdjust = style::ParagraphAdjust_BLOCK;
+        // modify this value also in 
sw/source/filter/ww8/docxattributeoutput.cxx
+        nWordSpacing = 300;
+        break;
     case NS_ooxml::LN_Value_ST_Jc_left:
     case NS_ooxml::LN_Value_ST_Jc_start:
     default:
@@ -4906,6 +4922,12 @@ void DomainMapper::handleParaJustification(const 
sal_Int32 nIntValue, const ::to
     }
     rContext->Insert( PROP_PARA_ADJUST, uno::Any( nAdjust ) );
     rContext->Insert( PROP_PARA_LAST_LINE_ADJUST, uno::Any( nLastLineAdjust ) 
);
+    if ( nWordSpacing > 100 )
+    {
+        rContext->Insert( PROP_PARA_WORD_SPACING, uno::Any( nWordSpacing ) );
+        rContext->Insert( PROP_PARA_WORD_SPACING_MINIMUM, uno::Any( 
nWordSpacing ) );
+        rContext->Insert( PROP_PARA_WORD_SPACING_MAXIMUM, uno::Any( 
nWordSpacing ) );
+    }
     m_pImpl->appendGrabBag(m_pImpl->m_aInteropGrabBag, u"jc"_ustr, 
aStringValue);
 }
 
diff --git a/sw/source/writerfilter/dmapper/PropertyIds.cxx 
b/sw/source/writerfilter/dmapper/PropertyIds.cxx
index 1049295a4aec..b3ca6ce2d6fa 100644
--- a/sw/source/writerfilter/dmapper/PropertyIds.cxx
+++ b/sw/source/writerfilter/dmapper/PropertyIds.cxx
@@ -123,6 +123,9 @@ const OUString & getPropertyName( PropertyIds eId )
         { PROP_PARA_RIGHT_BORDER_DISTANCE, u"ParaRightBorderDistance"_ustr},
         { PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR, 
u"ParaRightBorderComplexColor"_ustr},
         { PROP_PARA_WIDOWS, u"ParaWidows"_ustr},
+        { PROP_PARA_WORD_SPACING, u"ParaWordSpacing"_ustr},
+        { PROP_PARA_WORD_SPACING_MAXIMUM, u"ParaWordSpacingMaximum"_ustr},
+        { PROP_PARA_WORD_SPACING_MINIMUM, u"ParaWordSpacingMinimum"_ustr},
         { PROP_PARA_ORPHANS, u"ParaOrphans"_ustr},
         { PROP_PARA_LINE_NUMBER_START_VALUE, u"ParaLineNumberStartValue"_ustr},
         { PROP_NUMBERING_LEVEL, u"NumberingLevel"_ustr},
diff --git a/sw/source/writerfilter/dmapper/PropertyIds.hxx 
b/sw/source/writerfilter/dmapper/PropertyIds.hxx
index f9d5cb52806f..80dcafcb8501 100644
--- a/sw/source/writerfilter/dmapper/PropertyIds.hxx
+++ b/sw/source/writerfilter/dmapper/PropertyIds.hxx
@@ -280,6 +280,9 @@ enum PropertyIds
         ,PROP_PARA_RIGHT_BORDER_DISTANCE
         ,PROP_PARA_BORDER_RIGHT_COMPLEX_COLOR
         ,PROP_PARA_WIDOWS
+        ,PROP_PARA_WORD_SPACING
+        ,PROP_PARA_WORD_SPACING_MAXIMUM
+        ,PROP_PARA_WORD_SPACING_MINIMUM
         ,PROP_PAPER_TRAY
         ,PROP_PARENT_NUMBERING
         ,PROP_POSITION_AND_SPACE_MODE

Reply via email to