xref: /aoo41x/main/sc/source/ui/view/output.cxx (revision 0deba7fb)
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