fix baseline build (old cairo) - 'cairo_rectangle_int_t' does not name a type
[LibreOffice.git] / sc / source / ui / view / output2.cxx
blob7368322336792dec9381245c540f95fe704bd5d2
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 -----------------------------------------------------------
85 class ScDrawStringsVars
87 ScOutputData* pOutput; // Verbindung
89 const ScPatternAttr* pPattern; // Attribute
90 const SfxItemSet* pCondSet; // aus bedingter Formatierung
92 vcl::Font aFont; // aus Attributen erzeugt
93 FontMetric aMetric;
94 long nAscentPixel; // always pixels
95 SvxCellOrientation eAttrOrient;
96 SvxCellHorJustify eAttrHorJust;
97 SvxCellVerJustify eAttrVerJust;
98 SvxCellJustifyMethod eAttrHorJustMethod;
99 SvxCellJustifyMethod eAttrVerJustMethod;
100 const SvxMarginItem* pMargin;
101 sal_uInt16 nIndent;
102 bool bRotated;
104 OUString aString; // contents
105 Size aTextSize;
106 long nOriginalWidth;
107 long nMaxDigitWidth;
108 long nSignWidth;
109 long nDotWidth;
110 long nExpWidth;
112 ScRefCellValue maLastCell;
113 sal_uLong nValueFormat;
114 bool bLineBreak;
115 bool bRepeat;
116 bool bShrink;
118 bool bPixelToLogic;
119 bool bCellContrast;
121 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
122 Color aTextConfigColor;
123 sal_Int32 nPos;
124 sal_Unicode nChar;
126 public:
127 ScDrawStringsVars(ScOutputData* pData, bool bPTL);
128 ~ScDrawStringsVars();
130 // SetPattern = ex-SetVars
131 // SetPatternSimple: ohne Font
133 void SetPattern(
134 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
135 SvtScriptType nScript );
137 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
139 bool SetText( ScRefCellValue& rCell ); // TRUE -> pOldPattern vergessen
140 void SetHashText();
141 void SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth );
142 void SetAutoText( const OUString& rAutoText );
144 SvxCellOrientation GetOrient() const { return eAttrOrient; }
145 SvxCellHorJustify GetHorJust() const { return eAttrHorJust; }
146 SvxCellVerJustify GetVerJust() const { return eAttrVerJust; }
147 SvxCellJustifyMethod GetHorJustMethod() const { return eAttrHorJustMethod; }
148 const SvxMarginItem* GetMargin() const { return pMargin; }
150 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
151 sal_uInt16 GetRightTotal() const { return pMargin->GetRightMargin() + nIndent; }
153 const OUString& GetString() const { return aString; }
154 const Size& GetTextSize() const { return aTextSize; }
155 long GetOriginalWidth() const { return nOriginalWidth; }
157 // Get the effective number format, including formula result types.
158 // This assumes that a formula cell has already been calculated.
159 sal_uLong GetResultValueFormat() const { return nValueFormat;}
161 sal_uLong GetValueFormat() const { return nValueFormat; }
162 bool GetLineBreak() const { return bLineBreak; }
163 bool IsRepeat() const { return bRepeat; }
164 bool IsShrink() const { return bShrink; }
165 void RepeatToFill( long colWidth );
167 long GetAscent() const { return nAscentPixel; }
168 bool IsRotated() const { return bRotated; }
170 void SetShrinkScale( long nScale, SvtScriptType nScript );
172 bool HasCondHeight() const { return pCondSet && SfxItemState::SET ==
173 pCondSet->GetItemState( ATTR_FONT_HEIGHT, true ); }
175 bool HasEditCharacters() const;
177 private:
178 long GetMaxDigitWidth(); // in logic units
179 long GetSignWidth();
180 long GetDotWidth();
181 long GetExpWidth();
182 void TextChanged();
185 ScDrawStringsVars::ScDrawStringsVars(ScOutputData* pData, bool bPTL) :
186 pOutput ( pData ),
187 pPattern ( NULL ),
188 pCondSet ( NULL ),
189 nAscentPixel(0),
190 eAttrOrient ( SVX_ORIENTATION_STANDARD ),
191 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD ),
192 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM ),
193 eAttrHorJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
194 eAttrVerJustMethod( SVX_JUSTIFY_METHOD_AUTO ),
195 pMargin ( NULL ),
196 nIndent ( 0 ),
197 bRotated ( false ),
198 nOriginalWidth( 0 ),
199 nMaxDigitWidth( 0 ),
200 nSignWidth( 0 ),
201 nDotWidth( 0 ),
202 nExpWidth( 0 ),
203 nValueFormat( 0 ),
204 bLineBreak ( false ),
205 bRepeat ( false ),
206 bShrink ( false ),
207 bPixelToLogic( bPTL ),
208 nPos( -1 ),
209 nChar( 0x0 )
211 ScModule* pScMod = SC_MOD();
212 bCellContrast = pOutput->mbUseStyleColor &&
213 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
215 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
216 aBackConfigColor.SetColor( rColorConfig.GetColorValue(svtools::DOCCOLOR).nColor );
217 aTextConfigColor.SetColor( rColorConfig.GetColorValue(svtools::FONTCOLOR).nColor );
220 ScDrawStringsVars::~ScDrawStringsVars()
224 void ScDrawStringsVars::SetShrinkScale( long nScale, SvtScriptType nScript )
226 // text remains valid, size is updated
228 OutputDevice* pDev = pOutput->mpDev;
229 OutputDevice* pRefDevice = pOutput->mpRefDevice;
230 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
232 // call GetFont with a modified fraction, use only the height
234 Fraction aFraction( nScale, 100 );
235 if ( !bPixelToLogic )
236 aFraction *= pOutput->aZoomY;
237 vcl::Font aTmpFont;
238 pPattern->GetFont( aTmpFont, SC_AUTOCOL_RAW, pFmtDevice, &aFraction, pCondSet, nScript );
239 long nNewHeight = aTmpFont.GetHeight();
240 if ( nNewHeight > 0 )
241 aFont.SetHeight( nNewHeight );
243 // set font and dependent variables as in SetPattern
245 pDev->SetFont( aFont );
246 if ( pFmtDevice != pDev )
247 pFmtDevice->SetFont( aFont );
249 aMetric = pFmtDevice->GetFontMetric();
250 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
252 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
253 MapMode aOld = pDefaultDev->GetMapMode();
254 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
255 aMetric = pDefaultDev->GetFontMetric( aFont );
256 pDefaultDev->SetMapMode( aOld );
259 nAscentPixel = aMetric.GetAscent();
260 if ( bPixelToLogic )
261 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
263 SetAutoText( aString ); // same text again, to get text size
266 namespace {
268 template<typename _ItemType, typename _EnumType>
269 _EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
271 const _ItemType& rItem = static_cast<const _ItemType&>(rPattern.GetItem(nWhich, pCondSet));
272 return static_cast<_EnumType>(rItem.GetValue());
275 bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
277 return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
282 void ScDrawStringsVars::SetPattern(
283 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
284 SvtScriptType nScript )
286 nMaxDigitWidth = 0;
287 nSignWidth = 0;
288 nDotWidth = 0;
289 nExpWidth = 0;
291 pPattern = pNew;
292 pCondSet = pSet;
294 // pPattern auswerten
296 OutputDevice* pDev = pOutput->mpDev;
297 OutputDevice* pRefDevice = pOutput->mpRefDevice;
298 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
300 // Font
302 ScAutoFontColorMode eColorMode;
303 if ( pOutput->mbUseStyleColor )
305 if ( pOutput->mbForceAutoColor )
306 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREALL : SC_AUTOCOL_IGNOREFONT;
307 else
308 eColorMode = bCellContrast ? SC_AUTOCOL_IGNOREBACK : SC_AUTOCOL_DISPLAY;
310 else
311 eColorMode = SC_AUTOCOL_PRINT;
313 if ( bPixelToLogic )
314 pPattern->GetFont( aFont, eColorMode, pFmtDevice, NULL, pCondSet, nScript,
315 &aBackConfigColor, &aTextConfigColor );
316 else
317 pPattern->GetFont( aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript,
318 &aBackConfigColor, &aTextConfigColor );
319 aFont.SetAlign(ALIGN_BASELINE);
321 // Orientierung
323 eAttrOrient = pPattern->GetCellOrientation( pCondSet );
325 // alignment
327 eAttrHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(pPattern->GetItem( ATTR_HOR_JUSTIFY, pCondSet )).GetValue();
329 eAttrVerJust = (SvxCellVerJustify)static_cast<const SvxVerJustifyItem&>(pPattern->GetItem( ATTR_VER_JUSTIFY, pCondSet )).GetValue();
330 if ( eAttrVerJust == SVX_VER_JUSTIFY_STANDARD )
331 eAttrVerJust = SVX_VER_JUSTIFY_BOTTOM;
333 // justification method
335 eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
336 eAttrVerJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet);
338 // line break
340 bLineBreak = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_LINEBREAK, pCondSet )).GetValue();
342 // handle "repeat" alignment
344 bRepeat = ( eAttrHorJust == SVX_HOR_JUSTIFY_REPEAT );
345 if ( bRepeat )
347 // "repeat" disables rotation (before constructing the font)
348 eAttrOrient = SVX_ORIENTATION_STANDARD;
350 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
351 if ( bLineBreak )
352 eAttrHorJust = SVX_HOR_JUSTIFY_STANDARD;
355 short nRot;
356 switch (eAttrOrient)
358 case SVX_ORIENTATION_STANDARD:
359 nRot = 0;
360 bRotated = static_cast<const SfxInt32Item&>(pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet )).GetValue() != 0 &&
361 !bRepeat;
362 break;
363 case SVX_ORIENTATION_STACKED:
364 nRot = 0;
365 bRotated = false;
366 break;
367 case SVX_ORIENTATION_TOPBOTTOM:
368 nRot = 2700;
369 bRotated = false;
370 break;
371 case SVX_ORIENTATION_BOTTOMTOP:
372 nRot = 900;
373 bRotated = false;
374 break;
375 default:
376 OSL_FAIL("Falscher SvxCellOrientation Wert");
377 nRot = 0;
378 bRotated = false;
379 break;
381 aFont.SetOrientation( nRot );
383 // Syntax-Modus
385 if (pOutput->mbSyntaxMode)
386 pOutput->SetSyntaxColor(&aFont, rCell);
388 pDev->SetFont( aFont );
389 if ( pFmtDevice != pDev )
390 pFmtDevice->SetFont( aFont );
392 aMetric = pFmtDevice->GetFontMetric();
394 // Wenn auf dem Drucker das Leading 0 ist, gibt es Probleme
395 // -> Metric vom Bildschirm nehmen (wie EditEngine!)
397 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetIntLeading() == 0 )
399 OutputDevice* pDefaultDev = Application::GetDefaultDevice();
400 MapMode aOld = pDefaultDev->GetMapMode();
401 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
402 aMetric = pDefaultDev->GetFontMetric( aFont );
403 pDefaultDev->SetMapMode( aOld );
406 nAscentPixel = aMetric.GetAscent();
407 if ( bPixelToLogic )
408 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
410 Color aULineColor( static_cast<const SvxUnderlineItem&>(pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet )).GetColor() );
411 pDev->SetTextLineColor( aULineColor );
413 Color aOLineColor( static_cast<const SvxOverlineItem&>(pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet )).GetColor() );
414 pDev->SetOverlineColor( aOLineColor );
416 // Zahlenformat
418 nValueFormat = pPattern->GetNumberFormat( pOutput->mpDoc->GetFormatTable(), pCondSet );
420 // Raender
422 pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem( ATTR_MARGIN, pCondSet ));
423 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT || eAttrHorJust == SVX_HOR_JUSTIFY_RIGHT )
424 nIndent = static_cast<const SfxUInt16Item&>(pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
425 else
426 nIndent = 0;
428 // "Shrink to fit"
430 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
432 // zumindest die Text-Groesse muss neu geholt werden
433 //! unterscheiden, und den Text nicht neu vom Numberformatter holen?
435 maLastCell.clear();
438 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet )
440 nMaxDigitWidth = 0;
441 nSignWidth = 0;
442 nDotWidth = 0;
443 nExpWidth = 0;
444 // wird gerufen, wenn sich die Font-Variablen nicht aendern (!StringDiffer)
446 pPattern = pNew;
447 pCondSet = pSet; //! noetig ???
449 // Zahlenformat
451 sal_uLong nOld = nValueFormat;
452 const SfxPoolItem* pFormItem;
453 if ( !pCondSet || pCondSet->GetItemState(ATTR_VALUE_FORMAT,true,&pFormItem) != SfxItemState::SET )
454 pFormItem = &pPattern->GetItem(ATTR_VALUE_FORMAT);
455 const SfxPoolItem* pLangItem;
456 if ( !pCondSet || pCondSet->GetItemState(ATTR_LANGUAGE_FORMAT,true,&pLangItem) != SfxItemState::SET )
457 pLangItem = &pPattern->GetItem(ATTR_LANGUAGE_FORMAT);
458 nValueFormat = pOutput->mpDoc->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
459 static_cast<const SfxUInt32Item*>(pFormItem)->GetValue(),
460 static_cast<const SvxLanguageItem*>(pLangItem)->GetLanguage() );
462 if (nValueFormat != nOld)
463 maLastCell.clear(); // immer neu formatieren
465 // Raender
467 pMargin = static_cast<const SvxMarginItem*>(&pPattern->GetItem( ATTR_MARGIN, pCondSet ));
469 if ( eAttrHorJust == SVX_HOR_JUSTIFY_LEFT )
470 nIndent = static_cast<const SfxUInt16Item&>(pPattern->GetItem( ATTR_INDENT, pCondSet )).GetValue();
471 else
472 nIndent = 0;
474 // "Shrink to fit"
476 bShrink = static_cast<const SfxBoolItem&>(pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
479 inline bool SameValue( const ScRefCellValue& rCell, const ScRefCellValue& rOldCell )
481 return rOldCell.meType == CELLTYPE_VALUE && rCell.meType == CELLTYPE_VALUE &&
482 rCell.mfValue == rOldCell.mfValue;
485 bool ScDrawStringsVars::SetText( ScRefCellValue& rCell )
487 bool bChanged = false;
489 if (!rCell.isEmpty())
491 if (!SameValue(rCell, maLastCell))
493 maLastCell = rCell; // Zelle merken
495 Color* pColor;
496 sal_uLong nFormat = GetValueFormat();
497 ScCellFormat::GetString( rCell,
498 nFormat, aString, &pColor,
499 *pOutput->mpDoc->GetFormatTable(),
500 pOutput->mpDoc,
501 pOutput->mbShowNullValues,
502 pOutput->mbShowFormulas,
503 ftCheck, true );
504 if ( nFormat )
506 nPos = aString.indexOf( 0x1B );
507 if ( nPos != -1 )
509 nChar = aString[ nPos + 1 ];
510 // delete placeholder and char to repeat
511 aString = aString.replaceAt( nPos, 2, "" );
512 // Do not cache/reuse a repeat-filled string, column widths
513 // or fonts or sizes may differ.
514 maLastCell.clear();
517 else
519 nPos = -1;
520 nChar = 0x0;
522 if (aString.getLength() > DRAWTEXT_MAX)
523 aString = aString.copy(0, DRAWTEXT_MAX);
525 if ( pColor && !pOutput->mbSyntaxMode && !( pOutput->mbUseStyleColor && pOutput->mbForceAutoColor ) )
527 OutputDevice* pDev = pOutput->mpDev;
528 aFont.SetColor(*pColor);
529 pDev->SetFont( aFont ); // nur fuer Ausgabe
530 bChanged = true;
531 maLastCell.clear(); // naechstes Mal wieder hierherkommen
534 TextChanged();
536 // sonst String/Groesse behalten
538 else
540 aString.clear();
541 maLastCell.clear();
542 aTextSize = Size(0,0);
543 nOriginalWidth = 0;
546 return bChanged;
549 void ScDrawStringsVars::SetHashText()
551 SetAutoText(OUString("###"));
554 void ScDrawStringsVars::RepeatToFill( long colWidth )
556 if ( nPos == -1 || nPos > aString.getLength() )
557 return;
559 long charWidth = pOutput->pFmtDevice->GetTextWidth(OUString(nChar));
560 if ( charWidth < 1) return;
561 if (bPixelToLogic)
562 colWidth = pOutput->mpRefDevice->PixelToLogic(Size(colWidth,0)).Width();
563 // Are there restrictions on the cell type we should filter out here ?
564 long aSpaceToFill = ( colWidth - aTextSize.Width() );
566 if ( aSpaceToFill <= charWidth )
567 return;
569 long nCharsToInsert = aSpaceToFill / charWidth;
570 OUStringBuffer aFill;
571 comphelper::string::padToLength(aFill, nCharsToInsert, nChar);
572 aString = aString.replaceAt( nPos, 0, aFill.makeStringAndClear() );
573 TextChanged();
576 void ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue& rCell, long nWidth )
578 // #i113045# do the single-character width calculations in logic units
579 if (bPixelToLogic)
580 nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
582 CellType eType = rCell.meType;
583 if (eType != CELLTYPE_VALUE && eType != CELLTYPE_FORMULA)
584 // must be a value or formula cell.
585 return;
587 if (eType == CELLTYPE_FORMULA)
589 ScFormulaCell* pFCell = rCell.mpFormula;
590 if (pFCell->GetErrCode() != 0 || pOutput->mbShowFormulas)
592 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
593 return;
595 // If it's formula, the result must be a value.
596 if (!pFCell->IsValue())
597 return;
600 sal_uLong nFormat = GetResultValueFormat();
601 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
603 // Not 'General' number format. Set hash text and bail out.
604 SetHashText();
605 return;
608 double fVal = rCell.getValue();
610 const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
611 if (!pNumFormat)
612 return;
614 long nMaxDigit = GetMaxDigitWidth();
615 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
617 OUString sTempOut(aString);
618 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
620 aString = sTempOut;
621 // Failed to get output string. Bail out.
622 return;
624 aString = sTempOut;
626 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
627 sal_Int32 nLen = aString.getLength();
628 sal_Unicode cDecSep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator[0];
629 for( sal_Int32 i = 0; i < nLen; ++i )
631 sal_Unicode c = aString[i];
632 if (c == '-')
633 ++nSignCount;
634 else if (c == cDecSep)
635 ++nDecimalCount;
636 else if (c == 'E')
637 ++nExpCount;
640 // #i112250# A small value might be formatted as "0" when only counting the digits,
641 // but fit into the column when considering the smaller width of the decimal separator.
642 if (aString == "0" && fVal != 0.0)
643 nDecimalCount = 1;
645 if (nDecimalCount)
646 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
647 if (nSignCount)
648 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
649 if (nExpCount)
650 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
652 if (nDecimalCount || nSignCount || nExpCount)
654 // Re-calculate.
655 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
656 OUString sTempOut(aString);
657 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
659 aString = sTempOut;
660 // Failed to get output string. Bail out.
661 return;
663 aString = sTempOut;
666 long nActualTextWidth = pOutput->pFmtDevice->GetTextWidth(aString);
667 if (nActualTextWidth > nWidth)
669 // Even after the decimal adjustment the text doesn't fit. Give up.
670 SetHashText();
671 return;
674 TextChanged();
675 maLastCell.clear(); // #i113022# equal cell and format in another column may give different string
678 void ScDrawStringsVars::SetAutoText( const OUString& rAutoText )
680 aString = rAutoText;
682 OutputDevice* pRefDevice = pOutput->mpRefDevice;
683 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
684 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
685 aTextSize.Height() = pFmtDevice->GetTextHeight();
687 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
689 double fMul = pOutput->GetStretch();
690 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
693 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
694 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
696 long nTemp = aTextSize.Height();
697 aTextSize.Height() = aTextSize.Width();
698 aTextSize.Width() = nTemp;
701 nOriginalWidth = aTextSize.Width();
702 if ( bPixelToLogic )
703 aTextSize = pRefDevice->LogicToPixel( aTextSize );
705 maLastCell.clear(); // derselbe Text kann in der naechsten Zelle wieder passen
708 long ScDrawStringsVars::GetMaxDigitWidth()
710 if (nMaxDigitWidth > 0)
711 return nMaxDigitWidth;
713 sal_Char cZero = '0';
714 for (sal_Char i = 0; i < 10; ++i)
716 sal_Char cDigit = cZero + i;
717 long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
718 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
720 return nMaxDigitWidth;
723 long ScDrawStringsVars::GetSignWidth()
725 if (nSignWidth > 0)
726 return nSignWidth;
728 nSignWidth = pOutput->pFmtDevice->GetTextWidth(OUString('-'));
729 return nSignWidth;
732 long ScDrawStringsVars::GetDotWidth()
734 if (nDotWidth > 0)
735 return nDotWidth;
737 const OUString& sep = ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator;
738 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
739 return nDotWidth;
742 long ScDrawStringsVars::GetExpWidth()
744 if (nExpWidth > 0)
745 return nExpWidth;
747 nExpWidth = pOutput->pFmtDevice->GetTextWidth(OUString('E'));
748 return nExpWidth;
751 void ScDrawStringsVars::TextChanged()
753 OutputDevice* pRefDevice = pOutput->mpRefDevice;
754 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
755 aTextSize.Width() = pFmtDevice->GetTextWidth( aString );
756 aTextSize.Height() = pFmtDevice->GetTextHeight();
758 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
760 double fMul = pOutput->GetStretch();
761 aTextSize.Width() = (long)(aTextSize.Width() / fMul + 0.5);
764 aTextSize.Height() = aMetric.GetAscent() + aMetric.GetDescent();
765 if ( GetOrient() != SVX_ORIENTATION_STANDARD )
767 long nTemp = aTextSize.Height();
768 aTextSize.Height() = aTextSize.Width();
769 aTextSize.Width() = nTemp;
772 nOriginalWidth = aTextSize.Width();
773 if ( bPixelToLogic )
774 aTextSize = pRefDevice->LogicToPixel( aTextSize );
777 bool ScDrawStringsVars::HasEditCharacters() const
779 for (sal_Int32 nIdx = 0; nIdx < aString.getLength(); ++nIdx)
781 switch(aString[nIdx])
783 case CHAR_NBSP:
784 case CHAR_SHY:
785 case CHAR_ZWSP:
786 case CHAR_LRM:
787 case CHAR_RLM:
788 case CHAR_NBHY:
789 case CHAR_ZWNBSP:
790 return true;
791 default:
792 break;
796 return false;
799 double ScOutputData::GetStretch()
801 if ( mpRefDevice->IsMapModeEnabled() )
803 // If a non-trivial MapMode is set, its scale is now already
804 // taken into account in the OutputDevice's font handling
805 // (OutputDevice::ImplNewFont, see #95414#).
806 // The old handling below is only needed for pixel output.
807 return 1.0;
810 // calculation in double is faster than Fraction multiplication
811 // and doesn't overflow
813 if ( mpRefDevice == pFmtDevice )
815 MapMode aOld = mpRefDevice->GetMapMode();
816 return ((double)aOld.GetScaleY()) / ((double)aOld.GetScaleX()) * ((double)aZoomY) / ((double)aZoomX);
818 else
820 // when formatting for printer, device map mode has already been taken care of
821 return ((double)aZoomY) / ((double)aZoomX);
825 // output strings
827 static void lcl_DoHyperlinkResult( OutputDevice* pDev, const Rectangle& rRect, ScRefCellValue& rCell )
829 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
831 OUString aCellText;
832 OUString aURL;
833 if (rCell.meType == CELLTYPE_FORMULA)
835 ScFormulaCell* pFCell = rCell.mpFormula;
836 if ( pFCell->IsHyperLinkCell() )
837 pFCell->GetURLResult( aURL, aCellText );
840 if ( !aURL.isEmpty() && pPDFData )
842 vcl::PDFExtOutDevBookmarkEntry aBookmark;
843 aBookmark.nLinkId = pPDFData->CreateLink( rRect );
844 aBookmark.aBookmark = aURL;
845 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
846 rBookmarks.push_back( aBookmark );
850 void ScOutputData::SetSyntaxColor( vcl::Font* pFont, const ScRefCellValue& rCell )
852 switch (rCell.meType)
854 case CELLTYPE_VALUE:
855 pFont->SetColor(*pValueColor);
856 break;
857 case CELLTYPE_STRING:
858 pFont->SetColor(*pTextColor);
859 break;
860 case CELLTYPE_FORMULA:
861 pFont->SetColor(*pFormulaColor);
862 break;
863 default:
865 // added to avoid warnings
870 static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
872 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
873 SfxItemSet aSet( rEngine.GetEmptyItemSet() );
874 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
875 rEngine.QuickSetAttribs( aSet, aSel );
876 // function is called with update mode set to FALSE
879 void ScOutputData::SetEditSyntaxColor( EditEngine& rEngine, ScRefCellValue& rCell )
881 Color aColor;
882 switch (rCell.meType)
884 case CELLTYPE_VALUE:
885 aColor = *pValueColor;
886 break;
887 case CELLTYPE_STRING:
888 aColor = *pTextColor;
889 break;
890 case CELLTYPE_FORMULA:
891 aColor = *pFormulaColor;
892 break;
893 default:
895 // added to avoid warnings
898 lcl_SetEditColor( rEngine, aColor );
901 bool ScOutputData::GetMergeOrigin( SCCOL nX, SCROW nY, SCSIZE nArrY,
902 SCCOL& rOverX, SCROW& rOverY,
903 bool bVisRowChanged )
905 bool bDoMerge = false;
906 bool bIsLeft = ( nX == nVisX1 );
907 bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
909 CellInfo* pInfo = &pRowInfo[nArrY].pCellInfo[nX+1];
910 if ( pInfo->bHOverlapped && pInfo->bVOverlapped )
911 bDoMerge = bIsLeft && bIsTop;
912 else if ( pInfo->bHOverlapped )
913 bDoMerge = bIsLeft;
914 else if ( pInfo->bVOverlapped )
915 bDoMerge = bIsTop;
917 rOverX = nX;
918 rOverY = nY;
919 bool bHOver = pInfo->bHOverlapped;
920 bool bVOver = pInfo->bVOverlapped;
921 bool bHidden;
923 while (bHOver) // nY konstant
925 --rOverX;
926 bHidden = mpDoc->ColHidden(rOverX, nTab);
927 if ( !bDoMerge && !bHidden )
928 return false;
930 if (rOverX >= nX1 && !bHidden)
932 bHOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bHOverlapped;
933 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
935 else
937 sal_uInt16 nOverlap = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
938 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
939 bHOver = ((nOverlap & SC_MF_HOR) != 0);
940 bVOver = ((nOverlap & SC_MF_VER) != 0);
944 while (bVOver)
946 --rOverY;
947 bHidden = mpDoc->RowHidden(rOverY, nTab);
948 if ( !bDoMerge && !bHidden )
949 return false;
951 if (nArrY>0)
952 --nArrY; // lokale Kopie !
954 if (rOverX >= nX1 && rOverY >= nY1 &&
955 !mpDoc->ColHidden(rOverX, nTab) &&
956 !mpDoc->RowHidden(rOverY, nTab) &&
957 pRowInfo[nArrY].nRowNo == rOverY)
959 bVOver = pRowInfo[nArrY].pCellInfo[rOverX+1].bVOverlapped;
961 else
963 sal_uInt16 nOverlap = static_cast<const ScMergeFlagAttr*>(mpDoc->GetAttr(
964 rOverX, rOverY, nTab, ATTR_MERGE_FLAG ))->GetValue();
965 bVOver = ((nOverlap & SC_MF_VER) != 0);
969 return true;
972 inline bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr*& rpNewPattern )
974 OSL_ENSURE( rpNewPattern, "pNewPattern" );
976 if ( rpNewPattern == rpOldPattern )
977 return false;
978 else if ( !rpOldPattern )
979 return true;
980 else if ( &rpNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
981 return true;
982 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
983 return true;
984 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
985 return true;
986 else if ( &rpNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
987 return true;
988 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
989 return true;
990 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
991 return true;
992 else if ( &rpNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
993 return true;
994 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
995 return true;
996 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
997 return true;
998 else if ( &rpNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
999 return true;
1000 else if ( &rpNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
1001 return true;
1002 else if ( &rpNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
1003 return true;
1004 else if ( &rpNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
1005 return true;
1006 else if ( &rpNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
1007 return true;
1008 else if ( &rpNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
1009 return true;
1010 else if ( &rpNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
1011 return true;
1012 else if ( &rpNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
1013 return true;
1014 else if ( &rpNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
1015 return true;
1016 else if ( &rpNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
1017 return true;
1018 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
1019 return true;
1020 else if ( &rpNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
1021 return true;
1022 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
1023 return true;
1024 else if ( &rpNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
1025 return true;
1026 else if ( &rpNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
1027 return true;
1028 else if ( &rpNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
1029 return true;
1030 else if ( &rpNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
1031 return true;
1032 else if ( &rpNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
1033 return true;
1034 else if ( &rpNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
1035 return true;
1036 else if ( &rpNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
1037 return true;
1038 else if ( &rpNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
1039 return true;
1040 else if ( &rpNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
1041 return true; // needed with automatic text color
1042 else
1044 rpOldPattern = rpNewPattern;
1045 return false;
1049 static inline void lcl_CreateInterpretProgress( bool& bProgress, ScDocument* pDoc,
1050 ScFormulaCell* pFCell )
1052 if ( !bProgress && pFCell->GetDirty() )
1054 ScProgress::CreateInterpretProgress( pDoc, true );
1055 bProgress = true;
1059 inline bool IsAmbiguousScript( SvtScriptType nScript )
1061 return ( nScript != SvtScriptType::LATIN &&
1062 nScript != SvtScriptType::ASIAN &&
1063 nScript != SvtScriptType::COMPLEX );
1066 bool ScOutputData::IsEmptyCellText( RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1068 // pThisRowInfo may be NULL
1070 bool bEmpty;
1071 if ( pThisRowInfo && nX <= nX2 )
1072 bEmpty = pThisRowInfo->pCellInfo[nX+1].bEmptyCellText;
1073 else
1075 ScRefCellValue aCell;
1076 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1077 bEmpty = aCell.isEmpty();
1080 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1082 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1083 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1085 bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1087 if ( bIsPrint || bTabProtected )
1089 const ScProtectionAttr* pAttr = static_cast<const ScProtectionAttr*>(
1090 mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION ));
1091 if ( bIsPrint && pAttr->GetHidePrint() )
1092 bEmpty = true;
1093 else if ( bTabProtected )
1095 if ( pAttr->GetHideCell() )
1096 bEmpty = true;
1097 else if ( mbShowFormulas && pAttr->GetHideFormula() )
1099 if (mpDoc->GetCellType(ScAddress(nX, nY, nTab)) == CELLTYPE_FORMULA)
1100 bEmpty = true;
1105 return bEmpty;
1108 void ScOutputData::GetVisibleCell( SCCOL nCol, SCROW nRow, SCTAB nTabP, ScRefCellValue& rCell )
1110 rCell.assign(*mpDoc, ScAddress(nCol, nRow, nTabP));
1111 if (!rCell.isEmpty() && IsEmptyCellText(NULL, nCol, nRow))
1112 rCell.clear();
1115 bool ScOutputData::IsAvailable( SCCOL nX, SCROW nY )
1117 // apply the same logic here as in DrawStrings/DrawEdit:
1118 // Stop at non-empty or merged or overlapped cell,
1119 // where a note is empty as well as a cell that's hidden by protection settings
1121 ScRefCellValue aCell;
1122 aCell.assign(*mpDoc, ScAddress(nX, nY, nTab));
1123 if (!aCell.isEmpty() && !IsEmptyCellText(NULL, nX, nY))
1124 return false;
1126 const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
1127 if ( static_cast<const ScMergeAttr&>(pPattern->GetItem(ATTR_MERGE)).IsMerged() ||
1128 static_cast<const ScMergeFlagAttr&>(pPattern->GetItem(ATTR_MERGE_FLAG)).IsOverlapped() )
1130 return false;
1133 return true;
1136 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1137 // nPosX, nPosY: corresponding positions for nX, nArrY
1138 // nCellX, nCellY: position of the cell that contains the text
1139 // nNeeded: Text width, including margin
1140 // rPattern: cell format at nCellX, nCellY
1141 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1142 // bCellIsValue: if set, don't extend into empty cells
1143 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1144 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1145 // rParam output: various area parameters.
1147 void ScOutputData::GetOutputArea( SCCOL nX, SCSIZE nArrY, long nPosX, long nPosY,
1148 SCCOL nCellX, SCROW nCellY, long nNeeded,
1149 const ScPatternAttr& rPattern,
1150 sal_uInt16 nHorJustify, bool bCellIsValue,
1151 bool bBreak, bool bOverwrite,
1152 OutputAreaParam& rParam )
1154 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1155 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1157 long nLayoutSign = bLayoutRTL ? -1 : 1;
1159 long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
1160 SCCOL nCompCol = nX;
1161 while ( nCellX > nCompCol )
1163 //! extra member function for width?
1164 long nColWidth = ( nCompCol <= nX2 ) ?
1165 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1166 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1167 nCellPosX += nColWidth * nLayoutSign;
1168 ++nCompCol;
1170 while ( nCellX < nCompCol )
1172 --nCompCol;
1173 long nColWidth = ( nCompCol <= nX2 ) ?
1174 pRowInfo[0].pCellInfo[nCompCol+1].nWidth :
1175 (long) ( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1176 nCellPosX -= nColWidth * nLayoutSign;
1179 long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
1180 SCSIZE nCompArr = nArrY;
1181 SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1182 while ( nCellY > nCompRow )
1184 if ( nCompArr + 1 < nArrCount )
1186 nCellPosY += pRowInfo[nCompArr].nHeight;
1187 ++nCompArr;
1188 nCompRow = pRowInfo[nCompArr].nRowNo;
1190 else
1192 sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
1193 if ( nDocHeight )
1194 nCellPosY += (long) ( nDocHeight * mnPPTY );
1195 ++nCompRow;
1198 nCellPosY -= (long) mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
1200 const ScMergeAttr* pMerge = static_cast<const ScMergeAttr*>(&rPattern.GetItem( ATTR_MERGE ));
1201 bool bMerged = pMerge->IsMerged();
1202 long nMergeCols = pMerge->GetColMerge();
1203 if ( nMergeCols == 0 )
1204 nMergeCols = 1;
1205 long nMergeRows = pMerge->GetRowMerge();
1206 if ( nMergeRows == 0 )
1207 nMergeRows = 1;
1209 long nMergeSizeX = 0;
1210 for ( long i=0; i<nMergeCols; i++ )
1212 long nColWidth = ( nCellX+i <= nX2 ) ?
1213 pRowInfo[0].pCellInfo[nCellX+i+1].nWidth :
1214 (long) ( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
1215 nMergeSizeX += nColWidth;
1217 long nMergeSizeY = 0;
1218 short nDirect = 0;
1219 if ( rThisRowInfo.nRowNo == nCellY )
1221 // take first row's height from row info
1222 nMergeSizeY += rThisRowInfo.nHeight;
1223 nDirect = 1; // skip in loop
1225 // following rows always from document
1226 nMergeSizeY += (long) mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
1228 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
1230 rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1231 rParam.mnLeftClipLength = rParam.mnRightClipLength = 0;
1233 // construct the rectangles using logical left/right values (justify is called at the end)
1235 // rAlignRect is the single cell or merged area, used for alignment.
1237 rParam.maAlignRect.Left() = nCellPosX;
1238 rParam.maAlignRect.Right() = nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign;
1239 rParam.maAlignRect.Top() = nCellPosY;
1240 rParam.maAlignRect.Bottom() = nCellPosY + nMergeSizeY - 1;
1242 // rClipRect is all cells that are used for output.
1243 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1245 rParam.maClipRect = rParam.maAlignRect;
1246 if ( nNeeded > nMergeSizeX )
1248 SvxCellHorJustify eHorJust = (SvxCellHorJustify)nHorJustify;
1250 long nMissing = nNeeded - nMergeSizeX;
1251 long nLeftMissing = 0;
1252 long nRightMissing = 0;
1253 switch ( eHorJust )
1255 case SVX_HOR_JUSTIFY_LEFT:
1256 nRightMissing = nMissing;
1257 break;
1258 case SVX_HOR_JUSTIFY_RIGHT:
1259 nLeftMissing = nMissing;
1260 break;
1261 case SVX_HOR_JUSTIFY_CENTER:
1262 nLeftMissing = nMissing / 2;
1263 nRightMissing = nMissing - nLeftMissing;
1264 break;
1265 default:
1267 // added to avoid warnings
1271 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1272 if ( bLayoutRTL )
1273 ::std::swap( nLeftMissing, nRightMissing );
1275 SCCOL nRightX = nCellX;
1276 SCCOL nLeftX = nCellX;
1277 if ( !bMerged && !bCellIsValue && !bBreak )
1279 // look for empty cells into which the text can be extended
1281 while ( nRightMissing > 0 && nRightX < MAXCOL && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1283 ++nRightX;
1284 long nAdd = (long) ( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
1285 nRightMissing -= nAdd;
1286 rParam.maClipRect.Right() += nAdd * nLayoutSign;
1288 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1289 rThisRowInfo.pCellInfo[nRightX].bHideGrid = true;
1292 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1294 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1295 rThisRowInfo.pCellInfo[nLeftX].bHideGrid = true;
1297 --nLeftX;
1298 long nAdd = (long) ( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
1299 nLeftMissing -= nAdd;
1300 rParam.maClipRect.Left() -= nAdd * nLayoutSign;
1304 // Set flag and reserve space for clipping mark triangle,
1305 // even if rThisRowInfo isn't for nCellY (merged cells).
1306 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1308 rThisRowInfo.pCellInfo[nRightX+1].nClipMark |= SC_CLIPMARK_RIGHT;
1309 bAnyClipped = true;
1310 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1311 rParam.maClipRect.Right() -= nMarkPixel * nLayoutSign;
1313 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1315 rThisRowInfo.pCellInfo[nLeftX+1].nClipMark |= SC_CLIPMARK_LEFT;
1316 bAnyClipped = true;
1317 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
1318 rParam.maClipRect.Left() += nMarkPixel * nLayoutSign;
1321 rParam.mbLeftClip = ( nLeftMissing > 0 );
1322 rParam.mbRightClip = ( nRightMissing > 0 );
1323 rParam.mnLeftClipLength = nLeftMissing;
1324 rParam.mnRightClipLength = nRightMissing;
1326 else
1328 rParam.mbLeftClip = rParam.mbRightClip = false;
1330 // leave space for AutoFilter on screen
1331 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1333 if ( eType==OUTTYPE_WINDOW &&
1334 ( static_cast<const ScMergeFlagAttr&>(rPattern.GetItem(ATTR_MERGE_FLAG)).GetValue() & (SC_MF_AUTO|SC_MF_BUTTON|SC_MF_BUTTON_POPUP) ) &&
1335 ( !bBreak || mpRefDevice == pFmtDevice ) )
1337 // filter drop-down width is now independent from row height
1338 const long nFilter = DROPDOWN_BITMAP_SIZE;
1339 bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1340 if ( bFit || bCellIsValue )
1342 // content fits even in the remaining area without the filter button
1343 // -> align within that remaining area
1345 rParam.maAlignRect.Right() -= nFilter * nLayoutSign;
1346 rParam.maClipRect.Right() -= nFilter * nLayoutSign;
1348 // if a number doesn't fit, don't hide part of the number behind the button
1349 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1351 if ( !bFit )
1352 rParam.mbLeftClip = rParam.mbRightClip = true;
1357 // justify both rectangles for alignment calculation, use with DrawText etc.
1359 rParam.maAlignRect.Justify();
1360 rParam.maClipRect.Justify();
1363 namespace {
1365 bool beginsWithRTLCharacter(const OUString& rStr)
1367 if (rStr.isEmpty())
1368 return false;
1370 switch (ScGlobal::pCharClass->getCharacterDirection(rStr, 0))
1372 case i18n::DirectionProperty_RIGHT_TO_LEFT:
1373 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
1374 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
1375 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
1376 return true;
1377 default:
1381 return false;
1386 /** Get left, right or centered alignment from RTL context.
1388 Does not return standard, block or repeat, for these the contextual left or
1389 right alignment is returned.
1391 static SvxCellHorJustify getAlignmentFromContext( SvxCellHorJustify eInHorJust,
1392 bool bCellIsValue, const OUString& rText,
1393 const ScPatternAttr& rPattern, const SfxItemSet* pCondSet,
1394 const ScDocument* pDoc, SCTAB nTab )
1396 SvxCellHorJustify eHorJustContext = eInHorJust;
1397 bool bUseWritingDirection = false;
1398 if (eInHorJust == SVX_HOR_JUSTIFY_STANDARD)
1400 // fdo#32530: Default alignment depends on value vs
1401 // string, and the direction of the 1st letter.
1402 if (beginsWithRTLCharacter( rText))
1403 eHorJustContext = bCellIsValue ? SVX_HOR_JUSTIFY_LEFT : SVX_HOR_JUSTIFY_RIGHT;
1404 else if (bCellIsValue)
1405 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1406 else
1407 bUseWritingDirection = true;
1410 if (bUseWritingDirection ||
1411 eInHorJust == SVX_HOR_JUSTIFY_BLOCK || eInHorJust == SVX_HOR_JUSTIFY_REPEAT)
1413 sal_uInt16 nDirection = lcl_GetValue<SvxFrameDirectionItem, sal_uInt16>( rPattern, ATTR_WRITINGDIR, pCondSet);
1414 if (nDirection == FRMDIR_HORI_LEFT_TOP || nDirection == FRMDIR_VERT_TOP_LEFT)
1415 eHorJustContext = SVX_HOR_JUSTIFY_LEFT;
1416 else if (nDirection == FRMDIR_ENVIRONMENT)
1418 SAL_WARN_IF( !pDoc, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1419 // fdo#73588: The content of the cell must also
1420 // begin with a RTL character to be right
1421 // aligned; otherwise, it should be left aligned.
1422 eHorJustContext = (pDoc && pDoc->IsLayoutRTL(nTab) && (beginsWithRTLCharacter( rText))) ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
1424 else
1425 eHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
1427 return eHorJustContext;
1430 void ScOutputData::DrawStrings( bool bPixelToLogic )
1432 LayoutStrings(bPixelToLogic, true);
1435 Rectangle ScOutputData::LayoutStrings(bool bPixelToLogic, bool bPaint, const ScAddress &rAddress)
1437 OSL_ENSURE( mpDev == mpRefDevice ||
1438 mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
1439 "LayoutStrings: unterschiedliche MapUnits ?!?!" );
1441 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, mpDev->GetExtOutDevData() );
1443 sc::IdleSwitch aIdleSwitch(*mpDoc, false);
1444 ScDrawStringsVars aVars( this, bPixelToLogic );
1446 bool bProgress = false;
1448 long nInitPosX = nScrX;
1449 if ( bLayoutRTL )
1450 nInitPosX += nMirrorW - 1; // pixels
1451 long nLayoutSign = bLayoutRTL ? -1 : 1;
1453 SCCOL nLastContentCol = MAXCOL;
1454 if ( nX2 < MAXCOL )
1455 nLastContentCol = sal::static_int_cast<SCCOL>(
1456 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
1457 SCCOL nLoopStartX = nX1;
1458 if ( nX1 > 0 )
1459 --nLoopStartX; // start before nX1 for rest of long text to the left
1461 // variables for GetOutputArea
1462 OutputAreaParam aAreaParam;
1463 bool bCellIsValue = false;
1464 long nNeededWidth = 0;
1465 const ScPatternAttr* pPattern = NULL;
1466 const SfxItemSet* pCondSet = NULL;
1467 const ScPatternAttr* pOldPattern = NULL;
1468 const SfxItemSet* pOldCondSet = NULL;
1469 SvtScriptType nOldScript = SvtScriptType::NONE;
1471 // alternative pattern instances in case we need to modify the pattern
1472 // before processing the cell value.
1473 ::boost::ptr_vector<ScPatternAttr> aAltPatterns;
1475 std::vector<long> aDX;
1476 long nPosY = nScrY;
1477 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1479 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1480 SCROW nY = pThisRowInfo->nRowNo;
1481 if ((bPaint && pThisRowInfo->bChanged) || (!bPaint && rAddress.Row() == nY))
1483 long nPosX = nInitPosX;
1484 if ( nLoopStartX < nX1 )
1485 nPosX -= pRowInfo[0].pCellInfo[nLoopStartX+1].nWidth * nLayoutSign;
1486 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1488 bool bMergeEmpty = false;
1489 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
1490 bool bEmpty = nX < nX1 || pInfo->bEmptyCellText;
1492 SCCOL nCellX = nX; // position where the cell really starts
1493 SCROW nCellY = nY;
1494 bool bDoCell = false;
1495 bool bNeedEdit = false;
1497 // Part of a merged cell?
1499 bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
1500 if ( bOverlapped )
1502 bEmpty = true;
1504 SCCOL nOverX; // start of the merged cells
1505 SCROW nOverY;
1506 bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1507 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1509 nCellX = nOverX;
1510 nCellY = nOverY;
1511 bDoCell = true;
1513 else
1514 bMergeEmpty = true;
1517 // Rest of a long text further to the left?
1519 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1521 SCCOL nTempX=nX1;
1522 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1523 --nTempX;
1525 if ( nTempX < nX1 &&
1526 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1527 !mpDoc->HasAttrib( nTempX,nY,nTab, nX1,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1529 nCellX = nTempX;
1530 bDoCell = true;
1534 // Rest of a long text further to the right?
1536 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1538 // don't have to look further than nLastContentCol
1540 SCCOL nTempX=nX;
1541 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1542 ++nTempX;
1544 if ( nTempX > nX &&
1545 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1546 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
1548 nCellX = nTempX;
1549 bDoCell = true;
1553 // normal visible cell
1555 if (!bEmpty)
1556 bDoCell = true;
1558 // don't output the cell that's being edited
1560 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1561 bDoCell = false;
1563 // skip text in cell if data bar/icon set is set and only value selected
1564 if ( bDoCell )
1566 if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
1567 bDoCell = false;
1568 if(pInfo->pIconSet && !pInfo->pIconSet->mbShowValue)
1569 bDoCell = false;
1572 // output the cell text
1574 ScRefCellValue aCell;
1575 if (bDoCell)
1577 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1578 aCell = pThisRowInfo->pCellInfo[nCellX+1].maCell;
1579 else
1580 GetVisibleCell( nCellX, nCellY, nTab, aCell ); // get from document
1581 if (aCell.isEmpty())
1582 bDoCell = false;
1583 else if (aCell.meType == CELLTYPE_EDIT)
1584 bNeedEdit = true;
1587 // Check if this cell is mis-spelled.
1588 if (bDoCell && !bNeedEdit && aCell.meType == CELLTYPE_STRING)
1590 if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
1591 bNeedEdit = true;
1594 if (bDoCell && !bNeedEdit)
1596 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1598 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
1599 pPattern = rCellInfo.pPatternAttr;
1600 pCondSet = rCellInfo.pConditionSet;
1602 if ( !pPattern )
1604 // #i68085# pattern from cell info for hidden columns is null,
1605 // test for null is quicker than using column flags
1606 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1607 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1610 else // get from document
1612 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1613 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1615 if ( mpDoc->GetPreviewFont() || mpDoc->GetPreviewCellStyle() )
1617 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1618 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1619 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
1621 pAltPattern->SetStyleSheet(pPreviewStyle);
1623 else if ( SfxItemSet* pFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab ) )
1625 const SfxPoolItem* pItem;
1626 if ( pFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SfxItemState::SET )
1627 pAltPattern->GetItemSet().Put( static_cast<const SvxFontItem&>(*pItem) );
1628 if ( pFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SfxItemState::SET )
1629 pAltPattern->GetItemSet().Put( static_cast<const SvxFontItem&>(*pItem) );
1630 if ( pFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SfxItemState::SET )
1631 pAltPattern->GetItemSet().Put( static_cast<const SvxFontItem&>(*pItem) );
1633 pPattern = pAltPattern;
1636 if (aCell.hasNumeric() &&
1637 static_cast<const SfxBoolItem&>(
1638 pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue())
1640 // Disable line break when the cell content is numeric.
1641 aAltPatterns.push_back(new ScPatternAttr(*pPattern));
1642 ScPatternAttr* pAltPattern = &aAltPatterns.back();
1643 SfxBoolItem aLineBreak(ATTR_LINEBREAK, false);
1644 pAltPattern->GetItemSet().Put(aLineBreak);
1645 pPattern = pAltPattern;
1648 SvtScriptType nScript = mpDoc->GetCellScriptType(
1649 ScAddress(nCellX, nCellY, nTab),
1650 pPattern->GetNumberFormat(mpDoc->GetFormatTable(), pCondSet));
1652 if (nScript == SvtScriptType::NONE)
1653 nScript = ScGlobal::GetDefaultScriptType();
1655 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1656 nScript != nOldScript || mbSyntaxMode )
1658 if ( StringDiffer(pOldPattern,pPattern) ||
1659 pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
1661 aVars.SetPattern(pPattern, pCondSet, aCell, nScript);
1663 else
1664 aVars.SetPatternSimple( pPattern, pCondSet );
1665 pOldPattern = pPattern;
1666 pOldCondSet = pCondSet;
1667 nOldScript = nScript;
1670 // use edit engine for rotated, stacked or mixed-script text
1671 if ( aVars.GetOrient() == SVX_ORIENTATION_STACKED ||
1672 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1673 bNeedEdit = true;
1675 if (bDoCell && !bNeedEdit)
1677 bool bFormulaCell = (aCell.meType == CELLTYPE_FORMULA);
1678 if ( bFormulaCell )
1679 lcl_CreateInterpretProgress(bProgress, mpDoc, aCell.mpFormula);
1680 if ( aVars.SetText(aCell) )
1681 pOldPattern = NULL;
1682 bNeedEdit = aVars.HasEditCharacters() || (bFormulaCell && aCell.mpFormula->IsMultilineResult());
1684 long nTotalMargin = 0;
1685 SvxCellHorJustify eOutHorJust = SVX_HOR_JUSTIFY_STANDARD;
1686 if (bDoCell && !bNeedEdit)
1688 CellType eCellType = aCell.meType;
1689 bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1690 if ( eCellType == CELLTYPE_FORMULA )
1692 ScFormulaCell* pFCell = aCell.mpFormula;
1693 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1696 eOutHorJust = getAlignmentFromContext( aVars.GetHorJust(), bCellIsValue, aVars.GetString(),
1697 *pPattern, pCondSet, mpDoc, nTab);
1699 bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK );
1700 // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1701 if (bBreak && bCellIsValue && (aVars.GetResultValueFormat() % SV_COUNTRY_LANGUAGE_OFFSET) == 0)
1702 bBreak = false;
1704 bool bRepeat = aVars.IsRepeat() && !bBreak;
1705 bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1707 nTotalMargin =
1708 static_cast<long>(aVars.GetLeftTotal() * mnPPTX) +
1709 static_cast<long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
1711 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1713 // GetOutputArea gives justfied rectangles
1714 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1715 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1716 bCellIsValue || bRepeat || bShrink, bBreak, false,
1717 aAreaParam );
1719 aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
1720 if ( bShrink )
1722 if ( aVars.GetOrient() != SVX_ORIENTATION_STANDARD )
1724 // Only horizontal scaling is handled here.
1725 // DrawEdit is used to vertically scale 90 deg rotated text.
1726 bNeedEdit = true;
1728 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
1730 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1731 long nScaleSize = aVars.GetTextSize().Width(); // without margin
1733 if ( nAvailable > 0 && nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
1735 long nScale = ( nAvailable * 100 ) / nScaleSize;
1737 aVars.SetShrinkScale( nScale, nOldScript );
1738 long nNewSize = aVars.GetTextSize().Width();
1740 sal_uInt16 nShrinkAgain = 0;
1741 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1743 // If the text is still too large, reduce the scale again by 10%, until it fits,
1744 // at most 7 times (it's less than 50% of the calculated scale then).
1746 nScale = ( nScale * 9 ) / 10;
1747 aVars.SetShrinkScale( nScale, nOldScript );
1748 nNewSize = aVars.GetTextSize().Width();
1749 ++nShrinkAgain;
1751 // If even at half the size the font still isn't rendered smaller,
1752 // fall back to normal clipping (showing ### for numbers).
1753 if ( nNewSize <= nAvailable )
1755 // Reset relevant parameters.
1756 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1757 aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
1760 pOldPattern = NULL;
1765 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1767 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1768 long nRepeatSize = aVars.GetTextSize().Width(); // without margin
1769 // When formatting for the printer, the text sizes don't always add up.
1770 // Round down (too few repetitions) rather than exceeding the cell size then:
1771 if ( pFmtDevice != mpRefDevice )
1772 ++nRepeatSize;
1773 if ( nRepeatSize > 0 )
1775 long nRepeatCount = nAvailable / nRepeatSize;
1776 if ( nRepeatCount > 1 )
1778 OUString aCellStr = aVars.GetString();
1779 OUString aRepeated = aCellStr;
1780 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1781 aRepeated += aCellStr;
1782 aVars.SetAutoText( aRepeated );
1787 // use edit engine if automatic line breaks are needed
1788 if ( bBreak )
1790 if ( aVars.GetOrient() == SVX_ORIENTATION_STANDARD )
1791 bNeedEdit = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1792 else
1794 long nHeight = aVars.GetTextSize().Height() +
1795 (long)(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
1796 (long)(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
1797 bNeedEdit = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1800 if (!bNeedEdit)
1802 bNeedEdit =
1803 aVars.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK &&
1804 aVars.GetHorJustMethod() == SVX_JUSTIFY_METHOD_DISTRIBUTE;
1807 if (bNeedEdit)
1809 // mark the cell in CellInfo to be drawn in DrawEdit:
1810 // Cells to the left are marked directly, cells to the
1811 // right are handled by the flag for nX2
1812 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1813 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1814 pMarkRowInfo->pCellInfo[nMarkX+1].bEditEngine = true;
1815 bDoCell = false; // don't draw here
1817 if ( bDoCell )
1819 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1821 if (mbShowFormulas)
1822 aVars.SetHashText();
1823 else
1824 // Adjust the decimals to fit the available column width.
1825 aVars.SetTextToWidthOrHash(aCell, aAreaParam.mnColWidth - nTotalMargin);
1827 nNeededWidth = aVars.GetTextSize().Width() +
1828 (long) ( aVars.GetLeftTotal() * mnPPTX ) +
1829 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1830 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1832 // Cell value is no longer clipped. Reset relevant parameters.
1833 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1834 aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
1837 // If the "###" replacement doesn't fit into the cells, no clip marks
1838 // are shown, as the "###" already denotes too little space.
1839 // The rectangles from the first GetOutputArea call remain valid.
1842 long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
1843 long nJustPosY = aAreaParam.maAlignRect.Top();
1844 long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1845 long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1847 bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1848 if ( aAreaParam.maClipRect.Left() < nScrX )
1850 aAreaParam.maClipRect.Left() = nScrX;
1851 aAreaParam.mbLeftClip = true;
1853 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
1855 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
1856 aAreaParam.mbRightClip = true;
1859 bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1860 bool bVClip = false;
1862 if ( aAreaParam.maClipRect.Top() < nScrY )
1864 aAreaParam.maClipRect.Top() = nScrY;
1865 bVClip = true;
1867 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
1869 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
1870 bVClip = true;
1873 // check horizontal space
1875 bool bNeedEditEngine = false;
1876 if ( !bNeedEditEngine && !bOutside )
1878 bool bRightAdjusted = false; // to correct text width calculation later
1879 switch (eOutHorJust)
1881 case SVX_HOR_JUSTIFY_LEFT:
1882 nJustPosX += (long) ( aVars.GetLeftTotal() * mnPPTX );
1883 break;
1884 case SVX_HOR_JUSTIFY_RIGHT:
1885 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1886 (long) ( aVars.GetRightTotal() * mnPPTX );
1887 bRightAdjusted = true;
1888 break;
1889 case SVX_HOR_JUSTIFY_CENTER:
1890 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1891 (long) ( aVars.GetLeftTotal() * mnPPTX ) -
1892 (long) ( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
1893 break;
1894 default:
1896 // added to avoid warnings
1900 long nTestClipHeight = aVars.GetTextSize().Height();
1901 switch (aVars.GetVerJust())
1903 case SVX_VER_JUSTIFY_TOP:
1904 case SVX_VER_JUSTIFY_BLOCK:
1906 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1907 nJustPosY += nTop;
1908 nTestClipHeight += nTop;
1910 break;
1911 case SVX_VER_JUSTIFY_BOTTOM:
1913 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1914 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1915 nTestClipHeight += nBot;
1917 break;
1918 case SVX_VER_JUSTIFY_CENTER:
1920 long nTop = (long)( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1921 long nBot = (long)( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1922 nJustPosY += ( nOutHeight + nTop -
1923 aVars.GetTextSize().Height() - nBot ) / 2;
1924 nTestClipHeight += std::abs( nTop - nBot );
1926 break;
1927 default:
1929 // added to avoid warnings
1933 if ( nTestClipHeight > nOutHeight )
1935 // kein vertikales Clipping beim Drucken von Zellen mit
1936 // optimaler Hoehe, ausser bei Groesse in bedingter Formatierung
1937 if ( eType != OUTTYPE_PRINTER ||
1938 ( mpDoc->GetRowFlags( nCellY, nTab ) & CR_MANUALSIZE ) ||
1939 ( aVars.HasCondHeight() ) )
1940 bVClip = true;
1943 if ( bHClip || bVClip )
1945 // nur die betroffene Dimension clippen,
1946 // damit bei nicht-proportionalem Resize nicht alle
1947 // rechtsbuendigen Zahlen abgeschnitten werden:
1949 if (!bHClip)
1951 aAreaParam.maClipRect.Left() = nScrX;
1952 aAreaParam.maClipRect.Right() = nScrX+nScrW;
1954 if (!bVClip)
1956 aAreaParam.maClipRect.Top() = nScrY;
1957 aAreaParam.maClipRect.Bottom() = nScrY+nScrH;
1960 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
1961 // so it can be modified here
1962 if (bPixelToLogic)
1963 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
1965 if (bMetaFile)
1967 mpDev->Push();
1968 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
1970 else
1971 mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
1974 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
1976 switch (aVars.GetOrient())
1978 case SVX_ORIENTATION_STANDARD:
1979 nJustPosY += aVars.GetAscent();
1980 break;
1981 case SVX_ORIENTATION_TOPBOTTOM:
1982 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
1983 break;
1984 case SVX_ORIENTATION_BOTTOMTOP:
1985 nJustPosY += aVars.GetTextSize().Height();
1986 nJustPosX += aVars.GetAscent();
1987 break;
1988 default:
1990 // added to avoid warnings
1994 // When clipping, the visible part is now completely defined by the alignment,
1995 // there's no more special handling to show the right part of RTL text.
1997 Point aDrawTextPos( nJustPosX, nJustPosY );
1998 if ( bPixelToLogic )
2000 // undo text width adjustment in pixels
2001 if (bRightAdjusted)
2002 aDrawTextPos.X() += aVars.GetTextSize().Width();
2004 aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
2006 // redo text width adjustment in logic units
2007 if (bRightAdjusted)
2008 aDrawTextPos.X() -= aVars.GetOriginalWidth();
2011 // in Metafiles immer DrawTextArray, damit die Positionen mit
2012 // aufgezeichnet werden (fuer nicht-proportionales Resize):
2014 OUString aString = aVars.GetString();
2015 if (!aString.isEmpty())
2017 // If the string is clipped, make it shorter for
2018 // better performance since drawing by HarfBuzz is
2019 // quite expensive especiall for long string.
2021 OUString aShort = aString;
2023 // But never fiddle with numeric values.
2024 // (Which was the cause of tdf#86024).
2025 // The General automatic format output takes
2026 // care of this, or fixed width numbers either fit
2027 // or display as ###.
2028 if (!bCellIsValue)
2030 double fVisibleRatio = 1.0;
2031 double fTextWidth = aVars.GetTextSize().Width();
2032 sal_Int32 nTextLen = aString.getLength();
2033 if (eOutHorJust == SVX_HOR_JUSTIFY_LEFT && aAreaParam.mnRightClipLength > 0)
2035 fVisibleRatio = (fTextWidth - aAreaParam.mnRightClipLength) / fTextWidth;
2036 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2038 // Only show the left-end segment.
2039 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2040 aShort = aShort.copy(0, nShortLen);
2043 else if (eOutHorJust == SVX_HOR_JUSTIFY_RIGHT && aAreaParam.mnLeftClipLength > 0)
2045 fVisibleRatio = (fTextWidth - aAreaParam.mnLeftClipLength) / fTextWidth;
2046 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2048 // Only show the right-end segment.
2049 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2050 aShort = aShort.copy(nTextLen-nShortLen);
2052 // Adjust the text position after shortening of the string.
2053 double fShortWidth = pFmtDevice->GetTextWidth(aShort);
2054 double fOffset = fTextWidth - fShortWidth;
2055 aDrawTextPos.Move(fOffset, 0);
2060 // if we are not painting, it means we are interested in
2061 // the area of the text that covers the specified cell
2062 if (!bPaint && rAddress.Col() == nX)
2064 Rectangle aRect;
2065 mpDev->GetTextBoundRect(aRect, aShort);
2066 aRect += aDrawTextPos;
2067 return aRect;
2070 if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
2072 size_t nLen = aShort.getLength();
2073 if (aDX.size() < nLen)
2074 aDX.resize(nLen, 0);
2076 pFmtDevice->GetTextArray(aShort, &aDX[0]);
2078 if ( !mpRefDevice->GetConnectMetaFile() ||
2079 mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
2081 double fMul = GetStretch();
2082 for (size_t i = 0; i < nLen; ++i)
2083 aDX[i] = static_cast<sal_Int32>(aDX[i] / fMul + 0.5);
2086 if (bPaint)
2087 mpDev->DrawTextArray(aDrawTextPos, aShort, &aDX[0]);
2089 else
2091 if (bPaint)
2092 mpDev->DrawText(aDrawTextPos, aShort);
2096 if ( bHClip || bVClip )
2098 if (bMetaFile)
2099 mpDev->Pop();
2100 else
2101 mpDev->SetClipRegion();
2104 // PDF: whole-cell hyperlink from formula?
2105 bool bHasURL = pPDFData && aCell.meType == CELLTYPE_FORMULA && aCell.mpFormula->IsHyperLinkCell();
2106 if (bPaint && bHasURL)
2108 Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
2109 lcl_DoHyperlinkResult(mpDev, aURLRect, aCell);
2113 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
2116 nPosY += pRowInfo[nArrY].nHeight;
2118 if ( bProgress )
2119 ScProgress::DeleteInterpretProgress();
2121 return Rectangle();
2124 ScFieldEditEngine* ScOutputData::CreateOutputEditEngine()
2126 ScFieldEditEngine* pEngine = new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool());
2127 pEngine->SetUpdateMode( false );
2128 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2129 pEngine->SetRefDevice( pFmtDevice );
2130 EEControlBits nCtrl = pEngine->GetControlWord();
2131 if ( bShowSpellErrors )
2132 nCtrl |= EEControlBits::ONLINESPELLING;
2133 if ( eType == OUTTYPE_PRINTER )
2134 nCtrl &= ~EEControlBits::MARKFIELDS;
2135 if ( eType == OUTTYPE_WINDOW && mpRefDevice == pFmtDevice )
2136 nCtrl &= ~EEControlBits::FORMAT100; // use the actual MapMode
2137 pEngine->SetControlWord( nCtrl );
2138 mpDoc->ApplyAsianEditSettings( *pEngine );
2139 pEngine->EnableAutoColor( mbUseStyleColor );
2140 pEngine->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection)mpDoc->GetEditTextDirection( nTab ) );
2141 return pEngine;
2144 static void lcl_ClearEdit( EditEngine& rEngine ) // Text und Attribute
2146 rEngine.SetUpdateMode( false );
2148 rEngine.SetText(EMPTY_OUSTRING);
2149 // keine Para-Attribute uebrigbehalten...
2150 const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
2151 if (rPara.Count())
2152 rEngine.SetParaAttribs( 0,
2153 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
2156 static bool lcl_SafeIsValue( ScRefCellValue& rCell )
2158 switch (rCell.meType)
2160 case CELLTYPE_VALUE:
2161 return true;
2162 case CELLTYPE_FORMULA:
2164 ScFormulaCell* pFCell = rCell.mpFormula;
2165 if (pFCell->IsRunning() || pFCell->IsValue())
2166 return true;
2168 break;
2169 default:
2171 // added to avoid warnings
2174 return false;
2177 static void lcl_ScaleFonts( EditEngine& rEngine, long nPercent )
2179 bool bUpdateMode = rEngine.GetUpdateMode();
2180 if ( bUpdateMode )
2181 rEngine.SetUpdateMode( false );
2183 sal_Int32 nParCount = rEngine.GetParagraphCount();
2184 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
2186 std::vector<sal_Int32> aPortions;
2187 rEngine.GetPortions( nPar, aPortions );
2189 sal_Int32 nStart = 0;
2190 for ( std::vector<sal_Int32>::const_iterator it(aPortions.begin()); it != aPortions.end(); ++it )
2192 sal_Int32 nEnd = *it;
2193 ESelection aSel( nPar, nStart, nPar, nEnd );
2194 SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
2196 long nWestern = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT)).GetHeight();
2197 long nCJK = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK)).GetHeight();
2198 long nCTL = static_cast<const SvxFontHeightItem&>(aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL)).GetHeight();
2200 nWestern = ( nWestern * nPercent ) / 100;
2201 nCJK = ( nCJK * nPercent ) / 100;
2202 nCTL = ( nCTL * nPercent ) / 100;
2204 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
2205 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
2206 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
2208 rEngine.QuickSetAttribs( aAttribs, aSel ); //! remove paragraph attributes from aAttribs?
2210 nStart = nEnd;
2214 if ( bUpdateMode )
2215 rEngine.SetUpdateMode( true );
2218 static long lcl_GetEditSize( EditEngine& rEngine, bool bWidth, bool bSwap, long nAttrRotate )
2220 if ( bSwap )
2221 bWidth = !bWidth;
2223 if ( nAttrRotate )
2225 long nRealWidth = (long) rEngine.CalcTextWidth();
2226 long nRealHeight = rEngine.GetTextHeight();
2228 // assuming standard mode, otherwise width isn't used
2230 double nRealOrient = nAttrRotate * F_PI18000; // 1/100th degrees
2231 double nAbsCos = fabs( cos( nRealOrient ) );
2232 double nAbsSin = fabs( sin( nRealOrient ) );
2233 if ( bWidth )
2234 return (long) ( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2235 else
2236 return (long) ( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2238 else if ( bWidth )
2239 return (long) rEngine.CalcTextWidth();
2240 else
2241 return rEngine.GetTextHeight();
2244 void ScOutputData::ShrinkEditEngine( EditEngine& rEngine, const Rectangle& rAlignRect,
2245 long nLeftM, long nTopM, long nRightM, long nBottomM,
2246 bool bWidth, sal_uInt16 nOrient, long nAttrRotate, bool bPixelToLogic,
2247 long& rEngineWidth, long& rEngineHeight, long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2249 if ( !bWidth )
2251 // vertical
2253 long nScaleSize = bPixelToLogic ?
2254 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2256 // Don't scale if it fits already.
2257 // Allowing to extend into the margin, to avoid scaling at optimal height.
2258 if ( nScaleSize <= rAlignRect.GetHeight() )
2259 return;
2261 bool bSwap = ( nOrient == SVX_ORIENTATION_TOPBOTTOM || nOrient == SVX_ORIENTATION_BOTTOMTOP );
2262 long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2263 long nScale = ( nAvailable * 100 ) / nScaleSize;
2265 lcl_ScaleFonts( rEngine, nScale );
2266 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2267 long nNewSize = bPixelToLogic ?
2268 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2270 sal_uInt16 nShrinkAgain = 0;
2271 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2273 // further reduce, like in DrawStrings
2274 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2275 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2276 nNewSize = bPixelToLogic ?
2277 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2278 ++nShrinkAgain;
2281 // sizes for further processing (alignment etc):
2282 rEngineWidth = lcl_GetEditSize( rEngine, true, bSwap, nAttrRotate );
2283 long nPixelWidth = bPixelToLogic ?
2284 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2285 rNeededPixel = nPixelWidth + nLeftM + nRightM;
2287 else if ( rLeftClip || rRightClip )
2289 // horizontal
2291 long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2292 long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
2294 if ( nScaleSize <= nAvailable )
2295 return;
2297 long nScale = ( nAvailable * 100 ) / nScaleSize;
2299 lcl_ScaleFonts( rEngine, nScale );
2300 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2301 long nNewSize = bPixelToLogic ?
2302 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2304 sal_uInt16 nShrinkAgain = 0;
2305 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2307 // further reduce, like in DrawStrings
2308 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2309 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2310 nNewSize = bPixelToLogic ?
2311 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2312 ++nShrinkAgain;
2314 if ( nNewSize <= nAvailable )
2315 rLeftClip = rRightClip = false;
2317 // sizes for further processing (alignment etc):
2318 rNeededPixel = nNewSize + nLeftM + nRightM;
2319 rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
2323 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
2324 meHorJustAttr( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
2325 meHorJustContext( meHorJustAttr ),
2326 meHorJustResult( meHorJustAttr ),
2327 meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
2328 meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
2329 meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
2330 meOrient( pPattern->GetCellOrientation(pCondSet) ),
2331 mnArrY(0),
2332 mnX(0), mnY(0), mnCellX(0), mnCellY(0), mnTab(0),
2333 mnPosX(0), mnPosY(0), mnInitPosX(0),
2334 mbBreak( (meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
2335 mbCellIsValue(bCellIsValue),
2336 mbAsianVertical(false),
2337 mbPixelToLogic(false),
2338 mbHyphenatorSet(false),
2339 mpEngine(NULL),
2340 mpPattern(pPattern),
2341 mpCondSet(pCondSet),
2342 mpPreviewFontSet(NULL),
2343 mpOldPattern(NULL),
2344 mpOldCondSet(NULL),
2345 mpOldPreviewFontSet(NULL),
2346 mpThisRowInfo(NULL),
2347 mpMisspellRanges(NULL)
2350 bool ScOutputData::DrawEditParam::readCellContent(
2351 ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
2353 if (maCell.meType == CELLTYPE_EDIT)
2355 const EditTextObject* pData = maCell.mpEditText;
2356 if (pData)
2358 mpEngine->SetText(*pData);
2360 if ( mbBreak && !mbAsianVertical && pData->HasField() )
2362 // Fields aren't wrapped, so clipping is enabled to prevent
2363 // a field from being drawn beyond the cell size
2365 rWrapFields = true;
2368 else
2370 OSL_FAIL("pData == 0");
2371 return false;
2374 else
2376 sal_uLong nFormat = mpPattern->GetNumberFormat(
2377 pDoc->GetFormatTable(), mpCondSet );
2378 OUString aString;
2379 Color* pColor;
2380 ScCellFormat::GetString( maCell,
2381 nFormat,aString, &pColor,
2382 *pDoc->GetFormatTable(),
2383 pDoc,
2384 bShowNullValues,
2385 bShowFormulas,
2386 ftCheck );
2388 mpEngine->SetText(aString);
2389 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2390 lcl_SetEditColor( *mpEngine, *pColor );
2393 if (mpMisspellRanges)
2394 mpEngine->SetAllMisspellRanges(*mpMisspellRanges);
2396 return true;
2399 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor)
2401 // syntax highlighting mode is ignored here
2402 // StringDiffer doesn't look at hyphenate, language items
2404 if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
2405 return;
2407 sal_Int32 nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2408 bool bCellContrast = bUseStyleColor &&
2409 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2411 SfxItemSet* pSet = new SfxItemSet( mpEngine->GetEmptyItemSet() );
2412 mpPattern->FillEditItemSet( pSet, mpCondSet );
2413 if ( mpPreviewFontSet )
2415 const SfxPoolItem* pItem;
2416 if ( mpPreviewFontSet->GetItemState( ATTR_FONT, true, &pItem ) == SfxItemState::SET )
2418 SvxFontItem aFontItem(EE_CHAR_FONTINFO);
2419 aFontItem = static_cast<const SvxFontItem&>(*pItem);
2420 pSet->Put( aFontItem );
2422 if ( mpPreviewFontSet->GetItemState( ATTR_CJK_FONT, true, &pItem ) == SfxItemState::SET )
2424 SvxFontItem aCjkFontItem(EE_CHAR_FONTINFO_CJK);
2425 aCjkFontItem = static_cast<const SvxFontItem&>(*pItem);
2426 pSet->Put( aCjkFontItem );
2428 if ( mpPreviewFontSet->GetItemState( ATTR_CTL_FONT, true, &pItem ) == SfxItemState::SET )
2430 SvxFontItem aCtlFontItem(EE_CHAR_FONTINFO_CTL);
2431 aCtlFontItem = static_cast<const SvxFontItem&>(*pItem);
2432 pSet->Put( aCtlFontItem );
2435 mpEngine->SetDefaults( pSet );
2436 mpOldPattern = mpPattern;
2437 mpOldCondSet = mpCondSet;
2438 mpOldPreviewFontSet = mpPreviewFontSet;
2440 EEControlBits nControl = mpEngine->GetControlWord();
2441 if (meOrient == SVX_ORIENTATION_STACKED)
2442 nControl |= EEControlBits::ONECHARPERLINE;
2443 else
2444 nControl &= ~EEControlBits::ONECHARPERLINE;
2445 mpEngine->SetControlWord( nControl );
2447 if ( !mbHyphenatorSet && static_cast<const SfxBoolItem&>(pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
2449 // set hyphenator the first time it is needed
2450 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2451 mpEngine->SetHyphenator( xXHyphenator );
2452 mbHyphenatorSet = true;
2455 Color aBackCol = static_cast<const SvxBrushItem&>(mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet )).GetColor();
2456 if ( bUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
2457 aBackCol.SetColor( nConfBackColor );
2458 mpEngine->SetBackgroundColor( aBackCol );
2461 void ScOutputData::DrawEditParam::calcMargins(long& rTopM, long& rLeftM, long& rBottomM, long& rRightM, double nPPTX, double nPPTY) const
2463 const SvxMarginItem& rMargin =
2464 static_cast<const SvxMarginItem&>(mpPattern->GetItem(ATTR_MARGIN, mpCondSet));
2466 sal_uInt16 nIndent = 0;
2467 if (meHorJustAttr == SVX_HOR_JUSTIFY_LEFT || meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2468 nIndent = lcl_GetValue<SfxUInt16Item, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
2470 rLeftM = static_cast<long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
2471 rTopM = static_cast<long>((rMargin.GetTopMargin() * nPPTY));
2472 rRightM = static_cast<long>((rMargin.GetRightMargin() * nPPTX));
2473 rBottomM = static_cast<long>((rMargin.GetBottomMargin() * nPPTY));
2474 if(meHorJustAttr == SVX_HOR_JUSTIFY_RIGHT)
2476 rLeftM = static_cast<long>((rMargin.GetLeftMargin() * nPPTX));
2477 rRightM = static_cast<long>(((rMargin.GetRightMargin() + nIndent) * nPPTX));
2481 void ScOutputData::DrawEditParam::calcPaperSize(
2482 Size& rPaperSize, const Rectangle& rAlignRect, double nPPTX, double nPPTY) const
2484 long nTopM, nLeftM, nBottomM, nRightM;
2485 calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
2487 if (isVerticallyOriented())
2489 rPaperSize.Width() = rAlignRect.GetHeight() - nTopM - nBottomM;
2490 rPaperSize.Height() = rAlignRect.GetWidth() - nLeftM - nRightM;
2492 else
2494 rPaperSize.Width() = rAlignRect.GetWidth() - nLeftM - nRightM;
2495 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2498 if (mbAsianVertical)
2500 rPaperSize.Height() = rAlignRect.GetHeight() - nTopM - nBottomM;
2501 // Subtract some extra value from the height or else the text would go
2502 // outside the cell area. The value of 5 is arbitrary, and is based
2503 // entirely on heuristics.
2504 rPaperSize.Height() -= 5;
2508 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine* pEngine, long& rWidth, long& rHeight) const
2510 long nEngineWidth = 0;
2511 if (!mbBreak || meOrient == SVX_ORIENTATION_STACKED || mbAsianVertical)
2512 nEngineWidth = static_cast<long>(pEngine->CalcTextWidth());
2514 long nEngineHeight = pEngine->GetTextHeight();
2516 if (isVerticallyOriented())
2518 long nTemp = nEngineWidth;
2519 nEngineWidth = nEngineHeight;
2520 nEngineHeight = nTemp;
2523 if (meOrient == SVX_ORIENTATION_STACKED)
2524 nEngineWidth = nEngineWidth * 11 / 10;
2526 rWidth = nEngineWidth;
2527 rHeight = nEngineHeight;
2530 bool ScOutputData::DrawEditParam::hasLineBreak() const
2532 return (mbBreak || (meOrient == SVX_ORIENTATION_STACKED) || mbAsianVertical);
2535 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2537 if (maCell.meType != CELLTYPE_FORMULA)
2538 return false;
2540 return maCell.mpFormula->IsHyperLinkCell();
2543 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2545 return (meOrient == SVX_ORIENTATION_TOPBOTTOM || meOrient == SVX_ORIENTATION_BOTTOMTOP);
2548 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2549 Point& rLogicStart, long nCellWidth, long nEngineWidth, long nTopM, OutputDevice* pRefDevice)
2551 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2553 if (mbPixelToLogic)
2554 rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
2556 if (mbBreak)
2558 // vertical adjustment is within the EditEngine
2559 if (mbPixelToLogic)
2560 rLogicStart.Y() += pRefDevice->PixelToLogic(Size(0,nTopM)).Height();
2561 else
2562 rLogicStart.Y() += nTopM;
2564 switch (meHorJustResult)
2566 case SVX_HOR_JUSTIFY_CENTER:
2567 rLogicStart.X() += (nCellWidth - nEngineWidth) / 2;
2568 break;
2569 case SVX_HOR_JUSTIFY_RIGHT:
2570 rLogicStart.X() += nCellWidth - nEngineWidth;
2571 break;
2572 default:
2573 ; // do nothing
2578 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2580 if (isVerticallyOriented() || mbAsianVertical)
2582 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2583 switch (meVerJust)
2585 case SVX_VER_JUSTIFY_TOP:
2586 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2587 SVX_ADJUST_LEFT : SVX_ADJUST_RIGHT;
2588 break;
2589 case SVX_VER_JUSTIFY_CENTER:
2590 eSvxAdjust = SVX_ADJUST_CENTER;
2591 break;
2592 case SVX_VER_JUSTIFY_BOTTOM:
2593 case SVX_VER_JUSTIFY_STANDARD:
2594 eSvxAdjust = (meOrient == SVX_ORIENTATION_TOPBOTTOM || mbAsianVertical) ?
2595 SVX_ADJUST_RIGHT : SVX_ADJUST_LEFT;
2596 break;
2597 case SVX_VER_JUSTIFY_BLOCK:
2598 eSvxAdjust = SVX_ADJUST_BLOCK;
2599 break;
2602 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2603 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2605 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2606 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2608 else
2610 // horizontal alignment now may depend on cell content
2611 // (for values with number formats with mixed script types)
2612 // -> always set adjustment
2614 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
2615 if (meOrient == SVX_ORIENTATION_STACKED)
2616 eSvxAdjust = SVX_ADJUST_CENTER;
2617 else if (mbBreak)
2619 if (meOrient == SVX_ORIENTATION_STANDARD)
2620 switch (meHorJustResult)
2622 case SVX_HOR_JUSTIFY_REPEAT: // repeat is not yet implemented
2623 case SVX_HOR_JUSTIFY_STANDARD:
2624 assert(!"meHorJustResult does not match getAlignmentFromContext()");
2625 // fallthru
2626 case SVX_HOR_JUSTIFY_LEFT:
2627 eSvxAdjust = SVX_ADJUST_LEFT;
2628 break;
2629 case SVX_HOR_JUSTIFY_CENTER:
2630 eSvxAdjust = SVX_ADJUST_CENTER;
2631 break;
2632 case SVX_HOR_JUSTIFY_RIGHT:
2633 eSvxAdjust = SVX_ADJUST_RIGHT;
2634 break;
2635 case SVX_HOR_JUSTIFY_BLOCK:
2636 eSvxAdjust = SVX_ADJUST_BLOCK;
2637 break;
2639 else
2640 switch (meVerJust)
2642 case SVX_VER_JUSTIFY_TOP:
2643 eSvxAdjust = SVX_ADJUST_RIGHT;
2644 break;
2645 case SVX_VER_JUSTIFY_CENTER:
2646 eSvxAdjust = SVX_ADJUST_CENTER;
2647 break;
2648 case SVX_VER_JUSTIFY_BOTTOM:
2649 case SVX_VER_JUSTIFY_STANDARD:
2650 eSvxAdjust = SVX_ADJUST_LEFT;
2651 break;
2652 case SVX_VER_JUSTIFY_BLOCK:
2653 eSvxAdjust = SVX_ADJUST_BLOCK;
2654 break;
2658 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2660 if (mbAsianVertical)
2662 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2663 if (meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
2664 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2666 else
2668 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
2669 if (meVerJust == SVX_VER_JUSTIFY_BLOCK)
2670 mpEngine->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK, EE_PARA_VER_JUST) );
2674 mpEngine->SetVertical(mbAsianVertical);
2675 if (maCell.meType == CELLTYPE_EDIT)
2677 // We need to synchronize the vertical mode in the EditTextObject
2678 // instance too. No idea why we keep this state in two separate
2679 // instances.
2680 const EditTextObject* pData = maCell.mpEditText;
2681 if (pData)
2682 const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
2686 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine* pEngine)
2688 if (meHorJustResult == SVX_HOR_JUSTIFY_RIGHT || meHorJustResult == SVX_HOR_JUSTIFY_CENTER)
2690 SvxAdjust eEditAdjust = (meHorJustResult == SVX_HOR_JUSTIFY_CENTER) ?
2691 SVX_ADJUST_CENTER : SVX_ADJUST_RIGHT;
2693 pEngine->SetUpdateMode(false);
2694 pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
2695 pEngine->SetUpdateMode(true);
2696 return true;
2698 return false;
2701 void ScOutputData::DrawEditParam::adjustForRTL()
2703 if (!mpEngine->IsRightToLeft(0))
2704 // No RTL mode.
2705 return;
2707 // For right-to-left, EditEngine always calculates its lines
2708 // beginning from the right edge, but EditLine::nStartPosX is
2709 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2710 Size aLogicPaper = mpEngine->GetPaperSize();
2711 if ( aLogicPaper.Width() > USHRT_MAX )
2713 aLogicPaper.Width() = USHRT_MAX;
2714 mpEngine->SetPaperSize(aLogicPaper);
2718 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart, OutputDevice* pDev)
2720 // PDF: whole-cell hyperlink from formula?
2721 vcl::PDFExtOutDevData* pPDFData = PTR_CAST( vcl::PDFExtOutDevData, pDev->GetExtOutDevData() );
2722 bool bHasURL = pPDFData && isHyperlinkCell();
2723 if (!bHasURL)
2724 return;
2726 long nURLWidth = (long) mpEngine->CalcTextWidth();
2727 long nURLHeight = mpEngine->GetTextHeight();
2728 if (mbBreak)
2730 Size aPaper = mpEngine->GetPaperSize();
2731 if ( mbAsianVertical )
2732 nURLHeight = aPaper.Height();
2733 else
2734 nURLWidth = aPaper.Width();
2736 if (isVerticallyOriented())
2737 std::swap( nURLWidth, nURLHeight );
2738 else if (mbAsianVertical)
2739 aURLStart.X() -= nURLWidth;
2741 Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2742 lcl_DoHyperlinkResult(pDev, aURLRect, maCell);
2745 void ScOutputData::DrawEditStandard(DrawEditParam& rParam)
2747 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
2748 OSL_ASSERT(!rParam.mbAsianVertical);
2750 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
2752 bool bHidden = false;
2753 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
2754 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
2755 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
2757 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT )
2759 // ignore orientation/rotation if "repeat" is active
2760 rParam.meOrient = SVX_ORIENTATION_STANDARD;
2761 nAttrRotate = 0;
2763 // #i31843# "repeat" with "line breaks" is treated as default alignment
2764 // (but rotation is still disabled).
2765 // Default again leads to context dependent alignment instead of
2766 // SVX_HOR_JUSTIFY_STANDARD.
2767 if ( rParam.mbBreak )
2768 rParam.meHorJustResult = rParam.meHorJustContext;
2771 if (nAttrRotate)
2773 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2774 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2775 bHidden = true; // gedreht wird getrennt ausgegeben
2778 if (bHidden)
2779 return;
2781 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
2783 //! mirror margin values for RTL?
2784 //! move margin down to after final GetOutputArea call
2785 long nTopM, nLeftM, nBottomM, nRightM;
2786 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
2788 SCCOL nXForPos = rParam.mnX;
2789 if ( nXForPos < nX1 )
2791 nXForPos = nX1;
2792 rParam.mnPosX = rParam.mnInitPosX;
2794 SCSIZE nArrYForPos = rParam.mnArrY;
2795 if ( nArrYForPos < 1 )
2797 nArrYForPos = 1;
2798 rParam.mnPosY = nScrY;
2801 OutputAreaParam aAreaParam;
2803 // Initial page size - large for normal text, cell size for automatic line breaks
2805 Size aPaperSize = Size( 1000000, 1000000 );
2806 if (rParam.mbBreak)
2808 // call GetOutputArea with nNeeded=0, to get only the cell width
2810 //! handle nArrY == 0
2811 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
2812 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2813 rParam.mbCellIsValue, true, false, aAreaParam );
2815 //! special ScEditUtil handling if formatting for printer
2816 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
2818 if (rParam.mbPixelToLogic)
2820 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
2821 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
2823 // #i85342# screen display and formatting for printer,
2824 // use same GetEditArea call as in ScViewData::SetEditEngine
2826 Fraction aFract(1,1);
2827 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
2828 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
2829 aLogicSize.Width() = aUtilRect.GetWidth();
2831 rParam.mpEngine->SetPaperSize(aLogicSize);
2833 else
2834 rParam.mpEngine->SetPaperSize(aPaperSize);
2836 // Fill the EditEngine (cell attributes and text)
2838 // default alignment for asian vertical mode is top-right
2839 if ( rParam.mbAsianVertical && rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
2840 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
2842 rParam.setPatternToEngine(mbUseStyleColor);
2843 rParam.setAlignmentToEngine();
2845 // Read content from cell
2847 bool bWrapFields = false;
2848 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
2849 // Failed to read cell content. Bail out.
2850 return;
2852 if ( mbSyntaxMode )
2853 SetEditSyntaxColor(*rParam.mpEngine, rParam.maCell);
2854 else if ( mbUseStyleColor && mbForceAutoColor )
2855 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
2857 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
2859 // Get final output area using the calculated width
2861 long nEngineWidth, nEngineHeight;
2862 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
2864 long nNeededPixel = nEngineWidth;
2865 if (rParam.mbPixelToLogic)
2866 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2867 nNeededPixel += nLeftM + nRightM;
2869 if (!rParam.mbBreak || bShrink)
2871 // for break, the first GetOutputArea call is sufficient
2872 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
2873 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2874 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2876 if ( bShrink )
2878 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
2879 nLeftM, nTopM, nRightM, nBottomM, true,
2880 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
2881 nEngineWidth, nEngineHeight, nNeededPixel,
2882 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
2884 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
2886 // First check if twice the space for the formatted text is available
2887 // (otherwise just keep it unchanged).
2889 long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
2890 long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
2891 if ( nAvailable >= 2 * nFormatted )
2893 // "repeat" is handled with unformatted text (for performance reasons)
2894 OUString aCellStr = rParam.mpEngine->GetText();
2895 rParam.mpEngine->SetText( aCellStr );
2897 long nRepeatSize = (long) rParam.mpEngine->CalcTextWidth();
2898 if (rParam.mbPixelToLogic)
2899 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
2900 if ( pFmtDevice != mpRefDevice )
2901 ++nRepeatSize;
2902 if ( nRepeatSize > 0 )
2904 long nRepeatCount = nAvailable / nRepeatSize;
2905 if ( nRepeatCount > 1 )
2907 OUString aRepeated = aCellStr;
2908 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
2909 aRepeated += aCellStr;
2910 rParam.mpEngine->SetText( aRepeated );
2912 nEngineHeight = rParam.mpEngine->GetTextHeight();
2913 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2914 if (rParam.mbPixelToLogic)
2915 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2916 else
2917 nNeededPixel = nEngineWidth;
2918 nNeededPixel += nLeftM + nRightM;
2924 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
2926 rParam.mpEngine->SetText(OUString("###"));
2927 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
2928 if (rParam.mbPixelToLogic)
2929 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
2930 else
2931 nNeededPixel = nEngineWidth;
2932 nNeededPixel += nLeftM + nRightM;
2934 // No clip marks if "###" doesn't fit (same as in DrawStrings)
2937 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
2939 aPaperSize.Width() = nNeededPixel + 1;
2940 if (rParam.mbPixelToLogic)
2941 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
2942 else
2943 rParam.mpEngine->SetPaperSize(aPaperSize);
2947 long nStartX = aAreaParam.maAlignRect.Left();
2948 long nStartY = aAreaParam.maAlignRect.Top();
2949 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
2950 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
2951 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
2953 if (rParam.mbBreak)
2955 // text with automatic breaks is aligned only within the
2956 // edit engine's paper size, the output of the whole area
2957 // is always left-aligned
2959 nStartX += nLeftM;
2961 else
2963 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
2964 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
2965 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
2966 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
2967 else
2968 nStartX += nLeftM;
2971 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
2972 if (bOutside)
2973 return;
2975 if ( aAreaParam.maClipRect.Left() < nScrX )
2977 aAreaParam.maClipRect.Left() = nScrX;
2978 aAreaParam.mbLeftClip = true;
2980 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
2982 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
2983 aAreaParam.mbRightClip = true;
2986 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
2987 bool bSimClip = false;
2989 if ( bWrapFields )
2991 // Fields in a cell with automatic breaks: clip to cell width
2992 bClip = true;
2995 if ( aAreaParam.maClipRect.Top() < nScrY )
2997 aAreaParam.maClipRect.Top() = nScrY;
2998 bClip = true;
3000 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3002 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3003 bClip = true;
3006 Size aCellSize; // output area, excluding margins, in logical units
3007 if (rParam.mbPixelToLogic)
3008 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3009 else
3010 aCellSize = Size( nOutWidth, nOutHeight );
3012 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3014 const ScMergeAttr* pMerge =
3015 static_cast<const ScMergeAttr*>(&rParam.mpPattern->GetItem(ATTR_MERGE));
3016 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3018 // Don't clip for text height when printing rows with optimal height,
3019 // except when font size is from conditional formatting.
3020 //! Allow clipping when vertically merged?
3021 if ( eType != OUTTYPE_PRINTER ||
3022 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3023 ( rParam.mpCondSet && SfxItemState::SET ==
3024 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3025 bClip = true;
3026 else
3027 bSimClip = true;
3029 // Show clip marks if height is at least 5pt too small and
3030 // there are several lines of text.
3031 // Not for asian vertical text, because that would interfere
3032 // with the default right position of the text.
3033 // Only with automatic line breaks, to avoid having to find
3034 // the cells with the horizontal end of the text again.
3035 if ( nEngineHeight - aCellSize.Height() > 100 &&
3036 rParam.mbBreak && bMarkClipped &&
3037 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3039 CellInfo* pClipMarkCell = NULL;
3040 if ( bMerged )
3042 // anywhere in the merged area...
3043 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3044 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3046 else
3047 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3049 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3050 bAnyClipped = true;
3052 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
3053 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3054 aAreaParam.maClipRect.Right() -= nMarkPixel;
3058 Rectangle aLogicClip;
3059 if (bClip || bSimClip)
3061 // Clip marks are already handled in GetOutputArea
3063 if (rParam.mbPixelToLogic)
3064 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3065 else
3066 aLogicClip = aAreaParam.maClipRect;
3068 if (bClip) // bei bSimClip nur aClipRect initialisieren
3070 if (bMetaFile)
3072 mpDev->Push();
3073 mpDev->IntersectClipRegion( aLogicClip );
3075 else
3076 mpDev->SetClipRegion( vcl::Region( aLogicClip ) );
3080 Point aLogicStart;
3081 if (rParam.mbPixelToLogic)
3082 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
3083 else
3084 aLogicStart = Point(nStartX, nStartY);
3086 if (!rParam.mbBreak)
3088 // horizontal alignment
3089 if (rParam.adjustHorAlignment(rParam.mpEngine))
3090 // reset adjustment for the next cell
3091 rParam.mpOldPattern = NULL;
3094 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
3095 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
3097 //! if pRefDevice != pFmtDevice, keep heights in logic units,
3098 //! only converting margin?
3100 if (rParam.mbPixelToLogic)
3101 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
3102 mpRefDevice->LogicToPixel(aCellSize).Height() -
3103 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3104 )).Height();
3105 else
3106 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
3108 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
3110 if (rParam.mbPixelToLogic)
3111 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
3112 mpRefDevice->LogicToPixel(aCellSize).Height() -
3113 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
3114 / 2)).Height();
3115 else
3116 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
3118 else // top
3120 if (rParam.mbPixelToLogic)
3121 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3122 else
3123 aLogicStart.Y() += nTopM;
3126 Point aURLStart = aLogicStart; // copy before modifying for orientation
3128 rParam.adjustForRTL();
3130 // bMoveClipped handling has been replaced by complete alignment
3131 // handling (also extending to the left).
3133 if (bSimClip)
3135 // kein hartes Clipping, aber nur die betroffenen
3136 // Zeilen ausgeben
3138 Point aDocStart = aLogicClip.TopLeft();
3139 aDocStart -= aLogicStart;
3140 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
3142 else
3144 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
3147 if (bClip)
3149 if (bMetaFile)
3150 mpDev->Pop();
3151 else
3152 mpDev->SetClipRegion();
3155 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3158 void ScOutputData::ShowClipMarks( DrawEditParam& rParam, long nEngineHeight, const Size& aCellSize,
3159 bool bMerged, OutputAreaParam& aAreaParam)
3161 // Show clip marks if height is at least 5pt too small and
3162 // there are several lines of text.
3163 // Not for asian vertical text, because that would interfere
3164 // with the default right position of the text.
3165 // Only with automatic line breaks, to avoid having to find
3166 // the cells with the horizontal end of the text again.
3167 if ( nEngineHeight - aCellSize.Height() > 100 &&
3168 rParam.mbBreak && bMarkClipped &&
3169 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3171 CellInfo* pClipMarkCell = NULL;
3172 if ( bMerged )
3174 // anywhere in the merged area...
3175 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3176 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
3178 else
3179 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
3181 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
3182 bAnyClipped = true;
3184 const long nMarkPixel = static_cast<long>( SC_CLIPMARK_SIZE * mnPPTX );
3185 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3186 aAreaParam.maClipRect.Right() -= nMarkPixel;
3190 bool ScOutputData::Clip( DrawEditParam& rParam, const Size& aCellSize,
3191 OutputAreaParam& aAreaParam, long nEngineHeight,
3192 bool bWrapFields)
3194 if ( aAreaParam.maClipRect.Left() < nScrX )
3196 aAreaParam.maClipRect.Left() = nScrX;
3197 aAreaParam.mbLeftClip = true;
3199 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3201 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3202 aAreaParam.mbRightClip = true;
3205 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3206 bool bSimClip = false;
3208 if ( bWrapFields )
3210 // Fields in a cell with automatic breaks: clip to cell width
3211 bClip = true;
3214 if ( aAreaParam.maClipRect.Top() < nScrY )
3216 aAreaParam.maClipRect.Top() = nScrY;
3217 bClip = true;
3219 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3221 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3222 bClip = true;
3225 const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3226 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3228 const ScMergeAttr* pMerge =
3229 static_cast<const ScMergeAttr*>(&rParam.mpPattern->GetItem(ATTR_MERGE));
3230 const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3232 // Don't clip for text height when printing rows with optimal height,
3233 // except when font size is from conditional formatting.
3234 //! Allow clipping when vertically merged?
3235 if ( eType != OUTTYPE_PRINTER ||
3236 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3237 ( rParam.mpCondSet && SfxItemState::SET ==
3238 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
3239 bClip = true;
3240 else
3241 bSimClip = true;
3243 ShowClipMarks( rParam, nEngineHeight, aCellSize, bMerged, aAreaParam);
3246 Rectangle aLogicClip;
3247 if (bClip || bSimClip)
3249 // Clip marks are already handled in GetOutputArea
3251 if (rParam.mbPixelToLogic)
3252 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
3253 else
3254 aLogicClip = aAreaParam.maClipRect;
3256 if (bClip) // bei bSimClip nur aClipRect initialisieren
3258 if (bMetaFile)
3260 mpDev->Push();
3261 mpDev->IntersectClipRegion( aLogicClip );
3263 else
3264 mpDev->SetClipRegion( vcl::Region( aLogicClip ) );
3268 return bClip;
3271 void ScOutputData::DrawEditBottomTop(DrawEditParam& rParam)
3273 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3275 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3276 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3278 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3280 //! mirror margin values for RTL?
3281 //! move margin down to after final GetOutputArea call
3282 long nTopM, nLeftM, nBottomM, nRightM;
3283 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3285 SCCOL nXForPos = rParam.mnX;
3286 if ( nXForPos < nX1 )
3288 nXForPos = nX1;
3289 rParam.mnPosX = rParam.mnInitPosX;
3291 SCSIZE nArrYForPos = rParam.mnArrY;
3292 if ( nArrYForPos < 1 )
3294 nArrYForPos = 1;
3295 rParam.mnPosY = nScrY;
3298 OutputAreaParam aAreaParam;
3300 // Initial page size - large for normal text, cell size for automatic line breaks
3302 Size aPaperSize = Size( 1000000, 1000000 );
3303 if (rParam.mbBreak)
3305 // call GetOutputArea with nNeeded=0, to get only the cell width
3307 //! handle nArrY == 0
3308 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3309 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3310 rParam.mbCellIsValue, true, false, aAreaParam );
3312 //! special ScEditUtil handling if formatting for printer
3313 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3315 if (rParam.mbPixelToLogic)
3317 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3318 rParam.mpEngine->SetPaperSize(aLogicSize);
3320 else
3321 rParam.mpEngine->SetPaperSize(aPaperSize);
3323 // Fill the EditEngine (cell attributes and text)
3325 rParam.setPatternToEngine(mbUseStyleColor);
3326 rParam.setAlignmentToEngine();
3328 // Read content from cell
3330 bool bWrapFields = false;
3331 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3332 // Failed to read cell content. Bail out.
3333 return;
3335 if ( mbSyntaxMode )
3336 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3337 else if ( mbUseStyleColor && mbForceAutoColor )
3338 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3340 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3342 // Get final output area using the calculated width
3344 long nEngineWidth, nEngineHeight;
3345 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3347 long nNeededPixel = nEngineWidth;
3348 if (rParam.mbPixelToLogic)
3349 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3350 nNeededPixel += nLeftM + nRightM;
3352 if (!rParam.mbBreak || bShrink)
3354 // for break, the first GetOutputArea call is sufficient
3355 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3356 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3357 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3359 if ( bShrink )
3361 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3362 nLeftM, nTopM, nRightM, nBottomM, false,
3363 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3364 nEngineWidth, nEngineHeight, nNeededPixel,
3365 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3367 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3369 // First check if twice the space for the formatted text is available
3370 // (otherwise just keep it unchanged).
3372 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3373 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3374 if ( nAvailable >= 2 * nFormatted )
3376 // "repeat" is handled with unformatted text (for performance reasons)
3377 OUString aCellStr = rParam.mpEngine->GetText();
3378 rParam.mpEngine->SetText( aCellStr );
3380 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3381 if (rParam.mbPixelToLogic)
3382 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3383 if ( pFmtDevice != mpRefDevice )
3384 ++nRepeatSize;
3385 if ( nRepeatSize > 0 )
3387 const long nRepeatCount = nAvailable / nRepeatSize;
3388 if ( nRepeatCount > 1 )
3390 OUString aRepeated = aCellStr;
3391 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3392 aRepeated += aCellStr;
3393 rParam.mpEngine->SetText( aRepeated );
3395 nEngineHeight = rParam.mpEngine->GetTextHeight();
3396 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3397 if (rParam.mbPixelToLogic)
3398 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3399 else
3400 nNeededPixel = nEngineWidth;
3401 nNeededPixel += nLeftM + nRightM;
3407 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3409 rParam.mpEngine->SetText(OUString("###"));
3410 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3411 if (rParam.mbPixelToLogic)
3412 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3413 else
3414 nNeededPixel = nEngineWidth;
3415 nNeededPixel += nLeftM + nRightM;
3417 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3421 long nStartX = aAreaParam.maAlignRect.Left();
3422 const long nStartY = aAreaParam.maAlignRect.Top();
3423 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3424 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3425 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3427 if (rParam.mbBreak)
3429 // text with automatic breaks is aligned only within the
3430 // edit engine's paper size, the output of the whole area
3431 // is always left-aligned
3433 nStartX += nLeftM;
3435 else
3437 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3438 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3439 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3440 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3441 else
3442 nStartX += nLeftM;
3445 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3446 if (bOutside)
3447 return;
3449 // output area, excluding margins, in logical units
3450 const Size& aCellSize = rParam.mbPixelToLogic
3451 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3452 : Size( nOutWidth, nOutHeight );
3454 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3456 Point aLogicStart(nStartX, nStartY);
3457 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3459 Point aURLStart = aLogicStart; // copy before modifying for orientation
3461 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK || rParam.mbBreak)
3463 Size aPSize = rParam.mpEngine->GetPaperSize();
3464 aPSize.Width() = aCellSize.Height();
3465 rParam.mpEngine->SetPaperSize(aPSize);
3466 aLogicStart.Y() +=
3467 rParam.mbBreak ? aPSize.Width() : nEngineHeight;
3469 else
3471 // Note that the "paper" is rotated 90 degrees to the left, so
3472 // paper's width is in vertical direction. Also, the whole text
3473 // is on a single line, as text wrap is not in effect.
3475 // Set the paper width to be the width of the text.
3476 Size aPSize = rParam.mpEngine->GetPaperSize();
3477 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3478 rParam.mpEngine->SetPaperSize(aPSize);
3480 long nGap = 0;
3481 long nTopOffset = 0;
3482 if (rParam.mbPixelToLogic)
3484 nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
3485 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3486 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3488 else
3490 nGap = aCellSize.Height() - aPSize.Width();
3491 nTopOffset = nTopM;
3494 // First, align text to bottom.
3495 aLogicStart.Y() += aCellSize.Height();
3496 aLogicStart.Y() += nTopOffset;
3498 switch (rParam.meVerJust)
3500 case SVX_VER_JUSTIFY_STANDARD:
3501 case SVX_VER_JUSTIFY_BOTTOM:
3502 // align to bottom (do nothing).
3503 break;
3504 case SVX_VER_JUSTIFY_CENTER:
3505 // center it.
3506 aLogicStart.Y() -= nGap / 2;
3507 break;
3508 case SVX_VER_JUSTIFY_BLOCK:
3509 case SVX_VER_JUSTIFY_TOP:
3510 // align to top
3511 aLogicStart.Y() -= nGap;
3512 default:
3517 rParam.adjustForRTL();
3518 rParam.mpEngine->Draw(mpDev, aLogicStart, 900);
3520 if (bClip)
3522 if (bMetaFile)
3523 mpDev->Pop();
3524 else
3525 mpDev->SetClipRegion();
3528 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3531 void ScOutputData::DrawEditTopBottom(DrawEditParam& rParam)
3533 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3535 const bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3536 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3538 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3540 //! mirror margin values for RTL?
3541 //! move margin down to after final GetOutputArea call
3542 long nTopM, nLeftM, nBottomM, nRightM;
3543 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3545 SCCOL nXForPos = rParam.mnX;
3546 if ( nXForPos < nX1 )
3548 nXForPos = nX1;
3549 rParam.mnPosX = rParam.mnInitPosX;
3551 SCSIZE nArrYForPos = rParam.mnArrY;
3552 if ( nArrYForPos < 1 )
3554 nArrYForPos = 1;
3555 rParam.mnPosY = nScrY;
3558 OutputAreaParam aAreaParam;
3560 // Initial page size - large for normal text, cell size for automatic line breaks
3562 Size aPaperSize = Size( 1000000, 1000000 );
3563 if (rParam.hasLineBreak())
3565 // call GetOutputArea with nNeeded=0, to get only the cell width
3567 //! handle nArrY == 0
3568 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3569 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3570 rParam.mbCellIsValue, true, false, aAreaParam );
3572 //! special ScEditUtil handling if formatting for printer
3573 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3575 if (rParam.mbPixelToLogic)
3577 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3578 rParam.mpEngine->SetPaperSize(aLogicSize);
3580 else
3581 rParam.mpEngine->SetPaperSize(aPaperSize);
3583 // Fill the EditEngine (cell attributes and text)
3585 rParam.setPatternToEngine(mbUseStyleColor);
3586 rParam.setAlignmentToEngine();
3588 // Read content from cell
3590 bool bWrapFields = false;
3591 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3592 // Failed to read cell content. Bail out.
3593 return;
3595 if ( mbSyntaxMode )
3596 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3597 else if ( mbUseStyleColor && mbForceAutoColor )
3598 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3600 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3602 // Get final output area using the calculated width
3604 long nEngineWidth, nEngineHeight;
3605 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3607 long nNeededPixel = nEngineWidth;
3608 if (rParam.mbPixelToLogic)
3609 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3610 nNeededPixel += nLeftM + nRightM;
3612 if (!rParam.mbBreak || bShrink)
3614 // for break, the first GetOutputArea call is sufficient
3615 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3616 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3617 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3619 if ( bShrink )
3621 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3622 nLeftM, nTopM, nRightM, nBottomM, false,
3623 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3624 nEngineWidth, nEngineHeight, nNeededPixel,
3625 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3627 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3629 // First check if twice the space for the formatted text is available
3630 // (otherwise just keep it unchanged).
3632 const long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3633 const long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3634 if ( nAvailable >= 2 * nFormatted )
3636 // "repeat" is handled with unformatted text (for performance reasons)
3637 OUString aCellStr = rParam.mpEngine->GetText();
3638 rParam.mpEngine->SetText( aCellStr );
3640 long nRepeatSize = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3641 if (rParam.mbPixelToLogic)
3642 nRepeatSize = mpRefDevice->LogicToPixel(Size(nRepeatSize,0)).Width();
3643 if ( pFmtDevice != mpRefDevice )
3644 ++nRepeatSize;
3645 if ( nRepeatSize > 0 )
3647 const long nRepeatCount = nAvailable / nRepeatSize;
3648 if ( nRepeatCount > 1 )
3650 OUString aRepeated = aCellStr;
3651 for ( long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3652 aRepeated += aCellStr;
3653 rParam.mpEngine->SetText( aRepeated );
3655 nEngineHeight = rParam.mpEngine->GetTextHeight();
3656 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3657 if (rParam.mbPixelToLogic)
3658 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3659 else
3660 nNeededPixel = nEngineWidth;
3661 nNeededPixel += nLeftM + nRightM;
3667 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3669 rParam.mpEngine->SetText(OUString("###"));
3670 nEngineWidth = static_cast<long>( rParam.mpEngine->CalcTextWidth() );
3671 if (rParam.mbPixelToLogic)
3672 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3673 else
3674 nNeededPixel = nEngineWidth;
3675 nNeededPixel += nLeftM + nRightM;
3677 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3681 long nStartX = aAreaParam.maAlignRect.Left();
3682 const long nStartY = aAreaParam.maAlignRect.Top();
3683 const long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3684 const long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3685 const long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3687 if (rParam.mbBreak)
3689 // text with automatic breaks is aligned only within the
3690 // edit engine's paper size, the output of the whole area
3691 // is always left-aligned
3693 nStartX += nLeftM;
3694 if (rParam.meHorJustResult == SVX_HOR_JUSTIFY_BLOCK)
3695 nStartX += aPaperSize.Height();
3697 else
3699 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3700 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3701 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3702 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3703 else
3704 nStartX += nLeftM;
3707 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3708 if (bOutside)
3709 return;
3711 // output area, excluding margins, in logical units
3712 const Size& aCellSize = rParam.mbPixelToLogic
3713 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3714 : Size( nOutWidth, nOutHeight );
3716 const bool bClip = Clip( rParam, aCellSize, aAreaParam, nEngineHeight, bWrapFields );
3718 Point aLogicStart(nStartX, nStartY);
3719 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3721 Point aURLStart = aLogicStart; // copy before modifying for orientation
3723 if (rParam.meHorJustResult != SVX_HOR_JUSTIFY_BLOCK)
3725 aLogicStart.X() += nEngineWidth;
3726 if (!rParam.mbBreak)
3728 // Set the paper width to text size.
3729 Size aPSize = rParam.mpEngine->GetPaperSize();
3730 aPSize.Width() = rParam.mpEngine->CalcTextWidth();
3731 rParam.mpEngine->SetPaperSize(aPSize);
3733 long nGap = 0;
3734 long nTopOffset = 0; // offset by top margin
3735 if (rParam.mbPixelToLogic)
3737 nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
3738 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3739 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3741 else
3743 nGap = aPSize.Width() - aCellSize.Height();
3744 nTopOffset = nTopM;
3746 aLogicStart.Y() += nTopOffset;
3748 switch (rParam.meVerJust)
3750 case SVX_VER_JUSTIFY_STANDARD:
3751 case SVX_VER_JUSTIFY_BOTTOM:
3752 // align to bottom
3753 aLogicStart.Y() -= nGap;
3754 break;
3755 case SVX_VER_JUSTIFY_CENTER:
3756 // center it.
3757 aLogicStart.Y() -= nGap / 2;
3758 break;
3759 case SVX_VER_JUSTIFY_BLOCK:
3760 case SVX_VER_JUSTIFY_TOP:
3761 // align to top (do nothing)
3762 default:
3768 rParam.adjustForRTL();
3770 // bMoveClipped handling has been replaced by complete alignment
3771 // handling (also extending to the left).
3773 rParam.mpEngine->Draw(mpDev, aLogicStart, 2700);
3775 if (bClip)
3777 if (bMetaFile)
3778 mpDev->Pop();
3779 else
3780 mpDev->SetClipRegion();
3783 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3786 void ScOutputData::DrawEditStacked(DrawEditParam& rParam)
3788 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
3789 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3791 bool bRepeat = (rParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT && !rParam.mbBreak);
3792 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3794 rParam.mbAsianVertical =
3795 lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
3797 if ( rParam.mbAsianVertical )
3799 // in asian mode, use EditEngine::SetVertical instead of EEControlBits::ONECHARPERLINE
3800 rParam.meOrient = SVX_ORIENTATION_STANDARD;
3801 DrawEditAsianVertical(rParam);
3802 return;
3805 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3807 //! mirror margin values for RTL?
3808 //! move margin down to after final GetOutputArea call
3809 long nTopM, nLeftM, nBottomM, nRightM;
3810 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3812 SCCOL nXForPos = rParam.mnX;
3813 if ( nXForPos < nX1 )
3815 nXForPos = nX1;
3816 rParam.mnPosX = rParam.mnInitPosX;
3818 SCSIZE nArrYForPos = rParam.mnArrY;
3819 if ( nArrYForPos < 1 )
3821 nArrYForPos = 1;
3822 rParam.mnPosY = nScrY;
3825 OutputAreaParam aAreaParam;
3827 // Initial page size - large for normal text, cell size for automatic line breaks
3829 Size aPaperSize = Size( 1000000, 1000000 );
3830 // call GetOutputArea with nNeeded=0, to get only the cell width
3832 //! handle nArrY == 0
3833 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3834 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3835 rParam.mbCellIsValue, true, false, aAreaParam );
3837 //! special ScEditUtil handling if formatting for printer
3838 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3840 if (rParam.mbPixelToLogic)
3842 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3843 if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
3845 // #i85342# screen display and formatting for printer,
3846 // use same GetEditArea call as in ScViewData::SetEditEngine
3848 Fraction aFract(1,1);
3849 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
3850 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
3851 aLogicSize.Width() = aUtilRect.GetWidth();
3853 rParam.mpEngine->SetPaperSize(aLogicSize);
3855 else
3856 rParam.mpEngine->SetPaperSize(aPaperSize);
3858 // Fill the EditEngine (cell attributes and text)
3860 rParam.setPatternToEngine(mbUseStyleColor);
3861 rParam.setAlignmentToEngine();
3863 // Read content from cell
3865 bool bWrapFields = false;
3866 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
3867 // Failed to read cell content. Bail out.
3868 return;
3870 if ( mbSyntaxMode )
3871 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3872 else if ( mbUseStyleColor && mbForceAutoColor )
3873 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
3875 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3877 // Get final output area using the calculated width
3879 long nEngineWidth, nEngineHeight;
3880 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3882 long nNeededPixel = nEngineWidth;
3883 if (rParam.mbPixelToLogic)
3884 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3885 nNeededPixel += nLeftM + nRightM;
3887 if (bShrink)
3889 // for break, the first GetOutputArea call is sufficient
3890 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3891 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3892 true, false, false, aAreaParam );
3894 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3895 nLeftM, nTopM, nRightM, nBottomM, true,
3896 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
3897 nEngineWidth, nEngineHeight, nNeededPixel,
3898 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3900 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3902 rParam.mpEngine->SetText(OUString("###"));
3903 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
3904 if (rParam.mbPixelToLogic)
3905 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
3906 else
3907 nNeededPixel = nEngineWidth;
3908 nNeededPixel += nLeftM + nRightM;
3910 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3913 if ( eOutHorJust != SVX_HOR_JUSTIFY_LEFT )
3915 aPaperSize.Width() = nNeededPixel + 1;
3916 if (rParam.mbPixelToLogic)
3917 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3918 else
3919 rParam.mpEngine->SetPaperSize(aPaperSize);
3923 long nStartX = aAreaParam.maAlignRect.Left();
3924 long nStartY = aAreaParam.maAlignRect.Top();
3925 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3926 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3927 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3929 if (rParam.mbBreak)
3931 // text with automatic breaks is aligned only within the
3932 // edit engine's paper size, the output of the whole area
3933 // is always left-aligned
3935 nStartX += nLeftM;
3937 else
3939 if ( eOutHorJust == SVX_HOR_JUSTIFY_RIGHT )
3940 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3941 else if ( eOutHorJust == SVX_HOR_JUSTIFY_CENTER )
3942 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3943 else
3944 nStartX += nLeftM;
3947 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3948 if (bOutside)
3949 return;
3951 if ( aAreaParam.maClipRect.Left() < nScrX )
3953 aAreaParam.maClipRect.Left() = nScrX;
3954 aAreaParam.mbLeftClip = true;
3956 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
3958 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
3959 aAreaParam.mbRightClip = true;
3962 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
3963 bool bSimClip = false;
3965 if ( bWrapFields )
3967 // Fields in a cell with automatic breaks: clip to cell width
3968 bClip = true;
3971 if ( aAreaParam.maClipRect.Top() < nScrY )
3973 aAreaParam.maClipRect.Top() = nScrY;
3974 bClip = true;
3976 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
3978 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
3979 bClip = true;
3982 Size aCellSize; // output area, excluding margins, in logical units
3983 if (rParam.mbPixelToLogic)
3984 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3985 else
3986 aCellSize = Size( nOutWidth, nOutHeight );
3988 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3990 const ScMergeAttr* pMerge =
3991 static_cast<const ScMergeAttr*>(&rParam.mpPattern->GetItem(ATTR_MERGE));
3992 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3994 // Don't clip for text height when printing rows with optimal height,
3995 // except when font size is from conditional formatting.
3996 //! Allow clipping when vertically merged?
3997 if ( eType != OUTTYPE_PRINTER ||
3998 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
3999 ( rParam.mpCondSet && SfxItemState::SET ==
4000 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4001 bClip = true;
4002 else
4003 bSimClip = true;
4005 // Show clip marks if height is at least 5pt too small and
4006 // there are several lines of text.
4007 // Not for asian vertical text, because that would interfere
4008 // with the default right position of the text.
4009 // Only with automatic line breaks, to avoid having to find
4010 // the cells with the horizontal end of the text again.
4011 if ( nEngineHeight - aCellSize.Height() > 100 &&
4012 rParam.mbBreak && bMarkClipped &&
4013 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4015 CellInfo* pClipMarkCell = NULL;
4016 if ( bMerged )
4018 // anywhere in the merged area...
4019 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4020 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4022 else
4023 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4025 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4026 bAnyClipped = true;
4028 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4029 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4030 aAreaParam.maClipRect.Right() -= nMarkPixel;
4034 Rectangle aLogicClip;
4035 if (bClip || bSimClip)
4037 // Clip marks are already handled in GetOutputArea
4039 if (rParam.mbPixelToLogic)
4040 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4041 else
4042 aLogicClip = aAreaParam.maClipRect;
4044 if (bClip) // bei bSimClip nur aClipRect initialisieren
4046 if (bMetaFile)
4048 mpDev->Push();
4049 mpDev->IntersectClipRegion( aLogicClip );
4051 else
4052 mpDev->SetClipRegion( vcl::Region( aLogicClip ) );
4056 Point aLogicStart;
4057 if (rParam.mbPixelToLogic)
4058 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4059 else
4060 aLogicStart = Point(nStartX, nStartY);
4062 if (rParam.meVerJust==SVX_VER_JUSTIFY_BOTTOM ||
4063 rParam.meVerJust==SVX_VER_JUSTIFY_STANDARD)
4065 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4066 //! only converting margin?
4068 if (rParam.mbPixelToLogic)
4069 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM +
4070 mpRefDevice->LogicToPixel(aCellSize).Height() -
4071 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
4072 )).Height();
4073 else
4074 aLogicStart.Y() += nTopM + aCellSize.Height() - nEngineHeight;
4076 else if (rParam.meVerJust==SVX_VER_JUSTIFY_CENTER)
4078 if (rParam.mbPixelToLogic)
4079 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0, nTopM + (
4080 mpRefDevice->LogicToPixel(aCellSize).Height() -
4081 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
4082 / 2)).Height();
4083 else
4084 aLogicStart.Y() += nTopM + (aCellSize.Height() - nEngineHeight) / 2;
4086 else // top
4088 if (rParam.mbPixelToLogic)
4089 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4090 else
4091 aLogicStart.Y() += nTopM;
4094 Point aURLStart = aLogicStart; // copy before modifying for orientation
4096 Size aPaperLogic = rParam.mpEngine->GetPaperSize();
4097 aPaperLogic.Width() = nEngineWidth;
4098 rParam.mpEngine->SetPaperSize(aPaperLogic);
4100 rParam.adjustForRTL();
4102 // bMoveClipped handling has been replaced by complete alignment
4103 // handling (also extending to the left).
4105 if (bSimClip)
4107 // kein hartes Clipping, aber nur die betroffenen
4108 // Zeilen ausgeben
4110 Point aDocStart = aLogicClip.TopLeft();
4111 aDocStart -= aLogicStart;
4112 rParam.mpEngine->Draw( mpDev, aLogicClip, aDocStart, false );
4114 else
4116 rParam.mpEngine->Draw( mpDev, aLogicStart, 0 );
4119 if (bClip)
4121 if (bMetaFile)
4122 mpDev->Pop();
4123 else
4124 mpDev->SetClipRegion();
4127 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4130 void ScOutputData::DrawEditAsianVertical(DrawEditParam& rParam)
4132 // When in asian vertical orientation, the orientation value is STANDARD,
4133 // and the asian vertical boolean is true.
4134 OSL_ASSERT(rParam.meOrient == SVX_ORIENTATION_STANDARD);
4135 OSL_ASSERT(rParam.mbAsianVertical);
4136 OSL_ASSERT(rParam.meHorJustAttr != SVX_HOR_JUSTIFY_REPEAT);
4138 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
4140 bool bHidden = false;
4141 bool bShrink = !rParam.mbBreak && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
4142 long nAttrRotate = lcl_GetValue<SfxInt32Item, long>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
4144 if (nAttrRotate)
4146 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
4147 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
4148 bHidden = true; // gedreht wird getrennt ausgegeben
4151 // default alignment for asian vertical mode is top-right
4152 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4153 * SVX_HOR_JUSTIFY_RIGHT really wanted? Seems this was done all the time,
4154 * also before context was introduced and everything was attr only. */
4155 if ( rParam.meHorJustAttr == SVX_HOR_JUSTIFY_STANDARD )
4156 rParam.meHorJustResult = rParam.meHorJustContext = SVX_HOR_JUSTIFY_RIGHT;
4158 if (bHidden)
4159 return;
4161 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
4163 //! mirror margin values for RTL?
4164 //! move margin down to after final GetOutputArea call
4165 long nTopM, nLeftM, nBottomM, nRightM;
4166 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
4168 SCCOL nXForPos = rParam.mnX;
4169 if ( nXForPos < nX1 )
4171 nXForPos = nX1;
4172 rParam.mnPosX = rParam.mnInitPosX;
4174 SCSIZE nArrYForPos = rParam.mnArrY;
4175 if ( nArrYForPos < 1 )
4177 nArrYForPos = 1;
4178 rParam.mnPosY = nScrY;
4181 OutputAreaParam aAreaParam;
4183 // Initial page size - large for normal text, cell size for automatic line breaks
4185 Size aPaperSize = Size( 1000000, 1000000 );
4186 // call GetOutputArea with nNeeded=0, to get only the cell width
4188 //! handle nArrY == 0
4189 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
4190 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4191 rParam.mbCellIsValue, true, false, aAreaParam );
4193 //! special ScEditUtil handling if formatting for printer
4194 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
4196 if (rParam.mbPixelToLogic)
4198 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
4199 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
4201 // #i85342# screen display and formatting for printer,
4202 // use same GetEditArea call as in ScViewData::SetEditEngine
4204 Fraction aFract(1,1);
4205 Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
4206 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
4207 aLogicSize.Width() = aUtilRect.GetWidth();
4209 rParam.mpEngine->SetPaperSize(aLogicSize);
4211 else
4212 rParam.mpEngine->SetPaperSize(aPaperSize);
4214 // Fill the EditEngine (cell attributes and text)
4216 // default alignment for asian vertical mode is top-right
4217 if ( rParam.meVerJust == SVX_VER_JUSTIFY_STANDARD )
4218 rParam.meVerJust = SVX_VER_JUSTIFY_TOP;
4220 rParam.setPatternToEngine(mbUseStyleColor);
4221 rParam.setAlignmentToEngine();
4223 // Read content from cell
4225 bool bWrapFields = false;
4226 if (!rParam.readCellContent(mpDoc, mbShowNullValues, mbShowFormulas, mbSyntaxMode, mbUseStyleColor, mbForceAutoColor, bWrapFields))
4227 // Failed to read cell content. Bail out.
4228 return;
4230 if ( mbSyntaxMode )
4231 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
4232 else if ( mbUseStyleColor && mbForceAutoColor )
4233 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO ); //! or have a flag at EditEngine
4235 rParam.mpEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4237 // Get final output area using the calculated width
4239 long nEngineWidth, nEngineHeight;
4240 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
4242 long nNeededPixel = nEngineWidth;
4243 if (rParam.mbPixelToLogic)
4244 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
4245 nNeededPixel += nLeftM + nRightM;
4247 // for break, the first GetOutputArea call is sufficient
4248 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
4249 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4250 rParam.mbCellIsValue || bShrink, false, false, aAreaParam );
4252 if ( bShrink )
4254 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
4255 nLeftM, nTopM, nRightM, nBottomM, false,
4256 sal::static_int_cast<sal_uInt16>(rParam.meOrient), 0, rParam.mbPixelToLogic,
4257 nEngineWidth, nEngineHeight, nNeededPixel,
4258 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4261 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
4263 rParam.mpEngine->SetText(OUString("###"));
4264 nEngineWidth = (long) rParam.mpEngine->CalcTextWidth();
4265 if (rParam.mbPixelToLogic)
4266 nNeededPixel = mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width();
4267 else
4268 nNeededPixel = nEngineWidth;
4269 nNeededPixel += nLeftM + nRightM;
4271 // No clip marks if "###" doesn't fit (same as in DrawStrings)
4274 if (eOutHorJust != SVX_HOR_JUSTIFY_LEFT)
4276 aPaperSize.Width() = nNeededPixel + 1;
4277 if (rParam.mbPixelToLogic)
4278 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4279 else
4280 rParam.mpEngine->SetPaperSize(aPaperSize);
4283 long nStartX = aAreaParam.maAlignRect.Left();
4284 long nStartY = aAreaParam.maAlignRect.Top();
4285 long nCellWidth = aAreaParam.maAlignRect.GetWidth();
4286 long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
4287 long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
4289 // text with automatic breaks is aligned only within the
4290 // edit engine's paper size, the output of the whole area
4291 // is always left-aligned
4293 nStartX += nLeftM;
4295 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4296 if (bOutside)
4297 return;
4299 if ( aAreaParam.maClipRect.Left() < nScrX )
4301 aAreaParam.maClipRect.Left() = nScrX;
4302 aAreaParam.mbLeftClip = true;
4304 if ( aAreaParam.maClipRect.Right() > nScrX + nScrW )
4306 aAreaParam.maClipRect.Right() = nScrX + nScrW; //! minus one?
4307 aAreaParam.mbRightClip = true;
4310 bool bClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
4311 bool bSimClip = false;
4313 if ( bWrapFields )
4315 // Fields in a cell with automatic breaks: clip to cell width
4316 bClip = true;
4319 if ( aAreaParam.maClipRect.Top() < nScrY )
4321 aAreaParam.maClipRect.Top() = nScrY;
4322 bClip = true;
4324 if ( aAreaParam.maClipRect.Bottom() > nScrY + nScrH )
4326 aAreaParam.maClipRect.Bottom() = nScrY + nScrH; //! minus one?
4327 bClip = true;
4330 Size aCellSize; // output area, excluding margins, in logical units
4331 if (rParam.mbPixelToLogic)
4332 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4333 else
4334 aCellSize = Size( nOutWidth, nOutHeight );
4336 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4338 const ScMergeAttr* pMerge =
4339 static_cast<const ScMergeAttr*>(&rParam.mpPattern->GetItem(ATTR_MERGE));
4340 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4342 // Don't clip for text height when printing rows with optimal height,
4343 // except when font size is from conditional formatting.
4344 //! Allow clipping when vertically merged?
4345 if ( eType != OUTTYPE_PRINTER ||
4346 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CR_MANUALSIZE ) ||
4347 ( rParam.mpCondSet && SfxItemState::SET ==
4348 rParam.mpCondSet->GetItemState(ATTR_FONT_HEIGHT, true) ) )
4349 bClip = true;
4350 else
4351 bSimClip = true;
4353 // Show clip marks if height is at least 5pt too small and
4354 // there are several lines of text.
4355 // Not for asian vertical text, because that would interfere
4356 // with the default right position of the text.
4357 // Only with automatic line breaks, to avoid having to find
4358 // the cells with the horizontal end of the text again.
4359 if ( nEngineHeight - aCellSize.Height() > 100 &&
4360 ( rParam.mbBreak || rParam.meOrient == SVX_ORIENTATION_STACKED ) &&
4361 !rParam.mbAsianVertical && bMarkClipped &&
4362 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4364 CellInfo* pClipMarkCell = NULL;
4365 if ( bMerged )
4367 // anywhere in the merged area...
4368 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4369 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].pCellInfo[nClipX+1];
4371 else
4372 pClipMarkCell = &rParam.mpThisRowInfo->pCellInfo[rParam.mnX+1];
4374 pClipMarkCell->nClipMark |= SC_CLIPMARK_RIGHT; //! also allow left?
4375 bAnyClipped = true;
4377 long nMarkPixel = (long)( SC_CLIPMARK_SIZE * mnPPTX );
4378 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4379 aAreaParam.maClipRect.Right() -= nMarkPixel;
4383 Rectangle aLogicClip;
4384 if (bClip || bSimClip)
4386 // Clip marks are already handled in GetOutputArea
4388 if (rParam.mbPixelToLogic)
4389 aLogicClip = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
4390 else
4391 aLogicClip = aAreaParam.maClipRect;
4393 if (bClip) // bei bSimClip nur aClipRect initialisieren
4395 if (bMetaFile)
4397 mpDev->Push();
4398 mpDev->IntersectClipRegion( aLogicClip );
4400 else
4401 mpDev->SetClipRegion( vcl::Region( aLogicClip ) );
4405 Point aLogicStart;
4406 if (rParam.mbPixelToLogic)
4407 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4408 else
4409 aLogicStart = Point(nStartX, nStartY);
4411 long nAvailWidth = aCellSize.Width();
4412 // space for AutoFilter is already handled in GetOutputArea
4414 // horizontal alignment
4416 if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_RIGHT)
4417 aLogicStart.X() += nAvailWidth - nEngineWidth;
4418 else if (rParam.meHorJustResult==SVX_HOR_JUSTIFY_CENTER)
4419 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
4421 // paper size is subtracted below
4422 aLogicStart.X() += nEngineWidth;
4424 // vertical adjustment is within the EditEngine
4425 if (rParam.mbPixelToLogic)
4426 aLogicStart.Y() += mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
4427 else
4428 aLogicStart.Y() += nTopM;
4430 Point aURLStart = aLogicStart; // copy before modifying for orientation
4432 rParam.adjustForRTL();
4434 // bMoveClipped handling has been replaced by complete alignment
4435 // handling (also extending to the left).
4437 // with SetVertical, the start position is top left of
4438 // the whole output area, not the text itself
4439 aLogicStart.X() -= rParam.mpEngine->GetPaperSize().Width();
4441 rParam.mpEngine->Draw(mpDev, aLogicStart, 0);
4443 if (bClip)
4445 if (bMetaFile)
4446 mpDev->Pop();
4447 else
4448 mpDev->SetClipRegion();
4451 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4454 void ScOutputData::DrawEdit(bool bPixelToLogic)
4456 boost::scoped_ptr<ScFieldEditEngine> pEngine;
4457 bool bHyphenatorSet = false;
4458 const ScPatternAttr* pOldPattern = NULL;
4459 const SfxItemSet* pOldCondSet = NULL;
4460 const SfxItemSet* pOldPreviewFontSet = NULL;
4461 ScRefCellValue aCell;
4463 long nInitPosX = nScrX;
4464 if ( bLayoutRTL )
4466 nInitPosX += nMirrorW - 1;
4468 long nLayoutSign = bLayoutRTL ? -1 : 1;
4470 //! store nLastContentCol as member!
4471 SCCOL nLastContentCol = MAXCOL;
4472 if ( nX2 < MAXCOL )
4473 nLastContentCol = sal::static_int_cast<SCCOL>(
4474 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, MAXCOL, nY2, nTab, DIR_RIGHT ) );
4476 long nRowPosY = nScrY;
4477 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4479 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4481 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4483 if ( pThisRowInfo->bChanged || nArrY==0 )
4485 long nPosX = 0;
4486 for (SCCOL nX=0; nX<=nX2; nX++) // wegen Ueberhaengen
4488 boost::scoped_ptr< ScPatternAttr > pPreviewPattr;
4489 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4491 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4492 if (pInfo->bEditEngine)
4494 SCROW nY = pThisRowInfo->nRowNo;
4496 SCCOL nCellX = nX; // position where the cell really starts
4497 SCROW nCellY = nY;
4498 bool bDoCell = false;
4500 long nPosY = nRowPosY;
4501 if ( nArrY == 0 )
4503 nPosY = nScrY;
4504 nY = pRowInfo[1].nRowNo;
4505 SCCOL nOverX; // start of the merged cells
4506 SCROW nOverY;
4507 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, true ))
4509 nCellX = nOverX;
4510 nCellY = nOverY;
4511 bDoCell = true;
4514 else if ( nX == nX2 && pThisRowInfo->pCellInfo[nX+1].maCell.isEmpty() )
4516 // Rest of a long text further to the right?
4518 SCCOL nTempX=nX;
4519 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
4520 ++nTempX;
4522 if ( nTempX > nX &&
4523 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
4524 !mpDoc->HasAttrib( nTempX,nY,nTab, nX,nY,nTab, HASATTR_MERGED | HASATTR_OVERLAPPED ) )
4526 nCellX = nTempX;
4527 bDoCell = true;
4530 else
4532 bDoCell = true;
4535 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
4536 bDoCell = false;
4538 const ScPatternAttr* pPattern = NULL;
4539 const SfxItemSet* pCondSet = NULL;
4540 if (bDoCell)
4542 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
4543 !mpDoc->ColHidden(nCellX, nTab) )
4545 CellInfo& rCellInfo = pThisRowInfo->pCellInfo[nCellX+1];
4546 pPattern = rCellInfo.pPatternAttr;
4547 pCondSet = rCellInfo.pConditionSet;
4548 aCell = rCellInfo.maCell;
4550 else // get from document
4552 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
4553 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
4554 GetVisibleCell( nCellX, nCellY, nTab, aCell );
4556 if (aCell.isEmpty())
4557 bDoCell = false;
4559 if (bDoCell)
4561 if ( mpDoc->GetPreviewCellStyle() )
4563 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
4565 pPreviewPattr.reset( new ScPatternAttr(*pPattern) );
4566 pPreviewPattr->SetStyleSheet(pPreviewStyle);
4567 pPattern = pPreviewPattr.get();
4570 SfxItemSet* pPreviewFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab );
4571 if (!pEngine)
4572 pEngine.reset(CreateOutputEditEngine());
4573 else
4574 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4576 // fdo#32530: Check if the first character is RTL.
4577 OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
4579 DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(aCell));
4580 aParam.meHorJustContext = getAlignmentFromContext( aParam.meHorJustAttr,
4581 aParam.mbCellIsValue, aStr, *pPattern, pCondSet, mpDoc, nTab);
4582 aParam.meHorJustResult = (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_BLOCK) ?
4583 SVX_HOR_JUSTIFY_BLOCK : aParam.meHorJustContext;
4584 aParam.mbPixelToLogic = bPixelToLogic;
4585 aParam.mbHyphenatorSet = bHyphenatorSet;
4586 aParam.mpEngine = pEngine.get();
4587 aParam.maCell = aCell;
4588 aParam.mnArrY = nArrY;
4589 aParam.mnX = nX;
4590 aParam.mnY = nY;
4591 aParam.mnCellX = nCellX;
4592 aParam.mnCellY = nCellY;
4593 aParam.mnTab = nTab;
4594 aParam.mnPosX = nPosX;
4595 aParam.mnPosY = nPosY;
4596 aParam.mnInitPosX = nInitPosX;
4597 aParam.mpPreviewFontSet = pPreviewFontSet;
4598 aParam.mpOldPattern = pOldPattern;
4599 aParam.mpOldCondSet = pOldCondSet;
4600 aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
4601 aParam.mpThisRowInfo = pThisRowInfo;
4602 if (mpSpellCheckCxt)
4603 aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);
4605 if (aParam.meHorJustAttr == SVX_HOR_JUSTIFY_REPEAT)
4607 // ignore orientation/rotation if "repeat" is active
4608 aParam.meOrient = SVX_ORIENTATION_STANDARD;
4610 switch (aParam.meOrient)
4612 case SVX_ORIENTATION_BOTTOMTOP:
4613 DrawEditBottomTop(aParam);
4614 break;
4615 case SVX_ORIENTATION_TOPBOTTOM:
4616 DrawEditTopBottom(aParam);
4617 break;
4618 case SVX_ORIENTATION_STACKED:
4619 // this can be vertically stacked or asian vertical.
4620 DrawEditStacked(aParam);
4621 break;
4622 default:
4623 DrawEditStandard(aParam);
4626 // Retrieve parameters for next iteration.
4627 pOldPattern = aParam.mpOldPattern;
4628 pOldCondSet = aParam.mpOldCondSet;
4629 pOldPreviewFontSet = aParam.mpOldPreviewFontSet;
4630 bHyphenatorSet = aParam.mbHyphenatorSet;
4633 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
4636 nRowPosY += pRowInfo[nArrY].nHeight;
4639 pEngine.reset();
4641 if (bAnyRotated)
4642 DrawRotated(bPixelToLogic); //! von aussen rufen ?
4645 void ScOutputData::DrawRotated(bool bPixelToLogic)
4647 //! nRotMax speichern
4648 SCCOL nRotMax = nX2;
4649 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
4650 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
4651 nRotMax = pRowInfo[nRotY].nRotMaxCol;
4653 ScModule* pScMod = SC_MOD();
4654 sal_Int32 nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
4655 bool bCellContrast = mbUseStyleColor &&
4656 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4658 boost::scoped_ptr<ScFieldEditEngine> pEngine;
4659 bool bHyphenatorSet = false;
4660 const ScPatternAttr* pPattern;
4661 const SfxItemSet* pCondSet;
4662 const ScPatternAttr* pOldPattern = NULL;
4663 const SfxItemSet* pOldCondSet = NULL;
4664 ScRefCellValue aCell;
4666 long nInitPosX = nScrX;
4667 if ( bLayoutRTL )
4669 nInitPosX += nMirrorW - 1;
4671 long nLayoutSign = bLayoutRTL ? -1 : 1;
4673 long nRowPosY = nScrY;
4674 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 fuer Reste von zusammengefassten
4676 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4677 long nCellHeight = (long) pThisRowInfo->nHeight;
4678 if (nArrY==1) nRowPosY = nScrY; // vorher wird einzeln berechnet
4680 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
4682 long nPosX = 0;
4683 for (SCCOL nX=0; nX<=nRotMax; nX++)
4685 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4687 CellInfo* pInfo = &pThisRowInfo->pCellInfo[nX+1];
4688 if ( pInfo->nRotateDir != SC_ROTDIR_NONE )
4690 SCROW nY = pThisRowInfo->nRowNo;
4692 bool bHidden = false;
4693 if (bEditMode)
4694 if ( nX == nEditCol && nY == nEditRow )
4695 bHidden = true;
4697 if (!bHidden)
4699 if (!pEngine)
4700 pEngine.reset(CreateOutputEditEngine());
4701 else
4702 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4704 long nPosY = nRowPosY;
4705 bool bVisChanged = false;
4707 //! Rest von zusammengefasster Zelle weiter oben funktioniert nicht!
4709 bool bFromDoc = false;
4710 pPattern = pInfo->pPatternAttr;
4711 pCondSet = pInfo->pConditionSet;
4712 if (!pPattern)
4714 pPattern = mpDoc->GetPattern( nX, nY, nTab );
4715 bFromDoc = true;
4717 aCell = pInfo->maCell;
4718 if (bFromDoc)
4719 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
4721 if (aCell.isEmpty() && nX>nX2)
4722 GetVisibleCell( nX, nY, nTab, aCell );
4724 if (aCell.isEmpty() || IsEmptyCellText(pThisRowInfo, nX, nY))
4725 bHidden = true; // nRotateDir is also set without a cell
4727 long nCellWidth = (long) pRowInfo[0].pCellInfo[nX+1].nWidth;
4729 SvxCellHorJustify eHorJust = (SvxCellHorJustify)static_cast<const SvxHorJustifyItem&>(
4730 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet)).GetValue();
4731 bool bBreak = ( eHorJust == SVX_HOR_JUSTIFY_BLOCK ) ||
4732 static_cast<const SfxBoolItem&>(pPattern->GetItem(ATTR_LINEBREAK, pCondSet)).GetValue();
4733 bool bRepeat = ( eHorJust == SVX_HOR_JUSTIFY_REPEAT && !bBreak );
4734 bool bShrink = !bBreak && !bRepeat && static_cast<const SfxBoolItem&>
4735 (pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet )).GetValue();
4736 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
4738 const ScMergeAttr* pMerge =
4739 static_cast<const ScMergeAttr*>(&pPattern->GetItem(ATTR_MERGE));
4740 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4742 long nStartX = nPosX;
4743 long nStartY = nPosY;
4744 if (nX<nX1)
4746 if ((bBreak || eOrient!=SVX_ORIENTATION_STANDARD) && !bMerged)
4747 bHidden = true;
4748 else
4750 nStartX = nInitPosX;
4751 SCCOL nCol = nX1;
4752 while (nCol > nX)
4754 --nCol;
4755 nStartX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
4759 long nCellStartX = nStartX;
4761 // Ersatzdarstellung fuer zu kleinen Text weggelassen
4763 if (!bHidden)
4765 long nOutWidth = nCellWidth - 1;
4766 long nOutHeight = nCellHeight;
4768 if ( bMerged ) // Zusammengefasst
4770 SCCOL nCountX = pMerge->GetColMerge();
4771 for (SCCOL i=1; i<nCountX; i++)
4772 nOutWidth += (long) ( mpDoc->GetColWidth(nX+i,nTab) * mnPPTX );
4773 SCROW nCountY = pMerge->GetRowMerge();
4774 nOutHeight += (long) mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
4777 SvxCellVerJustify eVerJust = (SvxCellVerJustify)static_cast<const SvxVerJustifyItem&>(
4778 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet)).GetValue();
4780 // Syntax-Modus wird hier ignoriert...
4782 // StringDiffer doesn't look at hyphenate, language items
4783 if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
4785 SfxItemSet* pSet = new SfxItemSet( pEngine->GetEmptyItemSet() );
4786 pPattern->FillEditItemSet( pSet, pCondSet );
4788 // Ausrichtung fuer EditEngine
4789 SvxAdjust eSvxAdjust = SVX_ADJUST_LEFT;
4790 if (eOrient==SVX_ORIENTATION_STACKED)
4791 eSvxAdjust = SVX_ADJUST_CENTER;
4792 // Adjustment fuer bBreak ist hier weggelassen
4793 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
4795 pEngine->SetDefaults( pSet );
4796 pOldPattern = pPattern;
4797 pOldCondSet = pCondSet;
4799 EEControlBits nControl = pEngine->GetControlWord();
4800 if (eOrient==SVX_ORIENTATION_STACKED)
4801 nControl |= EEControlBits::ONECHARPERLINE;
4802 else
4803 nControl &= ~EEControlBits::ONECHARPERLINE;
4804 pEngine->SetControlWord( nControl );
4806 if ( !bHyphenatorSet && static_cast<const SfxBoolItem&>(pSet->Get(EE_PARA_HYPHENATE)).GetValue() )
4808 // set hyphenator the first time it is needed
4809 com::sun::star::uno::Reference<com::sun::star::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
4810 pEngine->SetHyphenator( xXHyphenator );
4811 bHyphenatorSet = true;
4814 Color aBackCol = static_cast<const SvxBrushItem&>(
4815 pPattern->GetItem( ATTR_BACKGROUND, pCondSet )).GetColor();
4816 if ( mbUseStyleColor && ( aBackCol.GetTransparency() > 0 || bCellContrast ) )
4817 aBackCol.SetColor( nConfBackColor );
4818 pEngine->SetBackgroundColor( aBackCol );
4821 // Raender
4823 //! Position und Papersize auf EditUtil umstellen !!!
4825 const SvxMarginItem* pMargin = static_cast<const SvxMarginItem*>(
4826 &pPattern->GetItem(ATTR_MARGIN, pCondSet));
4827 sal_uInt16 nIndent = 0;
4828 if ( eHorJust == SVX_HOR_JUSTIFY_LEFT )
4829 nIndent = static_cast<const SfxUInt16Item&>(pPattern->
4830 GetItem(ATTR_INDENT, pCondSet)).GetValue();
4832 long nTotalHeight = nOutHeight; // ohne Rand abzuziehen
4833 if ( bPixelToLogic )
4834 nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
4836 long nLeftM = (long) ( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
4837 long nTopM = (long) ( pMargin->GetTopMargin() * mnPPTY );
4838 long nRightM = (long) ( pMargin->GetRightMargin() * mnPPTX );
4839 long nBottomM = (long) ( pMargin->GetBottomMargin() * mnPPTY );
4840 nStartX += nLeftM;
4841 nStartY += nTopM;
4842 nOutWidth -= nLeftM + nRightM;
4843 nOutHeight -= nTopM + nBottomM;
4845 // Rotation schon hier, um bei Umbruch auch PaperSize anzupassen
4846 long nAttrRotate = 0;
4847 double nSin = 0.0;
4848 double nCos = 1.0;
4849 SvxRotateMode eRotMode = SVX_ROTATE_MODE_STANDARD;
4850 if ( eOrient == SVX_ORIENTATION_STANDARD )
4852 nAttrRotate = static_cast<const SfxInt32Item&>(pPattern->
4853 GetItem(ATTR_ROTATE_VALUE, pCondSet)).GetValue();
4854 if ( nAttrRotate )
4856 eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
4857 pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();
4859 if ( nAttrRotate == 18000 )
4860 eRotMode = SVX_ROTATE_MODE_STANDARD; // keinen Ueberlauf
4862 if ( bLayoutRTL )
4863 nAttrRotate = -nAttrRotate;
4865 double nRealOrient = nAttrRotate * F_PI18000; // 1/100 Grad
4866 nCos = cos( nRealOrient );
4867 nSin = sin( nRealOrient );
4871 Size aPaperSize = Size( 1000000, 1000000 );
4872 if (eOrient==SVX_ORIENTATION_STACKED)
4873 aPaperSize.Width() = nOutWidth; // zum Zentrieren
4874 else if (bBreak)
4876 if (nAttrRotate)
4878 //! richtige PaperSize fuer Umbruch haengt von der Zeilenzahl
4879 //! ab, solange die Zeilen nicht einzeln versetzt ausgegeben
4880 //! werden koennen -> darum unbegrenzt, also kein Umbruch.
4881 //! Mit versetzten Zeilen waere das folgende richtig:
4882 aPaperSize.Width() = (long)(nOutHeight / fabs(nSin));
4884 else if (eOrient == SVX_ORIENTATION_STANDARD)
4885 aPaperSize.Width() = nOutWidth;
4886 else
4887 aPaperSize.Width() = nOutHeight - 1;
4889 if (bPixelToLogic)
4890 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4891 else
4892 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4894 // Daten aus Zelle lesen
4896 if (aCell.meType == CELLTYPE_EDIT)
4898 if (aCell.mpEditText)
4899 pEngine->SetText(*aCell.mpEditText);
4900 else
4902 OSL_FAIL("pData == 0");
4905 else
4907 sal_uLong nFormat = pPattern->GetNumberFormat(
4908 mpDoc->GetFormatTable(), pCondSet );
4909 OUString aString;
4910 Color* pColor;
4911 ScCellFormat::GetString( aCell,
4912 nFormat,aString, &pColor,
4913 *mpDoc->GetFormatTable(),
4914 mpDoc,
4915 mbShowNullValues,
4916 mbShowFormulas,
4917 ftCheck );
4919 pEngine->SetText(aString);
4920 if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
4921 lcl_SetEditColor( *pEngine, *pColor );
4924 if ( mbSyntaxMode )
4926 SetEditSyntaxColor(*pEngine, aCell);
4928 else if ( mbUseStyleColor && mbForceAutoColor )
4929 lcl_SetEditColor( *pEngine, COL_AUTO ); //! or have a flag at EditEngine
4931 pEngine->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4933 long nEngineWidth = (long) pEngine->CalcTextWidth();
4934 long nEngineHeight = pEngine->GetTextHeight();
4936 if (nAttrRotate && bBreak)
4938 double nAbsCos = fabs( nCos );
4939 double nAbsSin = fabs( nSin );
4941 // adjust witdh of papersize for height of text
4942 int nSteps = 5;
4943 while (nSteps > 0)
4945 // everything is in pixels
4946 long nEnginePixel = mpRefDevice->LogicToPixel(
4947 Size(0,nEngineHeight)).Height();
4948 long nEffHeight = nOutHeight - (long)(nEnginePixel * nAbsCos) + 2;
4949 long nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
4950 bool bFits = ( nNewWidth >= aPaperSize.Width() );
4951 if ( bFits )
4952 nSteps = 0;
4953 else
4955 if ( nNewWidth < 4 )
4957 // can't fit -> fall back to using half height
4958 nEffHeight = nOutHeight / 2;
4959 nNewWidth = (long)(nEffHeight / nAbsSin) + 2;
4960 nSteps = 0;
4962 else
4963 --nSteps;
4965 // set paper width and get new text height
4966 aPaperSize.Width() = nNewWidth;
4967 if (bPixelToLogic)
4968 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4969 else
4970 pEngine->SetPaperSize(aPaperSize); // Scale ist immer 1
4971 //pEngine->QuickFormatDoc( sal_True );
4972 nEngineWidth = (long) pEngine->CalcTextWidth();
4973 nEngineHeight = pEngine->GetTextHeight();
4978 long nRealWidth = nEngineWidth;
4979 long nRealHeight = nEngineHeight;
4981 // wenn gedreht, Groesse anpassen
4982 if (nAttrRotate)
4984 double nAbsCos = fabs( nCos );
4985 double nAbsSin = fabs( nSin );
4987 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
4988 nEngineWidth = (long) ( nRealWidth * nAbsCos +
4989 nRealHeight * nAbsSin );
4990 else
4991 nEngineWidth = (long) ( nRealHeight / nAbsSin );
4992 //! begrenzen !!!
4994 nEngineHeight = (long) ( nRealHeight * nAbsCos +
4995 nRealWidth * nAbsSin );
4998 if (!nAttrRotate) // hier nur gedrehter Text
4999 bHidden = true; //! vorher abfragen !!!
5001 //! weglassen, was nicht hereinragt
5003 if (!bHidden)
5005 bool bClip = false;
5006 Size aClipSize = Size( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
5008 // weiterschreiben
5010 Size aCellSize;
5011 if (bPixelToLogic)
5012 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
5013 else
5014 aCellSize = Size( nOutWidth, nOutHeight ); // Scale ist 1
5016 long nGridWidth = nEngineWidth;
5017 bool bNegative = false;
5018 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5020 nGridWidth = aCellSize.Width() +
5021 std::abs((long) ( aCellSize.Height() * nCos / nSin ));
5022 bNegative = ( pInfo->nRotateDir == SC_ROTDIR_LEFT );
5023 if ( bLayoutRTL )
5024 bNegative = !bNegative;
5027 // use GetOutputArea to hide the grid
5028 // (clip region is done manually below)
5029 OutputAreaParam aAreaParam;
5031 SCCOL nCellX = nX;
5032 SCROW nCellY = nY;
5033 SvxCellHorJustify eOutHorJust = eHorJust;
5034 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5035 eOutHorJust = bNegative ? SVX_HOR_JUSTIFY_RIGHT : SVX_HOR_JUSTIFY_LEFT;
5036 long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
5037 if ( bPixelToLogic )
5038 nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
5040 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
5041 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
5042 false, false, true, aAreaParam );
5044 if ( bShrink )
5046 long nPixelWidth = bPixelToLogic ?
5047 mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
5048 long nNeededPixel = nPixelWidth + nLeftM + nRightM;
5050 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = true;
5052 // always do height
5053 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5054 false, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5055 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5057 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
5059 // do width only if rotating within the cell (standard mode)
5060 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
5061 true, sal::static_int_cast<sal_uInt16>(eOrient), nAttrRotate, bPixelToLogic,
5062 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
5065 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5066 // (but width is only valid for standard mode)
5067 nRealWidth = (long) pEngine->CalcTextWidth();
5068 nRealHeight = pEngine->GetTextHeight();
5070 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5071 nEngineWidth = (long) ( nRealHeight / fabs( nSin ) );
5074 long nClipStartX = nStartX;
5075 if (nX<nX1)
5077 //! Clipping unnoetig, wenn links am Fenster
5079 bClip = true; // nur Rest ausgeben!
5080 if (nStartX<nScrX)
5082 long nDif = nScrX - nStartX;
5083 nClipStartX = nScrX;
5084 aClipSize.Width() -= nDif;
5088 long nClipStartY = nStartY;
5089 if (nArrY==0 || bVisChanged)
5091 if ( nClipStartY < nRowPosY )
5093 long nDif = nRowPosY - nClipStartY;
5094 bClip = true;
5095 nClipStartY = nRowPosY;
5096 aClipSize.Height() -= nDif;
5100 bClip = true; // always clip at the window/page border
5102 //Rectangle aClipRect;
5103 if (bClip)
5105 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5107 // gedrehten, ausgerichteten Text nur an den
5108 // Seitengrenzen clippen
5109 nClipStartX = nScrX;
5110 aClipSize.Width() = nScrW;
5113 if (bPixelToLogic)
5114 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( Rectangle(
5115 Point(nClipStartX,nClipStartY), aClipSize ) );
5116 else
5117 aAreaParam.maClipRect = Rectangle(Point(nClipStartX, nClipStartY),
5118 aClipSize ); // Scale = 1
5120 if (bMetaFile)
5122 mpDev->Push();
5123 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
5125 else
5126 mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
5129 Point aLogicStart;
5130 if (bPixelToLogic)
5131 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
5132 else
5133 aLogicStart = Point(nStartX, nStartY);
5134 if ( eOrient!=SVX_ORIENTATION_STANDARD || !bBreak )
5136 long nAvailWidth = aCellSize.Width();
5137 if (eType==OUTTYPE_WINDOW &&
5138 eOrient!=SVX_ORIENTATION_STACKED &&
5139 pInfo->bAutoFilter)
5141 // filter drop-down width is now independent from row height
5142 if (bPixelToLogic)
5143 nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE)).Height();
5144 else
5145 nAvailWidth -= DROPDOWN_BITMAP_SIZE;
5146 long nComp = nEngineWidth;
5147 if (nAvailWidth<nComp) nAvailWidth=nComp;
5150 // horizontale Ausrichtung
5152 if (eOrient==SVX_ORIENTATION_STANDARD && !nAttrRotate)
5154 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT ||
5155 eHorJust==SVX_HOR_JUSTIFY_CENTER)
5157 pEngine->SetUpdateMode( false );
5159 SvxAdjust eSvxAdjust =
5160 (eHorJust==SVX_HOR_JUSTIFY_RIGHT) ?
5161 SVX_ADJUST_RIGHT : SVX_ADJUST_CENTER;
5162 pEngine->SetDefaultItem(
5163 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
5165 aPaperSize.Width() = nOutWidth;
5166 if (bPixelToLogic)
5167 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5168 else
5169 pEngine->SetPaperSize(aPaperSize);
5171 pEngine->SetUpdateMode( true );
5174 else
5176 // bei gedrehtem Text ist Standard zentriert
5177 if (eHorJust==SVX_HOR_JUSTIFY_RIGHT)
5178 aLogicStart.X() += nAvailWidth - nEngineWidth;
5179 else if (eHorJust==SVX_HOR_JUSTIFY_CENTER ||
5180 eHorJust==SVX_HOR_JUSTIFY_STANDARD)
5181 aLogicStart.X() += (nAvailWidth - nEngineWidth) / 2;
5185 if ( bLayoutRTL )
5187 if (bPixelToLogic)
5188 aLogicStart.X() -= mpRefDevice->PixelToLogic(
5189 Size( nCellWidth, 0 ) ).Width();
5190 else
5191 aLogicStart.X() -= nCellWidth;
5194 if ( eOrient==SVX_ORIENTATION_STANDARD ||
5195 eOrient==SVX_ORIENTATION_STACKED || !bBreak )
5197 if (eVerJust==SVX_VER_JUSTIFY_BOTTOM ||
5198 eVerJust==SVX_VER_JUSTIFY_STANDARD)
5200 if (bPixelToLogic)
5201 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,
5202 mpRefDevice->LogicToPixel(aCellSize).Height() -
5203 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
5204 )).Height();
5205 else
5206 aLogicStart.Y() += aCellSize.Height() - nEngineHeight;
5209 else if (eVerJust==SVX_VER_JUSTIFY_CENTER)
5211 if (bPixelToLogic)
5212 aLogicStart.Y() += mpRefDevice->PixelToLogic( Size(0,(
5213 mpRefDevice->LogicToPixel(aCellSize).Height() -
5214 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
5215 / 2)).Height();
5216 else
5217 aLogicStart.Y() += (aCellSize.Height() - nEngineHeight) / 2;
5221 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
5222 OSL_ENSURE( eOrient == SVX_ORIENTATION_STANDARD && nAttrRotate,
5223 "DrawRotated: no rotation" );
5225 long nOriVal = 0;
5226 if ( nAttrRotate )
5228 // Attribut ist 1/100, Font 1/10 Grad
5229 nOriVal = nAttrRotate / 10;
5231 double nAddX = 0.0;
5232 double nAddY = 0.0;
5233 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
5235 //! begrenzen !!!
5236 double nH = nRealHeight * nCos;
5237 nAddX += nH * ( nCos / fabs(nSin) );
5239 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
5240 nAddX -= nRealWidth * nCos;
5241 if ( nSin < 0.0 )
5242 nAddX -= nRealHeight * nSin;
5243 if ( nSin > 0.0 )
5244 nAddY += nRealWidth * nSin;
5245 if ( nCos < 0.0 )
5246 nAddY -= nRealHeight * nCos;
5248 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5250 //! begrenzen !!!
5251 double nSkew = nTotalHeight * nCos / fabs(nSin);
5252 if ( eRotMode == SVX_ROTATE_MODE_CENTER )
5253 nAddX -= nSkew * 0.5;
5254 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
5255 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
5256 nAddX -= nSkew;
5258 long nUp = 0;
5259 if ( eVerJust == SVX_VER_JUSTIFY_CENTER )
5260 nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
5261 else if ( eVerJust == SVX_VER_JUSTIFY_TOP )
5263 if ( nSin > 0.0 )
5264 nUp = aCellSize.Height() - nEngineHeight;
5266 else // BOTTOM / STANDARD
5268 if ( nSin < 0.0 )
5269 nUp = aCellSize.Height() - nEngineHeight;
5271 if ( nUp )
5272 nAddX += ( nUp * nCos / fabs(nSin) );
5275 aLogicStart.X() += (long) nAddX;
5276 aLogicStart.Y() += (long) nAddY;
5279 // bSimClip is not used here (because nOriVal is set)
5281 if ( pEngine->IsRightToLeft( 0 ) )
5283 // For right-to-left, EditEngine always calculates its lines
5284 // beginning from the right edge, but EditLine::nStartPosX is
5285 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
5286 Size aLogicPaper = pEngine->GetPaperSize();
5287 if ( aLogicPaper.Width() > USHRT_MAX )
5289 aLogicPaper.Width() = USHRT_MAX;
5290 pEngine->SetPaperSize(aLogicPaper);
5294 pEngine->Draw( mpDev, aLogicStart, (short)nOriVal );
5296 if (bClip)
5298 if (bMetaFile)
5299 mpDev->Pop();
5300 else
5301 mpDev->SetClipRegion();
5307 nPosX += pRowInfo[0].pCellInfo[nX+1].nWidth * nLayoutSign;
5310 nRowPosY += pRowInfo[nArrY].nHeight;
5314 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */