xref: /core/svx/source/svdraw/svdetc.cxx (revision 2c8c436c)
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
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/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
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 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <algorithm>
23 
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>
54 
55 #include <com/sun/star/frame/XModel.hpp>
56 #include <com/sun/star/embed/XEmbeddedObject.hpp>
57 
58 using namespace ::com::sun::star;
59 
60 // Global data of the DrawingEngine
61 SdrGlobalData::SdrGlobalData()
62 {
63     if (!utl::ConfigManager::IsFuzzing())
64     {
65         svx::ExtrusionBar::RegisterInterface();
66         svx::FontworkBar::RegisterInterface();
67     }
68 }
69 
70 const LocaleDataWrapper& SdrGlobalData::GetLocaleData()
71 {
72     return GetSysLocale().GetLocaleData();
73 }
74 
75 namespace {
76 
77 struct TheSdrGlobalData: public rtl::Static<SdrGlobalData, TheSdrGlobalData> {};
78 
79 }
80 
81 SdrGlobalData & GetSdrGlobalData() {
82     return TheSdrGlobalData::get();
83 }
84 
85 OLEObjCache::OLEObjCache()
86 {
87     if (!utl::ConfigManager::IsFuzzing())
88     {
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
96     }
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();
103 }
104 
105 OLEObjCache::~OLEObjCache()
106 {
107     pTimer->Stop();
108 }
109 
110 IMPL_LINK_NOARG(OLEObjCache, UnloadCheckHdl, Timer*, void)
111 {
112     if (nSize >= maObjs.size())
113         return;
114 
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 )
120     {
121         SdrOle2Obj* pUnloadObj = maObjs[nIndex--];
122         if (!pUnloadObj)
123             continue;
124 
125         try
126         {
127             // it is important to get object without reinitialization to avoid reentrance
128             const uno::Reference< embed::XEmbeddedObject > & xUnloadObj = pUnloadObj->GetObjRef_NoInit();
129 
130             bool bUnload = !xUnloadObj || SdrOle2Obj::CanUnloadRunningObj( xUnloadObj, pUnloadObj->GetAspect() );
131 
132             // check whether the object can be unloaded before looking for the parent objects
133             if ( xUnloadObj.is() && bUnload )
134             {
135                 uno::Reference< frame::XModel > xUnloadModel( xUnloadObj->getComponent(), uno::UNO_QUERY );
136                 if ( xUnloadModel.is() )
137                 {
138                     for (SdrOle2Obj* pCacheObj : maObjs)
139                     {
140                         if ( pCacheObj && pCacheObj != pUnloadObj )
141                         {
142                             uno::Reference< frame::XModel > xParentModel = pCacheObj->GetParentXModel();
143                             if ( xUnloadModel == xParentModel )
144                             {
145                                 bUnload = false; // the object has running embedded objects
146                                 break;
147                             }
148                         }
149                     }
150                 }
151             }
152 
153             if (bUnload && UnloadObj(*pUnloadObj))
154             {
155                 // object was successfully unloaded
156                 RemoveObj(pUnloadObj);
157                 nCount2 = std::min(nCount2 - 1, maObjs.size());
158                 if (nIndex >= nCount2)
159                     nIndex = nCount2 - 1;
160             }
161         }
162         catch( uno::Exception& )
163         {}
164     }
165 }
166 
167 void OLEObjCache::InsertObj(SdrOle2Obj* pObj)
168 {
169     if (!maObjs.empty())
170     {
171         SdrOle2Obj* pExistingObj = maObjs.front();
172         if ( pObj == pExistingObj )
173             // the object is already on the top, nothing has to be changed
174             return;
175     }
176 
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();
180 
181     if (bFound)
182         maObjs.erase(it);
183     // insert object into first position
184     maObjs.insert(maObjs.begin(), pObj);
185 
186     // if a new object was inserted, recalculate the cache
187     if (!bFound)
188         pTimer->Invoke();
189 
190     if (!bFound || !pTimer->IsActive())
191         pTimer->Start();
192 }
193 
194 void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
195 {
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();
201 }
202 
203 size_t OLEObjCache::size() const
204 {
205     return maObjs.size();
206 }
207 
208 SdrOle2Obj* OLEObjCache::operator[](size_t nPos)
209 {
210     return maObjs[nPos];
211 }
212 
213 const SdrOle2Obj* OLEObjCache::operator[](size_t nPos) const
214 {
215     return maObjs[nPos];
216 }
217 
218 bool OLEObjCache::UnloadObj(SdrOle2Obj& rObj)
219 {
220     bool bUnloaded = false;
221 
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.
225 
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());
231 
232     if(!bVisible)
233     {
234         bUnloaded = rObj.Unload();
235     }
236 
237     return bUnloaded;
238 }
239 
240 bool GetDraftFillColor(const SfxItemSet& rSet, Color& rCol)
241 {
242     drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
243     bool bRetval = false;
244 
245     switch(eFill)
246     {
247         case drawing::FillStyle_SOLID:
248         {
249             rCol = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
250             bRetval = true;
251 
252             break;
253         }
254         case drawing::FillStyle_HATCH:
255         {
256             Color aCol1(rSet.Get(XATTR_FILLHATCH).GetHatchValue().GetColor());
257             Color aCol2(COL_WHITE);
258 
259             // when hatched background is activated, use object fill color as hatch color
260             bool bFillHatchBackground = rSet.Get(XATTR_FILLBACKGROUND).GetValue();
261             if(bFillHatchBackground)
262             {
263                 aCol2 = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
264             }
265 
266             const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
267             rCol = Color(aAverageColor);
268             bRetval = true;
269 
270             break;
271         }
272         case drawing::FillStyle_GRADIENT: {
273             const basegfx::BGradient& rGrad=rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
274             Color aCol1(Color(rGrad.GetColorStops().front().getStopColor()));
275             Color aCol2(Color(rGrad.GetColorStops().back().getStopColor()));
276             const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
277             rCol = Color(aAverageColor);
278             bRetval = true;
279 
280             break;
281         }
282         case drawing::FillStyle_BITMAP:
283         {
284             Bitmap aBitmap(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmapEx().GetBitmap());
285             const Size aSize(aBitmap.GetSizePixel());
286             const sal_uInt32 nWidth = aSize.Width();
287             const sal_uInt32 nHeight = aSize.Height();
288             if (nWidth <= 0 || nHeight <= 0)
289                 return bRetval;
290 
291             Bitmap::ScopedReadAccess pAccess(aBitmap);
292 
293             if (pAccess)
294             {
295                 sal_uInt32 nRt(0);
296                 sal_uInt32 nGn(0);
297                 sal_uInt32 nBl(0);
298                 const sal_uInt32 nMaxSteps(8);
299                 const sal_uInt32 nXStep((nWidth > nMaxSteps) ? nWidth / nMaxSteps : 1);
300                 const sal_uInt32 nYStep((nHeight > nMaxSteps) ? nHeight / nMaxSteps : 1);
301                 sal_uInt32 nCount(0);
302 
303                 for(sal_uInt32 nY(0); nY < nHeight; nY += nYStep)
304                 {
305                     for(sal_uInt32 nX(0); nX < nWidth; nX += nXStep)
306                     {
307                         const BitmapColor& rCol2 = pAccess->GetColor(nY, nX);
308 
309                         nRt += rCol2.GetRed();
310                         nGn += rCol2.GetGreen();
311                         nBl += rCol2.GetBlue();
312                         nCount++;
313                     }
314                 }
315 
316                 nRt /= nCount;
317                 nGn /= nCount;
318                 nBl /= nCount;
319 
320                 rCol = Color(sal_uInt8(nRt), sal_uInt8(nGn), sal_uInt8(nBl));
321 
322                 bRetval = true;
323             }
324             break;
325         }
326         default: break;
327     }
328 
329     return bRetval;
330 }
331 
332 std::unique_ptr<SdrOutliner> SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel& rModel)
333 {
334     SfxItemPool* pPool = &rModel.GetItemPool();
335     std::unique_ptr<SdrOutliner> pOutl(new SdrOutliner( pPool, nOutlinerMode ));
336     pOutl->SetEditTextObjectPool( pPool );
337     pOutl->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(rModel.GetStyleSheetPool()));
338     pOutl->SetDefTab(rModel.GetDefaultTabulator());
339     Outliner::SetForbiddenCharsTable(rModel.GetForbiddenCharsTable());
340     pOutl->SetAsianCompressionMode(rModel.GetCharCompressType());
341     pOutl->SetKernAsianPunctuation(rModel.IsKernAsianPunctuation());
342     pOutl->SetAddExtLeading(rModel.IsAddExtLeading());
343     return pOutl;
344 }
345 
346 std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& ImpGetUserMakeObjHdl()
347 {
348     SdrGlobalData& rGlobalData=GetSdrGlobalData();
349     return rGlobalData.aUserMakeObjHdl;
350 }
351 
352 bool SearchOutlinerItems(const SfxItemSet& rSet, bool bInklDefaults, bool* pbOnlyEE)
353 {
354     bool bHas=false;
355     bool bOnly=true;
356     bool bLookOnly=pbOnlyEE!=nullptr;
357     SfxWhichIter aIter(rSet);
358     sal_uInt16 nWhich=aIter.FirstWhich();
359     while (((bLookOnly && bOnly) || !bHas) && nWhich!=0) {
360         // For bInklDefaults, the entire Which range is decisive,
361         // in other cases only the set items are.
362         // Disabled and DontCare are regarded as holes in the Which range.
363         SfxItemState eState=aIter.GetItemState();
364         if ((eState==SfxItemState::DEFAULT && bInklDefaults) || eState==SfxItemState::SET) {
365             if (nWhich<EE_ITEMS_START || nWhich>EE_ITEMS_END) bOnly=false;
366             else bHas=true;
367         }
368         nWhich=aIter.NextWhich();
369     }
370     if (!bHas) bOnly=false;
371     if (pbOnlyEE!=nullptr) *pbOnlyEE=bOnly;
372     return bHas;
373 }
374 
375 WhichRangesContainer RemoveWhichRange(const WhichRangesContainer& pOldWhichTable, sal_uInt16 nRangeBeg, sal_uInt16 nRangeEnd)
376 {
377     // Six possible cases (per range):
378     //         [Beg..End]          [nRangeBeg, nRangeEnd], to delete
379     // [b..e]    [b..e]    [b..e]  Cases 1,3,2: doesn't matter, delete, doesn't matter  + Ranges
380     // [b........e]  [b........e]  Cases 4,5  : shrink range                            | in
381     // [b......................e]  Case  6    : splitting                               + pOldWhichTable
382     std::vector<WhichPair> buf;
383     for (const auto & rPair : pOldWhichTable) {
384         auto const begin = rPair.first;
385         auto const end = rPair.second;
386         if (end < nRangeBeg || begin > nRangeEnd) { // cases 1, 2
387             buf.push_back({begin, end});
388         } else if (begin >= nRangeBeg && end <= nRangeEnd) { // case 3
389             // drop
390         } else if (end <= nRangeEnd) { // case 4
391             buf.push_back({begin, nRangeBeg - 1});
392         } else if (begin >= nRangeBeg) { // case 5
393             buf.push_back({nRangeEnd + 1, end});
394         } else { // case 6
395             buf.push_back({begin, nRangeBeg - 1});
396             buf.push_back({nRangeEnd + 1, end});
397         }
398     }
399     std::unique_ptr<WhichPair[]> pNewWhichTable(new WhichPair[buf.size()]);
400     std::copy(buf.begin(), buf.end(), pNewWhichTable.get());
401     return WhichRangesContainer(std::move(pNewWhichTable), buf.size());
402 }
403 
404 
405 SvdProgressInfo::SvdProgressInfo( const Link<void*,bool>&_rLink )
406 {
407     maLink = _rLink;
408     m_nSumCurAction   = 0;
409 
410     m_nObjCount = 0;
411     m_nCurObj   = 0;
412 
413     m_nActionCount = 0;
414     m_nCurAction   = 0;
415 
416     m_nInsertCount = 0;
417     m_nCurInsert   = 0;
418 }
419 
420 void SvdProgressInfo::Init( size_t nObjCount )
421 {
422     m_nObjCount = nObjCount;
423 }
424 
425 bool SvdProgressInfo::ReportActions( size_t nActionCount )
426 {
427     m_nSumCurAction += nActionCount;
428     m_nCurAction += nActionCount;
429     if(m_nCurAction > m_nActionCount)
430         m_nCurAction = m_nActionCount;
431 
432     return maLink.Call(nullptr);
433 }
434 
435 void SvdProgressInfo::ReportInserts( size_t nInsertCount )
436 {
437     m_nSumCurAction += nInsertCount;
438     m_nCurInsert += nInsertCount;
439 
440     maLink.Call(nullptr);
441 }
442 
443 void SvdProgressInfo::ReportRescales( size_t nRescaleCount )
444 {
445     m_nSumCurAction += nRescaleCount;
446     maLink.Call(nullptr);
447 }
448 
449 void SvdProgressInfo::SetActionCount( size_t nActionCount )
450 {
451     m_nActionCount = nActionCount;
452 }
453 
454 void SvdProgressInfo::SetInsertCount( size_t nInsertCount )
455 {
456     m_nInsertCount = nInsertCount;
457 }
458 
459 void SvdProgressInfo::SetNextObject()
460 {
461     m_nActionCount = 0;
462     m_nCurAction   = 0;
463 
464     m_nInsertCount = 0;
465     m_nCurInsert   = 0;
466 
467     m_nCurObj++;
468     ReportActions(0);
469 }
470 
471 // #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
472 // as text edit is not running on overlay
473 
474 namespace
475 {
476     bool impGetSdrObjListFillColor(
477         const SdrObjList& rList,
478         const Point& rPnt,
479         const SdrPageView& rTextEditPV,
480         const SdrLayerIDSet& rVisLayers,
481         Color& rCol)
482     {
483         bool bRet(false);
484         bool bMaster(rList.getSdrPageFromSdrObjList() && rList.getSdrPageFromSdrObjList()->IsMasterPage());
485 
486         for(size_t no(rList.GetObjCount()); !bRet && no > 0; )
487         {
488             no--;
489             SdrObject* pObj = rList.GetObj(no);
490             SdrObjList* pOL = pObj->GetSubList();
491 
492             if(pOL)
493             {
494                 // group object
495                 bRet = impGetSdrObjListFillColor(*pOL, rPnt, rTextEditPV, rVisLayers, rCol);
496             }
497             else
498             {
499                 SdrTextObj* pText = DynCastSdrTextObj(pObj);
500 
501                 // Exclude zero master page object (i.e. background shape) from color query
502                 if(pText
503                     && pObj->IsClosedObj()
504                     && (!bMaster || (!pObj->IsNotVisibleAsMaster() && 0 != no))
505                     && pObj->GetCurrentBoundRect().Contains(rPnt)
506                     && !pText->IsHideContour()
507                     && SdrObjectPrimitiveHit(*pObj, rPnt, {0, 0}, rTextEditPV, &rVisLayers, false))
508                 {
509                     bRet = GetDraftFillColor(pObj->GetMergedItemSet(), rCol);
510                 }
511             }
512         }
513 
514         return bRet;
515     }
516 
517     bool impGetSdrPageFillColor(
518         const SdrPage& rPage,
519         const Point& rPnt,
520         const SdrPageView& rTextEditPV,
521         const SdrLayerIDSet& rVisLayers,
522         Color& rCol,
523         bool bSkipBackgroundShape)
524     {
525         bool bRet(impGetSdrObjListFillColor(rPage, rPnt, rTextEditPV, rVisLayers, rCol));
526 
527         if(!bRet && !rPage.IsMasterPage())
528         {
529             if(rPage.TRG_HasMasterPage())
530             {
531                 SdrLayerIDSet aSet(rVisLayers);
532                 aSet &= rPage.TRG_GetMasterPageVisibleLayers();
533                 SdrPage& rMasterPage = rPage.TRG_GetMasterPage();
534 
535                 // Don't fall back to background shape on
536                 // master pages. This is later handled by
537                 // GetBackgroundColor, and is necessary to cater for
538                 // the silly ordering: 1. shapes, 2. master page
539                 // shapes, 3. page background, 4. master page
540                 // background.
541                 bRet = impGetSdrPageFillColor(rMasterPage, rPnt, rTextEditPV, aSet, rCol, true);
542             }
543         }
544 
545         // Only now determine background color from background shapes
546         if(!bRet && !bSkipBackgroundShape)
547         {
548             rCol = rPage.GetPageBackgroundColor();
549             return true;
550         }
551 
552         return bRet;
553     }
554 
555     Color impCalcBackgroundColor(
556         const tools::Rectangle& rArea,
557         const SdrPageView& rTextEditPV,
558         const SdrPage& rPage)
559     {
560         svtools::ColorConfig aColorConfig;
561         Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
562         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
563 
564         if(!rStyleSettings.GetHighContrastMode())
565         {
566             // search in page
567             const sal_uInt16 SPOTCOUNT(5);
568             Point aSpotPos[SPOTCOUNT];
569             Color aSpotColor[SPOTCOUNT];
570             sal_uInt32 nHeight( rArea.GetSize().Height() );
571             sal_uInt32 nWidth( rArea.GetSize().Width() );
572             sal_uInt32 nWidth14  = nWidth / 4;
573             sal_uInt32 nHeight14 = nHeight / 4;
574             sal_uInt32 nWidth34  = ( 3 * nWidth ) / 4;
575             sal_uInt32 nHeight34 = ( 3 * nHeight ) / 4;
576 
577             sal_uInt16 i;
578             for ( i = 0; i < SPOTCOUNT; i++ )
579             {
580                 // five spots are used
581                 switch ( i )
582                 {
583                     case 0 :
584                     {
585                         // Center-Spot
586                         aSpotPos[i] = rArea.Center();
587                     }
588                     break;
589 
590                     case 1 :
591                     {
592                         // TopLeft-Spot
593                         aSpotPos[i] = rArea.TopLeft();
594                         aSpotPos[i].AdjustX(nWidth14 );
595                         aSpotPos[i].AdjustY(nHeight14 );
596                     }
597                     break;
598 
599                     case 2 :
600                     {
601                         // TopRight-Spot
602                         aSpotPos[i] = rArea.TopLeft();
603                         aSpotPos[i].AdjustX(nWidth34 );
604                         aSpotPos[i].AdjustY(nHeight14 );
605                     }
606                     break;
607 
608                     case 3 :
609                     {
610                         // BottomLeft-Spot
611                         aSpotPos[i] = rArea.TopLeft();
612                         aSpotPos[i].AdjustX(nWidth14 );
613                         aSpotPos[i].AdjustY(nHeight34 );
614                     }
615                     break;
616 
617                     case 4 :
618                     {
619                         // BottomRight-Spot
620                         aSpotPos[i] = rArea.TopLeft();
621                         aSpotPos[i].AdjustX(nWidth34 );
622                         aSpotPos[i].AdjustY(nHeight34 );
623                     }
624                     break;
625 
626                 }
627 
628                 aSpotColor[i] = COL_WHITE;
629                 impGetSdrPageFillColor(rPage, aSpotPos[i], rTextEditPV, rTextEditPV.GetVisibleLayers(), aSpotColor[i], false);
630             }
631 
632             sal_uInt16 aMatch[SPOTCOUNT];
633 
634             for ( i = 0; i < SPOTCOUNT; i++ )
635             {
636                 // were same spot colors found?
637                 aMatch[i] = 0;
638 
639                 for ( sal_uInt16 j = 0; j < SPOTCOUNT; j++ )
640                 {
641                     if( j != i )
642                     {
643                         if( aSpotColor[i] == aSpotColor[j] )
644                         {
645                             aMatch[i]++;
646                         }
647                     }
648                 }
649             }
650 
651             // highest weight to center spot
652             aBackground = aSpotColor[0];
653 
654             for ( sal_uInt16 nMatchCount = SPOTCOUNT - 1; nMatchCount > 1; nMatchCount-- )
655             {
656                 // which spot color was found most?
657                 for ( i = 0; i < SPOTCOUNT; i++ )
658                 {
659                     if( aMatch[i] == nMatchCount )
660                     {
661                         aBackground = aSpotColor[i];
662                         nMatchCount = 1;   // break outer for-loop
663                         break;
664                     }
665                 }
666             }
667         }
668 
669         return aBackground;
670     }
671 } // end of anonymous namespace
672 
673 Color GetTextEditBackgroundColor(const SdrObjEditView& rView)
674 {
675     svtools::ColorConfig aColorConfig;
676     Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
677     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
678 
679     if(!rStyleSettings.GetHighContrastMode())
680     {
681         bool bFound(false);
682         SdrTextObj* pText = rView.GetTextEditObject();
683 
684         if(pText && pText->IsClosedObj())
685         {
686             sdr::table::SdrTableObj* pTable = dynamic_cast< sdr::table::SdrTableObj * >( pText );
687 
688             if( pTable )
689                 bFound = GetDraftFillColor(pTable->GetActiveCellItemSet(), aBackground );
690 
691             if( !bFound )
692                 bFound=GetDraftFillColor(pText->GetMergedItemSet(), aBackground);
693         }
694 
695         if(!bFound && pText)
696         {
697             SdrPageView* pTextEditPV = rView.GetTextEditPageView();
698 
699             if(pTextEditPV)
700             {
701                 Point aPvOfs(pText->GetTextEditOffset());
702                 const SdrPage* pPg = pTextEditPV->GetPage();
703 
704                 if(pPg)
705                 {
706                     tools::Rectangle aSnapRect( pText->GetSnapRect() );
707                     aSnapRect.Move(aPvOfs.X(), aPvOfs.Y());
708 
709                     return impCalcBackgroundColor(aSnapRect, *pTextEditPV, *pPg);
710                 }
711             }
712         }
713     }
714 
715     return aBackground;
716 }
717 
718 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
719