1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
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();
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();
94 nSize
= SAL_MAX_INT32
; // effectively disable the page-out mechanism
99 pTimer
.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) );
100 pTimer
->SetInvokeHandler( LINK(this, OLEObjCache
, UnloadCheckHdl
) );
101 pTimer
->SetTimeout(20000);
105 OLEObjCache::~OLEObjCache()
110 IMPL_LINK_NOARG(OLEObjCache
, UnloadCheckHdl
, Timer
*, void)
112 if (nSize
>= maObjs
.size())
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
--];
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
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
)
171 SdrOle2Obj
* pExistingObj
= maObjs
.front();
172 if ( pObj
== pExistingObj
)
173 // the object is already on the top, nothing has to be changed
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();
183 // insert object into first position
184 maObjs
.insert(maObjs
.begin(), pObj
);
186 // if a new object was inserted, recalculate the cache
190 if (!bFound
|| !pTimer
->IsActive())
194 void OLEObjCache::RemoveObj(SdrOle2Obj
* pObj
)
196 std::vector
<SdrOle2Obj
*>::iterator it
= std::find(maObjs
.begin(), maObjs
.end(), pObj
);
197 if (it
!= maObjs
.end())
203 size_t OLEObjCache::size() const
205 return maObjs
.size();
208 SdrOle2Obj
* OLEObjCache::operator[](size_t nPos
)
213 const SdrOle2Obj
* OLEObjCache::operator[](size_t nPos
) const
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());
234 bUnloaded
= rObj
.Unload();
240 std::optional
<Color
> GetDraftFillColor(const SfxItemSet
& rSet
)
242 drawing::FillStyle eFill
=rSet
.Get(XATTR_FILLSTYLE
).GetValue();
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)
281 BitmapScopedReadAccess
pAccess(aBitmap
);
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();
310 return Color(sal_uInt8(nRt
), sal_uInt8(nGn
), sal_uInt8(nBl
));
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());
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
)
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;
356 nWhich
=aIter
.NextWhich();
358 if (!bHas
) bOnly
=false;
359 if (pbOnlyEE
!=nullptr) *pbOnlyEE
=bOnly
;
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
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
});
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
)
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()
459 // #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
460 // as text edit is not running on overlay
464 std::optional
<Color
> impGetSdrObjListFillColor(
465 const SdrObjList
& rList
,
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; )
475 SdrObject
* pObj
= rList
.GetObj(no
);
476 SdrObjList
* pOL
= pObj
->GetSubList();
481 if (auto oColor
= impGetSdrObjListFillColor(*pOL
, rPnt
, rTextEditPV
, rVisLayers
))
486 SdrTextObj
* pText
= DynCastSdrTextObj(pObj
);
488 // Exclude zero master page object (i.e. background shape) from color query
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()))
505 std::optional
<Color
> impGetSdrPageFillColor(
506 const SdrPage
& rPage
,
508 const SdrPageView
& rTextEditPV
,
509 const SdrLayerIDSet
& rVisLayers
,
510 bool bSkipBackgroundShape
)
512 if (auto oColor
= impGetSdrObjListFillColor(rPage
, rPnt
, rTextEditPV
, rVisLayers
))
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
529 if (auto oColor
= impGetSdrPageFillColor(rMasterPage
, rPnt
, rTextEditPV
, aSet
, true))
534 // Only now determine background color from background shapes
535 if(!bSkipBackgroundShape
)
537 return rPage
.GetPageBackgroundColor();
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())
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;
566 for ( i
= 0; i
< SPOTCOUNT
; i
++ )
568 // five spots are used
574 aSpotPos
[i
] = rArea
.Center();
581 aSpotPos
[i
] = rArea
.TopLeft();
582 aSpotPos
[i
].AdjustX(nWidth14
);
583 aSpotPos
[i
].AdjustY(nHeight14
);
590 aSpotPos
[i
] = rArea
.TopLeft();
591 aSpotPos
[i
].AdjustX(nWidth34
);
592 aSpotPos
[i
].AdjustY(nHeight14
);
599 aSpotPos
[i
] = rArea
.TopLeft();
600 aSpotPos
[i
].AdjustX(nWidth14
);
601 aSpotPos
[i
].AdjustY(nHeight34
);
608 aSpotPos
[i
] = rArea
.TopLeft();
609 aSpotPos
[i
].AdjustX(nWidth34
);
610 aSpotPos
[i
].AdjustY(nHeight34
);
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?
627 for ( sal_uInt16 j
= 0; j
< SPOTCOUNT
; j
++ )
631 if( aSpotColor
[i
] == aSpotColor
[j
] )
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
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
);
674 if (auto oColor
= GetDraftFillColor(pTable
->GetActiveCellItemSet()))
677 if (auto oColor
= GetDraftFillColor(pText
->GetMergedItemSet()))
683 SdrPageView
* pTextEditPV
= rView
.GetTextEditPageView();
687 Point
aPvOfs(pText
->GetTextEditOffset());
688 const SdrPage
* pPg
= pTextEditPV
->GetPage();
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: */