Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / sdrpagewindow.cxx
blobfa8e5f4d7f84bab8852e2466b5ed67d676c8368b
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <svx/sdrpagewindow.hxx>
21 #include <com/sun/star/awt/XWindow.hpp>
22 #include <com/sun/star/awt/PosSize.hpp>
23 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
24 #include <comphelper/lok.hxx>
25 #include <comphelper/processfactory.hxx>
26 #include <toolkit/helper/vclunohelper.hxx>
27 #include <svx/svdview.hxx>
28 #include <svx/svdpagv.hxx>
29 #include <svx/sdrpaintwindow.hxx>
30 #include <svx/sdr/contact/objectcontactofpageview.hxx>
31 #include <svx/sdr/contact/displayinfo.hxx>
32 #include <svx/fmview.hxx>
33 #include <sfx2/lokhelper.hxx>
34 #include <svtools/optionsdrawinglayer.hxx>
35 #include <tools/debug.hxx>
36 #include <vcl/window.hxx>
38 using namespace ::com::sun::star;
40 struct SdrPageWindow::Impl
42 // #110094# ObjectContact section
43 mutable sdr::contact::ObjectContact* mpObjectContact;
45 // the SdrPageView this window belongs to
46 SdrPageView& mrPageView;
48 // the PaintWindow to paint on. Here is access to OutDev etc.
49 // #i72752# change to pointer to allow patcing it in DrawLayer() if necessary
50 SdrPaintWindow* mpPaintWindow;
51 SdrPaintWindow* mpOriginalPaintWindow;
53 // UNO stuff for xControls
54 uno::Reference<awt::XControlContainer> mxControlContainer;
56 Impl( SdrPageView& rPageView, SdrPaintWindow& rPaintWindow ) :
57 mpObjectContact(nullptr),
58 mrPageView(rPageView),
59 mpPaintWindow(&rPaintWindow),
60 mpOriginalPaintWindow(nullptr)
66 uno::Reference<awt::XControlContainer> const & SdrPageWindow::GetControlContainer( bool _bCreateIfNecessary ) const
68 if (!mpImpl->mxControlContainer.is() && _bCreateIfNecessary)
70 SdrView& rView = GetPageView().GetView();
72 const SdrPaintWindow& rPaintWindow( GetOriginalPaintWindow() ? *GetOriginalPaintWindow() : GetPaintWindow() );
73 if ( rPaintWindow.OutputToWindow() && !rView.IsPrintPreview() )
75 vcl::Window* pWindow = rPaintWindow.GetOutputDevice().GetOwnerWindow();
76 const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer = VCLUnoHelper::CreateControlContainer( pWindow );
78 // #100394# xC->setVisible triggers window->Show() and this has
79 // problems when the view is not completely constructed which may
80 // happen when loading. This leads to accessibility broadcasts which
81 // throw asserts due to the not finished view. All this chain can be avoided
82 // since xC->setVisible is here called only for the side effect in
83 // UnoControlContainer::setVisible(...) which calls createPeer(...).
84 // This will now be called directly from here.
86 uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
87 if(xControl.is())
89 uno::Reference< uno::XInterface > xContext = xControl->getContext();
90 if(!xContext.is())
92 xControl->createPeer( uno::Reference<awt::XToolkit>(), uno::Reference<awt::XWindowPeer>() );
96 else
98 // Printer and VirtualDevice, or rather: no OutDev
99 uno::Reference< lang::XMultiServiceFactory > xFactory( ::comphelper::getProcessServiceFactory() );
100 const_cast< SdrPageWindow* >( this )->mpImpl->mxControlContainer.set(xFactory->createInstance("com.sun.star.awt.UnoControlContainer"), uno::UNO_QUERY);
101 uno::Reference< awt::XControlModel > xModel(xFactory->createInstance("com.sun.star.awt.UnoControlContainerModel"), uno::UNO_QUERY);
102 uno::Reference< awt::XControl > xControl(mpImpl->mxControlContainer, uno::UNO_QUERY);
103 if (xControl.is())
104 xControl->setModel(xModel);
106 OutputDevice& rOutDev = rPaintWindow.GetOutputDevice();
107 Point aPosPix = rOutDev.GetMapMode().GetOrigin();
108 Size aSizePix = rOutDev.GetOutputSizePixel();
110 uno::Reference< awt::XWindow > xContComp(mpImpl->mxControlContainer, uno::UNO_QUERY);
111 if( xContComp.is() )
112 xContComp->setPosSize(aPosPix.X(), aPosPix.Y(), aSizePix.Width(), aSizePix.Height(), awt::PosSize::POSSIZE);
115 FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
116 if ( pViewAsFormView )
117 pViewAsFormView->InsertControlContainer(mpImpl->mxControlContainer);
119 return mpImpl->mxControlContainer;
122 SdrPageWindow::SdrPageWindow(SdrPageView& rPageView, SdrPaintWindow& rPaintWindow) :
123 mpImpl(new Impl(rPageView, rPaintWindow))
127 SdrPageWindow::~SdrPageWindow()
129 // #i26631#
130 ResetObjectContact();
132 if (!mpImpl->mxControlContainer.is())
133 return;
135 auto & rView = static_cast<SdrPaintView &>(GetPageView().GetView());
137 // notify derived views
138 FmFormView* pViewAsFormView = dynamic_cast< FmFormView* >( &rView );
139 if ( pViewAsFormView )
140 pViewAsFormView->RemoveControlContainer(mpImpl->mxControlContainer);
142 // dispose the control container
143 uno::Reference< lang::XComponent > xComponent(mpImpl->mxControlContainer, uno::UNO_QUERY);
144 xComponent->dispose();
147 SdrPageView& SdrPageWindow::GetPageView() const
149 return mpImpl->mrPageView;
152 SdrPaintWindow& SdrPageWindow::GetPaintWindow() const
154 return *mpImpl->mpPaintWindow;
157 const SdrPaintWindow* SdrPageWindow::GetOriginalPaintWindow() const
159 return mpImpl->mpOriginalPaintWindow;
162 // OVERLAY MANAGER
163 rtl::Reference< sdr::overlay::OverlayManager > const & SdrPageWindow::GetOverlayManager() const
165 return GetPaintWindow().GetOverlayManager();
168 SdrPaintWindow* SdrPageWindow::patchPaintWindow(SdrPaintWindow& rPaintWindow)
170 if (!mpImpl)
171 return nullptr;
173 if (!mpImpl->mpOriginalPaintWindow)
175 // first patch
176 mpImpl->mpOriginalPaintWindow = mpImpl->mpPaintWindow;
177 mpImpl->mpPaintWindow = &rPaintWindow;
178 mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
179 return mpImpl->mpOriginalPaintWindow;
181 else
183 // second or more patch
184 auto pPreviousPaintWindow = mpImpl->mpPaintWindow;
185 mpImpl->mpPaintWindow = &rPaintWindow;
186 mpImpl->mpOriginalPaintWindow->setPatched(&rPaintWindow);
187 return pPreviousPaintWindow;
191 void SdrPageWindow::unpatchPaintWindow(SdrPaintWindow* pPreviousPaintWindow)
193 if (pPreviousPaintWindow == mpImpl->mpOriginalPaintWindow)
195 // first patch
196 mpImpl->mpPaintWindow = mpImpl->mpOriginalPaintWindow;
197 mpImpl->mpOriginalPaintWindow->setPatched(nullptr);
198 mpImpl->mpOriginalPaintWindow = nullptr;
200 else
202 // second or more patch
203 mpImpl->mpPaintWindow = pPreviousPaintWindow;
204 mpImpl->mpOriginalPaintWindow->setPatched(pPreviousPaintWindow);
208 void SdrPageWindow::PrePaint()
210 // give OC the chance to do ProcessDisplay preparations
211 if(HasObjectContact())
213 GetObjectContact().PrepareProcessDisplay();
217 void SdrPageWindow::PrepareRedraw(const vcl::Region& rReg)
219 // give OC the chance to do ProcessDisplay preparations
220 if(HasObjectContact())
222 GetObjectContact().PrepareProcessDisplay();
225 // if necessary, remember changed RedrawArea at PaintWindow for usage with
226 // overlay and PreRenderDevice stuff
227 GetPaintWindow().SetRedrawRegion(rReg);
231 // clip test
232 #ifdef CLIPPER_TEST
233 #include <svx/svdopath.hxx>
234 #include <basegfx/polygon/b2dpolygon.hxx>
235 #include <tools/helpers.hxx>
236 #include <basegfx/polygon/b2dpolygoncutandtouch.hxx>
237 #include <basegfx/polygon/b2dpolypolygontools.hxx>
238 #include <basegfx/polygon/b2dpolygontools.hxx>
239 #include <basegfx/polygon/b2dpolygonclipper.hxx>
241 // for ::std::sort
242 #include <algorithm>
244 namespace
246 void impPaintStrokePolygon(const basegfx::B2DPolygon& rCandidate, OutputDevice& rOutDev, Color aColor)
248 basegfx::B2DPolygon aCandidate(rCandidate);
250 if(aCandidate.areControlPointsUsed())
252 aCandidate = basegfx::utils::adaptiveSubdivideByAngle(rCandidate);
255 if(aCandidate.count())
257 const sal_uInt32 nLoopCount(aCandidate.isClosed() ? aCandidate.count() : aCandidate.count() - 1);
258 rOutDev.SetFillColor();
259 rOutDev.SetLineColor(aColor);
261 for(sal_uInt32 a(0); a < nLoopCount; a++)
263 const basegfx::B2DPoint aBStart(aCandidate.getB2DPoint(a));
264 const basegfx::B2DPoint aBEnd(aCandidate.getB2DPoint((a + 1) % aCandidate.count()));
265 const Point aStart(FRound(aBStart.getX()), FRound(aBStart.getY()));
266 const Point aEnd(FRound(aBEnd.getX()), FRound(aBEnd.getY()));
267 rOutDev.DrawLine(aStart, aEnd);
272 void impTryTest(const SdrPageView& rPageView, OutputDevice& rOutDev)
274 if(rPageView.GetPage() && rPageView.GetPage()->GetObjCount() >= 2)
276 SdrPage* pPage = rPageView.GetPage();
277 SdrObject* pObjA = pPage->GetObj(0);
279 if(dynamic_cast<const SdrPathObj*>( pObjA))
281 basegfx::B2DPolyPolygon aPolyA(pObjA->GetPathPoly());
282 aPolyA = basegfx::utils::correctOrientations(aPolyA);
284 basegfx::B2DPolyPolygon aPolyB;
286 for (const rtl::Reference<SdrObject>& pObjB : *rPageView.GetPage())
288 if(dynamic_cast<const SdrPathObj*>( pObjB.get()))
290 basegfx::B2DPolyPolygon aCandidate(pObjB->GetPathPoly());
291 aCandidate = basegfx::utils::correctOrientations(aCandidate);
292 aPolyB.append(aCandidate);
296 if(aPolyA.count() && aPolyA.isClosed() && aPolyB.count())
298 // poly A is the clipregion, clip poly b against it. Algo depends on
299 // poly b being closed.
300 basegfx::B2DPolyPolygon aResult(basegfx::utils::clipPolyPolygonOnPolyPolygon(aPolyB, aPolyA));
302 for(auto const& rPolygon : aResult)
304 int nR = comphelper::rng::uniform_int_distribution(0, 254);
305 int nG = comphelper::rng::uniform_int_distribution(0, 254);
306 int nB = comphelper::rng::uniform_int_distribution(0, 254);
307 Color aColor(nR, nG, nB);
308 impPaintStrokePolygon(rPolygon, rOutDev, aColor);
314 } // end of anonymous namespace
315 #endif // CLIPPER_TEST
318 void SdrPageWindow::RedrawAll( sdr::contact::ViewObjectContactRedirector* pRedirector )
320 // set Redirector
321 GetObjectContact().SetViewObjectContactRedirector(pRedirector);
323 // set PaintingPageView
324 const SdrView& rView = mpImpl->mrPageView.GetView();
325 SdrModel& rModel = rView.GetModel();
327 // get to be processed layers
328 const bool bPrinter(GetPaintWindow().OutputToPrinter());
329 SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
331 // create PaintInfoRec; use Rectangle only temporarily
332 const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
334 // create processing data
335 sdr::contact::DisplayInfo aDisplayInfo;
337 // Draw all layers. do NOT draw form layer from CompleteRedraw, this is done separately
338 // as a single layer paint
339 const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
340 const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
341 aProcessLayers.Clear(nControlLayerId);
343 // still something to paint?
344 if(!aProcessLayers.IsEmpty())
346 aDisplayInfo.SetProcessLayers(aProcessLayers);
348 // Set region as redraw area
349 aDisplayInfo.SetRedrawArea(rRegion);
351 // paint page
352 GetObjectContact().ProcessDisplay(aDisplayInfo);
355 // reset redirector
356 GetObjectContact().SetViewObjectContactRedirector(nullptr);
358 // LineClip test
359 #ifdef CLIPPER_TEST
360 if(true)
362 impTryTest(GetPageView(), GetPaintWindow().GetOutputDevice());
364 #endif // CLIPPER_TEST
367 void SdrPageWindow::RedrawLayer(const SdrLayerID* pId,
368 sdr::contact::ViewObjectContactRedirector* pRedirector,
369 basegfx::B2IRectangle const*const pPageFrame)
371 // set redirector
372 GetObjectContact().SetViewObjectContactRedirector(pRedirector);
374 // set PaintingPageView
375 const SdrView& rView = mpImpl->mrPageView.GetView();
376 SdrModel& rModel = rView.GetModel();
378 // get the layers to process
379 const bool bPrinter(GetPaintWindow().OutputToPrinter());
380 SdrLayerIDSet aProcessLayers = bPrinter ? mpImpl->mrPageView.GetPrintableLayers() : mpImpl->mrPageView.GetVisibleLayers();
382 // is the given layer visible at all?
383 if(aProcessLayers.IsSet(*pId))
385 // find out if we are painting the ControlLayer
386 const SdrLayerAdmin& rLayerAdmin = rModel.GetLayerAdmin();
387 const SdrLayerID nControlLayerId = rLayerAdmin.GetLayerID(rLayerAdmin.GetControlLayerName());
388 const bool bControlLayerProcessingActive(nControlLayerId == *pId);
390 // create PaintInfoRec, use Rectangle only temporarily
391 const vcl::Region& rRegion = GetPaintWindow().GetRedrawRegion();
393 // create processing data
394 sdr::contact::DisplayInfo aDisplayInfo;
396 // is it the control layer? If Yes, set flag
397 aDisplayInfo.SetControlLayerProcessingActive(bControlLayerProcessingActive);
399 // Draw just the one given layer
400 aProcessLayers.ClearAll();
401 aProcessLayers.Set(*pId);
403 aDisplayInfo.SetProcessLayers(aProcessLayers);
405 // Set region as redraw area
406 aDisplayInfo.SetRedrawArea(rRegion);
408 // Writer or calc, coming from original RedrawOneLayer.
409 // #i72889# no page painting or MasterPage painting for layer painting
410 const bool bOldPageDecorationAllowed(GetPageView().GetView().IsPageDecorationAllowed());
411 const bool bOldMasterPageVisualizationAllowed(GetPageView().GetView().IsMasterPageVisualizationAllowed());
412 GetPageView().GetView().SetPageDecorationAllowed(false);
413 GetPageView().GetView().SetMasterPageVisualizationAllowed(false);
415 if (pPageFrame) // Writer page frame for anchor based clipping
417 aDisplayInfo.SetWriterPageFrame(*pPageFrame);
420 // paint page
421 GetObjectContact().ProcessDisplay(aDisplayInfo);
423 // reset temporarily changed flags
424 GetPageView().GetView().SetPageDecorationAllowed(bOldPageDecorationAllowed);
425 GetPageView().GetView().SetMasterPageVisualizationAllowed(bOldMasterPageVisualizationAllowed);
428 // reset redirector
429 GetObjectContact().SetViewObjectContactRedirector(nullptr);
432 // Invalidate call, used from ObjectContact(OfPageView) in InvalidatePartOfView(...)
433 void SdrPageWindow::InvalidatePageWindow(const basegfx::B2DRange& rRange)
435 if (GetPageView().IsVisible() && GetPaintWindow().OutputToWindow())
437 OutputDevice& rWindow(GetPaintWindow().GetOutputDevice());
438 basegfx::B2DRange aDiscreteRange(rRange);
439 aDiscreteRange.transform(rWindow.GetViewTransformation());
441 if (SvtOptionsDrawinglayer::IsAntiAliasing())
443 // invalidate one discrete unit more under the assumption that AA
444 // needs one pixel more
445 aDiscreteRange.grow(1.0);
448 // If the shapes use negative X coordinates, make them positive before sending
449 // the invalidation rectangle.
450 bool bNegativeX = mpImpl->mrPageView.GetView().IsNegativeX();
452 const tools::Rectangle aVCLDiscreteRectangle(
453 static_cast<tools::Long>(bNegativeX ? std::max(0.0, ceil(-aDiscreteRange.getMaxX())) : floor(aDiscreteRange.getMinX())),
454 static_cast<tools::Long>(floor(aDiscreteRange.getMinY())),
455 static_cast<tools::Long>(bNegativeX ? std::max(0.0, floor(-aDiscreteRange.getMinX())) : ceil(aDiscreteRange.getMaxX())),
456 static_cast<tools::Long>(ceil(aDiscreteRange.getMaxY())));
458 const bool bWasMapModeEnabled(rWindow.IsMapModeEnabled());
459 rWindow.EnableMapMode(false);
460 GetPageView().GetView().InvalidateOneWin(rWindow, aVCLDiscreteRectangle);
461 rWindow.EnableMapMode(bWasMapModeEnabled);
463 else if (comphelper::LibreOfficeKit::isActive())
465 // we don't really have to have a paint window with LOK; OTOH we know
466 // that the drawinglayer units are 100ths of mm, so they are easy to
467 // convert to twips
469 // If the shapes use negative X coordinates, make them positive before sending
470 // the invalidation rectangle.
471 bool bNegativeX = mpImpl->mrPageView.GetView().IsNegativeX();
472 const tools::Rectangle aRect100thMM(
473 static_cast<tools::Long>(bNegativeX ? std::max(0.0, ceil(-rRange.getMaxX())) : floor(rRange.getMinX())),
474 static_cast<tools::Long>(floor(rRange.getMinY())),
475 static_cast<tools::Long>(bNegativeX ? std::max(0.0, floor(-rRange.getMinX())) : ceil(rRange.getMaxX())),
476 static_cast<tools::Long>(ceil(rRange.getMaxY())));
478 const tools::Rectangle aRectTwips = o3tl::convert(aRect100thMM, o3tl::Length::mm100, o3tl::Length::twip);
480 if (SfxViewShell* pViewShell = SfxViewShell::Current())
481 SfxLokHelper::notifyInvalidation(pViewShell, &aRectTwips);
485 // ObjectContact section
486 const sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact() const
488 if (!mpImpl->mpObjectContact)
490 mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
491 const_cast<SdrPageWindow&>(*this),
492 "svx::svdraw::SdrPageWindow mpObjectContact");
495 return *mpImpl->mpObjectContact;
498 sdr::contact::ObjectContact& SdrPageWindow::GetObjectContact()
500 if (!mpImpl->mpObjectContact)
502 mpImpl->mpObjectContact = GetPageView().GetView().createViewSpecificObjectContact(
503 *this,
504 "svx::svdraw::SdrPageWindow mpObjectContact" );
507 return *mpImpl->mpObjectContact;
510 bool SdrPageWindow::HasObjectContact() const
512 return mpImpl->mpObjectContact != nullptr;
515 // #i26631#
516 void SdrPageWindow::ResetObjectContact()
518 if (mpImpl->mpObjectContact)
520 delete mpImpl->mpObjectContact;
521 mpImpl->mpObjectContact = nullptr;
525 void SdrPageWindow::SetDesignMode( bool _bDesignMode ) const
527 const sdr::contact::ObjectContactOfPageView* pOC = dynamic_cast< const sdr::contact::ObjectContactOfPageView* >( &GetObjectContact() );
528 DBG_ASSERT( pOC, "SdrPageWindow::SetDesignMode: invalid object contact!" );
529 if ( pOC )
530 pOC->SetUNOControlsDesignMode( _bDesignMode );
533 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */