xref: /trunk/main/sc/source/ui/view/output.cxx (revision dfbf5fd71e5d6a24d1fe5b6874b682c628cd37aa)
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 Region ScOutputData::GetChangedAreaRegion()
1689 {
1690     Region aRegion;
1691     Rectangle aDrawingRect;
1692     bool bHad(false);
1693     long nPosY = nScrY;
1694     SCSIZE nArrY;
1695 
1696     aDrawingRect.Left() = nScrX;
1697     aDrawingRect.Right() = nScrX+nScrW-1;
1698 
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 = true;
1709             }
1710 
1711             aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1712         }
1713         else if(bHad)
1714         {
1715             aRegion.Union(pDev->PixelToLogic(aDrawingRect));
1716             bHad = false;
1717         }
1718 
1719         nPosY += pRowInfo[nArrY].nHeight;
1720     }
1721 
1722     if(bHad)
1723     {
1724         aRegion.Union(pDev->PixelToLogic(aDrawingRect));
1725     }
1726 
1727     return aRegion;
1728 }
1729 
1730 sal_Bool ScOutputData::SetChangedClip()
1731 {
1732     PolyPolygon aPoly;
1733 
1734     Rectangle aDrawingRect;
1735     aDrawingRect.Left() = nScrX;
1736     aDrawingRect.Right() = nScrX+nScrW-1;
1737 
1738     sal_Bool    bHad    = sal_False;
1739     long    nPosY   = nScrY;
1740     SCSIZE  nArrY;
1741     for (nArrY=1; nArrY+1<nArrCount; nArrY++)
1742     {
1743         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1744 
1745         if ( pThisRowInfo->bChanged )
1746         {
1747             if (!bHad)
1748             {
1749                 aDrawingRect.Top() = nPosY;
1750                 bHad = sal_True;
1751             }
1752             aDrawingRect.Bottom() = nPosY + pRowInfo[nArrY].nHeight - 1;
1753         }
1754         else if (bHad)
1755         {
1756             aPoly.Insert( Polygon( pDev->PixelToLogic(aDrawingRect) ) );
1757             bHad = sal_False;
1758         }
1759         nPosY += pRowInfo[nArrY].nHeight;
1760     }
1761 
1762     if (bHad)
1763         aPoly.Insert( Polygon( pDev->PixelToLogic(aDrawingRect) ) );
1764 
1765     sal_Bool bRet = (aPoly.Count() != 0);
1766     if (bRet)
1767         pDev->SetClipRegion(Region(aPoly));
1768     return bRet;
1769 }
1770 
1771 void ScOutputData::FindChanged()
1772 {
1773     SCCOL   nX;
1774     SCSIZE  nArrY;
1775 
1776     sal_Bool bWasIdleDisabled = pDoc->IsIdleDisabled();
1777     pDoc->DisableIdle( sal_True );
1778     for (nArrY=0; nArrY<nArrCount; nArrY++)
1779         pRowInfo[nArrY].bChanged = sal_False;
1780 
1781     sal_Bool bProgress = sal_False;
1782     for (nArrY=0; nArrY<nArrCount; nArrY++)
1783     {
1784         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1785         for (nX=nX1; nX<=nX2; nX++)
1786         {
1787             ScBaseCell* pCell = pThisRowInfo->pCellInfo[nX+1].pCell;
1788             if (pCell)
1789                 if (pCell->GetCellType() == CELLTYPE_FORMULA)
1790                 {
1791                     ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1792                     if ( !bProgress && pFCell->GetDirty() )
1793                     {
1794                         ScProgress::CreateInterpretProgress( pDoc, sal_True );
1795                         bProgress = sal_True;
1796                     }
1797                     if (!pFCell->IsRunning())
1798                     {
1799                         (void)pFCell->GetValue();
1800                         if (pFCell->IsChanged())
1801                         {
1802                             pThisRowInfo->bChanged = sal_True;
1803                             if ( pThisRowInfo->pCellInfo[nX+1].bMerged )
1804                             {
1805                                 SCSIZE nOverY = nArrY + 1;
1806                                 while ( nOverY<nArrCount &&
1807                                         pRowInfo[nOverY].pCellInfo[nX+1].bVOverlapped )
1808                                 {
1809                                     pRowInfo[nOverY].bChanged = sal_True;
1810                                     ++nOverY;
1811                                 }
1812                             }
1813                         }
1814                     }
1815                 }
1816         }
1817     }
1818     if ( bProgress )
1819         ScProgress::DeleteInterpretProgress();
1820     pDoc->DisableIdle( bWasIdleDisabled );
1821 }
1822 
1823 #ifdef OLD_SELECTION_PAINT
1824 void ScOutputData::DrawMark( Window* pWin )
1825 {
1826     Rectangle aRect;
1827     ScInvertMerger aInvert( pWin );
1828     //! additional method AddLineRect for ScInvertMerger?
1829 
1830     long nPosY = nScrY;
1831     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1832     {
1833         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1834         if (pThisRowInfo->bChanged)
1835         {
1836             long nPosX = nScrX;
1837             if (bLayoutRTL)
1838                 nPosX += nMirrorW - 1;      // always in pixels
1839 
1840             aRect = Rectangle( Point( nPosX,nPosY ), Size(1, pThisRowInfo->nHeight) );
1841             if (bLayoutRTL)
1842                 aRect.Left() = aRect.Right() + 1;
1843             else
1844                 aRect.Right() = aRect.Left() - 1;
1845 
1846             sal_Bool bOldMarked = sal_False;
1847             for (SCCOL nX=nX1; nX<=nX2; nX++)
1848             {
1849                 if (pThisRowInfo->pCellInfo[nX+1].bMarked != bOldMarked)
1850                 {
1851                     if (bOldMarked && aRect.Right() >= aRect.Left())
1852                         aInvert.AddRect( aRect );
1853 
1854                     if (bLayoutRTL)
1855                         aRect.Right() = nPosX;
1856                     else
1857                         aRect.Left() = nPosX;
1858 
1859                     bOldMarked = pThisRowInfo->pCellInfo[nX+1].bMarked;
1860                 }
1861 
1862                 if (bLayoutRTL)
1863                 {
1864                     nPosX -= pRowInfo[0].pCellInfo[nX+1].nWidth;
1865                     aRect.Left() = nPosX+1;
1866                 }
1867                 else
1868                 {
1869                     nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth;
1870                     aRect.Right() = nPosX-1;
1871                 }
1872             }
1873             if (bOldMarked && aRect.Right() >= aRect.Left())
1874                 aInvert.AddRect( aRect );
1875         }
1876         nPosY += pThisRowInfo->nHeight;
1877     }
1878 }
1879 #endif
1880 
1881 void ScOutputData::DrawRefMark( SCCOL nRefStartX, SCROW nRefStartY,
1882                                 SCCOL nRefEndX, SCROW nRefEndY,
1883                                 const Color& rColor, sal_Bool bHandle )
1884 {
1885     PutInOrder( nRefStartX, nRefEndX );
1886     PutInOrder( nRefStartY, nRefEndY );
1887 
1888     if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1889         pDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1890 
1891     if ( nRefStartX <= nVisX2 && nRefEndX >= nVisX1 &&
1892          nRefStartY <= nVisY2 && nRefEndY >= nVisY1 )
1893     {
1894         long nMinX = nScrX;
1895         long nMinY = nScrY;
1896         long nMaxX = nScrX+nScrW-1;
1897         long nMaxY = nScrY+nScrH-1;
1898         if ( bLayoutRTL )
1899         {
1900             long nTemp = nMinX;
1901             nMinX = nMaxX;
1902             nMaxX = nTemp;
1903         }
1904         long nLayoutSign = bLayoutRTL ? -1 : 1;
1905 
1906         sal_Bool bTop    = sal_False;
1907         sal_Bool bBottom = sal_False;
1908         sal_Bool bLeft   = sal_False;
1909         sal_Bool bRight  = sal_False;
1910 
1911         long nPosY = nScrY;
1912         sal_Bool bNoStartY = ( nY1 < nRefStartY );
1913         sal_Bool bNoEndY   = sal_False;
1914         for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)      // loop to end for bNoEndY check
1915         {
1916             SCROW nY = pRowInfo[nArrY].nRowNo;
1917 
1918             if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
1919             {
1920                 nMinY = nPosY;
1921                 bTop = sal_True;
1922             }
1923             if ( nY==nRefEndY )
1924             {
1925                 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 2;
1926                 bBottom = sal_True;
1927             }
1928             if ( nY>nRefEndY && bNoEndY )
1929             {
1930                 nMaxY = nPosY-2;
1931                 bBottom = sal_True;
1932             }
1933             bNoStartY = ( nY < nRefStartY );
1934             bNoEndY   = ( nY < nRefEndY );
1935             nPosY += pRowInfo[nArrY].nHeight;
1936         }
1937 
1938         long nPosX = nScrX;
1939         if ( bLayoutRTL )
1940             nPosX += nMirrorW - 1;      // always in pixels
1941 
1942         for (SCCOL nX=nX1; nX<=nX2; nX++)
1943         {
1944             if ( nX==nRefStartX )
1945             {
1946                 nMinX = nPosX;
1947                 bLeft = sal_True;
1948             }
1949             if ( nX==nRefEndX )
1950             {
1951                 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 2 ) * nLayoutSign;
1952                 bRight = sal_True;
1953             }
1954             nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
1955         }
1956 
1957         if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
1958              nMaxY >= nMinY )
1959         {
1960             pDev->SetLineColor( rColor );
1961             if (bTop && bBottom && bLeft && bRight)
1962             {
1963                 pDev->SetFillColor();
1964                 pDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
1965             }
1966             else
1967             {
1968                 if (bTop)
1969                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
1970                 if (bBottom)
1971                     pDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
1972                 if (bLeft)
1973                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
1974                 if (bRight)
1975                     pDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
1976             }
1977             if ( bHandle && bRight && bBottom )
1978             {
1979                 pDev->SetLineColor();
1980                 pDev->SetFillColor( rColor );
1981                 pDev->DrawRect( Rectangle( nMaxX-3*nLayoutSign, nMaxY-3, nMaxX+nLayoutSign, nMaxY+1 ) );
1982             }
1983         }
1984     }
1985 }
1986 
1987 void ScOutputData::DrawOneChange( SCCOL nRefStartX, SCROW nRefStartY,
1988                                 SCCOL nRefEndX, SCROW nRefEndY,
1989                                 const Color& rColor, sal_uInt16 nType )
1990 {
1991     PutInOrder( nRefStartX, nRefEndX );
1992     PutInOrder( nRefStartY, nRefEndY );
1993 
1994     if ( nRefStartX == nRefEndX && nRefStartY == nRefEndY )
1995         pDoc->ExtendMerge( nRefStartX, nRefStartY, nRefEndX, nRefEndY, nTab );
1996 
1997     if ( nRefStartX <= nVisX2 + 1 && nRefEndX >= nVisX1 &&
1998          nRefStartY <= nVisY2 + 1 && nRefEndY >= nVisY1 )       // +1 because it touches next cells left/top
1999     {
2000         long nMinX = nScrX;
2001         long nMinY = nScrY;
2002         long nMaxX = nScrX+nScrW-1;
2003         long nMaxY = nScrY+nScrH-1;
2004         if ( bLayoutRTL )
2005         {
2006             long nTemp = nMinX;
2007             nMinX = nMaxX;
2008             nMaxX = nTemp;
2009         }
2010         long nLayoutSign = bLayoutRTL ? -1 : 1;
2011 
2012         sal_Bool bTop    = sal_False;
2013         sal_Bool bBottom = sal_False;
2014         sal_Bool bLeft   = sal_False;
2015         sal_Bool bRight  = sal_False;
2016 
2017         long nPosY = nScrY;
2018         sal_Bool bNoStartY = ( nY1 < nRefStartY );
2019         sal_Bool bNoEndY   = sal_False;
2020         for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)      // loop to end for bNoEndY check
2021         {
2022             SCROW nY = pRowInfo[nArrY].nRowNo;
2023 
2024             if ( nY==nRefStartY || (nY>nRefStartY && bNoStartY) )
2025             {
2026                 nMinY = nPosY - 1;
2027                 bTop = sal_True;
2028             }
2029             if ( nY==nRefEndY )
2030             {
2031                 nMaxY = nPosY + pRowInfo[nArrY].nHeight - 1;
2032                 bBottom = sal_True;
2033             }
2034             if ( nY>nRefEndY && bNoEndY )
2035             {
2036                 nMaxY = nPosY - 1;
2037                 bBottom = sal_True;
2038             }
2039             bNoStartY = ( nY < nRefStartY );
2040             bNoEndY   = ( nY < nRefEndY );
2041             nPosY += pRowInfo[nArrY].nHeight;
2042         }
2043 
2044         long nPosX = nScrX;
2045         if ( bLayoutRTL )
2046             nPosX += nMirrorW - 1;      // always in pixels
2047 
2048         for (SCCOL nX=nX1; nX<=nX2+1; nX++)
2049         {
2050             if ( nX==nRefStartX )
2051             {
2052                 nMinX = nPosX - nLayoutSign;
2053                 bLeft = sal_True;
2054             }
2055             if ( nX==nRefEndX )
2056             {
2057                 nMaxX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 1 ) * nLayoutSign;
2058                 bRight = sal_True;
2059             }
2060             nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2061         }
2062 
2063         if ( nMaxX * nLayoutSign >= nMinX * nLayoutSign &&
2064              nMaxY >= nMinY )
2065         {
2066             if ( nType == SC_CAT_DELETE_ROWS )
2067                 bLeft = bRight = bBottom = sal_False;       //! dicke Linie ???
2068             else if ( nType == SC_CAT_DELETE_COLS )
2069                 bTop = bBottom = bRight = sal_False;        //! dicke Linie ???
2070 
2071             pDev->SetLineColor( rColor );
2072             if (bTop && bBottom && bLeft && bRight)
2073             {
2074                 pDev->SetFillColor();
2075                 pDev->DrawRect( Rectangle( nMinX, nMinY, nMaxX, nMaxY ) );
2076             }
2077             else
2078             {
2079                 if (bTop)
2080                 {
2081                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMaxX,nMinY ) );
2082                     if ( nType == SC_CAT_DELETE_ROWS )
2083                         pDev->DrawLine( Point( nMinX,nMinY+1 ), Point( nMaxX,nMinY+1 ) );
2084                 }
2085                 if (bBottom)
2086                     pDev->DrawLine( Point( nMinX,nMaxY ), Point( nMaxX,nMaxY ) );
2087                 if (bLeft)
2088                 {
2089                     pDev->DrawLine( Point( nMinX,nMinY ), Point( nMinX,nMaxY ) );
2090                     if ( nType == SC_CAT_DELETE_COLS )
2091                         pDev->DrawLine( Point( nMinX+nLayoutSign,nMinY ), Point( nMinX+nLayoutSign,nMaxY ) );
2092                 }
2093                 if (bRight)
2094                     pDev->DrawLine( Point( nMaxX,nMinY ), Point( nMaxX,nMaxY ) );
2095             }
2096             if ( bLeft && bTop )
2097             {
2098                 pDev->SetLineColor();
2099                 pDev->SetFillColor( rColor );
2100                 pDev->DrawRect( Rectangle( nMinX+nLayoutSign, nMinY+1, nMinX+3*nLayoutSign, nMinY+3 ) );
2101             }
2102         }
2103     }
2104 }
2105 
2106 void ScOutputData::DrawChangeTrack()
2107 {
2108     ScChangeTrack* pTrack = pDoc->GetChangeTrack();
2109     ScChangeViewSettings* pSettings = pDoc->GetChangeViewSettings();
2110     if ( !pTrack || !pTrack->GetFirst() || !pSettings || !pSettings->ShowChanges() )
2111         return;         // nix da oder abgeschaltet
2112 
2113     ScActionColorChanger aColorChanger(*pTrack);
2114 
2115     //  Clipping passiert von aussen
2116     //! ohne Clipping, nur betroffene Zeilen painten ??!??!?
2117 
2118     SCCOL nEndX = nX2;
2119     SCROW nEndY = nY2;
2120     if ( nEndX < MAXCOL ) ++nEndX;      // auch noch von der naechsten Zelle, weil die Markierung
2121     if ( nEndY < MAXROW ) ++nEndY;      // in die jeweils vorhergehende Zelle hineinragt
2122     ScRange aViewRange( nX1, nY1, nTab, nEndX, nEndY, nTab );
2123     const ScChangeAction* pAction = pTrack->GetFirst();
2124     while (pAction)
2125     {
2126         ScChangeActionType eActionType;
2127         if ( pAction->IsVisible() )
2128         {
2129             eActionType = pAction->GetType();
2130             const ScBigRange& rBig = pAction->GetBigRange();
2131             if ( rBig.aStart.Tab() == nTab )
2132             {
2133                 ScRange aRange = rBig.MakeRange();
2134 
2135                 if ( eActionType == SC_CAT_DELETE_ROWS )
2136                     aRange.aEnd.SetRow( aRange.aStart.Row() );
2137                 else if ( eActionType == SC_CAT_DELETE_COLS )
2138                     aRange.aEnd.SetCol( aRange.aStart.Col() );
2139 
2140                 if ( aRange.Intersects( aViewRange ) &&
2141                      ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc ) )
2142                 {
2143                     aColorChanger.Update( *pAction );
2144                     Color aColor( aColorChanger.GetColor() );
2145                     DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2146                                     aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2147 
2148                 }
2149             }
2150             if ( eActionType == SC_CAT_MOVE &&
2151                     ((const ScChangeActionMove*)pAction)->
2152                         GetFromRange().aStart.Tab() == nTab )
2153             {
2154                 ScRange aRange = ((const ScChangeActionMove*)pAction)->
2155                         GetFromRange().MakeRange();
2156                 if ( aRange.Intersects( aViewRange ) &&
2157                      ScViewUtil::IsActionShown( *pAction, *pSettings, *pDoc ) )
2158                 {
2159                     aColorChanger.Update( *pAction );
2160                     Color aColor( aColorChanger.GetColor() );
2161                     DrawOneChange( aRange.aStart.Col(), aRange.aStart.Row(),
2162                                     aRange.aEnd.Col(), aRange.aEnd.Row(), aColor, sal::static_int_cast<sal_uInt16>(eActionType) );
2163                 }
2164             }
2165         }
2166 
2167         pAction = pAction->GetNext();
2168     }
2169 }
2170 
2171 void ScOutputData::DrawNoteMarks()
2172 {
2173     sal_Bool bFirst = sal_True;
2174 
2175     long nInitPosX = nScrX;
2176     if ( bLayoutRTL )
2177         nInitPosX += nMirrorW - 1;              // always in pixels
2178     long nLayoutSign = bLayoutRTL ? -1 : 1;
2179 
2180     long nPosY = nScrY;
2181     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2182     {
2183         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2184         if ( pThisRowInfo->bChanged )
2185         {
2186             long nPosX = nInitPosX;
2187             for (SCCOL nX=nX1; nX<=nX2; nX++)
2188             {
2189                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2190                 ScBaseCell* pCell = pInfo->pCell;
2191                 sal_Bool bIsMerged = sal_False;
2192 
2193                 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2194                 {
2195                     // find start of merged cell
2196                     bIsMerged = sal_True;
2197                     SCROW nY = pRowInfo[nArrY].nRowNo;
2198                     SCCOL nMergeX = nX;
2199                     SCROW nMergeY = nY;
2200                     pDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2201                     pCell = pDoc->GetCell( ScAddress(nMergeX,nMergeY,nTab) );
2202                     // use origin's pCell for NotePtr test below
2203                 }
2204 
2205                 if ( pCell && pCell->HasNote() && ( bIsMerged ||
2206                         ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2207                 {
2208                     if (bFirst)
2209                     {
2210                         pDev->SetLineColor();
2211 
2212                         const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2213                         if ( bUseStyleColor && rStyleSettings.GetHighContrastMode() )
2214                             pDev->SetFillColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2215                         else
2216                             pDev->SetFillColor(COL_LIGHTRED);
2217 
2218                         bFirst = sal_False;
2219                     }
2220 
2221                     long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - 4 ) * nLayoutSign;
2222                     if ( bIsMerged || pInfo->bMerged )
2223                     {
2224                         //  if merged, add widths of all cells
2225                         SCCOL nNextX = nX + 1;
2226                         while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2227                         {
2228                             nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2229                             ++nNextX;
2230                         }
2231                     }
2232                     if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2233                         pDev->DrawRect( Rectangle( nMarkX,nPosY,nMarkX+2*nLayoutSign,nPosY+2 ) );
2234                 }
2235 
2236                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2237             }
2238         }
2239         nPosY += pThisRowInfo->nHeight;
2240     }
2241 }
2242 
2243 void ScOutputData::AddPDFNotes()
2244 {
2245     vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2246     if ( !pPDFData || !pPDFData->GetIsExportNotes() )
2247         return;
2248 
2249     long nInitPosX = nScrX;
2250     if ( bLayoutRTL )
2251     {
2252         Size aOnePixel = pDev->PixelToLogic(Size(1,1));
2253         long nOneX = aOnePixel.Width();
2254         nInitPosX += nMirrorW - nOneX;
2255     }
2256     long nLayoutSign = bLayoutRTL ? -1 : 1;
2257 
2258     long nPosY = nScrY;
2259     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2260     {
2261         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2262         if ( pThisRowInfo->bChanged )
2263         {
2264             long nPosX = nInitPosX;
2265             for (SCCOL nX=nX1; nX<=nX2; nX++)
2266             {
2267                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2268                 ScBaseCell* pCell = pInfo->pCell;
2269                 sal_Bool bIsMerged = sal_False;
2270                 SCROW nY = pRowInfo[nArrY].nRowNo;
2271                 SCCOL nMergeX = nX;
2272                 SCROW nMergeY = nY;
2273 
2274                 if ( nX==nX1 && pInfo->bHOverlapped && !pInfo->bVOverlapped )
2275                 {
2276                     // find start of merged cell
2277                     bIsMerged = sal_True;
2278                     pDoc->ExtendOverlapped( nMergeX, nMergeY, nX, nY, nTab );
2279                     pCell = pDoc->GetCell( ScAddress(nMergeX,nMergeY,nTab) );
2280                     // use origin's pCell for NotePtr test below
2281                 }
2282 
2283                 if ( pCell && pCell->HasNote() && ( bIsMerged ||
2284                         ( !pInfo->bHOverlapped && !pInfo->bVOverlapped ) ) )
2285                 {
2286                     long nNoteWidth = (long)( SC_CLIPMARK_SIZE * nPPTX );
2287                     long nNoteHeight = (long)( SC_CLIPMARK_SIZE * nPPTY );
2288 
2289                     long nMarkX = nPosX + ( pRowInfo[0].pCellInfo[nX+1].nWidth - nNoteWidth ) * nLayoutSign;
2290                     if ( bIsMerged || pInfo->bMerged )
2291                     {
2292                         //  if merged, add widths of all cells
2293                         SCCOL nNextX = nX + 1;
2294                         while ( nNextX <= nX2 + 1 && pThisRowInfo->pCellInfo[nNextX+1].bHOverlapped )
2295                         {
2296                             nMarkX += pRowInfo[0].pCellInfo[nNextX+1].nWidth * nLayoutSign;
2297                             ++nNextX;
2298                         }
2299                     }
2300                     if ( bLayoutRTL ? ( nMarkX >= 0 ) : ( nMarkX < nScrX+nScrW ) )
2301                     {
2302                         Rectangle aNoteRect( nMarkX, nPosY, nMarkX+nNoteWidth*nLayoutSign, nPosY+nNoteHeight );
2303                         const ScPostIt* pNote = pCell->GetNote();
2304 
2305                         // Note title is the cell address (as on printed note pages)
2306                         String aTitle;
2307                         ScAddress aAddress( nMergeX, nMergeY, nTab );
2308                         aAddress.Format( aTitle, SCA_VALID, pDoc, pDoc->GetAddressConvention() );
2309 
2310                         // Content has to be a simple string without line breaks
2311                         String aContent = pNote->GetText();
2312                         xub_StrLen nPos;
2313                         while ( (nPos=aContent.Search('\n')) != STRING_NOTFOUND )
2314                             aContent.SetChar( nPos, ' ' );
2315 
2316                         vcl::PDFNote aNote;
2317                         aNote.Title = aTitle;
2318                         aNote.Contents = aContent;
2319                         pPDFData->CreateNote( aNoteRect, aNote );
2320                     }
2321                 }
2322 
2323                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2324             }
2325         }
2326         nPosY += pThisRowInfo->nHeight;
2327     }
2328 }
2329 
2330 void ScOutputData::DrawClipMarks()
2331 {
2332     if (!bAnyClipped)
2333         return;
2334 
2335     Color aArrowFillCol( COL_LIGHTRED );
2336 
2337     sal_uLong nOldDrawMode = pDev->GetDrawMode();
2338     const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
2339     if ( bUseStyleColor && rStyleSettings.GetHighContrastMode() )
2340     {
2341         //  use DrawMode to change the arrow's outline color
2342         pDev->SetDrawMode( nOldDrawMode | DRAWMODE_SETTINGSLINE );
2343         //  use text color also for the fill color
2344         aArrowFillCol.SetColor( SC_MOD()->GetColorConfig().GetColorValue(svtools::FONTCOLOR).nColor );
2345     }
2346 
2347     long nInitPosX = nScrX;
2348     if ( bLayoutRTL )
2349         nInitPosX += nMirrorW - 1;              // always in pixels
2350     long nLayoutSign = bLayoutRTL ? -1 : 1;
2351 
2352     Rectangle aCellRect;
2353     long nPosY = nScrY;
2354     for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
2355     {
2356         RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2357         if ( pThisRowInfo->bChanged )
2358         {
2359             SCROW nY = pThisRowInfo->nRowNo;
2360             long nPosX = nInitPosX;
2361             for (SCCOL nX=nX1; nX<=nX2; nX++)
2362             {
2363                 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
2364                 if (pInfo->nClipMark)
2365                 {
2366                     if (pInfo->bHOverlapped || pInfo->bVOverlapped)
2367                     {
2368                         //  merge origin may be outside of visible area - use document functions
2369 
2370                         SCCOL nOverX = nX;
2371                         SCROW nOverY = nY;
2372                         long nStartPosX = nPosX;
2373                         long nStartPosY = nPosY;
2374 
2375                         while ( nOverX > 0 && ( ((const ScMergeFlagAttr*)pDoc->GetAttr(
2376                                 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_HOR ) )
2377                         {
2378                             --nOverX;
2379                             nStartPosX -= nLayoutSign * (long) ( pDoc->GetColWidth(nOverX,nTab) * nPPTX );
2380                         }
2381 
2382                         while ( nOverY > 0 && ( ((const ScMergeFlagAttr*)pDoc->GetAttr(
2383                                 nOverX, nOverY, nTab, ATTR_MERGE_FLAG ))->GetValue() & SC_MF_VER ) )
2384                         {
2385                             --nOverY;
2386                             nStartPosY -= nLayoutSign * (long) ( pDoc->GetRowHeight(nOverY,nTab) * nPPTY );
2387                         }
2388 
2389                         long nOutWidth = (long) ( pDoc->GetColWidth(nOverX,nTab) * nPPTX );
2390                         long nOutHeight = (long) ( pDoc->GetRowHeight(nOverY,nTab) * nPPTY );
2391 
2392                         const ScMergeAttr* pMerge = (const ScMergeAttr*)
2393                                     pDoc->GetAttr( nOverX, nOverY, nTab, ATTR_MERGE );
2394                         SCCOL nCountX = pMerge->GetColMerge();
2395                         for (SCCOL i=1; i<nCountX; i++)
2396                             nOutWidth += (long) ( pDoc->GetColWidth(nOverX+i,nTab) * nPPTX );
2397                         SCROW nCountY = pMerge->GetRowMerge();
2398                         nOutHeight += (long) pDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, nPPTY);
2399 
2400                         if ( bLayoutRTL )
2401                             nStartPosX -= nOutWidth - 1;
2402                         aCellRect = Rectangle( Point( nStartPosX, nStartPosY ), Size( nOutWidth, nOutHeight ) );
2403                     }
2404                     else
2405                     {
2406                         long nOutWidth = pRowInfo[0].pCellInfo[nX+1].nWidth;
2407                         long nOutHeight = pThisRowInfo->nHeight;
2408 
2409                         if ( pInfo->bMerged && pInfo->pPatternAttr )
2410                         {
2411                             SCCOL nOverX = nX;
2412                             SCROW nOverY = nY;
2413                             const ScMergeAttr* pMerge =
2414                                     (ScMergeAttr*)&pInfo->pPatternAttr->GetItem(ATTR_MERGE);
2415                             SCCOL nCountX = pMerge->GetColMerge();
2416                             for (SCCOL i=1; i<nCountX; i++)
2417                                 nOutWidth += (long) ( pDoc->GetColWidth(nOverX+i,nTab) * nPPTX );
2418                             SCROW nCountY = pMerge->GetRowMerge();
2419                             nOutHeight += (long) pDoc->GetScaledRowHeight( nOverY+1, nOverY+nCountY-1, nTab, nPPTY);
2420                         }
2421 
2422                         long nStartPosX = nPosX;
2423                         if ( bLayoutRTL )
2424                             nStartPosX -= nOutWidth - 1;
2425                         // #i80447# create aCellRect from two points in case nOutWidth is 0
2426                         aCellRect = Rectangle( Point( nStartPosX, nPosY ),
2427                                                Point( nStartPosX+nOutWidth-1, nPosY+nOutHeight-1 ) );
2428                     }
2429 
2430                     aCellRect.Bottom() -= 1;    // don't paint over the cell grid
2431                     if ( bLayoutRTL )
2432                         aCellRect.Left() += 1;
2433                     else
2434                         aCellRect.Right() -= 1;
2435 
2436                     long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX );
2437                     Size aMarkSize( nMarkPixel, (nMarkPixel-1)*2 );
2438 
2439                     if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_RIGHT : SC_CLIPMARK_LEFT ) )
2440                     {
2441                         //  visually left
2442                         Rectangle aMarkRect = aCellRect;
2443                         aMarkRect.Right() = aCellRect.Left()+nMarkPixel-1;
2444 #if 0
2445                         //! Test
2446                         pDev->SetLineColor(); pDev->SetFillColor(COL_YELLOW);
2447                         pDev->DrawRect(aMarkRect);
2448                         //! Test
2449 #endif
2450                         SvxFont::DrawArrow( *pDev, aMarkRect, aMarkSize, aArrowFillCol, sal_True );
2451                     }
2452                     if ( pInfo->nClipMark & ( bLayoutRTL ? SC_CLIPMARK_LEFT : SC_CLIPMARK_RIGHT ) )
2453                     {
2454                         //  visually right
2455                         Rectangle aMarkRect = aCellRect;
2456                         aMarkRect.Left() = aCellRect.Right()-nMarkPixel+1;
2457 #if 0
2458                         //! Test
2459                         pDev->SetLineColor(); pDev->SetFillColor(COL_LIGHTGREEN);
2460                         pDev->DrawRect(aMarkRect);
2461                         //! Test
2462 #endif
2463                         SvxFont::DrawArrow( *pDev, aMarkRect, aMarkSize, aArrowFillCol, sal_False );
2464                     }
2465                 }
2466                 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2467             }
2468         }
2469         nPosY += pThisRowInfo->nHeight;
2470     }
2471 
2472     pDev->SetDrawMode(nOldDrawMode);
2473 }
2474 
2475 
2476 
2477