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