xref: /AOO41X/main/sc/source/ui/view/output2.cxx (revision 1ecadb572e7010ff3b3382ad9bf179dbc6efadbb)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_sc.hxx"
30 
31 
32 
33 
34 // INCLUDE ---------------------------------------------------------------
35 
36 #include "scitems.hxx"
37 #include <editeng/eeitem.hxx>
38 
39 
40 #include <editeng/adjitem.hxx>
41 #include <svx/algitem.hxx>
42 #include <editeng/brshitem.hxx>
43 #include <svtools/colorcfg.hxx>
44 #include <editeng/colritem.hxx>
45 #include <editeng/editobj.hxx>
46 #include <editeng/editstat.hxx>
47 #include <editeng/fhgtitem.hxx>
48 #include <editeng/forbiddencharacterstable.hxx>
49 #include <editeng/frmdiritem.hxx>
50 #include <editeng/langitem.hxx>
51 #include <svx/rotmodit.hxx>
52 #include <editeng/scripttypeitem.hxx>
53 #include <editeng/udlnitem.hxx>
54 #include <editeng/unolingu.hxx>
55 #include <svl/zforlist.hxx>
56 #include <svl/zformat.hxx>
57 #include <vcl/svapp.hxx>
58 #include <vcl/metric.hxx>
59 #include <vcl/outdev.hxx>
60 #include <vcl/pdfextoutdevdata.hxx>
61 
62 #ifndef _SVSTDARR_USHORTS
63 #define _SVSTDARR_USHORTS
64 #include <svl/svstdarr.hxx>
65 #endif
66 
67 #include "output.hxx"
68 #include "document.hxx"
69 #include "cell.hxx"
70 #include "attrib.hxx"
71 #include "patattr.hxx"
72 #include "cellform.hxx"
73 #include "editutil.hxx"
74 #include "progress.hxx"
75 #include "scmod.hxx"
76 #include "fillinfo.hxx"
77 
78 #include <math.h>
79 
80 //!	Autofilter-Breite mit column.cxx zusammenfassen
81 #define DROPDOWN_BITMAP_SIZE        18
82 
83 #define DRAWTEXT_MAX	32767
84 
85 const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
86 
87 // STATIC DATA -----------------------------------------------------------
88 
89 
90 // -----------------------------------------------------------------------
91 
92 class ScDrawStringsVars
93 {
94 	ScOutputData*		pOutput;				// Verbindung
95 
96 	const ScPatternAttr* pPattern;				// Attribute
97 	const SfxItemSet*	pCondSet;				// aus bedingter Formatierung
98 
99 	Font				aFont;					// aus Attributen erzeugt
100 	FontMetric			aMetric;
101 	long				nAscentPixel;			// always pixels
102 	SvxCellOrientation	eAttrOrient;
103 	SvxCellHorJustify	eAttrHorJust;
104 	SvxCellVerJustify	eAttrVerJust;
105 	const SvxMarginItem* pMargin;
106 	sal_uInt16				nIndent;
107 	sal_Bool				bRotated;
108 
109 	String				aString;				// Inhalte
110 	Size				aTextSize;
111 	long				nOriginalWidth;
112     long                nMaxDigitWidth;
113     long                nSignWidth;
114     long                nDotWidth;
115     long                nExpWidth;
116 
117 	ScBaseCell*			pLastCell;
118 	sal_uLong				nValueFormat;
119 	sal_Bool				bLineBreak;
120     sal_Bool                bRepeat;
121     sal_Bool                bShrink;
122 
123 	sal_Bool				bPixelToLogic;
124 	sal_Bool				bCellContrast;
125 
126 	Color				aBackConfigColor;		// used for ScPatternAttr::GetFont calls
127 	Color				aTextConfigColor;
128 
129 public:
130 				ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL);
131 				~ScDrawStringsVars();
132 
133 				//	SetPattern = ex-SetVars
134 				//	SetPatternSimple: ohne Font
135 
136 	void		SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet, ScBaseCell* pCell, sal_uInt8 nScript );
137 	void		SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
138 
139 	sal_Bool		SetText( ScBaseCell* pCell );	// sal_True -> pOldPattern vergessen
140     void        SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth );
141 	void		SetAutoText( const String& rAutoText );
142 
143 	const ScPatternAttr*	GetPattern() const		{ return pPattern; }
144 	SvxCellOrientation		GetOrient() const		{ return eAttrOrient; }
145 	SvxCellHorJustify		GetHorJust() const		{ return eAttrHorJust; }
146 	SvxCellVerJustify		GetVerJust() const		{ return eAttrVerJust; }
147 	const SvxMarginItem*	GetMargin() const		{ return pMargin; }
148 
149 	sal_uInt16	GetLeftTotal() const		{ return pMargin->GetLeftMargin() + nIndent; }
150 
151 	const String&			GetString() const		{ return aString; }
152 	const Size&				GetTextSize() const		{ return aTextSize; }
153 	long					GetOriginalWidth() const { return nOriginalWidth; }
154 
155     sal_uLong   GetResultValueFormat( const ScBaseCell* pCell ) const;
156 
157 	sal_uLong	GetValueFormat() const					{ return nValueFormat; }
158 	sal_Bool	GetLineBreak() const					{ return bLineBreak; }
159 	sal_Bool    IsRepeat() const                        { return bRepeat; }
160     sal_Bool    IsShrink() const                        { return bShrink; }
161 
162 	long	GetAscent() const	{ return nAscentPixel; }
163 	sal_Bool	IsRotated() const	{ return bRotated; }
164 
165     void    SetShrinkScale( long nScale, sal_uInt8 nScript );
166 
167 	sal_Bool	HasCondHeight() const	{ return pCondSet && SFX_ITEM_SET ==
168 										pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True ); }
169 
170     sal_Bool    HasEditCharacters() const;
171 
172 private:
173     void        SetHashText();
174     long        GetMaxDigitWidth();     // in logic units
175     long        GetSignWidth();
176     long        GetDotWidth();
177     long        GetExpWidth();
178     void        TextChanged();
179 };
180 
181 //==================================================================
182 
183 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL) :
184 	pOutput		( pData ),
185 	pPattern	( NULL ),
186 	pCondSet	( NULL ),
187 	eAttrOrient	( SVX_ORIENTATION_STANDARD ),
188 	eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ),
189 	eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ),
190 	pMargin		( NULL ),
191 	nIndent		( 0 ),
192 	bRotated	( sal_False ),
193 	nOriginalWidth( 0 ),
194     nMaxDigitWidth( 0 ),
195     nSignWidth( 0 ),
196     nDotWidth( 0 ),
197     nExpWidth( 0 ),
198 	pLastCell	( NULL ),
199 	nValueFormat( 0 ),
200 	bLineBreak	( sal_False ),
201     bRepeat     ( sal_False ),
202     bShrink     ( sal_False ),
203 	bPixelToLogic( bPTL )
204 {
205 	ScModule* pScMod = SC_MOD();
206 	//	#105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
207 	bCellContrast = pOutput->bUseStyleColor &&
208 			Application::GetSettings().GetStyleSettings().GetHighContrastMode();
209 
210     const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
211     aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor );
212     aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor );
213 }
214 
215 ScDrawStringsVars::~ScDrawStringsVars()
216 {
217 }
218 
219 void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript )
220 {
221     // text remains valid, size is updated
222 
223     OutputDevice* pDev = pOutput->pDev;
224     OutputDevice* pRefDevice = pOutput->pRefDevice;
225     OutputDevice* pFmtDevice = pOutput->pFmtDevice;
226 
227     // call GetFont with a modified fraction, use only the height
228 
229     Fraction aFraction( nScale, 100 );
230     if ( !bPixelToLogic )
231         aFraction *= pOutput->aZoomY;
232     Font aTmpFont;
233 	pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
234 	long nNewHeight = aTmpFont.GetHeight();
235 	if ( nNewHeight > 0 )
236         aFont.SetHeight( nNewHeight );
237 
238     // set font and dependent variables as in SetPattern
239 
240 	pDev->SetFont( aFont );
241 	if ( pFmtDevice != pDev )
242 		pFmtDevice->SetFont( aFont );
243 
244 	aMetric = pFmtDevice->GetFontMetric();
245 	if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
246 	{
247 		OutputDevice* pDefaultDev = Application::GetDefaultDevice();
248 		MapMode aOld = pDefaultDev->GetMapMode();
249 		pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
250 		aMetric = pDefaultDev->GetFontMetric( aFont );
251 		pDefaultDev->SetMapMode( aOld );
252 	}
253 
254 	nAscentPixel = aMetric.GetAscent();
255 	if ( bPixelToLogic )
256 		nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
257 
258     SetAutoText( aString );     // same text again, to get text size
259 }
260 
261 void ScDrawStringsVars::SetPattern( const ScPatternAttr* pNew, const SfxItemSet* pSet,
262 									ScBaseCell* pCell, sal_uInt8 nScript )
263 {
264     nMaxDigitWidth = 0;
265     nSignWidth     = 0;
266     nDotWidth      = 0;
267     nExpWidth      = 0;
268 
269 	pPattern = pNew;
270 	pCondSet = pSet;
271 
272 	//	pPattern auswerten
273 
274 	OutputDevice* pDev = pOutput->pDev;
275 	OutputDevice* pRefDevice = pOutput->pRefDevice;
276 	OutputDevice* pFmtDevice = pOutput->pFmtDevice;
277 
278 	//	Font
279 
280 	ScAutoFontColorMode eColorMode;
281 	if ( pOutput->bUseStyleColor )
282 	{
283 		if ( pOutput->bForceAutoColor )
284 			eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
285 		else
286 			eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
287 	}
288 	else
289 		eColorMode = SC_AUTOCOL_PRINT;
290 
291 	if ( bPixelToLogic )
292 		pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript,
293 							&aBackConfigColor, &aTextConfigColor );
294 	else
295 		pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
296 							&aBackConfigColor, &aTextConfigColor );
297 	aFont.SetAlign(ALIGN_BASELINE);
298 
299 	//	Orientierung
300 
301     eAttrOrient = pPattern->GetCellOrientation( pCondSet );
302 
303 	//	alignment
304 
305     eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
306 
307     eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue();
308 	if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD )
309 		eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM;
310 
311 	//	line break
312 
313     bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue();
314 
315     //  handle "repeat" alignment
316 
317     bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT );
318     if ( bRepeat )
319     {
320         // "repeat" disables rotation (before constructing the font)
321         eAttrOrient = SVX_ORIENTATION_STANDARD;
322 
323         // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
324         if ( bLineBreak )
325             eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD;
326     }
327 
328 	short nRot;
329 	switch (eAttrOrient)
330 	{
331 		case SVX_ORIENTATION_STANDARD:
332 			nRot = 0;
333             bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) &&
334                        !bRepeat;
335 			break;
336 		case SVX_ORIENTATION_STACKED:
337 			nRot = 0;
338 			bRotated = sal_False;
339 			break;
340 		case SVX_ORIENTATION_TOPBOTTOM:
341 			nRot = 2700;
342 			bRotated = sal_False;
343 			break;
344 		case SVX_ORIENTATION_BOTTOMTOP:
345 			nRot = 900;
346 			bRotated = sal_False;
347 			break;
348 		default:
349 			DBG_ERROR("Falscher SvxCellOrientation Wert");
350 			nRot = 0;
351 			bRotated = sal_False;
352 			break;
353 	}
354 	aFont.SetOrientation( nRot );
355 
356 	//	Syntax-Modus
357 
358 	if (pOutput->bSyntaxMode)
359 		pOutput->SetSyntaxColor( &aFont, pCell );
360 
361 	pDev->SetFont( aFont );
362 	if ( pFmtDevice != pDev )
363 		pFmtDevice->SetFont( aFont );
364 
365 	aMetric = pFmtDevice->GetFontMetric();
366 
367 	//
368 	//	Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme
369 	//	-> Metric vom Bildschirm nehmen (wie EditEngine!)
370 	//
371 
372 	if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
373 	{
374 		OutputDevice* pDefaultDev = Application::GetDefaultDevice();
375 		MapMode aOld = pDefaultDev->GetMapMode();
376 		pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
377 		aMetric = pDefaultDev->GetFontMetric( aFont );
378 		pDefaultDev->SetMapMode( aOld );
379 	}
380 
381 	nAscentPixel = aMetric.GetAscent();
382 	if ( bPixelToLogic )
383 		nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
384 
385     Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() );
386 	pDev->SetTextLineColor( aULineColor );
387 
388     Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() );
389 	pDev->SetOverlineColor( aOLineColor );
390 
391 	//	Zahlenformat
392 
393 //    sal_uLong nOld = nValueFormat;
394 	nValueFormat = pPattern->GetNumberFormat( pOutput->pDoc->GetFormatTable(), pCondSet );
395 
396 /*	s.u.
397 	if (nValueFormat != nOld)
398 		pLastCell = NULL;			// immer neu formatieren
399 */
400 	//	Raender
401 
402     pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
403 	if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
404         nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
405 	else
406 		nIndent = 0;
407 
408     //  "Shrink to fit"
409 
410     bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
411 
412 	//	zumindest die Text-Groesse muss neu geholt werden
413 	//!	unterscheiden, und den Text nicht neu vom Numberformatter holen?
414 
415 	pLastCell = NULL;
416 }
417 
418 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
419 {
420     nMaxDigitWidth = 0;
421     nSignWidth     = 0;
422     nDotWidth      = 0;
423     nExpWidth      = 0;
424 	//	wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer)
425 
426 	pPattern = pNew;
427 	pCondSet = pSet;		//! noetig ???
428 
429 	//	Zahlenformat
430 
431 	sal_uLong nOld = nValueFormat;
432 //	nValueFormat = pPattern->GetNumberFormat( pFormatter );
433 	const SfxPoolItem* pFormItem;
434 	if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,sal_True,&pFormItem) != SFX_ITEM_SET )
435 		pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT);
436 	const SfxPoolItem* pLangItem;
437 	if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET )
438 		pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT);
439 	nValueFormat = pOutput->pDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
440 					((SfxUInt32Item*)pFormItem)->GetValue(),
441 					((SvxLanguageItem*)pLangItem)->GetLanguage() );
442 
443 	if (nValueFormat != nOld)
444 		pLastCell = NULL;			// immer neu formatieren
445 
446 	//	Raender
447 
448     pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
449 
450 	if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
451         nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
452 	else
453 		nIndent = 0;
454 
455     //  "Shrink to fit"
456 
457     bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
458 }
459 
460 inline sal_Bool SameValue( ScBaseCell* pCell, ScBaseCell* pOldCell )	// pCell ist != 0
461 {
462 	return pOldCell && pOldCell->GetCellType() == CELLTYPE_VALUE &&
463 			pCell->GetCellType() == CELLTYPE_VALUE &&
464 			((ScValueCell*)pCell)->GetValue() == ((ScValueCell*)pOldCell)->GetValue();
465 }
466 
467 sal_Bool ScDrawStringsVars::SetText( ScBaseCell* pCell )
468 {
469 	sal_Bool bChanged = sal_False;
470 
471 	if (pCell)
472 	{
473 		if ( !SameValue( pCell, pLastCell ) )
474 		{
475 			pLastCell = pCell;			//	Zelle merken
476 
477 			Color* pColor;
478 			sal_uLong nFormat = GetValueFormat();
479 			ScCellFormat::GetString( pCell,
480 									 nFormat, aString, &pColor,
481 									 *pOutput->pDoc->GetFormatTable(),
482 									 pOutput->bShowNullValues,
483 									 pOutput->bShowFormulas,
484 									 ftCheck );
485 
486 			if (aString.Len() > DRAWTEXT_MAX)
487 				aString.Erase(DRAWTEXT_MAX);
488 
489 			if ( pColor && !pOutput->bSyntaxMode && !( pOutput->bUseStyleColor && pOutput->bForceAutoColor ) )
490 			{
491 				OutputDevice* pDev = pOutput->pDev;
492 				aFont.SetColor(*pColor);
493 				pDev->SetFont( aFont );	// nur fuer Ausgabe
494 				bChanged = sal_True;
495 				pLastCell = NULL;		// naechstes Mal wieder hierherkommen
496 			}
497 
498             TextChanged();
499 		}
500 		//	sonst String/Groesse behalten
501 	}
502 	else
503 	{
504 		aString.Erase();
505 		pLastCell = NULL;
506 		aTextSize = Size(0,0);
507 		nOriginalWidth = 0;
508 	}
509 
510 	return bChanged;
511 }
512 
513 void ScDrawStringsVars::SetHashText()
514 {
515     SetAutoText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) );
516 }
517 
518 void ScDrawStringsVars::SetTextToWidthOrHash( ScBaseCell* pCell, long nWidth )
519 {
520     // #i113045# do the single-character width calculations in logic units
521     if (bPixelToLogic)
522         nWidth = pOutput->pRefDevice->PixelToLogic(Size(nWidth,0)).Width();
523 
524     if (!pCell)
525         return;
526 
527     CellType eType = pCell->GetCellType();
528     if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
529         // must be a value or formula cell.
530         return;
531 
532     if (eType == CELLTYPE_FORMULA)
533     {
534         ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
535         if (pFCell->GetErrCode() != 0 || pOutput->bShowFormulas)
536         {
537             SetHashText();      // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
538             return;
539         }
540         // If it's formula, the result must be a value.
541         if (!pFCell->IsValue())
542             return;
543     }
544 
545     sal_uLong nFormat = GetResultValueFormat(pCell);
546     if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
547     {
548         // Not 'General' number format.  Set hash text and bail out.
549         SetHashText();
550         return;
551     }
552 
553     double fVal = (eType == CELLTYPE_VALUE) ?
554         static_cast<ScValueCell*>(pCell)->GetValue() : static_cast<ScFormulaCell*>(pCell)->GetValue();
555 
556     const SvNumberformat* pNumFormat = pOutput->pDoc->GetFormatTable()->GetEntry(nFormat);
557     if (!pNumFormat)
558         return;
559 
560     long nMaxDigit = GetMaxDigitWidth();
561     sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
562 
563     if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString))
564         // Failed to get output string.  Bail out.
565         return;
566 
567     sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
568     xub_StrLen nLen = aString.Len();
569     sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator.getStr()[0];
570     for (xub_StrLen i = 0; i < nLen; ++i)
571     {
572         sal_Unicode c = aString.GetChar(i);
573         if (c == sal_Unicode('-'))
574             ++nSignCount;
575         else if (c == cDecSep)
576             ++nDecimalCount;
577         else if (c == sal_Unicode('E'))
578             ++nExpCount;
579     }
580 
581     // #i112250# A small value might be formatted as "0" when only counting the digits,
582     // but fit into the column when considering the smaller width of the decimal separator.
583     if (aString.EqualsAscii("0") && fVal != 0.0)
584         nDecimalCount = 1;
585 
586     if (nDecimalCount)
587         nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
588     if (nSignCount)
589         nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
590     if (nExpCount)
591         nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
592 
593     if (nDecimalCount || nSignCount || nExpCount)
594     {
595         // Re-calculate.
596         nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
597         if (!pNumFormat->GetOutputString(fVal, nNumDigits, aString))
598             // Failed to get output string.  Bail out.
599             return;
600     }
601 
602     long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
603     if (nActualTextWidth > nWidth)
604     {
605         // Even after the decimal adjustment the text doesn't fit.  Give up.
606         SetHashText();
607         return;
608     }
609 
610     TextChanged();
611     pLastCell = NULL;   // #i113022# equal cell and format in another column may give different string
612 }
613 
614 void ScDrawStringsVars::SetAutoText( const String& rAutoText )
615 {
616 	aString = rAutoText;
617 
618 	OutputDevice* pRefDevice = pOutput->pRefDevice;
619 	OutputDevice* pFmtDevice = pOutput->pFmtDevice;
620 	aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
621 	aTextSize.Height() = pFmtDevice->GetTextHeight();
622 
623 	if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
624 	{
625 		double fMul = pOutput->GetStretch();
626 		aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
627 	}
628 
629 	aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
630 	if ( GetOrient() != SVX_ORIENTATION_STANDARD )
631 	{
632 		long nTemp = aTextSize.Height();
633 		aTextSize.Height() = aTextSize.Width();
634 		aTextSize.Width() = nTemp;
635 	}
636 
637 	nOriginalWidth = aTextSize.Width();
638 	if ( bPixelToLogic )
639 		aTextSize = pRefDevice->LogicToPixel( aTextSize );
640 
641 	pLastCell = NULL;		// derselbe Text kann in der naechsten Zelle wieder passen
642 }
643 
644 long ScDrawStringsVars::GetMaxDigitWidth()
645 {
646     if (nMaxDigitWidth > 0)
647         return nMaxDigitWidth;
648 
649     sal_Char cZero = '0';
650     for (sal_Char i = 0; i < 10; ++i)
651     {
652         sal_Char cDigit = cZero + i;
653         long n = pOutput->pFmtDevice->GetTextWidth(String(cDigit));
654         nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
655     }
656     return nMaxDigitWidth;
657 }
658 
659 long ScDrawStringsVars::GetSignWidth()
660 {
661     if (nSignWidth > 0)
662         return nSignWidth;
663 
664     nSignWidth = pOutput->pFmtDevice->GetTextWidth(String('-'));
665     return nSignWidth;
666 }
667 
668 long ScDrawStringsVars::GetDotWidth()
669 {
670     if (nDotWidth > 0)
671         return nDotWidth;
672 
673     const ::rtl::OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator;
674     nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
675     return nDotWidth;
676 }
677 
678 long ScDrawStringsVars::GetExpWidth()
679 {
680     if (nExpWidth > 0)
681         return nExpWidth;
682 
683     nExpWidth = pOutput->pFmtDevice->GetTextWidth(String('E'));
684     return nExpWidth;
685 }
686 
687 void ScDrawStringsVars::TextChanged()
688 {
689     OutputDevice* pRefDevice = pOutput->pRefDevice;
690     OutputDevice* pFmtDevice = pOutput->pFmtDevice;
691     aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
692     aTextSize.Height() = pFmtDevice->GetTextHeight();
693 
694     if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
695     {
696         double fMul = pOutput->GetStretch();
697         aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
698     }
699 
700     aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
701     if ( GetOrient() != SVX_ORIENTATION_STANDARD )
702     {
703         long nTemp = aTextSize.Height();
704         aTextSize.Height() = aTextSize.Width();
705         aTextSize.Width() = nTemp;
706     }
707 
708     nOriginalWidth = aTextSize.Width();
709     if ( bPixelToLogic )
710         aTextSize = pRefDevice->LogicToPixel( aTextSize );
711 }
712 
713 sal_Bool ScDrawStringsVars::HasEditCharacters() const
714 {
715     static const sal_Unicode pChars[] =
716     {
717         CHAR_NBSP, CHAR_SHY, CHAR_ZWSP, CHAR_LRM, CHAR_RLM, CHAR_NBHY, CHAR_ZWNBSP, 0
718     };
719     return aString.SearchChar( pChars ) != STRING_NOTFOUND;
720 }
721 
722 sal_uLong ScDrawStringsVars::GetResultValueFormat( const ScBaseCell* pCell ) const
723 {
724     // Get the effective number format, including formula result types.
725     // This assumes that a formula cell has already been calculated.
726 
727     if ( (nValueFormat % SV_COUNTRY_LANGUAGE_OFFSET) == 0 && pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
728         return static_cast<const ScFormulaCell*>(pCell)->GetStandardFormat(*pOutput->pDoc->GetFormatTable(), nValueFormat);
729     else
730         return nValueFormat;
731 }
732 
733 //==================================================================
734 
735 double ScOutputData::GetStretch()
736 {
737 	if ( pRefDevice->IsMapMode() )
738 	{
739 		//	#95920# If a non-trivial MapMode is set, its scale is now already
740 		//	taken into account in the OutputDevice's font handling
741 		//	(OutputDevice::ImplNewFont, see #95414#).
742 		//	The old handling below is only needed for pixel output.
743 		return 1.0;
744 	}
745 
746 	// calculation in double is faster than Fraction multiplication
747 	// and doesn't overflow
748 
749 	if ( pRefDevice == pFmtDevice )
750 	{
751 		MapMode aOld = pRefDevice->GetMapMode();
752 		return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX);
753 	}
754 	else
755 	{
756 		// when formatting for printer, device map mode has already been taken care of
757 		return ((double)aZoomY) / ((double)aZoomX);
758 	}
759 }
760 
761 //==================================================================
762 
763 //
764 //	output strings
765 //
766 
767 void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScBaseCell* pCell )
768 {
769     vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
770 
771     String aCellText;
772     String aURL;
773     if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
774     {
775         ScFormulaCell* pFCell = static_cast<ScFormulaCell*>(pCell);
776         if ( pFCell->IsHyperLinkCell() )
777             pFCell->GetURLResult( aURL, aCellText );
778     }
779 
780     if ( aURL.Len() && pPDFData )
781     {
782         vcl::PDFExtOutDevBookmarkEntry aBookmark;
783         aBookmark.nLinkId = pPDFData->CreateLink( rRect );
784         aBookmark.aBookmark = aURL;
785         std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
786         rBookmarks.push_back( aBookmark );
787     }
788 }
789 
790 void ScOutputData::SetSyntaxColor( Font* pFont, ScBaseCell* pCell )
791 {
792 	if (pCell)
793 	{
794 		switch (pCell->GetCellType())
795 		{
796 			case CELLTYPE_VALUE:
797 				pFont->SetColor( *pValueColor );
798 				break;
799 			case CELLTYPE_STRING:
800 				pFont->SetColor( *pTextColor );
801 				break;
802 			case CELLTYPE_FORMULA:
803 				pFont->SetColor( *pFormulaColor );
804 				break;
805             default:
806             {
807                 // added to avoid warnings
808             }
809 		}
810 	}
811 }
812 
813 void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
814 {
815 	ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
816 	SfxItemSet aSet( rEngine.GetEmptyItemSet() );
817 	aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
818 	rEngine.QuickSetAttribs( aSet, aSel );
819 	// function is called with update mode set to FALSE
820 }
821 
822 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScBaseCell* pCell )
823 {
824 	if (pCell)
825 	{
826 		Color aColor;
827 		switch (pCell->GetCellType())
828 		{
829 			case CELLTYPE_VALUE:
830 				aColor = *pValueColor;
831 				break;
832 			case CELLTYPE_STRING:
833 				aColor = *pTextColor;
834 				break;
835 			case CELLTYPE_FORMULA:
836 				aColor = *pFormulaColor;
837 				break;
838             default:
839             {
840                 // added to avoid warnings
841             }
842 		}
843 		lcl_SetEditColor( rEngine, aColor );
844 	}
845 }
846 
847 sal_Bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
848 									SCCOL& rOverX, SCROW& rOverY,
849 									sal_Bool bVisRowChanged )
850 {
851 	sal_Bool bDoMerge = sal_False;
852 	sal_Bool bIsLeft = ( nX == nVisX1 );
853 	sal_Bool bIsTop  = ( nY == nVisY1 ) || bVisRowChanged;
854 
855 	CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
856 	if ( pInfo->bHOverlapped && pInfo->bVOverlapped )
857 		bDoMerge = bIsLeft && bIsTop;
858 	else if ( pInfo->bHOverlapped )
859 		bDoMerge = bIsLeft;
860 	else if ( pInfo->bVOverlapped )
861 		bDoMerge = bIsTop;
862 
863 									// weiter solange versteckt
864 /*	if (!bDoMerge)
865 		return sal_False;
866 */
867 
868 	rOverX = nX;
869 	rOverY = nY;
870 	sal_Bool bHOver = pInfo->bHOverlapped;
871 	sal_Bool bVOver = pInfo->bVOverlapped;
872 	sal_Bool bHidden;
873 
874 	while (bHOver)				// nY konstant
875 	{
876 		--rOverX;
877         bHidden = pDoc->ColHidden(rOverX, nTab);
878 		if ( !bDoMerge && !bHidden )
879 			return sal_False;
880 
881 		if (rOverX >= nX1 && !bHidden)
882 		{
883 //			rVirtPosX -= pRowInfo[0].pCellInfo[rOverX+1].nWidth;
884 			bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
885 			bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
886 		}
887 		else
888 		{
889 //			if (!bClipVirt)
890 //				rVirtPosX -= (long) (pDoc->GetColWidth( rOverX, nTab ) * nPPTX);
891 			sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr(
892 								rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
893 			bHOver = ((nOverlap & SC_MF_HOR) != 0);
894 			bVOver = ((nOverlap & SC_MF_VER) != 0);
895 		}
896 	}
897 
898 	while (bVOver)
899 	{
900 		--rOverY;
901         bHidden = pDoc->RowHidden(rOverY, nTab);
902 		if ( !bDoMerge && !bHidden )
903 			return sal_False;
904 
905 		if (nArrY>0)
906 			--nArrY;						// lokale Kopie !
907 
908 		if (rOverX >= nX1 && rOverY >= nY1 &&
909             !pDoc->ColHidden(rOverX, nTab) &&
910             !pDoc->RowHidden(rOverY, nTab) &&
911 			pRowInfo[nArrY].nRowNo == rOverY)
912 		{
913 //			rVirtPosY -= pRowInfo[nArrY].nHeight;
914 			bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
915 			bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
916 		}
917 		else
918 		{
919 //			if (!bClipVirt)
920 //				rVirtPosY -= (long) (pDoc->GetRowHeight( rOverY, nTab ) * nPPTY);
921 			sal_uInt16 nOverlap = ((ScMergeFlagAttr*)pDoc->GetAttr(
922 								rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
923 			bHOver = ((nOverlap & SC_MF_HOR) != 0);
924 			bVOver = ((nOverlap & SC_MF_VER) != 0);
925 		}
926 	}
927 
928 	return sal_True;
929 }
930 
931 inline sal_Bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern )
932 {
933 	DBG_ASSERT( rpNewPattern, "pNewPattern" );
934 
935 	if ( rpNewPattern == rpOldPattern )
936 		return sal_False;
937 	else if ( !rpOldPattern )
938 		return sal_True;
939 	else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
940 		return sal_True;
941 	else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
942 		return sal_True;
943 	else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
944 		return sal_True;
945 	else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
946 		return sal_True;
947 	else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
948 		return sal_True;
949 	else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
950 		return sal_True;
951 	else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
952 		return sal_True;
953 	else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
954 		return sal_True;
955 	else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
956 		return sal_True;
957 	else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
958 		return sal_True;
959 	else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
960 		return sal_True;
961 	else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
962 		return sal_True;
963 	else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
964 		return sal_True;
965 	else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
966 		return sal_True;
967 	else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
968 		return sal_True;
969 	else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
970 		return sal_True;
971 	else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
972 		return sal_True;
973 	else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
974 		return sal_True;
975 	else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
976 		return sal_True;
977 	else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
978 		return sal_True;
979 	else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
980 		return sal_True;
981     else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
982 		return sal_True;
983 	else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
984 		return sal_True;
985 	else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
986 		return sal_True;
987 	else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
988 		return sal_True;
989 	else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
990 		return sal_True;
991 	else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
992 		return sal_True;
993 	else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
994 		return sal_True;
995 	else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
996 		return sal_True;	// needed with automatic text color
997 	else
998 	{
999 		rpOldPattern = rpNewPattern;
1000 		return sal_False;
1001 	}
1002 }
1003 
1004 inline void lcl_CreateInterpretProgress( sal_Bool& bProgress, ScDocument* pDoc,
1005 		ScFormulaCell* pFCell )
1006 {
1007 	if ( !bProgress && pFCell->GetDirty() )
1008 	{
1009 		ScProgress::CreateInterpretProgress( pDoc, sal_True );
1010 		bProgress = sal_True;
1011 	}
1012 }
1013 
1014 inline sal_uInt8 GetScriptType( ScDocument* pDoc, ScBaseCell* pCell,
1015 							const ScPatternAttr* pPattern,
1016 							const SfxItemSet* pCondSet )
1017 {
1018 	return pDoc->GetCellScriptType( pCell, pPattern->GetNumberFormat( pDoc->GetFormatTable(), pCondSet ) );
1019 }
1020 
1021 inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript )
1022 {
1023 	return ( nScript != SCRIPTTYPE_LATIN &&
1024 			 nScript != SCRIPTTYPE_ASIAN &&
1025 			 nScript != SCRIPTTYPE_COMPLEX );
1026 }
1027 
1028 sal_Bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1029 {
1030 	// pThisRowInfo may be NULL
1031 
1032 	sal_Bool bEmpty;
1033 	if ( pThisRowInfo && nX <= nX2 )
1034 		bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText;
1035 	else
1036 		bEmpty = ( pDoc->GetCell( ScAddress( nX, nY, nTab ) ) == NULL );
1037 
1038 	if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1039 	{
1040 		//	for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1041 		//	into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1042 
1043 		sal_Bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1044 
1045 		if ( bIsPrint || bTabProtected )
1046 		{
1047 			const ScProtectionAttr* pAttr = (const ScProtectionAttr*)
1048 					pDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
1049 			if ( bIsPrint && pAttr->GetHidePrint() )
1050 				bEmpty = sal_True;
1051 			else if ( bTabProtected )
1052 			{
1053 				if ( pAttr->GetHideCell() )
1054 					bEmpty = sal_True;
1055 				else if ( bShowFormulas && pAttr->GetHideFormula() )
1056 				{
1057 					ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) );
1058 					if ( pCell && pCell->GetCellType() == CELLTYPE_FORMULA )
1059 						bEmpty = sal_True;
1060 				}
1061 			}
1062 		}
1063 	}
1064 	return bEmpty;
1065 }
1066 
1067 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScBaseCell*& rpCell )
1068 {
1069 	pDoc->GetCell( nCol, nRow, nTabP, rpCell );
1070 	if ( rpCell && IsEmptyCellText( NULL, nCol, nRow ) )
1071 		rpCell = NULL;
1072 }
1073 
1074 sal_Bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
1075 {
1076 	//	apply the same logic here as in DrawStrings/DrawEdit:
1077 	//	Stop at non-empty or merged or overlapped cell,
1078 	//	where a note is empty as well as a cell that's hidden by protection settings
1079 
1080 	const ScBaseCell* pCell = pDoc->GetCell( ScAddress( nX, nY, nTab ) );
1081 	if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE && !IsEmptyCellText( NULL, nX, nY ) )
1082 	{
1083 		return sal_False;
1084 	}
1085 
1086 	const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
1087 	if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() ||
1088 		 ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() )
1089 	{
1090 		return sal_False;
1091 	}
1092 
1093 	return sal_True;
1094 }
1095 
1096 // nX, nArrY:		loop variables from DrawStrings / DrawEdit
1097 // nPosX, nPosY:	corresponding positions for nX, nArrY
1098 // nCellX, nCellY:	position of the cell that contains the text
1099 // nNeeded:			Text width, including margin
1100 // rPattern:		cell format at nCellX, nCellY
1101 // nHorJustify:		horizontal alignment (visual) to determine which cells to use for long strings
1102 // bCellIsValue:	if set, don't extend into empty cells
1103 // bBreak:			if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1104 // bOverwrite:		if set, also extend into non-empty cells (for rotated text)
1105 // rParam           output: various area parameters.
1106 
1107 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY,
1108                                   SCCOL nCellX, SCROW nCellY, long nNeeded,
1109                                   const ScPatternAttr& rPattern,
1110                                   sal_uInt16 nHorJustify, bool bCellIsValue,
1111                                   bool bBreak, bool bOverwrite,
1112                                   OutputAreaParam& rParam )
1113 {
1114     //  rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1115 	RowInfo& rThisRowInfo = pRowInfo[nArrY];
1116 
1117 	long nLayoutSign = bLayoutRTL ? -1 : 1;
1118 
1119     long nCellPosX = nPosX;         // find nCellX position, starting at nX/nPosX
1120 	SCCOL nCompCol = nX;
1121 	while ( nCellX > nCompCol )
1122 	{
1123         //! extra member function for width?
1124 		long nColWidth = ( nCompCol <= nX2 ) ?
1125 				pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1126 				(long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX );
1127 		nCellPosX += nColWidth * nLayoutSign;
1128 		++nCompCol;
1129 	}
1130 	while ( nCellX < nCompCol )
1131 	{
1132 		--nCompCol;
1133 		long nColWidth = ( nCompCol <= nX2 ) ?
1134 				pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1135 				(long) ( pDoc->GetColWidth( nCompCol, nTab ) * nPPTX );
1136 		nCellPosX -= nColWidth * nLayoutSign;
1137 	}
1138 
1139     long nCellPosY = nPosY;         // find nCellY position, starting at nArrY/nPosY
1140 	SCSIZE nCompArr = nArrY;
1141 	SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1142 	while ( nCellY > nCompRow )
1143 	{
1144 		if ( nCompArr + 1 < nArrCount )
1145 		{
1146 			nCellPosY += pRowInfo[nCompArr].nHeight;
1147 			++nCompArr;
1148 			nCompRow = pRowInfo[nCompArr].nRowNo;
1149 		}
1150 		else
1151 		{
1152 			sal_uInt16 nDocHeight = pDoc->GetRowHeight( nCompRow, nTab );
1153 			if ( nDocHeight )
1154 				nCellPosY += (long) ( nDocHeight * nPPTY );
1155 			++nCompRow;
1156 		}
1157 	}
1158     nCellPosY -= (long) pDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, nPPTY );
1159 
1160 	const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE );
1161 	sal_Bool bMerged = pMerge->IsMerged();
1162 	long nMergeCols = pMerge->GetColMerge();
1163 	if ( nMergeCols == 0 )
1164 		nMergeCols = 1;
1165 	long nMergeRows = pMerge->GetRowMerge();
1166 	if ( nMergeRows == 0 )
1167 		nMergeRows = 1;
1168 
1169 	long i;
1170 	long nMergeSizeX = 0;
1171 	for ( i=0; i<nMergeCols; i++ )
1172 	{
1173 		long nColWidth = ( nCellX+i <= nX2 ) ?
1174 				pRowInfo[0].pCellInfo[nCellX+i+1].nWidth :
1175                 (long) ( pDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * nPPTX );
1176 		nMergeSizeX += nColWidth;
1177 	}
1178 	long nMergeSizeY = 0;
1179 	short nDirect = 0;
1180 	if ( rThisRowInfo.nRowNo == nCellY )
1181 	{
1182 		// take first row's height from row info
1183 		nMergeSizeY += rThisRowInfo.nHeight;
1184         nDirect = 1;        // skip in loop
1185 	}
1186     // following rows always from document
1187     nMergeSizeY += (long) pDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, nPPTY);
1188 
1189     --nMergeSizeX;      // leave out the grid horizontally, also for alignment (align between grid lines)
1190 
1191     rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1192 
1193 	//
1194 	// construct the rectangles using logical left/right values (justify is called at the end)
1195 	//
1196 
1197     //  rAlignRect is the single cell or merged area, used for alignment.
1198 
1199     rParam.maAlignRect.Left() = nCellPosX;
1200     rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign;
1201     rParam.maAlignRect.Top() = nCellPosY;
1202     rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1;
1203 
1204     //  rClipRect is all cells that are used for output.
1205     //  For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1206 
1207     rParam.maClipRect = rParam.maAlignRect;
1208 	if ( nNeeded > nMergeSizeX )
1209 	{
1210 		SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify;
1211 
1212 		long nMissing = nNeeded - nMergeSizeX;
1213 		long nLeftMissing = 0;
1214 		long nRightMissing = 0;
1215 		switch ( eHorJust )
1216 		{
1217 			case SVX_HOR_JUSTIFY_LEFT:
1218 				nRightMissing = nMissing;
1219 				break;
1220 			case SVX_HOR_JUSTIFY_RIGHT:
1221 				nLeftMissing = nMissing;
1222 				break;
1223 			case SVX_HOR_JUSTIFY_CENTER:
1224 				nLeftMissing = nMissing / 2;
1225 				nRightMissing = nMissing - nLeftMissing;
1226 				break;
1227             default:
1228             {
1229                 // added to avoid warnings
1230             }
1231 		}
1232 
1233 		// nLeftMissing, nRightMissing are logical, eHorJust values are visual
1234 		if ( bLayoutRTL )
1235 			::std::swap( nLeftMissing, nRightMissing );
1236 
1237 		SCCOL nRightX = nCellX;
1238 		SCCOL nLeftX = nCellX;
1239 		if ( !bMerged && !bCellIsValue && !bBreak )
1240 		{
1241             //  look for empty cells into which the text can be extended
1242 
1243 			while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1244 			{
1245 				++nRightX;
1246 				long nAdd = (long) ( pDoc->GetColWidth( nRightX, nTab ) * nPPTX );
1247 				nRightMissing -= nAdd;
1248                 rParam.maClipRect.Right() += nAdd * nLayoutSign;
1249 
1250 				if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1251 					rThisRowInfo.pCellInfo[nRightX].bHideGrid = sal_True;
1252 			}
1253 
1254 			while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1255 			{
1256 				if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1257 					rThisRowInfo.pCellInfo[nLeftX].bHideGrid = sal_True;
1258 
1259 				--nLeftX;
1260 				long nAdd = (long) ( pDoc->GetColWidth( nLeftX, nTab ) * nPPTX );
1261 				nLeftMissing -= nAdd;
1262                 rParam.maClipRect.Left() -= nAdd * nLayoutSign;
1263 			}
1264 		}
1265 
1266         //  Set flag and reserve space for clipping mark triangle,
1267         //  even if rThisRowInfo isn't for nCellY (merged cells).
1268 		if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1269 		{
1270 			rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT;
1271 			bAnyClipped = sal_True;
1272 			long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX );
1273             rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign;
1274 		}
1275 		if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1276 		{
1277 			rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT;
1278 			bAnyClipped = sal_True;
1279 			long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX );
1280             rParam.maClipRect.Left() += nMarkPixel * nLayoutSign;
1281 		}
1282 
1283         rParam.mbLeftClip = ( nLeftMissing > 0 );
1284         rParam.mbRightClip = ( nRightMissing > 0 );
1285 	}
1286 	else
1287 	{
1288         rParam.mbLeftClip = rParam.mbRightClip = sal_False;
1289 
1290         // leave space for AutoFilter on screen
1291 		// (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1292 
1293         if ( eType==OUTTYPE_WINDOW &&
1294              ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & SC_MF_AUTO ) &&
1295              ( !bBreak || pRefDevice == pFmtDevice ) )
1296         {
1297             // filter drop-down width is now independent from row height
1298             const long nFilter = DROPDOWN_BITMAP_SIZE;
1299             sal_Bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1300             if ( bFit || bCellIsValue )
1301             {
1302                 // content fits even in the remaining area without the filter button
1303                 // -> align within that remaining area
1304 
1305                 rParam.maAlignRect.Right() -= nFilter * nLayoutSign;
1306                 rParam.maClipRect.Right() -= nFilter * nLayoutSign;
1307 
1308                 // if a number doesn't fit, don't hide part of the number behind the button
1309                 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1310 
1311                 if ( !bFit )
1312                     rParam.mbLeftClip = rParam.mbRightClip = sal_True;
1313             }
1314         }
1315 	}
1316 
1317     //  justify both rectangles for alignment calculation, use with DrawText etc.
1318 
1319     rParam.maAlignRect.Justify();
1320     rParam.maClipRect.Justify();
1321 
1322 #if 0
1323 	//! Test !!!
1324 	pDev->Push();
1325 	pDev->SetLineColor();
1326 	pDev->SetFillColor( COL_LIGHTGREEN );
1327     pDev->DrawRect( pDev->PixelToLogic(rParam.maClipRect) );
1328     pDev->DrawRect( rParam.maClipRect );    // print preview
1329 	pDev->Pop();
1330 	//! Test !!!
1331 #endif
1332 }
1333 
1334 void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
1335 {
1336 	DBG_ASSERT( pDev == pRefDevice ||
1337 				pDev->GetMapMode().GetMapUnit() == pRefDevice->GetMapMode().GetMapUnit(),
1338 				"DrawStrings: unterschiedliche MapUnits ?!?!" );
1339 
1340     vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
1341 
1342 	sal_Bool bWasIdleDisabled = pDoc->IsIdleDisabled();
1343 	pDoc->DisableIdle( sal_True );
1344 	Size aMinSize = pRefDevice->PixelToLogic(Size(0,100));		// erst darueber wird ausgegeben
1345 //    sal_uInt32 nMinHeight = aMinSize.Height() / 200;                // 1/2 Pixel
1346 
1347 	ScDrawStringsVars aVars( this, bPixelToLogic );
1348 
1349 	sal_Bool bProgress = sal_False;
1350 
1351 	long nInitPosX = nScrX;
1352 	if ( bLayoutRTL )
1353 		nInitPosX += nMirrorW - 1;				// pixels
1354 	long nLayoutSign = bLayoutRTL ? -1 : 1;
1355 
1356 	SCCOL nLastContentCol = MAXCOL;
1357 	if ( nX2 < MAXCOL )
1358         nLastContentCol = sal::static_int_cast<SCCOL>(
1359             nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
1360 	SCCOL nLoopStartX = nX1;
1361 	if ( nX1 > 0 )
1362 		--nLoopStartX;			// start before nX1 for rest of long text to the left
1363 
1364 	// variables for GetOutputArea
1365     OutputAreaParam aAreaParam;
1366 	sal_Bool bCellIsValue = sal_False;
1367 	long nNeededWidth = 0;
1368 	SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD;
1369 	const ScPatternAttr* pPattern = NULL;
1370 	const SfxItemSet* pCondSet = NULL;
1371     const ScPatternAttr* pOldPattern = NULL;
1372     const SfxItemSet* pOldCondSet = NULL;
1373     sal_uInt8 nOldScript = 0;
1374 
1375 	long nPosY = nScrY;
1376 	for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1377 	{
1378 		RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1379 		if ( pThisRowInfo->bChanged )
1380 		{
1381 			SCROW nY = pThisRowInfo->nRowNo;
1382 //            long nCellHeight = (long) pThisRowInfo->nHeight;
1383 			long nPosX = nInitPosX;
1384 			if ( nLoopStartX < nX1 )
1385 				nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
1386 			for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1387 			{
1388 				sal_Bool bMergeEmpty = sal_False;
1389 				CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1390 				sal_Bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
1391 
1392 				SCCOL nCellX = nX;					// position where the cell really starts
1393 				SCROW nCellY = nY;
1394 				sal_Bool bDoCell = sal_False;
1395 				sal_Bool bNeedEdit = sal_False;
1396 
1397 				//
1398 				//	Part of a merged cell?
1399 				//
1400 
1401                 sal_Bool bOverlapped = ( pInfo->bHOverlapped || pInfo->bVOverlapped );
1402                 if ( bOverlapped )
1403 				{
1404 					bEmpty = sal_True;
1405 
1406 					SCCOL nOverX;					// start of the merged cells
1407 					SCROW nOverY;
1408 					sal_Bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1409 					if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1410 					{
1411 						nCellX = nOverX;
1412 						nCellY = nOverY;
1413 						bDoCell = sal_True;
1414 					}
1415 					else
1416 						bMergeEmpty = sal_True;
1417 				}
1418 
1419 				//
1420 				//	Rest of a long text further to the left?
1421 				//
1422 
1423 				if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1424 				{
1425 					SCCOL nTempX=nX1;
1426 					while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1427 						--nTempX;
1428 
1429 					if ( nTempX < nX1 &&
1430 						 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1431 						 !pDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1432 					{
1433 						nCellX = nTempX;
1434 						bDoCell = sal_True;
1435 					}
1436 				}
1437 
1438 				//
1439 				//	Rest of a long text further to the right?
1440 				//
1441 
1442 				if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1443 				{
1444 					//	don't have to look further than nLastContentCol
1445 
1446 					SCCOL nTempX=nX;
1447 					while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1448 						++nTempX;
1449 
1450 					if ( nTempX > nX &&
1451 						 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1452 						 !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1453 					{
1454 						nCellX = nTempX;
1455 						bDoCell = sal_True;
1456 					}
1457 				}
1458 
1459 				//
1460 				//	normal visible cell
1461 				//
1462 
1463 				if (!bEmpty)
1464 					bDoCell = sal_True;
1465 
1466 				//
1467 				//	don't output the cell that's being edited
1468 				//
1469 
1470 				if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1471 					bDoCell = sal_False;
1472 
1473 				//
1474 				//	output the cell text
1475 				//
1476 
1477 				ScBaseCell* pCell = NULL;
1478 				if (bDoCell)
1479 				{
1480 					if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1481 						pCell = pThisRowInfo->pCellInfo[nCellX+1].pCell;
1482 					else
1483 						GetVisibleCell( nCellX, nCellY, nTab, pCell );		// get from document
1484 					if ( !pCell )
1485 						bDoCell = sal_False;
1486 					else if ( pCell->GetCellType() == CELLTYPE_EDIT )
1487 						bNeedEdit = sal_True;
1488 				}
1489 				if (bDoCell && !bNeedEdit)
1490 				{
1491 					if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1492 					{
1493 						CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
1494 						pPattern = rCellInfo.pPatternAttr;
1495 						pCondSet = rCellInfo.pConditionSet;
1496 
1497                         if ( !pPattern )
1498                         {
1499                             // #i68085# pattern from cell info for hidden columns is null,
1500                             // test for null is quicker than using column flags
1501                             pPattern = pDoc->GetPattern( nCellX, nCellY, nTab );
1502                             pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab );
1503                         }
1504 					}
1505 					else		// get from document
1506 					{
1507 						pPattern = pDoc->GetPattern( nCellX, nCellY, nTab );
1508 						pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab );
1509 					}
1510 
1511 					sal_uInt8 nScript = GetScriptType( pDoc, pCell, pPattern, pCondSet );
1512 					if (nScript == 0) nScript = ScGlobal::GetDefaultScriptType();
1513 					if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1514 						 nScript != nOldScript || bSyntaxMode )
1515 					{
1516 						if ( StringDiffer(pOldPattern,pPattern) ||
1517 							 pCondSet != pOldCondSet || nScript != nOldScript || bSyntaxMode )
1518 							aVars.SetPattern( pPattern, pCondSet, pCell, nScript );
1519 						else
1520 							aVars.SetPatternSimple( pPattern, pCondSet );
1521 						pOldPattern = pPattern;
1522 						pOldCondSet = pCondSet;
1523 						nOldScript = nScript;
1524 					}
1525 
1526 					//	use edit engine for rotated, stacked or mixed-script text
1527 					if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED ||
1528 						 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1529 						bNeedEdit = sal_True;
1530 				}
1531 				if (bDoCell && !bNeedEdit)
1532 				{
1533 					sal_Bool bFormulaCell = (pCell->GetCellType() == CELLTYPE_FORMULA );
1534 					if ( bFormulaCell )
1535 						lcl_CreateInterpretProgress( bProgress, pDoc, (ScFormulaCell*)pCell );
1536 					if ( aVars.SetText(pCell) )
1537 						pOldPattern = NULL;
1538                     bNeedEdit = aVars.HasEditCharacters() ||
1539 					                (bFormulaCell && ((ScFormulaCell*)pCell)->IsMultilineResult());
1540                 }
1541                 long nTotalMargin = 0;
1542                 if (bDoCell && !bNeedEdit)
1543                 {
1544 					CellType eCellType = pCell->GetCellType();
1545 					bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1546 					if ( eCellType == CELLTYPE_FORMULA )
1547 					{
1548 						ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1549 						bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1550 					}
1551 
1552 					eOutHorJust = ( aVars.GetHorJust() != SVX_HOR_JUSTIFY_STANDARD ) ?
1553 								  aVars.GetHorJust() :
1554 								  ( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
1555 
1556 					if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
1557 						eOutHorJust = SVX_HOR_JUSTIFY_LEFT;		// repeat is not yet implemented
1558 
1559 					sal_Bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK );
1560 
1561                     // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1562                     if ( bBreak && bCellIsValue && ( aVars.GetResultValueFormat(pCell) % SV_COUNTRY_LANGUAGE_OFFSET ) == 0 )
1563                         bBreak = sal_False;
1564 
1565 					sal_Bool bRepeat = aVars.IsRepeat() && !bBreak;
1566 					sal_Bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1567 
1568                     nTotalMargin =
1569                         static_cast<long>(aVars.GetLeftTotal() * nPPTX) +
1570                         static_cast<long>(aVars.GetMargin()->GetRightMargin() * nPPTX);
1571 
1572                     nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1573 
1574 					// GetOutputArea gives justfied rectangles
1575 					GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1576                                    *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1577                                    bCellIsValue || bRepeat || bShrink, bBreak, sal_False,
1578                                    aAreaParam );
1579 
1580                     if ( bShrink )
1581                     {
1582                         if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD )
1583                         {
1584                             // Only horizontal scaling is handled here.
1585                             // DrawEdit is used to vertically scale 90 deg rotated text.
1586                             bNeedEdit = sal_True;
1587                         }
1588                         else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip )     // horizontal
1589                         {
1590                             long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1591                             long nScaleSize = aVars.GetTextSize().Width();         // without margin
1592 
1593                             if ( nScaleSize > 0 )       // 0 if the text is empty (formulas, number formats)
1594                             {
1595                                 long nScale = ( nAvailable * 100 ) / nScaleSize;
1596 
1597                                 aVars.SetShrinkScale( nScale, nOldScript );
1598                                 long nNewSize = aVars.GetTextSize().Width();
1599 
1600                                 sal_uInt16 nShrinkAgain = 0;
1601                                 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1602                                 {
1603                                     // If the text is still too large, reduce the scale again by 10%, until it fits,
1604                                     // at most 7 times (it's less than 50% of the calculated scale then).
1605 
1606                                     nScale = ( nScale * 9 ) / 10;
1607                                     aVars.SetShrinkScale( nScale, nOldScript );
1608                                     nNewSize = aVars.GetTextSize().Width();
1609                                     ++nShrinkAgain;
1610                                 }
1611                                 // If even at half the size the font still isn't rendered smaller,
1612                                 // fall back to normal clipping (showing ### for numbers).
1613                                 if ( nNewSize <= nAvailable )
1614                                     aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False;
1615 
1616                                 pOldPattern = NULL;
1617                             }
1618                         }
1619                     }
1620 
1621                     if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1622                     {
1623                         long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1624                         long nRepeatSize = aVars.GetTextSize().Width();         // without margin
1625                         // When formatting for the printer, the text sizes don't always add up.
1626                         // Round down (too few repetitions) rather than exceeding the cell size then:
1627                         if ( pFmtDevice != pRefDevice )
1628                             ++nRepeatSize;
1629                         if ( nRepeatSize > 0 )
1630                         {
1631                             long nRepeatCount = nAvailable / nRepeatSize;
1632                             if ( nRepeatCount > 1 )
1633                             {
1634                                 String aCellStr = aVars.GetString();
1635                                 String aRepeated = aCellStr;
1636                                 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1637                                     aRepeated.Append( aCellStr );
1638                                 aVars.SetAutoText( aRepeated );
1639                             }
1640                         }
1641                     }
1642 
1643 					//	use edit engine if automatic line breaks are needed
1644 					if ( bBreak )
1645 					{
1646 						if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD )
1647                             bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1648 						else
1649 						{
1650 							long nHeight = aVars.GetTextSize().Height() +
1651 											(long)(aVars.GetMargin()->GetTopMargin()*nPPTY) +
1652 											(long)(aVars.GetMargin()->GetBottomMargin()*nPPTY);
1653                             bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1654 						}
1655 					}
1656 				}
1657 				if (bNeedEdit)
1658 				{
1659 					//	mark the cell in CellInfo to be drawn in DrawEdit:
1660 					//	Cells to the left are marked directly, cells to the
1661 					//	right are handled by the flag for nX2
1662 					SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1663 					RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1664 					pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = sal_True;
1665 					bDoCell = sal_False;	// don't draw here
1666 				}
1667 				if ( bDoCell )
1668 				{
1669                     if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1670 					{
1671                         // Adjust the decimals to fit the available column width.
1672                         aVars.SetTextToWidthOrHash(pCell, aAreaParam.mnColWidth - nTotalMargin);
1673 						nNeededWidth = aVars.GetTextSize().Width() +
1674 									(long) ( aVars.GetLeftTotal() * nPPTX ) +
1675 									(long) ( aVars.GetMargin()->GetRightMargin() * nPPTX );
1676                         if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1677                             aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_False;
1678 
1679 						//	If the "###" replacement doesn't fit into the cells, no clip marks
1680 						//	are shown, as the "###" already denotes too little space.
1681 						//	The rectangles from the first GetOutputArea call remain valid.
1682 					}
1683 
1684                     long nJustPosX = aAreaParam.maAlignRect.Left();		// "justified" - effect of alignment will be added
1685                     long nJustPosY = aAreaParam.maAlignRect.Top();
1686                     long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1687                     long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1688 
1689                     sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1690                     if ( aAreaParam.maClipRect.Left() < nScrX )
1691 					{
1692                         aAreaParam.maClipRect.Left() = nScrX;
1693                         aAreaParam.mbLeftClip = sal_True;
1694 					}
1695                     if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
1696 					{
1697                         aAreaParam.maClipRect.Right() = nScrX + nScrW;			//! minus one?
1698                         aAreaParam.mbRightClip = sal_True;
1699 					}
1700 
1701                     sal_Bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1702 					sal_Bool bVClip = sal_False;
1703 
1704                     if ( aAreaParam.maClipRect.Top() < nScrY )
1705                     {
1706                         aAreaParam.maClipRect.Top() = nScrY;
1707                         bVClip = sal_True;
1708                     }
1709                     if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
1710                     {
1711                         aAreaParam.maClipRect.Bottom() = nScrY + nScrH;         //! minus one?
1712                         bVClip = sal_True;
1713                     }
1714 
1715 					//
1716 					//		horizontalen Platz testen
1717 					//
1718 
1719 					sal_Bool bRightAdjusted = sal_False;		// to correct text width calculation later
1720 					sal_Bool bNeedEditEngine = sal_False;
1721 					if ( !bNeedEditEngine && !bOutside )
1722 					{
1723 						switch (eOutHorJust)
1724 						{
1725 							case SVX_HOR_JUSTIFY_LEFT:
1726 								nJustPosX += (long) ( aVars.GetLeftTotal() * nPPTX );
1727 								break;
1728 							case SVX_HOR_JUSTIFY_RIGHT:
1729 								nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1730 											(long) ( aVars.GetMargin()->GetRightMargin() * nPPTX );
1731 								bRightAdjusted = sal_True;
1732 								break;
1733 							case SVX_HOR_JUSTIFY_CENTER:
1734 								nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1735 											(long) ( aVars.GetLeftTotal() * nPPTX ) -
1736 											(long) ( aVars.GetMargin()->GetRightMargin() * nPPTX ) ) / 2;
1737 								break;
1738                             default:
1739                             {
1740                                 // added to avoid warnings
1741                             }
1742 						}
1743 
1744 						long nTestClipHeight = aVars.GetTextSize().Height();
1745 						switch (aVars.GetVerJust())
1746 						{
1747 							case SVX_VER_JUSTIFY_TOP:
1748 								{
1749 									long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY );
1750 									nJustPosY += nTop;
1751 									nTestClipHeight += nTop;
1752 								}
1753 								break;
1754 							case SVX_VER_JUSTIFY_BOTTOM:
1755 								{
1756 									long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY );
1757 									nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1758 									nTestClipHeight += nBot;
1759 								}
1760 								break;
1761 							case SVX_VER_JUSTIFY_CENTER:
1762 								{
1763 									long nTop = (long)( aVars.GetMargin()->GetTopMargin() * nPPTY );
1764 									long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * nPPTY );
1765 									nJustPosY += ( nOutHeight + nTop -
1766 													aVars.GetTextSize().Height() - nBot ) / 2;
1767 									nTestClipHeight += Abs( nTop - nBot );
1768 								}
1769 								break;
1770                             default:
1771                             {
1772                                 // added to avoid warnings
1773                             }
1774 						}
1775 
1776 						if ( nTestClipHeight > nOutHeight )
1777 						{
1778 							//	kein vertikales Clipping beim Drucken von Zellen mit
1779 							//	optimaler Hoehe, ausser bei Groesse in bedingter Formatierung
1780 							if ( eType != OUTTYPE_PRINTER ||
1781 									( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
1782 									( aVars.HasCondHeight() ) )
1783 								bVClip = sal_True;
1784 						}
1785 
1786 						if ( bHClip || bVClip )
1787 						{
1788 							//	nur die betroffene Dimension clippen,
1789 							//	damit bei nicht-proportionalem Resize nicht alle
1790 							//	rechtsbuendigen Zahlen abgeschnitten werden:
1791 
1792 							if (!bHClip)
1793 							{
1794                                 aAreaParam.maClipRect.Left() = nScrX;
1795                                 aAreaParam.maClipRect.Right() = nScrX+nScrW;
1796 							}
1797 							if (!bVClip)
1798 							{
1799                                 aAreaParam.maClipRect.Top() = nScrY;
1800                                 aAreaParam.maClipRect.Bottom() = nScrY+nScrH;
1801 							}
1802 
1803 							//	aClipRect is not used after SetClipRegion/IntersectClipRegion,
1804 							//	so it can be modified here
1805 							if (bPixelToLogic)
1806                                 aAreaParam.maClipRect = pRefDevice->PixelToLogic( aAreaParam.maClipRect );
1807 
1808 							if (bMetaFile)
1809 							{
1810 								pDev->Push();
1811                                 pDev->IntersectClipRegion( aAreaParam.maClipRect );
1812 							}
1813 							else
1814                                 pDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
1815 						}
1816 
1817                         Point aURLStart( nJustPosX, nJustPosY );    // copy before modifying for orientation
1818 
1819 						switch (aVars.GetOrient())
1820 						{
1821 							case SVX_ORIENTATION_STANDARD:
1822 								nJustPosY += aVars.GetAscent();
1823 								break;
1824 							case SVX_ORIENTATION_TOPBOTTOM:
1825 								nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
1826 								break;
1827 							case SVX_ORIENTATION_BOTTOMTOP:
1828 								nJustPosY += aVars.GetTextSize().Height();
1829 								nJustPosX += aVars.GetAscent();
1830 								break;
1831                             default:
1832                             {
1833                                 // added to avoid warnings
1834                             }
1835 						}
1836 
1837 						// When clipping, the visible part is now completely defined by the alignment,
1838 						// there's no more special handling to show the right part of RTL text.
1839 
1840 						Point aDrawTextPos( nJustPosX, nJustPosY );
1841 						if ( bPixelToLogic )
1842 						{
1843 							//	undo text width adjustment in pixels
1844 							if (bRightAdjusted)
1845 								aDrawTextPos.X() += aVars.GetTextSize().Width();
1846 
1847 							aDrawTextPos = pRefDevice->PixelToLogic( aDrawTextPos );
1848 
1849 							//	redo text width adjustment in logic units
1850 							if (bRightAdjusted)
1851 								aDrawTextPos.X() -= aVars.GetOriginalWidth();
1852 						}
1853 
1854 						//	in Metafiles immer DrawTextArray, damit die Positionen mit
1855 						//	aufgezeichnet werden (fuer nicht-proportionales Resize):
1856 
1857 						String aString = aVars.GetString();
1858 						if (bMetaFile || pFmtDevice != pDev || aZoomX != aZoomY)
1859 						{
1860 							sal_Int32* pDX = new sal_Int32[aString.Len()];
1861 							pFmtDevice->GetTextArray( aString, pDX );
1862 
1863 							if ( !pRefDevice->GetConnectMetaFile() ||
1864 									pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
1865 							{
1866 								double fMul = GetStretch();
1867 								xub_StrLen nLen = aString.Len();
1868 								for (xub_StrLen i=0; i<nLen; i++)
1869 									pDX[i] = (long)(pDX[i] / fMul + 0.5);
1870 							}
1871 
1872 							pDev->DrawTextArray( aDrawTextPos, aString, pDX );
1873 							delete[] pDX;
1874 						}
1875 						else
1876 							pDev->DrawText( aDrawTextPos, aString );
1877 
1878 						if ( bHClip || bVClip )
1879 						{
1880 							if (bMetaFile)
1881 								pDev->Pop();
1882 							else
1883 								pDev->SetClipRegion();
1884 						}
1885 
1886                         // PDF: whole-cell hyperlink from formula?
1887                         sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA &&
1888                                         static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell();
1889                         if ( bHasURL )
1890                         {
1891                             Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
1892                             lcl_DoHyperlinkResult( pDev, aURLRect, pCell );
1893                         }
1894 					}
1895 				}
1896 				nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
1897 			}
1898 		}
1899 		nPosY += pRowInfo[nArrY].nHeight;
1900 	}
1901 	if ( bProgress )
1902 		ScProgress::DeleteInterpretProgress();
1903 	pDoc->DisableIdle( bWasIdleDisabled );
1904 }
1905 
1906 //	-------------------------------------------------------------------------------
1907 
1908 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine()
1909 {
1910     ScFieldEditEngine* pEngine = new ScFieldEditEngine( pDoc->GetEnginePool() );
1911     pEngine->SetUpdateMode( sal_False );
1912     // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
1913     pEngine->SetRefDevice( pFmtDevice );
1914     sal_uInt32 nCtrl = pEngine->GetControlWord();
1915     if ( bShowSpellErrors )
1916         nCtrl |= EE_CNTRL_ONLINESPELLING;
1917     if ( eType == OUTTYPE_PRINTER )
1918         nCtrl &= ~EE_CNTRL_MARKFIELDS;
1919     if ( eType == OUTTYPE_WINDOW && pRefDevice == pFmtDevice )
1920         nCtrl &= ~EE_CNTRL_FORMAT100;       // use the actual MapMode
1921     pEngine->SetControlWord( nCtrl );
1922     pDoc->ApplyAsianEditSettings( *pEngine );
1923     pEngine->EnableAutoColor( bUseStyleColor );
1924     pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)pDoc->GetEditTextDirection( nTab ) );
1925     return pEngine;
1926 }
1927 
1928 void lcl_ClearEdit( EditEngine& rEngine )		// Text und Attribute
1929 {
1930 	rEngine.SetUpdateMode( sal_False );
1931 
1932 	rEngine.SetText(EMPTY_STRING);
1933 	//	keine Para-Attribute uebrigbehalten...
1934 	const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
1935 	if (rPara.Count())
1936 		rEngine.SetParaAttribs( 0,
1937 					SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
1938 }
1939 
1940 sal_Bool lcl_SafeIsValue( ScBaseCell* pCell )
1941 {
1942 	if (!pCell)
1943 		return sal_False;
1944 
1945 	sal_Bool bRet = sal_False;
1946 	switch ( pCell->GetCellType() )
1947 	{
1948 		case CELLTYPE_VALUE:
1949 			bRet = sal_True;
1950 			break;
1951 		case CELLTYPE_FORMULA:
1952 			{
1953 				ScFormulaCell* pFCell = (ScFormulaCell*)pCell;
1954 				if ( pFCell->IsRunning() || pFCell->IsValue() )
1955 					bRet = sal_True;
1956 			}
1957 			break;
1958         default:
1959         {
1960             // added to avoid warnings
1961         }
1962 	}
1963 	return bRet;
1964 }
1965 
1966 void lcl_ScaleFonts( EditEngine& rEngine, long nPercent )
1967 {
1968     sal_Bool bUpdateMode = rEngine.GetUpdateMode();
1969     if ( bUpdateMode )
1970         rEngine.SetUpdateMode( sal_False );
1971 
1972     sal_uInt16 nParCount = rEngine.GetParagraphCount();
1973     for (sal_uInt16 nPar=0; nPar<nParCount; nPar++)
1974     {
1975         SvUShorts aPortions;
1976         rEngine.GetPortions( nPar, aPortions );
1977 
1978         sal_uInt16 nPCount = aPortions.Count();
1979         sal_uInt16 nStart = 0;
1980         for ( sal_uInt16 nPos=0; nPos<nPCount; nPos++ )
1981         {
1982             sal_uInt16 nEnd = aPortions.GetObject( nPos );
1983             ESelection aSel( nPar, nStart, nPar, nEnd );
1984             SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
1985 
1986             long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight();
1987             long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight();
1988             long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight();
1989 
1990             nWestern = ( nWestern * nPercent ) / 100;
1991             nCJK     = ( nCJK     * nPercent ) / 100;
1992             nCTL     = ( nCTL     * nPercent ) / 100;
1993 
1994             aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
1995             aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
1996             aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
1997 
1998             rEngine.QuickSetAttribs( aAttribs, aSel );      //! remove paragraph attributes from aAttribs?
1999 
2000             nStart = nEnd;
2001         }
2002     }
2003 
2004     if ( bUpdateMode )
2005         rEngine.SetUpdateMode( sal_True );
2006 }
2007 
2008 long lcl_GetEditSize( EditEngine& rEngine, sal_Bool bWidth, sal_Bool bSwap, long nAttrRotate )
2009 {
2010     if ( bSwap )
2011         bWidth = !bWidth;
2012 
2013     if ( nAttrRotate )
2014     {
2015         long nRealWidth  = (long) rEngine.CalcTextWidth();
2016         long nRealHeight = rEngine.GetTextHeight();
2017 
2018         // assuming standard mode, otherwise width isn't used
2019 
2020         double nRealOrient = nAttrRotate * F_PI18000;	// 1/100th degrees
2021         double nAbsCos = fabs( cos( nRealOrient ) );
2022         double nAbsSin = fabs( sin( nRealOrient ) );
2023         if ( bWidth )
2024             return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2025         else
2026             return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2027     }
2028     else if ( bWidth )
2029         return (long) rEngine.CalcTextWidth();
2030     else
2031         return rEngine.GetTextHeight();
2032 }
2033 
2034 
2035 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect,
2036             long nLeftM, long nTopM, long nRightM, long nBottomM,
2037             sal_Bool bWidth, sal_uInt16 nOrient, long nAttrRotate, sal_Bool bPixelToLogic,
2038             long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2039 {
2040     if ( !bWidth )
2041     {
2042         // vertical
2043 
2044         long nScaleSize = bPixelToLogic ?
2045             pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2046 
2047         // Don't scale if it fits already.
2048         // Allowing to extend into the margin, to avoid scaling at optimal height.
2049         if ( nScaleSize <= rAlignRect.GetHeight() )
2050             return;
2051 
2052         sal_Bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP );
2053         long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2054         long nScale = ( nAvailable * 100 ) / nScaleSize;
2055 
2056         lcl_ScaleFonts( rEngine, nScale );
2057         rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate );
2058         long nNewSize = bPixelToLogic ?
2059             pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2060 
2061         sal_uInt16 nShrinkAgain = 0;
2062         while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2063         {
2064             // further reduce, like in DrawStrings
2065             lcl_ScaleFonts( rEngine, 90 );     // reduce by 10%
2066             rEngineHeight = lcl_GetEditSize( rEngine, sal_False, bSwap, nAttrRotate );
2067             nNewSize = bPixelToLogic ?
2068                 pRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2069             ++nShrinkAgain;
2070         }
2071 
2072         // sizes for further processing (alignment etc):
2073         rEngineWidth = lcl_GetEditSize( rEngine, sal_True, bSwap, nAttrRotate );
2074         long nPixelWidth = bPixelToLogic ?
2075             pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2076         rNeededPixel = nPixelWidth + nLeftM + nRightM;
2077     }
2078     else if ( rLeftClip || rRightClip )
2079     {
2080         // horizontal
2081 
2082         long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2083         long nScaleSize = rNeededPixel - nLeftM - nRightM;      // without margin
2084 
2085         if ( nScaleSize <= nAvailable )
2086             return;
2087 
2088         long nScale = ( nAvailable * 100 ) / nScaleSize;
2089 
2090         lcl_ScaleFonts( rEngine, nScale );
2091         rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate );
2092         long nNewSize = bPixelToLogic ?
2093             pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2094 
2095         sal_uInt16 nShrinkAgain = 0;
2096         while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2097         {
2098             // further reduce, like in DrawStrings
2099             lcl_ScaleFonts( rEngine, 90 );     // reduce by 10%
2100             rEngineWidth = lcl_GetEditSize( rEngine, sal_True, sal_False, nAttrRotate );
2101             nNewSize = bPixelToLogic ?
2102                 pRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2103             ++nShrinkAgain;
2104         }
2105         if ( nNewSize <= nAvailable )
2106             rLeftClip = rRightClip = sal_False;
2107 
2108         // sizes for further processing (alignment etc):
2109         rNeededPixel = nNewSize + nLeftM + nRightM;
2110         rEngineHeight = lcl_GetEditSize( rEngine, sal_False, sal_False, nAttrRotate );
2111     }
2112 }
2113 
2114 void ScOutputData::DrawEdit(sal_Bool bPixelToLogic)
2115 {
2116     vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2117 
2118 	Size aMinSize = pRefDevice->PixelToLogic(Size(0,100));		// erst darueber wird ausgegeben
2119 //    sal_uInt32 nMinHeight = aMinSize.Height() / 200;                // 1/2 Pixel
2120 
2121 	ScModule* pScMod = SC_MOD();
2122     sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2123 	//	#105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
2124 	sal_Bool bCellContrast = bUseStyleColor &&
2125 			Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2126 
2127 	ScFieldEditEngine* pEngine = NULL;
2128 	sal_Bool bHyphenatorSet = sal_False;
2129 	const ScPatternAttr* pOldPattern = NULL;
2130 	const SfxItemSet*	 pOldCondSet = NULL;
2131 	ScBaseCell* pCell = NULL;
2132 
2133 	Size aRefOne = pRefDevice->PixelToLogic(Size(1,1));
2134 
2135 	long nInitPosX = nScrX;
2136 	if ( bLayoutRTL )
2137 	{
2138 #if 0
2139 		Size aOnePixel = pDev->PixelToLogic(Size(1,1));
2140 		long nOneX = aOnePixel.Width();
2141 		nInitPosX += nMirrorW - nOneX;
2142 #endif
2143 		nInitPosX += nMirrorW - 1;
2144 	}
2145 	long nLayoutSign = bLayoutRTL ? -1 : 1;
2146 
2147 	//!	store nLastContentCol as member!
2148 	SCCOL nLastContentCol = MAXCOL;
2149 	if ( nX2 < MAXCOL )
2150         nLastContentCol = sal::static_int_cast<SCCOL>(
2151             nLastContentCol - pDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
2152 
2153 	long nRowPosY = nScrY;
2154 	for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++)			// 0 fuer Reste von zusammengefassten
2155 	{
2156 		RowInfo* pThisRowInfo = &pRowInfo[nArrY];
2157 //        long nCellHeight = (long) pThisRowInfo->nHeight;
2158 		if (nArrY==1) nRowPosY = nScrY;							// vorher wird einzeln berechnet
2159 
2160 		if ( pThisRowInfo->bChanged || nArrY==0 )
2161 		{
2162 			long nPosX = 0;
2163 			for (SCCOL nX=0; nX<=nX2; nX++)					// wegen Ueberhaengen
2164 			{
2165 				if (nX==nX1) nPosX = nInitPosX;					// positions before nX1 are calculated individually
2166 
2167 				CellInfo*	pInfo = &pThisRowInfo->pCellInfo[nX+1];
2168 				if (pInfo->bEditEngine)
2169 				{
2170 					SCROW nY = pThisRowInfo->nRowNo;
2171 
2172 					SCCOL nCellX = nX;					// position where the cell really starts
2173 					SCROW nCellY = nY;
2174 					sal_Bool bDoCell = sal_False;
2175 
2176 					long nPosY = nRowPosY;
2177 					if ( nArrY == 0 )
2178 					{
2179 						nPosY = nScrY;
2180 						nY = pRowInfo[1].nRowNo;
2181 						SCCOL nOverX;					// start of the merged cells
2182 						SCROW nOverY;
2183 						if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, sal_True ))
2184 						{
2185 							nCellX = nOverX;
2186 							nCellY = nOverY;
2187 							bDoCell = sal_True;
2188 						}
2189 					}
2190 					else if ( nX == nX2 && !pThisRowInfo->pCellInfo[nX+1].pCell )
2191 					{
2192 						//	Rest of a long text further to the right?
2193 
2194 						SCCOL nTempX=nX;
2195 						while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
2196 							++nTempX;
2197 
2198 						if ( nTempX > nX &&
2199 							 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
2200 							 !pDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
2201 						{
2202 							nCellX = nTempX;
2203 							bDoCell = sal_True;
2204 						}
2205 					}
2206 					else
2207 					{
2208 						bDoCell = sal_True;
2209 					}
2210 
2211 					if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
2212 						bDoCell = sal_False;
2213 
2214                     const ScPatternAttr* pPattern = NULL;
2215                     const SfxItemSet* pCondSet = NULL;
2216 					if (bDoCell)
2217 					{
2218                         if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
2219                              !pDoc->ColHidden(nCellX, nTab) )
2220 						{
2221 							CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
2222 							pPattern = rCellInfo.pPatternAttr;
2223 							pCondSet = rCellInfo.pConditionSet;
2224 							pCell = rCellInfo.pCell;
2225 						}
2226 						else		// get from document
2227 						{
2228 							pPattern = pDoc->GetPattern( nCellX, nCellY, nTab );
2229 							pCondSet = pDoc->GetCondResult( nCellX, nCellY, nTab );
2230 							GetVisibleCell( nCellX, nCellY, nTab, pCell );
2231 						}
2232 						if ( !pCell )
2233 							bDoCell = sal_False;
2234 					}
2235 					if (bDoCell)
2236 					{
2237 						sal_Bool bHidden = sal_False;
2238 
2239 						//
2240 						//	Create EditEngine
2241 						//
2242 
2243 						if (!pEngine)
2244                             pEngine = CreateOutputEditEngine();
2245 						else
2246 							lcl_ClearEdit( *pEngine );		// also calls SetUpdateMode(sal_False)
2247 
2248 						sal_Bool bCellIsValue = lcl_SafeIsValue(pCell);
2249 
2250 						SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
2251 											pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
2252 						sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
2253 										((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
2254                         sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
2255                         sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
2256                                         (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
2257                         SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
2258 						long nAttrRotate = ((const SfxInt32Item&)pPattern->
2259 											GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
2260                         if ( eHorJust == SVX_HOR_JUSTIFY_REPEAT )
2261                         {
2262                             // ignore orientation/rotation if "repeat" is active
2263                             eOrient = SVX_ORIENTATION_STANDARD;
2264                             nAttrRotate = 0;
2265 
2266                             // #i31843# "repeat" with "line breaks" is treated as default alignment
2267                             // (but rotation is still disabled)
2268                             if ( bBreak )
2269                                 eHorJust = SVX_HOR_JUSTIFY_STANDARD;
2270                         }
2271 						if ( eOrient==SVX_ORIENTATION_STANDARD && nAttrRotate )
2272 						{
2273 							//!	Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2274 							//!	(oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2275 							bHidden = sal_True;		// gedreht wird getrennt ausgegeben
2276 						}
2277 
2278 						sal_Bool bAsianVertical = ( eOrient == SVX_ORIENTATION_STACKED &&
2279 								((const SfxBoolItem&)pPattern->GetItem( ATTR_VERTICAL_ASIAN, pCondSet )).GetValue() );
2280 						if ( bAsianVertical )
2281 						{
2282 							// in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE
2283 							eOrient = SVX_ORIENTATION_STANDARD;
2284 							// default alignment for asian vertical mode is top-right
2285 							if ( eHorJust == SVX_HOR_JUSTIFY_STANDARD )
2286 								eHorJust = SVX_HOR_JUSTIFY_RIGHT;
2287 						}
2288 
2289 						SvxCellHorJustify eOutHorJust =
2290 							( eHorJust != SVX_HOR_JUSTIFY_STANDARD ) ? eHorJust :
2291 							( bCellIsValue ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT );
2292 
2293 						if ( eOutHorJust == SVX_HOR_JUSTIFY_BLOCK || eOutHorJust == SVX_HOR_JUSTIFY_REPEAT )
2294 							eOutHorJust = SVX_HOR_JUSTIFY_LEFT;		// repeat is not yet implemented
2295 
2296 
2297 //!						if ( !bHidden && eType == OUTTYPE_PRINTER &&
2298 //!							pDev->GetOutDevType() == OUTDEV_WINDOW &&
2299 //!							((const SvxFontHeightItem&)pPattern->
2300 //!							GetItem(ATTR_FONT_HEIGHT)).GetHeight() <= nMinHeight )
2301 //!						{
2302 //!							Point aPos( nStartX, nStartY );
2303 //!							pDev->DrawPixel( aPos,
2304 //!											((const SvxColorItem&)pPattern->
2305 //!											GetItem( ATTR_FONT_COLOR )).GetValue() );
2306 //!							bHidden = sal_True;
2307 //!						}
2308 
2309 						if (!bHidden)
2310 						{
2311 							//!	mirror margin values for RTL?
2312 							//!	move margin down to after final GetOutputArea call
2313 
2314 							const SvxMarginItem* pMargin = (const SvxMarginItem*)
2315 													&pPattern->GetItem(ATTR_MARGIN, pCondSet);
2316 							sal_uInt16 nIndent = 0;
2317 							if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
2318 								nIndent = ((const SfxUInt16Item&)pPattern->
2319 													GetItem(ATTR_INDENT, pCondSet)).GetValue();
2320 
2321 							long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX );
2322 							long nTopM  = (long) ( pMargin->GetTopMargin() * nPPTY );
2323 							long nRightM = (long) ( pMargin->GetRightMargin() * nPPTX );
2324 							long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY );
2325 
2326 							SCCOL nXForPos = nX;
2327 							if ( nXForPos < nX1 )
2328 							{
2329 								nXForPos = nX1;
2330 								nPosX = nInitPosX;
2331 							}
2332 							SCSIZE nArrYForPos = nArrY;
2333 							if ( nArrYForPos < 1 )
2334 							{
2335 								nArrYForPos = 1;
2336 								nPosY = nScrY;
2337 							}
2338 
2339                             OutputAreaParam aAreaParam;
2340 
2341 							//
2342 							//	Initial page size - large for normal text, cell size for automatic line breaks
2343 							//
2344 
2345 							Size aPaperSize = Size( 1000000, 1000000 );
2346 							if ( bBreak || eOrient == SVX_ORIENTATION_STACKED || bAsianVertical )
2347 							{
2348 								//!	also stacked, AsianVertical
2349 
2350 								//	call GetOutputArea with nNeeded=0, to get only the cell width
2351 
2352 								//!	handle nArrY == 0
2353 								GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, 0,
2354                                                *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2355                                                bCellIsValue, true, false, aAreaParam );
2356 
2357 								//! special ScEditUtil handling if formatting for printer
2358 
2359 								if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP )
2360                                     aPaperSize.Width() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2361 								else
2362                                     aPaperSize.Width() = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2363 
2364 								if (bAsianVertical && bBreak)
2365 								{
2366 									//	add some extra height (default margin value) for safety
2367 									//	as long as GetEditArea isn't used below
2368 									long nExtraHeight = (long)( 20 * nPPTY );
2369                                     aPaperSize.Height() = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM + nExtraHeight;
2370 								}
2371 							}
2372 							if (bPixelToLogic)
2373                             {
2374                                 Size aLogicSize = pRefDevice->PixelToLogic(aPaperSize);
2375                                 if ( bBreak && !bAsianVertical && pRefDevice != pFmtDevice )
2376                                 {
2377                                     // #i85342# screen display and formatting for printer,
2378                                     // use same GetEditArea call as in ScViewData::SetEditEngine
2379 
2380                                     Fraction aFract(1,1);
2381                                     Rectangle aUtilRect = ScEditUtil( pDoc, nCellX, nCellY, nTab, Point(0,0), pFmtDevice,
2382                                         HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( pPattern, sal_False );
2383                                     aLogicSize.Width() = aUtilRect.GetWidth();
2384                                 }
2385                                 pEngine->SetPaperSize(aLogicSize);
2386                             }
2387 							else
2388 								pEngine->SetPaperSize(aPaperSize);
2389 
2390 							//
2391 							//	Fill the EditEngine (cell attributes and text)
2392 							//
2393 
2394 							SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)
2395 												pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
2396 
2397 							// default alignment for asian vertical mode is top-right
2398 							if ( bAsianVertical && eVerJust == SVX_VER_JUSTIFY_STANDARD )
2399 								eVerJust = SVX_VER_JUSTIFY_TOP;
2400 
2401 							// syntax highlighting mode is ignored here
2402 							// StringDiffer doesn't look at hyphenate, language items
2403 							if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
2404 							{
2405 								SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
2406 								pPattern->FillEditItemSet( pSet, pCondSet );
2407 
2408 								pEngine->SetDefaults( pSet );
2409 								pOldPattern = pPattern;
2410 								pOldCondSet = pCondSet;
2411 
2412 								sal_uLong nControl = pEngine->GetControlWord();
2413 								if (eOrient==SVX_ORIENTATION_STACKED)
2414 									nControl |= EE_CNTRL_ONECHARPERLINE;
2415 								else
2416 									nControl &= ~EE_CNTRL_ONECHARPERLINE;
2417 								pEngine->SetControlWord( nControl );
2418 
2419 								if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
2420 								{
2421 									//	set hyphenator the first time it is needed
2422                                     com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2423 									pEngine->SetHyphenator( xXHyphenator );
2424 									bHyphenatorSet = sal_True;
2425 								}
2426 
2427 								Color aBackCol = ((const SvxBrushItem&)
2428 									pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
2429 								if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
2430 									aBackCol.SetColor( nConfBackColor );
2431 								pEngine->SetBackgroundColor( aBackCol );
2432 							}
2433 
2434 							//	horizontal alignment now may depend on cell content
2435 							//	(for values with number formats with mixed script types)
2436 							//	-> always set adjustment
2437 
2438 							SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2439 							if (eOrient==SVX_ORIENTATION_STACKED)
2440 								eSvxAdjust = SVX_ADJUST_CENTER;
2441 							else if (bBreak)
2442 							{
2443 								if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical)
2444 									switch (eHorJust)
2445 									{
2446 										case SVX_HOR_JUSTIFY_STANDARD:
2447 											eSvxAdjust = bCellIsValue ? SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2448 											break;
2449 										case SVX_HOR_JUSTIFY_LEFT:
2450 										case SVX_HOR_JUSTIFY_REPEAT:			// nicht implementiert
2451 											eSvxAdjust = SVX_ADJUST_LEFT;
2452 											break;
2453 										case SVX_HOR_JUSTIFY_RIGHT:
2454 											eSvxAdjust = SVX_ADJUST_RIGHT;
2455 											break;
2456 										case SVX_HOR_JUSTIFY_CENTER:
2457 											eSvxAdjust = SVX_ADJUST_CENTER;
2458 											break;
2459 										case SVX_HOR_JUSTIFY_BLOCK:
2460 											eSvxAdjust = SVX_ADJUST_BLOCK;
2461 											break;
2462 									}
2463 								else
2464 									switch (eVerJust)
2465 									{
2466 										case SVX_VER_JUSTIFY_TOP:
2467 											eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ?
2468 														SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT;
2469 											break;
2470 										case SVX_VER_JUSTIFY_CENTER:
2471 											eSvxAdjust = SVX_ADJUST_CENTER;
2472 											break;
2473 										case SVX_VER_JUSTIFY_BOTTOM:
2474 										case SVX_HOR_JUSTIFY_STANDARD:
2475 											eSvxAdjust = (eOrient==SVX_ORIENTATION_TOPBOTTOM || bAsianVertical) ?
2476 														SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2477 											break;
2478 									}
2479 							}
2480 							pEngine->SetDefaultItem( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
2481 
2482 							//	Read content from cell
2483 
2484 							sal_Bool bWrapFields = sal_False;
2485 							if (pCell)
2486 							{
2487 								if (pCell->GetCellType() == CELLTYPE_EDIT)
2488 								{
2489 									const EditTextObject* pData;
2490 									((ScEditCell*)pCell)->GetData(pData);
2491 
2492 									if (pData)
2493 									{
2494 										pEngine->SetText(*pData);
2495 
2496 										if ( bBreak && !bAsianVertical && pData->HasField() )
2497 										{
2498 											//	Fields aren't wrapped, so clipping is enabled to prevent
2499 											//	a field from being drawn beyond the cell size
2500 
2501 											bWrapFields = sal_True;
2502 										}
2503 									}
2504 									else
2505 									{
2506 										DBG_ERROR("pData == 0");
2507 									}
2508 								}
2509 								else
2510 								{
2511 									sal_uLong nFormat = pPattern->GetNumberFormat(
2512 																pDoc->GetFormatTable(), pCondSet );
2513 									String aString;
2514 									Color* pColor;
2515 									ScCellFormat::GetString( pCell,
2516 															 nFormat,aString, &pColor,
2517 															 *pDoc->GetFormatTable(),
2518 															 bShowNullValues,
2519 															 bShowFormulas,
2520 															 ftCheck );
2521 
2522 									pEngine->SetText(aString);
2523 									if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2524 										lcl_SetEditColor( *pEngine, *pColor );
2525 								}
2526 
2527 								if ( bSyntaxMode )
2528 									SetEditSyntaxColor( *pEngine, pCell );
2529 								else if ( bUseStyleColor && bForceAutoColor )
2530 									lcl_SetEditColor( *pEngine, COL_AUTO );		//! or have a flag at EditEngine
2531 							}
2532 							else
2533 							{
2534 								DBG_ERROR("pCell == NULL");
2535 							}
2536 
2537 							pEngine->SetVertical( bAsianVertical );
2538 							pEngine->SetUpdateMode( sal_True );		// after SetText, before CalcTextWidth/GetTextHeight
2539 
2540 							//
2541 							//	Get final output area using the calculated width
2542 							//
2543 
2544 							long nEngineWidth;
2545 							if ( bBreak && eOrient != SVX_ORIENTATION_STACKED && !bAsianVertical )
2546 								nEngineWidth = 0;
2547 							else
2548 								nEngineWidth = (long) pEngine->CalcTextWidth();
2549 							long nEngineHeight = pEngine->GetTextHeight();
2550 
2551 							if (eOrient != SVX_ORIENTATION_STANDARD &&
2552 								eOrient != SVX_ORIENTATION_STACKED)
2553 							{
2554 								long nTemp = nEngineWidth;
2555 								nEngineWidth = nEngineHeight;
2556 								nEngineHeight = nTemp;
2557 							}
2558 
2559 							if (eOrient == SVX_ORIENTATION_STACKED)
2560 								nEngineWidth = nEngineWidth * 11 / 10;
2561 
2562 							long nNeededPixel = nEngineWidth;
2563 							if (bPixelToLogic)
2564 								nNeededPixel = pRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2565 							nNeededPixel += nLeftM + nRightM;
2566 
2567 							if ( ( !bBreak && eOrient != SVX_ORIENTATION_STACKED ) || bAsianVertical || bShrink )
2568 							{
2569 								// for break, the first GetOutputArea call is sufficient
2570 								GetOutputArea( nXForPos, nArrYForPos, nPosX, nPosY, nCellX, nCellY, nNeededPixel,
2571                                                *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2572                                                bCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2573 
2574                                 if ( bShrink )
2575                                 {
2576                                     sal_Bool bWidth = ( eOrient == SVX_ORIENTATION_STANDARD && !bAsianVertical );
2577                                     ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect,
2578                                         nLeftM, nTopM, nRightM, nBottomM, bWidth,
2579                                         sal::static_int_cast<sal_uInt16>(eOrient), 0, bPixelToLogic,
2580                                         nEngineWidth, nEngineHeight, nNeededPixel,
2581                                         aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
2582                                 }
2583 
2584                                 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && pEngine->GetParagraphCount() == 1 )
2585                                 {
2586                                     // First check if twice the space for the formatted text is available
2587                                     // (otherwise just keep it unchanged).
2588 
2589                                     long nFormatted = nNeededPixel - nLeftM - nRightM;      // without margin
2590                                     long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2591                                     if ( nAvailable >= 2 * nFormatted )
2592                                     {
2593                                         // "repeat" is handled with unformatted text (for performance reasons)
2594                                         String aCellStr = pEngine->GetText();
2595                                         pEngine->SetText( aCellStr );
2596 
2597                                         long nRepeatSize = (long) pEngine->CalcTextWidth();
2598                                         if (bPixelToLogic)
2599                                             nRepeatSize = pRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
2600                                         if ( pFmtDevice != pRefDevice )
2601                                             ++nRepeatSize;
2602                                         if ( nRepeatSize > 0 )
2603                                         {
2604                                             long nRepeatCount = nAvailable / nRepeatSize;
2605                                             if ( nRepeatCount > 1 )
2606                                             {
2607                                                 String aRepeated = aCellStr;
2608                                                 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
2609                                                     aRepeated.Append( aCellStr );
2610                                                 pEngine->SetText( aRepeated );
2611 
2612                                                 nEngineHeight = pEngine->GetTextHeight();
2613                                                 nEngineWidth = (long) pEngine->CalcTextWidth();
2614                                                 if (bPixelToLogic)
2615                                                 	nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2616                                                 else
2617                                                     nNeededPixel = nEngineWidth;
2618                                                 nNeededPixel += nLeftM + nRightM;
2619                                             }
2620                                         }
2621                                     }
2622                                 }
2623 
2624                                 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
2625 								{
2626 									pEngine->SetText( String::CreateFromAscii(RTL_CONSTASCII_STRINGPARAM("###")) );
2627 									nEngineWidth = (long) pEngine->CalcTextWidth();
2628 									if (bPixelToLogic)
2629 										nNeededPixel = pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2630 									else
2631 										nNeededPixel = nEngineWidth;
2632 									nNeededPixel += nLeftM + nRightM;
2633 
2634 									//	No clip marks if "###" doesn't fit (same as in DrawStrings)
2635 								}
2636 
2637 								if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT && eOrient == SVX_ORIENTATION_STANDARD )
2638 								{
2639 									aPaperSize.Width() = nNeededPixel + 1;
2640 									if (bPixelToLogic)
2641 										pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize));
2642 									else
2643 										pEngine->SetPaperSize(aPaperSize);
2644 								}
2645 							}
2646 
2647                             long nStartX = aAreaParam.maAlignRect.Left();
2648                             long nStartY = aAreaParam.maAlignRect.Top();
2649                             long nCellWidth = aAreaParam.maAlignRect.GetWidth();
2650 							long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
2651                             long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2652 
2653 							if ( bBreak || eOrient != SVX_ORIENTATION_STANDARD || bAsianVertical )
2654 							{
2655 								//	text with automatic breaks is aligned only within the
2656 								//	edit engine's paper size, the output of the whole area
2657 								//	is always left-aligned
2658 
2659 								nStartX += nLeftM;
2660 							}
2661 							else
2662 							{
2663 								if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
2664 									nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
2665 								else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
2666 									nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
2667 								else
2668 									nStartX += nLeftM;
2669 							}
2670 
2671                             sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
2672                             if ( aAreaParam.maClipRect.Left() < nScrX )
2673 							{
2674                                 aAreaParam.maClipRect.Left() = nScrX;
2675                                 aAreaParam.mbLeftClip = true;
2676 							}
2677                             if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
2678 							{
2679                                 aAreaParam.maClipRect.Right() = nScrX + nScrW;			//! minus one?
2680                                 aAreaParam.mbRightClip = true;
2681 							}
2682 
2683 							if ( !bHidden && !bOutside )
2684 							{
2685                                 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
2686 								sal_Bool bSimClip = sal_False;
2687 
2688 								if ( bWrapFields )
2689 								{
2690 									//	Fields in a cell with automatic breaks: clip to cell width
2691 									bClip = sal_True;
2692 								}
2693 
2694                                 if ( aAreaParam.maClipRect.Top() < nScrY )
2695                                 {
2696                                     aAreaParam.maClipRect.Top() = nScrY;
2697                                     bClip = sal_True;
2698                                 }
2699                                 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
2700                                 {
2701                                     aAreaParam.maClipRect.Bottom() = nScrY + nScrH;     //! minus one?
2702                                     bClip = sal_True;
2703                                 }
2704 
2705 								Size aCellSize;			// output area, excluding margins, in logical units
2706 								if (bPixelToLogic)
2707 									aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
2708 								else
2709 									aCellSize = Size( nOutWidth, nOutHeight );
2710 
2711 								if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
2712 								{
2713 									const ScMergeAttr* pMerge =
2714 											(ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
2715 									sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
2716 
2717 									//	Don't clip for text height when printing rows with optimal height,
2718 									//	except when font size is from conditional formatting.
2719 									//!	Allow clipping when vertically merged?
2720 									if ( eType != OUTTYPE_PRINTER ||
2721 										( pDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
2722 										( pCondSet && SFX_ITEM_SET ==
2723 											pCondSet->GetItemState(ATTR_FONT_HEIGHT, sal_True) ) )
2724 										bClip = sal_True;
2725 									else
2726 										bSimClip = sal_True;
2727 
2728 									//	Show clip marks if height is at least 5pt too small and
2729 									//	there are several lines of text.
2730 									//	Not for asian vertical text, because that would interfere
2731 									//	with the default right position of the text.
2732 									//	Only with automatic line breaks, to avoid having to find
2733 									//	the cells with the horizontal end of the text again.
2734 									if ( nEngineHeight - aCellSize.Height() > 100 &&
2735 										 ( bBreak || eOrient == SVX_ORIENTATION_STACKED ) &&
2736 										 !bAsianVertical && bMarkClipped &&
2737 										 ( pEngine->GetParagraphCount() > 1 || pEngine->GetLineCount(0) > 1 ) )
2738 									{
2739 										CellInfo* pClipMarkCell = NULL;
2740 										if ( bMerged )
2741 										{
2742 											//	anywhere in the merged area...
2743 											SCCOL nClipX = ( nX < nX1 ) ? nX1 : nX;
2744 											pClipMarkCell = &pRowInfo[(nArrY != 0) ? nArrY : 1].pCellInfo[nClipX+1];
2745 										}
2746 										else
2747 											pClipMarkCell = &pThisRowInfo->pCellInfo[nX+1];
2748 
2749 										pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT;		//! also allow left?
2750 										bAnyClipped = sal_True;
2751 
2752 										long nMarkPixel = (long)( SC_CLIPMARK_SIZE * nPPTX );
2753                                         if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
2754                                             aAreaParam.maClipRect.Right() -= nMarkPixel;
2755 									}
2756 								}
2757 
2758 #if 0
2759 								long nClipStartY = nStartY;
2760 								if (nArrY==0 || bVisChanged)
2761 								{
2762 									if ( nClipStartY < nRowPosY )
2763 									{
2764 										long nDif = nRowPosY - nClipStartY;
2765 										bClip = sal_True;
2766 										nClipStartY = nRowPosY;
2767 										aClipSize.Height() -= nDif;
2768 									}
2769 								}
2770 #endif
2771 
2772 								Rectangle aLogicClip;
2773 								if (bClip || bSimClip)
2774 								{
2775 									// Clip marks are already handled in GetOutputArea
2776 
2777 									if (bPixelToLogic)
2778                                         aLogicClip = pRefDevice->PixelToLogic( aAreaParam.maClipRect );
2779 									else
2780                                         aLogicClip = aAreaParam.maClipRect;
2781 
2782 									if (bClip)	// bei bSimClip nur aClipRect initialisieren
2783 									{
2784 										if (bMetaFile)
2785 										{
2786 											pDev->Push();
2787 											pDev->IntersectClipRegion( aLogicClip );
2788 										}
2789 										else
2790 											pDev->SetClipRegion( Region( aLogicClip ) );
2791 									}
2792 								}
2793 
2794 								Point aLogicStart;
2795 								if (bPixelToLogic)
2796 									aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) );
2797 								else
2798 									aLogicStart = Point(nStartX, nStartY);
2799 								if ( eOrient!=SVX_ORIENTATION_STANDARD || bAsianVertical || !bBreak )
2800 								{
2801 									long nAvailWidth = aCellSize.Width();
2802                                     // space for AutoFilter is already handled in GetOutputArea
2803 
2804 									//	horizontal alignment
2805 
2806 									if (eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical)
2807 									{
2808 										if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
2809 											eHorJust==SVX_HOR_JUSTIFY_CENTER ||
2810 											(eHorJust==SVX_HOR_JUSTIFY_STANDARD && bCellIsValue) )
2811 										{
2812 											pEngine->SetUpdateMode( sal_False );
2813 
2814 											SvxAdjust eEditAdjust =
2815 												(eHorJust==SVX_HOR_JUSTIFY_CENTER) ?
2816 													SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT;
2817 											pEngine->SetDefaultItem(
2818 												SvxAdjustItem( eEditAdjust, EE_PARA_JUST ) );
2819 
2820 											// #55142# reset adjustment for the next cell
2821 											pOldPattern = NULL;
2822 
2823 											pEngine->SetUpdateMode( sal_True );
2824 										}
2825 									}
2826 									else
2827 									{
2828 										if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
2829 											aLogicStart.X() += nAvailWidth - nEngineWidth;
2830 										else if (eHorJust==SVX_HOR_JUSTIFY_CENTER)
2831 											aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
2832 									}
2833 								}
2834 
2835 								if ( bAsianVertical )
2836 								{
2837 									// paper size is subtracted below
2838 									aLogicStart.X() += nEngineWidth;
2839 								}
2840 
2841 								if ( ( bAsianVertical || eOrient == SVX_ORIENTATION_TOPBOTTOM ||
2842 										eOrient == SVX_ORIENTATION_BOTTOMTOP ) && bBreak )
2843 								{
2844 									// vertical adjustment is within the EditEngine
2845 									if (bPixelToLogic)
2846 										aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2847 									else
2848 										aLogicStart.Y() += nTopM;
2849 								}
2850 
2851 								if ( ( eOrient==SVX_ORIENTATION_STANDARD && !bAsianVertical ) ||
2852 									 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
2853 								{
2854 									if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
2855 										eVerJust==SVX_VER_JUSTIFY_STANDARD)
2856 									{
2857 										//!	if pRefDevice != pFmtDevice, keep heights in logic units,
2858 										//! only converting margin?
2859 
2860 										if (bPixelToLogic)
2861 											aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM +
2862 															pRefDevice->LogicToPixel(aCellSize).Height() -
2863 															pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
2864 															)).Height();
2865 										else
2866 											aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
2867 									}
2868 									else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
2869 									{
2870 										if (bPixelToLogic)
2871 											aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0, nTopM + (
2872 															pRefDevice->LogicToPixel(aCellSize).Height() -
2873 															pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
2874 															/ 2)).Height();
2875 										else
2876 											aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
2877 									}
2878 									else		// top
2879 									{
2880 										if (bPixelToLogic)
2881 											aLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2882 										else
2883 											aLogicStart.Y() += nTopM;
2884 									}
2885 								}
2886 
2887                                 Point aURLStart = aLogicStart;      // copy before modifying for orientation
2888 
2889 								short nOriVal = 0;
2890 								if (eOrient==SVX_ORIENTATION_TOPBOTTOM)
2891 								{
2892 									// nOriVal = -900;
2893 									nOriVal = 2700;
2894 									aLogicStart.X() += nEngineWidth;
2895 								}
2896 								else if (eOrient==SVX_ORIENTATION_BOTTOMTOP)
2897 								{
2898 									nOriVal = 900;
2899 									aLogicStart.Y() += bBreak ? pEngine->GetPaperSize().Width() :
2900 																nEngineHeight;
2901 								}
2902 								else if (eOrient==SVX_ORIENTATION_STACKED)
2903 								{
2904 									Size aPaperLogic = pEngine->GetPaperSize();
2905 									aPaperLogic.Width() = nEngineWidth;
2906 									pEngine->SetPaperSize(aPaperLogic);
2907 								}
2908 
2909 								if ( pEngine->IsRightToLeft( 0 ) )
2910 								{
2911 									//	For right-to-left, EditEngine always calculates its lines
2912 									//	beginning from the right edge, but EditLine::nStartPosX is
2913 									//	of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2914 									Size aLogicPaper = pEngine->GetPaperSize();
2915 									if ( aLogicPaper.Width() > USHRT_MAX )
2916 									{
2917 										aLogicPaper.Width() = USHRT_MAX;
2918 										pEngine->SetPaperSize(aLogicPaper);
2919 									}
2920 								}
2921 
2922 								// bMoveClipped handling has been replaced by complete alignment
2923 								// handling (also extending to the left).
2924 
2925 								if ( bSimClip && !nOriVal && !bAsianVertical )
2926 								{
2927 									//	kein hartes Clipping, aber nur die betroffenen
2928 									//	Zeilen ausgeben
2929 
2930 									Point aDocStart = aLogicClip.TopLeft();
2931 									aDocStart -= aLogicStart;
2932 									pEngine->Draw( pDev, aLogicClip, aDocStart, sal_False );
2933 								}
2934 								else
2935 								{
2936 									if (bAsianVertical)
2937 									{
2938 										//	with SetVertical, the start position is top left of
2939 										//	the whole output area, not the text itself
2940 										aLogicStart.X() -= pEngine->GetPaperSize().Width();
2941 									}
2942 									pEngine->Draw( pDev, aLogicStart, nOriVal );
2943 								}
2944 
2945 								if (bClip)
2946 								{
2947 									if (bMetaFile)
2948 										pDev->Pop();
2949 									else
2950 										pDev->SetClipRegion();
2951 								}
2952 
2953                                 // PDF: whole-cell hyperlink from formula?
2954                                 sal_Bool bHasURL = pPDFData && pCell && pCell->GetCellType() == CELLTYPE_FORMULA &&
2955                                                 static_cast<ScFormulaCell*>(pCell)->IsHyperLinkCell();
2956                                 if ( bHasURL )
2957                                 {
2958                                     long nURLWidth = (long) pEngine->CalcTextWidth();
2959                                     long nURLHeight = pEngine->GetTextHeight();
2960                                     if ( bBreak )
2961                                     {
2962                                         Size aPaper = pEngine->GetPaperSize();
2963                                         if ( bAsianVertical )
2964                                             nURLHeight = aPaper.Height();
2965                                         else
2966                                             nURLWidth = aPaper.Width();
2967                                     }
2968                                     if ( eOrient == SVX_ORIENTATION_TOPBOTTOM || eOrient == SVX_ORIENTATION_BOTTOMTOP )
2969                                         std::swap( nURLWidth, nURLHeight );
2970                                     else if ( bAsianVertical )
2971                                         aURLStart.X() -= nURLWidth;
2972 
2973                                     Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2974                                     lcl_DoHyperlinkResult( pDev, aURLRect, pCell );
2975                                 }
2976 							}
2977 						}
2978 					}
2979 				}
2980 				nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2981 			}
2982 		}
2983 		nRowPosY += pRowInfo[nArrY].nHeight;
2984 	}
2985 
2986 	delete pEngine;
2987 
2988 	if (bAnyRotated)
2989 		DrawRotated(bPixelToLogic);		//! von aussen rufen ?
2990 }
2991 
2992 //	-------------------------------------------------------------------------------
2993 
2994 void ScOutputData::DrawRotated(sal_Bool bPixelToLogic)
2995 {
2996 	//!	nRotMax speichern
2997 	SCCOL nRotMax = nX2;
2998 	for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
2999 		if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
3000 			nRotMax = pRowInfo[nRotY].nRotMaxCol;
3001 
3002 
3003 	ScModule* pScMod = SC_MOD();
3004     sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
3005 	//	#105733# SvtAccessibilityOptions::GetIsForBorders is no longer used (always assumed sal_True)
3006 	sal_Bool bCellContrast = bUseStyleColor &&
3007 			Application::GetSettings().GetStyleSettings().GetHighContrastMode();
3008 
3009 	ScFieldEditEngine* pEngine = NULL;
3010 	sal_Bool bHyphenatorSet = sal_False;
3011 	const ScPatternAttr* pPattern;
3012 	const SfxItemSet*	 pCondSet;
3013 	const ScPatternAttr* pOldPattern = NULL;
3014 	const SfxItemSet*	 pOldCondSet = NULL;
3015 	ScBaseCell* pCell = NULL;
3016 
3017 	long nInitPosX = nScrX;
3018 	if ( bLayoutRTL )
3019 	{
3020 #if 0
3021 		Size aOnePixel = pDev->PixelToLogic(Size(1,1));
3022 		long nOneX = aOnePixel.Width();
3023 		nInitPosX += nMirrorW - nOneX;
3024 #endif
3025 		nInitPosX += nMirrorW - 1;
3026 	}
3027 	long nLayoutSign = bLayoutRTL ? -1 : 1;
3028 
3029 	long nRowPosY = nScrY;
3030 	for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++)			// 0 fuer Reste von zusammengefassten
3031 	{
3032 		RowInfo* pThisRowInfo = &pRowInfo[nArrY];
3033 		long nCellHeight = (long) pThisRowInfo->nHeight;
3034 		if (nArrY==1) nRowPosY = nScrY;							// vorher wird einzeln berechnet
3035 
3036 		if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
3037 		{
3038 			long nPosX = 0;
3039 			for (SCCOL nX=0; nX<=nRotMax; nX++)
3040 			{
3041 				if (nX==nX1) nPosX = nInitPosX;					// positions before nX1 are calculated individually
3042 
3043 				CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
3044 				if ( pInfo->nRotateDir != SC_ROTDIR_NONE )
3045 				{
3046 					SCROW nY = pThisRowInfo->nRowNo;
3047 
3048 					sal_Bool bHidden = sal_False;
3049 					if (bEditMode)
3050 						if ( nX == nEditCol && nY == nEditRow )
3051 							bHidden = sal_True;
3052 
3053 					if (!bHidden)
3054 					{
3055 						if (!pEngine)
3056                             pEngine = CreateOutputEditEngine();
3057 						else
3058 							lcl_ClearEdit( *pEngine );		// also calls SetUpdateMode(sal_False)
3059 
3060 						long nPosY = nRowPosY;
3061 						sal_Bool bVisChanged = sal_False;
3062 
3063 						//!	Rest von zusammengefasster Zelle weiter oben funktioniert nicht!
3064 
3065 						sal_Bool bFromDoc = sal_False;
3066 						pPattern = pInfo->pPatternAttr;
3067 						pCondSet = pInfo->pConditionSet;
3068 						if (!pPattern)
3069 						{
3070 							pPattern = pDoc->GetPattern( nX, nY, nTab );
3071 							bFromDoc = sal_True;
3072 						}
3073 						pCell = pInfo->pCell;
3074 						if (bFromDoc)
3075 							pCondSet = pDoc->GetCondResult( nX, nY, nTab );
3076 
3077 						if (!pCell && nX>nX2)
3078 							GetVisibleCell( nX, nY, nTab, pCell );
3079 
3080 						if ( !pCell || IsEmptyCellText( pThisRowInfo, nX, nY ) )
3081 							bHidden = sal_True;		// nRotateDir is also set without a cell
3082 
3083 						long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth;
3084 
3085 						SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
3086 											pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
3087 						sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
3088 									((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
3089                         sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
3090                         sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
3091                                         (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
3092                         SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
3093 
3094 						const ScMergeAttr* pMerge =
3095 								(ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
3096 						sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3097 
3098 						long nStartX = nPosX;
3099 						long nStartY = nPosY;
3100 						if (nX<nX1)
3101 						{
3102 							if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged)
3103 								bHidden = sal_True;
3104 							else
3105 							{
3106 								nStartX = nInitPosX;
3107 								SCCOL nCol = nX1;
3108 								while (nCol > nX)
3109 								{
3110 									--nCol;
3111 									nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
3112 								}
3113 							}
3114 						}
3115 						long nCellStartX = nStartX;
3116 
3117 						//	Ersatzdarstellung fuer zu kleinen Text weggelassen
3118 
3119 						if (!bHidden)
3120 						{
3121 							long nOutWidth = nCellWidth - 1;
3122 							long nOutHeight;
3123 							if (pInfo)
3124 								nOutHeight = nCellHeight;
3125 							else
3126 								nOutHeight = (long) ( pDoc->GetRowHeight(nY,nTab) * nPPTY );
3127 
3128 							if ( bMerged )								// Zusammengefasst
3129 							{
3130 								SCCOL nCountX = pMerge->GetColMerge();
3131 								for (SCCOL i=1; i<nCountX; i++)
3132 									nOutWidth += (long) ( pDoc->GetColWidth(nX+i,nTab) * nPPTX );
3133 								SCROW nCountY = pMerge->GetRowMerge();
3134                                 nOutHeight += (long) pDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, nPPTY);
3135 							}
3136 
3137 							SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)
3138 												pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
3139 
3140 							// Syntax-Modus wird hier ignoriert...
3141 
3142 							// StringDiffer doesn't look at hyphenate, language items
3143 							if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
3144 							{
3145 								SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
3146 								pPattern->FillEditItemSet( pSet, pCondSet );
3147 
3148 																	// Ausrichtung fuer EditEngine
3149 								SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
3150 								if (eOrient==SVX_ORIENTATION_STACKED)
3151 									eSvxAdjust = SVX_ADJUST_CENTER;
3152 								// Adjustment fuer bBreak ist hier weggelassen
3153 								pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
3154 
3155 								pEngine->SetDefaults( pSet );
3156 								pOldPattern = pPattern;
3157 								pOldCondSet = pCondSet;
3158 
3159 								sal_uLong nControl = pEngine->GetControlWord();
3160 								if (eOrient==SVX_ORIENTATION_STACKED)
3161 									nControl |= EE_CNTRL_ONECHARPERLINE;
3162 								else
3163 									nControl &= ~EE_CNTRL_ONECHARPERLINE;
3164 								pEngine->SetControlWord( nControl );
3165 
3166 								if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
3167 								{
3168 									//	set hyphenator the first time it is needed
3169                                     com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
3170 									pEngine->SetHyphenator( xXHyphenator );
3171 									bHyphenatorSet = sal_True;
3172 								}
3173 
3174 								Color aBackCol = ((const SvxBrushItem&)
3175 									pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
3176 								if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
3177 									aBackCol.SetColor( nConfBackColor );
3178 								pEngine->SetBackgroundColor( aBackCol );
3179 							}
3180 
3181 							//	Raender
3182 
3183 							//!		Position und Papersize auf EditUtil umstellen !!!
3184 
3185 							const SvxMarginItem* pMargin = (const SvxMarginItem*)
3186 													&pPattern->GetItem(ATTR_MARGIN, pCondSet);
3187 							sal_uInt16 nIndent = 0;
3188 							if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
3189 								nIndent = ((const SfxUInt16Item&)pPattern->
3190 													GetItem(ATTR_INDENT, pCondSet)).GetValue();
3191 
3192 							long nTotalHeight = nOutHeight;	// ohne Rand abzuziehen
3193 							if ( bPixelToLogic )
3194 								nTotalHeight = pRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
3195 
3196 							long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * nPPTX );
3197 							long nTopM  = (long) ( pMargin->GetTopMargin() * nPPTY );
3198                             long nRightM  = (long) ( pMargin->GetRightMargin() * nPPTX );
3199                             long nBottomM = (long) ( pMargin->GetBottomMargin() * nPPTY );
3200 							nStartX += nLeftM;
3201 							nStartY += nTopM;
3202 							nOutWidth -= nLeftM + nRightM;
3203 							nOutHeight -= nTopM + nBottomM;
3204 
3205 							//	Rotation schon hier, um bei Umbruch auch PaperSize anzupassen
3206 							long nAttrRotate = 0;
3207 							double nSin = 0.0;
3208 							double nCos = 1.0;
3209 							SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
3210 							if ( eOrient == SVX_ORIENTATION_STANDARD )
3211 							{
3212 								nAttrRotate = ((const SfxInt32Item&)pPattern->
3213 													GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
3214 								if ( nAttrRotate )
3215 								{
3216 									eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
3217 												pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
3218 
3219 									if ( nAttrRotate == 18000 )
3220 										eRotMode = SVX_ROTATE_MODE_STANDARD;	// keinen Ueberlauf
3221 
3222 									if ( bLayoutRTL )
3223 										nAttrRotate = -nAttrRotate;
3224 
3225 									double nRealOrient = nAttrRotate * F_PI18000;	// 1/100 Grad
3226 									nCos = cos( nRealOrient );
3227 									nSin = sin( nRealOrient );
3228 								}
3229 							}
3230 
3231 							Size aPaperSize = Size( 1000000, 1000000 );
3232 							if (eOrient==SVX_ORIENTATION_STACKED)
3233 								aPaperSize.Width() = nOutWidth;				// zum Zentrieren
3234 							else if (bBreak)
3235 							{
3236 								if (nAttrRotate)
3237 								{
3238 									//!	richtige PaperSize fuer Umbruch haengt von der Zeilenzahl
3239 									//!	ab, solange die Zeilen nicht einzeln versetzt ausgegeben
3240 									//!	werden koennen -> darum unbegrenzt, also kein Umbruch.
3241 									//!	Mit versetzten Zeilen waere das folgende richtig:
3242 									aPaperSize.Width() = (long)(nOutHeight / fabs(nSin));
3243 								}
3244 								else if (eOrient == SVX_ORIENTATION_STANDARD)
3245 									aPaperSize.Width() = nOutWidth;
3246 								else
3247 									aPaperSize.Width() = nOutHeight - 1;
3248 							}
3249 							if (bPixelToLogic)
3250 								pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize));
3251 							else
3252 								pEngine->SetPaperSize(aPaperSize);	// Scale ist immer 1
3253 
3254 							//	Daten aus Zelle lesen
3255 
3256 							if (pCell)
3257 							{
3258 								if (pCell->GetCellType() == CELLTYPE_EDIT)
3259 								{
3260 									const EditTextObject* pData;
3261 									((ScEditCell*)pCell)->GetData(pData);
3262 
3263 									if (pData)
3264 										pEngine->SetText(*pData);
3265 									else
3266 									{
3267 										DBG_ERROR("pData == 0");
3268 									}
3269 								}
3270 								else
3271 								{
3272 									sal_uLong nFormat = pPattern->GetNumberFormat(
3273 																pDoc->GetFormatTable(), pCondSet );
3274 									String aString;
3275 									Color* pColor;
3276 									ScCellFormat::GetString( pCell,
3277 															 nFormat,aString, &pColor,
3278 															 *pDoc->GetFormatTable(),
3279 															 bShowNullValues,
3280 															 bShowFormulas,
3281 															 ftCheck );
3282 
3283 									pEngine->SetText(aString);
3284 									if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
3285 										lcl_SetEditColor( *pEngine, *pColor );
3286 								}
3287 
3288 								if ( bSyntaxMode )
3289 									SetEditSyntaxColor( *pEngine, pCell );
3290 								else if ( bUseStyleColor && bForceAutoColor )
3291 									lcl_SetEditColor( *pEngine, COL_AUTO );		//! or have a flag at EditEngine
3292 							}
3293 							else
3294 							{
3295 								DBG_ERROR("pCell == NULL");
3296 							}
3297 
3298 							pEngine->SetUpdateMode( sal_True );		// after SetText, before CalcTextWidth/GetTextHeight
3299 
3300 							long nEngineWidth  = (long) pEngine->CalcTextWidth();
3301 							long nEngineHeight = pEngine->GetTextHeight();
3302 
3303 							if (nAttrRotate && bBreak)
3304 							{
3305 								double nAbsCos = fabs( nCos );
3306 								double nAbsSin = fabs( nSin );
3307 
3308 								// #47740# adjust witdh of papersize for height of text
3309 								int nSteps = 5;
3310 								while (nSteps > 0)
3311 								{
3312 									// everything is in pixels
3313 									long nEnginePixel = pRefDevice->LogicToPixel(
3314 															Size(0,nEngineHeight)).Height();
3315 									long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2;
3316 									long nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
3317 									sal_Bool bFits = ( nNewWidth >= aPaperSize.Width() );
3318 									if ( bFits )
3319 										nSteps = 0;
3320 									else
3321 									{
3322 										if ( nNewWidth < 4 )
3323 										{
3324 											// can't fit -> fall back to using half height
3325 											nEffHeight = nOutHeight / 2;
3326 											nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
3327 											nSteps = 0;
3328 										}
3329 										else
3330 											--nSteps;
3331 
3332 										// set paper width and get new text height
3333 										aPaperSize.Width() = nNewWidth;
3334 										if (bPixelToLogic)
3335 											pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize));
3336 										else
3337 											pEngine->SetPaperSize(aPaperSize);	// Scale ist immer 1
3338 										//pEngine->QuickFormatDoc( sal_True );
3339 										nEngineWidth  = (long) pEngine->CalcTextWidth();
3340 										nEngineHeight = pEngine->GetTextHeight();
3341 									}
3342 								}
3343 							}
3344 
3345 							long nRealWidth  = nEngineWidth;
3346 							long nRealHeight = nEngineHeight;
3347 
3348 							//	wenn gedreht, Groesse anpassen
3349 							if (nAttrRotate)
3350 							{
3351 								double nAbsCos = fabs( nCos );
3352 								double nAbsSin = fabs( nSin );
3353 
3354 								if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
3355 									nEngineWidth = (long) ( nRealWidth * nAbsCos +
3356 															nRealHeight * nAbsSin );
3357 								else
3358 									nEngineWidth = (long) ( nRealHeight / nAbsSin );
3359 								//!	begrenzen !!!
3360 
3361 								nEngineHeight = (long) ( nRealHeight * nAbsCos +
3362 														 nRealWidth * nAbsSin );
3363 							}
3364 
3365 							if (!nAttrRotate)			//	hier nur gedrehter Text
3366 								bHidden = sal_True;			//! vorher abfragen !!!
3367 
3368 							//!	weglassen, was nicht hereinragt
3369 
3370 							if (!bHidden)
3371 							{
3372 								sal_Bool bClip = sal_False;
3373 								Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
3374 
3375 								//	weiterschreiben
3376 
3377 								Size aCellSize;
3378 								if (bPixelToLogic)
3379 									aCellSize = pRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3380 								else
3381 									aCellSize = Size( nOutWidth, nOutHeight );	// Scale ist 1
3382 
3383 								long nGridWidth = nEngineWidth;
3384 								sal_Bool bNegative = sal_False;
3385 								if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
3386 								{
3387 									nGridWidth = aCellSize.Width() +
3388 											Abs((long) ( aCellSize.Height() * nCos / nSin ));
3389 									bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT );
3390 									if ( bLayoutRTL )
3391 										bNegative = !bNegative;
3392 								}
3393 
3394 								// use GetOutputArea to hide the grid
3395 								// (clip region is done manually below)
3396                                 OutputAreaParam aAreaParam;
3397 
3398 								SCCOL nCellX = nX;
3399 								SCROW nCellY = nY;
3400 								SvxCellHorJustify eOutHorJust = eHorJust;
3401 								if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
3402 									eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
3403 								long nNeededWidth = nGridWidth;		// in pixel for GetOutputArea
3404 								if ( bPixelToLogic )
3405 									nNeededWidth =  pRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
3406 
3407 								GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
3408                                                 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3409                                                 sal_False, sal_False, sal_True, aAreaParam );
3410 
3411                                 if ( bShrink )
3412                                 {
3413                                     long nPixelWidth = bPixelToLogic ?
3414                                         pRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
3415                                     long nNeededPixel = nPixelWidth + nLeftM + nRightM;
3416 
3417                                     aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_True;
3418 
3419                                     // always do height
3420                                     ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
3421                                         sal_False, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
3422                                         nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3423 
3424                                     if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
3425                                     {
3426                                         // do width only if rotating within the cell (standard mode)
3427                                         ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
3428                                             sal_True, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
3429                                             nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3430                                     }
3431 
3432                                     // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
3433                                     // (but width is only valid for standard mode)
3434                                     nRealWidth  = (long) pEngine->CalcTextWidth();
3435                                     nRealHeight = pEngine->GetTextHeight();
3436 
3437                                     if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
3438                                         nEngineWidth = (long) ( nRealHeight / fabs( nSin ) );
3439                                 }
3440 
3441 								// sal_Bool bVClip = ( nEngineHeight > aCellSize.Height() );
3442 
3443 								long nClipStartX = nStartX;
3444 								if (nX<nX1)
3445 								{
3446 									//! Clipping unnoetig, wenn links am Fenster
3447 
3448 									bClip = sal_True;					// nur Rest ausgeben!
3449 									if (nStartX<nScrX)
3450 									{
3451 										long nDif = nScrX - nStartX;
3452 										nClipStartX = nScrX;
3453 										aClipSize.Width() -= nDif;
3454 									}
3455 								}
3456 
3457 								long nClipStartY = nStartY;
3458 								if (nArrY==0 || bVisChanged)
3459 								{
3460 									if ( nClipStartY < nRowPosY )
3461 									{
3462 										long nDif = nRowPosY - nClipStartY;
3463 										bClip = sal_True;
3464 										nClipStartY = nRowPosY;
3465 										aClipSize.Height() -= nDif;
3466 									}
3467 								}
3468 
3469 								bClip = sal_True;		// always clip at the window/page border
3470 
3471 								//Rectangle aClipRect;
3472 								if (bClip)
3473 								{
3474 									if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
3475 									{
3476 										//	gedrehten, ausgerichteten Text nur an den
3477 										//	Seitengrenzen clippen
3478 										nClipStartX = nScrX;
3479 										aClipSize.Width() = nScrW;
3480 									}
3481 
3482 									if (bPixelToLogic)
3483                                         aAreaParam.maClipRect = pRefDevice->PixelToLogic( Rectangle(
3484 														Point(nClipStartX,nClipStartY), aClipSize ) );
3485 									else
3486                                         aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY),
3487 																aClipSize );	// Scale = 1
3488 
3489 									if (bMetaFile)
3490 									{
3491 										pDev->Push();
3492                                         pDev->IntersectClipRegion( aAreaParam.maClipRect );
3493 									}
3494 									else
3495                                         pDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
3496 								}
3497 
3498 								Point aLogicStart;
3499 								if (bPixelToLogic)
3500 									aLogicStart = pRefDevice->PixelToLogic( Point(nStartX,nStartY) );
3501 								else
3502 									aLogicStart = Point(nStartX, nStartY);
3503 								if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak )
3504 								{
3505 									long nAvailWidth = aCellSize.Width();
3506 									if (eType==OUTTYPE_WINDOW &&
3507 											eOrient!=SVX_ORIENTATION_STACKED &&
3508 											pInfo && pInfo->bAutoFilter)
3509 									{
3510                                         // filter drop-down width is now independent from row height
3511                                         if (bPixelToLogic)
3512                                             nAvailWidth -= pRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height();
3513                                         else
3514                                             nAvailWidth -= DROPDOWN_BITMAP_SIZE;
3515 										long nComp = nEngineWidth;
3516 										if (nAvailWidth<nComp) nAvailWidth=nComp;
3517 									}
3518 
3519 									//	horizontale Ausrichtung
3520 
3521 									if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate)
3522 									{
3523 										if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
3524 											eHorJust==SVX_HOR_JUSTIFY_CENTER)
3525 										{
3526 											pEngine->SetUpdateMode( sal_False );
3527 
3528 											SvxAdjust eSvxAdjust =
3529 												(eHorJust==SVX_HOR_JUSTIFY_RIGHT) ?
3530 													SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER;
3531 											pEngine->SetDefaultItem(
3532 												SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
3533 
3534 											aPaperSize.Width() = nOutWidth;
3535 											if (bPixelToLogic)
3536 												pEngine->SetPaperSize(pRefDevice->PixelToLogic(aPaperSize));
3537 											else
3538 												pEngine->SetPaperSize(aPaperSize);
3539 
3540 											pEngine->SetUpdateMode( sal_True );
3541 										}
3542 									}
3543 									else
3544 									{
3545 										//	bei gedrehtem Text ist Standard zentriert
3546 										if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
3547 											aLogicStart.X() += nAvailWidth - nEngineWidth;
3548 										else if (eHorJust==SVX_HOR_JUSTIFY_CENTER ||
3549 												 eHorJust==SVX_HOR_JUSTIFY_STANDARD)
3550 											aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
3551 									}
3552 								}
3553 
3554 								if ( bLayoutRTL )
3555 								{
3556 									if (bPixelToLogic)
3557 										aLogicStart.X() -= pRefDevice->PixelToLogic(
3558 														Size( nCellWidth, 0 ) ).Width();
3559 									else
3560 										aLogicStart.X() -= nCellWidth;
3561 								}
3562 
3563 								if ( eOrient==SVX_ORIENTATION_STANDARD ||
3564 									 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
3565 								{
3566 									if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
3567 										eVerJust==SVX_VER_JUSTIFY_STANDARD)
3568 									{
3569 										if (bPixelToLogic)
3570 											aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0,
3571 															pRefDevice->LogicToPixel(aCellSize).Height() -
3572 															pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3573 															)).Height();
3574 										else
3575 											aLogicStart.Y() += aCellSize.Height() - nEngineHeight;
3576 									}
3577 
3578 									else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
3579 									{
3580 										if (bPixelToLogic)
3581 											aLogicStart.Y() += pRefDevice->PixelToLogic( Size(0,(
3582 															pRefDevice->LogicToPixel(aCellSize).Height() -
3583 															pRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
3584 															/ 2)).Height();
3585 										else
3586 											aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2;
3587 									}
3588 								}
3589 
3590 								// TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
3591 								DBG_ASSERT( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate,
3592 											"DrawRotated: no rotation" );
3593 
3594 								long nOriVal = 0;
3595 								if ( nAttrRotate )
3596 								{
3597 									// Attribut ist 1/100, Font 1/10 Grad
3598 									nOriVal = nAttrRotate / 10;
3599 
3600 									double nAddX = 0.0;
3601 									double nAddY = 0.0;
3602 									if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
3603 									{
3604 										//!	begrenzen !!!
3605 										double nH = nRealHeight * nCos;
3606 										nAddX += nH * ( nCos / fabs(nSin) );
3607 									}
3608 									if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
3609 										nAddX -= nRealWidth * nCos;
3610 									if ( nSin < 0.0 )
3611 										nAddX -= nRealHeight * nSin;
3612 									if ( nSin > 0.0 )
3613 										nAddY += nRealWidth * nSin;
3614 									if ( nCos < 0.0 )
3615 										nAddY -= nRealHeight * nCos;
3616 
3617 									if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
3618 									{
3619 										//!	begrenzen !!!
3620 										double nSkew = nTotalHeight * nCos / fabs(nSin);
3621 										if ( eRotMode == SVX_ROTATE_MODE_CENTER )
3622 											nAddX -= nSkew * 0.5;
3623 										if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
3624 											 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
3625 											nAddX -= nSkew;
3626 
3627 										long nUp = 0;
3628 										if ( eVerJust == SVX_VER_JUSTIFY_CENTER )
3629 											nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
3630 										else if ( eVerJust == SVX_VER_JUSTIFY_TOP )
3631 										{
3632 											if ( nSin > 0.0 )
3633 												nUp = aCellSize.Height() - nEngineHeight;
3634 										}
3635 										else	// BOTTOM / STANDARD
3636 										{
3637 											if ( nSin < 0.0 )
3638 												nUp = aCellSize.Height() - nEngineHeight;
3639 										}
3640 										if ( nUp )
3641 											nAddX += ( nUp * nCos / fabs(nSin) );
3642 									}
3643 
3644 									aLogicStart.X() += (long) nAddX;
3645 									aLogicStart.Y() += (long) nAddY;
3646 								}
3647 
3648 								//	bSimClip is not used here (because nOriVal is set)
3649 
3650 								if ( pEngine->IsRightToLeft( 0 ) )
3651 								{
3652 									//	For right-to-left, EditEngine always calculates its lines
3653 									//	beginning from the right edge, but EditLine::nStartPosX is
3654 									//	of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
3655 									Size aLogicPaper = pEngine->GetPaperSize();
3656 									if ( aLogicPaper.Width() > USHRT_MAX )
3657 									{
3658 										aLogicPaper.Width() = USHRT_MAX;
3659 										pEngine->SetPaperSize(aLogicPaper);
3660 									}
3661 								}
3662 
3663 								pEngine->Draw( pDev, aLogicStart, (short)nOriVal );
3664 
3665 								if (bClip)
3666 								{
3667 									if (bMetaFile)
3668 										pDev->Pop();
3669 									else
3670 										pDev->SetClipRegion();
3671 								}
3672 							}
3673 						}
3674 					}
3675 				}
3676 				nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
3677 			}
3678 		}
3679 		nRowPosY += pRowInfo[nArrY].nHeight;
3680 	}
3681 
3682 	delete pEngine;
3683 }
3684 
3685 
3686 
3687