tdf#142404 DOCX c15: add compat flag TabOverSpacing
DOCX in 2013 (compatibilityMode 15) no longer supports TabOverMargin (i.e. the text margin), but it does a similar kind of thing if the tab goes into the spacing-after of a paragraph. So add a compat flag to handle this in-between kind of situation. I grepped -i "tab_*over_*margin" to see if I was missing anything. Decimal/Center proved to be only tabOverMargin. IsInSect shouldn't matter since it fits inside the printing range. The other places where I didn't insert TabOverSpacing didn't seem relevant based on a code read. Tab-after-tab still doesn't work great, but what we have is already a massive house of cards that will just collapse if changed. No real provision for handling tabs-over-paragraph-end. -auto-tabs are created instead of "beyond nMyRight" tab, unless it is the first tab defined. -doesn't allow auto-tabs to fill the remaining space. But on the other hand, MS Word's implementation of tabs follows some kind of incomprehensible bizarre logic, so just ignore the tabs completely, please. Change-Id: I3723107b29ec3e287ea8661544711c13eee3ca48 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/116667 Tested-by: Jenkins Reviewed-by: Justin Luth <justin_luth@sil.org> Reviewed-by: Miklos Vajna <vmiklos@collabora.com>
This commit is contained in:
committed by
Miklos Vajna
parent
c4c8202359
commit
a2d8a737f4
@@ -82,6 +82,7 @@ enum class DocumentSettingId
|
||||
CLIPPED_PICTURES,
|
||||
BACKGROUND_PARA_OVER_DRAWINGS,
|
||||
TAB_OVER_MARGIN,
|
||||
TAB_OVER_SPACING,
|
||||
// MS Word still wraps text around objects with less space than LO would.
|
||||
SURROUND_TEXT_WRAP_SMALL,
|
||||
PROP_LINE_SPACING_SHRINKS_FIRST_LINE,
|
||||
|
BIN
sw/qa/extras/ooxmlexport/data/tdf142404_tabOverSpacingC15.odt
Normal file
BIN
sw/qa/extras/ooxmlexport/data/tdf142404_tabOverSpacingC15.odt
Normal file
Binary file not shown.
@@ -226,6 +226,24 @@ DECLARE_OOXMLEXPORT_TEST(testTdf142404_tabOverMarginC15, "tdf142404_tabOverMargi
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for one page", 2, getPages());
|
||||
}
|
||||
|
||||
DECLARE_OOXMLEXPORT_EXPORTONLY_TEST(testTdf142404_tabOverSpacingC15, "tdf142404_tabOverSpacingC15.odt")
|
||||
{
|
||||
// Although TabOverMargin no longer applies to compatibilityMode 15 DOCX files,
|
||||
// it still applies to a tab over the paragraph end (inside text boundaries).
|
||||
// The original 3-page ODT saved as DOCX would fit on one page in MS Word 2010, but 3 in Word 2013.
|
||||
CPPUNIT_ASSERT_EQUAL_MESSAGE("too big for two pages", 3, getPages());
|
||||
// The tab goes over the paragraph margin
|
||||
CPPUNIT_ASSERT_EQUAL(OUString("A left tab positioned at"), parseDump("//page[1]/body/txt[2]/Text[1]", "Portion"));
|
||||
sal_Int32 nTextLen = parseDump("//page[1]/body/txt[2]/Text[1]", "nWidth").toInt32();
|
||||
CPPUNIT_ASSERT_EQUAL(OUString("*"), parseDump("//page[1]/body/txt[2]/Text[2]", "Portion"));
|
||||
sal_Int32 nTabLen = parseDump("//page[1]/body/txt[2]/Text[2]", "nWidth").toInt32();
|
||||
CPPUNIT_ASSERT_MESSAGE("Large left tab", nTextLen < nTabLen);
|
||||
// Not 1 line high (Word 2010 DOCX), or 3 lines high (LO DOCX) or 5 lines high (ODT), but 4 lines high
|
||||
sal_Int32 nHeight = parseDump("//page[1]/body/txt[2]/infos/bounds", "height").toInt32();
|
||||
CPPUNIT_ASSERT_MESSAGE("4 lines high", 1100 < nHeight);
|
||||
CPPUNIT_ASSERT_MESSAGE("4 lines high", nHeight < 1300);
|
||||
}
|
||||
|
||||
DECLARE_OOXMLEXPORT_TEST(testTdf139580, "tdf139580.odt")
|
||||
{
|
||||
// Without the fix in place, this test would have crashed at export time
|
||||
|
@@ -90,6 +90,7 @@ sw::DocumentSettingManager::DocumentSettingManager(SwDoc &rDoc)
|
||||
mbClippedPictures(false),
|
||||
mbBackgroundParaOverDrawings(false),
|
||||
mbTabOverMargin(false),
|
||||
mbTabOverSpacing(false),
|
||||
mbTreatSingleColumnBreakAsPageBreak(false),
|
||||
mbSurroundTextWrapSmall(false),
|
||||
mbPropLineSpacingShrinksFirstLine(true),
|
||||
@@ -204,6 +205,7 @@ bool sw::DocumentSettingManager::get(/*[in]*/ DocumentSettingId id) const
|
||||
case DocumentSettingId::CLIPPED_PICTURES: return mbClippedPictures;
|
||||
case DocumentSettingId::BACKGROUND_PARA_OVER_DRAWINGS: return mbBackgroundParaOverDrawings;
|
||||
case DocumentSettingId::TAB_OVER_MARGIN: return mbTabOverMargin;
|
||||
case DocumentSettingId::TAB_OVER_SPACING: return mbTabOverSpacing;
|
||||
case DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK: return mbTreatSingleColumnBreakAsPageBreak;
|
||||
case DocumentSettingId::SURROUND_TEXT_WRAP_SMALL: return mbSurroundTextWrapSmall;
|
||||
case DocumentSettingId::PROP_LINE_SPACING_SHRINKS_FIRST_LINE: return mbPropLineSpacingShrinksFirstLine;
|
||||
@@ -390,6 +392,10 @@ void sw::DocumentSettingManager::set(/*[in]*/ DocumentSettingId id, /*[in]*/ boo
|
||||
mbTabOverMargin = value;
|
||||
break;
|
||||
|
||||
case DocumentSettingId::TAB_OVER_SPACING:
|
||||
mbTabOverSpacing = value;
|
||||
break;
|
||||
|
||||
case DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK:
|
||||
mbTreatSingleColumnBreakAsPageBreak = value;
|
||||
break;
|
||||
@@ -659,6 +665,7 @@ void sw::DocumentSettingManager::ReplaceCompatibilityOptions(const DocumentSetti
|
||||
mbClippedPictures = rSource.mbClippedPictures;
|
||||
mbBackgroundParaOverDrawings = rSource.mbBackgroundParaOverDrawings;
|
||||
mbTabOverMargin = rSource.mbTabOverMargin;
|
||||
mbTabOverSpacing = rSource.mbTabOverSpacing;
|
||||
mbTreatSingleColumnBreakAsPageBreak = rSource.mbTreatSingleColumnBreakAsPageBreak;
|
||||
mbSurroundTextWrapSmall = rSource.mbSurroundTextWrapSmall;
|
||||
mbPropLineSpacingShrinksFirstLine = rSource.mbPropLineSpacingShrinksFirstLine;
|
||||
@@ -928,6 +935,11 @@ void sw::DocumentSettingManager::dumpAsXml(xmlTextWriterPtr pWriter) const
|
||||
BAD_CAST(OString::boolean(mbTabOverMargin).getStr()));
|
||||
(void)xmlTextWriterEndElement(pWriter);
|
||||
|
||||
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbTabOverSpacing"));
|
||||
(void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("value"),
|
||||
BAD_CAST(OString::boolean(mbTabOverSpacing).getStr()));
|
||||
(void)xmlTextWriterEndElement(pWriter);
|
||||
|
||||
(void)xmlTextWriterStartElement(pWriter, BAD_CAST("mbTreatSingleColumnBreakAsPageBreak"));
|
||||
(void)xmlTextWriterWriteAttribute(
|
||||
pWriter, BAD_CAST("value"),
|
||||
|
@@ -153,6 +153,7 @@ class DocumentSettingManager final :
|
||||
bool mbClippedPictures;
|
||||
bool mbBackgroundParaOverDrawings;
|
||||
bool mbTabOverMargin;
|
||||
bool mbTabOverSpacing;
|
||||
bool mbTreatSingleColumnBreakAsPageBreak; // tdf#76349
|
||||
bool mbSurroundTextWrapSmall;
|
||||
bool mbPropLineSpacingShrinksFirstLine; // fdo#79602
|
||||
|
@@ -1761,7 +1761,9 @@ SwTwips SwTextFormatInfo::GetLineWidth()
|
||||
|
||||
const bool bTabOverMargin = GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
|
||||
DocumentSettingId::TAB_OVER_MARGIN);
|
||||
if (!bTabOverMargin)
|
||||
const bool bTabOverSpacing = GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
|
||||
DocumentSettingId::TAB_OVER_SPACING);
|
||||
if (!bTabOverMargin && !bTabOverSpacing)
|
||||
return nLineWidth;
|
||||
|
||||
SwTabPortion* pLastTab = GetLastTab();
|
||||
@@ -1792,6 +1794,12 @@ SwTwips SwTextFormatInfo::GetLineWidth()
|
||||
// text frame area to the right (RR above, but not LL).
|
||||
nLineWidth = nTextFrameWidth - X();
|
||||
|
||||
if (!bTabOverMargin) // thus bTabOverSpacing only
|
||||
{
|
||||
// right, center, decimal can back-fill all the available space - same as TabOverMargin
|
||||
if (pLastTab->GetWhichPor() == PortionType::TabLeft)
|
||||
nLineWidth = nTextFrameWidth - pLastTab->GetTabPos();
|
||||
}
|
||||
return nLineWidth;
|
||||
}
|
||||
|
||||
|
@@ -1223,7 +1223,9 @@ void SwTextCursor::GetCharRect( SwRect* pOrig, TextFrameIndex const nOfst,
|
||||
pCMS->m_x2Lines->aPortion.Pos().AdjustY(aCharPos.Y() );
|
||||
}
|
||||
|
||||
const bool bTabOverMargin = GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_MARGIN);
|
||||
const IDocumentSettingAccess& rIDSA = GetTextFrame()->GetDoc().getIDocumentSettingAccess();
|
||||
const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN)
|
||||
|| rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
|
||||
// Make sure the cursor respects the right margin, unless in compat mode, where the tab size has priority over the margin size.
|
||||
if( pOrig->Left() > nTmpRight && !bTabOverMargin)
|
||||
pOrig->Pos().setX( nTmpRight );
|
||||
|
@@ -329,6 +329,7 @@ bool SwTabPortion::PreFormat( SwTextFormatInfo &rInf )
|
||||
const bool bTabCompat = rIDSA.get(DocumentSettingId::TAB_COMPAT);
|
||||
const bool bTabOverflow = rIDSA.get(DocumentSettingId::TAB_OVERFLOW);
|
||||
const bool bTabOverMargin = rIDSA.get(DocumentSettingId::TAB_OVER_MARGIN);
|
||||
const bool bTabOverSpacing = rIDSA.get(DocumentSettingId::TAB_OVER_SPACING);
|
||||
|
||||
// The minimal width of a tab is one blank at least.
|
||||
// #i37686# In compatibility mode, the minimum width
|
||||
@@ -381,10 +382,13 @@ bool SwTabPortion::PreFormat( SwTextFormatInfo &rInf )
|
||||
case PortionType::TabLeft:
|
||||
{
|
||||
// handle this case in PostFormat
|
||||
if( bTabOverMargin && !m_bAutoTabStop && GetTabPos() > rInf.Width() )
|
||||
if ((bTabOverMargin || bTabOverSpacing) && !m_bAutoTabStop && GetTabPos() > rInf.Width())
|
||||
{
|
||||
rInf.SetLastTab( this );
|
||||
break;
|
||||
if (bTabOverMargin || GetTabPos() < rInf.GetTextFrame()->getFrameArea().Width())
|
||||
{
|
||||
rInf.SetLastTab(this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PrtWidth( o3tl::narrowing<sal_uInt16>(GetTabPos() - rInf.X()) );
|
||||
@@ -443,13 +447,19 @@ bool SwTabPortion::PostFormat( SwTextFormatInfo &rInf )
|
||||
{
|
||||
bool bTabOverMargin = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
|
||||
DocumentSettingId::TAB_OVER_MARGIN);
|
||||
|
||||
bool bTabOverSpacing = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(
|
||||
DocumentSettingId::TAB_OVER_SPACING);
|
||||
if (rInf.GetTextFrame()->IsInSct())
|
||||
bTabOverMargin = false;
|
||||
|
||||
// If the tab position is larger than the right margin, it gets scaled down by default.
|
||||
// However, if compat mode enabled, we allow tabs to go over the margin: the rest of the paragraph is not broken into lines.
|
||||
const sal_uInt16 nRight = bTabOverMargin ? GetTabPos() : std::min(GetTabPos(), rInf.Width());
|
||||
const sal_uInt16 nRight
|
||||
= bTabOverMargin
|
||||
? GetTabPos()
|
||||
: bTabOverSpacing
|
||||
? std::min<long>(GetTabPos(), rInf.GetTextFrame()->getFrameArea().Right())
|
||||
: std::min(GetTabPos(), rInf.Width());
|
||||
const SwLinePortion *pPor = GetNextPortion();
|
||||
|
||||
sal_uInt16 nPorWidth = 0;
|
||||
@@ -462,7 +472,7 @@ bool SwTabPortion::PostFormat( SwTextFormatInfo &rInf )
|
||||
const PortionType nWhich = GetWhichPor();
|
||||
const bool bTabCompat = rInf.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::TAB_COMPAT);
|
||||
|
||||
if ( bTabOverMargin && PortionType::TabLeft == nWhich )
|
||||
if ((bTabOverMargin || bTabOverSpacing) && PortionType::TabLeft == nWhich)
|
||||
{
|
||||
nPorWidth = 0;
|
||||
}
|
||||
|
@@ -134,6 +134,7 @@ enum SwDocumentSettingsPropertyHandles
|
||||
HANDLE_EMBED_COMPLEX_SCRIPT_FONTS,
|
||||
HANDLE_EMBED_SYSTEM_FONTS,
|
||||
HANDLE_TAB_OVER_MARGIN,
|
||||
HANDLE_TAB_OVER_SPACING,
|
||||
HANDLE_TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK,
|
||||
HANDLE_SURROUND_TEXT_WRAP_SMALL,
|
||||
HANDLE_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING,
|
||||
@@ -228,6 +229,7 @@ static rtl::Reference<MasterPropertySetInfo> lcl_createSettingsInfo()
|
||||
{ OUString("EmbedComplexScriptFonts"), HANDLE_EMBED_COMPLEX_SCRIPT_FONTS, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("EmbedSystemFonts"), HANDLE_EMBED_SYSTEM_FONTS, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("TabOverMargin"), HANDLE_TAB_OVER_MARGIN, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("TabOverSpacing"), HANDLE_TAB_OVER_SPACING, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("TreatSingleColumnBreakAsPageBreak"), HANDLE_TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("SurroundTextWrapSmall"), HANDLE_SURROUND_TEXT_WRAP_SMALL, cppu::UnoType<bool>::get(), 0},
|
||||
{ OUString("ApplyParagraphMarkFormatToNumbering"), HANDLE_APPLY_PARAGRAPH_MARK_FORMAT_TO_NUMBERING, cppu::UnoType<bool>::get(), 0},
|
||||
@@ -894,6 +896,12 @@ void SwXDocumentSettings::_setSingleValue( const comphelper::PropertyInfo & rInf
|
||||
mpDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_MARGIN, bTmp);
|
||||
}
|
||||
break;
|
||||
case HANDLE_TAB_OVER_SPACING:
|
||||
{
|
||||
bool bTmp = *o3tl::doAccess<bool>(rValue);
|
||||
mpDoc->getIDocumentSettingAccess().set(DocumentSettingId::TAB_OVER_SPACING, bTmp);
|
||||
}
|
||||
break;
|
||||
case HANDLE_TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK:
|
||||
{
|
||||
bool bTmp = *o3tl::doAccess<bool>(rValue);
|
||||
@@ -1441,6 +1449,11 @@ void SwXDocumentSettings::_getSingleValue( const comphelper::PropertyInfo & rInf
|
||||
rValue <<= mpDoc->getIDocumentSettingAccess().get( DocumentSettingId::TAB_OVER_MARGIN );
|
||||
}
|
||||
break;
|
||||
case HANDLE_TAB_OVER_SPACING:
|
||||
{
|
||||
rValue <<= mpDoc->getIDocumentSettingAccess().get(DocumentSettingId::TAB_OVER_SPACING);
|
||||
}
|
||||
break;
|
||||
case HANDLE_TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK:
|
||||
{
|
||||
rValue <<= mpDoc->getIDocumentSettingAccess().get( DocumentSettingId::TREAT_SINGLE_COLUMN_BREAK_AS_PAGE_BREAK );
|
||||
|
@@ -319,6 +319,11 @@ void WriterFilter::setTargetDocument(const uno::Reference<lang::XComponent>& xDo
|
||||
xSettings->setPropertyValue("InvertBorderSpacing", uno::makeAny(true));
|
||||
xSettings->setPropertyValue("CollapseEmptyCellPara", uno::makeAny(true));
|
||||
xSettings->setPropertyValue("TabOverflow", uno::makeAny(true));
|
||||
// tdf#142404 TabOverSpacing (new for compatiblityMode15/Word2013+) is a subset of TabOverMargin
|
||||
// (which applied to DOCX <= compatibilityMode14).
|
||||
// TabOverMargin looks at tabs beyond the normal text area,
|
||||
// while TabOverSpacing only refers to a tab beyond the paragraph margin.
|
||||
xSettings->setPropertyValue("TabOverSpacing", uno::makeAny(true));
|
||||
xSettings->setPropertyValue("UnbreakableNumberings", uno::makeAny(true));
|
||||
|
||||
xSettings->setPropertyValue("FloattableNomargins", uno::makeAny(true));
|
||||
|
Reference in New Issue
Block a user