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