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