xref: /AOO42X/main/sc/source/ui/view/output2.cxx (revision cdf0e10c4e3984b49a9502b011690b615761d4a3) !
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