Coverage Report

Created: 2025-12-08 09:28

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