1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
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>
47 #include <o3tl/make_unique.hxx>
50 #include "document.hxx"
51 #include "formulacell.hxx"
53 #include "patattr.hxx"
54 #include "cellform.hxx"
55 #include "editutil.hxx"
56 #include "progress.hxx"
58 #include "fillinfo.hxx"
59 #include "viewdata.hxx"
60 #include "tabvwsh.hxx"
62 #include "markdata.hxx"
63 #include "stlsheet.hxx"
64 #include "spellcheckcontext.hxx"
65 #include <scopetools.hxx>
67 #include <com/sun/star/i18n/DirectionProperty.hpp>
68 #include <comphelper/string.hxx>
75 using namespace com::sun::star
;
77 //! Merge Autofilter width with column.cxx
78 #define DROPDOWN_BITMAP_SIZE 18
80 #define DRAWTEXT_MAX 32767
82 const sal_uInt16 SC_SHRINKAGAIN_MAX
= 7;
84 class ScDrawStringsVars
86 ScOutputData
* pOutput
; // connection
88 const ScPatternAttr
* pPattern
; // attribute
89 const SfxItemSet
* pCondSet
; // from conditional formatting
91 vcl::Font aFont
; // created from attributes
93 long nAscentPixel
; // always pixels
94 SvxCellOrientation eAttrOrient
;
95 SvxCellHorJustify eAttrHorJust
;
96 SvxCellVerJustify eAttrVerJust
;
97 SvxCellJustifyMethod eAttrHorJustMethod
;
98 SvxCellJustifyMethod eAttrVerJustMethod
;
99 const SvxMarginItem
* pMargin
;
103 OUString aString
; // contents
111 ScRefCellValue maLastCell
;
112 sal_uLong nValueFormat
;
120 Color aBackConfigColor
; // used for ScPatternAttr::GetFont calls
121 Color aTextConfigColor
;
122 sal_Int32 nRepeatPos
;
123 sal_Unicode nRepeatChar
;
126 ScDrawStringsVars(ScOutputData
* pData
, bool bPTL
);
127 ~ScDrawStringsVars();
129 // SetPattern = ex-SetVars
130 // SetPatternSimple: ohne Font
133 const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
, const ScRefCellValue
& rCell
,
134 SvtScriptType nScript
);
136 void SetPatternSimple( const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
);
138 bool SetText( ScRefCellValue
& rCell
); // TRUE -> drop pOldPattern
140 void SetTextToWidthOrHash( ScRefCellValue
& rCell
, long nWidth
);
141 void SetAutoText( const OUString
& rAutoText
);
143 SvxCellOrientation
GetOrient() const { return eAttrOrient
; }
144 SvxCellHorJustify
GetHorJust() const { return eAttrHorJust
; }
145 SvxCellVerJustify
GetVerJust() const { return eAttrVerJust
; }
146 SvxCellJustifyMethod
GetHorJustMethod() const { return eAttrHorJustMethod
; }
147 const SvxMarginItem
* GetMargin() const { return pMargin
; }
149 sal_uInt16
GetLeftTotal() const { return pMargin
->GetLeftMargin() + nIndent
; }
150 sal_uInt16
GetRightTotal() const { return pMargin
->GetRightMargin() + nIndent
; }
152 const OUString
& GetString() const { return aString
; }
153 const Size
& GetTextSize() const { return aTextSize
; }
154 long GetOriginalWidth() const { return nOriginalWidth
; }
156 // Get the effective number format, including formula result types.
157 // This assumes that a formula cell has already been calculated.
158 sal_uLong
GetResultValueFormat() const { return nValueFormat
;}
160 sal_uLong
GetValueFormat() const { return nValueFormat
; }
161 bool GetLineBreak() const { return bLineBreak
; }
162 bool IsRepeat() const { return bRepeat
; }
163 bool IsShrink() const { return bShrink
; }
164 void RepeatToFill( long nColWidth
);
166 long GetAscent() const { return nAscentPixel
; }
167 bool IsRotated() const { return bRotated
; }
169 void SetShrinkScale( long nScale
, SvtScriptType nScript
);
171 bool HasCondHeight() const { return pCondSet
&& SfxItemState::SET
==
172 pCondSet
->GetItemState( ATTR_FONT_HEIGHT
); }
174 bool HasEditCharacters() const;
177 long GetMaxDigitWidth(); // in logic units
184 ScDrawStringsVars::ScDrawStringsVars(ScOutputData
* pData
, bool bPTL
) :
186 pPattern ( nullptr ),
187 pCondSet ( nullptr ),
189 eAttrOrient ( SVX_ORIENTATION_STANDARD
),
190 eAttrHorJust( SVX_HOR_JUSTIFY_STANDARD
),
191 eAttrVerJust( SVX_VER_JUSTIFY_BOTTOM
),
192 eAttrHorJustMethod( SVX_JUSTIFY_METHOD_AUTO
),
193 eAttrVerJustMethod( SVX_JUSTIFY_METHOD_AUTO
),
203 bLineBreak ( false ),
206 bPixelToLogic( bPTL
),
210 ScModule
* pScMod
= SC_MOD();
211 bCellContrast
= pOutput
->mbUseStyleColor
&&
212 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
214 const svtools::ColorConfig
& rColorConfig
= pScMod
->GetColorConfig();
215 aBackConfigColor
.SetColor( rColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
);
216 aTextConfigColor
.SetColor( rColorConfig
.GetColorValue(svtools::FONTCOLOR
).nColor
);
219 ScDrawStringsVars::~ScDrawStringsVars()
223 void ScDrawStringsVars::SetShrinkScale( long nScale
, SvtScriptType nScript
)
225 // text remains valid, size is updated
227 OutputDevice
* pDev
= pOutput
->mpDev
;
228 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
229 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
231 // call GetFont with a modified fraction, use only the height
233 Fraction
aFraction( nScale
, 100 );
234 if ( !bPixelToLogic
)
235 aFraction
*= pOutput
->aZoomY
;
237 pPattern
->GetFont( aTmpFont
, SC_AUTOCOL_RAW
, pFmtDevice
, &aFraction
, pCondSet
, nScript
);
238 long nNewHeight
= aTmpFont
.GetFontHeight();
239 if ( nNewHeight
> 0 )
240 aFont
.SetFontHeight( nNewHeight
);
242 // set font and dependent variables as in SetPattern
244 pDev
->SetFont( aFont
);
245 if ( pFmtDevice
!= pDev
)
246 pFmtDevice
->SetFont( aFont
);
248 aMetric
= pFmtDevice
->GetFontMetric();
249 if ( pFmtDevice
->GetOutDevType() == OUTDEV_PRINTER
&& aMetric
.GetInternalLeading() == 0 )
251 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
252 MapMode aOld
= pDefaultDev
->GetMapMode();
253 pDefaultDev
->SetMapMode( pFmtDevice
->GetMapMode() );
254 aMetric
= pDefaultDev
->GetFontMetric( aFont
);
255 pDefaultDev
->SetMapMode( aOld
);
258 nAscentPixel
= aMetric
.GetAscent();
260 nAscentPixel
= pRefDevice
->LogicToPixel( Size( 0, nAscentPixel
) ).Height();
262 SetAutoText( aString
); // same text again, to get text size
267 template<typename ItemType
, typename EnumType
>
268 EnumType
lcl_GetValue(const ScPatternAttr
& rPattern
, sal_uInt16 nWhich
, const SfxItemSet
* pCondSet
)
270 const ItemType
& rItem
= static_cast<const ItemType
&>(rPattern
.GetItem(nWhich
, pCondSet
));
271 return static_cast<EnumType
>(rItem
.GetValue());
274 bool lcl_GetBoolValue(const ScPatternAttr
& rPattern
, sal_uInt16 nWhich
, const SfxItemSet
* pCondSet
)
276 return lcl_GetValue
<SfxBoolItem
, bool>(rPattern
, nWhich
, pCondSet
);
281 bool lcl_isNumberFormatText(const ScDocument
* pDoc
, SCCOL nCellX
, SCROW nCellY
, SCTAB nTab
)
283 sal_uInt32 nCurrentNumberFormat
;
284 pDoc
->GetNumberFormat( nCellX
, nCellY
, nTab
, nCurrentNumberFormat
);
285 SvNumberFormatter
* pNumberFormatter
= pDoc
->GetFormatTable();
286 return pNumberFormatter
->GetType( nCurrentNumberFormat
) == css::util::NumberFormat::TEXT
;
289 void ScDrawStringsVars::SetPattern(
290 const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
, const ScRefCellValue
& rCell
,
291 SvtScriptType nScript
)
301 // évaluate pPattern
303 OutputDevice
* pDev
= pOutput
->mpDev
;
304 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
305 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
309 ScAutoFontColorMode eColorMode
;
310 if ( pOutput
->mbUseStyleColor
)
312 if ( pOutput
->mbForceAutoColor
)
313 eColorMode
= bCellContrast
? SC_AUTOCOL_IGNOREALL
: SC_AUTOCOL_IGNOREFONT
;
315 eColorMode
= bCellContrast
? SC_AUTOCOL_IGNOREBACK
: SC_AUTOCOL_DISPLAY
;
318 eColorMode
= SC_AUTOCOL_PRINT
;
321 pPattern
->GetFont( aFont
, eColorMode
, pFmtDevice
, nullptr, pCondSet
, nScript
,
322 &aBackConfigColor
, &aTextConfigColor
);
324 pPattern
->GetFont( aFont
, eColorMode
, pFmtDevice
, &pOutput
->aZoomY
, pCondSet
, nScript
,
325 &aBackConfigColor
, &aTextConfigColor
);
326 aFont
.SetAlignment(ALIGN_BASELINE
);
330 eAttrOrient
= pPattern
->GetCellOrientation( pCondSet
);
334 eAttrHorJust
= (SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
&>(pPattern
->GetItem( ATTR_HOR_JUSTIFY
, pCondSet
)).GetValue();
336 eAttrVerJust
= (SvxCellVerJustify
)static_cast<const SvxVerJustifyItem
&>(pPattern
->GetItem( ATTR_VER_JUSTIFY
, pCondSet
)).GetValue();
337 if ( eAttrVerJust
== SVX_VER_JUSTIFY_STANDARD
)
338 eAttrVerJust
= SVX_VER_JUSTIFY_BOTTOM
;
340 // justification method
342 eAttrHorJustMethod
= lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_HOR_JUSTIFY_METHOD
, pCondSet
);
343 eAttrVerJustMethod
= lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_VER_JUSTIFY_METHOD
, pCondSet
);
347 bLineBreak
= static_cast<const SfxBoolItem
&>(pPattern
->GetItem( ATTR_LINEBREAK
, pCondSet
)).GetValue();
349 // handle "repeat" alignment
351 bRepeat
= ( eAttrHorJust
== SVX_HOR_JUSTIFY_REPEAT
);
354 // "repeat" disables rotation (before constructing the font)
355 eAttrOrient
= SVX_ORIENTATION_STANDARD
;
357 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
359 eAttrHorJust
= SVX_HOR_JUSTIFY_STANDARD
;
365 case SVX_ORIENTATION_STANDARD
:
367 bRotated
= static_cast<const SfxInt32Item
&>(pPattern
->GetItem( ATTR_ROTATE_VALUE
, pCondSet
)).GetValue() != 0 &&
370 case SVX_ORIENTATION_STACKED
:
374 case SVX_ORIENTATION_TOPBOTTOM
:
378 case SVX_ORIENTATION_BOTTOMTOP
:
383 OSL_FAIL("Invalid SvxCellOrientation value");
388 aFont
.SetOrientation( nRot
);
392 if (pOutput
->mbSyntaxMode
)
393 pOutput
->SetSyntaxColor(&aFont
, rCell
);
395 pDev
->SetFont( aFont
);
396 if ( pFmtDevice
!= pDev
)
397 pFmtDevice
->SetFont( aFont
);
399 aMetric
= pFmtDevice
->GetFontMetric();
401 // if there is the leading 0 on a printer device, we have problems
402 // -> take metric from the screen (as for EditEngine!)
403 if ( pFmtDevice
->GetOutDevType() == OUTDEV_PRINTER
&& aMetric
.GetInternalLeading() == 0 )
405 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
406 MapMode aOld
= pDefaultDev
->GetMapMode();
407 pDefaultDev
->SetMapMode( pFmtDevice
->GetMapMode() );
408 aMetric
= pDefaultDev
->GetFontMetric( aFont
);
409 pDefaultDev
->SetMapMode( aOld
);
412 nAscentPixel
= aMetric
.GetAscent();
414 nAscentPixel
= pRefDevice
->LogicToPixel( Size( 0, nAscentPixel
) ).Height();
416 Color
aULineColor( static_cast<const SvxUnderlineItem
&>(pPattern
->GetItem( ATTR_FONT_UNDERLINE
, pCondSet
)).GetColor() );
417 pDev
->SetTextLineColor( aULineColor
);
419 Color
aOLineColor( static_cast<const SvxOverlineItem
&>(pPattern
->GetItem( ATTR_FONT_OVERLINE
, pCondSet
)).GetColor() );
420 pDev
->SetOverlineColor( aOLineColor
);
424 nValueFormat
= pPattern
->GetNumberFormat( pOutput
->mpDoc
->GetFormatTable(), pCondSet
);
427 pMargin
= static_cast<const SvxMarginItem
*>(&pPattern
->GetItem( ATTR_MARGIN
, pCondSet
));
428 if ( eAttrHorJust
== SVX_HOR_JUSTIFY_LEFT
|| eAttrHorJust
== SVX_HOR_JUSTIFY_RIGHT
)
429 nIndent
= static_cast<const SfxUInt16Item
&>(pPattern
->GetItem( ATTR_INDENT
, pCondSet
)).GetValue();
435 bShrink
= static_cast<const SfxBoolItem
&>(pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
)).GetValue();
437 // at least the text size needs to be retrieved again
438 //! differentiate and do not get the text again from the number format?
442 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
)
449 // Is called, when the font variables do not change (!StringDiffer)
452 pCondSet
= pSet
; //! is this needed ???
456 sal_uLong nOld
= nValueFormat
;
457 const SfxPoolItem
* pFormItem
;
458 if ( !pCondSet
|| pCondSet
->GetItemState(ATTR_VALUE_FORMAT
,true,&pFormItem
) != SfxItemState::SET
)
459 pFormItem
= &pPattern
->GetItem(ATTR_VALUE_FORMAT
);
460 const SfxPoolItem
* pLangItem
;
461 if ( !pCondSet
|| pCondSet
->GetItemState(ATTR_LANGUAGE_FORMAT
,true,&pLangItem
) != SfxItemState::SET
)
462 pLangItem
= &pPattern
->GetItem(ATTR_LANGUAGE_FORMAT
);
463 nValueFormat
= pOutput
->mpDoc
->GetFormatTable()->GetFormatForLanguageIfBuiltIn(
464 static_cast<const SfxUInt32Item
*>(pFormItem
)->GetValue(),
465 static_cast<const SvxLanguageItem
*>(pLangItem
)->GetLanguage() );
467 if (nValueFormat
!= nOld
)
468 maLastCell
.clear(); // always reformat
472 pMargin
= static_cast<const SvxMarginItem
*>(&pPattern
->GetItem( ATTR_MARGIN
, pCondSet
));
474 if ( eAttrHorJust
== SVX_HOR_JUSTIFY_LEFT
)
475 nIndent
= static_cast<const SfxUInt16Item
&>(pPattern
->GetItem( ATTR_INDENT
, pCondSet
)).GetValue();
481 bShrink
= static_cast<const SfxBoolItem
&>(pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
)).GetValue();
484 inline bool SameValue( const ScRefCellValue
& rCell
, const ScRefCellValue
& rOldCell
)
486 return rOldCell
.meType
== CELLTYPE_VALUE
&& rCell
.meType
== CELLTYPE_VALUE
&&
487 rCell
.mfValue
== rOldCell
.mfValue
;
490 bool ScDrawStringsVars::SetText( ScRefCellValue
& rCell
)
492 bool bChanged
= false;
494 if (!rCell
.isEmpty())
496 if (!SameValue(rCell
, maLastCell
))
498 maLastCell
= rCell
; // store cell
501 sal_uLong nFormat
= GetValueFormat();
502 ScCellFormat::GetString( rCell
,
503 nFormat
, aString
, &pColor
,
504 *pOutput
->mpDoc
->GetFormatTable(),
506 pOutput
->mbShowNullValues
,
507 pOutput
->mbShowFormulas
,
511 nRepeatPos
= aString
.indexOf( 0x1B );
512 if ( nRepeatPos
!= -1 )
514 if (nRepeatPos
+ 1 == aString
.getLength())
518 nRepeatChar
= aString
[ nRepeatPos
+ 1 ];
519 // delete placeholder and char to repeat
520 aString
= aString
.replaceAt( nRepeatPos
, 2, "" );
521 // Do not cache/reuse a repeat-filled string, column
522 // widths or fonts or sizes may differ.
532 if (aString
.getLength() > DRAWTEXT_MAX
)
533 aString
= aString
.copy(0, DRAWTEXT_MAX
);
535 if ( pColor
&& !pOutput
->mbSyntaxMode
&& !( pOutput
->mbUseStyleColor
&& pOutput
->mbForceAutoColor
) )
537 OutputDevice
* pDev
= pOutput
->mpDev
;
538 aFont
.SetColor(*pColor
);
539 pDev
->SetFont( aFont
); // only for output
541 maLastCell
.clear(); // next time return here again
546 // otherwise keep string/size
552 aTextSize
= Size(0,0);
559 void ScDrawStringsVars::SetHashText()
564 void ScDrawStringsVars::RepeatToFill( long nColWidth
)
566 if ( nRepeatPos
== -1 || nRepeatPos
> aString
.getLength() )
569 long nCharWidth
= pOutput
->pFmtDevice
->GetTextWidth(OUString(nRepeatChar
));
570 if ( nCharWidth
< 1) return;
572 nColWidth
= pOutput
->mpRefDevice
->PixelToLogic(Size(nColWidth
,0)).Width();
573 // Are there restrictions on the cell type we should filter out here ?
574 long nSpaceToFill
= ( nColWidth
- aTextSize
.Width() );
576 if ( nSpaceToFill
<= nCharWidth
)
579 long nCharsToInsert
= nSpaceToFill
/ nCharWidth
;
580 OUStringBuffer aFill
;
581 comphelper::string::padToLength(aFill
, nCharsToInsert
, nRepeatChar
);
582 aString
= aString
.replaceAt( nRepeatPos
, 0, aFill
.makeStringAndClear() );
586 void ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue
& rCell
, long nWidth
)
588 // #i113045# do the single-character width calculations in logic units
590 nWidth
= pOutput
->mpRefDevice
->PixelToLogic(Size(nWidth
,0)).Width();
592 CellType eType
= rCell
.meType
;
593 if (eType
!= CELLTYPE_VALUE
&& eType
!= CELLTYPE_FORMULA
)
594 // must be a value or formula cell.
597 if (eType
== CELLTYPE_FORMULA
)
599 ScFormulaCell
* pFCell
= rCell
.mpFormula
;
600 if (pFCell
->GetErrCode() != 0 || pOutput
->mbShowFormulas
)
602 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
605 // If it's formula, the result must be a value.
606 if (!pFCell
->IsValue())
610 sal_uLong nFormat
= GetResultValueFormat();
611 if ((nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) != 0)
613 // Not 'General' number format. Set hash text and bail out.
618 double fVal
= rCell
.getValue();
620 const SvNumberformat
* pNumFormat
= pOutput
->mpDoc
->GetFormatTable()->GetEntry(nFormat
);
624 long nMaxDigit
= GetMaxDigitWidth();
625 sal_uInt16 nNumDigits
= static_cast<sal_uInt16
>(nWidth
/ nMaxDigit
);
627 OUString
sTempOut(aString
);
628 if (!pNumFormat
->GetOutputString(fVal
, nNumDigits
, sTempOut
))
631 // Failed to get output string. Bail out.
636 sal_uInt8 nSignCount
= 0, nDecimalCount
= 0, nExpCount
= 0;
637 sal_Int32 nLen
= aString
.getLength();
638 sal_Unicode cDecSep
= ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator
[0];
639 for( sal_Int32 i
= 0; i
< nLen
; ++i
)
641 sal_Unicode c
= aString
[i
];
644 else if (c
== cDecSep
)
650 // #i112250# A small value might be formatted as "0" when only counting the digits,
651 // but fit into the column when considering the smaller width of the decimal separator.
652 if (aString
== "0" && fVal
!= 0.0)
656 nWidth
+= (nMaxDigit
- GetDotWidth()) * nDecimalCount
;
658 nWidth
+= (nMaxDigit
- GetSignWidth()) * nSignCount
;
660 nWidth
+= (nMaxDigit
- GetExpWidth()) * nExpCount
;
662 if (nDecimalCount
|| nSignCount
|| nExpCount
)
665 nNumDigits
= static_cast<sal_uInt16
>(nWidth
/ nMaxDigit
);
666 OUString
sTempOut(aString
);
667 if (!pNumFormat
->GetOutputString(fVal
, nNumDigits
, sTempOut
))
670 // Failed to get output string. Bail out.
676 long nActualTextWidth
= pOutput
->pFmtDevice
->GetTextWidth(aString
);
677 if (nActualTextWidth
> nWidth
)
679 // Even after the decimal adjustment the text doesn't fit. Give up.
685 maLastCell
.clear(); // #i113022# equal cell and format in another column may give different string
688 void ScDrawStringsVars::SetAutoText( const OUString
& rAutoText
)
692 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
693 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
694 aTextSize
.Width() = pFmtDevice
->GetTextWidth( aString
);
695 aTextSize
.Height() = pFmtDevice
->GetTextHeight();
697 if ( !pRefDevice
->GetConnectMetaFile() || pRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
699 double fMul
= pOutput
->GetStretch();
700 aTextSize
.Width() = (long)(aTextSize
.Width() / fMul
+ 0.5);
703 aTextSize
.Height() = aMetric
.GetAscent() + aMetric
.GetDescent();
704 if ( GetOrient() != SVX_ORIENTATION_STANDARD
)
706 long nTemp
= aTextSize
.Height();
707 aTextSize
.Height() = aTextSize
.Width();
708 aTextSize
.Width() = nTemp
;
711 nOriginalWidth
= aTextSize
.Width();
713 aTextSize
= pRefDevice
->LogicToPixel( aTextSize
);
715 maLastCell
.clear(); // the same text may fit in the next cell
718 long ScDrawStringsVars::GetMaxDigitWidth()
720 if (nMaxDigitWidth
> 0)
721 return nMaxDigitWidth
;
723 sal_Char cZero
= '0';
724 for (sal_Char i
= 0; i
< 10; ++i
)
726 sal_Char cDigit
= cZero
+ i
;
727 long n
= pOutput
->pFmtDevice
->GetTextWidth(OUString(cDigit
));
728 nMaxDigitWidth
= ::std::max(nMaxDigitWidth
, n
);
730 return nMaxDigitWidth
;
733 long ScDrawStringsVars::GetSignWidth()
738 nSignWidth
= pOutput
->pFmtDevice
->GetTextWidth(OUString('-'));
742 long ScDrawStringsVars::GetDotWidth()
747 const OUString
& sep
= ScGlobal::GetpLocaleData()->getLocaleItem().decimalSeparator
;
748 nDotWidth
= pOutput
->pFmtDevice
->GetTextWidth(sep
);
752 long ScDrawStringsVars::GetExpWidth()
757 nExpWidth
= pOutput
->pFmtDevice
->GetTextWidth(OUString('E'));
761 void ScDrawStringsVars::TextChanged()
763 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
764 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
765 aTextSize
.Width() = pFmtDevice
->GetTextWidth( aString
);
766 aTextSize
.Height() = pFmtDevice
->GetTextHeight();
768 if ( !pRefDevice
->GetConnectMetaFile() || pRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
770 double fMul
= pOutput
->GetStretch();
771 aTextSize
.Width() = (long)(aTextSize
.Width() / fMul
+ 0.5);
774 aTextSize
.Height() = aMetric
.GetAscent() + aMetric
.GetDescent();
775 if ( GetOrient() != SVX_ORIENTATION_STANDARD
)
777 long nTemp
= aTextSize
.Height();
778 aTextSize
.Height() = aTextSize
.Width();
779 aTextSize
.Width() = nTemp
;
782 nOriginalWidth
= aTextSize
.Width();
784 aTextSize
= pRefDevice
->LogicToPixel( aTextSize
);
787 bool ScDrawStringsVars::HasEditCharacters() const
789 for (sal_Int32 nIdx
= 0; nIdx
< aString
.getLength(); ++nIdx
)
791 switch(aString
[nIdx
])
809 double ScOutputData::GetStretch()
811 if ( mpRefDevice
->IsMapModeEnabled() )
813 // If a non-trivial MapMode is set, its scale is now already
814 // taken into account in the OutputDevice's font handling
815 // (OutputDevice::ImplNewFont, see #95414#).
816 // The old handling below is only needed for pixel output.
820 // calculation in double is faster than Fraction multiplication
821 // and doesn't overflow
823 if ( mpRefDevice
== pFmtDevice
)
825 MapMode aOld
= mpRefDevice
->GetMapMode();
826 return ((double)aOld
.GetScaleY()) / ((double)aOld
.GetScaleX()) * ((double)aZoomY
) / ((double)aZoomX
);
830 // when formatting for printer, device map mode has already been taken care of
831 return ((double)aZoomY
) / ((double)aZoomX
);
837 static void lcl_DoHyperlinkResult( OutputDevice
* pDev
, const Rectangle
& rRect
, ScRefCellValue
& rCell
)
839 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast< vcl::PDFExtOutDevData
* >( pDev
->GetExtOutDevData() );
843 if (rCell
.meType
== CELLTYPE_FORMULA
)
845 ScFormulaCell
* pFCell
= rCell
.mpFormula
;
846 if ( pFCell
->IsHyperLinkCell() )
847 pFCell
->GetURLResult( aURL
, aCellText
);
850 if ( !aURL
.isEmpty() && pPDFData
)
852 vcl::PDFExtOutDevBookmarkEntry aBookmark
;
853 aBookmark
.nLinkId
= pPDFData
->CreateLink( rRect
);
854 aBookmark
.aBookmark
= aURL
;
855 std::vector
< vcl::PDFExtOutDevBookmarkEntry
>& rBookmarks
= pPDFData
->GetBookmarks();
856 rBookmarks
.push_back( aBookmark
);
860 void ScOutputData::SetSyntaxColor( vcl::Font
* pFont
, const ScRefCellValue
& rCell
)
862 switch (rCell
.meType
)
865 pFont
->SetColor(*pValueColor
);
867 case CELLTYPE_STRING
:
868 pFont
->SetColor(*pTextColor
);
870 case CELLTYPE_FORMULA
:
871 pFont
->SetColor(*pFormulaColor
);
875 // added to avoid warnings
880 static void lcl_SetEditColor( EditEngine
& rEngine
, const Color
& rColor
)
882 ESelection
aSel( 0, 0, rEngine
.GetParagraphCount(), 0 );
883 SfxItemSet
aSet( rEngine
.GetEmptyItemSet() );
884 aSet
.Put( SvxColorItem( rColor
, EE_CHAR_COLOR
) );
885 rEngine
.QuickSetAttribs( aSet
, aSel
);
886 // function is called with update mode set to FALSE
889 void ScOutputData::SetEditSyntaxColor( EditEngine
& rEngine
, ScRefCellValue
& rCell
)
892 switch (rCell
.meType
)
895 aColor
= *pValueColor
;
897 case CELLTYPE_STRING
:
898 aColor
= *pTextColor
;
900 case CELLTYPE_FORMULA
:
901 aColor
= *pFormulaColor
;
905 // added to avoid warnings
908 lcl_SetEditColor( rEngine
, aColor
);
911 bool ScOutputData::GetMergeOrigin( SCCOL nX
, SCROW nY
, SCSIZE nArrY
,
912 SCCOL
& rOverX
, SCROW
& rOverY
,
913 bool bVisRowChanged
)
915 bool bDoMerge
= false;
916 bool bIsLeft
= ( nX
== nVisX1
);
917 bool bIsTop
= ( nY
== nVisY1
) || bVisRowChanged
;
919 CellInfo
* pInfo
= &pRowInfo
[nArrY
].pCellInfo
[nX
+1];
920 if ( pInfo
->bHOverlapped
&& pInfo
->bVOverlapped
)
921 bDoMerge
= bIsLeft
&& bIsTop
;
922 else if ( pInfo
->bHOverlapped
)
924 else if ( pInfo
->bVOverlapped
)
929 bool bHOver
= pInfo
->bHOverlapped
;
930 bool bVOver
= pInfo
->bVOverlapped
;
933 while (bHOver
) // nY constant
936 bHidden
= mpDoc
->ColHidden(rOverX
, nTab
);
937 if ( !bDoMerge
&& !bHidden
)
940 if (rOverX
>= nX1
&& !bHidden
)
942 bHOver
= pRowInfo
[nArrY
].pCellInfo
[rOverX
+1].bHOverlapped
;
943 bVOver
= pRowInfo
[nArrY
].pCellInfo
[rOverX
+1].bVOverlapped
;
947 ScMF nOverlap
= static_cast<const ScMergeFlagAttr
*>(mpDoc
->GetAttr(
948 rOverX
, rOverY
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
949 bHOver
= bool(nOverlap
& ScMF::Hor
);
950 bVOver
= bool(nOverlap
& ScMF::Ver
);
957 bHidden
= mpDoc
->RowHidden(rOverY
, nTab
);
958 if ( !bDoMerge
&& !bHidden
)
962 --nArrY
; // local copy !
964 if (rOverX
>= nX1
&& rOverY
>= nY1
&&
965 !mpDoc
->ColHidden(rOverX
, nTab
) &&
966 !mpDoc
->RowHidden(rOverY
, nTab
) &&
967 pRowInfo
[nArrY
].nRowNo
== rOverY
)
969 bVOver
= pRowInfo
[nArrY
].pCellInfo
[rOverX
+1].bVOverlapped
;
973 ScMF nOverlap
= static_cast<const ScMergeFlagAttr
*>(mpDoc
->GetAttr(
974 rOverX
, rOverY
, nTab
, ATTR_MERGE_FLAG
))->GetValue();
975 bVOver
= bool(nOverlap
& ScMF::Ver
);
982 inline bool StringDiffer( const ScPatternAttr
*& rpOldPattern
, const ScPatternAttr
*& rpNewPattern
)
984 OSL_ENSURE( rpNewPattern
, "pNewPattern" );
986 if ( rpNewPattern
== rpOldPattern
)
988 else if ( !rpOldPattern
)
990 else if ( &rpNewPattern
->GetItem( ATTR_FONT
) != &rpOldPattern
->GetItem( ATTR_FONT
) )
992 else if ( &rpNewPattern
->GetItem( ATTR_CJK_FONT
) != &rpOldPattern
->GetItem( ATTR_CJK_FONT
) )
994 else if ( &rpNewPattern
->GetItem( ATTR_CTL_FONT
) != &rpOldPattern
->GetItem( ATTR_CTL_FONT
) )
996 else if ( &rpNewPattern
->GetItem( ATTR_FONT_HEIGHT
) != &rpOldPattern
->GetItem( ATTR_FONT_HEIGHT
) )
998 else if ( &rpNewPattern
->GetItem( ATTR_CJK_FONT_HEIGHT
) != &rpOldPattern
->GetItem( ATTR_CJK_FONT_HEIGHT
) )
1000 else if ( &rpNewPattern
->GetItem( ATTR_CTL_FONT_HEIGHT
) != &rpOldPattern
->GetItem( ATTR_CTL_FONT_HEIGHT
) )
1002 else if ( &rpNewPattern
->GetItem( ATTR_FONT_WEIGHT
) != &rpOldPattern
->GetItem( ATTR_FONT_WEIGHT
) )
1004 else if ( &rpNewPattern
->GetItem( ATTR_CJK_FONT_WEIGHT
) != &rpOldPattern
->GetItem( ATTR_CJK_FONT_WEIGHT
) )
1006 else if ( &rpNewPattern
->GetItem( ATTR_CTL_FONT_WEIGHT
) != &rpOldPattern
->GetItem( ATTR_CTL_FONT_WEIGHT
) )
1008 else if ( &rpNewPattern
->GetItem( ATTR_FONT_POSTURE
) != &rpOldPattern
->GetItem( ATTR_FONT_POSTURE
) )
1010 else if ( &rpNewPattern
->GetItem( ATTR_CJK_FONT_POSTURE
) != &rpOldPattern
->GetItem( ATTR_CJK_FONT_POSTURE
) )
1012 else if ( &rpNewPattern
->GetItem( ATTR_CTL_FONT_POSTURE
) != &rpOldPattern
->GetItem( ATTR_CTL_FONT_POSTURE
) )
1014 else if ( &rpNewPattern
->GetItem( ATTR_FONT_UNDERLINE
) != &rpOldPattern
->GetItem( ATTR_FONT_UNDERLINE
) )
1016 else if ( &rpNewPattern
->GetItem( ATTR_FONT_OVERLINE
) != &rpOldPattern
->GetItem( ATTR_FONT_OVERLINE
) )
1018 else if ( &rpNewPattern
->GetItem( ATTR_FONT_WORDLINE
) != &rpOldPattern
->GetItem( ATTR_FONT_WORDLINE
) )
1020 else if ( &rpNewPattern
->GetItem( ATTR_FONT_CROSSEDOUT
) != &rpOldPattern
->GetItem( ATTR_FONT_CROSSEDOUT
) )
1022 else if ( &rpNewPattern
->GetItem( ATTR_FONT_CONTOUR
) != &rpOldPattern
->GetItem( ATTR_FONT_CONTOUR
) )
1024 else if ( &rpNewPattern
->GetItem( ATTR_FONT_SHADOWED
) != &rpOldPattern
->GetItem( ATTR_FONT_SHADOWED
) )
1026 else if ( &rpNewPattern
->GetItem( ATTR_FONT_COLOR
) != &rpOldPattern
->GetItem( ATTR_FONT_COLOR
) )
1028 else if ( &rpNewPattern
->GetItem( ATTR_HOR_JUSTIFY
) != &rpOldPattern
->GetItem( ATTR_HOR_JUSTIFY
) )
1030 else if ( &rpNewPattern
->GetItem( ATTR_HOR_JUSTIFY_METHOD
) != &rpOldPattern
->GetItem( ATTR_HOR_JUSTIFY_METHOD
) )
1032 else if ( &rpNewPattern
->GetItem( ATTR_VER_JUSTIFY
) != &rpOldPattern
->GetItem( ATTR_VER_JUSTIFY
) )
1034 else if ( &rpNewPattern
->GetItem( ATTR_VER_JUSTIFY_METHOD
) != &rpOldPattern
->GetItem( ATTR_VER_JUSTIFY_METHOD
) )
1036 else if ( &rpNewPattern
->GetItem( ATTR_STACKED
) != &rpOldPattern
->GetItem( ATTR_STACKED
) )
1038 else if ( &rpNewPattern
->GetItem( ATTR_LINEBREAK
) != &rpOldPattern
->GetItem( ATTR_LINEBREAK
) )
1040 else if ( &rpNewPattern
->GetItem( ATTR_MARGIN
) != &rpOldPattern
->GetItem( ATTR_MARGIN
) )
1042 else if ( &rpNewPattern
->GetItem( ATTR_ROTATE_VALUE
) != &rpOldPattern
->GetItem( ATTR_ROTATE_VALUE
) )
1044 else if ( &rpNewPattern
->GetItem( ATTR_FORBIDDEN_RULES
) != &rpOldPattern
->GetItem( ATTR_FORBIDDEN_RULES
) )
1046 else if ( &rpNewPattern
->GetItem( ATTR_FONT_EMPHASISMARK
) != &rpOldPattern
->GetItem( ATTR_FONT_EMPHASISMARK
) )
1048 else if ( &rpNewPattern
->GetItem( ATTR_FONT_RELIEF
) != &rpOldPattern
->GetItem( ATTR_FONT_RELIEF
) )
1050 else if ( &rpNewPattern
->GetItem( ATTR_BACKGROUND
) != &rpOldPattern
->GetItem( ATTR_BACKGROUND
) )
1051 return true; // needed with automatic text color
1054 rpOldPattern
= rpNewPattern
;
1059 static inline void lcl_CreateInterpretProgress( bool& bProgress
, ScDocument
* pDoc
,
1060 ScFormulaCell
* pFCell
)
1062 if ( !bProgress
&& pFCell
->GetDirty() )
1064 ScProgress::CreateInterpretProgress( pDoc
);
1069 inline bool IsAmbiguousScript( SvtScriptType nScript
)
1071 return ( nScript
!= SvtScriptType::LATIN
&&
1072 nScript
!= SvtScriptType::ASIAN
&&
1073 nScript
!= SvtScriptType::COMPLEX
);
1076 bool ScOutputData::IsEmptyCellText( RowInfo
* pThisRowInfo
, SCCOL nX
, SCROW nY
)
1078 // pThisRowInfo may be NULL
1081 if ( pThisRowInfo
&& nX
<= nX2
)
1082 bEmpty
= pThisRowInfo
->pCellInfo
[nX
+1].bEmptyCellText
;
1085 ScRefCellValue
aCell(*mpDoc
, ScAddress(nX
, nY
, nTab
));
1086 bEmpty
= aCell
.isEmpty();
1089 if ( !bEmpty
&& ( nX
< nX1
|| nX
> nX2
|| !pThisRowInfo
) )
1091 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1092 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1094 bool bIsPrint
= ( eType
== OUTTYPE_PRINTER
);
1096 if ( bIsPrint
|| bTabProtected
)
1098 const ScProtectionAttr
* pAttr
= static_cast<const ScProtectionAttr
*>(
1099 mpDoc
->GetEffItem( nX
, nY
, nTab
, ATTR_PROTECTION
));
1100 if ( bIsPrint
&& pAttr
->GetHidePrint() )
1102 else if ( bTabProtected
)
1104 if ( pAttr
->GetHideCell() )
1106 else if ( mbShowFormulas
&& pAttr
->GetHideFormula() )
1108 if (mpDoc
->GetCellType(ScAddress(nX
, nY
, nTab
)) == CELLTYPE_FORMULA
)
1117 void ScOutputData::GetVisibleCell( SCCOL nCol
, SCROW nRow
, SCTAB nTabP
, ScRefCellValue
& rCell
)
1119 rCell
.assign(*mpDoc
, ScAddress(nCol
, nRow
, nTabP
));
1120 if (!rCell
.isEmpty() && IsEmptyCellText(nullptr, nCol
, nRow
))
1124 bool ScOutputData::IsAvailable( SCCOL nX
, SCROW nY
)
1126 // apply the same logic here as in DrawStrings/DrawEdit:
1127 // Stop at non-empty or merged or overlapped cell,
1128 // where a note is empty as well as a cell that's hidden by protection settings
1130 ScRefCellValue
aCell(*mpDoc
, ScAddress(nX
, nY
, nTab
));
1131 if (!aCell
.isEmpty() && !IsEmptyCellText(nullptr, nX
, nY
))
1134 const ScPatternAttr
* pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
1135 if ( static_cast<const ScMergeAttr
&>(pPattern
->GetItem(ATTR_MERGE
)).IsMerged() ||
1136 static_cast<const ScMergeFlagAttr
&>(pPattern
->GetItem(ATTR_MERGE_FLAG
)).IsOverlapped() )
1144 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1145 // nPosX, nPosY: corresponding positions for nX, nArrY
1146 // nCellX, nCellY: position of the cell that contains the text
1147 // nNeeded: Text width, including margin
1148 // rPattern: cell format at nCellX, nCellY
1149 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1150 // bCellIsValue: if set, don't extend into empty cells
1151 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1152 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1153 // rParam output: various area parameters.
1155 void ScOutputData::GetOutputArea( SCCOL nX
, SCSIZE nArrY
, long nPosX
, long nPosY
,
1156 SCCOL nCellX
, SCROW nCellY
, long nNeeded
,
1157 const ScPatternAttr
& rPattern
,
1158 sal_uInt16 nHorJustify
, bool bCellIsValue
,
1159 bool bBreak
, bool bOverwrite
,
1160 OutputAreaParam
& rParam
)
1162 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1163 RowInfo
& rThisRowInfo
= pRowInfo
[nArrY
];
1165 long nLayoutSign
= bLayoutRTL
? -1 : 1;
1167 long nCellPosX
= nPosX
; // find nCellX position, starting at nX/nPosX
1168 SCCOL nCompCol
= nX
;
1169 while ( nCellX
> nCompCol
)
1171 //! extra member function for width?
1172 long nColWidth
= ( nCompCol
<= nX2
) ?
1173 pRowInfo
[0].pCellInfo
[nCompCol
+1].nWidth
:
1174 (long) ( mpDoc
->GetColWidth( nCompCol
, nTab
) * mnPPTX
);
1175 nCellPosX
+= nColWidth
* nLayoutSign
;
1178 while ( nCellX
< nCompCol
)
1181 long nColWidth
= ( nCompCol
<= nX2
) ?
1182 pRowInfo
[0].pCellInfo
[nCompCol
+1].nWidth
:
1183 (long) ( mpDoc
->GetColWidth( nCompCol
, nTab
) * mnPPTX
);
1184 nCellPosX
-= nColWidth
* nLayoutSign
;
1187 long nCellPosY
= nPosY
; // find nCellY position, starting at nArrY/nPosY
1188 SCSIZE nCompArr
= nArrY
;
1189 SCROW nCompRow
= pRowInfo
[nCompArr
].nRowNo
;
1190 while ( nCellY
> nCompRow
)
1192 if ( nCompArr
+ 1 < nArrCount
)
1194 nCellPosY
+= pRowInfo
[nCompArr
].nHeight
;
1196 nCompRow
= pRowInfo
[nCompArr
].nRowNo
;
1200 sal_uInt16 nDocHeight
= mpDoc
->GetRowHeight( nCompRow
, nTab
);
1202 nCellPosY
+= (long) ( nDocHeight
* mnPPTY
);
1206 nCellPosY
-= (long) mpDoc
->GetScaledRowHeight( nCellY
, nCompRow
-1, nTab
, mnPPTY
);
1208 const ScMergeAttr
* pMerge
= static_cast<const ScMergeAttr
*>(&rPattern
.GetItem( ATTR_MERGE
));
1209 bool bMerged
= pMerge
->IsMerged();
1210 long nMergeCols
= pMerge
->GetColMerge();
1211 if ( nMergeCols
== 0 )
1213 long nMergeRows
= pMerge
->GetRowMerge();
1214 if ( nMergeRows
== 0 )
1217 long nMergeSizeX
= 0;
1218 for ( long i
=0; i
<nMergeCols
; i
++ )
1220 long nColWidth
= ( nCellX
+i
<= nX2
) ?
1221 pRowInfo
[0].pCellInfo
[nCellX
+i
+1].nWidth
:
1222 (long) ( mpDoc
->GetColWidth( sal::static_int_cast
<SCCOL
>(nCellX
+i
), nTab
) * mnPPTX
);
1223 nMergeSizeX
+= nColWidth
;
1225 long nMergeSizeY
= 0;
1227 if ( rThisRowInfo
.nRowNo
== nCellY
)
1229 // take first row's height from row info
1230 nMergeSizeY
+= rThisRowInfo
.nHeight
;
1231 nDirect
= 1; // skip in loop
1233 // following rows always from document
1234 nMergeSizeY
+= (long) mpDoc
->GetScaledRowHeight( nCellY
+nDirect
, nCellY
+nMergeRows
-1, nTab
, mnPPTY
);
1236 --nMergeSizeX
; // leave out the grid horizontally, also for alignment (align between grid lines)
1238 rParam
.mnColWidth
= nMergeSizeX
; // store the actual column width.
1239 rParam
.mnLeftClipLength
= rParam
.mnRightClipLength
= 0;
1241 // construct the rectangles using logical left/right values (justify is called at the end)
1243 // rAlignRect is the single cell or merged area, used for alignment.
1245 rParam
.maAlignRect
.Left() = nCellPosX
;
1246 rParam
.maAlignRect
.Right() = nCellPosX
+ ( nMergeSizeX
- 1 ) * nLayoutSign
;
1247 rParam
.maAlignRect
.Top() = nCellPosY
;
1248 rParam
.maAlignRect
.Bottom() = nCellPosY
+ nMergeSizeY
- 1;
1250 // rClipRect is all cells that are used for output.
1251 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1253 rParam
.maClipRect
= rParam
.maAlignRect
;
1254 if ( nNeeded
> nMergeSizeX
)
1256 SvxCellHorJustify eHorJust
= (SvxCellHorJustify
)nHorJustify
;
1258 long nMissing
= nNeeded
- nMergeSizeX
;
1259 long nLeftMissing
= 0;
1260 long nRightMissing
= 0;
1263 case SVX_HOR_JUSTIFY_LEFT
:
1264 nRightMissing
= nMissing
;
1266 case SVX_HOR_JUSTIFY_RIGHT
:
1267 nLeftMissing
= nMissing
;
1269 case SVX_HOR_JUSTIFY_CENTER
:
1270 nLeftMissing
= nMissing
/ 2;
1271 nRightMissing
= nMissing
- nLeftMissing
;
1275 // added to avoid warnings
1279 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1281 ::std::swap( nLeftMissing
, nRightMissing
);
1283 SCCOL nRightX
= nCellX
;
1284 SCCOL nLeftX
= nCellX
;
1285 if ( !bMerged
&& !bCellIsValue
&& !bBreak
)
1287 // look for empty cells into which the text can be extended
1289 while ( nRightMissing
> 0 && nRightX
< MAXCOL
&& ( bOverwrite
|| IsAvailable( nRightX
+1, nCellY
) ) )
1292 long nAdd
= (long) ( mpDoc
->GetColWidth( nRightX
, nTab
) * mnPPTX
);
1293 nRightMissing
-= nAdd
;
1294 rParam
.maClipRect
.Right() += nAdd
* nLayoutSign
;
1296 if ( rThisRowInfo
.nRowNo
== nCellY
&& nRightX
>= nX1
&& nRightX
<= nX2
)
1297 rThisRowInfo
.pCellInfo
[nRightX
].bHideGrid
= true;
1300 while ( nLeftMissing
> 0 && nLeftX
> 0 && ( bOverwrite
|| IsAvailable( nLeftX
-1, nCellY
) ) )
1302 if ( rThisRowInfo
.nRowNo
== nCellY
&& nLeftX
>= nX1
&& nLeftX
<= nX2
)
1303 rThisRowInfo
.pCellInfo
[nLeftX
].bHideGrid
= true;
1306 long nAdd
= (long) ( mpDoc
->GetColWidth( nLeftX
, nTab
) * mnPPTX
);
1307 nLeftMissing
-= nAdd
;
1308 rParam
.maClipRect
.Left() -= nAdd
* nLayoutSign
;
1312 // Set flag and reserve space for clipping mark triangle,
1313 // even if rThisRowInfo isn't for nCellY (merged cells).
1314 if ( nRightMissing
> 0 && bMarkClipped
&& nRightX
>= nX1
&& nRightX
<= nX2
&& !bBreak
&& !bCellIsValue
)
1316 rThisRowInfo
.pCellInfo
[nRightX
+1].nClipMark
|= SC_CLIPMARK_RIGHT
;
1318 long nMarkPixel
= (long)( SC_CLIPMARK_SIZE
* mnPPTX
);
1319 rParam
.maClipRect
.Right() -= nMarkPixel
* nLayoutSign
;
1321 if ( nLeftMissing
> 0 && bMarkClipped
&& nLeftX
>= nX1
&& nLeftX
<= nX2
&& !bBreak
&& !bCellIsValue
)
1323 rThisRowInfo
.pCellInfo
[nLeftX
+1].nClipMark
|= SC_CLIPMARK_LEFT
;
1325 long nMarkPixel
= (long)( SC_CLIPMARK_SIZE
* mnPPTX
);
1326 rParam
.maClipRect
.Left() += nMarkPixel
* nLayoutSign
;
1329 rParam
.mbLeftClip
= ( nLeftMissing
> 0 );
1330 rParam
.mbRightClip
= ( nRightMissing
> 0 );
1331 rParam
.mnLeftClipLength
= nLeftMissing
;
1332 rParam
.mnRightClipLength
= nRightMissing
;
1336 rParam
.mbLeftClip
= rParam
.mbRightClip
= false;
1338 // leave space for AutoFilter on screen
1339 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1341 if ( eType
==OUTTYPE_WINDOW
&&
1342 ( static_cast<const ScMergeFlagAttr
&>(rPattern
.GetItem(ATTR_MERGE_FLAG
)).GetValue() & (ScMF::Auto
|ScMF::Button
|ScMF::ButtonPopup
) ) &&
1343 ( !bBreak
|| mpRefDevice
== pFmtDevice
) )
1345 // filter drop-down width is now independent from row height
1346 const long nFilter
= DROPDOWN_BITMAP_SIZE
;
1347 bool bFit
= ( nNeeded
+ nFilter
<= nMergeSizeX
);
1348 if ( bFit
|| bCellIsValue
)
1350 // content fits even in the remaining area without the filter button
1351 // -> align within that remaining area
1353 rParam
.maAlignRect
.Right() -= nFilter
* nLayoutSign
;
1354 rParam
.maClipRect
.Right() -= nFilter
* nLayoutSign
;
1356 // if a number doesn't fit, don't hide part of the number behind the button
1357 // -> set clip flags, so "###" replacement is used (but also within the smaller area)
1360 rParam
.mbLeftClip
= rParam
.mbRightClip
= true;
1365 // justify both rectangles for alignment calculation, use with DrawText etc.
1367 rParam
.maAlignRect
.Justify();
1368 rParam
.maClipRect
.Justify();
1373 bool beginsWithRTLCharacter(const OUString
& rStr
)
1378 switch (ScGlobal::pCharClass
->getCharacterDirection(rStr
, 0))
1380 case i18n::DirectionProperty_RIGHT_TO_LEFT
:
1381 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC
:
1382 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING
:
1383 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE
:
1394 /** Get left, right or centered alignment from RTL context.
1396 Does not return standard, block or repeat, for these the contextual left or
1397 right alignment is returned.
1399 static SvxCellHorJustify
getAlignmentFromContext( SvxCellHorJustify eInHorJust
,
1400 bool bCellIsValue
, const OUString
& rText
,
1401 const ScPatternAttr
& rPattern
, const SfxItemSet
* pCondSet
,
1402 const ScDocument
* pDoc
, SCTAB nTab
, const bool bNumberFormatIsText
)
1404 SvxCellHorJustify eHorJustContext
= eInHorJust
;
1405 bool bUseWritingDirection
= false;
1406 if (eInHorJust
== SVX_HOR_JUSTIFY_STANDARD
)
1408 // fdo#32530: Default alignment depends on value vs
1409 // string, and the direction of the 1st letter.
1410 if (beginsWithRTLCharacter( rText
)) //If language is RTL
1413 eHorJustContext
= bNumberFormatIsText
? SVX_HOR_JUSTIFY_RIGHT
: SVX_HOR_JUSTIFY_LEFT
;
1415 eHorJustContext
= SVX_HOR_JUSTIFY_RIGHT
;
1417 else if (bCellIsValue
) //If language is not RTL
1418 eHorJustContext
= bNumberFormatIsText
? SVX_HOR_JUSTIFY_LEFT
: SVX_HOR_JUSTIFY_RIGHT
;
1420 bUseWritingDirection
= true;
1423 if (bUseWritingDirection
||
1424 eInHorJust
== SVX_HOR_JUSTIFY_BLOCK
|| eInHorJust
== SVX_HOR_JUSTIFY_REPEAT
)
1426 sal_uInt16 nDirection
= lcl_GetValue
<SvxFrameDirectionItem
, sal_uInt16
>( rPattern
, ATTR_WRITINGDIR
, pCondSet
);
1427 if (nDirection
== FRMDIR_HORI_LEFT_TOP
|| nDirection
== FRMDIR_VERT_TOP_LEFT
)
1428 eHorJustContext
= SVX_HOR_JUSTIFY_LEFT
;
1429 else if (nDirection
== FRMDIR_ENVIRONMENT
)
1431 SAL_WARN_IF( !pDoc
, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1432 // fdo#73588: The content of the cell must also
1433 // begin with a RTL character to be right
1434 // aligned; otherwise, it should be left aligned.
1435 eHorJustContext
= (pDoc
&& pDoc
->IsLayoutRTL(nTab
) && (beginsWithRTLCharacter( rText
))) ? SVX_HOR_JUSTIFY_RIGHT
: SVX_HOR_JUSTIFY_LEFT
;
1438 eHorJustContext
= SVX_HOR_JUSTIFY_RIGHT
;
1440 return eHorJustContext
;
1443 void ScOutputData::DrawStrings( bool bPixelToLogic
)
1445 LayoutStrings(bPixelToLogic
);
1448 Rectangle
ScOutputData::LayoutStrings(bool bPixelToLogic
, bool bPaint
, const ScAddress
&rAddress
)
1450 OSL_ENSURE( mpDev
== mpRefDevice
||
1451 mpDev
->GetMapMode().GetMapUnit() == mpRefDevice
->GetMapMode().GetMapUnit(),
1452 "LayoutStrings: different MapUnits ?!?!" );
1454 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast< vcl::PDFExtOutDevData
* >(mpDev
->GetExtOutDevData() );
1456 sc::IdleSwitch
aIdleSwitch(*mpDoc
, false);
1457 ScDrawStringsVars
aVars( this, bPixelToLogic
);
1459 bool bProgress
= false;
1461 long nInitPosX
= nScrX
;
1463 nInitPosX
+= nMirrorW
- 1; // pixels
1464 long nLayoutSign
= bLayoutRTL
? -1 : 1;
1466 SCCOL nLastContentCol
= MAXCOL
;
1468 nLastContentCol
= sal::static_int_cast
<SCCOL
>(
1469 nLastContentCol
- mpDoc
->GetEmptyLinesInBlock( nX2
+1, nY1
, nTab
, MAXCOL
, nY2
, nTab
, DIR_RIGHT
) );
1470 SCCOL nLoopStartX
= nX1
;
1472 --nLoopStartX
; // start before nX1 for rest of long text to the left
1474 // variables for GetOutputArea
1475 OutputAreaParam aAreaParam
;
1476 bool bCellIsValue
= false;
1477 long nNeededWidth
= 0;
1478 const ScPatternAttr
* pPattern
= nullptr;
1479 const SfxItemSet
* pCondSet
= nullptr;
1480 const ScPatternAttr
* pOldPattern
= nullptr;
1481 const SfxItemSet
* pOldCondSet
= nullptr;
1482 SvtScriptType nOldScript
= SvtScriptType::NONE
;
1484 // alternative pattern instances in case we need to modify the pattern
1485 // before processing the cell value.
1486 std::vector
<std::unique_ptr
<ScPatternAttr
> > aAltPatterns
;
1488 std::vector
<long> aDX
;
1490 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1492 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1493 SCROW nY
= pThisRowInfo
->nRowNo
;
1494 if ((bPaint
&& pThisRowInfo
->bChanged
) || (!bPaint
&& rAddress
.Row() == nY
))
1496 long nPosX
= nInitPosX
;
1497 if ( nLoopStartX
< nX1
)
1498 nPosX
-= pRowInfo
[0].pCellInfo
[nLoopStartX
+1].nWidth
* nLayoutSign
;
1499 for (SCCOL nX
=nLoopStartX
; nX
<=nX2
; nX
++)
1501 bool bMergeEmpty
= false;
1502 CellInfo
* pInfo
= &pThisRowInfo
->pCellInfo
[nX
+1];
1503 bool bEmpty
= nX
< nX1
|| pInfo
->bEmptyCellText
;
1505 SCCOL nCellX
= nX
; // position where the cell really starts
1507 bool bDoCell
= false;
1508 bool bNeedEdit
= false;
1510 // Part of a merged cell?
1512 bool bOverlapped
= (pInfo
->bHOverlapped
|| pInfo
->bVOverlapped
);
1517 SCCOL nOverX
; // start of the merged cells
1519 bool bVisChanged
= !pRowInfo
[nArrY
-1].bChanged
;
1520 if (GetMergeOrigin( nX
,nY
, nArrY
, nOverX
,nOverY
, bVisChanged
))
1530 // Rest of a long text further to the left?
1532 if ( bEmpty
&& !bMergeEmpty
&& nX
< nX1
&& !bOverlapped
)
1535 while (nTempX
> 0 && IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
1538 if ( nTempX
< nX1
&&
1539 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
1540 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX1
,nY
,nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
) )
1547 // Rest of a long text further to the right?
1549 if ( bEmpty
&& !bMergeEmpty
&& nX
== nX2
&& !bOverlapped
)
1551 // don't have to look further than nLastContentCol
1554 while (nTempX
< nLastContentCol
&& IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
1558 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
1559 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX
,nY
,nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
) )
1566 // normal visible cell
1571 // don't output the cell that's being edited
1573 if ( bDoCell
&& bEditMode
&& nCellX
== nEditCol
&& nCellY
== nEditRow
)
1576 // skip text in cell if data bar/icon set is set and only value selected
1579 if(pInfo
->pDataBar
&& !pInfo
->pDataBar
->mbShowValue
)
1581 if(pInfo
->pIconSet
&& !pInfo
->pIconSet
->mbShowValue
)
1585 // output the cell text
1587 ScRefCellValue aCell
;
1590 if ( nCellY
== nY
&& nCellX
== nX
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1591 aCell
= pThisRowInfo
->pCellInfo
[nCellX
+1].maCell
;
1593 GetVisibleCell( nCellX
, nCellY
, nTab
, aCell
); // get from document
1594 if (aCell
.isEmpty())
1596 else if (aCell
.meType
== CELLTYPE_EDIT
)
1600 // Check if this cell is mis-spelled.
1601 if (bDoCell
&& !bNeedEdit
&& aCell
.meType
== CELLTYPE_STRING
)
1603 if (mpSpellCheckCxt
&& mpSpellCheckCxt
->isMisspelled(nCellX
, nCellY
))
1607 if (bDoCell
&& !bNeedEdit
)
1609 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1611 CellInfo
& rCellInfo
= pThisRowInfo
->pCellInfo
[nCellX
+1];
1612 pPattern
= rCellInfo
.pPatternAttr
;
1613 pCondSet
= rCellInfo
.pConditionSet
;
1617 // #i68085# pattern from cell info for hidden columns is null,
1618 // test for null is quicker than using column flags
1619 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
1620 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
1623 else // get from document
1625 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
1626 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
1628 if ( mpDoc
->GetPreviewFont() || mpDoc
->GetPreviewCellStyle() )
1630 aAltPatterns
.push_back(o3tl::make_unique
<ScPatternAttr
>(*pPattern
));
1631 ScPatternAttr
* pAltPattern
= aAltPatterns
.back().get();
1632 if ( ScStyleSheet
* pPreviewStyle
= mpDoc
->GetPreviewCellStyle( nCellX
, nCellY
, nTab
) )
1634 pAltPattern
->SetStyleSheet(pPreviewStyle
);
1636 else if ( SfxItemSet
* pFontSet
= mpDoc
->GetPreviewFont( nCellX
, nCellY
, nTab
) )
1638 const SfxPoolItem
* pItem
;
1639 if ( pFontSet
->GetItemState( ATTR_FONT
, true, &pItem
) == SfxItemState::SET
)
1640 pAltPattern
->GetItemSet().Put( static_cast<const SvxFontItem
&>(*pItem
) );
1641 if ( pFontSet
->GetItemState( ATTR_CJK_FONT
, true, &pItem
) == SfxItemState::SET
)
1642 pAltPattern
->GetItemSet().Put( static_cast<const SvxFontItem
&>(*pItem
) );
1643 if ( pFontSet
->GetItemState( ATTR_CTL_FONT
, true, &pItem
) == SfxItemState::SET
)
1644 pAltPattern
->GetItemSet().Put( static_cast<const SvxFontItem
&>(*pItem
) );
1646 pPattern
= pAltPattern
;
1649 if (aCell
.hasNumeric() &&
1650 static_cast<const SfxBoolItem
&>(
1651 pPattern
->GetItem(ATTR_LINEBREAK
, pCondSet
)).GetValue())
1653 // Disable line break when the cell content is numeric.
1654 aAltPatterns
.push_back(o3tl::make_unique
<ScPatternAttr
>(*pPattern
));
1655 ScPatternAttr
* pAltPattern
= aAltPatterns
.back().get();
1656 SfxBoolItem
aLineBreak(ATTR_LINEBREAK
, false);
1657 pAltPattern
->GetItemSet().Put(aLineBreak
);
1658 pPattern
= pAltPattern
;
1661 SvtScriptType nScript
= mpDoc
->GetCellScriptType(
1662 ScAddress(nCellX
, nCellY
, nTab
),
1663 pPattern
->GetNumberFormat(mpDoc
->GetFormatTable(), pCondSet
));
1665 if (nScript
== SvtScriptType::NONE
)
1666 nScript
= ScGlobal::GetDefaultScriptType();
1668 if ( pPattern
!= pOldPattern
|| pCondSet
!= pOldCondSet
||
1669 nScript
!= nOldScript
|| mbSyntaxMode
)
1671 if ( StringDiffer(pOldPattern
,pPattern
) ||
1672 pCondSet
!= pOldCondSet
|| nScript
!= nOldScript
|| mbSyntaxMode
)
1674 aVars
.SetPattern(pPattern
, pCondSet
, aCell
, nScript
);
1677 aVars
.SetPatternSimple( pPattern
, pCondSet
);
1678 pOldPattern
= pPattern
;
1679 pOldCondSet
= pCondSet
;
1680 nOldScript
= nScript
;
1683 // use edit engine for rotated, stacked or mixed-script text
1684 if ( aVars
.GetOrient() == SVX_ORIENTATION_STACKED
||
1685 aVars
.IsRotated() || IsAmbiguousScript(nScript
) )
1688 if (bDoCell
&& !bNeedEdit
)
1690 bool bFormulaCell
= (aCell
.meType
== CELLTYPE_FORMULA
);
1692 lcl_CreateInterpretProgress(bProgress
, mpDoc
, aCell
.mpFormula
);
1693 if ( aVars
.SetText(aCell
) )
1694 pOldPattern
= nullptr;
1695 bNeedEdit
= aVars
.HasEditCharacters() || (bFormulaCell
&& aCell
.mpFormula
->IsMultilineResult());
1697 long nTotalMargin
= 0;
1698 SvxCellHorJustify eOutHorJust
= SVX_HOR_JUSTIFY_STANDARD
;
1699 if (bDoCell
&& !bNeedEdit
)
1701 CellType eCellType
= aCell
.meType
;
1702 bCellIsValue
= ( eCellType
== CELLTYPE_VALUE
);
1703 if ( eCellType
== CELLTYPE_FORMULA
)
1705 ScFormulaCell
* pFCell
= aCell
.mpFormula
;
1706 bCellIsValue
= pFCell
->IsRunning() || pFCell
->IsValue();
1709 const bool bNumberFormatIsText
= lcl_isNumberFormatText( mpDoc
, nCellX
, nCellY
, nTab
);
1710 eOutHorJust
= getAlignmentFromContext( aVars
.GetHorJust(), bCellIsValue
, aVars
.GetString(),
1711 *pPattern
, pCondSet
, mpDoc
, nTab
, bNumberFormatIsText
);
1713 bool bBreak
= ( aVars
.GetLineBreak() || aVars
.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK
);
1714 // #i111387# #o11817313# disable automatic line breaks only for "General" number format
1715 if (bBreak
&& bCellIsValue
&& (aVars
.GetResultValueFormat() % SV_COUNTRY_LANGUAGE_OFFSET
) == 0)
1718 bool bRepeat
= aVars
.IsRepeat() && !bBreak
;
1719 bool bShrink
= aVars
.IsShrink() && !bBreak
&& !bRepeat
;
1722 static_cast<long>(aVars
.GetLeftTotal() * mnPPTX
) +
1723 static_cast<long>(aVars
.GetMargin()->GetRightMargin() * mnPPTX
);
1725 nNeededWidth
= aVars
.GetTextSize().Width() + nTotalMargin
;
1727 // GetOutputArea gives justified rectangles
1728 GetOutputArea( nX
, nArrY
, nPosX
, nPosY
, nCellX
, nCellY
, nNeededWidth
,
1729 *pPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
1730 bCellIsValue
|| bRepeat
|| bShrink
, bBreak
, false,
1733 aVars
.RepeatToFill( aAreaParam
.mnColWidth
- nTotalMargin
);
1736 if ( aVars
.GetOrient() != SVX_ORIENTATION_STANDARD
)
1738 // Only horizontal scaling is handled here.
1739 // DrawEdit is used to vertically scale 90 deg rotated text.
1742 else if ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) // horizontal
1744 long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nTotalMargin
;
1745 long nScaleSize
= aVars
.GetTextSize().Width(); // without margin
1747 if ( nAvailable
> 0 && nScaleSize
> 0 ) // 0 if the text is empty (formulas, number formats)
1749 long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
1751 aVars
.SetShrinkScale( nScale
, nOldScript
);
1752 long nNewSize
= aVars
.GetTextSize().Width();
1754 sal_uInt16 nShrinkAgain
= 0;
1755 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
1757 // If the text is still too large, reduce the scale again by 10%, until it fits,
1758 // at most 7 times (it's less than 50% of the calculated scale then).
1760 nScale
= ( nScale
* 9 ) / 10;
1761 aVars
.SetShrinkScale( nScale
, nOldScript
);
1762 nNewSize
= aVars
.GetTextSize().Width();
1765 // If even at half the size the font still isn't rendered smaller,
1766 // fall back to normal clipping (showing ### for numbers).
1767 if ( nNewSize
<= nAvailable
)
1769 // Reset relevant parameters.
1770 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= false;
1771 aAreaParam
.mnLeftClipLength
= aAreaParam
.mnRightClipLength
= 0;
1774 pOldPattern
= nullptr;
1779 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
)
1781 long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nTotalMargin
;
1782 long nRepeatSize
= aVars
.GetTextSize().Width(); // without margin
1783 // When formatting for the printer, the text sizes don't always add up.
1784 // Round down (too few repetitions) rather than exceeding the cell size then:
1785 if ( pFmtDevice
!= mpRefDevice
)
1787 if ( nRepeatSize
> 0 )
1789 long nRepeatCount
= nAvailable
/ nRepeatSize
;
1790 if ( nRepeatCount
> 1 )
1792 OUString aCellStr
= aVars
.GetString();
1793 OUString aRepeated
= aCellStr
;
1794 for ( long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
1795 aRepeated
+= aCellStr
;
1796 aVars
.SetAutoText( aRepeated
);
1801 // use edit engine if automatic line breaks are needed
1804 if ( aVars
.GetOrient() == SVX_ORIENTATION_STANDARD
)
1805 bNeedEdit
= ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
);
1808 long nHeight
= aVars
.GetTextSize().Height() +
1809 (long)(aVars
.GetMargin()->GetTopMargin()*mnPPTY
) +
1810 (long)(aVars
.GetMargin()->GetBottomMargin()*mnPPTY
);
1811 bNeedEdit
= ( nHeight
> aAreaParam
.maClipRect
.GetHeight() );
1817 aVars
.GetHorJust() == SVX_HOR_JUSTIFY_BLOCK
&&
1818 aVars
.GetHorJustMethod() == SVX_JUSTIFY_METHOD_DISTRIBUTE
;
1823 // mark the cell in CellInfo to be drawn in DrawEdit:
1824 // Cells to the left are marked directly, cells to the
1825 // right are handled by the flag for nX2
1826 SCCOL nMarkX
= ( nCellX
<= nX2
) ? nCellX
: nX2
;
1827 RowInfo
* pMarkRowInfo
= ( nCellY
== nY
) ? pThisRowInfo
: &pRowInfo
[0];
1828 pMarkRowInfo
->pCellInfo
[nMarkX
+1].bEditEngine
= true;
1829 bDoCell
= false; // don't draw here
1833 if ( bCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
1836 aVars
.SetHashText();
1838 // Adjust the decimals to fit the available column width.
1839 aVars
.SetTextToWidthOrHash(aCell
, aAreaParam
.mnColWidth
- nTotalMargin
);
1841 nNeededWidth
= aVars
.GetTextSize().Width() +
1842 (long) ( aVars
.GetLeftTotal() * mnPPTX
) +
1843 (long) ( aVars
.GetMargin()->GetRightMargin() * mnPPTX
);
1844 if ( nNeededWidth
<= aAreaParam
.maClipRect
.GetWidth() )
1846 // Cell value is no longer clipped. Reset relevant parameters.
1847 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= false;
1848 aAreaParam
.mnLeftClipLength
= aAreaParam
.mnRightClipLength
= 0;
1851 // If the "###" replacement doesn't fit into the cells, no clip marks
1852 // are shown, as the "###" already denotes too little space.
1853 // The rectangles from the first GetOutputArea call remain valid.
1856 long nJustPosX
= aAreaParam
.maAlignRect
.Left(); // "justified" - effect of alignment will be added
1857 long nJustPosY
= aAreaParam
.maAlignRect
.Top();
1858 long nAvailWidth
= aAreaParam
.maAlignRect
.GetWidth();
1859 long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight();
1861 bool bOutside
= ( aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
1862 if ( aAreaParam
.maClipRect
.Left() < nScrX
)
1864 aAreaParam
.maClipRect
.Left() = nScrX
;
1865 aAreaParam
.mbLeftClip
= true;
1867 if ( aAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
1869 aAreaParam
.maClipRect
.Right() = nScrX
+ nScrW
; //! minus one?
1870 aAreaParam
.mbRightClip
= true;
1873 bool bHClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
1874 bool bVClip
= false;
1876 if ( aAreaParam
.maClipRect
.Top() < nScrY
)
1878 aAreaParam
.maClipRect
.Top() = nScrY
;
1881 if ( aAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
1883 aAreaParam
.maClipRect
.Bottom() = nScrY
+ nScrH
; //! minus one?
1887 // check horizontal space
1889 bool bNeedEditEngine
= false;
1890 if ( !bNeedEditEngine
&& !bOutside
)
1892 bool bRightAdjusted
= false; // to correct text width calculation later
1893 switch (eOutHorJust
)
1895 case SVX_HOR_JUSTIFY_LEFT
:
1896 nJustPosX
+= (long) ( aVars
.GetLeftTotal() * mnPPTX
);
1898 case SVX_HOR_JUSTIFY_RIGHT
:
1899 nJustPosX
+= nAvailWidth
- aVars
.GetTextSize().Width() -
1900 (long) ( aVars
.GetRightTotal() * mnPPTX
);
1901 bRightAdjusted
= true;
1903 case SVX_HOR_JUSTIFY_CENTER
:
1904 nJustPosX
+= ( nAvailWidth
- aVars
.GetTextSize().Width() +
1905 (long) ( aVars
.GetLeftTotal() * mnPPTX
) -
1906 (long) ( aVars
.GetMargin()->GetRightMargin() * mnPPTX
) ) / 2;
1910 // added to avoid warnings
1914 long nTestClipHeight
= aVars
.GetTextSize().Height();
1915 switch (aVars
.GetVerJust())
1917 case SVX_VER_JUSTIFY_TOP
:
1918 case SVX_VER_JUSTIFY_BLOCK
:
1920 long nTop
= (long)( aVars
.GetMargin()->GetTopMargin() * mnPPTY
);
1922 nTestClipHeight
+= nTop
;
1925 case SVX_VER_JUSTIFY_BOTTOM
:
1927 long nBot
= (long)( aVars
.GetMargin()->GetBottomMargin() * mnPPTY
);
1928 nJustPosY
+= nOutHeight
- aVars
.GetTextSize().Height() - nBot
;
1929 nTestClipHeight
+= nBot
;
1932 case SVX_VER_JUSTIFY_CENTER
:
1934 long nTop
= (long)( aVars
.GetMargin()->GetTopMargin() * mnPPTY
);
1935 long nBot
= (long)( aVars
.GetMargin()->GetBottomMargin() * mnPPTY
);
1936 nJustPosY
+= ( nOutHeight
+ nTop
-
1937 aVars
.GetTextSize().Height() - nBot
) / 2;
1938 nTestClipHeight
+= std::abs( nTop
- nBot
);
1943 // added to avoid warnings
1947 if ( nTestClipHeight
> nOutHeight
)
1949 // no vertical clipping when printing cells with optimal height,
1950 // except when font size is from conditional formatting.
1951 if ( eType
!= OUTTYPE_PRINTER
||
1952 ( mpDoc
->GetRowFlags( nCellY
, nTab
) & CR_MANUALSIZE
) ||
1953 ( aVars
.HasCondHeight() ) )
1957 if ( bHClip
|| bVClip
)
1959 // only clip the affected dimension so that not all right-aligned
1960 // columns are cut off when performing a non-proportional resize
1963 aAreaParam
.maClipRect
.Left() = nScrX
;
1964 aAreaParam
.maClipRect
.Right() = nScrX
+nScrW
;
1968 aAreaParam
.maClipRect
.Top() = nScrY
;
1969 aAreaParam
.maClipRect
.Bottom() = nScrY
+nScrH
;
1972 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
1973 // so it can be modified here
1975 aAreaParam
.maClipRect
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
1980 mpDev
->IntersectClipRegion( aAreaParam
.maClipRect
);
1983 mpDev
->SetClipRegion( vcl::Region( aAreaParam
.maClipRect
) );
1986 Point
aURLStart( nJustPosX
, nJustPosY
); // copy before modifying for orientation
1988 switch (aVars
.GetOrient())
1990 case SVX_ORIENTATION_STANDARD
:
1991 nJustPosY
+= aVars
.GetAscent();
1993 case SVX_ORIENTATION_TOPBOTTOM
:
1994 nJustPosX
+= aVars
.GetTextSize().Width() - aVars
.GetAscent();
1996 case SVX_ORIENTATION_BOTTOMTOP
:
1997 nJustPosY
+= aVars
.GetTextSize().Height();
1998 nJustPosX
+= aVars
.GetAscent();
2002 // added to avoid warnings
2006 // When clipping, the visible part is now completely defined by the alignment,
2007 // there's no more special handling to show the right part of RTL text.
2009 Point
aDrawTextPos( nJustPosX
, nJustPosY
);
2010 if ( bPixelToLogic
)
2012 // undo text width adjustment in pixels
2014 aDrawTextPos
.X() += aVars
.GetTextSize().Width();
2016 aDrawTextPos
= mpRefDevice
->PixelToLogic( aDrawTextPos
);
2018 // redo text width adjustment in logic units
2020 aDrawTextPos
.X() -= aVars
.GetOriginalWidth();
2023 // in Metafiles always use DrawTextArray to ensure that positions are
2024 // recorded (for non-proportional resize):
2026 OUString aString
= aVars
.GetString();
2027 if (!aString
.isEmpty())
2029 // If the string is clipped, make it shorter for
2030 // better performance since drawing by HarfBuzz is
2031 // quite expensive especiall for long string.
2033 OUString aShort
= aString
;
2035 // But never fiddle with numeric values.
2036 // (Which was the cause of tdf#86024).
2037 // The General automatic format output takes
2038 // care of this, or fixed width numbers either fit
2039 // or display as ###.
2042 double fVisibleRatio
= 1.0;
2043 double fTextWidth
= aVars
.GetTextSize().Width();
2044 sal_Int32 nTextLen
= aString
.getLength();
2045 if (eOutHorJust
== SVX_HOR_JUSTIFY_LEFT
&& aAreaParam
.mnRightClipLength
> 0)
2047 fVisibleRatio
= (fTextWidth
- aAreaParam
.mnRightClipLength
) / fTextWidth
;
2048 if (0.0 < fVisibleRatio
&& fVisibleRatio
< 1.0)
2050 // Only show the left-end segment.
2051 sal_Int32 nShortLen
= fVisibleRatio
*nTextLen
+ 1;
2052 aShort
= aShort
.copy(0, nShortLen
);
2055 else if (eOutHorJust
== SVX_HOR_JUSTIFY_RIGHT
&& aAreaParam
.mnLeftClipLength
> 0)
2057 fVisibleRatio
= (fTextWidth
- aAreaParam
.mnLeftClipLength
) / fTextWidth
;
2058 if (0.0 < fVisibleRatio
&& fVisibleRatio
< 1.0)
2060 // Only show the right-end segment.
2061 sal_Int32 nShortLen
= fVisibleRatio
*nTextLen
+ 1;
2062 aShort
= aShort
.copy(nTextLen
-nShortLen
);
2064 // Adjust the text position after shortening of the string.
2065 double fShortWidth
= pFmtDevice
->GetTextWidth(aShort
);
2066 double fOffset
= fTextWidth
- fShortWidth
;
2067 aDrawTextPos
.Move(fOffset
, 0);
2072 // if we are not painting, it means we are interested in
2073 // the area of the text that covers the specified cell
2074 if (!bPaint
&& rAddress
.Col() == nX
)
2077 mpDev
->GetTextBoundRect(aRect
, aShort
);
2078 aRect
+= aDrawTextPos
;
2082 if (bMetaFile
|| pFmtDevice
!= mpDev
|| aZoomX
!= aZoomY
)
2084 size_t nLen
= aShort
.getLength();
2085 if (aDX
.size() < nLen
)
2086 aDX
.resize(nLen
, 0);
2088 pFmtDevice
->GetTextArray(aShort
, &aDX
[0]);
2090 if ( !mpRefDevice
->GetConnectMetaFile() ||
2091 mpRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
2093 double fMul
= GetStretch();
2094 for (size_t i
= 0; i
< nLen
; ++i
)
2095 aDX
[i
] = static_cast<sal_Int32
>(aDX
[i
] / fMul
+ 0.5);
2099 mpDev
->DrawTextArray(aDrawTextPos
, aShort
, &aDX
[0]);
2104 mpDev
->DrawText(aDrawTextPos
, aShort
);
2108 if ( bHClip
|| bVClip
)
2113 mpDev
->SetClipRegion();
2116 // PDF: whole-cell hyperlink from formula?
2117 bool bHasURL
= pPDFData
&& aCell
.meType
== CELLTYPE_FORMULA
&& aCell
.mpFormula
->IsHyperLinkCell();
2118 if (bPaint
&& bHasURL
)
2120 Rectangle
aURLRect( aURLStart
, aVars
.GetTextSize() );
2121 lcl_DoHyperlinkResult(mpDev
, aURLRect
, aCell
);
2125 nPosX
+= pRowInfo
[0].pCellInfo
[nX
+1].nWidth
* nLayoutSign
;
2128 nPosY
+= pRowInfo
[nArrY
].nHeight
;
2131 ScProgress::DeleteInterpretProgress();
2136 ScFieldEditEngine
* ScOutputData::CreateOutputEditEngine()
2138 ScFieldEditEngine
* pEngine
= new ScFieldEditEngine(mpDoc
, mpDoc
->GetEnginePool());
2139 pEngine
->SetUpdateMode( false );
2140 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2141 pEngine
->SetRefDevice( pFmtDevice
);
2142 EEControlBits nCtrl
= pEngine
->GetControlWord();
2143 if ( bShowSpellErrors
)
2144 nCtrl
|= EEControlBits::ONLINESPELLING
;
2145 if ( eType
== OUTTYPE_PRINTER
)
2146 nCtrl
&= ~EEControlBits::MARKFIELDS
;
2147 if ( eType
== OUTTYPE_WINDOW
&& mpRefDevice
== pFmtDevice
)
2148 nCtrl
&= ~EEControlBits::FORMAT100
; // use the actual MapMode
2149 pEngine
->SetControlWord( nCtrl
);
2150 mpDoc
->ApplyAsianEditSettings( *pEngine
);
2151 pEngine
->EnableAutoColor( mbUseStyleColor
);
2152 pEngine
->SetDefaultHorizontalTextDirection( (EEHorizontalTextDirection
)mpDoc
->GetEditTextDirection( nTab
) );
2156 static void lcl_ClearEdit( EditEngine
& rEngine
) // text and attributes
2158 rEngine
.SetUpdateMode( false );
2160 rEngine
.SetText(EMPTY_OUSTRING
);
2161 // do not keep any para-attributes
2162 const SfxItemSet
& rPara
= rEngine
.GetParaAttribs(0);
2164 rEngine
.SetParaAttribs( 0,
2165 SfxItemSet( *rPara
.GetPool(), rPara
.GetRanges() ) );
2168 static bool lcl_SafeIsValue( ScRefCellValue
& rCell
)
2170 switch (rCell
.meType
)
2172 case CELLTYPE_VALUE
:
2174 case CELLTYPE_FORMULA
:
2176 ScFormulaCell
* pFCell
= rCell
.mpFormula
;
2177 if (pFCell
->IsRunning() || pFCell
->IsValue())
2183 // added to avoid warnings
2189 static void lcl_ScaleFonts( EditEngine
& rEngine
, long nPercent
)
2191 bool bUpdateMode
= rEngine
.GetUpdateMode();
2193 rEngine
.SetUpdateMode( false );
2195 sal_Int32 nParCount
= rEngine
.GetParagraphCount();
2196 for (sal_Int32 nPar
=0; nPar
<nParCount
; nPar
++)
2198 std::vector
<sal_Int32
> aPortions
;
2199 rEngine
.GetPortions( nPar
, aPortions
);
2201 sal_Int32 nStart
= 0;
2202 for ( std::vector
<sal_Int32
>::const_iterator
it(aPortions
.begin()); it
!= aPortions
.end(); ++it
)
2204 sal_Int32 nEnd
= *it
;
2205 ESelection
aSel( nPar
, nStart
, nPar
, nEnd
);
2206 SfxItemSet aAttribs
= rEngine
.GetAttribs( aSel
);
2208 long nWestern
= static_cast<const SvxFontHeightItem
&>(aAttribs
.Get(EE_CHAR_FONTHEIGHT
)).GetHeight();
2209 long nCJK
= static_cast<const SvxFontHeightItem
&>(aAttribs
.Get(EE_CHAR_FONTHEIGHT_CJK
)).GetHeight();
2210 long nCTL
= static_cast<const SvxFontHeightItem
&>(aAttribs
.Get(EE_CHAR_FONTHEIGHT_CTL
)).GetHeight();
2212 nWestern
= ( nWestern
* nPercent
) / 100;
2213 nCJK
= ( nCJK
* nPercent
) / 100;
2214 nCTL
= ( nCTL
* nPercent
) / 100;
2216 aAttribs
.Put( SvxFontHeightItem( nWestern
, 100, EE_CHAR_FONTHEIGHT
) );
2217 aAttribs
.Put( SvxFontHeightItem( nCJK
, 100, EE_CHAR_FONTHEIGHT_CJK
) );
2218 aAttribs
.Put( SvxFontHeightItem( nCTL
, 100, EE_CHAR_FONTHEIGHT_CTL
) );
2220 rEngine
.QuickSetAttribs( aAttribs
, aSel
); //! remove paragraph attributes from aAttribs?
2227 rEngine
.SetUpdateMode( true );
2230 static long lcl_GetEditSize( EditEngine
& rEngine
, bool bWidth
, bool bSwap
, long nAttrRotate
)
2237 long nRealWidth
= (long) rEngine
.CalcTextWidth();
2238 long nRealHeight
= rEngine
.GetTextHeight();
2240 // assuming standard mode, otherwise width isn't used
2242 double nRealOrient
= nAttrRotate
* F_PI18000
; // 1/100th degrees
2243 double nAbsCos
= fabs( cos( nRealOrient
) );
2244 double nAbsSin
= fabs( sin( nRealOrient
) );
2246 return (long) ( nRealWidth
* nAbsCos
+ nRealHeight
* nAbsSin
);
2248 return (long) ( nRealHeight
* nAbsCos
+ nRealWidth
* nAbsSin
);
2251 return (long) rEngine
.CalcTextWidth();
2253 return rEngine
.GetTextHeight();
2256 void ScOutputData::ShrinkEditEngine( EditEngine
& rEngine
, const Rectangle
& rAlignRect
,
2257 long nLeftM
, long nTopM
, long nRightM
, long nBottomM
,
2258 bool bWidth
, sal_uInt16 nOrient
, long nAttrRotate
, bool bPixelToLogic
,
2259 long& rEngineWidth
, long& rEngineHeight
, long& rNeededPixel
, bool& rLeftClip
, bool& rRightClip
)
2265 long nScaleSize
= bPixelToLogic
?
2266 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2268 // Don't scale if it fits already.
2269 // Allowing to extend into the margin, to avoid scaling at optimal height.
2270 if ( nScaleSize
<= rAlignRect
.GetHeight() )
2273 bool bSwap
= ( nOrient
== SVX_ORIENTATION_TOPBOTTOM
|| nOrient
== SVX_ORIENTATION_BOTTOMTOP
);
2274 long nAvailable
= rAlignRect
.GetHeight() - nTopM
- nBottomM
;
2275 long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
2277 lcl_ScaleFonts( rEngine
, nScale
);
2278 rEngineHeight
= lcl_GetEditSize( rEngine
, false, bSwap
, nAttrRotate
);
2279 long nNewSize
= bPixelToLogic
?
2280 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2282 sal_uInt16 nShrinkAgain
= 0;
2283 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
2285 // further reduce, like in DrawStrings
2286 lcl_ScaleFonts( rEngine
, 90 ); // reduce by 10%
2287 rEngineHeight
= lcl_GetEditSize( rEngine
, false, bSwap
, nAttrRotate
);
2288 nNewSize
= bPixelToLogic
?
2289 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2293 // sizes for further processing (alignment etc):
2294 rEngineWidth
= lcl_GetEditSize( rEngine
, true, bSwap
, nAttrRotate
);
2295 long nPixelWidth
= bPixelToLogic
?
2296 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2297 rNeededPixel
= nPixelWidth
+ nLeftM
+ nRightM
;
2299 else if ( rLeftClip
|| rRightClip
)
2303 long nAvailable
= rAlignRect
.GetWidth() - nLeftM
- nRightM
;
2304 long nScaleSize
= rNeededPixel
- nLeftM
- nRightM
; // without margin
2306 if ( nScaleSize
<= nAvailable
)
2309 long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
2311 lcl_ScaleFonts( rEngine
, nScale
);
2312 rEngineWidth
= lcl_GetEditSize( rEngine
, true, false, nAttrRotate
);
2313 long nNewSize
= bPixelToLogic
?
2314 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2316 sal_uInt16 nShrinkAgain
= 0;
2317 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
2319 // further reduce, like in DrawStrings
2320 lcl_ScaleFonts( rEngine
, 90 ); // reduce by 10%
2321 rEngineWidth
= lcl_GetEditSize( rEngine
, true, false, nAttrRotate
);
2322 nNewSize
= bPixelToLogic
?
2323 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2326 if ( nNewSize
<= nAvailable
)
2327 rLeftClip
= rRightClip
= false;
2329 // sizes for further processing (alignment etc):
2330 rNeededPixel
= nNewSize
+ nLeftM
+ nRightM
;
2331 rEngineHeight
= lcl_GetEditSize( rEngine
, false, false, nAttrRotate
);
2335 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr
* pPattern
, const SfxItemSet
* pCondSet
, bool bCellIsValue
) :
2336 meHorJustAttr( lcl_GetValue
<SvxHorJustifyItem
, SvxCellHorJustify
>(*pPattern
, ATTR_HOR_JUSTIFY
, pCondSet
) ),
2337 meHorJustContext( meHorJustAttr
),
2338 meHorJustResult( meHorJustAttr
),
2339 meVerJust( lcl_GetValue
<SvxVerJustifyItem
, SvxCellVerJustify
>(*pPattern
, ATTR_VER_JUSTIFY
, pCondSet
) ),
2340 meHorJustMethod( lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_HOR_JUSTIFY_METHOD
, pCondSet
) ),
2341 meVerJustMethod( lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_VER_JUSTIFY_METHOD
, pCondSet
) ),
2342 meOrient( pPattern
->GetCellOrientation(pCondSet
) ),
2344 mnX(0), mnY(0), mnCellX(0), mnCellY(0), mnTab(0),
2345 mnPosX(0), mnPosY(0), mnInitPosX(0),
2346 mbBreak( (meHorJustAttr
== SVX_HOR_JUSTIFY_BLOCK
) || lcl_GetBoolValue(*pPattern
, ATTR_LINEBREAK
, pCondSet
) ),
2347 mbCellIsValue(bCellIsValue
),
2348 mbAsianVertical(false),
2349 mbPixelToLogic(false),
2350 mbHyphenatorSet(false),
2352 mpPattern(pPattern
),
2353 mpCondSet(pCondSet
),
2354 mpPreviewFontSet(nullptr),
2355 mpOldPattern(nullptr),
2356 mpOldCondSet(nullptr),
2357 mpOldPreviewFontSet(nullptr),
2358 mpThisRowInfo(nullptr),
2359 mpMisspellRanges(nullptr)
2362 bool ScOutputData::DrawEditParam::readCellContent(
2363 ScDocument
* pDoc
, bool bShowNullValues
, bool bShowFormulas
, bool bSyntaxMode
, bool bUseStyleColor
, bool bForceAutoColor
, bool& rWrapFields
)
2365 if (maCell
.meType
== CELLTYPE_EDIT
)
2367 const EditTextObject
* pData
= maCell
.mpEditText
;
2370 mpEngine
->SetText(*pData
);
2372 if ( mbBreak
&& !mbAsianVertical
&& pData
->HasField() )
2374 // Fields aren't wrapped, so clipping is enabled to prevent
2375 // a field from being drawn beyond the cell size
2382 OSL_FAIL("pData == 0");
2388 sal_uLong nFormat
= mpPattern
->GetNumberFormat(
2389 pDoc
->GetFormatTable(), mpCondSet
);
2392 ScCellFormat::GetString( maCell
,
2393 nFormat
,aString
, &pColor
,
2394 *pDoc
->GetFormatTable(),
2400 mpEngine
->SetText(aString
);
2401 if ( pColor
&& !bSyntaxMode
&& !( bUseStyleColor
&& bForceAutoColor
) )
2402 lcl_SetEditColor( *mpEngine
, *pColor
);
2405 if (mpMisspellRanges
)
2406 mpEngine
->SetAllMisspellRanges(*mpMisspellRanges
);
2411 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor
)
2413 // syntax highlighting mode is ignored here
2414 // StringDiffer doesn't look at hyphenate, language items
2416 if (mpPattern
== mpOldPattern
&& mpCondSet
== mpOldCondSet
&& mpPreviewFontSet
== mpOldPreviewFontSet
)
2419 sal_Int32 nConfBackColor
= SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
;
2420 bool bCellContrast
= bUseStyleColor
&&
2421 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2423 SfxItemSet
* pSet
= new SfxItemSet( mpEngine
->GetEmptyItemSet() );
2424 mpPattern
->FillEditItemSet( pSet
, mpCondSet
);
2425 if ( mpPreviewFontSet
)
2427 const SfxPoolItem
* pItem
;
2428 if ( mpPreviewFontSet
->GetItemState( ATTR_FONT
, true, &pItem
) == SfxItemState::SET
)
2430 SvxFontItem
aFontItem(EE_CHAR_FONTINFO
);
2431 aFontItem
= static_cast<const SvxFontItem
&>(*pItem
);
2432 pSet
->Put( aFontItem
);
2434 if ( mpPreviewFontSet
->GetItemState( ATTR_CJK_FONT
, true, &pItem
) == SfxItemState::SET
)
2436 SvxFontItem
aCjkFontItem(EE_CHAR_FONTINFO_CJK
);
2437 aCjkFontItem
= static_cast<const SvxFontItem
&>(*pItem
);
2438 pSet
->Put( aCjkFontItem
);
2440 if ( mpPreviewFontSet
->GetItemState( ATTR_CTL_FONT
, true, &pItem
) == SfxItemState::SET
)
2442 SvxFontItem
aCtlFontItem(EE_CHAR_FONTINFO_CTL
);
2443 aCtlFontItem
= static_cast<const SvxFontItem
&>(*pItem
);
2444 pSet
->Put( aCtlFontItem
);
2447 mpEngine
->SetDefaults( pSet
);
2448 mpOldPattern
= mpPattern
;
2449 mpOldCondSet
= mpCondSet
;
2450 mpOldPreviewFontSet
= mpPreviewFontSet
;
2452 EEControlBits nControl
= mpEngine
->GetControlWord();
2453 if (meOrient
== SVX_ORIENTATION_STACKED
)
2454 nControl
|= EEControlBits::ONECHARPERLINE
;
2456 nControl
&= ~EEControlBits::ONECHARPERLINE
;
2457 mpEngine
->SetControlWord( nControl
);
2459 if ( !mbHyphenatorSet
&& static_cast<const SfxBoolItem
&>(pSet
->Get(EE_PARA_HYPHENATE
)).GetValue() )
2461 // set hyphenator the first time it is needed
2462 css::uno::Reference
<css::linguistic2::XHyphenator
> xXHyphenator( LinguMgr::GetHyphenator() );
2463 mpEngine
->SetHyphenator( xXHyphenator
);
2464 mbHyphenatorSet
= true;
2467 Color aBackCol
= static_cast<const SvxBrushItem
&>(mpPattern
->GetItem( ATTR_BACKGROUND
, mpCondSet
)).GetColor();
2468 if ( bUseStyleColor
&& ( aBackCol
.GetTransparency() > 0 || bCellContrast
) )
2469 aBackCol
.SetColor( nConfBackColor
);
2470 mpEngine
->SetBackgroundColor( aBackCol
);
2473 void ScOutputData::DrawEditParam::calcMargins(long& rTopM
, long& rLeftM
, long& rBottomM
, long& rRightM
, double nPPTX
, double nPPTY
) const
2475 const SvxMarginItem
& rMargin
=
2476 static_cast<const SvxMarginItem
&>(mpPattern
->GetItem(ATTR_MARGIN
, mpCondSet
));
2478 sal_uInt16 nIndent
= 0;
2479 if (meHorJustAttr
== SVX_HOR_JUSTIFY_LEFT
|| meHorJustAttr
== SVX_HOR_JUSTIFY_RIGHT
)
2480 nIndent
= lcl_GetValue
<SfxUInt16Item
, sal_uInt16
>(*mpPattern
, ATTR_INDENT
, mpCondSet
);
2482 rLeftM
= static_cast<long>(((rMargin
.GetLeftMargin() + nIndent
) * nPPTX
));
2483 rTopM
= static_cast<long>((rMargin
.GetTopMargin() * nPPTY
));
2484 rRightM
= static_cast<long>((rMargin
.GetRightMargin() * nPPTX
));
2485 rBottomM
= static_cast<long>((rMargin
.GetBottomMargin() * nPPTY
));
2486 if(meHorJustAttr
== SVX_HOR_JUSTIFY_RIGHT
)
2488 rLeftM
= static_cast<long>((rMargin
.GetLeftMargin() * nPPTX
));
2489 rRightM
= static_cast<long>(((rMargin
.GetRightMargin() + nIndent
) * nPPTX
));
2493 void ScOutputData::DrawEditParam::calcPaperSize(
2494 Size
& rPaperSize
, const Rectangle
& rAlignRect
, double nPPTX
, double nPPTY
) const
2496 long nTopM
, nLeftM
, nBottomM
, nRightM
;
2497 calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, nPPTX
, nPPTY
);
2499 if (isVerticallyOriented())
2501 rPaperSize
.Width() = rAlignRect
.GetHeight() - nTopM
- nBottomM
;
2502 rPaperSize
.Height() = rAlignRect
.GetWidth() - nLeftM
- nRightM
;
2506 rPaperSize
.Width() = rAlignRect
.GetWidth() - nLeftM
- nRightM
;
2507 rPaperSize
.Height() = rAlignRect
.GetHeight() - nTopM
- nBottomM
;
2510 if (mbAsianVertical
)
2512 rPaperSize
.Height() = rAlignRect
.GetHeight() - nTopM
- nBottomM
;
2513 // Subtract some extra value from the height or else the text would go
2514 // outside the cell area. The value of 5 is arbitrary, and is based
2515 // entirely on heuristics.
2516 rPaperSize
.Height() -= 5;
2520 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine
* pEngine
, long& rWidth
, long& rHeight
) const
2522 long nEngineWidth
= 0;
2523 if (!mbBreak
|| meOrient
== SVX_ORIENTATION_STACKED
|| mbAsianVertical
)
2524 nEngineWidth
= static_cast<long>(pEngine
->CalcTextWidth());
2526 long nEngineHeight
= pEngine
->GetTextHeight();
2528 if (isVerticallyOriented())
2530 long nTemp
= nEngineWidth
;
2531 nEngineWidth
= nEngineHeight
;
2532 nEngineHeight
= nTemp
;
2535 if (meOrient
== SVX_ORIENTATION_STACKED
)
2536 nEngineWidth
= nEngineWidth
* 11 / 10;
2538 rWidth
= nEngineWidth
;
2539 rHeight
= nEngineHeight
;
2542 bool ScOutputData::DrawEditParam::hasLineBreak() const
2544 return (mbBreak
|| (meOrient
== SVX_ORIENTATION_STACKED
) || mbAsianVertical
);
2547 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2549 if (maCell
.meType
!= CELLTYPE_FORMULA
)
2552 return maCell
.mpFormula
->IsHyperLinkCell();
2555 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2557 return (meOrient
== SVX_ORIENTATION_TOPBOTTOM
|| meOrient
== SVX_ORIENTATION_BOTTOMTOP
);
2560 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2561 Point
& rLogicStart
, long nCellWidth
, long nEngineWidth
, long nTopM
, OutputDevice
* pRefDevice
)
2563 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2566 rLogicStart
= pRefDevice
->PixelToLogic(rLogicStart
);
2570 // vertical adjustment is within the EditEngine
2572 rLogicStart
.Y() += pRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
2574 rLogicStart
.Y() += nTopM
;
2576 switch (meHorJustResult
)
2578 case SVX_HOR_JUSTIFY_CENTER
:
2579 rLogicStart
.X() += (nCellWidth
- nEngineWidth
) / 2;
2581 case SVX_HOR_JUSTIFY_RIGHT
:
2582 rLogicStart
.X() += nCellWidth
- nEngineWidth
;
2590 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2592 if (isVerticallyOriented() || mbAsianVertical
)
2594 SvxAdjust eSvxAdjust
= SVX_ADJUST_LEFT
;
2597 case SVX_VER_JUSTIFY_TOP
:
2598 eSvxAdjust
= (meOrient
== SVX_ORIENTATION_TOPBOTTOM
|| mbAsianVertical
) ?
2599 SVX_ADJUST_LEFT
: SVX_ADJUST_RIGHT
;
2601 case SVX_VER_JUSTIFY_CENTER
:
2602 eSvxAdjust
= SVX_ADJUST_CENTER
;
2604 case SVX_VER_JUSTIFY_BOTTOM
:
2605 case SVX_VER_JUSTIFY_STANDARD
:
2606 eSvxAdjust
= (meOrient
== SVX_ORIENTATION_TOPBOTTOM
|| mbAsianVertical
) ?
2607 SVX_ADJUST_RIGHT
: SVX_ADJUST_LEFT
;
2609 case SVX_VER_JUSTIFY_BLOCK
:
2610 eSvxAdjust
= SVX_ADJUST_BLOCK
;
2614 mpEngine
->SetDefaultItem( SvxAdjustItem(eSvxAdjust
, EE_PARA_JUST
) );
2615 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod
, EE_PARA_JUST_METHOD
) );
2617 if (meHorJustResult
== SVX_HOR_JUSTIFY_BLOCK
)
2618 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK
, EE_PARA_VER_JUST
) );
2622 // horizontal alignment now may depend on cell content
2623 // (for values with number formats with mixed script types)
2624 // -> always set adjustment
2626 SvxAdjust eSvxAdjust
= SVX_ADJUST_LEFT
;
2627 if (meOrient
== SVX_ORIENTATION_STACKED
)
2628 eSvxAdjust
= SVX_ADJUST_CENTER
;
2631 if (meOrient
== SVX_ORIENTATION_STANDARD
)
2632 switch (meHorJustResult
)
2634 case SVX_HOR_JUSTIFY_REPEAT
: // repeat is not yet implemented
2635 case SVX_HOR_JUSTIFY_STANDARD
:
2636 SAL_WARN("sc.ui","meHorJustResult does not match getAlignmentFromContext()");
2638 case SVX_HOR_JUSTIFY_LEFT
:
2639 eSvxAdjust
= SVX_ADJUST_LEFT
;
2641 case SVX_HOR_JUSTIFY_CENTER
:
2642 eSvxAdjust
= SVX_ADJUST_CENTER
;
2644 case SVX_HOR_JUSTIFY_RIGHT
:
2645 eSvxAdjust
= SVX_ADJUST_RIGHT
;
2647 case SVX_HOR_JUSTIFY_BLOCK
:
2648 eSvxAdjust
= SVX_ADJUST_BLOCK
;
2654 case SVX_VER_JUSTIFY_TOP
:
2655 eSvxAdjust
= SVX_ADJUST_RIGHT
;
2657 case SVX_VER_JUSTIFY_CENTER
:
2658 eSvxAdjust
= SVX_ADJUST_CENTER
;
2660 case SVX_VER_JUSTIFY_BOTTOM
:
2661 case SVX_VER_JUSTIFY_STANDARD
:
2662 eSvxAdjust
= SVX_ADJUST_LEFT
;
2664 case SVX_VER_JUSTIFY_BLOCK
:
2665 eSvxAdjust
= SVX_ADJUST_BLOCK
;
2670 mpEngine
->SetDefaultItem( SvxAdjustItem(eSvxAdjust
, EE_PARA_JUST
) );
2672 if (mbAsianVertical
)
2674 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod
, EE_PARA_JUST_METHOD
) );
2675 if (meHorJustResult
== SVX_HOR_JUSTIFY_BLOCK
)
2676 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK
, EE_PARA_VER_JUST
) );
2680 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod
, EE_PARA_JUST_METHOD
) );
2681 if (meVerJust
== SVX_VER_JUSTIFY_BLOCK
)
2682 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SVX_VER_JUSTIFY_BLOCK
, EE_PARA_VER_JUST
) );
2686 mpEngine
->SetVertical(mbAsianVertical
);
2687 if (maCell
.meType
== CELLTYPE_EDIT
)
2689 // We need to synchronize the vertical mode in the EditTextObject
2690 // instance too. No idea why we keep this state in two separate
2692 const EditTextObject
* pData
= maCell
.mpEditText
;
2694 const_cast<EditTextObject
*>(pData
)->SetVertical(mbAsianVertical
);
2698 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine
* pEngine
)
2700 if (meHorJustResult
== SVX_HOR_JUSTIFY_RIGHT
|| meHorJustResult
== SVX_HOR_JUSTIFY_CENTER
)
2702 SvxAdjust eEditAdjust
= (meHorJustResult
== SVX_HOR_JUSTIFY_CENTER
) ?
2703 SVX_ADJUST_CENTER
: SVX_ADJUST_RIGHT
;
2705 pEngine
->SetUpdateMode(false);
2706 pEngine
->SetDefaultItem( SvxAdjustItem(eEditAdjust
, EE_PARA_JUST
) );
2707 pEngine
->SetUpdateMode(true);
2713 void ScOutputData::DrawEditParam::adjustForRTL()
2715 if (!mpEngine
->IsRightToLeft(0))
2719 // For right-to-left, EditEngine always calculates its lines
2720 // beginning from the right edge, but EditLine::nStartPosX is
2721 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
2722 Size aLogicPaper
= mpEngine
->GetPaperSize();
2723 if ( aLogicPaper
.Width() > USHRT_MAX
)
2725 aLogicPaper
.Width() = USHRT_MAX
;
2726 mpEngine
->SetPaperSize(aLogicPaper
);
2730 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart
, OutputDevice
* pDev
)
2732 // PDF: whole-cell hyperlink from formula?
2733 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast<vcl::PDFExtOutDevData
* >( pDev
->GetExtOutDevData() );
2734 bool bHasURL
= pPDFData
&& isHyperlinkCell();
2738 long nURLWidth
= (long) mpEngine
->CalcTextWidth();
2739 long nURLHeight
= mpEngine
->GetTextHeight();
2742 Size aPaper
= mpEngine
->GetPaperSize();
2743 if ( mbAsianVertical
)
2744 nURLHeight
= aPaper
.Height();
2746 nURLWidth
= aPaper
.Width();
2748 if (isVerticallyOriented())
2749 std::swap( nURLWidth
, nURLHeight
);
2750 else if (mbAsianVertical
)
2751 aURLStart
.X() -= nURLWidth
;
2753 Rectangle
aURLRect( aURLStart
, Size( nURLWidth
, nURLHeight
) );
2754 lcl_DoHyperlinkResult(pDev
, aURLRect
, maCell
);
2757 void ScOutputData::DrawEditStandard(DrawEditParam
& rParam
)
2759 OSL_ASSERT(rParam
.meOrient
== SVX_ORIENTATION_STANDARD
);
2760 OSL_ASSERT(!rParam
.mbAsianVertical
);
2762 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
2764 bool bHidden
= false;
2765 bool bRepeat
= (rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
&& !rParam
.mbBreak
);
2766 bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
2767 long nAttrRotate
= lcl_GetValue
<SfxInt32Item
, long>(*rParam
.mpPattern
, ATTR_ROTATE_VALUE
, rParam
.mpCondSet
);
2769 if ( rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
)
2771 // ignore orientation/rotation if "repeat" is active
2772 rParam
.meOrient
= SVX_ORIENTATION_STANDARD
;
2775 // #i31843# "repeat" with "line breaks" is treated as default alignment
2776 // (but rotation is still disabled).
2777 // Default again leads to context dependent alignment instead of
2778 // SVX_HOR_JUSTIFY_STANDARD.
2779 if ( rParam
.mbBreak
)
2780 rParam
.meHorJustResult
= rParam
.meHorJustContext
;
2785 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
2786 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
2787 bHidden
= true; // rotated is outputted separately
2793 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
2795 //! mirror margin values for RTL?
2796 //! move margin down to after final GetOutputArea call
2797 long nTopM
, nLeftM
, nBottomM
, nRightM
;
2798 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
2800 SCCOL nXForPos
= rParam
.mnX
;
2801 if ( nXForPos
< nX1
)
2804 rParam
.mnPosX
= rParam
.mnInitPosX
;
2806 SCSIZE nArrYForPos
= rParam
.mnArrY
;
2807 if ( nArrYForPos
< 1 )
2810 rParam
.mnPosY
= nScrY
;
2813 OutputAreaParam aAreaParam
;
2815 // Initial page size - large for normal text, cell size for automatic line breaks
2817 Size
aPaperSize( 1000000, 1000000 );
2820 // call GetOutputArea with nNeeded=0, to get only the cell width
2822 //! handle nArrY == 0
2823 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
2824 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
2825 rParam
.mbCellIsValue
, true, false, aAreaParam
);
2827 //! special ScEditUtil handling if formatting for printer
2828 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
2830 if (rParam
.mbPixelToLogic
)
2832 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
2833 if ( rParam
.mbBreak
&& !rParam
.mbAsianVertical
&& mpRefDevice
!= pFmtDevice
)
2835 // #i85342# screen display and formatting for printer,
2836 // use same GetEditArea call as in ScViewData::SetEditEngine
2838 Fraction
aFract(1,1);
2839 Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
2840 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
2841 aLogicSize
.Width() = aUtilRect
.GetWidth();
2843 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
2846 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
2848 // Fill the EditEngine (cell attributes and text)
2850 // default alignment for asian vertical mode is top-right
2851 if ( rParam
.mbAsianVertical
&& rParam
.meVerJust
== SVX_VER_JUSTIFY_STANDARD
)
2852 rParam
.meVerJust
= SVX_VER_JUSTIFY_TOP
;
2854 rParam
.setPatternToEngine(mbUseStyleColor
);
2855 rParam
.setAlignmentToEngine();
2857 // Read content from cell
2859 bool bWrapFields
= false;
2860 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
2861 // Failed to read cell content. Bail out.
2865 SetEditSyntaxColor(*rParam
.mpEngine
, rParam
.maCell
);
2866 else if ( mbUseStyleColor
&& mbForceAutoColor
)
2867 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
2869 rParam
.mpEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
2871 // Get final output area using the calculated width
2873 long nEngineWidth
, nEngineHeight
;
2874 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
2876 long nNeededPixel
= nEngineWidth
;
2877 if (rParam
.mbPixelToLogic
)
2878 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
2879 nNeededPixel
+= nLeftM
+ nRightM
;
2881 if (!rParam
.mbBreak
|| bShrink
)
2883 // for break, the first GetOutputArea call is sufficient
2884 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
2885 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
2886 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
2890 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
2891 nLeftM
, nTopM
, nRightM
, nBottomM
, true,
2892 sal::static_int_cast
<sal_uInt16
>(rParam
.meOrient
), 0, rParam
.mbPixelToLogic
,
2893 nEngineWidth
, nEngineHeight
, nNeededPixel
,
2894 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
2896 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
2898 // First check if twice the space for the formatted text is available
2899 // (otherwise just keep it unchanged).
2901 long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
2902 long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
2903 if ( nAvailable
>= 2 * nFormatted
)
2905 // "repeat" is handled with unformatted text (for performance reasons)
2906 OUString aCellStr
= rParam
.mpEngine
->GetText();
2907 rParam
.mpEngine
->SetText( aCellStr
);
2909 long nRepeatSize
= (long) rParam
.mpEngine
->CalcTextWidth();
2910 if (rParam
.mbPixelToLogic
)
2911 nRepeatSize
= mpRefDevice
->LogicToPixel(Size(nRepeatSize
,0)).Width();
2912 if ( pFmtDevice
!= mpRefDevice
)
2914 if ( nRepeatSize
> 0 )
2916 long nRepeatCount
= nAvailable
/ nRepeatSize
;
2917 if ( nRepeatCount
> 1 )
2919 OUString aRepeated
= aCellStr
;
2920 for ( long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
2921 aRepeated
+= aCellStr
;
2922 rParam
.mpEngine
->SetText( aRepeated
);
2924 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
2925 nEngineWidth
= (long) rParam
.mpEngine
->CalcTextWidth();
2926 if (rParam
.mbPixelToLogic
)
2927 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
2929 nNeededPixel
= nEngineWidth
;
2930 nNeededPixel
+= nLeftM
+ nRightM
;
2936 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
2938 rParam
.mpEngine
->SetText(OUString("###"));
2939 nEngineWidth
= (long) rParam
.mpEngine
->CalcTextWidth();
2940 if (rParam
.mbPixelToLogic
)
2941 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
2943 nNeededPixel
= nEngineWidth
;
2944 nNeededPixel
+= nLeftM
+ nRightM
;
2946 // No clip marks if "###" doesn't fit (same as in DrawStrings)
2949 if (eOutHorJust
!= SVX_HOR_JUSTIFY_LEFT
)
2951 aPaperSize
.Width() = nNeededPixel
+ 1;
2952 if (rParam
.mbPixelToLogic
)
2953 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
2955 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
2959 long nStartX
= aAreaParam
.maAlignRect
.Left();
2960 long nStartY
= aAreaParam
.maAlignRect
.Top();
2961 long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
2962 long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
2963 long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
2967 // text with automatic breaks is aligned only within the
2968 // edit engine's paper size, the output of the whole area
2969 // is always left-aligned
2975 if ( eOutHorJust
== SVX_HOR_JUSTIFY_RIGHT
)
2976 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
2977 else if ( eOutHorJust
== SVX_HOR_JUSTIFY_CENTER
)
2978 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
2983 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
2987 if ( aAreaParam
.maClipRect
.Left() < nScrX
)
2989 aAreaParam
.maClipRect
.Left() = nScrX
;
2990 aAreaParam
.mbLeftClip
= true;
2992 if ( aAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
2994 aAreaParam
.maClipRect
.Right() = nScrX
+ nScrW
; //! minus one?
2995 aAreaParam
.mbRightClip
= true;
2998 bool bClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
2999 bool bSimClip
= false;
3003 // Fields in a cell with automatic breaks: clip to cell width
3007 if ( aAreaParam
.maClipRect
.Top() < nScrY
)
3009 aAreaParam
.maClipRect
.Top() = nScrY
;
3012 if ( aAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
3014 aAreaParam
.maClipRect
.Bottom() = nScrY
+ nScrH
; //! minus one?
3018 Size aCellSize
; // output area, excluding margins, in logical units
3019 if (rParam
.mbPixelToLogic
)
3020 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
3022 aCellSize
= Size( nOutWidth
, nOutHeight
);
3024 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
3026 const ScMergeAttr
* pMerge
=
3027 static_cast<const ScMergeAttr
*>(&rParam
.mpPattern
->GetItem(ATTR_MERGE
));
3028 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
3030 // Don't clip for text height when printing rows with optimal height,
3031 // except when font size is from conditional formatting.
3032 //! Allow clipping when vertically merged?
3033 if ( eType
!= OUTTYPE_PRINTER
||
3034 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CR_MANUALSIZE
) ||
3035 ( rParam
.mpCondSet
&& SfxItemState::SET
==
3036 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
3041 // Show clip marks if height is at least 5pt too small and
3042 // there are several lines of text.
3043 // Not for asian vertical text, because that would interfere
3044 // with the default right position of the text.
3045 // Only with automatic line breaks, to avoid having to find
3046 // the cells with the horizontal end of the text again.
3047 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
3048 rParam
.mbBreak
&& bMarkClipped
&&
3049 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
3051 CellInfo
* pClipMarkCell
= nullptr;
3054 // anywhere in the merged area...
3055 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
3056 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].pCellInfo
[nClipX
+1];
3059 pClipMarkCell
= &rParam
.mpThisRowInfo
->pCellInfo
[rParam
.mnX
+1];
3061 pClipMarkCell
->nClipMark
|= SC_CLIPMARK_RIGHT
; //! also allow left?
3064 long nMarkPixel
= (long)( SC_CLIPMARK_SIZE
* mnPPTX
);
3065 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
3066 aAreaParam
.maClipRect
.Right() -= nMarkPixel
;
3070 Rectangle aLogicClip
;
3071 if (bClip
|| bSimClip
)
3073 // Clip marks are already handled in GetOutputArea
3075 if (rParam
.mbPixelToLogic
)
3076 aLogicClip
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
3078 aLogicClip
= aAreaParam
.maClipRect
;
3080 if (bClip
) // for bSimClip only initialize aClipRect
3085 mpDev
->IntersectClipRegion( aLogicClip
);
3088 mpDev
->SetClipRegion( vcl::Region( aLogicClip
) );
3093 if (rParam
.mbPixelToLogic
)
3094 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
3096 aLogicStart
= Point(nStartX
, nStartY
);
3098 if (!rParam
.mbBreak
)
3100 // horizontal alignment
3101 if (rParam
.adjustHorAlignment(rParam
.mpEngine
))
3102 // reset adjustment for the next cell
3103 rParam
.mpOldPattern
= nullptr;
3106 if (rParam
.meVerJust
==SVX_VER_JUSTIFY_BOTTOM
||
3107 rParam
.meVerJust
==SVX_VER_JUSTIFY_STANDARD
)
3109 //! if pRefDevice != pFmtDevice, keep heights in logic units,
3110 //! only converting margin?
3112 if (rParam
.mbPixelToLogic
)
3113 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0, nTopM
+
3114 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
3115 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
3118 aLogicStart
.Y() += nTopM
+ aCellSize
.Height() - nEngineHeight
;
3120 else if (rParam
.meVerJust
==SVX_VER_JUSTIFY_CENTER
)
3122 if (rParam
.mbPixelToLogic
)
3123 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0, nTopM
+ (
3124 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
3125 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height() )
3128 aLogicStart
.Y() += nTopM
+ (aCellSize
.Height() - nEngineHeight
) / 2;
3132 if (rParam
.mbPixelToLogic
)
3133 aLogicStart
.Y() += mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
3135 aLogicStart
.Y() += nTopM
;
3138 Point aURLStart
= aLogicStart
; // copy before modifying for orientation
3140 rParam
.adjustForRTL();
3142 // bMoveClipped handling has been replaced by complete alignment
3143 // handling (also extending to the left).
3147 // no hard clip, only draw the affected rows
3148 Point aDocStart
= aLogicClip
.TopLeft();
3149 aDocStart
-= aLogicStart
;
3150 rParam
.mpEngine
->Draw( mpDev
, aLogicClip
, aDocStart
, false );
3154 rParam
.mpEngine
->Draw(mpDev
, aLogicStart
);
3162 mpDev
->SetClipRegion();
3165 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3168 void ScOutputData::ShowClipMarks( DrawEditParam
& rParam
, long nEngineHeight
, const Size
& aCellSize
,
3169 bool bMerged
, OutputAreaParam
& aAreaParam
)
3171 // Show clip marks if height is at least 5pt too small and
3172 // there are several lines of text.
3173 // Not for asian vertical text, because that would interfere
3174 // with the default right position of the text.
3175 // Only with automatic line breaks, to avoid having to find
3176 // the cells with the horizontal end of the text again.
3177 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
3178 rParam
.mbBreak
&& bMarkClipped
&&
3179 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
3181 CellInfo
* pClipMarkCell
= nullptr;
3184 // anywhere in the merged area...
3185 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
3186 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].pCellInfo
[nClipX
+1];
3189 pClipMarkCell
= &rParam
.mpThisRowInfo
->pCellInfo
[rParam
.mnX
+1];
3191 pClipMarkCell
->nClipMark
|= SC_CLIPMARK_RIGHT
; //! also allow left?
3194 const long nMarkPixel
= static_cast<long>( SC_CLIPMARK_SIZE
* mnPPTX
);
3195 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
3196 aAreaParam
.maClipRect
.Right() -= nMarkPixel
;
3200 bool ScOutputData::Clip( DrawEditParam
& rParam
, const Size
& aCellSize
,
3201 OutputAreaParam
& aAreaParam
, long nEngineHeight
,
3204 if ( aAreaParam
.maClipRect
.Left() < nScrX
)
3206 aAreaParam
.maClipRect
.Left() = nScrX
;
3207 aAreaParam
.mbLeftClip
= true;
3209 if ( aAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
3211 aAreaParam
.maClipRect
.Right() = nScrX
+ nScrW
; //! minus one?
3212 aAreaParam
.mbRightClip
= true;
3215 bool bClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
3216 bool bSimClip
= false;
3220 // Fields in a cell with automatic breaks: clip to cell width
3224 if ( aAreaParam
.maClipRect
.Top() < nScrY
)
3226 aAreaParam
.maClipRect
.Top() = nScrY
;
3229 if ( aAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
3231 aAreaParam
.maClipRect
.Bottom() = nScrY
+ nScrH
; //! minus one?
3235 const Size
& aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
3236 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
3238 const ScMergeAttr
* pMerge
=
3239 static_cast<const ScMergeAttr
*>(&rParam
.mpPattern
->GetItem(ATTR_MERGE
));
3240 const bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
3242 // Don't clip for text height when printing rows with optimal height,
3243 // except when font size is from conditional formatting.
3244 //! Allow clipping when vertically merged?
3245 if ( eType
!= OUTTYPE_PRINTER
||
3246 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CR_MANUALSIZE
) ||
3247 ( rParam
.mpCondSet
&& SfxItemState::SET
==
3248 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
3253 ShowClipMarks( rParam
, nEngineHeight
, aCellSize
, bMerged
, aAreaParam
);
3256 Rectangle aLogicClip
;
3257 if (bClip
|| bSimClip
)
3259 // Clip marks are already handled in GetOutputArea
3261 if (rParam
.mbPixelToLogic
)
3262 aLogicClip
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
3264 aLogicClip
= aAreaParam
.maClipRect
;
3266 if (bClip
) // for bSimClip only initialize aClipRect
3271 mpDev
->IntersectClipRegion( aLogicClip
);
3274 mpDev
->SetClipRegion( vcl::Region( aLogicClip
) );
3281 void ScOutputData::DrawEditBottomTop(DrawEditParam
& rParam
)
3283 OSL_ASSERT(rParam
.meHorJustAttr
!= SVX_HOR_JUSTIFY_REPEAT
);
3285 const bool bRepeat
= (rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
&& !rParam
.mbBreak
);
3286 const bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3288 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3290 //! mirror margin values for RTL?
3291 //! move margin down to after final GetOutputArea call
3292 long nTopM
, nLeftM
, nBottomM
, nRightM
;
3293 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3295 SCCOL nXForPos
= rParam
.mnX
;
3296 if ( nXForPos
< nX1
)
3299 rParam
.mnPosX
= rParam
.mnInitPosX
;
3301 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3302 if ( nArrYForPos
< 1 )
3305 rParam
.mnPosY
= nScrY
;
3308 OutputAreaParam aAreaParam
;
3310 // Initial page size - large for normal text, cell size for automatic line breaks
3312 Size
aPaperSize( 1000000, 1000000 );
3315 // call GetOutputArea with nNeeded=0, to get only the cell width
3317 //! handle nArrY == 0
3318 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3319 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3320 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3322 //! special ScEditUtil handling if formatting for printer
3323 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3325 if (rParam
.mbPixelToLogic
)
3327 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3328 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3331 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3333 // Fill the EditEngine (cell attributes and text)
3335 rParam
.setPatternToEngine(mbUseStyleColor
);
3336 rParam
.setAlignmentToEngine();
3338 // Read content from cell
3340 bool bWrapFields
= false;
3341 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3342 // Failed to read cell content. Bail out.
3346 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3347 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3348 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3350 rParam
.mpEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3352 // Get final output area using the calculated width
3354 long nEngineWidth
, nEngineHeight
;
3355 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3357 long nNeededPixel
= nEngineWidth
;
3358 if (rParam
.mbPixelToLogic
)
3359 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3360 nNeededPixel
+= nLeftM
+ nRightM
;
3362 if (!rParam
.mbBreak
|| bShrink
)
3364 // for break, the first GetOutputArea call is sufficient
3365 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3366 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3367 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
3371 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3372 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
3373 sal::static_int_cast
<sal_uInt16
>(rParam
.meOrient
), 0, rParam
.mbPixelToLogic
,
3374 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3375 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3377 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
3379 // First check if twice the space for the formatted text is available
3380 // (otherwise just keep it unchanged).
3382 const long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
3383 const long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
3384 if ( nAvailable
>= 2 * nFormatted
)
3386 // "repeat" is handled with unformatted text (for performance reasons)
3387 OUString aCellStr
= rParam
.mpEngine
->GetText();
3388 rParam
.mpEngine
->SetText( aCellStr
);
3390 long nRepeatSize
= static_cast<long>( rParam
.mpEngine
->CalcTextWidth() );
3391 if (rParam
.mbPixelToLogic
)
3392 nRepeatSize
= mpRefDevice
->LogicToPixel(Size(nRepeatSize
,0)).Width();
3393 if ( pFmtDevice
!= mpRefDevice
)
3395 if ( nRepeatSize
> 0 )
3397 const long nRepeatCount
= nAvailable
/ nRepeatSize
;
3398 if ( nRepeatCount
> 1 )
3400 OUString aRepeated
= aCellStr
;
3401 for ( long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
3402 aRepeated
+= aCellStr
;
3403 rParam
.mpEngine
->SetText( aRepeated
);
3405 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
3406 nEngineWidth
= static_cast<long>( rParam
.mpEngine
->CalcTextWidth() );
3407 if (rParam
.mbPixelToLogic
)
3408 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
3410 nNeededPixel
= nEngineWidth
;
3411 nNeededPixel
+= nLeftM
+ nRightM
;
3417 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
3419 rParam
.mpEngine
->SetText(OUString("###"));
3420 nEngineWidth
= (long) rParam
.mpEngine
->CalcTextWidth();
3421 if (rParam
.mbPixelToLogic
)
3422 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
3424 nNeededPixel
= nEngineWidth
;
3425 nNeededPixel
+= nLeftM
+ nRightM
;
3427 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3431 long nStartX
= aAreaParam
.maAlignRect
.Left();
3432 const long nStartY
= aAreaParam
.maAlignRect
.Top();
3433 const long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3434 const long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3435 const long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3439 // text with automatic breaks is aligned only within the
3440 // edit engine's paper size, the output of the whole area
3441 // is always left-aligned
3447 if ( eOutHorJust
== SVX_HOR_JUSTIFY_RIGHT
)
3448 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3449 else if ( eOutHorJust
== SVX_HOR_JUSTIFY_CENTER
)
3450 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3455 const bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3459 // output area, excluding margins, in logical units
3460 const Size
& aCellSize
= rParam
.mbPixelToLogic
3461 ? mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) )
3462 : Size( nOutWidth
, nOutHeight
);
3464 const bool bClip
= Clip( rParam
, aCellSize
, aAreaParam
, nEngineHeight
, bWrapFields
);
3466 Point
aLogicStart(nStartX
, nStartY
);
3467 rParam
.calcStartPosForVertical(aLogicStart
, aCellSize
.Width(), nEngineWidth
, nTopM
, mpRefDevice
);
3469 Point aURLStart
= aLogicStart
; // copy before modifying for orientation
3471 if (rParam
.meHorJustResult
== SVX_HOR_JUSTIFY_BLOCK
|| rParam
.mbBreak
)
3473 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3474 aPSize
.Width() = aCellSize
.Height();
3475 rParam
.mpEngine
->SetPaperSize(aPSize
);
3477 rParam
.mbBreak
? aPSize
.Width() : nEngineHeight
;
3481 // Note that the "paper" is rotated 90 degrees to the left, so
3482 // paper's width is in vertical direction. Also, the whole text
3483 // is on a single line, as text wrap is not in effect.
3485 // Set the paper width to be the width of the text.
3486 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3487 aPSize
.Width() = rParam
.mpEngine
->CalcTextWidth();
3488 rParam
.mpEngine
->SetPaperSize(aPSize
);
3491 long nTopOffset
= 0;
3492 if (rParam
.mbPixelToLogic
)
3494 nGap
= mpRefDevice
->LogicToPixel(aCellSize
).Height() - mpRefDevice
->LogicToPixel(aPSize
).Width();
3495 nGap
= mpRefDevice
->PixelToLogic(Size(0, nGap
)).Height();
3496 nTopOffset
= mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
3500 nGap
= aCellSize
.Height() - aPSize
.Width();
3504 // First, align text to bottom.
3505 aLogicStart
.Y() += aCellSize
.Height();
3506 aLogicStart
.Y() += nTopOffset
;
3508 switch (rParam
.meVerJust
)
3510 case SVX_VER_JUSTIFY_STANDARD
:
3511 case SVX_VER_JUSTIFY_BOTTOM
:
3512 // align to bottom (do nothing).
3514 case SVX_VER_JUSTIFY_CENTER
:
3516 aLogicStart
.Y() -= nGap
/ 2;
3518 case SVX_VER_JUSTIFY_BLOCK
:
3519 case SVX_VER_JUSTIFY_TOP
:
3521 aLogicStart
.Y() -= nGap
;
3528 rParam
.adjustForRTL();
3529 rParam
.mpEngine
->Draw(mpDev
, aLogicStart
, 900);
3536 mpDev
->SetClipRegion();
3539 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3542 void ScOutputData::DrawEditTopBottom(DrawEditParam
& rParam
)
3544 OSL_ASSERT(rParam
.meHorJustAttr
!= SVX_HOR_JUSTIFY_REPEAT
);
3546 const bool bRepeat
= (rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
&& !rParam
.mbBreak
);
3547 const bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3549 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3551 //! mirror margin values for RTL?
3552 //! move margin down to after final GetOutputArea call
3553 long nTopM
, nLeftM
, nBottomM
, nRightM
;
3554 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3556 SCCOL nXForPos
= rParam
.mnX
;
3557 if ( nXForPos
< nX1
)
3560 rParam
.mnPosX
= rParam
.mnInitPosX
;
3562 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3563 if ( nArrYForPos
< 1 )
3566 rParam
.mnPosY
= nScrY
;
3569 OutputAreaParam aAreaParam
;
3571 // Initial page size - large for normal text, cell size for automatic line breaks
3573 Size
aPaperSize( 1000000, 1000000 );
3574 if (rParam
.hasLineBreak())
3576 // call GetOutputArea with nNeeded=0, to get only the cell width
3578 //! handle nArrY == 0
3579 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3580 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3581 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3583 //! special ScEditUtil handling if formatting for printer
3584 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3586 if (rParam
.mbPixelToLogic
)
3588 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3589 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3592 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3594 // Fill the EditEngine (cell attributes and text)
3596 rParam
.setPatternToEngine(mbUseStyleColor
);
3597 rParam
.setAlignmentToEngine();
3599 // Read content from cell
3601 bool bWrapFields
= false;
3602 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3603 // Failed to read cell content. Bail out.
3607 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3608 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3609 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3611 rParam
.mpEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3613 // Get final output area using the calculated width
3615 long nEngineWidth
, nEngineHeight
;
3616 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3618 long nNeededPixel
= nEngineWidth
;
3619 if (rParam
.mbPixelToLogic
)
3620 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3621 nNeededPixel
+= nLeftM
+ nRightM
;
3623 if (!rParam
.mbBreak
|| bShrink
)
3625 // for break, the first GetOutputArea call is sufficient
3626 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3627 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3628 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
3632 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3633 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
3634 sal::static_int_cast
<sal_uInt16
>(rParam
.meOrient
), 0, rParam
.mbPixelToLogic
,
3635 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3636 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3638 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
3640 // First check if twice the space for the formatted text is available
3641 // (otherwise just keep it unchanged).
3643 const long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
3644 const long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
3645 if ( nAvailable
>= 2 * nFormatted
)
3647 // "repeat" is handled with unformatted text (for performance reasons)
3648 OUString aCellStr
= rParam
.mpEngine
->GetText();
3649 rParam
.mpEngine
->SetText( aCellStr
);
3651 long nRepeatSize
= static_cast<long>( rParam
.mpEngine
->CalcTextWidth() );
3652 if (rParam
.mbPixelToLogic
)
3653 nRepeatSize
= mpRefDevice
->LogicToPixel(Size(nRepeatSize
,0)).Width();
3654 if ( pFmtDevice
!= mpRefDevice
)
3656 if ( nRepeatSize
> 0 )
3658 const long nRepeatCount
= nAvailable
/ nRepeatSize
;
3659 if ( nRepeatCount
> 1 )
3661 OUString aRepeated
= aCellStr
;
3662 for ( long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
3663 aRepeated
+= aCellStr
;
3664 rParam
.mpEngine
->SetText( aRepeated
);
3666 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
3667 nEngineWidth
= static_cast<long>( rParam
.mpEngine
->CalcTextWidth() );
3668 if (rParam
.mbPixelToLogic
)
3669 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
3671 nNeededPixel
= nEngineWidth
;
3672 nNeededPixel
+= nLeftM
+ nRightM
;
3678 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
3680 rParam
.mpEngine
->SetText(OUString("###"));
3681 nEngineWidth
= static_cast<long>( rParam
.mpEngine
->CalcTextWidth() );
3682 if (rParam
.mbPixelToLogic
)
3683 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
3685 nNeededPixel
= nEngineWidth
;
3686 nNeededPixel
+= nLeftM
+ nRightM
;
3688 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3692 long nStartX
= aAreaParam
.maAlignRect
.Left();
3693 const long nStartY
= aAreaParam
.maAlignRect
.Top();
3694 const long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3695 const long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3696 const long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3700 // text with automatic breaks is aligned only within the
3701 // edit engine's paper size, the output of the whole area
3702 // is always left-aligned
3705 if (rParam
.meHorJustResult
== SVX_HOR_JUSTIFY_BLOCK
)
3706 nStartX
+= aPaperSize
.Height();
3710 if ( eOutHorJust
== SVX_HOR_JUSTIFY_RIGHT
)
3711 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3712 else if ( eOutHorJust
== SVX_HOR_JUSTIFY_CENTER
)
3713 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3718 const bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3722 // output area, excluding margins, in logical units
3723 const Size
& aCellSize
= rParam
.mbPixelToLogic
3724 ? mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) )
3725 : Size( nOutWidth
, nOutHeight
);
3727 const bool bClip
= Clip( rParam
, aCellSize
, aAreaParam
, nEngineHeight
, bWrapFields
);
3729 Point
aLogicStart(nStartX
, nStartY
);
3730 rParam
.calcStartPosForVertical(aLogicStart
, aCellSize
.Width(), nEngineWidth
, nTopM
, mpRefDevice
);
3732 Point aURLStart
= aLogicStart
; // copy before modifying for orientation
3734 if (rParam
.meHorJustResult
!= SVX_HOR_JUSTIFY_BLOCK
)
3736 aLogicStart
.X() += nEngineWidth
;
3737 if (!rParam
.mbBreak
)
3739 // Set the paper width to text size.
3740 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3741 aPSize
.Width() = rParam
.mpEngine
->CalcTextWidth();
3742 rParam
.mpEngine
->SetPaperSize(aPSize
);
3745 long nTopOffset
= 0; // offset by top margin
3746 if (rParam
.mbPixelToLogic
)
3748 nGap
= mpRefDevice
->LogicToPixel(aPSize
).Width() - mpRefDevice
->LogicToPixel(aCellSize
).Height();
3749 nGap
= mpRefDevice
->PixelToLogic(Size(0, nGap
)).Height();
3750 nTopOffset
= mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
3754 nGap
= aPSize
.Width() - aCellSize
.Height();
3757 aLogicStart
.Y() += nTopOffset
;
3759 switch (rParam
.meVerJust
)
3761 case SVX_VER_JUSTIFY_STANDARD
:
3762 case SVX_VER_JUSTIFY_BOTTOM
:
3764 aLogicStart
.Y() -= nGap
;
3766 case SVX_VER_JUSTIFY_CENTER
:
3768 aLogicStart
.Y() -= nGap
/ 2;
3770 case SVX_VER_JUSTIFY_BLOCK
:
3771 case SVX_VER_JUSTIFY_TOP
:
3772 // align to top (do nothing)
3779 rParam
.adjustForRTL();
3781 // bMoveClipped handling has been replaced by complete alignment
3782 // handling (also extending to the left).
3784 rParam
.mpEngine
->Draw(mpDev
, aLogicStart
, 2700);
3791 mpDev
->SetClipRegion();
3794 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3797 void ScOutputData::DrawEditStacked(DrawEditParam
& rParam
)
3799 OSL_ASSERT(rParam
.meHorJustAttr
!= SVX_HOR_JUSTIFY_REPEAT
);
3800 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
3802 bool bRepeat
= (rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
&& !rParam
.mbBreak
);
3803 bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3805 rParam
.mbAsianVertical
=
3806 lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_VERTICAL_ASIAN
, rParam
.mpCondSet
);
3808 if ( rParam
.mbAsianVertical
)
3810 // in asian mode, use EditEngine::SetVertical instead of EEControlBits::ONECHARPERLINE
3811 rParam
.meOrient
= SVX_ORIENTATION_STANDARD
;
3812 DrawEditAsianVertical(rParam
);
3816 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3818 //! mirror margin values for RTL?
3819 //! move margin down to after final GetOutputArea call
3820 long nTopM
, nLeftM
, nBottomM
, nRightM
;
3821 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3823 SCCOL nXForPos
= rParam
.mnX
;
3824 if ( nXForPos
< nX1
)
3827 rParam
.mnPosX
= rParam
.mnInitPosX
;
3829 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3830 if ( nArrYForPos
< 1 )
3833 rParam
.mnPosY
= nScrY
;
3836 OutputAreaParam aAreaParam
;
3838 // Initial page size - large for normal text, cell size for automatic line breaks
3840 Size
aPaperSize( 1000000, 1000000 );
3841 // call GetOutputArea with nNeeded=0, to get only the cell width
3843 //! handle nArrY == 0
3844 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3845 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3846 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3848 //! special ScEditUtil handling if formatting for printer
3849 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3851 if (rParam
.mbPixelToLogic
)
3853 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3854 if ( rParam
.mbBreak
&& mpRefDevice
!= pFmtDevice
)
3856 // #i85342# screen display and formatting for printer,
3857 // use same GetEditArea call as in ScViewData::SetEditEngine
3859 Fraction
aFract(1,1);
3860 Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
3861 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
3862 aLogicSize
.Width() = aUtilRect
.GetWidth();
3864 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3867 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3869 // Fill the EditEngine (cell attributes and text)
3871 rParam
.setPatternToEngine(mbUseStyleColor
);
3872 rParam
.setAlignmentToEngine();
3874 // Read content from cell
3876 bool bWrapFields
= false;
3877 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3878 // Failed to read cell content. Bail out.
3882 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3883 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3884 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3886 rParam
.mpEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
3888 // Get final output area using the calculated width
3890 long nEngineWidth
, nEngineHeight
;
3891 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3893 long nNeededPixel
= nEngineWidth
;
3894 if (rParam
.mbPixelToLogic
)
3895 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3896 nNeededPixel
+= nLeftM
+ nRightM
;
3900 // for break, the first GetOutputArea call is sufficient
3901 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3902 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3903 true, false, false, aAreaParam
);
3905 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3906 nLeftM
, nTopM
, nRightM
, nBottomM
, true,
3907 sal::static_int_cast
<sal_uInt16
>(rParam
.meOrient
), 0, rParam
.mbPixelToLogic
,
3908 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3909 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3911 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
3913 rParam
.mpEngine
->SetText(OUString("###"));
3914 nEngineWidth
= (long) rParam
.mpEngine
->CalcTextWidth();
3915 if (rParam
.mbPixelToLogic
)
3916 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
3918 nNeededPixel
= nEngineWidth
;
3919 nNeededPixel
+= nLeftM
+ nRightM
;
3921 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3924 if ( eOutHorJust
!= SVX_HOR_JUSTIFY_LEFT
)
3926 aPaperSize
.Width() = nNeededPixel
+ 1;
3927 if (rParam
.mbPixelToLogic
)
3928 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
3930 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3934 long nStartX
= aAreaParam
.maAlignRect
.Left();
3935 long nStartY
= aAreaParam
.maAlignRect
.Top();
3936 long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3937 long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3938 long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3942 // text with automatic breaks is aligned only within the
3943 // edit engine's paper size, the output of the whole area
3944 // is always left-aligned
3950 if ( eOutHorJust
== SVX_HOR_JUSTIFY_RIGHT
)
3951 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3952 else if ( eOutHorJust
== SVX_HOR_JUSTIFY_CENTER
)
3953 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3958 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3962 if ( aAreaParam
.maClipRect
.Left() < nScrX
)
3964 aAreaParam
.maClipRect
.Left() = nScrX
;
3965 aAreaParam
.mbLeftClip
= true;
3967 if ( aAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
3969 aAreaParam
.maClipRect
.Right() = nScrX
+ nScrW
; //! minus one?
3970 aAreaParam
.mbRightClip
= true;
3973 bool bClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
3974 bool bSimClip
= false;
3978 // Fields in a cell with automatic breaks: clip to cell width
3982 if ( aAreaParam
.maClipRect
.Top() < nScrY
)
3984 aAreaParam
.maClipRect
.Top() = nScrY
;
3987 if ( aAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
3989 aAreaParam
.maClipRect
.Bottom() = nScrY
+ nScrH
; //! minus one?
3993 Size aCellSize
; // output area, excluding margins, in logical units
3994 if (rParam
.mbPixelToLogic
)
3995 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
3997 aCellSize
= Size( nOutWidth
, nOutHeight
);
3999 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
4001 const ScMergeAttr
* pMerge
=
4002 static_cast<const ScMergeAttr
*>(&rParam
.mpPattern
->GetItem(ATTR_MERGE
));
4003 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4005 // Don't clip for text height when printing rows with optimal height,
4006 // except when font size is from conditional formatting.
4007 //! Allow clipping when vertically merged?
4008 if ( eType
!= OUTTYPE_PRINTER
||
4009 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CR_MANUALSIZE
) ||
4010 ( rParam
.mpCondSet
&& SfxItemState::SET
==
4011 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
4016 // Show clip marks if height is at least 5pt too small and
4017 // there are several lines of text.
4018 // Not for asian vertical text, because that would interfere
4019 // with the default right position of the text.
4020 // Only with automatic line breaks, to avoid having to find
4021 // the cells with the horizontal end of the text again.
4022 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
4023 rParam
.mbBreak
&& bMarkClipped
&&
4024 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
4026 CellInfo
* pClipMarkCell
= nullptr;
4029 // anywhere in the merged area...
4030 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
4031 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].pCellInfo
[nClipX
+1];
4034 pClipMarkCell
= &rParam
.mpThisRowInfo
->pCellInfo
[rParam
.mnX
+1];
4036 pClipMarkCell
->nClipMark
|= SC_CLIPMARK_RIGHT
; //! also allow left?
4039 long nMarkPixel
= (long)( SC_CLIPMARK_SIZE
* mnPPTX
);
4040 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
4041 aAreaParam
.maClipRect
.Right() -= nMarkPixel
;
4045 Rectangle aLogicClip
;
4046 if (bClip
|| bSimClip
)
4048 // Clip marks are already handled in GetOutputArea
4050 if (rParam
.mbPixelToLogic
)
4051 aLogicClip
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
4053 aLogicClip
= aAreaParam
.maClipRect
;
4055 if (bClip
) // for bSimClip only initialize aClipRect
4060 mpDev
->IntersectClipRegion( aLogicClip
);
4063 mpDev
->SetClipRegion( vcl::Region( aLogicClip
) );
4068 if (rParam
.mbPixelToLogic
)
4069 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
4071 aLogicStart
= Point(nStartX
, nStartY
);
4073 if (rParam
.meVerJust
==SVX_VER_JUSTIFY_BOTTOM
||
4074 rParam
.meVerJust
==SVX_VER_JUSTIFY_STANDARD
)
4076 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4077 //! only converting margin?
4079 if (rParam
.mbPixelToLogic
)
4080 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0, nTopM
+
4081 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
4082 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
4085 aLogicStart
.Y() += nTopM
+ aCellSize
.Height() - nEngineHeight
;
4087 else if (rParam
.meVerJust
==SVX_VER_JUSTIFY_CENTER
)
4089 if (rParam
.mbPixelToLogic
)
4090 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0, nTopM
+ (
4091 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
4092 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height() )
4095 aLogicStart
.Y() += nTopM
+ (aCellSize
.Height() - nEngineHeight
) / 2;
4099 if (rParam
.mbPixelToLogic
)
4100 aLogicStart
.Y() += mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
4102 aLogicStart
.Y() += nTopM
;
4105 Point aURLStart
= aLogicStart
; // copy before modifying for orientation
4107 Size aPaperLogic
= rParam
.mpEngine
->GetPaperSize();
4108 aPaperLogic
.Width() = nEngineWidth
;
4109 rParam
.mpEngine
->SetPaperSize(aPaperLogic
);
4111 rParam
.adjustForRTL();
4113 // bMoveClipped handling has been replaced by complete alignment
4114 // handling (also extending to the left).
4118 // no hard clip, only draw the affected rows
4119 Point aDocStart
= aLogicClip
.TopLeft();
4120 aDocStart
-= aLogicStart
;
4121 rParam
.mpEngine
->Draw( mpDev
, aLogicClip
, aDocStart
, false );
4125 rParam
.mpEngine
->Draw( mpDev
, aLogicStart
);
4133 mpDev
->SetClipRegion();
4136 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
4139 void ScOutputData::DrawEditAsianVertical(DrawEditParam
& rParam
)
4141 // When in asian vertical orientation, the orientation value is STANDARD,
4142 // and the asian vertical boolean is true.
4143 OSL_ASSERT(rParam
.meOrient
== SVX_ORIENTATION_STANDARD
);
4144 OSL_ASSERT(rParam
.mbAsianVertical
);
4145 OSL_ASSERT(rParam
.meHorJustAttr
!= SVX_HOR_JUSTIFY_REPEAT
);
4147 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
4149 bool bHidden
= false;
4150 bool bShrink
= !rParam
.mbBreak
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
4151 long nAttrRotate
= lcl_GetValue
<SfxInt32Item
, long>(*rParam
.mpPattern
, ATTR_ROTATE_VALUE
, rParam
.mpCondSet
);
4155 //! Flag setzen, um die Zelle in DrawRotated wiederzufinden ?
4156 //! (oder Flag schon bei DrawBackground, dann hier keine Abfrage)
4157 bHidden
= true; // rotated is outputted separately
4160 // default alignment for asian vertical mode is top-right
4161 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4162 * SVX_HOR_JUSTIFY_RIGHT really wanted? Seems this was done all the time,
4163 * also before context was introduced and everything was attr only. */
4164 if ( rParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_STANDARD
)
4165 rParam
.meHorJustResult
= rParam
.meHorJustContext
= SVX_HOR_JUSTIFY_RIGHT
;
4170 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
4172 //! mirror margin values for RTL?
4173 //! move margin down to after final GetOutputArea call
4174 long nTopM
, nLeftM
, nBottomM
, nRightM
;
4175 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
4177 SCCOL nXForPos
= rParam
.mnX
;
4178 if ( nXForPos
< nX1
)
4181 rParam
.mnPosX
= rParam
.mnInitPosX
;
4183 SCSIZE nArrYForPos
= rParam
.mnArrY
;
4184 if ( nArrYForPos
< 1 )
4187 rParam
.mnPosY
= nScrY
;
4190 OutputAreaParam aAreaParam
;
4192 // Initial page size - large for normal text, cell size for automatic line breaks
4194 Size
aPaperSize( 1000000, 1000000 );
4195 // call GetOutputArea with nNeeded=0, to get only the cell width
4197 //! handle nArrY == 0
4198 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
4199 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
4200 rParam
.mbCellIsValue
, true, false, aAreaParam
);
4202 //! special ScEditUtil handling if formatting for printer
4203 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
4205 if (rParam
.mbPixelToLogic
)
4207 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
4208 if ( rParam
.mbBreak
&& !rParam
.mbAsianVertical
&& mpRefDevice
!= pFmtDevice
)
4210 // #i85342# screen display and formatting for printer,
4211 // use same GetEditArea call as in ScViewData::SetEditEngine
4213 Fraction
aFract(1,1);
4214 Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
4215 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
4216 aLogicSize
.Width() = aUtilRect
.GetWidth();
4218 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
4221 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
4223 // Fill the EditEngine (cell attributes and text)
4225 // default alignment for asian vertical mode is top-right
4226 if ( rParam
.meVerJust
== SVX_VER_JUSTIFY_STANDARD
)
4227 rParam
.meVerJust
= SVX_VER_JUSTIFY_TOP
;
4229 rParam
.setPatternToEngine(mbUseStyleColor
);
4230 rParam
.setAlignmentToEngine();
4232 // Read content from cell
4234 bool bWrapFields
= false;
4235 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
4236 // Failed to read cell content. Bail out.
4240 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
4241 else if ( mbUseStyleColor
&& mbForceAutoColor
)
4242 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
4244 rParam
.mpEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4246 // Get final output area using the calculated width
4248 long nEngineWidth
, nEngineHeight
;
4249 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
4251 long nNeededPixel
= nEngineWidth
;
4252 if (rParam
.mbPixelToLogic
)
4253 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
4254 nNeededPixel
+= nLeftM
+ nRightM
;
4256 // for break, the first GetOutputArea call is sufficient
4257 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
4258 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
4259 rParam
.mbCellIsValue
|| bShrink
, false, false, aAreaParam
);
4263 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
4264 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
4265 sal::static_int_cast
<sal_uInt16
>(rParam
.meOrient
), 0, rParam
.mbPixelToLogic
,
4266 nEngineWidth
, nEngineHeight
, nNeededPixel
,
4267 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
4270 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
4272 rParam
.mpEngine
->SetText(OUString("###"));
4273 nEngineWidth
= (long) rParam
.mpEngine
->CalcTextWidth();
4274 if (rParam
.mbPixelToLogic
)
4275 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width();
4277 nNeededPixel
= nEngineWidth
;
4278 nNeededPixel
+= nLeftM
+ nRightM
;
4280 // No clip marks if "###" doesn't fit (same as in DrawStrings)
4283 if (eOutHorJust
!= SVX_HOR_JUSTIFY_LEFT
)
4285 aPaperSize
.Width() = nNeededPixel
+ 1;
4286 if (rParam
.mbPixelToLogic
)
4287 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4289 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
4292 long nStartX
= aAreaParam
.maAlignRect
.Left();
4293 long nStartY
= aAreaParam
.maAlignRect
.Top();
4294 long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
4295 long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
4296 long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
4298 // text with automatic breaks is aligned only within the
4299 // edit engine's paper size, the output of the whole area
4300 // is always left-aligned
4304 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
4308 if ( aAreaParam
.maClipRect
.Left() < nScrX
)
4310 aAreaParam
.maClipRect
.Left() = nScrX
;
4311 aAreaParam
.mbLeftClip
= true;
4313 if ( aAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
4315 aAreaParam
.maClipRect
.Right() = nScrX
+ nScrW
; //! minus one?
4316 aAreaParam
.mbRightClip
= true;
4319 bool bClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
4320 bool bSimClip
= false;
4324 // Fields in a cell with automatic breaks: clip to cell width
4328 if ( aAreaParam
.maClipRect
.Top() < nScrY
)
4330 aAreaParam
.maClipRect
.Top() = nScrY
;
4333 if ( aAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
4335 aAreaParam
.maClipRect
.Bottom() = nScrY
+ nScrH
; //! minus one?
4339 Size aCellSize
; // output area, excluding margins, in logical units
4340 if (rParam
.mbPixelToLogic
)
4341 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
4343 aCellSize
= Size( nOutWidth
, nOutHeight
);
4345 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
4347 const ScMergeAttr
* pMerge
=
4348 static_cast<const ScMergeAttr
*>(&rParam
.mpPattern
->GetItem(ATTR_MERGE
));
4349 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4351 // Don't clip for text height when printing rows with optimal height,
4352 // except when font size is from conditional formatting.
4353 //! Allow clipping when vertically merged?
4354 if ( eType
!= OUTTYPE_PRINTER
||
4355 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CR_MANUALSIZE
) ||
4356 ( rParam
.mpCondSet
&& SfxItemState::SET
==
4357 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
4362 // Show clip marks if height is at least 5pt too small and
4363 // there are several lines of text.
4364 // Not for asian vertical text, because that would interfere
4365 // with the default right position of the text.
4366 // Only with automatic line breaks, to avoid having to find
4367 // the cells with the horizontal end of the text again.
4368 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
4369 ( rParam
.mbBreak
|| rParam
.meOrient
== SVX_ORIENTATION_STACKED
) &&
4370 !rParam
.mbAsianVertical
&& bMarkClipped
&&
4371 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
4373 CellInfo
* pClipMarkCell
= nullptr;
4376 // anywhere in the merged area...
4377 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
4378 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].pCellInfo
[nClipX
+1];
4381 pClipMarkCell
= &rParam
.mpThisRowInfo
->pCellInfo
[rParam
.mnX
+1];
4383 pClipMarkCell
->nClipMark
|= SC_CLIPMARK_RIGHT
; //! also allow left?
4386 long nMarkPixel
= (long)( SC_CLIPMARK_SIZE
* mnPPTX
);
4387 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
4388 aAreaParam
.maClipRect
.Right() -= nMarkPixel
;
4392 Rectangle aLogicClip
;
4393 if (bClip
|| bSimClip
)
4395 // Clip marks are already handled in GetOutputArea
4397 if (rParam
.mbPixelToLogic
)
4398 aLogicClip
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
4400 aLogicClip
= aAreaParam
.maClipRect
;
4402 if (bClip
) // bei bSimClip nur aClipRect initialisieren
4407 mpDev
->IntersectClipRegion( aLogicClip
);
4410 mpDev
->SetClipRegion( vcl::Region( aLogicClip
) );
4415 if (rParam
.mbPixelToLogic
)
4416 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
4418 aLogicStart
= Point(nStartX
, nStartY
);
4420 long nAvailWidth
= aCellSize
.Width();
4421 // space for AutoFilter is already handled in GetOutputArea
4423 // horizontal alignment
4425 if (rParam
.meHorJustResult
==SVX_HOR_JUSTIFY_RIGHT
)
4426 aLogicStart
.X() += nAvailWidth
- nEngineWidth
;
4427 else if (rParam
.meHorJustResult
==SVX_HOR_JUSTIFY_CENTER
)
4428 aLogicStart
.X() += (nAvailWidth
- nEngineWidth
) / 2;
4430 // paper size is subtracted below
4431 aLogicStart
.X() += nEngineWidth
;
4433 // vertical adjustment is within the EditEngine
4434 if (rParam
.mbPixelToLogic
)
4435 aLogicStart
.Y() += mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
4437 aLogicStart
.Y() += nTopM
;
4439 Point aURLStart
= aLogicStart
; // copy before modifying for orientation
4441 rParam
.adjustForRTL();
4443 // bMoveClipped handling has been replaced by complete alignment
4444 // handling (also extending to the left).
4446 // with SetVertical, the start position is top left of
4447 // the whole output area, not the text itself
4448 aLogicStart
.X() -= rParam
.mpEngine
->GetPaperSize().Width();
4450 rParam
.mpEngine
->Draw(mpDev
, aLogicStart
);
4457 mpDev
->SetClipRegion();
4460 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
4463 void ScOutputData::DrawEdit(bool bPixelToLogic
)
4465 std::unique_ptr
<ScFieldEditEngine
> pEngine
;
4466 bool bHyphenatorSet
= false;
4467 const ScPatternAttr
* pOldPattern
= nullptr;
4468 const SfxItemSet
* pOldCondSet
= nullptr;
4469 const SfxItemSet
* pOldPreviewFontSet
= nullptr;
4470 ScRefCellValue aCell
;
4472 long nInitPosX
= nScrX
;
4475 nInitPosX
+= nMirrorW
- 1;
4477 long nLayoutSign
= bLayoutRTL
? -1 : 1;
4479 //! store nLastContentCol as member!
4480 SCCOL nLastContentCol
= MAXCOL
;
4482 nLastContentCol
= sal::static_int_cast
<SCCOL
>(
4483 nLastContentCol
- mpDoc
->GetEmptyLinesInBlock( nX2
+1, nY1
, nTab
, MAXCOL
, nY2
, nTab
, DIR_RIGHT
) );
4485 long nRowPosY
= nScrY
;
4486 for (SCSIZE nArrY
=0; nArrY
+1<nArrCount
; nArrY
++) // 0 fo the rest of the merged
4488 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
4490 if (nArrY
==1) nRowPosY
= nScrY
; // positions before are calculated individually
4492 if ( pThisRowInfo
->bChanged
|| nArrY
==0 )
4495 for (SCCOL nX
=0; nX
<=nX2
; nX
++) // due to overflow
4497 std::unique_ptr
< ScPatternAttr
> pPreviewPattr
;
4498 if (nX
==nX1
) nPosX
= nInitPosX
; // positions before nX1 are calculated individually
4500 CellInfo
* pInfo
= &pThisRowInfo
->pCellInfo
[nX
+1];
4501 if (pInfo
->bEditEngine
)
4503 SCROW nY
= pThisRowInfo
->nRowNo
;
4505 SCCOL nCellX
= nX
; // position where the cell really starts
4507 bool bDoCell
= false;
4509 long nPosY
= nRowPosY
;
4513 nY
= pRowInfo
[1].nRowNo
;
4514 SCCOL nOverX
; // start of the merged cells
4516 if (GetMergeOrigin( nX
,nY
, 1, nOverX
,nOverY
, true ))
4523 else if ( nX
== nX2
&& pThisRowInfo
->pCellInfo
[nX
+1].maCell
.isEmpty() )
4525 // Rest of a long text further to the right?
4528 while (nTempX
< nLastContentCol
&& IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
4532 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
4533 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX
,nY
,nTab
, HASATTR_MERGED
| HASATTR_OVERLAPPED
) )
4544 if ( bDoCell
&& bEditMode
&& nCellX
== nEditCol
&& nCellY
== nEditRow
)
4547 const ScPatternAttr
* pPattern
= nullptr;
4548 const SfxItemSet
* pCondSet
= nullptr;
4551 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
&&
4552 !mpDoc
->ColHidden(nCellX
, nTab
) )
4554 CellInfo
& rCellInfo
= pThisRowInfo
->pCellInfo
[nCellX
+1];
4555 pPattern
= rCellInfo
.pPatternAttr
;
4556 pCondSet
= rCellInfo
.pConditionSet
;
4557 aCell
= rCellInfo
.maCell
;
4559 else // get from document
4561 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
4562 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
4563 GetVisibleCell( nCellX
, nCellY
, nTab
, aCell
);
4565 if (aCell
.isEmpty())
4570 if ( mpDoc
->GetPreviewCellStyle() )
4572 if ( ScStyleSheet
* pPreviewStyle
= mpDoc
->GetPreviewCellStyle( nCellX
, nCellY
, nTab
) )
4574 pPreviewPattr
.reset( new ScPatternAttr(*pPattern
) );
4575 pPreviewPattr
->SetStyleSheet(pPreviewStyle
);
4576 pPattern
= pPreviewPattr
.get();
4579 SfxItemSet
* pPreviewFontSet
= mpDoc
->GetPreviewFont( nCellX
, nCellY
, nTab
);
4581 pEngine
.reset(CreateOutputEditEngine());
4583 lcl_ClearEdit( *pEngine
); // also calls SetUpdateMode(sal_False)
4585 // fdo#32530: Check if the first character is RTL.
4586 OUString aStr
= mpDoc
->GetString(nCellX
, nCellY
, nTab
);
4588 DrawEditParam
aParam(pPattern
, pCondSet
, lcl_SafeIsValue(aCell
));
4589 const bool bNumberFormatIsText
= lcl_isNumberFormatText( mpDoc
, nCellX
, nCellY
, nTab
);
4590 aParam
.meHorJustContext
= getAlignmentFromContext( aParam
.meHorJustAttr
,
4591 aParam
.mbCellIsValue
, aStr
, *pPattern
, pCondSet
, mpDoc
, nTab
, bNumberFormatIsText
);
4592 aParam
.meHorJustResult
= (aParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_BLOCK
) ?
4593 SVX_HOR_JUSTIFY_BLOCK
: aParam
.meHorJustContext
;
4594 aParam
.mbPixelToLogic
= bPixelToLogic
;
4595 aParam
.mbHyphenatorSet
= bHyphenatorSet
;
4596 aParam
.mpEngine
= pEngine
.get();
4597 aParam
.maCell
= aCell
;
4598 aParam
.mnArrY
= nArrY
;
4601 aParam
.mnCellX
= nCellX
;
4602 aParam
.mnCellY
= nCellY
;
4603 aParam
.mnTab
= nTab
;
4604 aParam
.mnPosX
= nPosX
;
4605 aParam
.mnPosY
= nPosY
;
4606 aParam
.mnInitPosX
= nInitPosX
;
4607 aParam
.mpPreviewFontSet
= pPreviewFontSet
;
4608 aParam
.mpOldPattern
= pOldPattern
;
4609 aParam
.mpOldCondSet
= pOldCondSet
;
4610 aParam
.mpOldPreviewFontSet
= pOldPreviewFontSet
;
4611 aParam
.mpThisRowInfo
= pThisRowInfo
;
4612 if (mpSpellCheckCxt
)
4613 aParam
.mpMisspellRanges
= mpSpellCheckCxt
->getMisspellRanges(nCellX
, nCellY
);
4615 if (aParam
.meHorJustAttr
== SVX_HOR_JUSTIFY_REPEAT
)
4617 // ignore orientation/rotation if "repeat" is active
4618 aParam
.meOrient
= SVX_ORIENTATION_STANDARD
;
4620 switch (aParam
.meOrient
)
4622 case SVX_ORIENTATION_BOTTOMTOP
:
4623 DrawEditBottomTop(aParam
);
4625 case SVX_ORIENTATION_TOPBOTTOM
:
4626 DrawEditTopBottom(aParam
);
4628 case SVX_ORIENTATION_STACKED
:
4629 // this can be vertically stacked or asian vertical.
4630 DrawEditStacked(aParam
);
4633 DrawEditStandard(aParam
);
4636 // Retrieve parameters for next iteration.
4637 pOldPattern
= aParam
.mpOldPattern
;
4638 pOldCondSet
= aParam
.mpOldCondSet
;
4639 pOldPreviewFontSet
= aParam
.mpOldPreviewFontSet
;
4640 bHyphenatorSet
= aParam
.mbHyphenatorSet
;
4643 nPosX
+= pRowInfo
[0].pCellInfo
[nX
+1].nWidth
* nLayoutSign
;
4646 nRowPosY
+= pRowInfo
[nArrY
].nHeight
;
4652 DrawRotated(bPixelToLogic
); //! call from outside ?
4655 void ScOutputData::DrawRotated(bool bPixelToLogic
)
4658 SCCOL nRotMax
= nX2
;
4659 for (SCSIZE nRotY
=0; nRotY
<nArrCount
; nRotY
++)
4660 if (pRowInfo
[nRotY
].nRotMaxCol
!= SC_ROTMAX_NONE
&& pRowInfo
[nRotY
].nRotMaxCol
> nRotMax
)
4661 nRotMax
= pRowInfo
[nRotY
].nRotMaxCol
;
4663 ScModule
* pScMod
= SC_MOD();
4664 sal_Int32 nConfBackColor
= pScMod
->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
;
4665 bool bCellContrast
= mbUseStyleColor
&&
4666 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4668 std::unique_ptr
<ScFieldEditEngine
> pEngine
;
4669 bool bHyphenatorSet
= false;
4670 const ScPatternAttr
* pPattern
;
4671 const SfxItemSet
* pCondSet
;
4672 const ScPatternAttr
* pOldPattern
= nullptr;
4673 const SfxItemSet
* pOldCondSet
= nullptr;
4674 ScRefCellValue aCell
;
4676 long nInitPosX
= nScrX
;
4679 nInitPosX
+= nMirrorW
- 1;
4681 long nLayoutSign
= bLayoutRTL
? -1 : 1;
4683 long nRowPosY
= nScrY
;
4684 for (SCSIZE nArrY
=0; nArrY
+1<nArrCount
; nArrY
++) // 0 for the rest of the merged
4686 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
4687 long nCellHeight
= (long) pThisRowInfo
->nHeight
;
4688 if (nArrY
==1) nRowPosY
= nScrY
; // positions before are calculated individually
4690 if ( ( pThisRowInfo
->bChanged
|| nArrY
==0 ) && pThisRowInfo
->nRotMaxCol
!= SC_ROTMAX_NONE
)
4693 for (SCCOL nX
=0; nX
<=nRotMax
; nX
++)
4695 if (nX
==nX1
) nPosX
= nInitPosX
; // positions before nX1 are calculated individually
4697 CellInfo
* pInfo
= &pThisRowInfo
->pCellInfo
[nX
+1];
4698 if ( pInfo
->nRotateDir
!= SC_ROTDIR_NONE
)
4700 SCROW nY
= pThisRowInfo
->nRowNo
;
4702 bool bHidden
= false;
4704 if ( nX
== nEditCol
&& nY
== nEditRow
)
4710 pEngine
.reset(CreateOutputEditEngine());
4712 lcl_ClearEdit( *pEngine
); // also calls SetUpdateMode(sal_False)
4714 long nPosY
= nRowPosY
;
4716 //! rest from merged cells further up do not work!
4718 bool bFromDoc
= false;
4719 pPattern
= pInfo
->pPatternAttr
;
4720 pCondSet
= pInfo
->pConditionSet
;
4723 pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
4726 aCell
= pInfo
->maCell
;
4728 pCondSet
= mpDoc
->GetCondResult( nX
, nY
, nTab
);
4730 if (aCell
.isEmpty() && nX
>nX2
)
4731 GetVisibleCell( nX
, nY
, nTab
, aCell
);
4733 if (aCell
.isEmpty() || IsEmptyCellText(pThisRowInfo
, nX
, nY
))
4734 bHidden
= true; // nRotateDir is also set without a cell
4736 long nCellWidth
= (long) pRowInfo
[0].pCellInfo
[nX
+1].nWidth
;
4738 SvxCellHorJustify eHorJust
= (SvxCellHorJustify
)static_cast<const SvxHorJustifyItem
&>(
4739 pPattern
->GetItem(ATTR_HOR_JUSTIFY
, pCondSet
)).GetValue();
4740 bool bBreak
= ( eHorJust
== SVX_HOR_JUSTIFY_BLOCK
) ||
4741 static_cast<const SfxBoolItem
&>(pPattern
->GetItem(ATTR_LINEBREAK
, pCondSet
)).GetValue();
4742 bool bRepeat
= ( eHorJust
== SVX_HOR_JUSTIFY_REPEAT
&& !bBreak
);
4743 bool bShrink
= !bBreak
&& !bRepeat
&& static_cast<const SfxBoolItem
&>
4744 (pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
)).GetValue();
4745 SvxCellOrientation eOrient
= pPattern
->GetCellOrientation( pCondSet
);
4747 const ScMergeAttr
* pMerge
=
4748 static_cast<const ScMergeAttr
*>(&pPattern
->GetItem(ATTR_MERGE
));
4749 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4751 long nStartX
= nPosX
;
4752 long nStartY
= nPosY
;
4755 if ((bBreak
|| eOrient
!=SVX_ORIENTATION_STANDARD
) && !bMerged
)
4759 nStartX
= nInitPosX
;
4764 nStartX
-= nLayoutSign
* (long) pRowInfo
[0].pCellInfo
[nCol
+1].nWidth
;
4768 long nCellStartX
= nStartX
;
4770 // omit substitute representation of small text
4774 long nOutWidth
= nCellWidth
- 1;
4775 long nOutHeight
= nCellHeight
;
4779 SCCOL nCountX
= pMerge
->GetColMerge();
4780 for (SCCOL i
=1; i
<nCountX
; i
++)
4781 nOutWidth
+= (long) ( mpDoc
->GetColWidth(nX
+i
,nTab
) * mnPPTX
);
4782 SCROW nCountY
= pMerge
->GetRowMerge();
4783 nOutHeight
+= (long) mpDoc
->GetScaledRowHeight( nY
+1, nY
+nCountY
-1, nTab
, mnPPTY
);
4786 SvxCellVerJustify eVerJust
= (SvxCellVerJustify
)static_cast<const SvxVerJustifyItem
&>(
4787 pPattern
->GetItem(ATTR_VER_JUSTIFY
, pCondSet
)).GetValue();
4789 // syntax mode is ignored here...
4791 // StringDiffer doesn't look at hyphenate, language items
4792 if ( pPattern
!= pOldPattern
|| pCondSet
!= pOldCondSet
)
4794 SfxItemSet
* pSet
= new SfxItemSet( pEngine
->GetEmptyItemSet() );
4795 pPattern
->FillEditItemSet( pSet
, pCondSet
);
4797 // adjustment for EditEngine
4798 SvxAdjust eSvxAdjust
= SVX_ADJUST_LEFT
;
4799 if (eOrient
==SVX_ORIENTATION_STACKED
)
4800 eSvxAdjust
= SVX_ADJUST_CENTER
;
4801 // adjustment for bBreak is omitted here
4802 pSet
->Put( SvxAdjustItem( eSvxAdjust
, EE_PARA_JUST
) );
4804 pEngine
->SetDefaults( pSet
);
4805 pOldPattern
= pPattern
;
4806 pOldCondSet
= pCondSet
;
4808 EEControlBits nControl
= pEngine
->GetControlWord();
4809 if (eOrient
==SVX_ORIENTATION_STACKED
)
4810 nControl
|= EEControlBits::ONECHARPERLINE
;
4812 nControl
&= ~EEControlBits::ONECHARPERLINE
;
4813 pEngine
->SetControlWord( nControl
);
4815 if ( !bHyphenatorSet
&& static_cast<const SfxBoolItem
&>(pSet
->Get(EE_PARA_HYPHENATE
)).GetValue() )
4817 // set hyphenator the first time it is needed
4818 css::uno::Reference
<css::linguistic2::XHyphenator
> xXHyphenator( LinguMgr::GetHyphenator() );
4819 pEngine
->SetHyphenator( xXHyphenator
);
4820 bHyphenatorSet
= true;
4823 Color aBackCol
= static_cast<const SvxBrushItem
&>(
4824 pPattern
->GetItem( ATTR_BACKGROUND
, pCondSet
)).GetColor();
4825 if ( mbUseStyleColor
&& ( aBackCol
.GetTransparency() > 0 || bCellContrast
) )
4826 aBackCol
.SetColor( nConfBackColor
);
4827 pEngine
->SetBackgroundColor( aBackCol
);
4832 //! change position and paper size to EditUtil !!!
4834 const SvxMarginItem
* pMargin
= static_cast<const SvxMarginItem
*>(
4835 &pPattern
->GetItem(ATTR_MARGIN
, pCondSet
));
4836 sal_uInt16 nIndent
= 0;
4837 if ( eHorJust
== SVX_HOR_JUSTIFY_LEFT
)
4838 nIndent
= static_cast<const SfxUInt16Item
&>(pPattern
->
4839 GetItem(ATTR_INDENT
, pCondSet
)).GetValue();
4841 long nTotalHeight
= nOutHeight
; // without subtracting the margin
4842 if ( bPixelToLogic
)
4843 nTotalHeight
= mpRefDevice
->PixelToLogic(Size(0,nTotalHeight
)).Height();
4845 long nLeftM
= (long) ( (pMargin
->GetLeftMargin() + nIndent
) * mnPPTX
);
4846 long nTopM
= (long) ( pMargin
->GetTopMargin() * mnPPTY
);
4847 long nRightM
= (long) ( pMargin
->GetRightMargin() * mnPPTX
);
4848 long nBottomM
= (long) ( pMargin
->GetBottomMargin() * mnPPTY
);
4851 nOutWidth
-= nLeftM
+ nRightM
;
4852 nOutHeight
-= nTopM
+ nBottomM
;
4854 // rotate here already, to adjust paper size for page breaks
4855 long nAttrRotate
= 0;
4858 SvxRotateMode eRotMode
= SVX_ROTATE_MODE_STANDARD
;
4859 if ( eOrient
== SVX_ORIENTATION_STANDARD
)
4861 nAttrRotate
= static_cast<const SfxInt32Item
&>(pPattern
->
4862 GetItem(ATTR_ROTATE_VALUE
, pCondSet
)).GetValue();
4865 eRotMode
= (SvxRotateMode
)static_cast<const SvxRotateModeItem
&>(
4866 pPattern
->GetItem(ATTR_ROTATE_MODE
, pCondSet
)).GetValue();
4868 if ( nAttrRotate
== 18000 )
4869 eRotMode
= SVX_ROTATE_MODE_STANDARD
; // no overflow
4872 nAttrRotate
= -nAttrRotate
;
4874 double nRealOrient
= nAttrRotate
* F_PI18000
; // 1/100 degree
4875 nCos
= cos( nRealOrient
);
4876 nSin
= sin( nRealOrient
);
4880 Size
aPaperSize( 1000000, 1000000 );
4881 if (eOrient
==SVX_ORIENTATION_STACKED
)
4882 aPaperSize
.Width() = nOutWidth
; // to center
4887 //! the correct paper size for break depends on the number
4888 //! of rows, as long as the rows can not be outputted individually
4889 //! offsetted -> therefore unlimited, so no wrapping.
4890 //! With offset rows the following would be correct:
4891 aPaperSize
.Width() = (long)(nOutHeight
/ fabs(nSin
));
4893 else if (eOrient
== SVX_ORIENTATION_STANDARD
)
4894 aPaperSize
.Width() = nOutWidth
;
4896 aPaperSize
.Width() = nOutHeight
- 1;
4899 pEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4901 pEngine
->SetPaperSize(aPaperSize
); // scale is always 1
4903 // read data from cell
4905 if (aCell
.meType
== CELLTYPE_EDIT
)
4907 if (aCell
.mpEditText
)
4908 pEngine
->SetText(*aCell
.mpEditText
);
4911 OSL_FAIL("pData == 0");
4916 sal_uLong nFormat
= pPattern
->GetNumberFormat(
4917 mpDoc
->GetFormatTable(), pCondSet
);
4920 ScCellFormat::GetString( aCell
,
4921 nFormat
,aString
, &pColor
,
4922 *mpDoc
->GetFormatTable(),
4928 pEngine
->SetText(aString
);
4929 if ( pColor
&& !mbSyntaxMode
&& !( mbUseStyleColor
&& mbForceAutoColor
) )
4930 lcl_SetEditColor( *pEngine
, *pColor
);
4935 SetEditSyntaxColor(*pEngine
, aCell
);
4937 else if ( mbUseStyleColor
&& mbForceAutoColor
)
4938 lcl_SetEditColor( *pEngine
, COL_AUTO
); //! or have a flag at EditEngine
4940 pEngine
->SetUpdateMode( true ); // after SetText, before CalcTextWidth/GetTextHeight
4942 long nEngineWidth
= (long) pEngine
->CalcTextWidth();
4943 long nEngineHeight
= pEngine
->GetTextHeight();
4945 if (nAttrRotate
&& bBreak
)
4947 double nAbsCos
= fabs( nCos
);
4948 double nAbsSin
= fabs( nSin
);
4950 // adjust witdh of papersize for height of text
4954 // everything is in pixels
4955 long nEnginePixel
= mpRefDevice
->LogicToPixel(
4956 Size(0,nEngineHeight
)).Height();
4957 long nEffHeight
= nOutHeight
- (long)(nEnginePixel
* nAbsCos
) + 2;
4958 long nNewWidth
= (long)(nEffHeight
/ nAbsSin
) + 2;
4959 bool bFits
= ( nNewWidth
>= aPaperSize
.Width() );
4964 if ( nNewWidth
< 4 )
4966 // can't fit -> fall back to using half height
4967 nEffHeight
= nOutHeight
/ 2;
4968 nNewWidth
= (long)(nEffHeight
/ nAbsSin
) + 2;
4974 // set paper width and get new text height
4975 aPaperSize
.Width() = nNewWidth
;
4977 pEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4979 pEngine
->SetPaperSize(aPaperSize
); // Scale is always 1
4980 //pEngine->QuickFormatDoc( sal_True );
4982 nEngineWidth
= (long) pEngine
->CalcTextWidth();
4983 nEngineHeight
= pEngine
->GetTextHeight();
4988 long nRealWidth
= nEngineWidth
;
4989 long nRealHeight
= nEngineHeight
;
4991 // when rotated, adjust size
4994 double nAbsCos
= fabs( nCos
);
4995 double nAbsSin
= fabs( nSin
);
4997 if ( eRotMode
== SVX_ROTATE_MODE_STANDARD
)
4998 nEngineWidth
= (long) ( nRealWidth
* nAbsCos
+
4999 nRealHeight
* nAbsSin
);
5001 nEngineWidth
= (long) ( nRealHeight
/ nAbsSin
);
5004 nEngineHeight
= (long) ( nRealHeight
* nAbsCos
+
5005 nRealWidth
* nAbsSin
);
5008 if (!nAttrRotate
) // only rotated text here
5009 bHidden
= true; //! check first !!!
5011 //! omit which doesn't stick out
5016 Size
aClipSize( nScrX
+nScrW
-nStartX
, nScrY
+nScrH
-nStartY
);
5022 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
5024 aCellSize
= Size( nOutWidth
, nOutHeight
); // Scale ist 1
5026 long nGridWidth
= nEngineWidth
;
5027 bool bNegative
= false;
5028 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5030 nGridWidth
= aCellSize
.Width() +
5031 std::abs((long) ( aCellSize
.Height() * nCos
/ nSin
));
5032 bNegative
= ( pInfo
->nRotateDir
== SC_ROTDIR_LEFT
);
5034 bNegative
= !bNegative
;
5037 // use GetOutputArea to hide the grid
5038 // (clip region is done manually below)
5039 OutputAreaParam aAreaParam
;
5043 SvxCellHorJustify eOutHorJust
= eHorJust
;
5044 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5045 eOutHorJust
= bNegative
? SVX_HOR_JUSTIFY_RIGHT
: SVX_HOR_JUSTIFY_LEFT
;
5046 long nNeededWidth
= nGridWidth
; // in pixel for GetOutputArea
5047 if ( bPixelToLogic
)
5048 nNeededWidth
= mpRefDevice
->LogicToPixel(Size(nNeededWidth
,0)).Width();
5050 GetOutputArea( nX
, nArrY
, nCellStartX
, nPosY
, nCellX
, nCellY
, nNeededWidth
,
5051 *pPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
5052 false, false, true, aAreaParam
);
5056 long nPixelWidth
= bPixelToLogic
?
5057 mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width() : nEngineWidth
;
5058 long nNeededPixel
= nPixelWidth
+ nLeftM
+ nRightM
;
5060 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= true;
5063 ShrinkEditEngine( *pEngine
, aAreaParam
.maAlignRect
, nLeftM
, nTopM
, nRightM
, nBottomM
,
5064 false, sal::static_int_cast
<sal_uInt16
>(eOrient
), nAttrRotate
, bPixelToLogic
,
5065 nEngineWidth
, nEngineHeight
, nNeededPixel
, aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
5067 if ( eRotMode
== SVX_ROTATE_MODE_STANDARD
)
5069 // do width only if rotating within the cell (standard mode)
5070 ShrinkEditEngine( *pEngine
, aAreaParam
.maAlignRect
, nLeftM
, nTopM
, nRightM
, nBottomM
,
5071 true, sal::static_int_cast
<sal_uInt16
>(eOrient
), nAttrRotate
, bPixelToLogic
,
5072 nEngineWidth
, nEngineHeight
, nNeededPixel
, aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
5075 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5076 // (but width is only valid for standard mode)
5077 nRealWidth
= (long) pEngine
->CalcTextWidth();
5078 nRealHeight
= pEngine
->GetTextHeight();
5080 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5081 nEngineWidth
= (long) ( nRealHeight
/ fabs( nSin
) );
5084 long nClipStartX
= nStartX
;
5087 //! clipping is not needed when on the left side of the window
5091 long nDif
= nScrX
- nStartX
;
5092 nClipStartX
= nScrX
;
5093 aClipSize
.Width() -= nDif
;
5097 long nClipStartY
= nStartY
;
5100 if ( nClipStartY
< nRowPosY
)
5102 long nDif
= nRowPosY
- nClipStartY
;
5103 nClipStartY
= nRowPosY
;
5104 aClipSize
.Height() -= nDif
;
5108 bClip
= true; // always clip at the window/page border
5110 //Rectangle aClipRect;
5113 if ( nAttrRotate
/* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5115 // only clip rotated output text at the page border
5116 nClipStartX
= nScrX
;
5117 aClipSize
.Width() = nScrW
;
5121 aAreaParam
.maClipRect
= mpRefDevice
->PixelToLogic( Rectangle(
5122 Point(nClipStartX
,nClipStartY
), aClipSize
) );
5124 aAreaParam
.maClipRect
= Rectangle(Point(nClipStartX
, nClipStartY
),
5125 aClipSize
); // Scale = 1
5130 mpDev
->IntersectClipRegion( aAreaParam
.maClipRect
);
5133 mpDev
->SetClipRegion( vcl::Region( aAreaParam
.maClipRect
) );
5138 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
5140 aLogicStart
= Point(nStartX
, nStartY
);
5141 if ( eOrient
!=SVX_ORIENTATION_STANDARD
|| !bBreak
)
5143 long nAvailWidth
= aCellSize
.Width();
5144 if (eType
==OUTTYPE_WINDOW
&&
5145 eOrient
!=SVX_ORIENTATION_STACKED
&&
5148 // filter drop-down width is now independent from row height
5150 nAvailWidth
-= mpRefDevice
->PixelToLogic(Size(0,DROPDOWN_BITMAP_SIZE
)).Height();
5152 nAvailWidth
-= DROPDOWN_BITMAP_SIZE
;
5153 long nComp
= nEngineWidth
;
5154 if (nAvailWidth
<nComp
) nAvailWidth
=nComp
;
5157 // horizontal orientation
5159 if (eOrient
==SVX_ORIENTATION_STANDARD
&& !nAttrRotate
)
5161 if (eHorJust
==SVX_HOR_JUSTIFY_RIGHT
||
5162 eHorJust
==SVX_HOR_JUSTIFY_CENTER
)
5164 pEngine
->SetUpdateMode( false );
5166 SvxAdjust eSvxAdjust
=
5167 (eHorJust
==SVX_HOR_JUSTIFY_RIGHT
) ?
5168 SVX_ADJUST_RIGHT
: SVX_ADJUST_CENTER
;
5169 pEngine
->SetDefaultItem(
5170 SvxAdjustItem( eSvxAdjust
, EE_PARA_JUST
) );
5172 aPaperSize
.Width() = nOutWidth
;
5174 pEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
5176 pEngine
->SetPaperSize(aPaperSize
);
5178 pEngine
->SetUpdateMode( true );
5183 // rotated text is centered by default
5184 if (eHorJust
==SVX_HOR_JUSTIFY_RIGHT
)
5185 aLogicStart
.X() += nAvailWidth
- nEngineWidth
;
5186 else if (eHorJust
==SVX_HOR_JUSTIFY_CENTER
||
5187 eHorJust
==SVX_HOR_JUSTIFY_STANDARD
)
5188 aLogicStart
.X() += (nAvailWidth
- nEngineWidth
) / 2;
5195 aLogicStart
.X() -= mpRefDevice
->PixelToLogic(
5196 Size( nCellWidth
, 0 ) ).Width();
5198 aLogicStart
.X() -= nCellWidth
;
5201 if ( eOrient
==SVX_ORIENTATION_STANDARD
||
5202 eOrient
==SVX_ORIENTATION_STACKED
|| !bBreak
)
5204 if (eVerJust
==SVX_VER_JUSTIFY_BOTTOM
||
5205 eVerJust
==SVX_VER_JUSTIFY_STANDARD
)
5208 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0,
5209 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
5210 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
5213 aLogicStart
.Y() += aCellSize
.Height() - nEngineHeight
;
5216 else if (eVerJust
==SVX_VER_JUSTIFY_CENTER
)
5219 aLogicStart
.Y() += mpRefDevice
->PixelToLogic( Size(0,(
5220 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
5221 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height())
5224 aLogicStart
.Y() += (aCellSize
.Height() - nEngineHeight
) / 2;
5228 // TOPBOTTON and BOTTOMTOP are handled in DrawStrings/DrawEdit
5229 OSL_ENSURE( eOrient
== SVX_ORIENTATION_STANDARD
&& nAttrRotate
,
5230 "DrawRotated: no rotation" );
5235 // Attribut ist 1/100, Font 1/10 Grad
5236 nOriVal
= nAttrRotate
/ 10;
5240 if ( nCos
> 0.0 && eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5243 double nH
= nRealHeight
* nCos
;
5244 nAddX
+= nH
* ( nCos
/ fabs(nSin
) );
5246 if ( nCos
< 0.0 && eRotMode
== SVX_ROTATE_MODE_STANDARD
)
5247 nAddX
-= nRealWidth
* nCos
;
5249 nAddX
-= nRealHeight
* nSin
;
5251 nAddY
+= nRealWidth
* nSin
;
5253 nAddY
-= nRealHeight
* nCos
;
5255 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5258 double nSkew
= nTotalHeight
* nCos
/ fabs(nSin
);
5259 if ( eRotMode
== SVX_ROTATE_MODE_CENTER
)
5260 nAddX
-= nSkew
* 0.5;
5261 if ( ( eRotMode
== SVX_ROTATE_MODE_TOP
&& nSin
> 0.0 ) ||
5262 ( eRotMode
== SVX_ROTATE_MODE_BOTTOM
&& nSin
< 0.0 ) )
5266 if ( eVerJust
== SVX_VER_JUSTIFY_CENTER
)
5267 nUp
= ( aCellSize
.Height() - nEngineHeight
) / 2;
5268 else if ( eVerJust
== SVX_VER_JUSTIFY_TOP
)
5271 nUp
= aCellSize
.Height() - nEngineHeight
;
5273 else // BOTTOM / STANDARD
5276 nUp
= aCellSize
.Height() - nEngineHeight
;
5279 nAddX
+= ( nUp
* nCos
/ fabs(nSin
) );
5282 aLogicStart
.X() += (long) nAddX
;
5283 aLogicStart
.Y() += (long) nAddY
;
5286 // bSimClip is not used here (because nOriVal is set)
5288 if ( pEngine
->IsRightToLeft( 0 ) )
5290 // For right-to-left, EditEngine always calculates its lines
5291 // beginning from the right edge, but EditLine::nStartPosX is
5292 // of sal_uInt16 type, so the PaperSize must be limited to USHRT_MAX.
5293 Size aLogicPaper
= pEngine
->GetPaperSize();
5294 if ( aLogicPaper
.Width() > USHRT_MAX
)
5296 aLogicPaper
.Width() = USHRT_MAX
;
5297 pEngine
->SetPaperSize(aLogicPaper
);
5301 pEngine
->Draw( mpDev
, aLogicStart
, (short)nOriVal
);
5308 mpDev
->SetClipRegion();
5314 nPosX
+= pRowInfo
[0].pCellInfo
[nX
+1].nWidth
* nLayoutSign
;
5317 nRowPosY
+= pRowInfo
[nArrY
].nHeight
;
5321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */