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:
@@ -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))
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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 ) )
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user