GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / sc / source / ui / view / output2.cxx
blob9c09b5c9212b6229c4db370f93759274cca98477
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "scitems.hxx"
21 #include <editeng/eeitem.hxx>
23 #include <editeng/adjustitem.hxx>
24 #include <svx/algitem.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <svtools/colorcfg.hxx>
27 #include <editeng/colritem.hxx>
28 #include <editeng/editobj.hxx>
29 #include <editeng/editstat.hxx>
30 #include <editeng/fhgtitem.hxx>
31 #include <editeng/forbiddencharacterstable.hxx>
32 #include <editeng/frmdiritem.hxx>
33 #include <editeng/langitem.hxx>
34 #include <editeng/justifyitem.hxx>
35 #include <svx/rotmodit.hxx>
36 #include <editeng/scripttypeitem.hxx>
37 #include <editeng/udlnitem.hxx>
38 #include <editeng/unolingu.hxx>
39 #include <editeng/fontitem.hxx>
40 #include <svl/zforlist.hxx>
41 #include <svl/zformat.hxx>
42 #include <vcl/svapp.hxx>
43 #include <vcl/metric.hxx>
44 #include <vcl/outdev.hxx>
45 #include <vcl/pdfextoutdevdata.hxx>
47 #include "output.hxx"
48 #include "document.hxx"
49 #include "formulacell.hxx"
50 #include "attrib.hxx"
51 #include "patattr.hxx"
52 #include "cellform.hxx"
53 #include "editutil.hxx"
54 #include "progress.hxx"
55 #include "scmod.hxx"
56 #include "fillinfo.hxx"
57 #include "viewdata.hxx"
58 #include "tabvwsh.hxx"
59 #include "docsh.hxx"
60 #include "markdata.hxx"
61 #include "stlsheet.hxx"
62 #include "spellcheckcontext.hxx"
64 #include <com/sun/star/i18n/DirectionProperty.hpp>
65 #include <comphelper/string.hxx>
67 #include <boost/ptr_container/ptr_vector.hpp>
69 #include <math.h>
71 using namespace com::sun::star;
73 //! Autofilter-Breite mit column.cxx zusammenfassen
74 #define DROPDOWN_BITMAP_SIZE 18
76 #define DRAWTEXT_MAX 32767
78 const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
80 // STATIC DATA -----------------------------------------------------------
83 // -----------------------------------------------------------------------
85 class ScDrawStringsVars
87 ScOutputData* pOutput; // Verbindung
89 const ScPatternAttr* pPattern; // Attribute
90 const SfxItemSet* pCondSet; // aus bedingter Formatierung
92 Font aFont; // aus Attributen erzeugt
93 FontMetric aMetric;
94 long nAscentPixel; // always pixels
95 SvxCellOrientation eAttrOrient;
96 SvxCellHorJustify eAttrHorJust;
97 SvxCellVerJustify eAttrVerJust;
98 SvxCellJustifyMethod eAttrHorJustMethod;
99 SvxCellJustifyMethod eAttrVerJustMethod;
100 const SvxMarginItem* pMargin;
101 sal_uInt16 nIndent;
102 sal_Bool bRotated;
104 OUString aString; // contents
105 Size aTextSize;
106 long nOriginalWidth;
107 long nMaxDigitWidth;
108 long nSignWidth;
109 long nDotWidth;
110 long nExpWidth;
112 ScRefCellValue maLastCell;
113 sal_uLong nValueFormat;
114 sal_Bool bLineBreak;
115 sal_Bool bRepeat;
116 sal_Bool bShrink;
118 sal_Bool bPixelToLogic;
119 sal_Bool bCellContrast;
121 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
122 Color aTextConfigColor;
123 sal_Int32 nPos;
124 sal_Unicode nChar;
126 public:
127 ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL);
128 ~ScDrawStringsVars();
130 // SetPattern = ex-SetVars
131 // SetPatternSimple: ohne Font
133 void SetPattern(
134 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
135 sal_uInt8 nScript );
137 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
139 bool SetText( ScRefCellValue& rCell ); // TRUE -> pOldPattern vergessen
140 void SetHashText();
141 void SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth );
142 void SetAutoText( const OUString& rAutoText );
144 const ScPatternAttr* GetPattern() const { return pPattern; }
145 SvxCellOrientation GetOrient() const { return eAttrOrient; }
146 SvxCellHorJustify GetHorJust() const { return eAttrHorJust; }
147 SvxCellVerJustify GetVerJust() const { return eAttrVerJust; }
148 SvxCellJustifyMethod GetHorJustMethod() const { return eAttrHorJustMethod; }
149 SvxCellJustifyMethod GetVerJustMethod() const { return eAttrVerJustMethod; }
150 const SvxMarginItem* GetMargin() const { return pMargin; }
152 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
153 sal_uInt16 GetRightTotal() const { return pMargin->GetRightMargin() + nIndent; }
155 const OUString& GetString() const { return aString; }
156 const Size& GetTextSize() const { return aTextSize; }
157 long GetOriginalWidth() const { return nOriginalWidth; }
159 sal_uLong GetResultValueFormat() const;
161 sal_uLong GetValueFormat() const { return nValueFormat; }
162 sal_Bool GetLineBreak() const { return bLineBreak; }
163 sal_Bool IsRepeat() const { return bRepeat; }
164 sal_Bool IsShrink() const { return bShrink; }
165 void RepeatToFill( long colWidth );
167 long GetAscent() const { return nAscentPixel; }
168 sal_Bool IsRotated() const { return bRotated; }
170 void SetShrinkScale( long nScale, sal_uInt8 nScript );
172 sal_Bool HasCondHeight() const { return pCondSet && SFX_ITEM_SET ==
173 pCondSet->GetItemState( ATTR_FONT_HEIGHT, sal_True ); }
175 sal_Bool HasEditCharacters() const;
177 private:
178 long GetMaxDigitWidth(); // in logic units
179 long GetSignWidth();
180 long GetDotWidth();
181 long GetExpWidth();
182 void TextChanged();
185 //==================================================================
187 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, sal_Bool bPTL) :
188 pOutput ( pData ),
189 pPattern ( NULL ),
190 pCondSet ( NULL ),
191 nAscentPixel(0),
192 eAttrOrient ( SVX_ORIENTATION_STANDARD ),
193 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ),
194 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ),
195 eAttrHorJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
196 eAttrVerJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
197 pMargin ( NULL ),
198 nIndent ( 0 ),
199 bRotated ( false ),
200 nOriginalWidth( 0 ),
201 nMaxDigitWidth( 0 ),
202 nSignWidth( 0 ),
203 nDotWidth( 0 ),
204 nExpWidth( 0 ),
205 nValueFormat( 0 ),
206 bLineBreak ( false ),
207 bRepeat ( false ),
208 bShrink ( false ),
209 bPixelToLogic( bPTL ),
210 nPos( -1 ),
211 nChar( 0x0 )
213 ScModule* pScMod = SC_MOD();
214 bCellContrast = pOutput->mbUseStyleColor &&
215 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
217 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
218 aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor );
219 aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor );
222 ScDrawStringsVars::~ScDrawStringsVars()
226 void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript )
228 // text remains valid, size is updated
230 OutputDevice* pDev = pOutput->mpDev;
231 OutputDevice* pRefDevice = pOutput->mpRefDevice;
232 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
234 // call GetFont with a modified fraction, use only the height
236 Fraction aFraction( nScale, 100 );
237 if ( !bPixelToLogic )
238 aFraction *= pOutput->aZoomY;
239 Font aTmpFont;
240 pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
241 long nNewHeight = aTmpFont.GetHeight();
242 if ( nNewHeight > 0 )
243 aFont.SetHeight( nNewHeight );
245 // set font and dependent variables as in SetPattern
247 pDev->SetFont( aFont );
248 if ( pFmtDevice != pDev )
249 pFmtDevice->SetFont( aFont );
251 aMetric = pFmtDevice->GetFontMetric();
252 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
254 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
255 MapMode aOld = pDefaultDev->GetMapMode();
256 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
257 aMetric = pDefaultDev->GetFontMetric( aFont );
258 pDefaultDev->SetMapMode( aOld );
261 nAscentPixel = aMetric.GetAscent();
262 if ( bPixelToLogic )
263 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
265 SetAutoText( aString ); // same text again, to get text size
268 namespace {
270 template<typename _ItemType, typename _EnumType>
271 _EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
273 const _ItemType& rItem = static_cast<const _ItemType&>(rPattern.GetItem(nWhich, pCondSet));
274 return static_cast<_EnumType>(rItem.GetValue());
277 bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
279 return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
284 void ScDrawStringsVars::SetPattern(
285 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
286 sal_uInt8 nScript )
288 nMaxDigitWidth = 0;
289 nSignWidth = 0;
290 nDotWidth = 0;
291 nExpWidth = 0;
293 pPattern = pNew;
294 pCondSet = pSet;
296 // pPattern auswerten
298 OutputDevice* pDev = pOutput->mpDev;
299 OutputDevice* pRefDevice = pOutput->mpRefDevice;
300 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
302 // Font
304 ScAutoFontColorMode eColorMode;
305 if ( pOutput->mbUseStyleColor )
307 if ( pOutput->mbForceAutoColor )
308 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
309 else
310 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
312 else
313 eColorMode = SC_AUTOCOL_PRINT;
315 if ( bPixelToLogic )
316 pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript,
317 &aBackConfigColor, &aTextConfigColor );
318 else
319 pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
320 &aBackConfigColor, &aTextConfigColor );
321 aFont.SetAlign(ALIGN_BASELINE);
323 // Orientierung
325 eAttrOrient = pPattern->GetCellOrientation( pCondSet );
327 // alignment
329 eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
331 eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue();
332 if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD )
333 eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM;
335 // justification method
337 eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
338 eAttrVerJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet);
340 // line break
342 bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue();
344 // handle "repeat" alignment
346 bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT );
347 if ( bRepeat )
349 // "repeat" disables rotation (before constructing the font)
350 eAttrOrient = SVX_ORIENTATION_STANDARD;
352 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
353 if ( bLineBreak )
354 eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD;
357 short nRot;
358 switch (eAttrOrient)
360 case SVX_ORIENTATION_STANDARD:
361 nRot = 0;
362 bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) &&
363 !bRepeat;
364 break;
365 case SVX_ORIENTATION_STACKED:
366 nRot = 0;
367 bRotated = false;
368 break;
369 case SVX_ORIENTATION_TOPBOTTOM:
370 nRot = 2700;
371 bRotated = false;
372 break;
373 case SVX_ORIENTATION_BOTTOMTOP:
374 nRot = 900;
375 bRotated = false;
376 break;
377 default:
378 OSL_FAIL("Falscher SvxCellOrientation Wert");
379 nRot = 0;
380 bRotated = false;
381 break;
383 aFont.SetOrientation( nRot );
385 // Syntax-Modus
387 if (pOutput->mbSyntaxMode)
388 pOutput->SetSyntaxColor(&aFont, rCell);
390 pDev->SetFont( aFont );
391 if ( pFmtDevice != pDev )
392 pFmtDevice->SetFont( aFont );
394 aMetric = pFmtDevice->GetFontMetric();
397 // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme
398 // -> Metric vom Bildschirm nehmen (wie EditEngine!)
401 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
403 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
404 MapMode aOld = pDefaultDev->GetMapMode();
405 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
406 aMetric = pDefaultDev->GetFontMetric( aFont );
407 pDefaultDev->SetMapMode( aOld );
410 nAscentPixel = aMetric.GetAscent();
411 if ( bPixelToLogic )
412 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
414 Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() );
415 pDev->SetTextLineColor( aULineColor );
417 Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() );
418 pDev->SetOverlineColor( aOLineColor );
420 // Zahlenformat
422 nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
424 // Raender
426 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
427 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT || eAttrHorJust == SVX_HOR_JUSTIFY_RIGHT )
428 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
429 else
430 nIndent = 0;
432 // "Shrink to fit"
434 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
436 // zumindest die Text-Groesse muss neu geholt werden
437 //! unterscheiden, und den Text nicht neu vom Numberformatter holen?
439 maLastCell.clear();
442 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
444 nMaxDigitWidth = 0;
445 nSignWidth = 0;
446 nDotWidth = 0;
447 nExpWidth = 0;
448 // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer)
450 pPattern = pNew;
451 pCondSet = pSet; //! noetig ???
453 // Zahlenformat
455 sal_uLong nOld = nValueFormat;
456 const SfxPoolItem* pFormItem;
457 if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,sal_True,&pFormItem) != SFX_ITEM_SET )
458 pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT);
459 const SfxPoolItem* pLangItem;
460 if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,sal_True,&pLangItem) != SFX_ITEM_SET )
461 pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT);
462 nValueFormat = pOutput->mpDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
463 ((SfxUInt32Item*)pFormItem)->GetValue(),
464 ((SvxLanguageItem*)pLangItem)->GetLanguage() );
466 if (nValueFormat != nOld)
467 maLastCell.clear(); // immer neu formatieren
469 // Raender
471 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
473 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
474 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
475 else
476 nIndent = 0;
478 // "Shrink to fit"
480 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
483 inline bool SameValue( const ScRefCellValue& rCell, const ScRefCellValue& rOldCell )
485 return rOldCell.meType == CELLTYPE_VALUE && rCell.meType == CELLTYPE_VALUE &&
486 rCell.mfValue == rOldCell.mfValue;
489 bool ScDrawStringsVars::SetText( ScRefCellValue& rCell )
491 bool bChanged = false;
493 if (!rCell.isEmpty())
495 if (!SameValue(rCell, maLastCell))
497 maLastCell = rCell; // Zelle merken
499 Color* pColor;
500 sal_uLong nFormat = GetValueFormat();
501 ScCellFormat::GetString( rCell,
502 nFormat, aString, &pColor,
503 *pOutput->mpDoc->GetFormatTable(),
504 pOutput->mpDoc,
505 pOutput->mbShowNullValues,
506 pOutput->mbShowFormulas,
507 ftCheck, true );
508 if ( nFormat )
510 nPos = aString.indexOf( 0x1B );
511 if ( nPos != -1 )
513 nChar = aString[ nPos + 1 ];
514 // delete placeholder and char to repeat
515 aString = aString.replaceAt( nPos, 2, "" );
518 else
520 nPos = -1;
521 nChar = 0x0;
523 if (aString.getLength() > DRAWTEXT_MAX)
524 aString = aString.copy(0, DRAWTEXT_MAX);
526 if ( pColor && !pOutput->mbSyntaxMode && !( pOutput->mbUseStyleColor && pOutput->mbForceAutoColor ) )
528 OutputDevice* pDev = pOutput->mpDev;
529 aFont.SetColor(*pColor);
530 pDev->SetFont( aFont ); // nur fuer Ausgabe
531 bChanged = true;
532 maLastCell.clear(); // naechstes Mal wieder hierherkommen
535 TextChanged();
537 // sonst String/Groesse behalten
539 else
541 aString = OUString();
542 maLastCell.clear();
543 aTextSize = Size(0,0);
544 nOriginalWidth = 0;
547 return bChanged;
550 void ScDrawStringsVars::SetHashText()
552 SetAutoText(OUString("###"));
555 void ScDrawStringsVars::RepeatToFill( long colWidth )
557 if ( nPos == -1 || nPos > aString.getLength() )
558 return;
560 long charWidth = pOutput->pFmtDevice->GetTextWidth(OUString(nChar));
561 if ( charWidth < 1) return;
562 if (bPixelToLogic)
563 colWidth = pOutput->mpRefDevice->PixelToLogic(Size(colWidth,0)).Width();
564 // Are there restrictions on the cell type we should filter out here ?
565 long aSpaceToFill = ( colWidth - aTextSize.Width() );
567 if ( aSpaceToFill <= charWidth )
568 return;
570 long nCharsToInsert = aSpaceToFill / charWidth;
571 OUStringBuffer aFill;
572 comphelper::string::padToLength(aFill, nCharsToInsert, nChar);
573 aString = aString.replaceAt( nPos, 0, aFill.makeStringAndClear() );
574 TextChanged();
577 void ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth )
579 // #i113045# do the single-character width calculations in logic units
580 if (bPixelToLogic)
581 nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
583 CellType eType = rCell.meType;
584 if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
585 // must be a value or formula cell.
586 return;
588 if (eType == CELLTYPE_FORMULA)
590 ScFormulaCell* pFCell = rCell.mpFormula;
591 if (pFCell->GetErrCode() != 0 || pOutput->mbShowFormulas)
593 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
594 return;
596 // If it's formula, the result must be a value.
597 if (!pFCell->IsValue())
598 return;
601 sal_uLong nFormat = GetResultValueFormat();
602 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
604 // Not 'General' number format. Set hash text and bail out.
605 SetHashText();
606 return;
609 double fVal = rCell.getValue();
611 const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
612 if (!pNumFormat)
613 return;
615 long nMaxDigit = GetMaxDigitWidth();
616 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
618 OUString sTempOut(aString);
619 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
621 aString = sTempOut;
622 // Failed to get output string. Bail out.
623 return;
625 aString = sTempOut;
627 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
628 sal_Int32 nLen = aString.getLength();
629 sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator[0];
630 for( sal_Int32 i = 0; i < nLen; ++i )
632 sal_Unicode c = aString[i];
633 if (c == '-')
634 ++nSignCount;
635 else if (c == cDecSep)
636 ++nDecimalCount;
637 else if (c == 'E')
638 ++nExpCount;
641 // #i112250# A small value might be formatted as "0" when only counting the digits,
642 // but fit into the column when considering the smaller width of the decimal separator.
643 if (aString == "0" && fVal != 0.0)
644 nDecimalCount = 1;
646 if (nDecimalCount)
647 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
648 if (nSignCount)
649 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
650 if (nExpCount)
651 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
653 if (nDecimalCount || nSignCount || nExpCount)
655 // Re-calculate.
656 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
657 OUString sTempOut(aString);
658 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
660 aString = sTempOut;
661 // Failed to get output string. Bail out.
662 return;
664 aString = sTempOut;
667 long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
668 if (nActualTextWidth > nWidth)
670 // Even after the decimal adjustment the text doesn't fit. Give up.
671 SetHashText();
672 return;
675 TextChanged();
676 maLastCell.clear(); // #i113022# equal cell and format in another column may give different string
679 void ScDrawStringsVars::SetAutoText( const OUString& rAutoText )
681 aString = rAutoText;
683 OutputDevice* pRefDevice = pOutput->mpRefDevice;
684 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
685 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
686 aTextSize.Height() = pFmtDevice->GetTextHeight();
688 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
690 double fMul = pOutput->GetStretch();
691 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
694 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
695 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
697 long nTemp = aTextSize.Height();
698 aTextSize.Height() = aTextSize.Width();
699 aTextSize.Width() = nTemp;
702 nOriginalWidth = aTextSize.Width();
703 if ( bPixelToLogic )
704 aTextSize = pRefDevice->LogicToPixel( aTextSize );
706 maLastCell.clear(); // derselbe Text kann in der naechsten Zelle wieder passen
709 long ScDrawStringsVars::GetMaxDigitWidth()
711 if (nMaxDigitWidth > 0)
712 return nMaxDigitWidth;
714 sal_Char cZero = '0';
715 for (sal_Char i = 0; i < 10; ++i)
717 sal_Char cDigit = cZero + i;
718 long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
719 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
721 return nMaxDigitWidth;
724 long ScDrawStringsVars::GetSignWidth()
726 if (nSignWidth > 0)
727 return nSignWidth;
729 nSignWidth = pOutput->pFmtDevice->GetTextWidth(OUString('-'));
730 return nSignWidth;
733 long ScDrawStringsVars::GetDotWidth()
735 if (nDotWidth > 0)
736 return nDotWidth;
738 const OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator;
739 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
740 return nDotWidth;
743 long ScDrawStringsVars::GetExpWidth()
745 if (nExpWidth > 0)
746 return nExpWidth;
748 nExpWidth = pOutput->pFmtDevice->GetTextWidth(OUString('E'));
749 return nExpWidth;
752 void ScDrawStringsVars::TextChanged()
754 OutputDevice* pRefDevice = pOutput->mpRefDevice;
755 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
756 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
757 aTextSize.Height() = pFmtDevice->GetTextHeight();
759 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
761 double fMul = pOutput->GetStretch();
762 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
765 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
766 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
768 long nTemp = aTextSize.Height();
769 aTextSize.Height() = aTextSize.Width();
770 aTextSize.Width() = nTemp;
773 nOriginalWidth = aTextSize.Width();
774 if ( bPixelToLogic )
775 aTextSize = pRefDevice->LogicToPixel( aTextSize );
778 sal_Bool ScDrawStringsVars::HasEditCharacters() const
780 for (sal_Int32 nIdx = 0; nIdx < aString.getLength(); ++nIdx)
782 switch(aString[nIdx])
784 case CHAR_NBSP:
785 case CHAR_SHY:
786 case CHAR_ZWSP:
787 case CHAR_LRM:
788 case CHAR_RLM:
789 case CHAR_NBHY:
790 case CHAR_ZWNBSP:
791 return sal_True;
792 default:
793 break;
797 return sal_False;
800 sal_uLong ScDrawStringsVars::GetResultValueFormat() const
802 // Get the effective number format, including formula result types.
803 // This assumes that a formula cell has already been calculated.
805 return nValueFormat;
808 //==================================================================
810 double ScOutputData::GetStretch()
812 if ( mpRefDevice->IsMapMode() )
814 // If a non-trivial MapMode is set, its scale is now already
815 // taken into account in the OutputDevice's font handling
816 // (OutputDevice::ImplNewFont, see #95414#).
817 // The old handling below is only needed for pixel output.
818 return 1.0;
821 // calculation in double is faster than Fraction multiplication
822 // and doesn't overflow
824 if ( mpRefDevice == pFmtDevice )
826 MapMode aOld = mpRefDevice->GetMapMode();
827 return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX);
829 else
831 // when formatting for printer, device map mode has already been taken care of
832 return ((double)aZoomY) / ((double)aZoomX);
836 //==================================================================
839 // output strings
842 static void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScRefCellValue& rCell )
844 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
846 OUString aCellText;
847 OUString aURL;
848 if (rCell.meType == CELLTYPE_FORMULA)
850 ScFormulaCell* pFCell = rCell.mpFormula;
851 if ( pFCell->IsHyperLinkCell() )
852 pFCell->GetURLResult( aURL, aCellText );
855 if ( !aURL.isEmpty() && pPDFData )
857 vcl::PDFExtOutDevBookmarkEntry aBookmark;
858 aBookmark.nLinkId = pPDFData->CreateLink( rRect );
859 aBookmark.aBookmark = aURL;
860 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
861 rBookmarks.push_back( aBookmark );
865 void ScOutputData::SetSyntaxColor( Font* pFont, const ScRefCellValue& rCell )
867 switch (rCell.meType)
869 case CELLTYPE_VALUE:
870 pFont->SetColor(*pValueColor);
871 break;
872 case CELLTYPE_STRING:
873 pFont->SetColor(*pTextColor);
874 break;
875 case CELLTYPE_FORMULA:
876 pFont->SetColor(*pFormulaColor);
877 break;
878 default:
880 // added to avoid warnings
885 static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
887 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
888 SfxItemSet aSet( rEngine.GetEmptyItemSet() );
889 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
890 rEngine.QuickSetAttribs( aSet, aSel );
891 // function is called with update mode set to FALSE
894 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScRefCellValue& rCell )
896 Color aColor;
897 switch (rCell.meType)
899 case CELLTYPE_VALUE:
900 aColor = *pValueColor;
901 break;
902 case CELLTYPE_STRING:
903 aColor = *pTextColor;
904 break;
905 case CELLTYPE_FORMULA:
906 aColor = *pFormulaColor;
907 break;
908 default:
910 // added to avoid warnings
913 lcl_SetEditColor( rEngine, aColor );
916 sal_Bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
917 SCCOL& rOverX, SCROW& rOverY,
918 sal_Bool bVisRowChanged )
920 sal_Bool bDoMerge = false;
921 sal_Bool bIsLeft = ( nX == nVisX1 );
922 sal_Bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
924 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
925 if ( pInfo->bHOverlapped && pInfo->bVOverlapped )
926 bDoMerge = bIsLeft && bIsTop;
927 else if ( pInfo->bHOverlapped )
928 bDoMerge = bIsLeft;
929 else if ( pInfo->bVOverlapped )
930 bDoMerge = bIsTop;
932 rOverX = nX;
933 rOverY = nY;
934 sal_Bool bHOver = pInfo->bHOverlapped;
935 sal_Bool bVOver = pInfo->bVOverlapped;
936 sal_Bool bHidden;
938 while (bHOver) // nY konstant
940 --rOverX;
941 bHidden = mpDoc->ColHidden(rOverX, nTab);
942 if ( !bDoMerge && !bHidden )
943 return false;
945 if (rOverX >= nX1 && !bHidden)
947 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
948 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
950 else
952 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
953 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
954 bHOver = ((nOverlap & SC_MF_HOR) != 0);
955 bVOver = ((nOverlap & SC_MF_VER) != 0);
959 while (bVOver)
961 --rOverY;
962 bHidden = mpDoc->RowHidden(rOverY, nTab);
963 if ( !bDoMerge && !bHidden )
964 return false;
966 if (nArrY>0)
967 --nArrY; // lokale Kopie !
969 if (rOverX >= nX1 && rOverY >= nY1 &&
970 !mpDoc->ColHidden(rOverX, nTab) &&
971 !mpDoc->RowHidden(rOverY, nTab) &&
972 pRowInfo[nArrY].nRowNo == rOverY)
974 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
975 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
977 else
979 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
980 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
981 bHOver = ((nOverlap & SC_MF_HOR) != 0);
982 bVOver = ((nOverlap & SC_MF_VER) != 0);
986 return sal_True;
989 inline sal_Bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern )
991 OSL_ENSURE( rpNewPattern, "pNewPattern" );
993 if ( rpNewPattern == rpOldPattern )
994 return false;
995 else if ( !rpOldPattern )
996 return sal_True;
997 else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
998 return sal_True;
999 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
1000 return sal_True;
1001 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
1002 return sal_True;
1003 else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
1004 return sal_True;
1005 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
1006 return sal_True;
1007 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
1008 return sal_True;
1009 else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
1010 return sal_True;
1011 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
1012 return sal_True;
1013 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
1014 return sal_True;
1015 else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
1016 return sal_True;
1017 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
1018 return sal_True;
1019 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
1020 return sal_True;
1021 else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
1022 return sal_True;
1023 else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
1024 return sal_True;
1025 else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
1026 return sal_True;
1027 else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
1028 return sal_True;
1029 else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
1030 return sal_True;
1031 else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
1032 return sal_True;
1033 else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
1034 return sal_True;
1035 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
1036 return true;
1037 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
1038 return true;
1039 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
1040 return true;
1041 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
1042 return true;
1043 else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
1044 return sal_True;
1045 else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
1046 return sal_True;
1047 else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
1048 return sal_True;
1049 else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
1050 return sal_True;
1051 else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
1052 return sal_True;
1053 else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
1054 return sal_True;
1055 else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
1056 return sal_True;
1057 else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
1058 return sal_True; // needed with automatic text color
1059 else
1061 rpOldPattern = rpNewPattern;
1062 return false;
1066 static inline void lcl_CreateInterpretProgress( sal_Bool& bProgress, ScDocument* pDoc,
1067 ScFormulaCell* pFCell )
1069 if ( !bProgress && pFCell->GetDirty() )
1071 ScProgress::CreateInterpretProgress( pDoc, sal_True );
1072 bProgress = sal_True;
1076 inline sal_Bool IsAmbiguousScript( sal_uInt8 nScript )
1078 return ( nScript != SCRIPTTYPE_LATIN &&
1079 nScript != SCRIPTTYPE_ASIAN &&
1080 nScript != SCRIPTTYPE_COMPLEX );
1083 bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1085 // pThisRowInfo may be NULL
1087 bool bEmpty;
1088 if ( pThisRowInfo && nX <= nX2 )
1089 bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText;
1090 else
1092 ScRefCellValue aCell;
1093 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1094 bEmpty = aCell.isEmpty();
1097 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1099 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1100 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1102 bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1104 if ( bIsPrint || bTabProtected )
1106 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)
1107 mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
1108 if ( bIsPrint && pAttr->GetHidePrint() )
1109 bEmpty = true;
1110 else if ( bTabProtected )
1112 if ( pAttr->GetHideCell() )
1113 bEmpty = true;
1114 else if ( mbShowFormulas && pAttr->GetHideFormula() )
1116 if (mpDoc->GetCellType(ScAddress(nX, nY, nTab)) == CELLTYPE_FORMULA)
1117 bEmpty = true;
1122 return bEmpty;
1125 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScRefCellValue& rCell )
1127 rCell.assign(*mpDoc, ScAddress(nCol, nRow, nTabP));
1128 if (!rCell.isEmpty() && IsEmptyCellText(NULL, nCol, nRow))
1129 rCell.clear();
1132 bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
1134 // apply the same logic here as in DrawStrings/DrawEdit:
1135 // Stop at non-empty or merged or overlapped cell,
1136 // where a note is empty as well as a cell that's hidden by protection settings
1138 ScRefCellValue aCell;
1139 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1140 if (!aCell.isEmpty() && !IsEmptyCellText(NULL, nX, nY))
1141 return false;
1143 const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
1144 if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() ||
1145 ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() )
1147 return false;
1150 return sal_True;
1153 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1154 // nPosX, nPosY: corresponding positions for nX, nArrY
1155 // nCellX, nCellY: position of the cell that contains the text
1156 // nNeeded: Text width, including margin
1157 // rPattern: cell format at nCellX, nCellY
1158 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1159 // bCellIsValue: if set, don't extend into empty cells
1160 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1161 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1162 // rParam output: various area parameters.
1164 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY,
1165 SCCOL nCellX, SCROW nCellY, long nNeeded,
1166 const ScPatternAttr& rPattern,
1167 sal_uInt16 nHorJustify, bool bCellIsValue,
1168 bool bBreak, bool bOverwrite,
1169 OutputAreaParam& rParam )
1171 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1172 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1174 long nLayoutSign = bLayoutRTL ? -1 : 1;
1176 long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
1177 SCCOL nCompCol = nX;
1178 while ( nCellX > nCompCol )
1180 //! extra member function for width?
1181 long nColWidth = ( nCompCol <= nX2 ) ?
1182 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1183 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1184 nCellPosX += nColWidth * nLayoutSign;
1185 ++nCompCol;
1187 while ( nCellX < nCompCol )
1189 --nCompCol;
1190 long nColWidth = ( nCompCol <= nX2 ) ?
1191 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1192 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1193 nCellPosX -= nColWidth * nLayoutSign;
1196 long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
1197 SCSIZE nCompArr = nArrY;
1198 SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1199 while ( nCellY > nCompRow )
1201 if ( nCompArr + 1 < nArrCount )
1203 nCellPosY += pRowInfo[nCompArr].nHeight;
1204 ++nCompArr;
1205 nCompRow = pRowInfo[nCompArr].nRowNo;
1207 else
1209 sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
1210 if ( nDocHeight )
1211 nCellPosY += (long) ( nDocHeight * mnPPTY );
1212 ++nCompRow;
1215 nCellPosY -= (long) mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
1217 const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE );
1218 sal_Bool bMerged = pMerge->IsMerged();
1219 long nMergeCols = pMerge->GetColMerge();
1220 if ( nMergeCols == 0 )
1221 nMergeCols = 1;
1222 long nMergeRows = pMerge->GetRowMerge();
1223 if ( nMergeRows == 0 )
1224 nMergeRows = 1;
1226 long nMergeSizeX = 0;
1227 for ( long i=0; i<nMergeCols; i++ )
1229 long nColWidth = ( nCellX+i <= nX2 ) ?
1230 pRowInfo[0].pCellInfo[nCellX+i+1].nWidth :
1231 (long) ( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
1232 nMergeSizeX += nColWidth;
1234 long nMergeSizeY = 0;
1235 short nDirect = 0;
1236 if ( rThisRowInfo.nRowNo == nCellY )
1238 // take first row's height from row info
1239 nMergeSizeY += rThisRowInfo.nHeight;
1240 nDirect = 1; // skip in loop
1242 // following rows always from document
1243 nMergeSizeY += (long) mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
1245 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
1247 rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1250 // construct the rectangles using logical left/right values (justify is called at the end)
1253 // rAlignRect is the single cell or merged area, used for alignment.
1255 rParam.maAlignRect.Left() = nCellPosX;
1256 rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign;
1257 rParam.maAlignRect.Top() = nCellPosY;
1258 rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1;
1260 // rClipRect is all cells that are used for output.
1261 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1263 rParam.maClipRect = rParam.maAlignRect;
1264 if ( nNeeded > nMergeSizeX )
1266 SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify;
1268 long nMissing = nNeeded - nMergeSizeX;
1269 long nLeftMissing = 0;
1270 long nRightMissing = 0;
1271 switch ( eHorJust )
1273 case SVX_HOR_JUSTIFY_LEFT:
1274 nRightMissing = nMissing;
1275 break;
1276 case SVX_HOR_JUSTIFY_RIGHT:
1277 nLeftMissing = nMissing;
1278 break;
1279 case SVX_HOR_JUSTIFY_CENTER:
1280 nLeftMissing = nMissing / 2;
1281 nRightMissing = nMissing - nLeftMissing;
1282 break;
1283 default:
1285 // added to avoid warnings
1289 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1290 if ( bLayoutRTL )
1291 ::std::swap( nLeftMissing, nRightMissing );
1293 SCCOL nRightX = nCellX;
1294 SCCOL nLeftX = nCellX;
1295 if ( !bMerged && !bCellIsValue && !bBreak )
1297 // look for empty cells into which the text can be extended
1299 while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1301 ++nRightX;
1302 long nAdd = (long) ( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
1303 nRightMissing -= nAdd;
1304 rParam.maClipRect.Right() += nAdd * nLayoutSign;
1306 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1307 rThisRowInfo.pCellInfo[nRightX].bHideGrid = sal_True;
1310 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1312 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1313 rThisRowInfo.pCellInfo[nLeftX].bHideGrid = sal_True;
1315 --nLeftX;
1316 long nAdd = (long) ( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
1317 nLeftMissing -= nAdd;
1318 rParam.maClipRect.Left() -= nAdd * nLayoutSign;
1322 // Set flag and reserve space for clipping mark triangle,
1323 // even if rThisRowInfo isn't for nCellY (merged cells).
1324 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1326 rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT;
1327 bAnyClipped = sal_True;
1328 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1329 rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign;
1331 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1333 rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT;
1334 bAnyClipped = sal_True;
1335 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1336 rParam.maClipRect.Left() += nMarkPixel * nLayoutSign;
1339 rParam.mbLeftClip = ( nLeftMissing > 0 );
1340 rParam.mbRightClip = ( nRightMissing > 0 );
1342 else
1344 rParam.mbLeftClip = rParam.mbRightClip = false;
1346 // leave space for AutoFilter on screen
1347 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1349 if ( eType==OUTTYPE_WINDOW &&
1350 ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & (SC_MF_AUTO|SC_MF_BUTTON|SC_MF_BUTTON_POPUP) ) &&
1351 ( !bBreak || mpRefDevice == pFmtDevice ) )
1353 // filter drop-down width is now independent from row height
1354 const long nFilter = DROPDOWN_BITMAP_SIZE;
1355 sal_Bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1356 if ( bFit || bCellIsValue )
1358 // content fits even in the remaining area without the filter button
1359 // -> align within that remaining area
1361 rParam.maAlignRect.Right() -= nFilter * nLayoutSign;
1362 rParam.maClipRect.Right() -= nFilter * nLayoutSign;
1364 // if a number doesn't fit, don't hide part of the number behind the button
1365 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1367 if ( !bFit )
1368 rParam.mbLeftClip = rParam.mbRightClip = sal_True;
1373 // justify both rectangles for alignment calculation, use with DrawText etc.
1375 rParam.maAlignRect.Justify();
1376 rParam.maClipRect.Justify();
1379 namespace {
1381 bool beginsWithRTLCharacter(const OUString& rStr)
1383 if (rStr.isEmpty())
1384 return false;
1386 switch (ScGlobal::pCharClass->getCharacterDirection(rStr, 0))
1388 case i18n::DirectionProperty_RIGHT_TO_LEFT:
1389 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
1390 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
1391 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
1392 return true;
1393 default:
1397 return false;
1402 /** Get left, right or centered alignment from RTL context.
1404 Does not return standard, block or repeat, for these the contextual left or
1405 right alignment is returned.
1407 static SvxCellHorJustify getAlignmentFromContext( SvxCellHorJustify eInHorJust,
1408 bool bCellIsValue, const OUString& rText,
1409 const ScPatternAttr& rPattern, const SfxItemSet* pCondSet,
1410 const ScDocument* pDoc, SCTAB nTab )
1412 SvxCellHorJustify eHorJustContext = eInHorJust;
1413 bool bUseWritingDirection = false;
1414 if (eInHorJust == SVX_HOR_JUSTIFY_STANDARD)
1416 // fdo#32530: Default alignment depends on value vs
1417 // string, and the direction of the 1st letter.
1418 if (beginsWithRTLCharacter( rText))
1419 eHorJustContext = bCellIsValue ? SVX_HOR_JUSTIFY_LEFT : SVX_HOR_JUSTIFY_RIGHT;
1420 else if (bCellIsValue)
1421 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1422 else
1423 bUseWritingDirection = true;
1426 if (bUseWritingDirection ||
1427 eInHorJust == SVX_HOR_JUSTIFY_BLOCK || eInHorJust == SVX_HOR_JUSTIFY_REPEAT)
1429 sal_uInt16 nDirection = lcl_GetValue<SvxFrameDirectionItem, sal_uInt16>( rPattern, ATTR_WRITINGDIR, pCondSet);
1430 if (nDirection == FRMDIR_HORI_LEFT_TOP || nDirection == FRMDIR_VERT_TOP_LEFT)
1431 eHorJustContext = SVX_HOR_JUSTIFY_LEFT;
1432 else if (nDirection == FRMDIR_ENVIRONMENT)
1434 SAL_WARN_IF( !pDoc, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1435 eHorJustContext = (pDoc && pDoc->IsLayoutRTL(nTab)) ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
1437 else
1438 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1440 return eHorJustContext;
1443 void ScOutputData::DrawStrings( sal_Bool bPixelToLogic )
1445 OSL_ENSURE( mpDev == mpRefDevice ||
1446 mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
1447 "DrawStrings: unterschiedliche MapUnits ?!?!" );
1449 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
1451 bool bWasIdleEnabled = mpDoc->IsIdleEnabled();
1452 mpDoc->EnableIdle(false);
1454 ScDrawStringsVars aVars( this, bPixelToLogic );
1456 sal_Bool bProgress = false;
1458 long nInitPosX = nScrX;
1459 if ( bLayoutRTL )
1460 nInitPosX += nMirrorW - 1; // pixels
1461 long nLayoutSign = bLayoutRTL ? -1 : 1;
1463 SCCOL nLastContentCol = MAXCOL;
1464 if ( nX2 < MAXCOL )
1465 nLastContentCol = sal::static_int_cast<SCCOL>(
1466 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
1467 SCCOL nLoopStartX = nX1;
1468 if ( nX1 > 0 )
1469 --nLoopStartX; // start before nX1 for rest of long text to the left
1471 // variables for GetOutputArea
1472 OutputAreaParam aAreaParam;
1473 sal_Bool bCellIsValue = false;
1474 long nNeededWidth = 0;
1475 const ScPatternAttr* pPattern = NULL;
1476 const SfxItemSet* pCondSet = NULL;
1477 const ScPatternAttr* pOldPattern = NULL;
1478 const SfxItemSet* pOldCondSet = NULL;
1479 sal_uInt8 nOldScript = 0;
1481 // alternative pattern instances in case we need to modify the pattern
1482 // before processing the cell value.
1483 ::boost::ptr_vector<ScPatternAttr> aAltPatterns;
1485 long nPosY = nScrY;
1486 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1488 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1489 if ( pThisRowInfo->bChanged )
1491 SCROW nY = pThisRowInfo->nRowNo;
1492 long nPosX = nInitPosX;
1493 if ( nLoopStartX < nX1 )
1494 nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
1495 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1497 bool bMergeEmpty = false;
1498 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1499 bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
1501 SCCOL nCellX = nX; // position where the cell really starts
1502 SCROW nCellY = nY;
1503 bool bDoCell = false;
1504 bool bNeedEdit = false;
1507 // Part of a merged cell?
1510 bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
1511 if ( bOverlapped )
1513 bEmpty = true;
1515 SCCOL nOverX; // start of the merged cells
1516 SCROW nOverY;
1517 sal_Bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1518 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1520 nCellX = nOverX;
1521 nCellY = nOverY;
1522 bDoCell = sal_True;
1524 else
1525 bMergeEmpty = true;
1529 // Rest of a long text further to the left?
1532 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1534 SCCOL nTempX=nX1;
1535 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1536 --nTempX;
1538 if ( nTempX < nX1 &&
1539 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1540 !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1542 nCellX = nTempX;
1543 bDoCell = true;
1548 // Rest of a long text further to the right?
1551 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1553 // don't have to look further than nLastContentCol
1555 SCCOL nTempX=nX;
1556 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1557 ++nTempX;
1559 if ( nTempX > nX &&
1560 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1561 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1563 nCellX = nTempX;
1564 bDoCell = sal_True;
1569 // normal visible cell
1572 if (!bEmpty)
1573 bDoCell = true;
1576 // don't output the cell that's being edited
1579 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1580 bDoCell = false;
1582 // skip text in cell if data bar/icon set is set and only value selected
1583 if ( bDoCell )
1585 if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
1586 bDoCell = false;
1587 if(pInfo->pIconSet && !pInfo->pIconSet->mbShowValue)
1588 bDoCell = false;
1592 // output the cell text
1595 ScRefCellValue aCell;
1596 if (bDoCell)
1598 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1599 aCell = pThisRowInfo->pCellInfo[nCellX+1].maCell;
1600 else
1601 GetVisibleCell( nCellX, nCellY, nTab, aCell ); // get from document
1602 if (aCell.isEmpty())
1603 bDoCell = false;
1604 else if (aCell.meType == CELLTYPE_EDIT)
1605 bNeedEdit = true;
1608 // Check if this cell is mis-spelled.
1609 if (bDoCell && !bNeedEdit && aCell.meType == CELLTYPE_STRING)
1611 if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
1612 bNeedEdit = true;
1615 if (bDoCell && !bNeedEdit)
1617 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1619 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
1620 pPattern = rCellInfo.pPatternAttr;
1621 pCondSet = rCellInfo.pConditionSet;
1623 if ( !pPattern )
1625 // #i68085# pattern from cell info for hidden columns is null,
1626 // test for null is quicker than using column flags
1627 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1628 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1631 else // get from document
1633 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1634 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1636 if ( mpDoc->GetPreviewFont() || mpDoc->GetPreviewCellStyle() )
1638 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1639 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1640 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
1642 pAltPattern->SetStyleSheet(pPreviewStyle);
1644 else if ( SfxItemSet* pFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab ) )
1646 const SfxPoolItem* pItem;
1647 if ( pFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SFX_ITEM_SET )
1648 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1649 if ( pFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SFX_ITEM_SET )
1650 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1651 if ( pFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SFX_ITEM_SET )
1652 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1654 pPattern = pAltPattern;
1657 if (aCell.hasNumeric() &&
1658 static_cast<const SfxBoolItem&>(
1659 pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue())
1661 // Disable line break when the cell content is numeric.
1662 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1663 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1664 SfxBoolItem aLineBreak(ATTR_LINEBREAK, false);
1665 pAltPattern->GetItemSet().Put(aLineBreak);
1666 pPattern = pAltPattern;
1669 sal_uInt8 nScript = mpDoc->GetCellScriptType(
1670 ScAddress(nCellX, nCellY, nTab),
1671 pPattern->GetNumberFormat(mpDoc->GetFormatTable(), pCondSet));
1673 if (nScript == 0)
1674 nScript = ScGlobal::GetDefaultScriptType();
1676 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1677 nScript != nOldScript || mbSyntaxMode )
1679 if ( StringDiffer(pOldPattern,pPattern) ||
1680 pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
1682 aVars.SetPattern(pPattern, pCondSet, aCell, nScript);
1684 else
1685 aVars.SetPatternSimple( pPattern, pCondSet );
1686 pOldPattern = pPattern;
1687 pOldCondSet = pCondSet;
1688 nOldScript = nScript;
1691 // use edit engine for rotated, stacked or mixed-script text
1692 if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED ||
1693 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1694 bNeedEdit = sal_True;
1696 if (bDoCell && !bNeedEdit)
1698 bool bFormulaCell = (aCell.meType == CELLTYPE_FORMULA);
1699 if ( bFormulaCell )
1700 lcl_CreateInterpretProgress(bProgress, mpDoc, aCell.mpFormula);
1701 if ( aVars.SetText(aCell) )
1702 pOldPattern = NULL;
1703 bNeedEdit = aVars.HasEditCharacters() || (bFormulaCell && aCell.mpFormula->IsMultilineResult());
1705 long nTotalMargin = 0;
1706 SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD;
1707 if (bDoCell && !bNeedEdit)
1709 CellType eCellType = aCell.meType;
1710 bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1711 if ( eCellType == CELLTYPE_FORMULA )
1713 ScFormulaCell* pFCell = aCell.mpFormula;
1714 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1717 eOutHorJust = getAlignmentFromContext( aVars.GetHorJust(), bCellIsValue, aVars.GetString(),
1718 *pPattern, pCondSet, mpDoc, nTab);
1720 bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK );
1721 // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1722 if (bBreak && bCellIsValue && (aVars.GetResultValueFormat() % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1723 bBreak = false;
1725 bool bRepeat = aVars.IsRepeat() && !bBreak;
1726 bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1728 nTotalMargin =
1729 static_cast<long>(aVars.GetLeftTotal() * mnPPTX) +
1730 static_cast<long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
1732 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1734 // GetOutputArea gives justfied rectangles
1735 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1736 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1737 bCellIsValue || bRepeat || bShrink, bBreak, false,
1738 aAreaParam );
1740 aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
1741 if ( bShrink )
1743 if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD )
1745 // Only horizontal scaling is handled here.
1746 // DrawEdit is used to vertically scale 90 deg rotated text.
1747 bNeedEdit = sal_True;
1749 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
1751 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1752 long nScaleSize = aVars.GetTextSize().Width(); // without margin
1754 if ( nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
1756 long nScale = ( nAvailable * 100 ) / nScaleSize;
1758 aVars.SetShrinkScale( nScale, nOldScript );
1759 long nNewSize = aVars.GetTextSize().Width();
1761 sal_uInt16 nShrinkAgain = 0;
1762 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1764 // If the text is still too large, reduce the scale again by 10%, until it fits,
1765 // at most 7 times (it's less than 50% of the calculated scale then).
1767 nScale = ( nScale * 9 ) / 10;
1768 aVars.SetShrinkScale( nScale, nOldScript );
1769 nNewSize = aVars.GetTextSize().Width();
1770 ++nShrinkAgain;
1772 // If even at half the size the font still isn't rendered smaller,
1773 // fall back to normal clipping (showing ### for numbers).
1774 if ( nNewSize <= nAvailable )
1775 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1777 pOldPattern = NULL;
1782 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1784 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1785 long nRepeatSize = aVars.GetTextSize().Width(); // without margin
1786 // When formatting for the printer, the text sizes don't always add up.
1787 // Round down (too few repetitions) rather than exceeding the cell size then:
1788 if ( pFmtDevice != mpRefDevice )
1789 ++nRepeatSize;
1790 if ( nRepeatSize > 0 )
1792 long nRepeatCount = nAvailable / nRepeatSize;
1793 if ( nRepeatCount > 1 )
1795 OUString aCellStr = aVars.GetString();
1796 OUString aRepeated = aCellStr;
1797 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1798 aRepeated += aCellStr;
1799 aVars.SetAutoText( aRepeated );
1804 // use edit engine if automatic line breaks are needed
1805 if ( bBreak )
1807 if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD )
1808 bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1809 else
1811 long nHeight = aVars.GetTextSize().Height() +
1812 (long)(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
1813 (long)(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
1814 bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1817 if (!bNeedEdit)
1819 bNeedEdit =
1820 aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK &&
1821 aVars.GetHorJustMethod() == SVX_JUSTIFY_METHOD_DISTRIBUTE;
1824 if (bNeedEdit)
1826 // mark the cell in CellInfo to be drawn in DrawEdit:
1827 // Cells to the left are marked directly, cells to the
1828 // right are handled by the flag for nX2
1829 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1830 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1831 pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = sal_True;
1832 bDoCell = false; // don't draw here
1834 if ( bDoCell )
1836 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1838 if (mbShowFormulas)
1839 aVars.SetHashText();
1840 else
1841 // Adjust the decimals to fit the available column width.
1842 aVars.SetTextToWidthOrHash(aCell, aAreaParam.mnColWidth - nTotalMargin);
1844 nNeededWidth = aVars.GetTextSize().Width() +
1845 (long) ( aVars.GetLeftTotal() * mnPPTX ) +
1846 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1847 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1848 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1850 // If the "###" replacement doesn't fit into the cells, no clip marks
1851 // are shown, as the "###" already denotes too little space.
1852 // The rectangles from the first GetOutputArea call remain valid.
1855 long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
1856 long nJustPosY = aAreaParam.maAlignRect.Top();
1857 long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1858 long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1860 sal_Bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1861 if ( aAreaParam.maClipRect.Left() < nScrX )
1863 aAreaParam.maClipRect.Left() = nScrX;
1864 aAreaParam.mbLeftClip = sal_True;
1866 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
1868 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
1869 aAreaParam.mbRightClip = sal_True;
1872 sal_Bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1873 sal_Bool bVClip = false;
1875 if ( aAreaParam.maClipRect.Top() < nScrY )
1877 aAreaParam.maClipRect.Top() = nScrY;
1878 bVClip = sal_True;
1880 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
1882 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
1883 bVClip = sal_True;
1887 // horizontalen Platz testen
1890 sal_Bool bRightAdjusted = false; // to correct text width calculation later
1891 sal_Bool bNeedEditEngine = false;
1892 if ( !bNeedEditEngine && !bOutside )
1894 switch (eOutHorJust)
1896 case SVX_HOR_JUSTIFY_LEFT:
1897 nJustPosX += (long) ( aVars.GetLeftTotal() * mnPPTX );
1898 break;
1899 case SVX_HOR_JUSTIFY_RIGHT:
1900 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1901 (long) ( aVars.GetRightTotal() * mnPPTX );
1902 bRightAdjusted = sal_True;
1903 break;
1904 case SVX_HOR_JUSTIFY_CENTER:
1905 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1906 (long) ( aVars.GetLeftTotal() * mnPPTX ) -
1907 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
1908 break;
1909 default:
1911 // added to avoid warnings
1915 long nTestClipHeight = aVars.GetTextSize().Height();
1916 switch (aVars.GetVerJust())
1918 case SVX_VER_JUSTIFY_TOP:
1919 case SVX_VER_JUSTIFY_BLOCK:
1921 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1922 nJustPosY += nTop;
1923 nTestClipHeight += nTop;
1925 break;
1926 case SVX_VER_JUSTIFY_BOTTOM:
1928 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1929 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1930 nTestClipHeight += nBot;
1932 break;
1933 case SVX_VER_JUSTIFY_CENTER:
1935 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1936 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1937 nJustPosY += ( nOutHeight + nTop -
1938 aVars.GetTextSize().Height() - nBot ) / 2;
1939 nTestClipHeight += std::abs( nTop - nBot );
1941 break;
1942 default:
1944 // added to avoid warnings
1948 if ( nTestClipHeight > nOutHeight )
1950 // kein vertikales Clipping beim Drucken von Zellen mit
1951 // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung
1952 if ( eType != OUTTYPE_PRINTER ||
1953 ( mpDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
1954 ( aVars.HasCondHeight() ) )
1955 bVClip = sal_True;
1958 if ( bHClip || bVClip )
1960 // nur die betroffene Dimension clippen,
1961 // damit bei nicht-proportionalem Resize nicht alle
1962 // rechtsbuendigen Zahlen abgeschnitten werden:
1964 if (!bHClip)
1966 aAreaParam.maClipRect.Left() = nScrX;
1967 aAreaParam.maClipRect.Right() = nScrX+nScrW;
1969 if (!bVClip)
1971 aAreaParam.maClipRect.Top() = nScrY;
1972 aAreaParam.maClipRect.Bottom() = nScrY+nScrH;
1975 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
1976 // so it can be modified here
1977 if (bPixelToLogic)
1978 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
1980 if (bMetaFile)
1982 mpDev->Push();
1983 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
1985 else
1986 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
1989 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
1991 switch (aVars.GetOrient())
1993 case SVX_ORIENTATION_STANDARD:
1994 nJustPosY += aVars.GetAscent();
1995 break;
1996 case SVX_ORIENTATION_TOPBOTTOM:
1997 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
1998 break;
1999 case SVX_ORIENTATION_BOTTOMTOP:
2000 nJustPosY += aVars.GetTextSize().Height();
2001 nJustPosX += aVars.GetAscent();
2002 break;
2003 default:
2005 // added to avoid warnings
2009 // When clipping, the visible part is now completely defined by the alignment,
2010 // there's no more special handling to show the right part of RTL text.
2012 Point aDrawTextPos( nJustPosX, nJustPosY );
2013 if ( bPixelToLogic )
2015 // undo text width adjustment in pixels
2016 if (bRightAdjusted)
2017 aDrawTextPos.X() += aVars.GetTextSize().Width();
2019 aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
2021 // redo text width adjustment in logic units
2022 if (bRightAdjusted)
2023 aDrawTextPos.X() -= aVars.GetOriginalWidth();
2026 // in Metafiles immer DrawTextArray, damit die Positionen mit
2027 // aufgezeichnet werden (fuer nicht-proportionales Resize):
2029 OUString aString = aVars.GetString();
2030 if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
2032 sal_Int32* pDX = new sal_Int32[aString.getLength()];
2033 pFmtDevice->GetTextArray( aString, pDX );
2035 if ( !mpRefDevice->GetConnectMetaFile() ||
2036 mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
2038 double fMul = GetStretch();
2039 sal_Int32 nLen = aString.getLength();
2040 for( sal_Int32 i = 0; i<nLen; i++ )
2041 pDX[i] = (long)(pDX[i] / fMul + 0.5);
2044 mpDev->DrawTextArray( aDrawTextPos, aString, pDX );
2045 delete[] pDX;
2047 else
2048 mpDev->DrawText( aDrawTextPos, aString );
2050 if ( bHClip || bVClip )
2052 if (bMetaFile)
2053 mpDev->Pop();
2054 else
2055 mpDev->SetClipRegion();
2058 // PDF: whole-cell hyperlink from formula?
2059 bool bHasURL = pPDFData && aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->IsHyperLinkCell();
2060 if ( bHasURL )
2062 Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
2063 lcl_DoHyperlinkResult(mpDev, aURLRect, aCell);
2067 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2070 nPosY += pRowInfo[nArrY].nHeight;
2072 if ( bProgress )
2073 ScProgress::DeleteInterpretProgress();
2074 mpDoc->EnableIdle(bWasIdleEnabled);
2077 // -------------------------------------------------------------------------------
2079 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine()
2081 ScFieldEditEngine* pEngine = new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool());
2082 pEngine->SetUpdateMode( false );
2083 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2084 pEngine->SetRefDevice( pFmtDevice );
2085 sal_uLong nCtrl = pEngine->GetControlWord();
2086 if ( bShowSpellErrors )
2087 nCtrl |= EE_CNTRL_ONLINESPELLING;
2088 if ( eType == OUTTYPE_PRINTER )
2089 nCtrl &= ~EE_CNTRL_MARKFIELDS;
2090 if ( eType == OUTTYPE_WINDOW && mpRefDevice == pFmtDevice )
2091 nCtrl &= ~EE_CNTRL_FORMAT100; // use the actual MapMode
2092 pEngine->SetControlWord( nCtrl );
2093 mpDoc->ApplyAsianEditSettings( *pEngine );
2094 pEngine->EnableAutoColor( mbUseStyleColor );
2095 pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)mpDoc->GetEditTextDirection( nTab ) );
2096 return pEngine;
2099 static void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute
2101 rEngine.SetUpdateMode( false );
2103 rEngine.SetText(EMPTY_OUSTRING);
2104 // keine Para-Attribute uebrigbehalten...
2105 const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
2106 if (rPara.Count())
2107 rEngine.SetParaAttribs( 0,
2108 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
2111 static bool lcl_SafeIsValue( ScRefCellValue& rCell )
2113 switch (rCell.meType)
2115 case CELLTYPE_VALUE:
2116 return true;
2117 case CELLTYPE_FORMULA:
2119 ScFormulaCell* pFCell = rCell.mpFormula;
2120 if (pFCell->IsRunning() || pFCell->IsValue())
2121 return true;
2123 break;
2124 default:
2126 // added to avoid warnings
2129 return false;
2132 static void lcl_ScaleFonts( EditEngine& rEngine, long nPercent )
2134 sal_Bool bUpdateMode = rEngine.GetUpdateMode();
2135 if ( bUpdateMode )
2136 rEngine.SetUpdateMode( false );
2138 sal_Int32 nParCount = rEngine.GetParagraphCount();
2139 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
2141 std::vector<sal_uInt16> aPortions;
2142 rEngine.GetPortions( nPar, aPortions );
2144 sal_uInt16 nStart = 0;
2145 for ( std::vector<sal_uInt16>::const_iterator it(aPortions.begin()); it != aPortions.end(); ++it )
2147 sal_uInt16 nEnd = *it;
2148 ESelection aSel( nPar, nStart, nPar, nEnd );
2149 SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
2151 long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight();
2152 long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight();
2153 long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight();
2155 nWestern = ( nWestern * nPercent ) / 100;
2156 nCJK = ( nCJK * nPercent ) / 100;
2157 nCTL = ( nCTL * nPercent ) / 100;
2159 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
2160 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
2161 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
2163 rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs?
2165 nStart = nEnd;
2169 if ( bUpdateMode )
2170 rEngine.SetUpdateMode( sal_True );
2173 static long lcl_GetEditSize( EditEngine& rEngine, sal_Bool bWidth, sal_Bool bSwap, long nAttrRotate )
2175 if ( bSwap )
2176 bWidth = !bWidth;
2178 if ( nAttrRotate )
2180 long nRealWidth = (long) rEngine.CalcTextWidth();
2181 long nRealHeight = rEngine.GetTextHeight();
2183 // assuming standard mode, otherwise width isn't used
2185 double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees
2186 double nAbsCos = fabs( cos( nRealOrient ) );
2187 double nAbsSin = fabs( sin( nRealOrient ) );
2188 if ( bWidth )
2189 return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2190 else
2191 return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2193 else if ( bWidth )
2194 return (long) rEngine.CalcTextWidth();
2195 else
2196 return rEngine.GetTextHeight();
2200 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect,
2201 long nLeftM, long nTopM, long nRightM, long nBottomM,
2202 sal_Bool bWidth, sal_uInt16 nOrient, long nAttrRotate, sal_Bool bPixelToLogic,
2203 long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2205 if ( !bWidth )
2207 // vertical
2209 long nScaleSize = bPixelToLogic ?
2210 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2212 // Don't scale if it fits already.
2213 // Allowing to extend into the margin, to avoid scaling at optimal height.
2214 if ( nScaleSize <= rAlignRect.GetHeight() )
2215 return;
2217 sal_Bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP );
2218 long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2219 long nScale = ( nAvailable * 100 ) / nScaleSize;
2221 lcl_ScaleFonts( rEngine, nScale );
2222 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2223 long nNewSize = bPixelToLogic ?
2224 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2226 sal_uInt16 nShrinkAgain = 0;
2227 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2229 // further reduce, like in DrawStrings
2230 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2231 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2232 nNewSize = bPixelToLogic ?
2233 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2234 ++nShrinkAgain;
2237 // sizes for further processing (alignment etc):
2238 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, bSwap, nAttrRotate );
2239 long nPixelWidth = bPixelToLogic ?
2240 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2241 rNeededPixel = nPixelWidth + nLeftM + nRightM;
2243 else if ( rLeftClip || rRightClip )
2245 // horizontal
2247 long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2248 long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
2250 if ( nScaleSize <= nAvailable )
2251 return;
2253 long nScale = ( nAvailable * 100 ) / nScaleSize;
2255 lcl_ScaleFonts( rEngine, nScale );
2256 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, false, nAttrRotate );
2257 long nNewSize = bPixelToLogic ?
2258 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2260 sal_uInt16 nShrinkAgain = 0;
2261 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2263 // further reduce, like in DrawStrings
2264 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2265 rEngineWidth = lcl_GetEditSize( rEngine, sal_True, false, nAttrRotate );
2266 nNewSize = bPixelToLogic ?
2267 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2268 ++nShrinkAgain;
2270 if ( nNewSize <= nAvailable )
2271 rLeftClip = rRightClip = false;
2273 // sizes for further processing (alignment etc):
2274 rNeededPixel = nNewSize + nLeftM + nRightM;
2275 rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
2279 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
2280 meHorJustAttr( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
2281 meHorJustContext( meHorJustAttr ),
2282 meHorJustResult( meHorJustAttr ),
2283 meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
2284 meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
2285 meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
2286 meOrient( pPattern->GetCellOrientation(pCondSet) ),
2287 mnArrY(0),
2288 mnX(0), mnY(0), mnCellX(0), mnCellY(0), mnTab(0),
2289 mnPosX(0), mnPosY(0), mnInitPosX(0),
2290 mbBreak( (meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
2291 mbCellIsValue(bCellIsValue),
2292 mbAsianVertical(false),
2293 mbPixelToLogic(false),
2294 mbHyphenatorSet(false),
2295 mpEngine(NULL),
2296 mpPattern(pPattern),
2297 mpCondSet(pCondSet),
2298 mpPreviewFontSet(NULL),
2299 mpOldPattern(NULL),
2300 mpOldCondSet(NULL),
2301 mpOldPreviewFontSet(NULL),
2302 mpThisRowInfo(NULL),
2303 mpMisspellRanges(NULL)
2306 bool ScOutputData::DrawEditParam::readCellContent(
2307 ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
2309 if (maCell.meType == CELLTYPE_EDIT)
2311 const EditTextObject* pData = maCell.mpEditText;
2312 if (pData)
2314 mpEngine->SetText(*pData);
2316 if ( mbBreak && !mbAsianVertical && pData->HasField() )
2318 // Fields aren't wrapped, so clipping is enabled to prevent
2319 // a field from being drawn beyond the cell size
2321 rWrapFields = true;
2324 else
2326 OSL_FAIL("pData == 0");
2327 return false;
2330 else
2332 sal_uLong nFormat = mpPattern->GetNumberFormat(
2333 pDoc->GetFormatTable(), mpCondSet );
2334 OUString aString;
2335 Color* pColor;
2336 ScCellFormat::GetString( maCell,
2337 nFormat,aString, &pColor,
2338 *pDoc->GetFormatTable(),
2339 pDoc,
2340 bShowNullValues,
2341 bShowFormulas,
2342 ftCheck );
2344 mpEngine->SetText(aString);
2345 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2346 lcl_SetEditColor( *mpEngine, *pColor );
2349 if (mpMisspellRanges)
2350 mpEngine->SetAllMisspellRanges(*mpMisspellRanges);
2352 return true;
2355 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
2357 // syntax highlighting mode is ignored here
2358 // StringDiffer doesn't look at hyphenate, language items
2360 if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
2361 return;
2363 sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2364 bool bCellContrast = bUseStyleColor &&
2365 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2367 SfxItemSet* pSet = new SfxItemSet( mpEngine->GetEmptyItemSet() );
2368 mpPattern->FillEditItemSet( pSet, mpCondSet );
2369 if ( mpPreviewFontSet )
2371 const SfxPoolItem* pItem;
2372 if ( mpPreviewFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SFX_ITEM_SET )
2374 SvxFontItem aFontItem(EE_CHAR_FONTINFO);
2375 aFontItem = (const SvxFontItem&)*pItem;
2376 pSet->Put( aFontItem );
2378 if ( mpPreviewFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SFX_ITEM_SET )
2380 SvxFontItem aCjkFontItem(EE_CHAR_FONTINFO_CJK);
2381 aCjkFontItem = (const SvxFontItem&)*pItem;
2382 pSet->Put( aCjkFontItem );
2384 if ( mpPreviewFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SFX_ITEM_SET )
2386 SvxFontItem aCtlFontItem(EE_CHAR_FONTINFO_CTL);
2387 aCtlFontItem = (const SvxFontItem&)*pItem;
2388 pSet->Put( aCtlFontItem );
2391 mpEngine->SetDefaults( pSet );
2392 mpOldPattern = mpPattern;
2393 mpOldCondSet = mpCondSet;
2394 mpOldPreviewFontSet = mpPreviewFontSet;
2396 sal_uLong nControl = mpEngine->GetControlWord();
2397 if (meOrient == SVX_ORIENTATION_STACKED)
2398 nControl |= EE_CNTRL_ONECHARPERLINE;
2399 else
2400 nControl &= ~EE_CNTRL_ONECHARPERLINE;
2401 mpEngine->SetControlWord( nControl );
2403 if ( !mbHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
2405 // set hyphenator the first time it is needed
2406 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2407 mpEngine->SetHyphenator( xXHyphenator );
2408 mbHyphenatorSet = true;
2411 Color aBackCol = ((const SvxBrushItem&)mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet )).GetColor();
2412 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
2413 aBackCol.SetColor( nConfBackColor );
2414 mpEngine->SetBackgroundColor( aBackCol );
2417 void ScOutputData::DrawEditParam::calcMargins(long& rTopM, long& rLeftM, long& rBottomM, long& rRightM, double nPPTX, double nPPTY) const
2419 const SvxMarginItem& rMargin =
2420 static_cast<const SvxMarginItem&>(mpPattern->GetItem(ATTR_MARGIN, mpCondSet));
2422 sal_uInt16 nIndent = 0;
2423 if (meHorJustAttr == SVX_HOR_JUSTIFY_LEFT || meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2424 nIndent = lcl_GetValue<SfxUInt16Item, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
2426 rLeftM = static_cast<long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
2427 rTopM = static_cast<long>((rMargin.GetTopMargin() * nPPTY));
2428 rRightM = static_cast<long>((rMargin.GetRightMargin() * nPPTX));
2429 rBottomM = static_cast<long>((rMargin.GetBottomMargin() * nPPTY));
2430 if(meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2432 rLeftM = static_cast<long>((rMargin.GetLeftMargin() * nPPTX));
2433 rRightM = static_cast<long>(((rMargin.GetRightMargin() + nIndent) * nPPTX));
2437 void ScOutputData::DrawEditParam::calcPaperSize(
2438 Size& rPaperSize, const Rectangle& rAlignRect, double nPPTX, double nPPTY) const
2440 long nTopM, nLeftM, nBottomM, nRightM;
2441 calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
2443 if (isVerticallyOriented())
2445 rPaperSize.Width() = rAlignRect.GetHeight() - nTopM - nBottomM;
2446 rPaperSize.Height() = rAlignRect.GetWidth() - nLeftM - nRightM;
2448 else
2450 rPaperSize.Width() = rAlignRect.GetWidth() - nLeftM - nRightM;
2451 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2454 if (mbAsianVertical)
2456 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2457 // Subtract some extra value from the height or else the text would go
2458 // outside the cell area. The value of 5 is arbitrary, and is based
2459 // entirely on heuristics.
2460 rPaperSize.Height() -= 5;
2464 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine* pEngine, long& rWidth, long& rHeight) const
2466 long nEngineWidth = 0;
2467 if (!mbBreak || meOrient == SVX_ORIENTATION_STACKED || mbAsianVertical)
2468 nEngineWidth = static_cast<long>(pEngine->CalcTextWidth());
2470 long nEngineHeight = pEngine->GetTextHeight();
2472 if (isVerticallyOriented())
2474 long nTemp = nEngineWidth;
2475 nEngineWidth = nEngineHeight;
2476 nEngineHeight = nTemp;
2479 if (meOrient == SVX_ORIENTATION_STACKED)
2480 nEngineWidth = nEngineWidth * 11 / 10;
2482 rWidth = nEngineWidth;
2483 rHeight = nEngineHeight;
2486 bool ScOutputData::DrawEditParam::hasLineBreak() const
2488 return (mbBreak || (meOrient == SVX_ORIENTATION_STACKED) || mbAsianVertical);
2491 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2493 if (maCell.meType != CELLTYPE_FORMULA)
2494 return false;
2496 return maCell.mpFormula->IsHyperLinkCell();
2499 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2501 return (meOrient == SVX_ORIENTATION_TOPBOTTOM || meOrient == SVX_ORIENTATION_BOTTOMTOP);
2504 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2505 Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice)
2507 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2509 if (mbPixelToLogic)
2510 rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
2512 if (mbBreak)
2514 // vertical adjustment is within the EditEngine
2515 if (mbPixelToLogic)
2516 rLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2517 else
2518 rLogicStart.Y() += nTopM;
2520 switch (meHorJustResult)
2522 case SVX_HOR_JUSTIFY_CENTER:
2523 rLogicStart.X() += (nCellWidth - nEngineWidth) / 2;
2524 break;
2525 case SVX_HOR_JUSTIFY_RIGHT:
2526 rLogicStart.X() += nCellWidth - nEngineWidth;
2527 break;
2528 default:
2529 ; // do nothing
2534 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2536 if (isVerticallyOriented() || mbAsianVertical)
2538 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2539 switch (meVerJust)
2541 case SVX_VER_JUSTIFY_TOP:
2542 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2543 SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT;
2544 break;
2545 case SVX_VER_JUSTIFY_CENTER:
2546 eSvxAdjust = SVX_ADJUST_CENTER;
2547 break;
2548 case SVX_VER_JUSTIFY_BOTTOM:
2549 case SVX_VER_JUSTIFY_STANDARD:
2550 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2551 SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2552 break;
2553 case SVX_VER_JUSTIFY_BLOCK:
2554 eSvxAdjust = SVX_ADJUST_BLOCK;
2555 break;
2558 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2559 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2561 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2562 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2564 else
2566 // horizontal alignment now may depend on cell content
2567 // (for values with number formats with mixed script types)
2568 // -> always set adjustment
2570 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2571 if (meOrient == SVX_ORIENTATION_STACKED)
2572 eSvxAdjust = SVX_ADJUST_CENTER;
2573 else if (mbBreak)
2575 if (meOrient == SVX_ORIENTATION_STANDARD)
2576 switch (meHorJustResult)
2578 case SVX_HOR_JUSTIFY_REPEAT: // repeat is not yet implemented
2579 case SVX_HOR_JUSTIFY_STANDARD:
2580 assert(!"meHorJustResult does not match getAlignmentFromContext()");
2581 // fallthru
2582 case SVX_HOR_JUSTIFY_LEFT:
2583 eSvxAdjust = SVX_ADJUST_LEFT;
2584 break;
2585 case SVX_HOR_JUSTIFY_CENTER:
2586 eSvxAdjust = SVX_ADJUST_CENTER;
2587 break;
2588 case SVX_HOR_JUSTIFY_RIGHT:
2589 eSvxAdjust = SVX_ADJUST_RIGHT;
2590 break;
2591 case SVX_HOR_JUSTIFY_BLOCK:
2592 eSvxAdjust = SVX_ADJUST_BLOCK;
2593 break;
2595 else
2596 switch (meVerJust)
2598 case SVX_VER_JUSTIFY_TOP:
2599 eSvxAdjust = SVX_ADJUST_RIGHT;
2600 break;
2601 case SVX_VER_JUSTIFY_CENTER:
2602 eSvxAdjust = SVX_ADJUST_CENTER;
2603 break;
2604 case SVX_VER_JUSTIFY_BOTTOM:
2605 case SVX_VER_JUSTIFY_STANDARD:
2606 eSvxAdjust = SVX_ADJUST_LEFT;
2607 break;
2608 case SVX_VER_JUSTIFY_BLOCK:
2609 eSvxAdjust = SVX_ADJUST_BLOCK;
2610 break;
2614 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2616 if (mbAsianVertical)
2618 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2619 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2620 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2622 else
2624 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
2625 if (meVerJust == SVX_VER_JUSTIFY_BLOCK)
2626 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2630 mpEngine->SetVertical(mbAsianVertical);
2631 if (maCell.meType == CELLTYPE_EDIT)
2633 // We need to synchronize the vertical mode in the EditTextObject
2634 // instance too. No idea why we keep this state in two separate
2635 // instances.
2636 const EditTextObject* pData = maCell.mpEditText;
2637 if (pData)
2638 const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
2642 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine)
2644 if (meHorJustResult == SVX_HOR_JUSTIFY_RIGHT || meHorJustResult == SVX_HOR_JUSTIFY_CENTER)
2646 SvxAdjust eEditAdjust = (meHorJustResult == SVX_HOR_JUSTIFY_CENTER) ?
2647 SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT;
2649 pEngine->SetUpdateMode(false);
2650 pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
2651 pEngine->SetUpdateMode(true);
2652 return true;
2654 return false;
2657 void ScOutputData::DrawEditParam::adjustForRTL()
2659 if (!mpEngine->IsRightToLeft(0))
2660 // No RTL mode.
2661 return;
2663 // For right-to-left, EditEngine always calculates its lines
2664 // beginning from the right edge, but EditLine::nStartPosX is
2665 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2666 Size aLogicPaper = mpEngine->GetPaperSize();
2667 if ( aLogicPaper.Width() > USHRT_MAX )
2669 aLogicPaper.Width() = USHRT_MAX;
2670 mpEngine->SetPaperSize(aLogicPaper);
2674 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev)
2676 // PDF: whole-cell hyperlink from formula?
2677 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2678 bool bHasURL = pPDFData && isHyperlinkCell();
2679 if (!bHasURL)
2680 return;
2682 long nURLWidth = (long) mpEngine->CalcTextWidth();
2683 long nURLHeight = mpEngine->GetTextHeight();
2684 if (mbBreak)
2686 Size aPaper = mpEngine->GetPaperSize();
2687 if ( mbAsianVertical )
2688 nURLHeight = aPaper.Height();
2689 else
2690 nURLWidth = aPaper.Width();
2692 if (isVerticallyOriented())
2693 std::swap( nURLWidth, nURLHeight );
2694 else if (mbAsianVertical)
2695 aURLStart.X() -= nURLWidth;
2697 Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2698 lcl_DoHyperlinkResult(pDev, aURLRect, maCell);
2701 void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
2703 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
2704 OSL_ASSERT(!rParam.mbAsianVertical);
2706 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
2708 bool bHidden = false;
2709 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
2710 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
2711 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
2713 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT )
2715 // ignore orientation/rotation if "repeat" is active
2716 rParam.meOrient = SVX_ORIENTATION_STANDARD;
2717 nAttrRotate = 0;
2719 // #i31843# "repeat" with "line breaks" is treated as default alignment
2720 // (but rotation is still disabled).
2721 // Default again leads to context dependent alignment instead of
2722 // SVX_HOR_JUSTIFY_STANDARD.
2723 if ( rParam.mbBreak )
2724 rParam.meHorJustResult = rParam.meHorJustContext;
2727 if (nAttrRotate)
2729 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2730 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2731 bHidden = true; // gedreht wird getrennt ausgegeben
2734 if (bHidden)
2735 return;
2737 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
2739 //! mirror margin values for RTL?
2740 //! move margin down to after final GetOutputArea call
2741 long nTopM, nLeftM, nBottomM, nRightM;
2742 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
2744 SCCOL nXForPos = rParam.mnX;
2745 if ( nXForPos < nX1 )
2747 nXForPos = nX1;
2748 rParam.mnPosX = rParam.mnInitPosX;
2750 SCSIZE nArrYForPos = rParam.mnArrY;
2751 if ( nArrYForPos < 1 )
2753 nArrYForPos = 1;
2754 rParam.mnPosY = nScrY;
2757 OutputAreaParam aAreaParam;
2760 // Initial page size - large for normal text, cell size for automatic line breaks
2763 Size aPaperSize = Size( 1000000, 1000000 );
2764 if (rParam.mbBreak)
2766 // call GetOutputArea with nNeeded=0, to get only the cell width
2768 //! handle nArrY == 0
2769 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
2770 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2771 rParam.mbCellIsValue, true, false, aAreaParam );
2773 //! special ScEditUtil handling if formatting for printer
2774 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
2776 if (rParam.mbPixelToLogic)
2778 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
2779 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
2781 // #i85342# screen display and formatting for printer,
2782 // use same GetEditArea call as in ScViewData::SetEditEngine
2784 Fraction aFract(1,1);
2785 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
2786 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
2787 aLogicSize.Width() = aUtilRect.GetWidth();
2789 rParam.mpEngine->SetPaperSize(aLogicSize);
2791 else
2792 rParam.mpEngine->SetPaperSize(aPaperSize);
2795 // Fill the EditEngine (cell attributes and text)
2798 // default alignment for asian vertical mode is top-right
2799 if ( rParam.mbAsianVertical && rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
2800 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
2802 rParam.setPatternToEngine(mbUseStyleColor);
2803 rParam.setAlignmentToEngine();
2805 // Read content from cell
2807 bool bWrapFields = false;
2808 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
2809 // Failed to read cell content. Bail out.
2810 return;
2812 if ( mbSyntaxMode )
2813 SetEditSyntaxColor(*rParam.mpEngine, rParam.maCell);
2814 else if ( mbUseStyleColor && mbForceAutoColor )
2815 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
2817 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
2820 // Get final output area using the calculated width
2823 long nEngineWidth, nEngineHeight;
2824 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
2826 long nNeededPixel = nEngineWidth;
2827 if (rParam.mbPixelToLogic)
2828 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2829 nNeededPixel += nLeftM + nRightM;
2831 if (!rParam.mbBreak || bShrink)
2833 // for break, the first GetOutputArea call is sufficient
2834 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
2835 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2836 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2838 if ( bShrink )
2840 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
2841 nLeftM, nTopM, nRightM, nBottomM, true,
2842 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
2843 nEngineWidth, nEngineHeight, nNeededPixel,
2844 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
2846 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
2848 // First check if twice the space for the formatted text is available
2849 // (otherwise just keep it unchanged).
2851 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
2852 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2853 if ( nAvailable >= 2 * nFormatted )
2855 // "repeat" is handled with unformatted text (for performance reasons)
2856 OUString aCellStr = rParam.mpEngine->GetText();
2857 rParam.mpEngine->SetText( aCellStr );
2859 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
2860 if (rParam.mbPixelToLogic)
2861 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
2862 if ( pFmtDevice != mpRefDevice )
2863 ++nRepeatSize;
2864 if ( nRepeatSize > 0 )
2866 long nRepeatCount = nAvailable / nRepeatSize;
2867 if ( nRepeatCount > 1 )
2869 OUString aRepeated = aCellStr;
2870 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
2871 aRepeated += aCellStr;
2872 rParam.mpEngine->SetText( aRepeated );
2874 nEngineHeight = rParam.mpEngine->GetTextHeight();
2875 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2876 if (rParam.mbPixelToLogic)
2877 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2878 else
2879 nNeededPixel = nEngineWidth;
2880 nNeededPixel += nLeftM + nRightM;
2886 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
2888 rParam.mpEngine->SetText(OUString("###"));
2889 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2890 if (rParam.mbPixelToLogic)
2891 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2892 else
2893 nNeededPixel = nEngineWidth;
2894 nNeededPixel += nLeftM + nRightM;
2896 // No clip marks if "###" doesn't fit (same as in DrawStrings)
2899 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
2901 aPaperSize.Width() = nNeededPixel + 1;
2902 if (rParam.mbPixelToLogic)
2903 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
2904 else
2905 rParam.mpEngine->SetPaperSize(aPaperSize);
2909 long nStartX = aAreaParam.maAlignRect.Left();
2910 long nStartY = aAreaParam.maAlignRect.Top();
2911 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
2912 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
2913 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2915 if (rParam.mbBreak)
2917 // text with automatic breaks is aligned only within the
2918 // edit engine's paper size, the output of the whole area
2919 // is always left-aligned
2921 nStartX += nLeftM;
2923 else
2925 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
2926 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
2927 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
2928 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
2929 else
2930 nStartX += nLeftM;
2933 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
2934 if (bOutside)
2935 return;
2937 if ( aAreaParam.maClipRect.Left() < nScrX )
2939 aAreaParam.maClipRect.Left() = nScrX;
2940 aAreaParam.mbLeftClip = true;
2942 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
2944 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
2945 aAreaParam.mbRightClip = true;
2948 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
2949 bool bSimClip = false;
2951 if ( bWrapFields )
2953 // Fields in a cell with automatic breaks: clip to cell width
2954 bClip = true;
2957 if ( aAreaParam.maClipRect.Top() < nScrY )
2959 aAreaParam.maClipRect.Top() = nScrY;
2960 bClip = true;
2962 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
2964 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
2965 bClip = true;
2968 Size aCellSize; // output area, excluding margins, in logical units
2969 if (rParam.mbPixelToLogic)
2970 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
2971 else
2972 aCellSize = Size( nOutWidth, nOutHeight );
2974 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
2976 const ScMergeAttr* pMerge =
2977 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
2978 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
2980 // Don't clip for text height when printing rows with optimal height,
2981 // except when font size is from conditional formatting.
2982 //! Allow clipping when vertically merged?
2983 if ( eType != OUTTYPE_PRINTER ||
2984 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
2985 ( rParam.mpCondSet && SFX_ITEM_SET ==
2986 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
2987 bClip = true;
2988 else
2989 bSimClip = true;
2991 // Show clip marks if height is at least 5pt too small and
2992 // there are several lines of text.
2993 // Not for asian vertical text, because that would interfere
2994 // with the default right position of the text.
2995 // Only with automatic line breaks, to avoid having to find
2996 // the cells with the horizontal end of the text again.
2997 if ( nEngineHeight - aCellSize.Height() > 100 &&
2998 rParam.mbBreak && bMarkClipped &&
2999 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3001 CellInfo* pClipMarkCell = NULL;
3002 if ( bMerged )
3004 // anywhere in the merged area...
3005 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3006 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3008 else
3009 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3011 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3012 bAnyClipped = true;
3014 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
3015 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3016 aAreaParam.maClipRect.Right() -= nMarkPixel;
3020 Rectangle aLogicClip;
3021 if (bClip || bSimClip)
3023 // Clip marks are already handled in GetOutputArea
3025 if (rParam.mbPixelToLogic)
3026 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3027 else
3028 aLogicClip = aAreaParam.maClipRect;
3030 if (bClip) // bei bSimClip nur aClipRect initialisieren
3032 if (bMetaFile)
3034 mpDev->Push();
3035 mpDev->IntersectClipRegion( aLogicClip );
3037 else
3038 mpDev->SetClipRegion( Region( aLogicClip ) );
3042 Point aLogicStart;
3043 if (rParam.mbPixelToLogic)
3044 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
3045 else
3046 aLogicStart = Point(nStartX, nStartY);
3048 if (!rParam.mbBreak)
3050 // horizontal alignment
3051 if (rParam.adjustHorAlignment(rParam.mpEngine))
3052 // reset adjustment for the next cell
3053 rParam.mpOldPattern = NULL;
3056 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
3057 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
3059 //! if pRefDevice != pFmtDevice, keep heights in logic units,
3060 //! only converting margin?
3062 if (rParam.mbPixelToLogic)
3063 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
3064 mpRefDevice->LogicToPixel(aCellSize).Height() -
3065 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3066 )).Height();
3067 else
3068 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
3070 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
3072 if (rParam.mbPixelToLogic)
3073 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
3074 mpRefDevice->LogicToPixel(aCellSize).Height() -
3075 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
3076 / 2)).Height();
3077 else
3078 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
3080 else // top
3082 if (rParam.mbPixelToLogic)
3083 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3084 else
3085 aLogicStart.Y() += nTopM;
3088 Point aURLStart = aLogicStart; // copy before modifying for orientation
3090 rParam.adjustForRTL();
3092 // bMoveClipped handling has been replaced by complete alignment
3093 // handling (also extending to the left).
3095 if (bSimClip)
3097 // kein hartes Clipping, aber nur die betroffenen
3098 // Zeilen ausgeben
3100 Point aDocStart = aLogicClip.TopLeft();
3101 aDocStart -= aLogicStart;
3102 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
3104 else
3106 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
3109 if (bClip)
3111 if (bMetaFile)
3112 mpDev->Pop();
3113 else
3114 mpDev->SetClipRegion();
3117 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3120 void ScOutputData::ShowClipMarks( DrawEditParam& rParam, long nEngineHeight, const Size& aCellSize,
3121 bool bMerged, OutputAreaParam& aAreaParam)
3123 // Show clip marks if height is at least 5pt too small and
3124 // there are several lines of text.
3125 // Not for asian vertical text, because that would interfere
3126 // with the default right position of the text.
3127 // Only with automatic line breaks, to avoid having to find
3128 // the cells with the horizontal end of the text again.
3129 if ( nEngineHeight - aCellSize.Height() > 100 &&
3130 rParam.mbBreak && bMarkClipped &&
3131 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3133 CellInfo* pClipMarkCell = NULL;
3134 if ( bMerged )
3136 // anywhere in the merged area...
3137 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3138 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3140 else
3141 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3143 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3144 bAnyClipped = true;
3146 const long nMarkPixel = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTX );
3147 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3148 aAreaParam.maClipRect.Right() -= nMarkPixel;
3152 bool ScOutputData::Clip( DrawEditParam& rParam, const Size& aCellSize,
3153 OutputAreaParam& aAreaParam, long nEngineHeight,
3154 bool bWrapFields)
3156 if ( aAreaParam.maClipRect.Left() < nScrX )
3158 aAreaParam.maClipRect.Left() = nScrX;
3159 aAreaParam.mbLeftClip = true;
3161 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3163 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3164 aAreaParam.mbRightClip = true;
3167 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3168 bool bSimClip = false;
3170 if ( bWrapFields )
3172 // Fields in a cell with automatic breaks: clip to cell width
3173 bClip = true;
3176 if ( aAreaParam.maClipRect.Top() < nScrY )
3178 aAreaParam.maClipRect.Top() = nScrY;
3179 bClip = true;
3181 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3183 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3184 bClip = true;
3187 const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3188 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3190 const ScMergeAttr* pMerge =
3191 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
3192 const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3194 // Don't clip for text height when printing rows with optimal height,
3195 // except when font size is from conditional formatting.
3196 //! Allow clipping when vertically merged?
3197 if ( eType != OUTTYPE_PRINTER ||
3198 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3199 ( rParam.mpCondSet && SFX_ITEM_SET ==
3200 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3201 bClip = true;
3202 else
3203 bSimClip = true;
3205 ShowClipMarks( rParam, nEngineHeight, aCellSize, bMerged, aAreaParam);
3208 Rectangle aLogicClip;
3209 if (bClip || bSimClip)
3211 // Clip marks are already handled in GetOutputArea
3213 if (rParam.mbPixelToLogic)
3214 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3215 else
3216 aLogicClip = aAreaParam.maClipRect;
3218 if (bClip) // bei bSimClip nur aClipRect initialisieren
3220 if (bMetaFile)
3222 mpDev->Push();
3223 mpDev->IntersectClipRegion( aLogicClip );
3225 else
3226 mpDev->SetClipRegion( Region( aLogicClip ) );
3230 return bClip;
3233 void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
3235 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3237 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3238 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3240 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3242 //! mirror margin values for RTL?
3243 //! move margin down to after final GetOutputArea call
3244 long nTopM, nLeftM, nBottomM, nRightM;
3245 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3247 SCCOL nXForPos = rParam.mnX;
3248 if ( nXForPos < nX1 )
3250 nXForPos = nX1;
3251 rParam.mnPosX = rParam.mnInitPosX;
3253 SCSIZE nArrYForPos = rParam.mnArrY;
3254 if ( nArrYForPos < 1 )
3256 nArrYForPos = 1;
3257 rParam.mnPosY = nScrY;
3260 OutputAreaParam aAreaParam;
3263 // Initial page size - large for normal text, cell size for automatic line breaks
3266 Size aPaperSize = Size( 1000000, 1000000 );
3267 if (rParam.mbBreak)
3269 // call GetOutputArea with nNeeded=0, to get only the cell width
3271 //! handle nArrY == 0
3272 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3273 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3274 rParam.mbCellIsValue, true, false, aAreaParam );
3276 //! special ScEditUtil handling if formatting for printer
3277 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3279 if (rParam.mbPixelToLogic)
3281 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3282 rParam.mpEngine->SetPaperSize(aLogicSize);
3284 else
3285 rParam.mpEngine->SetPaperSize(aPaperSize);
3288 // Fill the EditEngine (cell attributes and text)
3291 rParam.setPatternToEngine(mbUseStyleColor);
3292 rParam.setAlignmentToEngine();
3294 // Read content from cell
3296 bool bWrapFields = false;
3297 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3298 // Failed to read cell content. Bail out.
3299 return;
3301 if ( mbSyntaxMode )
3302 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3303 else if ( mbUseStyleColor && mbForceAutoColor )
3304 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3306 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3309 // Get final output area using the calculated width
3312 long nEngineWidth, nEngineHeight;
3313 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3315 long nNeededPixel = nEngineWidth;
3316 if (rParam.mbPixelToLogic)
3317 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3318 nNeededPixel += nLeftM + nRightM;
3320 if (!rParam.mbBreak || bShrink)
3322 // for break, the first GetOutputArea call is sufficient
3323 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3324 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3325 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3327 if ( bShrink )
3329 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3330 nLeftM, nTopM, nRightM, nBottomM, false,
3331 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3332 nEngineWidth, nEngineHeight, nNeededPixel,
3333 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3335 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3337 // First check if twice the space for the formatted text is available
3338 // (otherwise just keep it unchanged).
3340 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3341 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3342 if ( nAvailable >= 2 * nFormatted )
3344 // "repeat" is handled with unformatted text (for performance reasons)
3345 OUString aCellStr = rParam.mpEngine->GetText();
3346 rParam.mpEngine->SetText( aCellStr );
3348 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3349 if (rParam.mbPixelToLogic)
3350 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3351 if ( pFmtDevice != mpRefDevice )
3352 ++nRepeatSize;
3353 if ( nRepeatSize > 0 )
3355 const long nRepeatCount = nAvailable / nRepeatSize;
3356 if ( nRepeatCount > 1 )
3358 OUString aRepeated = aCellStr;
3359 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3360 aRepeated += aCellStr;
3361 rParam.mpEngine->SetText( aRepeated );
3363 nEngineHeight = rParam.mpEngine->GetTextHeight();
3364 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3365 if (rParam.mbPixelToLogic)
3366 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3367 else
3368 nNeededPixel = nEngineWidth;
3369 nNeededPixel += nLeftM + nRightM;
3375 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3377 rParam.mpEngine->SetText(OUString("###"));
3378 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3379 if (rParam.mbPixelToLogic)
3380 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3381 else
3382 nNeededPixel = nEngineWidth;
3383 nNeededPixel += nLeftM + nRightM;
3385 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3389 long nStartX = aAreaParam.maAlignRect.Left();
3390 const long nStartY = aAreaParam.maAlignRect.Top();
3391 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3392 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3393 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3395 if (rParam.mbBreak)
3397 // text with automatic breaks is aligned only within the
3398 // edit engine's paper size, the output of the whole area
3399 // is always left-aligned
3401 nStartX += nLeftM;
3403 else
3405 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3406 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3407 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3408 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3409 else
3410 nStartX += nLeftM;
3413 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3414 if (bOutside)
3415 return;
3417 // output area, excluding margins, in logical units
3418 const Size& aCellSize = rParam.mbPixelToLogic
3419 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3420 : Size( nOutWidth, nOutHeight );
3422 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3424 Point aLogicStart(nStartX, nStartY);
3425 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3427 Point aURLStart = aLogicStart; // copy before modifying for orientation
3429 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak)
3431 Size aPSize = rParam.mpEngine->GetPaperSize();
3432 aPSize.Width() = aCellSize.Height();
3433 rParam.mpEngine->SetPaperSize(aPSize);
3434 aLogicStart.Y() +=
3435 rParam.mbBreak ? aPSize.Width() : nEngineHeight;
3437 else
3439 // Note that the "paper" is rotated 90 degrees to the left, so
3440 // paper's width is in vertical direction. Also, the whole text
3441 // is on a single line, as text wrap is not in effect.
3443 // Set the paper width to be the width of the text.
3444 Size aPSize = rParam.mpEngine->GetPaperSize();
3445 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3446 rParam.mpEngine->SetPaperSize(aPSize);
3448 long nGap = 0;
3449 long nTopOffset = 0;
3450 if (rParam.mbPixelToLogic)
3452 nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
3453 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3454 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3456 else
3458 nGap = aCellSize.Height() - aPSize.Width();
3459 nTopOffset = nTopM;
3462 // First, align text to bottom.
3463 aLogicStart.Y() += aCellSize.Height();
3464 aLogicStart.Y() += nTopOffset;
3466 switch (rParam.meVerJust)
3468 case SVX_VER_JUSTIFY_STANDARD:
3469 case SVX_VER_JUSTIFY_BOTTOM:
3470 // align to bottom (do nothing).
3471 break;
3472 case SVX_VER_JUSTIFY_CENTER:
3473 // center it.
3474 aLogicStart.Y() -= nGap / 2;
3475 break;
3476 case SVX_VER_JUSTIFY_BLOCK:
3477 case SVX_VER_JUSTIFY_TOP:
3478 // align to top
3479 aLogicStart.Y() -= nGap;
3480 default:
3485 rParam.adjustForRTL();
3486 rParam.mpEngine->Draw(mpDev, aLogicStart, 900);
3488 if (bClip)
3490 if (bMetaFile)
3491 mpDev->Pop();
3492 else
3493 mpDev->SetClipRegion();
3496 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3499 void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
3501 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3503 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3504 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3506 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3508 //! mirror margin values for RTL?
3509 //! move margin down to after final GetOutputArea call
3510 long nTopM, nLeftM, nBottomM, nRightM;
3511 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3513 SCCOL nXForPos = rParam.mnX;
3514 if ( nXForPos < nX1 )
3516 nXForPos = nX1;
3517 rParam.mnPosX = rParam.mnInitPosX;
3519 SCSIZE nArrYForPos = rParam.mnArrY;
3520 if ( nArrYForPos < 1 )
3522 nArrYForPos = 1;
3523 rParam.mnPosY = nScrY;
3526 OutputAreaParam aAreaParam;
3529 // Initial page size - large for normal text, cell size for automatic line breaks
3532 Size aPaperSize = Size( 1000000, 1000000 );
3533 if (rParam.hasLineBreak())
3535 // call GetOutputArea with nNeeded=0, to get only the cell width
3537 //! handle nArrY == 0
3538 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3539 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3540 rParam.mbCellIsValue, true, false, aAreaParam );
3542 //! special ScEditUtil handling if formatting for printer
3543 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3545 if (rParam.mbPixelToLogic)
3547 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3548 rParam.mpEngine->SetPaperSize(aLogicSize);
3550 else
3551 rParam.mpEngine->SetPaperSize(aPaperSize);
3554 // Fill the EditEngine (cell attributes and text)
3557 rParam.setPatternToEngine(mbUseStyleColor);
3558 rParam.setAlignmentToEngine();
3560 // Read content from cell
3562 bool bWrapFields = false;
3563 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3564 // Failed to read cell content. Bail out.
3565 return;
3567 if ( mbSyntaxMode )
3568 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3569 else if ( mbUseStyleColor && mbForceAutoColor )
3570 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3572 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3575 // Get final output area using the calculated width
3578 long nEngineWidth, nEngineHeight;
3579 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3581 long nNeededPixel = nEngineWidth;
3582 if (rParam.mbPixelToLogic)
3583 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3584 nNeededPixel += nLeftM + nRightM;
3586 if (!rParam.mbBreak || bShrink)
3588 // for break, the first GetOutputArea call is sufficient
3589 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3590 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3591 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3593 if ( bShrink )
3595 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3596 nLeftM, nTopM, nRightM, nBottomM, false,
3597 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3598 nEngineWidth, nEngineHeight, nNeededPixel,
3599 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3601 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3603 // First check if twice the space for the formatted text is available
3604 // (otherwise just keep it unchanged).
3606 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3607 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3608 if ( nAvailable >= 2 * nFormatted )
3610 // "repeat" is handled with unformatted text (for performance reasons)
3611 OUString aCellStr = rParam.mpEngine->GetText();
3612 rParam.mpEngine->SetText( aCellStr );
3614 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3615 if (rParam.mbPixelToLogic)
3616 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3617 if ( pFmtDevice != mpRefDevice )
3618 ++nRepeatSize;
3619 if ( nRepeatSize > 0 )
3621 const long nRepeatCount = nAvailable / nRepeatSize;
3622 if ( nRepeatCount > 1 )
3624 OUString aRepeated = aCellStr;
3625 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3626 aRepeated += aCellStr;
3627 rParam.mpEngine->SetText( aRepeated );
3629 nEngineHeight = rParam.mpEngine->GetTextHeight();
3630 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3631 if (rParam.mbPixelToLogic)
3632 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3633 else
3634 nNeededPixel = nEngineWidth;
3635 nNeededPixel += nLeftM + nRightM;
3641 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3643 rParam.mpEngine->SetText(OUString("###"));
3644 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3645 if (rParam.mbPixelToLogic)
3646 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3647 else
3648 nNeededPixel = nEngineWidth;
3649 nNeededPixel += nLeftM + nRightM;
3651 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3655 long nStartX = aAreaParam.maAlignRect.Left();
3656 const long nStartY = aAreaParam.maAlignRect.Top();
3657 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3658 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3659 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3661 if (rParam.mbBreak)
3663 // text with automatic breaks is aligned only within the
3664 // edit engine's paper size, the output of the whole area
3665 // is always left-aligned
3667 nStartX += nLeftM;
3668 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
3669 nStartX += aPaperSize.Height();
3671 else
3673 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3674 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3675 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3676 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3677 else
3678 nStartX += nLeftM;
3681 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3682 if (bOutside)
3683 return;
3685 // output area, excluding margins, in logical units
3686 const Size& aCellSize = rParam.mbPixelToLogic
3687 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3688 : Size( nOutWidth, nOutHeight );
3690 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3692 Point aLogicStart(nStartX, nStartY);
3693 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3695 Point aURLStart = aLogicStart; // copy before modifying for orientation
3697 if (rParam.meHorJustResult != SVX_HOR_JUSTIFY_BLOCK)
3699 aLogicStart.X() += nEngineWidth;
3700 if (!rParam.mbBreak)
3702 // Set the paper width to text size.
3703 Size aPSize = rParam.mpEngine->GetPaperSize();
3704 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3705 rParam.mpEngine->SetPaperSize(aPSize);
3707 long nGap = 0;
3708 long nTopOffset = 0; // offset by top margin
3709 if (rParam.mbPixelToLogic)
3711 nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
3712 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3713 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3715 else
3717 nGap = aPSize.Width() - aCellSize.Height();
3718 nTopOffset = nTopM;
3720 aLogicStart.Y() += nTopOffset;
3722 switch (rParam.meVerJust)
3724 case SVX_VER_JUSTIFY_STANDARD:
3725 case SVX_VER_JUSTIFY_BOTTOM:
3726 // align to bottom
3727 aLogicStart.Y() -= nGap;
3728 break;
3729 case SVX_VER_JUSTIFY_CENTER:
3730 // center it.
3731 aLogicStart.Y() -= nGap / 2;
3732 break;
3733 case SVX_VER_JUSTIFY_BLOCK:
3734 case SVX_VER_JUSTIFY_TOP:
3735 // align to top (do nothing)
3736 default:
3742 rParam.adjustForRTL();
3744 // bMoveClipped handling has been replaced by complete alignment
3745 // handling (also extending to the left).
3747 rParam.mpEngine->Draw(mpDev, aLogicStart, 2700);
3749 if (bClip)
3751 if (bMetaFile)
3752 mpDev->Pop();
3753 else
3754 mpDev->SetClipRegion();
3757 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3760 void ScOutputData::DrawEditStacked(DrawEditParam& rParam)
3762 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3763 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3765 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3766 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3768 rParam.mbAsianVertical =
3769 lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
3771 if ( rParam.mbAsianVertical )
3773 // in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE
3774 rParam.meOrient = SVX_ORIENTATION_STANDARD;
3775 DrawEditAsianVertical(rParam);
3776 return;
3779 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3781 //! mirror margin values for RTL?
3782 //! move margin down to after final GetOutputArea call
3783 long nTopM, nLeftM, nBottomM, nRightM;
3784 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3786 SCCOL nXForPos = rParam.mnX;
3787 if ( nXForPos < nX1 )
3789 nXForPos = nX1;
3790 rParam.mnPosX = rParam.mnInitPosX;
3792 SCSIZE nArrYForPos = rParam.mnArrY;
3793 if ( nArrYForPos < 1 )
3795 nArrYForPos = 1;
3796 rParam.mnPosY = nScrY;
3799 OutputAreaParam aAreaParam;
3802 // Initial page size - large for normal text, cell size for automatic line breaks
3805 Size aPaperSize = Size( 1000000, 1000000 );
3806 // call GetOutputArea with nNeeded=0, to get only the cell width
3808 //! handle nArrY == 0
3809 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3810 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3811 rParam.mbCellIsValue, true, false, aAreaParam );
3813 //! special ScEditUtil handling if formatting for printer
3814 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3816 if (rParam.mbPixelToLogic)
3818 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3819 if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
3821 // #i85342# screen display and formatting for printer,
3822 // use same GetEditArea call as in ScViewData::SetEditEngine
3824 Fraction aFract(1,1);
3825 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
3826 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
3827 aLogicSize.Width() = aUtilRect.GetWidth();
3829 rParam.mpEngine->SetPaperSize(aLogicSize);
3831 else
3832 rParam.mpEngine->SetPaperSize(aPaperSize);
3835 // Fill the EditEngine (cell attributes and text)
3838 rParam.setPatternToEngine(mbUseStyleColor);
3839 rParam.setAlignmentToEngine();
3841 // Read content from cell
3843 bool bWrapFields = false;
3844 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3845 // Failed to read cell content. Bail out.
3846 return;
3848 if ( mbSyntaxMode )
3849 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3850 else if ( mbUseStyleColor && mbForceAutoColor )
3851 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3853 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3856 // Get final output area using the calculated width
3859 long nEngineWidth, nEngineHeight;
3860 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3862 long nNeededPixel = nEngineWidth;
3863 if (rParam.mbPixelToLogic)
3864 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3865 nNeededPixel += nLeftM + nRightM;
3867 if (bShrink)
3869 // for break, the first GetOutputArea call is sufficient
3870 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3871 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3872 true, false, false, aAreaParam );
3874 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3875 nLeftM, nTopM, nRightM, nBottomM, true,
3876 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3877 nEngineWidth, nEngineHeight, nNeededPixel,
3878 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3880 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3882 // First check if twice the space for the formatted text is available
3883 // (otherwise just keep it unchanged).
3885 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3886 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3887 if ( nAvailable >= 2 * nFormatted )
3889 // "repeat" is handled with unformatted text (for performance reasons)
3890 OUString aCellStr = rParam.mpEngine->GetText();
3891 rParam.mpEngine->SetText( aCellStr );
3893 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
3894 if (rParam.mbPixelToLogic)
3895 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3896 if ( pFmtDevice != mpRefDevice )
3897 ++nRepeatSize;
3898 if ( nRepeatSize > 0 )
3900 long nRepeatCount = nAvailable / nRepeatSize;
3901 if ( nRepeatCount > 1 )
3903 OUString aRepeated = aCellStr;
3904 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3905 aRepeated += aCellStr;
3906 rParam.mpEngine->SetText( aRepeated );
3908 nEngineHeight = rParam.mpEngine->GetTextHeight();
3909 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3910 if (rParam.mbPixelToLogic)
3911 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3912 else
3913 nNeededPixel = nEngineWidth;
3914 nNeededPixel += nLeftM + nRightM;
3920 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3922 rParam.mpEngine->SetText(OUString("###"));
3923 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3924 if (rParam.mbPixelToLogic)
3925 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3926 else
3927 nNeededPixel = nEngineWidth;
3928 nNeededPixel += nLeftM + nRightM;
3930 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3933 if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT )
3935 aPaperSize.Width() = nNeededPixel + 1;
3936 if (rParam.mbPixelToLogic)
3937 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3938 else
3939 rParam.mpEngine->SetPaperSize(aPaperSize);
3943 long nStartX = aAreaParam.maAlignRect.Left();
3944 long nStartY = aAreaParam.maAlignRect.Top();
3945 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3946 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3947 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3949 if (rParam.mbBreak)
3951 // text with automatic breaks is aligned only within the
3952 // edit engine's paper size, the output of the whole area
3953 // is always left-aligned
3955 nStartX += nLeftM;
3957 else
3959 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3960 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3961 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3962 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3963 else
3964 nStartX += nLeftM;
3967 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3968 if (bOutside)
3969 return;
3971 if ( aAreaParam.maClipRect.Left() < nScrX )
3973 aAreaParam.maClipRect.Left() = nScrX;
3974 aAreaParam.mbLeftClip = true;
3976 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3978 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3979 aAreaParam.mbRightClip = true;
3982 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3983 bool bSimClip = false;
3985 if ( bWrapFields )
3987 // Fields in a cell with automatic breaks: clip to cell width
3988 bClip = true;
3991 if ( aAreaParam.maClipRect.Top() < nScrY )
3993 aAreaParam.maClipRect.Top() = nScrY;
3994 bClip = true;
3996 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3998 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3999 bClip = true;
4002 Size aCellSize; // output area, excluding margins, in logical units
4003 if (rParam.mbPixelToLogic)
4004 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4005 else
4006 aCellSize = Size( nOutWidth, nOutHeight );
4008 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4010 const ScMergeAttr* pMerge =
4011 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4012 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4014 // Don't clip for text height when printing rows with optimal height,
4015 // except when font size is from conditional formatting.
4016 //! Allow clipping when vertically merged?
4017 if ( eType != OUTTYPE_PRINTER ||
4018 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4019 ( rParam.mpCondSet && SFX_ITEM_SET ==
4020 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4021 bClip = true;
4022 else
4023 bSimClip = true;
4025 // Show clip marks if height is at least 5pt too small and
4026 // there are several lines of text.
4027 // Not for asian vertical text, because that would interfere
4028 // with the default right position of the text.
4029 // Only with automatic line breaks, to avoid having to find
4030 // the cells with the horizontal end of the text again.
4031 if ( nEngineHeight - aCellSize.Height() > 100 &&
4032 rParam.mbBreak && bMarkClipped &&
4033 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4035 CellInfo* pClipMarkCell = NULL;
4036 if ( bMerged )
4038 // anywhere in the merged area...
4039 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4040 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4042 else
4043 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4045 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4046 bAnyClipped = true;
4048 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4049 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4050 aAreaParam.maClipRect.Right() -= nMarkPixel;
4054 Rectangle aLogicClip;
4055 if (bClip || bSimClip)
4057 // Clip marks are already handled in GetOutputArea
4059 if (rParam.mbPixelToLogic)
4060 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4061 else
4062 aLogicClip = aAreaParam.maClipRect;
4064 if (bClip) // bei bSimClip nur aClipRect initialisieren
4066 if (bMetaFile)
4068 mpDev->Push();
4069 mpDev->IntersectClipRegion( aLogicClip );
4071 else
4072 mpDev->SetClipRegion( Region( aLogicClip ) );
4076 Point aLogicStart;
4077 if (rParam.mbPixelToLogic)
4078 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4079 else
4080 aLogicStart = Point(nStartX, nStartY);
4082 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
4083 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
4085 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4086 //! only converting margin?
4088 if (rParam.mbPixelToLogic)
4089 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
4090 mpRefDevice->LogicToPixel(aCellSize).Height() -
4091 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
4092 )).Height();
4093 else
4094 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
4096 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
4098 if (rParam.mbPixelToLogic)
4099 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
4100 mpRefDevice->LogicToPixel(aCellSize).Height() -
4101 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
4102 / 2)).Height();
4103 else
4104 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
4106 else // top
4108 if (rParam.mbPixelToLogic)
4109 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4110 else
4111 aLogicStart.Y() += nTopM;
4114 Point aURLStart = aLogicStart; // copy before modifying for orientation
4116 Size aPaperLogic = rParam.mpEngine->GetPaperSize();
4117 aPaperLogic.Width() = nEngineWidth;
4118 rParam.mpEngine->SetPaperSize(aPaperLogic);
4120 rParam.adjustForRTL();
4122 // bMoveClipped handling has been replaced by complete alignment
4123 // handling (also extending to the left).
4125 if (bSimClip)
4127 // kein hartes Clipping, aber nur die betroffenen
4128 // Zeilen ausgeben
4130 Point aDocStart = aLogicClip.TopLeft();
4131 aDocStart -= aLogicStart;
4132 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
4134 else
4136 rParam.mpEngine->Draw( mpDev, aLogicStart, 0 );
4139 if (bClip)
4141 if (bMetaFile)
4142 mpDev->Pop();
4143 else
4144 mpDev->SetClipRegion();
4147 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4150 void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam)
4152 // When in asian vertical orientation, the orientation value is STANDARD,
4153 // and the asian vertical boolean is true.
4154 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
4155 OSL_ASSERT(rParam.mbAsianVertical);
4156 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
4158 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
4160 bool bHidden = false;
4161 bool bRepeat = false;
4162 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
4163 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
4165 if (nAttrRotate)
4167 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
4168 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
4169 bHidden = true; // gedreht wird getrennt ausgegeben
4172 // default alignment for asian vertical mode is top-right
4173 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4174 * SVX_HOR_JUSTIFY_RIGHT really wanted? Seems this was done all the time,
4175 * also before context was introduced and everything was attr only. */
4176 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_STANDARD )
4177 rParam.meHorJustResult = rParam.meHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
4179 if (bHidden)
4180 return;
4182 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
4184 //! mirror margin values for RTL?
4185 //! move margin down to after final GetOutputArea call
4186 long nTopM, nLeftM, nBottomM, nRightM;
4187 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
4189 SCCOL nXForPos = rParam.mnX;
4190 if ( nXForPos < nX1 )
4192 nXForPos = nX1;
4193 rParam.mnPosX = rParam.mnInitPosX;
4195 SCSIZE nArrYForPos = rParam.mnArrY;
4196 if ( nArrYForPos < 1 )
4198 nArrYForPos = 1;
4199 rParam.mnPosY = nScrY;
4202 OutputAreaParam aAreaParam;
4205 // Initial page size - large for normal text, cell size for automatic line breaks
4208 Size aPaperSize = Size( 1000000, 1000000 );
4209 // call GetOutputArea with nNeeded=0, to get only the cell width
4211 //! handle nArrY == 0
4212 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
4213 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4214 rParam.mbCellIsValue, true, false, aAreaParam );
4216 //! special ScEditUtil handling if formatting for printer
4217 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
4219 if (rParam.mbPixelToLogic)
4221 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
4222 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
4224 // #i85342# screen display and formatting for printer,
4225 // use same GetEditArea call as in ScViewData::SetEditEngine
4227 Fraction aFract(1,1);
4228 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
4229 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
4230 aLogicSize.Width() = aUtilRect.GetWidth();
4232 rParam.mpEngine->SetPaperSize(aLogicSize);
4234 else
4235 rParam.mpEngine->SetPaperSize(aPaperSize);
4238 // Fill the EditEngine (cell attributes and text)
4241 // default alignment for asian vertical mode is top-right
4242 if ( rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
4243 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
4245 rParam.setPatternToEngine(mbUseStyleColor);
4246 rParam.setAlignmentToEngine();
4248 // Read content from cell
4250 bool bWrapFields = false;
4251 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
4252 // Failed to read cell content. Bail out.
4253 return;
4255 if ( mbSyntaxMode )
4256 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
4257 else if ( mbUseStyleColor && mbForceAutoColor )
4258 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
4260 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4263 // Get final output area using the calculated width
4266 long nEngineWidth, nEngineHeight;
4267 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
4269 long nNeededPixel = nEngineWidth;
4270 if (rParam.mbPixelToLogic)
4271 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
4272 nNeededPixel += nLeftM + nRightM;
4274 // for break, the first GetOutputArea call is sufficient
4275 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
4276 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4277 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
4279 if ( bShrink )
4281 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
4282 nLeftM, nTopM, nRightM, nBottomM, false,
4283 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
4284 nEngineWidth, nEngineHeight, nNeededPixel,
4285 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4287 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
4289 // First check if twice the space for the formatted text is available
4290 // (otherwise just keep it unchanged).
4292 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
4293 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
4294 if ( nAvailable >= 2 * nFormatted )
4296 // "repeat" is handled with unformatted text (for performance reasons)
4297 OUString aCellStr = rParam.mpEngine->GetText();
4298 rParam.mpEngine->SetText( aCellStr );
4300 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
4301 if (rParam.mbPixelToLogic)
4302 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
4303 if ( pFmtDevice != mpRefDevice )
4304 ++nRepeatSize;
4305 if ( nRepeatSize > 0 )
4307 long nRepeatCount = nAvailable / nRepeatSize;
4308 if ( nRepeatCount > 1 )
4310 OUString aRepeated = aCellStr;
4311 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
4312 aRepeated += aCellStr;
4313 rParam.mpEngine->SetText( aRepeated );
4315 nEngineHeight = rParam.mpEngine->GetTextHeight();
4316 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4317 if (rParam.mbPixelToLogic)
4318 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4319 else
4320 nNeededPixel = nEngineWidth;
4321 nNeededPixel += nLeftM + nRightM;
4327 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
4329 rParam.mpEngine->SetText(OUString("###"));
4330 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4331 if (rParam.mbPixelToLogic)
4332 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4333 else
4334 nNeededPixel = nEngineWidth;
4335 nNeededPixel += nLeftM + nRightM;
4337 // No clip marks if "###" doesn't fit (same as in DrawStrings)
4340 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
4342 aPaperSize.Width() = nNeededPixel + 1;
4343 if (rParam.mbPixelToLogic)
4344 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4345 else
4346 rParam.mpEngine->SetPaperSize(aPaperSize);
4349 long nStartX = aAreaParam.maAlignRect.Left();
4350 long nStartY = aAreaParam.maAlignRect.Top();
4351 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
4352 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
4353 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
4355 // text with automatic breaks is aligned only within the
4356 // edit engine's paper size, the output of the whole area
4357 // is always left-aligned
4359 nStartX += nLeftM;
4361 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4362 if (bOutside)
4363 return;
4365 if ( aAreaParam.maClipRect.Left() < nScrX )
4367 aAreaParam.maClipRect.Left() = nScrX;
4368 aAreaParam.mbLeftClip = true;
4370 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
4372 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
4373 aAreaParam.mbRightClip = true;
4376 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
4377 bool bSimClip = false;
4379 if ( bWrapFields )
4381 // Fields in a cell with automatic breaks: clip to cell width
4382 bClip = true;
4385 if ( aAreaParam.maClipRect.Top() < nScrY )
4387 aAreaParam.maClipRect.Top() = nScrY;
4388 bClip = true;
4390 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
4392 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
4393 bClip = true;
4396 Size aCellSize; // output area, excluding margins, in logical units
4397 if (rParam.mbPixelToLogic)
4398 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4399 else
4400 aCellSize = Size( nOutWidth, nOutHeight );
4402 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4404 const ScMergeAttr* pMerge =
4405 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4406 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4408 // Don't clip for text height when printing rows with optimal height,
4409 // except when font size is from conditional formatting.
4410 //! Allow clipping when vertically merged?
4411 if ( eType != OUTTYPE_PRINTER ||
4412 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4413 ( rParam.mpCondSet && SFX_ITEM_SET ==
4414 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4415 bClip = true;
4416 else
4417 bSimClip = true;
4419 // Show clip marks if height is at least 5pt too small and
4420 // there are several lines of text.
4421 // Not for asian vertical text, because that would interfere
4422 // with the default right position of the text.
4423 // Only with automatic line breaks, to avoid having to find
4424 // the cells with the horizontal end of the text again.
4425 if ( nEngineHeight - aCellSize.Height() > 100 &&
4426 ( rParam.mbBreak || rParam.meOrient == SVX_ORIENTATION_STACKED ) &&
4427 !rParam.mbAsianVertical && bMarkClipped &&
4428 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4430 CellInfo* pClipMarkCell = NULL;
4431 if ( bMerged )
4433 // anywhere in the merged area...
4434 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4435 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4437 else
4438 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4440 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4441 bAnyClipped = true;
4443 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4444 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4445 aAreaParam.maClipRect.Right() -= nMarkPixel;
4449 Rectangle aLogicClip;
4450 if (bClip || bSimClip)
4452 // Clip marks are already handled in GetOutputArea
4454 if (rParam.mbPixelToLogic)
4455 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4456 else
4457 aLogicClip = aAreaParam.maClipRect;
4459 if (bClip) // bei bSimClip nur aClipRect initialisieren
4461 if (bMetaFile)
4463 mpDev->Push();
4464 mpDev->IntersectClipRegion( aLogicClip );
4466 else
4467 mpDev->SetClipRegion( Region( aLogicClip ) );
4471 Point aLogicStart;
4472 if (rParam.mbPixelToLogic)
4473 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4474 else
4475 aLogicStart = Point(nStartX, nStartY);
4477 long nAvailWidth = aCellSize.Width();
4478 // space for AutoFilter is already handled in GetOutputArea
4480 // horizontal alignment
4482 if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_RIGHT)
4483 aLogicStart.X() += nAvailWidth - nEngineWidth;
4484 else if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_CENTER)
4485 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
4487 // paper size is subtracted below
4488 aLogicStart.X() += nEngineWidth;
4490 // vertical adjustment is within the EditEngine
4491 if (rParam.mbPixelToLogic)
4492 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4493 else
4494 aLogicStart.Y() += nTopM;
4496 Point aURLStart = aLogicStart; // copy before modifying for orientation
4498 rParam.adjustForRTL();
4500 // bMoveClipped handling has been replaced by complete alignment
4501 // handling (also extending to the left).
4503 // with SetVertical, the start position is top left of
4504 // the whole output area, not the text itself
4505 aLogicStart.X() -= rParam.mpEngine->GetPaperSize().Width();
4507 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
4509 if (bClip)
4511 if (bMetaFile)
4512 mpDev->Pop();
4513 else
4514 mpDev->SetClipRegion();
4517 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4520 void ScOutputData::DrawEdit(sal_Bool bPixelToLogic)
4522 ScFieldEditEngine* pEngine = NULL;
4523 bool bHyphenatorSet = false;
4524 const ScPatternAttr* pOldPattern = NULL;
4525 const SfxItemSet* pOldCondSet = NULL;
4526 const SfxItemSet* pOldPreviewFontSet = NULL;
4527 ScRefCellValue aCell;
4529 long nInitPosX = nScrX;
4530 if ( bLayoutRTL )
4532 nInitPosX += nMirrorW - 1;
4534 long nLayoutSign = bLayoutRTL ? -1 : 1;
4536 //! store nLastContentCol as member!
4537 SCCOL nLastContentCol = MAXCOL;
4538 if ( nX2 < MAXCOL )
4539 nLastContentCol = sal::static_int_cast<SCCOL>(
4540 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
4542 long nRowPosY = nScrY;
4543 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4545 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4547 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4549 if ( pThisRowInfo->bChanged || nArrY==0 )
4551 long nPosX = 0;
4552 for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen
4554 std::auto_ptr< ScPatternAttr > pPreviewPattr;
4555 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4557 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4558 if (pInfo->bEditEngine)
4560 SCROW nY = pThisRowInfo->nRowNo;
4562 SCCOL nCellX = nX; // position where the cell really starts
4563 SCROW nCellY = nY;
4564 sal_Bool bDoCell = false;
4566 long nPosY = nRowPosY;
4567 if ( nArrY == 0 )
4569 nPosY = nScrY;
4570 nY = pRowInfo[1].nRowNo;
4571 SCCOL nOverX; // start of the merged cells
4572 SCROW nOverY;
4573 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, sal_True ))
4575 nCellX = nOverX;
4576 nCellY = nOverY;
4577 bDoCell = sal_True;
4580 else if ( nX == nX2 && pThisRowInfo->pCellInfo[nX+1].maCell.isEmpty() )
4582 // Rest of a long text further to the right?
4584 SCCOL nTempX=nX;
4585 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
4586 ++nTempX;
4588 if ( nTempX > nX &&
4589 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
4590 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
4592 nCellX = nTempX;
4593 bDoCell = sal_True;
4596 else
4598 bDoCell = true;
4601 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
4602 bDoCell = false;
4604 const ScPatternAttr* pPattern = NULL;
4605 const SfxItemSet* pCondSet = NULL;
4606 if (bDoCell)
4608 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
4609 !mpDoc->ColHidden(nCellX, nTab) )
4611 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
4612 pPattern = rCellInfo.pPatternAttr;
4613 pCondSet = rCellInfo.pConditionSet;
4614 aCell = rCellInfo.maCell;
4616 else // get from document
4618 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
4619 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
4620 GetVisibleCell( nCellX, nCellY, nTab, aCell );
4622 if (aCell.isEmpty())
4623 bDoCell = false;
4625 if (bDoCell)
4627 if ( mpDoc->GetPreviewCellStyle() )
4629 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
4631 pPreviewPattr.reset( new ScPatternAttr(*pPattern) );
4632 pPreviewPattr->SetStyleSheet(pPreviewStyle);
4633 pPattern = const_cast<ScPatternAttr*>(pPreviewPattr.get());
4636 SfxItemSet* pPreviewFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab );
4637 if (!pEngine)
4638 pEngine = CreateOutputEditEngine();
4639 else
4640 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4642 // fdo#32530: Check if the first character is RTL.
4643 OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
4645 DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(aCell));
4646 aParam.meHorJustContext = getAlignmentFromContext( aParam.meHorJustAttr,
4647 aParam.mbCellIsValue, aStr, *pPattern, pCondSet, mpDoc, nTab);
4648 aParam.meHorJustResult = (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) ?
4649 SVX_HOR_JUSTIFY_BLOCK : aParam.meHorJustContext;
4650 aParam.mbPixelToLogic = bPixelToLogic;
4651 aParam.mbHyphenatorSet = bHyphenatorSet;
4652 aParam.mpEngine = pEngine;
4653 aParam.maCell = aCell;
4654 aParam.mnArrY = nArrY;
4655 aParam.mnX = nX;
4656 aParam.mnY = nY;
4657 aParam.mnCellX = nCellX;
4658 aParam.mnCellY = nCellY;
4659 aParam.mnTab = nTab;
4660 aParam.mnPosX = nPosX;
4661 aParam.mnPosY = nPosY;
4662 aParam.mnInitPosX = nInitPosX;
4663 aParam.mpPreviewFontSet = pPreviewFontSet;
4664 aParam.mpPreviewFontSet = pPreviewFontSet;
4665 aParam.mpOldPattern = pOldPattern;
4666 aParam.mpOldCondSet = pOldCondSet;
4667 aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
4668 aParam.mpThisRowInfo = pThisRowInfo;
4669 if (mpSpellCheckCxt)
4670 aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);
4672 if (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT)
4674 // ignore orientation/rotation if "repeat" is active
4675 aParam.meOrient = SVX_ORIENTATION_STANDARD;
4677 switch (aParam.meOrient)
4679 case SVX_ORIENTATION_BOTTOMTOP:
4680 DrawEditBottomTop(aParam);
4681 break;
4682 case SVX_ORIENTATION_TOPBOTTOM:
4683 DrawEditTopBottom(aParam);
4684 break;
4685 case SVX_ORIENTATION_STACKED:
4686 // this can be vertically stacked or asian vertical.
4687 DrawEditStacked(aParam);
4688 break;
4689 default:
4690 DrawEditStandard(aParam);
4693 // Retrieve parameters for next iteration.
4694 pOldPattern = aParam.mpOldPattern;
4695 pOldCondSet = aParam.mpOldCondSet;
4696 pOldPreviewFontSet = aParam.mpOldPreviewFontSet;
4697 bHyphenatorSet = aParam.mbHyphenatorSet;
4700 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
4703 nRowPosY += pRowInfo[nArrY].nHeight;
4706 delete pEngine;
4708 if (bAnyRotated)
4709 DrawRotated(bPixelToLogic); //! von aussen rufen ?
4712 // -------------------------------------------------------------------------------
4714 void ScOutputData::DrawRotated(sal_Bool bPixelToLogic)
4716 //! nRotMax speichern
4717 SCCOL nRotMax = nX2;
4718 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
4719 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
4720 nRotMax = pRowInfo[nRotY].nRotMaxCol;
4723 ScModule* pScMod = SC_MOD();
4724 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
4725 sal_Bool bCellContrast = mbUseStyleColor &&
4726 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4728 ScFieldEditEngine* pEngine = NULL;
4729 sal_Bool bHyphenatorSet = false;
4730 const ScPatternAttr* pPattern;
4731 const SfxItemSet* pCondSet;
4732 const ScPatternAttr* pOldPattern = NULL;
4733 const SfxItemSet* pOldCondSet = NULL;
4734 ScRefCellValue aCell;
4736 long nInitPosX = nScrX;
4737 if ( bLayoutRTL )
4739 nInitPosX += nMirrorW - 1;
4741 long nLayoutSign = bLayoutRTL ? -1 : 1;
4743 long nRowPosY = nScrY;
4744 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4746 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4747 long nCellHeight = (long) pThisRowInfo->nHeight;
4748 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4750 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
4752 long nPosX = 0;
4753 for (SCCOL nX=0; nX<=nRotMax; nX++)
4755 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4757 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4758 if ( pInfo->nRotateDir != SC_ROTDIR_NONE )
4760 SCROW nY = pThisRowInfo->nRowNo;
4762 sal_Bool bHidden = false;
4763 if (bEditMode)
4764 if ( nX == nEditCol && nY == nEditRow )
4765 bHidden = sal_True;
4767 if (!bHidden)
4769 if (!pEngine)
4770 pEngine = CreateOutputEditEngine();
4771 else
4772 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4774 long nPosY = nRowPosY;
4775 sal_Bool bVisChanged = false;
4777 //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht!
4779 sal_Bool bFromDoc = false;
4780 pPattern = pInfo->pPatternAttr;
4781 pCondSet = pInfo->pConditionSet;
4782 if (!pPattern)
4784 pPattern = mpDoc->GetPattern( nX, nY, nTab );
4785 bFromDoc = sal_True;
4787 aCell = pInfo->maCell;
4788 if (bFromDoc)
4789 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
4791 if (aCell.isEmpty() && nX>nX2)
4792 GetVisibleCell( nX, nY, nTab, aCell );
4794 if (aCell.isEmpty() || IsEmptyCellText(pThisRowInfo, nX, nY))
4795 bHidden = true; // nRotateDir is also set without a cell
4797 long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth;
4799 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
4800 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
4801 sal_Bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
4802 ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
4803 sal_Bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
4804 sal_Bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
4805 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
4806 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
4808 const ScMergeAttr* pMerge =
4809 (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
4810 sal_Bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4812 long nStartX = nPosX;
4813 long nStartY = nPosY;
4814 if (nX<nX1)
4816 if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged)
4817 bHidden = sal_True;
4818 else
4820 nStartX = nInitPosX;
4821 SCCOL nCol = nX1;
4822 while (nCol > nX)
4824 --nCol;
4825 nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
4829 long nCellStartX = nStartX;
4831 // Ersatzdarstellung fuer zu kleinen Text weggelassen
4833 if (!bHidden)
4835 long nOutWidth = nCellWidth - 1;
4836 long nOutHeight = nCellHeight;
4838 if ( bMerged ) // Zusammengefasst
4840 SCCOL nCountX = pMerge->GetColMerge();
4841 for (SCCOL i=1; i<nCountX; i++)
4842 nOutWidth += (long) ( mpDoc->GetColWidth(nX+i,nTab) * mnPPTX );
4843 SCROW nCountY = pMerge->GetRowMerge();
4844 nOutHeight += (long) mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
4847 SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)
4848 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
4850 // Syntax-Modus wird hier ignoriert...
4852 // StringDiffer doesn't look at hyphenate, language items
4853 if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
4855 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
4856 pPattern->FillEditItemSet( pSet, pCondSet );
4858 // Ausrichtung fuer EditEngine
4859 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
4860 if (eOrient==SVX_ORIENTATION_STACKED)
4861 eSvxAdjust = SVX_ADJUST_CENTER;
4862 // Adjustment fuer bBreak ist hier weggelassen
4863 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
4865 pEngine->SetDefaults( pSet );
4866 pOldPattern = pPattern;
4867 pOldCondSet = pCondSet;
4869 sal_uLong nControl = pEngine->GetControlWord();
4870 if (eOrient==SVX_ORIENTATION_STACKED)
4871 nControl |= EE_CNTRL_ONECHARPERLINE;
4872 else
4873 nControl &= ~EE_CNTRL_ONECHARPERLINE;
4874 pEngine->SetControlWord( nControl );
4876 if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
4878 // set hyphenator the first time it is needed
4879 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
4880 pEngine->SetHyphenator( xXHyphenator );
4881 bHyphenatorSet = sal_True;
4884 Color aBackCol = ((const SvxBrushItem&)
4885 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
4886 if ( mbUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
4887 aBackCol.SetColor( nConfBackColor );
4888 pEngine->SetBackgroundColor( aBackCol );
4891 // Raender
4893 //! Position und Papersize auf EditUtil umstellen !!!
4895 const SvxMarginItem* pMargin = (const SvxMarginItem*)
4896 &pPattern->GetItem(ATTR_MARGIN, pCondSet);
4897 sal_uInt16 nIndent = 0;
4898 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
4899 nIndent = ((const SfxUInt16Item&)pPattern->
4900 GetItem(ATTR_INDENT, pCondSet)).GetValue();
4902 long nTotalHeight = nOutHeight; // ohne Rand abzuziehen
4903 if ( bPixelToLogic )
4904 nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
4906 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
4907 long nTopM = (long) ( pMargin->GetTopMargin() * mnPPTY );
4908 long nRightM = (long) ( pMargin->GetRightMargin() * mnPPTX );
4909 long nBottomM = (long) ( pMargin->GetBottomMargin() * mnPPTY );
4910 nStartX += nLeftM;
4911 nStartY += nTopM;
4912 nOutWidth -= nLeftM + nRightM;
4913 nOutHeight -= nTopM + nBottomM;
4915 // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen
4916 long nAttrRotate = 0;
4917 double nSin = 0.0;
4918 double nCos = 1.0;
4919 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
4920 if ( eOrient == SVX_ORIENTATION_STANDARD )
4922 nAttrRotate = ((const SfxInt32Item&)pPattern->
4923 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
4924 if ( nAttrRotate )
4926 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
4927 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
4929 if ( nAttrRotate == 18000 )
4930 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
4932 if ( bLayoutRTL )
4933 nAttrRotate = -nAttrRotate;
4935 double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad
4936 nCos = cos( nRealOrient );
4937 nSin = sin( nRealOrient );
4941 Size aPaperSize = Size( 1000000, 1000000 );
4942 if (eOrient==SVX_ORIENTATION_STACKED)
4943 aPaperSize.Width() = nOutWidth; // zum Zentrieren
4944 else if (bBreak)
4946 if (nAttrRotate)
4948 //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl
4949 //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben
4950 //! werden koennen -> darum unbegrenzt, also kein Umbruch.
4951 //! Mit versetzten Zeilen waere das folgende richtig:
4952 aPaperSize.Width() = (long)(nOutHeight / fabs(nSin));
4954 else if (eOrient == SVX_ORIENTATION_STANDARD)
4955 aPaperSize.Width() = nOutWidth;
4956 else
4957 aPaperSize.Width() = nOutHeight - 1;
4959 if (bPixelToLogic)
4960 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4961 else
4962 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4964 // Daten aus Zelle lesen
4966 if (aCell.meType == CELLTYPE_EDIT)
4968 if (aCell.mpEditText)
4969 pEngine->SetText(*aCell.mpEditText);
4970 else
4972 OSL_FAIL("pData == 0");
4975 else
4977 sal_uLong nFormat = pPattern->GetNumberFormat(
4978 mpDoc->GetFormatTable(), pCondSet );
4979 OUString aString;
4980 Color* pColor;
4981 ScCellFormat::GetString( aCell,
4982 nFormat,aString, &pColor,
4983 *mpDoc->GetFormatTable(),
4984 mpDoc,
4985 mbShowNullValues,
4986 mbShowFormulas,
4987 ftCheck );
4989 pEngine->SetText(aString);
4990 if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
4991 lcl_SetEditColor( *pEngine, *pColor );
4994 if ( mbSyntaxMode )
4996 SetEditSyntaxColor(*pEngine, aCell);
4998 else if ( mbUseStyleColor && mbForceAutoColor )
4999 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine
5001 pEngine->SetUpdateMode( sal_True ); // after SetText, before CalcTextWidth/GetTextHeight
5003 long nEngineWidth = (long) pEngine->CalcTextWidth();
5004 long nEngineHeight = pEngine->GetTextHeight();
5006 if (nAttrRotate && bBreak)
5008 double nAbsCos = fabs( nCos );
5009 double nAbsSin = fabs( nSin );
5011 // adjust witdh of papersize for height of text
5012 int nSteps = 5;
5013 while (nSteps > 0)
5015 // everything is in pixels
5016 long nEnginePixel = mpRefDevice->LogicToPixel(
5017 Size(0,nEngineHeight)).Height();
5018 long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2;
5019 long nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
5020 sal_Bool bFits = ( nNewWidth >= aPaperSize.Width() );
5021 if ( bFits )
5022 nSteps = 0;
5023 else
5025 if ( nNewWidth < 4 )
5027 // can't fit -> fall back to using half height
5028 nEffHeight = nOutHeight / 2;
5029 nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
5030 nSteps = 0;
5032 else
5033 --nSteps;
5035 // set paper width and get new text height
5036 aPaperSize.Width() = nNewWidth;
5037 if (bPixelToLogic)
5038 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5039 else
5040 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
5041 //pEngine->QuickFormatDoc( sal_True );
5042 nEngineWidth = (long) pEngine->CalcTextWidth();
5043 nEngineHeight = pEngine->GetTextHeight();
5048 long nRealWidth = nEngineWidth;
5049 long nRealHeight = nEngineHeight;
5051 // wenn gedreht, Groesse anpassen
5052 if (nAttrRotate)
5054 double nAbsCos = fabs( nCos );
5055 double nAbsSin = fabs( nSin );
5057 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5058 nEngineWidth = (long) ( nRealWidth * nAbsCos +
5059 nRealHeight * nAbsSin );
5060 else
5061 nEngineWidth = (long) ( nRealHeight / nAbsSin );
5062 //! begrenzen !!!
5064 nEngineHeight = (long) ( nRealHeight * nAbsCos +
5065 nRealWidth * nAbsSin );
5068 if (!nAttrRotate) // hier nur gedrehter Text
5069 bHidden = sal_True; //! vorher abfragen !!!
5071 //! weglassen, was nicht hereinragt
5073 if (!bHidden)
5075 sal_Bool bClip = false;
5076 Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
5078 // weiterschreiben
5080 Size aCellSize;
5081 if (bPixelToLogic)
5082 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
5083 else
5084 aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1
5086 long nGridWidth = nEngineWidth;
5087 sal_Bool bNegative = false;
5088 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5090 nGridWidth = aCellSize.Width() +
5091 std::abs((long) ( aCellSize.Height() * nCos / nSin ));
5092 bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT );
5093 if ( bLayoutRTL )
5094 bNegative = !bNegative;
5097 // use GetOutputArea to hide the grid
5098 // (clip region is done manually below)
5099 OutputAreaParam aAreaParam;
5101 SCCOL nCellX = nX;
5102 SCROW nCellY = nY;
5103 SvxCellHorJustify eOutHorJust = eHorJust;
5104 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5105 eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
5106 long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
5107 if ( bPixelToLogic )
5108 nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
5110 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
5111 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
5112 false, false, sal_True, aAreaParam );
5114 if ( bShrink )
5116 long nPixelWidth = bPixelToLogic ?
5117 mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
5118 long nNeededPixel = nPixelWidth + nLeftM + nRightM;
5120 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = sal_True;
5122 // always do height
5123 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5124 false, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5125 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5127 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5129 // do width only if rotating within the cell (standard mode)
5130 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5131 sal_True, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5132 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5135 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5136 // (but width is only valid for standard mode)
5137 nRealWidth = (long) pEngine->CalcTextWidth();
5138 nRealHeight = pEngine->GetTextHeight();
5140 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5141 nEngineWidth = (long) ( nRealHeight / fabs( nSin ) );
5144 long nClipStartX = nStartX;
5145 if (nX<nX1)
5147 //! Clipping unnoetig, wenn links am Fenster
5149 bClip = sal_True; // nur Rest ausgeben!
5150 if (nStartX<nScrX)
5152 long nDif = nScrX - nStartX;
5153 nClipStartX = nScrX;
5154 aClipSize.Width() -= nDif;
5158 long nClipStartY = nStartY;
5159 if (nArrY==0 || bVisChanged)
5161 if ( nClipStartY < nRowPosY )
5163 long nDif = nRowPosY - nClipStartY;
5164 bClip = sal_True;
5165 nClipStartY = nRowPosY;
5166 aClipSize.Height() -= nDif;
5170 bClip = sal_True; // always clip at the window/page border
5172 //Rectangle aClipRect;
5173 if (bClip)
5175 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5177 // gedrehten, ausgerichteten Text nur an den
5178 // Seitengrenzen clippen
5179 nClipStartX = nScrX;
5180 aClipSize.Width() = nScrW;
5183 if (bPixelToLogic)
5184 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( Rectangle(
5185 Point(nClipStartX,nClipStartY), aClipSize ) );
5186 else
5187 aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY),
5188 aClipSize ); // Scale = 1
5190 if (bMetaFile)
5192 mpDev->Push();
5193 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
5195 else
5196 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
5199 Point aLogicStart;
5200 if (bPixelToLogic)
5201 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
5202 else
5203 aLogicStart = Point(nStartX, nStartY);
5204 if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak )
5206 long nAvailWidth = aCellSize.Width();
5207 if (eType==OUTTYPE_WINDOW &&
5208 eOrient!=SVX_ORIENTATION_STACKED &&
5209 pInfo && pInfo->bAutoFilter)
5211 // filter drop-down width is now independent from row height
5212 if (bPixelToLogic)
5213 nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height();
5214 else
5215 nAvailWidth -= DROPDOWN_BITMAP_SIZE;
5216 long nComp = nEngineWidth;
5217 if (nAvailWidth<nComp) nAvailWidth=nComp;
5220 // horizontale Ausrichtung
5222 if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate)
5224 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
5225 eHorJust==SVX_HOR_JUSTIFY_CENTER)
5227 pEngine->SetUpdateMode( false );
5229 SvxAdjust eSvxAdjust =
5230 (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ?
5231 SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER;
5232 pEngine->SetDefaultItem(
5233 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
5235 aPaperSize.Width() = nOutWidth;
5236 if (bPixelToLogic)
5237 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5238 else
5239 pEngine->SetPaperSize(aPaperSize);
5241 pEngine->SetUpdateMode( sal_True );
5244 else
5246 // bei gedrehtem Text ist Standard zentriert
5247 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
5248 aLogicStart.X() += nAvailWidth - nEngineWidth;
5249 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER ||
5250 eHorJust==SVX_HOR_JUSTIFY_STANDARD)
5251 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
5255 if ( bLayoutRTL )
5257 if (bPixelToLogic)
5258 aLogicStart.X() -= mpRefDevice->PixelToLogic(
5259 Size( nCellWidth, 0 ) ).Width();
5260 else
5261 aLogicStart.X() -= nCellWidth;
5264 if ( eOrient==SVX_ORIENTATION_STANDARD ||
5265 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
5267 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
5268 eVerJust==SVX_VER_JUSTIFY_STANDARD)
5270 if (bPixelToLogic)
5271 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,
5272 mpRefDevice->LogicToPixel(aCellSize).Height() -
5273 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
5274 )).Height();
5275 else
5276 aLogicStart.Y() += aCellSize.Height() - nEngineHeight;
5279 else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
5281 if (bPixelToLogic)
5282 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,(
5283 mpRefDevice->LogicToPixel(aCellSize).Height() -
5284 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
5285 / 2)).Height();
5286 else
5287 aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2;
5291 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
5292 OSL_ENSURE( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate,
5293 "DrawRotated: no rotation" );
5295 long nOriVal = 0;
5296 if ( nAttrRotate )
5298 // Attribut ist 1/100, Font 1/10 Grad
5299 nOriVal = nAttrRotate / 10;
5301 double nAddX = 0.0;
5302 double nAddY = 0.0;
5303 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
5305 //! begrenzen !!!
5306 double nH = nRealHeight * nCos;
5307 nAddX += nH * ( nCos / fabs(nSin) );
5309 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
5310 nAddX -= nRealWidth * nCos;
5311 if ( nSin < 0.0 )
5312 nAddX -= nRealHeight * nSin;
5313 if ( nSin > 0.0 )
5314 nAddY += nRealWidth * nSin;
5315 if ( nCos < 0.0 )
5316 nAddY -= nRealHeight * nCos;
5318 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5320 //! begrenzen !!!
5321 double nSkew = nTotalHeight * nCos / fabs(nSin);
5322 if ( eRotMode == SVX_ROTATE_MODE_CENTER )
5323 nAddX -= nSkew * 0.5;
5324 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
5325 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
5326 nAddX -= nSkew;
5328 long nUp = 0;
5329 if ( eVerJust == SVX_VER_JUSTIFY_CENTER )
5330 nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
5331 else if ( eVerJust == SVX_VER_JUSTIFY_TOP )
5333 if ( nSin > 0.0 )
5334 nUp = aCellSize.Height() - nEngineHeight;
5336 else // BOTTOM / STANDARD
5338 if ( nSin < 0.0 )
5339 nUp = aCellSize.Height() - nEngineHeight;
5341 if ( nUp )
5342 nAddX += ( nUp * nCos / fabs(nSin) );
5345 aLogicStart.X() += (long) nAddX;
5346 aLogicStart.Y() += (long) nAddY;
5349 // bSimClip is not used here (because nOriVal is set)
5351 if ( pEngine->IsRightToLeft( 0 ) )
5353 // For right-to-left, EditEngine always calculates its lines
5354 // beginning from the right edge, but EditLine::nStartPosX is
5355 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
5356 Size aLogicPaper = pEngine->GetPaperSize();
5357 if ( aLogicPaper.Width() > USHRT_MAX )
5359 aLogicPaper.Width() = USHRT_MAX;
5360 pEngine->SetPaperSize(aLogicPaper);
5364 pEngine->Draw( mpDev, aLogicStart, (short)nOriVal );
5366 if (bClip)
5368 if (bMetaFile)
5369 mpDev->Pop();
5370 else
5371 mpDev->SetClipRegion();
5377 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
5380 nRowPosY += pRowInfo[nArrY].nHeight;
5383 delete pEngine;
5388 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */