fdo#69636 VML import: handle mso-layout-flow-alt shape prop for sw frames
Writer core doesn't support this, and this has been a problem for table cells as well. There the workaround we're using for quite a while is to do the rotation at a text portion level instead, which results in reasonable layout for simple cases. Do the same here. One additional complexity is that the API between oox and writerfilter is a single UNO shape, we get this property in oox, and we have to handle it in writerfilter, when the text frame is already attached to some text. Kill this problem by adding a FrameInteropGrabBag for sw text frames: it's useful anyway, and then we can pass around this property inside the grab bag. Change-Id: Idb5ec83b5cbdde8f29d15b2cebfad24226bb6507
This commit is contained in:
committed by
Miklos Vajna
parent
634f1d11d2
commit
8738ded7bb
@@ -101,6 +101,7 @@ struct OOX_DLLPUBLIC ShapeTypeModel
|
||||
OUString maWrapDistanceRight; ///< Distance from the right side of the shape to the text that wraps around it.
|
||||
OUString maWrapDistanceTop; ///< Distance from the top of the shape to the text that wraps around it.
|
||||
OUString maWrapDistanceBottom; ///< Distance from the bottom of the shape to the text that wraps around it.
|
||||
OUString maLayoutFlowAlt; ///< Specifies the alternate layout flow for text in textboxes.
|
||||
|
||||
explicit ShapeTypeModel();
|
||||
|
||||
|
@@ -326,6 +326,16 @@ published service BaseFrameProperties
|
||||
*/
|
||||
[optional, property] short ShadowTransparence;
|
||||
|
||||
/** Grab bag of frame properties, used as a string-any map for interim interop purposes.
|
||||
|
||||
@since LibreOffice 4.2
|
||||
|
||||
<p>This property is intentionally not handled by the ODF filter. Any
|
||||
member that should be handled there should be first moved out from this grab
|
||||
bag to a separate property.</p>
|
||||
*/
|
||||
[optional, property] sequence<com::sun::star::beans::PropertyValue> FrameInteropGrabBag;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@@ -554,6 +554,28 @@ Reference< XShape > SimpleShape::implConvertAndInsert( const Reference< XShapes
|
||||
PropertySet( xShape ).setAnyProperty( PROP_RightBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceRight )));
|
||||
PropertySet( xShape ).setAnyProperty( PROP_BottomBorderDistance, makeAny( sal_Int32( getTextBox()->borderDistanceBottom )));
|
||||
}
|
||||
if (!maTypeModel.maLayoutFlowAlt.isEmpty())
|
||||
{
|
||||
// Can't handle this property here, as the frame is not attached yet: pass it to writerfilter.
|
||||
uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
|
||||
uno::Sequence<beans::PropertyValue> aGrabBag;
|
||||
xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
|
||||
beans::PropertyValue aPair;
|
||||
aPair.Name = "mso-layout-flow-alt";
|
||||
aPair.Value = uno::makeAny(maTypeModel.maLayoutFlowAlt);
|
||||
if (aGrabBag.hasElements())
|
||||
{
|
||||
sal_Int32 nLength = aGrabBag.getLength();
|
||||
aGrabBag.realloc(nLength + 1);
|
||||
aGrabBag[nLength + 1] = aPair;
|
||||
}
|
||||
else
|
||||
{
|
||||
aGrabBag.realloc(1);
|
||||
aGrabBag[0] = aPair;
|
||||
}
|
||||
xPropertySet->setPropertyValue("FrameInteropGrabBag", uno::makeAny(aGrabBag));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@@ -215,6 +215,8 @@ TextBoxContext::TextBoxContext( ContextHandler2Helper& rParent, TextBox& rTextBo
|
||||
if( aName == "layout-flow" ) rTextBox.maLayoutFlow = aValue;
|
||||
else if (aName == "mso-fit-shape-to-text")
|
||||
rTextBox.mrTypeModel.mbAutoHeight = true;
|
||||
else if (aName == "mso-layout-flow-alt")
|
||||
rTextBox.mrTypeModel.maLayoutFlowAlt = aValue;
|
||||
else
|
||||
SAL_WARN("oox", "unhandled style property: " << aName);
|
||||
}
|
||||
|
@@ -227,6 +227,7 @@ RES_FRMATR_BEGIN = RES_PARATR_LIST_END,
|
||||
RES_FRMATR_CONDITIONAL_STYLE_NAME, // 126
|
||||
RES_FILL_STYLE, // 127
|
||||
RES_FILL_GRADIENT, // 128
|
||||
RES_FRMATR_GRABBAG,
|
||||
RES_FRMATR_END
|
||||
};
|
||||
|
||||
|
@@ -839,6 +839,7 @@ enum SwPropNameIds
|
||||
/* 0773 */ UNO_NAME_SHADOW_TRANSPARENCE,
|
||||
|
||||
/* 0774 */ UNO_NAME_DOC_INTEROP_GRAB_BAG,
|
||||
/* 0775 */ UNO_NAME_FRAME_INTEROP_GRAB_BAG,
|
||||
|
||||
SW_PROPNAME_END
|
||||
|
||||
|
BIN
sw/qa/extras/ooxmlimport/data/fdo69636.docx
Normal file
BIN
sw/qa/extras/ooxmlimport/data/fdo69636.docx
Normal file
Binary file not shown.
@@ -135,6 +135,7 @@ public:
|
||||
void testVmlTextVerticalAdjust();
|
||||
void testGroupshapeSdt();
|
||||
void testDefaultSectBreakCols();
|
||||
void testFdo69636();
|
||||
|
||||
CPPUNIT_TEST_SUITE(Test);
|
||||
#if !defined(MACOSX) && !defined(WNT)
|
||||
@@ -234,6 +235,7 @@ void Test::run()
|
||||
{"vml-text-vertical-adjust.docx", &Test::testVmlTextVerticalAdjust},
|
||||
{"groupshape-sdt.docx", &Test::testGroupshapeSdt},
|
||||
{"default-sect-break-cols.docx", &Test::testDefaultSectBreakCols},
|
||||
{"fdo69636.docx", &Test::testFdo69636},
|
||||
};
|
||||
header();
|
||||
for (unsigned int i = 0; i < SAL_N_ELEMENTS(aMethods); ++i)
|
||||
@@ -1559,6 +1561,15 @@ void Test::testDefaultSectBreakCols()
|
||||
CPPUNIT_ASSERT_EQUAL(sal_Int16(0), xTextColumns->getColumnCount());
|
||||
}
|
||||
|
||||
void Test::testFdo69636()
|
||||
{
|
||||
// The problem was that the mso-layout-flow-alt:bottom-to-top VML shape property wasn't handled for sw text frames.
|
||||
uno::Reference<text::XTextFramesSupplier> xTextFramesSupplier(mxComponent, uno::UNO_QUERY);
|
||||
uno::Reference<container::XIndexAccess> xIndexAccess(xTextFramesSupplier->getTextFrames(), uno::UNO_QUERY);
|
||||
uno::Reference<text::XTextRange> xFrame(xIndexAccess->getByIndex(0), uno::UNO_QUERY);
|
||||
CPPUNIT_ASSERT_EQUAL(sal_Int32(900), getProperty<sal_Int32>(getRun(getParagraphOfText(1, xFrame->getText()), 1), "CharRotation"));
|
||||
}
|
||||
|
||||
CPPUNIT_TEST_SUITE_REGISTRATION(Test);
|
||||
|
||||
CPPUNIT_PLUGIN_IMPLEMENT();
|
||||
|
@@ -389,6 +389,7 @@ SfxItemInfo aSlotTab[] =
|
||||
{ 0, SFX_ITEM_POOLABLE }, // RES_FRMATR_CONDITIONAL_STYLE_NAME
|
||||
{ SID_SW_ATTR_FILL_STYLE, SFX_ITEM_POOLABLE }, // RES_FILL_STYLE
|
||||
{ SID_SW_ATTR_FILL_GRADIENT, SFX_ITEM_POOLABLE }, // RES_FILL_GRADIENT
|
||||
{ 0, SFX_ITEM_POOLABLE }, // RES_FRMATR_GRABBAG
|
||||
|
||||
{ 0, SFX_ITEM_POOLABLE }, // RES_GRFATR_MIRRORGRF
|
||||
{ SID_ATTR_GRAF_CROP, SFX_ITEM_POOLABLE }, // RES_GRFATR_CROPGRF
|
||||
@@ -604,6 +605,7 @@ void _InitCore()
|
||||
aAttrTab[ RES_FRMATR_CONDITIONAL_STYLE_NAME - POOLATTR_BEGIN ] = new SfxStringItem( RES_FRMATR_CONDITIONAL_STYLE_NAME, aEmptyStr );
|
||||
aAttrTab[ RES_FILL_STYLE - POOLATTR_BEGIN ] = new XFillStyleItem(XFILL_SOLID, RES_FILL_STYLE);
|
||||
aAttrTab[ RES_FILL_GRADIENT - POOLATTR_BEGIN ] = new XFillGradientItem(RES_FILL_GRADIENT);
|
||||
aAttrTab[ RES_FRMATR_GRABBAG - POOLATTR_BEGIN ] = new SfxGrabBagItem(RES_FRMATR_GRABBAG);
|
||||
|
||||
aAttrTab[ RES_GRFATR_MIRRORGRF- POOLATTR_BEGIN ] = new SwMirrorGrf;
|
||||
aAttrTab[ RES_GRFATR_CROPGRF- POOLATTR_BEGIN ] = new SwCropGrf;
|
||||
|
@@ -302,6 +302,7 @@ SwUnoPropertyMapProvider::~SwUnoPropertyMapProvider()
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_STYLE), RES_FILL_STYLE, CPPU_E2T(CPPUTYPE_FILLSTYLE), PROPERTY_NONE ,0}, \
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_GRADIENT), RES_FILL_GRADIENT, CPPU_E2T(CPPUTYPE_GRADIENT), PROPERTY_NONE ,MID_FILLGRADIENT}, \
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_GRADIENT_NAME), RES_FILL_GRADIENT, CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE ,MID_NAME}, \
|
||||
{ SW_PROP_NMID(UNO_NAME_FRAME_INTEROP_GRAB_BAG), RES_FRMATR_GRABBAG, CPPU_E2T(CPPUTYPE_PROPERTYVALUE), PROPERTY_NONE, 0}, \
|
||||
{ SW_PROP_NMID(UNO_NAME_CONTENT_PROTECTED), RES_PROTECT, CPPU_E2T(CPPUTYPE_BOOLEAN), PROPERTY_NONE, MID_PROTECT_CONTENT }, \
|
||||
{ SW_PROP_NMID(UNO_NAME_FRAME_STYLE_NAME), FN_UNO_FRAME_STYLE_NAME,CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE, 0}, \
|
||||
{ SW_PROP_NMID(UNO_NAME_BACK_GRAPHIC_URL), RES_BACKGROUND, CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE ,MID_GRAPHIC_URL }, \
|
||||
@@ -713,6 +714,7 @@ const SfxItemPropertyMapEntry* SwUnoPropertyMapProvider::GetPropertyMapEntries(s
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_STYLE), RES_FILL_STYLE, CPPU_E2T(CPPUTYPE_FILLSTYLE), PROPERTY_NONE ,0},
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_GRADIENT), RES_FILL_GRADIENT, CPPU_E2T(CPPUTYPE_GRADIENT), PROPERTY_NONE ,MID_FILLGRADIENT},
|
||||
{ SW_PROP_NMID(UNO_NAME_FILL_GRADIENT_NAME), RES_FILL_GRADIENT, CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE ,MID_NAME},
|
||||
{ SW_PROP_NMID(UNO_NAME_FRAME_INTEROP_GRAB_BAG), RES_FRMATR_GRABBAG, CPPU_E2T(CPPUTYPE_PROPERTYVALUE), PROPERTY_NONE, 0},
|
||||
// { SW_PROP_NMID(UNO_NAME_CHAIN_NEXT_NAME), RES_CHAIN, CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE ,MID_CHAIN_NEXTNAME},
|
||||
// { SW_PROP_NMID(UNO_NAME_CHAIN_PREV_NAME), RES_CHAIN, CPPU_E2T(CPPUTYPE_OUSTRING), PROPERTY_NONE ,MID_CHAIN_PREVNAME},
|
||||
/*not impl*/ { SW_PROP_NMID(UNO_NAME_CLIENT_MAP), RES_URL, CPPU_E2T(CPPUTYPE_BOOLEAN), PROPERTY_NONE ,MID_URL_CLIENTMAP },
|
||||
|
@@ -806,6 +806,7 @@ const SwPropNameTab aPropNameTab = {
|
||||
/* 0772 UNO_NAME_CHAR_SHADOW_FORMAT */ {MAP_CHAR_LEN("CharShadowFormat")},
|
||||
/* 0773 UNO_NAME_SHADOW_TRANSPARENCE */ {MAP_CHAR_LEN("ShadowTransparence")},
|
||||
/* 0774 UNO_NAME_DOC_INTEROP_GRAB_BAG */ {MAP_CHAR_LEN("InteropGrabBag")},
|
||||
/* 0775 UNO_NAME_FRAME_INTEROP_GRAB_BAG */ {MAP_CHAR_LEN("FrameInteropGrabBag")},
|
||||
|
||||
|
||||
// new items in this array must match enum SwPropNameIds
|
||||
|
@@ -3649,6 +3649,9 @@ void DomainMapper::PopListProperties()
|
||||
void DomainMapper::lcl_startCharacterGroup()
|
||||
{
|
||||
m_pImpl->PushProperties(CONTEXT_CHARACTER);
|
||||
if (m_pImpl->m_bFrameBtLr)
|
||||
// No support for this in core, work around by char rotation, as we do so for table cells already.
|
||||
m_pImpl->GetTopContext()->Insert(PROP_CHAR_ROTATION, uno::makeAny(sal_Int16(900)));
|
||||
}
|
||||
|
||||
void DomainMapper::lcl_endCharacterGroup()
|
||||
|
@@ -177,7 +177,8 @@ DomainMapper_Impl::DomainMapper_Impl(
|
||||
m_pSdtHelper(0),
|
||||
m_nTableDepth(0),
|
||||
m_bHasFtnSep(false),
|
||||
m_bIgnoreNextPara(false)
|
||||
m_bIgnoreNextPara(false),
|
||||
m_bFrameBtLr(false)
|
||||
|
||||
{
|
||||
appendTableManager( );
|
||||
@@ -1778,6 +1779,19 @@ void DomainMapper_Impl::PushShapeContext( const uno::Reference< drawing::XShape
|
||||
uno::makeAny( true ) );
|
||||
if (xSInfo->supportsService("com.sun.star.text.TextFrame"))
|
||||
{
|
||||
// Extract the special "btLr text frame" mode, requested by oox, if needed.
|
||||
uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
|
||||
uno::Sequence<beans::PropertyValue> aGrabBag;
|
||||
xPropertySet->getPropertyValue("FrameInteropGrabBag") >>= aGrabBag;
|
||||
for (int i = 0; i < aGrabBag.getLength(); ++i)
|
||||
{
|
||||
if (aGrabBag[i].Name == "mso-layout-flow-alt")
|
||||
{
|
||||
m_bFrameBtLr = aGrabBag[i].Value.get<OUString>() == "bottom-to-top";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY_THROW);
|
||||
uno::Reference<text::XTextRange> xTextRange(xTextAppend->createTextCursorByRange(xTextAppend->getEnd()), uno::UNO_QUERY_THROW);
|
||||
xTextAppend->insertTextContent(xTextRange, xTextContent, sal_False);
|
||||
@@ -1858,6 +1872,7 @@ void DomainMapper_Impl::PopShapeContext()
|
||||
}
|
||||
m_aAnchoredStack.pop();
|
||||
}
|
||||
m_bFrameBtLr = false;
|
||||
}
|
||||
|
||||
sal_Int16 lcl_ParseNumberingType( const OUString& rCommand )
|
||||
|
@@ -709,6 +709,7 @@ public:
|
||||
|
||||
/// If the next newline should be ignored, used by the special footnote separator paragraph.
|
||||
bool m_bIgnoreNextPara;
|
||||
bool m_bFrameBtLr; ///< Bottom to top, left to right text frame direction is requested for the current text frame.
|
||||
};
|
||||
} //namespace dmapper
|
||||
} //namespace writerfilter
|
||||
|
Reference in New Issue
Block a user