tdf#166030 Read bullet indents from metroBlob in ppt

for each shape there is a metroBlob which contains
a small ooxml part with some properties for the shape.

Read 'marL' and 'indent' from that metroBlob to properly
import margin and indent and thus have functioning hanging indent.

Change-Id: I126e13c6ed4fc062fdbe6b80ff358bcc363a1b84
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202157
Reviewed-by: Stephan Bergmann <stephan.bergmann@collabora.com>
Tested-by: Jenkins CollaboraOffice <jenkinscollaboraoffice@gmail.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202418
Tested-by: Jenkins
Reviewed-by: Samuel Mehrbrodt <samuel.mehrbrodt@collabora.com>
This commit is contained in:
Samuel Mehrbrodt
2026-03-24 07:36:23 +01:00
parent c26dd0e1f2
commit 0534223b18
10 changed files with 258 additions and 51 deletions
+1
View File
@@ -24,6 +24,7 @@ $(eval $(call gb_Library_set_componentfile,msfilter,filter/source/msfilter/msfil
$(eval $(call gb_Library_use_externals,msfilter,\
boost_headers \
frozen \
libxml2 \
))
$(eval $(call gb_Library_use_sdk_api,msfilter))
+42
View File
@@ -35,6 +35,7 @@
#include <rtl/math.hxx>
#include <comphelper/classids.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <toolkit/helper/vclunohelper.hxx>
#include <comphelper/configuration.hxx>
#include <unotools/streamwrap.hxx>
@@ -159,6 +160,7 @@
#include <com/sun/star/beans/XPropertySetInfo.hpp>
#include <com/sun/star/beans/XPropertySet.hpp>
#include <com/sun/star/drawing/ProjectionMode.hpp>
#include <com/sun/star/xml/dom/DocumentBuilder.hpp>
#include <svx/EnhancedCustomShape2d.hxx>
#include <rtl/ustring.hxx>
#include <svtools/embedhlp.hxx>
@@ -2750,6 +2752,7 @@ void DffPropertyReader::CheckAndCorrectExcelTextRotation( SvStream& rIn, SfxItem
if ( rObjData.bOpt2 ) // sj: #158494# is the second property set available ? if then we have to check the xml data of
{ // the shape, because the textrotation of Excel 2003 and greater versions is stored there
// (upright property of the textbox)
// TODO: Refactor this to also use GetNodeValueFromMetroBlobShapeXML method
if ( rManager.pSecPropSet->SeekToContent( DFF_Prop_metroBlob, rIn ) )
{
sal_uInt32 nLen = rManager.pSecPropSet->GetPropertyValue( DFF_Prop_metroBlob, 0 );
@@ -7625,6 +7628,45 @@ SdrObject* SvxMSDffManager::getShapeForId( sal_Int32 nShapeId )
return aIter != maShapeIdContainer.end() ? (*aIter).second : nullptr;
}
css::uno::Reference<css::xml::dom::XDocument> SvxMSDffManager::ParseMetroBlobShapeXML(SvStream& rStream)
{
if (!pSecPropSet || !pSecPropSet->SeekToContent(DFF_Prop_metroBlob, rStream))
return {};
sal_uInt32 nLen = pSecPropSet->GetPropertyValue(DFF_Prop_metroBlob, 0);
if (!nLen)
return {};
css::uno::Sequence<sal_Int8> aXMLDataSeq(nLen);
rStream.ReadBytes(aXMLDataSeq.getArray(), nLen);
css::uno::Reference<css::io::XInputStream> xInputStream(
new ::comphelper::SequenceInputStream(aXMLDataSeq));
try
{
auto xContext(::comphelper::getProcessComponentContext());
auto xStorage(::comphelper::OStorageHelper::GetStorageOfFormatFromInputStream(
OFOPXML_STORAGE_FORMAT_STRING, xInputStream, xContext, true));
if (!xStorage.is())
return {};
auto xDRS(xStorage->openStorageElement(
u"drs"_ustr, css::embed::ElementModes::SEEKABLEREAD));
if (!xDRS.is())
return {};
auto xStream(xDRS->openStreamElement(
u"shapexml.xml"_ustr, css::embed::ElementModes::SEEKABLEREAD));
if (!xStream.is())
return {};
auto xInStr(xStream->getInputStream());
if (!xInStr.is())
return {};
auto xDocBuilder(css::xml::dom::DocumentBuilder::create(xContext));
return xDocBuilder->parse(xInStr);
}
catch (css::uno::Exception&)
{
TOOLS_WARN_EXCEPTION("filter.ms", "Opening/Parsing of metroBlob failed");
}
return {};
}
SvxMSDffImportData::SvxMSDffImportData(const tools::Rectangle& rParentRect)
: aParentRect(rParentRect)
{
+147 -49
View File
@@ -24,6 +24,9 @@
#include <vcl/svapp.hxx>
#include <unotools/tempfile.hxx>
#include <comphelper/diagnose_ex.hxx>
#include <comphelper/processfactory.hxx>
#include <comphelper/seqstream.hxx>
#include <comphelper/storagehelper.hxx>
#include <tools/debug.hxx>
#include <tools/UnitConversion.hxx>
#include <editeng/eeitem.hxx>
@@ -32,6 +35,7 @@
#include <sot/storinfo.hxx>
#include <sot/stg.hxx>
#include <com/sun/star/embed/Aspects.hpp>
#include <com/sun/star/embed/ElementModes.hpp>
#include <com/sun/star/embed/XEmbeddedObject.hpp>
#include <com/sun/star/frame/XModel.hpp>
#include <com/sun/star/frame/XModel3.hpp>
@@ -120,6 +124,7 @@
#include <com/sun/star/table/BorderLine2.hpp>
#include <com/sun/star/table/BorderLineStyle.hpp>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/xml/xpath/XPathAPI.hpp>
#include <svtools/embedhlp.hxx>
#include <o3tl/enumrange.hxx>
#include <o3tl/safeint.hxx>
@@ -2270,6 +2275,7 @@ SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj*
rOutliner.SetStyleSheet( 0, pSheet );
}
rOutliner.SetVertical( pTextObj->GetVertical() );
sal_Int32 nMetroParaIndex = 0;
for ( PPTParagraphObj* pPara = pTextObj->First(); pPara; pPara = pTextObj->Next() )
{
sal_uInt32 nTextSize = pPara->GetTextSize();
@@ -2353,7 +2359,10 @@ SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj*
}
std::optional< sal_Int16 > oStartNumbering;
SfxItemSet aParagraphAttribs( rOutliner.GetEmptyItemSet() );
pPara->ApplyTo( aParagraphAttribs, oStartNumbering, *this, nDestinationInstance );
const MetroParagraphIndent* pMetroIndent = nullptr;
if (o3tl::make_unsigned(nMetroParaIndex) < pTextObj->GetMetroParagraphIndents().size())
pMetroIndent = &pTextObj->GetMetroParagraphIndents()[nMetroParaIndex];
pPara->ApplyTo( aParagraphAttribs, oStartNumbering, *this, nDestinationInstance, pMetroIndent, nMetroParaIndex );
sal_uInt32 nIsBullet2 = 0; //, nInstance = nDestinationInstance != 0xffffffff ? nDestinationInstance : pTextObj->GetInstance();
pPara->GetAttrib( PPT_ParaAttr_BulletOn, nIsBullet2, nDestinationInstance );
@@ -2368,6 +2377,7 @@ SdrObject* SdrPowerPointImport::ApplyTextObj( PPTTextObj* pTextObj, SdrTextObj*
}
aSelection.start.nIndex = 0;
rOutliner.QuickSetAttribs( aParagraphAttribs, aSelection );
nMetroParaIndex++;
}
}
std::optional<OutlinerParaObject> pNewText = rOutliner.CreateParaObject();
@@ -3777,17 +3787,20 @@ void PPTNumberFormatCreator::ImplGetNumberFormat( SdrPowerPointImport const & rM
rNumberFormat.SetBulletRelSize( static_cast<sal_uInt16>(nBulletHeight) );
rNumberFormat.SetBulletColor( aCol );
// tdf#166030 When bullet is enabled but both offsets are 0 (which is the case for TextInShape)
// add some default indentation to match PowerPoint's behavior.
if ( nIsBullet && nTextOfs == 0 && nBulletOfs == 0 )
{
nTextOfs = 216; // 3/8 inch text indent (~0.95 cm, default PowerPoint bullet indent)
nBulletOfs = 0; // bullet at left edge
}
sal_uInt32 nAbsLSpace = convertMasterUnitToMm100(nTextOfs);
sal_uInt32 nFirstLineOffset = nAbsLSpace - convertMasterUnitToMm100(nBulletOfs);
rNumberFormat.SetAbsLSpace( nAbsLSpace );
rNumberFormat.SetFirstLineOffset( -static_cast<sal_Int32>(nFirstLineOffset) );
sal_uInt32 nBulletMm100 = convertMasterUnitToMm100(nBulletOfs);
if (nTextOfs >= nBulletOfs)
{
// Default hanging indent: bullet is left of text
rNumberFormat.SetAbsLSpace( nAbsLSpace );
rNumberFormat.SetFirstLineOffset( -static_cast<sal_Int32>(nAbsLSpace - nBulletMm100) );
}
else
{
// First-line indent: text starts at nBulletOfs, bullet at nTextOfs
rNumberFormat.SetAbsLSpace( nBulletMm100 );
rNumberFormat.SetFirstLineOffset( -static_cast<sal_Int32>(nBulletMm100 - nAbsLSpace) );
}
}
PPTCharSheet::PPTCharSheet( TSS_Type nInstance )
@@ -6137,51 +6150,65 @@ bool PPTParagraphObj::GetAttrib( sal_uInt32 nAttr, sal_uInt32& rRetValue, TSS_Ty
return bIsHardAttribute;
}
void PPTParagraphObj::ApplyTo( SfxItemSet& rSet, std::optional< sal_Int16 >& rStartNumbering, SdrPowerPointImport const & rManager, TSS_Type nDestinationInstance )
void PPTParagraphObj::ApplyTo(SfxItemSet& rSet, std::optional<sal_Int16>& rStartNumbering,
SdrPowerPointImport const& rManager, TSS_Type nDestinationInstance,
const MetroParagraphIndent* pMetroIndent, sal_Int32 nParaIndex)
{
sal_Int16 nVal2;
sal_uInt32 nVal, nUpperDist, nLowerDist;
TSS_Type nInstance = nDestinationInstance != TSS_Type::Unknown ? nDestinationInstance : mnInstance;
if ( ( nDestinationInstance != TSS_Type::Unknown ) || ( mxParaSet->mnDepth <= 1 ) )
SvxNumBulletItem* pNumBulletItem = mrStyleSheet.mpNumBulletItem[ nInstance ].get();
if ( pNumBulletItem )
{
SvxNumBulletItem* pNumBulletItem = mrStyleSheet.mpNumBulletItem[ nInstance ].get();
if ( pNumBulletItem )
SvxNumberFormat aNumberFormat( SVX_NUM_NUMBER_NONE );
if ( GetNumberFormat( rManager, aNumberFormat, this, nDestinationInstance, rStartNumbering ) )
{
SvxNumberFormat aNumberFormat( SVX_NUM_NUMBER_NONE );
if ( GetNumberFormat( rManager, aNumberFormat, this, nDestinationInstance, rStartNumbering ) )
if (pMetroIndent && (pMetroIndent->nMarginLeft.has_value() || pMetroIndent->nIndent.has_value()))
{
if ( aNumberFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE )
{
aNumberFormat.SetAbsLSpace( 0 );
aNumberFormat.SetFirstLineOffset( 0 );
aNumberFormat.SetCharTextDistance( 0 );
aNumberFormat.SetFirstLineIndent( 0 );
aNumberFormat.SetIndentAt( 0 );
}
SvxNumBulletItem aNewNumBulletItem( *pNumBulletItem );
SvxNumRule& rRule = aNewNumBulletItem.GetNumRule();
rRule.SetLevel( mxParaSet->mnDepth, aNumberFormat );
for (sal_uInt16 i = 0; i < rRule.GetLevelCount(); ++i)
{
if ( i != mxParaSet->mnDepth )
{
sal_uInt16 n = sanitizeForMaxPPTLevels(i);
SvxNumberFormat aNumberFormat2( rRule.GetLevel( i ) );
const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ nInstance ]->maParaLevel[ n ];
const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ nInstance ]->maCharLevel[ n ];
sal_uInt32 nColor;
if ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) )
nColor = rParaLevel.mnBulletColor;
else
nColor = rCharLevel.mnFontColor;
aNumberFormat2.SetBulletColor( rManager.MSO_TEXT_CLR_ToColor( nColor ) );
rRule.SetLevel( i, aNumberFormat2 );
}
}
rSet.Put( aNewNumBulletItem );
sal_Int32 nMarginEmu = pMetroIndent->nMarginLeft.value_or(0);
sal_Int32 nIndentEmu = pMetroIndent->nIndent.value_or(0);
if (nIndentEmu < 0 && -nIndentEmu > nMarginEmu)
nMarginEmu = -nIndentEmu;
// AbsLSpace is where wrapped text starts. With positive
// indent (first-line indent) the text starts at margin +
// indent; with negative (hanging indent) at margin.
sal_Int32 nAbsLSpaceMm100 = (nMarginEmu + std::max(nIndentEmu, sal_Int32(0))) / 360;
// FirstLineOffset is always negative or zero: the bullet
// hangs to the left of AbsLSpace by indent.
sal_Int32 nFirstLineOffsetMm100 = -std::abs(nIndentEmu) / 360;
aNumberFormat.SetAbsLSpace(nAbsLSpaceMm100);
aNumberFormat.SetFirstLineOffset(nFirstLineOffsetMm100);
}
if ( aNumberFormat.GetNumberingType() == SVX_NUM_NUMBER_NONE )
{
aNumberFormat.SetAbsLSpace( 0 );
aNumberFormat.SetFirstLineOffset( 0 );
aNumberFormat.SetCharTextDistance( 0 );
aNumberFormat.SetFirstLineIndent( 0 );
aNumberFormat.SetIndentAt( 0 );
}
SvxNumBulletItem aNewNumBulletItem( *pNumBulletItem );
SvxNumRule& rRule = aNewNumBulletItem.GetNumRule();
rRule.SetLevel( mxParaSet->mnDepth, aNumberFormat );
for (sal_uInt16 i = 0; i < rRule.GetLevelCount(); ++i)
{
if ( i != mxParaSet->mnDepth )
{
sal_uInt16 n = sanitizeForMaxPPTLevels(i);
SvxNumberFormat aNumberFormat2( rRule.GetLevel( i ) );
const PPTParaLevel& rParaLevel = mrStyleSheet.mpParaSheet[ nInstance ]->maParaLevel[ n ];
const PPTCharLevel& rCharLevel = mrStyleSheet.mpCharSheet[ nInstance ]->maCharLevel[ n ];
sal_uInt32 nColor;
if ( rParaLevel.mnBuFlags & ( 1 << PPT_ParaAttr_BuHardColor ) )
nColor = rParaLevel.mnBulletColor;
else
nColor = rCharLevel.mnFontColor;
aNumberFormat2.SetBulletColor( rManager.MSO_TEXT_CLR_ToColor( nColor ) );
rRule.SetLevel( i, aNumberFormat2 );
}
}
rSet.Put( aNewNumBulletItem );
}
}
@@ -6190,7 +6217,37 @@ void PPTParagraphObj::ApplyTo( SfxItemSet& rSet, std::optional< sal_Int16 >& rS
GetAttrib(PPT_ParaAttr_TextOfs, _nTextOfs, nDestinationInstance);
GetAttrib(PPT_ParaAttr_BulletOfs, _nBulletOfs, nDestinationInstance);
SvxLRSpaceItem aLRSpaceItem( EE_PARA_LRSPACE );
if ( !nIsBullet2 )
// Check if matching metro blob override exists
bool bHasMetroIndent = false;
if (nParaIndex != -1 && pMetroIndent)
{
sal_Int32 nMarginLeftTwips = 0;
sal_Int32 nIndentTwips = 0;
// Need to convert those from EMU to twips (divide by 635)
if (pMetroIndent->nMarginLeft.has_value())
{
nMarginLeftTwips = pMetroIndent->nMarginLeft.value() / 635;
bHasMetroIndent = true;
}
// indent in ooxml is relative to margin, so calculate offset accordingly
if (pMetroIndent->nIndent.has_value())
{
bHasMetroIndent = true;
nIndentTwips
= pMetroIndent->nIndent.value() / 635;
}
if (bHasMetroIndent && !nIsBullet2)
{
if (nIndentTwips < 0 && -nIndentTwips > nMarginLeftTwips)
{
// When hanging indent exceeds margin, adjust margin to avoid negative text left value, which is not supported in PPT
nMarginLeftTwips = -nIndentTwips;
}
aLRSpaceItem.SetTextLeft(SvxIndentValue::twips(nMarginLeftTwips));
aLRSpaceItem.SetTextFirstLineOffset(SvxIndentValue::twips(nIndentTwips));
}
}
if ( !bHasMetroIndent && !nIsBullet2 )
{
// The margin value can't be greater than 51206400 Emu, which is 142240 MM100 ([ISO/IEC 29500-1] 20.1.10.72)
sal_uInt32 nMaxMarginVal = 142240;
@@ -6419,6 +6476,39 @@ void PPTFieldEntry::SetDateTime( sal_uInt32 nVal )
}
}
namespace
{
std::vector<MetroParagraphIndent> lcl_readMetroParaIndents(SvxMSDffManager& rManager,
SvStream& rStream)
{
std::vector<MetroParagraphIndent> aIndents;
auto xDoc = rManager.ParseMetroBlobShapeXML(rStream);
if (!xDoc)
return aIndents;
auto xContext(::comphelper::getProcessComponentContext());
auto xXPath(css::xml::xpath::XPathAPI::create(xContext));
xXPath->registerNS("p", "http://schemas.openxmlformats.org/presentationml/2006/main");
xXPath->registerNS("a", "http://schemas.openxmlformats.org/drawingml/2006/main");
auto xNodeList = xXPath->selectNodeList(xDoc, "//p:txBody/a:p");
sal_Int32 nCount = xNodeList->getLength();
for (sal_Int32 i = 0; i < nCount; i++)
{
auto xPara = xNodeList->item(i);
MetroParagraphIndent indent;
auto xMarginLeft = xXPath->selectSingleNode(xPara, "a:pPr/@marL");
if (xMarginLeft.is())
indent.nMarginLeft = xMarginLeft->getNodeValue().toInt32();
auto xIndent = xXPath->selectSingleNode(xPara, "a:pPr/@indent");
if (xIndent.is())
indent.nIndent = xIndent->getNodeValue().toInt32();
aIndents.emplace_back(indent);
}
return aIndents;
}
}
PPTTextObj::PPTTextObj( SvStream& rIn, SdrPowerPointImport& rSdrPowerPointImport, PptSlidePersistEntry& rPersistEntry, DffObjData const * pObjData ) :
mxImplTextObj ( new ImplPPTTextObj( rPersistEntry ) )
{
@@ -6447,6 +6537,14 @@ PPTTextObj::PPTTextObj( SvStream& rIn, SdrPowerPointImport& rSdrPowerPointImport
if ( pObjData->nSpFlags & ShapeFlag::HaveMaster )
mxImplTextObj->mnShapeMaster = rSdrPowerPointImport.GetPropertyValue( DFF_Prop_hspMaster, 0 );
}
// tdf#171265 paragraph indent is stored in a special record (metroBlob) which contains some sort of ooxml.
// Need to read it from there.
if (pObjData && pObjData->bOpt2 && rSdrPowerPointImport.pSecPropSet)
{
mxImplTextObj->aMetroParagraphIndentList = lcl_readMetroParaIndents(rSdrPowerPointImport, rIn);
}
// ClientData
if ( rSdrPowerPointImport.maShapeRecords.SeekToContent( rIn, DFF_msofbtClientData, SEEK_FROM_CURRENT_AND_RESTART ) )
{
+4
View File
@@ -30,6 +30,7 @@
#include <com/sun/star/uno/Any.hxx>
#include <com/sun/star/uno/Reference.hxx>
#include <com/sun/star/xml/dom/XDocument.hpp>
#include <comphelper/stl_types.hxx>
#include <filter/msfilter/dffpropset.hxx>
#include <filter/msfilter/dffrecordheader.hxx>
@@ -748,6 +749,9 @@ public:
void insertShapeId( sal_Int32 nShapeId, SdrObject* pShape );
void removeShapeId( SdrObject const * pShape );
SdrObject* getShapeForId( sal_Int32 nShapeId );
// Read drs/shapexml.xml from metroBlob and return the document element
css::uno::Reference<css::xml::dom::XDocument> ParseMetroBlobShapeXML(SvStream& rStream);
};
struct SvxMSDffShapeInfo
+14 -1
View File
@@ -1128,6 +1128,12 @@ public:
sal_uInt32 Count() const { return mpFieldItem ? 1 : maString.getLength(); };
};
struct MetroParagraphIndent
{
std::optional<sal_Int32> nMarginLeft;
std::optional<sal_Int32> nIndent;
};
class MSFILTER_DLLPUBLIC PPTParagraphObj
: public PPTParaPropSet,
public PPTNumberFormatCreator,
@@ -1144,6 +1150,8 @@ class MSFILTER_DLLPUBLIC PPTParagraphObj
sal_uInt32 mnCurrentObject;
::std::vector<std::unique_ptr<PPTPortionObj>> m_PortionList;
std::optional<sal_Int32> mnMetroMarginLevel;
std::optional<sal_Int32> mnMetroIndent;
public:
void UpdateBulletRelSize( sal_uInt32& nBulletRelSize ) const;
@@ -1173,7 +1181,9 @@ public:
SfxItemSet& rSet,
std::optional< sal_Int16 >& rStartNumbering,
SdrPowerPointImport const & rManager,
TSS_Type nInstanceInSheet
TSS_Type nInstanceInSheet,
const MetroParagraphIndent* pMetroParaIndent = nullptr,
sal_Int32 nParaIndex = -1
);
};
@@ -1196,6 +1206,7 @@ struct ImplPPTTextObj final : public salhelper::SimpleReferenceObject
sal_uInt32 mnParagraphCount;
std::vector<std::unique_ptr<PPTParagraphObj>>
maParagraphList;
std::vector<MetroParagraphIndent> aMetroParagraphIndentList;
PptSlidePersistEntry& mrPersistEntry;
sal_uInt32 mnTextFlags;
@@ -1255,6 +1266,8 @@ public:
const SfxItemSet* GetBackground() const;
const std::vector<MetroParagraphIndent>& GetMetroParagraphIndents() const { return mxImplTextObj->aMetroParagraphIndentList; }
PPTTextObj& operator=( const PPTTextObj& rTextObj );
};
Binary file not shown.
Binary file not shown.
Binary file not shown.
+49
View File
@@ -15,6 +15,7 @@
#include <editeng/eeitem.hxx>
#include <editeng/editobj.hxx>
#include <editeng/numitem.hxx>
#include <editeng/lrspitem.hxx>
#include <svx/svdotable.hxx>
#include <svx/xfillit0.hxx>
@@ -1220,6 +1221,54 @@ CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf114913)
pItem->GetNumRule().GetLevel(0).GetGraphicSize().getHeight());
}
CPPUNIT_TEST_FIXTURE(SdImportTest2, testPptIndentsMetroBlob)
{
createSdImpressDoc("ppt/indent_multiple_spacings.ppt");
const SdrPage* pPage = GetPage(1);
SdrTextObj* pTxtObj = DynCastSdrTextObj(pPage->GetObj(0));
const EditTextObject& aEdit = pTxtObj->GetOutlinerParaObject()->GetTextObject();
const SvxNumBulletItem* pNumFmt = aEdit.GetParaAttribs(0).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(0), pNumFmt->GetNumRule().GetLevel(0).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(952), pNumFmt->GetNumRule().GetLevel(1).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(2540), pNumFmt->GetNumRule().GetLevel(2).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(3810), pNumFmt->GetNumRule().GetLevel(3).GetAbsLSpace());
}
CPPUNIT_TEST_FIXTURE(SdImportTest2, testPptHangingIndentMetroBlob)
{
// Verify hanging indent from metroBlob is applied correctly.
createSdImpressDoc("ppt/hanging-indent.ppt");
const SdrPage* pPage = GetPage(1);
SdrTextObj* pTxtObj = DynCastSdrTextObj(pPage->GetObj(0));
const EditTextObject& aEdit = pTxtObj->GetOutlinerParaObject()->GetTextObject();
const SvxNumBulletItem* pNum1 = aEdit.GetParaAttribs(1).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(1500), pNum1->GetNumRule().GetLevel(1).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(-1500), pNum1->GetNumRule().GetLevel(1).GetFirstLineOffset());
const SvxNumBulletItem* pNum2 = aEdit.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(952), pNum2->GetNumRule().GetLevel(1).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(-952), pNum2->GetNumRule().GetLevel(1).GetFirstLineOffset());
}
CPPUNIT_TEST_FIXTURE(SdImportTest2, testPptIndentationBullets)
{
createSdImpressDoc("ppt/ppt-indentation-bullets.ppt");
const SdrPage* pPage = GetPage(1);
SdrTextObj* pObj = DynCastSdrTextObj(pPage->GetObj(0));
const EditTextObject& aE = pObj->GetOutlinerParaObject()->GetTextObject();
const SvxNumBulletItem* pNum = aE.GetParaAttribs(0).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(2500), pNum->GetNumRule().GetLevel(0).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(-1500), pNum->GetNumRule().GetLevel(0).GetFirstLineOffset());
const SvxNumBulletItem* pNum1 = aE.GetParaAttribs(1).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), pNum1->GetNumRule().GetLevel(0).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(-1500), pNum1->GetNumRule().GetLevel(0).GetFirstLineOffset());
const SvxNumBulletItem* pNum2 = aE.GetParaAttribs(2).GetItem(EE_PARA_NUMBULLET);
CPPUNIT_ASSERT_EQUAL(sal_Int32(3000), pNum2->GetNumRule().GetLevel(0).GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(-1000), pNum2->GetNumRule().GetLevel(0).GetFirstLineOffset());
}
CPPUNIT_TEST_FIXTURE(SdImportTest2, testTdf114821)
{
css::uno::Any aAny;
+1 -1
View File
@@ -225,7 +225,7 @@ CPPUNIT_TEST_FIXTURE(SdImportTest4, testTdf166030)
const EditTextObject& aEdit = pTxtObj->GetOutlinerParaObject()->GetTextObject();
const SvxNumBulletItem* pNumFmt = aEdit.GetParaAttribs(1).GetItem(EE_PARA_NUMBULLET);
const SvxNumberFormat& rFmt = pNumFmt->GetNumRule().GetLevel(1);
CPPUNIT_ASSERT_EQUAL(sal_Int32(953), rFmt.GetAbsLSpace());
CPPUNIT_ASSERT_EQUAL(sal_Int32(952), rFmt.GetAbsLSpace());
}
CPPUNIT_TEST_FIXTURE(SdImportTest4, testTdf150770)