diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:06:44 +0000 |
commit | ed5640d8b587fbcfed7dd7967f3de04b37a76f26 (patch) | |
tree | 7a5f7c6c9d02226d7471cb3cc8fbbf631b415303 /filter/source/msfilter/eschesdo.cxx | |
parent | Initial commit. (diff) | |
download | libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.tar.xz libreoffice-ed5640d8b587fbcfed7dd7967f3de04b37a76f26.zip |
Adding upstream version 4:7.4.7.upstream/4%7.4.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'filter/source/msfilter/eschesdo.cxx')
-rw-r--r-- | filter/source/msfilter/eschesdo.cxx | 1237 |
1 files changed, 1237 insertions, 0 deletions
diff --git a/filter/source/msfilter/eschesdo.cxx b/filter/source/msfilter/eschesdo.cxx new file mode 100644 index 000000000..d052b5968 --- /dev/null +++ b/filter/source/msfilter/eschesdo.cxx @@ -0,0 +1,1237 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <memory> +#include "eschesdo.hxx" +#include <o3tl/any.hxx> +#include <svx/svdobj.hxx> +#include <tools/poly.hxx> +#include <tools/debug.hxx> +#include <tools/diagnose_ex.h> +#include <svx/fmdpage.hxx> +#include <com/sun/star/awt/Rectangle.hpp> +#include <com/sun/star/beans/PropertyValue.hpp> +#include <com/sun/star/beans/XPropertySet.hpp> +#include <com/sun/star/beans/XPropertySetInfo.hpp> +#include <com/sun/star/text/XText.hpp> +#include <com/sun/star/text/TextContentAnchorType.hpp> +#include <com/sun/star/drawing/CircleKind.hpp> +#include <com/sun/star/drawing/FillStyle.hpp> +#include <comphelper/extract.hxx> +#include <com/sun/star/drawing/HomogenMatrix3.hpp> +#include <basegfx/matrix/b2dhommatrix.hxx> + +using namespace ::com::sun::star; +using namespace ::com::sun::star::beans; +using namespace ::com::sun::star::container; +using namespace ::com::sun::star::uno; +using namespace ::com::sun::star::drawing; +using namespace ::com::sun::star::text; +using namespace ::com::sun::star::task; + +constexpr o3tl::Length geUnitsSrc(o3tl::Length::mm100); +// PowerPoint: 576 dpi, WinWord: 1440 dpi, Excel: 1440 dpi +constexpr o3tl::Length geUnitsDest(o3tl::Length::twip); + +ImplEESdrWriter::ImplEESdrWriter( EscherEx& rEx ) + : mpEscherEx(&rEx) + , mpPicStrm(nullptr) + , mpHostAppData(nullptr) + , mbIsTitlePossible(false) + , mpSdrPage( nullptr ) +{ +} + + + +Point ImplEESdrWriter::ImplMapPoint( const Point& rPoint ) +{ + return o3tl::convert( rPoint, geUnitsSrc, geUnitsDest ); +} + +Size ImplEESdrWriter::ImplMapSize( const Size& rSize ) +{ + Size aRetSize( o3tl::convert( rSize, geUnitsSrc, geUnitsDest ) ); + + if ( !aRetSize.Width() ) + aRetSize.AdjustWidth( 1 ); + if ( !aRetSize.Height() ) + aRetSize.AdjustHeight( 1 ); + return aRetSize; +} + +void ImplEESdrWriter::ImplFlipBoundingBox( ImplEESdrObject& rObj, EscherPropertyContainer& rPropOpt ) +{ + sal_Int32 nAngle = rObj.GetAngle(); + tools::Rectangle aRect( rObj.GetRect() ); + + // for position calculations, we normalize the angle between 0 and 90 degrees + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + if ( nAngle % 18000 == 0 ) + nAngle = 0; + while ( nAngle > 9000 ) + nAngle = ( 18000 - ( nAngle % 18000 ) ); + + double fVal = basegfx::deg2rad<100>(nAngle); + double fCos = cos( fVal ); + double fSin = sin( fVal ); + + double nWidthHalf = static_cast<double>(aRect.GetWidth()) / 2; + double nHeightHalf = static_cast<double>(aRect.GetHeight()) / 2; + + // fdo#70838: + // when you rotate an object, the top-left corner of its bounding box is moved + // nXDiff and nYDiff pixels. To get their values we use these equations: + // + // fSin * nHeightHalf + fCos * nWidthHalf == nXDiff + nWidthHalf + // fSin * nWidthHalf + fCos * nHeightHalf == nYDiff + nHeightHalf + + double nXDiff = fSin * nHeightHalf + fCos * nWidthHalf - nWidthHalf; + double nYDiff = fSin * nWidthHalf + fCos * nHeightHalf - nHeightHalf; + + aRect.Move( static_cast<sal_Int32>(nXDiff), static_cast<sal_Int32>(nYDiff) ); + + // calculate the proper angle value to be saved + nAngle = rObj.GetAngle(); + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + else + nAngle = ( 36000 - ( nAngle % 36000 ) ); + + nAngle *= 655; + nAngle += 0x8000; + nAngle &=~0xffff; // nAngle round to full degrees + rPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle ); + + rObj.SetAngle( nAngle ); + rObj.SetRect( aRect ); +} + + +sal_uInt32 ImplEESdrWriter::ImplWriteShape( ImplEESdrObject& rObj, + EscherSolverContainer& rSolverContainer, + const bool bOOxmlExport ) +{ + sal_uInt32 nShapeID = 0; + sal_uInt16 nShapeType = 0; + bool bDontWriteText = false; // if a metafile is written as shape replacement, then the text is already part of the metafile + bool bAdditionalText = false; + sal_uInt32 nGrpShapeID = 0; + auto addShape = [this, &rObj, &rSolverContainer, &nShapeID, &nShapeType](sal_uInt16 nType, ShapeFlag nFlags) + { + nShapeType = nType; + nShapeID = mpEscherEx->GenerateShapeId(); + rObj.SetShapeId( nShapeID ); + mpEscherEx->AddShape( nType, nFlags, nShapeID ); + rSolverContainer.AddShape( rObj.GetShapeRef(), nShapeID ); + }; + + do { + mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr ); + if ( mpHostAppData && mpHostAppData->DontWriteShape() ) + break; + + // #i51348# get shape name + OUString aShapeName; + if( const SdrObject* pSdrObj = rObj.GetSdrObject() ) + if (!pSdrObj->GetName().isEmpty()) + aShapeName = pSdrObj->GetName(); + uno::Reference< drawing::XShape> xShape = rObj.GetShapeRef(); + if (xShape.is()) + { + uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY); + if (xPropertySet.is()) + { + uno::Sequence<beans::PropertyValue> aGrabBag; + uno::Reference< XPropertySetInfo > xPropInfo = xPropertySet->getPropertySetInfo(); + if ( xPropInfo.is() && xPropInfo->hasPropertyByName( "InteropGrabBag" ) ) + { + xPropertySet->getPropertyValue( "InteropGrabBag" ) >>= aGrabBag; + for (const beans::PropertyValue& rProp : std::as_const(aGrabBag)) + { + if (rProp.Name == "mso-edit-as") + { + OUString rEditAs; + rProp.Value >>= rEditAs; + mpEscherEx->SetEditAs(rEditAs); + break; + } + } + } + } + } + + if( rObj.GetType() == "drawing.Group" ) + { + Reference< XIndexAccess > xXIndexAccess( rObj.GetShapeRef(), UNO_QUERY ); + + if( xXIndexAccess.is() && 0 != xXIndexAccess->getCount() ) + { + nShapeID = mpEscherEx->EnterGroup( aShapeName, &rObj.GetRect() ); + nShapeType = ESCHER_ShpInst_Min; + + for( sal_uInt32 n = 0, nCnt = xXIndexAccess->getCount(); + n < nCnt; ++n ) + { + ImplEESdrObject aObj( *o3tl::doAccess<Reference<XShape>>( + xXIndexAccess->getByIndex( n )) ); + if( aObj.IsValid() ) + { + aObj.SetOOXML(bOOxmlExport); + ImplWriteShape( aObj, rSolverContainer, bOOxmlExport ); + } + } + mpEscherEx->LeaveGroup(); + } + break; + } + rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" )); + + if( ( rObj.ImplGetPropertyValue( "IsFontwork" ) && + ::cppu::any2bool( rObj.GetUsrAny() ) ) || + rObj.GetType() == "drawing.Measure" ) + { + rObj.SetType("drawing.dontknow"); + } + + const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() ); + const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() ); + tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) ); + if ( !mpPicStrm ) + mpPicStrm = mpEscherEx->QueryPictureStream(); + EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm ); + + // #i51348# shape name + if (!aShapeName.isEmpty()) + aPropOpt.AddOpt( ESCHER_Prop_wzName, aShapeName ); + if ( InteractionInfo* pInteraction = mpHostAppData ? mpHostAppData->GetInteractionInfo():nullptr ) + { + const std::unique_ptr< SvMemoryStream >& pMemStrm = pInteraction->getHyperlinkRecord(); + if (pMemStrm) + { + aPropOpt.AddOpt(ESCHER_Prop_pihlShape, false, 0, *pMemStrm); + } + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080008 ); + } + + if ( rObj.GetType() == "drawing.Custom" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + ShapeFlag nMirrorFlags; + + OUString sCustomShapeType; + MSO_SPT eShapeType = EscherPropertyContainer::GetCustomShapeType( rObj.GetShapeRef(), nMirrorFlags, sCustomShapeType, rObj.GetOOXML() ); + if ( sCustomShapeType == "col-502ad400" || sCustomShapeType == "col-60da8460" ) + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + { + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); // no fill + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); // no linestyle + SdrObject* pObj = SdrObject::getSdrObjectFromXShape(rObj.GetShapeRef()); + if ( pObj ) + { + tools::Rectangle aBound = pObj->GetCurrentBoundRect(); + Point aPosition( ImplMapPoint( aBound.TopLeft() ) ); + Size aSize( ImplMapSize( aBound.GetSize() ) ); + rObj.SetRect( tools::Rectangle( aPosition, aSize ) ); + rObj.SetAngle( 0 ); + bDontWriteText = true; + } + } + } + else + { + const Reference< XPropertySet > xPropSet = rObj.mXPropSet; + drawing::FillStyle eFS = drawing::FillStyle_NONE; + if(xPropSet.is()) + { + uno::Reference< XPropertySetInfo > xPropInfo = xPropSet->getPropertySetInfo(); + if ( xPropInfo.is() && xPropInfo->hasPropertyByName("FillStyle")) + xPropSet->getPropertyValue("FillStyle") >>= eFS; + } + + if (eFS == drawing::FillStyle_BITMAP && eShapeType == mso_sptMax) + { + // We can't map this custom shape to a DOC preset and it has a bitmap fill. + // Make sure that at least the bitmap fill is not lost. + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false, true, true, bOOxmlExport ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else + { + addShape(sal::static_int_cast< sal_uInt16 >(eShapeType), + nMirrorFlags | ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor); + aPropOpt.CreateCustomShapeProperties( eShapeType, rObj.GetShapeRef() ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if ( rObj.ImplGetText() ) + { + if ( !aPropOpt.IsFontWork() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, mpEscherEx->QueryTextID( + rObj.GetShapeRef(), rObj.GetShapeId() ), true, false ); + } + } + } + } + else if ( rObj.GetType() == "drawing.Rectangle" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + sal_Int32 nRadius = rObj.ImplGetInt32PropertyValue("CornerRadius"); + if( nRadius ) + { + nRadius = ImplMapSize( Size( nRadius, 0 )).Width(); + addShape( ESCHER_ShpInst_RoundRectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + sal_Int32 nLength = rObj.GetRect().GetWidth(); + if ( nLength > rObj.GetRect().GetHeight() ) + nLength = rObj.GetRect().GetHeight(); + nLength >>= 1; + if ( nRadius >= nLength || nLength == 0 ) + nRadius = 0x2a30; // 0x2a30 is PPTs maximum radius + else + nRadius = ( 0x2a30 * nRadius ) / nLength; + aPropOpt.AddOpt( ESCHER_Prop_adjustValue, nRadius ); + } + else + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + } + else if ( rObj.GetType() == "drawing.Ellipse" ) + { + CircleKind eCircleKind = CircleKind_FULL; + PolyStyle ePolyKind = PolyStyle(); + if ( rObj.ImplGetPropertyValue( "CircleKind" ) ) + { + eCircleKind = *o3tl::doAccess<CircleKind>(rObj.GetUsrAny()); + switch ( eCircleKind ) + { + case CircleKind_SECTION : + { + ePolyKind = PolyStyle::Pie; + } + break; + case CircleKind_ARC : + { + ePolyKind = PolyStyle::Arc; + } + break; + + case CircleKind_CUT : + { + ePolyKind = PolyStyle::Chord; + } + break; + + default: + eCircleKind = CircleKind_FULL; + } + } + if ( eCircleKind == CircleKind_FULL ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_Ellipse, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + } + else + { + sal_Int32 nStartAngle, nEndAngle; + if ( !rObj.ImplGetPropertyValue( "CircleStartAngle" ) ) + break; + nStartAngle = *o3tl::doAccess<sal_Int32>(rObj.GetUsrAny()); + if( !rObj.ImplGetPropertyValue( "CircleEndAngle" ) ) + break; + nEndAngle = *o3tl::doAccess<sal_Int32>(rObj.GetUsrAny()); + + Point aStart, aEnd, aCenter; + aStart.setX( static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) ); + aStart.setY( - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nStartAngle) ) * 100.0 ) ); + aEnd.setX( static_cast<sal_Int32>( cos( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) ); + aEnd.setY( - static_cast<sal_Int32>( sin( basegfx::deg2rad<100>(nEndAngle) ) * 100.0 ) ); + const tools::Rectangle& rRect = aRect100thmm; + aCenter.setX( rRect.Left() + ( rRect.GetWidth() / 2 ) ); + aCenter.setY( rRect.Top() + ( rRect.GetHeight() / 2 ) ); + aStart.AdjustX(aCenter.X() ); + aStart.AdjustY(aCenter.Y() ); + aEnd.AdjustX(aCenter.X() ); + aEnd.AdjustY(aCenter.Y() ); + tools::Polygon aPolygon( rRect, aStart, aEnd, ePolyKind ); + if( rObj.GetAngle() ) + { + aPolygon.Rotate( rRect.TopLeft(), Degree10(static_cast<sal_Int16>( rObj.GetAngle() / 10 )) ); + rObj.SetAngle( 0 ); + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + switch ( ePolyKind ) + { + case PolyStyle::Pie : + case PolyStyle::Chord : + { + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect, &aPolygon ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + } + break; + + case PolyStyle::Arc : + { + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect, &aPolygon ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + } + break; + } + rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ), + ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) ); + } + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + + } + else if ( rObj.GetType() == "drawing.Control" ) + { + const Reference< XPropertySet > xPropSet = rObj.mXPropSet; + const Reference<XPropertySetInfo> xPropInfo = xPropSet.is() ? xPropSet->getPropertySetInfo() : Reference<XPropertySetInfo>(); + // This code is expected to be called only for DOCX/XLSX formats. + if (xPropInfo.is() && bOOxmlExport) + { + bool bInline = false; + if (xPropInfo->hasPropertyByName("AnchorType")) + { + text::TextContentAnchorType eAnchorType; + xPropSet->getPropertyValue("AnchorType") >>= eAnchorType; + bInline = eAnchorType == text::TextContentAnchorType_AS_CHARACTER; + } + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + if(bInline) + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + else + { + addShape( ESCHER_ShpInst_HostControl, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + } + } + else + break; + } + else if ( rObj.GetType() == "drawing.Connector" ) + { + sal_uInt16 nSpType; + ShapeFlag nSpFlags; + css::awt::Rectangle aNewRect; + if ( ! aPropOpt.CreateConnectorProperties( rObj.GetShapeRef(), + rSolverContainer, aNewRect, nSpType, nSpFlags ) ) + break; + rObj.SetRect( tools::Rectangle( ImplMapPoint( Point( aNewRect.X, aNewRect.Y ) ), + ImplMapSize( Size( aNewRect.Width, aNewRect.Height ) ) ) ); + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( nSpType, nSpFlags ); + } + else if ( rObj.GetType() == "drawing.Measure" ) + { + break; + } + else if ( rObj.GetType() == "drawing.Line" ) + { + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_LINE, false, aNewRect ); + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + ShapeFlag nFlags = ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor; + if( aNewRect.Height < 0 ) + nFlags |= ShapeFlag::FlipV; + if( aNewRect.Width < 0 ) + nFlags |= ShapeFlag::FlipH; + + addShape( ESCHER_ShpInst_Line, nFlags ); + aPropOpt.AddOpt( ESCHER_Prop_shapePath, ESCHER_ShapeComplex ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.PolyPolygon" ) + { + if( rObj.ImplHasText() ) + { + nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() ); + bAdditionalText = true; + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, false, aNewRect ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.PolyLine" ) + { + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, false, aNewRect ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.OpenBezier" ) + { + //i27942: Poly/Lines/Bezier do not support text. + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYLINE, true, aNewRect ); + aPropOpt.CreateLineProperties( rObj.mXPropSet, false ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.ClosedBezier" ) + { + if ( rObj.ImplHasText() ) + { + nGrpShapeID = ImplEnterAdditionalTextGroup( rObj.GetShapeRef(), &rObj.GetRect() ); + bAdditionalText = true; + } + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_NotPrimitive, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + css::awt::Rectangle aNewRect; + aPropOpt.CreatePolygonProperties( rObj.mXPropSet, ESCHER_CREATEPOLYGON_POLYPOLYGON, true, aNewRect ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + rObj.SetAngle( 0 ); + } + else if ( rObj.GetType() == "drawing.GraphicObject" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + + // a GraphicObject can also be a ClickMe element + if( rObj.IsEmptyPresObj() ) + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor ); + sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ); + aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 ); + } + else + { + if( rObj.ImplGetText() ) + { + /* SJ #i34951#: because M. documents are not allowing GraphicObjects containing text, we + have to create a simple Rectangle with fill bitmap instead (while not allowing BitmapMode_Repeat). + */ + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", true, true, false ) ) + { + aPropOpt.AddOpt( ESCHER_Prop_WrapText, ESCHER_WrapNone ); + aPropOpt.AddOpt( ESCHER_Prop_AnchorText, ESCHER_AnchorMiddle ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x140014 ); + aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x8000000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x80000 ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ), false, false ); + } + } + else + { + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Graphic", false, true, true, bOOxmlExport ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + } + } + else if ( rObj.GetType() == "drawing.Text" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.CreateFillProperties( rObj.mXPropSet, true ); + if( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + } + else if ( rObj.GetType() == "drawing.Page" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x40004 ); + aPropOpt.AddOpt( ESCHER_Prop_fFillOK, 0x100001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x110011 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90008 ); + aPropOpt.AddOpt( ESCHER_Prop_fshadowObscured, 0x10001 ); + } + else if ( rObj.GetType() == "drawing.Frame" ) + { + break; + } + else if ( rObj.GetType() == "drawing.OLE2" ) + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + if( rObj.IsEmptyPresObj() ) + { + addShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveMaster | ShapeFlag::HaveAnchor ); + sal_uInt32 nTxtBxId = mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ); + aPropOpt.AddOpt( ESCHER_Prop_lTxid, nTxtBxId ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x10001 ); + aPropOpt.AddOpt( ESCHER_Prop_hspMaster, 0 ); + } + else + { + //2do: could be made an option in HostAppData whether OLE object should be written or not + const bool bAppOLE = true; + addShape( ESCHER_ShpInst_PictureFrame, + ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor | (bAppOLE ? ShapeFlag::OLEShape : ShapeFlag::NONE) ); + if ( aPropOpt.CreateOLEGraphicProperties( rObj.GetShapeRef() ) ) + { + if ( bAppOLE ) + { // snooped from Xcl hex dump, nobody knows the trouble I have seen + aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x00080008 ); + aPropOpt.AddOpt( ESCHER_Prop_pictureId, 0x00000001 ); + aPropOpt.AddOpt( ESCHER_Prop_fillColor, 0x08000041 ); + aPropOpt.AddOpt( ESCHER_Prop_fillBackColor, 0x08000041 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x00110010 ); + aPropOpt.AddOpt( ESCHER_Prop_lineColor, 0x08000040 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash,0x00080008 ); + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x00080000 ); + } + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + } + } + else if( '3' == rObj.GetType()[8] && + 'D' == rObj.GetType()[9] ) // drawing.3D + { + // SceneObject, CubeObject, SphereObject, LatheObject, ExtrudeObject, PolygonObject + if ( !rObj.ImplGetPropertyValue( "Bitmap" ) ) + break; + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "Bitmap", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else if ( rObj.GetType() == "drawing.Caption" ) + { + rObj.SetAngle( 0 ); + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else if ( rObj.GetType() == "drawing.dontknow" ) + { + rObj.SetAngle( 0 ); + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + addShape( ESCHER_ShpInst_PictureFrame, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( aPropOpt.CreateGraphicProperties( rObj.mXPropSet, "MetaFile", false ) ) + aPropOpt.AddOpt( ESCHER_Prop_LockAgainstGrouping, 0x800080 ); + } + else + { + break; + } + aPropOpt.CreateShadowProperties( rObj.mXPropSet ); + + if( SDRLAYER_NOTFOUND != mpEscherEx->GetHellLayerId() && + rObj.ImplGetPropertyValue( "LayerID" ) && + *o3tl::doAccess<sal_Int16>(rObj.GetUsrAny()) == mpEscherEx->GetHellLayerId().get() ) + { + aPropOpt.AddOpt( ESCHER_Prop_fPrint, 0x200020 ); + } + + { + tools::Rectangle aRect( rObj.GetRect() ); + aRect.Justify(); + rObj.SetRect( aRect ); + } + + if( rObj.GetAngle() ) + ImplFlipBoundingBox( rObj, aPropOpt ); + + aPropOpt.CreateShapeProperties( rObj.GetShapeRef() ); + const SdrObject* sdrObj = rObj.GetSdrObject(); + mpEscherEx->AddSdrObjectVMLObject(*sdrObj ); + mpEscherEx->Commit( aPropOpt, rObj.GetRect()); + if( mpEscherEx->GetGroupLevel() > 1 ) + mpEscherEx->AddChildAnchor( rObj.GetRect() ); + + if ( mpHostAppData ) + { //! with AdditionalText the App has to control whether these are written or not + mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() ); + mpHostAppData->WriteClientData( *mpEscherEx ); + if ( !bDontWriteText ) + mpHostAppData->WriteClientTextbox( *mpEscherEx ); + } + mpEscherEx->CloseContainer(); // ESCHER_SpContainer + + if( bAdditionalText ) + { + mpEscherEx->EndShape( nShapeType, nShapeID ); + ImplWriteAdditionalText( rObj ); + } + + } while ( false ); + + if ( bAdditionalText ) + mpEscherEx->EndShape( ESCHER_ShpInst_Min, nGrpShapeID ); + else + mpEscherEx->EndShape( nShapeType, nShapeID ); + return nShapeID; +} + +void ImplEESdrWriter::ImplWriteAdditionalText( ImplEESdrObject& rObj ) +{ + sal_uInt32 nShapeID = 0; + sal_uInt16 nShapeType = 0; + do + { + mpHostAppData = mpEscherEx->StartShape( rObj.GetShapeRef(), (mpEscherEx->GetGroupLevel() > 1) ? &rObj.GetRect() : nullptr ); + if ( mpHostAppData && mpHostAppData->DontWriteShape() ) + break; + + const css::awt::Size aSize100thmm( rObj.GetShapeRef()->getSize() ); + const css::awt::Point aPoint100thmm( rObj.GetShapeRef()->getPosition() ); + tools::Rectangle aRect100thmm( Point( aPoint100thmm.X, aPoint100thmm.Y ), Size( aSize100thmm.Width, aSize100thmm.Height ) ); + if ( !mpPicStrm ) + mpPicStrm = mpEscherEx->QueryPictureStream(); + EscherPropertyContainer aPropOpt( mpEscherEx->GetGraphicProvider(), mpPicStrm, aRect100thmm ); + rObj.SetAngle( rObj.ImplGetInt32PropertyValue( "RotateAngle" )); + sal_Int32 nAngle = rObj.GetAngle(); + if( rObj.GetType() == "drawing.Line" ) + { +//2do: this does not work right + double fDist = hypot( rObj.GetRect().GetWidth(), + rObj.GetRect().GetHeight() ); + rObj.SetRect( tools::Rectangle( Point(), + Point( static_cast<sal_Int32>( fDist ), -1 ) ) ); + + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + mpEscherEx->AddShape( ESCHER_ShpInst_TextBox, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + aPropOpt.AddOpt( ESCHER_Prop_FitTextToShape, 0x60006 ); // Size Shape To Fit Text + if ( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + if ( nAngle ) + ImplFlipBoundingBox( rObj, aPropOpt ); + } + else + { + mpEscherEx->OpenContainer( ESCHER_SpContainer ); + nShapeID = mpEscherEx->GenerateShapeId(); + nShapeType = ESCHER_ShpInst_TextBox; + mpEscherEx->AddShape( nShapeType, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID ); + if ( rObj.ImplGetText() ) + aPropOpt.CreateTextProperties( rObj.mXPropSet, + mpEscherEx->QueryTextID( rObj.GetShapeRef(), + rObj.GetShapeId() ) ); + aPropOpt.AddOpt( ESCHER_Prop_fNoLineDrawDash, 0x90000 ); + aPropOpt.AddOpt( ESCHER_Prop_fNoFillHitTest, 0x100000 ); + + if( nAngle < 0 ) + nAngle = ( 36000 + nAngle ) % 36000; + else + nAngle = ( 36000 - ( nAngle % 36000 ) ); + + nAngle *= 655; + nAngle += 0x8000; + nAngle &=~0xffff; // nAngle round to full degrees + aPropOpt.AddOpt( ESCHER_Prop_Rotation, nAngle ); + mpEscherEx->SetGroupSnapRect( mpEscherEx->GetGroupLevel(), + rObj.GetRect() ); + mpEscherEx->SetGroupLogicRect( mpEscherEx->GetGroupLevel(), + rObj.GetRect() ); + } + rObj.SetAngle( nAngle ); + aPropOpt.CreateShapeProperties( rObj.GetShapeRef() ); + const SdrObject* sdrObj = rObj.GetSdrObject(); + mpEscherEx->AddSdrObjectVMLObject(*sdrObj ); + mpEscherEx->Commit( aPropOpt, rObj.GetRect()); + + // write the childanchor + mpEscherEx->AddChildAnchor( rObj.GetRect() ); + +#if defined EES_WRITE_EPP + // ClientAnchor + mpEscherEx->AddClientAnchor( maRect ); + // ClientTextbox + mpEscherEx->OpenContainer( ESCHER_ClientTextbox ); + mpEscherEx->AddAtom( 4, EPP_TextHeaderAtom ); + *mpStrm << (sal_uInt32)EPP_TEXTTYPE_Other; // Text in a Shape + ImplWriteTextStyleAtom(); + mpEscherEx->CloseContainer(); // ESCHER_ClientTextBox +#else // !EES_WRITE_EPP + if ( mpHostAppData ) + { //! the App has to control whether these are written or not + mpHostAppData->WriteClientAnchor( *mpEscherEx, rObj.GetRect() ); + mpHostAppData->WriteClientData( *mpEscherEx ); + mpHostAppData->WriteClientTextbox( *mpEscherEx ); + } +#endif // EES_WRITE_EPP + mpEscherEx->CloseContainer(); // ESCHER_SpContainer + } while ( false ); + mpEscherEx->LeaveGroup(); + mpEscherEx->EndShape( nShapeType, nShapeID ); +} + + +sal_uInt32 ImplEESdrWriter::ImplEnterAdditionalTextGroup( const Reference< XShape >& rShape, + const tools::Rectangle* pBoundRect ) +{ + mpHostAppData = mpEscherEx->EnterAdditionalTextGroup(); + sal_uInt32 nGrpId = mpEscherEx->EnterGroup( pBoundRect ); + mpHostAppData = mpEscherEx->StartShape( rShape, pBoundRect ); + return nGrpId; +} + + +void ImplEESdrWriter::ImplInitPageValues() +{ + mbIsTitlePossible = true; // With more than one title PowerPoint will fail. +} + +void ImplEESdrWriter::ImplWritePage( + EscherSolverContainer& rSolverContainer, bool ooxmlExport ) +{ + ImplInitPageValues(); + + const sal_uInt32 nShapes = mXShapes->getCount(); + for( sal_uInt32 n = 0; n < nShapes; ++n ) + { + ImplEESdrObject aObj( *o3tl::doAccess<Reference<XShape>>( + mXShapes->getByIndex( n )) ); + if( aObj.IsValid() ) + { + ImplWriteShape( aObj, rSolverContainer, ooxmlExport ); + } + } +} + +ImplEESdrWriter::~ImplEESdrWriter() +{ + DBG_ASSERT( !mpSolverContainer, "ImplEESdrWriter::~ImplEESdrWriter: unwritten SolverContainer" ); + Reference<css::lang::XComponent> xComp(mXDrawPage, UNO_QUERY); + if (xComp.is()) + xComp->dispose(); +} + + +bool ImplEESdrWriter::ImplInitPage( const SdrPage& rPage ) +{ + rtl::Reference<SvxDrawPage> pSvxDrawPage; + if ( mpSdrPage != &rPage || !mXDrawPage.is() ) + { + // eventually write SolverContainer of current page, deletes the Solver + ImplFlushSolverContainer(); + + mpSdrPage = nullptr; + Reference<css::lang::XComponent> xOldDrawPage(mXDrawPage, UNO_QUERY); + if (xOldDrawPage.is()) + xOldDrawPage->dispose(); + mXDrawPage = pSvxDrawPage = new SvxFmDrawPage( const_cast<SdrPage*>(&rPage) ); + mXShapes = mXDrawPage; + if ( !mXShapes.is() ) + return false; + ImplInitPageValues(); + mpSdrPage = &rPage; + + mpSolverContainer.reset( new EscherSolverContainer ); + } + else + pSvxDrawPage = comphelper::getFromUnoTunnel<SvxDrawPage>(mXDrawPage); + + return pSvxDrawPage != nullptr; +} + +bool ImplEESdrWriter::ImplInitUnoShapes( const Reference< XShapes >& rxShapes ) +{ + // eventually write SolverContainer of current page, deletes the Solver + ImplFlushSolverContainer(); + + if( !rxShapes.is() ) + return false; + + mpSdrPage = nullptr; + mXDrawPage.clear(); + mXShapes = rxShapes; + + ImplInitPageValues(); + + mpSolverContainer.reset( new EscherSolverContainer ); + return true; +} + +void ImplEESdrWriter::ImplExitPage() +{ + // close all groups before the solver container is written + while( mpEscherEx->GetGroupLevel() ) + mpEscherEx->LeaveGroup(); + + ImplFlushSolverContainer(); + mpSdrPage = nullptr; // reset page for next init +} + + +void ImplEESdrWriter::ImplFlushSolverContainer() +{ + if ( mpSolverContainer ) + { + mpSolverContainer->WriteSolver( mpEscherEx->GetStream() ); + mpSolverContainer.reset(); + } +} + +void ImplEESdrWriter::ImplWriteCurrentPage(bool ooxmlExport) +{ + assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteCurrentPage: no SolverContainer"); + ImplWritePage( *mpSolverContainer, ooxmlExport ); + ImplExitPage(); +} + +sal_uInt32 ImplEESdrWriter::ImplWriteTheShape( ImplEESdrObject& rObj , bool ooxmlExport ) +{ + assert(mpSolverContainer && "ImplEESdrWriter::ImplWriteShape: no SolverContainer"); + return ImplWriteShape( rObj, *mpSolverContainer, ooxmlExport ); +} + +void EscherEx::AddSdrPage( const SdrPage& rPage, bool ooxmlExport ) +{ + if ( mpImplEESdrWriter->ImplInitPage( rPage ) ) + mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport); +} + +void EscherEx::AddUnoShapes( const Reference< XShapes >& rxShapes, bool ooxmlExport ) +{ + if ( mpImplEESdrWriter->ImplInitUnoShapes( rxShapes ) ) + mpImplEESdrWriter->ImplWriteCurrentPage(ooxmlExport); +} + +sal_uInt32 EscherEx::AddSdrObject( const SdrObject& rObj, bool ooxmlExport ) +{ + ImplEESdrObject aObj( *mpImplEESdrWriter, rObj, mbOOXML ); + if( aObj.IsValid() ) + return mpImplEESdrWriter->ImplWriteTheShape( aObj, ooxmlExport ); + return 0; +} + + +void EscherEx::EndSdrObjectPage() +{ + mpImplEESdrWriter->ImplExitPage(); +} + +EscherExHostAppData* EscherEx::StartShape( const Reference< XShape >& /* rShape */, const tools::Rectangle* /*pChildAnchor*/ ) +{ + return nullptr; +} + +void EscherEx::EndShape( sal_uInt16 /* nShapeType */, sal_uInt32 /* nShapeID */ ) +{ +} + +sal_uInt32 EscherEx::QueryTextID( const Reference< XShape >&, sal_uInt32 ) +{ + return 0; +} + +// add a dummy rectangle shape into the escher stream +sal_uInt32 EscherEx::AddDummyShape() +{ + OpenContainer( ESCHER_SpContainer ); + sal_uInt32 nShapeID = GenerateShapeId(); + AddShape( ESCHER_ShpInst_Rectangle, ShapeFlag::HaveShapeProperty | ShapeFlag::HaveAnchor, nShapeID ); + CloseContainer(); + + return nShapeID; +} + +// static +const SdrObject* EscherEx::GetSdrObject( const Reference< XShape >& rShape ) +{ + const SdrObject* pRet = SdrObject::getSdrObjectFromXShape( rShape ); + DBG_ASSERT( pRet, "EscherEx::GetSdrObject: no SdrObj" ); + return pRet; +} + + +ImplEESdrObject::ImplEESdrObject( ImplEESdrWriter& rEx, + const SdrObject& rObj, bool bOOXML ) : + mnShapeId( 0 ), + mnTextSize( 0 ), + mnAngle( 0 ), + mbValid( false ), + mbPresObj( false ), + mbEmptyPresObj( false ), + mbOOXML(bOOXML) +{ + SdrPage* pPage = rObj.getSdrPageFromSdrObject(); + DBG_ASSERT( pPage, "ImplEESdrObject::ImplEESdrObject: no SdrPage" ); + if( pPage && rEx.ImplInitPage( *pPage ) ) + { + // why not declare a const parameter if the object will + // not be modified? + mXShape.set( const_cast<SdrObject*>(&rObj)->getUnoShape(), UNO_QUERY ); + Init(); + } +} + +ImplEESdrObject::ImplEESdrObject( const Reference< XShape >& rShape ) : + mXShape( rShape ), + mnShapeId( 0 ), + mnTextSize( 0 ), + mnAngle( 0 ), + mbValid( false ), + mbPresObj( false ), + mbEmptyPresObj( false ), + mbOOXML(false) +{ + Init(); +} + + +ImplEESdrObject::~ImplEESdrObject() +{ +} + +static basegfx::B2DRange getUnrotatedGroupBoundRange(const Reference< XShape >& rxShape) +{ + basegfx::B2DRange aRetval; + + try + { + if(rxShape.is()) + { + if(rxShape->getShapeType() == "com.sun.star.drawing.GroupShape") + { + // it's a group shape, iterate over children + const Reference< XIndexAccess > xXIndexAccess(rxShape, UNO_QUERY); + + if(xXIndexAccess.is()) + { + for(sal_uInt32 n(0), nCnt = xXIndexAccess->getCount(); n < nCnt; ++n) + { + const Reference< XShape > axShape(xXIndexAccess->getByIndex(n), UNO_QUERY); + + if(axShape.is()) + { + // we are calculating the bound for a group, correct rotation for sub-objects + // to get the unrotated bounds for the group + const basegfx::B2DRange aExtend(getUnrotatedGroupBoundRange(axShape)); + + aRetval.expand(aExtend); + } + } + } + } + else + { + // iT#s a xShape, get its transformation + const Reference< XPropertySet > xPropSet(rxShape, UNO_QUERY); + + if(xPropSet.is()) + { + const Any aAny = xPropSet->getPropertyValue("Transformation"); + + if(aAny.hasValue()) + { + HomogenMatrix3 aMatrix; + + if(aAny >>= aMatrix) + { + basegfx::B2DHomMatrix aHomogenMatrix; + + aHomogenMatrix.set(0, 0, aMatrix.Line1.Column1); + aHomogenMatrix.set(0, 1, aMatrix.Line1.Column2); + aHomogenMatrix.set(0, 2, aMatrix.Line1.Column3); + aHomogenMatrix.set(1, 0, aMatrix.Line2.Column1); + aHomogenMatrix.set(1, 1, aMatrix.Line2.Column2); + aHomogenMatrix.set(1, 2, aMatrix.Line2.Column3); + aHomogenMatrix.set(2, 0, aMatrix.Line3.Column1); + aHomogenMatrix.set(2, 1, aMatrix.Line3.Column2); + aHomogenMatrix.set(2, 2, aMatrix.Line3.Column3); + + basegfx::B2DVector aScale, aTranslate; + double fRotate, fShearX; + + // decompose transformation + aHomogenMatrix.decompose(aScale, aTranslate, fRotate, fShearX); + + // check if rotation needs to be corrected + if(!basegfx::fTools::equalZero(fRotate)) + { + // to correct, keep in mind that ppt graphics are rotated around their center + const basegfx::B2DPoint aCenter(aHomogenMatrix * basegfx::B2DPoint(0.5, 0.5)); + + aHomogenMatrix.translate(-aCenter.getX(), -aCenter.getY()); + aHomogenMatrix.rotate(-fRotate); + aHomogenMatrix.translate(aCenter.getX(), aCenter.getY()); + } + + + // check if shear needs to be corrected (always correct shear, + // ppt does not know about it) + if(!basegfx::fTools::equalZero(fShearX)) + { + const basegfx::B2DPoint aMinimum(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0)); + + aHomogenMatrix.translate(-aMinimum.getX(), -aMinimum.getY()); + aHomogenMatrix.shearX(-fShearX); + aHomogenMatrix.translate(aMinimum.getX(), aMinimum.getY()); + } + + // create range. It's no longer rotated (or sheared), so use + // minimum and maximum values + aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(0.0, 0.0)); + aRetval.expand(aHomogenMatrix * basegfx::B2DPoint(1.0, 1.0)); + } + } + } + } + } + } + catch(css::uno::Exception&) + { + } + + return aRetval; +} + +void ImplEESdrObject::Init() +{ + mXPropSet.set( mXShape, UNO_QUERY ); + if( !mXPropSet.is() ) + return; + + // detect name first to make below test (is group) work + mType = mXShape->getShapeType(); + (void)mType.startsWith( "com.sun.star.", &mType ); // strip "com.sun.star." + (void)mType.endsWith( "Shape", &mType ); // strip "Shape" + + if(GetType() == "drawing.Group") + { + // if it's a group, the unrotated range is needed for that group + const basegfx::B2DRange aUnrotatedRange(getUnrotatedGroupBoundRange(mXShape)); + const Point aNewP(basegfx::fround(aUnrotatedRange.getMinX()), basegfx::fround(aUnrotatedRange.getMinY())); + const Size aNewS(basegfx::fround(aUnrotatedRange.getWidth()), basegfx::fround(aUnrotatedRange.getHeight())); + + SetRect(ImplEESdrWriter::ImplMapPoint(aNewP), ImplEESdrWriter::ImplMapSize(aNewS)); + } + else + { + // if it's no group, use position and size directly, rotated/sheared or not + const Point aOldP(mXShape->getPosition().X, mXShape->getPosition().Y); + const Size aOldS(mXShape->getSize().Width, mXShape->getSize().Height); + + SetRect(ImplEESdrWriter::ImplMapPoint(aOldP), ImplEESdrWriter::ImplMapSize(aOldS)); + } + + if( ImplGetPropertyValue( "IsPresentationObject" ) ) + mbPresObj = ::cppu::any2bool( mAny ); + + if( mbPresObj && ImplGetPropertyValue( "IsEmptyPresentationObject" ) ) + mbEmptyPresObj = ::cppu::any2bool( mAny ); + + mbValid = true; +} + +bool ImplEESdrObject::ImplGetPropertyValue( const OUString& rString ) +{ + bool bRetValue = false; + if( mbValid ) + { + try + { + mAny = mXPropSet->getPropertyValue( rString ); + if( mAny.hasValue() ) + bRetValue = true; + } + catch( const css::uno::Exception& ) + { + bRetValue = false; + } + } + return bRetValue; +} + +void ImplEESdrObject::SetRect( const Point& rPos, const Size& rSz ) +{ + maRect = tools::Rectangle( rPos, rSz ); +} + +const SdrObject* ImplEESdrObject::GetSdrObject() const +{ + return EscherEx::GetSdrObject( mXShape ); +} + +// loads and converts text from shape, result is saved in mnTextSize +sal_uInt32 ImplEESdrObject::ImplGetText() +{ + Reference< XText > xXText( mXShape, UNO_QUERY ); + mnTextSize = 0; + if (xXText.is()) + { + try + { + mnTextSize = xXText->getString().getLength(); + } + catch (const uno::RuntimeException&) + { + TOOLS_WARN_EXCEPTION("filter.ms", "ImplGetText"); + } + } + return mnTextSize; +} + +bool ImplEESdrObject::ImplHasText() const +{ + Reference< XText > xXText( mXShape, UNO_QUERY ); + return xXText.is() && !xXText->getString().isEmpty(); +} + + +void ImplEESdrObject::SetOOXML(bool bOOXML) +{ + mbOOXML = bOOXML; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |