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