Bump version to 24.04.3.4
[LibreOffice.git] / svx / source / svdraw / svdetc.cxx
blobe5f99a8f8f015479ed98efdf5b6d9188073afcff
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 <sal/config.h>
22 #include <algorithm>
24 #include <officecfg/Office/Common.hxx>
25 #include <svtools/colorcfg.hxx>
26 #include <svx/svdetc.hxx>
27 #include <svx/svdedxv.hxx>
28 #include <svx/svdmodel.hxx>
29 #include <svx/svdoutl.hxx>
30 #include <vcl/BitmapReadAccess.hxx>
31 #include <editeng/eeitem.hxx>
32 #include <svl/itemset.hxx>
33 #include <svl/whiter.hxx>
34 #include <svx/xfillit0.hxx>
35 #include <svx/xflclit.hxx>
36 #include <svx/xflhtit.hxx>
37 #include <svx/xbtmpit.hxx>
38 #include <svx/xflgrit.hxx>
39 #include <svx/svdoole2.hxx>
40 #include <svl/itempool.hxx>
41 #include <unotools/configmgr.hxx>
42 #include <unotools/localedatawrapper.hxx>
43 #include <unotools/syslocale.hxx>
44 #include <svx/xflbckit.hxx>
45 #include <svx/extrusionbar.hxx>
46 #include <svx/fontworkbar.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/settings.hxx>
49 #include <svx/sdr/contact/viewcontact.hxx>
50 #include <svx/svdpage.hxx>
51 #include <svx/svdpagv.hxx>
52 #include <svx/svdotable.hxx>
53 #include <svx/sdrhittesthelper.hxx>
55 #include <com/sun/star/frame/XModel.hpp>
56 #include <com/sun/star/embed/XEmbeddedObject.hpp>
58 using namespace ::com::sun::star;
60 // Global data of the DrawingEngine
61 SdrGlobalData::SdrGlobalData()
63 if (!utl::ConfigManager::IsFuzzing())
65 svx::ExtrusionBar::RegisterInterface();
66 svx::FontworkBar::RegisterInterface();
70 const LocaleDataWrapper& SdrGlobalData::GetLocaleData()
72 return GetSysLocale().GetLocaleData();
75 namespace {
77 struct TheSdrGlobalData: public rtl::Static<SdrGlobalData, TheSdrGlobalData> {};
81 SdrGlobalData & GetSdrGlobalData() {
82 return TheSdrGlobalData::get();
85 OLEObjCache::OLEObjCache()
87 if (!utl::ConfigManager::IsFuzzing())
89 // This limit is only useful on 32-bit windows, where we can run out of virtual memory (see tdf#95579)
90 // For everything else, we are better off keeping it in main memory rather than using our hacky page-out thing
91 #if defined _WIN32 && !defined _WIN64
92 nSize = officecfg::Office::Common::Cache::DrawingEngine::OLE_Objects::get();
93 #else
94 nSize = SAL_MAX_INT32; // effectively disable the page-out mechanism
95 #endif
97 else
98 nSize = 100;
99 pTimer.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) );
100 pTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
101 pTimer->SetTimeout(20000);
102 pTimer->SetStatic();
105 OLEObjCache::~OLEObjCache()
107 pTimer->Stop();
110 IMPL_LINK_NOARG(OLEObjCache, UnloadCheckHdl, Timer*, void)
112 if (nSize >= maObjs.size())
113 return;
115 // more objects than configured cache size try to remove objects
116 // of course not the freshly inserted one at nIndex=0
117 size_t nCount2 = maObjs.size();
118 size_t nIndex = nCount2-1;
119 while( nIndex && nCount2 > nSize )
121 SdrOle2Obj* pUnloadObj = maObjs[nIndex--];
122 if (!pUnloadObj)
123 continue;
127 // it is important to get object without reinitialization to avoid reentrance
128 const uno::Reference< embed::XEmbeddedObject > & xUnloadObj = pUnloadObj->GetObjRef_NoInit();
130 bool bUnload = !xUnloadObj || SdrOle2Obj::CanUnloadRunningObj( xUnloadObj, pUnloadObj->GetAspect() );
132 // check whether the object can be unloaded before looking for the parent objects
133 if ( xUnloadObj.is() && bUnload )
135 uno::Reference< frame::XModel > xUnloadModel( xUnloadObj->getComponent(), uno::UNO_QUERY );
136 if ( xUnloadModel.is() )
138 for (SdrOle2Obj* pCacheObj : maObjs)
140 if ( pCacheObj && pCacheObj != pUnloadObj )
142 uno::Reference< frame::XModel > xParentModel = pCacheObj->GetParentXModel();
143 if ( xUnloadModel == xParentModel )
145 bUnload = false; // the object has running embedded objects
146 break;
153 if (bUnload && UnloadObj(*pUnloadObj))
155 // object was successfully unloaded
156 RemoveObj(pUnloadObj);
157 nCount2 = std::min(nCount2 - 1, maObjs.size());
158 if (nIndex >= nCount2)
159 nIndex = nCount2 - 1;
162 catch( uno::Exception& )
167 void OLEObjCache::InsertObj(SdrOle2Obj* pObj)
169 if (!maObjs.empty())
171 SdrOle2Obj* pExistingObj = maObjs.front();
172 if ( pObj == pExistingObj )
173 // the object is already on the top, nothing has to be changed
174 return;
177 // get the old position of the object to know whether it is already in container
178 std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
179 bool bFound = it != maObjs.end();
181 if (bFound)
182 maObjs.erase(it);
183 // insert object into first position
184 maObjs.insert(maObjs.begin(), pObj);
186 // if a new object was inserted, recalculate the cache
187 if (!bFound)
188 pTimer->Invoke();
190 if (!bFound || !pTimer->IsActive())
191 pTimer->Start();
194 void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
196 std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
197 if (it != maObjs.end())
198 maObjs.erase(it);
199 if (maObjs.empty())
200 pTimer->Stop();
203 size_t OLEObjCache::size() const
205 return maObjs.size();
208 SdrOle2Obj* OLEObjCache::operator[](size_t nPos)
210 return maObjs[nPos];
213 const SdrOle2Obj* OLEObjCache::operator[](size_t nPos) const
215 return maObjs[nPos];
218 bool OLEObjCache::UnloadObj(SdrOle2Obj& rObj)
220 bool bUnloaded = false;
222 //#i80528# The old mechanism is completely useless, only taking into account if
223 // in all views the GrafDraft feature is used. This will nearly never have been the
224 // case since no one ever used this option.
226 // A much better (and working) criteria would be the VOC contact count.
227 // The question is what will happen when i make it work now suddenly? I
228 // will try it for 2.4.
229 const sdr::contact::ViewContact& rViewContact = rObj.GetViewContact();
230 const bool bVisible(rViewContact.HasViewObjectContacts());
232 if(!bVisible)
234 bUnloaded = rObj.Unload();
237 return bUnloaded;
240 std::optional<Color> GetDraftFillColor(const SfxItemSet& rSet)
242 drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
244 switch(eFill)
246 case drawing::FillStyle_SOLID:
248 return rSet.Get(XATTR_FILLCOLOR).GetColorValue();
250 case drawing::FillStyle_HATCH:
252 Color aCol1(rSet.Get(XATTR_FILLHATCH).GetHatchValue().GetColor());
253 Color aCol2(COL_WHITE);
255 // when hatched background is activated, use object fill color as hatch color
256 bool bFillHatchBackground = rSet.Get(XATTR_FILLBACKGROUND).GetValue();
257 if(bFillHatchBackground)
259 aCol2 = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
262 const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
263 return Color(aAverageColor);
265 case drawing::FillStyle_GRADIENT: {
266 const basegfx::BGradient& rGrad=rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
267 Color aCol1(Color(rGrad.GetColorStops().front().getStopColor()));
268 Color aCol2(Color(rGrad.GetColorStops().back().getStopColor()));
269 const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
270 return Color(aAverageColor);
272 case drawing::FillStyle_BITMAP:
274 Bitmap aBitmap(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
275 const Size aSize(aBitmap.GetSizePixel());
276 const sal_uInt32 nWidth = aSize.Width();
277 const sal_uInt32 nHeight = aSize.Height();
278 if (nWidth <= 0 || nHeight <= 0)
279 return {};
281 BitmapScopedReadAccess pAccess(aBitmap);
283 if (pAccess)
285 sal_uInt32 nRt(0);
286 sal_uInt32 nGn(0);
287 sal_uInt32 nBl(0);
288 const sal_uInt32 nMaxSteps(8);
289 const sal_uInt32 nXStep((nWidth > nMaxSteps) ? nWidth / nMaxSteps : 1);
290 const sal_uInt32 nYStep((nHeight > nMaxSteps) ? nHeight / nMaxSteps : 1);
291 sal_uInt32 nCount(0);
293 for(sal_uInt32 nY(0); nY < nHeight; nY += nYStep)
295 for(sal_uInt32 nX(0); nX < nWidth; nX += nXStep)
297 const BitmapColor& rCol2 = pAccess->GetColor(nY, nX);
299 nRt += rCol2.GetRed();
300 nGn += rCol2.GetGreen();
301 nBl += rCol2.GetBlue();
302 nCount++;
306 nRt /= nCount;
307 nGn /= nCount;
308 nBl /= nCount;
310 return Color(sal_uInt8(nRt), sal_uInt8(nGn), sal_uInt8(nBl));
312 break;
314 default: break;
317 return {};
320 std::unique_ptr<SdrOutliner> SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel& rModel)
322 SfxItemPool* pPool = &rModel.GetItemPool();
323 std::unique_ptr<SdrOutliner> pOutl(new SdrOutliner( pPool, nOutlinerMode ));
324 pOutl->SetEditTextObjectPool( pPool );
325 pOutl->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(rModel.GetStyleSheetPool()));
326 pOutl->SetDefTab(rModel.GetDefaultTabulator());
327 Outliner::SetForbiddenCharsTable(rModel.GetForbiddenCharsTable());
328 pOutl->SetAsianCompressionMode(rModel.GetCharCompressType());
329 pOutl->SetKernAsianPunctuation(rModel.IsKernAsianPunctuation());
330 pOutl->SetAddExtLeading(rModel.IsAddExtLeading());
331 return pOutl;
334 std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& ImpGetUserMakeObjHdl()
336 SdrGlobalData& rGlobalData=GetSdrGlobalData();
337 return rGlobalData.aUserMakeObjHdl;
340 bool SearchOutlinerItems(const SfxItemSet& rSet, bool bInklDefaults, bool* pbOnlyEE)
342 bool bHas=false;
343 bool bOnly=true;
344 bool bLookOnly=pbOnlyEE!=nullptr;
345 SfxWhichIter aIter(rSet);
346 sal_uInt16 nWhich=aIter.FirstWhich();
347 while (((bLookOnly && bOnly) || !bHas) && nWhich!=0) {
348 // For bInklDefaults, the entire Which range is decisive,
349 // in other cases only the set items are.
350 // Disabled and DontCare are regarded as holes in the Which range.
351 SfxItemState eState=aIter.GetItemState();
352 if ((eState==SfxItemState::DEFAULT && bInklDefaults) || eState==SfxItemState::SET) {
353 if (nWhich<EE_ITEMS_START || nWhich>EE_ITEMS_END) bOnly=false;
354 else bHas=true;
356 nWhich=aIter.NextWhich();
358 if (!bHas) bOnly=false;
359 if (pbOnlyEE!=nullptr) *pbOnlyEE=bOnly;
360 return bHas;
363 WhichRangesContainer RemoveWhichRange(const WhichRangesContainer& pOldWhichTable, sal_uInt16 nRangeBeg, sal_uInt16 nRangeEnd)
365 // Six possible cases (per range):
366 // [Beg..End] [nRangeBeg, nRangeEnd], to delete
367 // [b..e] [b..e] [b..e] Cases 1,3,2: doesn't matter, delete, doesn't matter + Ranges
368 // [b........e] [b........e] Cases 4,5 : shrink range | in
369 // [b......................e] Case 6 : splitting + pOldWhichTable
370 std::vector<WhichPair> buf;
371 for (const auto & rPair : pOldWhichTable) {
372 auto const begin = rPair.first;
373 auto const end = rPair.second;
374 if (end < nRangeBeg || begin > nRangeEnd) { // cases 1, 2
375 buf.push_back({begin, end});
376 } else if (begin >= nRangeBeg && end <= nRangeEnd) { // case 3
377 // drop
378 } else if (end <= nRangeEnd) { // case 4
379 buf.push_back({begin, nRangeBeg - 1});
380 } else if (begin >= nRangeBeg) { // case 5
381 buf.push_back({nRangeEnd + 1, end});
382 } else { // case 6
383 buf.push_back({begin, nRangeBeg - 1});
384 buf.push_back({nRangeEnd + 1, end});
387 std::unique_ptr<WhichPair[]> pNewWhichTable(new WhichPair[buf.size()]);
388 std::copy(buf.begin(), buf.end(), pNewWhichTable.get());
389 return WhichRangesContainer(std::move(pNewWhichTable), buf.size());
393 SvdProgressInfo::SvdProgressInfo( const Link<void*,bool>&_rLink )
395 maLink = _rLink;
396 m_nSumCurAction = 0;
398 m_nObjCount = 0;
399 m_nCurObj = 0;
401 m_nActionCount = 0;
402 m_nCurAction = 0;
404 m_nInsertCount = 0;
405 m_nCurInsert = 0;
408 void SvdProgressInfo::Init( size_t nObjCount )
410 m_nObjCount = nObjCount;
413 bool SvdProgressInfo::ReportActions( size_t nActionCount )
415 m_nSumCurAction += nActionCount;
416 m_nCurAction += nActionCount;
417 if(m_nCurAction > m_nActionCount)
418 m_nCurAction = m_nActionCount;
420 return maLink.Call(nullptr);
423 void SvdProgressInfo::ReportInserts( size_t nInsertCount )
425 m_nSumCurAction += nInsertCount;
426 m_nCurInsert += nInsertCount;
428 maLink.Call(nullptr);
431 void SvdProgressInfo::ReportRescales( size_t nRescaleCount )
433 m_nSumCurAction += nRescaleCount;
434 maLink.Call(nullptr);
437 void SvdProgressInfo::SetActionCount( size_t nActionCount )
439 m_nActionCount = nActionCount;
442 void SvdProgressInfo::SetInsertCount( size_t nInsertCount )
444 m_nInsertCount = nInsertCount;
447 void SvdProgressInfo::SetNextObject()
449 m_nActionCount = 0;
450 m_nCurAction = 0;
452 m_nInsertCount = 0;
453 m_nCurInsert = 0;
455 m_nCurObj++;
456 ReportActions(0);
459 // #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
460 // as text edit is not running on overlay
462 namespace
464 std::optional<Color> impGetSdrObjListFillColor(
465 const SdrObjList& rList,
466 const Point& rPnt,
467 const SdrPageView& rTextEditPV,
468 const SdrLayerIDSet& rVisLayers)
470 bool bMaster(rList.getSdrPageFromSdrObjList() && rList.getSdrPageFromSdrObjList()->IsMasterPage());
472 for(size_t no(rList.GetObjCount()); no > 0; )
474 no--;
475 SdrObject* pObj = rList.GetObj(no);
476 SdrObjList* pOL = pObj->GetSubList();
478 if(pOL)
480 // group object
481 if (auto oColor = impGetSdrObjListFillColor(*pOL, rPnt, rTextEditPV, rVisLayers))
482 return oColor;
484 else
486 SdrTextObj* pText = DynCastSdrTextObj(pObj);
488 // Exclude zero master page object (i.e. background shape) from color query
489 if(pText
490 && pObj->IsClosedObj()
491 && (!bMaster || (!pObj->IsNotVisibleAsMaster() && 0 != no))
492 && pObj->GetCurrentBoundRect().Contains(rPnt)
493 && !pText->IsHideContour()
494 && SdrObjectPrimitiveHit(*pObj, rPnt, {0, 0}, rTextEditPV, &rVisLayers, false))
496 if (auto oColor = GetDraftFillColor(pObj->GetMergedItemSet()))
497 return oColor;
502 return {};
505 std::optional<Color> impGetSdrPageFillColor(
506 const SdrPage& rPage,
507 const Point& rPnt,
508 const SdrPageView& rTextEditPV,
509 const SdrLayerIDSet& rVisLayers,
510 bool bSkipBackgroundShape)
512 if (auto oColor = impGetSdrObjListFillColor(rPage, rPnt, rTextEditPV, rVisLayers))
513 return oColor;
515 if(!rPage.IsMasterPage())
517 if(rPage.TRG_HasMasterPage())
519 SdrLayerIDSet aSet(rVisLayers);
520 aSet &= rPage.TRG_GetMasterPageVisibleLayers();
521 SdrPage& rMasterPage = rPage.TRG_GetMasterPage();
523 // Don't fall back to background shape on
524 // master pages. This is later handled by
525 // GetBackgroundColor, and is necessary to cater for
526 // the silly ordering: 1. shapes, 2. master page
527 // shapes, 3. page background, 4. master page
528 // background.
529 if (auto oColor = impGetSdrPageFillColor(rMasterPage, rPnt, rTextEditPV, aSet, true))
530 return oColor;
534 // Only now determine background color from background shapes
535 if(!bSkipBackgroundShape)
537 return rPage.GetPageBackgroundColor();
540 return {};
543 Color impCalcBackgroundColor(
544 const tools::Rectangle& rArea,
545 const SdrPageView& rTextEditPV,
546 const SdrPage& rPage)
548 svtools::ColorConfig aColorConfig;
549 Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
550 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
552 if(!rStyleSettings.GetHighContrastMode())
554 // search in page
555 const sal_uInt16 SPOTCOUNT(5);
556 Point aSpotPos[SPOTCOUNT];
557 Color aSpotColor[SPOTCOUNT];
558 sal_uInt32 nHeight( rArea.GetSize().Height() );
559 sal_uInt32 nWidth( rArea.GetSize().Width() );
560 sal_uInt32 nWidth14 = nWidth / 4;
561 sal_uInt32 nHeight14 = nHeight / 4;
562 sal_uInt32 nWidth34 = ( 3 * nWidth ) / 4;
563 sal_uInt32 nHeight34 = ( 3 * nHeight ) / 4;
565 sal_uInt16 i;
566 for ( i = 0; i < SPOTCOUNT; i++ )
568 // five spots are used
569 switch ( i )
571 case 0 :
573 // Center-Spot
574 aSpotPos[i] = rArea.Center();
576 break;
578 case 1 :
580 // TopLeft-Spot
581 aSpotPos[i] = rArea.TopLeft();
582 aSpotPos[i].AdjustX(nWidth14 );
583 aSpotPos[i].AdjustY(nHeight14 );
585 break;
587 case 2 :
589 // TopRight-Spot
590 aSpotPos[i] = rArea.TopLeft();
591 aSpotPos[i].AdjustX(nWidth34 );
592 aSpotPos[i].AdjustY(nHeight14 );
594 break;
596 case 3 :
598 // BottomLeft-Spot
599 aSpotPos[i] = rArea.TopLeft();
600 aSpotPos[i].AdjustX(nWidth14 );
601 aSpotPos[i].AdjustY(nHeight34 );
603 break;
605 case 4 :
607 // BottomRight-Spot
608 aSpotPos[i] = rArea.TopLeft();
609 aSpotPos[i].AdjustX(nWidth34 );
610 aSpotPos[i].AdjustY(nHeight34 );
612 break;
616 aSpotColor[i] =
617 impGetSdrPageFillColor(rPage, aSpotPos[i], rTextEditPV, rTextEditPV.GetVisibleLayers(), false).value_or(COL_WHITE);
620 sal_uInt16 aMatch[SPOTCOUNT];
622 for ( i = 0; i < SPOTCOUNT; i++ )
624 // were same spot colors found?
625 aMatch[i] = 0;
627 for ( sal_uInt16 j = 0; j < SPOTCOUNT; j++ )
629 if( j != i )
631 if( aSpotColor[i] == aSpotColor[j] )
633 aMatch[i]++;
639 // highest weight to center spot
640 aBackground = aSpotColor[0];
642 for ( sal_uInt16 nMatchCount = SPOTCOUNT - 1; nMatchCount > 1; nMatchCount-- )
644 // which spot color was found most?
645 for ( i = 0; i < SPOTCOUNT; i++ )
647 if( aMatch[i] == nMatchCount )
649 aBackground = aSpotColor[i];
650 nMatchCount = 1; // break outer for-loop
651 break;
657 return aBackground;
659 } // end of anonymous namespace
661 Color GetTextEditBackgroundColor(const SdrObjEditView& rView)
663 const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
665 if(!rStyleSettings.GetHighContrastMode())
667 SdrTextObj* pText = rView.GetTextEditObject();
669 if(pText && pText->IsClosedObj())
671 sdr::table::SdrTableObj* pTable = dynamic_cast< sdr::table::SdrTableObj * >( pText );
673 if( pTable )
674 if (auto oColor = GetDraftFillColor(pTable->GetActiveCellItemSet()))
675 return *oColor;
677 if (auto oColor = GetDraftFillColor(pText->GetMergedItemSet()))
678 return *oColor;
681 if (pText)
683 SdrPageView* pTextEditPV = rView.GetTextEditPageView();
685 if(pTextEditPV)
687 Point aPvOfs(pText->GetTextEditOffset());
688 const SdrPage* pPg = pTextEditPV->GetPage();
690 if(pPg)
692 tools::Rectangle aSnapRect( pText->GetSnapRect() );
693 aSnapRect.Move(aPvOfs.X(), aPvOfs.Y());
695 return impCalcBackgroundColor(aSnapRect, *pTextEditPV, *pPg);
701 return svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
704 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */