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