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/charreliefitem.hxx>
29 #include <editeng/crossedoutitem.hxx>
30 #include <editeng/contouritem.hxx>
31 #include <editeng/editobj.hxx>
32 #include <editeng/editstat.hxx>
33 #include <editeng/emphasismarkitem.hxx>
34 #include <editeng/fhgtitem.hxx>
35 #include <editeng/forbiddenruleitem.hxx>
36 #include <editeng/frmdiritem.hxx>
37 #include <editeng/justifyitem.hxx>
38 #include <svx/rotmodit.hxx>
39 #include <editeng/udlnitem.hxx>
40 #include <editeng/unolingu.hxx>
41 #include <editeng/fontitem.hxx>
42 #include <editeng/postitem.hxx>
43 #include <editeng/shdditem.hxx>
44 #include <editeng/wghtitem.hxx>
45 #include <editeng/wrlmitem.hxx>
46 #include <formula/errorcodes.hxx>
47 #include <svl/numformat.hxx>
48 #include <svl/zforlist.hxx>
49 #include <svl/zformat.hxx>
50 #include <vcl/kernarray.hxx>
51 #include <vcl/svapp.hxx>
52 #include <vcl/metric.hxx>
53 #include <vcl/outdev.hxx>
54 #include <vcl/pdfextoutdevdata.hxx>
55 #include <vcl/settings.hxx>
56 #include <vcl/glyphitem.hxx>
57 #include <vcl/glyphitemcache.hxx>
58 #include <sal/log.hxx>
59 #include <unotools/charclass.hxx>
60 #include <osl/diagnose.h>
63 #include <document.hxx>
64 #include <formulacell.hxx>
66 #include <patattr.hxx>
67 #include <cellform.hxx>
68 #include <editutil.hxx>
69 #include <progress.hxx>
71 #include <fillinfo.hxx>
72 #include <stlsheet.hxx>
73 #include <spellcheckcontext.hxx>
74 #include <scopetools.hxx>
75 #include <tabvwsh.hxx>
77 #include <com/sun/star/i18n/DirectionProperty.hpp>
78 #include <comphelper/scopeguard.hxx>
79 #include <comphelper/string.hxx>
86 using namespace com::sun::star
;
88 //! Merge Autofilter width with column.cxx
89 #define DROPDOWN_BITMAP_SIZE 18
91 #define DRAWTEXT_MAX 32767
93 const sal_uInt16 SC_SHRINKAGAIN_MAX
= 7;
94 constexpr auto HMM_PER_TWIPS
= o3tl::convert(1.0, o3tl::Length::twip
, o3tl::Length::mm100
);
96 class ScDrawStringsVars
98 ScOutputData
* pOutput
; // connection
100 const ScPatternAttr
* pPattern
; // attribute
101 const SfxItemSet
* pCondSet
; // from conditional formatting
103 vcl::Font aFont
; // created from attributes
105 tools::Long nAscentPixel
; // always pixels
106 SvxCellOrientation eAttrOrient
;
107 SvxCellHorJustify eAttrHorJust
;
108 SvxCellVerJustify eAttrVerJust
;
109 SvxCellJustifyMethod eAttrHorJustMethod
;
110 const SvxMarginItem
* pMargin
;
114 OUString aString
; // contents
116 tools::Long nOriginalWidth
;
117 tools::Long nMaxDigitWidth
;
118 tools::Long nSignWidth
;
119 tools::Long nDotWidth
;
120 tools::Long nExpWidth
;
122 ScRefCellValue maLastCell
;
123 sal_uLong nValueFormat
;
131 Color aBackConfigColor
; // used for ScPatternAttr::GetFont calls
132 Color aTextConfigColor
;
133 sal_Int32 nRepeatPos
;
134 sal_Unicode nRepeatChar
;
137 ScDrawStringsVars(ScOutputData
* pData
, bool bPTL
);
139 // SetPattern = ex-SetVars
140 // SetPatternSimple: without Font
143 const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
, const ScRefCellValue
& rCell
,
144 SvtScriptType nScript
);
146 void SetPatternSimple( const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
);
148 bool SetText( const ScRefCellValue
& rCell
); // TRUE -> drop pOldPattern
150 bool SetTextToWidthOrHash( ScRefCellValue
& rCell
, tools::Long nWidth
);
151 void SetAutoText( const OUString
& rAutoText
);
153 SvxCellOrientation
GetOrient() const { return eAttrOrient
; }
154 SvxCellHorJustify
GetHorJust() const { return eAttrHorJust
; }
155 SvxCellVerJustify
GetVerJust() const { return eAttrVerJust
; }
156 SvxCellJustifyMethod
GetHorJustMethod() const { return eAttrHorJustMethod
; }
157 const SvxMarginItem
* GetMargin() const { return pMargin
; }
159 sal_uInt16
GetLeftTotal() const { return pMargin
->GetLeftMargin() + nIndent
; }
160 sal_uInt16
GetRightTotal() const { return pMargin
->GetRightMargin() + nIndent
; }
162 const OUString
& GetString() const { return aString
; }
163 const Size
& GetTextSize() const { return aTextSize
; }
164 tools::Long
GetOriginalWidth() const { return nOriginalWidth
; }
165 tools::Long
GetFmtTextWidth(const OUString
& rString
);
167 // Get the effective number format, including formula result types.
168 // This assumes that a formula cell has already been calculated.
169 sal_uLong
GetResultValueFormat() const { return nValueFormat
;}
171 bool GetLineBreak() const { return bLineBreak
; }
172 bool IsRepeat() const { return bRepeat
; }
173 bool IsShrink() const { return bShrink
; }
174 void RepeatToFill( tools::Long nColWidth
);
176 tools::Long
GetAscent() const { return nAscentPixel
; }
177 bool IsRotated() const { return bRotated
; }
179 void SetShrinkScale( tools::Long nScale
, SvtScriptType nScript
);
181 bool HasCondHeight() const { return pCondSet
&& SfxItemState::SET
==
182 pCondSet
->GetItemState( ATTR_FONT_HEIGHT
); }
184 bool HasEditCharacters() const;
186 // ScOutputData::LayoutStrings() usually triggers a number of calls that require
187 // to lay out the text, which is relatively slow, so cache that operation.
188 const SalLayoutGlyphs
* GetLayoutGlyphs(const OUString
& rString
) const
190 return SalLayoutGlyphsCache::self()->GetLayoutGlyphs(pOutput
->pFmtDevice
, rString
);
194 tools::Long
GetMaxDigitWidth(); // in logic units
195 tools::Long
GetSignWidth();
196 tools::Long
GetDotWidth();
197 tools::Long
GetExpWidth();
201 ScDrawStringsVars::ScDrawStringsVars(ScOutputData
* pData
, bool bPTL
) :
203 pPattern ( nullptr ),
204 pCondSet ( nullptr ),
206 eAttrOrient ( SvxCellOrientation::Standard
),
207 eAttrHorJust( SvxCellHorJustify::Standard
),
208 eAttrVerJust( SvxCellVerJustify::Bottom
),
209 eAttrHorJustMethod( SvxCellJustifyMethod::Auto
),
219 bLineBreak ( false ),
222 bPixelToLogic( bPTL
),
226 bCellContrast
= pOutput
->mbUseStyleColor
&&
227 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
229 const svtools::ColorConfig
& rColorConfig
= ScModule::get()->GetColorConfig();
230 aBackConfigColor
= rColorConfig
.GetColorValue(svtools::DOCCOLOR
).nColor
;
231 aTextConfigColor
= rColorConfig
.GetColorValue(svtools::FONTCOLOR
).nColor
;
234 void ScDrawStringsVars::SetShrinkScale( tools::Long nScale
, SvtScriptType nScript
)
236 // text remains valid, size is updated
238 OutputDevice
* pDev
= pOutput
->mpDev
;
239 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
240 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
242 // call GetFont with a modified fraction, use only the height
244 Fraction
aFraction( nScale
, 100 );
245 if ( !bPixelToLogic
)
246 aFraction
*= pOutput
->aZoomY
;
248 pPattern
->fillFontOnly(aTmpFont
, pFmtDevice
, &aFraction
, pCondSet
, nScript
);
249 // only need font height
250 tools::Long nNewHeight
= aTmpFont
.GetFontHeight();
251 if ( nNewHeight
> 0 )
252 aFont
.SetFontHeight( nNewHeight
);
254 // set font and dependent variables as in SetPattern
256 pDev
->SetFont( aFont
);
257 if ( pFmtDevice
!= pDev
)
258 pFmtDevice
->SetFont( aFont
);
260 aMetric
= pFmtDevice
->GetFontMetric();
261 if ( pFmtDevice
->GetOutDevType() == OUTDEV_PRINTER
&& aMetric
.GetInternalLeading() == 0 )
263 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
264 MapMode aOld
= pDefaultDev
->GetMapMode();
265 pDefaultDev
->SetMapMode( pFmtDevice
->GetMapMode() );
266 aMetric
= pDefaultDev
->GetFontMetric( aFont
);
267 pDefaultDev
->SetMapMode( aOld
);
270 nAscentPixel
= aMetric
.GetAscent();
272 nAscentPixel
= pRefDevice
->LogicToPixel( Size( 0, nAscentPixel
) ).Height();
274 SetAutoText( aString
); // same text again, to get text size
279 template<typename ItemType
, typename EnumType
>
280 EnumType
lcl_GetValue(const ScPatternAttr
& rPattern
, sal_uInt16 nWhich
, const SfxItemSet
* pCondSet
)
282 const ItemType
& rItem
= static_cast<const ItemType
&>(rPattern
.GetItem(nWhich
, pCondSet
));
283 return static_cast<EnumType
>(rItem
.GetValue());
286 bool lcl_GetBoolValue(const ScPatternAttr
& rPattern
, sal_uInt16 nWhich
, const SfxItemSet
* pCondSet
)
288 return lcl_GetValue
<SfxBoolItem
, bool>(rPattern
, nWhich
, pCondSet
);
293 static bool lcl_isNumberFormatText(const ScDocument
* pDoc
, SCCOL nCellX
, SCROW nCellY
, SCTAB nTab
)
295 sal_uInt32 nCurrentNumberFormat
= pDoc
->GetNumberFormat( nCellX
, nCellY
, nTab
);
296 SvNumberFormatter
* pNumberFormatter
= pDoc
->GetFormatTable();
297 return pNumberFormatter
->GetType( nCurrentNumberFormat
) == SvNumFormatType::TEXT
;
300 void ScDrawStringsVars::SetPattern(
301 const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
, const ScRefCellValue
& rCell
,
302 SvtScriptType nScript
)
314 OutputDevice
* pDev
= pOutput
->mpDev
;
315 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
316 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
320 ScAutoFontColorMode eColorMode
;
321 if ( pOutput
->mbUseStyleColor
)
323 if ( pOutput
->mbForceAutoColor
)
324 eColorMode
= bCellContrast
? ScAutoFontColorMode::IgnoreAll
: ScAutoFontColorMode::IgnoreFont
;
326 eColorMode
= bCellContrast
? ScAutoFontColorMode::IgnoreBack
: ScAutoFontColorMode::Display
;
329 eColorMode
= ScAutoFontColorMode::Print
;
332 pPattern
->fillFont(aFont
, eColorMode
, pFmtDevice
, nullptr, pCondSet
, nScript
, &aBackConfigColor
, &aTextConfigColor
);
334 pPattern
->fillFont(aFont
, eColorMode
, pFmtDevice
, &pOutput
->aZoomY
, pCondSet
, nScript
, &aBackConfigColor
, &aTextConfigColor
);
336 aFont
.SetAlignment(ALIGN_BASELINE
);
340 eAttrOrient
= pPattern
->GetCellOrientation( pCondSet
);
344 eAttrHorJust
= pPattern
->GetItem( ATTR_HOR_JUSTIFY
, pCondSet
).GetValue();
346 eAttrVerJust
= pPattern
->GetItem( ATTR_VER_JUSTIFY
, pCondSet
).GetValue();
347 if ( eAttrVerJust
== SvxCellVerJustify::Standard
)
348 eAttrVerJust
= SvxCellVerJustify::Bottom
;
350 // justification method
352 eAttrHorJustMethod
= lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_HOR_JUSTIFY_METHOD
, pCondSet
);
356 bLineBreak
= pPattern
->GetItem( ATTR_LINEBREAK
, pCondSet
).GetValue();
358 // handle "repeat" alignment
360 bRepeat
= ( eAttrHorJust
== SvxCellHorJustify::Repeat
);
363 // "repeat" disables rotation (before constructing the font)
364 eAttrOrient
= SvxCellOrientation::Standard
;
366 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
368 eAttrHorJust
= SvxCellHorJustify::Standard
;
374 case SvxCellOrientation::Standard
:
376 bRotated
= pPattern
->GetItem( ATTR_ROTATE_VALUE
, pCondSet
).GetValue() != 0_deg100
&&
379 case SvxCellOrientation::Stacked
:
383 case SvxCellOrientation::TopBottom
:
387 case SvxCellOrientation::BottomUp
:
392 OSL_FAIL("Invalid SvxCellOrientation value");
397 aFont
.SetOrientation( Degree10(nRot
) );
401 if (pOutput
->mbSyntaxMode
)
402 pOutput
->SetSyntaxColor(&aFont
, rCell
);
404 // There is no cell attribute for kerning, default is kerning OFF, all
405 // kerning is stored at an EditText object that is drawn using EditEngine.
406 // See also matching kerning cases in ScColumn::GetNeededSize and
407 // ScColumn::GetOptimalColWidth.
408 aFont
.SetKerning(FontKerning::NONE
);
410 pDev
->SetFont( aFont
);
411 if ( pFmtDevice
!= pDev
)
412 pFmtDevice
->SetFont( aFont
);
414 aMetric
= pFmtDevice
->GetFontMetric();
416 // if there is the leading 0 on a printer device, we have problems
417 // -> take metric from the screen (as for EditEngine!)
418 if ( pFmtDevice
->GetOutDevType() == OUTDEV_PRINTER
&& aMetric
.GetInternalLeading() == 0 )
420 OutputDevice
* pDefaultDev
= Application::GetDefaultDevice();
421 MapMode aOld
= pDefaultDev
->GetMapMode();
422 pDefaultDev
->SetMapMode( pFmtDevice
->GetMapMode() );
423 aMetric
= pDefaultDev
->GetFontMetric( aFont
);
424 pDefaultDev
->SetMapMode( aOld
);
427 nAscentPixel
= aMetric
.GetAscent();
429 nAscentPixel
= pRefDevice
->LogicToPixel( Size( 0, nAscentPixel
) ).Height();
431 Color
aULineColor( pPattern
->GetItem( ATTR_FONT_UNDERLINE
, pCondSet
).GetColor() );
432 pDev
->SetTextLineColor( aULineColor
);
434 Color
aOLineColor( pPattern
->GetItem( ATTR_FONT_OVERLINE
, pCondSet
).GetColor() );
435 pDev
->SetOverlineColor( aOLineColor
);
439 nValueFormat
= pPattern
->GetNumberFormat( pOutput
->mpDoc
->GetFormatTable(), pCondSet
);
442 pMargin
= &pPattern
->GetItem( ATTR_MARGIN
, pCondSet
);
443 if ( eAttrHorJust
== SvxCellHorJustify::Left
|| eAttrHorJust
== SvxCellHorJustify::Right
)
444 nIndent
= pPattern
->GetItem( ATTR_INDENT
, pCondSet
).GetValue();
450 bShrink
= pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
).GetValue();
452 // at least the text size needs to be retrieved again
453 //! differentiate and do not get the text again from the number format?
457 void ScDrawStringsVars::SetPatternSimple( const ScPatternAttr
* pNew
, const SfxItemSet
* pSet
)
464 // Is called, when the font variables do not change (!StringDiffer)
467 pCondSet
= pSet
; //! is this needed ???
471 sal_uLong nOld
= nValueFormat
;
472 nValueFormat
= pPattern
->GetNumberFormat( pOutput
->mpDoc
->GetFormatTable(), pCondSet
);
474 if (nValueFormat
!= nOld
)
475 maLastCell
.clear(); // always reformat
479 pMargin
= &pPattern
->GetItem( ATTR_MARGIN
, pCondSet
);
481 if ( eAttrHorJust
== SvxCellHorJustify::Left
)
482 nIndent
= pPattern
->GetItem( ATTR_INDENT
, pCondSet
).GetValue();
488 bShrink
= pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
).GetValue();
491 static bool SameValue( const ScRefCellValue
& rCell
, const ScRefCellValue
& rOldCell
)
493 return rOldCell
.getType() == CELLTYPE_VALUE
&& rCell
.getType() == CELLTYPE_VALUE
&&
494 rCell
.getDouble() == rOldCell
.getDouble();
497 bool ScDrawStringsVars::SetText( const ScRefCellValue
& rCell
)
499 bool bChanged
= false;
501 if (!rCell
.isEmpty())
503 if (!SameValue(rCell
, maLastCell
))
505 maLastCell
= rCell
; // store cell
508 sal_uLong nFormat
= nValueFormat
;
509 aString
= ScCellFormat::GetString( rCell
,
513 pOutput
->mbShowNullValues
,
514 pOutput
->mbShowFormulas
,
518 nRepeatPos
= aString
.indexOf( 0x1B );
519 if ( nRepeatPos
!= -1 )
521 if (nRepeatPos
+ 1 == aString
.getLength())
525 nRepeatChar
= aString
[ nRepeatPos
+ 1 ];
526 // delete placeholder and char to repeat
527 aString
= aString
.replaceAt( nRepeatPos
, 2, u
"" );
528 // Do not cache/reuse a repeat-filled string, column
529 // widths or fonts or sizes may differ.
539 if (aString
.getLength() > DRAWTEXT_MAX
)
540 aString
= aString
.copy(0, DRAWTEXT_MAX
);
542 if ( pColor
&& !pOutput
->mbSyntaxMode
&& !( pOutput
->mbUseStyleColor
&& pOutput
->mbForceAutoColor
) )
544 OutputDevice
* pDev
= pOutput
->mpDev
;
545 aFont
.SetColor(*pColor
);
546 pDev
->SetFont( aFont
); // only for output
548 maLastCell
.clear(); // next time return here again
553 // otherwise keep string/size
559 aTextSize
= Size(0,0);
566 void ScDrawStringsVars::SetHashText()
568 SetAutoText(u
"###"_ustr
);
571 void ScDrawStringsVars::RepeatToFill( tools::Long nColWidth
)
573 if ( nRepeatPos
== -1 || nRepeatPos
> aString
.getLength() )
576 // Measuring a string containing a single copy of the repeat char is inaccurate.
577 // To increase accuracy, start with a representative sample of a padding sequence.
578 constexpr sal_Int32 nSampleSize
= 20;
579 OUStringBuffer
aFill(nSampleSize
);
580 comphelper::string::padToLength(aFill
, nSampleSize
, nRepeatChar
);
582 tools::Long nSampleWidth
= GetFmtTextWidth(aFill
.makeStringAndClear());
583 double nAvgCharWidth
= static_cast<double>(nSampleWidth
) / static_cast<double>(nSampleSize
);
585 // Intentionally truncate to round toward zero
586 auto nCharWidth
= static_cast<tools::Long
>(nAvgCharWidth
);
587 if ( nCharWidth
< 1 || (bPixelToLogic
&& nCharWidth
< pOutput
->mpRefDevice
->PixelToLogic(Size(1,0)).Width()) )
590 // Are there restrictions on the cell type we should filter out here ?
591 tools::Long nTextWidth
= aTextSize
.Width();
594 nColWidth
= pOutput
->mpRefDevice
->PixelToLogic(Size(nColWidth
,0)).Width();
595 nTextWidth
= pOutput
->mpRefDevice
->PixelToLogic(Size(nTextWidth
,0)).Width();
598 tools::Long nSpaceToFill
= nColWidth
- nTextWidth
;
599 if ( nSpaceToFill
<= nCharWidth
)
602 // Intentionally truncate to round toward zero
603 auto nCharsToInsert
= static_cast<sal_Int32
>(static_cast<double>(nSpaceToFill
) / nAvgCharWidth
);
604 aFill
.ensureCapacity(nCharsToInsert
);
605 comphelper::string::padToLength(aFill
, nCharsToInsert
, nRepeatChar
);
606 aString
= aString
.replaceAt( nRepeatPos
, 0, aFill
);
610 bool ScDrawStringsVars::SetTextToWidthOrHash( ScRefCellValue
& rCell
, tools::Long nWidth
)
612 // #i113045# do the single-character width calculations in logic units
614 nWidth
= pOutput
->mpRefDevice
->PixelToLogic(Size(nWidth
,0)).Width();
616 CellType eType
= rCell
.getType();
617 if (eType
!= CELLTYPE_VALUE
&& eType
!= CELLTYPE_FORMULA
)
618 // must be a value or formula cell.
621 if (eType
== CELLTYPE_FORMULA
)
623 ScFormulaCell
* pFCell
= rCell
.getFormula();
624 if (pFCell
->GetErrCode() != FormulaError::NONE
|| pOutput
->mbShowFormulas
)
626 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
629 // If it's formula, the result must be a value.
630 if (!pFCell
->IsValue())
634 sal_uLong nFormat
= GetResultValueFormat();
635 if ((nFormat
% SV_COUNTRY_LANGUAGE_OFFSET
) != 0)
637 // Not 'General' number format. Set hash text and bail out.
642 double fVal
= rCell
.getValue();
644 const SvNumberformat
* pNumFormat
= pOutput
->mpDoc
->GetFormatTable()->GetEntry(nFormat
);
648 tools::Long nMaxDigit
= GetMaxDigitWidth();
652 sal_uInt16 nNumDigits
= static_cast<sal_uInt16
>(nWidth
/ nMaxDigit
);
654 OUString
sTempOut(aString
);
655 if (!pNumFormat
->GetOutputString(fVal
, nNumDigits
, sTempOut
, pOutput
->mpDoc
->GetFormatTable()->GetNatNum()))
658 // Failed to get output string. Bail out.
663 sal_uInt8 nSignCount
= 0, nDecimalCount
= 0, nExpCount
= 0;
664 sal_Int32 nLen
= aString
.getLength();
665 sal_Unicode cDecSep
= ScGlobal::getLocaleData().getLocaleItem().decimalSeparator
[0];
666 for( sal_Int32 i
= 0; i
< nLen
; ++i
)
668 sal_Unicode c
= aString
[i
];
671 else if (c
== cDecSep
)
677 // #i112250# A small value might be formatted as "0" when only counting the digits,
678 // but fit into the column when considering the smaller width of the decimal separator.
679 if (aString
== "0" && fVal
!= 0.0)
683 nWidth
+= (nMaxDigit
- GetDotWidth()) * nDecimalCount
;
685 nWidth
+= (nMaxDigit
- GetSignWidth()) * nSignCount
;
687 nWidth
+= (nMaxDigit
- GetExpWidth()) * nExpCount
;
689 if (nDecimalCount
|| nSignCount
|| nExpCount
)
692 nNumDigits
= static_cast<sal_uInt16
>(nWidth
/ nMaxDigit
);
693 OUString
sTempOut(aString
);
694 if (!pNumFormat
->GetOutputString(fVal
, nNumDigits
, sTempOut
, pOutput
->mpDoc
->GetFormatTable()->GetNatNum()))
697 // Failed to get output string. Bail out.
703 tools::Long nActualTextWidth
= GetFmtTextWidth(aString
);
704 if (nActualTextWidth
> nWidth
)
706 // Even after the decimal adjustment the text doesn't fit. Give up.
712 maLastCell
.clear(); // #i113022# equal cell and format in another column may give different string
716 void ScDrawStringsVars::SetAutoText( const OUString
& rAutoText
)
720 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
721 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
722 aTextSize
.setWidth( GetFmtTextWidth( aString
) );
723 aTextSize
.setHeight( pFmtDevice
->GetTextHeight() );
725 if ( !pRefDevice
->GetConnectMetaFile() || pRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
727 double fMul
= pOutput
->GetStretch();
728 aTextSize
.setWidth( static_cast<tools::Long
>(aTextSize
.Width() / fMul
+ 0.5) );
731 aTextSize
.setHeight( aMetric
.GetAscent() + aMetric
.GetDescent() );
732 if ( GetOrient() != SvxCellOrientation::Standard
)
734 tools::Long nTemp
= aTextSize
.Height();
735 aTextSize
.setHeight( aTextSize
.Width() );
736 aTextSize
.setWidth( nTemp
);
739 nOriginalWidth
= aTextSize
.Width();
741 aTextSize
= pRefDevice
->LogicToPixel( aTextSize
);
743 maLastCell
.clear(); // the same text may fit in the next cell
746 tools::Long
ScDrawStringsVars::GetMaxDigitWidth()
748 if (nMaxDigitWidth
> 0)
749 return nMaxDigitWidth
;
751 for (char i
= 0; i
< 10; ++i
)
753 char cDigit
= '0' + i
;
754 // Do not cache this with GetFmtTextWidth(), nMaxDigitWidth is already cached.
755 tools::Long n
= pOutput
->pFmtDevice
->GetTextWidth(OUString(cDigit
));
756 nMaxDigitWidth
= ::std::max(nMaxDigitWidth
, n
);
758 return nMaxDigitWidth
;
761 tools::Long
ScDrawStringsVars::GetSignWidth()
766 nSignWidth
= pOutput
->pFmtDevice
->GetTextWidth(OUString('-'));
770 tools::Long
ScDrawStringsVars::GetDotWidth()
775 const OUString
& sep
= ScGlobal::getLocaleData().getLocaleItem().decimalSeparator
;
776 nDotWidth
= pOutput
->pFmtDevice
->GetTextWidth(sep
);
780 tools::Long
ScDrawStringsVars::GetExpWidth()
785 nExpWidth
= pOutput
->pFmtDevice
->GetTextWidth(OUString('E'));
789 tools::Long
ScDrawStringsVars::GetFmtTextWidth( const OUString
& rString
)
791 return pOutput
->pFmtDevice
->GetTextWidth( rString
, 0, -1, nullptr, GetLayoutGlyphs( rString
));
794 void ScDrawStringsVars::TextChanged()
796 OutputDevice
* pRefDevice
= pOutput
->mpRefDevice
;
797 OutputDevice
* pFmtDevice
= pOutput
->pFmtDevice
;
798 aTextSize
.setWidth( GetFmtTextWidth( aString
) );
799 aTextSize
.setHeight( pFmtDevice
->GetTextHeight() );
801 if ( !pRefDevice
->GetConnectMetaFile() || pRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
803 double fMul
= pOutput
->GetStretch();
804 aTextSize
.setWidth( static_cast<tools::Long
>(aTextSize
.Width() / fMul
+ 0.5) );
807 aTextSize
.setHeight( aMetric
.GetAscent() + aMetric
.GetDescent() );
808 if ( GetOrient() != SvxCellOrientation::Standard
)
810 tools::Long nTemp
= aTextSize
.Height();
811 aTextSize
.setHeight( aTextSize
.Width() );
812 aTextSize
.setWidth( nTemp
);
815 nOriginalWidth
= aTextSize
.Width();
817 aTextSize
= pRefDevice
->LogicToPixel( aTextSize
);
820 bool ScDrawStringsVars::HasEditCharacters() const
822 for (sal_Int32 nIdx
= 0; nIdx
< aString
.getLength(); ++nIdx
)
824 switch(aString
[nIdx
])
827 // tdf#122676: Ignore CHAR_NBSP (this is thousand separator in any number)
828 // if repeat character is set
847 double ScOutputData::GetStretch() const
849 if ( mpRefDevice
->IsMapModeEnabled() )
851 // If a non-trivial MapMode is set, its scale is now already
852 // taken into account in the OutputDevice's font handling
853 // (OutputDevice::ImplNewFont, see #95414#).
854 // The old handling below is only needed for pixel output.
858 // calculation in double is faster than Fraction multiplication
859 // and doesn't overflow
861 if ( mpRefDevice
== pFmtDevice
)
863 MapMode aOld
= mpRefDevice
->GetMapMode();
864 return static_cast<double>(aOld
.GetScaleY()) / static_cast<double>(aOld
.GetScaleX()) * static_cast<double>(aZoomY
) / static_cast<double>(aZoomX
);
868 // when formatting for printer, device map mode has already been taken care of
869 return static_cast<double>(aZoomY
) / static_cast<double>(aZoomX
);
875 static void lcl_DoHyperlinkResult( const OutputDevice
* pDev
, const tools::Rectangle
& rRect
, ScRefCellValue
& rCell
)
877 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast< vcl::PDFExtOutDevData
* >( pDev
->GetExtOutDevData() );
881 if (rCell
.getType() == CELLTYPE_FORMULA
)
883 ScFormulaCell
* pFCell
= rCell
.getFormula();
884 if ( pFCell
->IsHyperLinkCell() )
885 pFCell
->GetURLResult( aURL
, aCellText
);
888 if ( !aURL
.isEmpty() && pPDFData
)
890 vcl::PDFExtOutDevBookmarkEntry aBookmark
;
891 aBookmark
.nLinkId
= pPDFData
->CreateLink(rRect
, aCellText
);
892 aBookmark
.aBookmark
= aURL
;
893 std::vector
< vcl::PDFExtOutDevBookmarkEntry
>& rBookmarks
= pPDFData
->GetBookmarks();
894 rBookmarks
.push_back( aBookmark
);
898 void ScOutputData::SetSyntaxColor( vcl::Font
* pFont
, const ScRefCellValue
& rCell
)
900 switch (rCell
.getType())
903 pFont
->SetColor(*mxValueColor
);
905 case CELLTYPE_STRING
:
906 pFont
->SetColor(*mxTextColor
);
908 case CELLTYPE_FORMULA
:
909 pFont
->SetColor(*mxFormulaColor
);
913 // added to avoid warnings
918 static void lcl_SetEditColor( EditEngine
& rEngine
, const Color
& rColor
)
920 ESelection
aSel( 0, 0, rEngine
.GetParagraphCount(), 0 );
921 SfxItemSet
aSet( rEngine
.GetEmptyItemSet() );
922 aSet
.Put( SvxColorItem( rColor
, EE_CHAR_COLOR
) );
923 rEngine
.QuickSetAttribs( aSet
, aSel
);
924 // function is called with update mode set to FALSE
927 void ScOutputData::SetEditSyntaxColor( EditEngine
& rEngine
, const ScRefCellValue
& rCell
)
930 switch (rCell
.getType())
933 aColor
= *mxValueColor
;
935 case CELLTYPE_STRING
:
937 aColor
= *mxTextColor
;
939 case CELLTYPE_FORMULA
:
940 aColor
= *mxFormulaColor
;
944 // added to avoid warnings
947 lcl_SetEditColor( rEngine
, aColor
);
950 bool ScOutputData::GetMergeOrigin( SCCOL nX
, SCROW nY
, SCSIZE nArrY
,
951 SCCOL
& rOverX
, SCROW
& rOverY
,
952 bool bVisRowChanged
)
954 bool bDoMerge
= false;
955 bool bIsLeft
= ( nX
== nVisX1
);
956 bool bIsTop
= ( nY
== nVisY1
) || bVisRowChanged
;
962 if (!mpDoc
->ColHidden(nX
, nTab
) && nX
>= nX1
&& nX
<= nX2
963 && !mpDoc
->RowHidden(nY
, nTab
) && nY
>= nY1
&& nY
<= nY2
)
965 ScCellInfo
* pInfo
= &pRowInfo
[nArrY
].cellInfo(nX
);
966 bHOver
= pInfo
->bHOverlapped
;
967 bVOver
= pInfo
->bVOverlapped
;
971 ScMF nOverlap2
= mpDoc
->GetAttr(nX
, nY
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
972 bHOver
= bool(nOverlap2
& ScMF::Hor
);
973 bVOver
= bool(nOverlap2
& ScMF::Ver
);
976 if ( bHOver
&& bVOver
)
977 bDoMerge
= bIsLeft
&& bIsTop
;
986 while (bHOver
) // nY constant
989 bHidden
= mpDoc
->ColHidden(rOverX
, nTab
);
990 if ( !bDoMerge
&& !bHidden
)
993 if (rOverX
>= nX1
&& !bHidden
)
995 bHOver
= pRowInfo
[nArrY
].cellInfo(rOverX
).bHOverlapped
;
996 bVOver
= pRowInfo
[nArrY
].cellInfo(rOverX
).bVOverlapped
;
1000 ScMF nOverlap
= mpDoc
->GetAttr(rOverX
, rOverY
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
1001 bHOver
= bool(nOverlap
& ScMF::Hor
);
1002 bVOver
= bool(nOverlap
& ScMF::Ver
);
1009 bHidden
= mpDoc
->RowHidden(rOverY
, nTab
);
1010 if ( !bDoMerge
&& !bHidden
)
1014 --nArrY
; // local copy !
1016 if (rOverX
>= nX1
&& rOverY
>= nY1
&&
1017 !mpDoc
->ColHidden(rOverX
, nTab
) &&
1018 !mpDoc
->RowHidden(rOverY
, nTab
) &&
1019 pRowInfo
[nArrY
].nRowNo
== rOverY
)
1021 bVOver
= pRowInfo
[nArrY
].cellInfo(rOverX
).bVOverlapped
;
1025 ScMF nOverlap
= mpDoc
->GetAttr( rOverX
, rOverY
, nTab
, ATTR_MERGE_FLAG
)->GetValue();
1026 bVOver
= bool(nOverlap
& ScMF::Ver
);
1033 static bool StringDiffer( const ScPatternAttr
*& rpOldPattern
, const ScPatternAttr
* pNewPattern
)
1035 assert(pNewPattern
&& "pNewPattern");
1037 if ( ScPatternAttr::areSame( pNewPattern
, rpOldPattern
) )
1039 else if ( !rpOldPattern
)
1041 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT
), rpOldPattern
->GetItem( ATTR_FONT
) ) )
1043 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CJK_FONT
), rpOldPattern
->GetItem( ATTR_CJK_FONT
) ) )
1045 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CTL_FONT
), rpOldPattern
->GetItem( ATTR_CTL_FONT
) ) )
1047 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_HEIGHT
), rpOldPattern
->GetItem( ATTR_FONT_HEIGHT
) ) )
1049 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CJK_FONT_HEIGHT
), rpOldPattern
->GetItem( ATTR_CJK_FONT_HEIGHT
) ) )
1051 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CTL_FONT_HEIGHT
), rpOldPattern
->GetItem( ATTR_CTL_FONT_HEIGHT
) ) )
1053 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_WEIGHT
), rpOldPattern
->GetItem( ATTR_FONT_WEIGHT
) ) )
1055 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CJK_FONT_WEIGHT
), rpOldPattern
->GetItem( ATTR_CJK_FONT_WEIGHT
) ) )
1057 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CTL_FONT_WEIGHT
), rpOldPattern
->GetItem( ATTR_CTL_FONT_WEIGHT
) ) )
1059 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_POSTURE
), rpOldPattern
->GetItem( ATTR_FONT_POSTURE
) ) )
1061 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CJK_FONT_POSTURE
), rpOldPattern
->GetItem( ATTR_CJK_FONT_POSTURE
) ) )
1063 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_CTL_FONT_POSTURE
), rpOldPattern
->GetItem( ATTR_CTL_FONT_POSTURE
) ) )
1065 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_UNDERLINE
), rpOldPattern
->GetItem( ATTR_FONT_UNDERLINE
) ) )
1067 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_OVERLINE
), rpOldPattern
->GetItem( ATTR_FONT_OVERLINE
) ) )
1069 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_WORDLINE
), rpOldPattern
->GetItem( ATTR_FONT_WORDLINE
) ) )
1071 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_CROSSEDOUT
), rpOldPattern
->GetItem( ATTR_FONT_CROSSEDOUT
) ) )
1073 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_CONTOUR
), rpOldPattern
->GetItem( ATTR_FONT_CONTOUR
) ) )
1075 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_SHADOWED
), rpOldPattern
->GetItem( ATTR_FONT_SHADOWED
) ) )
1077 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_COLOR
), rpOldPattern
->GetItem( ATTR_FONT_COLOR
) ) )
1079 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_HOR_JUSTIFY
), rpOldPattern
->GetItem( ATTR_HOR_JUSTIFY
) ) )
1081 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_HOR_JUSTIFY_METHOD
), rpOldPattern
->GetItem( ATTR_HOR_JUSTIFY_METHOD
) ) )
1083 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_VER_JUSTIFY
), rpOldPattern
->GetItem( ATTR_VER_JUSTIFY
) ) )
1085 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_VER_JUSTIFY_METHOD
), rpOldPattern
->GetItem( ATTR_VER_JUSTIFY_METHOD
) ) )
1087 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_STACKED
), rpOldPattern
->GetItem( ATTR_STACKED
) ) )
1089 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_LINEBREAK
), rpOldPattern
->GetItem( ATTR_LINEBREAK
) ) )
1091 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_MARGIN
), rpOldPattern
->GetItem( ATTR_MARGIN
) ) )
1093 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_ROTATE_VALUE
), rpOldPattern
->GetItem( ATTR_ROTATE_VALUE
) ) )
1095 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FORBIDDEN_RULES
), rpOldPattern
->GetItem( ATTR_FORBIDDEN_RULES
) ) )
1097 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_EMPHASISMARK
), rpOldPattern
->GetItem( ATTR_FONT_EMPHASISMARK
) ) )
1099 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_FONT_RELIEF
), rpOldPattern
->GetItem( ATTR_FONT_RELIEF
) ) )
1101 else if ( !SfxPoolItem::areSame( pNewPattern
->GetItem( ATTR_BACKGROUND
), rpOldPattern
->GetItem( ATTR_BACKGROUND
) ) )
1102 return true; // needed with automatic text color
1105 rpOldPattern
= pNewPattern
;
1110 static void lcl_CreateInterpretProgress( bool& bProgress
, ScDocument
* pDoc
,
1111 const ScFormulaCell
* pFCell
)
1113 if ( !bProgress
&& pFCell
->GetDirty() )
1115 ScProgress::CreateInterpretProgress( pDoc
);
1120 static bool IsAmbiguousScript( SvtScriptType nScript
)
1122 return ( nScript
!= SvtScriptType::LATIN
&&
1123 nScript
!= SvtScriptType::ASIAN
&&
1124 nScript
!= SvtScriptType::COMPLEX
);
1127 bool ScOutputData::IsEmptyCellText( const RowInfo
* pThisRowInfo
, SCCOL nX
, SCROW nY
)
1129 // pThisRowInfo may be NULL
1132 if ( pThisRowInfo
&& nX
<= nX2
)
1133 bEmpty
= pThisRowInfo
->basicCellInfo(nX
).bEmptyCellText
;
1136 ScRefCellValue
aCell(*mpDoc
, ScAddress(nX
, nY
, nTab
));
1137 bEmpty
= aCell
.isEmpty();
1140 if ( !bEmpty
&& ( nX
< nX1
|| nX
> nX2
|| !pThisRowInfo
) )
1142 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1143 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1145 bool bIsPrint
= ( eType
== OUTTYPE_PRINTER
);
1147 if ( bIsPrint
|| bTabProtected
)
1149 const ScProtectionAttr
* pAttr
=
1150 mpDoc
->GetEffItem( nX
, nY
, nTab
, ATTR_PROTECTION
);
1151 if ( bIsPrint
&& pAttr
->GetHidePrint() )
1153 else if ( bTabProtected
)
1155 if ( pAttr
->GetHideCell() )
1157 else if ( mbShowFormulas
&& pAttr
->GetHideFormula() )
1159 if (mpDoc
->GetCellType(ScAddress(nX
, nY
, nTab
)) == CELLTYPE_FORMULA
)
1168 void ScOutputData::GetVisibleCell( SCCOL nCol
, SCROW nRow
, SCTAB nTabP
, ScRefCellValue
& rCell
)
1170 rCell
.assign(*mpDoc
, ScAddress(nCol
, nRow
, nTabP
));
1171 if (!rCell
.isEmpty() && IsEmptyCellText(nullptr, nCol
, nRow
))
1175 bool ScOutputData::IsAvailable( SCCOL nX
, SCROW nY
)
1177 // apply the same logic here as in DrawStrings/DrawEdit:
1178 // Stop at non-empty or merged or overlapped cell,
1179 // where a note is empty as well as a cell that's hidden by protection settings
1181 ScRefCellValue
aCell(*mpDoc
, ScAddress(nX
, nY
, nTab
));
1182 if (!aCell
.isEmpty() && !IsEmptyCellText(nullptr, nX
, nY
))
1185 const ScPatternAttr
* pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
1186 return !(pPattern
->GetItem(ATTR_MERGE
).IsMerged() ||
1187 pPattern
->GetItem(ATTR_MERGE_FLAG
).IsOverlapped());
1190 // nX, nArrY: loop variables from DrawStrings / DrawEdit
1191 // nPosX, nPosY: corresponding positions for nX, nArrY
1192 // nCellX, nCellY: position of the cell that contains the text
1193 // nNeeded: Text width, including margin
1194 // rPattern: cell format at nCellX, nCellY
1195 // nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1196 // bCellIsValue: if set, don't extend into empty cells
1197 // bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1198 // bOverwrite: if set, also extend into non-empty cells (for rotated text)
1199 // rParam output: various area parameters.
1201 void ScOutputData::GetOutputArea( SCCOL nX
, SCSIZE nArrY
, tools::Long nPosX
, tools::Long nPosY
,
1202 SCCOL nCellX
, SCROW nCellY
, tools::Long nNeeded
,
1203 const ScPatternAttr
& rPattern
,
1204 sal_uInt16 nHorJustify
, bool bCellIsValue
,
1205 bool bBreak
, bool bOverwrite
,
1206 OutputAreaParam
& rParam
)
1208 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1209 RowInfo
& rThisRowInfo
= pRowInfo
[nArrY
];
1211 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1213 tools::Long nCellPosX
= nPosX
; // find nCellX position, starting at nX/nPosX
1214 SCCOL nCompCol
= nX
;
1215 while ( nCellX
> nCompCol
)
1217 //! extra member function for width?
1218 tools::Long nColWidth
= ( nCompCol
<= nX2
) ?
1219 pRowInfo
[0].basicCellInfo(nCompCol
).nWidth
:
1220 static_cast<tools::Long
>( mpDoc
->GetColWidth( nCompCol
, nTab
) * mnPPTX
);
1221 nCellPosX
+= nColWidth
* nLayoutSign
;
1224 while ( nCellX
< nCompCol
)
1227 tools::Long nColWidth
= ( nCompCol
<= nX2
) ?
1228 pRowInfo
[0].basicCellInfo(nCompCol
).nWidth
:
1229 static_cast<tools::Long
>( mpDoc
->GetColWidth( nCompCol
, nTab
) * mnPPTX
);
1230 nCellPosX
-= nColWidth
* nLayoutSign
;
1233 tools::Long nCellPosY
= nPosY
; // find nCellY position, starting at nArrY/nPosY
1234 SCSIZE nCompArr
= nArrY
;
1235 SCROW nCompRow
= pRowInfo
[nCompArr
].nRowNo
;
1236 while ( nCellY
> nCompRow
)
1238 if ( nCompArr
+ 1 < nArrCount
)
1240 nCellPosY
+= pRowInfo
[nCompArr
].nHeight
;
1242 nCompRow
= pRowInfo
[nCompArr
].nRowNo
;
1246 sal_uInt16 nDocHeight
= mpDoc
->GetRowHeight( nCompRow
, nTab
);
1248 nCellPosY
+= static_cast<tools::Long
>( nDocHeight
* mnPPTY
);
1252 nCellPosY
-= mpDoc
->GetScaledRowHeight( nCellY
, nCompRow
-1, nTab
, mnPPTY
);
1254 const ScMergeAttr
* pMerge
= &rPattern
.GetItem( ATTR_MERGE
);
1255 bool bMerged
= pMerge
->IsMerged();
1256 tools::Long nMergeCols
= pMerge
->GetColMerge();
1257 if ( nMergeCols
== 0 )
1259 tools::Long nMergeRows
= pMerge
->GetRowMerge();
1260 if ( nMergeRows
== 0 )
1263 tools::Long nMergeSizeX
= 0;
1264 for ( tools::Long i
=0; i
<nMergeCols
; i
++ )
1266 tools::Long nColWidth
= ( nCellX
+i
<= nX2
) ?
1267 pRowInfo
[0].basicCellInfo(nCellX
+i
).nWidth
:
1268 static_cast<tools::Long
>( mpDoc
->GetColWidth( sal::static_int_cast
<SCCOL
>(nCellX
+i
), nTab
) * mnPPTX
);
1269 nMergeSizeX
+= nColWidth
;
1271 tools::Long nMergeSizeY
= 0;
1273 if ( rThisRowInfo
.nRowNo
== nCellY
)
1275 // take first row's height from row info
1276 nMergeSizeY
+= rThisRowInfo
.nHeight
;
1277 nDirect
= 1; // skip in loop
1279 // following rows always from document
1280 nMergeSizeY
+= mpDoc
->GetScaledRowHeight( nCellY
+nDirect
, nCellY
+nMergeRows
-1, nTab
, mnPPTY
);
1282 --nMergeSizeX
; // leave out the grid horizontally, also for alignment (align between grid lines)
1284 rParam
.mnColWidth
= nMergeSizeX
; // store the actual column width.
1285 rParam
.mnLeftClipLength
= rParam
.mnRightClipLength
= 0;
1287 // construct the rectangles using logical left/right values (justify is called at the end)
1289 // rAlignRect is the single cell or merged area, used for alignment.
1291 rParam
.maAlignRect
.SetLeft( nCellPosX
);
1292 rParam
.maAlignRect
.SetRight( nCellPosX
+ ( nMergeSizeX
- 1 ) * nLayoutSign
);
1293 rParam
.maAlignRect
.SetTop( nCellPosY
);
1294 rParam
.maAlignRect
.SetBottom( nCellPosY
+ nMergeSizeY
- 1 );
1296 // rClipRect is all cells that are used for output.
1297 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1299 rParam
.maClipRect
= rParam
.maAlignRect
;
1300 if ( nNeeded
> nMergeSizeX
)
1302 SvxCellHorJustify eHorJust
= static_cast<SvxCellHorJustify
>(nHorJustify
);
1304 tools::Long nMissing
= nNeeded
- nMergeSizeX
;
1305 tools::Long nLeftMissing
= 0;
1306 tools::Long nRightMissing
= 0;
1309 case SvxCellHorJustify::Left
:
1310 nRightMissing
= nMissing
;
1312 case SvxCellHorJustify::Right
:
1313 nLeftMissing
= nMissing
;
1315 case SvxCellHorJustify::Center
:
1316 nLeftMissing
= nMissing
/ 2;
1317 nRightMissing
= nMissing
- nLeftMissing
;
1321 // added to avoid warnings
1325 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1327 ::std::swap( nLeftMissing
, nRightMissing
);
1329 SCCOL nRightX
= nCellX
;
1330 SCCOL nLeftX
= nCellX
;
1331 if ( !bMerged
&& !bCellIsValue
&& !bBreak
)
1333 // look for empty cells into which the text can be extended
1335 while ( nRightMissing
> 0 && nRightX
< mpDoc
->MaxCol() && ( bOverwrite
|| IsAvailable( nRightX
+1, nCellY
) ) )
1338 tools::Long nAdd
= static_cast<tools::Long
>( mpDoc
->GetColWidth( nRightX
, nTab
) * mnPPTX
);
1339 nRightMissing
-= nAdd
;
1340 rParam
.maClipRect
.AdjustRight(nAdd
* nLayoutSign
);
1342 if ( rThisRowInfo
.nRowNo
== nCellY
&& nRightX
>= nX1
&& nRightX
<= nX2
)
1343 rThisRowInfo
.cellInfo(nRightX
-1).bHideGrid
= true;
1346 while ( nLeftMissing
> 0 && nLeftX
> 0 && ( bOverwrite
|| IsAvailable( nLeftX
-1, nCellY
) ) )
1348 if ( rThisRowInfo
.nRowNo
== nCellY
&& nLeftX
>= nX1
&& nLeftX
<= nX2
)
1349 rThisRowInfo
.cellInfo(nLeftX
-1).bHideGrid
= true;
1352 tools::Long nAdd
= static_cast<tools::Long
>( mpDoc
->GetColWidth( nLeftX
, nTab
) * mnPPTX
);
1353 nLeftMissing
-= nAdd
;
1354 rParam
.maClipRect
.AdjustLeft( -(nAdd
* nLayoutSign
) );
1358 // Set flag and reserve space for clipping mark triangle,
1359 // even if rThisRowInfo isn't for nCellY (merged cells).
1360 if ( nRightMissing
> 0 && bMarkClipped
&& nRightX
>= nX1
&& nRightX
<= nX2
&& !bBreak
&& !bCellIsValue
)
1362 rThisRowInfo
.cellInfo(nRightX
).nClipMark
|= ScClipMark::Right
;
1364 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
1365 rParam
.maClipRect
.AdjustRight( -(nMarkPixel
* nLayoutSign
) );
1367 if ( nLeftMissing
> 0 && bMarkClipped
&& nLeftX
>= nX1
&& nLeftX
<= nX2
&& !bBreak
&& !bCellIsValue
)
1369 rThisRowInfo
.cellInfo(nLeftX
).nClipMark
|= ScClipMark::Left
;
1371 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
1372 rParam
.maClipRect
.AdjustLeft(nMarkPixel
* nLayoutSign
);
1375 rParam
.mbLeftClip
= ( nLeftMissing
> 0 );
1376 rParam
.mbRightClip
= ( nRightMissing
> 0 );
1377 rParam
.mnLeftClipLength
= nLeftMissing
;
1378 rParam
.mnRightClipLength
= nRightMissing
;
1382 rParam
.mbLeftClip
= rParam
.mbRightClip
= false;
1384 // leave space for AutoFilter on screen
1385 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1387 if ( eType
==OUTTYPE_WINDOW
&&
1388 ( rPattern
.GetItem(ATTR_MERGE_FLAG
).GetValue() & (ScMF::Auto
|ScMF::Button
|ScMF::ButtonPopup
) ) &&
1389 ( !bBreak
|| mpRefDevice
== pFmtDevice
) )
1391 // filter drop-down width depends on row height
1392 double fZoom
= mpRefDevice
? static_cast<double>(mpRefDevice
->GetMapMode().GetScaleY()) : 1.0;
1393 fZoom
= fZoom
> 1.0 ? fZoom
: 1.0;
1394 const tools::Long nFilter
= fZoom
* DROPDOWN_BITMAP_SIZE
;
1395 bool bFit
= ( nNeeded
+ nFilter
<= nMergeSizeX
);
1398 // content fits even in the remaining area without the filter button
1399 // -> align within that remaining area
1401 rParam
.maAlignRect
.AdjustRight( -(nFilter
* nLayoutSign
) );
1402 rParam
.maClipRect
.AdjustRight( -(nFilter
* nLayoutSign
) );
1407 // justify both rectangles for alignment calculation, use with DrawText etc.
1409 rParam
.maAlignRect
.Normalize();
1410 rParam
.maClipRect
.Normalize();
1415 bool beginsWithRTLCharacter(const OUString
& rStr
)
1420 switch (ScGlobal::getCharClass().getCharacterDirection(rStr
, 0))
1422 case i18n::DirectionProperty_RIGHT_TO_LEFT
:
1423 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC
:
1424 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING
:
1425 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE
:
1436 /** Get left, right or centered alignment from RTL context.
1438 Does not return standard, block or repeat, for these the contextual left or
1439 right alignment is returned.
1441 static SvxCellHorJustify
getAlignmentFromContext( SvxCellHorJustify eInHorJust
,
1442 bool bCellIsValue
, const OUString
& rText
,
1443 const ScPatternAttr
& rPattern
, const SfxItemSet
* pCondSet
,
1444 const ScDocument
* pDoc
, SCTAB nTab
, const bool bNumberFormatIsText
)
1446 SvxCellHorJustify eHorJustContext
= eInHorJust
;
1447 bool bUseWritingDirection
= false;
1448 if (eInHorJust
== SvxCellHorJustify::Standard
)
1450 // fdo#32530: Default alignment depends on value vs
1451 // string, and the direction of the 1st letter.
1452 if (beginsWithRTLCharacter( rText
)) //If language is RTL
1455 eHorJustContext
= bNumberFormatIsText
? SvxCellHorJustify::Right
: SvxCellHorJustify::Left
;
1457 eHorJustContext
= SvxCellHorJustify::Right
;
1459 else if (bCellIsValue
) //If language is not RTL
1460 eHorJustContext
= bNumberFormatIsText
? SvxCellHorJustify::Left
: SvxCellHorJustify::Right
;
1462 bUseWritingDirection
= true;
1465 if (bUseWritingDirection
||
1466 eInHorJust
== SvxCellHorJustify::Block
|| eInHorJust
== SvxCellHorJustify::Repeat
)
1468 SvxFrameDirection nDirection
= lcl_GetValue
<SvxFrameDirectionItem
, SvxFrameDirection
>(rPattern
, ATTR_WRITINGDIR
, pCondSet
);
1469 if (nDirection
== SvxFrameDirection::Horizontal_LR_TB
|| nDirection
== SvxFrameDirection::Vertical_LR_TB
)
1470 eHorJustContext
= SvxCellHorJustify::Left
;
1471 else if (nDirection
== SvxFrameDirection::Environment
)
1473 SAL_WARN_IF( !pDoc
, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1474 // fdo#73588: The content of the cell must also
1475 // begin with a RTL character to be right
1476 // aligned; otherwise, it should be left aligned.
1477 eHorJustContext
= (pDoc
&& pDoc
->IsLayoutRTL(nTab
) && (beginsWithRTLCharacter( rText
))) ? SvxCellHorJustify::Right
: SvxCellHorJustify::Left
;
1480 eHorJustContext
= SvxCellHorJustify::Right
;
1482 return eHorJustContext
;
1485 void ScOutputData::DrawStrings( bool bPixelToLogic
)
1487 LayoutStrings(bPixelToLogic
);
1490 void ScOutputData::LayoutStrings(bool bPixelToLogic
)
1492 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
1493 bool bTaggedPDF
= pPDF
&& pPDF
->GetIsExportTaggedPDF();
1496 bool bReopenTag
= ReopenPDFStructureElement(vcl::PDFWriter::Table
);
1499 sal_Int32 nId
= pPDF
->EnsureStructureElement(nullptr);
1500 pPDF
->InitStructureElement(nId
, vcl::PDFWriter::Table
, u
"Table"_ustr
);
1501 pPDF
->BeginStructureElement(nId
);
1502 pPDF
->GetScPDFState()->m_TableId
= nId
;
1506 bool bOrigIsInLayoutStrings
= mpDoc
->IsInLayoutStrings();
1507 mpDoc
->SetLayoutStrings(true);
1508 OSL_ENSURE( mpDev
== mpRefDevice
||
1509 mpDev
->GetMapMode().GetMapUnit() == mpRefDevice
->GetMapMode().GetMapUnit(),
1510 "LayoutStrings: different MapUnits ?!?!" );
1511 vcl::text::ComplexTextLayoutFlags eTextLayout
= mpDev
->GetLayoutMode();
1512 mpDev
->SetLayoutMode(vcl::text::ComplexTextLayoutFlags::Default
);
1514 comphelper::ScopeGuard
g([this, bOrigIsInLayoutStrings
, eTextLayout
] {
1515 mpDoc
->SetLayoutStrings(bOrigIsInLayoutStrings
);
1516 mpDev
->SetLayoutMode(eTextLayout
);
1519 sc::IdleSwitch
aIdleSwitch(*mpDoc
, false);
1521 // Try to limit interpreting to only visible cells. Calling e.g. IsValue()
1522 // on a formula cell that needs interpreting would call Interpret()
1523 // for the entire formula group, which could be large.
1524 mpDoc
->InterpretCellsIfNeeded( ScRange( nX1
, nY1
, nTab
, nX2
, nY2
, nTab
));
1526 ScDrawStringsVars
aVars( this, bPixelToLogic
);
1528 bool bProgress
= false;
1530 tools::Long nInitPosX
= nScrX
;
1532 nInitPosX
+= nMirrorW
- 1; // pixels
1533 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
1535 SCCOL nLastContentCol
= mpDoc
->MaxCol();
1536 if ( nX2
< mpDoc
->MaxCol() )
1539 mpDoc
->GetCellArea(nTab
, nLastContentCol
, nEndRow
);
1542 SCCOL nLoopStartX
= nX1
;
1543 if ( nX1
> 0 && !bTaggedPDF
)
1544 --nLoopStartX
; // start before nX1 for rest of long text to the left
1546 // variables for GetOutputArea
1547 OutputAreaParam aAreaParam
;
1548 bool bCellIsValue
= false;
1549 tools::Long nNeededWidth
= 0;
1550 const ScPatternAttr
* pPattern
= nullptr;
1551 const SfxItemSet
* pCondSet
= nullptr;
1552 const ScPatternAttr
* pOldPattern
= nullptr;
1553 const SfxItemSet
* pOldCondSet
= nullptr;
1554 SvtScriptType nOldScript
= SvtScriptType::NONE
;
1556 // alternative pattern instances in case we need to modify the pattern
1557 // before processing the cell value.
1558 std::vector
<std::unique_ptr
<ScPatternAttr
> > aAltPatterns
;
1561 tools::Long nPosY
= nScrY
;
1562 for (SCSIZE nArrY
=1; nArrY
+1<nArrCount
; nArrY
++)
1564 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
1565 SCROW nY
= pThisRowInfo
->nRowNo
;
1566 if (pThisRowInfo
->bChanged
)
1570 bool bReopenTag
= false;
1571 if (nLoopStartX
!= 0)
1574 = ReopenPDFStructureElement(vcl::PDFWriter::TableRow
, nY
);
1578 sal_Int32 nId
= pPDF
->EnsureStructureElement(nullptr);
1579 pPDF
->InitStructureElement(nId
, vcl::PDFWriter::TableRow
, u
"TR"_ustr
);
1580 pPDF
->BeginStructureElement(nId
);
1581 pPDF
->GetScPDFState()->m_TableRowMap
.emplace(nY
, nId
);
1585 tools::Long nPosX
= nInitPosX
;
1586 if ( nLoopStartX
< nX1
)
1587 nPosX
-= pRowInfo
[0].basicCellInfo(nLoopStartX
).nWidth
* nLayoutSign
;
1588 for (SCCOL nX
=nLoopStartX
; nX
<=nX2
; nX
++)
1591 pPDF
->WrapBeginStructureElement(vcl::PDFWriter::TableData
, u
"TD"_ustr
);
1593 bool bMergeEmpty
= false;
1594 const ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
1595 bool bEmpty
= nX
< nX1
|| pThisRowInfo
->basicCellInfo(nX
).bEmptyCellText
;
1597 SCCOL nCellX
= nX
; // position where the cell really starts
1599 bool bDoCell
= false;
1600 bool bUseEditEngine
= false;
1602 // Part of a merged cell?
1604 bool bOverlapped
= (pInfo
->bHOverlapped
|| pInfo
->bVOverlapped
);
1609 SCCOL nOverX
; // start of the merged cells
1611 bool bVisChanged
= !pRowInfo
[nArrY
-1].bChanged
;
1612 if (GetMergeOrigin( nX
,nY
, nArrY
, nOverX
,nOverY
, bVisChanged
))
1622 // Rest of a long text further to the left?
1624 if ( bEmpty
&& !bMergeEmpty
&& nX
< nX1
&& !bOverlapped
)
1627 while (nTempX
> 0 && IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
1630 if ( nTempX
< nX1
&&
1631 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
1632 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX1
,nY
,nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
) )
1639 // Rest of a long text further to the right?
1641 if ( bEmpty
&& !bMergeEmpty
&& nX
== nX2
&& !bOverlapped
)
1643 // don't have to look further than nLastContentCol
1646 while (nTempX
< nLastContentCol
&& IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
1650 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
1651 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX
,nY
,nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
) )
1658 // normal visible cell
1663 // don't output the cell that's being edited
1665 if ( bDoCell
&& bEditMode
&& nCellX
== nEditCol
&& nCellY
== nEditRow
)
1668 // skip text in cell if data bar/icon set is set and only value selected
1671 if(pInfo
->pDataBar
&& !pInfo
->pDataBar
->mbShowValue
)
1673 if(pInfo
->pIconSet
&& !pInfo
->pIconSet
->mbShowValue
)
1677 // output the cell text
1679 ScRefCellValue aCell
;
1682 if ( nCellY
== nY
&& nCellX
== nX
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1683 aCell
= pThisRowInfo
->cellInfo(nCellX
).maCell
;
1685 GetVisibleCell( nCellX
, nCellY
, nTab
, aCell
); // get from document
1686 if (aCell
.isEmpty())
1688 else if (aCell
.getType() == CELLTYPE_EDIT
)
1689 bUseEditEngine
= true;
1692 // Check if this cell is mis-spelled.
1693 if (bDoCell
&& !bUseEditEngine
&& aCell
.getType() == CELLTYPE_STRING
)
1695 if (mpSpellCheckCxt
&& mpSpellCheckCxt
->isMisspelled(nCellX
, nCellY
))
1696 bUseEditEngine
= true;
1699 if (bDoCell
&& !bUseEditEngine
)
1701 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1703 ScCellInfo
& rCellInfo
= pThisRowInfo
->cellInfo(nCellX
);
1704 pPattern
= rCellInfo
.pPatternAttr
;
1705 pCondSet
= rCellInfo
.pConditionSet
;
1709 // #i68085# pattern from cell info for hidden columns is null,
1710 // test for null is quicker than using column flags
1711 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
1712 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
1715 else // get from document
1717 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
1718 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
1720 if ( mpDoc
->GetPreviewFont() || mpDoc
->GetPreviewCellStyle() )
1722 aAltPatterns
.push_back(std::make_unique
<ScPatternAttr
>(*pPattern
));
1723 ScPatternAttr
* pAltPattern
= aAltPatterns
.back().get();
1724 if ( ScStyleSheet
* pPreviewStyle
= mpDoc
->GetPreviewCellStyle( nCellX
, nCellY
, nTab
) )
1726 pAltPattern
->SetStyleSheet(pPreviewStyle
);
1728 else if ( SfxItemSet
* pFontSet
= mpDoc
->GetPreviewFont( nCellX
, nCellY
, nTab
) )
1730 if ( const SvxFontItem
* pItem
= pFontSet
->GetItemIfSet( ATTR_FONT
) )
1731 pAltPattern
->GetItemSet().Put( *pItem
);
1732 if ( const SvxFontItem
* pItem
= pFontSet
->GetItemIfSet( ATTR_CJK_FONT
) )
1733 pAltPattern
->GetItemSet().Put( *pItem
);
1734 if ( const SvxFontItem
* pItem
= pFontSet
->GetItemIfSet( ATTR_CTL_FONT
) )
1735 pAltPattern
->GetItemSet().Put( *pItem
);
1737 pPattern
= pAltPattern
;
1740 if (aCell
.hasNumeric() &&
1741 pPattern
->GetItem(ATTR_LINEBREAK
, pCondSet
).GetValue())
1743 // Disable line break when the cell content is numeric.
1744 aAltPatterns
.push_back(std::make_unique
<ScPatternAttr
>(*pPattern
));
1745 ScPatternAttr
* pAltPattern
= aAltPatterns
.back().get();
1746 ScLineBreakCell
aLineBreak(false);
1747 pAltPattern
->GetItemSet().Put(aLineBreak
);
1748 pPattern
= pAltPattern
;
1751 SvtScriptType nScript
= mpDoc
->GetCellScriptType(
1752 ScAddress(nCellX
, nCellY
, nTab
),
1753 pPattern
->GetNumberFormat(mpDoc
->GetFormatTable(), pCondSet
));
1755 if (nScript
== SvtScriptType::NONE
)
1756 nScript
= ScGlobal::GetDefaultScriptType();
1758 if ( !ScPatternAttr::areSame(pPattern
, pOldPattern
) || pCondSet
!= pOldCondSet
||
1759 nScript
!= nOldScript
|| mbSyntaxMode
)
1761 if ( StringDiffer(pOldPattern
,pPattern
) ||
1762 pCondSet
!= pOldCondSet
|| nScript
!= nOldScript
|| mbSyntaxMode
)
1764 aVars
.SetPattern(pPattern
, pCondSet
, aCell
, nScript
);
1767 aVars
.SetPatternSimple( pPattern
, pCondSet
);
1768 pOldPattern
= pPattern
;
1769 pOldCondSet
= pCondSet
;
1770 nOldScript
= nScript
;
1773 // use edit engine for rotated, stacked or mixed-script text
1774 if ( aVars
.GetOrient() == SvxCellOrientation::Stacked
||
1775 aVars
.IsRotated() || IsAmbiguousScript(nScript
) )
1776 bUseEditEngine
= true;
1778 if (bDoCell
&& !bUseEditEngine
)
1780 bool bFormulaCell
= (aCell
.getType() == CELLTYPE_FORMULA
);
1782 lcl_CreateInterpretProgress(bProgress
, mpDoc
, aCell
.getFormula());
1783 if ( aVars
.SetText(aCell
) )
1784 pOldPattern
= nullptr;
1785 bUseEditEngine
= aVars
.HasEditCharacters() || (bFormulaCell
&& aCell
.getFormula()->IsMultilineResult());
1787 tools::Long nTotalMargin
= 0;
1788 SvxCellHorJustify eOutHorJust
= SvxCellHorJustify::Standard
;
1789 if (bDoCell
&& !bUseEditEngine
)
1791 CellType eCellType
= aCell
.getType();
1792 bCellIsValue
= ( eCellType
== CELLTYPE_VALUE
);
1793 if ( eCellType
== CELLTYPE_FORMULA
)
1795 ScFormulaCell
* pFCell
= aCell
.getFormula();
1796 bCellIsValue
= pFCell
->IsRunning() || pFCell
->IsValue();
1799 const bool bNumberFormatIsText
= lcl_isNumberFormatText( mpDoc
, nCellX
, nCellY
, nTab
);
1800 eOutHorJust
= getAlignmentFromContext( aVars
.GetHorJust(), bCellIsValue
, aVars
.GetString(),
1801 *pPattern
, pCondSet
, mpDoc
, nTab
, bNumberFormatIsText
);
1803 bool bBreak
= ( aVars
.GetLineBreak() || aVars
.GetHorJust() == SvxCellHorJustify::Block
);
1804 // #i111387# #o11817313# tdf#121040 disable automatic line breaks for all number formats
1805 // Must be synchronized with ScColumn::GetNeededSize()
1806 SvNumberFormatter
* pFormatter
= mpDoc
->GetFormatTable();
1807 if (bBreak
&& bCellIsValue
&& (pFormatter
->GetType(aVars
.GetResultValueFormat()) == SvNumFormatType::NUMBER
))
1810 bool bRepeat
= aVars
.IsRepeat() && !bBreak
;
1811 bool bShrink
= aVars
.IsShrink() && !bBreak
&& !bRepeat
;
1814 static_cast<tools::Long
>(aVars
.GetLeftTotal() * mnPPTX
) +
1815 static_cast<tools::Long
>(aVars
.GetMargin()->GetRightMargin() * mnPPTX
);
1817 nNeededWidth
= aVars
.GetTextSize().Width() + nTotalMargin
;
1819 // GetOutputArea gives justified rectangles
1820 GetOutputArea( nX
, nArrY
, nPosX
, nPosY
, nCellX
, nCellY
, nNeededWidth
,
1821 *pPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
1822 bCellIsValue
|| bRepeat
|| bShrink
, bBreak
, false,
1825 aVars
.RepeatToFill( aAreaParam
.mnColWidth
- nTotalMargin
);
1828 if ( aVars
.GetOrient() != SvxCellOrientation::Standard
)
1830 // Only horizontal scaling is handled here.
1831 // DrawEdit is used to vertically scale 90 deg rotated text.
1832 bUseEditEngine
= true;
1834 else if ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) // horizontal
1836 tools::Long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nTotalMargin
;
1837 tools::Long nScaleSize
= aVars
.GetTextSize().Width(); // without margin
1839 if ( nAvailable
> 0 && nScaleSize
> 0 ) // 0 if the text is empty (formulas, number formats)
1841 tools::Long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
1843 aVars
.SetShrinkScale( nScale
, nOldScript
);
1844 tools::Long nNewSize
= aVars
.GetTextSize().Width();
1846 sal_uInt16 nShrinkAgain
= 0;
1847 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
1849 // If the text is still too large, reduce the scale again by 10%, until it fits,
1850 // at most 7 times (it's less than 50% of the calculated scale then).
1852 nScale
= ( nScale
* 9 ) / 10;
1853 aVars
.SetShrinkScale( nScale
, nOldScript
);
1854 nNewSize
= aVars
.GetTextSize().Width();
1857 // If even at half the size the font still isn't rendered smaller,
1858 // fall back to normal clipping (showing ### for numbers).
1859 if ( nNewSize
<= nAvailable
)
1861 // Reset relevant parameters.
1862 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= false;
1863 aAreaParam
.mnLeftClipLength
= aAreaParam
.mnRightClipLength
= 0;
1866 pOldPattern
= nullptr;
1871 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
)
1873 tools::Long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nTotalMargin
;
1874 tools::Long nRepeatSize
= aVars
.GetTextSize().Width(); // without margin
1875 // When formatting for the printer, the text sizes don't always add up.
1876 // Round down (too few repetitions) rather than exceeding the cell size then:
1877 if ( pFmtDevice
!= mpRefDevice
)
1879 if ( nRepeatSize
> 0 )
1881 tools::Long nRepeatCount
= nAvailable
/ nRepeatSize
;
1882 if ( nRepeatCount
> 1 )
1884 OUString aCellStr
= aVars
.GetString();
1885 OUStringBuffer
aRepeated(aCellStr
);
1886 for ( tools::Long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
1887 aRepeated
.append(aCellStr
);
1888 aVars
.SetAutoText( aRepeated
.makeStringAndClear() );
1893 // use edit engine if automatic line breaks are needed
1896 if ( aVars
.GetOrient() == SvxCellOrientation::Standard
)
1897 bUseEditEngine
= ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
);
1900 tools::Long nHeight
= aVars
.GetTextSize().Height() +
1901 static_cast<tools::Long
>(aVars
.GetMargin()->GetTopMargin()*mnPPTY
) +
1902 static_cast<tools::Long
>(aVars
.GetMargin()->GetBottomMargin()*mnPPTY
);
1903 bUseEditEngine
= ( nHeight
> aAreaParam
.maClipRect
.GetHeight() );
1906 if (!bUseEditEngine
)
1909 aVars
.GetHorJust() == SvxCellHorJustify::Block
&&
1910 aVars
.GetHorJustMethod() == SvxCellJustifyMethod::Distribute
;
1915 // mark the cell in ScCellInfo to be drawn in DrawEdit:
1916 // Cells to the left are marked directly, cells to the
1917 // right are handled by the flag for nX2
1918 SCCOL nMarkX
= ( nCellX
<= nX2
) ? nCellX
: nX2
;
1919 pThisRowInfo
->basicCellInfo(nMarkX
).bEditEngine
= true;
1920 bDoCell
= false; // don't draw here
1922 // Mark the tagged "TD" structure element to be drawn in DrawEdit
1925 sal_Int32 nId
= pPDF
->GetCurrentStructureElement();
1926 pPDF
->GetScPDFState()->m_TableDataMap
[{nY
, nX
}] = nId
;
1931 if ( bCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
1933 bool bHasHashText
= false;
1936 aVars
.SetHashText();
1937 bHasHashText
= true;
1940 // Adjust the decimals to fit the available column width.
1941 bHasHashText
= aVars
.SetTextToWidthOrHash( aCell
, aAreaParam
.mnColWidth
- nTotalMargin
);
1945 tools::Long nMarkPixel
= SC_CLIPMARK_SIZE
* mnPPTX
;
1947 if ( eOutHorJust
== SvxCellHorJustify::Left
)
1949 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1950 pRowInfo
[nArrY
].cellInfo(nCellX
).nClipMark
|= ScClipMark::Right
;
1952 aAreaParam
.maClipRect
.AdjustRight( -(nMarkPixel
* nLayoutSign
) );
1954 else if ( eOutHorJust
== SvxCellHorJustify::Right
)
1956 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1957 pRowInfo
[nArrY
].cellInfo(nCellX
).nClipMark
|= ScClipMark::Left
;
1959 aAreaParam
.maClipRect
.AdjustLeft(nMarkPixel
* nLayoutSign
);
1963 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
)
1965 pRowInfo
[nArrY
].cellInfo(nCellX
).nClipMark
|= ScClipMark::Right
;
1966 pRowInfo
[nArrY
].cellInfo(nCellX
).nClipMark
|= ScClipMark::Left
;
1969 aAreaParam
.maClipRect
.AdjustRight( -(nMarkPixel
* nLayoutSign
) );
1970 aAreaParam
.maClipRect
.AdjustLeft(nMarkPixel
* nLayoutSign
);
1974 nNeededWidth
= aVars
.GetTextSize().Width() +
1975 static_cast<tools::Long
>( aVars
.GetLeftTotal() * mnPPTX
) +
1976 static_cast<tools::Long
>( aVars
.GetMargin()->GetRightMargin() * mnPPTX
);
1977 if ( nNeededWidth
<= aAreaParam
.maClipRect
.GetWidth() )
1979 // Cell value is no longer clipped. Reset relevant parameters.
1980 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= false;
1981 aAreaParam
.mnLeftClipLength
= aAreaParam
.mnRightClipLength
= 0;
1985 tools::Long nJustPosX
= aAreaParam
.maAlignRect
.Left(); // "justified" - effect of alignment will be added
1986 tools::Long nJustPosY
= aAreaParam
.maAlignRect
.Top();
1987 tools::Long nAvailWidth
= aAreaParam
.maAlignRect
.GetWidth();
1988 tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight();
1990 bool bOutside
= ( aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
1991 // Take adjusted values of aAreaParam.mbLeftClip and aAreaParam.mbRightClip
1992 bool bVClip
= AdjustAreaParamClipRect(aAreaParam
);
1993 bool bHClip
= aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
;
1995 // check horizontal space
1999 bool bRightAdjusted
= false; // to correct text width calculation later
2000 switch (eOutHorJust
)
2002 case SvxCellHorJustify::Left
:
2003 nJustPosX
+= static_cast<tools::Long
>( aVars
.GetLeftTotal() * mnPPTX
);
2005 case SvxCellHorJustify::Right
:
2006 nJustPosX
+= nAvailWidth
- aVars
.GetTextSize().Width() -
2007 static_cast<tools::Long
>( aVars
.GetRightTotal() * mnPPTX
);
2008 bRightAdjusted
= true;
2010 case SvxCellHorJustify::Center
:
2011 nJustPosX
+= ( nAvailWidth
- aVars
.GetTextSize().Width() +
2012 static_cast<tools::Long
>( aVars
.GetLeftTotal() * mnPPTX
) -
2013 static_cast<tools::Long
>( aVars
.GetMargin()->GetRightMargin() * mnPPTX
) ) / 2;
2017 // added to avoid warnings
2021 tools::Long nTestClipHeight
= aVars
.GetTextSize().Height();
2022 switch (aVars
.GetVerJust())
2024 case SvxCellVerJustify::Top
:
2025 case SvxCellVerJustify::Block
:
2027 tools::Long nTop
= static_cast<tools::Long
>( aVars
.GetMargin()->GetTopMargin() * mnPPTY
);
2029 nTestClipHeight
+= nTop
;
2032 case SvxCellVerJustify::Bottom
:
2034 tools::Long nBot
= static_cast<tools::Long
>( aVars
.GetMargin()->GetBottomMargin() * mnPPTY
);
2035 nJustPosY
+= nOutHeight
- aVars
.GetTextSize().Height() - nBot
;
2036 nTestClipHeight
+= nBot
;
2039 case SvxCellVerJustify::Center
:
2041 tools::Long nTop
= static_cast<tools::Long
>( aVars
.GetMargin()->GetTopMargin() * mnPPTY
);
2042 tools::Long nBot
= static_cast<tools::Long
>( aVars
.GetMargin()->GetBottomMargin() * mnPPTY
);
2043 nJustPosY
+= ( nOutHeight
+ nTop
-
2044 aVars
.GetTextSize().Height() - nBot
) / 2;
2045 nTestClipHeight
+= std::abs( nTop
- nBot
);
2050 // added to avoid warnings
2054 if ( nTestClipHeight
> nOutHeight
)
2056 // no vertical clipping when printing cells with optimal height,
2057 // except when font size is from conditional formatting.
2058 if ( eType
!= OUTTYPE_PRINTER
||
2059 ( mpDoc
->GetRowFlags( nCellY
, nTab
) & CRFlags::ManualSize
) ||
2060 ( aVars
.HasCondHeight() ) )
2064 if ( bHClip
|| bVClip
)
2066 // only clip the affected dimension so that not all right-aligned
2067 // columns are cut off when performing a non-proportional resize
2070 aAreaParam
.maClipRect
.SetLeft( nScrX
);
2071 aAreaParam
.maClipRect
.SetRight( nScrX
+nScrW
);
2075 aAreaParam
.maClipRect
.SetTop( nScrY
);
2076 aAreaParam
.maClipRect
.SetBottom( nScrY
+nScrH
);
2079 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
2080 // so it can be modified here
2082 aAreaParam
.maClipRect
= mpRefDevice
->PixelToLogic( aAreaParam
.maClipRect
);
2087 mpDev
->IntersectClipRegion( aAreaParam
.maClipRect
);
2090 mpDev
->SetClipRegion( vcl::Region( aAreaParam
.maClipRect
) );
2093 Point
aURLStart( nJustPosX
, nJustPosY
); // copy before modifying for orientation
2095 switch (aVars
.GetOrient())
2097 case SvxCellOrientation::Standard
:
2098 nJustPosY
+= aVars
.GetAscent();
2100 case SvxCellOrientation::TopBottom
:
2101 nJustPosX
+= aVars
.GetTextSize().Width() - aVars
.GetAscent();
2103 case SvxCellOrientation::BottomUp
:
2104 nJustPosY
+= aVars
.GetTextSize().Height();
2105 nJustPosX
+= aVars
.GetAscent();
2109 // added to avoid warnings
2113 // When clipping, the visible part is now completely defined by the alignment,
2114 // there's no more special handling to show the right part of RTL text.
2116 Point
aDrawTextPos( nJustPosX
, nJustPosY
);
2117 if ( bPixelToLogic
)
2119 // undo text width adjustment in pixels
2121 aDrawTextPos
.AdjustX(aVars
.GetTextSize().Width() );
2123 aDrawTextPos
= mpRefDevice
->PixelToLogic( aDrawTextPos
);
2125 // redo text width adjustment in logic units
2127 aDrawTextPos
.AdjustX( -(aVars
.GetOriginalWidth()) );
2130 // in Metafiles always use DrawTextArray to ensure that positions are
2131 // recorded (for non-proportional resize):
2133 const OUString
& aString
= aVars
.GetString();
2134 if (!aString
.isEmpty())
2137 pPDF
->WrapBeginStructureElement(vcl::PDFWriter::Paragraph
, u
"P"_ustr
);
2139 // If the string is clipped, make it shorter for
2140 // better performance since drawing by HarfBuzz is
2141 // quite expensive especially for long string.
2143 OUString aShort
= aString
;
2145 // But never fiddle with numeric values.
2146 // (Which was the cause of tdf#86024).
2147 // The General automatic format output takes
2148 // care of this, or fixed width numbers either fit
2149 // or display as ###.
2152 double fVisibleRatio
= 1.0;
2153 double fTextWidth
= aVars
.GetTextSize().Width();
2154 sal_Int32 nTextLen
= aString
.getLength();
2155 if (eOutHorJust
== SvxCellHorJustify::Left
&& aAreaParam
.mnRightClipLength
> 0)
2157 fVisibleRatio
= (fTextWidth
- aAreaParam
.mnRightClipLength
) / fTextWidth
;
2158 if (0.0 < fVisibleRatio
&& fVisibleRatio
< 1.0)
2160 // Only show the left-end segment.
2161 sal_Int32 nShortLen
= fVisibleRatio
*nTextLen
+ 1;
2162 aShort
= aShort
.copy(0, nShortLen
);
2165 else if (eOutHorJust
== SvxCellHorJustify::Right
&& aAreaParam
.mnLeftClipLength
> 0)
2167 fVisibleRatio
= (fTextWidth
- aAreaParam
.mnLeftClipLength
) / fTextWidth
;
2168 if (0.0 < fVisibleRatio
&& fVisibleRatio
< 1.0)
2170 // Only show the right-end segment.
2171 sal_Int32 nShortLen
= fVisibleRatio
*nTextLen
+ 1;
2172 aShort
= aShort
.copy(nTextLen
-nShortLen
);
2174 // Adjust the text position after shortening of the string.
2175 double fShortWidth
= aVars
.GetFmtTextWidth(aShort
);
2176 double fOffset
= fTextWidth
- fShortWidth
;
2177 aDrawTextPos
.Move(fOffset
, 0);
2182 if (bMetaFile
|| pFmtDevice
!= mpDev
|| aZoomX
!= aZoomY
)
2184 size_t nLen
= aShort
.getLength();
2185 if (aDX
.size() < nLen
)
2186 aDX
.resize(nLen
, 0);
2188 pFmtDevice
->GetTextArray(aShort
, &aDX
);
2190 if ( !mpRefDevice
->GetConnectMetaFile() ||
2191 mpRefDevice
->GetOutDevType() == OUTDEV_PRINTER
)
2193 double fMul
= GetStretch();
2194 for (size_t i
= 0; i
< nLen
; ++i
)
2198 mpDev
->DrawTextArray(aDrawTextPos
, aShort
, aDX
, {}, 0, nLen
);
2202 mpDev
->DrawText(aDrawTextPos
, aShort
, 0, -1, nullptr, nullptr,
2203 aVars
.GetLayoutGlyphs(aShort
));
2206 pPDF
->EndStructureElement();
2209 if ( bHClip
|| bVClip
)
2214 mpDev
->SetClipRegion();
2217 // PDF: whole-cell hyperlink from formula?
2218 bool bHasURL
= pPDF
&& aCell
.getType() == CELLTYPE_FORMULA
&& aCell
.getFormula()->IsHyperLinkCell();
2221 tools::Rectangle
aURLRect( aURLStart
, aVars
.GetTextSize() );
2222 lcl_DoHyperlinkResult(mpDev
, aURLRect
, aCell
);
2226 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
2228 pPDF
->EndStructureElement();
2231 pPDF
->EndStructureElement();
2233 nPosY
+= pRowInfo
[nArrY
].nHeight
;
2236 pPDF
->EndStructureElement();
2239 ScProgress::DeleteInterpretProgress();
2242 void ScOutputData::SetRefDevice( OutputDevice
* pRDev
)
2244 mpRefDevice
= pFmtDevice
= pRDev
;
2245 // reset EditEngine because it depends on pFmtDevice and mpRefDevice
2246 mxOutputEditEngine
.reset();
2249 void ScOutputData::SetFmtDevice( OutputDevice
* pRDev
)
2252 // reset EditEngine because it depends on pFmtDevice
2253 mxOutputEditEngine
.reset();
2256 void ScOutputData::SetUseStyleColor( bool bSet
)
2258 mbUseStyleColor
= bSet
;
2259 // reset EditEngine because it depends on mbUseStyleColor
2260 mxOutputEditEngine
.reset();
2263 void ScOutputData::InitOutputEditEngine()
2265 if (!mxOutputEditEngine
)
2267 mxOutputEditEngine
= std::make_unique
<ScFieldEditEngine
>(mpDoc
, mpDoc
->GetEnginePool());
2268 mxOutputEditEngine
->SetUpdateLayout( false );
2269 mxOutputEditEngine
->EnableUndo( false ); // don't need undo for painting purposes
2270 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2271 mxOutputEditEngine
->SetRefDevice( pFmtDevice
);
2272 EEControlBits nCtrl
= mxOutputEditEngine
->GetControlWord();
2273 if ( bShowSpellErrors
)
2274 nCtrl
|= EEControlBits::ONLINESPELLING
;
2275 if ( eType
== OUTTYPE_PRINTER
)
2276 nCtrl
&= ~EEControlBits::MARKFIELDS
;
2278 nCtrl
&= ~EEControlBits::MARKURLFIELDS
; // URLs not shaded for output
2279 mxOutputEditEngine
->SetControlWord( nCtrl
);
2280 mxOutputEditEngine
->EnableAutoColor( mbUseStyleColor
);
2284 // just in case someone turned it on during the last paint cycle
2285 mxOutputEditEngine
->SetUpdateLayout( false );
2287 // we don't track changes to these settings, so we have to apply them every time
2288 mpDoc
->ApplyAsianEditSettings( *mxOutputEditEngine
);
2289 mxOutputEditEngine
->SetDefaultHorizontalTextDirection( mpDoc
->GetEditTextDirection( nTab
) );
2292 static void lcl_ClearEdit( EditEngine
& rEngine
) // text and attributes
2294 rEngine
.SetUpdateLayout( false );
2296 rEngine
.SetText(OUString());
2297 // do not keep any para-attributes
2298 const SfxItemSet
& rPara
= rEngine
.GetParaAttribs(0);
2300 rEngine
.SetParaAttribs( 0,
2301 SfxItemSet( *rPara
.GetPool(), rPara
.GetRanges() ) );
2302 rEngine
.EnableSkipOutsideFormat(false);
2305 static bool lcl_SafeIsValue( ScRefCellValue
& rCell
)
2307 switch (rCell
.getType())
2309 case CELLTYPE_VALUE
:
2311 case CELLTYPE_FORMULA
:
2313 ScFormulaCell
* pFCell
= rCell
.getFormula();
2314 if (pFCell
->IsRunning() || pFCell
->IsValue())
2320 // added to avoid warnings
2326 static void lcl_ScaleFonts( EditEngine
& rEngine
, tools::Long nPercent
)
2328 bool bUpdateMode
= rEngine
.SetUpdateLayout( false );
2330 sal_Int32 nParCount
= rEngine
.GetParagraphCount();
2331 for (sal_Int32 nPar
=0; nPar
<nParCount
; nPar
++)
2333 std::vector
<sal_Int32
> aPortions
;
2334 rEngine
.GetPortions( nPar
, aPortions
);
2336 sal_Int32 nStart
= 0;
2337 for ( const sal_Int32 nEnd
: aPortions
)
2339 ESelection
aSel( nPar
, nStart
, nPar
, nEnd
);
2340 SfxItemSet aAttribs
= rEngine
.GetAttribs( aSel
);
2342 tools::Long nWestern
= aAttribs
.Get(EE_CHAR_FONTHEIGHT
).GetHeight();
2343 tools::Long nCJK
= aAttribs
.Get(EE_CHAR_FONTHEIGHT_CJK
).GetHeight();
2344 tools::Long nCTL
= aAttribs
.Get(EE_CHAR_FONTHEIGHT_CTL
).GetHeight();
2346 nWestern
= ( nWestern
* nPercent
) / 100;
2347 nCJK
= ( nCJK
* nPercent
) / 100;
2348 nCTL
= ( nCTL
* nPercent
) / 100;
2350 aAttribs
.Put( SvxFontHeightItem( nWestern
, 100, EE_CHAR_FONTHEIGHT
) );
2351 aAttribs
.Put( SvxFontHeightItem( nCJK
, 100, EE_CHAR_FONTHEIGHT_CJK
) );
2352 aAttribs
.Put( SvxFontHeightItem( nCTL
, 100, EE_CHAR_FONTHEIGHT_CTL
) );
2354 rEngine
.QuickSetAttribs( aAttribs
, aSel
); //! remove paragraph attributes from aAttribs?
2361 rEngine
.SetUpdateLayout( true );
2364 static tools::Long
lcl_GetEditSize( EditEngine
& rEngine
, bool bWidth
, bool bSwap
, Degree100 nAttrRotate
)
2371 tools::Long nRealWidth
= static_cast<tools::Long
>(rEngine
.CalcTextWidth());
2372 tools::Long nRealHeight
= rEngine
.GetTextHeight();
2374 // assuming standard mode, otherwise width isn't used
2376 double nRealOrient
= toRadians(nAttrRotate
); // 1/100th degrees
2377 double nAbsCos
= fabs( cos( nRealOrient
) );
2378 double nAbsSin
= fabs( sin( nRealOrient
) );
2380 return static_cast<tools::Long
>( nRealWidth
* nAbsCos
+ nRealHeight
* nAbsSin
);
2382 return static_cast<tools::Long
>( nRealHeight
* nAbsCos
+ nRealWidth
* nAbsSin
);
2385 return static_cast<tools::Long
>(rEngine
.CalcTextWidth());
2387 return rEngine
.GetTextHeight();
2390 void ScOutputData::ShrinkEditEngine( EditEngine
& rEngine
, const tools::Rectangle
& rAlignRect
,
2391 tools::Long nLeftM
, tools::Long nTopM
, tools::Long nRightM
, tools::Long nBottomM
,
2392 bool bWidth
, SvxCellOrientation nOrient
, Degree100 nAttrRotate
, bool bPixelToLogic
,
2393 tools::Long
& rEngineWidth
, tools::Long
& rEngineHeight
, tools::Long
& rNeededPixel
, bool& rLeftClip
, bool& rRightClip
)
2399 tools::Long nScaleSize
= bPixelToLogic
?
2400 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2402 // Don't scale if it fits already.
2403 // Allowing to extend into the margin, to avoid scaling at optimal height.
2404 if ( nScaleSize
<= rAlignRect
.GetHeight() )
2407 bool bSwap
= ( nOrient
== SvxCellOrientation::TopBottom
|| nOrient
== SvxCellOrientation::BottomUp
);
2408 tools::Long nAvailable
= rAlignRect
.GetHeight() - nTopM
- nBottomM
;
2409 tools::Long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
2411 lcl_ScaleFonts( rEngine
, nScale
);
2412 rEngineHeight
= lcl_GetEditSize( rEngine
, false, bSwap
, nAttrRotate
);
2413 tools::Long nNewSize
= bPixelToLogic
?
2414 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2416 sal_uInt16 nShrinkAgain
= 0;
2417 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
2419 // further reduce, like in DrawStrings
2420 lcl_ScaleFonts( rEngine
, 90 ); // reduce by 10%
2421 rEngineHeight
= lcl_GetEditSize( rEngine
, false, bSwap
, nAttrRotate
);
2422 nNewSize
= bPixelToLogic
?
2423 mpRefDevice
->LogicToPixel(Size(0,rEngineHeight
)).Height() : rEngineHeight
;
2427 // sizes for further processing (alignment etc):
2428 rEngineWidth
= lcl_GetEditSize( rEngine
, true, bSwap
, nAttrRotate
);
2429 tools::Long nPixelWidth
= bPixelToLogic
?
2430 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2431 rNeededPixel
= nPixelWidth
+ nLeftM
+ nRightM
;
2433 else if ( rLeftClip
|| rRightClip
)
2437 tools::Long nAvailable
= rAlignRect
.GetWidth() - nLeftM
- nRightM
;
2438 tools::Long nScaleSize
= rNeededPixel
- nLeftM
- nRightM
; // without margin
2440 if ( nScaleSize
<= nAvailable
)
2443 tools::Long nScale
= ( nAvailable
* 100 ) / nScaleSize
;
2445 lcl_ScaleFonts( rEngine
, nScale
);
2446 rEngineWidth
= lcl_GetEditSize( rEngine
, true, false, nAttrRotate
);
2447 tools::Long nNewSize
= bPixelToLogic
?
2448 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2450 sal_uInt16 nShrinkAgain
= 0;
2451 while ( nNewSize
> nAvailable
&& nShrinkAgain
< SC_SHRINKAGAIN_MAX
)
2453 // further reduce, like in DrawStrings
2454 lcl_ScaleFonts( rEngine
, 90 ); // reduce by 10%
2455 rEngineWidth
= lcl_GetEditSize( rEngine
, true, false, nAttrRotate
);
2456 nNewSize
= bPixelToLogic
?
2457 mpRefDevice
->LogicToPixel(Size(rEngineWidth
,0)).Width() : rEngineWidth
;
2460 if ( nNewSize
<= nAvailable
)
2461 rLeftClip
= rRightClip
= false;
2463 // sizes for further processing (alignment etc):
2464 rNeededPixel
= nNewSize
+ nLeftM
+ nRightM
;
2465 rEngineHeight
= lcl_GetEditSize( rEngine
, false, false, nAttrRotate
);
2469 ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr
* pPattern
, const SfxItemSet
* pCondSet
, bool bCellIsValue
) :
2470 meHorJustAttr( lcl_GetValue
<SvxHorJustifyItem
, SvxCellHorJustify
>(*pPattern
, ATTR_HOR_JUSTIFY
, pCondSet
) ),
2471 meHorJustContext( meHorJustAttr
),
2472 meHorJustResult( meHorJustAttr
),
2473 meVerJust( lcl_GetValue
<SvxVerJustifyItem
, SvxCellVerJustify
>(*pPattern
, ATTR_VER_JUSTIFY
, pCondSet
) ),
2474 meHorJustMethod( lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_HOR_JUSTIFY_METHOD
, pCondSet
) ),
2475 meVerJustMethod( lcl_GetValue
<SvxJustifyMethodItem
, SvxCellJustifyMethod
>(*pPattern
, ATTR_VER_JUSTIFY_METHOD
, pCondSet
) ),
2476 meOrient( pPattern
->GetCellOrientation(pCondSet
) ),
2478 mnX(0), mnCellX(0), mnCellY(0),
2479 mnPosX(0), mnPosY(0), mnInitPosX(0),
2480 mbBreak( (meHorJustAttr
== SvxCellHorJustify::Block
) || lcl_GetBoolValue(*pPattern
, ATTR_LINEBREAK
, pCondSet
) ),
2481 mbCellIsValue(bCellIsValue
),
2482 mbAsianVertical(false),
2483 mbPixelToLogic(false),
2484 mbHyphenatorSet(false),
2486 mpPattern(pPattern
),
2487 mpCondSet(pCondSet
),
2488 mpPreviewFontSet(nullptr),
2489 mpOldPattern(nullptr),
2490 mpOldCondSet(nullptr),
2491 mpOldPreviewFontSet(nullptr),
2492 mpThisRowInfo(nullptr),
2493 mpMisspellRanges(nullptr)
2496 bool ScOutputData::DrawEditParam::readCellContent(
2497 const ScDocument
* pDoc
, bool bShowNullValues
, bool bShowFormulas
, bool bSyntaxMode
, bool bUseStyleColor
, bool bForceAutoColor
, bool& rWrapFields
)
2499 if (maCell
.getType() == CELLTYPE_EDIT
)
2501 const EditTextObject
* pData
= maCell
.getEditText();
2504 mpEngine
->SetTextCurrentDefaults(*pData
);
2506 if ( mbBreak
&& !mbAsianVertical
&& pData
->HasField() )
2508 // Fields aren't wrapped, so clipping is enabled to prevent
2509 // a field from being drawn beyond the cell size
2516 OSL_FAIL("pData == 0");
2522 sal_uInt32 nFormat
= mpPattern
->GetNumberFormat(
2523 pDoc
->GetFormatTable(), mpCondSet
);
2524 const Color
* pColor
;
2525 OUString aString
= ScCellFormat::GetString( maCell
,
2532 mpEngine
->SetTextCurrentDefaults(aString
);
2533 if ( pColor
&& !bSyntaxMode
&& !( bUseStyleColor
&& bForceAutoColor
) )
2534 lcl_SetEditColor( *mpEngine
, *pColor
);
2537 if (mpMisspellRanges
)
2538 mpEngine
->SetAllMisspellRanges(*mpMisspellRanges
);
2543 static Color
GetConfBackgroundColor()
2545 if (const ScTabViewShell
* pTabViewShellBg
= ScTabViewShell::GetActiveViewShell())
2546 return pTabViewShellBg
->GetViewRenderingData().GetDocColor();
2547 return ScModule::get()->GetColorConfig().GetColorValue(svtools::DOCCOLOR
).nColor
;
2550 void ScOutputData::DrawEditParam::setPatternToEngine(bool bUseStyleColor
)
2552 // syntax highlighting mode is ignored here
2553 // StringDiffer doesn't look at hyphenate, language items
2555 if (ScPatternAttr::areSame(mpPattern
, mpOldPattern
) && mpCondSet
== mpOldCondSet
&& mpPreviewFontSet
== mpOldPreviewFontSet
)
2558 Color nConfBackColor
= GetConfBackgroundColor();
2559 bool bCellContrast
= bUseStyleColor
&&
2560 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
2562 auto pSet
= std::make_unique
<SfxItemSet
>( mpEngine
->GetEmptyItemSet() );
2563 mpPattern
->FillEditItemSet( pSet
.get(), mpCondSet
);
2564 if ( mpPreviewFontSet
)
2566 if ( const SvxFontItem
* pItem
= mpPreviewFontSet
->GetItemIfSet( ATTR_FONT
) )
2568 // tdf#125054 adapt WhichID
2569 pSet
->PutAsTargetWhich(*pItem
, EE_CHAR_FONTINFO
);
2571 if ( const SvxFontItem
* pItem
= mpPreviewFontSet
->GetItemIfSet( ATTR_CJK_FONT
) )
2573 // tdf#125054 adapt WhichID
2574 pSet
->PutAsTargetWhich(*pItem
, EE_CHAR_FONTINFO_CJK
);
2576 if ( const SvxFontItem
* pItem
= mpPreviewFontSet
->GetItemIfSet( ATTR_CTL_FONT
) )
2578 // tdf#125054 adapt WhichID
2579 pSet
->PutAsTargetWhich(*pItem
, EE_CHAR_FONTINFO_CTL
);
2582 bool bParaHyphenate
= pSet
->Get(EE_PARA_HYPHENATE
).GetValue();
2583 mpEngine
->SetDefaults( std::move(pSet
) );
2584 mpOldPattern
= mpPattern
;
2585 mpOldCondSet
= mpCondSet
;
2586 mpOldPreviewFontSet
= mpPreviewFontSet
;
2588 EEControlBits nControl
= mpEngine
->GetControlWord();
2589 if (meOrient
== SvxCellOrientation::Stacked
)
2590 nControl
|= EEControlBits::ONECHARPERLINE
;
2592 nControl
&= ~EEControlBits::ONECHARPERLINE
;
2593 mpEngine
->SetControlWord( nControl
);
2595 if ( !mbHyphenatorSet
&& bParaHyphenate
)
2597 // set hyphenator the first time it is needed
2598 css::uno::Reference
<css::linguistic2::XHyphenator
> xXHyphenator( LinguMgr::GetHyphenator() );
2599 mpEngine
->SetHyphenator( xXHyphenator
);
2600 mbHyphenatorSet
= true;
2603 Color aBackCol
= mpPattern
->GetItem( ATTR_BACKGROUND
, mpCondSet
).GetColor();
2604 if ( bUseStyleColor
&& ( aBackCol
.IsTransparent() || bCellContrast
) )
2605 aBackCol
= nConfBackColor
;
2606 mpEngine
->SetBackgroundColor( aBackCol
);
2609 void ScOutputData::DrawEditParam::calcMargins(tools::Long
& rTopM
, tools::Long
& rLeftM
, tools::Long
& rBottomM
, tools::Long
& rRightM
, double nPPTX
, double nPPTY
) const
2611 const SvxMarginItem
& rMargin
= mpPattern
->GetItem(ATTR_MARGIN
, mpCondSet
);
2613 sal_uInt16 nIndent
= 0;
2614 if (meHorJustAttr
== SvxCellHorJustify::Left
|| meHorJustAttr
== SvxCellHorJustify::Right
)
2615 nIndent
= lcl_GetValue
<ScIndentItem
, sal_uInt16
>(*mpPattern
, ATTR_INDENT
, mpCondSet
);
2617 rLeftM
= static_cast<tools::Long
>(((rMargin
.GetLeftMargin() + nIndent
) * nPPTX
));
2618 rTopM
= static_cast<tools::Long
>((rMargin
.GetTopMargin() * nPPTY
));
2619 rRightM
= static_cast<tools::Long
>((rMargin
.GetRightMargin() * nPPTX
));
2620 rBottomM
= static_cast<tools::Long
>((rMargin
.GetBottomMargin() * nPPTY
));
2621 if(meHorJustAttr
== SvxCellHorJustify::Right
)
2623 rLeftM
= static_cast<tools::Long
>((rMargin
.GetLeftMargin() * nPPTX
));
2624 rRightM
= static_cast<tools::Long
>(((rMargin
.GetRightMargin() + nIndent
) * nPPTX
));
2628 void ScOutputData::DrawEditParam::calcPaperSize(
2629 Size
& rPaperSize
, const tools::Rectangle
& rAlignRect
, double nPPTX
, double nPPTY
) const
2631 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
2632 calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, nPPTX
, nPPTY
);
2634 if (isVerticallyOriented())
2636 rPaperSize
.setWidth( rAlignRect
.GetHeight() - nTopM
- nBottomM
);
2637 rPaperSize
.setHeight( rAlignRect
.GetWidth() - nLeftM
- nRightM
);
2641 rPaperSize
.setWidth( rAlignRect
.GetWidth() - nLeftM
- nRightM
);
2642 rPaperSize
.setHeight( rAlignRect
.GetHeight() - nTopM
- nBottomM
);
2645 if (mbAsianVertical
)
2647 rPaperSize
.setHeight( rAlignRect
.GetHeight() - nTopM
- nBottomM
);
2648 // Subtract some extra value from the height or else the text would go
2649 // outside the cell area. The value of 5 is arbitrary, and is based
2650 // entirely on heuristics.
2651 rPaperSize
.AdjustHeight( -5 );
2655 void ScOutputData::DrawEditParam::getEngineSize(ScFieldEditEngine
* pEngine
, tools::Long
& rWidth
, tools::Long
& rHeight
) const
2657 tools::Long nEngineWidth
= 0;
2658 if (!mbBreak
|| meOrient
== SvxCellOrientation::Stacked
|| mbAsianVertical
)
2659 nEngineWidth
= static_cast<tools::Long
>(pEngine
->CalcTextWidth());
2661 tools::Long nEngineHeight
= pEngine
->GetTextHeight();
2663 if (isVerticallyOriented())
2664 std::swap( nEngineWidth
, nEngineHeight
);
2666 if (meOrient
== SvxCellOrientation::Stacked
)
2667 nEngineWidth
= nEngineWidth
* 11 / 10;
2669 rWidth
= nEngineWidth
;
2670 rHeight
= nEngineHeight
;
2673 bool ScOutputData::DrawEditParam::hasLineBreak() const
2675 return (mbBreak
|| (meOrient
== SvxCellOrientation::Stacked
) || mbAsianVertical
);
2678 bool ScOutputData::DrawEditParam::isHyperlinkCell() const
2680 if (maCell
.getType() != CELLTYPE_FORMULA
)
2683 return maCell
.getFormula()->IsHyperLinkCell();
2686 bool ScOutputData::DrawEditParam::isVerticallyOriented() const
2688 return (meOrient
== SvxCellOrientation::TopBottom
|| meOrient
== SvxCellOrientation::BottomUp
);
2691 void ScOutputData::DrawEditParam::calcStartPosForVertical(
2692 Point
& rLogicStart
, tools::Long nCellWidth
, tools::Long nEngineWidth
, tools::Long nTopM
, const OutputDevice
* pRefDevice
)
2694 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2697 rLogicStart
= pRefDevice
->PixelToLogic(rLogicStart
);
2702 // vertical adjustment is within the EditEngine
2704 rLogicStart
.AdjustY(pRefDevice
->PixelToLogic(Size(0,nTopM
)).Height() );
2706 rLogicStart
.AdjustY(nTopM
);
2708 switch (meHorJustResult
)
2710 case SvxCellHorJustify::Center
:
2711 rLogicStart
.AdjustX((nCellWidth
- nEngineWidth
) / 2 );
2713 case SvxCellHorJustify::Right
:
2714 rLogicStart
.AdjustX(nCellWidth
- nEngineWidth
);
2721 void ScOutputData::DrawEditParam::setAlignmentToEngine()
2723 if (isVerticallyOriented() || mbAsianVertical
)
2725 SvxAdjust eSvxAdjust
= SvxAdjust::Left
;
2728 case SvxCellVerJustify::Top
:
2729 eSvxAdjust
= (meOrient
== SvxCellOrientation::TopBottom
|| mbAsianVertical
) ?
2730 SvxAdjust::Left
: SvxAdjust::Right
;
2732 case SvxCellVerJustify::Center
:
2733 eSvxAdjust
= SvxAdjust::Center
;
2735 case SvxCellVerJustify::Bottom
:
2736 case SvxCellVerJustify::Standard
:
2737 eSvxAdjust
= (meOrient
== SvxCellOrientation::TopBottom
|| mbAsianVertical
) ?
2738 SvxAdjust::Right
: SvxAdjust::Left
;
2740 case SvxCellVerJustify::Block
:
2741 eSvxAdjust
= SvxAdjust::Block
;
2745 mpEngine
->SetDefaultItem( SvxAdjustItem(eSvxAdjust
, EE_PARA_JUST
) );
2746 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod
, EE_PARA_JUST_METHOD
) );
2748 if (meHorJustResult
== SvxCellHorJustify::Block
)
2749 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block
, EE_PARA_VER_JUST
) );
2753 // horizontal alignment now may depend on cell content
2754 // (for values with number formats with mixed script types)
2755 // -> always set adjustment
2757 SvxAdjust eSvxAdjust
= SvxAdjust::Left
;
2758 if (meOrient
== SvxCellOrientation::Stacked
)
2759 eSvxAdjust
= SvxAdjust::Center
;
2762 if (meOrient
== SvxCellOrientation::Standard
)
2763 switch (meHorJustResult
)
2765 case SvxCellHorJustify::Repeat
: // repeat is not yet implemented
2766 case SvxCellHorJustify::Standard
:
2767 SAL_WARN("sc.ui","meHorJustResult does not match getAlignmentFromContext()");
2769 case SvxCellHorJustify::Left
:
2770 eSvxAdjust
= SvxAdjust::Left
;
2772 case SvxCellHorJustify::Center
:
2773 eSvxAdjust
= SvxAdjust::Center
;
2775 case SvxCellHorJustify::Right
:
2776 eSvxAdjust
= SvxAdjust::Right
;
2778 case SvxCellHorJustify::Block
:
2779 eSvxAdjust
= SvxAdjust::Block
;
2785 case SvxCellVerJustify::Top
:
2786 eSvxAdjust
= SvxAdjust::Right
;
2788 case SvxCellVerJustify::Center
:
2789 eSvxAdjust
= SvxAdjust::Center
;
2791 case SvxCellVerJustify::Bottom
:
2792 case SvxCellVerJustify::Standard
:
2793 eSvxAdjust
= SvxAdjust::Left
;
2795 case SvxCellVerJustify::Block
:
2796 eSvxAdjust
= SvxAdjust::Block
;
2801 mpEngine
->SetDefaultItem( SvxAdjustItem(eSvxAdjust
, EE_PARA_JUST
) );
2803 if (mbAsianVertical
)
2805 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod
, EE_PARA_JUST_METHOD
) );
2806 if (meHorJustResult
== SvxCellHorJustify::Block
)
2807 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block
, EE_PARA_VER_JUST
) );
2811 mpEngine
->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod
, EE_PARA_JUST_METHOD
) );
2812 if (meVerJust
== SvxCellVerJustify::Block
)
2813 mpEngine
->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block
, EE_PARA_VER_JUST
) );
2817 mpEngine
->SetVertical(mbAsianVertical
);
2818 if (maCell
.getType() == CELLTYPE_EDIT
)
2820 // We need to synchronize the vertical mode in the EditTextObject
2821 // instance too. No idea why we keep this state in two separate
2823 const EditTextObject
* pData
= maCell
.getEditText();
2825 const_cast<EditTextObject
*>(pData
)->SetVertical(mbAsianVertical
);
2829 bool ScOutputData::DrawEditParam::adjustHorAlignment(ScFieldEditEngine
* pEngine
)
2831 if (meHorJustResult
== SvxCellHorJustify::Right
|| meHorJustResult
== SvxCellHorJustify::Center
)
2833 SvxAdjust eEditAdjust
= (meHorJustResult
== SvxCellHorJustify::Center
) ?
2834 SvxAdjust::Center
: SvxAdjust::Right
;
2836 const bool bPrevUpdateLayout
= pEngine
->SetUpdateLayout(false);
2837 pEngine
->SetDefaultItem( SvxAdjustItem(eEditAdjust
, EE_PARA_JUST
) );
2838 pEngine
->SetUpdateLayout(bPrevUpdateLayout
);
2844 void ScOutputData::DrawEditParam::adjustForHyperlinkInPDF(Point aURLStart
, const OutputDevice
* pDev
)
2846 // PDF: whole-cell hyperlink from formula?
2847 vcl::PDFExtOutDevData
* pPDFData
= dynamic_cast<vcl::PDFExtOutDevData
* >( pDev
->GetExtOutDevData() );
2848 bool bHasURL
= pPDFData
&& isHyperlinkCell();
2852 tools::Long nURLWidth
= static_cast<tools::Long
>(mpEngine
->CalcTextWidth());
2853 tools::Long nURLHeight
= mpEngine
->GetTextHeight();
2856 Size aPaper
= mpEngine
->GetPaperSize();
2857 if ( mbAsianVertical
)
2858 nURLHeight
= aPaper
.Height();
2860 nURLWidth
= aPaper
.Width();
2862 if (isVerticallyOriented())
2863 std::swap( nURLWidth
, nURLHeight
);
2864 else if (mbAsianVertical
)
2865 aURLStart
.AdjustX( -nURLWidth
);
2867 tools::Rectangle
aURLRect( aURLStart
, Size( nURLWidth
, nURLHeight
) );
2868 lcl_DoHyperlinkResult(pDev
, aURLRect
, maCell
);
2871 // Returns true if the rect is clipped vertically
2872 bool ScOutputData::AdjustAreaParamClipRect(OutputAreaParam
& rAreaParam
)
2874 if( rAreaParam
.maClipRect
.Left() < nScrX
)
2876 rAreaParam
.maClipRect
.SetLeft( nScrX
);
2877 rAreaParam
.mbLeftClip
= true;
2879 if( rAreaParam
.maClipRect
.Right() > nScrX
+ nScrW
)
2881 rAreaParam
.maClipRect
.SetRight( nScrX
+ nScrW
); //! minus one?
2882 rAreaParam
.mbRightClip
= true;
2885 bool bVClip
= false;
2887 if( rAreaParam
.maClipRect
.Top() < nScrY
)
2889 rAreaParam
.maClipRect
.SetTop( nScrY
);
2892 if( rAreaParam
.maClipRect
.Bottom() > nScrY
+ nScrH
)
2894 rAreaParam
.maClipRect
.SetBottom( nScrY
+ nScrH
); //! minus one?
2900 // Doesn't handle clip marks - should be handled in advance using GetOutputArea
2901 class ClearableClipRegion
2904 ClearableClipRegion( const tools::Rectangle
& rRect
, bool bClip
, bool bSimClip
,
2905 const VclPtr
<OutputDevice
>& pDev
, bool bMetaFile
)
2906 :mbMetaFile(bMetaFile
)
2908 if (!(bClip
|| bSimClip
))
2912 if (bClip
) // for bSimClip only initialize aClipRect
2918 mpDev
->IntersectClipRegion(maRect
);
2921 mpDev
->SetClipRegion(vcl::Region(maRect
));
2925 ~ClearableClipRegion() COVERITY_NOEXCEPT_FALSE
2927 // Pop() or SetClipRegion() must only be called in case bClip was true
2928 // in the ctor, and only then mpDev is set.
2934 mpDev
->SetClipRegion();
2938 const tools::Rectangle
& getRect() const { return maRect
; }
2941 tools::Rectangle maRect
;
2942 VclPtr
<OutputDevice
> mpDev
;
2946 // Returns needed width in current units; sets rNeededPixel to needed width in pixels
2947 tools::Long
ScOutputData::SetEngineTextAndGetWidth( DrawEditParam
& rParam
, const OUString
& rSetString
,
2948 tools::Long
& rNeededPixel
, tools::Long nAddWidthPixels
)
2950 rParam
.mpEngine
->SetTextCurrentDefaults( rSetString
);
2951 tools::Long nEngineWidth
= static_cast<tools::Long
>( rParam
.mpEngine
->CalcTextWidth() );
2952 if ( rParam
.mbPixelToLogic
)
2953 rNeededPixel
= mpRefDevice
->LogicToPixel( Size( nEngineWidth
, 0 ) ).Width();
2955 rNeededPixel
= nEngineWidth
;
2957 rNeededPixel
+= nAddWidthPixels
;
2959 return nEngineWidth
;
2962 void ScOutputData::DrawEditStandard(DrawEditParam
& rParam
)
2964 OSL_ASSERT(rParam
.meOrient
== SvxCellOrientation::Standard
);
2965 OSL_ASSERT(!rParam
.mbAsianVertical
);
2967 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
2969 bool bRepeat
= (rParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
&& !rParam
.mbBreak
);
2970 bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
2971 Degree100 nAttrRotate
= lcl_GetValue
<ScRotateValueItem
, Degree100
>(*rParam
.mpPattern
, ATTR_ROTATE_VALUE
, rParam
.mpCondSet
);
2973 if ( rParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
)
2975 // ignore orientation/rotation if "repeat" is active
2976 rParam
.meOrient
= SvxCellOrientation::Standard
;
2977 nAttrRotate
= 0_deg100
;
2979 // #i31843# "repeat" with "line breaks" is treated as default alignment
2980 // (but rotation is still disabled).
2981 // Default again leads to context dependent alignment instead of
2982 // SvxCellHorJustify::Standard.
2983 if ( rParam
.mbBreak
)
2984 rParam
.meHorJustResult
= rParam
.meHorJustContext
;
2989 //! set flag to find the cell in DrawRotated again ?
2990 //! (or flag already set during DrawBackground, then no query here)
2991 return; // rotated is outputted separately
2994 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
2996 //! mirror margin values for RTL?
2997 //! move margin down to after final GetOutputArea call
2998 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
2999 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3001 SCCOL nXForPos
= rParam
.mnX
;
3002 if ( nXForPos
< nX1
)
3005 rParam
.mnPosX
= rParam
.mnInitPosX
;
3007 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3008 if ( nArrYForPos
< 1 )
3011 rParam
.mnPosY
= nScrY
;
3014 OutputAreaParam aAreaParam
;
3016 // Initial page size - large for normal text, cell size for automatic line breaks
3018 Size
aPaperSize( 1000000, 1000000 );
3021 // call GetOutputArea with nNeeded=0, to get only the cell width
3023 //! handle nArrY == 0
3024 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3025 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3026 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3028 //! special ScEditUtil handling if formatting for printer
3029 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3031 if (rParam
.mbPixelToLogic
)
3033 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3034 if ( rParam
.mbBreak
&& !rParam
.mbAsianVertical
&& mpRefDevice
!= pFmtDevice
)
3036 // #i85342# screen display and formatting for printer,
3037 // use same GetEditArea call as in ScViewData::SetEditEngine
3039 Fraction
aFract(1,1);
3040 tools::Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
3041 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
3042 aLogicSize
.setWidth( aUtilRect
.GetWidth() );
3044 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3047 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3049 // Fill the EditEngine (cell attributes and text)
3051 // default alignment for asian vertical mode is top-right
3052 if ( rParam
.mbAsianVertical
&& rParam
.meVerJust
== SvxCellVerJustify::Standard
)
3053 rParam
.meVerJust
= SvxCellVerJustify::Top
;
3055 rParam
.setPatternToEngine(mbUseStyleColor
);
3056 rParam
.setAlignmentToEngine();
3057 // Don't format unnecessary parts if the text will be drawn from top (Standard will
3058 // act that way if text doesn't fit, see below).
3059 rParam
.mpEngine
->EnableSkipOutsideFormat(rParam
.meVerJust
==SvxCellVerJustify::Top
3060 || rParam
.meVerJust
==SvxCellVerJustify::Standard
);
3062 // Read content from cell
3064 bool bWrapFields
= false;
3065 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3066 // Failed to read cell content. Bail out.
3070 SetEditSyntaxColor(*rParam
.mpEngine
, rParam
.maCell
);
3071 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3072 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3074 rParam
.mpEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3076 // Get final output area using the calculated width
3078 tools::Long nEngineWidth
, nEngineHeight
;
3079 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3081 tools::Long nNeededPixel
= nEngineWidth
;
3082 if (rParam
.mbPixelToLogic
)
3083 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3084 nNeededPixel
+= nLeftM
+ nRightM
;
3086 if (!rParam
.mbBreak
|| bShrink
)
3088 // for break, the first GetOutputArea call is sufficient
3089 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3090 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3091 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
3095 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3096 nLeftM
, nTopM
, nRightM
, nBottomM
, true,
3097 rParam
.meOrient
, 0_deg100
, rParam
.mbPixelToLogic
,
3098 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3099 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3101 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
3103 // First check if twice the space for the formatted text is available
3104 // (otherwise just keep it unchanged).
3106 tools::Long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
3107 tools::Long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
3108 if ( nAvailable
>= 2 * nFormatted
)
3110 // "repeat" is handled with unformatted text (for performance reasons)
3111 OUString aCellStr
= rParam
.mpEngine
->GetText();
3113 tools::Long nRepeatSize
= 0;
3114 SetEngineTextAndGetWidth( rParam
, aCellStr
, nRepeatSize
, 0 );
3115 if ( pFmtDevice
!= mpRefDevice
)
3117 if ( nRepeatSize
> 0 )
3119 tools::Long nRepeatCount
= nAvailable
/ nRepeatSize
;
3120 if ( nRepeatCount
> 1 )
3122 OUStringBuffer
aRepeated(aCellStr
);
3123 for ( tools::Long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
3124 aRepeated
.append(aCellStr
);
3126 SetEngineTextAndGetWidth( rParam
, aRepeated
.makeStringAndClear(),
3127 nNeededPixel
, (nLeftM
+ nRightM
) );
3129 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
3135 if (rParam
.mnX
>= nX1
&& rParam
.mbCellIsValue
3136 && (aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
))
3138 SetEngineTextAndGetWidth( rParam
, u
"###"_ustr
, nNeededPixel
, ( nLeftM
+ nRightM
) );
3139 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
3140 ScCellInfo
* pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
3141 SetClipMarks( aAreaParam
, pClipMarkCell
, eOutHorJust
, nLayoutSign
);
3144 if (eOutHorJust
!= SvxCellHorJustify::Left
)
3146 aPaperSize
.setWidth( nNeededPixel
+ 1 );
3147 if (rParam
.mbPixelToLogic
)
3148 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
3150 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3154 tools::Long nStartX
= aAreaParam
.maAlignRect
.Left();
3155 tools::Long nStartY
= aAreaParam
.maAlignRect
.Top();
3156 tools::Long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3157 tools::Long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3158 tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3162 // text with automatic breaks is aligned only within the
3163 // edit engine's paper size, the output of the whole area
3164 // is always left-aligned
3170 if ( eOutHorJust
== SvxCellHorJustify::Right
)
3171 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3172 else if ( eOutHorJust
== SvxCellHorJustify::Center
)
3173 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3178 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3182 // Also take fields in a cell with automatic breaks into account: clip to cell width
3183 bool bClip
= AdjustAreaParamClipRect(aAreaParam
) || aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
|| bWrapFields
;
3184 bool bSimClip
= false;
3186 Size aCellSize
; // output area, excluding margins, in logical units
3187 if (rParam
.mbPixelToLogic
)
3188 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
3190 aCellSize
= Size( nOutWidth
, nOutHeight
);
3192 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
3194 const ScMergeAttr
* pMerge
= &rParam
.mpPattern
->GetItem(ATTR_MERGE
);
3195 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
3197 // Don't clip for text height when printing rows with optimal height,
3198 // except when font size is from conditional formatting.
3199 //! Allow clipping when vertically merged?
3200 if ( eType
!= OUTTYPE_PRINTER
||
3201 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CRFlags::ManualSize
) ||
3202 ( rParam
.mpCondSet
&& SfxItemState::SET
==
3203 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
3208 // Show clip marks if height is at least 5pt too small and
3209 // there are several lines of text.
3210 // Not for asian vertical text, because that would interfere
3211 // with the default right position of the text.
3212 // Only with automatic line breaks, to avoid having to find
3213 // the cells with the horizontal end of the text again.
3214 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
3215 rParam
.mbBreak
&& bMarkClipped
&&
3216 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
3218 ScCellInfo
* pClipMarkCell
= nullptr;
3221 // anywhere in the merged area...
3222 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
3223 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].cellInfo(nClipX
);
3226 pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
3228 pClipMarkCell
->nClipMark
|= ScClipMark::Right
; //! also allow left?
3231 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
3232 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
3233 aAreaParam
.maClipRect
.AdjustRight( -nMarkPixel
);
3235 // Standard is normally treated as Bottom, but if text height is clipped, then
3236 // Top looks better and also allows using EditEngine::EnableSkipOutsideFormat().
3237 if (rParam
.meVerJust
==SvxCellVerJustify::Standard
)
3238 rParam
.meVerJust
=SvxCellVerJustify::Top
;
3244 { // Clip marks are already handled in GetOutputArea
3245 ClearableClipRegion
aClip(rParam
.mbPixelToLogic
? mpRefDevice
->PixelToLogic(aAreaParam
.maClipRect
)
3246 : aAreaParam
.maClipRect
, bClip
, bSimClip
, mpDev
, bMetaFile
);
3249 if (rParam
.mbPixelToLogic
)
3250 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
3252 aLogicStart
= Point(nStartX
, nStartY
);
3254 if (!rParam
.mbBreak
)
3256 // horizontal alignment
3257 if (rParam
.adjustHorAlignment(rParam
.mpEngine
))
3258 // reset adjustment for the next cell
3259 rParam
.mpOldPattern
= nullptr;
3262 if (rParam
.meVerJust
==SvxCellVerJustify::Bottom
||
3263 rParam
.meVerJust
==SvxCellVerJustify::Standard
)
3265 //! if pRefDevice != pFmtDevice, keep heights in logic units,
3266 //! only converting margin?
3268 if (rParam
.mbPixelToLogic
)
3269 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0, nTopM
+
3270 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
3271 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
3274 aLogicStart
.AdjustY(nTopM
+ aCellSize
.Height() - nEngineHeight
);
3276 else if (rParam
.meVerJust
==SvxCellVerJustify::Center
)
3278 if (rParam
.mbPixelToLogic
)
3279 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0, nTopM
+ (
3280 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
3281 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height() )
3284 aLogicStart
.AdjustY(nTopM
+ (aCellSize
.Height() - nEngineHeight
) / 2 );
3288 if (rParam
.mbPixelToLogic
)
3289 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height() );
3291 aLogicStart
.AdjustY(nTopM
);
3294 aURLStart
= aLogicStart
; // copy before modifying for orientation
3296 // bMoveClipped handling has been replaced by complete alignment
3297 // handling (also extending to the left).
3301 // no hard clip, only draw the affected rows
3302 Point aDocStart
= aClip
.getRect().TopLeft();
3303 aDocStart
-= aLogicStart
;
3304 rParam
.mpEngine
->Draw(*mpDev
, aClip
.getRect(), aDocStart
, false);
3308 rParam
.mpEngine
->Draw(*mpDev
, aLogicStart
);
3312 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3315 void ScOutputData::SetClipMarks( OutputAreaParam
&aAreaParam
, ScCellInfo
* pClipMarkCell
,
3316 SvxCellHorJustify eOutHorJust
,
3317 tools::Long nLayoutSign
)
3319 tools::Long nMarkPixel
= SC_CLIPMARK_SIZE
* mnPPTX
;
3321 if ( eOutHorJust
== SvxCellHorJustify::Left
)
3323 pClipMarkCell
->nClipMark
|= ScClipMark::Right
;
3325 aAreaParam
.maClipRect
.AdjustRight( -( nMarkPixel
* nLayoutSign
) );
3327 else if ( eOutHorJust
== SvxCellHorJustify::Right
)
3329 pClipMarkCell
->nClipMark
|= ScClipMark::Left
;
3331 aAreaParam
.maClipRect
.AdjustLeft( nMarkPixel
* nLayoutSign
);
3335 pClipMarkCell
->nClipMark
|= ScClipMark::Right
;
3336 pClipMarkCell
->nClipMark
|= ScClipMark::Left
;
3338 aAreaParam
.maClipRect
.AdjustRight( -( nMarkPixel
* nLayoutSign
) );
3339 aAreaParam
.maClipRect
.AdjustLeft( nMarkPixel
* nLayoutSign
);
3344 void ScOutputData::ShowClipMarks( DrawEditParam
& rParam
, tools::Long nEngineWidth
, const Size
& aCellSize
,
3345 bool bMerged
, OutputAreaParam
& aAreaParam
, bool bTop
)
3347 // Show clip marks if width is at least 5pt too small and
3348 // there are several lines of text.
3349 // Not for asian vertical text, because that would interfere
3350 // with the default right position of the text.
3351 // Only with automatic line breaks, to avoid having to find
3352 // the cells with the horizontal end of the text again.
3353 if (nEngineWidth
- aCellSize
.Width() <= 100 || !rParam
.mbBreak
|| !bMarkClipped
3354 || (rParam
.mpEngine
->GetParagraphCount() <= 1 && rParam
.mpEngine
->GetLineCount(0) <= 1))
3357 ScCellInfo
* pClipMarkCell
= nullptr;
3360 // anywhere in the merged area...
3361 SCCOL nClipX
= (rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
3362 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].cellInfo(nClipX
);
3365 pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
3369 const tools::Long nMarkPixel
= static_cast<tools::Long
>(SC_CLIPMARK_SIZE
* mnPPTX
);
3372 pClipMarkCell
->nClipMark
|= ScClipMark::Top
;
3373 if (aAreaParam
.maClipRect
.Top() - nMarkPixel
< aAreaParam
.maClipRect
.Bottom())
3374 aAreaParam
.maClipRect
.AdjustTop(+nMarkPixel
);
3378 pClipMarkCell
->nClipMark
|= ScClipMark::Bottom
;
3379 if (aAreaParam
.maClipRect
.Top() - nMarkPixel
< aAreaParam
.maClipRect
.Bottom())
3380 aAreaParam
.maClipRect
.AdjustBottom(-nMarkPixel
);
3384 ClearableClipRegionPtr
ScOutputData::Clip( DrawEditParam
& rParam
, const Size
& aCellSize
,
3385 OutputAreaParam
& aAreaParam
, tools::Long nEngineWidth
,
3386 bool bWrapFields
, bool bTop
)
3388 // Also take fields in a cell with automatic breaks into account: clip to cell width
3389 bool bClip
= AdjustAreaParamClipRect(aAreaParam
) || aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
|| bWrapFields
;
3390 bool bSimClip
= false;
3392 const Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
3393 if ( nEngineWidth
>= aCellSize
.Width() + aRefOne
.Width() )
3395 const ScMergeAttr
* pMerge
= &rParam
.mpPattern
->GetItem(ATTR_MERGE
);
3396 const bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
3398 // Don't clip for text height when printing rows with optimal height,
3399 // except when font size is from conditional formatting.
3400 //! Allow clipping when vertically merged?
3401 if ( eType
!= OUTTYPE_PRINTER
||
3402 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CRFlags::ManualSize
) ||
3403 ( rParam
.mpCondSet
&& SfxItemState::SET
==
3404 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
3409 ShowClipMarks( rParam
, nEngineWidth
, aCellSize
, bMerged
, aAreaParam
, bTop
);
3412 // Clip marks are already handled in GetOutputArea
3413 return ClearableClipRegionPtr(new ClearableClipRegion(rParam
.mbPixelToLogic
?
3414 mpRefDevice
->PixelToLogic(aAreaParam
.maClipRect
)
3415 : aAreaParam
.maClipRect
, bClip
, bSimClip
, mpDev
, bMetaFile
));
3418 void ScOutputData::DrawEditBottomTop(DrawEditParam
& rParam
)
3420 OSL_ASSERT(rParam
.meHorJustAttr
!= SvxCellHorJustify::Repeat
);
3422 const bool bRepeat
= (rParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
&& !rParam
.mbBreak
);
3423 const bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3425 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3427 //! mirror margin values for RTL?
3428 //! move margin down to after final GetOutputArea call
3429 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
3430 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3432 SCCOL nXForPos
= rParam
.mnX
;
3433 if ( nXForPos
< nX1
)
3436 rParam
.mnPosX
= rParam
.mnInitPosX
;
3438 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3439 if ( nArrYForPos
< 1 )
3442 rParam
.mnPosY
= nScrY
;
3445 OutputAreaParam aAreaParam
;
3447 // Initial page size - large for normal text, cell size for automatic line breaks
3449 Size
aPaperSize( 1000000, 1000000 );
3452 // call GetOutputArea with nNeeded=0, to get only the cell width
3454 //! handle nArrY == 0
3455 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3456 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3457 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3459 //! special ScEditUtil handling if formatting for printer
3460 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3462 if (rParam
.mbPixelToLogic
)
3464 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3465 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3468 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3470 // Fill the EditEngine (cell attributes and text)
3472 rParam
.setPatternToEngine(mbUseStyleColor
);
3473 rParam
.setAlignmentToEngine();
3475 // Read content from cell
3477 bool bWrapFields
= false;
3478 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3479 // Failed to read cell content. Bail out.
3483 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3484 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3485 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3487 rParam
.mpEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3489 // Get final output area using the calculated width
3491 tools::Long nEngineWidth
, nEngineHeight
;
3492 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3494 tools::Long nNeededPixel
= nEngineWidth
;
3495 if (rParam
.mbPixelToLogic
)
3496 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3497 nNeededPixel
+= nLeftM
+ nRightM
;
3499 if (!rParam
.mbBreak
|| bShrink
)
3501 // for break, the first GetOutputArea call is sufficient
3502 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3503 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3504 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
3508 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3509 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
3510 (rParam
.meOrient
), 0_deg100
, rParam
.mbPixelToLogic
,
3511 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3512 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3514 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
3516 // First check if twice the space for the formatted text is available
3517 // (otherwise just keep it unchanged).
3519 const tools::Long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
3520 const tools::Long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
3521 if ( nAvailable
>= 2 * nFormatted
)
3523 // "repeat" is handled with unformatted text (for performance reasons)
3524 OUString aCellStr
= rParam
.mpEngine
->GetText();
3526 tools::Long nRepeatSize
= 0;
3527 SetEngineTextAndGetWidth( rParam
, aCellStr
, nRepeatSize
, 0 );
3528 if ( pFmtDevice
!= mpRefDevice
)
3530 if ( nRepeatSize
> 0 )
3532 const tools::Long nRepeatCount
= nAvailable
/ nRepeatSize
;
3533 if ( nRepeatCount
> 1 )
3535 OUStringBuffer
aRepeated(aCellStr
);
3536 for ( tools::Long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
3537 aRepeated
.append(aCellStr
);
3539 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, aRepeated
.makeStringAndClear(),
3540 nNeededPixel
, (nLeftM
+ nRightM
) );
3542 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
3547 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
3549 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, u
"###"_ustr
, nNeededPixel
, ( nLeftM
+ nRightM
) );
3551 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3555 tools::Long nStartX
= aAreaParam
.maAlignRect
.Left();
3556 const tools::Long nStartY
= aAreaParam
.maAlignRect
.Top();
3557 const tools::Long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3558 const tools::Long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3559 const tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3563 // text with automatic breaks is aligned only within the
3564 // edit engine's paper size, the output of the whole area
3565 // is always left-aligned
3571 if ( eOutHorJust
== SvxCellHorJustify::Right
)
3572 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3573 else if ( eOutHorJust
== SvxCellHorJustify::Center
)
3574 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3579 const bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3583 // output area, excluding margins, in logical units
3584 const Size aCellSize
= rParam
.mbPixelToLogic
3585 ? mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) )
3586 : Size( nOutWidth
, nOutHeight
);
3591 const auto pClipRegion
= Clip( rParam
, aCellSize
, aAreaParam
, nEngineWidth
, bWrapFields
, true );
3593 Point
aLogicStart(nStartX
, nStartY
);
3594 rParam
.calcStartPosForVertical(aLogicStart
, aCellSize
.Width(), nEngineWidth
, nTopM
, mpRefDevice
);
3596 aURLStart
= aLogicStart
; // copy before modifying for orientation
3598 if (rParam
.meHorJustResult
== SvxCellHorJustify::Block
|| rParam
.mbBreak
)
3600 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3601 aPSize
.setWidth( aCellSize
.Height() );
3602 rParam
.mpEngine
->SetPaperSize(aPSize
);
3603 aLogicStart
.AdjustY(
3604 rParam
.mbBreak
? aPSize
.Width() : nEngineHeight
);
3608 // Note that the "paper" is rotated 90 degrees to the left, so
3609 // paper's width is in vertical direction. Also, the whole text
3610 // is on a single line, as text wrap is not in effect.
3612 // Set the paper width to be the width of the text.
3613 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3614 aPSize
.setWidth( rParam
.mpEngine
->CalcTextWidth() );
3615 rParam
.mpEngine
->SetPaperSize(aPSize
);
3617 tools::Long nGap
= 0;
3618 tools::Long nTopOffset
= 0;
3619 if (rParam
.mbPixelToLogic
)
3621 nGap
= mpRefDevice
->LogicToPixel(aCellSize
).Height() - mpRefDevice
->LogicToPixel(aPSize
).Width();
3622 nGap
= mpRefDevice
->PixelToLogic(Size(0, nGap
)).Height();
3623 nTopOffset
= mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
3627 nGap
= aCellSize
.Height() - aPSize
.Width();
3631 // First, align text to bottom.
3632 aLogicStart
.AdjustY(aCellSize
.Height() );
3633 aLogicStart
.AdjustY(nTopOffset
);
3635 switch (rParam
.meVerJust
)
3637 case SvxCellVerJustify::Standard
:
3638 case SvxCellVerJustify::Bottom
:
3639 // align to bottom (do nothing).
3641 case SvxCellVerJustify::Center
:
3643 aLogicStart
.AdjustY( -(nGap
/ 2) );
3645 case SvxCellVerJustify::Block
:
3646 case SvxCellVerJustify::Top
:
3648 aLogicStart
.AdjustY( -nGap
);
3655 rParam
.mpEngine
->Draw(*mpDev
, aLogicStart
, 900_deg10
);
3658 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3661 void ScOutputData::DrawEditTopBottom(DrawEditParam
& rParam
)
3663 OSL_ASSERT(rParam
.meHorJustAttr
!= SvxCellHorJustify::Repeat
);
3665 const bool bRepeat
= (rParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
&& !rParam
.mbBreak
);
3666 const bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3668 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3670 //! mirror margin values for RTL?
3671 //! move margin down to after final GetOutputArea call
3672 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
3673 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3675 SCCOL nXForPos
= rParam
.mnX
;
3676 if ( nXForPos
< nX1
)
3679 rParam
.mnPosX
= rParam
.mnInitPosX
;
3681 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3682 if ( nArrYForPos
< 1 )
3685 rParam
.mnPosY
= nScrY
;
3688 OutputAreaParam aAreaParam
;
3690 // Initial page size - large for normal text, cell size for automatic line breaks
3692 Size
aPaperSize( 1000000, 1000000 );
3693 if (rParam
.hasLineBreak())
3695 // call GetOutputArea with nNeeded=0, to get only the cell width
3697 //! handle nArrY == 0
3698 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3699 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3700 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3702 //! special ScEditUtil handling if formatting for printer
3703 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3705 if (rParam
.mbPixelToLogic
)
3707 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3708 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3711 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3713 // Fill the EditEngine (cell attributes and text)
3715 rParam
.setPatternToEngine(mbUseStyleColor
);
3716 rParam
.setAlignmentToEngine();
3718 // Read content from cell
3720 bool bWrapFields
= false;
3721 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3722 // Failed to read cell content. Bail out.
3726 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3727 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3728 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3730 rParam
.mpEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3732 // Get final output area using the calculated width
3734 tools::Long nEngineWidth
, nEngineHeight
;
3735 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3737 tools::Long nNeededPixel
= nEngineWidth
;
3738 if (rParam
.mbPixelToLogic
)
3739 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3740 nNeededPixel
+= nLeftM
+ nRightM
;
3742 if (!rParam
.mbBreak
|| bShrink
)
3744 // for break, the first GetOutputArea call is sufficient
3745 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
3746 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3747 rParam
.mbCellIsValue
|| bRepeat
|| bShrink
, false, false, aAreaParam
);
3751 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
3752 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
3753 rParam
.meOrient
, 0_deg100
, rParam
.mbPixelToLogic
,
3754 nEngineWidth
, nEngineHeight
, nNeededPixel
,
3755 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
3757 if ( bRepeat
&& !aAreaParam
.mbLeftClip
&& !aAreaParam
.mbRightClip
&& rParam
.mpEngine
->GetParagraphCount() == 1 )
3759 // First check if twice the space for the formatted text is available
3760 // (otherwise just keep it unchanged).
3762 const tools::Long nFormatted
= nNeededPixel
- nLeftM
- nRightM
; // without margin
3763 const tools::Long nAvailable
= aAreaParam
.maAlignRect
.GetWidth() - nLeftM
- nRightM
;
3764 if ( nAvailable
>= 2 * nFormatted
)
3766 // "repeat" is handled with unformatted text (for performance reasons)
3767 OUString aCellStr
= rParam
.mpEngine
->GetText();
3769 tools::Long nRepeatSize
= 0;
3770 SetEngineTextAndGetWidth( rParam
, aCellStr
, nRepeatSize
, 0 );
3772 if ( pFmtDevice
!= mpRefDevice
)
3774 if ( nRepeatSize
> 0 )
3776 const tools::Long nRepeatCount
= nAvailable
/ nRepeatSize
;
3777 if ( nRepeatCount
> 1 )
3779 OUStringBuffer
aRepeated(aCellStr
);
3780 for ( tools::Long nRepeat
= 1; nRepeat
< nRepeatCount
; nRepeat
++ )
3781 aRepeated
.append(aCellStr
);
3783 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, aRepeated
.makeStringAndClear(),
3784 nNeededPixel
, (nLeftM
+ nRightM
) );
3786 nEngineHeight
= rParam
.mpEngine
->GetTextHeight();
3791 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
3793 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, u
"###"_ustr
, nNeededPixel
, ( nLeftM
+ nRightM
) );
3795 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3799 tools::Long nStartX
= aAreaParam
.maAlignRect
.Left();
3800 const tools::Long nStartY
= aAreaParam
.maAlignRect
.Top();
3801 const tools::Long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
3802 const tools::Long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
3803 const tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
3807 // text with automatic breaks is aligned only within the
3808 // edit engine's paper size, the output of the whole area
3809 // is always left-aligned
3812 if (rParam
.meHorJustResult
== SvxCellHorJustify::Block
)
3813 nStartX
+= aPaperSize
.Height();
3817 if ( eOutHorJust
== SvxCellHorJustify::Right
)
3818 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
3819 else if ( eOutHorJust
== SvxCellHorJustify::Center
)
3820 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
3825 const bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
3829 // output area, excluding margins, in logical units
3830 const Size aCellSize
= rParam
.mbPixelToLogic
3831 ? mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) )
3832 : Size( nOutWidth
, nOutHeight
);
3837 const auto pClipRegion
= Clip( rParam
, aCellSize
, aAreaParam
, nEngineWidth
, bWrapFields
, false );
3839 Point
aLogicStart(nStartX
, nStartY
);
3840 rParam
.calcStartPosForVertical(aLogicStart
, aCellSize
.Width(), nEngineWidth
, nTopM
, mpRefDevice
);
3842 aURLStart
= aLogicStart
; // copy before modifying for orientation
3844 if (rParam
.meHorJustResult
!= SvxCellHorJustify::Block
)
3846 aLogicStart
.AdjustX(nEngineWidth
);
3847 if (!rParam
.mbBreak
)
3849 // Set the paper width to text size.
3850 Size aPSize
= rParam
.mpEngine
->GetPaperSize();
3851 aPSize
.setWidth( rParam
.mpEngine
->CalcTextWidth() );
3852 rParam
.mpEngine
->SetPaperSize(aPSize
);
3854 tools::Long nGap
= 0;
3855 tools::Long nTopOffset
= 0; // offset by top margin
3856 if (rParam
.mbPixelToLogic
)
3858 nGap
= mpRefDevice
->LogicToPixel(aPSize
).Width() - mpRefDevice
->LogicToPixel(aCellSize
).Height();
3859 nGap
= mpRefDevice
->PixelToLogic(Size(0, nGap
)).Height();
3860 nTopOffset
= mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height();
3864 nGap
= aPSize
.Width() - aCellSize
.Height();
3867 aLogicStart
.AdjustY(nTopOffset
);
3869 switch (rParam
.meVerJust
)
3871 case SvxCellVerJustify::Standard
:
3872 case SvxCellVerJustify::Bottom
:
3874 aLogicStart
.AdjustY( -nGap
);
3876 case SvxCellVerJustify::Center
:
3878 aLogicStart
.AdjustY( -(nGap
/ 2) );
3880 case SvxCellVerJustify::Block
:
3881 case SvxCellVerJustify::Top
:
3882 // align to top (do nothing)
3889 // bMoveClipped handling has been replaced by complete alignment
3890 // handling (also extending to the left).
3892 rParam
.mpEngine
->Draw(*mpDev
, aLogicStart
, 2700_deg10
);
3895 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
3898 void ScOutputData::DrawEditStacked(DrawEditParam
& rParam
)
3900 OSL_ASSERT(rParam
.meHorJustAttr
!= SvxCellHorJustify::Repeat
);
3901 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
3903 bool bRepeat
= (rParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
&& !rParam
.mbBreak
);
3904 bool bShrink
= !rParam
.mbBreak
&& !bRepeat
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
3906 rParam
.mbAsianVertical
=
3907 lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_VERTICAL_ASIAN
, rParam
.mpCondSet
);
3909 if ( rParam
.mbAsianVertical
)
3911 // in asian mode, use EditEngine::SetVertical instead of EEControlBits::ONECHARPERLINE
3912 rParam
.meOrient
= SvxCellOrientation::Standard
;
3913 DrawEditAsianVertical(rParam
);
3917 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
3919 //! mirror margin values for RTL?
3920 //! move margin down to after final GetOutputArea call
3921 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
3922 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
3924 SCCOL nXForPos
= rParam
.mnX
;
3925 if ( nXForPos
< nX1
)
3928 rParam
.mnPosX
= rParam
.mnInitPosX
;
3930 SCSIZE nArrYForPos
= rParam
.mnArrY
;
3931 if ( nArrYForPos
< 1 )
3934 rParam
.mnPosY
= nScrY
;
3937 OutputAreaParam aAreaParam
;
3939 // Initial page size - large for normal text, cell size for automatic line breaks
3941 Size
aPaperSize( 1000000, 1000000 );
3942 // call GetOutputArea with nNeeded=0, to get only the cell width
3944 //! handle nArrY == 0
3945 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
3946 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
3947 rParam
.mbCellIsValue
, true, false, aAreaParam
);
3949 //! special ScEditUtil handling if formatting for printer
3950 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
3952 if (rParam
.mbPixelToLogic
)
3954 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
3955 if ( rParam
.mbBreak
&& mpRefDevice
!= pFmtDevice
)
3957 // #i85342# screen display and formatting for printer,
3958 // use same GetEditArea call as in ScViewData::SetEditEngine
3960 Fraction
aFract(1,1);
3961 tools::Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
3962 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
3963 aLogicSize
.setWidth( aUtilRect
.GetWidth() );
3965 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
3968 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
3970 // Fill the EditEngine (cell attributes and text)
3972 rParam
.setPatternToEngine(mbUseStyleColor
);
3973 rParam
.setAlignmentToEngine();
3975 // Read content from cell
3977 bool bWrapFields
= false;
3978 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
3979 // Failed to read cell content. Bail out.
3983 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
3984 else if ( mbUseStyleColor
&& mbForceAutoColor
)
3985 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
3987 rParam
.mpEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3989 // Get final output area using the calculated width
3991 tools::Long nEngineWidth
, nEngineHeight
;
3992 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
3994 tools::Long nNeededPixel
= nEngineWidth
;
3995 if (rParam
.mbPixelToLogic
)
3996 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
3997 nNeededPixel
+= nLeftM
+ nRightM
;
4001 // for break, the first GetOutputArea call is sufficient
4002 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
4003 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
4004 true, false, false, aAreaParam
);
4006 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
4007 nLeftM
, nTopM
, nRightM
, nBottomM
, true,
4008 rParam
.meOrient
, 0_deg100
, rParam
.mbPixelToLogic
,
4009 nEngineWidth
, nEngineHeight
, nNeededPixel
,
4010 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
4012 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
4014 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, u
"###"_ustr
, nNeededPixel
, ( nLeftM
+ nRightM
) );
4015 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
4016 ScCellInfo
* pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
4017 SetClipMarks( aAreaParam
, pClipMarkCell
, eOutHorJust
, nLayoutSign
);
4020 if ( eOutHorJust
!= SvxCellHorJustify::Left
)
4022 aPaperSize
.setWidth( nNeededPixel
+ 1 );
4023 if (rParam
.mbPixelToLogic
)
4024 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4026 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
4030 tools::Long nStartX
= aAreaParam
.maAlignRect
.Left();
4031 tools::Long nStartY
= aAreaParam
.maAlignRect
.Top();
4032 tools::Long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
4033 tools::Long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
4034 tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
4038 // text with automatic breaks is aligned only within the
4039 // edit engine's paper size, the output of the whole area
4040 // is always left-aligned
4046 if ( eOutHorJust
== SvxCellHorJustify::Right
)
4047 nStartX
-= nNeededPixel
- nCellWidth
+ nRightM
+ 1;
4048 else if ( eOutHorJust
== SvxCellHorJustify::Center
)
4049 nStartX
-= ( nNeededPixel
- nCellWidth
+ nRightM
+ 1 - nLeftM
) / 2;
4054 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
4058 // Also take fields in a cell with automatic breaks into account: clip to cell width
4059 bool bClip
= AdjustAreaParamClipRect(aAreaParam
) || aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
|| bWrapFields
;
4060 bool bSimClip
= false;
4062 Size aCellSize
; // output area, excluding margins, in logical units
4063 if (rParam
.mbPixelToLogic
)
4064 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
4066 aCellSize
= Size( nOutWidth
, nOutHeight
);
4068 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
4070 const ScMergeAttr
* pMerge
= &rParam
.mpPattern
->GetItem(ATTR_MERGE
);
4071 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4073 // Don't clip for text height when printing rows with optimal height,
4074 // except when font size is from conditional formatting.
4075 //! Allow clipping when vertically merged?
4076 if ( eType
!= OUTTYPE_PRINTER
||
4077 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CRFlags::ManualSize
) ||
4078 ( rParam
.mpCondSet
&& SfxItemState::SET
==
4079 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
4084 // Show clip marks if height is at least 5pt too small and
4085 // there are several lines of text.
4086 // Not for asian vertical text, because that would interfere
4087 // with the default right position of the text.
4088 // Only with automatic line breaks, to avoid having to find
4089 // the cells with the horizontal end of the text again.
4090 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
4091 rParam
.mbBreak
&& bMarkClipped
&&
4092 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
4094 ScCellInfo
* pClipMarkCell
= nullptr;
4097 // anywhere in the merged area...
4098 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
4099 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].cellInfo(nClipX
);
4102 pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
4104 pClipMarkCell
->nClipMark
|= ScClipMark::Right
; //! also allow left?
4107 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
4108 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
4109 aAreaParam
.maClipRect
.AdjustRight( -nMarkPixel
);
4115 { // Clip marks are already handled in GetOutputArea
4116 ClearableClipRegion
aClip(rParam
.mbPixelToLogic
? mpRefDevice
->PixelToLogic(aAreaParam
.maClipRect
)
4117 : aAreaParam
.maClipRect
, bClip
, bSimClip
, mpDev
, bMetaFile
);
4120 if (rParam
.mbPixelToLogic
)
4121 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
4123 aLogicStart
= Point(nStartX
, nStartY
);
4125 if (rParam
.meVerJust
==SvxCellVerJustify::Bottom
||
4126 rParam
.meVerJust
==SvxCellVerJustify::Standard
)
4128 //! if pRefDevice != pFmtDevice, keep heights in logic units,
4129 //! only converting margin?
4131 if (rParam
.mbPixelToLogic
)
4132 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0, nTopM
+
4133 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
4134 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
4137 aLogicStart
.AdjustY(nTopM
+ aCellSize
.Height() - nEngineHeight
);
4139 else if (rParam
.meVerJust
==SvxCellVerJustify::Center
)
4141 if (rParam
.mbPixelToLogic
)
4142 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0, nTopM
+ (
4143 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
4144 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height() )
4147 aLogicStart
.AdjustY(nTopM
+ (aCellSize
.Height() - nEngineHeight
) / 2 );
4151 if (rParam
.mbPixelToLogic
)
4152 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height() );
4154 aLogicStart
.AdjustY(nTopM
);
4157 aURLStart
= aLogicStart
; // copy before modifying for orientation
4159 Size aPaperLogic
= rParam
.mpEngine
->GetPaperSize();
4160 aPaperLogic
.setWidth( nEngineWidth
);
4161 rParam
.mpEngine
->SetPaperSize(aPaperLogic
);
4163 // bMoveClipped handling has been replaced by complete alignment
4164 // handling (also extending to the left).
4168 // no hard clip, only draw the affected rows
4169 Point aDocStart
= aClip
.getRect().TopLeft();
4170 aDocStart
-= aLogicStart
;
4171 rParam
.mpEngine
->Draw(*mpDev
, aClip
.getRect(), aDocStart
, false);
4175 rParam
.mpEngine
->Draw(*mpDev
, aLogicStart
);
4179 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
4182 void ScOutputData::DrawEditAsianVertical(DrawEditParam
& rParam
)
4184 // When in asian vertical orientation, the orientation value is STANDARD,
4185 // and the asian vertical boolean is true.
4186 OSL_ASSERT(rParam
.meOrient
== SvxCellOrientation::Standard
);
4187 OSL_ASSERT(rParam
.mbAsianVertical
);
4188 OSL_ASSERT(rParam
.meHorJustAttr
!= SvxCellHorJustify::Repeat
);
4190 Size aRefOne
= mpRefDevice
->PixelToLogic(Size(1,1));
4192 bool bHidden
= false;
4193 bool bShrink
= !rParam
.mbBreak
&& lcl_GetBoolValue(*rParam
.mpPattern
, ATTR_SHRINKTOFIT
, rParam
.mpCondSet
);
4194 Degree100 nAttrRotate
= lcl_GetValue
<ScRotateValueItem
, Degree100
>(*rParam
.mpPattern
, ATTR_ROTATE_VALUE
, rParam
.mpCondSet
);
4198 //! set flag to find the cell in DrawRotated again ?
4199 //! (or flag already set during DrawBackground, then no query here)
4200 bHidden
= true; // rotated is outputted separately
4203 // default alignment for asian vertical mode is top-right
4204 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4205 * SvxCellHorJustify::Right really wanted? Seems this was done all the time,
4206 * also before context was introduced and everything was attr only. */
4207 if ( rParam
.meHorJustAttr
== SvxCellHorJustify::Standard
)
4208 rParam
.meHorJustResult
= rParam
.meHorJustContext
= SvxCellHorJustify::Right
;
4213 SvxCellHorJustify eOutHorJust
= rParam
.meHorJustContext
;
4215 //! mirror margin values for RTL?
4216 //! move margin down to after final GetOutputArea call
4217 tools::Long nTopM
, nLeftM
, nBottomM
, nRightM
;
4218 rParam
.calcMargins(nTopM
, nLeftM
, nBottomM
, nRightM
, mnPPTX
, mnPPTY
);
4220 SCCOL nXForPos
= rParam
.mnX
;
4221 if ( nXForPos
< nX1
)
4224 rParam
.mnPosX
= rParam
.mnInitPosX
;
4226 SCSIZE nArrYForPos
= rParam
.mnArrY
;
4227 if ( nArrYForPos
< 1 )
4230 rParam
.mnPosY
= nScrY
;
4233 OutputAreaParam aAreaParam
;
4235 // Initial page size - large for normal text, cell size for automatic line breaks
4237 Size
aPaperSize( 1000000, 1000000 );
4238 // call GetOutputArea with nNeeded=0, to get only the cell width
4240 //! handle nArrY == 0
4241 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, 0,
4242 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
4243 rParam
.mbCellIsValue
, true, false, aAreaParam
);
4245 //! special ScEditUtil handling if formatting for printer
4246 rParam
.calcPaperSize(aPaperSize
, aAreaParam
.maAlignRect
, mnPPTX
, mnPPTY
);
4248 if (rParam
.mbPixelToLogic
)
4250 Size aLogicSize
= mpRefDevice
->PixelToLogic(aPaperSize
);
4251 if ( rParam
.mbBreak
&& !rParam
.mbAsianVertical
&& mpRefDevice
!= pFmtDevice
)
4253 // #i85342# screen display and formatting for printer,
4254 // use same GetEditArea call as in ScViewData::SetEditEngine
4256 Fraction
aFract(1,1);
4257 tools::Rectangle aUtilRect
= ScEditUtil( mpDoc
, rParam
.mnCellX
, rParam
.mnCellY
, nTab
, Point(0,0), pFmtDevice
,
4258 HMM_PER_TWIPS
, HMM_PER_TWIPS
, aFract
, aFract
).GetEditArea( rParam
.mpPattern
, false );
4259 aLogicSize
.setWidth( aUtilRect
.GetWidth() );
4261 rParam
.mpEngine
->SetPaperSize(aLogicSize
);
4264 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
4266 // Fill the EditEngine (cell attributes and text)
4268 // default alignment for asian vertical mode is top-right
4269 if ( rParam
.meVerJust
== SvxCellVerJustify::Standard
)
4270 rParam
.meVerJust
= SvxCellVerJustify::Top
;
4272 rParam
.setPatternToEngine(mbUseStyleColor
);
4273 rParam
.setAlignmentToEngine();
4275 // Read content from cell
4277 bool bWrapFields
= false;
4278 if (!rParam
.readCellContent(mpDoc
, mbShowNullValues
, mbShowFormulas
, mbSyntaxMode
, mbUseStyleColor
, mbForceAutoColor
, bWrapFields
))
4279 // Failed to read cell content. Bail out.
4283 SetEditSyntaxColor( *rParam
.mpEngine
, rParam
.maCell
);
4284 else if ( mbUseStyleColor
&& mbForceAutoColor
)
4285 lcl_SetEditColor( *rParam
.mpEngine
, COL_AUTO
); //! or have a flag at EditEngine
4287 rParam
.mpEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
4289 // Get final output area using the calculated width
4291 tools::Long nEngineWidth
, nEngineHeight
;
4292 rParam
.getEngineSize(rParam
.mpEngine
, nEngineWidth
, nEngineHeight
);
4294 tools::Long nNeededPixel
= nEngineWidth
;
4295 if (rParam
.mbPixelToLogic
)
4296 nNeededPixel
= mpRefDevice
->LogicToPixel(Size(nNeededPixel
,0)).Width();
4297 nNeededPixel
+= nLeftM
+ nRightM
;
4299 // for break, the first GetOutputArea call is sufficient
4300 GetOutputArea( nXForPos
, nArrYForPos
, rParam
.mnPosX
, rParam
.mnPosY
, rParam
.mnCellX
, rParam
.mnCellY
, nNeededPixel
,
4301 *rParam
.mpPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
4302 rParam
.mbCellIsValue
|| bShrink
, false, false, aAreaParam
);
4306 ShrinkEditEngine( *rParam
.mpEngine
, aAreaParam
.maAlignRect
,
4307 nLeftM
, nTopM
, nRightM
, nBottomM
, false,
4308 rParam
.meOrient
, 0_deg100
, rParam
.mbPixelToLogic
,
4309 nEngineWidth
, nEngineHeight
, nNeededPixel
,
4310 aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
4312 if ( rParam
.mbCellIsValue
&& ( aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
) )
4314 nEngineWidth
= SetEngineTextAndGetWidth( rParam
, u
"###"_ustr
, nNeededPixel
, ( nLeftM
+ nRightM
) );
4315 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
4316 ScCellInfo
* pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
4317 SetClipMarks( aAreaParam
, pClipMarkCell
, eOutHorJust
, nLayoutSign
);
4320 if (eOutHorJust
!= SvxCellHorJustify::Left
)
4322 aPaperSize
.setWidth( nNeededPixel
+ 1 );
4323 if (rParam
.mbPixelToLogic
)
4324 rParam
.mpEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4326 rParam
.mpEngine
->SetPaperSize(aPaperSize
);
4329 tools::Long nStartX
= aAreaParam
.maAlignRect
.Left();
4330 tools::Long nStartY
= aAreaParam
.maAlignRect
.Top();
4331 tools::Long nCellWidth
= aAreaParam
.maAlignRect
.GetWidth();
4332 tools::Long nOutWidth
= nCellWidth
- 1 - nLeftM
- nRightM
;
4333 tools::Long nOutHeight
= aAreaParam
.maAlignRect
.GetHeight() - nTopM
- nBottomM
;
4335 // text with automatic breaks is aligned only within the
4336 // edit engine's paper size, the output of the whole area
4337 // is always left-aligned
4341 bool bOutside
= (aAreaParam
.maClipRect
.Right() < nScrX
|| aAreaParam
.maClipRect
.Left() >= nScrX
+ nScrW
);
4345 // Also take fields in a cell with automatic breaks into account: clip to cell width
4346 bool bClip
= AdjustAreaParamClipRect(aAreaParam
) || aAreaParam
.mbLeftClip
|| aAreaParam
.mbRightClip
|| bWrapFields
;
4347 bool bSimClip
= false;
4349 Size aCellSize
; // output area, excluding margins, in logical units
4350 if (rParam
.mbPixelToLogic
)
4351 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
4353 aCellSize
= Size( nOutWidth
, nOutHeight
);
4355 if ( nEngineHeight
>= aCellSize
.Height() + aRefOne
.Height() )
4357 const ScMergeAttr
* pMerge
= &rParam
.mpPattern
->GetItem(ATTR_MERGE
);
4358 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4360 // Don't clip for text height when printing rows with optimal height,
4361 // except when font size is from conditional formatting.
4362 //! Allow clipping when vertically merged?
4363 if ( eType
!= OUTTYPE_PRINTER
||
4364 ( mpDoc
->GetRowFlags( rParam
.mnCellY
, nTab
) & CRFlags::ManualSize
) ||
4365 ( rParam
.mpCondSet
&& SfxItemState::SET
==
4366 rParam
.mpCondSet
->GetItemState(ATTR_FONT_HEIGHT
) ) )
4371 // Show clip marks if height is at least 5pt too small and
4372 // there are several lines of text.
4373 // Not for asian vertical text, because that would interfere
4374 // with the default right position of the text.
4375 // Only with automatic line breaks, to avoid having to find
4376 // the cells with the horizontal end of the text again.
4377 if ( nEngineHeight
- aCellSize
.Height() > 100 &&
4378 ( rParam
.mbBreak
|| rParam
.meOrient
== SvxCellOrientation::Stacked
) &&
4379 !rParam
.mbAsianVertical
&& bMarkClipped
&&
4380 ( rParam
.mpEngine
->GetParagraphCount() > 1 || rParam
.mpEngine
->GetLineCount(0) > 1 ) )
4382 ScCellInfo
* pClipMarkCell
= nullptr;
4385 // anywhere in the merged area...
4386 SCCOL nClipX
= ( rParam
.mnX
< nX1
) ? nX1
: rParam
.mnX
;
4387 pClipMarkCell
= &pRowInfo
[(rParam
.mnArrY
!= 0) ? rParam
.mnArrY
: 1].cellInfo(nClipX
);
4390 pClipMarkCell
= &rParam
.mpThisRowInfo
->cellInfo(rParam
.mnX
);
4392 pClipMarkCell
->nClipMark
|= ScClipMark::Right
; //! also allow left?
4395 tools::Long nMarkPixel
= static_cast<tools::Long
>( SC_CLIPMARK_SIZE
* mnPPTX
);
4396 if ( aAreaParam
.maClipRect
.Right() - nMarkPixel
> aAreaParam
.maClipRect
.Left() )
4397 aAreaParam
.maClipRect
.AdjustRight( -nMarkPixel
);
4403 { // Clip marks are already handled in GetOutputArea
4404 ClearableClipRegion
aClip(rParam
.mbPixelToLogic
? mpRefDevice
->PixelToLogic(aAreaParam
.maClipRect
)
4405 : aAreaParam
.maClipRect
, bClip
, bSimClip
, mpDev
, bMetaFile
);
4408 if (rParam
.mbPixelToLogic
)
4409 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
4411 aLogicStart
= Point(nStartX
, nStartY
);
4413 tools::Long nAvailWidth
= aCellSize
.Width();
4414 // space for AutoFilter is already handled in GetOutputArea
4416 // horizontal alignment
4418 if (rParam
.meHorJustResult
==SvxCellHorJustify::Right
)
4419 aLogicStart
.AdjustX(nAvailWidth
- nEngineWidth
);
4420 else if (rParam
.meHorJustResult
==SvxCellHorJustify::Center
)
4421 aLogicStart
.AdjustX((nAvailWidth
- nEngineWidth
) / 2 );
4423 // paper size is subtracted below
4424 aLogicStart
.AdjustX(nEngineWidth
);
4426 // vertical adjustment is within the EditEngine
4427 if (rParam
.mbPixelToLogic
)
4428 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic(Size(0,nTopM
)).Height() );
4430 aLogicStart
.AdjustY(nTopM
);
4432 aURLStart
= aLogicStart
; // copy before modifying for orientation
4434 // bMoveClipped handling has been replaced by complete alignment
4435 // handling (also extending to the left).
4437 // with SetVertical, the start position is top left of
4438 // the whole output area, not the text itself
4439 aLogicStart
.AdjustX( -(rParam
.mpEngine
->GetPaperSize().Width()) );
4441 rParam
.mpEngine
->Draw(*mpDev
, aLogicStart
);
4444 rParam
.adjustForHyperlinkInPDF(aURLStart
, mpDev
);
4447 void ScOutputData::DrawEdit(bool bPixelToLogic
)
4449 vcl::PDFExtOutDevData
* pPDF
= dynamic_cast<vcl::PDFExtOutDevData
*>(mpDev
->GetExtOutDevData());
4450 bool bTaggedPDF
= pPDF
&& pPDF
->GetIsExportTaggedPDF();
4452 InitOutputEditEngine();
4454 bool bHyphenatorSet
= false;
4455 const ScPatternAttr
* pOldPattern
= nullptr;
4456 const SfxItemSet
* pOldCondSet
= nullptr;
4457 const SfxItemSet
* pOldPreviewFontSet
= nullptr;
4458 ScRefCellValue aCell
;
4460 tools::Long nInitPosX
= nScrX
;
4463 nInitPosX
+= nMirrorW
- 1;
4465 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
4467 SCCOL nLastContentCol
= mpDoc
->MaxCol();
4468 if ( nX2
< mpDoc
->MaxCol() )
4471 mpDoc
->GetCellArea(nTab
, nLastContentCol
, nEndRow
);
4474 tools::Long nRowPosY
= nScrY
;
4475 for (SCSIZE nArrY
=0; nArrY
+1<nArrCount
; nArrY
++) // 0 of the rest of the merged
4477 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
4479 if (nArrY
==1) nRowPosY
= nScrY
; // positions before are calculated individually
4481 if ( pThisRowInfo
->bChanged
|| nArrY
==0 )
4483 tools::Long nPosX
= 0;
4484 for (SCCOL nX
=0; nX
<=nX2
; nX
++) // due to overflow
4486 std::unique_ptr
< ScPatternAttr
> pPreviewPattr
;
4487 if (nX
==nX1
) nPosX
= nInitPosX
; // positions before nX1 are calculated individually
4489 if (pThisRowInfo
->basicCellInfo(nX
).bEditEngine
)
4491 SCROW nY
= pThisRowInfo
->nRowNo
;
4493 bool bReopenTag
= false;
4495 bReopenTag
= ReopenPDFStructureElement(vcl::PDFWriter::TableData
, nY
, nX
);
4497 SCCOL nCellX
= nX
; // position where the cell really starts
4499 bool bDoCell
= false;
4501 // if merged cell contains hidden row or column or both
4502 const ScMergeFlagAttr
* pMergeFlag
= mpDoc
->GetAttr(nX
, nY
, nTab
, ATTR_MERGE_FLAG
);
4503 bool bOverlapped
= (pMergeFlag
->IsHorOverlapped() || pMergeFlag
->IsVerOverlapped());
4505 tools::Long nPosY
= nRowPosY
;
4508 nY
= pRowInfo
[nArrY
].nRowNo
;
4509 SCCOL nOverX
; // start of the merged cells
4511 if (GetMergeOrigin( nX
,nY
, nArrY
, nOverX
,nOverY
, true ))
4518 else if ( nX
== nX2
&& pThisRowInfo
->cellInfo(nX
).maCell
.isEmpty() )
4520 // Rest of a long text further to the right?
4523 while (nTempX
< nLastContentCol
&& IsEmptyCellText( pThisRowInfo
, nTempX
, nY
))
4527 !IsEmptyCellText( pThisRowInfo
, nTempX
, nY
) &&
4528 !mpDoc
->HasAttrib( nTempX
,nY
,nTab
, nX
,nY
,nTab
, HasAttrFlags::Merged
| HasAttrFlags::Overlapped
) )
4539 if ( bDoCell
&& bEditMode
&& nCellX
== nEditCol
&& nCellY
== nEditRow
)
4542 const ScPatternAttr
* pPattern
= nullptr;
4543 const SfxItemSet
* pCondSet
= nullptr;
4546 if ( nCellY
== nY
&& nCellX
>= nX1
&& nCellX
<= nX2
&&
4547 !mpDoc
->ColHidden(nCellX
, nTab
) )
4549 ScCellInfo
& rCellInfo
= pThisRowInfo
->cellInfo(nCellX
);
4550 pPattern
= rCellInfo
.pPatternAttr
;
4551 pCondSet
= rCellInfo
.pConditionSet
;
4552 aCell
= rCellInfo
.maCell
;
4554 else // get from document
4556 pPattern
= mpDoc
->GetPattern( nCellX
, nCellY
, nTab
);
4557 pCondSet
= mpDoc
->GetCondResult( nCellX
, nCellY
, nTab
);
4558 GetVisibleCell( nCellX
, nCellY
, nTab
, aCell
);
4560 if (aCell
.isEmpty())
4565 if ( mpDoc
->GetPreviewCellStyle() )
4567 if ( ScStyleSheet
* pPreviewStyle
= mpDoc
->GetPreviewCellStyle( nCellX
, nCellY
, nTab
) )
4569 pPreviewPattr
.reset( new ScPatternAttr(*pPattern
) );
4570 pPreviewPattr
->SetStyleSheet(pPreviewStyle
);
4571 pPattern
= pPreviewPattr
.get();
4574 SfxItemSet
* pPreviewFontSet
= mpDoc
->GetPreviewFont( nCellX
, nCellY
, nTab
);
4575 lcl_ClearEdit( *mxOutputEditEngine
); // also calls SetUpdateMode(sal_False)
4577 // fdo#32530: Check if the first character is RTL.
4578 OUString aStr
= mpDoc
->GetString(nCellX
, nCellY
, nTab
);
4580 DrawEditParam
aParam(pPattern
, pCondSet
, lcl_SafeIsValue(aCell
));
4581 const bool bNumberFormatIsText
= lcl_isNumberFormatText( mpDoc
, nCellX
, nCellY
, nTab
);
4582 aParam
.meHorJustContext
= getAlignmentFromContext( aParam
.meHorJustAttr
,
4583 aParam
.mbCellIsValue
, aStr
, *pPattern
, pCondSet
, mpDoc
, nTab
, bNumberFormatIsText
);
4584 aParam
.meHorJustResult
= (aParam
.meHorJustAttr
== SvxCellHorJustify::Block
) ?
4585 SvxCellHorJustify::Block
: aParam
.meHorJustContext
;
4586 aParam
.mbPixelToLogic
= bPixelToLogic
;
4587 aParam
.mbHyphenatorSet
= bHyphenatorSet
;
4588 aParam
.mpEngine
= mxOutputEditEngine
.get();
4589 aParam
.maCell
= aCell
;
4590 aParam
.mnArrY
= nArrY
;
4592 aParam
.mnCellX
= nCellX
;
4593 aParam
.mnCellY
= nCellY
;
4594 aParam
.mnPosX
= nPosX
;
4595 aParam
.mnPosY
= nPosY
;
4596 aParam
.mnInitPosX
= nInitPosX
;
4597 aParam
.mpPreviewFontSet
= pPreviewFontSet
;
4598 aParam
.mpOldPattern
= pOldPattern
;
4599 aParam
.mpOldCondSet
= pOldCondSet
;
4600 aParam
.mpOldPreviewFontSet
= pOldPreviewFontSet
;
4601 aParam
.mpThisRowInfo
= pThisRowInfo
;
4602 if (mpSpellCheckCxt
)
4603 aParam
.mpMisspellRanges
= mpSpellCheckCxt
->getMisspellRanges(nCellX
, nCellY
);
4605 if (aParam
.meHorJustAttr
== SvxCellHorJustify::Repeat
)
4607 // ignore orientation/rotation if "repeat" is active
4608 aParam
.meOrient
= SvxCellOrientation::Standard
;
4610 switch (aParam
.meOrient
)
4612 case SvxCellOrientation::BottomUp
:
4613 DrawEditBottomTop(aParam
);
4615 case SvxCellOrientation::TopBottom
:
4616 DrawEditTopBottom(aParam
);
4618 case SvxCellOrientation::Stacked
:
4619 // this can be vertically stacked or asian vertical.
4620 DrawEditStacked(aParam
);
4623 DrawEditStandard(aParam
);
4626 // Retrieve parameters for next iteration.
4627 pOldPattern
= aParam
.mpOldPattern
;
4628 pOldCondSet
= aParam
.mpOldCondSet
;
4629 pOldPreviewFontSet
= aParam
.mpOldPreviewFontSet
;
4630 bHyphenatorSet
= aParam
.mbHyphenatorSet
;
4633 pPDF
->EndStructureElement();
4635 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
4638 nRowPosY
+= pRowInfo
[nArrY
].nHeight
;
4641 if (mrTabInfo
.maArray
.HasCellRotation())
4643 DrawRotated(bPixelToLogic
); //! call from outside ?
4647 void ScOutputData::DrawRotated(bool bPixelToLogic
)
4649 InitOutputEditEngine();
4651 SCCOL nRotMax
= nX2
;
4652 for (SCSIZE nRotY
=0; nRotY
<nArrCount
; nRotY
++)
4653 if (pRowInfo
[nRotY
].nRotMaxCol
!= SC_ROTMAX_NONE
&& pRowInfo
[nRotY
].nRotMaxCol
> nRotMax
)
4654 nRotMax
= pRowInfo
[nRotY
].nRotMaxCol
;
4656 Color nConfBackColor
= GetConfBackgroundColor();
4657 bool bCellContrast
= mbUseStyleColor
&&
4658 Application::GetSettings().GetStyleSettings().GetHighContrastMode();
4660 bool bHyphenatorSet
= false;
4661 const ScPatternAttr
* pPattern
;
4662 const SfxItemSet
* pCondSet
;
4663 const ScPatternAttr
* pOldPattern
= nullptr;
4664 const SfxItemSet
* pOldCondSet
= nullptr;
4665 ScRefCellValue aCell
;
4667 tools::Long nInitPosX
= nScrX
;
4670 nInitPosX
+= nMirrorW
- 1;
4672 tools::Long nLayoutSign
= bLayoutRTL
? -1 : 1;
4674 tools::Long nRowPosY
= nScrY
;
4675 for (SCSIZE nArrY
=0; nArrY
+1<nArrCount
; nArrY
++) // 0 for the rest of the merged
4677 RowInfo
* pThisRowInfo
= &pRowInfo
[nArrY
];
4678 tools::Long nCellHeight
= static_cast<tools::Long
>(pThisRowInfo
->nHeight
);
4679 if (nArrY
==1) nRowPosY
= nScrY
; // positions before are calculated individually
4681 if ( ( pThisRowInfo
->bChanged
|| nArrY
==0 ) && pThisRowInfo
->nRotMaxCol
!= SC_ROTMAX_NONE
)
4683 tools::Long nPosX
= 0;
4684 for (SCCOL nX
=0; nX
<=nRotMax
; nX
++)
4686 if (nX
==nX1
) nPosX
= nInitPosX
; // positions before nX1 are calculated individually
4688 const ScCellInfo
* pInfo
= &pThisRowInfo
->cellInfo(nX
);
4689 if ( pInfo
->nRotateDir
!= ScRotateDir::NONE
)
4691 SCROW nY
= pThisRowInfo
->nRowNo
;
4693 bool bHidden
= false;
4695 if ( nX
== nEditCol
&& nY
== nEditRow
)
4700 lcl_ClearEdit( *mxOutputEditEngine
); // also calls SetUpdateMode(sal_False)
4702 tools::Long nPosY
= nRowPosY
;
4704 //! rest from merged cells further up do not work!
4706 bool bFromDoc
= false;
4707 pPattern
= pInfo
->pPatternAttr
;
4708 pCondSet
= pInfo
->pConditionSet
;
4711 pPattern
= mpDoc
->GetPattern( nX
, nY
, nTab
);
4714 aCell
= pInfo
->maCell
;
4716 pCondSet
= mpDoc
->GetCondResult( nX
, nY
, nTab
);
4718 if (aCell
.isEmpty() && nX
>nX2
)
4719 GetVisibleCell( nX
, nY
, nTab
, aCell
);
4721 if (aCell
.isEmpty() || IsEmptyCellText(pThisRowInfo
, nX
, nY
))
4722 bHidden
= true; // nRotateDir is also set without a cell
4724 tools::Long nCellWidth
= static_cast<tools::Long
>(pRowInfo
[0].basicCellInfo(nX
).nWidth
);
4726 SvxCellHorJustify eHorJust
=
4727 pPattern
->GetItem(ATTR_HOR_JUSTIFY
, pCondSet
).GetValue();
4728 bool bBreak
= ( eHorJust
== SvxCellHorJustify::Block
) ||
4729 pPattern
->GetItem(ATTR_LINEBREAK
, pCondSet
).GetValue();
4730 bool bRepeat
= ( eHorJust
== SvxCellHorJustify::Repeat
&& !bBreak
);
4731 bool bShrink
= !bBreak
&& !bRepeat
&&
4732 pPattern
->GetItem( ATTR_SHRINKTOFIT
, pCondSet
).GetValue();
4733 SvxCellOrientation eOrient
= pPattern
->GetCellOrientation( pCondSet
);
4735 const ScMergeAttr
* pMerge
= &pPattern
->GetItem(ATTR_MERGE
);
4736 bool bMerged
= pMerge
->GetColMerge() > 1 || pMerge
->GetRowMerge() > 1;
4738 tools::Long nStartX
= nPosX
;
4739 tools::Long nStartY
= nPosY
;
4742 if ((bBreak
|| eOrient
!=SvxCellOrientation::Standard
) && !bMerged
)
4746 nStartX
= nInitPosX
;
4751 nStartX
-= nLayoutSign
* static_cast<tools::Long
>(pRowInfo
[0].basicCellInfo(nCol
).nWidth
);
4755 tools::Long nCellStartX
= nStartX
;
4757 // omit substitute representation of small text
4761 tools::Long nOutWidth
= nCellWidth
- 1;
4762 tools::Long nOutHeight
= nCellHeight
;
4766 SCCOL nCountX
= pMerge
->GetColMerge();
4767 for (SCCOL i
=1; i
<nCountX
; i
++)
4768 nOutWidth
+= mpDoc
->GetColWidth(nX
+i
,nTab
) * mnPPTX
;
4769 SCROW nCountY
= pMerge
->GetRowMerge();
4770 nOutHeight
+= mpDoc
->GetScaledRowHeight( nY
+1, nY
+nCountY
-1, nTab
, mnPPTY
);
4773 SvxCellVerJustify eVerJust
=
4774 pPattern
->GetItem(ATTR_VER_JUSTIFY
, pCondSet
).GetValue();
4776 // syntax mode is ignored here...
4778 // StringDiffer doesn't look at hyphenate, language items
4779 if ( !ScPatternAttr::areSame(pPattern
, pOldPattern
) || pCondSet
!= pOldCondSet
)
4781 auto pSet
= std::make_unique
<SfxItemSet
>( mxOutputEditEngine
->GetEmptyItemSet() );
4782 pPattern
->FillEditItemSet( pSet
.get(), pCondSet
);
4784 // adjustment for EditEngine
4785 SvxAdjust eSvxAdjust
= SvxAdjust::Left
;
4786 if (eOrient
==SvxCellOrientation::Stacked
)
4787 eSvxAdjust
= SvxAdjust::Center
;
4788 // adjustment for bBreak is omitted here
4789 pSet
->Put( SvxAdjustItem( eSvxAdjust
, EE_PARA_JUST
) );
4791 bool bParaHyphenate
= pSet
->Get(EE_PARA_HYPHENATE
).GetValue();
4792 mxOutputEditEngine
->SetDefaults( std::move(pSet
) );
4793 pOldPattern
= pPattern
;
4794 pOldCondSet
= pCondSet
;
4796 EEControlBits nControl
= mxOutputEditEngine
->GetControlWord();
4797 if (eOrient
==SvxCellOrientation::Stacked
)
4798 nControl
|= EEControlBits::ONECHARPERLINE
;
4800 nControl
&= ~EEControlBits::ONECHARPERLINE
;
4801 mxOutputEditEngine
->SetControlWord( nControl
);
4803 if ( !bHyphenatorSet
&& bParaHyphenate
)
4805 // set hyphenator the first time it is needed
4806 css::uno::Reference
<css::linguistic2::XHyphenator
> xXHyphenator( LinguMgr::GetHyphenator() );
4807 mxOutputEditEngine
->SetHyphenator( xXHyphenator
);
4808 bHyphenatorSet
= true;
4812 pPattern
->GetItem( ATTR_BACKGROUND
, pCondSet
).GetColor();
4813 if ( mbUseStyleColor
&& ( aBackCol
.IsTransparent() || bCellContrast
) )
4814 aBackCol
= nConfBackColor
;
4815 mxOutputEditEngine
->SetBackgroundColor( aBackCol
);
4820 //! change position and paper size to EditUtil !!!
4822 const SvxMarginItem
* pMargin
=
4823 &pPattern
->GetItem(ATTR_MARGIN
, pCondSet
);
4824 sal_uInt16 nIndent
= 0;
4825 if ( eHorJust
== SvxCellHorJustify::Left
)
4826 nIndent
= pPattern
->GetItem(ATTR_INDENT
, pCondSet
).GetValue();
4828 tools::Long nTotalHeight
= nOutHeight
; // without subtracting the margin
4829 if ( bPixelToLogic
)
4830 nTotalHeight
= mpRefDevice
->PixelToLogic(Size(0,nTotalHeight
)).Height();
4832 tools::Long nLeftM
= static_cast<tools::Long
>( (pMargin
->GetLeftMargin() + nIndent
) * mnPPTX
);
4833 tools::Long nTopM
= static_cast<tools::Long
>( pMargin
->GetTopMargin() * mnPPTY
);
4834 tools::Long nRightM
= static_cast<tools::Long
>( pMargin
->GetRightMargin() * mnPPTX
);
4835 tools::Long nBottomM
= static_cast<tools::Long
>( pMargin
->GetBottomMargin() * mnPPTY
);
4838 nOutWidth
-= nLeftM
+ nRightM
;
4839 nOutHeight
-= nTopM
+ nBottomM
;
4841 // rotate here already, to adjust paper size for page breaks
4842 Degree100 nAttrRotate
;
4845 SvxRotateMode eRotMode
= SVX_ROTATE_MODE_STANDARD
;
4846 if ( eOrient
== SvxCellOrientation::Standard
)
4848 nAttrRotate
= pPattern
->
4849 GetItem(ATTR_ROTATE_VALUE
, pCondSet
).GetValue();
4852 eRotMode
= pPattern
->GetItem(ATTR_ROTATE_MODE
, pCondSet
).GetValue();
4854 // tdf#143377 To use the same limits to avoid too big Skew
4855 // with TextOrientation in Calc, use 1/2 degree here, too.
4856 // This equals '50' in the notation here (100th degree)
4857 static const sal_Int32
nMinRad(50);
4859 // bring nAttrRotate to the range [0..36000[
4860 nAttrRotate
= Degree100(((nAttrRotate
.get() % 36000) + 36000) % 36000);
4862 // check for to be avoided extreme values and correct
4863 if (nAttrRotate
< Degree100(nMinRad
))
4866 nAttrRotate
= Degree100(nMinRad
);
4867 eRotMode
= SVX_ROTATE_MODE_STANDARD
; // no overflow
4869 else if (nAttrRotate
> Degree100(36000 - nMinRad
))
4871 // range [35950..36000[
4872 nAttrRotate
= Degree100(36000 - nMinRad
);
4873 eRotMode
= SVX_ROTATE_MODE_STANDARD
; // no overflow
4875 else if (nAttrRotate
> Degree100(18000 - nMinRad
) && (nAttrRotate
< Degree100(18000 + nMinRad
)))
4877 // range 50 around 18000, [17950..18050]
4878 nAttrRotate
= (nAttrRotate
> Degree100(18000))
4879 ? Degree100(18000 + nMinRad
)
4880 : Degree100(18000 - nMinRad
);
4881 eRotMode
= SVX_ROTATE_MODE_STANDARD
; // no overflow
4886 // keep in range [0..36000[
4887 nAttrRotate
= Degree100(36000 - nAttrRotate
.get());
4890 double nRealOrient
= toRadians(nAttrRotate
); // 1/100 degree
4891 nCos
= cos( nRealOrient
);
4893 // tdf#143377 new strategy: instead of using zero for nSin, which
4894 // would be the *correct* value, continue with the corrected maximum
4895 // allowed value which is then *not* zero. This is similar to
4896 // the behaviour before where (just due to numerical unprecisions)
4897 // nSin was also not zero (pure coincidence), but very close to it.
4898 // I checked and tried to make safe all places below that use
4899 // nSin and divide by it, but there is too much going on and that
4900 // would not be safe, so rely on the same values as before, but
4901 // now numerically limited to not get the Skew go havoc
4902 nSin
= sin( nRealOrient
);
4906 Size
aPaperSize( 1000000, 1000000 );
4907 if (eOrient
==SvxCellOrientation::Stacked
)
4908 aPaperSize
.setWidth( nOutWidth
); // to center
4913 //! the correct paper size for break depends on the number
4914 //! of rows, as long as the rows can not be outputted individually
4915 //! offsetted -> therefore unlimited, so no wrapping.
4916 //! With offset rows the following would be correct:
4917 aPaperSize
.setWidth( static_cast<tools::Long
>(nOutHeight
/ fabs(nSin
)) );
4919 else if (eOrient
== SvxCellOrientation::Standard
)
4920 aPaperSize
.setWidth( nOutWidth
);
4922 aPaperSize
.setWidth( nOutHeight
- 1 );
4925 mxOutputEditEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
4927 mxOutputEditEngine
->SetPaperSize(aPaperSize
); // scale is always 1
4929 // read data from cell
4931 if (aCell
.getType() == CELLTYPE_EDIT
)
4933 if (aCell
.getEditText())
4934 mxOutputEditEngine
->SetTextCurrentDefaults(*aCell
.getEditText());
4937 OSL_FAIL("pData == 0");
4942 sal_uInt32 nFormat
= pPattern
->GetNumberFormat(
4943 mpDoc
->GetFormatTable(), pCondSet
);
4944 const Color
* pColor
;
4945 OUString aString
= ScCellFormat::GetString( aCell
,
4952 mxOutputEditEngine
->SetTextCurrentDefaults(aString
);
4953 if ( pColor
&& !mbSyntaxMode
&& !( mbUseStyleColor
&& mbForceAutoColor
) )
4954 lcl_SetEditColor( *mxOutputEditEngine
, *pColor
);
4959 SetEditSyntaxColor(*mxOutputEditEngine
, aCell
);
4961 else if ( mbUseStyleColor
&& mbForceAutoColor
)
4962 lcl_SetEditColor( *mxOutputEditEngine
, COL_AUTO
); //! or have a flag at EditEngine
4964 mxOutputEditEngine
->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
4966 tools::Long nEngineWidth
= static_cast<tools::Long
>(mxOutputEditEngine
->CalcTextWidth());
4967 tools::Long nEngineHeight
= mxOutputEditEngine
->GetTextHeight();
4969 if (nAttrRotate
&& bBreak
)
4971 double nAbsCos
= fabs( nCos
);
4972 double nAbsSin
= fabs( nSin
);
4974 // adjust width of papersize for height of text
4978 // everything is in pixels
4979 tools::Long nEnginePixel
= mpRefDevice
->LogicToPixel(
4980 Size(0,nEngineHeight
)).Height();
4981 tools::Long nEffHeight
= nOutHeight
- static_cast<tools::Long
>(nEnginePixel
* nAbsCos
) + 2;
4982 tools::Long nNewWidth
= static_cast<tools::Long
>(nEffHeight
/ nAbsSin
) + 2;
4983 bool bFits
= ( nNewWidth
>= aPaperSize
.Width() );
4988 if ( nNewWidth
< 4 )
4990 // can't fit -> fall back to using half height
4991 nEffHeight
= nOutHeight
/ 2;
4992 nNewWidth
= static_cast<tools::Long
>(nEffHeight
/ nAbsSin
) + 2;
4998 // set paper width and get new text height
4999 aPaperSize
.setWidth( nNewWidth
);
5001 mxOutputEditEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
5003 mxOutputEditEngine
->SetPaperSize(aPaperSize
); // Scale is always 1
5004 //mxOutputEditEngine->QuickFormatDoc( sal_True );
5006 nEngineWidth
= static_cast<tools::Long
>(mxOutputEditEngine
->CalcTextWidth());
5007 nEngineHeight
= mxOutputEditEngine
->GetTextHeight();
5012 tools::Long nRealWidth
= nEngineWidth
;
5013 tools::Long nRealHeight
= nEngineHeight
;
5015 // when rotated, adjust size
5018 double nAbsCos
= fabs( nCos
);
5019 double nAbsSin
= fabs( nSin
);
5021 if ( eRotMode
== SVX_ROTATE_MODE_STANDARD
)
5022 nEngineWidth
= static_cast<tools::Long
>( nRealWidth
* nAbsCos
+
5023 nRealHeight
* nAbsSin
);
5025 nEngineWidth
= static_cast<tools::Long
>( nRealHeight
/ nAbsSin
);
5028 nEngineHeight
= static_cast<tools::Long
>( nRealHeight
* nAbsCos
+
5029 nRealWidth
* nAbsSin
);
5032 if (!nAttrRotate
) // only rotated text here
5033 bHidden
= true; //! check first !!!
5035 //! omit which doesn't stick out
5039 Size
aClipSize( nScrX
+nScrW
-nStartX
, nScrY
+nScrH
-nStartY
);
5045 aCellSize
= mpRefDevice
->PixelToLogic( Size( nOutWidth
, nOutHeight
) );
5047 aCellSize
= Size( nOutWidth
, nOutHeight
); // scale is one
5049 tools::Long nGridWidth
= nEngineWidth
;
5050 bool bNegative
= false;
5051 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5053 nGridWidth
= aCellSize
.Width() +
5054 std::abs(static_cast<tools::Long
>( aCellSize
.Height() * nCos
/ nSin
));
5055 bNegative
= ( pInfo
->nRotateDir
== ScRotateDir::Left
);
5057 bNegative
= !bNegative
;
5060 // use GetOutputArea to hide the grid
5061 // (clip region is done manually below)
5062 OutputAreaParam aAreaParam
;
5066 SvxCellHorJustify eOutHorJust
= eHorJust
;
5067 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5068 eOutHorJust
= bNegative
? SvxCellHorJustify::Right
: SvxCellHorJustify::Left
;
5069 tools::Long nNeededWidth
= nGridWidth
; // in pixel for GetOutputArea
5070 if ( bPixelToLogic
)
5071 nNeededWidth
= mpRefDevice
->LogicToPixel(Size(nNeededWidth
,0)).Width();
5073 GetOutputArea( nX
, nArrY
, nCellStartX
, nPosY
, nCellX
, nCellY
, nNeededWidth
,
5074 *pPattern
, sal::static_int_cast
<sal_uInt16
>(eOutHorJust
),
5075 false, false, true, aAreaParam
);
5079 tools::Long nPixelWidth
= bPixelToLogic
?
5080 mpRefDevice
->LogicToPixel(Size(nEngineWidth
,0)).Width() : nEngineWidth
;
5081 tools::Long nNeededPixel
= nPixelWidth
+ nLeftM
+ nRightM
;
5083 aAreaParam
.mbLeftClip
= aAreaParam
.mbRightClip
= true;
5086 ShrinkEditEngine( *mxOutputEditEngine
, aAreaParam
.maAlignRect
, nLeftM
, nTopM
, nRightM
, nBottomM
,
5087 false, eOrient
, nAttrRotate
, bPixelToLogic
,
5088 nEngineWidth
, nEngineHeight
, nNeededPixel
, aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
5090 if ( eRotMode
== SVX_ROTATE_MODE_STANDARD
)
5092 // do width only if rotating within the cell (standard mode)
5093 ShrinkEditEngine( *mxOutputEditEngine
, aAreaParam
.maAlignRect
, nLeftM
, nTopM
, nRightM
, nBottomM
,
5094 true, eOrient
, nAttrRotate
, bPixelToLogic
,
5095 nEngineWidth
, nEngineHeight
, nNeededPixel
, aAreaParam
.mbLeftClip
, aAreaParam
.mbRightClip
);
5098 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
5099 // (but width is only valid for standard mode)
5100 nRealWidth
= static_cast<tools::Long
>(mxOutputEditEngine
->CalcTextWidth());
5101 nRealHeight
= mxOutputEditEngine
->GetTextHeight();
5103 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5104 nEngineWidth
= static_cast<tools::Long
>( nRealHeight
/ fabs( nSin
) );
5107 tools::Long nClipStartX
= nStartX
;
5110 //! clipping is not needed when on the left side of the window
5114 tools::Long nDif
= nScrX
- nStartX
;
5115 nClipStartX
= nScrX
;
5116 aClipSize
.AdjustWidth( -nDif
);
5120 tools::Long nClipStartY
= nStartY
;
5121 if (nArrY
==0 && nClipStartY
< nRowPosY
)
5123 tools::Long nDif
= nRowPosY
- nClipStartY
;
5124 nClipStartY
= nRowPosY
;
5125 aClipSize
.AdjustHeight( -nDif
);
5128 if ( nAttrRotate
/* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5130 // only clip rotated output text at the page border
5131 nClipStartX
= nScrX
;
5132 aClipSize
.setWidth( nScrW
);
5136 aAreaParam
.maClipRect
= mpRefDevice
->PixelToLogic( tools::Rectangle(
5137 Point(nClipStartX
,nClipStartY
), aClipSize
) );
5139 aAreaParam
.maClipRect
= tools::Rectangle(Point(nClipStartX
, nClipStartY
),
5140 aClipSize
); // Scale = 1
5145 mpDev
->IntersectClipRegion( aAreaParam
.maClipRect
);
5148 mpDev
->SetClipRegion( vcl::Region( aAreaParam
.maClipRect
) );
5152 aLogicStart
= mpRefDevice
->PixelToLogic( Point(nStartX
,nStartY
) );
5154 aLogicStart
= Point(nStartX
, nStartY
);
5155 if ( eOrient
!=SvxCellOrientation::Standard
|| !bBreak
)
5157 tools::Long nAvailWidth
= aCellSize
.Width();
5158 if (eType
==OUTTYPE_WINDOW
&&
5159 eOrient
!=SvxCellOrientation::Stacked
&&
5162 // filter drop-down width depends on row height
5163 double fZoom
= mpRefDevice
? static_cast<double>(mpRefDevice
->GetMapMode().GetScaleY()) : 1.0;
5164 fZoom
= fZoom
> 1.0 ? fZoom
: 1.0;
5166 nAvailWidth
-= mpRefDevice
->PixelToLogic(Size(0,fZoom
* DROPDOWN_BITMAP_SIZE
)).Height();
5168 nAvailWidth
-= fZoom
* DROPDOWN_BITMAP_SIZE
;
5169 tools::Long nComp
= nEngineWidth
;
5170 if (nAvailWidth
<nComp
) nAvailWidth
=nComp
;
5173 // horizontal orientation
5175 if (eOrient
==SvxCellOrientation::Standard
&& !nAttrRotate
)
5177 if (eHorJust
==SvxCellHorJustify::Right
||
5178 eHorJust
==SvxCellHorJustify::Center
)
5180 mxOutputEditEngine
->SetUpdateLayout( false );
5182 SvxAdjust eSvxAdjust
=
5183 (eHorJust
==SvxCellHorJustify::Right
) ?
5184 SvxAdjust::Right
: SvxAdjust::Center
;
5185 mxOutputEditEngine
->SetDefaultItem(
5186 SvxAdjustItem( eSvxAdjust
, EE_PARA_JUST
) );
5188 aPaperSize
.setWidth( nOutWidth
);
5190 mxOutputEditEngine
->SetPaperSize(mpRefDevice
->PixelToLogic(aPaperSize
));
5192 mxOutputEditEngine
->SetPaperSize(aPaperSize
);
5194 mxOutputEditEngine
->SetUpdateLayout( true );
5199 // rotated text is centered by default
5200 if (eHorJust
==SvxCellHorJustify::Right
)
5201 aLogicStart
.AdjustX(nAvailWidth
- nEngineWidth
);
5202 else if (eHorJust
==SvxCellHorJustify::Center
||
5203 eHorJust
==SvxCellHorJustify::Standard
)
5204 aLogicStart
.AdjustX((nAvailWidth
- nEngineWidth
) / 2 );
5211 aLogicStart
.AdjustX( -(mpRefDevice
->PixelToLogic(
5212 Size( nCellWidth
, 0 ) ).Width()) );
5214 aLogicStart
.AdjustX( -nCellWidth
);
5217 if ( eOrient
==SvxCellOrientation::Standard
||
5218 eOrient
==SvxCellOrientation::Stacked
|| !bBreak
)
5220 if (eVerJust
==SvxCellVerJustify::Bottom
||
5221 eVerJust
==SvxCellVerJustify::Standard
)
5224 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0,
5225 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
5226 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height()
5229 aLogicStart
.AdjustY(aCellSize
.Height() - nEngineHeight
);
5232 else if (eVerJust
==SvxCellVerJustify::Center
)
5235 aLogicStart
.AdjustY(mpRefDevice
->PixelToLogic( Size(0,(
5236 mpRefDevice
->LogicToPixel(aCellSize
).Height() -
5237 mpRefDevice
->LogicToPixel(Size(0,nEngineHeight
)).Height())
5240 aLogicStart
.AdjustY((aCellSize
.Height() - nEngineHeight
) / 2 );
5244 // TOPBOTTOM and BOTTOMTOP are handled in DrawStrings/DrawEdit
5245 OSL_ENSURE( eOrient
== SvxCellOrientation::Standard
&& nAttrRotate
,
5246 "DrawRotated: no rotation" );
5248 Degree10 nOriVal
= 0_deg10
;
5251 // attribute is 1/100, Font 1/10 degrees
5252 nOriVal
= to
<Degree10
>(nAttrRotate
);
5256 if ( nCos
> 0.0 && eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5259 double nH
= nRealHeight
* nCos
;
5260 nAddX
+= nH
* ( nCos
/ fabs(nSin
) );
5262 if ( nCos
< 0.0 && eRotMode
== SVX_ROTATE_MODE_STANDARD
)
5263 nAddX
-= nRealWidth
* nCos
;
5265 nAddX
-= nRealHeight
* nSin
;
5267 nAddY
+= nRealWidth
* nSin
;
5269 nAddY
-= nRealHeight
* nCos
;
5271 if ( eRotMode
!= SVX_ROTATE_MODE_STANDARD
)
5274 double nSkew
= nTotalHeight
* nCos
/ fabs(nSin
);
5275 if ( eRotMode
== SVX_ROTATE_MODE_CENTER
)
5276 nAddX
-= nSkew
* 0.5;
5277 if ( ( eRotMode
== SVX_ROTATE_MODE_TOP
&& nSin
> 0.0 ) ||
5278 ( eRotMode
== SVX_ROTATE_MODE_BOTTOM
&& nSin
< 0.0 ) )
5281 tools::Long nUp
= 0;
5282 if ( eVerJust
== SvxCellVerJustify::Center
)
5283 nUp
= ( aCellSize
.Height() - nEngineHeight
) / 2;
5284 else if ( eVerJust
== SvxCellVerJustify::Top
)
5287 nUp
= aCellSize
.Height() - nEngineHeight
;
5289 else // BOTTOM / STANDARD
5292 nUp
= aCellSize
.Height() - nEngineHeight
;
5295 nAddX
+= ( nUp
* nCos
/ fabs(nSin
) );
5298 aLogicStart
.AdjustX(static_cast<tools::Long
>(nAddX
) );
5299 aLogicStart
.AdjustY(static_cast<tools::Long
>(nAddY
) );
5302 // bSimClip is not used here (because nOriVal is set)
5304 mxOutputEditEngine
->Draw(*mpDev
, aLogicStart
, nOriVal
);
5309 mpDev
->SetClipRegion();
5314 nPosX
+= pRowInfo
[0].basicCellInfo(nX
).nWidth
* nLayoutSign
;
5317 nRowPosY
+= pRowInfo
[nArrY
].nHeight
;
5321 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */