Bump version to 4.3-4
[LibreOffice.git] / sc / source / ui / view / output2.cxx
blob6a1bbf184b07d79f706d9f69f503936494e28b56
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>
46 #include <vcl/settings.hxx>
48 #include "output.hxx"
49 #include "document.hxx"
50 #include "formulacell.hxx"
51 #include "attrib.hxx"
52 #include "patattr.hxx"
53 #include "cellform.hxx"
54 #include "editutil.hxx"
55 #include "progress.hxx"
56 #include "scmod.hxx"
57 #include "fillinfo.hxx"
58 #include "viewdata.hxx"
59 #include "tabvwsh.hxx"
60 #include "docsh.hxx"
61 #include "markdata.hxx"
62 #include "stlsheet.hxx"
63 #include "spellcheckcontext.hxx"
64 #include <scopetools.hxx>
66 #include <com/sun/star/i18n/DirectionProperty.hpp>
67 #include <comphelper/string.hxx>
69 #include <boost/ptr_container/ptr_vector.hpp>
70 #include <boost/scoped_ptr.hpp>
72 #include <math.h>
74 using namespace com::sun::star;
76 //! Autofilter-Breite mit column.cxx zusammenfassen
77 #define DROPDOWN_BITMAP_SIZE 18
79 #define DRAWTEXT_MAX 32767
81 const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
83 // STATIC DATA -----------------------------------------------------------
86 class ScDrawStringsVars
88 ScOutputData* pOutput; // Verbindung
90 const ScPatternAttr* pPattern; // Attribute
91 const SfxItemSet* pCondSet; // aus bedingter Formatierung
93 Font aFont; // aus Attributen erzeugt
94 FontMetric aMetric;
95 long nAscentPixel; // always pixels
96 SvxCellOrientation eAttrOrient;
97 SvxCellHorJustify eAttrHorJust;
98 SvxCellVerJustify eAttrVerJust;
99 SvxCellJustifyMethod eAttrHorJustMethod;
100 SvxCellJustifyMethod eAttrVerJustMethod;
101 const SvxMarginItem* pMargin;
102 sal_uInt16 nIndent;
103 bool bRotated;
105 OUString aString; // contents
106 Size aTextSize;
107 long nOriginalWidth;
108 long nMaxDigitWidth;
109 long nSignWidth;
110 long nDotWidth;
111 long nExpWidth;
113 ScRefCellValue maLastCell;
114 sal_uLong nValueFormat;
115 bool bLineBreak;
116 bool bRepeat;
117 bool bShrink;
119 bool bPixelToLogic;
120 bool bCellContrast;
122 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
123 Color aTextConfigColor;
124 sal_Int32 nPos;
125 sal_Unicode nChar;
127 public:
128 ScDrawStringsVars(ScOutputData* pData, bool bPTL);
129 ~ScDrawStringsVars();
131 // SetPattern = ex-SetVars
132 // SetPatternSimple: ohne Font
134 void SetPattern(
135 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
136 sal_uInt8 nScript );
138 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
140 bool SetText( ScRefCellValue& rCell ); // TRUE -> pOldPattern vergessen
141 void SetHashText();
142 void SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth );
143 void SetAutoText( const OUString& rAutoText );
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 const SvxMarginItem* GetMargin() const { return pMargin; }
151 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
152 sal_uInt16 GetRightTotal() const { return pMargin->GetRightMargin() + nIndent; }
154 const OUString& GetString() const { return aString; }
155 const Size& GetTextSize() const { return aTextSize; }
156 long GetOriginalWidth() const { return nOriginalWidth; }
158 sal_uLong GetResultValueFormat() const;
160 sal_uLong GetValueFormat() const { return nValueFormat; }
161 bool GetLineBreak() const { return bLineBreak; }
162 bool IsRepeat() const { return bRepeat; }
163 bool IsShrink() const { return bShrink; }
164 void RepeatToFill( long colWidth );
166 long GetAscent() const { return nAscentPixel; }
167 bool IsRotated() const { return bRotated; }
169 void SetShrinkScale( long nScale, sal_uInt8 nScript );
171 bool HasCondHeight() const { return pCondSet && SFX_ITEM_SET ==
172 pCondSet->GetItemState( ATTR_FONT_HEIGHT, true ); }
174 bool HasEditCharacters() const;
176 private:
177 long GetMaxDigitWidth(); // in logic units
178 long GetSignWidth();
179 long GetDotWidth();
180 long GetExpWidth();
181 void TextChanged();
184 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, bool bPTL) :
185 pOutput ( pData ),
186 pPattern ( NULL ),
187 pCondSet ( NULL ),
188 nAscentPixel(0),
189 eAttrOrient ( SVX_ORIENTATION_STANDARD ),
190 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ),
191 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ),
192 eAttrHorJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
193 eAttrVerJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
194 pMargin ( NULL ),
195 nIndent ( 0 ),
196 bRotated ( false ),
197 nOriginalWidth( 0 ),
198 nMaxDigitWidth( 0 ),
199 nSignWidth( 0 ),
200 nDotWidth( 0 ),
201 nExpWidth( 0 ),
202 nValueFormat( 0 ),
203 bLineBreak ( false ),
204 bRepeat ( false ),
205 bShrink ( false ),
206 bPixelToLogic( bPTL ),
207 nPos( -1 ),
208 nChar( 0x0 )
210 ScModule* pScMod = SC_MOD();
211 bCellContrast = pOutput->mbUseStyleColor &&
212 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
214 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
215 aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor );
216 aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor );
219 ScDrawStringsVars::~ScDrawStringsVars()
223 void ScDrawStringsVars::SetShrinkScale( long nScale, sal_uInt8 nScript )
225 // text remains valid, size is updated
227 OutputDevice* pDev = pOutput->mpDev;
228 OutputDevice* pRefDevice = pOutput->mpRefDevice;
229 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
231 // call GetFont with a modified fraction, use only the height
233 Fraction aFraction( nScale, 100 );
234 if ( !bPixelToLogic )
235 aFraction *= pOutput->aZoomY;
236 Font aTmpFont;
237 pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
238 long nNewHeight = aTmpFont.GetHeight();
239 if ( nNewHeight > 0 )
240 aFont.SetHeight( nNewHeight );
242 // set font and dependent variables as in SetPattern
244 pDev->SetFont( aFont );
245 if ( pFmtDevice != pDev )
246 pFmtDevice->SetFont( aFont );
248 aMetric = pFmtDevice->GetFontMetric();
249 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
251 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
252 MapMode aOld = pDefaultDev->GetMapMode();
253 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
254 aMetric = pDefaultDev->GetFontMetric( aFont );
255 pDefaultDev->SetMapMode( aOld );
258 nAscentPixel = aMetric.GetAscent();
259 if ( bPixelToLogic )
260 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
262 SetAutoText( aString ); // same text again, to get text size
265 namespace {
267 template<typename _ItemType, typename _EnumType>
268 _EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
270 const _ItemType& rItem = static_cast<const _ItemType&>(rPattern.GetItem(nWhich, pCondSet));
271 return static_cast<_EnumType>(rItem.GetValue());
274 bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
276 return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
281 void ScDrawStringsVars::SetPattern(
282 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
283 sal_uInt8 nScript )
285 nMaxDigitWidth = 0;
286 nSignWidth = 0;
287 nDotWidth = 0;
288 nExpWidth = 0;
290 pPattern = pNew;
291 pCondSet = pSet;
293 // pPattern auswerten
295 OutputDevice* pDev = pOutput->mpDev;
296 OutputDevice* pRefDevice = pOutput->mpRefDevice;
297 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
299 // Font
301 ScAutoFontColorMode eColorMode;
302 if ( pOutput->mbUseStyleColor )
304 if ( pOutput->mbForceAutoColor )
305 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
306 else
307 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
309 else
310 eColorMode = SC_AUTOCOL_PRINT;
312 if ( bPixelToLogic )
313 pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript,
314 &aBackConfigColor, &aTextConfigColor );
315 else
316 pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
317 &aBackConfigColor, &aTextConfigColor );
318 aFont.SetAlign(ALIGN_BASELINE);
320 // Orientierung
322 eAttrOrient = pPattern->GetCellOrientation( pCondSet );
324 // alignment
326 eAttrHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
328 eAttrVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue();
329 if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD )
330 eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM;
332 // justification method
334 eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
335 eAttrVerJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet);
337 // line break
339 bLineBreak = ((const SfxBoolItem&)pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue();
341 // handle "repeat" alignment
343 bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT );
344 if ( bRepeat )
346 // "repeat" disables rotation (before constructing the font)
347 eAttrOrient = SVX_ORIENTATION_STANDARD;
349 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
350 if ( bLineBreak )
351 eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD;
354 short nRot;
355 switch (eAttrOrient)
357 case SVX_ORIENTATION_STANDARD:
358 nRot = 0;
359 bRotated = (((const SfxInt32Item&)pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0) &&
360 !bRepeat;
361 break;
362 case SVX_ORIENTATION_STACKED:
363 nRot = 0;
364 bRotated = false;
365 break;
366 case SVX_ORIENTATION_TOPBOTTOM:
367 nRot = 2700;
368 bRotated = false;
369 break;
370 case SVX_ORIENTATION_BOTTOMTOP:
371 nRot = 900;
372 bRotated = false;
373 break;
374 default:
375 OSL_FAIL("Falscher SvxCellOrientation Wert");
376 nRot = 0;
377 bRotated = false;
378 break;
380 aFont.SetOrientation( nRot );
382 // Syntax-Modus
384 if (pOutput->mbSyntaxMode)
385 pOutput->SetSyntaxColor(&aFont, rCell);
387 pDev->SetFont( aFont );
388 if ( pFmtDevice != pDev )
389 pFmtDevice->SetFont( aFont );
391 aMetric = pFmtDevice->GetFontMetric();
394 // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme
395 // -> Metric vom Bildschirm nehmen (wie EditEngine!)
398 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
400 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
401 MapMode aOld = pDefaultDev->GetMapMode();
402 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
403 aMetric = pDefaultDev->GetFontMetric( aFont );
404 pDefaultDev->SetMapMode( aOld );
407 nAscentPixel = aMetric.GetAscent();
408 if ( bPixelToLogic )
409 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
411 Color aULineColor( ((const SvxUnderlineItem&)pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() );
412 pDev->SetTextLineColor( aULineColor );
414 Color aOLineColor( ((const SvxOverlineItem&)pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() );
415 pDev->SetOverlineColor( aOLineColor );
417 // Zahlenformat
419 nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
421 // Raender
423 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
424 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT || eAttrHorJust == SVX_HOR_JUSTIFY_RIGHT )
425 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
426 else
427 nIndent = 0;
429 // "Shrink to fit"
431 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
433 // zumindest die Text-Groesse muss neu geholt werden
434 //! unterscheiden, und den Text nicht neu vom Numberformatter holen?
436 maLastCell.clear();
439 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
441 nMaxDigitWidth = 0;
442 nSignWidth = 0;
443 nDotWidth = 0;
444 nExpWidth = 0;
445 // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer)
447 pPattern = pNew;
448 pCondSet = pSet; //! noetig ???
450 // Zahlenformat
452 sal_uLong nOld = nValueFormat;
453 const SfxPoolItem* pFormItem;
454 if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,true,&pFormItem) != SFX_ITEM_SET )
455 pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT);
456 const SfxPoolItem* pLangItem;
457 if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,true,&pLangItem) != SFX_ITEM_SET )
458 pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT);
459 nValueFormat = pOutput->mpDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
460 ((SfxUInt32Item*)pFormItem)->GetValue(),
461 ((SvxLanguageItem*)pLangItem)->GetLanguage() );
463 if (nValueFormat != nOld)
464 maLastCell.clear(); // immer neu formatieren
466 // Raender
468 pMargin = (const SvxMarginItem*)&pPattern->GetItem( ATTR_MARGIN, pCondSet );
470 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
471 nIndent = ((const SfxUInt16Item&)pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
472 else
473 nIndent = 0;
475 // "Shrink to fit"
477 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
480 inline bool SameValue( const ScRefCellValue& rCell, const ScRefCellValue& rOldCell )
482 return rOldCell.meType == CELLTYPE_VALUE && rCell.meType == CELLTYPE_VALUE &&
483 rCell.mfValue == rOldCell.mfValue;
486 bool ScDrawStringsVars::SetText( ScRefCellValue& rCell )
488 bool bChanged = false;
490 if (!rCell.isEmpty())
492 if (!SameValue(rCell, maLastCell))
494 maLastCell = rCell; // Zelle merken
496 Color* pColor;
497 sal_uLong nFormat = GetValueFormat();
498 ScCellFormat::GetString( rCell,
499 nFormat, aString, &pColor,
500 *pOutput->mpDoc->GetFormatTable(),
501 pOutput->mpDoc,
502 pOutput->mbShowNullValues,
503 pOutput->mbShowFormulas,
504 ftCheck, true );
505 if ( nFormat )
507 nPos = aString.indexOf( 0x1B );
508 if ( nPos != -1 )
510 nChar = aString[ nPos + 1 ];
511 // delete placeholder and char to repeat
512 aString = aString.replaceAt( nPos, 2, "" );
515 else
517 nPos = -1;
518 nChar = 0x0;
520 if (aString.getLength() > DRAWTEXT_MAX)
521 aString = aString.copy(0, DRAWTEXT_MAX);
523 if ( pColor && !pOutput->mbSyntaxMode && !( pOutput->mbUseStyleColor && pOutput->mbForceAutoColor ) )
525 OutputDevice* pDev = pOutput->mpDev;
526 aFont.SetColor(*pColor);
527 pDev->SetFont( aFont ); // nur fuer Ausgabe
528 bChanged = true;
529 maLastCell.clear(); // naechstes Mal wieder hierherkommen
532 TextChanged();
534 // sonst String/Groesse behalten
536 else
538 aString = OUString();
539 maLastCell.clear();
540 aTextSize = Size(0,0);
541 nOriginalWidth = 0;
544 return bChanged;
547 void ScDrawStringsVars::SetHashText()
549 SetAutoText(OUString("###"));
552 void ScDrawStringsVars::RepeatToFill( long colWidth )
554 if ( nPos == -1 || nPos > aString.getLength() )
555 return;
557 long charWidth = pOutput->pFmtDevice->GetTextWidth(OUString(nChar));
558 if ( charWidth < 1) return;
559 if (bPixelToLogic)
560 colWidth = pOutput->mpRefDevice->PixelToLogic(Size(colWidth,0)).Width();
561 // Are there restrictions on the cell type we should filter out here ?
562 long aSpaceToFill = ( colWidth - aTextSize.Width() );
564 if ( aSpaceToFill <= charWidth )
565 return;
567 long nCharsToInsert = aSpaceToFill / charWidth;
568 OUStringBuffer aFill;
569 comphelper::string::padToLength(aFill, nCharsToInsert, nChar);
570 aString = aString.replaceAt( nPos, 0, aFill.makeStringAndClear() );
571 TextChanged();
574 void ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth )
576 // #i113045# do the single-character width calculations in logic units
577 if (bPixelToLogic)
578 nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
580 CellType eType = rCell.meType;
581 if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
582 // must be a value or formula cell.
583 return;
585 if (eType == CELLTYPE_FORMULA)
587 ScFormulaCell* pFCell = rCell.mpFormula;
588 if (pFCell->GetErrCode() != 0 || pOutput->mbShowFormulas)
590 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
591 return;
593 // If it's formula, the result must be a value.
594 if (!pFCell->IsValue())
595 return;
598 sal_uLong nFormat = GetResultValueFormat();
599 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
601 // Not 'General' number format. Set hash text and bail out.
602 SetHashText();
603 return;
606 double fVal = rCell.getValue();
608 const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
609 if (!pNumFormat)
610 return;
612 long nMaxDigit = GetMaxDigitWidth();
613 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
615 OUString sTempOut(aString);
616 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
618 aString = sTempOut;
619 // Failed to get output string. Bail out.
620 return;
622 aString = sTempOut;
624 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
625 sal_Int32 nLen = aString.getLength();
626 sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator[0];
627 for( sal_Int32 i = 0; i < nLen; ++i )
629 sal_Unicode c = aString[i];
630 if (c == '-')
631 ++nSignCount;
632 else if (c == cDecSep)
633 ++nDecimalCount;
634 else if (c == 'E')
635 ++nExpCount;
638 // #i112250# A small value might be formatted as "0" when only counting the digits,
639 // but fit into the column when considering the smaller width of the decimal separator.
640 if (aString == "0" && fVal != 0.0)
641 nDecimalCount = 1;
643 if (nDecimalCount)
644 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
645 if (nSignCount)
646 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
647 if (nExpCount)
648 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
650 if (nDecimalCount || nSignCount || nExpCount)
652 // Re-calculate.
653 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
654 OUString sTempOut(aString);
655 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
657 aString = sTempOut;
658 // Failed to get output string. Bail out.
659 return;
661 aString = sTempOut;
664 long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
665 if (nActualTextWidth > nWidth)
667 // Even after the decimal adjustment the text doesn't fit. Give up.
668 SetHashText();
669 return;
672 TextChanged();
673 maLastCell.clear(); // #i113022# equal cell and format in another column may give different string
676 void ScDrawStringsVars::SetAutoText( const OUString& rAutoText )
678 aString = rAutoText;
680 OutputDevice* pRefDevice = pOutput->mpRefDevice;
681 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
682 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
683 aTextSize.Height() = pFmtDevice->GetTextHeight();
685 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
687 double fMul = pOutput->GetStretch();
688 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
691 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
692 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
694 long nTemp = aTextSize.Height();
695 aTextSize.Height() = aTextSize.Width();
696 aTextSize.Width() = nTemp;
699 nOriginalWidth = aTextSize.Width();
700 if ( bPixelToLogic )
701 aTextSize = pRefDevice->LogicToPixel( aTextSize );
703 maLastCell.clear(); // derselbe Text kann in der naechsten Zelle wieder passen
706 long ScDrawStringsVars::GetMaxDigitWidth()
708 if (nMaxDigitWidth > 0)
709 return nMaxDigitWidth;
711 sal_Char cZero = '0';
712 for (sal_Char i = 0; i < 10; ++i)
714 sal_Char cDigit = cZero + i;
715 long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
716 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
718 return nMaxDigitWidth;
721 long ScDrawStringsVars::GetSignWidth()
723 if (nSignWidth > 0)
724 return nSignWidth;
726 nSignWidth = pOutput->pFmtDevice->GetTextWidth(OUString('-'));
727 return nSignWidth;
730 long ScDrawStringsVars::GetDotWidth()
732 if (nDotWidth > 0)
733 return nDotWidth;
735 const OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator;
736 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
737 return nDotWidth;
740 long ScDrawStringsVars::GetExpWidth()
742 if (nExpWidth > 0)
743 return nExpWidth;
745 nExpWidth = pOutput->pFmtDevice->GetTextWidth(OUString('E'));
746 return nExpWidth;
749 void ScDrawStringsVars::TextChanged()
751 OutputDevice* pRefDevice = pOutput->mpRefDevice;
752 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
753 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
754 aTextSize.Height() = pFmtDevice->GetTextHeight();
756 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
758 double fMul = pOutput->GetStretch();
759 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
762 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
763 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
765 long nTemp = aTextSize.Height();
766 aTextSize.Height() = aTextSize.Width();
767 aTextSize.Width() = nTemp;
770 nOriginalWidth = aTextSize.Width();
771 if ( bPixelToLogic )
772 aTextSize = pRefDevice->LogicToPixel( aTextSize );
775 bool ScDrawStringsVars::HasEditCharacters() const
777 for (sal_Int32 nIdx = 0; nIdx < aString.getLength(); ++nIdx)
779 switch(aString[nIdx])
781 case CHAR_NBSP:
782 case CHAR_SHY:
783 case CHAR_ZWSP:
784 case CHAR_LRM:
785 case CHAR_RLM:
786 case CHAR_NBHY:
787 case CHAR_ZWNBSP:
788 return true;
789 default:
790 break;
794 return false;
797 sal_uLong ScDrawStringsVars::GetResultValueFormat() const
799 // Get the effective number format, including formula result types.
800 // This assumes that a formula cell has already been calculated.
802 return nValueFormat;
805 double ScOutputData::GetStretch()
807 if ( mpRefDevice->IsMapMode() )
809 // If a non-trivial MapMode is set, its scale is now already
810 // taken into account in the OutputDevice's font handling
811 // (OutputDevice::ImplNewFont, see #95414#).
812 // The old handling below is only needed for pixel output.
813 return 1.0;
816 // calculation in double is faster than Fraction multiplication
817 // and doesn't overflow
819 if ( mpRefDevice == pFmtDevice )
821 MapMode aOld = mpRefDevice->GetMapMode();
822 return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX);
824 else
826 // when formatting for printer, device map mode has already been taken care of
827 return ((double)aZoomY) / ((double)aZoomX);
832 // output strings
835 static void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScRefCellValue& rCell )
837 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
839 OUString aCellText;
840 OUString aURL;
841 if (rCell.meType == CELLTYPE_FORMULA)
843 ScFormulaCell* pFCell = rCell.mpFormula;
844 if ( pFCell->IsHyperLinkCell() )
845 pFCell->GetURLResult( aURL, aCellText );
848 if ( !aURL.isEmpty() && pPDFData )
850 vcl::PDFExtOutDevBookmarkEntry aBookmark;
851 aBookmark.nLinkId = pPDFData->CreateLink( rRect );
852 aBookmark.aBookmark = aURL;
853 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
854 rBookmarks.push_back( aBookmark );
858 void ScOutputData::SetSyntaxColor( Font* pFont, const ScRefCellValue& rCell )
860 switch (rCell.meType)
862 case CELLTYPE_VALUE:
863 pFont->SetColor(*pValueColor);
864 break;
865 case CELLTYPE_STRING:
866 pFont->SetColor(*pTextColor);
867 break;
868 case CELLTYPE_FORMULA:
869 pFont->SetColor(*pFormulaColor);
870 break;
871 default:
873 // added to avoid warnings
878 static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
880 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
881 SfxItemSet aSet( rEngine.GetEmptyItemSet() );
882 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
883 rEngine.QuickSetAttribs( aSet, aSel );
884 // function is called with update mode set to FALSE
887 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScRefCellValue& rCell )
889 Color aColor;
890 switch (rCell.meType)
892 case CELLTYPE_VALUE:
893 aColor = *pValueColor;
894 break;
895 case CELLTYPE_STRING:
896 aColor = *pTextColor;
897 break;
898 case CELLTYPE_FORMULA:
899 aColor = *pFormulaColor;
900 break;
901 default:
903 // added to avoid warnings
906 lcl_SetEditColor( rEngine, aColor );
909 bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
910 SCCOL& rOverX, SCROW& rOverY,
911 bool bVisRowChanged )
913 bool bDoMerge = false;
914 bool bIsLeft = ( nX == nVisX1 );
915 bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
917 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
918 if ( pInfo->bHOverlapped && pInfo->bVOverlapped )
919 bDoMerge = bIsLeft && bIsTop;
920 else if ( pInfo->bHOverlapped )
921 bDoMerge = bIsLeft;
922 else if ( pInfo->bVOverlapped )
923 bDoMerge = bIsTop;
925 rOverX = nX;
926 rOverY = nY;
927 bool bHOver = pInfo->bHOverlapped;
928 bool bVOver = pInfo->bVOverlapped;
929 bool bHidden;
931 while (bHOver) // nY konstant
933 --rOverX;
934 bHidden = mpDoc->ColHidden(rOverX, nTab);
935 if ( !bDoMerge && !bHidden )
936 return false;
938 if (rOverX >= nX1 && !bHidden)
940 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
941 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
943 else
945 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
946 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
947 bHOver = ((nOverlap & SC_MF_HOR) != 0);
948 bVOver = ((nOverlap & SC_MF_VER) != 0);
952 while (bVOver)
954 --rOverY;
955 bHidden = mpDoc->RowHidden(rOverY, nTab);
956 if ( !bDoMerge && !bHidden )
957 return false;
959 if (nArrY>0)
960 --nArrY; // lokale Kopie !
962 if (rOverX >= nX1 && rOverY >= nY1 &&
963 !mpDoc->ColHidden(rOverX, nTab) &&
964 !mpDoc->RowHidden(rOverY, nTab) &&
965 pRowInfo[nArrY].nRowNo == rOverY)
967 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
968 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
970 else
972 sal_uInt16 nOverlap = ((ScMergeFlagAttr*)mpDoc->GetAttr(
973 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
974 bHOver = ((nOverlap & SC_MF_HOR) != 0);
975 bVOver = ((nOverlap & SC_MF_VER) != 0);
979 return true;
982 inline bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern )
984 OSL_ENSURE( rpNewPattern, "pNewPattern" );
986 if ( rpNewPattern == rpOldPattern )
987 return false;
988 else if ( !rpOldPattern )
989 return true;
990 else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
991 return true;
992 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
993 return true;
994 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
995 return true;
996 else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
997 return true;
998 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
999 return true;
1000 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
1001 return true;
1002 else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
1003 return true;
1004 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
1005 return true;
1006 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
1007 return true;
1008 else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
1009 return true;
1010 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
1011 return true;
1012 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
1013 return true;
1014 else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
1015 return true;
1016 else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
1017 return true;
1018 else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
1019 return true;
1020 else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
1021 return true;
1022 else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
1023 return true;
1024 else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
1025 return true;
1026 else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
1027 return true;
1028 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
1029 return true;
1030 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
1031 return true;
1032 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
1033 return true;
1034 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
1035 return true;
1036 else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
1037 return true;
1038 else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
1039 return true;
1040 else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
1041 return true;
1042 else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
1043 return true;
1044 else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
1045 return true;
1046 else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
1047 return true;
1048 else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
1049 return true;
1050 else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
1051 return true; // needed with automatic text color
1052 else
1054 rpOldPattern = rpNewPattern;
1055 return false;
1059 static inline void lcl_CreateInterpretProgress( bool& bProgress, ScDocument* pDoc,
1060 ScFormulaCell* pFCell )
1062 if ( !bProgress && pFCell->GetDirty() )
1064 ScProgress::CreateInterpretProgress( pDoc, true );
1065 bProgress = true;
1069 inline bool IsAmbiguousScript( sal_uInt8 nScript )
1071 return ( nScript != SCRIPTTYPE_LATIN &&
1072 nScript != SCRIPTTYPE_ASIAN &&
1073 nScript != SCRIPTTYPE_COMPLEX );
1076 bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1078 // pThisRowInfo may be NULL
1080 bool bEmpty;
1081 if ( pThisRowInfo && nX <= nX2 )
1082 bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText;
1083 else
1085 ScRefCellValue aCell;
1086 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1087 bEmpty = aCell.isEmpty();
1090 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1092 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1093 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1095 bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1097 if ( bIsPrint || bTabProtected )
1099 const ScProtectionAttr* pAttr = (const ScProtectionAttr*)
1100 mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
1101 if ( bIsPrint && pAttr->GetHidePrint() )
1102 bEmpty = true;
1103 else if ( bTabProtected )
1105 if ( pAttr->GetHideCell() )
1106 bEmpty = true;
1107 else if ( mbShowFormulas && pAttr->GetHideFormula() )
1109 if (mpDoc->GetCellType(ScAddress(nX, nY, nTab)) == CELLTYPE_FORMULA)
1110 bEmpty = true;
1115 return bEmpty;
1118 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScRefCellValue& rCell )
1120 rCell.assign(*mpDoc, ScAddress(nCol, nRow, nTabP));
1121 if (!rCell.isEmpty() && IsEmptyCellText(NULL, nCol, nRow))
1122 rCell.clear();
1125 bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
1127 // apply the same logic here as in DrawStrings/DrawEdit:
1128 // Stop at non-empty or merged or overlapped cell,
1129 // where a note is empty as well as a cell that's hidden by protection settings
1131 ScRefCellValue aCell;
1132 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1133 if (!aCell.isEmpty() && !IsEmptyCellText(NULL, nX, nY))
1134 return false;
1136 const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
1137 if ( ((const ScMergeAttr&)pPattern->GetItem(ATTR_MERGE)).IsMerged() ||
1138 ((const ScMergeFlagAttr&)pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() )
1140 return false;
1143 return true;
1146 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1147 // nPosX, nPosY: corresponding positions for nX, nArrY
1148 // nCellX, nCellY: position of the cell that contains the text
1149 // nNeeded: Text width, including margin
1150 // rPattern: cell format at nCellX, nCellY
1151 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1152 // bCellIsValue: if set, don't extend into empty cells
1153 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1154 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1155 // rParam output: various area parameters.
1157 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY,
1158 SCCOL nCellX, SCROW nCellY, long nNeeded,
1159 const ScPatternAttr& rPattern,
1160 sal_uInt16 nHorJustify, bool bCellIsValue,
1161 bool bBreak, bool bOverwrite,
1162 OutputAreaParam& rParam )
1164 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1165 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1167 long nLayoutSign = bLayoutRTL ? -1 : 1;
1169 long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
1170 SCCOL nCompCol = nX;
1171 while ( nCellX > nCompCol )
1173 //! extra member function for width?
1174 long nColWidth = ( nCompCol <= nX2 ) ?
1175 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1176 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1177 nCellPosX += nColWidth * nLayoutSign;
1178 ++nCompCol;
1180 while ( nCellX < nCompCol )
1182 --nCompCol;
1183 long nColWidth = ( nCompCol <= nX2 ) ?
1184 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1185 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1186 nCellPosX -= nColWidth * nLayoutSign;
1189 long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
1190 SCSIZE nCompArr = nArrY;
1191 SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1192 while ( nCellY > nCompRow )
1194 if ( nCompArr + 1 < nArrCount )
1196 nCellPosY += pRowInfo[nCompArr].nHeight;
1197 ++nCompArr;
1198 nCompRow = pRowInfo[nCompArr].nRowNo;
1200 else
1202 sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
1203 if ( nDocHeight )
1204 nCellPosY += (long) ( nDocHeight * mnPPTY );
1205 ++nCompRow;
1208 nCellPosY -= (long) mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
1210 const ScMergeAttr* pMerge = (const ScMergeAttr*)&rPattern.GetItem( ATTR_MERGE );
1211 bool bMerged = pMerge->IsMerged();
1212 long nMergeCols = pMerge->GetColMerge();
1213 if ( nMergeCols == 0 )
1214 nMergeCols = 1;
1215 long nMergeRows = pMerge->GetRowMerge();
1216 if ( nMergeRows == 0 )
1217 nMergeRows = 1;
1219 long nMergeSizeX = 0;
1220 for ( long i=0; i<nMergeCols; i++ )
1222 long nColWidth = ( nCellX+i <= nX2 ) ?
1223 pRowInfo[0].pCellInfo[nCellX+i+1].nWidth :
1224 (long) ( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
1225 nMergeSizeX += nColWidth;
1227 long nMergeSizeY = 0;
1228 short nDirect = 0;
1229 if ( rThisRowInfo.nRowNo == nCellY )
1231 // take first row's height from row info
1232 nMergeSizeY += rThisRowInfo.nHeight;
1233 nDirect = 1; // skip in loop
1235 // following rows always from document
1236 nMergeSizeY += (long) mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
1238 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
1240 rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1241 rParam.mnLeftClipLength = rParam.mnRightClipLength = 0;
1243 // construct the rectangles using logical left/right values (justify is called at the end)
1246 // rAlignRect is the single cell or merged area, used for alignment.
1248 rParam.maAlignRect.Left() = nCellPosX;
1249 rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign;
1250 rParam.maAlignRect.Top() = nCellPosY;
1251 rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1;
1253 // rClipRect is all cells that are used for output.
1254 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1256 rParam.maClipRect = rParam.maAlignRect;
1257 if ( nNeeded > nMergeSizeX )
1259 SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify;
1261 long nMissing = nNeeded - nMergeSizeX;
1262 long nLeftMissing = 0;
1263 long nRightMissing = 0;
1264 switch ( eHorJust )
1266 case SVX_HOR_JUSTIFY_LEFT:
1267 nRightMissing = nMissing;
1268 break;
1269 case SVX_HOR_JUSTIFY_RIGHT:
1270 nLeftMissing = nMissing;
1271 break;
1272 case SVX_HOR_JUSTIFY_CENTER:
1273 nLeftMissing = nMissing / 2;
1274 nRightMissing = nMissing - nLeftMissing;
1275 break;
1276 default:
1278 // added to avoid warnings
1282 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1283 if ( bLayoutRTL )
1284 ::std::swap( nLeftMissing, nRightMissing );
1286 SCCOL nRightX = nCellX;
1287 SCCOL nLeftX = nCellX;
1288 if ( !bMerged && !bCellIsValue && !bBreak )
1290 // look for empty cells into which the text can be extended
1292 while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1294 ++nRightX;
1295 long nAdd = (long) ( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
1296 nRightMissing -= nAdd;
1297 rParam.maClipRect.Right() += nAdd * nLayoutSign;
1299 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1300 rThisRowInfo.pCellInfo[nRightX].bHideGrid = true;
1303 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1305 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1306 rThisRowInfo.pCellInfo[nLeftX].bHideGrid = true;
1308 --nLeftX;
1309 long nAdd = (long) ( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
1310 nLeftMissing -= nAdd;
1311 rParam.maClipRect.Left() -= nAdd * nLayoutSign;
1315 // Set flag and reserve space for clipping mark triangle,
1316 // even if rThisRowInfo isn't for nCellY (merged cells).
1317 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1319 rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT;
1320 bAnyClipped = true;
1321 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1322 rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign;
1324 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1326 rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT;
1327 bAnyClipped = true;
1328 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1329 rParam.maClipRect.Left() += nMarkPixel * nLayoutSign;
1332 rParam.mbLeftClip = ( nLeftMissing > 0 );
1333 rParam.mbRightClip = ( nRightMissing > 0 );
1334 rParam.mnLeftClipLength = nLeftMissing;
1335 rParam.mnRightClipLength = nRightMissing;
1337 else
1339 rParam.mbLeftClip = rParam.mbRightClip = false;
1341 // leave space for AutoFilter on screen
1342 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1344 if ( eType==OUTTYPE_WINDOW &&
1345 ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & (SC_MF_AUTO|SC_MF_BUTTON|SC_MF_BUTTON_POPUP) ) &&
1346 ( !bBreak || mpRefDevice == pFmtDevice ) )
1348 // filter drop-down width is now independent from row height
1349 const long nFilter = DROPDOWN_BITMAP_SIZE;
1350 bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1351 if ( bFit || bCellIsValue )
1353 // content fits even in the remaining area without the filter button
1354 // -> align within that remaining area
1356 rParam.maAlignRect.Right() -= nFilter * nLayoutSign;
1357 rParam.maClipRect.Right() -= nFilter * nLayoutSign;
1359 // if a number doesn't fit, don't hide part of the number behind the button
1360 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1362 if ( !bFit )
1363 rParam.mbLeftClip = rParam.mbRightClip = true;
1368 // justify both rectangles for alignment calculation, use with DrawText etc.
1370 rParam.maAlignRect.Justify();
1371 rParam.maClipRect.Justify();
1374 namespace {
1376 bool beginsWithRTLCharacter(const OUString& rStr)
1378 if (rStr.isEmpty())
1379 return false;
1381 switch (ScGlobal::pCharClass->getCharacterDirection(rStr, 0))
1383 case i18n::DirectionProperty_RIGHT_TO_LEFT:
1384 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
1385 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
1386 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
1387 return true;
1388 default:
1392 return false;
1397 /** Get left, right or centered alignment from RTL context.
1399 Does not return standard, block or repeat, for these the contextual left or
1400 right alignment is returned.
1402 static SvxCellHorJustify getAlignmentFromContext( SvxCellHorJustify eInHorJust,
1403 bool bCellIsValue, const OUString& rText,
1404 const ScPatternAttr& rPattern, const SfxItemSet* pCondSet,
1405 const ScDocument* pDoc, SCTAB nTab )
1407 SvxCellHorJustify eHorJustContext = eInHorJust;
1408 bool bUseWritingDirection = false;
1409 if (eInHorJust == SVX_HOR_JUSTIFY_STANDARD)
1411 // fdo#32530: Default alignment depends on value vs
1412 // string, and the direction of the 1st letter.
1413 if (beginsWithRTLCharacter( rText))
1414 eHorJustContext = bCellIsValue ? SVX_HOR_JUSTIFY_LEFT : SVX_HOR_JUSTIFY_RIGHT;
1415 else if (bCellIsValue)
1416 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1417 else
1418 bUseWritingDirection = true;
1421 if (bUseWritingDirection ||
1422 eInHorJust == SVX_HOR_JUSTIFY_BLOCK || eInHorJust == SVX_HOR_JUSTIFY_REPEAT)
1424 sal_uInt16 nDirection = lcl_GetValue<SvxFrameDirectionItem, sal_uInt16>( rPattern, ATTR_WRITINGDIR, pCondSet);
1425 if (nDirection == FRMDIR_HORI_LEFT_TOP || nDirection == FRMDIR_VERT_TOP_LEFT)
1426 eHorJustContext = SVX_HOR_JUSTIFY_LEFT;
1427 else if (nDirection == FRMDIR_ENVIRONMENT)
1429 SAL_WARN_IF( !pDoc, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1430 // fdo#73588: The content of the cell must also
1431 // begin with a RTL character to be right
1432 // aligned; otherwise, it should be left aligned.
1433 eHorJustContext = (pDoc && pDoc->IsLayoutRTL(nTab) && (beginsWithRTLCharacter( rText))) ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
1435 else
1436 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1438 return eHorJustContext;
1441 void ScOutputData::DrawStrings( bool bPixelToLogic )
1443 OSL_ENSURE( mpDev == mpRefDevice ||
1444 mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
1445 "DrawStrings: unterschiedliche MapUnits ?!?!" );
1447 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
1449 sc::IdleSwitch aIdleSwitch(*mpDoc, false);
1450 ScDrawStringsVars aVars( this, bPixelToLogic );
1452 bool bProgress = false;
1454 long nInitPosX = nScrX;
1455 if ( bLayoutRTL )
1456 nInitPosX += nMirrorW - 1; // pixels
1457 long nLayoutSign = bLayoutRTL ? -1 : 1;
1459 SCCOL nLastContentCol = MAXCOL;
1460 if ( nX2 < MAXCOL )
1461 nLastContentCol = sal::static_int_cast<SCCOL>(
1462 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
1463 SCCOL nLoopStartX = nX1;
1464 if ( nX1 > 0 )
1465 --nLoopStartX; // start before nX1 for rest of long text to the left
1467 // variables for GetOutputArea
1468 OutputAreaParam aAreaParam;
1469 bool bCellIsValue = false;
1470 long nNeededWidth = 0;
1471 const ScPatternAttr* pPattern = NULL;
1472 const SfxItemSet* pCondSet = NULL;
1473 const ScPatternAttr* pOldPattern = NULL;
1474 const SfxItemSet* pOldCondSet = NULL;
1475 sal_uInt8 nOldScript = 0;
1477 // alternative pattern instances in case we need to modify the pattern
1478 // before processing the cell value.
1479 ::boost::ptr_vector<ScPatternAttr> aAltPatterns;
1481 std::vector<sal_Int32> aDX;
1482 long nPosY = nScrY;
1483 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1485 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1486 if ( pThisRowInfo->bChanged )
1488 SCROW nY = pThisRowInfo->nRowNo;
1489 long nPosX = nInitPosX;
1490 if ( nLoopStartX < nX1 )
1491 nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
1492 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1494 bool bMergeEmpty = false;
1495 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1496 bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
1498 SCCOL nCellX = nX; // position where the cell really starts
1499 SCROW nCellY = nY;
1500 bool bDoCell = false;
1501 bool bNeedEdit = false;
1504 // Part of a merged cell?
1507 bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
1508 if ( bOverlapped )
1510 bEmpty = true;
1512 SCCOL nOverX; // start of the merged cells
1513 SCROW nOverY;
1514 bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1515 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1517 nCellX = nOverX;
1518 nCellY = nOverY;
1519 bDoCell = true;
1521 else
1522 bMergeEmpty = true;
1526 // Rest of a long text further to the left?
1529 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1531 SCCOL nTempX=nX1;
1532 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1533 --nTempX;
1535 if ( nTempX < nX1 &&
1536 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1537 !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1539 nCellX = nTempX;
1540 bDoCell = true;
1545 // Rest of a long text further to the right?
1548 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1550 // don't have to look further than nLastContentCol
1552 SCCOL nTempX=nX;
1553 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1554 ++nTempX;
1556 if ( nTempX > nX &&
1557 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1558 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1560 nCellX = nTempX;
1561 bDoCell = true;
1566 // normal visible cell
1569 if (!bEmpty)
1570 bDoCell = true;
1573 // don't output the cell that's being edited
1576 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1577 bDoCell = false;
1579 // skip text in cell if data bar/icon set is set and only value selected
1580 if ( bDoCell )
1582 if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
1583 bDoCell = false;
1584 if(pInfo->pIconSet && !pInfo->pIconSet->mbShowValue)
1585 bDoCell = false;
1589 // output the cell text
1592 ScRefCellValue aCell;
1593 if (bDoCell)
1595 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1596 aCell = pThisRowInfo->pCellInfo[nCellX+1].maCell;
1597 else
1598 GetVisibleCell( nCellX, nCellY, nTab, aCell ); // get from document
1599 if (aCell.isEmpty())
1600 bDoCell = false;
1601 else if (aCell.meType == CELLTYPE_EDIT)
1602 bNeedEdit = true;
1605 // Check if this cell is mis-spelled.
1606 if (bDoCell && !bNeedEdit && aCell.meType == CELLTYPE_STRING)
1608 if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
1609 bNeedEdit = true;
1612 if (bDoCell && !bNeedEdit)
1614 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1616 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
1617 pPattern = rCellInfo.pPatternAttr;
1618 pCondSet = rCellInfo.pConditionSet;
1620 if ( !pPattern )
1622 // #i68085# pattern from cell info for hidden columns is null,
1623 // test for null is quicker than using column flags
1624 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1625 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1628 else // get from document
1630 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1631 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1633 if ( mpDoc->GetPreviewFont() || mpDoc->GetPreviewCellStyle() )
1635 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1636 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1637 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
1639 pAltPattern->SetStyleSheet(pPreviewStyle);
1641 else if ( SfxItemSet* pFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab ) )
1643 const SfxPoolItem* pItem;
1644 if ( pFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SFX_ITEM_SET )
1645 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1646 if ( pFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SFX_ITEM_SET )
1647 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1648 if ( pFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SFX_ITEM_SET )
1649 pAltPattern->GetItemSet().Put( (const SvxFontItem&)*pItem );
1651 pPattern = pAltPattern;
1654 if (aCell.hasNumeric() &&
1655 static_cast<const SfxBoolItem&>(
1656 pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue())
1658 // Disable line break when the cell content is numeric.
1659 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1660 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1661 SfxBoolItem aLineBreak(ATTR_LINEBREAK, false);
1662 pAltPattern->GetItemSet().Put(aLineBreak);
1663 pPattern = pAltPattern;
1666 sal_uInt8 nScript = mpDoc->GetCellScriptType(
1667 ScAddress(nCellX, nCellY, nTab),
1668 pPattern->GetNumberFormat(mpDoc->GetFormatTable(), pCondSet));
1670 if (nScript == 0)
1671 nScript = ScGlobal::GetDefaultScriptType();
1673 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1674 nScript != nOldScript || mbSyntaxMode )
1676 if ( StringDiffer(pOldPattern,pPattern) ||
1677 pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
1679 aVars.SetPattern(pPattern, pCondSet, aCell, nScript);
1681 else
1682 aVars.SetPatternSimple( pPattern, pCondSet );
1683 pOldPattern = pPattern;
1684 pOldCondSet = pCondSet;
1685 nOldScript = nScript;
1688 // use edit engine for rotated, stacked or mixed-script text
1689 if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED ||
1690 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1691 bNeedEdit = true;
1693 if (bDoCell && !bNeedEdit)
1695 bool bFormulaCell = (aCell.meType == CELLTYPE_FORMULA);
1696 if ( bFormulaCell )
1697 lcl_CreateInterpretProgress(bProgress, mpDoc, aCell.mpFormula);
1698 if ( aVars.SetText(aCell) )
1699 pOldPattern = NULL;
1700 bNeedEdit = aVars.HasEditCharacters() || (bFormulaCell && aCell.mpFormula->IsMultilineResult());
1702 long nTotalMargin = 0;
1703 SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD;
1704 if (bDoCell && !bNeedEdit)
1706 CellType eCellType = aCell.meType;
1707 bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1708 if ( eCellType == CELLTYPE_FORMULA )
1710 ScFormulaCell* pFCell = aCell.mpFormula;
1711 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1714 eOutHorJust = getAlignmentFromContext( aVars.GetHorJust(), bCellIsValue, aVars.GetString(),
1715 *pPattern, pCondSet, mpDoc, nTab);
1717 bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK );
1718 // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1719 if (bBreak && bCellIsValue && (aVars.GetResultValueFormat() % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1720 bBreak = false;
1722 bool bRepeat = aVars.IsRepeat() && !bBreak;
1723 bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1725 nTotalMargin =
1726 static_cast<long>(aVars.GetLeftTotal() * mnPPTX) +
1727 static_cast<long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
1729 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1731 // GetOutputArea gives justfied rectangles
1732 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1733 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1734 bCellIsValue || bRepeat || bShrink, bBreak, false,
1735 aAreaParam );
1737 aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
1738 if ( bShrink )
1740 if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD )
1742 // Only horizontal scaling is handled here.
1743 // DrawEdit is used to vertically scale 90 deg rotated text.
1744 bNeedEdit = true;
1746 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
1748 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1749 long nScaleSize = aVars.GetTextSize().Width(); // without margin
1751 if ( nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
1753 long nScale = ( nAvailable * 100 ) / nScaleSize;
1755 aVars.SetShrinkScale( nScale, nOldScript );
1756 long nNewSize = aVars.GetTextSize().Width();
1758 sal_uInt16 nShrinkAgain = 0;
1759 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1761 // If the text is still too large, reduce the scale again by 10%, until it fits,
1762 // at most 7 times (it's less than 50% of the calculated scale then).
1764 nScale = ( nScale * 9 ) / 10;
1765 aVars.SetShrinkScale( nScale, nOldScript );
1766 nNewSize = aVars.GetTextSize().Width();
1767 ++nShrinkAgain;
1769 // If even at half the size the font still isn't rendered smaller,
1770 // fall back to normal clipping (showing ### for numbers).
1771 if ( nNewSize <= nAvailable )
1772 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1774 pOldPattern = NULL;
1779 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1781 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1782 long nRepeatSize = aVars.GetTextSize().Width(); // without margin
1783 // When formatting for the printer, the text sizes don't always add up.
1784 // Round down (too few repetitions) rather than exceeding the cell size then:
1785 if ( pFmtDevice != mpRefDevice )
1786 ++nRepeatSize;
1787 if ( nRepeatSize > 0 )
1789 long nRepeatCount = nAvailable / nRepeatSize;
1790 if ( nRepeatCount > 1 )
1792 OUString aCellStr = aVars.GetString();
1793 OUString aRepeated = aCellStr;
1794 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1795 aRepeated += aCellStr;
1796 aVars.SetAutoText( aRepeated );
1801 // use edit engine if automatic line breaks are needed
1802 if ( bBreak )
1804 if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD )
1805 bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1806 else
1808 long nHeight = aVars.GetTextSize().Height() +
1809 (long)(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
1810 (long)(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
1811 bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1814 if (!bNeedEdit)
1816 bNeedEdit =
1817 aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK &&
1818 aVars.GetHorJustMethod() == SVX_JUSTIFY_METHOD_DISTRIBUTE;
1821 if (bNeedEdit)
1823 // mark the cell in CellInfo to be drawn in DrawEdit:
1824 // Cells to the left are marked directly, cells to the
1825 // right are handled by the flag for nX2
1826 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1827 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1828 pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = true;
1829 bDoCell = false; // don't draw here
1831 if ( bDoCell )
1833 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1835 if (mbShowFormulas)
1836 aVars.SetHashText();
1837 else
1838 // Adjust the decimals to fit the available column width.
1839 aVars.SetTextToWidthOrHash(aCell, aAreaParam.mnColWidth - nTotalMargin);
1841 nNeededWidth = aVars.GetTextSize().Width() +
1842 (long) ( aVars.GetLeftTotal() * mnPPTX ) +
1843 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1844 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1846 // Cell value is no longer clipped. Reset relevant parameters.
1847 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1848 aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
1851 // If the "###" replacement doesn't fit into the cells, no clip marks
1852 // are shown, as the "###" already denotes too little space.
1853 // The rectangles from the first GetOutputArea call remain valid.
1856 long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
1857 long nJustPosY = aAreaParam.maAlignRect.Top();
1858 long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1859 long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1861 bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1862 if ( aAreaParam.maClipRect.Left() < nScrX )
1864 aAreaParam.maClipRect.Left() = nScrX;
1865 aAreaParam.mbLeftClip = true;
1867 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
1869 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
1870 aAreaParam.mbRightClip = true;
1873 bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1874 bool bVClip = false;
1876 if ( aAreaParam.maClipRect.Top() < nScrY )
1878 aAreaParam.maClipRect.Top() = nScrY;
1879 bVClip = true;
1881 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
1883 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
1884 bVClip = true;
1888 // horizontalen Platz testen
1891 bool bRightAdjusted = false; // to correct text width calculation later
1892 bool bNeedEditEngine = false;
1893 if ( !bNeedEditEngine && !bOutside )
1895 switch (eOutHorJust)
1897 case SVX_HOR_JUSTIFY_LEFT:
1898 nJustPosX += (long) ( aVars.GetLeftTotal() * mnPPTX );
1899 break;
1900 case SVX_HOR_JUSTIFY_RIGHT:
1901 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1902 (long) ( aVars.GetRightTotal() * mnPPTX );
1903 bRightAdjusted = true;
1904 break;
1905 case SVX_HOR_JUSTIFY_CENTER:
1906 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1907 (long) ( aVars.GetLeftTotal() * mnPPTX ) -
1908 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
1909 break;
1910 default:
1912 // added to avoid warnings
1916 long nTestClipHeight = aVars.GetTextSize().Height();
1917 switch (aVars.GetVerJust())
1919 case SVX_VER_JUSTIFY_TOP:
1920 case SVX_VER_JUSTIFY_BLOCK:
1922 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1923 nJustPosY += nTop;
1924 nTestClipHeight += nTop;
1926 break;
1927 case SVX_VER_JUSTIFY_BOTTOM:
1929 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1930 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1931 nTestClipHeight += nBot;
1933 break;
1934 case SVX_VER_JUSTIFY_CENTER:
1936 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1937 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1938 nJustPosY += ( nOutHeight + nTop -
1939 aVars.GetTextSize().Height() - nBot ) / 2;
1940 nTestClipHeight += std::abs( nTop - nBot );
1942 break;
1943 default:
1945 // added to avoid warnings
1949 if ( nTestClipHeight > nOutHeight )
1951 // kein vertikales Clipping beim Drucken von Zellen mit
1952 // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung
1953 if ( eType != OUTTYPE_PRINTER ||
1954 ( mpDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
1955 ( aVars.HasCondHeight() ) )
1956 bVClip = true;
1959 if ( bHClip || bVClip )
1961 // nur die betroffene Dimension clippen,
1962 // damit bei nicht-proportionalem Resize nicht alle
1963 // rechtsbuendigen Zahlen abgeschnitten werden:
1965 if (!bHClip)
1967 aAreaParam.maClipRect.Left() = nScrX;
1968 aAreaParam.maClipRect.Right() = nScrX+nScrW;
1970 if (!bVClip)
1972 aAreaParam.maClipRect.Top() = nScrY;
1973 aAreaParam.maClipRect.Bottom() = nScrY+nScrH;
1976 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
1977 // so it can be modified here
1978 if (bPixelToLogic)
1979 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
1981 if (bMetaFile)
1983 mpDev->Push();
1984 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
1986 else
1987 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
1990 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
1992 switch (aVars.GetOrient())
1994 case SVX_ORIENTATION_STANDARD:
1995 nJustPosY += aVars.GetAscent();
1996 break;
1997 case SVX_ORIENTATION_TOPBOTTOM:
1998 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
1999 break;
2000 case SVX_ORIENTATION_BOTTOMTOP:
2001 nJustPosY += aVars.GetTextSize().Height();
2002 nJustPosX += aVars.GetAscent();
2003 break;
2004 default:
2006 // added to avoid warnings
2010 // When clipping, the visible part is now completely defined by the alignment,
2011 // there's no more special handling to show the right part of RTL text.
2013 Point aDrawTextPos( nJustPosX, nJustPosY );
2014 if ( bPixelToLogic )
2016 // undo text width adjustment in pixels
2017 if (bRightAdjusted)
2018 aDrawTextPos.X() += aVars.GetTextSize().Width();
2020 aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
2022 // redo text width adjustment in logic units
2023 if (bRightAdjusted)
2024 aDrawTextPos.X() -= aVars.GetOriginalWidth();
2027 // in Metafiles immer DrawTextArray, damit die Positionen mit
2028 // aufgezeichnet werden (fuer nicht-proportionales Resize):
2030 OUString aString = aVars.GetString();
2031 if (!aString.isEmpty())
2033 // If the string is clipped, make it shorter for
2034 // better performance since drawing by HarfBuzz is
2035 // quite expensive especiall for long string.
2037 OUString aShort = aString;
2039 double fVisibleRatio = 1.0;
2040 double fTextWidth = aVars.GetTextSize().Width();
2041 sal_Int32 nTextLen = aString.getLength();
2042 if (eOutHorJust == SVX_HOR_JUSTIFY_LEFT && aAreaParam.mnRightClipLength > 0)
2044 fVisibleRatio = (fTextWidth - aAreaParam.mnRightClipLength) / fTextWidth;
2045 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2047 // Only show the left-end segment.
2048 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2049 aShort = aShort.copy(0, nShortLen);
2052 else if (eOutHorJust == SVX_HOR_JUSTIFY_RIGHT && aAreaParam.mnLeftClipLength > 0)
2054 fVisibleRatio = (fTextWidth - aAreaParam.mnLeftClipLength) / fTextWidth;
2055 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2057 // Only show the right-end segment.
2058 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2059 aShort = aShort.copy(nTextLen-nShortLen);
2061 // Adjust the text position after shortening of the string.
2062 double fShortWidth = pFmtDevice->GetTextWidth(aShort);
2063 double fOffset = fTextWidth - fShortWidth;
2064 aDrawTextPos.Move(fOffset, 0);
2068 if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
2070 size_t nLen = aShort.getLength();
2071 if (aDX.size() < nLen)
2072 aDX.resize(nLen, 0);
2074 pFmtDevice->GetTextArray(aShort, &aDX[0]);
2076 if ( !mpRefDevice->GetConnectMetaFile() ||
2077 mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
2079 double fMul = GetStretch();
2080 for (size_t i = 0; i < nLen; ++i)
2081 aDX[i] = static_cast<sal_Int32>(aDX[i] / fMul + 0.5);
2084 mpDev->DrawTextArray(aDrawTextPos, aShort, &aDX[0]);
2086 else
2087 mpDev->DrawText(aDrawTextPos, aShort);
2090 if ( bHClip || bVClip )
2092 if (bMetaFile)
2093 mpDev->Pop();
2094 else
2095 mpDev->SetClipRegion();
2098 // PDF: whole-cell hyperlink from formula?
2099 bool bHasURL = pPDFData && aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->IsHyperLinkCell();
2100 if ( bHasURL )
2102 Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
2103 lcl_DoHyperlinkResult(mpDev, aURLRect, aCell);
2107 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2110 nPosY += pRowInfo[nArrY].nHeight;
2112 if ( bProgress )
2113 ScProgress::DeleteInterpretProgress();
2116 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine()
2118 ScFieldEditEngine* pEngine = new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool());
2119 pEngine->SetUpdateMode( false );
2120 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2121 pEngine->SetRefDevice( pFmtDevice );
2122 sal_uLong nCtrl = pEngine->GetControlWord();
2123 if ( bShowSpellErrors )
2124 nCtrl |= EE_CNTRL_ONLINESPELLING;
2125 if ( eType == OUTTYPE_PRINTER )
2126 nCtrl &= ~EE_CNTRL_MARKFIELDS;
2127 if ( eType == OUTTYPE_WINDOW && mpRefDevice == pFmtDevice )
2128 nCtrl &= ~EE_CNTRL_FORMAT100; // use the actual MapMode
2129 pEngine->SetControlWord( nCtrl );
2130 mpDoc->ApplyAsianEditSettings( *pEngine );
2131 pEngine->EnableAutoColor( mbUseStyleColor );
2132 pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)mpDoc->GetEditTextDirection( nTab ) );
2133 return pEngine;
2136 static void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute
2138 rEngine.SetUpdateMode( false );
2140 rEngine.SetText(EMPTY_OUSTRING);
2141 // keine Para-Attribute uebrigbehalten...
2142 const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
2143 if (rPara.Count())
2144 rEngine.SetParaAttribs( 0,
2145 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
2148 static bool lcl_SafeIsValue( ScRefCellValue& rCell )
2150 switch (rCell.meType)
2152 case CELLTYPE_VALUE:
2153 return true;
2154 case CELLTYPE_FORMULA:
2156 ScFormulaCell* pFCell = rCell.mpFormula;
2157 if (pFCell->IsRunning() || pFCell->IsValue())
2158 return true;
2160 break;
2161 default:
2163 // added to avoid warnings
2166 return false;
2169 static void lcl_ScaleFonts( EditEngine& rEngine, long nPercent )
2171 bool bUpdateMode = rEngine.GetUpdateMode();
2172 if ( bUpdateMode )
2173 rEngine.SetUpdateMode( false );
2175 sal_Int32 nParCount = rEngine.GetParagraphCount();
2176 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
2178 std::vector<sal_Int32> aPortions;
2179 rEngine.GetPortions( nPar, aPortions );
2181 sal_Int32 nStart = 0;
2182 for ( std::vector<sal_Int32>::const_iterator it(aPortions.begin()); it != aPortions.end(); ++it )
2184 sal_Int32 nEnd = *it;
2185 ESelection aSel( nPar, nStart, nPar, nEnd );
2186 SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
2188 long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight();
2189 long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight();
2190 long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight();
2192 nWestern = ( nWestern * nPercent ) / 100;
2193 nCJK = ( nCJK * nPercent ) / 100;
2194 nCTL = ( nCTL * nPercent ) / 100;
2196 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
2197 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
2198 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
2200 rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs?
2202 nStart = nEnd;
2206 if ( bUpdateMode )
2207 rEngine.SetUpdateMode( true );
2210 static long lcl_GetEditSize( EditEngine& rEngine, bool bWidth, bool bSwap, long nAttrRotate )
2212 if ( bSwap )
2213 bWidth = !bWidth;
2215 if ( nAttrRotate )
2217 long nRealWidth = (long) rEngine.CalcTextWidth();
2218 long nRealHeight = rEngine.GetTextHeight();
2220 // assuming standard mode, otherwise width isn't used
2222 double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees
2223 double nAbsCos = fabs( cos( nRealOrient ) );
2224 double nAbsSin = fabs( sin( nRealOrient ) );
2225 if ( bWidth )
2226 return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2227 else
2228 return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2230 else if ( bWidth )
2231 return (long) rEngine.CalcTextWidth();
2232 else
2233 return rEngine.GetTextHeight();
2237 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect,
2238 long nLeftM, long nTopM, long nRightM, long nBottomM,
2239 bool bWidth, sal_uInt16 nOrient, long nAttrRotate, bool bPixelToLogic,
2240 long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2242 if ( !bWidth )
2244 // vertical
2246 long nScaleSize = bPixelToLogic ?
2247 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2249 // Don't scale if it fits already.
2250 // Allowing to extend into the margin, to avoid scaling at optimal height.
2251 if ( nScaleSize <= rAlignRect.GetHeight() )
2252 return;
2254 bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP );
2255 long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2256 long nScale = ( nAvailable * 100 ) / nScaleSize;
2258 lcl_ScaleFonts( rEngine, nScale );
2259 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2260 long nNewSize = bPixelToLogic ?
2261 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2263 sal_uInt16 nShrinkAgain = 0;
2264 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2266 // further reduce, like in DrawStrings
2267 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2268 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2269 nNewSize = bPixelToLogic ?
2270 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2271 ++nShrinkAgain;
2274 // sizes for further processing (alignment etc):
2275 rEngineWidth = lcl_GetEditSize( rEngine, true, bSwap, nAttrRotate );
2276 long nPixelWidth = bPixelToLogic ?
2277 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2278 rNeededPixel = nPixelWidth + nLeftM + nRightM;
2280 else if ( rLeftClip || rRightClip )
2282 // horizontal
2284 long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2285 long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
2287 if ( nScaleSize <= nAvailable )
2288 return;
2290 long nScale = ( nAvailable * 100 ) / nScaleSize;
2292 lcl_ScaleFonts( rEngine, nScale );
2293 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2294 long nNewSize = bPixelToLogic ?
2295 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2297 sal_uInt16 nShrinkAgain = 0;
2298 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2300 // further reduce, like in DrawStrings
2301 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2302 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2303 nNewSize = bPixelToLogic ?
2304 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2305 ++nShrinkAgain;
2307 if ( nNewSize <= nAvailable )
2308 rLeftClip = rRightClip = false;
2310 // sizes for further processing (alignment etc):
2311 rNeededPixel = nNewSize + nLeftM + nRightM;
2312 rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
2316 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
2317 meHorJustAttr( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
2318 meHorJustContext( meHorJustAttr ),
2319 meHorJustResult( meHorJustAttr ),
2320 meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
2321 meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
2322 meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
2323 meOrient( pPattern->GetCellOrientation(pCondSet) ),
2324 mnArrY(0),
2325 mnX(0), mnY(0), mnCellX(0), mnCellY(0), mnTab(0),
2326 mnPosX(0), mnPosY(0), mnInitPosX(0),
2327 mbBreak( (meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
2328 mbCellIsValue(bCellIsValue),
2329 mbAsianVertical(false),
2330 mbPixelToLogic(false),
2331 mbHyphenatorSet(false),
2332 mpEngine(NULL),
2333 mpPattern(pPattern),
2334 mpCondSet(pCondSet),
2335 mpPreviewFontSet(NULL),
2336 mpOldPattern(NULL),
2337 mpOldCondSet(NULL),
2338 mpOldPreviewFontSet(NULL),
2339 mpThisRowInfo(NULL),
2340 mpMisspellRanges(NULL)
2343 bool ScOutputData::DrawEditParam::readCellContent(
2344 ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
2346 if (maCell.meType == CELLTYPE_EDIT)
2348 const EditTextObject* pData = maCell.mpEditText;
2349 if (pData)
2351 mpEngine->SetText(*pData);
2353 if ( mbBreak && !mbAsianVertical && pData->HasField() )
2355 // Fields aren't wrapped, so clipping is enabled to prevent
2356 // a field from being drawn beyond the cell size
2358 rWrapFields = true;
2361 else
2363 OSL_FAIL("pData == 0");
2364 return false;
2367 else
2369 sal_uLong nFormat = mpPattern->GetNumberFormat(
2370 pDoc->GetFormatTable(), mpCondSet );
2371 OUString aString;
2372 Color* pColor;
2373 ScCellFormat::GetString( maCell,
2374 nFormat,aString, &pColor,
2375 *pDoc->GetFormatTable(),
2376 pDoc,
2377 bShowNullValues,
2378 bShowFormulas,
2379 ftCheck );
2381 mpEngine->SetText(aString);
2382 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2383 lcl_SetEditColor( *mpEngine, *pColor );
2386 if (mpMisspellRanges)
2387 mpEngine->SetAllMisspellRanges(*mpMisspellRanges);
2389 return true;
2392 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
2394 // syntax highlighting mode is ignored here
2395 // StringDiffer doesn't look at hyphenate, language items
2397 if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
2398 return;
2400 sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2401 bool bCellContrast = bUseStyleColor &&
2402 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2404 SfxItemSet* pSet = new SfxItemSet( mpEngine->GetEmptyItemSet() );
2405 mpPattern->FillEditItemSet( pSet, mpCondSet );
2406 if ( mpPreviewFontSet )
2408 const SfxPoolItem* pItem;
2409 if ( mpPreviewFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SFX_ITEM_SET )
2411 SvxFontItem aFontItem(EE_CHAR_FONTINFO);
2412 aFontItem = (const SvxFontItem&)*pItem;
2413 pSet->Put( aFontItem );
2415 if ( mpPreviewFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SFX_ITEM_SET )
2417 SvxFontItem aCjkFontItem(EE_CHAR_FONTINFO_CJK);
2418 aCjkFontItem = (const SvxFontItem&)*pItem;
2419 pSet->Put( aCjkFontItem );
2421 if ( mpPreviewFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SFX_ITEM_SET )
2423 SvxFontItem aCtlFontItem(EE_CHAR_FONTINFO_CTL);
2424 aCtlFontItem = (const SvxFontItem&)*pItem;
2425 pSet->Put( aCtlFontItem );
2428 mpEngine->SetDefaults( pSet );
2429 mpOldPattern = mpPattern;
2430 mpOldCondSet = mpCondSet;
2431 mpOldPreviewFontSet = mpPreviewFontSet;
2433 sal_uLong nControl = mpEngine->GetControlWord();
2434 if (meOrient == SVX_ORIENTATION_STACKED)
2435 nControl |= EE_CNTRL_ONECHARPERLINE;
2436 else
2437 nControl &= ~EE_CNTRL_ONECHARPERLINE;
2438 mpEngine->SetControlWord( nControl );
2440 if ( !mbHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
2442 // set hyphenator the first time it is needed
2443 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2444 mpEngine->SetHyphenator( xXHyphenator );
2445 mbHyphenatorSet = true;
2448 Color aBackCol = ((const SvxBrushItem&)mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet )).GetColor();
2449 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
2450 aBackCol.SetColor( nConfBackColor );
2451 mpEngine->SetBackgroundColor( aBackCol );
2454 void ScOutputData::DrawEditParam::calcMargins(long& rTopM, long& rLeftM, long& rBottomM, long& rRightM, double nPPTX, double nPPTY) const
2456 const SvxMarginItem& rMargin =
2457 static_cast<const SvxMarginItem&>(mpPattern->GetItem(ATTR_MARGIN, mpCondSet));
2459 sal_uInt16 nIndent = 0;
2460 if (meHorJustAttr == SVX_HOR_JUSTIFY_LEFT || meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2461 nIndent = lcl_GetValue<SfxUInt16Item, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
2463 rLeftM = static_cast<long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
2464 rTopM = static_cast<long>((rMargin.GetTopMargin() * nPPTY));
2465 rRightM = static_cast<long>((rMargin.GetRightMargin() * nPPTX));
2466 rBottomM = static_cast<long>((rMargin.GetBottomMargin() * nPPTY));
2467 if(meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2469 rLeftM = static_cast<long>((rMargin.GetLeftMargin() * nPPTX));
2470 rRightM = static_cast<long>(((rMargin.GetRightMargin() + nIndent) * nPPTX));
2474 void ScOutputData::DrawEditParam::calcPaperSize(
2475 Size& rPaperSize, const Rectangle& rAlignRect, double nPPTX, double nPPTY) const
2477 long nTopM, nLeftM, nBottomM, nRightM;
2478 calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
2480 if (isVerticallyOriented())
2482 rPaperSize.Width() = rAlignRect.GetHeight() - nTopM - nBottomM;
2483 rPaperSize.Height() = rAlignRect.GetWidth() - nLeftM - nRightM;
2485 else
2487 rPaperSize.Width() = rAlignRect.GetWidth() - nLeftM - nRightM;
2488 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2491 if (mbAsianVertical)
2493 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2494 // Subtract some extra value from the height or else the text would go
2495 // outside the cell area. The value of 5 is arbitrary, and is based
2496 // entirely on heuristics.
2497 rPaperSize.Height() -= 5;
2501 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine* pEngine, long& rWidth, long& rHeight) const
2503 long nEngineWidth = 0;
2504 if (!mbBreak || meOrient == SVX_ORIENTATION_STACKED || mbAsianVertical)
2505 nEngineWidth = static_cast<long>(pEngine->CalcTextWidth());
2507 long nEngineHeight = pEngine->GetTextHeight();
2509 if (isVerticallyOriented())
2511 long nTemp = nEngineWidth;
2512 nEngineWidth = nEngineHeight;
2513 nEngineHeight = nTemp;
2516 if (meOrient == SVX_ORIENTATION_STACKED)
2517 nEngineWidth = nEngineWidth * 11 / 10;
2519 rWidth = nEngineWidth;
2520 rHeight = nEngineHeight;
2523 bool ScOutputData::DrawEditParam::hasLineBreak() const
2525 return (mbBreak || (meOrient == SVX_ORIENTATION_STACKED) || mbAsianVertical);
2528 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2530 if (maCell.meType != CELLTYPE_FORMULA)
2531 return false;
2533 return maCell.mpFormula->IsHyperLinkCell();
2536 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2538 return (meOrient == SVX_ORIENTATION_TOPBOTTOM || meOrient == SVX_ORIENTATION_BOTTOMTOP);
2541 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2542 Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice)
2544 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2546 if (mbPixelToLogic)
2547 rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
2549 if (mbBreak)
2551 // vertical adjustment is within the EditEngine
2552 if (mbPixelToLogic)
2553 rLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2554 else
2555 rLogicStart.Y() += nTopM;
2557 switch (meHorJustResult)
2559 case SVX_HOR_JUSTIFY_CENTER:
2560 rLogicStart.X() += (nCellWidth - nEngineWidth) / 2;
2561 break;
2562 case SVX_HOR_JUSTIFY_RIGHT:
2563 rLogicStart.X() += nCellWidth - nEngineWidth;
2564 break;
2565 default:
2566 ; // do nothing
2571 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2573 if (isVerticallyOriented() || mbAsianVertical)
2575 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2576 switch (meVerJust)
2578 case SVX_VER_JUSTIFY_TOP:
2579 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2580 SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT;
2581 break;
2582 case SVX_VER_JUSTIFY_CENTER:
2583 eSvxAdjust = SVX_ADJUST_CENTER;
2584 break;
2585 case SVX_VER_JUSTIFY_BOTTOM:
2586 case SVX_VER_JUSTIFY_STANDARD:
2587 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2588 SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2589 break;
2590 case SVX_VER_JUSTIFY_BLOCK:
2591 eSvxAdjust = SVX_ADJUST_BLOCK;
2592 break;
2595 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2596 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2598 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2599 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2601 else
2603 // horizontal alignment now may depend on cell content
2604 // (for values with number formats with mixed script types)
2605 // -> always set adjustment
2607 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2608 if (meOrient == SVX_ORIENTATION_STACKED)
2609 eSvxAdjust = SVX_ADJUST_CENTER;
2610 else if (mbBreak)
2612 if (meOrient == SVX_ORIENTATION_STANDARD)
2613 switch (meHorJustResult)
2615 case SVX_HOR_JUSTIFY_REPEAT: // repeat is not yet implemented
2616 case SVX_HOR_JUSTIFY_STANDARD:
2617 assert(!"meHorJustResult does not match getAlignmentFromContext()");
2618 // fallthru
2619 case SVX_HOR_JUSTIFY_LEFT:
2620 eSvxAdjust = SVX_ADJUST_LEFT;
2621 break;
2622 case SVX_HOR_JUSTIFY_CENTER:
2623 eSvxAdjust = SVX_ADJUST_CENTER;
2624 break;
2625 case SVX_HOR_JUSTIFY_RIGHT:
2626 eSvxAdjust = SVX_ADJUST_RIGHT;
2627 break;
2628 case SVX_HOR_JUSTIFY_BLOCK:
2629 eSvxAdjust = SVX_ADJUST_BLOCK;
2630 break;
2632 else
2633 switch (meVerJust)
2635 case SVX_VER_JUSTIFY_TOP:
2636 eSvxAdjust = SVX_ADJUST_RIGHT;
2637 break;
2638 case SVX_VER_JUSTIFY_CENTER:
2639 eSvxAdjust = SVX_ADJUST_CENTER;
2640 break;
2641 case SVX_VER_JUSTIFY_BOTTOM:
2642 case SVX_VER_JUSTIFY_STANDARD:
2643 eSvxAdjust = SVX_ADJUST_LEFT;
2644 break;
2645 case SVX_VER_JUSTIFY_BLOCK:
2646 eSvxAdjust = SVX_ADJUST_BLOCK;
2647 break;
2651 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2653 if (mbAsianVertical)
2655 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2656 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2657 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2659 else
2661 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
2662 if (meVerJust == SVX_VER_JUSTIFY_BLOCK)
2663 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2667 mpEngine->SetVertical(mbAsianVertical);
2668 if (maCell.meType == CELLTYPE_EDIT)
2670 // We need to synchronize the vertical mode in the EditTextObject
2671 // instance too. No idea why we keep this state in two separate
2672 // instances.
2673 const EditTextObject* pData = maCell.mpEditText;
2674 if (pData)
2675 const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
2679 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine)
2681 if (meHorJustResult == SVX_HOR_JUSTIFY_RIGHT || meHorJustResult == SVX_HOR_JUSTIFY_CENTER)
2683 SvxAdjust eEditAdjust = (meHorJustResult == SVX_HOR_JUSTIFY_CENTER) ?
2684 SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT;
2686 pEngine->SetUpdateMode(false);
2687 pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
2688 pEngine->SetUpdateMode(true);
2689 return true;
2691 return false;
2694 void ScOutputData::DrawEditParam::adjustForRTL()
2696 if (!mpEngine->IsRightToLeft(0))
2697 // No RTL mode.
2698 return;
2700 // For right-to-left, EditEngine always calculates its lines
2701 // beginning from the right edge, but EditLine::nStartPosX is
2702 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2703 Size aLogicPaper = mpEngine->GetPaperSize();
2704 if ( aLogicPaper.Width() > USHRT_MAX )
2706 aLogicPaper.Width() = USHRT_MAX;
2707 mpEngine->SetPaperSize(aLogicPaper);
2711 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev)
2713 // PDF: whole-cell hyperlink from formula?
2714 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2715 bool bHasURL = pPDFData && isHyperlinkCell();
2716 if (!bHasURL)
2717 return;
2719 long nURLWidth = (long) mpEngine->CalcTextWidth();
2720 long nURLHeight = mpEngine->GetTextHeight();
2721 if (mbBreak)
2723 Size aPaper = mpEngine->GetPaperSize();
2724 if ( mbAsianVertical )
2725 nURLHeight = aPaper.Height();
2726 else
2727 nURLWidth = aPaper.Width();
2729 if (isVerticallyOriented())
2730 std::swap( nURLWidth, nURLHeight );
2731 else if (mbAsianVertical)
2732 aURLStart.X() -= nURLWidth;
2734 Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2735 lcl_DoHyperlinkResult(pDev, aURLRect, maCell);
2738 void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
2740 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
2741 OSL_ASSERT(!rParam.mbAsianVertical);
2743 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
2745 bool bHidden = false;
2746 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
2747 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
2748 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
2750 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT )
2752 // ignore orientation/rotation if "repeat" is active
2753 rParam.meOrient = SVX_ORIENTATION_STANDARD;
2754 nAttrRotate = 0;
2756 // #i31843# "repeat" with "line breaks" is treated as default alignment
2757 // (but rotation is still disabled).
2758 // Default again leads to context dependent alignment instead of
2759 // SVX_HOR_JUSTIFY_STANDARD.
2760 if ( rParam.mbBreak )
2761 rParam.meHorJustResult = rParam.meHorJustContext;
2764 if (nAttrRotate)
2766 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2767 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2768 bHidden = true; // gedreht wird getrennt ausgegeben
2771 if (bHidden)
2772 return;
2774 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
2776 //! mirror margin values for RTL?
2777 //! move margin down to after final GetOutputArea call
2778 long nTopM, nLeftM, nBottomM, nRightM;
2779 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
2781 SCCOL nXForPos = rParam.mnX;
2782 if ( nXForPos < nX1 )
2784 nXForPos = nX1;
2785 rParam.mnPosX = rParam.mnInitPosX;
2787 SCSIZE nArrYForPos = rParam.mnArrY;
2788 if ( nArrYForPos < 1 )
2790 nArrYForPos = 1;
2791 rParam.mnPosY = nScrY;
2794 OutputAreaParam aAreaParam;
2797 // Initial page size - large for normal text, cell size for automatic line breaks
2800 Size aPaperSize = Size( 1000000, 1000000 );
2801 if (rParam.mbBreak)
2803 // call GetOutputArea with nNeeded=0, to get only the cell width
2805 //! handle nArrY == 0
2806 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
2807 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2808 rParam.mbCellIsValue, true, false, aAreaParam );
2810 //! special ScEditUtil handling if formatting for printer
2811 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
2813 if (rParam.mbPixelToLogic)
2815 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
2816 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
2818 // #i85342# screen display and formatting for printer,
2819 // use same GetEditArea call as in ScViewData::SetEditEngine
2821 Fraction aFract(1,1);
2822 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
2823 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
2824 aLogicSize.Width() = aUtilRect.GetWidth();
2826 rParam.mpEngine->SetPaperSize(aLogicSize);
2828 else
2829 rParam.mpEngine->SetPaperSize(aPaperSize);
2832 // Fill the EditEngine (cell attributes and text)
2835 // default alignment for asian vertical mode is top-right
2836 if ( rParam.mbAsianVertical && rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
2837 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
2839 rParam.setPatternToEngine(mbUseStyleColor);
2840 rParam.setAlignmentToEngine();
2842 // Read content from cell
2844 bool bWrapFields = false;
2845 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
2846 // Failed to read cell content. Bail out.
2847 return;
2849 if ( mbSyntaxMode )
2850 SetEditSyntaxColor(*rParam.mpEngine, rParam.maCell);
2851 else if ( mbUseStyleColor && mbForceAutoColor )
2852 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
2854 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
2857 // Get final output area using the calculated width
2860 long nEngineWidth, nEngineHeight;
2861 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
2863 long nNeededPixel = nEngineWidth;
2864 if (rParam.mbPixelToLogic)
2865 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2866 nNeededPixel += nLeftM + nRightM;
2868 if (!rParam.mbBreak || bShrink)
2870 // for break, the first GetOutputArea call is sufficient
2871 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
2872 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2873 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2875 if ( bShrink )
2877 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
2878 nLeftM, nTopM, nRightM, nBottomM, true,
2879 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
2880 nEngineWidth, nEngineHeight, nNeededPixel,
2881 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
2883 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
2885 // First check if twice the space for the formatted text is available
2886 // (otherwise just keep it unchanged).
2888 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
2889 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2890 if ( nAvailable >= 2 * nFormatted )
2892 // "repeat" is handled with unformatted text (for performance reasons)
2893 OUString aCellStr = rParam.mpEngine->GetText();
2894 rParam.mpEngine->SetText( aCellStr );
2896 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
2897 if (rParam.mbPixelToLogic)
2898 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
2899 if ( pFmtDevice != mpRefDevice )
2900 ++nRepeatSize;
2901 if ( nRepeatSize > 0 )
2903 long nRepeatCount = nAvailable / nRepeatSize;
2904 if ( nRepeatCount > 1 )
2906 OUString aRepeated = aCellStr;
2907 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
2908 aRepeated += aCellStr;
2909 rParam.mpEngine->SetText( aRepeated );
2911 nEngineHeight = rParam.mpEngine->GetTextHeight();
2912 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2913 if (rParam.mbPixelToLogic)
2914 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2915 else
2916 nNeededPixel = nEngineWidth;
2917 nNeededPixel += nLeftM + nRightM;
2923 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
2925 rParam.mpEngine->SetText(OUString("###"));
2926 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2927 if (rParam.mbPixelToLogic)
2928 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2929 else
2930 nNeededPixel = nEngineWidth;
2931 nNeededPixel += nLeftM + nRightM;
2933 // No clip marks if "###" doesn't fit (same as in DrawStrings)
2936 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
2938 aPaperSize.Width() = nNeededPixel + 1;
2939 if (rParam.mbPixelToLogic)
2940 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
2941 else
2942 rParam.mpEngine->SetPaperSize(aPaperSize);
2946 long nStartX = aAreaParam.maAlignRect.Left();
2947 long nStartY = aAreaParam.maAlignRect.Top();
2948 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
2949 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
2950 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2952 if (rParam.mbBreak)
2954 // text with automatic breaks is aligned only within the
2955 // edit engine's paper size, the output of the whole area
2956 // is always left-aligned
2958 nStartX += nLeftM;
2960 else
2962 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
2963 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
2964 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
2965 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
2966 else
2967 nStartX += nLeftM;
2970 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
2971 if (bOutside)
2972 return;
2974 if ( aAreaParam.maClipRect.Left() < nScrX )
2976 aAreaParam.maClipRect.Left() = nScrX;
2977 aAreaParam.mbLeftClip = true;
2979 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
2981 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
2982 aAreaParam.mbRightClip = true;
2985 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
2986 bool bSimClip = false;
2988 if ( bWrapFields )
2990 // Fields in a cell with automatic breaks: clip to cell width
2991 bClip = true;
2994 if ( aAreaParam.maClipRect.Top() < nScrY )
2996 aAreaParam.maClipRect.Top() = nScrY;
2997 bClip = true;
2999 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3001 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3002 bClip = true;
3005 Size aCellSize; // output area, excluding margins, in logical units
3006 if (rParam.mbPixelToLogic)
3007 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3008 else
3009 aCellSize = Size( nOutWidth, nOutHeight );
3011 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3013 const ScMergeAttr* pMerge =
3014 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
3015 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3017 // Don't clip for text height when printing rows with optimal height,
3018 // except when font size is from conditional formatting.
3019 //! Allow clipping when vertically merged?
3020 if ( eType != OUTTYPE_PRINTER ||
3021 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3022 ( rParam.mpCondSet && SFX_ITEM_SET ==
3023 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3024 bClip = true;
3025 else
3026 bSimClip = true;
3028 // Show clip marks if height is at least 5pt too small and
3029 // there are several lines of text.
3030 // Not for asian vertical text, because that would interfere
3031 // with the default right position of the text.
3032 // Only with automatic line breaks, to avoid having to find
3033 // the cells with the horizontal end of the text again.
3034 if ( nEngineHeight - aCellSize.Height() > 100 &&
3035 rParam.mbBreak && bMarkClipped &&
3036 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3038 CellInfo* pClipMarkCell = NULL;
3039 if ( bMerged )
3041 // anywhere in the merged area...
3042 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3043 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3045 else
3046 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3048 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3049 bAnyClipped = true;
3051 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
3052 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3053 aAreaParam.maClipRect.Right() -= nMarkPixel;
3057 Rectangle aLogicClip;
3058 if (bClip || bSimClip)
3060 // Clip marks are already handled in GetOutputArea
3062 if (rParam.mbPixelToLogic)
3063 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3064 else
3065 aLogicClip = aAreaParam.maClipRect;
3067 if (bClip) // bei bSimClip nur aClipRect initialisieren
3069 if (bMetaFile)
3071 mpDev->Push();
3072 mpDev->IntersectClipRegion( aLogicClip );
3074 else
3075 mpDev->SetClipRegion( Region( aLogicClip ) );
3079 Point aLogicStart;
3080 if (rParam.mbPixelToLogic)
3081 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
3082 else
3083 aLogicStart = Point(nStartX, nStartY);
3085 if (!rParam.mbBreak)
3087 // horizontal alignment
3088 if (rParam.adjustHorAlignment(rParam.mpEngine))
3089 // reset adjustment for the next cell
3090 rParam.mpOldPattern = NULL;
3093 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
3094 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
3096 //! if pRefDevice != pFmtDevice, keep heights in logic units,
3097 //! only converting margin?
3099 if (rParam.mbPixelToLogic)
3100 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
3101 mpRefDevice->LogicToPixel(aCellSize).Height() -
3102 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3103 )).Height();
3104 else
3105 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
3107 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
3109 if (rParam.mbPixelToLogic)
3110 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
3111 mpRefDevice->LogicToPixel(aCellSize).Height() -
3112 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
3113 / 2)).Height();
3114 else
3115 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
3117 else // top
3119 if (rParam.mbPixelToLogic)
3120 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3121 else
3122 aLogicStart.Y() += nTopM;
3125 Point aURLStart = aLogicStart; // copy before modifying for orientation
3127 rParam.adjustForRTL();
3129 // bMoveClipped handling has been replaced by complete alignment
3130 // handling (also extending to the left).
3132 if (bSimClip)
3134 // kein hartes Clipping, aber nur die betroffenen
3135 // Zeilen ausgeben
3137 Point aDocStart = aLogicClip.TopLeft();
3138 aDocStart -= aLogicStart;
3139 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
3141 else
3143 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
3146 if (bClip)
3148 if (bMetaFile)
3149 mpDev->Pop();
3150 else
3151 mpDev->SetClipRegion();
3154 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3157 void ScOutputData::ShowClipMarks( DrawEditParam& rParam, long nEngineHeight, const Size& aCellSize,
3158 bool bMerged, OutputAreaParam& aAreaParam)
3160 // Show clip marks if height is at least 5pt too small and
3161 // there are several lines of text.
3162 // Not for asian vertical text, because that would interfere
3163 // with the default right position of the text.
3164 // Only with automatic line breaks, to avoid having to find
3165 // the cells with the horizontal end of the text again.
3166 if ( nEngineHeight - aCellSize.Height() > 100 &&
3167 rParam.mbBreak && bMarkClipped &&
3168 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3170 CellInfo* pClipMarkCell = NULL;
3171 if ( bMerged )
3173 // anywhere in the merged area...
3174 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3175 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3177 else
3178 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3180 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3181 bAnyClipped = true;
3183 const long nMarkPixel = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTX );
3184 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3185 aAreaParam.maClipRect.Right() -= nMarkPixel;
3189 bool ScOutputData::Clip( DrawEditParam& rParam, const Size& aCellSize,
3190 OutputAreaParam& aAreaParam, long nEngineHeight,
3191 bool bWrapFields)
3193 if ( aAreaParam.maClipRect.Left() < nScrX )
3195 aAreaParam.maClipRect.Left() = nScrX;
3196 aAreaParam.mbLeftClip = true;
3198 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3200 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3201 aAreaParam.mbRightClip = true;
3204 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3205 bool bSimClip = false;
3207 if ( bWrapFields )
3209 // Fields in a cell with automatic breaks: clip to cell width
3210 bClip = true;
3213 if ( aAreaParam.maClipRect.Top() < nScrY )
3215 aAreaParam.maClipRect.Top() = nScrY;
3216 bClip = true;
3218 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3220 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3221 bClip = true;
3224 const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3225 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3227 const ScMergeAttr* pMerge =
3228 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
3229 const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3231 // Don't clip for text height when printing rows with optimal height,
3232 // except when font size is from conditional formatting.
3233 //! Allow clipping when vertically merged?
3234 if ( eType != OUTTYPE_PRINTER ||
3235 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3236 ( rParam.mpCondSet && SFX_ITEM_SET ==
3237 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3238 bClip = true;
3239 else
3240 bSimClip = true;
3242 ShowClipMarks( rParam, nEngineHeight, aCellSize, bMerged, aAreaParam);
3245 Rectangle aLogicClip;
3246 if (bClip || bSimClip)
3248 // Clip marks are already handled in GetOutputArea
3250 if (rParam.mbPixelToLogic)
3251 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3252 else
3253 aLogicClip = aAreaParam.maClipRect;
3255 if (bClip) // bei bSimClip nur aClipRect initialisieren
3257 if (bMetaFile)
3259 mpDev->Push();
3260 mpDev->IntersectClipRegion( aLogicClip );
3262 else
3263 mpDev->SetClipRegion( Region( aLogicClip ) );
3267 return bClip;
3270 void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
3272 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3274 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3275 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3277 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3279 //! mirror margin values for RTL?
3280 //! move margin down to after final GetOutputArea call
3281 long nTopM, nLeftM, nBottomM, nRightM;
3282 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3284 SCCOL nXForPos = rParam.mnX;
3285 if ( nXForPos < nX1 )
3287 nXForPos = nX1;
3288 rParam.mnPosX = rParam.mnInitPosX;
3290 SCSIZE nArrYForPos = rParam.mnArrY;
3291 if ( nArrYForPos < 1 )
3293 nArrYForPos = 1;
3294 rParam.mnPosY = nScrY;
3297 OutputAreaParam aAreaParam;
3300 // Initial page size - large for normal text, cell size for automatic line breaks
3303 Size aPaperSize = Size( 1000000, 1000000 );
3304 if (rParam.mbBreak)
3306 // call GetOutputArea with nNeeded=0, to get only the cell width
3308 //! handle nArrY == 0
3309 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3310 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3311 rParam.mbCellIsValue, true, false, aAreaParam );
3313 //! special ScEditUtil handling if formatting for printer
3314 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3316 if (rParam.mbPixelToLogic)
3318 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3319 rParam.mpEngine->SetPaperSize(aLogicSize);
3321 else
3322 rParam.mpEngine->SetPaperSize(aPaperSize);
3325 // Fill the EditEngine (cell attributes and text)
3328 rParam.setPatternToEngine(mbUseStyleColor);
3329 rParam.setAlignmentToEngine();
3331 // Read content from cell
3333 bool bWrapFields = false;
3334 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3335 // Failed to read cell content. Bail out.
3336 return;
3338 if ( mbSyntaxMode )
3339 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3340 else if ( mbUseStyleColor && mbForceAutoColor )
3341 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3343 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3346 // Get final output area using the calculated width
3349 long nEngineWidth, nEngineHeight;
3350 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3352 long nNeededPixel = nEngineWidth;
3353 if (rParam.mbPixelToLogic)
3354 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3355 nNeededPixel += nLeftM + nRightM;
3357 if (!rParam.mbBreak || bShrink)
3359 // for break, the first GetOutputArea call is sufficient
3360 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3361 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3362 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3364 if ( bShrink )
3366 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3367 nLeftM, nTopM, nRightM, nBottomM, false,
3368 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3369 nEngineWidth, nEngineHeight, nNeededPixel,
3370 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3372 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3374 // First check if twice the space for the formatted text is available
3375 // (otherwise just keep it unchanged).
3377 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3378 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3379 if ( nAvailable >= 2 * nFormatted )
3381 // "repeat" is handled with unformatted text (for performance reasons)
3382 OUString aCellStr = rParam.mpEngine->GetText();
3383 rParam.mpEngine->SetText( aCellStr );
3385 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3386 if (rParam.mbPixelToLogic)
3387 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3388 if ( pFmtDevice != mpRefDevice )
3389 ++nRepeatSize;
3390 if ( nRepeatSize > 0 )
3392 const long nRepeatCount = nAvailable / nRepeatSize;
3393 if ( nRepeatCount > 1 )
3395 OUString aRepeated = aCellStr;
3396 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3397 aRepeated += aCellStr;
3398 rParam.mpEngine->SetText( aRepeated );
3400 nEngineHeight = rParam.mpEngine->GetTextHeight();
3401 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3402 if (rParam.mbPixelToLogic)
3403 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3404 else
3405 nNeededPixel = nEngineWidth;
3406 nNeededPixel += nLeftM + nRightM;
3412 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3414 rParam.mpEngine->SetText(OUString("###"));
3415 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3416 if (rParam.mbPixelToLogic)
3417 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3418 else
3419 nNeededPixel = nEngineWidth;
3420 nNeededPixel += nLeftM + nRightM;
3422 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3426 long nStartX = aAreaParam.maAlignRect.Left();
3427 const long nStartY = aAreaParam.maAlignRect.Top();
3428 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3429 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3430 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3432 if (rParam.mbBreak)
3434 // text with automatic breaks is aligned only within the
3435 // edit engine's paper size, the output of the whole area
3436 // is always left-aligned
3438 nStartX += nLeftM;
3440 else
3442 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3443 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3444 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3445 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3446 else
3447 nStartX += nLeftM;
3450 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3451 if (bOutside)
3452 return;
3454 // output area, excluding margins, in logical units
3455 const Size& aCellSize = rParam.mbPixelToLogic
3456 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3457 : Size( nOutWidth, nOutHeight );
3459 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3461 Point aLogicStart(nStartX, nStartY);
3462 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3464 Point aURLStart = aLogicStart; // copy before modifying for orientation
3466 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak)
3468 Size aPSize = rParam.mpEngine->GetPaperSize();
3469 aPSize.Width() = aCellSize.Height();
3470 rParam.mpEngine->SetPaperSize(aPSize);
3471 aLogicStart.Y() +=
3472 rParam.mbBreak ? aPSize.Width() : nEngineHeight;
3474 else
3476 // Note that the "paper" is rotated 90 degrees to the left, so
3477 // paper's width is in vertical direction. Also, the whole text
3478 // is on a single line, as text wrap is not in effect.
3480 // Set the paper width to be the width of the text.
3481 Size aPSize = rParam.mpEngine->GetPaperSize();
3482 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3483 rParam.mpEngine->SetPaperSize(aPSize);
3485 long nGap = 0;
3486 long nTopOffset = 0;
3487 if (rParam.mbPixelToLogic)
3489 nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
3490 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3491 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3493 else
3495 nGap = aCellSize.Height() - aPSize.Width();
3496 nTopOffset = nTopM;
3499 // First, align text to bottom.
3500 aLogicStart.Y() += aCellSize.Height();
3501 aLogicStart.Y() += nTopOffset;
3503 switch (rParam.meVerJust)
3505 case SVX_VER_JUSTIFY_STANDARD:
3506 case SVX_VER_JUSTIFY_BOTTOM:
3507 // align to bottom (do nothing).
3508 break;
3509 case SVX_VER_JUSTIFY_CENTER:
3510 // center it.
3511 aLogicStart.Y() -= nGap / 2;
3512 break;
3513 case SVX_VER_JUSTIFY_BLOCK:
3514 case SVX_VER_JUSTIFY_TOP:
3515 // align to top
3516 aLogicStart.Y() -= nGap;
3517 default:
3522 rParam.adjustForRTL();
3523 rParam.mpEngine->Draw(mpDev, aLogicStart, 900);
3525 if (bClip)
3527 if (bMetaFile)
3528 mpDev->Pop();
3529 else
3530 mpDev->SetClipRegion();
3533 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3536 void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
3538 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3540 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3541 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3543 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3545 //! mirror margin values for RTL?
3546 //! move margin down to after final GetOutputArea call
3547 long nTopM, nLeftM, nBottomM, nRightM;
3548 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3550 SCCOL nXForPos = rParam.mnX;
3551 if ( nXForPos < nX1 )
3553 nXForPos = nX1;
3554 rParam.mnPosX = rParam.mnInitPosX;
3556 SCSIZE nArrYForPos = rParam.mnArrY;
3557 if ( nArrYForPos < 1 )
3559 nArrYForPos = 1;
3560 rParam.mnPosY = nScrY;
3563 OutputAreaParam aAreaParam;
3566 // Initial page size - large for normal text, cell size for automatic line breaks
3569 Size aPaperSize = Size( 1000000, 1000000 );
3570 if (rParam.hasLineBreak())
3572 // call GetOutputArea with nNeeded=0, to get only the cell width
3574 //! handle nArrY == 0
3575 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3576 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3577 rParam.mbCellIsValue, true, false, aAreaParam );
3579 //! special ScEditUtil handling if formatting for printer
3580 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3582 if (rParam.mbPixelToLogic)
3584 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3585 rParam.mpEngine->SetPaperSize(aLogicSize);
3587 else
3588 rParam.mpEngine->SetPaperSize(aPaperSize);
3591 // Fill the EditEngine (cell attributes and text)
3594 rParam.setPatternToEngine(mbUseStyleColor);
3595 rParam.setAlignmentToEngine();
3597 // Read content from cell
3599 bool bWrapFields = false;
3600 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3601 // Failed to read cell content. Bail out.
3602 return;
3604 if ( mbSyntaxMode )
3605 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3606 else if ( mbUseStyleColor && mbForceAutoColor )
3607 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3609 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3612 // Get final output area using the calculated width
3615 long nEngineWidth, nEngineHeight;
3616 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3618 long nNeededPixel = nEngineWidth;
3619 if (rParam.mbPixelToLogic)
3620 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3621 nNeededPixel += nLeftM + nRightM;
3623 if (!rParam.mbBreak || bShrink)
3625 // for break, the first GetOutputArea call is sufficient
3626 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3627 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3628 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3630 if ( bShrink )
3632 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3633 nLeftM, nTopM, nRightM, nBottomM, false,
3634 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3635 nEngineWidth, nEngineHeight, nNeededPixel,
3636 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3638 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3640 // First check if twice the space for the formatted text is available
3641 // (otherwise just keep it unchanged).
3643 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3644 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3645 if ( nAvailable >= 2 * nFormatted )
3647 // "repeat" is handled with unformatted text (for performance reasons)
3648 OUString aCellStr = rParam.mpEngine->GetText();
3649 rParam.mpEngine->SetText( aCellStr );
3651 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3652 if (rParam.mbPixelToLogic)
3653 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3654 if ( pFmtDevice != mpRefDevice )
3655 ++nRepeatSize;
3656 if ( nRepeatSize > 0 )
3658 const long nRepeatCount = nAvailable / nRepeatSize;
3659 if ( nRepeatCount > 1 )
3661 OUString aRepeated = aCellStr;
3662 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3663 aRepeated += aCellStr;
3664 rParam.mpEngine->SetText( aRepeated );
3666 nEngineHeight = rParam.mpEngine->GetTextHeight();
3667 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3668 if (rParam.mbPixelToLogic)
3669 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3670 else
3671 nNeededPixel = nEngineWidth;
3672 nNeededPixel += nLeftM + nRightM;
3678 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3680 rParam.mpEngine->SetText(OUString("###"));
3681 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3682 if (rParam.mbPixelToLogic)
3683 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3684 else
3685 nNeededPixel = nEngineWidth;
3686 nNeededPixel += nLeftM + nRightM;
3688 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3692 long nStartX = aAreaParam.maAlignRect.Left();
3693 const long nStartY = aAreaParam.maAlignRect.Top();
3694 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3695 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3696 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3698 if (rParam.mbBreak)
3700 // text with automatic breaks is aligned only within the
3701 // edit engine's paper size, the output of the whole area
3702 // is always left-aligned
3704 nStartX += nLeftM;
3705 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
3706 nStartX += aPaperSize.Height();
3708 else
3710 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3711 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3712 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3713 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3714 else
3715 nStartX += nLeftM;
3718 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3719 if (bOutside)
3720 return;
3722 // output area, excluding margins, in logical units
3723 const Size& aCellSize = rParam.mbPixelToLogic
3724 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3725 : Size( nOutWidth, nOutHeight );
3727 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3729 Point aLogicStart(nStartX, nStartY);
3730 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3732 Point aURLStart = aLogicStart; // copy before modifying for orientation
3734 if (rParam.meHorJustResult != SVX_HOR_JUSTIFY_BLOCK)
3736 aLogicStart.X() += nEngineWidth;
3737 if (!rParam.mbBreak)
3739 // Set the paper width to text size.
3740 Size aPSize = rParam.mpEngine->GetPaperSize();
3741 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3742 rParam.mpEngine->SetPaperSize(aPSize);
3744 long nGap = 0;
3745 long nTopOffset = 0; // offset by top margin
3746 if (rParam.mbPixelToLogic)
3748 nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
3749 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3750 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3752 else
3754 nGap = aPSize.Width() - aCellSize.Height();
3755 nTopOffset = nTopM;
3757 aLogicStart.Y() += nTopOffset;
3759 switch (rParam.meVerJust)
3761 case SVX_VER_JUSTIFY_STANDARD:
3762 case SVX_VER_JUSTIFY_BOTTOM:
3763 // align to bottom
3764 aLogicStart.Y() -= nGap;
3765 break;
3766 case SVX_VER_JUSTIFY_CENTER:
3767 // center it.
3768 aLogicStart.Y() -= nGap / 2;
3769 break;
3770 case SVX_VER_JUSTIFY_BLOCK:
3771 case SVX_VER_JUSTIFY_TOP:
3772 // align to top (do nothing)
3773 default:
3779 rParam.adjustForRTL();
3781 // bMoveClipped handling has been replaced by complete alignment
3782 // handling (also extending to the left).
3784 rParam.mpEngine->Draw(mpDev, aLogicStart, 2700);
3786 if (bClip)
3788 if (bMetaFile)
3789 mpDev->Pop();
3790 else
3791 mpDev->SetClipRegion();
3794 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3797 void ScOutputData::DrawEditStacked(DrawEditParam& rParam)
3799 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3800 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3802 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3803 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3805 rParam.mbAsianVertical =
3806 lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
3808 if ( rParam.mbAsianVertical )
3810 // in asian mode, use EditEngine::SetVertical instead of EE_CNTRL_ONECHARPERLINE
3811 rParam.meOrient = SVX_ORIENTATION_STANDARD;
3812 DrawEditAsianVertical(rParam);
3813 return;
3816 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3818 //! mirror margin values for RTL?
3819 //! move margin down to after final GetOutputArea call
3820 long nTopM, nLeftM, nBottomM, nRightM;
3821 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3823 SCCOL nXForPos = rParam.mnX;
3824 if ( nXForPos < nX1 )
3826 nXForPos = nX1;
3827 rParam.mnPosX = rParam.mnInitPosX;
3829 SCSIZE nArrYForPos = rParam.mnArrY;
3830 if ( nArrYForPos < 1 )
3832 nArrYForPos = 1;
3833 rParam.mnPosY = nScrY;
3836 OutputAreaParam aAreaParam;
3839 // Initial page size - large for normal text, cell size for automatic line breaks
3842 Size aPaperSize = Size( 1000000, 1000000 );
3843 // call GetOutputArea with nNeeded=0, to get only the cell width
3845 //! handle nArrY == 0
3846 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3847 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3848 rParam.mbCellIsValue, true, false, aAreaParam );
3850 //! special ScEditUtil handling if formatting for printer
3851 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3853 if (rParam.mbPixelToLogic)
3855 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3856 if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
3858 // #i85342# screen display and formatting for printer,
3859 // use same GetEditArea call as in ScViewData::SetEditEngine
3861 Fraction aFract(1,1);
3862 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
3863 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
3864 aLogicSize.Width() = aUtilRect.GetWidth();
3866 rParam.mpEngine->SetPaperSize(aLogicSize);
3868 else
3869 rParam.mpEngine->SetPaperSize(aPaperSize);
3872 // Fill the EditEngine (cell attributes and text)
3875 rParam.setPatternToEngine(mbUseStyleColor);
3876 rParam.setAlignmentToEngine();
3878 // Read content from cell
3880 bool bWrapFields = false;
3881 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3882 // Failed to read cell content. Bail out.
3883 return;
3885 if ( mbSyntaxMode )
3886 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3887 else if ( mbUseStyleColor && mbForceAutoColor )
3888 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3890 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3893 // Get final output area using the calculated width
3896 long nEngineWidth, nEngineHeight;
3897 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3899 long nNeededPixel = nEngineWidth;
3900 if (rParam.mbPixelToLogic)
3901 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3902 nNeededPixel += nLeftM + nRightM;
3904 if (bShrink)
3906 // for break, the first GetOutputArea call is sufficient
3907 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3908 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3909 true, false, false, aAreaParam );
3911 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3912 nLeftM, nTopM, nRightM, nBottomM, true,
3913 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3914 nEngineWidth, nEngineHeight, nNeededPixel,
3915 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3917 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3919 rParam.mpEngine->SetText(OUString("###"));
3920 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3921 if (rParam.mbPixelToLogic)
3922 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3923 else
3924 nNeededPixel = nEngineWidth;
3925 nNeededPixel += nLeftM + nRightM;
3927 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3930 if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT )
3932 aPaperSize.Width() = nNeededPixel + 1;
3933 if (rParam.mbPixelToLogic)
3934 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3935 else
3936 rParam.mpEngine->SetPaperSize(aPaperSize);
3940 long nStartX = aAreaParam.maAlignRect.Left();
3941 long nStartY = aAreaParam.maAlignRect.Top();
3942 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3943 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3944 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3946 if (rParam.mbBreak)
3948 // text with automatic breaks is aligned only within the
3949 // edit engine's paper size, the output of the whole area
3950 // is always left-aligned
3952 nStartX += nLeftM;
3954 else
3956 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3957 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3958 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3959 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3960 else
3961 nStartX += nLeftM;
3964 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3965 if (bOutside)
3966 return;
3968 if ( aAreaParam.maClipRect.Left() < nScrX )
3970 aAreaParam.maClipRect.Left() = nScrX;
3971 aAreaParam.mbLeftClip = true;
3973 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3975 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3976 aAreaParam.mbRightClip = true;
3979 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3980 bool bSimClip = false;
3982 if ( bWrapFields )
3984 // Fields in a cell with automatic breaks: clip to cell width
3985 bClip = true;
3988 if ( aAreaParam.maClipRect.Top() < nScrY )
3990 aAreaParam.maClipRect.Top() = nScrY;
3991 bClip = true;
3993 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3995 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3996 bClip = true;
3999 Size aCellSize; // output area, excluding margins, in logical units
4000 if (rParam.mbPixelToLogic)
4001 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4002 else
4003 aCellSize = Size( nOutWidth, nOutHeight );
4005 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4007 const ScMergeAttr* pMerge =
4008 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4009 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4011 // Don't clip for text height when printing rows with optimal height,
4012 // except when font size is from conditional formatting.
4013 //! Allow clipping when vertically merged?
4014 if ( eType != OUTTYPE_PRINTER ||
4015 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4016 ( rParam.mpCondSet && SFX_ITEM_SET ==
4017 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4018 bClip = true;
4019 else
4020 bSimClip = true;
4022 // Show clip marks if height is at least 5pt too small and
4023 // there are several lines of text.
4024 // Not for asian vertical text, because that would interfere
4025 // with the default right position of the text.
4026 // Only with automatic line breaks, to avoid having to find
4027 // the cells with the horizontal end of the text again.
4028 if ( nEngineHeight - aCellSize.Height() > 100 &&
4029 rParam.mbBreak && bMarkClipped &&
4030 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4032 CellInfo* pClipMarkCell = NULL;
4033 if ( bMerged )
4035 // anywhere in the merged area...
4036 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4037 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4039 else
4040 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4042 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4043 bAnyClipped = true;
4045 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4046 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4047 aAreaParam.maClipRect.Right() -= nMarkPixel;
4051 Rectangle aLogicClip;
4052 if (bClip || bSimClip)
4054 // Clip marks are already handled in GetOutputArea
4056 if (rParam.mbPixelToLogic)
4057 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4058 else
4059 aLogicClip = aAreaParam.maClipRect;
4061 if (bClip) // bei bSimClip nur aClipRect initialisieren
4063 if (bMetaFile)
4065 mpDev->Push();
4066 mpDev->IntersectClipRegion( aLogicClip );
4068 else
4069 mpDev->SetClipRegion( Region( aLogicClip ) );
4073 Point aLogicStart;
4074 if (rParam.mbPixelToLogic)
4075 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4076 else
4077 aLogicStart = Point(nStartX, nStartY);
4079 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
4080 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
4082 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4083 //! only converting margin?
4085 if (rParam.mbPixelToLogic)
4086 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
4087 mpRefDevice->LogicToPixel(aCellSize).Height() -
4088 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
4089 )).Height();
4090 else
4091 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
4093 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
4095 if (rParam.mbPixelToLogic)
4096 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
4097 mpRefDevice->LogicToPixel(aCellSize).Height() -
4098 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
4099 / 2)).Height();
4100 else
4101 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
4103 else // top
4105 if (rParam.mbPixelToLogic)
4106 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4107 else
4108 aLogicStart.Y() += nTopM;
4111 Point aURLStart = aLogicStart; // copy before modifying for orientation
4113 Size aPaperLogic = rParam.mpEngine->GetPaperSize();
4114 aPaperLogic.Width() = nEngineWidth;
4115 rParam.mpEngine->SetPaperSize(aPaperLogic);
4117 rParam.adjustForRTL();
4119 // bMoveClipped handling has been replaced by complete alignment
4120 // handling (also extending to the left).
4122 if (bSimClip)
4124 // kein hartes Clipping, aber nur die betroffenen
4125 // Zeilen ausgeben
4127 Point aDocStart = aLogicClip.TopLeft();
4128 aDocStart -= aLogicStart;
4129 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
4131 else
4133 rParam.mpEngine->Draw( mpDev, aLogicStart, 0 );
4136 if (bClip)
4138 if (bMetaFile)
4139 mpDev->Pop();
4140 else
4141 mpDev->SetClipRegion();
4144 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4147 void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam)
4149 // When in asian vertical orientation, the orientation value is STANDARD,
4150 // and the asian vertical boolean is true.
4151 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
4152 OSL_ASSERT(rParam.mbAsianVertical);
4153 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
4155 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
4157 bool bHidden = false;
4158 bool bShrink = !rParam.mbBreak && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
4159 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
4161 if (nAttrRotate)
4163 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
4164 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
4165 bHidden = true; // gedreht wird getrennt ausgegeben
4168 // default alignment for asian vertical mode is top-right
4169 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4170 * SVX_HOR_JUSTIFY_RIGHT really wanted? Seems this was done all the time,
4171 * also before context was introduced and everything was attr only. */
4172 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_STANDARD )
4173 rParam.meHorJustResult = rParam.meHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
4175 if (bHidden)
4176 return;
4178 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
4180 //! mirror margin values for RTL?
4181 //! move margin down to after final GetOutputArea call
4182 long nTopM, nLeftM, nBottomM, nRightM;
4183 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
4185 SCCOL nXForPos = rParam.mnX;
4186 if ( nXForPos < nX1 )
4188 nXForPos = nX1;
4189 rParam.mnPosX = rParam.mnInitPosX;
4191 SCSIZE nArrYForPos = rParam.mnArrY;
4192 if ( nArrYForPos < 1 )
4194 nArrYForPos = 1;
4195 rParam.mnPosY = nScrY;
4198 OutputAreaParam aAreaParam;
4201 // Initial page size - large for normal text, cell size for automatic line breaks
4204 Size aPaperSize = Size( 1000000, 1000000 );
4205 // call GetOutputArea with nNeeded=0, to get only the cell width
4207 //! handle nArrY == 0
4208 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
4209 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4210 rParam.mbCellIsValue, true, false, aAreaParam );
4212 //! special ScEditUtil handling if formatting for printer
4213 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
4215 if (rParam.mbPixelToLogic)
4217 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
4218 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
4220 // #i85342# screen display and formatting for printer,
4221 // use same GetEditArea call as in ScViewData::SetEditEngine
4223 Fraction aFract(1,1);
4224 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
4225 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
4226 aLogicSize.Width() = aUtilRect.GetWidth();
4228 rParam.mpEngine->SetPaperSize(aLogicSize);
4230 else
4231 rParam.mpEngine->SetPaperSize(aPaperSize);
4234 // Fill the EditEngine (cell attributes and text)
4237 // default alignment for asian vertical mode is top-right
4238 if ( rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
4239 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
4241 rParam.setPatternToEngine(mbUseStyleColor);
4242 rParam.setAlignmentToEngine();
4244 // Read content from cell
4246 bool bWrapFields = false;
4247 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
4248 // Failed to read cell content. Bail out.
4249 return;
4251 if ( mbSyntaxMode )
4252 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
4253 else if ( mbUseStyleColor && mbForceAutoColor )
4254 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
4256 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4259 // Get final output area using the calculated width
4262 long nEngineWidth, nEngineHeight;
4263 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
4265 long nNeededPixel = nEngineWidth;
4266 if (rParam.mbPixelToLogic)
4267 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
4268 nNeededPixel += nLeftM + nRightM;
4270 // for break, the first GetOutputArea call is sufficient
4271 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
4272 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4273 rParam.mbCellIsValue || bShrink, false, false, aAreaParam );
4275 if ( bShrink )
4277 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
4278 nLeftM, nTopM, nRightM, nBottomM, false,
4279 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
4280 nEngineWidth, nEngineHeight, nNeededPixel,
4281 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4284 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
4286 rParam.mpEngine->SetText(OUString("###"));
4287 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4288 if (rParam.mbPixelToLogic)
4289 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4290 else
4291 nNeededPixel = nEngineWidth;
4292 nNeededPixel += nLeftM + nRightM;
4294 // No clip marks if "###" doesn't fit (same as in DrawStrings)
4297 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
4299 aPaperSize.Width() = nNeededPixel + 1;
4300 if (rParam.mbPixelToLogic)
4301 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4302 else
4303 rParam.mpEngine->SetPaperSize(aPaperSize);
4306 long nStartX = aAreaParam.maAlignRect.Left();
4307 long nStartY = aAreaParam.maAlignRect.Top();
4308 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
4309 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
4310 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
4312 // text with automatic breaks is aligned only within the
4313 // edit engine's paper size, the output of the whole area
4314 // is always left-aligned
4316 nStartX += nLeftM;
4318 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4319 if (bOutside)
4320 return;
4322 if ( aAreaParam.maClipRect.Left() < nScrX )
4324 aAreaParam.maClipRect.Left() = nScrX;
4325 aAreaParam.mbLeftClip = true;
4327 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
4329 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
4330 aAreaParam.mbRightClip = true;
4333 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
4334 bool bSimClip = false;
4336 if ( bWrapFields )
4338 // Fields in a cell with automatic breaks: clip to cell width
4339 bClip = true;
4342 if ( aAreaParam.maClipRect.Top() < nScrY )
4344 aAreaParam.maClipRect.Top() = nScrY;
4345 bClip = true;
4347 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
4349 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
4350 bClip = true;
4353 Size aCellSize; // output area, excluding margins, in logical units
4354 if (rParam.mbPixelToLogic)
4355 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4356 else
4357 aCellSize = Size( nOutWidth, nOutHeight );
4359 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4361 const ScMergeAttr* pMerge =
4362 (ScMergeAttr*)&rParam.mpPattern->GetItem(ATTR_MERGE);
4363 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4365 // Don't clip for text height when printing rows with optimal height,
4366 // except when font size is from conditional formatting.
4367 //! Allow clipping when vertically merged?
4368 if ( eType != OUTTYPE_PRINTER ||
4369 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4370 ( rParam.mpCondSet && SFX_ITEM_SET ==
4371 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4372 bClip = true;
4373 else
4374 bSimClip = true;
4376 // Show clip marks if height is at least 5pt too small and
4377 // there are several lines of text.
4378 // Not for asian vertical text, because that would interfere
4379 // with the default right position of the text.
4380 // Only with automatic line breaks, to avoid having to find
4381 // the cells with the horizontal end of the text again.
4382 if ( nEngineHeight - aCellSize.Height() > 100 &&
4383 ( rParam.mbBreak || rParam.meOrient == SVX_ORIENTATION_STACKED ) &&
4384 !rParam.mbAsianVertical && bMarkClipped &&
4385 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4387 CellInfo* pClipMarkCell = NULL;
4388 if ( bMerged )
4390 // anywhere in the merged area...
4391 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4392 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4394 else
4395 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4397 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4398 bAnyClipped = true;
4400 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4401 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4402 aAreaParam.maClipRect.Right() -= nMarkPixel;
4406 Rectangle aLogicClip;
4407 if (bClip || bSimClip)
4409 // Clip marks are already handled in GetOutputArea
4411 if (rParam.mbPixelToLogic)
4412 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4413 else
4414 aLogicClip = aAreaParam.maClipRect;
4416 if (bClip) // bei bSimClip nur aClipRect initialisieren
4418 if (bMetaFile)
4420 mpDev->Push();
4421 mpDev->IntersectClipRegion( aLogicClip );
4423 else
4424 mpDev->SetClipRegion( Region( aLogicClip ) );
4428 Point aLogicStart;
4429 if (rParam.mbPixelToLogic)
4430 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4431 else
4432 aLogicStart = Point(nStartX, nStartY);
4434 long nAvailWidth = aCellSize.Width();
4435 // space for AutoFilter is already handled in GetOutputArea
4437 // horizontal alignment
4439 if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_RIGHT)
4440 aLogicStart.X() += nAvailWidth - nEngineWidth;
4441 else if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_CENTER)
4442 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
4444 // paper size is subtracted below
4445 aLogicStart.X() += nEngineWidth;
4447 // vertical adjustment is within the EditEngine
4448 if (rParam.mbPixelToLogic)
4449 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4450 else
4451 aLogicStart.Y() += nTopM;
4453 Point aURLStart = aLogicStart; // copy before modifying for orientation
4455 rParam.adjustForRTL();
4457 // bMoveClipped handling has been replaced by complete alignment
4458 // handling (also extending to the left).
4460 // with SetVertical, the start position is top left of
4461 // the whole output area, not the text itself
4462 aLogicStart.X() -= rParam.mpEngine->GetPaperSize().Width();
4464 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
4466 if (bClip)
4468 if (bMetaFile)
4469 mpDev->Pop();
4470 else
4471 mpDev->SetClipRegion();
4474 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4477 void ScOutputData::DrawEdit(bool bPixelToLogic)
4479 boost::scoped_ptr<ScFieldEditEngine> pEngine;
4480 bool bHyphenatorSet = false;
4481 const ScPatternAttr* pOldPattern = NULL;
4482 const SfxItemSet* pOldCondSet = NULL;
4483 const SfxItemSet* pOldPreviewFontSet = NULL;
4484 ScRefCellValue aCell;
4486 long nInitPosX = nScrX;
4487 if ( bLayoutRTL )
4489 nInitPosX += nMirrorW - 1;
4491 long nLayoutSign = bLayoutRTL ? -1 : 1;
4493 //! store nLastContentCol as member!
4494 SCCOL nLastContentCol = MAXCOL;
4495 if ( nX2 < MAXCOL )
4496 nLastContentCol = sal::static_int_cast<SCCOL>(
4497 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
4499 long nRowPosY = nScrY;
4500 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4502 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4504 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4506 if ( pThisRowInfo->bChanged || nArrY==0 )
4508 long nPosX = 0;
4509 for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen
4511 boost::scoped_ptr< ScPatternAttr > pPreviewPattr;
4512 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4514 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4515 if (pInfo->bEditEngine)
4517 SCROW nY = pThisRowInfo->nRowNo;
4519 SCCOL nCellX = nX; // position where the cell really starts
4520 SCROW nCellY = nY;
4521 bool bDoCell = false;
4523 long nPosY = nRowPosY;
4524 if ( nArrY == 0 )
4526 nPosY = nScrY;
4527 nY = pRowInfo[1].nRowNo;
4528 SCCOL nOverX; // start of the merged cells
4529 SCROW nOverY;
4530 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, true ))
4532 nCellX = nOverX;
4533 nCellY = nOverY;
4534 bDoCell = true;
4537 else if ( nX == nX2 && pThisRowInfo->pCellInfo[nX+1].maCell.isEmpty() )
4539 // Rest of a long text further to the right?
4541 SCCOL nTempX=nX;
4542 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
4543 ++nTempX;
4545 if ( nTempX > nX &&
4546 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
4547 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
4549 nCellX = nTempX;
4550 bDoCell = true;
4553 else
4555 bDoCell = true;
4558 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
4559 bDoCell = false;
4561 const ScPatternAttr* pPattern = NULL;
4562 const SfxItemSet* pCondSet = NULL;
4563 if (bDoCell)
4565 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
4566 !mpDoc->ColHidden(nCellX, nTab) )
4568 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
4569 pPattern = rCellInfo.pPatternAttr;
4570 pCondSet = rCellInfo.pConditionSet;
4571 aCell = rCellInfo.maCell;
4573 else // get from document
4575 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
4576 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
4577 GetVisibleCell( nCellX, nCellY, nTab, aCell );
4579 if (aCell.isEmpty())
4580 bDoCell = false;
4582 if (bDoCell)
4584 if ( mpDoc->GetPreviewCellStyle() )
4586 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
4588 pPreviewPattr.reset( new ScPatternAttr(*pPattern) );
4589 pPreviewPattr->SetStyleSheet(pPreviewStyle);
4590 pPattern = const_cast<ScPatternAttr*>(pPreviewPattr.get());
4593 SfxItemSet* pPreviewFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab );
4594 if (!pEngine)
4595 pEngine.reset(CreateOutputEditEngine());
4596 else
4597 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4599 // fdo#32530: Check if the first character is RTL.
4600 OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
4602 DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(aCell));
4603 aParam.meHorJustContext = getAlignmentFromContext( aParam.meHorJustAttr,
4604 aParam.mbCellIsValue, aStr, *pPattern, pCondSet, mpDoc, nTab);
4605 aParam.meHorJustResult = (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) ?
4606 SVX_HOR_JUSTIFY_BLOCK : aParam.meHorJustContext;
4607 aParam.mbPixelToLogic = bPixelToLogic;
4608 aParam.mbHyphenatorSet = bHyphenatorSet;
4609 aParam.mpEngine = pEngine.get();
4610 aParam.maCell = aCell;
4611 aParam.mnArrY = nArrY;
4612 aParam.mnX = nX;
4613 aParam.mnY = nY;
4614 aParam.mnCellX = nCellX;
4615 aParam.mnCellY = nCellY;
4616 aParam.mnTab = nTab;
4617 aParam.mnPosX = nPosX;
4618 aParam.mnPosY = nPosY;
4619 aParam.mnInitPosX = nInitPosX;
4620 aParam.mpPreviewFontSet = pPreviewFontSet;
4621 aParam.mpPreviewFontSet = pPreviewFontSet;
4622 aParam.mpOldPattern = pOldPattern;
4623 aParam.mpOldCondSet = pOldCondSet;
4624 aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
4625 aParam.mpThisRowInfo = pThisRowInfo;
4626 if (mpSpellCheckCxt)
4627 aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);
4629 if (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT)
4631 // ignore orientation/rotation if "repeat" is active
4632 aParam.meOrient = SVX_ORIENTATION_STANDARD;
4634 switch (aParam.meOrient)
4636 case SVX_ORIENTATION_BOTTOMTOP:
4637 DrawEditBottomTop(aParam);
4638 break;
4639 case SVX_ORIENTATION_TOPBOTTOM:
4640 DrawEditTopBottom(aParam);
4641 break;
4642 case SVX_ORIENTATION_STACKED:
4643 // this can be vertically stacked or asian vertical.
4644 DrawEditStacked(aParam);
4645 break;
4646 default:
4647 DrawEditStandard(aParam);
4650 // Retrieve parameters for next iteration.
4651 pOldPattern = aParam.mpOldPattern;
4652 pOldCondSet = aParam.mpOldCondSet;
4653 pOldPreviewFontSet = aParam.mpOldPreviewFontSet;
4654 bHyphenatorSet = aParam.mbHyphenatorSet;
4657 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
4660 nRowPosY += pRowInfo[nArrY].nHeight;
4663 pEngine.reset();
4665 if (bAnyRotated)
4666 DrawRotated(bPixelToLogic); //! von aussen rufen ?
4669 void ScOutputData::DrawRotated(bool bPixelToLogic)
4671 //! nRotMax speichern
4672 SCCOL nRotMax = nX2;
4673 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
4674 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
4675 nRotMax = pRowInfo[nRotY].nRotMaxCol;
4678 ScModule* pScMod = SC_MOD();
4679 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
4680 bool bCellContrast = mbUseStyleColor &&
4681 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4683 boost::scoped_ptr<ScFieldEditEngine> pEngine;
4684 bool bHyphenatorSet = false;
4685 const ScPatternAttr* pPattern;
4686 const SfxItemSet* pCondSet;
4687 const ScPatternAttr* pOldPattern = NULL;
4688 const SfxItemSet* pOldCondSet = NULL;
4689 ScRefCellValue aCell;
4691 long nInitPosX = nScrX;
4692 if ( bLayoutRTL )
4694 nInitPosX += nMirrorW - 1;
4696 long nLayoutSign = bLayoutRTL ? -1 : 1;
4698 long nRowPosY = nScrY;
4699 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4701 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4702 long nCellHeight = (long) pThisRowInfo->nHeight;
4703 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4705 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
4707 long nPosX = 0;
4708 for (SCCOL nX=0; nX<=nRotMax; nX++)
4710 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4712 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4713 if ( pInfo->nRotateDir != SC_ROTDIR_NONE )
4715 SCROW nY = pThisRowInfo->nRowNo;
4717 bool bHidden = false;
4718 if (bEditMode)
4719 if ( nX == nEditCol && nY == nEditRow )
4720 bHidden = true;
4722 if (!bHidden)
4724 if (!pEngine)
4725 pEngine.reset(CreateOutputEditEngine());
4726 else
4727 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4729 long nPosY = nRowPosY;
4730 bool bVisChanged = false;
4732 //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht!
4734 bool bFromDoc = false;
4735 pPattern = pInfo->pPatternAttr;
4736 pCondSet = pInfo->pConditionSet;
4737 if (!pPattern)
4739 pPattern = mpDoc->GetPattern( nX, nY, nTab );
4740 bFromDoc = true;
4742 aCell = pInfo->maCell;
4743 if (bFromDoc)
4744 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
4746 if (aCell.isEmpty() && nX>nX2)
4747 GetVisibleCell( nX, nY, nTab, aCell );
4749 if (aCell.isEmpty() || IsEmptyCellText(pThisRowInfo, nX, nY))
4750 bHidden = true; // nRotateDir is also set without a cell
4752 long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth;
4754 SvxCellHorJustify eHorJust = (SvxCellHorJustify)((const SvxHorJustifyItem&)
4755 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
4756 bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
4757 ((const SfxBoolItem&)pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
4758 bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
4759 bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
4760 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
4761 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
4763 const ScMergeAttr* pMerge =
4764 (ScMergeAttr*)&pPattern->GetItem(ATTR_MERGE);
4765 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4767 long nStartX = nPosX;
4768 long nStartY = nPosY;
4769 if (nX<nX1)
4771 if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged)
4772 bHidden = true;
4773 else
4775 nStartX = nInitPosX;
4776 SCCOL nCol = nX1;
4777 while (nCol > nX)
4779 --nCol;
4780 nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
4784 long nCellStartX = nStartX;
4786 // Ersatzdarstellung fuer zu kleinen Text weggelassen
4788 if (!bHidden)
4790 long nOutWidth = nCellWidth - 1;
4791 long nOutHeight = nCellHeight;
4793 if ( bMerged ) // Zusammengefasst
4795 SCCOL nCountX = pMerge->GetColMerge();
4796 for (SCCOL i=1; i<nCountX; i++)
4797 nOutWidth += (long) ( mpDoc->GetColWidth(nX+i,nTab) * mnPPTX );
4798 SCROW nCountY = pMerge->GetRowMerge();
4799 nOutHeight += (long) mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
4802 SvxCellVerJustify eVerJust = (SvxCellVerJustify)((const SvxVerJustifyItem&)
4803 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
4805 // Syntax-Modus wird hier ignoriert...
4807 // StringDiffer doesn't look at hyphenate, language items
4808 if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
4810 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
4811 pPattern->FillEditItemSet( pSet, pCondSet );
4813 // Ausrichtung fuer EditEngine
4814 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
4815 if (eOrient==SVX_ORIENTATION_STACKED)
4816 eSvxAdjust = SVX_ADJUST_CENTER;
4817 // Adjustment fuer bBreak ist hier weggelassen
4818 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
4820 pEngine->SetDefaults( pSet );
4821 pOldPattern = pPattern;
4822 pOldCondSet = pCondSet;
4824 sal_uLong nControl = pEngine->GetControlWord();
4825 if (eOrient==SVX_ORIENTATION_STACKED)
4826 nControl |= EE_CNTRL_ONECHARPERLINE;
4827 else
4828 nControl &= ~EE_CNTRL_ONECHARPERLINE;
4829 pEngine->SetControlWord( nControl );
4831 if ( !bHyphenatorSet && ((const SfxBoolItem&)pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
4833 // set hyphenator the first time it is needed
4834 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
4835 pEngine->SetHyphenator( xXHyphenator );
4836 bHyphenatorSet = true;
4839 Color aBackCol = ((const SvxBrushItem&)
4840 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
4841 if ( mbUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
4842 aBackCol.SetColor( nConfBackColor );
4843 pEngine->SetBackgroundColor( aBackCol );
4846 // Raender
4848 //! Position und Papersize auf EditUtil umstellen !!!
4850 const SvxMarginItem* pMargin = (const SvxMarginItem*)
4851 &pPattern->GetItem(ATTR_MARGIN, pCondSet);
4852 sal_uInt16 nIndent = 0;
4853 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
4854 nIndent = ((const SfxUInt16Item&)pPattern->
4855 GetItem(ATTR_INDENT, pCondSet)).GetValue();
4857 long nTotalHeight = nOutHeight; // ohne Rand abzuziehen
4858 if ( bPixelToLogic )
4859 nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
4861 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
4862 long nTopM = (long) ( pMargin->GetTopMargin() * mnPPTY );
4863 long nRightM = (long) ( pMargin->GetRightMargin() * mnPPTX );
4864 long nBottomM = (long) ( pMargin->GetBottomMargin() * mnPPTY );
4865 nStartX += nLeftM;
4866 nStartY += nTopM;
4867 nOutWidth -= nLeftM + nRightM;
4868 nOutHeight -= nTopM + nBottomM;
4870 // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen
4871 long nAttrRotate = 0;
4872 double nSin = 0.0;
4873 double nCos = 1.0;
4874 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
4875 if ( eOrient == SVX_ORIENTATION_STANDARD )
4877 nAttrRotate = ((const SfxInt32Item&)pPattern->
4878 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
4879 if ( nAttrRotate )
4881 eRotMode = (SvxRotateMode)((const SvxRotateModeItem&)
4882 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
4884 if ( nAttrRotate == 18000 )
4885 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
4887 if ( bLayoutRTL )
4888 nAttrRotate = -nAttrRotate;
4890 double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad
4891 nCos = cos( nRealOrient );
4892 nSin = sin( nRealOrient );
4896 Size aPaperSize = Size( 1000000, 1000000 );
4897 if (eOrient==SVX_ORIENTATION_STACKED)
4898 aPaperSize.Width() = nOutWidth; // zum Zentrieren
4899 else if (bBreak)
4901 if (nAttrRotate)
4903 //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl
4904 //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben
4905 //! werden koennen -> darum unbegrenzt, also kein Umbruch.
4906 //! Mit versetzten Zeilen waere das folgende richtig:
4907 aPaperSize.Width() = (long)(nOutHeight / fabs(nSin));
4909 else if (eOrient == SVX_ORIENTATION_STANDARD)
4910 aPaperSize.Width() = nOutWidth;
4911 else
4912 aPaperSize.Width() = nOutHeight - 1;
4914 if (bPixelToLogic)
4915 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4916 else
4917 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4919 // Daten aus Zelle lesen
4921 if (aCell.meType == CELLTYPE_EDIT)
4923 if (aCell.mpEditText)
4924 pEngine->SetText(*aCell.mpEditText);
4925 else
4927 OSL_FAIL("pData == 0");
4930 else
4932 sal_uLong nFormat = pPattern->GetNumberFormat(
4933 mpDoc->GetFormatTable(), pCondSet );
4934 OUString aString;
4935 Color* pColor;
4936 ScCellFormat::GetString( aCell,
4937 nFormat,aString, &pColor,
4938 *mpDoc->GetFormatTable(),
4939 mpDoc,
4940 mbShowNullValues,
4941 mbShowFormulas,
4942 ftCheck );
4944 pEngine->SetText(aString);
4945 if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
4946 lcl_SetEditColor( *pEngine, *pColor );
4949 if ( mbSyntaxMode )
4951 SetEditSyntaxColor(*pEngine, aCell);
4953 else if ( mbUseStyleColor && mbForceAutoColor )
4954 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine
4956 pEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4958 long nEngineWidth = (long) pEngine->CalcTextWidth();
4959 long nEngineHeight = pEngine->GetTextHeight();
4961 if (nAttrRotate && bBreak)
4963 double nAbsCos = fabs( nCos );
4964 double nAbsSin = fabs( nSin );
4966 // adjust witdh of papersize for height of text
4967 int nSteps = 5;
4968 while (nSteps > 0)
4970 // everything is in pixels
4971 long nEnginePixel = mpRefDevice->LogicToPixel(
4972 Size(0,nEngineHeight)).Height();
4973 long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2;
4974 long nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
4975 bool bFits = ( nNewWidth >= aPaperSize.Width() );
4976 if ( bFits )
4977 nSteps = 0;
4978 else
4980 if ( nNewWidth < 4 )
4982 // can't fit -> fall back to using half height
4983 nEffHeight = nOutHeight / 2;
4984 nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
4985 nSteps = 0;
4987 else
4988 --nSteps;
4990 // set paper width and get new text height
4991 aPaperSize.Width() = nNewWidth;
4992 if (bPixelToLogic)
4993 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4994 else
4995 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4996 //pEngine->QuickFormatDoc( sal_True );
4997 nEngineWidth = (long) pEngine->CalcTextWidth();
4998 nEngineHeight = pEngine->GetTextHeight();
5003 long nRealWidth = nEngineWidth;
5004 long nRealHeight = nEngineHeight;
5006 // wenn gedreht, Groesse anpassen
5007 if (nAttrRotate)
5009 double nAbsCos = fabs( nCos );
5010 double nAbsSin = fabs( nSin );
5012 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5013 nEngineWidth = (long) ( nRealWidth * nAbsCos +
5014 nRealHeight * nAbsSin );
5015 else
5016 nEngineWidth = (long) ( nRealHeight / nAbsSin );
5017 //! begrenzen !!!
5019 nEngineHeight = (long) ( nRealHeight * nAbsCos +
5020 nRealWidth * nAbsSin );
5023 if (!nAttrRotate) // hier nur gedrehter Text
5024 bHidden = true; //! vorher abfragen !!!
5026 //! weglassen, was nicht hereinragt
5028 if (!bHidden)
5030 bool bClip = false;
5031 Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
5033 // weiterschreiben
5035 Size aCellSize;
5036 if (bPixelToLogic)
5037 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
5038 else
5039 aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1
5041 long nGridWidth = nEngineWidth;
5042 bool bNegative = false;
5043 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5045 nGridWidth = aCellSize.Width() +
5046 std::abs((long) ( aCellSize.Height() * nCos / nSin ));
5047 bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT );
5048 if ( bLayoutRTL )
5049 bNegative = !bNegative;
5052 // use GetOutputArea to hide the grid
5053 // (clip region is done manually below)
5054 OutputAreaParam aAreaParam;
5056 SCCOL nCellX = nX;
5057 SCROW nCellY = nY;
5058 SvxCellHorJustify eOutHorJust = eHorJust;
5059 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5060 eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
5061 long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
5062 if ( bPixelToLogic )
5063 nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
5065 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
5066 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
5067 false, false, true, aAreaParam );
5069 if ( bShrink )
5071 long nPixelWidth = bPixelToLogic ?
5072 mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
5073 long nNeededPixel = nPixelWidth + nLeftM + nRightM;
5075 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = true;
5077 // always do height
5078 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5079 false, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5080 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5082 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5084 // do width only if rotating within the cell (standard mode)
5085 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5086 true, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5087 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5090 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5091 // (but width is only valid for standard mode)
5092 nRealWidth = (long) pEngine->CalcTextWidth();
5093 nRealHeight = pEngine->GetTextHeight();
5095 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5096 nEngineWidth = (long) ( nRealHeight / fabs( nSin ) );
5099 long nClipStartX = nStartX;
5100 if (nX<nX1)
5102 //! Clipping unnoetig, wenn links am Fenster
5104 bClip = true; // nur Rest ausgeben!
5105 if (nStartX<nScrX)
5107 long nDif = nScrX - nStartX;
5108 nClipStartX = nScrX;
5109 aClipSize.Width() -= nDif;
5113 long nClipStartY = nStartY;
5114 if (nArrY==0 || bVisChanged)
5116 if ( nClipStartY < nRowPosY )
5118 long nDif = nRowPosY - nClipStartY;
5119 bClip = true;
5120 nClipStartY = nRowPosY;
5121 aClipSize.Height() -= nDif;
5125 bClip = true; // always clip at the window/page border
5127 //Rectangle aClipRect;
5128 if (bClip)
5130 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5132 // gedrehten, ausgerichteten Text nur an den
5133 // Seitengrenzen clippen
5134 nClipStartX = nScrX;
5135 aClipSize.Width() = nScrW;
5138 if (bPixelToLogic)
5139 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( Rectangle(
5140 Point(nClipStartX,nClipStartY), aClipSize ) );
5141 else
5142 aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY),
5143 aClipSize ); // Scale = 1
5145 if (bMetaFile)
5147 mpDev->Push();
5148 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
5150 else
5151 mpDev->SetClipRegion( Region( aAreaParam.maClipRect ) );
5154 Point aLogicStart;
5155 if (bPixelToLogic)
5156 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
5157 else
5158 aLogicStart = Point(nStartX, nStartY);
5159 if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak )
5161 long nAvailWidth = aCellSize.Width();
5162 if (eType==OUTTYPE_WINDOW &&
5163 eOrient!=SVX_ORIENTATION_STACKED &&
5164 pInfo->bAutoFilter)
5166 // filter drop-down width is now independent from row height
5167 if (bPixelToLogic)
5168 nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height();
5169 else
5170 nAvailWidth -= DROPDOWN_BITMAP_SIZE;
5171 long nComp = nEngineWidth;
5172 if (nAvailWidth<nComp) nAvailWidth=nComp;
5175 // horizontale Ausrichtung
5177 if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate)
5179 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
5180 eHorJust==SVX_HOR_JUSTIFY_CENTER)
5182 pEngine->SetUpdateMode( false );
5184 SvxAdjust eSvxAdjust =
5185 (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ?
5186 SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER;
5187 pEngine->SetDefaultItem(
5188 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
5190 aPaperSize.Width() = nOutWidth;
5191 if (bPixelToLogic)
5192 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5193 else
5194 pEngine->SetPaperSize(aPaperSize);
5196 pEngine->SetUpdateMode( true );
5199 else
5201 // bei gedrehtem Text ist Standard zentriert
5202 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
5203 aLogicStart.X() += nAvailWidth - nEngineWidth;
5204 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER ||
5205 eHorJust==SVX_HOR_JUSTIFY_STANDARD)
5206 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
5210 if ( bLayoutRTL )
5212 if (bPixelToLogic)
5213 aLogicStart.X() -= mpRefDevice->PixelToLogic(
5214 Size( nCellWidth, 0 ) ).Width();
5215 else
5216 aLogicStart.X() -= nCellWidth;
5219 if ( eOrient==SVX_ORIENTATION_STANDARD ||
5220 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
5222 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
5223 eVerJust==SVX_VER_JUSTIFY_STANDARD)
5225 if (bPixelToLogic)
5226 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,
5227 mpRefDevice->LogicToPixel(aCellSize).Height() -
5228 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
5229 )).Height();
5230 else
5231 aLogicStart.Y() += aCellSize.Height() - nEngineHeight;
5234 else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
5236 if (bPixelToLogic)
5237 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,(
5238 mpRefDevice->LogicToPixel(aCellSize).Height() -
5239 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
5240 / 2)).Height();
5241 else
5242 aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2;
5246 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
5247 OSL_ENSURE( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate,
5248 "DrawRotated: no rotation" );
5250 long nOriVal = 0;
5251 if ( nAttrRotate )
5253 // Attribut ist 1/100, Font 1/10 Grad
5254 nOriVal = nAttrRotate / 10;
5256 double nAddX = 0.0;
5257 double nAddY = 0.0;
5258 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
5260 //! begrenzen !!!
5261 double nH = nRealHeight * nCos;
5262 nAddX += nH * ( nCos / fabs(nSin) );
5264 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
5265 nAddX -= nRealWidth * nCos;
5266 if ( nSin < 0.0 )
5267 nAddX -= nRealHeight * nSin;
5268 if ( nSin > 0.0 )
5269 nAddY += nRealWidth * nSin;
5270 if ( nCos < 0.0 )
5271 nAddY -= nRealHeight * nCos;
5273 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5275 //! begrenzen !!!
5276 double nSkew = nTotalHeight * nCos / fabs(nSin);
5277 if ( eRotMode == SVX_ROTATE_MODE_CENTER )
5278 nAddX -= nSkew * 0.5;
5279 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
5280 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
5281 nAddX -= nSkew;
5283 long nUp = 0;
5284 if ( eVerJust == SVX_VER_JUSTIFY_CENTER )
5285 nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
5286 else if ( eVerJust == SVX_VER_JUSTIFY_TOP )
5288 if ( nSin > 0.0 )
5289 nUp = aCellSize.Height() - nEngineHeight;
5291 else // BOTTOM / STANDARD
5293 if ( nSin < 0.0 )
5294 nUp = aCellSize.Height() - nEngineHeight;
5296 if ( nUp )
5297 nAddX += ( nUp * nCos / fabs(nSin) );
5300 aLogicStart.X() += (long) nAddX;
5301 aLogicStart.Y() += (long) nAddY;
5304 // bSimClip is not used here (because nOriVal is set)
5306 if ( pEngine->IsRightToLeft( 0 ) )
5308 // For right-to-left, EditEngine always calculates its lines
5309 // beginning from the right edge, but EditLine::nStartPosX is
5310 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
5311 Size aLogicPaper = pEngine->GetPaperSize();
5312 if ( aLogicPaper.Width() > USHRT_MAX )
5314 aLogicPaper.Width() = USHRT_MAX;
5315 pEngine->SetPaperSize(aLogicPaper);
5319 pEngine->Draw( mpDev, aLogicStart, (short)nOriVal );
5321 if (bClip)
5323 if (bMetaFile)
5324 mpDev->Pop();
5325 else
5326 mpDev->SetClipRegion();
5332 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
5335 nRowPosY += pRowInfo[nArrY].nHeight;
5339 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */