tdf#97128 DOCX import: fix frame direction
Frames used to be imported with zero rotation even if a w:textDirection
tag explicitly called for a non-default orientation.
I found no other solution to pass the incoming frame direction property
on to the SwXFrame about to be created.
1. If you put the property into the GetSectionContext(), it gets
overwritten when the next w:pPr tag is parsed, so all three frames will
end up having the same direction.
2. If you put the property into the GetTopContextOfType(CONTEXT_PARAGRAPH)
that context gets popped off the stack before control even gets to
CheckUnregisteredFrameConversion().
3. If you use PushStyleSheetProperties (which is bad in and of itself),
the order will be messed up because the frames are not necessarily
created in the same order as they are described in the file, so each
frame gets a wrong frame direction in the end.
Follow-up of commit 5a5597655a4bf12e4ca07c9c2b6f6221e217f080
(tentative fix for fdo#30474# [DOCX rotated text import failure]).
Change-Id: I6e3d68fe60c6e2a5b6684c65a964dd86d0168181
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/103553
Tested-by: Jenkins
Reviewed-by: László Németh <nemeth@numbertext.org>
diff --git a/sw/source/core/unocore/unoframe.cxx b/sw/source/core/unocore/unoframe.cxx
index e8461393..a73b8e7 100644
--- a/sw/source/core/unocore/unoframe.cxx
+++ b/sw/source/core/unocore/unoframe.cxx
@@ -1402,6 +1402,23 @@ void SwXFrame::setPropertyValue(const OUString& rPropertyName, const ::uno::Any&
{
SolarMutexGuard aGuard;
SwFrameFormat* pFormat = GetFrameFormat();
// Hack to support hidden property to transfer textDirection
if(rPropertyName == "FRMDirection")
{
if (pFormat)
{
SvxFrameDirectionItem aItem(SvxFrameDirection::Environment, RES_FRAMEDIR);
aItem.PutValue(_rValue, 0);
GetFrameFormat()->SetFormatAttr(aItem);
}
else if(IsDescriptor())
{
m_pProps->SetProperty(static_cast<sal_uInt16>(RES_FRAMEDIR), 0, _rValue);
}
return;
}
const ::SfxItemPropertySimpleEntry* pEntry = m_pPropSet->getPropertyMap().getByName(rPropertyName);
if (!pEntry)
diff --git a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
index 893db16..de63ec4 100644
--- a/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/qa/cppunittests/dmapper/DomainMapper_Impl.cxx
@@ -14,6 +14,8 @@
#include <com/sun/star/text/XTextDocument.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/style/BreakType.hpp>
#include <com/sun/star/drawing/XDrawPageSupplier.hpp>
#include <com/sun/star/text/WritingMode2.hpp>
using namespace ::com::sun::star;
@@ -104,6 +106,25 @@ CPPUNIT_TEST_FIXTURE(Test, testNumberingRestartStyleParent)
xPara.set(xParaEnum->nextElement(), uno::UNO_QUERY);
CPPUNIT_ASSERT_EQUAL(OUString("2."), xPara->getPropertyValue(aProp).get<OUString>());
}
CPPUNIT_TEST_FIXTURE(Test, testFrameDirection)
{
OUString aURL = m_directories.getURLFromSrc(DATA_DIRECTORY) + "frame-direction.docx";
getComponent() = loadFromDesktop(aURL);
uno::Reference<drawing::XDrawPageSupplier> xDrawPageSupplier(getComponent(), uno::UNO_QUERY);
uno::Reference<container::XIndexAccess> xDrawPage = xDrawPageSupplier->getDrawPage();
uno::Reference<beans::XPropertySet> xFrame0(xDrawPage->getByIndex(0), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFrame1(xDrawPage->getByIndex(1), uno::UNO_QUERY);
uno::Reference<beans::XPropertySet> xFrame2(xDrawPage->getByIndex(2), uno::UNO_QUERY);
// Without the accompanying fix in place, all of the following values would be text::WritingMode2::CONTEXT
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::CONTEXT,
xFrame0->getPropertyValue("WritingMode").get<sal_Int16>());
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::BT_LR,
xFrame1->getPropertyValue("WritingMode").get<sal_Int16>());
CPPUNIT_ASSERT_EQUAL(text::WritingMode2::TB_RL,
xFrame2->getPropertyValue("WritingMode").get<sal_Int16>());
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx b/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx
new file mode 100644
index 0000000..33f191e
--- /dev/null
+++ b/writerfilter/qa/cppunittests/dmapper/data/frame-direction.docx
Binary files differ
diff --git a/writerfilter/source/dmapper/DomainMapper.cxx b/writerfilter/source/dmapper/DomainMapper.cxx
index b3faa56..ca118c0 100644
--- a/writerfilter/source/dmapper/DomainMapper.cxx
+++ b/writerfilter/source/dmapper/DomainMapper.cxx
@@ -1501,6 +1501,35 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
}
break;
case NS_ooxml::LN_CT_PPrBase_textDirection:
{
switch (nIntValue)
{
case NS_ooxml::LN_Value_ST_TextDirection_tbRl:
{
m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_btLr:
{
m_pImpl->SetFrameDirection(text::WritingMode2::BT_LR);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_lrTbV:
{
m_pImpl->SetFrameDirection(text::WritingMode2::LR_TB);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_tbRlV:
{
m_pImpl->SetFrameDirection(text::WritingMode2::TB_RL);
break;
}
case NS_ooxml::LN_Value_ST_TextDirection_lrTb:
case NS_ooxml::LN_Value_ST_TextDirection_tbLrV:
default:
SAL_WARN("writerfilter", "DomainMapper::sprmWithProps: unhandled textDirection");
}
}
break;
case NS_ooxml::LN_CT_PPrBase_outlineLvl:
{
@@ -2088,6 +2117,7 @@ void DomainMapper::sprmWithProps( Sprm& rSprm, const PropertyMapPtr& rContext )
{
//TODO: What about style sheet import of frame properties
}
m_pImpl->NewFrameDirection();
resolveSprmProps(*this, rSprm);
}
break;
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.cxx b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
index cd78ab3..2fcd6ba 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.cxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.cxx
@@ -1155,6 +1155,11 @@ void DomainMapper_Impl::CheckUnregisteredFrameConversion( )
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_WIDTH_TYPE), bAutoWidth ? text::SizeType::MIN : text::SizeType::FIX));
if (const std::optional<sal_Int16> nDirection = PopFrameDirection())
{
aFrameProperties.push_back(comphelper::makePropertyValue(getPropertyName(PROP_FRM_DIRECTION), *nDirection));
}
sal_Int16 nHoriOrient = sal_Int16(
rAppendContext.pLastParagraphProperties->GetxAlign() >= 0 ?
rAppendContext.pLastParagraphProperties->GetxAlign() :
@@ -1538,7 +1543,6 @@ void DomainMapper_Impl::finishParagraph( const PropertyMapPtr& pPropertyMap, con
if ( hasTableManager() && getTableManager().isInCell() )
getTableManager().setCellLastParaAfterAutospacing( bApplyAutospacing );
if (xTextAppend.is() && pParaContext && hasTableManager() && !getTableManager().isIgnore())
{
try
diff --git a/writerfilter/source/dmapper/DomainMapper_Impl.hxx b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
index 1a9f934..ba81c4c 100644
--- a/writerfilter/source/dmapper/DomainMapper_Impl.hxx
+++ b/writerfilter/source/dmapper/DomainMapper_Impl.hxx
@@ -490,6 +490,8 @@ private:
//each context needs a stack of currently used attributes
std::stack<PropertyMapPtr> m_aPropertyStacks[NUMBER_OF_CONTEXTS];
std::stack<ContextType> m_aContextStack;
std::queue<std::optional<sal_Int16>> m_aFrameDirectionQueue;
bool m_bFrameDirectionSet;
FontTablePtr m_pFontTable;
ListsManager::Pointer m_pListTable;
std::deque< css::uno::Reference<css::drawing::XShape> > m_aPendingShapes;
@@ -954,6 +956,25 @@ public:
return m_aTextAppendStack.empty() ? nullptr : m_aTextAppendStack.top().xTextAppend;
}
void NewFrameDirection() {
m_aFrameDirectionQueue.push(std::nullopt);
m_bFrameDirectionSet = false;
}
void SetFrameDirection(sal_Int16 nDirection) {
if (!m_bFrameDirectionSet) {
assert(!m_aFrameDirectionQueue.empty());
m_aFrameDirectionQueue.back() = nDirection;
m_bFrameDirectionSet = true;
}
}
std::optional<sal_Int16> PopFrameDirection() {
if (m_aFrameDirectionQueue.empty())
return {};
const std::optional<sal_Int16> nDirection = m_aFrameDirectionQueue.front();
m_aFrameDirectionQueue.pop();
return nDirection;
}
SectionPropertyMap * GetSectionContext();
/// If the current paragraph has a numbering style associated, this method returns its character style (part of the numbering rules)
css::uno::Reference<css::beans::XPropertySet> GetCurrentNumberingCharStyle();