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