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 5a48070f59
"tdf#126154 sw offapi xmloff cui: add min/max word spacing",
and commit 7d6696757d
"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 <nemeth@numbertext.org>
Tested-by: Jenkins
This commit is contained in:
László Németh
2025-05-13 09:45:26 +02:00
parent 7b31b1a582
commit 7d4ad3fa74
7 changed files with 64 additions and 1 deletions
Binary file not shown.
@@ -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");
+5 -1
View File
@@ -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 &&
@@ -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;
@@ -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);
}
@@ -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},
@@ -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