summaryrefslogtreecommitdiffstats
path: root/svx/source/svdraw/svdograf.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/svdraw/svdograf.cxx')
-rw-r--r--svx/source/svdraw/svdograf.cxx1252
1 files changed, 1252 insertions, 0 deletions
diff --git a/svx/source/svdraw/svdograf.cxx b/svx/source/svdraw/svdograf.cxx
new file mode 100644
index 0000000000..0f7151e295
--- /dev/null
+++ b/svx/source/svdraw/svdograf.cxx
@@ -0,0 +1,1252 @@
+/* -*- 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 <unotools/streamwrap.hxx>
+
+#include <sfx2/lnkbase.hxx>
+#include <rtl/ustrbuf.hxx>
+#include <tools/helpers.hxx>
+#include <tools/stream.hxx>
+#include <sot/exchange.hxx>
+#include <sot/formats.hxx>
+#include <vcl/GraphicObject.hxx>
+#include <vcl/svapp.hxx>
+
+#include <sfx2/linkmgr.hxx>
+#include <svx/dialmgr.hxx>
+#include <svx/strings.hrc>
+#include <svx/svdhdl.hxx>
+#include <svx/svdmodel.hxx>
+#include <svx/svdpage.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/svdogrp.hxx>
+#include <svx/xbtmpit.hxx>
+#include <svx/xfillit0.hxx>
+#include <svx/xflbmtit.hxx>
+#include "svdfmtf.hxx"
+#include <sdgcoitm.hxx>
+#include <svx/sdgcpitm.hxx>
+#include <svx/sdggaitm.hxx>
+#include <sdginitm.hxx>
+#include <svx/sdgluitm.hxx>
+#include <svx/sdgmoitm.hxx>
+#include <sdgtritm.hxx>
+#include <sdr/properties/graphicproperties.hxx>
+#include <sdr/contact/viewcontactofgraphic.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <drawinglayer/processor2d/objectinfoextractor2d.hxx>
+#include <drawinglayer/primitive2d/objectinfoprimitive2d.hxx>
+#include <memory>
+
+using namespace ::com::sun::star;
+
+class SdrGraphicLink : public sfx2::SvBaseLink
+{
+ SdrGrafObj& rGrafObj;
+
+public:
+ explicit SdrGraphicLink(SdrGrafObj& rObj);
+
+ virtual void Closed() override;
+
+ virtual ::sfx2::SvBaseLink::UpdateResult DataChanged(
+ const OUString& rMimeType, const uno::Any & rValue ) override;
+
+ void Connect() { GetRealObject(); }
+};
+
+SdrGraphicLink::SdrGraphicLink(SdrGrafObj& rObj)
+: ::sfx2::SvBaseLink( ::SfxLinkUpdateMode::ONCALL, SotClipboardFormatId::SVXB )
+, rGrafObj( rObj )
+{
+ SetSynchron( false );
+}
+
+::sfx2::SvBaseLink::UpdateResult SdrGraphicLink::DataChanged(
+ const OUString& rMimeType, const uno::Any & rValue )
+{
+ SdrModel& rModel(rGrafObj.getSdrModelFromSdrObject());
+ sfx2::LinkManager* pLinkManager(rModel.GetLinkManager());
+
+ if( pLinkManager && rValue.hasValue() )
+ {
+ sfx2::LinkManager::GetDisplayNames( this, nullptr, &rGrafObj.aFileName, nullptr, &rGrafObj.aFilterName );
+
+ Graphic aGraphic;
+ if (pLinkManager->GetGraphicFromAny(rMimeType, rValue, aGraphic, nullptr))
+ {
+ rGrafObj.ImpSetLinkedGraphic(aGraphic);
+ }
+ else if( SotExchange::GetFormatIdFromMimeType( rMimeType ) != sfx2::LinkManager::RegisterStatusInfoId() )
+ {
+ // broadcasting, to update slide sorter
+ rGrafObj.BroadcastObjectChange();
+ }
+ }
+ return SUCCESS;
+}
+
+void SdrGraphicLink::Closed()
+{
+ // close connection; set pLink of the object to NULL, as link instance is just about getting destructed.
+ rGrafObj.ForceSwapIn();
+ rGrafObj.pGraphicLink=nullptr;
+ rGrafObj.ReleaseGraphicLink();
+ SvBaseLink::Closed();
+}
+
+std::unique_ptr<sdr::properties::BaseProperties> SdrGrafObj::CreateObjectSpecificProperties()
+{
+ return std::make_unique<sdr::properties::GraphicProperties>(*this);
+}
+
+
+// DrawContact section
+
+std::unique_ptr<sdr::contact::ViewContact> SdrGrafObj::CreateObjectSpecificViewContact()
+{
+ return std::make_unique<sdr::contact::ViewContactOfGraphic>(*this);
+}
+
+
+// check if SVG and if try to get ObjectInfoPrimitive2D and extract info
+
+void SdrGrafObj::onGraphicChanged()
+{
+ if (!mpGraphicObject || !mpGraphicObject->GetGraphic().isAvailable())
+ return;
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ if (!rVectorGraphicDataPtr)
+ return;
+
+ // Skip for PDF as it is only a bitmap primitive in a sequence and
+ // doesn't contain metadata. However getting the primitive sequence
+ // will also trigger a premature rendering of the PDF.
+ if (rVectorGraphicDataPtr->getType() == VectorGraphicDataType::Pdf)
+ return;
+
+ const std::deque<uno::Reference<graphic::XPrimitive2D>>& rContainer(rVectorGraphicDataPtr->getPrimitive2DSequence());
+
+ if (rContainer.empty())
+ return;
+
+ drawinglayer::geometry::ViewInformation2D aViewInformation2D;
+ drawinglayer::processor2d::ObjectInfoPrimitiveExtractor2D aProcessor(aViewInformation2D);
+
+ aProcessor.process(rContainer);
+
+ const drawinglayer::primitive2d::ObjectInfoPrimitive2D* pResult = aProcessor.getResult();
+
+ if (!pResult)
+ return;
+
+ OUString aName = pResult->getName();
+ OUString aTitle = pResult->getTitle();
+ OUString aDesc = pResult->getDesc();
+
+ if(!aName.isEmpty())
+ {
+ SetName(aName);
+ }
+
+ if(!aTitle.isEmpty())
+ {
+ SetTitle(aTitle);
+ }
+
+ if(!aDesc.isEmpty())
+ {
+ SetDescription(aDesc);
+ }
+}
+
+SdrGrafObj::SdrGrafObj(SdrModel& rSdrModel)
+: SdrRectObj(rSdrModel)
+ ,mpGraphicObject(new GraphicObject)
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::SdrGrafObj(SdrModel& rSdrModel, SdrGrafObj const & rSource)
+: SdrRectObj(rSdrModel, rSource)
+ ,mpGraphicObject(new GraphicObject)
+ ,pGraphicLink(nullptr)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+
+ aFileName = rSource.aFileName;
+ bMirrored = rSource.bMirrored;
+
+ mbIsSignatureLine = rSource.mbIsSignatureLine;
+ maSignatureLineId = rSource.maSignatureLineId;
+ maSignatureLineSuggestedSignerName = rSource.maSignatureLineSuggestedSignerName;
+ maSignatureLineSuggestedSignerTitle = rSource.maSignatureLineSuggestedSignerTitle;
+ maSignatureLineSuggestedSignerEmail = rSource.maSignatureLineSuggestedSignerEmail;
+ maSignatureLineSigningInstructions = rSource.maSignatureLineSigningInstructions;
+ mbIsSignatureLineShowSignDate = rSource.mbIsSignatureLineShowSignDate;
+ mbIsSignatureLineCanAddComment = rSource.mbIsSignatureLineCanAddComment;
+ mbSignatureLineIsSigned = false;
+ mpSignatureLineUnsignedGraphic = rSource.mpSignatureLineUnsignedGraphic;
+
+ if(rSource.mpBarCode)
+ {
+ mpBarCode = std::make_unique<drawing::BarCode>(*rSource.mpBarCode);
+ }
+ else
+ {
+ mpBarCode.reset();
+ }
+
+ if (mbIsSignatureLine && rSource.mpSignatureLineUnsignedGraphic)
+ mpGraphicObject->SetGraphic(rSource.mpSignatureLineUnsignedGraphic);
+ else
+ mpGraphicObject->SetGraphic( rSource.GetGraphic() );
+
+ if( rSource.IsLinkedGraphic() )
+ {
+ SetGraphicLink( aFileName );
+ }
+
+ ImpSetAttrToGrafInfo();
+}
+
+SdrGrafObj::SdrGrafObj(
+ SdrModel& rSdrModel,
+ const Graphic& rGraphic,
+ const tools::Rectangle& rRect)
+: SdrRectObj(rSdrModel, rRect)
+ ,mpGraphicObject(new GraphicObject(rGraphic))
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::SdrGrafObj(
+ SdrModel& rSdrModel,
+ const Graphic& rGraphic)
+: SdrRectObj(rSdrModel)
+ ,mpGraphicObject(new GraphicObject(rGraphic))
+ ,pGraphicLink(nullptr)
+ ,bMirrored(false)
+ ,mbIsSignatureLine(false)
+ ,mbIsSignatureLineShowSignDate(true)
+ ,mbIsSignatureLineCanAddComment(false)
+ ,mbSignatureLineIsSigned(false)
+{
+ onGraphicChanged();
+
+ // #i118485# Shear allowed and possible now
+ mbNoShear = false;
+
+ mbGrafAnimationAllowed = true;
+
+ // #i25616#
+ mbLineIsOutsideGeometry = true;
+
+ // #i25616#
+ mbSupportTextIndentingOnLineWidthChange = false;
+}
+
+SdrGrafObj::~SdrGrafObj()
+{
+ ImpDeregisterLink();
+}
+
+void SdrGrafObj::SetGraphicObject(const GraphicObject& rGraphicObject)
+{
+ mpGraphicObject.reset(new GraphicObject(rGraphicObject));
+ mpReplacementGraphicObject.reset();
+ mpGraphicObject->SetUserData();
+ SetChanged();
+ BroadcastObjectChange();
+ onGraphicChanged();
+}
+
+const GraphicObject& SdrGrafObj::GetGraphicObject(bool bForceSwapIn) const
+{
+ if (bForceSwapIn)
+ ForceSwapIn();
+ return *mpGraphicObject;
+}
+
+const GraphicObject* SdrGrafObj::GetReplacementGraphicObject() const
+{
+ if (!mpReplacementGraphicObject && mpGraphicObject)
+ {
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ if (rVectorGraphicDataPtr)
+ {
+ const_cast< SdrGrafObj* >(this)->mpReplacementGraphicObject.reset(new GraphicObject(rVectorGraphicDataPtr->getReplacement()));
+ }
+ else if (mpGraphicObject->GetGraphic().GetType() == GraphicType::GdiMetafile)
+ {
+ // Replacement graphic for PDF and metafiles is just the bitmap.
+ const_cast<SdrGrafObj*>(this)->mpReplacementGraphicObject.reset(new GraphicObject(mpGraphicObject->GetGraphic().GetBitmapEx()));
+ }
+ }
+
+ return mpReplacementGraphicObject.get();
+}
+
+void SdrGrafObj::NbcSetGraphic(const Graphic& rGraphic)
+{
+ mpGraphicObject->SetGraphic(rGraphic);
+ mpReplacementGraphicObject.reset();
+ mpGraphicObject->SetUserData();
+ onGraphicChanged();
+}
+
+void SdrGrafObj::SetGraphic( const Graphic& rGraphic )
+{
+ if (!rGraphic.getOriginURL().isEmpty())
+ {
+ ImpDeregisterLink();
+ aFileName = rGraphic.getOriginURL();
+ aFilterName = "";
+ }
+ NbcSetGraphic(rGraphic);
+ if (!rGraphic.getOriginURL().isEmpty())
+ {
+ ImpRegisterLink();
+ mpGraphicObject->SetUserData();
+ }
+ SetChanged();
+ BroadcastObjectChange();
+ ForceSwapIn();
+}
+
+const Graphic& SdrGrafObj::GetGraphic() const
+{
+ return mpGraphicObject->GetGraphic();
+}
+
+Graphic SdrGrafObj::GetTransformedGraphic( SdrGrafObjTransformsAttrs nTransformFlags ) const
+{
+ // Refactored most of the code to GraphicObject, where
+ // everybody can use e.g. the cropping functionality
+ MapMode aDestMap(getSdrModelFromSdrObject().GetScaleUnit());
+ const Size aDestSize( GetLogicRect().GetSize() );
+ GraphicAttr aActAttr = GetGraphicAttr(nTransformFlags);
+
+ // Delegate to moved code in GraphicObject
+ return GetGraphicObject().GetTransformedGraphic( aDestSize, aDestMap, aActAttr );
+}
+
+GraphicType SdrGrafObj::GetGraphicType() const
+{
+ return mpGraphicObject->GetType();
+}
+
+GraphicAttr SdrGrafObj::GetGraphicAttr( SdrGrafObjTransformsAttrs nTransformFlags ) const
+{
+ GraphicAttr aActAttr;
+
+ GraphicType eType = GetGraphicType();
+ if( SdrGrafObjTransformsAttrs::NONE != nTransformFlags &&
+ GraphicType::NONE != eType )
+ {
+ const bool bMirror = bool( nTransformFlags & SdrGrafObjTransformsAttrs::MIRROR );
+ const bool bRotate = bool( nTransformFlags & SdrGrafObjTransformsAttrs::ROTATE ) &&
+ (maGeo.m_nRotationAngle && maGeo.m_nRotationAngle != 18000_deg100);
+
+ // Need cropping info earlier
+ const_cast<SdrGrafObj*>(this)->ImpSetAttrToGrafInfo();
+
+ // Actually transform the graphic only in this case.
+ // Cropping always happens, though.
+ aActAttr = aGrafInfo;
+
+ if( bMirror )
+ {
+ sal_uInt16 nMirrorCase = ( maGeo.m_nRotationAngle == 18000_deg100 ) ? ( bMirrored ? 3 : 4 ) : ( bMirrored ? 2 : 1 );
+ bool bHMirr = nMirrorCase == 2 || nMirrorCase == 4;
+ bool bVMirr = nMirrorCase == 3 || nMirrorCase == 4;
+
+ aActAttr.SetMirrorFlags( ( bHMirr ? BmpMirrorFlags::Horizontal : BmpMirrorFlags::NONE ) | ( bVMirr ? BmpMirrorFlags::Vertical : BmpMirrorFlags::NONE ) );
+ }
+
+ if( bRotate )
+ aActAttr.SetRotation( to<Degree10>(maGeo.m_nRotationAngle ) );
+ }
+
+ return aActAttr;
+}
+
+bool SdrGrafObj::IsAnimated() const
+{
+ return mpGraphicObject->IsAnimated();
+}
+
+bool SdrGrafObj::IsEPS() const
+{
+ return mpGraphicObject->IsEPS();
+}
+
+MapMode SdrGrafObj::GetGrafPrefMapMode() const
+{
+ return mpGraphicObject->GetPrefMapMode();
+}
+
+Size SdrGrafObj::GetGrafPrefSize() const
+{
+ return mpGraphicObject->GetPrefSize();
+}
+
+void SdrGrafObj::SetGrafStreamURL( const OUString& rGraphicStreamURL )
+{
+ if( rGraphicStreamURL.isEmpty() )
+ {
+ mpGraphicObject->SetUserData();
+ }
+ else if(getSdrModelFromSdrObject().IsSwapGraphics() )
+ {
+ mpGraphicObject->SetUserData( rGraphicStreamURL );
+ }
+}
+
+OUString const & SdrGrafObj::GetGrafStreamURL() const
+{
+ return mpGraphicObject->GetUserData();
+}
+
+Size SdrGrafObj::getOriginalSize() const
+{
+ Size aSize = GetGrafPrefSize();
+
+ if (GetGrafPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(aSize, MapMode(getSdrModelFromSdrObject().GetScaleUnit()));
+ else
+ aSize = OutputDevice::LogicToLogic(aSize, GetGrafPrefMapMode(), MapMode(getSdrModelFromSdrObject().GetScaleUnit()));
+
+ if (aGrafInfo.IsCropped())
+ {
+ const tools::Long aCroppedWidth(aSize.getWidth() - aGrafInfo.GetLeftCrop()
+ - aGrafInfo.GetRightCrop());
+ const tools::Long aCroppedHeight(aSize.getHeight() - aGrafInfo.GetTopCrop()
+ - aGrafInfo.GetBottomCrop());
+
+ aSize = Size(aCroppedWidth, aCroppedHeight);
+ }
+
+ return aSize;
+}
+
+// TODO Remove
+void SdrGrafObj::ForceSwapIn() const
+{
+ if (pGraphicLink && (mpGraphicObject->GetType() == GraphicType::NONE ||
+ mpGraphicObject->GetType() == GraphicType::Default) )
+ {
+ pGraphicLink->Update();
+ }
+}
+
+void SdrGrafObj::ImpRegisterLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if( pLinkManager != nullptr && pGraphicLink == nullptr )
+ {
+ if (!aFileName.isEmpty())
+ {
+ pGraphicLink = new SdrGraphicLink( *this );
+ pLinkManager->InsertFileLink(
+ *pGraphicLink, sfx2::SvBaseLinkObjectType::ClientGraphic, aFileName, (aFilterName.isEmpty() ? nullptr : &aFilterName));
+ pGraphicLink->Connect();
+ }
+ }
+}
+
+void SdrGrafObj::ImpDeregisterLink()
+{
+ sfx2::LinkManager* pLinkManager(getSdrModelFromSdrObject().GetLinkManager());
+
+ if( pLinkManager != nullptr && pGraphicLink!=nullptr)
+ {
+ // When using Remove, the *pGraphicLink is implicitly deleted
+ pLinkManager->Remove( pGraphicLink );
+ pGraphicLink=nullptr;
+ }
+}
+
+void SdrGrafObj::SetGraphicLink(const OUString& rFileName)
+{
+ Graphic aGraphic;
+ aGraphic.setOriginURL(rFileName);
+ SetGraphic(aGraphic);
+}
+
+void SdrGrafObj::ReleaseGraphicLink()
+{
+ ImpDeregisterLink();
+ aFileName.clear();
+ aFilterName.clear();
+
+ auto aGraphic = mpGraphicObject->GetGraphic();
+ aGraphic.setOriginURL("");
+ SetGraphic(aGraphic);
+}
+
+bool SdrGrafObj::IsLinkedGraphic() const
+{
+ return !mpGraphicObject->GetGraphic().getOriginURL().isEmpty();
+}
+
+void SdrGrafObj::TakeObjInfo(SdrObjTransformInfoRec& rInfo) const
+{
+ bool bNoPresGrf = ( mpGraphicObject->GetType() != GraphicType::NONE ) && !m_bEmptyPresObj;
+
+ rInfo.bResizeFreeAllowed = maGeo.m_nRotationAngle.get() % 9000 == 0 ||
+ maGeo.m_nRotationAngle.get() % 18000 == 0 ||
+ maGeo.m_nRotationAngle.get() % 27000 == 0;
+
+ rInfo.bResizePropAllowed = true;
+ rInfo.bRotateFreeAllowed = bNoPresGrf;
+ rInfo.bRotate90Allowed = bNoPresGrf;
+ rInfo.bMirrorFreeAllowed = bNoPresGrf;
+ rInfo.bMirror45Allowed = bNoPresGrf;
+ rInfo.bMirror90Allowed = !m_bEmptyPresObj;
+ rInfo.bTransparenceAllowed = false;
+
+ // #i118485# Shear allowed and possible now
+ rInfo.bShearAllowed = true;
+
+ rInfo.bEdgeRadiusAllowed=false;
+ rInfo.bCanConvToPath = !IsEPS();
+ rInfo.bCanConvToPathLineToArea = false;
+ rInfo.bCanConvToPolyLineToArea = false;
+ rInfo.bCanConvToPoly = !IsEPS();
+ rInfo.bCanConvToContour = (rInfo.bCanConvToPoly || LineGeometryUsageIsNecessary());
+}
+
+SdrObjKind SdrGrafObj::GetObjIdentifier() const
+{
+ return SdrObjKind::Graphic;
+}
+
+void SdrGrafObj::ImpSetLinkedGraphic( const Graphic& rGraphic )
+{
+ const bool bIsChanged(getSdrModelFromSdrObject().IsChanged());
+ NbcSetGraphic( rGraphic );
+ ActionChanged();
+ BroadcastObjectChange();
+ getSdrModelFromSdrObject().SetChanged(bIsChanged);
+}
+
+OUString SdrGrafObj::TakeObjNameSingul() const
+{
+ if (!mpGraphicObject)
+ return OUString();
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ OUStringBuffer sName;
+
+ if (rVectorGraphicDataPtr)
+ {
+ switch (rVectorGraphicDataPtr->getType())
+ {
+ case VectorGraphicDataType::Svg:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFSVG));
+ break;
+ }
+ case VectorGraphicDataType::Wmf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFWMF));
+ break;
+ }
+ case VectorGraphicDataType::Emf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFEMF));
+ break;
+ }
+ case VectorGraphicDataType::Pdf:
+ {
+ sName.append(SvxResId(STR_ObjNameSingulGRAFPDF));
+ break;
+ }
+ } //no default, see tdf#137813
+ }
+ else
+ {
+ switch( mpGraphicObject->GetType() )
+ {
+ case GraphicType::Bitmap:
+ {
+ TranslateId pId = ( ( mpGraphicObject->IsTransparent() || GetObjectItem( SDRATTR_GRAFTRANSPARENCE ).GetValue() ) ?
+ ( IsLinkedGraphic() ? STR_ObjNameSingulGRAFBMPTRANSLNK : STR_ObjNameSingulGRAFBMPTRANS ) :
+ ( IsLinkedGraphic() ? STR_ObjNameSingulGRAFBMPLNK : STR_ObjNameSingulGRAFBMP ) );
+
+ sName.append(SvxResId(pId));
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFMTFLNK : STR_ObjNameSingulGRAFMTF));
+ break;
+
+ case GraphicType::NONE:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFNONELNK : STR_ObjNameSingulGRAFNONE));
+ break;
+
+ default:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNameSingulGRAFLNK : STR_ObjNameSingulGRAF));
+ break;
+ }
+ }
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ sName.append(" '" + aName + "\'" );
+ }
+
+ return sName.makeStringAndClear();
+}
+
+OUString SdrGrafObj::TakeObjNamePlural() const
+{
+ if (!mpGraphicObject)
+ return OUString();
+
+ auto const & rVectorGraphicDataPtr = mpGraphicObject->GetGraphic().getVectorGraphicData();
+
+ OUStringBuffer sName;
+
+ if (rVectorGraphicDataPtr)
+ {
+ switch (rVectorGraphicDataPtr->getType())
+ {
+ case VectorGraphicDataType::Svg:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFSVG));
+ break;
+ }
+ case VectorGraphicDataType::Wmf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFWMF));
+ break;
+ }
+ case VectorGraphicDataType::Emf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFEMF));
+ break;
+ }
+ case VectorGraphicDataType::Pdf:
+ {
+ sName.append(SvxResId(STR_ObjNamePluralGRAFPDF));
+ break;
+ }
+ } //no default, see tdf#137813
+ }
+ else
+ {
+ switch(mpGraphicObject->GetType())
+ {
+ case GraphicType::Bitmap:
+ {
+ TranslateId pId = ( ( mpGraphicObject->IsTransparent() || GetObjectItem( SDRATTR_GRAFTRANSPARENCE ).GetValue() ) ?
+ ( IsLinkedGraphic() ? STR_ObjNamePluralGRAFBMPTRANSLNK : STR_ObjNamePluralGRAFBMPTRANS ) :
+ ( IsLinkedGraphic() ? STR_ObjNamePluralGRAFBMPLNK : STR_ObjNamePluralGRAFBMP ) );
+
+ sName.append(SvxResId(pId));
+ }
+ break;
+
+ case GraphicType::GdiMetafile:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFMTFLNK : STR_ObjNamePluralGRAFMTF));
+ break;
+
+ case GraphicType::NONE:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFNONELNK : STR_ObjNamePluralGRAFNONE));
+ break;
+
+ default:
+ sName.append(SvxResId(IsLinkedGraphic() ? STR_ObjNamePluralGRAFLNK : STR_ObjNamePluralGRAF));
+ break;
+ }
+ }
+
+ const OUString aName(GetName());
+
+ if (!aName.isEmpty())
+ {
+ sName.append(" '" + aName + "\'");
+ }
+
+ return sName.makeStringAndClear();
+}
+
+rtl::Reference<SdrObject> SdrGrafObj::getFullDragClone() const
+{
+ // call parent
+ rtl::Reference<SdrObject> pRetval = SdrRectObj::getFullDragClone();
+
+ // #i103116# the full drag clone leads to problems
+ // with linked graphics, so reset the link in this
+ // temporary interaction object and load graphic
+ if(pRetval && IsLinkedGraphic())
+ {
+ static_cast< SdrGrafObj* >(pRetval.get())->ReleaseGraphicLink();
+ }
+
+ return pRetval;
+}
+
+rtl::Reference<SdrObject> SdrGrafObj::CloneSdrObject(SdrModel& rTargetModel) const
+{
+ return new SdrGrafObj(rTargetModel, *this);
+}
+
+sal_uInt32 SdrGrafObj::GetHdlCount() const
+{
+ return 8;
+}
+
+void SdrGrafObj::AddToHdlList(SdrHdlList& rHdlList) const
+{
+ SdrHdlList tempList(nullptr);
+ SdrRectObj::AddToHdlList( tempList );
+ tempList.RemoveHdl(0);
+ tempList.MoveTo(rHdlList);
+}
+
+void SdrGrafObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+{
+ SdrRectObj::NbcResize( rRef, xFact, yFact );
+
+ bool bMirrX = xFact.GetNumerator() < 0;
+ bool bMirrY = yFact.GetNumerator() < 0;
+
+ if( bMirrX != bMirrY )
+ bMirrored = !bMirrored;
+}
+
+void SdrGrafObj::NbcMirror(const Point& rRef1, const Point& rRef2)
+{
+ SdrRectObj::NbcMirror(rRef1,rRef2);
+ bMirrored = !bMirrored;
+}
+
+std::unique_ptr<SdrObjGeoData> SdrGrafObj::NewGeoData() const
+{
+ return std::make_unique<SdrGrafObjGeoData>();
+}
+
+void SdrGrafObj::SaveGeoData(SdrObjGeoData& rGeo) const
+{
+ SdrRectObj::SaveGeoData(rGeo);
+ SdrGrafObjGeoData& rGGeo=static_cast<SdrGrafObjGeoData&>(rGeo);
+ rGGeo.bMirrored=bMirrored;
+}
+
+void SdrGrafObj::RestoreGeoData(const SdrObjGeoData& rGeo)
+{
+ SdrRectObj::RestoreGeoData(rGeo);
+ const SdrGrafObjGeoData& rGGeo=static_cast<const SdrGrafObjGeoData&>(rGeo);
+ bMirrored=rGGeo.bMirrored;
+}
+
+void SdrGrafObj::handlePageChange(SdrPage* pOldPage, SdrPage* pNewPage)
+{
+ const bool bRemove(pNewPage == nullptr && pOldPage != nullptr);
+ const bool bInsert(pNewPage != nullptr && pOldPage == nullptr);
+
+ if( bRemove )
+ {
+ // No SwapIn necessary here, because if something's not loaded, it can't be animated either.
+ if( mpGraphicObject->IsAnimated())
+ mpGraphicObject->StopAnimation();
+
+ if( pGraphicLink != nullptr )
+ ImpDeregisterLink();
+ }
+
+ // call parent
+ SdrRectObj::handlePageChange(pOldPage, pNewPage);
+
+ if (!aFileName.isEmpty() && bInsert)
+ {
+ ImpRegisterLink();
+ }
+}
+
+void SdrGrafObj::StartAnimation()
+{
+ SetGrafAnimationAllowed(true);
+}
+
+bool SdrGrafObj::HasGDIMetaFile() const
+{
+ return( mpGraphicObject->GetType() == GraphicType::GdiMetafile );
+}
+
+bool SdrGrafObj::isEmbeddedVectorGraphicData() const
+{
+ return GraphicType::Bitmap == GetGraphicType() && GetGraphic().getVectorGraphicData();
+}
+
+GDIMetaFile SdrGrafObj::getMetafileFromEmbeddedVectorGraphicData() const
+{
+ GDIMetaFile aRetval;
+
+ if(isEmbeddedVectorGraphicData())
+ {
+ ScopedVclPtrInstance< VirtualDevice > pOut;
+ const tools::Rectangle aBoundRect(GetCurrentBoundRect());
+ const MapMode aMap(getSdrModelFromSdrObject().GetScaleUnit());
+
+ pOut->EnableOutput(false);
+ pOut->SetMapMode(aMap);
+ aRetval.Record(pOut);
+ SingleObjectPainter(*pOut);
+ aRetval.Stop();
+ aRetval.WindStart();
+ aRetval.Move(-aBoundRect.Left(), -aBoundRect.Top());
+ aRetval.SetPrefMapMode(aMap);
+ aRetval.SetPrefSize(aBoundRect.GetSize());
+ }
+
+ return aRetval;
+}
+
+GDIMetaFile SdrGrafObj::GetMetaFile(GraphicType &rGraphicType) const
+{
+ if (isEmbeddedVectorGraphicData())
+ {
+ // Embedded Vector Graphic Data
+ // There is currently no helper to create SdrObjects from primitives (even if I'm thinking
+ // about writing one for some time). To get the roundtrip to SdrObjects it is necessary to
+ // use the old converter path over the MetaFile mechanism. Create Metafile from Svg
+ // primitives here pretty directly
+ rGraphicType = GraphicType::GdiMetafile;
+ return getMetafileFromEmbeddedVectorGraphicData();
+ }
+ else if (GraphicType::GdiMetafile == rGraphicType)
+ {
+ return GetTransformedGraphic(SdrGrafObjTransformsAttrs::MIRROR).GetGDIMetaFile();
+ }
+ return GDIMetaFile();
+}
+
+rtl::Reference<SdrObject> SdrGrafObj::DoConvertToPolyObj(bool bBezier, bool bAddText ) const
+{
+ rtl::Reference<SdrObject> pRetval;
+ GraphicType aGraphicType(GetGraphicType());
+ GDIMetaFile aMtf(GetMetaFile(aGraphicType));
+ switch(aGraphicType)
+ {
+ case GraphicType::GdiMetafile:
+ {
+ // Sort into group and return ONLY those objects that can be created from the MetaFile.
+ ImpSdrGDIMetaFileImport aFilter(
+ getSdrModelFromSdrObject(),
+ GetLayer(),
+ getRectangle());
+ rtl::Reference<SdrObjGroup> pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
+
+ if(aFilter.DoImport(aMtf, *pGrp->GetSubList(), 0))
+ {
+ {
+ // copy transformation
+ GeoStat aGeoStat(GetGeoStat());
+
+ if(aGeoStat.m_nShearAngle)
+ {
+ aGeoStat.RecalcTan();
+ pGrp->NbcShear(getRectangle().TopLeft(), aGeoStat.m_nShearAngle, aGeoStat.mfTanShearAngle, false);
+ }
+
+ if(aGeoStat.m_nRotationAngle)
+ {
+ aGeoStat.RecalcSinCos();
+ pGrp->NbcRotate(getRectangle().TopLeft(), aGeoStat.m_nRotationAngle, aGeoStat.mfSinRotationAngle, aGeoStat.mfCosRotationAngle);
+ }
+ }
+
+ pRetval = pGrp;
+ pGrp->NbcSetLayer(GetLayer());
+
+ if(bAddText)
+ {
+ pRetval = ImpConvertAddText(pRetval, bBezier);
+ }
+
+ // convert all children
+ if( pRetval )
+ {
+ pRetval = pRetval->DoConvertToPolyObj(bBezier, bAddText);
+
+ if( pRetval )
+ {
+ // flatten subgroups. As we call
+ // DoConvertToPolyObj() on the resulting group
+ // objects, subgroups can exist (e.g. text is
+ // a group object for every line).
+ SdrObjList* pList = pRetval->GetSubList();
+ if( pList )
+ pList->FlattenGroups();
+ }
+ }
+ }
+ else
+ pGrp.clear();
+
+ // #i118485# convert line and fill
+ rtl::Reference<SdrObject> pLineFill = SdrRectObj::DoConvertToPolyObj(bBezier, false);
+
+ if(pLineFill)
+ {
+ if(pRetval)
+ {
+ pGrp = dynamic_cast< SdrObjGroup* >(pRetval.get());
+
+ if(!pGrp)
+ {
+ pGrp = new SdrObjGroup(getSdrModelFromSdrObject());
+ pGrp->NbcSetLayer(GetLayer());
+ pGrp->GetSubList()->NbcInsertObject(pRetval.get());
+ }
+
+ pGrp->GetSubList()->NbcInsertObject(pLineFill.get(), 0);
+ }
+ else
+ {
+ pRetval = pLineFill;
+ }
+ }
+
+ break;
+ }
+ case GraphicType::Bitmap:
+ {
+ // create basic object and add fill
+ pRetval = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
+
+ // save bitmap as an attribute
+ if(pRetval)
+ {
+ // retrieve bitmap for the fill
+ SfxItemSet aSet(GetObjectItemSet());
+
+ aSet.Put(XFillStyleItem(drawing::FillStyle_BITMAP));
+ const BitmapEx aBitmapEx(GetTransformedGraphic().GetBitmapEx());
+ aSet.Put(XFillBitmapItem(OUString(), Graphic(aBitmapEx)));
+ aSet.Put(XFillBmpTileItem(false));
+
+ pRetval->SetMergedItemSet(aSet);
+ }
+ break;
+ }
+ case GraphicType::NONE:
+ case GraphicType::Default:
+ {
+ pRetval = SdrRectObj::DoConvertToPolyObj(bBezier, bAddText);
+ break;
+ }
+ }
+
+ return pRetval;
+}
+
+void SdrGrafObj::Notify( SfxBroadcaster& rBC, const SfxHint& rHint )
+{
+ SetXPolyDirty();
+ SdrRectObj::Notify( rBC, rHint );
+ ImpSetAttrToGrafInfo();
+}
+
+
+void SdrGrafObj::SetMirrored( bool _bMirrored )
+{
+ bMirrored = _bMirrored;
+}
+
+void SdrGrafObj::ImpSetAttrToGrafInfo()
+{
+ const SfxItemSet& rSet = GetObjectItemSet();
+ const sal_uInt16 nTrans = rSet.Get( SDRATTR_GRAFTRANSPARENCE ).GetValue();
+ const SdrGrafCropItem& rCrop = rSet.Get( SDRATTR_GRAFCROP );
+
+ aGrafInfo.SetLuminance( rSet.Get( SDRATTR_GRAFLUMINANCE ).GetValue() );
+ aGrafInfo.SetContrast( rSet.Get( SDRATTR_GRAFCONTRAST ).GetValue() );
+ aGrafInfo.SetChannelR( rSet.Get( SDRATTR_GRAFRED ).GetValue() );
+ aGrafInfo.SetChannelG( rSet.Get( SDRATTR_GRAFGREEN ).GetValue() );
+ aGrafInfo.SetChannelB( rSet.Get( SDRATTR_GRAFBLUE ).GetValue() );
+ aGrafInfo.SetGamma( rSet.Get( SDRATTR_GRAFGAMMA ).GetValue() * 0.01 );
+ aGrafInfo.SetAlpha( 255 - static_cast<sal_uInt8>(FRound( std::min( nTrans, sal_uInt16(100) ) * 2.55 )) );
+ aGrafInfo.SetInvert( rSet.Get( SDRATTR_GRAFINVERT ).GetValue() );
+ aGrafInfo.SetDrawMode( rSet.Get( SDRATTR_GRAFMODE ).GetValue() );
+ aGrafInfo.SetCrop( rCrop.GetLeft(), rCrop.GetTop(), rCrop.GetRight(), rCrop.GetBottom() );
+
+ SetXPolyDirty();
+ SetBoundAndSnapRectsDirty();
+}
+
+void SdrGrafObj::AdjustToMaxRect( const tools::Rectangle& rMaxRect, bool bShrinkOnly )
+{
+ Size aSize;
+ Size aMaxSize( rMaxRect.GetSize() );
+ if (mpGraphicObject->GetPrefMapMode().GetMapUnit() == MapUnit::MapPixel)
+ aSize = Application::GetDefaultDevice()->PixelToLogic(mpGraphicObject->GetPrefSize(), MapMode(MapUnit::Map100thMM));
+ else
+ aSize = OutputDevice::LogicToLogic( mpGraphicObject->GetPrefSize(),
+ mpGraphicObject->GetPrefMapMode(),
+ MapMode( MapUnit::Map100thMM ) );
+
+ if( aSize.IsEmpty() )
+ return;
+
+ Point aPos( rMaxRect.TopLeft() );
+
+ // if the graphic is too large, fit it to page
+ if ( (!bShrinkOnly ||
+ ( aSize.Height() > aMaxSize.Height() ) ||
+ ( aSize.Width() > aMaxSize.Width() ) )&&
+ aSize.Height() && aMaxSize.Height() )
+ {
+ float fGrfWH = static_cast<float>(aSize.Width()) /
+ static_cast<float>(aSize.Height());
+ float fWinWH = static_cast<float>(aMaxSize.Width()) /
+ static_cast<float>(aMaxSize.Height());
+
+ // Scale graphic to page size
+ if ( fGrfWH < fWinWH )
+ {
+ aSize.setWidth( static_cast<tools::Long>(aMaxSize.Height() * fGrfWH) );
+ aSize.setHeight( aMaxSize.Height() );
+ }
+ else if ( fGrfWH > 0.F )
+ {
+ aSize.setWidth( aMaxSize.Width() );
+ aSize.setHeight( static_cast<tools::Long>(aMaxSize.Width() / fGrfWH) );
+ }
+
+ aPos = rMaxRect.Center();
+ }
+
+ if( bShrinkOnly )
+ aPos = getRectangle().TopLeft();
+
+ aPos.AdjustX( -(aSize.Width() / 2) );
+ aPos.AdjustY( -(aSize.Height() / 2) );
+ SetLogicRect( tools::Rectangle( aPos, aSize ) );
+}
+
+void SdrGrafObj::SetGrafAnimationAllowed(bool bNew)
+{
+ if(mbGrafAnimationAllowed != bNew)
+ {
+ mbGrafAnimationAllowed = bNew;
+ ActionChanged();
+ }
+}
+
+uno::Reference<io::XInputStream> SdrGrafObj::getInputStream() const
+{
+ uno::Reference<io::XInputStream> xStream;
+
+ if (mpGraphicObject && GetGraphic().IsGfxLink())
+ {
+ Graphic aGraphic( GetGraphic() );
+ GfxLink aLink( aGraphic.GetGfxLink() );
+ sal_uInt32 nSize = aLink.GetDataSize();
+ const void* pSourceData = static_cast<const void*>(aLink.GetData());
+ if( nSize && pSourceData )
+ {
+ sal_uInt8 * pBuffer = new sal_uInt8[ nSize ];
+ memcpy( pBuffer, pSourceData, nSize );
+
+ SvMemoryStream* pStream = new SvMemoryStream( static_cast<void*>(pBuffer), static_cast<std::size_t>(nSize), StreamMode::READ );
+ pStream->ObjectOwnsMemory( true );
+ xStream.set( new utl::OInputStreamWrapper( pStream, true ) );
+ }
+ }
+
+ if (!xStream.is() && !aFileName.isEmpty())
+ {
+ SvFileStream* pStream = new SvFileStream( aFileName, StreamMode::READ );
+ xStream.set( new utl::OInputStreamWrapper( pStream ) );
+ }
+
+ return xStream;
+}
+
+// moved crop handle creation here; this is the object type using them
+void SdrGrafObj::addCropHandles(SdrHdlList& rTarget) const
+{
+ basegfx::B2DHomMatrix aMatrix;
+ basegfx::B2DPolyPolygon aPolyPolygon;
+
+ // get object transformation
+ TRGetBaseGeometry(aMatrix, aPolyPolygon);
+
+ // part of object transformation correction, but used later, so defined outside next scope
+ double fShearX(0.0), fRotate(0.0);
+
+ { // TTTT correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
+ basegfx::B2DTuple aScale;
+ basegfx::B2DTuple aTranslate;
+
+ aMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+
+ if(!basegfx::fTools::equalZero(fShearX))
+ {
+ // shearX is used, correct it
+ fShearX = -fShearX;
+ }
+
+ aMatrix = basegfx::utils::createScaleShearXRotateTranslateB2DHomMatrix(
+ aScale,
+ fShearX,
+ fRotate,
+ aTranslate);
+ }
+
+ // get crop values
+ const SdrGrafCropItem& rCrop = GetMergedItem(SDRATTR_GRAFCROP);
+
+ if(rCrop.GetLeft() || rCrop.GetTop() || rCrop.GetRight() ||rCrop.GetBottom())
+ {
+ // decompose object transformation to have current translate and scale
+ basegfx::B2DVector aScale, aTranslate;
+ double fLclRotate, fLclShearX;
+
+ aMatrix.decompose(aScale, aTranslate, fLclRotate, fLclShearX);
+
+ if(!aScale.equalZero())
+ {
+ // get crop scale
+ const basegfx::B2DVector aCropScaleFactor(
+ GetGraphicObject().calculateCropScaling(
+ aScale.getX(),
+ aScale.getY(),
+ rCrop.GetLeft(),
+ rCrop.GetTop(),
+ rCrop.GetRight(),
+ rCrop.GetBottom()));
+
+ // apply crop scale
+ const double fCropLeft(rCrop.GetLeft() * aCropScaleFactor.getX());
+ const double fCropTop(rCrop.GetTop() * aCropScaleFactor.getY());
+ const double fCropRight(rCrop.GetRight() * aCropScaleFactor.getX());
+ const double fCropBottom(rCrop.GetBottom() * aCropScaleFactor.getY());
+ basegfx::B2DHomMatrix aMatrixForCropViewHdl(aMatrix);
+
+ if(IsMirrored())
+ {
+ // create corrected new matrix, TTTT can be removed with aw080
+ // the old mirror only can mirror horizontally; the vertical mirror
+ // is faked by using the horizontal and 180 degree rotation. Since
+ // the object can be rotated differently from 180 degree, this is
+ // not safe to detect. Just correct horizontal mirror (which is
+ // in IsMirrored()) and keep the rotation angle
+ // caution: Do not modify aMatrix, it is used below to calculate
+ // the exact handle positions
+ basegfx::B2DHomMatrix aPreMultiply;
+
+ // mirrored X, apply
+ aPreMultiply.translate(-0.5, 0.0);
+ aPreMultiply.scale(-1.0, 1.0);
+ aPreMultiply.translate(0.5, 0.0);
+
+ aMatrixForCropViewHdl = aMatrixForCropViewHdl * aPreMultiply;
+ }
+
+ rTarget.AddHdl(
+ std::make_unique<SdrCropViewHdl>(
+ aMatrixForCropViewHdl,
+ GetGraphicObject().GetGraphic(),
+ fCropLeft,
+ fCropTop,
+ fCropRight,
+ fCropBottom));
+ }
+ }
+
+ basegfx::B2DPoint aPos;
+
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperLeft, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.5, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Upper, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 0.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::UpperRight, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Left , fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 0.5);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Right, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerLeft, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(0.5, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::Lower, fShearX, fRotate));
+ aPos = aMatrix * basegfx::B2DPoint(1.0, 1.0);
+ rTarget.AddHdl(std::make_unique<SdrCropHdl>(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), SdrHdlKind::LowerRight, fShearX, fRotate));
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */