Coverage Report

Created: 2026-09-28 10:59

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libreoffice/sc/source/ui/view/output.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 <scitems.hxx>
21
#include <editeng/brushitem.hxx>
22
#include <svtools/colorcfg.hxx>
23
#include <svx/rotmodit.hxx>
24
#include <svx/svdocapt.hxx>
25
#include <editeng/shaditem.hxx>
26
#include <editeng/svxfont.hxx>
27
#include <tools/poly.hxx>
28
#include <vcl/svapp.hxx>
29
#include <vcl/pdfextoutdevdata.hxx>
30
#include <svx/framelinkarray.hxx>
31
#include <drawinglayer/geometry/viewinformation2d.hxx>
32
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
33
#include <drawinglayer/processor2d/processor2dtools.hxx>
34
#include <officecfg/Office/Common.hxx>
35
#include <officecfg/Office/Calc.hxx>
36
#include <vcl/lineinfo.hxx>
37
#include <vcl/gradient.hxx>
38
#include <vcl/rendercontext/DrawModeFlags.hxx>
39
#include <vcl/settings.hxx>
40
#include <vcl/pdf/PDFNote.hxx>
41
#include <svx/unoapi.hxx>
42
#include <sal/log.hxx>
43
#include <comphelper/lok.hxx>
44
#include <o3tl/unit_conversion.hxx>
45
#include <basegfx/matrix/b2dhommatrix.hxx>
46
47
#include <output.hxx>
48
#include <document.hxx>
49
#include <drwlayer.hxx>
50
#include <formulacell.hxx>
51
#include <attrib.hxx>
52
#include <patattr.hxx>
53
#include <progress.hxx>
54
#include <pagedata.hxx>
55
#include <chgtrack.hxx>
56
#include <chgviset.hxx>
57
#include <viewutil.hxx>
58
#include <gridmerg.hxx>
59
#include <fillinfo.hxx>
60
#include <scmod.hxx>
61
#include <appoptio.hxx>
62
#include <postit.hxx>
63
#include <validat.hxx>
64
#include <detfunc.hxx>
65
#include <editutil.hxx>
66
67
#include <MatrixResizeGuard.hxx>
68
#include <SparklineRenderer.hxx>
69
#include <colorscale.hxx>
70
71
#include <math.h>
72
#include <memory>
73
74
using namespace com::sun::star;
75
76
// Static Data
77
78
// color for ChangeTracking "by author" as in the writer (swmodul1.cxx)
79
80
0
#define SC_AUTHORCOLORCOUNT     9
81
82
const Color nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
83
                    COL_LIGHTRED,       COL_LIGHTBLUE,      COL_LIGHTMAGENTA,
84
                    COL_GREEN,          COL_RED,            COL_BLUE,
85
                    COL_BROWN,          COL_MAGENTA,        COL_CYAN };
86
87
// Helper class for color assignment to avoid repeated lookups for the same user
88
89
ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
90
0
    rOpt( ScModule::get()->GetAppOptions() ),
91
0
    rUsers( rTrack.GetUserCollection() ),
92
0
    nLastUserIndex( 0 ),
93
0
    nColor( COL_BLACK )
94
0
{
95
0
}
96
97
void ScActionColorChanger::Update( const ScChangeAction& rAction )
98
0
{
99
0
    Color nSetColor;
100
0
    switch (rAction.GetType())
101
0
    {
102
0
        case SC_CAT_INSERT_COLS:
103
0
        case SC_CAT_INSERT_ROWS:
104
0
        case SC_CAT_INSERT_TABS:
105
0
            nSetColor = rOpt.GetTrackInsertColor();
106
0
            break;
107
0
        case SC_CAT_DELETE_COLS:
108
0
        case SC_CAT_DELETE_ROWS:
109
0
        case SC_CAT_DELETE_TABS:
110
0
            nSetColor = rOpt.GetTrackDeleteColor();
111
0
            break;
112
0
        case SC_CAT_MOVE:
113
0
            nSetColor = rOpt.GetTrackMoveColor();
114
0
            break;
115
0
        default:
116
0
            nSetColor = rOpt.GetTrackContentColor();
117
0
            break;
118
0
    }
119
0
    if ( nSetColor != COL_TRANSPARENT )     // color assigned
120
0
        nColor = nSetColor;
121
0
    else                                    // by author
122
0
    {
123
0
        if (aLastUserName != rAction.GetUser())
124
0
        {
125
0
            aLastUserName = rAction.GetUser();
126
0
            std::set<OUString>::const_iterator it = rUsers.find(aLastUserName);
127
0
            if (it == rUsers.end())
128
0
            {
129
                // empty string is possible if a name wasn't found while saving a 5.0 file
130
0
                SAL_INFO_IF( aLastUserName.isEmpty(), "sc.ui", "Author not found" );
131
0
                nLastUserIndex = 0;
132
0
            }
133
0
            else
134
0
            {
135
0
                size_t nPos = std::distance(rUsers.begin(), it);
136
0
                nLastUserIndex = nPos % SC_AUTHORCOLORCOUNT;
137
0
            }
138
0
        }
139
0
        nColor = nAuthorColor[nLastUserIndex];
140
0
    }
141
0
}
142
143
ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
144
                            ScTableInfo& rTabInfo, ScDocument* pNewDoc,
145
                            SCTAB nNewTab, tools::Long nNewScrX, tools::Long nNewScrY,
146
                            SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
147
                            double nPixelPerTwipsX, double nPixelPerTwipsY,
148
                            const double* pZoomX, const double* pZoomY ) :
149
0
    mpOriginalTargetDevice( pNewDev ),
150
0
    mpDev( pNewDev ),
151
0
    mpRefDevice( pNewDev ),      // default is output device
152
0
    pFmtDevice( pNewDev ),      // default is output device
153
0
    mrTabInfo( rTabInfo ),
154
0
    mpRowInfo( rTabInfo.mpRowInfo.get() ),
155
0
    mnArrCount( rTabInfo.mnArrCount ),
156
0
    mpDoc( pNewDoc ),
157
0
    mnTab( nNewTab ),
158
0
    mnScrX( nNewScrX ),
159
0
    mnScrY( nNewScrY ),
160
0
    mnX1( nNewX1 ),
161
0
    mnY1( nNewY1 ),
162
0
    mnX2( nNewX2 ),
163
0
    mnY2( nNewY2 ),
164
0
    meType( eNewType ),
165
0
    mnPPTX( nPixelPerTwipsX ),
166
0
    mnPPTY( nPixelPerTwipsY ),
167
0
    mpViewShell( nullptr ),
168
0
    mpDrawView( nullptr ),
169
0
    mbEditMode( false ),
170
0
    mnEditCol( 0 ),
171
0
    mnEditRow( 0 ),
172
0
    mbMetaFile( false ),
173
0
    mbPagebreakMode( false ),
174
0
    mbSolidBackground( false ),
175
0
    mbUseStyleColor( false ),
176
0
    mbForceAutoColor( officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get() ),
177
0
    mbSyntaxMode( false ),
178
0
    maGridColor( COL_BLACK ),
179
0
    mbShowNullValues( true ),
180
0
    mbShowFormulas( false ),
181
0
    mbShowSpellErrors( false ),
182
0
    mbMarkClipped( false ), // sal_False for printer/metafile etc.
183
0
    mbSnapPixel( false ),
184
0
    mbAnyClipped( false ),
185
0
    mbVertical(false),
186
0
    mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
187
0
    mpSpellCheckCxt(nullptr)
188
0
{
189
0
    if (pZoomX)
190
0
        mfZoomX = *pZoomX;
191
0
    else
192
0
        mfZoomX = 1.0;
193
0
    if (pZoomY)
194
0
        mfZoomY = *pZoomY;
195
0
    else
196
0
        mfZoomY = 1.0;
197
198
0
    mnVisX1 = mnX1;
199
0
    mnVisY1 = mnY1;
200
0
    mnVisX2 = mnX2;
201
0
    mnVisY2 = mnY2;
202
0
    mpDoc->StripHidden( mnVisX1, mnVisY1, mnVisX2, mnVisY2, mnTab );
203
204
0
    mnScrW = 0;
205
0
    for (SCCOL nX=mnVisX1; nX<=mnVisX2; nX++)
206
0
        mnScrW += mpRowInfo[0].basicCellInfo(nX).nWidth;
207
208
0
    mnMirrorW = mnScrW;
209
210
0
    mnScrH = 0;
211
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
212
0
        mnScrH += mpRowInfo[nArrY].nHeight;
213
214
0
    mbTabProtected = mpDoc->IsTabProtected( mnTab );
215
0
    mbLayoutRTL = mpDoc->IsLayoutRTL( mnTab );
216
217
    // always needed, so call at the end of the constructor
218
0
    SetCellRotations();
219
0
    InitOutputEditEngine();
220
0
}
221
222
ScOutputData::~ScOutputData()
223
0
{
224
0
}
225
226
void ScOutputData::SetSpellCheckContext( const sc::SpellCheckContext* pCxt )
227
0
{
228
0
    mpSpellCheckCxt = pCxt;
229
0
}
230
231
void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
232
0
{
233
    // use pContentDev instead of pDev where used
234
235
0
    if ( mpRefDevice == mpDev )
236
0
        mpRefDevice = pContentDev;
237
0
    if ( pFmtDevice == mpDev )
238
0
        pFmtDevice = pContentDev;
239
0
    mpDev = pContentDev;
240
0
}
241
242
void ScOutputData::SetMirrorWidth( tools::Long nNew )
243
0
{
244
0
    mnMirrorW = nNew;
245
0
}
246
247
void ScOutputData::SetGridColor( const Color& rColor )
248
0
{
249
0
    maGridColor = rColor;
250
0
}
251
252
void ScOutputData::SetMarkClipped( bool bSet )
253
0
{
254
0
    mbMarkClipped = bSet;
255
0
}
256
257
void ScOutputData::SetShowNullValues( bool bSet )
258
0
{
259
0
    mbShowNullValues = bSet;
260
0
}
261
262
void ScOutputData::SetShowFormulas( bool bSet )
263
0
{
264
0
    mbShowFormulas = bSet;
265
0
}
266
267
void ScOutputData::SetShowSpellErrors( bool bSet )
268
0
{
269
0
    mbShowSpellErrors = bSet;
270
    // reset EditEngine because it depends on bShowSpellErrors
271
0
    mxOutputEditEngine.reset();
272
0
}
273
274
void ScOutputData::SetSnapPixel()
275
0
{
276
0
    mbSnapPixel = true;
277
0
}
278
279
void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
280
0
{
281
0
    mnEditCol = nCol;
282
0
    mnEditRow = nRow;
283
0
    mbEditMode = true;
284
0
}
285
286
void ScOutputData::SetMetaFileMode( bool bNewMode )
287
0
{
288
0
    mbMetaFile = bNewMode;
289
0
}
290
291
void ScOutputData::SetSyntaxMode( bool bNewMode )
292
0
{
293
0
    mbSyntaxMode = bNewMode;
294
0
    if ( bNewMode && !mxValueColor )
295
0
    {
296
0
        const svtools::ColorConfig& rColorCfg = ScModule::get()->GetColorConfig();
297
0
        mxValueColor = rColorCfg.GetColorValue( svtools::CALCVALUE ).nColor;
298
0
        mxTextColor = rColorCfg.GetColorValue( svtools::CALCTEXT ).nColor;
299
0
        mxFormulaColor = rColorCfg.GetColorValue( svtools::CALCFORMULA ).nColor;
300
0
    }
301
0
}
302
303
bool ScOutputData::ReopenPDFStructureElement(vcl::pdf::StructElement aType, SCROW nRow, SCCOL nCol)
304
0
{
305
0
    bool bReopenTag = false;
306
0
    vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(mpDev->GetExtOutDevData());
307
0
    if (pPDF)
308
0
    {
309
0
        if (aType == vcl::pdf::StructElement::Part) // Worksheet
310
0
        {
311
0
            if (pPDF->GetScPDFState()->m_WorksheetId != -1)
312
0
            {
313
0
                sal_Int32 nId = pPDF->GetScPDFState()->m_WorksheetId;
314
0
                pPDF->BeginStructureElement(nId);
315
0
                bReopenTag = true;
316
0
            }
317
0
        }
318
0
        else if (aType == vcl::pdf::StructElement::TableRow)
319
0
        {
320
0
            const auto aIter = pPDF->GetScPDFState()->m_TableRowMap.find(nRow);
321
0
            if (aIter != pPDF->GetScPDFState()->m_TableRowMap.end() && nRow == aIter->first)
322
0
            {
323
0
                sal_Int32 nId = (*aIter).second;
324
0
                pPDF->BeginStructureElement(nId);
325
0
                bReopenTag = true;
326
0
            }
327
0
        }
328
0
        else if (aType == vcl::pdf::StructElement::TableData)
329
0
        {
330
0
            const std::pair<SCROW, SCCOL> keyToFind = std::make_pair(nRow, nCol);
331
0
            const auto aIter = pPDF->GetScPDFState()->m_TableDataMap.find(keyToFind);
332
0
            if (aIter != pPDF->GetScPDFState()->m_TableDataMap.end() && keyToFind == aIter->first)
333
0
            {
334
0
                sal_Int32 nId = (*aIter).second;
335
0
                pPDF->BeginStructureElement(nId);
336
0
                bReopenTag = true;
337
0
            }
338
0
        }
339
0
    }
340
341
0
    return bReopenTag;
342
0
}
343
344
void ScOutputData::DrawGrid(vcl::RenderContext& rRenderContext, bool bGrid, bool bPage, bool bMergeCover)
345
0
{
346
    // bMergeCover : Draw lines in sheet bgcolor to cover lok client grid lines in merged cell areas.
347
    // When scNoGridBackground is set in lok mode, bMergeCover is set to true and bGrid to false.
348
349
0
    SCCOL nX;
350
0
    SCROW nY;
351
0
    tools::Long nPosX;
352
0
    tools::Long nPosY;
353
0
    SCSIZE nArrY;
354
0
    ScBreakType nBreak    = ScBreakType::NONE;
355
0
    ScBreakType nBreakOld = ScBreakType::NONE;
356
357
0
    bool bDashed = false;
358
0
    Color aPageColor;
359
0
    Color aManualColor;
360
361
0
    if (mbPagebreakMode)
362
0
        bPage = false;          // no "normal" breaks over the whole width/height
363
364
    // It is a big mess to distinguish when we are using pixels and when logic
365
    // units for drawing.  Ultimately we want to work only in the logic units,
366
    // but until that happens, we need to special-case:
367
    //
368
    //   * metafile
369
    //   * drawing to the screen - everything is internally counted in pixels there
370
    //
371
    // 'Internally' in the above means the pCellInfo[...].nWidth and
372
    // mpRowInfo[...]->nHeight:
373
    //
374
    //   * when bWorksInPixels is true: these are in pixels
375
    //   * when bWorksInPixels is false: these are in the logic units
376
    //
377
    // This is where all the confusion comes from, ultimately we want them
378
    // always in the logic units (100th of millimeters), but we need to get
379
    // there gradually (get rid of setting MapUnit::MapPixel first), otherwise we'd
380
    // break all the drawing by one change.
381
    // So until that happens, we need to special case.
382
0
    bool bWorksInPixels = mbMetaFile;
383
0
    const svtools::ColorConfig& rColorCfg = ScModule::get()->GetColorConfig();
384
0
    Color aSheetBGColor = rColorCfg.GetColorValue(::svtools::DOCCOLOR).nColor;
385
386
0
    if ( meType == OUTTYPE_WINDOW )
387
0
    {
388
0
        bWorksInPixels = true;
389
0
        aPageColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor;
390
0
        aManualColor = rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor;
391
0
    }
392
0
    else
393
0
    {
394
0
        aPageColor = maGridColor;
395
0
        aManualColor = maGridColor;
396
0
    }
397
398
0
    tools::Long nOneX = 1;
399
0
    tools::Long nOneY = 1;
400
0
    if (!bWorksInPixels)
401
0
    {
402
0
        Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
403
0
        nOneX = aOnePixel.Width();
404
0
        nOneY = aOnePixel.Height();
405
0
    }
406
407
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
408
0
    tools::Long nSignedOneX = nOneX * nLayoutSign;
409
410
0
    rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : maGridColor);
411
412
0
    ScGridMerger aGrid(&rRenderContext, nOneX, nOneY);
413
414
    // vertical lines
415
416
0
    nPosX = mnScrX;
417
0
    if ( mbLayoutRTL )
418
0
        nPosX += mnMirrorW - nOneX;
419
420
0
    for (nX=mnX1; nX<=mnX2; nX++)
421
0
    {
422
0
        sal_uInt16 nWidth = mpRowInfo[0].basicCellInfo(nX).nWidth;
423
0
        if (nWidth)
424
0
        {
425
0
            nPosX += nWidth * nLayoutSign;
426
427
0
            if ( bPage )
428
0
            {
429
                // Search also in hidden part for page breaks
430
0
                SCCOL nCol = nX + 1;
431
0
                while (nCol <= mpDoc->MaxCol())
432
0
                {
433
0
                    nBreak = mpDoc->HasColBreak(nCol, mnTab);
434
0
                    bool bHidden = mpDoc->ColHidden(nCol, mnTab);
435
436
0
                    if ( nBreak != ScBreakType::NONE || !bHidden )
437
0
                        break;
438
0
                    ++nCol;
439
0
                }
440
441
0
                if (nBreak != nBreakOld)
442
0
                {
443
0
                    aGrid.Flush();
444
445
0
                    if (static_cast<int>(nBreak))
446
0
                    {
447
0
                        rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
448
0
                                                        aPageColor );
449
0
                        bDashed = true;
450
0
                    }
451
0
                    else
452
0
                    {
453
0
                        rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : maGridColor);
454
0
                        bDashed = false;
455
0
                    }
456
457
0
                    nBreakOld = nBreak;
458
0
                }
459
0
            }
460
461
0
            bool bDraw = bGrid || nBreakOld != ScBreakType::NONE || bMergeCover; // simple grid only if set that way
462
463
0
            sal_uInt16 nWidthXplus1 = mpRowInfo[0].basicCellInfo(nX+1).nWidth;
464
0
            bool bSingle = false; //! get into Fillinfo !!!!!
465
0
            if ( nX<mpDoc->MaxCol() )
466
0
            {
467
0
                bSingle = ( nWidthXplus1 == 0 );
468
0
                for (nArrY=1; nArrY+1<mnArrCount && !bSingle; nArrY++)
469
0
                {
470
0
                    if (mpRowInfo[nArrY].cellInfo(nX+1).bHOverlapped)
471
0
                        bSingle = true;
472
0
                    if (mpRowInfo[nArrY].cellInfo(nX).bHideGrid)
473
0
                        bSingle = true;
474
0
                }
475
0
            }
476
477
0
            if (bDraw)
478
0
            {
479
0
                if ( nX<mpDoc->MaxCol() && bSingle )
480
0
                {
481
0
                    SCCOL nVisX = nX + 1;
482
0
                    while ( nVisX < mpDoc->MaxCol() && !mpDoc->GetColWidth(nVisX,mnTab) )
483
0
                        ++nVisX;
484
485
0
                    nPosY = mnScrY;
486
0
                    for (nArrY=1; nArrY+1<mnArrCount; nArrY++)
487
0
                    {
488
0
                        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
489
0
                        const tools::Long nNextY = nPosY + pThisRowInfo->nHeight;
490
491
0
                        bool bHOver = pThisRowInfo->cellInfo(nX).bHideGrid;
492
0
                        if (!bHOver)
493
0
                        {
494
0
                            if (nWidthXplus1)
495
0
                                bHOver = pThisRowInfo->cellInfo(nX+1).bHOverlapped;
496
0
                            else
497
0
                            {
498
0
                                if (nVisX <= mnX2)
499
0
                                    bHOver = pThisRowInfo->cellInfo(nVisX).bHOverlapped;
500
0
                                else
501
0
                                    bHOver = mpDoc->GetAttr(
502
0
                                                nVisX,pThisRowInfo->nRowNo,mnTab,ATTR_MERGE_FLAG)
503
0
                                                .IsHorOverlapped();
504
0
                                if (bHOver)
505
0
                                    bHOver = mpDoc->GetAttr(
506
0
                                                nX + 1,pThisRowInfo->nRowNo,mnTab,ATTR_MERGE_FLAG)
507
0
                                                .IsHorOverlapped();
508
0
                            }
509
0
                        }
510
511
0
                        if ((pThisRowInfo->bChanged && !bHOver && !bMergeCover) || (bHOver && bMergeCover))
512
0
                        {
513
0
                            aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, nPosY, nNextY-nOneY, bDashed);
514
0
                        }
515
0
                        nPosY = nNextY;
516
0
                    }
517
0
                }
518
0
                else if (!bMergeCover)
519
0
                {
520
0
                    aGrid.AddVerLine(bWorksInPixels, nPosX-nSignedOneX, mnScrY, mnScrY+mnScrH-nOneY, bDashed);
521
0
                }
522
0
            }
523
0
        }
524
0
    }
525
526
    // horizontal lines
527
528
0
    bool bHiddenRow = true;
529
0
    SCROW nHiddenEndRow = -1;
530
0
    nPosY = mnScrY;
531
0
    for (nArrY=1; nArrY+1<mnArrCount; nArrY++)
532
0
    {
533
0
        SCSIZE nArrYplus1 = nArrY+1;
534
0
        nY = mpRowInfo[nArrY].nRowNo;
535
0
        SCROW nYplus1 = nY+1;
536
0
        nPosY += mpRowInfo[nArrY].nHeight;
537
538
0
        if (mpRowInfo[nArrY].bChanged)
539
0
        {
540
0
            if ( bPage )
541
0
            {
542
0
                for (SCROW i = nYplus1; i <= mpDoc->MaxRow(); ++i)
543
0
                {
544
0
                    if (i > nHiddenEndRow)
545
0
                        bHiddenRow = mpDoc->RowHidden(i, mnTab, nullptr, &nHiddenEndRow);
546
                    /* TODO: optimize the row break thing for large hidden
547
                     * segments where HasRowBreak() has to be called
548
                     * nevertheless for each row, as a row break is drawn also
549
                     * for hidden rows, above them. This needed to be done only
550
                     * once per hidden segment, maybe giving manual breaks
551
                     * priority. Something like GetNextRowBreak() and
552
                     * GetNextManualRowBreak(). */
553
0
                    nBreak = mpDoc->HasRowBreak(i, mnTab);
554
0
                    if (!bHiddenRow || nBreak != ScBreakType::NONE)
555
0
                        break;
556
0
                }
557
558
0
                if (nBreakOld != nBreak)
559
0
                {
560
0
                    aGrid.Flush();
561
562
0
                    if (static_cast<int>(nBreak))
563
0
                    {
564
0
                        rRenderContext.SetLineColor( (nBreak & ScBreakType::Manual) ? aManualColor :
565
0
                                                        aPageColor );
566
0
                        bDashed = true;
567
0
                    }
568
0
                    else
569
0
                    {
570
0
                        rRenderContext.SetLineColor(bMergeCover ? aSheetBGColor : maGridColor);
571
0
                        bDashed = false;
572
0
                    }
573
574
0
                    nBreakOld = nBreak;
575
0
                }
576
0
            }
577
578
0
            bool bDraw = bGrid || nBreakOld != ScBreakType::NONE || bMergeCover;    // simple grid only if set so
579
580
0
            bool bNextYisNextRow = (mpRowInfo[nArrYplus1].nRowNo == nYplus1);
581
0
            bool bSingle = !bNextYisNextRow;             // Hidden
582
0
            for (SCCOL i=mnX1; i<=mnX2 && !bSingle; i++)
583
0
            {
584
0
                if (mpRowInfo[nArrYplus1].cellInfo(i).bVOverlapped)
585
0
                    bSingle = true;
586
0
            }
587
588
0
            if (bDraw)
589
0
            {
590
0
                if ( bSingle && nY<mpDoc->MaxRow() )
591
0
                {
592
0
                    SCROW nVisY = mpRowInfo[nArrYplus1].nRowNo;
593
594
0
                    nPosX = mnScrX;
595
0
                    if ( mbLayoutRTL )
596
0
                        nPosX += mnMirrorW - nOneX;
597
598
0
                    for (SCCOL i=mnX1; i<=mnX2; i++)
599
0
                    {
600
0
                        const tools::Long nNextX = nPosX + mpRowInfo[0].basicCellInfo(i).nWidth * nLayoutSign;
601
0
                        if (nNextX != nPosX)                                // visible
602
0
                        {
603
0
                            bool bVOver;
604
0
                            if ( bNextYisNextRow )
605
0
                                bVOver = mpRowInfo[nArrYplus1].cellInfo(i).bVOverlapped;
606
0
                            else
607
0
                            {
608
0
                                bVOver = mpDoc->GetAttr(
609
0
                                            i,nYplus1,mnTab,ATTR_MERGE_FLAG)
610
0
                                            .IsVerOverlapped()
611
0
                                    &&   mpDoc->GetAttr(
612
0
                                            i,nVisY,mnTab,ATTR_MERGE_FLAG)
613
0
                                            .IsVerOverlapped();
614
                                    //! nVisY from Array ??
615
0
                            }
616
617
0
                            if ((!bVOver && !bMergeCover) || (bVOver && bMergeCover))
618
0
                            {
619
0
                                aGrid.AddHorLine(bWorksInPixels, nPosX, nNextX-nSignedOneX, nPosY-nOneY, bDashed);
620
0
                            }
621
0
                        }
622
0
                        nPosX = nNextX;
623
0
                    }
624
0
                }
625
0
                else if (!bMergeCover)
626
0
                {
627
0
                    aGrid.AddHorLine(bWorksInPixels, mnScrX, mnScrX+mnScrW-nOneX, nPosY-nOneY, bDashed);
628
0
                }
629
0
            }
630
0
        }
631
0
    }
632
0
}
633
634
void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
635
0
{
636
0
    mbPagebreakMode = true;
637
0
    if (!pPageData)
638
0
        return;                     // not yet initialized -> everything "not printed"
639
640
    // mark printed range
641
    // (everything in FillInfo is already initialized to sal_False)
642
643
0
    sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
644
0
    for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
645
0
    {
646
0
        ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
647
648
0
        SCCOL nStartX = std::max( aRange.aStart.Col(), mnX1 );
649
0
        SCCOL nEndX   = std::min( aRange.aEnd.Col(),   mnX2 );
650
0
        SCROW nStartY = std::max( aRange.aStart.Row(), mnY1 );
651
0
        SCROW nEndY   = std::min( aRange.aEnd.Row(),   mnY2 );
652
653
0
        for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
654
0
        {
655
0
            RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
656
0
            if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
657
0
                                           pThisRowInfo->nRowNo <= nEndY )
658
0
            {
659
0
                for (SCCOL nX=nStartX; nX<=nEndX; nX++)
660
0
                    pThisRowInfo->cellInfo(nX).bPrinted = true;
661
0
            }
662
0
        }
663
0
    }
664
0
}
665
666
void ScOutputData::SetCellRotations()
667
0
{
668
    //! save nRotMax
669
0
    SCCOL nRotMax = mnX2;
670
0
    for (SCSIZE nRotY=0; nRotY<mnArrCount; nRotY++)
671
0
        if (mpRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && mpRowInfo[nRotY].nRotMaxCol > nRotMax)
672
0
            nRotMax = mpRowInfo[nRotY].nRotMaxCol;
673
674
0
    for (SCSIZE nArrY=1; nArrY<mnArrCount; nArrY++)
675
0
    {
676
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
677
0
        if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
678
0
             ( pThisRowInfo->bChanged || mpRowInfo[nArrY-1].bChanged ||
679
0
               ( nArrY+1<mnArrCount && mpRowInfo[nArrY+1].bChanged ) ) )
680
0
        {
681
0
            SCROW nY = pThisRowInfo->nRowNo;
682
683
0
            for (SCCOL nX=0; nX<=nRotMax; nX++)
684
0
            {
685
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
686
0
                const ScPatternAttr* pPattern = pInfo->getPatternAttr();
687
0
                const SfxItemSet* pCondSet = pInfo->pConditionSet;
688
689
0
                if ( !pPattern && !mpDoc->ColHidden(nX, mnTab) )
690
0
                {
691
0
                    pPattern = mpDoc->GetPattern( nX, nY, mnTab );
692
0
                    pCondSet = mpDoc->GetCondResult( nX, nY, mnTab );
693
0
                }
694
695
0
                if ( pPattern )     // column isn't hidden
696
0
                {
697
0
                    ScRotateDir nDir = pPattern->GetRotateDir( pCondSet );
698
0
                    if (nDir != ScRotateDir::NONE)
699
0
                    {
700
                        // Needed for ScCellInfo internal decisions (bg fill, ...)
701
0
                        pInfo->nRotateDir = nDir;
702
703
                        // create target coordinates
704
0
                        const SCCOL nTargetX(nX - mnVisX1 + 1);
705
0
                        const SCROW nTargetY(nY - mnVisY1 + 1);
706
707
                        // Check for values - below in SetCellRotation these will
708
                        // be converted to size_t and thus may not be negative
709
                        // tdf#168023: also do not rotate if the cell is empty
710
0
                        if(nTargetX >= 0 && nTargetY >= 0 && !pInfo->maCell.hasEmptyValue())
711
0
                        {
712
                            // add rotation info to Array information
713
0
                            const Degree100 nAttrRotate(pPattern->GetRotateVal(pCondSet));
714
0
                            const SvxRotateMode eRotMode(pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue());
715
0
                            const double fOrient((mbLayoutRTL ? -1.0 : 1.0) * toRadians(nAttrRotate)); // 1/100th degrees -> [0..2PI]
716
0
                            svx::frame::Array& rArray = mrTabInfo.maArray;
717
718
0
                            rArray.SetCellRotation(nTargetX, nTargetY, eRotMode, fOrient);
719
0
                        }
720
0
                    }
721
0
                }
722
0
            }
723
0
        }
724
0
    }
725
0
}
726
727
static ScRotateDir lcl_GetRotateDir( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB mnTab )
728
0
{
729
0
    const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, mnTab );
730
0
    const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, mnTab );
731
732
0
    ScRotateDir nRet = ScRotateDir::NONE;
733
734
0
    Degree100 nAttrRotate = pPattern->GetRotateVal( pCondSet );
735
0
    if ( nAttrRotate )
736
0
    {
737
0
        SvxRotateMode eRotMode =
738
0
                    pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
739
740
0
        if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
741
0
            nRet = ScRotateDir::Standard;
742
0
        else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
743
0
            nRet = ScRotateDir::Center;
744
0
        else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
745
0
        {
746
0
            tools::Long nRot180 = nAttrRotate.get() % 18000;     // 1/100 degree
747
0
            if ( nRot180 == 9000 )
748
0
                nRet = ScRotateDir::Center;
749
0
            else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
750
0
                      ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
751
0
                nRet = ScRotateDir::Left;
752
0
            else
753
0
                nRet = ScRotateDir::Right;
754
0
        }
755
0
    }
756
757
0
    return nRet;
758
0
}
759
760
static const SvxBrushItem* lcl_FindBackground( const ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB mnTab )
761
0
{
762
0
    const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, mnTab );
763
0
    const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, mnTab );
764
0
    const SvxBrushItem* pBackground =
765
0
                            &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
766
767
0
    ScRotateDir nDir = lcl_GetRotateDir( pDoc, nCol, nRow, mnTab );
768
769
    // treat CENTER like RIGHT
770
0
    if ( nDir == ScRotateDir::Right || nDir == ScRotateDir::Center )
771
0
    {
772
        // text goes to the right -> take background from the left
773
0
        while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, mnTab ) == nDir &&
774
0
                            pBackground->GetColor().GetAlpha() != 0 )
775
0
        {
776
0
            --nCol;
777
0
            pPattern = pDoc->GetPattern( nCol, nRow, mnTab );
778
0
            pCondSet = pDoc->GetCondResult( nCol, nRow, mnTab );
779
0
            pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
780
0
        }
781
0
    }
782
0
    else if ( nDir == ScRotateDir::Left )
783
0
    {
784
        // text goes to the left -> take background from the right
785
0
        while ( nCol < pDoc->MaxCol() && lcl_GetRotateDir( pDoc, nCol, nRow, mnTab ) == nDir &&
786
0
                            pBackground->GetColor().GetAlpha() != 0 )
787
0
        {
788
0
            ++nCol;
789
0
            pPattern = pDoc->GetPattern( nCol, nRow, mnTab );
790
0
            pCondSet = pDoc->GetCondResult( nCol, nRow, mnTab );
791
0
            pBackground = &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
792
0
        }
793
0
    }
794
795
0
    return pBackground;
796
0
}
797
798
static bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
799
                    SCCOL mnX1, SCCOL mnX2, bool bShowProt, bool bPagebreakMode )
800
0
{
801
0
    if ( rFirst.bChanged   != rOther.bChanged ||
802
0
         rFirst.bEmptyBack != rOther.bEmptyBack )
803
0
        return false;
804
805
0
    SCCOL nX;
806
0
    if ( bShowProt )
807
0
    {
808
0
        for ( nX=mnX1; nX<=mnX2; nX++ )
809
0
        {
810
0
            const ScPatternAttr* pPat1 = rFirst.cellInfo(nX).getPatternAttr();
811
0
            const ScPatternAttr* pPat2 = rOther.cellInfo(nX).getPatternAttr();
812
0
            if ( !pPat1 || !pPat2 ||
813
0
                    !SfxPoolItem::areSame(pPat1->GetItem(ATTR_PROTECTION), pPat2->GetItem(ATTR_PROTECTION) ) )
814
0
                return false;
815
0
        }
816
0
    }
817
0
    else
818
0
    {
819
0
        for ( nX=mnX1; nX<=mnX2; nX++ )
820
0
            if ( !SfxPoolItem::areSame(rFirst.cellInfo(nX).maBackground.getItem(), rOther.cellInfo(nX).maBackground.getItem() ) )
821
0
                return false;
822
0
    }
823
824
0
    if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
825
0
        for ( nX=mnX1; nX<=mnX2; nX++ )
826
0
            if ( rFirst.cellInfo(nX).nRotateDir != rOther.cellInfo(nX).nRotateDir )
827
0
                return false;
828
829
0
    if ( bPagebreakMode )
830
0
        for ( nX=mnX1; nX<=mnX2; nX++ )
831
0
            if ( rFirst.cellInfo(nX).bPrinted != rOther.cellInfo(nX).bPrinted )
832
0
                return false;
833
834
0
    for ( nX=mnX1; nX<=mnX2; nX++ )
835
0
    {
836
0
        std::optional<Color> const & pCol1 = rFirst.cellInfo(nX).mxColorScale;
837
0
        std::optional<Color> const & pCol2 = rOther.cellInfo(nX).mxColorScale;
838
0
        if( (pCol1 && !pCol2) || (!pCol1 && pCol2) )
839
0
            return false;
840
841
0
        if (pCol1 && (*pCol1 != *pCol2))
842
0
            return false;
843
844
0
        const ScDataBarInfo* pInfo1 = rFirst.cellInfo(nX).pDataBar;
845
0
        const ScDataBarInfo* pInfo2 = rOther.cellInfo(nX).pDataBar;
846
847
0
        if( (pInfo1 && !pInfo2) || (!pInfo1 && pInfo2) )
848
0
            return false;
849
850
0
        if (pInfo1 && (*pInfo1 != *pInfo2))
851
0
            return false;
852
853
        // each cell with an icon set should be painted the same way
854
0
        const ScIconSetInfo* pIconSet1 = rFirst.cellInfo(nX).pIconSet;
855
0
        const ScIconSetInfo* pIconSet2 = rOther.cellInfo(nX).pIconSet;
856
857
0
        if(pIconSet1 || pIconSet2)
858
0
            return false;
859
0
    }
860
861
0
    return true;
862
0
}
863
864
void ScOutputData::DrawDocumentBackground()
865
0
{
866
0
    if ( !mbSolidBackground )
867
0
        return;
868
869
0
    Color aBgColor(ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);
870
0
    mpDev->SetLineColor(aBgColor);
871
0
    mpDev->SetFillColor(aBgColor);
872
873
0
    Point aScreenPos  = mpDev->PixelToLogic(Point(mnScrX, mnScrY));
874
0
    Size  aScreenSize = mpDev->PixelToLogic(Size(mnScrW - 1,mnScrH - 1));
875
876
0
    mpDev->DrawRect(tools::Rectangle(aScreenPos, aScreenSize));
877
0
}
878
879
namespace {
880
881
const double lclCornerRectTransparency = 40.0;
882
883
void drawDataBars(vcl::RenderContext& rRenderContext, const ScDataBarInfo* pOldDataBarInfo, const tools::Rectangle& rRect, tools::Long nOneX, tools::Long nOneY)
884
0
{
885
0
    tools::Long nPosZero = 0;
886
0
    tools::Rectangle aPaintRect = rRect;
887
0
    aPaintRect.AdjustTop(2 * nOneY );
888
0
    aPaintRect.AdjustBottom( -(2 * nOneY) );
889
0
    aPaintRect.AdjustLeft( 2 * nOneX );
890
0
    aPaintRect.AdjustRight( -(2 * nOneX) );
891
0
    if(pOldDataBarInfo->mnZero)
892
0
    {
893
        // need to calculate null point in cell
894
0
        tools::Long nLength = aPaintRect.Right() - aPaintRect.Left();
895
0
        nPosZero = static_cast<tools::Long>(aPaintRect.Left() + nLength*pOldDataBarInfo->mnZero/100.0);
896
0
    }
897
0
    else
898
0
    {
899
0
        nPosZero = aPaintRect.Left();
900
0
    }
901
902
0
    if(pOldDataBarInfo->mnLength < 0)
903
0
    {
904
0
        aPaintRect.SetRight( nPosZero );
905
0
        tools::Long nLength = nPosZero - aPaintRect.Left();
906
0
        aPaintRect.SetLeft( nPosZero + static_cast<tools::Long>(nLength * pOldDataBarInfo->mnLength/100.0) );
907
0
    }
908
0
    else if(pOldDataBarInfo->mnLength > 0)
909
0
    {
910
0
        aPaintRect.SetLeft( nPosZero );
911
0
        tools::Long nLength = aPaintRect.Right() - nPosZero;
912
0
        aPaintRect.SetRight( nPosZero + static_cast<tools::Long>(nLength * pOldDataBarInfo->mnLength/100.0) );
913
0
    }
914
0
    else
915
0
        return;
916
917
0
    if(pOldDataBarInfo->mbGradient)
918
0
    {
919
0
        rRenderContext.SetLineColor(pOldDataBarInfo->maColor);
920
0
        Gradient aGradient(css::awt::GradientStyle_LINEAR, pOldDataBarInfo->maColor, COL_TRANSPARENT);
921
0
        aGradient.SetSteps(255);
922
923
0
        if(pOldDataBarInfo->mnLength < 0)
924
0
            aGradient.SetAngle(2700_deg10);
925
0
        else
926
0
            aGradient.SetAngle(900_deg10);
927
928
0
        rRenderContext.DrawGradient(aPaintRect, aGradient);
929
930
0
        rRenderContext.SetLineColor();
931
0
    }
932
0
    else
933
0
    {
934
0
        rRenderContext.SetFillColor(pOldDataBarInfo->maColor);
935
0
        rRenderContext.DrawRect(aPaintRect);
936
0
    }
937
938
    //draw axis
939
0
    if(!(pOldDataBarInfo->mnZero && pOldDataBarInfo->mnZero != 100))
940
0
        return;
941
942
0
    Point aPoint1(nPosZero, rRect.Top());
943
0
    Point aPoint2(nPosZero, rRect.Bottom());
944
0
    LineInfo aLineInfo(LineStyle::Dash, 1);
945
0
    aLineInfo.SetDashCount( 4 );
946
0
    aLineInfo.SetDistance( 3 );
947
0
    aLineInfo.SetDashLen( 3 );
948
0
    rRenderContext.SetFillColor(pOldDataBarInfo->maAxisColor);
949
0
    rRenderContext.SetLineColor(pOldDataBarInfo->maAxisColor);
950
0
    rRenderContext.DrawLine(aPoint1, aPoint2, aLineInfo);
951
0
    rRenderContext.SetLineColor();
952
0
    rRenderContext.SetFillColor();
953
0
}
954
955
const Bitmap& getIcon(sc::IconSetBitmapMap & rIconSetBitmapMap, ScIconSetType eType, sal_Int32 nIndex)
956
0
{
957
0
    return ScIconSetFormat::getBitmap(rIconSetBitmapMap, eType, nIndex);
958
0
}
959
960
void drawIconSets(vcl::RenderContext& rRenderContext, const ScIconSetInfo* pOldIconSetInfo, const tools::Rectangle& rRect, tools::Long nOneX, tools::Long nOneY,
961
        sc::IconSetBitmapMap & rIconSetBitmapMap)
962
0
{
963
0
    ScIconSetType eType = pOldIconSetInfo->eIconSetType;
964
0
    sal_Int32 nIndex = pOldIconSetInfo->nIconIndex;
965
0
    const Bitmap& rIcon = getIcon(rIconSetBitmapMap, eType, nIndex);
966
967
0
    tools::Long aHeight = o3tl::convert(10, o3tl::Length::pt, o3tl::Length::mm100);
968
969
0
    if (pOldIconSetInfo->mnHeight)
970
0
    {
971
0
        if (comphelper::LibreOfficeKit::isActive())
972
0
        {
973
0
            aHeight = rRenderContext.LogicToPixel(Size(0, pOldIconSetInfo->mnHeight), MapMode(MapUnit::MapTwip)).Height();
974
0
            aHeight *= comphelper::LibreOfficeKit::getDPIScale();
975
0
        }
976
0
        else
977
0
        {
978
0
            aHeight = o3tl::convert(pOldIconSetInfo->mnHeight, o3tl::Length::twip, o3tl::Length::mm100);
979
0
        }
980
0
    }
981
982
0
    Size aSize = rIcon.GetSizePixel();
983
0
    double fRatio = static_cast<double>(aSize.Width()) / aSize.Height();
984
0
    tools::Long aWidth = fRatio * aHeight;
985
986
0
    auto popIt = rRenderContext.ScopedPush();
987
0
    rRenderContext.SetClipRegion(vcl::Region(rRect));
988
0
    rRenderContext.DrawBitmap(Point(rRect.Left() + 2 * nOneX, rRect.Bottom() - 2 * nOneY - aHeight), Size(aWidth, aHeight), rIcon);
989
0
}
990
991
void drawCells(vcl::RenderContext& rRenderContext, std::optional<Color> const & pColor, const SvxBrushItem* pBackground, std::optional<Color>& pOldColor, const SvxBrushItem*& pOldBackground,
992
        tools::Rectangle& rRect, tools::Long nPosX, tools::Long nLayoutSign, tools::Long nOneX, tools::Long nOneY, const ScDataBarInfo* pDataBarInfo, const ScDataBarInfo*& pOldDataBarInfo,
993
        const ScIconSetInfo* pIconSetInfo, const ScIconSetInfo*& pOldIconSetInfo,
994
        sc::IconSetBitmapMap & rIconSetBitmapMap)
995
0
{
996
0
    tools::Long nSignedOneX = nOneX * nLayoutSign;
997
    // need to paint if old color scale has been used and now
998
    // we have a different color or a style based background
999
    // we can here fall back to pointer comparison
1000
0
    if (pOldColor && (pBackground || pOldColor != pColor || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo))
1001
0
    {
1002
0
        rRect.SetRight( nPosX-nSignedOneX );
1003
0
        if( !pOldColor->IsTransparent() )
1004
0
        {
1005
0
            rRenderContext.SetFillColor( *pOldColor );
1006
0
            rRenderContext.DrawRect( rRect );
1007
0
        }
1008
0
        if( pOldDataBarInfo )
1009
0
            drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
1010
0
        if( pOldIconSetInfo )
1011
0
            drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
1012
1013
0
        rRect.SetLeft( nPosX - nSignedOneX );
1014
0
    }
1015
1016
0
    if ( pOldBackground && (pColor || !SfxPoolItem::areSame(pBackground, pOldBackground) || pOldDataBarInfo || pDataBarInfo || pIconSetInfo || pOldIconSetInfo) )
1017
0
    {
1018
0
        rRect.SetRight( nPosX-nSignedOneX );
1019
0
        if (pOldBackground)             // ==0 if hidden
1020
0
        {
1021
0
            Color aBackCol = pOldBackground->GetColor();
1022
0
            if ( !aBackCol.IsTransparent() )      //! partial transparency?
1023
0
            {
1024
0
                rRenderContext.SetFillColor( aBackCol );
1025
0
                rRenderContext.DrawRect( rRect );
1026
0
            }
1027
0
        }
1028
0
        if( pOldDataBarInfo )
1029
0
            drawDataBars(rRenderContext, pOldDataBarInfo, rRect, nOneX, nOneY);
1030
0
        if( pOldIconSetInfo )
1031
0
            drawIconSets(rRenderContext, pOldIconSetInfo, rRect, nOneX, nOneY, rIconSetBitmapMap);
1032
1033
0
        rRect.SetLeft( nPosX - nSignedOneX );
1034
0
    }
1035
1036
0
    if (!pOldBackground && !pOldColor && (pDataBarInfo || pIconSetInfo))
1037
0
    {
1038
0
        rRect.SetRight( nPosX -nSignedOneX );
1039
0
        rRect.SetLeft( nPosX - nSignedOneX );
1040
0
    }
1041
1042
0
    if(pColor)
1043
0
    {
1044
        // only update pOldColor if the colors changed
1045
0
        if (!pOldColor || *pOldColor != *pColor)
1046
0
            pOldColor = pColor;
1047
1048
0
        pOldBackground = nullptr;
1049
0
    }
1050
0
    else if(pBackground)
1051
0
    {
1052
0
        pOldBackground = pBackground;
1053
0
        pOldColor.reset();
1054
0
    }
1055
1056
0
    if(pDataBarInfo)
1057
0
        pOldDataBarInfo = pDataBarInfo;
1058
0
    else
1059
0
        pOldDataBarInfo = nullptr;
1060
1061
0
    if(pIconSetInfo)
1062
0
        pOldIconSetInfo = pIconSetInfo;
1063
0
    else
1064
0
        pOldIconSetInfo = nullptr;
1065
0
}
1066
1067
}
1068
1069
void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext)
1070
0
{
1071
0
    vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(mpDev->GetExtOutDevData());
1072
0
    bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
1073
1074
0
    Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1075
0
    tools::Long nOneXLogic = aOnePixel.Width();
1076
0
    tools::Long nOneYLogic = aOnePixel.Height();
1077
1078
    // See more about bWorksInPixels in ScOutputData::DrawGrid
1079
0
    bool bWorksInPixels = (meType == OUTTYPE_WINDOW);
1080
    // tdf#135891 - avoid visible gaps for metafile and window output as in ScOutputData::DrawGrid
1081
0
    const tools::Long nOneX = (bWorksInPixels || mbMetaFile) ? 1 : nOneXLogic;
1082
0
    const tools::Long nOneY = (bWorksInPixels || mbMetaFile) ? 1 : nOneYLogic;
1083
0
    const tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
1084
0
    const tools::Long nSignedOneX = nOneX * nLayoutSign;
1085
1086
0
    tools::Rectangle aRect;
1087
1088
0
    rRenderContext.SetLineColor();
1089
1090
0
    bool bShowProt = mbSyntaxMode && mpDoc->IsTabProtected(mnTab);
1091
0
    bool bDoAll = bShowProt || mbPagebreakMode || mbSolidBackground;
1092
1093
0
    bool bCellContrast = mbUseStyleColor &&
1094
0
            Application::GetSettings().GetStyleSettings().GetHighContrastMode();
1095
1096
0
    tools::Long nPosY = mnScrY;
1097
1098
0
    const svtools::ColorConfig& rColorCfg = ScModule::get()->GetColorConfig();
1099
0
    Color aProtectedColor( rColorCfg.GetColorValue( svtools::CALCPROTECTEDBACKGROUND ).nColor );
1100
0
    auto pProtectedBackground = std::make_shared<SvxBrushItem>( aProtectedColor, ATTR_BACKGROUND );
1101
1102
    // iterate through the rows to show
1103
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
1104
0
    {
1105
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1106
0
        tools::Long nRowHeight = pThisRowInfo->nHeight;
1107
1108
0
        if ( pThisRowInfo->bChanged )
1109
0
        {
1110
0
            if ( ( ( pThisRowInfo->bEmptyBack ) || mbSyntaxMode ) && !bDoAll )
1111
0
            {
1112
                // nothing
1113
0
            }
1114
0
            else
1115
0
            {
1116
0
                if (bTaggedPDF)
1117
0
                    pPDF->WrapBeginStructureElement(vcl::pdf::StructElement::NonStructElement);
1118
1119
                // scan for rows with the same background:
1120
0
                SCSIZE nSkip = 0;
1121
0
                while ( nArrY+nSkip+2<mnArrCount &&
1122
0
                        lcl_EqualBack( *pThisRowInfo, mpRowInfo[nArrY+nSkip+1],
1123
0
                                        mnX1, mnX2, bShowProt, mbPagebreakMode ) )
1124
0
                {
1125
0
                    ++nSkip;
1126
0
                    nRowHeight += mpRowInfo[nArrY+nSkip].nHeight;    // after incrementing
1127
0
                }
1128
1129
0
                tools::Long nPosX = mnScrX;
1130
0
                if ( mbLayoutRTL )
1131
0
                    nPosX += mnMirrorW - nOneX;
1132
1133
                // tdf#135891 - adjust the x position for printer output
1134
0
                if (!bWorksInPixels && !mbMetaFile)
1135
0
                    nPosX -= nLayoutSign + 1;
1136
1137
0
                aRect = tools::Rectangle(nPosX, nPosY - 1, nPosX, nPosY - 1 + nRowHeight);
1138
0
                if (bWorksInPixels)
1139
0
                    aRect = rRenderContext.PixelToLogic(aRect); // internal data in pixels, but we'll be drawing in logic units
1140
1141
0
                const SvxBrushItem* pOldBackground = nullptr;
1142
0
                const SvxBrushItem* pBackground = nullptr;
1143
0
                std::optional<Color> pOldColor;
1144
0
                const ScDataBarInfo* pOldDataBarInfo = nullptr;
1145
0
                const ScIconSetInfo* pOldIconSetInfo = nullptr;
1146
0
                SCCOL nMergedCols = 1;
1147
0
                SCCOL nOldMerged = 0;
1148
1149
0
                for (SCCOL nX=mnX1; nX + nMergedCols <= mnX2 + 1; nX += nOldMerged)
1150
0
                {
1151
0
                    ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX-1+nMergedCols);
1152
1153
0
                    nOldMerged = nMergedCols;
1154
1155
0
                    tools::Long nNewPosX = nPosX;
1156
                    // extend for all merged cells
1157
0
                    nMergedCols = 1;
1158
0
                    if (pInfo->bMerged && pInfo->pPatternAttr)
1159
0
                    {
1160
0
                            const ScMergeAttr* pMerge =
1161
0
                                    &pInfo->getPatternAttr()->GetItem(ATTR_MERGE);
1162
0
                            nMergedCols = std::max<SCCOL>(1, pMerge->GetColMerge());
1163
0
                    }
1164
1165
0
                    for (SCCOL nMerged = 0; nMerged < nMergedCols; ++nMerged)
1166
0
                    {
1167
0
                        SCCOL nCol = nX+nOldMerged+nMerged;
1168
0
                        if (nCol > mnX2+2)
1169
0
                            break;
1170
0
                        nNewPosX += mpRowInfo[0].basicCellInfo(nCol-1).nWidth * nLayoutSign;
1171
0
                    }
1172
1173
0
                    if (nNewPosX == nPosX)
1174
0
                        continue; // Zero width, no need to draw.
1175
1176
0
                    if (bCellContrast)
1177
0
                    {
1178
                        //  high contrast for cell borders and backgrounds -> empty background
1179
0
                        pBackground = ScGlobal::GetEmptyBrushItem();
1180
0
                    }
1181
0
                    else if (bShowProt)         // show cell protection in syntax mode
1182
0
                    {
1183
0
                        const ScPatternAttr* pP = pInfo->getPatternAttr();
1184
0
                        if (pP)
1185
0
                        {
1186
0
                            const ScProtectionAttr& rProt = pP->GetItem(ATTR_PROTECTION);
1187
0
                            if (rProt.GetProtection() || rProt.GetHideCell())
1188
0
                                pBackground = pProtectedBackground.get();
1189
0
                            else
1190
0
                                pBackground = ScGlobal::GetEmptyBrushItem();
1191
0
                        }
1192
0
                        else
1193
0
                            pBackground = nullptr;
1194
0
                    }
1195
0
                    else
1196
0
                        pBackground = static_cast<const SvxBrushItem*>(pInfo->maBackground.getItem());
1197
1198
0
                    if ( mbPagebreakMode && !pInfo->bPrinted )
1199
0
                        pBackground = pProtectedBackground.get();
1200
1201
0
                    if ( pInfo->nRotateDir > ScRotateDir::Standard &&
1202
0
                            !pBackground->GetColor().IsFullyTransparent() &&
1203
0
                            !bCellContrast )
1204
0
                    {
1205
0
                        SCROW nY = mpRowInfo[nArrY].nRowNo;
1206
0
                        pBackground = lcl_FindBackground( mpDoc, nX, nY, mnTab );
1207
0
                    }
1208
1209
0
                    std::optional<Color> const & pColor = pInfo->mxColorScale;
1210
0
                    const ScDataBarInfo* pDataBarInfo = pInfo->pDataBar;
1211
0
                    const ScIconSetInfo* pIconSetInfo = pInfo->pIconSet;
1212
1213
0
                    tools::Long nPosXLogic = nPosX;
1214
0
                    if (bWorksInPixels)
1215
0
                        nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1216
1217
                    // tdf#135891 - use adjusted nOneX/nOneY to avoid white gaps between colored cells
1218
0
                    drawCells(rRenderContext, pColor, pBackground, pOldColor, pOldBackground, aRect,
1219
0
                              nPosXLogic, nLayoutSign, nOneX, nOneY, pDataBarInfo, pOldDataBarInfo,
1220
0
                              pIconSetInfo, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1221
1222
0
                    nPosX = nNewPosX;
1223
                    // tdf#135891 - adjust the x position for printer output
1224
0
                    if (!bWorksInPixels && !mbMetaFile && nX == mnX1)
1225
0
                        nPosX += nSignedOneX + 1;
1226
0
                }
1227
1228
0
                tools::Long nPosXLogic = nPosX;
1229
0
                if (bWorksInPixels)
1230
0
                    nPosXLogic = rRenderContext.PixelToLogic(Point(nPosX, 0)).X();
1231
1232
                // tdf#135891 - use adjusted nOneX/nOneY to avoid white gaps between colored cells
1233
0
                drawCells(rRenderContext, std::optional<Color>(), nullptr, pOldColor,
1234
0
                          pOldBackground, aRect, nPosXLogic, nLayoutSign, nOneX, nOneY, nullptr,
1235
0
                          pOldDataBarInfo, nullptr, pOldIconSetInfo, mpDoc->GetIconSetBitmapMap());
1236
1237
0
                nArrY += nSkip;
1238
1239
0
                if (bTaggedPDF)
1240
0
                    pPDF->EndStructureElement();
1241
0
            }
1242
0
        }
1243
0
        nPosY += nRowHeight;
1244
0
    }
1245
0
}
1246
1247
void ScOutputData::DrawShadow()
1248
0
{
1249
0
    DrawExtraShadow( false, false, false, false );
1250
0
}
1251
1252
void ScOutputData::DrawExtraShadow(bool bLeft, bool bTop, bool bRight, bool bBottom)
1253
0
{
1254
0
    vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(mpDev->GetExtOutDevData());
1255
0
    bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
1256
1257
0
    mpDev->SetLineColor();
1258
1259
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1260
0
    bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1261
0
    Color aAutoTextColor;
1262
0
    if ( bCellContrast )
1263
0
        aAutoTextColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1264
1265
0
    tools::Long nInitPosX = mnScrX;
1266
0
    if ( mbLayoutRTL )
1267
0
    {
1268
0
        Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1269
0
        tools::Long nOneX = aOnePixel.Width();
1270
0
        nInitPosX += mnMirrorW - nOneX;
1271
0
    }
1272
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
1273
1274
0
    tools::Long nPosY = mnScrY - mpRowInfo[0].nHeight;
1275
0
    for (SCSIZE nArrY=0; nArrY<mnArrCount; nArrY++)
1276
0
    {
1277
0
        bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == mnArrCount );
1278
0
        bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == mnArrCount && !bBottom );
1279
1280
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1281
0
        tools::Long nRowHeight = pThisRowInfo->nHeight;
1282
1283
0
        if ( pThisRowInfo->bChanged && !bSkipY )
1284
0
        {
1285
0
            tools::Long nPosX = nInitPosX - mpRowInfo[0].basicCellInfo(mnX1-1).nWidth * nLayoutSign;
1286
0
            for (SCCOL nCol=mnX1-1; nCol<=mnX2+1; nCol++)
1287
0
            {
1288
0
                bool bCornerX = ( nCol==mnX1-1 || nCol==mnX2+1 );
1289
0
                bool bSkipX = ( nCol==mnX1-1 && !bLeft ) || ( nCol==mnX2+1 && !bRight );
1290
1291
0
                for (sal_uInt16 nPass=0; nPass<2; nPass++) // horizontal / vertical
1292
0
                {
1293
0
                    const SvxShadowItem* pAttr = nPass ?
1294
0
                            pThisRowInfo->cellInfo(nCol).pVShadowOrigin :
1295
0
                            pThisRowInfo->cellInfo(nCol).pHShadowOrigin;
1296
0
                    if ( pAttr && !bSkipX )
1297
0
                    {
1298
0
                        if (bTaggedPDF)
1299
0
                            pPDF->WrapBeginStructureElement(vcl::pdf::StructElement::NonStructElement);
1300
1301
0
                        ScShadowPart ePart = nPass ?
1302
0
                                pThisRowInfo->cellInfo(nCol).eVShadowPart :
1303
0
                                pThisRowInfo->cellInfo(nCol).eHShadowPart;
1304
1305
0
                        bool bDo = true;
1306
0
                        if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
1307
0
                            if ( ePart != SC_SHADOW_CORNER )
1308
0
                                bDo = false;
1309
1310
0
                        if (bDo)
1311
0
                        {
1312
0
                            tools::Long nThisWidth = mpRowInfo[0].basicCellInfo(nCol).nWidth;
1313
0
                            tools::Long nMaxWidth = nThisWidth;
1314
0
                            if (!nMaxWidth)
1315
0
                            {
1316
                                //! direction must depend on shadow location
1317
0
                                SCCOL nWx = nCol+1;
1318
0
                                while (nWx<mnX2 && !mpRowInfo[0].basicCellInfo(nWx).nWidth)
1319
0
                                    ++nWx;
1320
0
                                nMaxWidth = mpRowInfo[0].basicCellInfo(nWx).nWidth;
1321
0
                            }
1322
1323
                            // rectangle is in logical orientation
1324
0
                            tools::Rectangle aRect( nPosX, nPosY,
1325
0
                                             nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1326
0
                                             nPosY + mpRowInfo[nArrY].nHeight - 1 );
1327
1328
0
                            tools::Long nSize = pAttr->GetWidth();
1329
0
                            tools::Long nSizeX = static_cast<tools::Long>(nSize*mnPPTX);
1330
0
                            if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1331
0
                            tools::Long nSizeY = static_cast<tools::Long>(nSize*mnPPTY);
1332
0
                            if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1333
1334
0
                            nSizeX *= nLayoutSign;      // used only to add to rectangle values
1335
1336
0
                            SvxShadowLocation eLoc = pAttr->GetLocation();
1337
0
                            if ( mbLayoutRTL )
1338
0
                            {
1339
                                //  Shadow location is specified as "visual" (right is always right),
1340
                                //  so the attribute's location value is mirrored here and in FillInfo.
1341
0
                                switch (eLoc)
1342
0
                                {
1343
0
                                    case SvxShadowLocation::BottomRight: eLoc = SvxShadowLocation::BottomLeft;  break;
1344
0
                                    case SvxShadowLocation::BottomLeft:  eLoc = SvxShadowLocation::BottomRight; break;
1345
0
                                    case SvxShadowLocation::TopRight:    eLoc = SvxShadowLocation::TopLeft;     break;
1346
0
                                    case SvxShadowLocation::TopLeft:     eLoc = SvxShadowLocation::TopRight;    break;
1347
0
                                    default:
1348
0
                                    {
1349
                                        // added to avoid warnings
1350
0
                                    }
1351
0
                                }
1352
0
                            }
1353
1354
0
                            if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1355
0
                                ePart == SC_SHADOW_CORNER)
1356
0
                            {
1357
0
                                if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
1358
0
                                    aRect.SetTop( aRect.Bottom() - nSizeY );
1359
0
                                else
1360
0
                                    aRect.SetBottom( aRect.Top() + nSizeY );
1361
0
                            }
1362
0
                            if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1363
0
                                ePart == SC_SHADOW_CORNER)
1364
0
                            {
1365
0
                                if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
1366
0
                                    aRect.SetLeft( aRect.Right() - nSizeX );
1367
0
                                else
1368
0
                                    aRect.SetRight( aRect.Left() + nSizeX );
1369
0
                            }
1370
0
                            if (ePart == SC_SHADOW_HSTART)
1371
0
                            {
1372
0
                                if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::BottomLeft)
1373
0
                                    aRect.AdjustRight( -nSizeX );
1374
0
                                else
1375
0
                                    aRect.AdjustLeft(nSizeX );
1376
0
                            }
1377
0
                            if (ePart == SC_SHADOW_VSTART)
1378
0
                            {
1379
0
                                if (eLoc == SvxShadowLocation::TopLeft || eLoc == SvxShadowLocation::TopRight)
1380
0
                                    aRect.AdjustBottom( -nSizeY );
1381
0
                                else
1382
0
                                    aRect.AdjustTop(nSizeY );
1383
0
                            }
1384
1385
                            //! merge rectangles?
1386
0
                            mpDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1387
0
                            mpDev->DrawRect( aRect );
1388
1389
0
                            if (bTaggedPDF)
1390
0
                                pPDF->EndStructureElement();
1391
0
                        }
1392
0
                    }
1393
0
                }
1394
1395
0
                nPosX += mpRowInfo[0].basicCellInfo(nCol).nWidth * nLayoutSign;
1396
0
            }
1397
0
        }
1398
0
        nPosY += nRowHeight;
1399
0
    }
1400
0
}
1401
1402
void ScOutputData::DrawClear()
1403
0
{
1404
0
    tools::Rectangle aRect;
1405
0
    Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
1406
0
    tools::Long nOneX = aOnePixel.Width();
1407
0
    tools::Long nOneY = aOnePixel.Height();
1408
1409
    // (called only for ScGridWindow)
1410
0
    Color aBgColor(ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor);
1411
1412
0
    if (mbMetaFile)
1413
0
        nOneX = nOneY = 0;
1414
1415
0
    mpDev->SetLineColor();
1416
1417
0
    mpDev->SetFillColor( aBgColor );
1418
1419
0
    tools::Long nPosY = mnScrY;
1420
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
1421
0
    {
1422
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1423
0
        tools::Long nRowHeight = pThisRowInfo->nHeight;
1424
1425
0
        if ( pThisRowInfo->bChanged )
1426
0
        {
1427
            // scan for more rows which must be painted:
1428
0
            SCSIZE nSkip = 0;
1429
0
            while ( nArrY+nSkip+2<mnArrCount && mpRowInfo[nArrY+nSkip+1].bChanged )
1430
0
            {
1431
0
                ++nSkip;
1432
0
                nRowHeight += mpRowInfo[nArrY+nSkip].nHeight;    // after incrementing
1433
0
            }
1434
1435
0
            aRect = tools::Rectangle( Point( mnScrX, nPosY ),
1436
0
                    Size( mnScrW+1-nOneX, nRowHeight+1-nOneY) );
1437
0
            mpDev->DrawRect( aRect );
1438
1439
0
            nArrY += nSkip;
1440
0
        }
1441
0
        nPosY += nRowHeight;
1442
0
    }
1443
0
}
1444
1445
// Lines
1446
1447
static tools::Long lclGetSnappedX( const OutputDevice& rDev, tools::Long nPosX, bool mbSnapPixel )
1448
0
{
1449
0
    return (mbSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1450
0
}
1451
1452
static tools::Long lclGetSnappedY( const OutputDevice& rDev, tools::Long nPosY, bool mbSnapPixel )
1453
0
{
1454
0
    return (mbSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1455
0
}
1456
1457
void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
1458
0
{
1459
0
    vcl::PDFExtOutDevData* pPDF = dynamic_cast<vcl::PDFExtOutDevData*>(mpDev->GetExtOutDevData());
1460
0
    bool bTaggedPDF = pPDF && pPDF->GetIsExportTaggedPDF();
1461
0
    if (bTaggedPDF)
1462
0
        pPDF->WrapBeginStructureElement(vcl::pdf::StructElement::NonStructElement);
1463
1464
0
    DrawModeFlags nOldDrawMode = rRenderContext.GetDrawMode();
1465
1466
0
    Color aSingleColor;
1467
0
    bool bUseSingleColor = false;
1468
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1469
0
    bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1470
1471
    //  if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1472
    //  for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1473
    //  that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1474
    //  must be reset and the border colors handled here.
1475
1476
0
    if ( ( nOldDrawMode & DrawModeFlags::WhiteFill ) && ( nOldDrawMode & DrawModeFlags::BlackLine ) )
1477
0
    {
1478
0
        rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::WhiteFill) );
1479
0
        aSingleColor = COL_BLACK;
1480
0
        bUseSingleColor = true;
1481
0
    }
1482
0
    else if ( ( nOldDrawMode & DrawModeFlags::SettingsFill ) && ( nOldDrawMode & DrawModeFlags::SettingsLine ) )
1483
0
    {
1484
0
        rRenderContext.SetDrawMode( nOldDrawMode & (~DrawModeFlags::SettingsFill) );
1485
0
        aSingleColor = rStyleSettings.GetWindowTextColor();     // same as used in VCL for DrawModeFlags::SettingsLine
1486
0
        bUseSingleColor = true;
1487
0
    }
1488
0
    else if ( bCellContrast )
1489
0
    {
1490
0
        aSingleColor = ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor;
1491
0
        bUseSingleColor = true;
1492
0
    }
1493
1494
0
    const Color* pForceColor = bUseSingleColor ? &aSingleColor : nullptr;
1495
1496
0
    if (mrTabInfo.maArray.HasCellRotation())
1497
0
    {
1498
0
        DrawRotatedFrame(rRenderContext);        // removes the lines that must not be painted here
1499
0
    }
1500
1501
0
    tools::Long nInitPosX = mnScrX;
1502
0
    if ( mbLayoutRTL )
1503
0
    {
1504
0
        Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1505
0
        tools::Long nOneX = aOnePixel.Width();
1506
0
        nInitPosX += mnMirrorW - nOneX;
1507
0
    }
1508
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
1509
1510
    // *** set column and row sizes of the frame border array ***
1511
1512
0
    svx::frame::Array& rArray = mrTabInfo.maArray;
1513
0
    size_t nColCount = rArray.GetColCount();
1514
0
    size_t nRowCount = rArray.GetRowCount();
1515
1516
    // row heights
1517
1518
    // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1519
    // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1520
0
    tools::Long nOldPosY = mnScrY - 1 - mpRowInfo[ 0 ].nHeight;
1521
0
    tools::Long nOldSnapY = lclGetSnappedY( rRenderContext, nOldPosY, mbSnapPixel );
1522
0
    rArray.SetYOffset( nOldSnapY );
1523
0
    for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1524
0
    {
1525
0
        tools::Long nNewPosY = nOldPosY + mpRowInfo[ nRow ].nHeight;
1526
0
        tools::Long nNewSnapY = lclGetSnappedY( rRenderContext, nNewPosY, mbSnapPixel );
1527
0
        rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1528
0
        nOldPosY = nNewPosY;
1529
0
        nOldSnapY = nNewSnapY;
1530
0
    }
1531
1532
    // column widths
1533
1534
    // column mnX1-1 is not visible (dummy for borders from left) - subtract its width from initial position
1535
    // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1536
0
    tools::Long nOldPosX = nInitPosX - nLayoutSign * (1 + mpRowInfo[ 0 ].basicCellInfo( mnX1 - 1 ).nWidth);
1537
0
    tools::Long nOldSnapX = lclGetSnappedX( rRenderContext, nOldPosX, mbSnapPixel );
1538
    // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1539
0
    if( !mbLayoutRTL )
1540
0
        rArray.SetXOffset( nOldSnapX );
1541
0
    for( SCCOL nCol = mnX1 - 1; nCol <= mnX2 + 1; ++nCol )
1542
0
    {
1543
0
        size_t nArrCol = mbLayoutRTL ? mnX2 + 1 - nCol : nCol - (mnX1 - 1);
1544
0
        tools::Long nNewPosX = nOldPosX + mpRowInfo[ 0 ].basicCellInfo( nCol ).nWidth * nLayoutSign;
1545
0
        tools::Long nNewSnapX = lclGetSnappedX( rRenderContext, nNewPosX, mbSnapPixel );
1546
0
        rArray.SetColWidth( nArrCol, std::abs( nNewSnapX - nOldSnapX ) );
1547
0
        nOldPosX = nNewPosX;
1548
0
        nOldSnapX = nNewSnapX;
1549
0
    }
1550
0
    if( mbLayoutRTL )
1551
0
        rArray.SetXOffset( nOldSnapX );
1552
1553
    // *** draw the array ***
1554
1555
0
    if (nColCount < 3 || nRowCount < 3)
1556
0
    {
1557
0
        SAL_WARN("sc.ui", "DrawFrame: unexpected array size:"
1558
0
            " nColCount=" << nColCount << " nRowCount=" << nRowCount);
1559
0
        return;
1560
0
    }
1561
1562
0
    size_t nFirstCol = 1;
1563
0
    size_t nFirstRow = 1;
1564
0
    size_t nLastCol = nColCount - 2;
1565
0
    size_t nLastRow = nRowCount - 2;
1566
1567
0
    if( mrTabInfo.mbPageMode )
1568
0
        rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1569
1570
    // draw only rows with set RowInfo::bChanged flag
1571
0
    size_t nRow1 = nFirstRow;
1572
0
    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D());
1573
0
    if (!pProcessor)
1574
0
        return;
1575
0
    while( nRow1 <= nLastRow )
1576
0
    {
1577
0
        while( (nRow1 <= nLastRow) && !mpRowInfo[ nRow1 ].bChanged ) ++nRow1;
1578
0
        if( nRow1 <= nLastRow )
1579
0
        {
1580
0
            size_t nRow2 = nRow1;
1581
0
            while( (nRow2 + 1 <= nLastRow) && mpRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1582
0
            auto xPrimitive = rArray.CreateB2DPrimitiveRange(
1583
0
                    nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
1584
0
            pProcessor->process(xPrimitive);
1585
0
            nRow1 = nRow2 + 1;
1586
0
        }
1587
0
    }
1588
0
    pProcessor.reset();
1589
1590
0
    rRenderContext.SetDrawMode(nOldDrawMode);
1591
1592
0
    if (bTaggedPDF)
1593
0
        pPDF->EndStructureElement();
1594
0
}
1595
1596
void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext)
1597
0
{
1598
    //! save nRotMax
1599
0
    SCCOL nRotMax = mnX2;
1600
0
    for (SCSIZE nRotY=0; nRotY<mnArrCount; nRotY++)
1601
0
        if (mpRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && mpRowInfo[nRotY].nRotMaxCol > nRotMax)
1602
0
            nRotMax = mpRowInfo[nRotY].nRotMaxCol;
1603
1604
0
    CellAttributeHolder  aPatternHolder;
1605
0
    const SfxItemSet*    pCondSet;
1606
1607
0
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1608
0
    bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();
1609
1610
0
    tools::Long nInitPosX = mnScrX;
1611
0
    if ( mbLayoutRTL )
1612
0
    {
1613
0
        Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
1614
0
        tools::Long nOneX = aOnePixel.Width();
1615
0
        nInitPosX += mnMirrorW - nOneX;
1616
0
    }
1617
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
1618
1619
0
    tools::Rectangle aClipRect( Point(mnScrX, mnScrY), Size(mnScrW, mnScrH) );
1620
0
    if (mbMetaFile)
1621
0
    {
1622
0
        rRenderContext.Push();
1623
0
        rRenderContext.IntersectClipRegion( aClipRect );
1624
0
    }
1625
0
    else
1626
0
        rRenderContext.SetClipRegion( vcl::Region( aClipRect ) );
1627
1628
0
    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));
1629
0
    tools::Long nPosY = mnScrY;
1630
0
    for (SCSIZE nArrY=1; nArrY<mnArrCount; nArrY++)
1631
0
    {
1632
        // Rotated is also drawn one line above/below Changed if parts extend into the cell
1633
1634
0
        RowInfo& rPrevRowInfo = mpRowInfo[nArrY-1];
1635
0
        RowInfo& rThisRowInfo = mpRowInfo[nArrY];
1636
0
        RowInfo& rNextRowInfo = mpRowInfo[nArrY+1];
1637
1638
0
        tools::Long nRowHeight = rThisRowInfo.nHeight;
1639
0
        if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1640
0
             ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1641
0
               ( nArrY+1<mnArrCount && rNextRowInfo.bChanged ) ) )
1642
0
        {
1643
0
            SCROW nY = rThisRowInfo.nRowNo;
1644
0
            tools::Long nPosX = 0;
1645
0
            SCCOL nX;
1646
0
            for (nX=0; nX<=nRotMax; nX++)
1647
0
            {
1648
0
                if (nX==mnX1) nPosX = nInitPosX;     // calculated individually for preceding positions
1649
1650
0
                ScCellInfo* pInfo = &rThisRowInfo.cellInfo(nX);
1651
0
                tools::Long nColWidth = mpRowInfo[0].basicCellInfo(nX).nWidth;
1652
0
                if ( pInfo->nRotateDir > ScRotateDir::Standard &&
1653
0
                        !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1654
0
                {
1655
0
                    aPatternHolder.setScPatternAttr(pInfo->getPatternAttr());
1656
0
                    pCondSet = pInfo->pConditionSet;
1657
0
                    if (!aPatternHolder)
1658
0
                    {
1659
0
                        aPatternHolder.setScPatternAttr(mpDoc->GetPattern( nX, nY, mnTab ));
1660
0
                        pInfo->pPatternAttr = aPatternHolder;
1661
0
                        pCondSet = mpDoc->GetCondResult( nX, nY, mnTab );
1662
0
                        pInfo->pConditionSet = pCondSet;
1663
0
                    }
1664
1665
                    //! LastPattern etc.
1666
1667
0
                    Degree100 nAttrRotate = aPatternHolder.getScPatternAttr()->GetRotateVal( pCondSet );
1668
0
                    SvxRotateMode eRotMode =
1669
0
                                    aPatternHolder.getScPatternAttr()->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
1670
1671
0
                    if (nAttrRotate)
1672
0
                    {
1673
0
                        if (nX < mnX1)         // compute negative position
1674
0
                        {
1675
0
                            nPosX = nInitPosX;
1676
0
                            SCCOL nCol = mnX1;
1677
0
                            while (nCol > nX)
1678
0
                            {
1679
0
                                --nCol;
1680
0
                                nPosX -= nLayoutSign * static_cast<tools::Long>(mpRowInfo[0].basicCellInfo(nCol).nWidth);
1681
0
                            }
1682
0
                        }
1683
1684
                        // start position minus 1 so rotated backgrounds suit the border
1685
                        // (border is on the grid)
1686
1687
0
                        tools::Long nTop = nPosY - 1;
1688
0
                        tools::Long nBottom = nPosY + nRowHeight - 1;
1689
0
                        tools::Long nTopLeft = nPosX - nLayoutSign;
1690
0
                        tools::Long nTopRight = nPosX + (nColWidth - 1) * nLayoutSign;
1691
0
                        tools::Long nBotLeft = nTopLeft;
1692
0
                        tools::Long nBotRight = nTopRight;
1693
1694
                        // inclusion of the sign here hasn't been decided yet
1695
                        // (if not, the extension of the non-rotated background must also be changed)
1696
0
                        double nRealOrient = nLayoutSign * toRadians(nAttrRotate);     // 1/100th degrees
1697
0
                        double nCos = cos(nRealOrient);
1698
0
                        double nSin = sin(nRealOrient);
1699
                        //! restrict !!!
1700
0
                        tools::Long nSkew = static_cast<tools::Long>(nRowHeight * nCos / nSin);
1701
1702
0
                        switch (eRotMode)
1703
0
                        {
1704
0
                        case SVX_ROTATE_MODE_BOTTOM:
1705
0
                            nTopLeft += nSkew;
1706
0
                            nTopRight += nSkew;
1707
0
                            break;
1708
0
                        case SVX_ROTATE_MODE_CENTER:
1709
0
                            nSkew /= 2;
1710
0
                            nTopLeft += nSkew;
1711
0
                            nTopRight += nSkew;
1712
0
                            nBotLeft -= nSkew;
1713
0
                            nBotRight -= nSkew;
1714
0
                            break;
1715
0
                        case SVX_ROTATE_MODE_TOP:
1716
0
                            nBotLeft -= nSkew;
1717
0
                            nBotRight -= nSkew;
1718
0
                            break;
1719
0
                        default:
1720
0
                        {
1721
                            // added to avoid warnings
1722
0
                        }
1723
0
                        }
1724
1725
0
                        Point aPoints[4];
1726
0
                        aPoints[0] = Point(nTopLeft, nTop);
1727
0
                        aPoints[1] = Point(nTopRight, nTop);
1728
0
                        aPoints[2] = Point(nBotRight, nBottom);
1729
0
                        aPoints[3] = Point(nBotLeft, nBottom);
1730
1731
0
                        const SvxBrushItem* pBackground(static_cast<const SvxBrushItem*>(pInfo->maBackground.getItem()));
1732
0
                        if (!pBackground)
1733
0
                            pBackground = &aPatternHolder.getScPatternAttr()->GetItem(ATTR_BACKGROUND, pCondSet);
1734
0
                        if (bCellContrast)
1735
0
                        {
1736
                            //  high contrast for cell borders and backgrounds -> empty background
1737
0
                            pBackground = ScGlobal::GetEmptyBrushItem();
1738
0
                        }
1739
0
                        if (!pInfo->mxColorScale)
1740
0
                        {
1741
0
                            const Color& rColor = pBackground->GetColor();
1742
0
                            if (rColor.GetAlpha() != 0)
1743
0
                            {
1744
                                //  draw background only for the changed row itself
1745
                                //  (background doesn't extend into other cells).
1746
                                //  For the borders (rotated and normal), clipping should be
1747
                                //  set if the row isn't changed, but at least the borders
1748
                                //  don't cover the cell contents.
1749
0
                                if (rThisRowInfo.bChanged)
1750
0
                                {
1751
0
                                    tools::Polygon aPoly(4, aPoints);
1752
1753
                                    // for DrawPolygon, without Pen one pixel is left out
1754
                                    // to the right and below...
1755
0
                                    if (!rColor.IsTransparent())
1756
0
                                        rRenderContext.SetLineColor(rColor);
1757
0
                                    else
1758
0
                                        rRenderContext.SetLineColor();
1759
0
                                    rRenderContext.SetFillColor(rColor);
1760
0
                                    rRenderContext.DrawPolygon(aPoly);
1761
0
                                }
1762
0
                            }
1763
0
                        }
1764
0
                        else
1765
0
                        {
1766
0
                            tools::Polygon aPoly(4, aPoints);
1767
0
                            std::optional<Color> const & pColor = pInfo->mxColorScale;
1768
1769
                            // for DrawPolygon, without Pen one pixel is left out
1770
                            // to the right and below...
1771
0
                            if (!pColor->IsTransparent())
1772
0
                                rRenderContext.SetLineColor(*pColor);
1773
0
                            else
1774
0
                                rRenderContext.SetLineColor();
1775
0
                            rRenderContext.SetFillColor(*pColor);
1776
0
                            rRenderContext.DrawPolygon(aPoly);
1777
1778
0
                        }
1779
0
                    }
1780
0
                }
1781
0
                nPosX += nColWidth * nLayoutSign;
1782
0
            }
1783
0
        }
1784
0
        nPosY += nRowHeight;
1785
0
    }
1786
1787
0
    pProcessor.reset();
1788
1789
0
    if (mbMetaFile)
1790
0
        rRenderContext.Pop();
1791
0
    else
1792
0
        rRenderContext.SetClipRegion();
1793
0
}
1794
1795
std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> ScOutputData::CreateProcessor2D( )
1796
0
{
1797
0
    mpDoc->InitDrawLayer(mpDoc->GetDocumentShell());
1798
0
    ScDrawLayer* pDrawLayer = mpDoc->GetDrawLayer();
1799
0
    if (!pDrawLayer)
1800
0
        return nullptr;
1801
1802
0
    basegfx::B2DRange aViewRange;
1803
0
    SdrPage *pDrawPage = pDrawLayer->GetPage( static_cast< sal_uInt16 >( mnTab ) );
1804
0
    drawinglayer::geometry::ViewInformation2D aNewViewInfos;
1805
0
    aNewViewInfos.setViewTransformation(mpDev->GetViewTransformation());
1806
0
    aNewViewInfos.setViewport(aViewRange);
1807
0
    aNewViewInfos.setVisualizedPage(GetXDrawPageForSdrPage( pDrawPage ));
1808
1809
0
    return drawinglayer::processor2d::createProcessor2DFromOutputDevice(
1810
0
                    *mpDev, aNewViewInfos );
1811
0
}
1812
1813
// Printer
1814
1815
vcl::Region ScOutputData::GetChangedAreaRegion()
1816
0
{
1817
0
    vcl::Region aRegion;
1818
0
    tools::Rectangle aDrawingRect;
1819
0
    bool bHad(false);
1820
0
    tools::Long nPosY = mnScrY;
1821
0
    SCSIZE nArrY;
1822
1823
0
    aDrawingRect.SetLeft( mnScrX );
1824
0
    aDrawingRect.SetRight( mnScrX+mnScrW-1 );
1825
1826
0
    for(nArrY=1; nArrY+1<mnArrCount; nArrY++)
1827
0
    {
1828
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1829
1830
0
        if(pThisRowInfo->bChanged)
1831
0
        {
1832
0
            if(!bHad)
1833
0
            {
1834
0
                aDrawingRect.SetTop( nPosY );
1835
0
                bHad = true;
1836
0
            }
1837
1838
0
            aDrawingRect.SetBottom( nPosY + mpRowInfo[nArrY].nHeight - 1 );
1839
0
        }
1840
0
        else if(bHad)
1841
0
        {
1842
0
            aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1843
0
            bHad = false;
1844
0
        }
1845
1846
0
        nPosY += mpRowInfo[nArrY].nHeight;
1847
0
    }
1848
1849
0
    if(bHad)
1850
0
    {
1851
0
        aRegion.Union(mpDev->PixelToLogic(aDrawingRect));
1852
0
    }
1853
1854
0
    return aRegion;
1855
0
}
1856
1857
bool ScOutputData::SetChangedClip()
1858
0
{
1859
0
    tools::PolyPolygon aPoly;
1860
1861
0
    tools::Rectangle aDrawingRect;
1862
0
    aDrawingRect.SetLeft( mnScrX );
1863
0
    aDrawingRect.SetRight( mnScrX+mnScrW-1 );
1864
1865
0
    bool    bHad    = false;
1866
0
    tools::Long    nPosY   = mnScrY;
1867
0
    SCSIZE  nArrY;
1868
0
    for (nArrY=1; nArrY+1<mnArrCount; nArrY++)
1869
0
    {
1870
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1871
1872
0
        if ( pThisRowInfo->bChanged )
1873
0
        {
1874
0
            if (!bHad)
1875
0
            {
1876
0
                aDrawingRect.SetTop( nPosY );
1877
0
                bHad = true;
1878
0
            }
1879
0
            aDrawingRect.SetBottom( nPosY + mpRowInfo[nArrY].nHeight - 1 );
1880
0
        }
1881
0
        else if (bHad)
1882
0
        {
1883
0
            aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1884
0
            bHad = false;
1885
0
        }
1886
0
        nPosY += mpRowInfo[nArrY].nHeight;
1887
0
    }
1888
1889
0
    if (bHad)
1890
0
        aPoly.Insert( tools::Polygon( mpDev->PixelToLogic(aDrawingRect) ) );
1891
1892
0
    bool bRet = (aPoly.Count() != 0);
1893
0
    if (bRet)
1894
0
        mpDev->SetClipRegion(vcl::Region(aPoly));
1895
0
    return bRet;
1896
0
}
1897
1898
void ScOutputData::FindChanged()
1899
0
{
1900
0
    SCCOL   nX;
1901
0
    SCSIZE  nArrY;
1902
1903
0
    bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
1904
0
    mpDoc->EnableIdle(false);
1905
0
    for (nArrY=0; nArrY<mnArrCount; nArrY++)
1906
0
        mpRowInfo[nArrY].bChanged = false;
1907
1908
0
    SCCOL nCol1 = mpDoc->MaxCol(), nCol2 = 0;
1909
0
    SCROW nRow1 = mpDoc->MaxRow(), nRow2 = 0;
1910
0
    bool bAnyDirty = false;
1911
0
    bool bAnyChanged = false;
1912
1913
0
    for (nArrY=0; nArrY<mnArrCount; nArrY++)
1914
0
    {
1915
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1916
0
        for (nX=mnX1; nX<=mnX2; nX++)
1917
0
        {
1918
0
            const ScRefCellValue& rCell = pThisRowInfo->cellInfo(nX).maCell;
1919
1920
0
            if (rCell.getType() != CELLTYPE_FORMULA)
1921
0
                continue;
1922
1923
0
            ScFormulaCell* pFCell = rCell.getFormula();
1924
0
            if (pFCell->IsRunning())
1925
                // still being interpreted. Skip it.
1926
0
                continue;
1927
1928
0
            bool bDirty = pFCell->GetDirty();
1929
0
            bAnyChanged = bAnyChanged || pFCell->IsChanged();
1930
1931
0
            if (bDirty)
1932
0
            {
1933
0
                if (!bAnyDirty)
1934
0
                {
1935
0
                    ScProgress::CreateInterpretProgress(mpDoc);
1936
0
                    bAnyDirty = true;
1937
0
                }
1938
1939
0
                ScAddress& rPos(pFCell->aPos);
1940
0
                nCol1 = std::min(rPos.Col(), nCol1);
1941
0
                nCol2 = std::max(rPos.Col(), nCol2);
1942
0
                nRow1 = std::min(rPos.Row(), nRow1);
1943
0
                nRow2 = std::max(rPos.Row(), nRow2);
1944
1945
0
                const SfxUInt32Item& rItem = mpDoc->GetAttr(rPos, ATTR_VALIDDATA);
1946
0
                const ScValidationData* pData = mpDoc->GetValidationEntry(rItem.GetValue());
1947
0
                if (pData)
1948
0
                {
1949
0
                    ScRefCellValue aCell(*mpDoc, rPos);
1950
0
                    if (pData->IsDataValid(aCell, rPos))
1951
0
                        ScDetectiveFunc(*mpDoc, rPos.Tab()).DeleteCirclesAt(rPos.Col(), rPos.Row());
1952
0
                }
1953
0
            }
1954
0
        }
1955
0
    }
1956
1957
0
    if (bAnyDirty || bAnyChanged)
1958
0
    {
1959
0
        sc::MatrixResizeGuard aGuard(*mpDoc);
1960
1961
0
        if (bAnyDirty)
1962
0
            mpDoc->EnsureFormulaCellResults(ScRange(nCol1, nRow1, mnTab, nCol2, nRow2, mnTab), true);
1963
1964
0
        for (nArrY=0; nArrY<mnArrCount; nArrY++)
1965
0
        {
1966
0
            RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
1967
0
            for (nX=mnX1; nX<=mnX2; nX++)
1968
0
            {
1969
0
                const ScRefCellValue& rCell = pThisRowInfo->cellInfo(nX).maCell;
1970
1971
0
                if (rCell.getType() != CELLTYPE_FORMULA)
1972
0
                    continue;
1973
1974
0
                ScFormulaCell* pFCell = rCell.getFormula();
1975
0
                if (pFCell->IsRunning())
1976
                    // still being interpreted. Skip it.
1977
0
                    continue;
1978
1979
0
                if (!pFCell->IsChanged())
1980
                    // the result hasn't changed. Skip it.
1981
0
                    continue;
1982
1983
0
                pThisRowInfo->bChanged = true;
1984
0
                if ( pThisRowInfo->cellInfo(nX).bMerged )
1985
0
                {
1986
0
                    SCSIZE nOverY = nArrY + 1;
1987
0
                    while ( nOverY<mnArrCount &&
1988
0
                            mpRowInfo[nOverY].cellInfo(nX).bVOverlapped )
1989
0
                    {
1990
0
                        mpRowInfo[nOverY].bChanged = true;
1991
0
                        ++nOverY;
1992
0
                    }
1993
0
                }
1994
0
            }
1995
0
        }
1996
1997
0
        if (bAnyDirty)
1998
0
            ScProgress::DeleteInterpretProgress();
1999
0
    }
2000
2001
0
    mpDoc->EnableIdle(bWasIdleEnabled);
2002
0
}
2003
2004
ReferenceMark ScOutputData::FillReferenceMark( SCCOL nRefStartX, SCROW nRefStartY,
2005
                                SCCOL nRefEndX, SCROW nRefEndY, const Color& rColor)
2006
0
{
2007
0
    ReferenceMark aResult;
2008
2009
0
    PutInOrder( nRefStartX, nRefEndX );
2010
0
    PutInOrder( nRefStartY, nRefEndY );
2011
2012
0
    if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2013
0
        mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, mnTab );
2014
2015
0
    if ( nRefStartX <= mnVisX2 && nRefEndX >= mnVisX1 &&
2016
0
         nRefStartY <= mnVisY2 && nRefEndY >= mnVisY1 )
2017
0
    {
2018
0
        tools::Long nMinX = mnScrX;
2019
0
        tools::Long nMinY = mnScrY;
2020
0
        tools::Long nMaxX = mnScrX + mnScrW - 1;
2021
0
        tools::Long nMaxY = mnScrY + mnScrH - 1;
2022
0
        if ( mbLayoutRTL )
2023
0
            std::swap( nMinX, nMaxX );
2024
0
        tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2025
2026
0
        bool bTop    = false;
2027
0
        bool bBottom = false;
2028
0
        bool bLeft   = false;
2029
0
        bool bRight  = false;
2030
2031
0
        tools::Long nPosY = mnScrY;
2032
0
        bool bNoStartY = ( mnY1 < nRefStartY );
2033
0
        bool bNoEndY   = false;
2034
0
        for (SCSIZE nArrY=1; nArrY<mnArrCount; nArrY++)      // loop to end for bNoEndY check
2035
0
        {
2036
0
            SCROW nY = mpRowInfo[nArrY].nRowNo;
2037
2038
0
            if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2039
0
            {
2040
0
                nMinY = nPosY;
2041
0
                bTop = true;
2042
0
            }
2043
0
            if ( nY==nRefEndY )
2044
0
            {
2045
0
                nMaxY = nPosY + mpRowInfo[nArrY].nHeight - 2;
2046
0
                bBottom = true;
2047
0
            }
2048
0
            if ( nY>nRefEndY && bNoEndY )
2049
0
            {
2050
0
                nMaxY = nPosY-2;
2051
0
                bBottom = true;
2052
0
            }
2053
0
            bNoStartY = ( nY < nRefStartY );
2054
0
            bNoEndY   = ( nY < nRefEndY );
2055
0
            nPosY += mpRowInfo[nArrY].nHeight;
2056
0
        }
2057
2058
0
        tools::Long nPosX = mnScrX;
2059
0
        if ( mbLayoutRTL )
2060
0
            nPosX += mnMirrorW - 1;      // always in pixels
2061
2062
0
        for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2063
0
        {
2064
0
            if ( nX==nRefStartX )
2065
0
            {
2066
0
                nMinX = nPosX;
2067
0
                bLeft = true;
2068
0
            }
2069
0
            if ( nX==nRefEndX )
2070
0
            {
2071
0
                nMaxX = nPosX + ( mpRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
2072
0
                bRight = true;
2073
0
            }
2074
0
            nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2075
0
        }
2076
2077
0
        if (bTop && bBottom && bLeft && bRight)
2078
0
        {
2079
            // mnPPT[XY] already has the factor aZoom[XY] in it.
2080
0
            aResult = ReferenceMark( nMinX / mnPPTX,
2081
0
                                     nMinY / mnPPTY,
2082
0
                                     ( nMaxX - nMinX ) / mnPPTX,
2083
0
                                     ( nMaxY - nMinY ) / mnPPTY,
2084
0
                                     mnTab,
2085
0
                                     rColor );
2086
0
        }
2087
0
    }
2088
2089
0
    return aResult;
2090
0
}
2091
2092
void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
2093
                                SCCOL nRefEndX, SCROW nRefEndY,
2094
                                const Color& rColor, bool bHandle )
2095
0
{
2096
0
    PutInOrder( nRefStartX, nRefEndX );
2097
0
    PutInOrder( nRefStartY, nRefEndY );
2098
2099
0
    if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2100
0
        mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, mnTab );
2101
0
    else if (mpDoc->ValidCol(nRefEndX) && mpDoc->ValidRow(nRefEndY) &&
2102
0
             mpDoc->HasAttrib(nRefEndX, nRefEndY, mnTab, HasAttrFlags::Merged))
2103
0
        mpDoc->ExtendMerge(nRefEndX, nRefEndY, nRefEndX, nRefEndY, mnTab);
2104
2105
0
    if ( !(nRefStartX <= mnVisX2 && nRefEndX >= mnVisX1 &&
2106
0
         nRefStartY <= mnVisY2 && nRefEndY >= mnVisY1) )
2107
0
        return;
2108
2109
0
    tools::Long nMinX = mnScrX;
2110
0
    tools::Long nMinY = mnScrY;
2111
0
    tools::Long nMaxX = mnScrX + mnScrW - 1;
2112
0
    tools::Long nMaxY = mnScrY + mnScrH - 1;
2113
0
    if ( mbLayoutRTL )
2114
0
        std::swap( nMinX, nMaxX );
2115
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2116
2117
0
    bool bTop    = false;
2118
0
    bool bBottom = false;
2119
0
    bool bLeft   = false;
2120
0
    bool bRight  = false;
2121
2122
0
    tools::Long nPosY = mnScrY;
2123
0
    bool bNoStartY = ( mnY1 < nRefStartY );
2124
0
    bool bNoEndY   = false;
2125
0
    for (SCSIZE nArrY=1; nArrY<mnArrCount; nArrY++)      // loop to end for bNoEndY check
2126
0
    {
2127
0
        SCROW nY = mpRowInfo[nArrY].nRowNo;
2128
2129
0
        if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2130
0
        {
2131
0
            nMinY = nPosY;
2132
0
            bTop = true;
2133
0
        }
2134
0
        if ( nY==nRefEndY )
2135
0
        {
2136
0
            nMaxY = nPosY + mpRowInfo[nArrY].nHeight - 2;
2137
0
            bBottom = true;
2138
0
        }
2139
0
        if ( nY>nRefEndY && bNoEndY )
2140
0
        {
2141
0
            nMaxY = nPosY-2;
2142
0
            bBottom = true;
2143
0
        }
2144
0
        bNoStartY = ( nY < nRefStartY );
2145
0
        bNoEndY   = ( nY < nRefEndY );
2146
0
        nPosY += mpRowInfo[nArrY].nHeight;
2147
0
    }
2148
2149
0
    tools::Long nPosX = mnScrX;
2150
0
    if ( mbLayoutRTL )
2151
0
        nPosX += mnMirrorW - 1;      // always in pixels
2152
2153
0
    for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2154
0
    {
2155
0
        if ( nX==nRefStartX )
2156
0
        {
2157
0
            nMinX = nPosX;
2158
0
            bLeft = true;
2159
0
        }
2160
0
        if ( nX==nRefEndX )
2161
0
        {
2162
0
            nMaxX = nPosX + ( mpRowInfo[0].basicCellInfo(nX).nWidth - 2 ) * nLayoutSign;
2163
0
            bRight = true;
2164
0
        }
2165
0
        nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2166
0
    }
2167
2168
0
    if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
2169
0
        return;
2170
2171
0
    mpDev->SetLineColor( rColor );
2172
0
    if (bTop && bBottom && bLeft && bRight && !comphelper::LibreOfficeKit::isActive() )
2173
0
    {
2174
0
            mpDev->SetFillColor();
2175
0
            mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2176
0
    }
2177
0
    else if ( !comphelper::LibreOfficeKit::isActive() )
2178
0
    {
2179
0
        if (bTop)
2180
0
            mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMaxX, nMinY ) );
2181
0
        if (bBottom)
2182
0
            mpDev->DrawLine( Point( nMinX, nMaxY ), Point( nMaxX, nMaxY ) );
2183
0
        if (bLeft)
2184
0
            mpDev->DrawLine( Point( nMinX, nMinY ), Point( nMinX, nMaxY ) );
2185
0
        if (bRight)
2186
0
            mpDev->DrawLine( Point( nMaxX, nMinY ), Point( nMaxX, nMaxY ) );
2187
0
    }
2188
0
    if ( !bHandle || !bRight || !bBottom || comphelper::LibreOfficeKit::isActive() )
2189
0
        return;
2190
2191
0
    mpDev->SetLineColor( rColor );
2192
0
    mpDev->SetFillColor( rColor );
2193
2194
0
    const sal_Int32 aRadius = 4;
2195
2196
0
    sal_Int32 aRectMaxX1 = nMaxX - nLayoutSign * aRadius;
2197
0
    sal_Int32 aRectMaxX2 = nMaxX + nLayoutSign;
2198
0
    sal_Int32 aRectMinX1 = nMinX - nLayoutSign;
2199
0
    sal_Int32 aRectMinX2 = nMinX + nLayoutSign * aRadius;
2200
2201
0
    sal_Int32 aRectMaxY1 = nMaxY - aRadius;
2202
0
    sal_Int32 aRectMaxY2 = nMaxY + 1;
2203
0
    sal_Int32 aRectMinY1 = nMinY - 1;
2204
0
    sal_Int32 aRectMinY2 = nMinY + aRadius;
2205
2206
    // Draw corner rectangles
2207
0
    tools::Rectangle aLowerRight( aRectMaxX1, aRectMaxY1, aRectMaxX2, aRectMaxY2 );
2208
0
    tools::Rectangle aUpperLeft ( aRectMinX1, aRectMinY1, aRectMinX2, aRectMinY2 );
2209
0
    tools::Rectangle aLowerLeft ( aRectMinX1, aRectMaxY1, aRectMinX2, aRectMaxY2 );
2210
0
    tools::Rectangle aUpperRight( aRectMaxX1, aRectMinY1, aRectMaxX2, aRectMinY2 );
2211
2212
0
    mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerRight ) ), lclCornerRectTransparency );
2213
0
    mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperLeft  ) ), lclCornerRectTransparency );
2214
0
    mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aLowerLeft  ) ), lclCornerRectTransparency );
2215
0
    mpDev->DrawTransparent( tools::PolyPolygon( tools::Polygon( aUpperRight ) ), lclCornerRectTransparency );
2216
0
}
2217
2218
void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
2219
                                SCCOL nRefEndX, SCROW nRefEndY,
2220
                                const Color& rColor, sal_uInt16 nType )
2221
0
{
2222
0
    PutInOrder( nRefStartX, nRefEndX );
2223
0
    PutInOrder( nRefStartY, nRefEndY );
2224
2225
0
    if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
2226
0
        mpDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, mnTab );
2227
2228
0
    if ( !(nRefStartX <= mnVisX2 + 1 && nRefEndX >= mnVisX1 &&
2229
0
         nRefStartY <= mnVisY2 + 1 && nRefEndY >= mnVisY1) )       // +1 because it touches next cells left/top
2230
0
        return;
2231
2232
0
    tools::Long nMinX = mnScrX;
2233
0
    tools::Long nMinY = mnScrY;
2234
0
    tools::Long nMaxX = mnScrX+mnScrW-1;
2235
0
    tools::Long nMaxY = mnScrY+mnScrH-1;
2236
0
    if ( mbLayoutRTL )
2237
0
        std::swap( nMinX, nMaxX );
2238
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2239
2240
0
    bool bTop    = false;
2241
0
    bool bBottom = false;
2242
0
    bool bLeft   = false;
2243
0
    bool bRight  = false;
2244
2245
0
    tools::Long nPosY = mnScrY;
2246
0
    bool bNoStartY = ( mnY1 < nRefStartY );
2247
0
    bool bNoEndY   = false;
2248
0
    for (SCSIZE nArrY=1; nArrY<mnArrCount; nArrY++)      // loop to end for bNoEndY check
2249
0
    {
2250
0
        SCROW nY = mpRowInfo[nArrY].nRowNo;
2251
2252
0
        if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2253
0
        {
2254
0
            nMinY = nPosY - 1;
2255
0
            bTop = true;
2256
0
        }
2257
0
        if ( nY==nRefEndY )
2258
0
        {
2259
0
            nMaxY = nPosY + mpRowInfo[nArrY].nHeight - 1;
2260
0
            bBottom = true;
2261
0
        }
2262
0
        if ( nY>nRefEndY && bNoEndY )
2263
0
        {
2264
0
            nMaxY = nPosY - 1;
2265
0
            bBottom = true;
2266
0
        }
2267
0
        bNoStartY = ( nY < nRefStartY );
2268
0
        bNoEndY   = ( nY < nRefEndY );
2269
0
        nPosY += mpRowInfo[nArrY].nHeight;
2270
0
    }
2271
2272
0
    tools::Long nPosX = mnScrX;
2273
0
    if ( mbLayoutRTL )
2274
0
        nPosX += mnMirrorW - 1;      // always in pixels
2275
2276
0
    for (SCCOL nX=mnX1; nX<=mnX2+1; nX++)
2277
0
    {
2278
0
        if ( nX==nRefStartX )
2279
0
        {
2280
0
            nMinX = nPosX - nLayoutSign;
2281
0
            bLeft = true;
2282
0
        }
2283
0
        if ( nX==nRefEndX )
2284
0
        {
2285
0
            nMaxX = nPosX + ( mpRowInfo[0].basicCellInfo(nX).nWidth - 1 ) * nLayoutSign;
2286
0
            bRight = true;
2287
0
        }
2288
0
        nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2289
0
    }
2290
2291
0
    if ( nMaxX * nLayoutSign < nMinX * nLayoutSign || nMaxY < nMinY )
2292
0
        return;
2293
2294
0
    if ( nType == SC_CAT_DELETE_ROWS )
2295
0
        bLeft = bRight = bBottom = false;       //! thick lines???
2296
0
    else if ( nType == SC_CAT_DELETE_COLS )
2297
0
        bTop = bBottom = bRight = false;        //! thick lines???
2298
2299
0
    mpDev->SetLineColor( rColor );
2300
0
    if (bTop && bBottom && bLeft && bRight)
2301
0
    {
2302
0
        mpDev->SetFillColor();
2303
0
        mpDev->DrawRect( tools::Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2304
0
    }
2305
0
    else
2306
0
    {
2307
0
        if (bTop)
2308
0
        {
2309
0
            mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2310
0
            if ( nType == SC_CAT_DELETE_ROWS )
2311
0
                mpDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2312
0
        }
2313
0
        if (bBottom)
2314
0
            mpDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2315
0
        if (bLeft)
2316
0
        {
2317
0
            mpDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2318
0
            if ( nType == SC_CAT_DELETE_COLS )
2319
0
                mpDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2320
0
        }
2321
0
        if (bRight)
2322
0
            mpDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2323
0
    }
2324
0
    if ( bLeft && bTop )
2325
0
    {
2326
0
        mpDev->SetLineColor();
2327
0
        mpDev->SetFillColor( rColor );
2328
0
        mpDev->DrawRect( tools::Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2329
0
    }
2330
0
}
2331
2332
void ScOutputData::DrawChangeTrack()
2333
0
{
2334
0
    ScChangeTrack* pTrack = mpDoc->GetChangeTrack();
2335
0
    ScChangeViewSettings* pSettings = mpDoc->GetChangeViewSettings();
2336
0
    if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2337
0
        return;         // nothing there or hidden
2338
2339
0
    ScActionColorChanger aColorChanger(*pTrack);
2340
2341
    //  clipping happens from the outside
2342
    //! without clipping, only paint affected cells ??!??!?
2343
2344
0
    SCCOL nEndX = mnX2;
2345
0
    SCROW nEndY = mnY2;
2346
0
    if ( nEndX < mpDoc->MaxCol() ) ++nEndX;      // also from the next cell since the mark
2347
0
    if ( nEndY < mpDoc->MaxRow() ) ++nEndY;      // protrudes from the preceding cell
2348
0
    ScRange aViewRange( mnX1, mnY1, mnTab, nEndX, nEndY, mnTab );
2349
0
    const ScChangeAction* pAction = pTrack->GetFirst();
2350
0
    while (pAction)
2351
0
    {
2352
0
        if ( pAction->IsVisible() )
2353
0
        {
2354
0
            ScChangeActionType eActionType = pAction->GetType();
2355
0
            const ScBigRange& rBig = pAction->GetBigRange();
2356
0
            if ( rBig.aStart.Tab() == mnTab )
2357
0
            {
2358
0
                ScRange aRange = rBig.MakeRange( *mpDoc );
2359
2360
0
                if ( eActionType == SC_CAT_DELETE_ROWS )
2361
0
                    aRange.aEnd.SetRow( aRange.aStart.Row() );
2362
0
                else if ( eActionType == SC_CAT_DELETE_COLS )
2363
0
                    aRange.aEnd.SetCol( aRange.aStart.Col() );
2364
2365
0
                if ( aRange.Intersects( aViewRange ) &&
2366
0
                     ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2367
0
                {
2368
0
                    aColorChanger.Update( *pAction );
2369
0
                    Color aColor( aColorChanger.GetColor() );
2370
0
                    DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2371
0
                                    aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2372
2373
0
                }
2374
0
            }
2375
0
            if ( eActionType == SC_CAT_MOVE &&
2376
0
                    static_cast<const ScChangeActionMove*>(pAction)->
2377
0
                        GetFromRange().aStart.Tab() == mnTab )
2378
0
            {
2379
0
                ScRange aRange = static_cast<const ScChangeActionMove*>(pAction)->
2380
0
                        GetFromRange().MakeRange( *mpDoc );
2381
0
                if ( aRange.Intersects( aViewRange ) &&
2382
0
                     ScViewUtil::IsActionShown( *pAction, *pSettings, *mpDoc ) )
2383
0
                {
2384
0
                    aColorChanger.Update( *pAction );
2385
0
                    Color aColor( aColorChanger.GetColor() );
2386
0
                    DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2387
0
                                    aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2388
0
                }
2389
0
            }
2390
0
        }
2391
2392
0
        pAction = pAction->GetNext();
2393
0
    }
2394
0
}
2395
2396
void ScOutputData::DrawSparklines(vcl::RenderContext& rRenderContext)
2397
0
{
2398
0
    tools::Long nInitPosX = mnScrX;
2399
0
    if ( mbLayoutRTL )
2400
0
        nInitPosX += mnMirrorW - 1;              // always in pixels
2401
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2402
2403
0
    tools::Long nPosY = mnScrY;
2404
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
2405
0
    {
2406
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
2407
0
        if ( pThisRowInfo->bChanged )
2408
0
        {
2409
0
            tools::Long nPosX = nInitPosX;
2410
0
            for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2411
0
            {
2412
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
2413
0
                bool bIsMerged = false;
2414
2415
0
                SCCOL nOverX = nX;
2416
0
                SCROW nOverY = pThisRowInfo->nRowNo;
2417
0
                tools::Long nStartPosX = nPosX;
2418
0
                tools::Long nStartPosY = nPosY;
2419
2420
0
                ScAddress aCurrentAddress(nX, mpRowInfo[nArrY].nRowNo, mnTab);
2421
0
                std::shared_ptr<sc::Sparkline> pSparkline = mpDoc->GetSparkline(aCurrentAddress);
2422
2423
0
                if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2424
0
                {
2425
0
                    while (nOverX > 0 && (mpDoc->GetAttr(
2426
0
                           nOverX, nOverY, mnTab, ATTR_MERGE_FLAG).GetValue() & ScMF::Hor))
2427
0
                    {
2428
0
                        --nOverX;
2429
0
                        nStartPosX -= nLayoutSign
2430
0
                                      * static_cast<tools::Long>(mpDoc->GetColWidth(nOverX, mnTab)
2431
0
                                                                 * mnPPTX);
2432
0
                    }
2433
2434
0
                    while (nOverY > 0 && (mpDoc->GetAttr(
2435
0
                           nOverX, nOverY, mnTab, ATTR_MERGE_FLAG).GetValue() & ScMF::Ver))
2436
0
                    {
2437
0
                        --nOverY;
2438
0
                        nStartPosY -= nLayoutSign
2439
0
                                      * static_cast<tools::Long>(mpDoc->GetRowHeight(nOverY, mnTab)
2440
0
                                                                 * mnPPTY);
2441
0
                    }
2442
2443
0
                    pSparkline = mpDoc->GetSparkline(ScAddress(nOverX, nOverY, mnTab));
2444
0
                    bIsMerged = pSparkline ? true : false;
2445
0
                }
2446
2447
0
                if (!mpDoc->ColHidden(nX, mnTab) && pSparkline
2448
0
                    && (bIsMerged || (!pInfo->bHOverlapped && !pInfo->bVOverlapped)))
2449
0
                {
2450
0
                    tools::Long nWidth = mpRowInfo[0].basicCellInfo(nX).nWidth;
2451
0
                    tools::Long nHeight = pThisRowInfo->nHeight;
2452
2453
0
                    if (bIsMerged || pInfo->bMerged)
2454
0
                    {
2455
0
                        const ScMergeAttr& rMerge = mpDoc->GetAttr(nOverX, nOverY, mnTab, ATTR_MERGE);
2456
0
                        SCROW nCountX = rMerge.GetColMerge();
2457
0
                        if (nCountX > 0)
2458
0
                        {
2459
0
                            sal_Int32 nIndex = 1;
2460
0
                            while (nCountX > nIndex && (mpDoc->GetAttr(
2461
0
                                   nOverX + nIndex, nOverY, mnTab, ATTR_MERGE_FLAG).GetValue() & ScMF::Hor))
2462
0
                            {
2463
0
                                nWidth += nLayoutSign
2464
0
                                          * static_cast<tools::Long>(
2465
0
                                              mpDoc->GetColWidth(nOverX + nIndex, mnTab) * mnPPTX);
2466
0
                                nIndex++;
2467
0
                            }
2468
0
                        }
2469
2470
0
                        SCROW nCountY = rMerge.GetRowMerge();
2471
0
                        if (nCountY > 0)
2472
0
                        {
2473
0
                            sal_Int32 nIndex = 1;
2474
0
                            while (nCountY > nIndex && (mpDoc->GetAttr(
2475
0
                                   nOverX, nOverY + nIndex, mnTab, ATTR_MERGE_FLAG).GetValue() & ScMF::Ver))
2476
0
                            {
2477
0
                                nHeight += nLayoutSign
2478
0
                                           * static_cast<tools::Long>(
2479
0
                                               mpDoc->GetRowHeight(nOverY + nIndex, mnTab) * mnPPTY);
2480
0
                                nIndex++;
2481
0
                            }
2482
0
                        }
2483
0
                    }
2484
2485
0
                    Point aPoint(nStartPosX, nStartPosY);
2486
0
                    Size aSize(nWidth, nHeight);
2487
2488
0
                    sc::SparklineRenderer renderer(*mpDoc);
2489
0
                    renderer.render(pSparkline, rRenderContext, tools::Rectangle(aPoint, aSize), 1, 1, mfZoomX, mfZoomY);
2490
0
                }
2491
2492
0
                nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2493
0
            }
2494
0
        }
2495
0
        nPosY += pThisRowInfo->nHeight;
2496
0
    }
2497
2498
0
}
2499
2500
//TODO: moggi Need to check if this can't be written simpler
2501
void ScOutputData::DrawNoteMarks(vcl::RenderContext& rRenderContext)
2502
0
{
2503
    // cool#6911 draw the note indicator browser-side instead
2504
0
    if (comphelper::LibreOfficeKit::isActive())
2505
0
        return;
2506
2507
0
    tools::Long nInitPosX = mnScrX;
2508
0
    if ( mbLayoutRTL )
2509
0
        nInitPosX += mnMirrorW - 1;              // always in pixels
2510
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2511
2512
0
    tools::Long nPosY = mnScrY - 1;
2513
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
2514
0
    {
2515
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
2516
0
        if ( pThisRowInfo->bChanged )
2517
0
        {
2518
0
            tools::Long nPosX = nInitPosX;
2519
0
            for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2520
0
            {
2521
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
2522
0
                bool bIsMerged = false;
2523
2524
0
                if ( nX==mnX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2525
0
                {
2526
                    // find start of merged cell
2527
0
                    bIsMerged = true;
2528
0
                    SCROW nY = mpRowInfo[nArrY].nRowNo;
2529
0
                    SCCOL nMergeX = nX;
2530
0
                    SCROW nMergeY = nY;
2531
0
                    mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, mnTab );
2532
0
                }
2533
2534
0
                if (!mpDoc->ColHidden(nX, mnTab) && mpDoc->GetNote(nX, mpRowInfo[nArrY].nRowNo, mnTab)
2535
0
                    && (bIsMerged || (!pInfo->bHOverlapped && !pInfo->bVOverlapped)))
2536
0
                {
2537
0
                    ScModule* mod = ScModule::get();
2538
0
                    rRenderContext.SetLineColor(mod->GetColorConfig().GetColorValue(svtools::CALCGRID).nColor);
2539
2540
0
                    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2541
0
                    if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2542
0
                        rRenderContext.SetFillColor( mod->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2543
0
                    else
2544
0
                        rRenderContext.SetFillColor( mod->GetColorConfig().GetColorValue(svtools::CALCCOMMENTS).nColor );
2545
2546
0
                    tools::Long nMarkX = nPosX + ( mpRowInfo[0].basicCellInfo(nX).nWidth - 1) * nLayoutSign;
2547
0
                    if ( bIsMerged || pInfo->bMerged )
2548
0
                    {
2549
                        //  if merged, add widths of all cells
2550
0
                        SCCOL nNextX = nX + 1;
2551
0
                        while ( nNextX <= mnX2 + 1 && pThisRowInfo->cellInfo(nNextX).bHOverlapped )
2552
0
                        {
2553
0
                            nMarkX += mpRowInfo[0].basicCellInfo(nNextX).nWidth * nLayoutSign;
2554
0
                            ++nNextX;
2555
0
                        }
2556
0
                    }
2557
                    // DPI/ZOOM 100/100 => 6, 100/50 => 4.5, 100/150 => 7.5
2558
                    // DPI/ZOOM 150/100 => 7.5, 150/50 => 6, 150/150 => 9
2559
0
                    sal_Int16 nSize = officecfg::Office::Calc::Content::Display::NoteIndicator::get();
2560
0
                    if (nSize < 1)
2561
0
                    {
2562
0
                       const double fSize(rRenderContext.GetDPIScaleFactor() * mfZoomX * 3 + 3);
2563
0
                       nSize = static_cast<sal_Int16>(fSize);
2564
0
                    }
2565
0
                    Point aPoints[3];
2566
0
                    aPoints[0] = Point(nMarkX, nPosY);
2567
0
                    aPoints[0].setX( mbLayoutRTL ? aPoints[0].X() + nSize : aPoints[0].X() - nSize );
2568
0
                    aPoints[1] = Point(nMarkX, nPosY);
2569
0
                    aPoints[2] = Point(nMarkX, nPosY + nSize);
2570
0
                    tools::Polygon aPoly(3, aPoints);
2571
2572
0
                    if ( mbLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < mnScrX+mnScrW ) )
2573
0
                        rRenderContext.DrawPolygon(aPoly);
2574
0
                }
2575
2576
0
                nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2577
0
            }
2578
0
        }
2579
0
        nPosY += pThisRowInfo->nHeight;
2580
0
    }
2581
0
}
2582
2583
void ScOutputData::DrawFormulaMarks(vcl::RenderContext& rRenderContext)
2584
0
{
2585
0
    bool bFirst = true;
2586
2587
0
    tools::Long nInitPosX = mnScrX;
2588
0
    if ( mbLayoutRTL )
2589
0
        nInitPosX += mnMirrorW - 1;              // always in pixels
2590
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2591
2592
0
    tools::Long nPosY = mnScrY;
2593
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
2594
0
    {
2595
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
2596
0
        if ( pThisRowInfo->bChanged )
2597
0
        {
2598
0
            tools::Long nPosX = nInitPosX;
2599
0
            for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2600
0
            {
2601
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
2602
0
                if (!mpDoc->ColHidden(nX, mnTab) && !mpDoc->GetFormula(nX, mpRowInfo[nArrY].nRowNo, mnTab).isEmpty()
2603
0
                    && (!pInfo->bHOverlapped && !pInfo->bVOverlapped))
2604
0
                {
2605
0
                    if (bFirst)
2606
0
                    {
2607
0
                        rRenderContext.SetLineColor(COL_WHITE);
2608
2609
0
                        const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2610
0
                        if ( mbUseStyleColor && rStyleSettings.GetHighContrastMode() )
2611
0
                            rRenderContext.SetFillColor( ScModule::get()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2612
0
                        else
2613
0
                            rRenderContext.SetFillColor(COL_LIGHTBLUE);
2614
2615
0
                        bFirst = false;
2616
0
                    }
2617
2618
0
                    tools::Long nMarkX = nPosX;
2619
0
                    tools::Long nMarkY = nPosY + pThisRowInfo->nHeight - 2;
2620
0
                    if ( pInfo->bMerged )
2621
0
                    {
2622
0
                        for (SCSIZE nNextY=nArrY+1; nNextY+1<mnArrCount; nNextY++)
2623
0
                        {
2624
0
                            bool bVOver;
2625
0
                            if (mpRowInfo[nNextY + 1].nRowNo == (mpRowInfo[nNextY].nRowNo + 1)) {
2626
0
                                bVOver = mpRowInfo[nNextY].cellInfo(nX).bVOverlapped;
2627
0
                            } else {
2628
0
                                bVOver = mpDoc->GetAttr(nX,nNextY,mnTab,ATTR_MERGE_FLAG).IsVerOverlapped();
2629
0
                            }
2630
0
                            if (!bVOver) break;
2631
0
                            nMarkY += mpRowInfo[nNextY].nHeight;
2632
0
                        }
2633
0
                    }
2634
                    // DPI/ZOOM 100/100 => 10, 100/50 => 7, 100/150 => 13
2635
                    // DPI/ZOOM 150/100 => 13, 150/50 => 8.5, 150/150 => 17.5
2636
0
                    const double nSize( rRenderContext.GetDPIScaleFactor() * mfZoomX * 6 + 4);
2637
0
                    Point aPoints[3];
2638
0
                    aPoints[0] = Point(nMarkX, nMarkY);
2639
0
                    aPoints[0].setX( mbLayoutRTL ? aPoints[0].X() - nSize : aPoints[0].X() + nSize );
2640
0
                    aPoints[1] = Point(nMarkX, nMarkY);
2641
0
                    aPoints[2] = Point(nMarkX, nMarkY - nSize);
2642
0
                    tools::Polygon aPoly(3, aPoints);
2643
2644
0
                    if ( mbLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < mnScrX+mnScrW ) )
2645
0
                        rRenderContext.DrawPolygon(aPoly);
2646
0
                }
2647
2648
0
                nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2649
0
            }
2650
0
        }
2651
0
        nPosY += pThisRowInfo->nHeight;
2652
0
    }
2653
0
}
2654
2655
void ScOutputData::AddPDFNotes()
2656
0
{
2657
0
    vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( mpDev->GetExtOutDevData() );
2658
0
    if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2659
0
        return;
2660
2661
0
    tools::Long nInitPosX = mnScrX;
2662
0
    if ( mbLayoutRTL )
2663
0
    {
2664
0
        Size aOnePixel = mpDev->PixelToLogic(Size(1,1));
2665
0
        tools::Long nOneX = aOnePixel.Width();
2666
0
        nInitPosX += mnMirrorW - nOneX;
2667
0
    }
2668
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2669
2670
0
    tools::Long nPosY = mnScrY;
2671
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
2672
0
    {
2673
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
2674
0
        if ( pThisRowInfo->bChanged )
2675
0
        {
2676
0
            tools::Long nPosX = nInitPosX;
2677
0
            for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2678
0
            {
2679
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
2680
0
                bool bIsMerged = false;
2681
0
                SCROW nY = mpRowInfo[nArrY].nRowNo;
2682
0
                SCCOL nMergeX = nX;
2683
0
                SCROW nMergeY = nY;
2684
2685
0
                if ( nX==mnX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2686
0
                {
2687
                    // find start of merged cell
2688
0
                    bIsMerged = true;
2689
0
                    mpDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, mnTab );
2690
                    // use origin's pCell for NotePtr test below
2691
0
                }
2692
2693
0
                ScPostIt* pNote = mpDoc->GetNote(nMergeX, nMergeY, mnTab);
2694
2695
0
                if ( pNote && ( bIsMerged || ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2696
0
                {
2697
0
                    tools::Long nNoteWidth = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
2698
0
                    tools::Long nNoteHeight = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTY );
2699
2700
0
                    tools::Long nMarkX = nPosX + ( mpRowInfo[0].basicCellInfo(nX).nWidth - nNoteWidth ) * nLayoutSign;
2701
0
                    if ( bIsMerged || pInfo->bMerged )
2702
0
                    {
2703
                        //  if merged, add widths of all cells
2704
0
                        SCCOL nNextX = nX + 1;
2705
0
                        while ( nNextX <= mnX2 + 1 && pThisRowInfo->cellInfo(nNextX).bHOverlapped )
2706
0
                        {
2707
0
                            nMarkX += mpRowInfo[0].basicCellInfo(nNextX).nWidth * nLayoutSign;
2708
0
                            ++nNextX;
2709
0
                        }
2710
0
                    }
2711
0
                    if ( mbLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < mnScrX+mnScrW ) )
2712
0
                    {
2713
0
                        tools::Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2714
2715
0
                        vcl::pdf::PDFNote aNote;
2716
2717
                        // Note title is the cell address (as on printed note pages)
2718
0
                        ScAddress aAddress( nMergeX, nMergeY, mnTab );
2719
0
                        aNote.maTitle = aAddress.Format(ScRefFlags::VALID, mpDoc, mpDoc->GetAddressConvention());
2720
2721
                        // Content has to be a simple string without line breaks
2722
0
                        OUString aContent = pNote->GetText();
2723
0
                        aNote.maContents = aContent.replaceAll("\n", " ");
2724
2725
                        // If the caption is hidden, we need to show it to get its rectangle,
2726
                        // then hide it again because it is also hidden in the file.
2727
0
                        bool bShowCaption = pNote->IsCaptionShown();
2728
0
                        if (!bShowCaption)
2729
0
                            pNote->ShowCaption(aAddress, true);
2730
2731
0
                        SdrCaptionObj* pCaption = pNote->GetCaption();
2732
0
                        tools::Rectangle aCaptionRect(pCaption->GetLogicRect());
2733
0
                        Point aPoint(aCaptionRect.getX() + mnScrX, aCaptionRect.getY() + mnScrY);
2734
0
                        Size aSize(aCaptionRect.GetWidth(), aCaptionRect.GetHeight());
2735
0
                        tools::Rectangle aPopupRect(aPoint, aSize);
2736
2737
0
                        if (!bShowCaption)
2738
0
                            pNote->ShowCaption(aAddress, false);
2739
2740
0
                        pPDFData->CreateNote(aNoteRect, aNote, aPopupRect);
2741
0
                    }
2742
0
                }
2743
2744
0
                nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2745
0
            }
2746
0
        }
2747
0
        nPosY += pThisRowInfo->nHeight;
2748
0
    }
2749
0
}
2750
2751
void ScOutputData::DrawClipMarks()
2752
0
{
2753
0
    if (!mbAnyClipped)
2754
0
        return;
2755
2756
0
    ScModule* mod = ScModule::get();
2757
0
    Color aArrowFillCol(mod->GetColorConfig().GetColorValue(svtools::CALCTEXTOVERFLOW).nColor);
2758
0
    const bool bIsDarkBackground = mod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor.IsDark();
2759
2760
0
    DrawModeFlags nOldDrawMode = mpDev->GetDrawMode();
2761
2762
0
    tools::Long nInitPosX = mnScrX;
2763
0
    if ( mbLayoutRTL )
2764
0
        nInitPosX += mnMirrorW - 1;              // always in pixels
2765
0
    tools::Long nLayoutSign = mbLayoutRTL ? -1 : 1;
2766
2767
0
    tools::Rectangle aCellRect;
2768
0
    tools::Long nPosY = mnScrY;
2769
0
    for (SCSIZE nArrY=1; nArrY+1<mnArrCount; nArrY++)
2770
0
    {
2771
0
        RowInfo* pThisRowInfo = &mpRowInfo[nArrY];
2772
0
        if ( pThisRowInfo->bChanged )
2773
0
        {
2774
0
            SCROW nY = pThisRowInfo->nRowNo;
2775
0
            tools::Long nPosX = nInitPosX;
2776
0
            for (SCCOL nX=mnX1; nX<=mnX2; nX++)
2777
0
            {
2778
0
                ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
2779
0
                if (pInfo->nClipMark != ScClipMark::NONE)
2780
0
                {
2781
0
                    if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2782
0
                    {
2783
                        //  merge origin may be outside of visible area - use document functions
2784
2785
0
                        SCCOL nOverX = nX;
2786
0
                        SCROW nOverY = nY;
2787
0
                        tools::Long nStartPosX = nPosX;
2788
0
                        tools::Long nStartPosY = nPosY;
2789
2790
0
                        while ( nOverX > 0 && ( mpDoc->GetAttr(
2791
0
                                nOverX, nOverY, mnTab, ATTR_MERGE_FLAG ).GetValue() & ScMF::Hor ) )
2792
0
                        {
2793
0
                            --nOverX;
2794
0
                            nStartPosX -= nLayoutSign * static_cast<tools::Long>( mpDoc->GetColWidth(nOverX,mnTab) * mnPPTX );
2795
0
                        }
2796
2797
0
                        while ( nOverY > 0 && ( mpDoc->GetAttr(
2798
0
                                nOverX, nOverY, mnTab, ATTR_MERGE_FLAG ).GetValue() & ScMF::Ver ) )
2799
0
                        {
2800
0
                            --nOverY;
2801
0
                            nStartPosY -= nLayoutSign * static_cast<tools::Long>( mpDoc->GetRowHeight(nOverY,mnTab) * mnPPTY );
2802
0
                        }
2803
2804
0
                        tools::Long nOutWidth = static_cast<tools::Long>( mpDoc->GetColWidth(nOverX,mnTab) * mnPPTX );
2805
0
                        tools::Long nOutHeight = static_cast<tools::Long>( mpDoc->GetRowHeight(nOverY,mnTab) * mnPPTY );
2806
2807
0
                        const ScMergeAttr& rMerge = mpDoc->GetAttr( nOverX, nOverY, mnTab, ATTR_MERGE );
2808
0
                        SCCOL nCountX = rMerge.GetColMerge();
2809
0
                        for (SCCOL i=1; i<nCountX; i++)
2810
0
                            nOutWidth += mpDoc->GetColWidth(nOverX+i,mnTab) * mnPPTX;
2811
0
                        SCROW nCountY = rMerge.GetRowMerge();
2812
0
                        nOutHeight += mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, mnTab, mnPPTY);
2813
2814
0
                        if ( mbLayoutRTL )
2815
0
                            nStartPosX -= nOutWidth - 1;
2816
0
                        aCellRect = tools::Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2817
0
                    }
2818
0
                    else
2819
0
                    {
2820
0
                        tools::Long nOutWidth = mpRowInfo[0].basicCellInfo(nX).nWidth;
2821
0
                        tools::Long nOutHeight = pThisRowInfo->nHeight;
2822
2823
0
                        if ( pInfo->bMerged && pInfo->pPatternAttr )
2824
0
                        {
2825
0
                            SCCOL nOverX = nX;
2826
0
                            SCROW nOverY = nY;
2827
0
                            const ScMergeAttr* pMerge =
2828
0
                                    &pInfo->getPatternAttr()->GetItem(ATTR_MERGE);
2829
0
                            SCCOL nCountX = pMerge->GetColMerge();
2830
0
                            for (SCCOL i=1; i<nCountX; i++)
2831
0
                                nOutWidth += mpDoc->GetColWidth(nOverX+i,mnTab) * mnPPTX;
2832
0
                            SCROW nCountY = pMerge->GetRowMerge();
2833
0
                            nOutHeight += mpDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, mnTab, mnPPTY);
2834
0
                        }
2835
2836
0
                        tools::Long nStartPosX = nPosX;
2837
0
                        if ( mbLayoutRTL )
2838
0
                            nStartPosX -= nOutWidth - 1;
2839
                        // #i80447# create aCellRect from two points in case nOutWidth is 0
2840
0
                        aCellRect = tools::Rectangle( Point( nStartPosX, nPosY ),
2841
0
                                               Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2842
0
                    }
2843
2844
0
                    aCellRect.AdjustBottom( -1 );    // don't paint over the cell grid
2845
0
                    if ( mbLayoutRTL )
2846
0
                        aCellRect.AdjustLeft(1 );
2847
0
                    else
2848
0
                        aCellRect.AdjustRight( -1 );
2849
2850
0
                    tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
2851
0
                    Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2852
2853
0
                    const Color aColor = pInfo->maBackground ?
2854
0
                        static_cast<const SvxBrushItem*>(pInfo->maBackground.getItem())->GetColor() :
2855
0
                        COL_AUTO;
2856
0
                    if ( aColor == COL_AUTO ? bIsDarkBackground : aColor.IsDark() )
2857
0
                        mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::WhiteLine );
2858
0
                    else
2859
0
                        mpDev->SetDrawMode( nOldDrawMode | DrawModeFlags::BlackLine );
2860
2861
0
                    if (mbVertical)
2862
0
                    {
2863
0
                        if (pInfo->nClipMark & (mbLayoutRTL ? ScClipMark::Bottom : ScClipMark::Top))
2864
0
                        {
2865
                            //  visually top
2866
0
                            tools::Rectangle aMarkRect = aCellRect;
2867
0
                            aMarkRect.SetBottom(aCellRect.Top() + nMarkPixel - 1);
2868
0
                            SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true, true);
2869
0
                        }
2870
0
                        if (pInfo->nClipMark & (mbLayoutRTL ? ScClipMark::Top : ScClipMark::Bottom))
2871
0
                        {
2872
                            //  visually bottom
2873
0
                            tools::Rectangle aMarkRect = aCellRect;
2874
0
                            aMarkRect.SetTop(aCellRect.Bottom() + nMarkPixel + 1);
2875
0
                            SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
2876
0
                                true);
2877
0
                        }
2878
0
                    }
2879
0
                    else
2880
0
                    {
2881
0
                        if (pInfo->nClipMark & (mbLayoutRTL ? ScClipMark::Right : ScClipMark::Left))
2882
0
                        {
2883
                            //  visually left
2884
0
                            tools::Rectangle aMarkRect = aCellRect;
2885
0
                            aMarkRect.SetRight(aCellRect.Left() + nMarkPixel - 1);
2886
0
                            SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, true,
2887
0
                                false);
2888
0
                        }
2889
0
                        if (pInfo->nClipMark & (mbLayoutRTL ? ScClipMark::Left : ScClipMark::Right))
2890
0
                        {
2891
                            //  visually right
2892
0
                            tools::Rectangle aMarkRect = aCellRect;
2893
0
                            aMarkRect.SetLeft(aCellRect.Right() - nMarkPixel + 1);
2894
0
                            SvxFont::DrawArrow(*mpDev, aMarkRect, aMarkSize, aArrowFillCol, false,
2895
0
                                false);
2896
0
                        }
2897
0
                    }
2898
0
                }
2899
0
                nPosX += mpRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2900
0
            }
2901
0
        }
2902
0
        nPosY += pThisRowInfo->nHeight;
2903
0
    }
2904
2905
0
    mpDev->SetDrawMode(nOldDrawMode);
2906
0
}
2907
2908
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */