Coverage Report

Created: 2026-05-16 09:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/svx/source/svdraw/svdetc.cxx
Line
Count
Source
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
#if defined _WIN32 && !defined _WIN64
25
#include <officecfg/Office/Common.hxx>
26
#endif
27
#include <svtools/colorcfg.hxx>
28
#include <svx/svdetc.hxx>
29
#include <svx/svdedxv.hxx>
30
#include <svx/svdmodel.hxx>
31
#include <svx/svdoutl.hxx>
32
#include <vcl/BitmapReadAccess.hxx>
33
#include <editeng/eeitem.hxx>
34
#include <svl/itemset.hxx>
35
#include <svl/whiter.hxx>
36
#include <svx/xfillit0.hxx>
37
#include <svx/xflclit.hxx>
38
#include <svx/xflhtit.hxx>
39
#include <svx/xbtmpit.hxx>
40
#include <svx/xflgrit.hxx>
41
#include <svx/svdoole2.hxx>
42
#include <svx/xfltrit.hxx>
43
#include <svl/itempool.hxx>
44
#include <comphelper/configuration.hxx>
45
#include <unotools/localedatawrapper.hxx>
46
#include <unotools/syslocale.hxx>
47
#include <svx/xflbckit.hxx>
48
#include <svx/extrusionbar.hxx>
49
#include <svx/fontworkbar.hxx>
50
#include <vcl/svapp.hxx>
51
#include <vcl/settings.hxx>
52
#include <svx/sdr/contact/viewcontact.hxx>
53
#include <svx/svdpage.hxx>
54
#include <svx/svdpagv.hxx>
55
#include <svx/svdotable.hxx>
56
#include <svx/sdrhittesthelper.hxx>
57
58
#include <com/sun/star/frame/XModel.hpp>
59
#include <com/sun/star/embed/XEmbeddedObject.hpp>
60
61
using namespace ::com::sun::star;
62
63
// Global data of the DrawingEngine
64
SdrGlobalData::SdrGlobalData()
65
26
{
66
26
    if (!comphelper::IsFuzzing())
67
0
    {
68
0
        svx::ExtrusionBar::RegisterInterface();
69
0
        svx::FontworkBar::RegisterInterface();
70
0
    }
71
26
}
72
73
const LocaleDataWrapper& SdrGlobalData::GetLocaleData()
74
0
{
75
0
    return GetSysLocale().GetLocaleData();
76
0
}
77
78
namespace {
79
80
struct TheSdrGlobalData: public rtl::Static<SdrGlobalData, TheSdrGlobalData> {};
81
82
}
83
84
70
SdrGlobalData & GetSdrGlobalData() {
85
70
    return TheSdrGlobalData::get();
86
70
}
87
88
OLEObjCache::OLEObjCache()
89
26
{
90
26
    if (!comphelper::IsFuzzing())
91
0
    {
92
// This limit is only useful on 32-bit windows, where we can run out of virtual memory (see tdf#95579)
93
// For everything else, we are better off keeping it in main memory rather than using our hacky page-out thing
94
#if defined _WIN32 && !defined _WIN64
95
        mnSize = officecfg::Office::Common::Cache::DrawingEngine::OLE_Objects::get();
96
#else
97
0
        mnSize = SAL_MAX_INT32; // effectively disable the page-out mechanism
98
0
#endif
99
0
    }
100
26
    else
101
26
        mnSize = 100;
102
26
    mpTimer.reset( new AutoTimer( "svx OLEObjCache pTimer UnloadCheck" ) );
103
26
    mpTimer->SetInvokeHandler( LINK(this, OLEObjCache, UnloadCheckHdl) );
104
26
    mpTimer->SetTimeout(20000);
105
26
    mpTimer->SetStatic();
106
26
}
107
108
OLEObjCache::~OLEObjCache()
109
26
{
110
26
    mpTimer->Stop();
111
26
}
112
113
IMPL_LINK_NOARG(OLEObjCache, UnloadCheckHdl, Timer*, void)
114
0
{
115
0
    if (mnSize >= maObjs.size())
116
0
        return;
117
118
    // more objects than configured cache size try to remove objects
119
    // of course not the freshly inserted one at nIndex=0
120
0
    size_t nCount2 = maObjs.size();
121
0
    size_t nIndex = nCount2-1;
122
0
    while( nIndex && nCount2 > mnSize )
123
0
    {
124
0
        SdrOle2Obj* pUnloadObj = maObjs[nIndex--];
125
0
        if (!pUnloadObj)
126
0
            continue;
127
128
0
        try
129
0
        {
130
            // it is important to get object without reinitialization to avoid reentrance
131
0
            const uno::Reference< embed::XEmbeddedObject > & xUnloadObj = pUnloadObj->GetObjRef_NoInit();
132
133
0
            bool bUnload = !xUnloadObj || SdrOle2Obj::CanUnloadRunningObj( xUnloadObj, pUnloadObj->GetAspect() );
134
135
            // check whether the object can be unloaded before looking for the parent objects
136
0
            if ( xUnloadObj.is() && bUnload )
137
0
            {
138
0
                uno::Reference< frame::XModel > xUnloadModel( xUnloadObj->getComponent(), uno::UNO_QUERY );
139
0
                if ( xUnloadModel.is() )
140
0
                {
141
0
                    for (SdrOle2Obj* pCacheObj : maObjs)
142
0
                    {
143
0
                        if ( pCacheObj && pCacheObj != pUnloadObj )
144
0
                        {
145
0
                            uno::Reference< frame::XModel > xParentModel = pCacheObj->GetParentXModel();
146
0
                            if ( xUnloadModel == xParentModel )
147
0
                            {
148
0
                                bUnload = false; // the object has running embedded objects
149
0
                                break;
150
0
                            }
151
0
                        }
152
0
                    }
153
0
                }
154
0
            }
155
156
0
            if (bUnload && UnloadObj(*pUnloadObj))
157
0
            {
158
                // object was successfully unloaded
159
0
                RemoveObj(pUnloadObj);
160
0
                nCount2 = std::min(nCount2 - 1, maObjs.size());
161
0
                if (nIndex >= nCount2)
162
0
                    nIndex = nCount2 - 1;
163
0
            }
164
0
        }
165
0
        catch( uno::Exception& )
166
0
        {}
167
0
    }
168
0
}
169
170
void OLEObjCache::InsertObj(SdrOle2Obj* pObj)
171
0
{
172
0
    if (!maObjs.empty())
173
0
    {
174
0
        SdrOle2Obj* pExistingObj = maObjs.front();
175
0
        if ( pObj == pExistingObj )
176
            // the object is already on the top, nothing has to be changed
177
0
            return;
178
0
    }
179
180
    // get the old position of the object to know whether it is already in container
181
0
    std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
182
0
    bool bFound = it != maObjs.end();
183
184
0
    if (bFound)
185
0
        maObjs.erase(it);
186
    // insert object into first position
187
0
    maObjs.insert(maObjs.begin(), pObj);
188
189
    // if a new object was inserted, recalculate the cache
190
0
    if (!bFound)
191
0
        mpTimer->Invoke();
192
193
0
    if (!bFound || !mpTimer->IsActive())
194
0
        mpTimer->Start();
195
0
}
196
197
void OLEObjCache::RemoveObj(SdrOle2Obj* pObj)
198
0
{
199
0
    std::vector<SdrOle2Obj*>::iterator it = std::find(maObjs.begin(), maObjs.end(), pObj);
200
0
    if (it != maObjs.end())
201
0
        maObjs.erase(it);
202
0
    if (maObjs.empty())
203
0
        mpTimer->Stop();
204
0
}
205
206
size_t OLEObjCache::size() const
207
0
{
208
0
    return maObjs.size();
209
0
}
210
211
SdrOle2Obj* OLEObjCache::operator[](size_t nPos)
212
0
{
213
0
    return maObjs[nPos];
214
0
}
215
216
const SdrOle2Obj* OLEObjCache::operator[](size_t nPos) const
217
0
{
218
0
    return maObjs[nPos];
219
0
}
220
221
bool OLEObjCache::UnloadObj(SdrOle2Obj& rObj)
222
0
{
223
0
    bool bUnloaded = false;
224
225
    //#i80528# The old mechanism is completely useless, only taking into account if
226
    // in all views the GrafDraft feature is used. This will nearly never have been the
227
    // case since no one ever used this option.
228
229
    // A much better (and working) criteria would be the VOC contact count.
230
    // The question is what will happen when i make it work now suddenly? I
231
    // will try it for 2.4.
232
0
    const sdr::contact::ViewContact& rViewContact = rObj.GetViewContact();
233
0
    const bool bVisible(rViewContact.HasViewObjectContacts());
234
235
0
    if(!bVisible)
236
0
    {
237
0
        bUnloaded = rObj.Unload();
238
0
    }
239
240
0
    return bUnloaded;
241
0
}
242
243
std::optional<Color> GetDraftFillColor(const SfxItemSet& rSet)
244
640
{
245
640
    drawing::FillStyle eFill=rSet.Get(XATTR_FILLSTYLE).GetValue();
246
640
    Color aResult;
247
640
    switch(eFill)
248
640
    {
249
337
        case drawing::FillStyle_SOLID:
250
337
        {
251
337
            aResult = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
252
337
            break;
253
0
        }
254
0
        case drawing::FillStyle_HATCH:
255
0
        {
256
0
            Color aCol1(rSet.Get(XATTR_FILLHATCH).GetHatchValue().GetColor());
257
0
            Color aCol2(COL_WHITE);
258
259
            // when hatched background is activated, use object fill color as hatch color
260
0
            bool bFillHatchBackground = rSet.Get(XATTR_FILLBACKGROUND).GetValue();
261
0
            if(bFillHatchBackground)
262
0
            {
263
0
                aCol2 = rSet.Get(XATTR_FILLCOLOR).GetColorValue();
264
0
            }
265
266
0
            const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
267
0
            aResult = Color(aAverageColor);
268
0
            break;
269
0
        }
270
0
        case drawing::FillStyle_GRADIENT: {
271
0
            const basegfx::BGradient& rGrad=rSet.Get(XATTR_FILLGRADIENT).GetGradientValue();
272
0
            Color aCol1(Color(rGrad.GetColorStops().front().getStopColor()));
273
0
            Color aCol2(Color(rGrad.GetColorStops().back().getStopColor()));
274
0
            const basegfx::BColor aAverageColor(basegfx::average(aCol1.getBColor(), aCol2.getBColor()));
275
0
            aResult = Color(aAverageColor);
276
0
            break;
277
0
        }
278
0
        case drawing::FillStyle_BITMAP:
279
0
        {
280
0
            Bitmap aBitmap(rSet.Get(XATTR_FILLBITMAP).GetGraphicObject().GetGraphic().GetBitmap().CreateColorBitmap());
281
0
            const Size aSize(aBitmap.GetSizePixel());
282
0
            const sal_uInt32 nWidth = aSize.Width();
283
0
            const sal_uInt32 nHeight = aSize.Height();
284
0
            if (nWidth <= 0 || nHeight <= 0)
285
0
                return {};
286
287
0
            BitmapScopedReadAccess pAccess(aBitmap);
288
289
0
            if (pAccess)
290
0
            {
291
0
                sal_uInt32 nRt(0);
292
0
                sal_uInt32 nGn(0);
293
0
                sal_uInt32 nBl(0);
294
0
                const sal_uInt32 nMaxSteps(8);
295
0
                const sal_uInt32 nXStep((nWidth > nMaxSteps) ? nWidth / nMaxSteps : 1);
296
0
                const sal_uInt32 nYStep((nHeight > nMaxSteps) ? nHeight / nMaxSteps : 1);
297
0
                sal_uInt32 nCount(0);
298
299
0
                for(sal_uInt32 nY(0); nY < nHeight; nY += nYStep)
300
0
                {
301
0
                    for(sal_uInt32 nX(0); nX < nWidth; nX += nXStep)
302
0
                    {
303
0
                        const BitmapColor aCol2 = pAccess->GetColor(nY, nX);
304
305
0
                        nRt += aCol2.GetRed();
306
0
                        nGn += aCol2.GetGreen();
307
0
                        nBl += aCol2.GetBlue();
308
0
                        nCount++;
309
0
                    }
310
0
                }
311
312
0
                nRt /= nCount;
313
0
                nGn /= nCount;
314
0
                nBl /= nCount;
315
316
0
                aResult = Color(sal_uInt8(nRt), sal_uInt8(nGn), sal_uInt8(nBl));
317
0
            }
318
0
            break;
319
0
        }
320
303
        default:
321
303
            return {};
322
640
    }
323
324
337
    sal_uInt16 nTransparencyPercentage = rSet.Get(XATTR_FILLTRANSPARENCE).GetValue();
325
337
    if (!nTransparencyPercentage)
326
300
        return aResult;
327
328
37
    auto nTransparency = nTransparencyPercentage / 100.0;
329
37
    auto nOpacity = 1 - nTransparency;
330
331
37
    svtools::ColorConfig aColorConfig;
332
37
    Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
333
334
    // https://en.wikipedia.org/wiki/Alpha_compositing
335
    // We are here calculating transparency fill color against background with
336
    // To put it is simple words with example
337
    // I.E: fill is Red (FF0000) and background is pure white (FFFFFF)
338
    // If we add 50% transparency to fill color will look like Pink(ff7777)
339
340
    // TODO: calculate this colors based on object in background  and not just the doc color
341
37
    aResult.SetRed(
342
37
        std::min(aResult.GetRed() * nOpacity + aBackground.GetRed() * nTransparency, 255.0));
343
37
    aResult.SetGreen(
344
37
        std::min(aResult.GetGreen() * nOpacity + aBackground.GetGreen() * nTransparency, 255.0));
345
37
    aResult.SetBlue(
346
37
        std::min(aResult.GetBlue() * nOpacity + aBackground.GetBlue() * nTransparency, 255.0));
347
37
    return aResult;
348
337
}
349
350
std::unique_ptr<SdrOutliner> SdrMakeOutliner(OutlinerMode nOutlinerMode, SdrModel& rModel)
351
577k
{
352
577k
    SfxItemPool* pPool = &rModel.GetItemPool();
353
577k
    std::unique_ptr<SdrOutliner> pOutl(new SdrOutliner( pPool, nOutlinerMode ));
354
577k
    pOutl->SetStyleSheetPool( static_cast<SfxStyleSheetPool*>(rModel.GetStyleSheetPool()));
355
577k
    pOutl->SetDefTab(rModel.GetDefaultTabulator());
356
577k
    Outliner::SetForbiddenCharsTable(rModel.GetForbiddenCharsTable());
357
577k
    pOutl->SetAsianCompressionMode(rModel.GetCharCompressType());
358
577k
    pOutl->SetKernAsianPunctuation(rModel.IsKernAsianPunctuation());
359
577k
    pOutl->SetAddExtLeading(rModel.IsAddExtLeading());
360
577k
    return pOutl;
361
577k
}
362
363
std::vector<Link<SdrObjCreatorParams, rtl::Reference<SdrObject>>>& ImpGetUserMakeObjHdl()
364
70
{
365
70
    SdrGlobalData& rGlobalData=GetSdrGlobalData();
366
70
    return rGlobalData.maUserMakeObjHdl;
367
70
}
368
369
bool SearchOutlinerItems(const SfxItemSet& rSet, bool bInklDefaults, bool* pbOnlyEE)
370
0
{
371
0
    bool bHas=false;
372
0
    bool bOnly=true;
373
0
    bool bLookOnly=pbOnlyEE!=nullptr;
374
0
    SfxWhichIter aIter(rSet);
375
0
    sal_uInt16 nWhich=aIter.FirstWhich();
376
0
    while (((bLookOnly && bOnly) || !bHas) && nWhich!=0) {
377
        // For bInklDefaults, the entire Which range is decisive,
378
        // in other cases only the set items are.
379
        // Disabled and DontCare are regarded as holes in the Which range.
380
0
        SfxItemState eState=aIter.GetItemState();
381
0
        if ((eState==SfxItemState::DEFAULT && bInklDefaults) || eState==SfxItemState::SET) {
382
0
            if (nWhich<EE_ITEMS_START || nWhich>EE_ITEMS_END) bOnly=false;
383
0
            else bHas=true;
384
0
        }
385
0
        nWhich=aIter.NextWhich();
386
0
    }
387
0
    if (!bHas) bOnly=false;
388
0
    if (pbOnlyEE!=nullptr) *pbOnlyEE=bOnly;
389
0
    return bHas;
390
0
}
391
392
WhichRangesContainer RemoveWhichRange(const WhichRangesContainer& pOldWhichTable, sal_uInt16 nRangeBeg, sal_uInt16 nRangeEnd)
393
0
{
394
    // Six possible cases (per range):
395
    //         [Beg..End]          [nRangeBeg, nRangeEnd], to delete
396
    // [b..e]    [b..e]    [b..e]  Cases 1,3,2: doesn't matter, delete, doesn't matter  + Ranges
397
    // [b........e]  [b........e]  Cases 4,5  : shrink range                            | in
398
    // [b......................e]  Case  6    : splitting                               + pOldWhichTable
399
0
    std::vector<WhichPair> buf;
400
0
    for (const auto & rPair : pOldWhichTable) {
401
0
        auto const begin = rPair.first;
402
0
        auto const end = rPair.second;
403
0
        if (end < nRangeBeg || begin > nRangeEnd) { // cases 1, 2
404
0
            buf.push_back({begin, end});
405
0
        } else if (begin >= nRangeBeg && end <= nRangeEnd) { // case 3
406
            // drop
407
0
        } else if (end <= nRangeEnd) { // case 4
408
0
            buf.push_back({begin, nRangeBeg - 1});
409
0
        } else if (begin >= nRangeBeg) { // case 5
410
0
            buf.push_back({nRangeEnd + 1, end});
411
0
        } else { // case 6
412
0
            buf.push_back({begin, nRangeBeg - 1});
413
0
            buf.push_back({nRangeEnd + 1, end});
414
0
        }
415
0
    }
416
0
    std::unique_ptr<WhichPair[]> pNewWhichTable(new WhichPair[buf.size()]);
417
0
    std::copy(buf.begin(), buf.end(), pNewWhichTable.get());
418
0
    return WhichRangesContainer(std::move(pNewWhichTable), buf.size());
419
0
}
420
421
422
SvdProgressInfo::SvdProgressInfo( const Link<void*,bool>&_rLink )
423
0
{
424
0
    maLink = _rLink;
425
0
    m_nSumCurAction   = 0;
426
427
0
    m_nObjCount = 0;
428
0
    m_nCurObj   = 0;
429
430
0
    m_nActionCount = 0;
431
0
    m_nCurAction   = 0;
432
433
0
    m_nInsertCount = 0;
434
0
    m_nCurInsert   = 0;
435
0
}
436
437
void SvdProgressInfo::Init( size_t nObjCount )
438
0
{
439
0
    m_nObjCount = nObjCount;
440
0
}
441
442
bool SvdProgressInfo::ReportActions( size_t nActionCount )
443
0
{
444
0
    m_nSumCurAction += nActionCount;
445
0
    m_nCurAction += nActionCount;
446
0
    if(m_nCurAction > m_nActionCount)
447
0
        m_nCurAction = m_nActionCount;
448
449
0
    return maLink.Call(nullptr);
450
0
}
451
452
void SvdProgressInfo::ReportInserts( size_t nInsertCount )
453
0
{
454
0
    m_nSumCurAction += nInsertCount;
455
0
    m_nCurInsert += nInsertCount;
456
457
0
    maLink.Call(nullptr);
458
0
}
459
460
void SvdProgressInfo::ReportRescales( size_t nRescaleCount )
461
0
{
462
0
    m_nSumCurAction += nRescaleCount;
463
0
    maLink.Call(nullptr);
464
0
}
465
466
void SvdProgressInfo::SetActionCount( size_t nActionCount )
467
0
{
468
0
    m_nActionCount = nActionCount;
469
0
}
470
471
void SvdProgressInfo::SetInsertCount( size_t nInsertCount )
472
0
{
473
0
    m_nInsertCount = nInsertCount;
474
0
}
475
476
void SvdProgressInfo::SetNextObject()
477
0
{
478
0
    m_nActionCount = 0;
479
0
    m_nCurAction   = 0;
480
481
0
    m_nInsertCount = 0;
482
0
    m_nCurInsert   = 0;
483
484
0
    m_nCurObj++;
485
0
    ReportActions(0);
486
0
}
487
488
// #i101872# isolate GetTextEditBackgroundColor to tooling; it will anyways only be used as long
489
// as text edit is not running on overlay
490
491
namespace
492
{
493
    std::optional<Color> impGetSdrObjListFillColor(
494
        const SdrObjList& rList,
495
        const Point& rPnt,
496
        const SdrPageView& rTextEditPV,
497
        const SdrLayerIDSet& rVisLayers)
498
0
    {
499
0
        bool bMaster(rList.getSdrPageFromSdrObjList() && rList.getSdrPageFromSdrObjList()->IsMasterPage());
500
501
0
        for(size_t no(rList.GetObjCount()); no > 0; )
502
0
        {
503
0
            no--;
504
0
            SdrObject* pObj = rList.GetObj(no);
505
0
            SdrObjList* pOL = pObj->GetSubList();
506
507
0
            if(pOL)
508
0
            {
509
                // group object
510
0
                if (auto oColor = impGetSdrObjListFillColor(*pOL, rPnt, rTextEditPV, rVisLayers))
511
0
                    return oColor;
512
0
            }
513
0
            else
514
0
            {
515
0
                SdrTextObj* pText = DynCastSdrTextObj(pObj);
516
517
                // Exclude zero master page object (i.e. background shape) from color query
518
0
                if(pText
519
0
                    && pObj->IsClosedObj()
520
0
                    && (!bMaster || (!pObj->IsNotVisibleAsMaster() && 0 != no))
521
0
                    && pObj->GetCurrentBoundRect().Contains(rPnt)
522
0
                    && !pText->IsHideContour()
523
0
                    && SdrObjectPrimitiveHit(*pObj, rPnt, {0, 0}, rTextEditPV, &rVisLayers, false))
524
0
                {
525
0
                    if (auto oColor = GetDraftFillColor(pObj->GetMergedItemSet()))
526
0
                        return oColor;
527
0
                }
528
0
            }
529
0
        }
530
531
0
        return {};
532
0
    }
533
534
    std::optional<Color> impGetSdrPageFillColor(
535
        const SdrPage& rPage,
536
        const Point& rPnt,
537
        const SdrPageView& rTextEditPV,
538
        const SdrLayerIDSet& rVisLayers,
539
        bool bSkipBackgroundShape)
540
0
    {
541
0
        if (auto oColor = impGetSdrObjListFillColor(rPage, rPnt, rTextEditPV, rVisLayers))
542
0
            return oColor;
543
544
0
        if(!rPage.IsMasterPage())
545
0
        {
546
0
            if(rPage.TRG_HasMasterPage())
547
0
            {
548
0
                SdrLayerIDSet aSet(rVisLayers);
549
0
                aSet &= rPage.TRG_GetMasterPageVisibleLayers();
550
0
                SdrPage& rMasterPage = rPage.TRG_GetMasterPage();
551
552
                // Don't fall back to background shape on
553
                // master pages. This is later handled by
554
                // GetBackgroundColor, and is necessary to cater for
555
                // the silly ordering: 1. shapes, 2. master page
556
                // shapes, 3. page background, 4. master page
557
                // background.
558
0
                if (auto oColor = impGetSdrPageFillColor(rMasterPage, rPnt, rTextEditPV, aSet, true))
559
0
                    return oColor;
560
0
            }
561
0
        }
562
563
        // Only now determine background color from background shapes
564
0
        if(!bSkipBackgroundShape)
565
0
        {
566
0
            return rPage.GetPageBackgroundColor();
567
0
        }
568
569
0
        return {};
570
0
    }
571
572
    Color impCalcBackgroundColor(
573
        const tools::Rectangle& rArea,
574
        const SdrPageView& rTextEditPV,
575
        const SdrPage& rPage)
576
0
    {
577
0
        svtools::ColorConfig aColorConfig;
578
0
        Color aBackground(aColorConfig.GetColorValue(svtools::DOCCOLOR).nColor);
579
0
        const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
580
581
0
        if(!rStyleSettings.GetHighContrastMode())
582
0
        {
583
            // search in page
584
0
            const sal_uInt16 SPOTCOUNT(5);
585
0
            Point aSpotPos[SPOTCOUNT];
586
0
            Color aSpotColor[SPOTCOUNT];
587
0
            sal_uInt32 nHeight( rArea.GetSize().Height() );
588
0
            sal_uInt32 nWidth( rArea.GetSize().Width() );
589
0
            sal_uInt32 nWidth14  = nWidth / 4;
590
0
            sal_uInt32 nHeight14 = nHeight / 4;
591
0
            sal_uInt32 nWidth34  = ( 3 * nWidth ) / 4;
592
0
            sal_uInt32 nHeight34 = ( 3 * nHeight ) / 4;
593
594
0
            sal_uInt16 i;
595
0
            for ( i = 0; i < SPOTCOUNT; i++ )
596
0
            {
597
                // five spots are used
598
0
                switch ( i )
599
0
                {
600
0
                    case 0 :
601
0
                    {
602
                        // Center-Spot
603
0
                        aSpotPos[i] = rArea.Center();
604
0
                    }
605
0
                    break;
606
607
0
                    case 1 :
608
0
                    {
609
                        // TopLeft-Spot
610
0
                        aSpotPos[i] = rArea.TopLeft();
611
0
                        aSpotPos[i].AdjustX(nWidth14 );
612
0
                        aSpotPos[i].AdjustY(nHeight14 );
613
0
                    }
614
0
                    break;
615
616
0
                    case 2 :
617
0
                    {
618
                        // TopRight-Spot
619
0
                        aSpotPos[i] = rArea.TopLeft();
620
0
                        aSpotPos[i].AdjustX(nWidth34 );
621
0
                        aSpotPos[i].AdjustY(nHeight14 );
622
0
                    }
623
0
                    break;
624
625
0
                    case 3 :
626
0
                    {
627
                        // BottomLeft-Spot
628
0
                        aSpotPos[i] = rArea.TopLeft();
629
0
                        aSpotPos[i].AdjustX(nWidth14 );
630
0
                        aSpotPos[i].AdjustY(nHeight34 );
631
0
                    }
632
0
                    break;
633
634
0
                    case 4 :
635
0
                    {
636
                        // BottomRight-Spot
637
0
                        aSpotPos[i] = rArea.TopLeft();
638
0
                        aSpotPos[i].AdjustX(nWidth34 );
639
0
                        aSpotPos[i].AdjustY(nHeight34 );
640
0
                    }
641
0
                    break;
642
643
0
                }
644
645
0
                aSpotColor[i] =
646
0
                    impGetSdrPageFillColor(rPage, aSpotPos[i], rTextEditPV, rTextEditPV.GetVisibleLayers(), false).value_or(COL_WHITE);
647
0
            }
648
649
0
            sal_uInt16 aMatch[SPOTCOUNT];
650
651
0
            for ( i = 0; i < SPOTCOUNT; i++ )
652
0
            {
653
                // were same spot colors found?
654
0
                aMatch[i] = 0;
655
656
0
                for ( sal_uInt16 j = 0; j < SPOTCOUNT; j++ )
657
0
                {
658
0
                    if( j != i )
659
0
                    {
660
0
                        if( aSpotColor[i] == aSpotColor[j] )
661
0
                        {
662
0
                            aMatch[i]++;
663
0
                        }
664
0
                    }
665
0
                }
666
0
            }
667
668
            // highest weight to center spot
669
0
            aBackground = aSpotColor[0];
670
671
0
            for ( sal_uInt16 nMatchCount = SPOTCOUNT - 1; nMatchCount > 1; nMatchCount-- )
672
0
            {
673
                // which spot color was found most?
674
0
                for ( i = 0; i < SPOTCOUNT; i++ )
675
0
                {
676
0
                    if( aMatch[i] == nMatchCount )
677
0
                    {
678
0
                        aBackground = aSpotColor[i];
679
0
                        nMatchCount = 1;   // break outer for-loop
680
0
                        break;
681
0
                    }
682
0
                }
683
0
            }
684
0
        }
685
686
0
        return aBackground;
687
0
    }
688
} // end of anonymous namespace
689
690
Color GetTextEditBackgroundColor(const SdrObjEditView& rView)
691
0
{
692
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
693
694
0
    if(!rStyleSettings.GetHighContrastMode())
695
0
    {
696
0
        SdrTextObj* pText = rView.GetTextEditObject();
697
698
0
        if(pText && pText->IsClosedObj())
699
0
        {
700
0
            sdr::table::SdrTableObj* pTable = dynamic_cast< sdr::table::SdrTableObj * >( pText );
701
702
0
            if( pTable )
703
0
                if (auto oColor = GetDraftFillColor(pTable->GetActiveCellItemSet()))
704
0
                    return *oColor;
705
706
0
            if (auto oColor = GetDraftFillColor(pText->GetMergedItemSet()))
707
0
                return *oColor;
708
0
        }
709
710
0
        if (pText)
711
0
        {
712
0
            SdrPageView* pTextEditPV = rView.GetTextEditPageView();
713
714
0
            if(pTextEditPV)
715
0
            {
716
0
                Point aPvOfs(pText->GetTextEditOffset());
717
0
                const SdrPage* pPg = pTextEditPV->GetPage();
718
719
0
                if(pPg)
720
0
                {
721
0
                    tools::Rectangle aSnapRect( pText->GetSnapRect() );
722
0
                    aSnapRect.Move(aPvOfs.X(), aPvOfs.Y());
723
724
0
                    return impCalcBackgroundColor(aSnapRect, *pTextEditPV, *pPg);
725
0
                }
726
0
            }
727
0
        }
728
0
    }
729
730
0
    return svtools::ColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
731
0
}
732
733
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */