xref: /AOO41X/main/sc/source/ui/view/output.cxx (revision 24c56ab9f1bd1305754aa2f564704f38ff57627e)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26 
27 // INCLUDE ---------------------------------------------------------------
28 
29 #include <com/sun/star/embed/EmbedMisc.hpp>
30 
31 #include "scitems.hxx"
32 #include <editeng/boxitem.hxx>
33 #include <editeng/brshitem.hxx>
34 #include <editeng/editdata.hxx>
35 #include <svtools/colorcfg.hxx>
36 #include <svx/rotmodit.hxx>
37 #include <editeng/shaditem.hxx>
38 #include <editeng/svxfont.hxx>
39 #include <svx/svdoole2.hxx>
40 #include <tools/poly.hxx>
41 #include <vcl/svapp.hxx>
42 #include <vcl/pdfextoutdevdata.hxx>
43 #include <svtools/accessibilityoptions.hxx>
44 #include <svx/framelinkarray.hxx>
45 
46 #include "output.hxx"
47 #include "document.hxx"
48 #include "cell.hxx"
49 #include "attrib.hxx"
50 #include "patattr.hxx"
51 #include "docpool.hxx"
52 #include "tabvwsh.hxx"
53 #include "progress.hxx"
54 #include "pagedata.hxx"
55 #include "chgtrack.hxx"
56 #include "chgviset.hxx"
57 #include "viewutil.hxx"
58 #include "gridmerg.hxx"
59 #include "invmerge.hxx"
60 #include "fillinfo.hxx"
61 #include "scmod.hxx"
62 #include "appoptio.hxx"
63 #include "postit.hxx"
64 
65 #include <math.h>
66 
67 using namespace com::sun::star;
68 
69 // STATIC DATA -----------------------------------------------------------
70 
71 //  Farben fuer ChangeTracking "nach Autor" wie im Writer (swmodul1.cxx)
72 
73 #define SC_AUTHORCOLORCOUNT     9
74 
75 static ColorData nAuthorColor[ SC_AUTHORCOLORCOUNT ] = {
76                     COL_LIGHTRED,       COL_LIGHTBLUE,      COL_LIGHTMAGENTA,
77                     COL_GREEN,          COL_RED,            COL_BLUE,
78                     COL_BROWN,          COL_MAGENTA,        COL_CYAN };
79 
80 //  Hilfsklasse, fuer die Farbzuordnung,
81 //  um nicht mehrfach hintereinander denselben User aus der Liste zu suchen
82 
83 //Move this class declare to Chgtrack.hxx
84 /*
85 class ScActionColorChanger
86 {
87 private:
88     const ScAppOptions&     rOpt;
89     const ScStrCollection&  rUsers;
90     String                  aLastUserName;
91     sal_uInt16                  nLastUserIndex;
92     ColorData               nColor;
93 
94 public:
95                 ScActionColorChanger( const ScChangeTrack& rTrack );
96                 ~ScActionColorChanger() {}
97 
98     void        Update( const ScChangeAction& rAction );
99     ColorData   GetColor() const    { return nColor; }
100 };
101 */
102 
103 //------------------------------------------------------------------
104 
105 ScActionColorChanger::ScActionColorChanger( const ScChangeTrack& rTrack ) :
106     rOpt( SC_MOD()->GetAppOptions() ),
107     rUsers( rTrack.GetUserCollection() ),
108     nLastUserIndex( 0 ),
109     nColor( COL_BLACK )
110 {
111 }
112 
113 void ScActionColorChanger::Update( const ScChangeAction& rAction )
114 {
115     ColorData nSetColor;
116     switch (rAction.GetType())
117     {
118         case SC_CAT_INSERT_COLS:
119         case SC_CAT_INSERT_ROWS:
120         case SC_CAT_INSERT_TABS:
121             nSetColor = rOpt.GetTrackInsertColor();
122             break;
123         case SC_CAT_DELETE_COLS:
124         case SC_CAT_DELETE_ROWS:
125         case SC_CAT_DELETE_TABS:
126             nSetColor = rOpt.GetTrackDeleteColor();
127             break;
128         case SC_CAT_MOVE:
129             nSetColor = rOpt.GetTrackMoveColor();
130             break;
131         default:
132             nSetColor = rOpt.GetTrackContentColor();
133             break;
134     }
135     if ( nSetColor != COL_TRANSPARENT )     // Farbe eingestellt
136         nColor = nSetColor;
137     else                                    // nach Autor
138     {
139         if ( rAction.GetUser() != aLastUserName )
140         {
141             aLastUserName = rAction.GetUser();
142             StrData aData(aLastUserName);
143             sal_uInt16 nIndex;
144             if (!rUsers.Search(&aData, nIndex))
145             {
146                 // empty string is possible if a name wasn't found while saving a 5.0 file
147                 DBG_ASSERT( aLastUserName.Len() == 0, "Author not found" );
148                 nIndex = 0;
149             }
150             nLastUserIndex = nIndex % SC_AUTHORCOLORCOUNT;
151         }
152         nColor = nAuthorColor[nLastUserIndex];
153     }
154 }
155 
156 //==================================================================
157 
158 ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
159                             ScTableInfo& rTabInfo, ScDocument* pNewDoc,
160                             SCTAB nNewTab, long nNewScrX, long nNewScrY,
161                             SCCOL nNewX1, SCROW nNewY1, SCCOL nNewX2, SCROW nNewY2,
162                             double nPixelPerTwipsX, double nPixelPerTwipsY,
163                             const Fraction* pZoomX, const Fraction* pZoomY ) :
164     pDev( pNewDev ),
165     pRefDevice( pNewDev ),      // default is output device
166     pFmtDevice( pNewDev ),      // default is output device
167     mrTabInfo( rTabInfo ),
168     pRowInfo( rTabInfo.mpRowInfo ),
169     nArrCount( rTabInfo.mnArrCount ),
170     pDoc( pNewDoc ),
171     nTab( nNewTab ),
172     nScrX( nNewScrX ),
173     nScrY( nNewScrY ),
174     nX1( nNewX1 ),
175     nY1( nNewY1 ),
176     nX2( nNewX2 ),
177     nY2( nNewY2 ),
178     eType( eNewType ),
179     nPPTX( nPixelPerTwipsX ),
180     nPPTY( nPixelPerTwipsY ),
181     pEditObj( NULL ),
182     pViewShell( NULL ),
183     pDrawView( NULL ), // #114135#
184     bEditMode( sal_False ),
185     bMetaFile( sal_False ),
186     bSingleGrid( sal_False ),
187     bPagebreakMode( sal_False ),
188     bSolidBackground( sal_False ),
189     bUseStyleColor( sal_False ),
190     bForceAutoColor( SC_MOD()->GetAccessOptions().GetIsAutomaticFontColor() ),
191     bSyntaxMode( sal_False ),
192     pValueColor( NULL ),
193     pTextColor( NULL ),
194     pFormulaColor( NULL ),
195     aGridColor( COL_BLACK ),
196     bShowNullValues( sal_True ),
197     bShowFormulas( sal_False ),
198     bShowSpellErrors( sal_False ),
199     bMarkClipped( sal_False ),          // sal_False fuer Drucker/Metafile etc.
200     bSnapPixel( sal_False ),
201     bAnyRotated( sal_False ),
202     bAnyClipped( sal_False ),
203     mpTargetPaintWindow(0) // #i74769# use SdrPaintWindow direct
204 {
205     if (pZoomX)
206         aZoomX = *pZoomX;
207     else
208         aZoomX = Fraction(1,1);
209     if (pZoomY)
210         aZoomY = *pZoomY;
211     else
212         aZoomY = Fraction(1,1);
213 
214     nVisX1 = nX1;
215     nVisY1 = nY1;
216     nVisX2 = nX2;
217     nVisY2 = nY2;
218     pDoc->StripHidden( nVisX1, nVisY1, nVisX2, nVisY2, nTab );
219 
220     nScrW = 0;
221     for (SCCOL nX=nVisX1; nX<=nVisX2; nX++)
222         nScrW += pRowInfo[0].pCellInfo[nX+1].nWidth;
223 
224     nMirrorW = nScrW;
225 
226     nScrH = 0;
227     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
228         nScrH += pRowInfo[nArrY].nHeight;
229 
230     bTabProtected = pDoc->IsTabProtected( nTab );
231     nTabTextDirection = pDoc->GetEditTextDirection( nTab );
232     bLayoutRTL = pDoc->IsLayoutRTL( nTab );
233 }
234 
235 ScOutputData::~ScOutputData()
236 {
237     delete pValueColor;
238     delete pTextColor;
239     delete pFormulaColor;
240 }
241 
242 void ScOutputData::SetContentDevice( OutputDevice* pContentDev )
243 {
244     // use pContentDev instead of pDev where used
245 
246     if ( pRefDevice == pDev )
247         pRefDevice = pContentDev;
248     if ( pFmtDevice == pDev )
249         pFmtDevice = pContentDev;
250     pDev = pContentDev;
251 }
252 
253 void ScOutputData::SetMirrorWidth( long nNew )
254 {
255     nMirrorW = nNew;
256 }
257 
258 void ScOutputData::SetGridColor( const Color& rColor )
259 {
260     aGridColor = rColor;
261 }
262 
263 void ScOutputData::SetMarkClipped( sal_Bool bSet )
264 {
265     bMarkClipped = bSet;
266 }
267 
268 void ScOutputData::SetShowNullValues( sal_Bool bSet )
269 {
270     bShowNullValues = bSet;
271 }
272 
273 void ScOutputData::SetShowFormulas( sal_Bool bSet )
274 {
275     bShowFormulas = bSet;
276 }
277 
278 void ScOutputData::SetShowSpellErrors( sal_Bool bSet )
279 {
280     bShowSpellErrors = bSet;
281 }
282 
283 void ScOutputData::SetSnapPixel( sal_Bool bSet )
284 {
285     bSnapPixel = bSet;
286 }
287 
288 void ScOutputData::SetEditCell( SCCOL nCol, SCROW nRow )
289 {
290     nEditCol = nCol;
291     nEditRow = nRow;
292     bEditMode = sal_True;
293 }
294 
295 void ScOutputData::SetMetaFileMode( sal_Bool bNewMode )
296 {
297     bMetaFile = bNewMode;
298 }
299 
300 void ScOutputData::SetSingleGrid( sal_Bool bNewMode )
301 {
302     bSingleGrid = bNewMode;
303 }
304 
305 void ScOutputData::SetSyntaxMode( sal_Bool bNewMode )
306 {
307     bSyntaxMode = bNewMode;
308     if (bNewMode)
309         if (!pValueColor)
310         {
311             pValueColor = new Color( COL_LIGHTBLUE );
312             pTextColor = new Color( COL_BLACK );
313             pFormulaColor = new Color( COL_GREEN );
314         }
315 }
316 
317 void ScOutputData::DrawGrid( sal_Bool bGrid, sal_Bool bPage )
318 {
319     SCCOL nX;
320     SCROW nY;
321     long nPosX;
322     long nPosY;
323     SCSIZE nArrY;
324     ScBreakType nBreak    = BREAK_NONE;
325     ScBreakType nBreakOld = BREAK_NONE;
326 
327     sal_Bool bSingle;
328     Color aPageColor;
329     Color aManualColor;
330 
331     if (bPagebreakMode)
332         bPage = sal_False;          // keine "normalen" Umbrueche ueber volle Breite/Hoehe
333 
334     //! um den einen Pixel sieht das Metafile (oder die Druck-Ausgabe) anders aus
335     //! als die Bildschirmdarstellung, aber wenigstens passen Druck und Metafile zusammen
336 
337     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
338     long nOneX = aOnePixel.Width();
339     long nOneY = aOnePixel.Height();
340     if (bMetaFile)
341         nOneX = nOneY = 1;
342 
343     long nLayoutSign = bLayoutRTL ? -1 : 1;
344     long nSignedOneX = nOneX * nLayoutSign;
345 
346     if ( eType == OUTTYPE_WINDOW )
347     {
348         const svtools::ColorConfig& rColorCfg = SC_MOD()->GetColorConfig();
349         aPageColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKAUTOMATIC).nColor );
350         aManualColor.SetColor( rColorCfg.GetColorValue(svtools::CALCPAGEBREAKMANUAL).nColor );
351     }
352     else
353     {
354         aPageColor = aGridColor;
355         aManualColor = aGridColor;
356     }
357 
358     pDev->SetLineColor( aGridColor );
359     ScGridMerger aGrid( pDev, nOneX, nOneY );
360 
361                                         //
362                                         //  Vertikale Linien
363                                         //
364 
365     nPosX = nScrX;
366     if ( bLayoutRTL )
367         nPosX += nMirrorW - nOneX;
368 
369     for (nX=nX1; nX<=nX2; nX++)
370     {
371         SCCOL nXplus1 = nX+1;
372         SCCOL nXplus2 = nX+2;
373         sal_uInt16 nWidth = pRowInfo[0].pCellInfo[nXplus1].nWidth;
374         if (nWidth)
375         {
376             nPosX += nWidth * nLayoutSign;
377 
378             if ( bPage )
379             {
380                 //  Seitenumbrueche auch in ausgeblendeten suchen
381                 SCCOL nCol = nXplus1;
382                 while (nCol <= MAXCOL)
383                 {
384                     nBreak = pDoc->HasColBreak(nCol, nTab);
385                     bool bHidden = pDoc->ColHidden(nCol, nTab);
386 
387                     if ( nBreak || !bHidden )
388                         break;
389                     ++nCol;
390                 }
391 
392                 if (nBreak != nBreakOld)
393                 {
394                     aGrid.Flush();
395                     pDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
396                                         nBreak ? aPageColor : aGridColor );
397                     nBreakOld = nBreak;
398                 }
399             }
400 
401             sal_Bool bDraw = bGrid || nBreakOld;    // einfaches Gitter nur wenn eingestellt
402 
403             //! Mit dieser Abfrage wird zuviel weggelassen, wenn ein automatischer
404             //! Umbruch mitten in den Wiederholungsspalten liegt.
405             //! Dann lieber den aeusseren Rahmen zweimal ausgeben...
406 #if 0
407             //  auf dem Drucker die Aussen-Linien weglassen (werden getrennt ausgegeben)
408             if ( eType == OUTTYPE_PRINTER && !bMetaFile )
409             {
410                 if ( nX == MAXCOL )
411                     bDraw = sal_False;
412                 else if (pDoc->HasColBreak(nXplus1, nTab))
413                     bDraw = sal_False;
414             }
415 #endif
416 
417             sal_uInt16 nWidthXplus2 = pRowInfo[0].pCellInfo[nXplus2].nWidth;
418             bSingle = bSingleGrid;                                  //! in Fillinfo holen !!!!!
419             if ( nX<MAXCOL && !bSingle )
420             {
421                 bSingle = ( nWidthXplus2 == 0 );
422                 for (nArrY=1; nArrY+1<nArrCount && !bSingle; nArrY++)
423                 {
424                     if (pRowInfo[nArrY].pCellInfo[nXplus2].bHOverlapped)
425                         bSingle = sal_True;
426                     if (pRowInfo[nArrY].pCellInfo[nXplus1].bHideGrid)
427                         bSingle = sal_True;
428                 }
429             }
430 
431             if (bDraw)
432             {
433                 if ( nX<MAXCOL && bSingle )
434                 {
435                     SCCOL nVisX = nXplus1;
436                     while ( nVisX < MAXCOL && !pDoc->GetColWidth(nVisX,nTab) )
437                         ++nVisX;
438 
439                     nPosY = nScrY;
440                     long nNextY;
441                     for (nArrY=1; nArrY+1<nArrCount; nArrY++)
442                     {
443                         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
444                         nNextY = nPosY + pThisRowInfo->nHeight;
445 
446                         sal_Bool bHOver = pThisRowInfo->pCellInfo[nXplus1].bHideGrid;
447                         if (!bHOver)
448                         {
449                             if (nWidthXplus2)
450                                 bHOver = pThisRowInfo->pCellInfo[nXplus2].bHOverlapped;
451                             else
452                             {
453                                 if (nVisX <= nX2)
454                                     bHOver = pThisRowInfo->pCellInfo[nVisX+1].bHOverlapped;
455                                 else
456                                     bHOver = ((ScMergeFlagAttr*)pDoc->GetAttr(
457                                                 nVisX,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
458                                                 ->IsHorOverlapped();
459                                 if (bHOver)
460                                     bHOver = ((ScMergeFlagAttr*)pDoc->GetAttr(
461                                                 nXplus1,pThisRowInfo->nRowNo,nTab,ATTR_MERGE_FLAG))
462                                                 ->IsHorOverlapped();
463                             }
464                         }
465 
466                         if (pThisRowInfo->bChanged && !bHOver)
467                         {
468                             //Point aStart( nPosX-nSignedOneX, nPosY );
469                             //Point aEnd( nPosX-nSignedOneX, nNextY-nOneY );
470                             //pDev->DrawLine( aStart, aEnd );
471                             aGrid.AddVerLine( nPosX-nSignedOneX, nPosY, nNextY-nOneY );
472                         }
473                         nPosY = nNextY;
474                     }
475                 }
476                 else
477                 {
478                     //Point aStart( nPosX-nSignedOneX, nScrY );
479                     //Point aEnd( nPosX-nSignedOneX, nScrY+nScrH-nOneY );
480                     //pDev->DrawLine( aStart, aEnd );
481                     aGrid.AddVerLine( nPosX-nSignedOneX, nScrY, nScrY+nScrH-nOneY );
482                 }
483             }
484         }
485     }
486 
487                                         //
488                                         //  Horizontale Linien
489                                         //
490 
491     bool bHiddenRow = true;
492     SCROW nHiddenEndRow = -1;
493     nPosY = nScrY;
494     for (nArrY=1; nArrY+1<nArrCount; nArrY++)
495     {
496         SCSIZE nArrYplus1 = nArrY+1;
497         nY = pRowInfo[nArrY].nRowNo;
498         SCROW nYplus1 = nY+1;
499         nPosY += pRowInfo[nArrY].nHeight;
500 
501         if (pRowInfo[nArrY].bChanged)
502         {
503             if ( bPage )
504             {
505                 for (SCROW i = nYplus1; i <= MAXROW; ++i)
506                 {
507                     if (i > nHiddenEndRow)
508                         bHiddenRow = pDoc->RowHidden(i, nTab, nHiddenEndRow);
509                     /* TODO: optimize the row break thing for large hidden
510                      * segments where HasRowBreak() has to be called
511                      * nevertheless for each row, as a row break is drawn also
512                      * for hidden rows, above them. This needed to be done only
513                      * once per hidden segment, maybe giving manual breaks
514                      * priority. Something like GetNextRowBreak() and
515                      * GetNextManualRowBreak(). */
516                     nBreak = pDoc->HasRowBreak(i, nTab);
517                     if (!bHiddenRow || nBreak)
518                         break;
519                 }
520 
521                 if (nBreakOld != nBreak)
522                 {
523                     aGrid.Flush();
524                     pDev->SetLineColor( (nBreak & BREAK_MANUAL) ? aManualColor :
525                                         (nBreak) ? aPageColor : aGridColor );
526                     nBreakOld = nBreak;
527                 }
528             }
529 
530             sal_Bool bDraw = bGrid || nBreakOld;    // einfaches Gitter nur wenn eingestellt
531 
532             //! Mit dieser Abfrage wird zuviel weggelassen, wenn ein automatischer
533             //! Umbruch mitten in den Wiederholungszeilen liegt.
534             //! Dann lieber den aeusseren Rahmen zweimal ausgeben...
535 #if 0
536             //  auf dem Drucker die Aussen-Linien weglassen (werden getrennt ausgegeben)
537             if ( eType == OUTTYPE_PRINTER && !bMetaFile )
538             {
539                 if ( nY == MAXROW )
540                     bDraw = sal_False;
541                 else if (pDoc->HasRowBreak(nYplus1, nTab))
542                     bDraw = sal_False;
543             }
544 #endif
545 
546             sal_Bool bNextYisNextRow = (pRowInfo[nArrYplus1].nRowNo == nYplus1);
547             bSingle = !bNextYisNextRow;             // Hidden
548             for (SCCOL i=nX1; i<=nX2 && !bSingle; i++)
549             {
550                 if (pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped)
551                     bSingle = sal_True;
552             }
553 
554             if (bDraw)
555             {
556                 if ( bSingle && nY<MAXROW )
557                 {
558                     SCROW nVisY = pRowInfo[nArrYplus1].nRowNo;
559 
560                     nPosX = nScrX;
561                     if ( bLayoutRTL )
562                         nPosX += nMirrorW - nOneX;
563 
564                     long nNextX;
565                     for (SCCOL i=nX1; i<=nX2; i++)
566                     {
567                         nNextX = nPosX + pRowInfo[0].pCellInfo[i+1].nWidth * nLayoutSign;
568                         if (nNextX != nPosX)                                // sichtbar
569                         {
570                             sal_Bool bVOver;
571                             if ( bNextYisNextRow )
572                                 bVOver = pRowInfo[nArrYplus1].pCellInfo[i+1].bVOverlapped;
573                             else
574                             {
575                                 bVOver = ((ScMergeFlagAttr*)pDoc->GetAttr(
576                                             i,nYplus1,nTab,ATTR_MERGE_FLAG))
577                                             ->IsVerOverlapped()
578                                     &&   ((ScMergeFlagAttr*)pDoc->GetAttr(
579                                             i,nVisY,nTab,ATTR_MERGE_FLAG))
580                                             ->IsVerOverlapped();
581                                     //! nVisY aus Array ??
582                             }
583                             if (!bVOver)
584                             {
585                                 //Point aStart( nPosX, nPosY-nOneY );
586                                 //Point aEnd( nNextX-nSignedOneX, nPosY-nOneY );
587                                 //pDev->DrawLine( aStart, aEnd );
588                                 aGrid.AddHorLine( nPosX, nNextX-nSignedOneX, nPosY-nOneY );
589                             }
590                         }
591                         nPosX = nNextX;
592                     }
593                 }
594                 else
595                 {
596                     //Point aStart( nScrX, nPosY-nOneY );
597                     //Point aEnd( nScrX+nScrW-nOneX, nPosY-nOneY );
598                     //pDev->DrawLine( aStart, aEnd );
599                     aGrid.AddHorLine( nScrX, nScrX+nScrW-nOneX, nPosY-nOneY );
600                 }
601             }
602         }
603     }
604 }
605 
606 //  ----------------------------------------------------------------------------
607 
608 void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
609 {
610     bPagebreakMode = sal_True;
611     if (!pPageData)
612         return;                     // noch nicht initialisiert -> alles "nicht gedruckt"
613 
614     //  gedruckten Bereich markieren
615     //  (in FillInfo ist schon alles auf sal_False initialisiert)
616 
617     sal_uInt16 nRangeCount = sal::static_int_cast<sal_uInt16>(pPageData->GetCount());
618     for (sal_uInt16 nPos=0; nPos<nRangeCount; nPos++)
619     {
620         ScRange aRange = pPageData->GetData( nPos ).GetPrintRange();
621 
622         SCCOL nStartX = Max( aRange.aStart.Col(), nX1 );
623         SCCOL nEndX   = Min( aRange.aEnd.Col(),   nX2 );
624         SCROW nStartY = Max( aRange.aStart.Row(), nY1 );
625         SCROW nEndY   = Min( aRange.aEnd.Row(),   nY2 );
626 
627         for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
628         {
629             RowInfo* pThisRowInfo = &pRowInfo[nArrY];
630             if ( pThisRowInfo->bChanged && pThisRowInfo->nRowNo >= nStartY &&
631                                            pThisRowInfo->nRowNo <= nEndY )
632             {
633                 for (SCCOL nX=nStartX; nX<=nEndX; nX++)
634                     pThisRowInfo->pCellInfo[nX+1].bPrinted = sal_True;
635             }
636         }
637     }
638 }
639 
640 void ScOutputData::FindRotated()
641 {
642     //! nRotMax speichern
643     SCCOL nRotMax = nX2;
644     for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
645         if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
646             nRotMax = pRowInfo[nRotY].nRotMaxCol;
647 
648     for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
649     {
650         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
651         if ( pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE &&
652              ( pThisRowInfo->bChanged || pRowInfo[nArrY-1].bChanged ||
653                ( nArrY+1<nArrCount && pRowInfo[nArrY+1].bChanged ) ) )
654         {
655             SCROW nY = pThisRowInfo->nRowNo;
656 
657             for (SCCOL nX=0; nX<=nRotMax; nX++)
658             {
659                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
660                 const ScPatternAttr* pPattern = pInfo->pPatternAttr;
661                 const SfxItemSet* pCondSet = pInfo->pConditionSet;
662 
663                 if ( !pPattern && !pDoc->ColHidden(nX, nTab) )
664                 {
665                     pPattern = pDoc->GetPattern( nX, nY, nTab );
666                     pCondSet = pDoc->GetCondResult( nX, nY, nTab );
667                 }
668 
669                 if ( pPattern )     // Spalte nicht ausgeblendet
670                 {
671                     sal_uInt8 nDir = pPattern->GetRotateDir( pCondSet );
672                     if (nDir != SC_ROTDIR_NONE)
673                     {
674                         pInfo->nRotateDir = nDir;
675                         bAnyRotated = sal_True;
676                     }
677                 }
678             }
679         }
680     }
681 }
682 
683 //  ----------------------------------------------------------------------------
684 
685 sal_uInt16 lcl_GetRotateDir( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
686 {
687     const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
688     const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
689 
690     sal_uInt16 nRet = SC_ROTDIR_NONE;
691 
692     long nAttrRotate = pPattern->GetRotateVal( pCondSet );
693     if ( nAttrRotate )
694     {
695         SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
696                     pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
697 
698         if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
699             nRet = SC_ROTDIR_STANDARD;
700         else if ( eRotMode == SVX_ROTATE_MODE_CENTER )
701             nRet = SC_ROTDIR_CENTER;
702         else if ( eRotMode == SVX_ROTATE_MODE_TOP || eRotMode == SVX_ROTATE_MODE_BOTTOM )
703         {
704             long nRot180 = nAttrRotate % 18000;     // 1/100 Grad
705             if ( nRot180 == 9000 )
706                 nRet = SC_ROTDIR_CENTER;
707             else if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nRot180 < 9000 ) ||
708                       ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nRot180 > 9000 ) )
709                 nRet = SC_ROTDIR_LEFT;
710             else
711                 nRet = SC_ROTDIR_RIGHT;
712         }
713     }
714 
715     return nRet;
716 }
717 
718 const SvxBrushItem* lcl_FindBackground( ScDocument* pDoc, SCCOL nCol, SCROW nRow, SCTAB nTab )
719 {
720     const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
721     const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
722     const SvxBrushItem* pBackground = (const SvxBrushItem*)
723                             &pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
724 
725     sal_uInt16 nDir = lcl_GetRotateDir( pDoc, nCol, nRow, nTab );
726 
727     //  CENTER wird wie RIGHT behandelt...
728     if ( nDir == SC_ROTDIR_RIGHT || nDir == SC_ROTDIR_CENTER )
729     {
730         //  Text geht nach rechts -> Hintergrund von links nehmen
731         while ( nCol > 0 && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
732                             pBackground->GetColor().GetTransparency() != 255 )
733         {
734             --nCol;
735             pPattern = pDoc->GetPattern( nCol, nRow, nTab );
736             pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
737             pBackground = (const SvxBrushItem*)&pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
738         }
739     }
740     else if ( nDir == SC_ROTDIR_LEFT )
741     {
742         //  Text geht nach links -> Hintergrund von rechts nehmen
743         while ( nCol < MAXCOL && lcl_GetRotateDir( pDoc, nCol, nRow, nTab ) == nDir &&
744                             pBackground->GetColor().GetTransparency() != 255 )
745         {
746             ++nCol;
747             pPattern = pDoc->GetPattern( nCol, nRow, nTab );
748             pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
749             pBackground = (const SvxBrushItem*)&pPattern->GetItem( ATTR_BACKGROUND, pCondSet );
750         }
751     }
752 
753     return pBackground;
754 }
755 
756 //  ----------------------------------------------------------------------------
757 
758 sal_Bool lcl_EqualBack( const RowInfo& rFirst, const RowInfo& rOther,
759                     SCCOL nX1, SCCOL nX2, sal_Bool bShowProt, sal_Bool bPagebreakMode )
760 {
761     if ( rFirst.bChanged   != rOther.bChanged ||
762          rFirst.bEmptyBack != rOther.bEmptyBack )
763         return sal_False;
764 
765     SCCOL nX;
766     if ( bShowProt )
767     {
768         for ( nX=nX1; nX<=nX2; nX++ )
769         {
770             const ScPatternAttr* pPat1 = rFirst.pCellInfo[nX+1].pPatternAttr;
771             const ScPatternAttr* pPat2 = rOther.pCellInfo[nX+1].pPatternAttr;
772             if ( !pPat1 || !pPat2 ||
773                     &pPat1->GetItem(ATTR_PROTECTION) != &pPat2->GetItem(ATTR_PROTECTION) )
774                 return sal_False;
775         }
776     }
777     else
778     {
779         for ( nX=nX1; nX<=nX2; nX++ )
780             if ( rFirst.pCellInfo[nX+1].pBackground != rOther.pCellInfo[nX+1].pBackground )
781                 return sal_False;
782     }
783 
784     if ( rFirst.nRotMaxCol != SC_ROTMAX_NONE || rOther.nRotMaxCol != SC_ROTMAX_NONE )
785         for ( nX=nX1; nX<=nX2; nX++ )
786             if ( rFirst.pCellInfo[nX+1].nRotateDir != rOther.pCellInfo[nX+1].nRotateDir )
787                 return sal_False;
788 
789     if ( bPagebreakMode )
790         for ( nX=nX1; nX<=nX2; nX++ )
791             if ( rFirst.pCellInfo[nX+1].bPrinted != rOther.pCellInfo[nX+1].bPrinted )
792                 return sal_False;
793 
794     return sal_True;
795 }
796 
797 void ScOutputData::DrawBackground()
798 {
799     FindRotated();              //! von aussen ?
800 
801     ScModule* pScMod = SC_MOD();
802 
803     // used only if bSolidBackground is set (only for ScGridWindow):
804     Color aBgColor( pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
805 
806     Rectangle aRect;
807     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
808     long nOneX = aOnePixel.Width();
809     long nOneY = aOnePixel.Height();
810 
811     if (bMetaFile)
812         nOneX = nOneY = 0;
813 
814     long nLayoutSign = bLayoutRTL ? -1 : 1;
815     long nSignedOneX = nOneX * nLayoutSign;
816 
817     pDev->SetLineColor();
818 
819     sal_Bool bShowProt = bSyntaxMode && pDoc->IsTabProtected(nTab);
820     sal_Bool bDoAll = bShowProt || bPagebreakMode || bSolidBackground;
821 
822     //  #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
823     sal_Bool bCellContrast = bUseStyleColor &&
824             Application::GetSettings().GetStyleSettings().GetHighContrastMode();
825 
826     long nPosY = nScrY;
827     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
828     {
829         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
830         long nRowHeight = pThisRowInfo->nHeight;
831 
832         if ( pThisRowInfo->bChanged )
833         {
834             if ( ( ( pThisRowInfo->bEmptyBack ) || bSyntaxMode ) && !bDoAll )
835             {
836                 //  nichts
837             }
838             else
839             {
840                 // scan for rows with the same background:
841                 SCSIZE nSkip = 0;
842                 while ( nArrY+nSkip+2<nArrCount &&
843                         lcl_EqualBack( *pThisRowInfo, pRowInfo[nArrY+nSkip+1],
844                                         nX1, nX2, bShowProt, bPagebreakMode ) )
845                 {
846                     ++nSkip;
847                     nRowHeight += pRowInfo[nArrY+nSkip].nHeight;    // after incrementing
848                 }
849 
850                 long nPosX = nScrX;
851                 if ( bLayoutRTL )
852                     nPosX += nMirrorW - nOneX;
853                 aRect = Rectangle( nPosX,nPosY, nPosX,nPosY+nRowHeight-nOneY );
854 
855                 const SvxBrushItem* pOldBackground = NULL;
856                 const SvxBrushItem* pBackground;
857                 for (SCCOL nX=nX1; nX<=nX2; nX++)
858                 {
859                     CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
860 
861                     if (bCellContrast)
862                     {
863                         //  high contrast for cell borders and backgrounds -> empty background
864                         pBackground = ScGlobal::GetEmptyBrushItem();
865                     }
866                     else if (bShowProt)         // show cell protection in syntax mode
867                     {
868                         const ScPatternAttr* pP = pInfo->pPatternAttr;
869                         if (pP)
870                         {
871                             const ScProtectionAttr& rProt = (const ScProtectionAttr&)
872                                                                 pP->GetItem(ATTR_PROTECTION);
873                             if (rProt.GetProtection() || rProt.GetHideCell())
874                                 pBackground = ScGlobal::GetProtectedBrushItem();
875                             else
876                                 pBackground = ScGlobal::GetEmptyBrushItem();
877                         }
878                         else
879                             pBackground = NULL;
880                     }
881                     else
882                         pBackground = pInfo->pBackground;
883 
884                     if ( bPagebreakMode && !pInfo->bPrinted )
885                         pBackground = ScGlobal::GetProtectedBrushItem();
886 
887                     if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
888                             pBackground->GetColor().GetTransparency() != 255 &&
889                             !bCellContrast )
890                     {
891                         SCROW nY = pRowInfo[nArrY].nRowNo;
892                         pBackground = lcl_FindBackground( pDoc, nX, nY, nTab );
893                     }
894 
895                     if ( pBackground != pOldBackground )
896                     {
897                         aRect.Right() = nPosX-nSignedOneX;
898                         if (pOldBackground)             // ==0 if hidden
899                         {
900                             Color aBackCol = pOldBackground->GetColor();
901                             if ( bSolidBackground && aBackCol.GetTransparency() )
902                                 aBackCol = aBgColor;
903                             if ( !aBackCol.GetTransparency() )      //! partial transparency?
904                             {
905                                 pDev->SetFillColor( aBackCol );
906                                 pDev->DrawRect( aRect );
907                             }
908                         }
909                         aRect.Left() = nPosX;
910                         pOldBackground = pBackground;
911                     }
912                     nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
913                 }
914                 aRect.Right() = nPosX-nSignedOneX;
915                 if (pOldBackground)
916                 {
917                     Color aBackCol = pOldBackground->GetColor();
918                     if ( bSolidBackground && aBackCol.GetTransparency() )
919                         aBackCol = aBgColor;
920                     if ( !aBackCol.GetTransparency() )      //! partial transparency?
921                     {
922                         pDev->SetFillColor( aBackCol );
923                         pDev->DrawRect( aRect );
924                     }
925                 }
926 
927                 nArrY += nSkip;
928             }
929         }
930         nPosY += nRowHeight;
931     }
932 }
933 
934 void ScOutputData::DrawShadow()
935 {
936     DrawExtraShadow( sal_False, sal_False, sal_False, sal_False );
937 }
938 
939 void ScOutputData::DrawExtraShadow(sal_Bool bLeft, sal_Bool bTop, sal_Bool bRight, sal_Bool bBottom)
940 {
941     pDev->SetLineColor();
942 
943     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
944     //  #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
945     sal_Bool bCellContrast = bUseStyleColor && rStyleSettings.GetHighContrastMode();
946     Color aAutoTextColor;
947     if ( bCellContrast )
948         aAutoTextColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
949 
950     long nInitPosX = nScrX;
951     if ( bLayoutRTL )
952     {
953         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
954         long nOneX = aOnePixel.Width();
955         nInitPosX += nMirrorW - nOneX;
956     }
957     long nLayoutSign = bLayoutRTL ? -1 : 1;
958 
959     long nPosY = nScrY - pRowInfo[0].nHeight;
960     for (SCSIZE nArrY=0; nArrY<nArrCount; nArrY++)
961     {
962         sal_Bool bCornerY = ( nArrY == 0 ) || ( nArrY+1 == nArrCount );
963         sal_Bool bSkipY = ( nArrY==0 && !bTop ) || ( nArrY+1 == nArrCount && !bBottom );
964 
965         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
966         long nRowHeight = pThisRowInfo->nHeight;
967 
968         if ( pThisRowInfo->bChanged && !bSkipY )
969         {
970             long nPosX = nInitPosX - pRowInfo[0].pCellInfo[nX1].nWidth * nLayoutSign;
971             for (SCCOL nArrX=nX1; nArrX<=nX2+2; nArrX++)
972             {
973                 sal_Bool bCornerX = ( nArrX==nX1 || nArrX==nX2+2 );
974                 sal_Bool bSkipX = ( nArrX==nX1 && !bLeft ) || ( nArrX==nX2+2 && !bRight );
975 
976                 for (sal_uInt16 nPass=0; nPass<2; nPass++)          // horizontal / vertikal
977                 {
978                     const SvxShadowItem* pAttr = nPass ?
979                             pThisRowInfo->pCellInfo[nArrX].pVShadowOrigin :
980                             pThisRowInfo->pCellInfo[nArrX].pHShadowOrigin;
981                     if ( pAttr && !bSkipX )
982                     {
983                         ScShadowPart ePart = nPass ?
984                                 pThisRowInfo->pCellInfo[nArrX].eVShadowPart :
985                                 pThisRowInfo->pCellInfo[nArrX].eHShadowPart;
986 
987                         sal_Bool bDo = sal_True;
988                         if ( (nPass==0 && bCornerX) || (nPass==1 && bCornerY) )
989                             if ( ePart != SC_SHADOW_CORNER )
990                                 bDo = sal_False;
991 
992                         if (bDo)
993                         {
994                             long nThisWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
995                             long nMaxWidth = nThisWidth;
996                             if (!nMaxWidth)
997                             {
998                                 //! direction must depend on shadow location
999                                 SCCOL nWx = nArrX;      // nX+1
1000                                 while (nWx<nX2 && !pRowInfo[0].pCellInfo[nWx+1].nWidth)
1001                                     ++nWx;
1002                                 nMaxWidth = pRowInfo[0].pCellInfo[nWx+1].nWidth;
1003                             }
1004 
1005 //                          Rectangle aRect( Point(nPosX,nPosY),
1006 //                                           Size( pRowInfo[0].pCellInfo[nArrX].nWidth,
1007 //                                                  pRowInfo[nArrY].nHeight ) );
1008 
1009                             // rectangle is in logical orientation
1010                             Rectangle aRect( nPosX, nPosY,
1011                                              nPosX + ( nThisWidth - 1 ) * nLayoutSign,
1012                                              nPosY + pRowInfo[nArrY].nHeight - 1 );
1013 
1014                             long nSize = pAttr->GetWidth();
1015                             long nSizeX = (long)(nSize*nPPTX);
1016                             if (nSizeX >= nMaxWidth) nSizeX = nMaxWidth-1;
1017                             long nSizeY = (long)(nSize*nPPTY);
1018                             if (nSizeY >= nRowHeight) nSizeY = nRowHeight-1;
1019 
1020                             nSizeX *= nLayoutSign;      // used only to add to rectangle values
1021 
1022                             SvxShadowLocation eLoc = pAttr->GetLocation();
1023                             if ( bLayoutRTL )
1024                             {
1025                                 //  Shadow location is specified as "visual" (right is always right),
1026                                 //  so the attribute's location value is mirrored here and in FillInfo.
1027                                 switch (eLoc)
1028                                 {
1029                                     case SVX_SHADOW_BOTTOMRIGHT: eLoc = SVX_SHADOW_BOTTOMLEFT;  break;
1030                                     case SVX_SHADOW_BOTTOMLEFT:  eLoc = SVX_SHADOW_BOTTOMRIGHT; break;
1031                                     case SVX_SHADOW_TOPRIGHT:    eLoc = SVX_SHADOW_TOPLEFT;     break;
1032                                     case SVX_SHADOW_TOPLEFT:     eLoc = SVX_SHADOW_TOPRIGHT;    break;
1033                                     default:
1034                                     {
1035                                         // added to avoid warnings
1036                                     }
1037                                 }
1038                             }
1039 
1040                             if (ePart == SC_SHADOW_HORIZ || ePart == SC_SHADOW_HSTART ||
1041                                 ePart == SC_SHADOW_CORNER)
1042                             {
1043                                 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1044                                     aRect.Top() = aRect.Bottom() - nSizeY;
1045                                 else
1046                                     aRect.Bottom() = aRect.Top() + nSizeY;
1047                             }
1048                             if (ePart == SC_SHADOW_VERT || ePart == SC_SHADOW_VSTART ||
1049                                 ePart == SC_SHADOW_CORNER)
1050                             {
1051                                 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1052                                     aRect.Left() = aRect.Right() - nSizeX;
1053                                 else
1054                                     aRect.Right() = aRect.Left() + nSizeX;
1055                             }
1056                             if (ePart == SC_SHADOW_HSTART)
1057                             {
1058                                 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_BOTTOMLEFT)
1059                                     aRect.Right() -= nSizeX;
1060                                 else
1061                                     aRect.Left() += nSizeX;
1062                             }
1063                             if (ePart == SC_SHADOW_VSTART)
1064                             {
1065                                 if (eLoc == SVX_SHADOW_TOPLEFT || eLoc == SVX_SHADOW_TOPRIGHT)
1066                                     aRect.Bottom() -= nSizeY;
1067                                 else
1068                                     aRect.Top() += nSizeY;
1069                             }
1070 
1071                             //! merge rectangles?
1072                             pDev->SetFillColor( bCellContrast ? aAutoTextColor : pAttr->GetColor() );
1073                             pDev->DrawRect( aRect );
1074                         }
1075                     }
1076                 }
1077 
1078                 nPosX += pRowInfo[0].pCellInfo[nArrX].nWidth * nLayoutSign;
1079             }
1080         }
1081         nPosY += nRowHeight;
1082     }
1083 }
1084 
1085 //
1086 //  Loeschen
1087 //
1088 
1089 void ScOutputData::DrawClear()
1090 {
1091     Rectangle aRect;
1092     Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1093     long nOneX = aOnePixel.Width();
1094     long nOneY = aOnePixel.Height();
1095 
1096     // (called only for ScGridWindow)
1097     Color aBgColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor );
1098 
1099     if (bMetaFile)
1100         nOneX = nOneY = 0;
1101 
1102     pDev->SetLineColor();
1103 
1104     pDev->SetFillColor( aBgColor );
1105 
1106     long nPosY = nScrY;
1107     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1108     {
1109         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1110         long nRowHeight = pThisRowInfo->nHeight;
1111 
1112         if ( pThisRowInfo->bChanged )
1113         {
1114             // scan for more rows which must be painted:
1115             SCSIZE nSkip = 0;
1116             while ( nArrY+nSkip+2<nArrCount && pRowInfo[nArrY+nSkip+1].bChanged )
1117             {
1118                 ++nSkip;
1119                 nRowHeight += pRowInfo[nArrY+nSkip].nHeight;    // after incrementing
1120             }
1121 
1122             aRect = Rectangle( Point( nScrX, nPosY ),
1123                     Size( nScrW+1-nOneX, nRowHeight+1-nOneY) );
1124             pDev->DrawRect( aRect );
1125 
1126             nArrY += nSkip;
1127         }
1128         nPosY += nRowHeight;
1129     }
1130 }
1131 
1132 
1133 //
1134 //  Linien
1135 //
1136 
1137 long lclGetSnappedX( OutputDevice& rDev, long nPosX, bool bSnapPixel )
1138 {
1139     return (bSnapPixel && nPosX) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( nPosX, 0 ) ) ).Width() : nPosX;
1140 }
1141 
1142 long lclGetSnappedY( OutputDevice& rDev, long nPosY, bool bSnapPixel )
1143 {
1144     return (bSnapPixel && nPosY) ? rDev.PixelToLogic( rDev.LogicToPixel( Size( 0, nPosY ) ) ).Height() : nPosY;
1145 }
1146 
1147 size_t lclGetArrayColFromCellInfoX( sal_uInt16 nCellInfoX, sal_uInt16 nCellInfoFirstX, sal_uInt16 nCellInfoLastX, bool bRTL )
1148 {
1149     return static_cast< size_t >( bRTL ? (nCellInfoLastX + 2 - nCellInfoX) : (nCellInfoX - nCellInfoFirstX) );
1150 }
1151 
1152 void ScOutputData::DrawFrame()
1153 {
1154     sal_uLong nOldDrawMode = pDev->GetDrawMode();
1155 
1156     Color aSingleColor;
1157     sal_Bool bUseSingleColor = sal_False;
1158     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1159     //  #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
1160     sal_Bool bCellContrast = bUseStyleColor && rStyleSettings.GetHighContrastMode();
1161 
1162     //  #107519# if a Calc OLE object is embedded in Draw/Impress, the VCL DrawMode is used
1163     //  for display mode / B&W printing. The VCL DrawMode handling doesn't work for lines
1164     //  that are drawn with DrawRect, so if the line/background bits are set, the DrawMode
1165     //  must be reset and the border colors handled here.
1166 
1167     if ( ( nOldDrawMode & DRAWMODE_WHITEFILL ) && ( nOldDrawMode & DRAWMODE_BLACKLINE ) )
1168     {
1169         pDev->SetDrawMode( nOldDrawMode & (~DRAWMODE_WHITEFILL) );
1170         aSingleColor.SetColor( COL_BLACK );
1171         bUseSingleColor = sal_True;
1172     }
1173     else if ( ( nOldDrawMode & DRAWMODE_SETTINGSFILL ) && ( nOldDrawMode & DRAWMODE_SETTINGSLINE ) )
1174     {
1175         pDev->SetDrawMode( nOldDrawMode & (~DRAWMODE_SETTINGSFILL) );
1176         aSingleColor = rStyleSettings.GetWindowTextColor();     // same as used in VCL for DRAWMODE_SETTINGSLINE
1177         bUseSingleColor = sal_True;
1178     }
1179     else if ( bCellContrast )
1180     {
1181         aSingleColor.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
1182         bUseSingleColor = sal_True;
1183     }
1184 
1185     const Color* pForceColor = bUseSingleColor ? &aSingleColor : 0;
1186 
1187     if (bAnyRotated)
1188         DrawRotatedFrame( pForceColor );        // removes the lines that must not be painted here
1189 
1190     long nInitPosX = nScrX;
1191     if ( bLayoutRTL )
1192     {
1193         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1194         long nOneX = aOnePixel.Width();
1195         nInitPosX += nMirrorW - nOneX;
1196     }
1197     long nLayoutSign = bLayoutRTL ? -1 : 1;
1198 
1199 
1200     // *** set column and row sizes of the frame border array ***
1201 
1202     svx::frame::Array& rArray = mrTabInfo.maArray;
1203     size_t nColCount = rArray.GetColCount();
1204     size_t nRowCount = rArray.GetRowCount();
1205 
1206     // row heights
1207 
1208     // row 0 is not visible (dummy for borders from top) - subtract its height from initial position
1209     // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit before
1210     long nOldPosY = nScrY - 1 - pRowInfo[ 0 ].nHeight;
1211     long nOldSnapY = lclGetSnappedY( *pDev, nOldPosY, bSnapPixel );
1212     rArray.SetYOffset( nOldSnapY );
1213     for( size_t nRow = 0; nRow < nRowCount; ++nRow )
1214     {
1215         long nNewPosY = nOldPosY + pRowInfo[ nRow ].nHeight;
1216         long nNewSnapY = lclGetSnappedY( *pDev, nNewPosY, bSnapPixel );
1217         rArray.SetRowHeight( nRow, nNewSnapY - nOldSnapY );
1218         nOldPosY = nNewPosY;
1219         nOldSnapY = nNewSnapY;
1220     }
1221 
1222     // column widths
1223 
1224     // column nX1 is not visible (dummy for borders from left) - subtract its width from initial position
1225     // subtract 1 unit more, because position 0 is first *in* cell, grid line is one unit above
1226     long nOldPosX = nInitPosX - nLayoutSign * (1 + pRowInfo[ 0 ].pCellInfo[ nX1 ].nWidth);
1227     long nOldSnapX = lclGetSnappedX( *pDev, nOldPosX, bSnapPixel );
1228     // set X offset for left-to-right sheets; for right-to-left sheets this is done after for() loop
1229     if( !bLayoutRTL )
1230         rArray.SetXOffset( nOldSnapX );
1231     for( sal_uInt16 nInfoIdx = nX1; nInfoIdx <= nX2 + 2; ++nInfoIdx )
1232     {
1233         size_t nCol = lclGetArrayColFromCellInfoX( nInfoIdx, nX1, nX2, bLayoutRTL );
1234         long nNewPosX = nOldPosX + pRowInfo[ 0 ].pCellInfo[ nInfoIdx ].nWidth * nLayoutSign;
1235         long nNewSnapX = lclGetSnappedX( *pDev, nNewPosX, bSnapPixel );
1236         rArray.SetColWidth( nCol, Abs( nNewSnapX - nOldSnapX ) );
1237         nOldPosX = nNewPosX;
1238         nOldSnapX = nNewSnapX;
1239     }
1240     if( bLayoutRTL )
1241         rArray.SetXOffset( nOldSnapX );
1242 
1243     // *** draw the array ***
1244 
1245     size_t nFirstCol = 1;
1246     size_t nFirstRow = 1;
1247     size_t nLastCol = nColCount - 2;
1248     size_t nLastRow = nRowCount - 2;
1249 
1250     if( mrTabInfo.mbPageMode )
1251         rArray.SetClipRange( nFirstCol, nFirstRow, nLastCol, nLastRow );
1252 
1253     // draw only rows with set RowInfo::bChanged flag
1254     size_t nRow1 = nFirstRow;
1255     while( nRow1 <= nLastRow )
1256     {
1257         while( (nRow1 <= nLastRow) && !pRowInfo[ nRow1 ].bChanged ) ++nRow1;
1258         if( nRow1 <= nLastRow )
1259         {
1260             size_t nRow2 = nRow1;
1261             while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
1262             rArray.DrawRange( *pDev, nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
1263             nRow1 = nRow2 + 1;
1264         }
1265     }
1266 
1267     pDev->SetDrawMode(nOldDrawMode);
1268 }
1269 
1270 //  -------------------------------------------------------------------------
1271 
1272 //  Linie unter der Zelle
1273 
1274 const SvxBorderLine* lcl_FindHorLine( ScDocument* pDoc,
1275                         SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nRotDir,
1276                         sal_Bool bTopLine )
1277 {
1278     if ( nRotDir != SC_ROTDIR_LEFT && nRotDir != SC_ROTDIR_RIGHT )
1279         return NULL;
1280 
1281     sal_Bool bFound = sal_False;
1282     while (!bFound)
1283     {
1284         if ( nRotDir == SC_ROTDIR_LEFT )
1285         {
1286             //  Text nach links -> Linie von rechts
1287             if ( nCol < MAXCOL )
1288                 ++nCol;
1289             else
1290                 return NULL;                // war nix
1291         }
1292         else
1293         {
1294             //  Text nach rechts -> Linie von links
1295             if ( nCol > 0 )
1296                 --nCol;
1297             else
1298                 return NULL;                // war nix
1299         }
1300         const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
1301         const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
1302         if ( !pPattern->GetRotateVal( pCondSet ) ||
1303                 ((const SvxRotateModeItem&)pPattern->GetItem(
1304                     ATTR_ROTATE_MODE, pCondSet)).GetValue() == SVX_ROTATE_MODE_STANDARD )
1305             bFound = sal_True;
1306     }
1307 
1308     if (bTopLine)
1309         --nRow;
1310     const SvxBorderLine* pThisBottom;
1311     if ( ValidRow(nRow) )
1312         pThisBottom = ((const SvxBoxItem*)pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ))->GetBottom();
1313     else
1314         pThisBottom = NULL;
1315     const SvxBorderLine* pNextTop;
1316     if ( nRow < MAXROW )
1317         pNextTop = ((const SvxBoxItem*)pDoc->GetAttr( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
1318     else
1319         pNextTop = NULL;
1320 
1321     if ( ScHasPriority( pThisBottom, pNextTop ) )
1322         return pThisBottom;
1323     else
1324         return pNextTop;
1325 }
1326 
1327 // lcl_HorizLine muss genau zu normal ausgegebenen Linien passen!
1328 
1329 void lcl_HorizLine( OutputDevice& rDev, const Point& rLeft, const Point& rRight,
1330                     const svx::frame::Style& rLine, const Color* pForceColor )
1331 {
1332     svx::frame::DrawHorFrameBorder( rDev, rLeft, rRight, rLine, pForceColor );
1333 }
1334 
1335 void lcl_VertLineEnds( OutputDevice& rDev, const Point& rTop, const Point& rBottom,
1336         const Color& rColor, long nXOffs, long nWidth,
1337         const svx::frame::Style& rTopLine, const svx::frame::Style& rBottomLine )
1338 {
1339     rDev.SetLineColor(rColor);              // PEN_NULL ???
1340     rDev.SetFillColor(rColor);
1341 
1342     //  Position oben/unten muss unabhaengig von der Liniendicke sein,
1343     //  damit der Winkel stimmt (oder X-Position auch anpassen)
1344     long nTopPos = rTop.Y();
1345     long nBotPos = rBottom.Y();
1346 
1347     long nTopLeft = rTop.X() + nXOffs;
1348     long nTopRight = nTopLeft + nWidth - 1;
1349 
1350     long nBotLeft = rBottom.X() + nXOffs;
1351     long nBotRight = nBotLeft + nWidth - 1;
1352 
1353     //  oben abschliessen
1354 
1355     if ( rTopLine.Prim() )
1356     {
1357         long nLineW = rTopLine.GetWidth();
1358         if (nLineW >= 2)
1359         {
1360             Point aTriangle[3];
1361             aTriangle[0] = Point( nTopLeft, nTopPos );      // wie aPoints[0]
1362             aTriangle[1] = Point( nTopRight, nTopPos );     // wie aPoints[1]
1363             aTriangle[2] = Point( rTop.X(), nTopPos - (nLineW - 1) / 2 );
1364             Polygon aTriPoly( 3, aTriangle );
1365             rDev.DrawPolygon( aTriPoly );
1366         }
1367     }
1368 
1369     //  unten abschliessen
1370 
1371     if ( rBottomLine.Prim() )
1372     {
1373         long nLineW = rBottomLine.GetWidth();
1374         if (nLineW >= 2)
1375         {
1376             Point aTriangle[3];
1377             aTriangle[0] = Point( nBotLeft, nBotPos );      // wie aPoints[3]
1378             aTriangle[1] = Point( nBotRight, nBotPos );     // wie aPoints[2]
1379             aTriangle[2] = Point( rBottom.X(), nBotPos - (nLineW - 1) / 2 + nLineW - 1 );
1380             Polygon aTriPoly( 3, aTriangle );
1381             rDev.DrawPolygon( aTriPoly );
1382         }
1383     }
1384 }
1385 
1386 void lcl_VertLine( OutputDevice& rDev, const Point& rTop, const Point& rBottom,
1387                     const svx::frame::Style& rLine,
1388                     const svx::frame::Style& rTopLine, const svx::frame::Style& rBottomLine,
1389                     const Color* pForceColor )
1390 {
1391     if( rLine.Prim() )
1392     {
1393         svx::frame::DrawVerFrameBorderSlanted( rDev, rTop, rBottom, rLine, pForceColor );
1394 
1395         svx::frame::Style aScaled( rLine );
1396         aScaled.ScaleSelf( 1.0 / cos( svx::frame::GetVerDiagAngle( rTop, rBottom ) ) );
1397         if( pForceColor )
1398             aScaled.SetColor( *pForceColor );
1399 
1400         long nXOffs = (aScaled.GetWidth() - 1) / -2L;
1401 
1402         lcl_VertLineEnds( rDev, rTop, rBottom, aScaled.GetColor(),
1403             nXOffs, aScaled.Prim(), rTopLine, rBottomLine );
1404 
1405         if( aScaled.Secn() )
1406             lcl_VertLineEnds( rDev, rTop, rBottom, aScaled.GetColor(),
1407                 nXOffs + aScaled.Prim() + aScaled.Dist(), aScaled.Secn(), rTopLine, rBottomLine );
1408     }
1409 }
1410 
1411 void ScOutputData::DrawRotatedFrame( const Color* pForceColor )
1412 {
1413     //! nRotMax speichern
1414     SCCOL nRotMax = nX2;
1415     for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
1416         if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
1417             nRotMax = pRowInfo[nRotY].nRotMaxCol;
1418 
1419     const ScPatternAttr* pPattern;
1420     const SfxItemSet*    pCondSet;
1421 
1422     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
1423     //  #105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
1424     sal_Bool bCellContrast = bUseStyleColor && rStyleSettings.GetHighContrastMode();
1425 
1426     //  color (pForceColor) is determined externally, including DrawMode changes
1427 
1428     long nInitPosX = nScrX;
1429     if ( bLayoutRTL )
1430     {
1431         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
1432         long nOneX = aOnePixel.Width();
1433         nInitPosX += nMirrorW - nOneX;
1434     }
1435     long nLayoutSign = bLayoutRTL ? -1 : 1;
1436 
1437     Rectangle aClipRect( Point(nScrX, nScrY), Size(nScrW, nScrH) );
1438     if (bMetaFile)
1439     {
1440         pDev->Push();
1441         pDev->IntersectClipRegion( aClipRect );
1442     }
1443     else
1444         pDev->SetClipRegion( Region( aClipRect ) );
1445 
1446     svx::frame::Array& rArray = mrTabInfo.maArray;
1447 
1448     long nPosY = nScrY;
1449     for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
1450     {
1451         //  Rotated wird auch 1 Zeile ueber/unter Changed gezeichnet, falls Teile
1452         //  in die Zeile hineinragen...
1453 
1454         RowInfo& rPrevRowInfo = pRowInfo[nArrY-1];
1455         RowInfo& rThisRowInfo = pRowInfo[nArrY];
1456         RowInfo& rNextRowInfo = pRowInfo[nArrY+1];
1457 
1458         size_t nRow = static_cast< size_t >( nArrY );
1459 
1460         long nRowHeight = rThisRowInfo.nHeight;
1461         if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
1462              ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
1463                ( nArrY+1<nArrCount && rNextRowInfo.bChanged ) ) )
1464         {
1465             SCROW nY = rThisRowInfo.nRowNo;
1466             long nPosX = 0;
1467             SCCOL nX;
1468             for (nX=0; nX<=nRotMax; nX++)
1469             {
1470                 if (nX==nX1) nPosX = nInitPosX;     // calculated individually for preceding positions
1471 
1472                 sal_uInt16 nArrX = nX + 1;
1473 
1474                 CellInfo* pInfo = &rThisRowInfo.pCellInfo[nArrX];
1475                 long nColWidth = pRowInfo[0].pCellInfo[nArrX].nWidth;
1476                 if ( pInfo->nRotateDir > SC_ROTDIR_STANDARD &&
1477                         !pInfo->bHOverlapped && !pInfo->bVOverlapped )
1478                 {
1479                     pPattern = pInfo->pPatternAttr;
1480                     pCondSet = pInfo->pConditionSet;
1481                     if (!pPattern)
1482                     {
1483                         pPattern = pDoc->GetPattern( nX, nY, nTab );
1484                         pInfo->pPatternAttr = pPattern;
1485                         pCondSet = pDoc->GetCondResult( nX, nY, nTab );
1486                         pInfo->pConditionSet = pCondSet;
1487                     }
1488 
1489                     //! LastPattern etc.
1490 
1491                     long nAttrRotate = pPattern->GetRotateVal( pCondSet );
1492                     SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
1493                                     pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
1494 
1495                     if ( nAttrRotate )
1496                     {
1497                         if (nX<nX1)         // negative Position berechnen
1498                         {
1499                             nPosX = nInitPosX;
1500                             SCCOL nCol = nX1;
1501                             while (nCol > nX)
1502                             {
1503                                 --nCol;
1504                                 nPosX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
1505                             }
1506                         }
1507 
1508                         //  Startposition minus 1, damit auch schraege Hintergruende
1509                         //  zur Umrandung passen (Umrandung ist auf dem Gitter)
1510 
1511                         long nTop = nPosY - 1;
1512                         long nBottom = nPosY + nRowHeight - 1;
1513                         long nTopLeft = nPosX - nLayoutSign;
1514                         long nTopRight = nPosX + ( nColWidth - 1 ) * nLayoutSign;
1515                         long nBotLeft = nTopLeft;
1516                         long nBotRight = nTopRight;
1517 
1518                         //  inclusion of the sign here hasn't been decided yet
1519                         //  (if not, the extension of the non-rotated background must also be changed)
1520                         double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000;     // 1/100th degrees
1521                         double nCos = cos( nRealOrient );
1522                         double nSin = sin( nRealOrient );
1523                         //! begrenzen !!!
1524                         long nSkew = (long) ( nRowHeight * nCos / nSin );
1525 
1526                         switch (eRotMode)
1527                         {
1528                             case SVX_ROTATE_MODE_BOTTOM:
1529                                 nTopLeft += nSkew;
1530                                 nTopRight += nSkew;
1531                                 break;
1532                             case SVX_ROTATE_MODE_CENTER:
1533                                 nSkew /= 2;
1534                                 nTopLeft += nSkew;
1535                                 nTopRight += nSkew;
1536                                 nBotLeft -= nSkew;
1537                                 nBotRight -= nSkew;
1538                                 break;
1539                             case SVX_ROTATE_MODE_TOP:
1540                                 nBotLeft -= nSkew;
1541                                 nBotRight -= nSkew;
1542                                 break;
1543                             default:
1544                             {
1545                                 // added to avoid warnings
1546                             }
1547                         }
1548 
1549                         Point aPoints[4];
1550                         aPoints[0] = Point( nTopLeft, nTop );
1551                         aPoints[1] = Point( nTopRight, nTop );
1552                         aPoints[2] = Point( nBotRight, nBottom );
1553                         aPoints[3] = Point( nBotLeft, nBottom );
1554 
1555                         const SvxBrushItem* pBackground = pInfo->pBackground;
1556                         if (!pBackground)
1557                             pBackground = (const SvxBrushItem*) &pPattern->GetItem(
1558                                                 ATTR_BACKGROUND, pCondSet );
1559                         if (bCellContrast)
1560                         {
1561                             //  high contrast for cell borders and backgrounds -> empty background
1562                             pBackground = ScGlobal::GetEmptyBrushItem();
1563                         }
1564                         const Color& rColor = pBackground->GetColor();
1565                         if ( rColor.GetTransparency() != 255 )
1566                         {
1567                             //  #95879# draw background only for the changed row itself
1568                             //  (background doesn't extend into other cells).
1569                             //  For the borders (rotated and normal), clipping should be
1570                             //  set if the row isn't changed, but at least the borders
1571                             //  don't cover the cell contents.
1572                             if ( rThisRowInfo.bChanged )
1573                             {
1574                                 Polygon aPoly( 4, aPoints );
1575 
1576                                 //  ohne Pen wird bei DrawPolygon rechts und unten
1577                                 //  ein Pixel weggelassen...
1578                                 if ( rColor.GetTransparency() == 0 )
1579                                     pDev->SetLineColor(rColor);
1580                                 else
1581                                     pDev->SetLineColor();
1582                                 pDev->SetFillColor(rColor);
1583                                 pDev->DrawPolygon( aPoly );
1584                             }
1585                         }
1586 
1587                         svx::frame::Style aTopLine, aBottomLine, aLeftLine, aRightLine;
1588 
1589                         if ( nX < nX1 || nX > nX2 )     // Attribute in FillInfo nicht gesetzt
1590                         {
1591                             //! Seitengrenzen fuer Druck beruecksichtigen !!!!!
1592                             const SvxBorderLine* pLeftLine;
1593                             const SvxBorderLine* pTopLine;
1594                             const SvxBorderLine* pRightLine;
1595                             const SvxBorderLine* pBottomLine;
1596                             pDoc->GetBorderLines( nX, nY, nTab,
1597                                     &pLeftLine, &pTopLine, &pRightLine, &pBottomLine );
1598                             aTopLine.Set( pTopLine, nPPTY );
1599                             aBottomLine.Set( pBottomLine, nPPTY );
1600                             aLeftLine.Set( pLeftLine, nPPTX );
1601                             aRightLine.Set( pRightLine, nPPTX );
1602                         }
1603                         else
1604                         {
1605                             size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1606                             aTopLine = rArray.GetCellStyleTop( nCol, nRow );
1607                             aBottomLine = rArray.GetCellStyleBottom( nCol, nRow );
1608                             aLeftLine = rArray.GetCellStyleLeft( nCol, nRow );
1609                             aRightLine = rArray.GetCellStyleRight( nCol, nRow );
1610                             // in RTL mode the array is already mirrored -> swap back left/right borders
1611                             if( bLayoutRTL )
1612                                 std::swap( aLeftLine, aRightLine );
1613                         }
1614 
1615                         lcl_HorizLine( *pDev, aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine, pForceColor );
1616                         lcl_HorizLine( *pDev, aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine, pForceColor );
1617 
1618                         lcl_VertLine( *pDev, aPoints[0], aPoints[3], aLeftLine, aTopLine, aBottomLine, pForceColor );
1619                         lcl_VertLine( *pDev, aPoints[1], aPoints[2], aRightLine, aTopLine, aBottomLine, pForceColor );
1620                     }
1621                 }
1622                 nPosX += nColWidth * nLayoutSign;
1623             }
1624 
1625             //  erst hinterher im zweiten Schritt die Linien fuer normale Ausgabe loeschen
1626 
1627             nX = nX1 > 0 ? (nX1-1) : static_cast<SCCOL>(0);
1628             for (; nX<=nX2+1; nX++)         // sichtbarer Teil +- 1
1629             {
1630                 sal_uInt16 nArrX = nX + 1;
1631                 CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrX];
1632                 if ( rInfo.nRotateDir > SC_ROTDIR_STANDARD &&
1633                         !rInfo.bHOverlapped && !rInfo.bVOverlapped )
1634                 {
1635                     pPattern = rInfo.pPatternAttr;
1636                     pCondSet = rInfo.pConditionSet;
1637                     SvxRotateMode eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
1638                                     pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
1639 
1640                     size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
1641 
1642                     //  horizontal: angrenzende Linie verlaengern
1643                     //  (nur, wenn die gedrehte Zelle eine Umrandung hat)
1644                     sal_uInt16 nDir = rInfo.nRotateDir;
1645                     if ( rArray.GetCellStyleTop( nCol, nRow ).Prim() && eRotMode != SVX_ROTATE_MODE_TOP )
1646                     {
1647                         svx::frame::Style aStyle( lcl_FindHorLine( pDoc, nX, nY, nTab, nDir, sal_True ), nPPTY );
1648                         rArray.SetCellStyleTop( nCol, nRow, aStyle );
1649                         if( nRow > 0 )
1650                             rArray.SetCellStyleBottom( nCol, nRow - 1, aStyle );
1651                     }
1652                     if ( rArray.GetCellStyleBottom( nCol, nRow ).Prim() && eRotMode != SVX_ROTATE_MODE_BOTTOM )
1653                     {
1654                         svx::frame::Style aStyle( lcl_FindHorLine( pDoc, nX, nY, nTab, nDir, sal_False ), nPPTY );
1655                         rArray.SetCellStyleBottom( nCol, nRow, aStyle );
1656                         if( nRow + 1 < rArray.GetRowCount() )
1657                             rArray.SetCellStyleTop( nCol, nRow + 1, aStyle );
1658                     }
1659 
1660                     // always remove vertical borders
1661                     if( !rArray.IsMergedOverlappedLeft( nCol, nRow ) )
1662                     {
1663                         rArray.SetCellStyleLeft( nCol, nRow, svx::frame::Style() );
1664                         if( nCol > 0 )
1665                             rArray.SetCellStyleRight( nCol - 1, nRow, svx::frame::Style() );
1666                     }
1667                     if( !rArray.IsMergedOverlappedRight( nCol, nRow ) )
1668                     {
1669                         rArray.SetCellStyleRight( nCol, nRow, svx::frame::Style() );
1670                         if( nCol + 1 < rArray.GetColCount() )
1671                             rArray.SetCellStyleLeft( nCol + 1, nRow, svx::frame::Style() );
1672                     }
1673 
1674                     // remove diagonal borders
1675                     rArray.SetCellStyleTLBR( nCol, nRow, svx::frame::Style() );
1676                     rArray.SetCellStyleBLTR( nCol, nRow, svx::frame::Style() );
1677                 }
1678             }
1679         }
1680         nPosY += nRowHeight;
1681     }
1682 
1683     if (bMetaFile)
1684         pDev->Pop();
1685     else
1686         pDev->SetClipRegion();
1687 }
1688 
1689 //  Drucker
1690 
1691 Region ScOutputData::GetChangedAreaRegion()
1692 {
1693     Region aRegion;
1694     Rectangle aDrawingRect;
1695     bool bHad(false);
1696     long nPosY = nScrY;
1697     SCSIZE nArrY;
1698 
1699     aDrawingRect.Left() = nScrX;
1700     aDrawingRect.Right() = nScrX+nScrW-1;
1701 
1702     for(nArrY=1; nArrY+1<nArrCount; nArrY++)
1703     {
1704         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1705 
1706         if(pThisRowInfo->bChanged)
1707         {
1708             if(!bHad)
1709             {
1710                 aDrawingRect.Top() = nPosY;
1711                 bHad = true;
1712             }
1713 
1714             aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1715         }
1716         else if(bHad)
1717         {
1718             aRegion.Union(pDev->PixelToLogic(aDrawingRect));
1719             bHad = false;
1720         }
1721 
1722         nPosY += pRowInfo[nArrY].nHeight;
1723     }
1724 
1725     if(bHad)
1726     {
1727         aRegion.Union(pDev->PixelToLogic(aDrawingRect));
1728     }
1729 
1730     return aRegion;
1731 }
1732 
1733 sal_Bool ScOutputData::SetChangedClip()
1734 {
1735     PolyPolygon aPoly;
1736 
1737     Rectangle aDrawingRect;
1738     aDrawingRect.Left() = nScrX;
1739     aDrawingRect.Right() = nScrX+nScrW-1;
1740 
1741     sal_Bool    bHad    = sal_False;
1742     long    nPosY   = nScrY;
1743     SCSIZE  nArrY;
1744     for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1745     {
1746         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1747 
1748         if ( pThisRowInfo->bChanged )
1749         {
1750             if (!bHad)
1751             {
1752                 aDrawingRect.Top() = nPosY;
1753                 bHad = sal_True;
1754             }
1755             aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1756         }
1757         else if (bHad)
1758         {
1759             aPoly.Insert( Polygon( pDev->PixelToLogic(aDrawingRect) ) );
1760             bHad = sal_False;
1761         }
1762         nPosY += pRowInfo[nArrY].nHeight;
1763     }
1764 
1765     if (bHad)
1766         aPoly.Insert( Polygon( pDev->PixelToLogic(aDrawingRect) ) );
1767 
1768     sal_Bool bRet = (aPoly.Count() != 0);
1769     if (bRet)
1770         pDev->SetClipRegion(Region(aPoly));
1771     return bRet;
1772 }
1773 
1774 void ScOutputData::FindChanged()
1775 {
1776     SCCOL   nX;
1777     SCSIZE  nArrY;
1778 
1779     sal_Bool bWasIdleDisabled = pDoc->IsIdleDisabled();
1780     pDoc->DisableIdle( sal_True );
1781     for (nArrY=0; nArrY<nArrCount; nArrY++)
1782         pRowInfo[nArrY].bChanged = sal_False;
1783 
1784     sal_Bool bProgress = sal_False;
1785     for (nArrY=0; nArrY<nArrCount; nArrY++)
1786     {
1787         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1788         for (nX=nX1; nX<=nX2; nX++)
1789         {
1790             ScBaseCell* pCell = pThisRowInfo->pCellInfo[nX+1].pCell;
1791             if (pCell)
1792                 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1793                 {
1794                     ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1795                     if ( !bProgress && pFCell->GetDirty() )
1796                     {
1797                         ScProgress::CreateInterpretProgress( pDoc, sal_True );
1798                         bProgress = sal_True;
1799                     }
1800                     if (!pFCell->IsRunning())
1801                     {
1802                         (void)pFCell->GetValue();
1803                         if (pFCell->IsChanged())
1804                         {
1805                             pThisRowInfo->bChanged = sal_True;
1806                             if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
1807                             {
1808                                 SCSIZE nOverY = nArrY + 1;
1809                                 while ( nOverY<nArrCount &&
1810                                         pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
1811                                 {
1812                                     pRowInfo[nOverY].bChanged = sal_True;
1813                                     ++nOverY;
1814                                 }
1815                             }
1816                         }
1817                     }
1818                 }
1819         }
1820     }
1821     if ( bProgress )
1822         ScProgress::DeleteInterpretProgress();
1823     pDoc->DisableIdle( bWasIdleDisabled );
1824 }
1825 
1826 #ifdef OLD_SELECTION_PAINT
1827 void ScOutputData::DrawMark( Window* pWin )
1828 {
1829     Rectangle aRect;
1830     ScInvertMerger aInvert( pWin );
1831     //! additional method AddLineRect for ScInvertMerger?
1832 
1833     long nPosY = nScrY;
1834     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1835     {
1836         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1837         if (pThisRowInfo->bChanged)
1838         {
1839             long nPosX = nScrX;
1840             if (bLayoutRTL)
1841                 nPosX += nMirrorW - 1;      // always in pixels
1842 
1843             aRect = Rectangle( Point( nPosX,nPosY ), Size(1, pThisRowInfo->nHeight) );
1844             if (bLayoutRTL)
1845                 aRect.Left() = aRect.Right() + 1;
1846             else
1847                 aRect.Right() = aRect.Left() - 1;
1848 
1849             sal_Bool bOldMarked = sal_False;
1850             for (SCCOL nX=nX1; nX<=nX2; nX++)
1851             {
1852                 if (pThisRowInfo->pCellInfo[nX+1].bMarked != bOldMarked)
1853                 {
1854                     if (bOldMarked && aRect.Right() >= aRect.Left())
1855                         aInvert.AddRect( aRect );
1856 
1857                     if (bLayoutRTL)
1858                         aRect.Right() = nPosX;
1859                     else
1860                         aRect.Left() = nPosX;
1861 
1862                     bOldMarked = pThisRowInfo->pCellInfo[nX+1].bMarked;
1863                 }
1864 
1865                 if (bLayoutRTL)
1866                 {
1867                     nPosX -= pRowInfo[0].pCellInfo[nX+1].nWidth;
1868                     aRect.Left() = nPosX+1;
1869                 }
1870                 else
1871                 {
1872                     nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth;
1873                     aRect.Right() = nPosX-1;
1874                 }
1875             }
1876             if (bOldMarked && aRect.Right() >= aRect.Left())
1877                 aInvert.AddRect( aRect );
1878         }
1879         nPosY += pThisRowInfo->nHeight;
1880     }
1881 }
1882 #endif
1883 
1884 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
1885                                 SCCOL nRefEndX, SCROW nRefEndY,
1886                                 const Color& rColor, sal_Bool bHandle )
1887 {
1888     PutInOrder( nRefStartX, nRefEndX );
1889     PutInOrder( nRefStartY, nRefEndY );
1890 
1891     if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1892         pDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1893 
1894     if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
1895          nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
1896     {
1897         long nMinX = nScrX;
1898         long nMinY = nScrY;
1899         long nMaxX = nScrX+nScrW-1;
1900         long nMaxY = nScrY+nScrH-1;
1901         if ( bLayoutRTL )
1902         {
1903             long nTemp = nMinX;
1904             nMinX = nMaxX;
1905             nMaxX = nTemp;
1906         }
1907         long nLayoutSign = bLayoutRTL ? -1 : 1;
1908 
1909         sal_Bool bTop    = sal_False;
1910         sal_Bool bBottom = sal_False;
1911         sal_Bool bLeft   = sal_False;
1912         sal_Bool bRight  = sal_False;
1913 
1914         long nPosY = nScrY;
1915         sal_Bool bNoStartY = ( nY1 < nRefStartY );
1916         sal_Bool bNoEndY   = sal_False;
1917         for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)      // loop to end for bNoEndY check
1918         {
1919             SCROW nY = pRowInfo[nArrY].nRowNo;
1920 
1921             if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
1922             {
1923                 nMinY = nPosY;
1924                 bTop = sal_True;
1925             }
1926             if ( nY==nRefEndY )
1927             {
1928                 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
1929                 bBottom = sal_True;
1930             }
1931             if ( nY>nRefEndY && bNoEndY )
1932             {
1933                 nMaxY = nPosY-2;
1934                 bBottom = sal_True;
1935             }
1936             bNoStartY = ( nY < nRefStartY );
1937             bNoEndY   = ( nY < nRefEndY );
1938             nPosY += pRowInfo[nArrY].nHeight;
1939         }
1940 
1941         long nPosX = nScrX;
1942         if ( bLayoutRTL )
1943             nPosX += nMirrorW - 1;      // always in pixels
1944 
1945         for (SCCOL nX=nX1; nX<=nX2; nX++)
1946         {
1947             if ( nX==nRefStartX )
1948             {
1949                 nMinX = nPosX;
1950                 bLeft = sal_True;
1951             }
1952             if ( nX==nRefEndX )
1953             {
1954                 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
1955                 bRight = sal_True;
1956             }
1957             nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
1958         }
1959 
1960         if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
1961              nMaxY >= nMinY )
1962         {
1963             pDev->SetLineColor( rColor );
1964             if (bTop && bBottom && bLeft && bRight)
1965             {
1966                 pDev->SetFillColor();
1967                 pDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
1968             }
1969             else
1970             {
1971                 if (bTop)
1972                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
1973                 if (bBottom)
1974                     pDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
1975                 if (bLeft)
1976                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
1977                 if (bRight)
1978                     pDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
1979             }
1980             if ( bHandle && bRight && bBottom )
1981             {
1982                 pDev->SetLineColor();
1983                 pDev->SetFillColor( rColor );
1984                 pDev->DrawRect( Rectangle( nMaxX-3*nLayoutSign, nMaxY-3, nMaxX+nLayoutSign, nMaxY+1 ) );
1985             }
1986         }
1987     }
1988 }
1989 
1990 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
1991                                 SCCOL nRefEndX, SCROW nRefEndY,
1992                                 const Color& rColor, sal_uInt16 nType )
1993 {
1994     PutInOrder( nRefStartX, nRefEndX );
1995     PutInOrder( nRefStartY, nRefEndY );
1996 
1997     if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1998         pDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1999 
2000     if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
2001          nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 )       // +1 because it touches next cells left/top
2002     {
2003         long nMinX = nScrX;
2004         long nMinY = nScrY;
2005         long nMaxX = nScrX+nScrW-1;
2006         long nMaxY = nScrY+nScrH-1;
2007         if ( bLayoutRTL )
2008         {
2009             long nTemp = nMinX;
2010             nMinX = nMaxX;
2011             nMaxX = nTemp;
2012         }
2013         long nLayoutSign = bLayoutRTL ? -1 : 1;
2014 
2015         sal_Bool bTop    = sal_False;
2016         sal_Bool bBottom = sal_False;
2017         sal_Bool bLeft   = sal_False;
2018         sal_Bool bRight  = sal_False;
2019 
2020         long nPosY = nScrY;
2021         sal_Bool bNoStartY = ( nY1 < nRefStartY );
2022         sal_Bool bNoEndY   = sal_False;
2023         for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)      // loop to end for bNoEndY check
2024         {
2025             SCROW nY = pRowInfo[nArrY].nRowNo;
2026 
2027             if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2028             {
2029                 nMinY = nPosY - 1;
2030                 bTop = sal_True;
2031             }
2032             if ( nY==nRefEndY )
2033             {
2034                 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2035                 bBottom = sal_True;
2036             }
2037             if ( nY>nRefEndY && bNoEndY )
2038             {
2039                 nMaxY = nPosY - 1;
2040                 bBottom = sal_True;
2041             }
2042             bNoStartY = ( nY < nRefStartY );
2043             bNoEndY   = ( nY < nRefEndY );
2044             nPosY += pRowInfo[nArrY].nHeight;
2045         }
2046 
2047         long nPosX = nScrX;
2048         if ( bLayoutRTL )
2049             nPosX += nMirrorW - 1;      // always in pixels
2050 
2051         for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2052         {
2053             if ( nX==nRefStartX )
2054             {
2055                 nMinX = nPosX - nLayoutSign;
2056                 bLeft = sal_True;
2057             }
2058             if ( nX==nRefEndX )
2059             {
2060                 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2061                 bRight = sal_True;
2062             }
2063             nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2064         }
2065 
2066         if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2067              nMaxY >= nMinY )
2068         {
2069             if ( nType == SC_CAT_DELETE_ROWS )
2070                 bLeft = bRight = bBottom = sal_False;       //! dicke Linie ???
2071             else if ( nType == SC_CAT_DELETE_COLS )
2072                 bTop = bBottom = bRight = sal_False;        //! dicke Linie ???
2073 
2074             pDev->SetLineColor( rColor );
2075             if (bTop && bBottom && bLeft && bRight)
2076             {
2077                 pDev->SetFillColor();
2078                 pDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2079             }
2080             else
2081             {
2082                 if (bTop)
2083                 {
2084                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2085                     if ( nType == SC_CAT_DELETE_ROWS )
2086                         pDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2087                 }
2088                 if (bBottom)
2089                     pDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2090                 if (bLeft)
2091                 {
2092                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2093                     if ( nType == SC_CAT_DELETE_COLS )
2094                         pDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2095                 }
2096                 if (bRight)
2097                     pDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2098             }
2099             if ( bLeft && bTop )
2100             {
2101                 pDev->SetLineColor();
2102                 pDev->SetFillColor( rColor );
2103                 pDev->DrawRect( Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2104             }
2105         }
2106     }
2107 }
2108 
2109 void ScOutputData::DrawChangeTrack()
2110 {
2111     ScChangeTrack* pTrack = pDoc->GetChangeTrack();
2112     ScChangeViewSettings* pSettings = pDoc->GetChangeViewSettings();
2113     if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2114         return;         // nix da oder abgeschaltet
2115 
2116     ScActionColorChanger aColorChanger(*pTrack);
2117 
2118     //  Clipping passiert von aussen
2119     //! ohne Clipping, nur betroffene Zeilen painten ??!??!?
2120 
2121     SCCOL nEndX = nX2;
2122     SCROW nEndY = nY2;
2123     if ( nEndX < MAXCOL ) ++nEndX;      // auch noch von der naechsten Zelle, weil die Markierung
2124     if ( nEndY < MAXROW ) ++nEndY;      // in die jeweils vorhergehende Zelle hineinragt
2125     ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2126     const ScChangeAction* pAction = pTrack->GetFirst();
2127     while (pAction)
2128     {
2129         ScChangeActionType eActionType;
2130         if ( pAction->IsVisible() )
2131         {
2132             eActionType = pAction->GetType();
2133             const ScBigRange& rBig = pAction->GetBigRange();
2134             if ( rBig.aStart.Tab() == nTab )
2135             {
2136                 ScRange aRange = rBig.MakeRange();
2137 
2138                 if ( eActionType == SC_CAT_DELETE_ROWS )
2139                     aRange.aEnd.SetRow( aRange.aStart.Row() );
2140                 else if ( eActionType == SC_CAT_DELETE_COLS )
2141                     aRange.aEnd.SetCol( aRange.aStart.Col() );
2142 
2143                 if ( aRange.Intersects( aViewRange ) &&
2144                      ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc ) )
2145                 {
2146                     aColorChanger.Update( *pAction );
2147                     Color aColor( aColorChanger.GetColor() );
2148                     DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2149                                     aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2150 
2151                 }
2152             }
2153             if ( eActionType == SC_CAT_MOVE &&
2154                     ((const ScChangeActionMove*)pAction)->
2155                         GetFromRange().aStart.Tab() == nTab )
2156             {
2157                 ScRange aRange = ((const ScChangeActionMove*)pAction)->
2158                         GetFromRange().MakeRange();
2159                 if ( aRange.Intersects( aViewRange ) &&
2160                      ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc ) )
2161                 {
2162                     aColorChanger.Update( *pAction );
2163                     Color aColor( aColorChanger.GetColor() );
2164                     DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2165                                     aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2166                 }
2167             }
2168         }
2169 
2170         pAction = pAction->GetNext();
2171     }
2172 }
2173 
2174 void ScOutputData::DrawNoteMarks()
2175 {
2176     sal_Bool bFirst = sal_True;
2177 
2178     long nInitPosX = nScrX;
2179     if ( bLayoutRTL )
2180         nInitPosX += nMirrorW - 1;              // always in pixels
2181     long nLayoutSign = bLayoutRTL ? -1 : 1;
2182 
2183     long nPosY = nScrY;
2184     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2185     {
2186         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2187         if ( pThisRowInfo->bChanged )
2188         {
2189             long nPosX = nInitPosX;
2190             for (SCCOL nX=nX1; nX<=nX2; nX++)
2191             {
2192                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2193                 ScBaseCell* pCell = pInfo->pCell;
2194                 sal_Bool bIsMerged = sal_False;
2195 
2196                 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2197                 {
2198                     // find start of merged cell
2199                     bIsMerged = sal_True;
2200                     SCROW nY = pRowInfo[nArrY].nRowNo;
2201                     SCCOL nMergeX = nX;
2202                     SCROW nMergeY = nY;
2203                     pDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2204                     pCell = pDoc->GetCell( ScAddress(nMergeX,nMergeY,nTab) );
2205                     // use origin's pCell for NotePtr test below
2206                 }
2207 
2208                 if ( pCell && pCell->HasNote() && ( bIsMerged ||
2209                         ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2210                 {
2211                     if (bFirst)
2212                     {
2213                         pDev->SetLineColor();
2214 
2215                         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2216                         if ( bUseStyleColor && rStyleSettings.GetHighContrastMode() )
2217                             pDev->SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2218                         else
2219                             pDev->SetFillColor(COL_LIGHTRED);
2220 
2221                         bFirst = sal_False;
2222                     }
2223 
2224                     long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2225                     if ( bIsMerged || pInfo->bMerged )
2226                     {
2227                         //  if merged, add widths of all cells
2228                         SCCOL nNextX = nX + 1;
2229                         while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2230                         {
2231                             nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2232                             ++nNextX;
2233                         }
2234                     }
2235                     if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2236                         pDev->DrawRect( Rectangle( nMarkX,nPosY,nMarkX+2*nLayoutSign,nPosY+2 ) );
2237                 }
2238 
2239                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2240             }
2241         }
2242         nPosY += pThisRowInfo->nHeight;
2243     }
2244 }
2245 
2246 void ScOutputData::AddPDFNotes()
2247 {
2248     vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2249     if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2250         return;
2251 
2252     long nInitPosX = nScrX;
2253     if ( bLayoutRTL )
2254     {
2255         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
2256         long nOneX = aOnePixel.Width();
2257         nInitPosX += nMirrorW - nOneX;
2258     }
2259     long nLayoutSign = bLayoutRTL ? -1 : 1;
2260 
2261     long nPosY = nScrY;
2262     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2263     {
2264         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2265         if ( pThisRowInfo->bChanged )
2266         {
2267             long nPosX = nInitPosX;
2268             for (SCCOL nX=nX1; nX<=nX2; nX++)
2269             {
2270                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2271                 ScBaseCell* pCell = pInfo->pCell;
2272                 sal_Bool bIsMerged = sal_False;
2273                 SCROW nY = pRowInfo[nArrY].nRowNo;
2274                 SCCOL nMergeX = nX;
2275                 SCROW nMergeY = nY;
2276 
2277                 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2278                 {
2279                     // find start of merged cell
2280                     bIsMerged = sal_True;
2281                     pDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2282                     pCell = pDoc->GetCell( ScAddress(nMergeX,nMergeY,nTab) );
2283                     // use origin's pCell for NotePtr test below
2284                 }
2285 
2286                 if ( pCell && pCell->HasNote() && ( bIsMerged ||
2287                         ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2288                 {
2289                     long nNoteWidth = (long)( SC_CLIPMARK_SIZE * nPPTX );
2290                     long nNoteHeight = (long)( SC_CLIPMARK_SIZE * nPPTY );
2291 
2292                     long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2293                     if ( bIsMerged || pInfo->bMerged )
2294                     {
2295                         //  if merged, add widths of all cells
2296                         SCCOL nNextX = nX + 1;
2297                         while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2298                         {
2299                             nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2300                             ++nNextX;
2301                         }
2302                     }
2303                     if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2304                     {
2305                         Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2306                         const ScPostIt* pNote = pCell->GetNote();
2307 
2308                         // Note title is the cell address (as on printed note pages)
2309                         String aTitle;
2310                         ScAddress aAddress( nMergeX, nMergeY, nTab );
2311                         aAddress.Format( aTitle, SCA_VALID, pDoc, pDoc->GetAddressConvention() );
2312 
2313                         // Content has to be a simple string without line breaks
2314                         String aContent = pNote->GetText();
2315                         xub_StrLen nPos;
2316                         while ( (nPos=aContent.Search('\n')) != STRING_NOTFOUND )
2317                             aContent.SetChar( nPos, ' ' );
2318 
2319                         vcl::PDFNote aNote;
2320                         aNote.Title = aTitle;
2321                         aNote.Contents = aContent;
2322                         pPDFData->CreateNote( aNoteRect, aNote );
2323                     }
2324                 }
2325 
2326                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2327             }
2328         }
2329         nPosY += pThisRowInfo->nHeight;
2330     }
2331 }
2332 
2333 void ScOutputData::DrawClipMarks()
2334 {
2335     if (!bAnyClipped)
2336         return;
2337 
2338     Color aArrowFillCol( COL_LIGHTRED );
2339 
2340     sal_uLong nOldDrawMode = pDev->GetDrawMode();
2341     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2342     if ( bUseStyleColor && rStyleSettings.GetHighContrastMode() )
2343     {
2344         //  use DrawMode to change the arrow's outline color
2345         pDev->SetDrawMode( nOldDrawMode | DRAWMODE_SETTINGSLINE );
2346         //  use text color also for the fill color
2347         aArrowFillCol.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2348     }
2349 
2350     long nInitPosX = nScrX;
2351     if ( bLayoutRTL )
2352         nInitPosX += nMirrorW - 1;              // always in pixels
2353     long nLayoutSign = bLayoutRTL ? -1 : 1;
2354 
2355     Rectangle aCellRect;
2356     long nPosY = nScrY;
2357     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2358     {
2359         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2360         if ( pThisRowInfo->bChanged )
2361         {
2362             SCROW nY = pThisRowInfo->nRowNo;
2363             long nPosX = nInitPosX;
2364             for (SCCOL nX=nX1; nX<=nX2; nX++)
2365             {
2366                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2367                 if (pInfo->nClipMark)
2368                 {
2369                     if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2370                     {
2371                         //  merge origin may be outside of visible area - use document functions
2372 
2373                         SCCOL nOverX = nX;
2374                         SCROW nOverY = nY;
2375                         long nStartPosX = nPosX;
2376                         long nStartPosY = nPosY;
2377 
2378                         while ( nOverX > 0 && ( ((const ScMergeFlagAttr*)pDoc->GetAttr(
2379                                 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_HOR ) )
2380                         {
2381                             --nOverX;
2382                             nStartPosX -= nLayoutSign * (long) ( pDoc->GetColWidth(nOverX,nTab) * nPPTX );
2383                         }
2384 
2385                         while ( nOverY > 0 && ( ((const ScMergeFlagAttr*)pDoc->GetAttr(
2386                                 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_VER ) )
2387                         {
2388                             --nOverY;
2389                             nStartPosY -= nLayoutSign * (long) ( pDoc->GetRowHeight(nOverY,nTab) * nPPTY );
2390                         }
2391 
2392                         long nOutWidth = (long) ( pDoc->GetColWidth(nOverX,nTab) * nPPTX );
2393                         long nOutHeight = (long) ( pDoc->GetRowHeight(nOverY,nTab) * nPPTY );
2394 
2395                         const ScMergeAttr* pMerge = (const ScMergeAttr*)
2396                                     pDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE );
2397                         SCCOL nCountX = pMerge->GetColMerge();
2398                         for (SCCOL i=1; i<nCountX; i++)
2399                             nOutWidth += (long) ( pDoc->GetColWidth(nOverX+i,nTab) * nPPTX );
2400                         SCROW nCountY = pMerge->GetRowMerge();
2401                         nOutHeight += (long) pDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, nPPTY);
2402 
2403                         if ( bLayoutRTL )
2404                             nStartPosX -= nOutWidth - 1;
2405                         aCellRect = Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2406                     }
2407                     else
2408                     {
2409                         long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2410                         long nOutHeight = pThisRowInfo->nHeight;
2411 
2412                         if ( pInfo->bMerged && pInfo->pPatternAttr )
2413                         {
2414                             SCCOL nOverX = nX;
2415                             SCROW nOverY = nY;
2416                             const ScMergeAttr* pMerge =
2417                                     (ScMergeAttr*)&pInfo->pPatternAttr->GetItem(ATTR_MERGE);
2418                             SCCOL nCountX = pMerge->GetColMerge();
2419                             for (SCCOL i=1; i<nCountX; i++)
2420                                 nOutWidth += (long) ( pDoc->GetColWidth(nOverX+i,nTab) * nPPTX );
2421                             SCROW nCountY = pMerge->GetRowMerge();
2422                             nOutHeight += (long) pDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, nPPTY);
2423                         }
2424 
2425                         long nStartPosX = nPosX;
2426                         if ( bLayoutRTL )
2427                             nStartPosX -= nOutWidth - 1;
2428                         // #i80447# create aCellRect from two points in case nOutWidth is 0
2429                         aCellRect = Rectangle( Point( nStartPosX, nPosY ),
2430                                                Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2431                     }
2432 
2433                     aCellRect.Bottom() -= 1;    // don't paint over the cell grid
2434                     if ( bLayoutRTL )
2435                         aCellRect.Left() += 1;
2436                     else
2437                         aCellRect.Right() -= 1;
2438 
2439                     long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX );
2440                     Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2441 
2442                     if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_RIGHT : SC_CLIPMARK_LEFT ) )
2443                     {
2444                         //  visually left
2445                         Rectangle aMarkRect = aCellRect;
2446                         aMarkRect.Right() = aCellRect.Left()+nMarkPixel-1;
2447 #if 0
2448                         //! Test
2449                         pDev->SetLineColor(); pDev->SetFillColor(COL_YELLOW);
2450                         pDev->DrawRect(aMarkRect);
2451                         //! Test
2452 #endif
2453                         SvxFont::DrawArrow( *pDev, aMarkRect, aMarkSize, aArrowFillCol, sal_True );
2454                     }
2455                     if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_LEFT : SC_CLIPMARK_RIGHT ) )
2456                     {
2457                         //  visually right
2458                         Rectangle aMarkRect = aCellRect;
2459                         aMarkRect.Left() = aCellRect.Right()-nMarkPixel+1;
2460 #if 0
2461                         //! Test
2462                         pDev->SetLineColor(); pDev->SetFillColor(COL_LIGHTGREEN);
2463                         pDev->DrawRect(aMarkRect);
2464                         //! Test
2465 #endif
2466                         SvxFont::DrawArrow( *pDev, aMarkRect, aMarkSize, aArrowFillCol, sal_False );
2467                     }
2468                 }
2469                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2470             }
2471         }
2472         nPosY += pThisRowInfo->nHeight;
2473     }
2474 
2475     pDev->SetDrawMode(nOldDrawMode);
2476 }
2477 
2478 
2479 
2480