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>
22 #include <officecfg/Office/Common.hxx>
23 #include <svtools/colorcfg.hxx>
24 #include <svx/svdetc.hxx>
25 #include <svx/svdedxv.hxx>
26 #include <svx/svdmodel.hxx>
27 #include <svx/svdoutl.hxx>
28 #include <vcl/bitmapaccess.hxx>
29 #include <editeng/eeitem.hxx>
30 #include <svl/itemset.hxx>
31 #include <svl/whiter.hxx>
32 #include <svx/xgrad.hxx>
33 #include <svx/xfillit0.hxx>
34 #include <svx/xflclit.hxx>
35 #include <svx/xflhtit.hxx>
36 #include <svx/xbtmpit.hxx>
37 #include <svx/xflgrit.hxx>
38 #include <svx/svdoole2.hxx>
39 #include <svl/itempool.hxx>
40 #include <tools/debug.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 , pLocaleData(nullptr)
65 if (!utl::ConfigManager::IsFuzzing())
67 svx::ExtrusionBar::RegisterInterface();
68 svx::FontworkBar::RegisterInterface();
72 const SvtSysLocale
* SdrGlobalData::GetSysLocale()
75 pSysLocale
= new SvtSysLocale
;
78 const LocaleDataWrapper
* SdrGlobalData::GetLocaleData()
81 pLocaleData
= GetSysLocale()->GetLocaleDataPtr();
87 struct TheSdrGlobalData
: public rtl::Static
<SdrGlobalData
, TheSdrGlobalData
> {};
91 SdrGlobalData
& GetSdrGlobalData() {
92 return TheSdrGlobalData::get();
95 OLEObjCache::OLEObjCache()
97 if (!utl::ConfigManager::IsFuzzing())
98 nSize
= officecfg::Office::Common::Cache::DrawingEngine::OLE_Objects::get();
101 pTimer
.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) );
102 pTimer
->SetInvokeHandler( LINK(this, OLEObjCache
, UnloadCheckHdl
) );
103 pTimer
->SetTimeout(20000);
107 OLEObjCache::~OLEObjCache()
112 IMPL_LINK_NOARG(OLEObjCache
, UnloadCheckHdl
, Timer
*, void)
114 if (nSize
>= maObjs
.size())
117 // more objects than configured cache size try to remove objects
118 // of course not the freshly inserted one at nIndex=0
119 size_t nCount2
= maObjs
.size();
120 size_t nIndex
= nCount2
-1;
121 while( nIndex
&& nCount2
> nSize
)
123 SdrOle2Obj
* pUnloadObj
= maObjs
[nIndex
--];
129 // it is important to get object without reinitialization to avoid reentrance
130 uno::Reference
< embed::XEmbeddedObject
> xUnloadObj
= pUnloadObj
->GetObjRef_NoInit();
132 bool bUnload
= SdrOle2Obj::CanUnloadRunningObj( xUnloadObj
, pUnloadObj
->GetAspect() );
134 // check whether the object can be unloaded before looking for the parent objects
135 if ( xUnloadObj
.is() && bUnload
)
137 uno::Reference
< frame::XModel
> xUnloadModel( xUnloadObj
->getComponent(), uno::UNO_QUERY
);
138 if ( xUnloadModel
.is() )
140 for (SdrOle2Obj
* pCacheObj
: maObjs
)
142 if ( pCacheObj
&& pCacheObj
!= pUnloadObj
)
144 uno::Reference
< frame::XModel
> xParentModel
= pCacheObj
->GetParentXModel();
145 if ( xUnloadModel
== xParentModel
)
146 bUnload
= false; // the object has running embedded objects
152 if ( bUnload
&& UnloadObj(pUnloadObj
) )
153 // object was successfully unloaded
156 catch( uno::Exception
& )
161 void OLEObjCache::InsertObj(SdrOle2Obj
* pObj
)
165 SdrOle2Obj
* pExistingObj
= maObjs
.front();
166 if ( pObj
== pExistingObj
)
167 // the object is already on the top, nothing has to be changed
171 // get the old position of the object to know whether it is already in container
172 std::vector
<SdrOle2Obj
*>::iterator it
= std::find(maObjs
.begin(), maObjs
.end(), pObj
);
173 bool bFound
= it
!= maObjs
.end();
177 // insert object into first position
178 maObjs
.insert(maObjs
.begin(), pObj
);
180 // if a new object was inserted, recalculate the cache
184 if (!bFound
|| !pTimer
->IsActive())
188 void OLEObjCache::RemoveObj(SdrOle2Obj
* pObj
)
190 std::vector
<SdrOle2Obj
*>::iterator it
= std::find(maObjs
.begin(), maObjs
.end(), pObj
);
191 if (it
!= maObjs
.end())
197 size_t OLEObjCache::size() const
199 return maObjs
.size();
202 SdrOle2Obj
* OLEObjCache::operator[](size_t nPos
)
207 const SdrOle2Obj
* OLEObjCache::operator[](size_t nPos
) const
212 bool OLEObjCache::UnloadObj(SdrOle2Obj
* pObj
)
214 bool bUnloaded
= false;
217 //#i80528# The old mechanism is completely useless, only taking into account if
218 // in all views the GrafDraft feature is used. This will nearly never have been the
219 // case since no one ever used this option.
221 // A much better (and working) criteria would be the VOC contact count.
222 // The question is what will happen when i make it work now suddenly? I
223 // will try it for 2.4.
224 const sdr::contact::ViewContact
& rViewContact
= pObj
->GetViewContact();
225 const bool bVisible(rViewContact
.HasViewObjectContacts());
229 bUnloaded
= pObj
->Unload();
236 bool GetDraftFillColor(const SfxItemSet
& rSet
, Color
& rCol
)
238 drawing::FillStyle eFill
=rSet
.Get(XATTR_FILLSTYLE
).GetValue();
239 bool bRetval
= false;
243 case drawing::FillStyle_SOLID
:
245 rCol
= 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 rCol
= Color(aAverageColor
);
268 case drawing::FillStyle_GRADIENT
: {
269 const XGradient
& rGrad
=rSet
.Get(XATTR_FILLGRADIENT
).GetGradientValue();
270 Color
aCol1(rGrad
.GetStartColor());
271 Color
aCol2(rGrad
.GetEndColor());
272 const basegfx::BColor
aAverageColor(basegfx::average(aCol1
.getBColor(), aCol2
.getBColor()));
273 rCol
= Color(aAverageColor
);
278 case drawing::FillStyle_BITMAP
:
280 Bitmap
aBitmap(rSet
.Get(XATTR_FILLBITMAP
).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
281 const Size
aSize(aBitmap
.GetSizePixel());
282 const sal_uInt32 nWidth
= aSize
.Width();
283 const sal_uInt32 nHeight
= aSize
.Height();
284 if (nWidth
<= 0 || nHeight
<= 0)
287 Bitmap::ScopedReadAccess
pAccess(aBitmap
);
294 const sal_uInt32
nMaxSteps(8);
295 const sal_uInt32
nXStep((nWidth
> nMaxSteps
) ? nWidth
/ nMaxSteps
: 1);
296 const sal_uInt32
nYStep((nHeight
> nMaxSteps
) ? nHeight
/ nMaxSteps
: 1);
297 sal_uInt32
nCount(0);
299 for(sal_uInt32
nY(0); nY
< nHeight
; nY
+= nYStep
)
301 for(sal_uInt32
nX(0); nX
< nWidth
; nX
+= nXStep
)
303 const BitmapColor
& rCol2
= pAccess
->GetColor(nY
, nX
);
305 nRt
+= rCol2
.GetRed();
306 nGn
+= rCol2
.GetGreen();
307 nBl
+= rCol2
.GetBlue();
316 rCol
= Color(sal_uInt8(nRt
), sal_uInt8(nGn
), sal_uInt8(nBl
));
328 std::unique_ptr
<SdrOutliner
> SdrMakeOutliner(OutlinerMode nOutlinerMode
, SdrModel
& rModel
)
330 SfxItemPool
* pPool
= &rModel
.GetItemPool();
331 std::unique_ptr
<SdrOutliner
> pOutl(new SdrOutliner( pPool
, nOutlinerMode
));
332 pOutl
->SetEditTextObjectPool( pPool
);
333 pOutl
->SetStyleSheetPool( static_cast<SfxStyleSheetPool
*>(rModel
.GetStyleSheetPool()));
334 pOutl
->SetDefTab(rModel
.GetDefaultTabulator());
335 Outliner::SetForbiddenCharsTable(rModel
.GetForbiddenCharsTable());
336 pOutl
->SetAsianCompressionMode(rModel
.GetCharCompressType());
337 pOutl
->SetKernAsianPunctuation(rModel
.IsKernAsianPunctuation());
338 pOutl
->SetAddExtLeading(rModel
.IsAddExtLeading());
342 std::vector
<Link
<SdrObjCreatorParams
, SdrObject
*>>& ImpGetUserMakeObjHdl()
344 SdrGlobalData
& rGlobalData
=GetSdrGlobalData();
345 return rGlobalData
.aUserMakeObjHdl
;
348 bool SearchOutlinerItems(const SfxItemSet
& rSet
, bool bInklDefaults
, bool* pbOnlyEE
)
352 bool bLookOnly
=pbOnlyEE
!=nullptr;
353 SfxWhichIter
aIter(rSet
);
354 sal_uInt16 nWhich
=aIter
.FirstWhich();
355 while (((bLookOnly
&& bOnly
) || !bHas
) && nWhich
!=0) {
356 // For bInklDefaults, the entire Which range is decisive,
357 // in other cases only the set items are.
358 // Disabled and DontCare are regarded as holes in the Which range.
359 SfxItemState eState
=rSet
.GetItemState(nWhich
);
360 if ((eState
==SfxItemState::DEFAULT
&& bInklDefaults
) || eState
==SfxItemState::SET
) {
361 if (nWhich
<EE_ITEMS_START
|| nWhich
>EE_ITEMS_END
) bOnly
=false;
364 nWhich
=aIter
.NextWhich();
366 if (!bHas
) bOnly
=false;
367 if (pbOnlyEE
!=nullptr) *pbOnlyEE
=bOnly
;
371 std::unique_ptr
<sal_uInt16
[]> RemoveWhichRange(const sal_uInt16
* pOldWhichTable
, sal_uInt16 nRangeBeg
, sal_uInt16 nRangeEnd
)
373 // Six possible cases (per range):
374 // [Beg..End] Range, to delete
375 // [b..e] [b..e] [b..e] Cases 1,3,2: doesn't matter, delete, doesn't matter + Ranges
376 // [b........e] [b........e] Cases 4,5 : shrink range | in
377 // [b......................e] Case 6 : splitting + pOldWhichTable
379 while (pOldWhichTable
[nCount
]!=0) nCount
++;
380 nCount
++; // nCount should now be an odd number (0 for end of array)
381 DBG_ASSERT((nCount
&1)==1,"RemoveWhichRange: WhichTable doesn't have an odd number of entries.");
382 sal_uInt16 nAlloc
=nCount
;
383 // check necessary size of new array
384 sal_uInt16 nNum
=nCount
-1;
387 sal_uInt16 nBeg
=pOldWhichTable
[nNum
];
388 sal_uInt16 nEnd
=pOldWhichTable
[nNum
+1];
389 if (nEnd
<nRangeBeg
) /*nCase=1*/ ;
390 else if (nBeg
>nRangeEnd
) /* nCase=2 */ ;
391 else if (nBeg
>=nRangeBeg
&& nEnd
<=nRangeEnd
) /* nCase=3 */ nAlloc
-=2;
392 else if (nEnd
<=nRangeEnd
) /* nCase=4 */;
393 else if (nBeg
>=nRangeBeg
) /* nCase=5*/ ;
394 else /* nCase=6 */ nAlloc
+=2;
397 std::unique_ptr
<sal_uInt16
[]> pNewWhichTable(new sal_uInt16
[nAlloc
]);
398 memcpy(pNewWhichTable
.get(), pOldWhichTable
, nAlloc
*sizeof(sal_uInt16
));
399 pNewWhichTable
[nAlloc
-1]=0; // in case 3, there's no 0 at the end.
400 // now remove the unwanted ranges
404 sal_uInt16 nBeg
=pNewWhichTable
[nNum
];
405 sal_uInt16 nEnd
=pNewWhichTable
[nNum
+1];
407 if (nEnd
<nRangeBeg
) nCase
=1;
408 else if (nBeg
>nRangeEnd
) nCase
=2;
409 else if (nBeg
>=nRangeBeg
&& nEnd
<=nRangeEnd
) nCase
=3;
410 else if (nEnd
<=nRangeEnd
) nCase
=4;
411 else if (nBeg
>=nRangeBeg
) nCase
=5;
415 unsigned nTailBytes
=(nCount
-(nNum
+2))*sizeof(sal_uInt16
);
416 memcpy(&pNewWhichTable
[nNum
],&pNewWhichTable
[nNum
+2],nTailBytes
);
417 nCount
-=2; // remember: array is now smaller
419 case 4: pNewWhichTable
[nNum
+1]=nRangeBeg
-1; break;
420 case 5: pNewWhichTable
[nNum
]=nRangeEnd
+1; break;
422 unsigned nTailBytes
=(nCount
-(nNum
+2))*sizeof(sal_uInt16
);
423 memcpy(&pNewWhichTable
[nNum
+4],&pNewWhichTable
[nNum
+2],nTailBytes
);
424 nCount
+=2; // remember:array is now larger
425 pNewWhichTable
[nNum
+2]=nRangeEnd
+1;
426 pNewWhichTable
[nNum
+3]=pNewWhichTable
[nNum
+1];
427 pNewWhichTable
[nNum
+1]=nRangeBeg
-1;
431 return pNewWhichTable
;
435 SvdProgressInfo::SvdProgressInfo( const Link
<void*,bool>&_rLink
)
450 void SvdProgressInfo::Init( size_t nObjCount
)
452 m_nObjCount
= nObjCount
;
455 bool SvdProgressInfo::ReportActions( size_t nActionCount
)
457 m_nSumCurAction
+= nActionCount
;
458 m_nCurAction
+= nActionCount
;
459 if(m_nCurAction
> m_nActionCount
)
460 m_nCurAction
= m_nActionCount
;
462 return maLink
.Call(nullptr);
465 void SvdProgressInfo::ReportInserts( size_t nInsertCount
)
467 m_nSumCurAction
+= nInsertCount
;
468 m_nCurInsert
+= nInsertCount
;
470 maLink
.Call(nullptr);
473 void SvdProgressInfo::ReportRescales( size_t nRescaleCount
)
475 m_nSumCurAction
+= nRescaleCount
;
476 maLink
.Call(nullptr);
479 void SvdProgressInfo::SetActionCount( size_t nActionCount
)
481 m_nActionCount
= nActionCount
;
484 void SvdProgressInfo::SetInsertCount( size_t nInsertCount
)
486 m_nInsertCount
= nInsertCount
;
489 void SvdProgressInfo::SetNextObject()
501 // #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
502 // as text edit is not running on overlay
506 bool impGetSdrObjListFillColor(
507 const SdrObjList
& rList
,
509 const SdrPageView
& rTextEditPV
,
510 const SdrLayerIDSet
& rVisLayers
,
514 bool bMaster(rList
.getSdrPageFromSdrObjList() && rList
.getSdrPageFromSdrObjList()->IsMasterPage());
516 for(size_t no(rList
.GetObjCount()); !bRet
&& no
> 0; )
519 SdrObject
* pObj
= rList
.GetObj(no
);
520 SdrObjList
* pOL
= pObj
->GetSubList();
525 bRet
= impGetSdrObjListFillColor(*pOL
, rPnt
, rTextEditPV
, rVisLayers
, rCol
);
529 SdrTextObj
* pText
= dynamic_cast< SdrTextObj
* >(pObj
);
531 // Exclude zero master page object (i.e. background shape) from color query
533 && pObj
->IsClosedObj()
534 && (!bMaster
|| (!pObj
->IsNotVisibleAsMaster() && 0 != no
))
535 && pObj
->GetCurrentBoundRect().IsInside(rPnt
)
536 && !pText
->IsHideContour()
537 && SdrObjectPrimitiveHit(*pObj
, rPnt
, 0, rTextEditPV
, &rVisLayers
, false))
539 bRet
= GetDraftFillColor(pObj
->GetMergedItemSet(), rCol
);
547 bool impGetSdrPageFillColor(
548 const SdrPage
& rPage
,
550 const SdrPageView
& rTextEditPV
,
551 const SdrLayerIDSet
& rVisLayers
,
553 bool bSkipBackgroundShape
)
555 bool bRet(impGetSdrObjListFillColor(rPage
, rPnt
, rTextEditPV
, rVisLayers
, rCol
));
557 if(!bRet
&& !rPage
.IsMasterPage())
559 if(rPage
.TRG_HasMasterPage())
561 SdrLayerIDSet
aSet(rVisLayers
);
562 aSet
&= rPage
.TRG_GetMasterPageVisibleLayers();
563 SdrPage
& rMasterPage
= rPage
.TRG_GetMasterPage();
565 // Don't fall back to background shape on
566 // master pages. This is later handled by
567 // GetBackgroundColor, and is necessary to cater for
568 // the silly ordering: 1. shapes, 2. master page
569 // shapes, 3. page background, 4. master page
571 bRet
= impGetSdrPageFillColor(rMasterPage
, rPnt
, rTextEditPV
, aSet
, rCol
, true);
575 // Only now determine background color from background shapes
576 if(!bRet
&& !bSkipBackgroundShape
)
578 rCol
= rPage
.GetPageBackgroundColor();
585 Color
impCalcBackgroundColor(
586 const tools::Rectangle
& rArea
,
587 const SdrPageView
& rTextEditPV
,
588 const SdrPage
& rPage
)
590 svtools::ColorConfig aColorConfig
;
591 Color
aBackground(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
592 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
594 if(!rStyleSettings
.GetHighContrastMode())
597 const sal_uInt16
SPOTCOUNT(5);
598 Point aSpotPos
[SPOTCOUNT
];
599 Color aSpotColor
[SPOTCOUNT
];
600 sal_uInt32
nHeight( rArea
.GetSize().Height() );
601 sal_uInt32
nWidth( rArea
.GetSize().Width() );
602 sal_uInt32 nWidth14
= nWidth
/ 4;
603 sal_uInt32 nHeight14
= nHeight
/ 4;
604 sal_uInt32 nWidth34
= ( 3 * nWidth
) / 4;
605 sal_uInt32 nHeight34
= ( 3 * nHeight
) / 4;
608 for ( i
= 0; i
< SPOTCOUNT
; i
++ )
610 // five spots are used
616 aSpotPos
[i
] = rArea
.Center();
623 aSpotPos
[i
] = rArea
.TopLeft();
624 aSpotPos
[i
].AdjustX(nWidth14
);
625 aSpotPos
[i
].AdjustY(nHeight14
);
632 aSpotPos
[i
] = rArea
.TopLeft();
633 aSpotPos
[i
].AdjustX(nWidth34
);
634 aSpotPos
[i
].AdjustY(nHeight14
);
641 aSpotPos
[i
] = rArea
.TopLeft();
642 aSpotPos
[i
].AdjustX(nWidth14
);
643 aSpotPos
[i
].AdjustY(nHeight34
);
650 aSpotPos
[i
] = rArea
.TopLeft();
651 aSpotPos
[i
].AdjustX(nWidth34
);
652 aSpotPos
[i
].AdjustY(nHeight34
);
658 aSpotColor
[i
] = COL_WHITE
;
659 impGetSdrPageFillColor(rPage
, aSpotPos
[i
], rTextEditPV
, rTextEditPV
.GetVisibleLayers(), aSpotColor
[i
], false);
662 sal_uInt16 aMatch
[SPOTCOUNT
];
664 for ( i
= 0; i
< SPOTCOUNT
; i
++ )
666 // were same spot colors found?
669 for ( sal_uInt16 j
= 0; j
< SPOTCOUNT
; j
++ )
673 if( aSpotColor
[i
] == aSpotColor
[j
] )
681 // highest weight to center spot
682 aBackground
= aSpotColor
[0];
684 for ( sal_uInt16 nMatchCount
= SPOTCOUNT
- 1; nMatchCount
> 1; nMatchCount
-- )
686 // which spot color was found most?
687 for ( i
= 0; i
< SPOTCOUNT
; i
++ )
689 if( aMatch
[i
] == nMatchCount
)
691 aBackground
= aSpotColor
[i
];
692 nMatchCount
= 1; // break outer for-loop
701 } // end of anonymous namespace
703 Color
GetTextEditBackgroundColor(const SdrObjEditView
& rView
)
705 svtools::ColorConfig aColorConfig
;
706 Color
aBackground(aColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
707 const StyleSettings
& rStyleSettings
= Application::GetSettings().GetStyleSettings();
709 if(!rStyleSettings
.GetHighContrastMode())
712 SdrTextObj
* pText
= rView
.GetTextEditObject();
714 if(pText
&& pText
->IsClosedObj())
716 sdr::table::SdrTableObj
* pTable
= dynamic_cast< sdr::table::SdrTableObj
* >( pText
);
719 bFound
= GetDraftFillColor(pTable
->GetActiveCellItemSet(), aBackground
);
722 bFound
=GetDraftFillColor(pText
->GetMergedItemSet(), aBackground
);
727 SdrPageView
* pTextEditPV
= rView
.GetTextEditPageView();
731 Point
aPvOfs(pText
->GetTextEditOffset());
732 const SdrPage
* pPg
= pTextEditPV
->GetPage();
736 tools::Rectangle
aSnapRect( pText
->GetSnapRect() );
737 aSnapRect
.Move(aPvOfs
.X(), aPvOfs
.Y());
739 return impCalcBackgroundColor(aSnapRect
, *pTextEditPV
, *pPg
);
748 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */