svx/source/svdraw/svdedtv2.cxx |   87 +++++++++++++++++++++++++++++++++++++++++
 1 file changed, 87 insertions(+)

New commits:
commit 085164937959b99e7dac4332a3de36cc0cf3ed7f
Author:     lancebord <[email protected]>
AuthorDate: Wed Mar 11 01:55:40 2026 -0400
Commit:     Noel Grandin <[email protected]>
CommitDate: Thu Mar 12 08:25:47 2026 +0100

    tdf#40259: pre-crop graphic objects before shape intersect
    
    fixes issue where intersect would rescale the grpahic to the new
    intersect region instead of properly masking the original image.
    Cropping the graphic resolves this.
    
    Change-Id: I2f64a199ff82257ad2ad141e2d36fce9f34af1b2
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/201423
    Reviewed-by: Noel Grandin <[email protected]>
    Tested-by: Jenkins

diff --git a/svx/source/svdraw/svdedtv2.cxx b/svx/source/svdraw/svdedtv2.cxx
index 193a1c9e91f7..925f24061e95 100644
--- a/svx/source/svdraw/svdedtv2.cxx
+++ b/svx/source/svdraw/svdedtv2.cxx
@@ -33,6 +33,10 @@
 #include <svx/xfillit0.hxx>
 #include <svx/xlineit0.hxx>
 #include <svx/xtextit0.hxx>
+#include <svx/svdograf.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <svx/sdgcpitm.hxx>   // SdrGrafCropItem
+#include <svx/sdmetitm.hxx>
 #include "svdfmtf.hxx"
 #include <svdpdf.hxx>
 #include <svx/svdetc.hxx>
@@ -49,6 +53,7 @@
 #include <memory>
 #include <vector>
 #include <vcl/graph.hxx>
+#include <vcl/svapp.hxx>
 #include <vcl/vectorgraphicdata.hxx>
 #include <svx/svxids.hrc>
 #include <dstribut_enum.hxx>
@@ -1013,6 +1018,88 @@ void SdrEditView::MergeMarkedObjects(SdrMergeMode eMode)
     if( bUndo )
         BegUndo();
 
+    if (eMode == SdrMergeMode::Intersect)
+    {
+        tools::Rectangle aShapeBoundRect;
+        bool bHasShape = false;
+        bool bHasGraf = false;
+
+        for (size_t a = 0; a < rMarkList.GetMarkCount(); ++a)
+        {
+            SdrObject* pObj = rMarkList.GetMark(a)->GetMarkedSdrObj();
+            if (dynamic_cast<SdrGrafObj*>(pObj))
+            {
+                bHasGraf = true;
+            }
+            else
+            {
+                tools::Rectangle aBound = pObj->GetCurrentBoundRect();
+                if (!bHasShape)
+                    aShapeBoundRect = aBound;
+                else
+                    aShapeBoundRect.Union(aBound);
+                bHasShape = true;
+            }
+        }
+
+        // Only pre-crop if combining image with shape
+        if (bHasGraf && bHasShape)
+        {
+            for (size_t a = 0; a < rMarkList.GetMarkCount(); ++a)
+            {
+                SdrMark* pMark = rMarkList.GetMark(a);
+                SdrGrafObj* pGrafObj = 
dynamic_cast<SdrGrafObj*>(pMark->GetMarkedSdrObj());
+                if (!pGrafObj)
+                    continue;
+
+                tools::Rectangle aGrafRect = pGrafObj->GetLogicRect();
+                tools::Rectangle aCropTarget = 
aGrafRect.GetIntersection(aShapeBoundRect);
+                if (aCropTarget.IsEmpty() || aCropTarget == aGrafRect)
+                    continue;
+
+                tools::Long nLeft   = std::max(aCropTarget.Left()  - 
aGrafRect.Left(),  tools::Long(0));
+                tools::Long nTop    = std::max(aCropTarget.Top()   - 
aGrafRect.Top(),   tools::Long(0));
+                tools::Long nRight  = std::max(aGrafRect.Right()   - 
aCropTarget.Right(),  tools::Long(0));
+                tools::Long nBottom = std::max(aGrafRect.Bottom()  - 
aCropTarget.Bottom(), tools::Long(0));
+
+                const SdrGrafCropItem& rExistingCrop =
+                    
pGrafObj->GetMergedItem(SDRATTR_GRAFCROP).StaticWhichCast(SDRATTR_GRAFCROP);
+
+                const MapMode aMapMode100thmm(MapUnit::Map100thMM);
+                const GraphicObject* pGraphicObject = 
&pGrafObj->GetGraphicObject();
+                Size aGraphicSize(pGraphicObject->GetPrefSize());
+                if (MapUnit::MapPixel == 
pGraphicObject->GetPrefMapMode().GetMapUnit())
+                    aGraphicSize = 
Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapMode100thmm);
+                else
+                    aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, 
pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
+
+                if (aGraphicSize.IsEmpty())
+                    continue;
+
+                double fScaleX = (aGraphicSize.Width()  - 
rExistingCrop.GetLeft() - rExistingCrop.GetRight())
+                                 / static_cast<double>(aGrafRect.GetWidth());
+                double fScaleY = (aGraphicSize.Height() - 
rExistingCrop.GetTop()  - rExistingCrop.GetBottom())
+                                 / static_cast<double>(aGrafRect.GetHeight());
+
+                SdrGrafCropItem aNewCrop(
+                    rExistingCrop.GetLeft()   + static_cast<sal_Int32>(nLeft   
* fScaleX),
+                    rExistingCrop.GetTop()    + static_cast<sal_Int32>(nTop    
* fScaleY),
+                    rExistingCrop.GetRight()  + static_cast<sal_Int32>(nRight  
* fScaleX),
+                    rExistingCrop.GetBottom() + static_cast<sal_Int32>(nBottom 
* fScaleY));
+
+                if (bUndo)
+                {
+                    
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoGeoObject(*pGrafObj));
+                    
AddUndo(GetModel().GetSdrUndoFactory().CreateUndoAttrObject(*pGrafObj));
+                }
+
+                pGrafObj->SetMergedItem(aNewCrop);
+                pGrafObj->SetLogicRect(aCropTarget);
+            }
+        }
+    }
+
+
     size_t nInsPos = SAL_MAX_SIZE;
     const SdrObject* pAttrObj = nullptr;
     basegfx::B2DPolyPolygon aMergePolyPolygonA;

Reply via email to