LibreOffice Module sc (master) 1
output2.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <scitems.hxx>
21#include <editeng/eeitem.hxx>
22
24#include <svx/algitem.hxx>
25#include <editeng/brushitem.hxx>
26#include <svtools/colorcfg.hxx>
27#include <editeng/colritem.hxx>
31#include <editeng/editobj.hxx>
32#include <editeng/editstat.hxx>
34#include <editeng/fhgtitem.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>
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>
55#include <vcl/settings.hxx>
56#include <vcl/glyphitem.hxx>
57#include <vcl/vcllayout.hxx>
59#include <sal/log.hxx>
61#include <osl/diagnose.h>
62#include <tools/stream.hxx>
63
64#include <output.hxx>
65#include <document.hxx>
66#include <formulacell.hxx>
67#include <attrib.hxx>
68#include <patattr.hxx>
69#include <cellform.hxx>
70#include <editutil.hxx>
71#include <progress.hxx>
72#include <scmod.hxx>
73#include <fillinfo.hxx>
74#include <stlsheet.hxx>
75#include <spellcheckcontext.hxx>
76#include <scopetools.hxx>
77
78#include <com/sun/star/i18n/DirectionProperty.hpp>
80#include <comphelper/string.hxx>
81
82#include <memory>
83#include <vector>
84#include <o3tl/lru_map.hxx>
85#include <o3tl/hash_combine.hxx>
86
87#include <math.h>
88
89using namespace com::sun::star;
90
92#define DROPDOWN_BITMAP_SIZE 18
93
94#define DRAWTEXT_MAX 32767
95
96const sal_uInt16 SC_SHRINKAGAIN_MAX = 7;
98
100{
101 ScOutputData* pOutput; // connection
102
103 const ScPatternAttr* pPattern; // attribute
104 const SfxItemSet* pCondSet; // from conditional formatting
105
106 vcl::Font aFont; // created from attributes
108 tools::Long nAscentPixel; // always pixels
114 sal_uInt16 nIndent;
116
117 OUString aString; // contents
124
130
133
134 Color aBackConfigColor; // used for ScPatternAttr::GetFont calls
136 sal_Int32 nRepeatPos;
138
139public:
140 ScDrawStringsVars(ScOutputData* pData, bool bPTL);
141
142 // SetPattern = ex-SetVars
143 // SetPatternSimple: without Font
144
145 void SetPattern(
146 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
147 SvtScriptType nScript );
148
149 void SetPatternSimple( const ScPatternAttr* pNew, const SfxItemSet* pSet );
150
151 bool SetText( const ScRefCellValue& rCell ); // TRUE -> drop pOldPattern
152 void SetHashText();
153 bool SetTextToWidthOrHash( ScRefCellValue& rCell, tools::Long nWidth );
154 void SetAutoText( const OUString& rAutoText );
155
160 const SvxMarginItem* GetMargin() const { return pMargin; }
161
162 sal_uInt16 GetLeftTotal() const { return pMargin->GetLeftMargin() + nIndent; }
163 sal_uInt16 GetRightTotal() const { return pMargin->GetRightMargin() + nIndent; }
164
165 const OUString& GetString() const { return aString; }
166 const Size& GetTextSize() const { return aTextSize; }
168 tools::Long GetFmtTextWidth(const OUString& rString);
169
170 // Get the effective number format, including formula result types.
171 // This assumes that a formula cell has already been calculated.
173
174 bool GetLineBreak() const { return bLineBreak; }
175 bool IsRepeat() const { return bRepeat; }
176 bool IsShrink() const { return bShrink; }
177 void RepeatToFill( tools::Long nColWidth );
178
180 bool IsRotated() const { return bRotated; }
181
182 void SetShrinkScale( tools::Long nScale, SvtScriptType nScript );
183
184 bool HasCondHeight() const { return pCondSet && SfxItemState::SET ==
186
187 bool HasEditCharacters() const;
188
189 // ScOutputData::LayoutStrings() usually triggers a number of calls that require
190 // to lay out the text, which is relatively slow, so cache that operation.
191 const SalLayoutGlyphs* GetLayoutGlyphs(const OUString& rString) const
192 {
194 }
195
196private:
197 tools::Long GetMaxDigitWidth(); // in logic units
201 void TextChanged();
202};
203
205 pOutput ( pData ),
206 pPattern ( nullptr ),
207 pCondSet ( nullptr ),
208 nAscentPixel(0),
209 eAttrOrient ( SvxCellOrientation::Standard ),
210 eAttrHorJust( SvxCellHorJustify::Standard ),
211 eAttrVerJust( SvxCellVerJustify::Bottom ),
212 eAttrHorJustMethod( SvxCellJustifyMethod::Auto ),
213 pMargin ( nullptr ),
214 nIndent ( 0 ),
215 bRotated ( false ),
216 nOriginalWidth( 0 ),
217 nMaxDigitWidth( 0 ),
218 nSignWidth( 0 ),
219 nDotWidth( 0 ),
220 nExpWidth( 0 ),
221 nValueFormat( 0 ),
222 bLineBreak ( false ),
223 bRepeat ( false ),
224 bShrink ( false ),
225 bPixelToLogic( bPTL ),
226 nRepeatPos( -1 ),
227 nRepeatChar( 0x0 )
228{
229 ScModule* pScMod = SC_MOD();
232
233 const svtools::ColorConfig& rColorConfig = pScMod->GetColorConfig();
236}
237
239{
240 // text remains valid, size is updated
241
242 OutputDevice* pDev = pOutput->mpDev;
243 OutputDevice* pRefDevice = pOutput->mpRefDevice;
244 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
245
246 // call GetFont with a modified fraction, use only the height
247
248 Fraction aFraction( nScale, 100 );
249 if ( !bPixelToLogic )
250 aFraction *= pOutput->aZoomY;
251 vcl::Font aTmpFont;
252 pPattern->fillFontOnly(aTmpFont, pFmtDevice, &aFraction, pCondSet, nScript);
253 // only need font height
254 tools::Long nNewHeight = aTmpFont.GetFontHeight();
255 if ( nNewHeight > 0 )
256 aFont.SetFontHeight( nNewHeight );
257
258 // set font and dependent variables as in SetPattern
259
260 pDev->SetFont( aFont );
261 if ( pFmtDevice != pDev )
262 pFmtDevice->SetFont( aFont );
263
264 aMetric = pFmtDevice->GetFontMetric();
265 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetInternalLeading() == 0 )
266 {
268 MapMode aOld = pDefaultDev->GetMapMode();
269 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
270 aMetric = pDefaultDev->GetFontMetric( aFont );
271 pDefaultDev->SetMapMode( aOld );
272 }
273
275 if ( bPixelToLogic )
276 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
277
278 SetAutoText( aString ); // same text again, to get text size
279}
280
281namespace {
282
283template<typename ItemType, typename EnumType>
284EnumType lcl_GetValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
285{
286 const ItemType& rItem = static_cast<const ItemType&>(rPattern.GetItem(nWhich, pCondSet));
287 return static_cast<EnumType>(rItem.GetValue());
288}
289
290bool lcl_GetBoolValue(const ScPatternAttr& rPattern, sal_uInt16 nWhich, const SfxItemSet* pCondSet)
291{
292 return lcl_GetValue<SfxBoolItem, bool>(rPattern, nWhich, pCondSet);
293}
294
295}
296
297static bool lcl_isNumberFormatText(const ScDocument* pDoc, SCCOL nCellX, SCROW nCellY, SCTAB nTab )
298{
299 sal_uInt32 nCurrentNumberFormat = pDoc->GetNumberFormat( nCellX, nCellY, nTab );
300 SvNumberFormatter* pNumberFormatter = pDoc->GetFormatTable();
301 return pNumberFormatter->GetType( nCurrentNumberFormat ) == SvNumFormatType::TEXT;
302}
303
305 const ScPatternAttr* pNew, const SfxItemSet* pSet, const ScRefCellValue& rCell,
306 SvtScriptType nScript )
307{
308 nMaxDigitWidth = 0;
309 nSignWidth = 0;
310 nDotWidth = 0;
311 nExpWidth = 0;
312
313 pPattern = pNew;
314 pCondSet = pSet;
315
316 // evaluate pPattern
317
318 OutputDevice* pDev = pOutput->mpDev;
319 OutputDevice* pRefDevice = pOutput->mpRefDevice;
320 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
321
322 // font
323
324 ScAutoFontColorMode eColorMode;
326 {
329 else
331 }
332 else
333 eColorMode = ScAutoFontColorMode::Print;
334
335 if (bPixelToLogic)
336 pPattern->fillFont(aFont, eColorMode, pFmtDevice, nullptr, pCondSet, nScript, &aBackConfigColor, &aTextConfigColor);
337 else
338 pPattern->fillFont(aFont, eColorMode, pFmtDevice, &pOutput->aZoomY, pCondSet, nScript, &aBackConfigColor, &aTextConfigColor );
339
341
342 // orientation
343
345
346 // alignment
347
349
351 if ( eAttrVerJust == SvxCellVerJustify::Standard )
352 eAttrVerJust = SvxCellVerJustify::Bottom;
353
354 // justification method
355
356 eAttrHorJustMethod = lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet);
357
358 // line break
359
361
362 // handle "repeat" alignment
363
364 bRepeat = ( eAttrHorJust == SvxCellHorJustify::Repeat );
365 if ( bRepeat )
366 {
367 // "repeat" disables rotation (before constructing the font)
368 eAttrOrient = SvxCellOrientation::Standard;
369
370 // #i31843# "repeat" with "line breaks" is treated as default alignment (but rotation is still disabled)
371 if ( bLineBreak )
372 eAttrHorJust = SvxCellHorJustify::Standard;
373 }
374
375 sal_Int16 nRot;
376 switch (eAttrOrient)
377 {
378 case SvxCellOrientation::Standard:
379 nRot = 0;
380 bRotated = pPattern->GetItem( ATTR_ROTATE_VALUE, pCondSet ).GetValue() != 0_deg100 &&
381 !bRepeat;
382 break;
383 case SvxCellOrientation::Stacked:
384 nRot = 0;
385 bRotated = false;
386 break;
387 case SvxCellOrientation::TopBottom:
388 nRot = 2700;
389 bRotated = false;
390 break;
391 case SvxCellOrientation::BottomUp:
392 nRot = 900;
393 bRotated = false;
394 break;
395 default:
396 OSL_FAIL("Invalid SvxCellOrientation value");
397 nRot = 0;
398 bRotated = false;
399 break;
400 }
402
403 // syntax mode
404
406 pOutput->SetSyntaxColor(&aFont, rCell);
407
408 // There is no cell attribute for kerning, default is kerning OFF, all
409 // kerning is stored at an EditText object that is drawn using EditEngine.
410 aFont.SetKerning( FontKerning::NONE);
411
412 pDev->SetFont( aFont );
413 if ( pFmtDevice != pDev )
414 pFmtDevice->SetFont( aFont );
415
416 aMetric = pFmtDevice->GetFontMetric();
417
418 // if there is the leading 0 on a printer device, we have problems
419 // -> take metric from the screen (as for EditEngine!)
420 if ( pFmtDevice->GetOutDevType() == OUTDEV_PRINTER && aMetric.GetInternalLeading() == 0 )
421 {
423 MapMode aOld = pDefaultDev->GetMapMode();
424 pDefaultDev->SetMapMode( pFmtDevice->GetMapMode() );
425 aMetric = pDefaultDev->GetFontMetric( aFont );
426 pDefaultDev->SetMapMode( aOld );
427 }
428
430 if ( bPixelToLogic )
431 nAscentPixel = pRefDevice->LogicToPixel( Size( 0, nAscentPixel ) ).Height();
432
433 Color aULineColor( pPattern->GetItem( ATTR_FONT_UNDERLINE, pCondSet ).GetColor() );
434 pDev->SetTextLineColor( aULineColor );
435
436 Color aOLineColor( pPattern->GetItem( ATTR_FONT_OVERLINE, pCondSet ).GetColor() );
437 pDev->SetOverlineColor( aOLineColor );
438
439 // number format
440
442
443 // margins
445 if ( eAttrHorJust == SvxCellHorJustify::Left || eAttrHorJust == SvxCellHorJustify::Right )
446 nIndent = pPattern->GetItem( ATTR_INDENT, pCondSet ).GetValue();
447 else
448 nIndent = 0;
449
450 // "Shrink to fit"
451
453
454 // at least the text size needs to be retrieved again
457}
458
460{
461 nMaxDigitWidth = 0;
462 nSignWidth = 0;
463 nDotWidth = 0;
464 nExpWidth = 0;
465
466 // Is called, when the font variables do not change (!StringDiffer)
467
468 pPattern = pNew;
469 pCondSet = pSet;
470
471 // number format
472
473 sal_uLong nOld = nValueFormat;
475
476 if (nValueFormat != nOld)
477 maLastCell.clear(); // always reformat
478
479 // margins
480
482
483 if ( eAttrHorJust == SvxCellHorJustify::Left )
484 nIndent = pPattern->GetItem( ATTR_INDENT, pCondSet ).GetValue();
485 else
486 nIndent = 0;
487
488 // "Shrink to fit"
489
491}
492
493static bool SameValue( const ScRefCellValue& rCell, const ScRefCellValue& rOldCell )
494{
495 return rOldCell.getType() == CELLTYPE_VALUE && rCell.getType() == CELLTYPE_VALUE &&
496 rCell.getDouble() == rOldCell.getDouble();
497}
498
500{
501 bool bChanged = false;
502
503 if (!rCell.isEmpty())
504 {
505 if (!SameValue(rCell, maLastCell))
506 {
507 maLastCell = rCell; // store cell
508
509 const Color* pColor;
510 sal_uLong nFormat = nValueFormat;
512 nFormat, &pColor,
514 *pOutput->mpDoc,
517 true );
518 if ( nFormat )
519 {
520 nRepeatPos = aString.indexOf( 0x1B );
521 if ( nRepeatPos != -1 )
522 {
523 if (nRepeatPos + 1 == aString.getLength())
524 nRepeatPos = -1;
525 else
526 {
528 // delete placeholder and char to repeat
529 aString = aString.replaceAt( nRepeatPos, 2, u"" );
530 // Do not cache/reuse a repeat-filled string, column
531 // widths or fonts or sizes may differ.
533 }
534 }
535 }
536 else
537 {
538 nRepeatPos = -1;
539 nRepeatChar = 0x0;
540 }
541 if (aString.getLength() > DRAWTEXT_MAX)
542 aString = aString.copy(0, DRAWTEXT_MAX);
543
545 {
546 OutputDevice* pDev = pOutput->mpDev;
547 aFont.SetColor(*pColor);
548 pDev->SetFont( aFont ); // only for output
549 bChanged = true;
550 maLastCell.clear(); // next time return here again
551 }
552
553 TextChanged();
554 }
555 // otherwise keep string/size
556 }
557 else
558 {
559 aString.clear();
561 aTextSize = Size(0,0);
562 nOriginalWidth = 0;
563 }
564
565 return bChanged;
566}
567
569{
570 SetAutoText("###");
571}
572
574{
575 if ( nRepeatPos == -1 || nRepeatPos > aString.getLength() )
576 return;
577
578 tools::Long nCharWidth = GetFmtTextWidth(OUString(nRepeatChar));
579
580 if ( nCharWidth < 1 || (bPixelToLogic && nCharWidth < pOutput->mpRefDevice->PixelToLogic(Size(1,0)).Width()) )
581 return;
582
583 // Are there restrictions on the cell type we should filter out here ?
584 tools::Long nTextWidth = aTextSize.Width();
585 if ( bPixelToLogic )
586 {
587 nColWidth = pOutput->mpRefDevice->PixelToLogic(Size(nColWidth,0)).Width();
588 nTextWidth = pOutput->mpRefDevice->PixelToLogic(Size(nTextWidth,0)).Width();
589 }
590
591 tools::Long nSpaceToFill = nColWidth - nTextWidth;
592 if ( nSpaceToFill <= nCharWidth )
593 return;
594
595 sal_Int32 nCharsToInsert = nSpaceToFill / nCharWidth;
596 OUStringBuffer aFill(nCharsToInsert);
597 comphelper::string::padToLength(aFill, nCharsToInsert, nRepeatChar);
598 aString = aString.replaceAt( nRepeatPos, 0, aFill );
599 TextChanged();
600}
601
603{
604 // #i113045# do the single-character width calculations in logic units
605 if (bPixelToLogic)
606 nWidth = pOutput->mpRefDevice->PixelToLogic(Size(nWidth,0)).Width();
607
608 CellType eType = rCell.getType();
610 // must be a value or formula cell.
611 return false;
612
613 if (eType == CELLTYPE_FORMULA)
614 {
615 ScFormulaCell* pFCell = rCell.getFormula();
616 if (pFCell->GetErrCode() != FormulaError::NONE || pOutput->mbShowFormulas)
617 {
618 SetHashText(); // If the error string doesn't fit, always use "###". Also for "display formulas" (#i116691#)
619 return true;
620 }
621 // If it's formula, the result must be a value.
622 if (!pFCell->IsValue())
623 return false;
624 }
625
627 if ((nFormat % SV_COUNTRY_LANGUAGE_OFFSET) != 0)
628 {
629 // Not 'General' number format. Set hash text and bail out.
630 SetHashText();
631 return true;
632 }
633
634 double fVal = rCell.getValue();
635
636 const SvNumberformat* pNumFormat = pOutput->mpDoc->GetFormatTable()->GetEntry(nFormat);
637 if (!pNumFormat)
638 return false;
639
640 tools::Long nMaxDigit = GetMaxDigitWidth();
641 if (!nMaxDigit)
642 return false;
643
644 sal_uInt16 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
645 {
646 OUString sTempOut(aString);
647 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
648 {
649 aString = sTempOut;
650 // Failed to get output string. Bail out.
651 return false;
652 }
653 aString = sTempOut;
654 }
655 sal_uInt8 nSignCount = 0, nDecimalCount = 0, nExpCount = 0;
656 sal_Int32 nLen = aString.getLength();
657 sal_Unicode cDecSep = ScGlobal::getLocaleData().getLocaleItem().decimalSeparator[0];
658 for( sal_Int32 i = 0; i < nLen; ++i )
659 {
660 sal_Unicode c = aString[i];
661 if (c == '-')
662 ++nSignCount;
663 else if (c == cDecSep)
664 ++nDecimalCount;
665 else if (c == 'E')
666 ++nExpCount;
667 }
668
669 // #i112250# A small value might be formatted as "0" when only counting the digits,
670 // but fit into the column when considering the smaller width of the decimal separator.
671 if (aString == "0" && fVal != 0.0)
672 nDecimalCount = 1;
673
674 if (nDecimalCount)
675 nWidth += (nMaxDigit - GetDotWidth()) * nDecimalCount;
676 if (nSignCount)
677 nWidth += (nMaxDigit - GetSignWidth()) * nSignCount;
678 if (nExpCount)
679 nWidth += (nMaxDigit - GetExpWidth()) * nExpCount;
680
681 if (nDecimalCount || nSignCount || nExpCount)
682 {
683 // Re-calculate.
684 nNumDigits = static_cast<sal_uInt16>(nWidth / nMaxDigit);
685 OUString sTempOut(aString);
686 if (!pNumFormat->GetOutputString(fVal, nNumDigits, sTempOut))
687 {
688 aString = sTempOut;
689 // Failed to get output string. Bail out.
690 return false;
691 }
692 aString = sTempOut;
693 }
694
695 tools::Long nActualTextWidth = GetFmtTextWidth(aString);
696 if (nActualTextWidth > nWidth)
697 {
698 // Even after the decimal adjustment the text doesn't fit. Give up.
699 SetHashText();
700 return true;
701 }
702
703 TextChanged();
704 maLastCell.clear(); // #i113022# equal cell and format in another column may give different string
705 return false;
706}
707
708void ScDrawStringsVars::SetAutoText( const OUString& rAutoText )
709{
710 aString = rAutoText;
711
712 OutputDevice* pRefDevice = pOutput->mpRefDevice;
713 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
715 aTextSize.setHeight( pFmtDevice->GetTextHeight() );
716
717 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
718 {
719 double fMul = pOutput->GetStretch();
720 aTextSize.setWidth( static_cast<tools::Long>(aTextSize.Width() / fMul + 0.5) );
721 }
722
724 if ( GetOrient() != SvxCellOrientation::Standard )
725 {
726 tools::Long nTemp = aTextSize.Height();
728 aTextSize.setWidth( nTemp );
729 }
730
732 if ( bPixelToLogic )
733 aTextSize = pRefDevice->LogicToPixel( aTextSize );
734
735 maLastCell.clear(); // the same text may fit in the next cell
736}
737
739{
740 if (nMaxDigitWidth > 0)
741 return nMaxDigitWidth;
742
743 for (char i = 0; i < 10; ++i)
744 {
745 char cDigit = '0' + i;
746 // Do not cache this with GetFmtTextWidth(), nMaxDigitWidth is already cached.
747 tools::Long n = pOutput->pFmtDevice->GetTextWidth(OUString(cDigit));
748 nMaxDigitWidth = ::std::max(nMaxDigitWidth, n);
749 }
750 return nMaxDigitWidth;
751}
752
754{
755 if (nSignWidth > 0)
756 return nSignWidth;
757
758 nSignWidth = pOutput->pFmtDevice->GetTextWidth(OUString('-'));
759 return nSignWidth;
760}
761
763{
764 if (nDotWidth > 0)
765 return nDotWidth;
766
767 const OUString& sep = ScGlobal::getLocaleData().getLocaleItem().decimalSeparator;
768 nDotWidth = pOutput->pFmtDevice->GetTextWidth(sep);
769 return nDotWidth;
770}
771
773{
774 if (nExpWidth > 0)
775 return nExpWidth;
776
777 nExpWidth = pOutput->pFmtDevice->GetTextWidth(OUString('E'));
778 return nExpWidth;
779}
780
782{
783 return pOutput->pFmtDevice->GetTextWidth( rString, 0, -1, nullptr, GetLayoutGlyphs( rString ));
784}
785
787{
788 OutputDevice* pRefDevice = pOutput->mpRefDevice;
789 OutputDevice* pFmtDevice = pOutput->pFmtDevice;
791 aTextSize.setHeight( pFmtDevice->GetTextHeight() );
792
793 if ( !pRefDevice->GetConnectMetaFile() || pRefDevice->GetOutDevType() == OUTDEV_PRINTER )
794 {
795 double fMul = pOutput->GetStretch();
796 aTextSize.setWidth( static_cast<tools::Long>(aTextSize.Width() / fMul + 0.5) );
797 }
798
800 if ( GetOrient() != SvxCellOrientation::Standard )
801 {
802 tools::Long nTemp = aTextSize.Height();
804 aTextSize.setWidth( nTemp );
805 }
806
808 if ( bPixelToLogic )
809 aTextSize = pRefDevice->LogicToPixel( aTextSize );
810}
811
813{
814 for (sal_Int32 nIdx = 0; nIdx < aString.getLength(); ++nIdx)
815 {
816 switch(aString[nIdx])
817 {
818 case CHAR_NBSP:
819 // tdf#122676: Ignore CHAR_NBSP (this is thousand separator in any number)
820 // if repeat character is set
821 if (nRepeatPos < 0)
822 return true;
823 break;
824 case CHAR_SHY:
825 case CHAR_ZWSP:
826 case CHAR_LRM:
827 case CHAR_RLM:
828 case CHAR_NBHY:
829 case CHAR_WJ:
830 return true;
831 default:
832 break;
833 }
834 }
835
836 return false;
837}
838
840{
841 if ( mpRefDevice->IsMapModeEnabled() )
842 {
843 // If a non-trivial MapMode is set, its scale is now already
844 // taken into account in the OutputDevice's font handling
845 // (OutputDevice::ImplNewFont, see #95414#).
846 // The old handling below is only needed for pixel output.
847 return 1.0;
848 }
849
850 // calculation in double is faster than Fraction multiplication
851 // and doesn't overflow
852
853 if ( mpRefDevice == pFmtDevice )
854 {
855 MapMode aOld = mpRefDevice->GetMapMode();
856 return static_cast<double>(aOld.GetScaleY()) / static_cast<double>(aOld.GetScaleX()) * static_cast<double>(aZoomY) / static_cast<double>(aZoomX);
857 }
858 else
859 {
860 // when formatting for printer, device map mode has already been taken care of
861 return static_cast<double>(aZoomY) / static_cast<double>(aZoomX);
862 }
863}
864
865// output strings
866
867static void lcl_DoHyperlinkResult( const OutputDevice* pDev, const tools::Rectangle& rRect, ScRefCellValue& rCell )
868{
869 vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >( pDev->GetExtOutDevData() );
870
871 OUString aURL;
872 OUString aCellText;
873 if (rCell.getType() == CELLTYPE_FORMULA)
874 {
875 ScFormulaCell* pFCell = rCell.getFormula();
876 if ( pFCell->IsHyperLinkCell() )
877 pFCell->GetURLResult( aURL, aCellText );
878 }
879
880 if ( !aURL.isEmpty() && pPDFData )
881 {
883 aBookmark.nLinkId = pPDFData->CreateLink(rRect, aCellText);
884 aBookmark.aBookmark = aURL;
885 std::vector< vcl::PDFExtOutDevBookmarkEntry >& rBookmarks = pPDFData->GetBookmarks();
886 rBookmarks.push_back( aBookmark );
887 }
888}
889
891{
892 switch (rCell.getType())
893 {
894 case CELLTYPE_VALUE:
895 pFont->SetColor(*mxValueColor);
896 break;
897 case CELLTYPE_STRING:
898 pFont->SetColor(*mxTextColor);
899 break;
900 case CELLTYPE_FORMULA:
901 pFont->SetColor(*mxFormulaColor);
902 break;
903 default:
904 {
905 // added to avoid warnings
906 }
907 }
908}
909
910static void lcl_SetEditColor( EditEngine& rEngine, const Color& rColor )
911{
912 ESelection aSel( 0, 0, rEngine.GetParagraphCount(), 0 );
913 SfxItemSet aSet( rEngine.GetEmptyItemSet() );
914 aSet.Put( SvxColorItem( rColor, EE_CHAR_COLOR ) );
915 rEngine.QuickSetAttribs( aSet, aSel );
916 // function is called with update mode set to FALSE
917}
918
920{
921 Color aColor;
922 switch (rCell.getType())
923 {
924 case CELLTYPE_VALUE:
925 aColor = *mxValueColor;
926 break;
927 case CELLTYPE_STRING:
928 aColor = *mxTextColor;
929 break;
930 case CELLTYPE_FORMULA:
931 aColor = *mxFormulaColor;
932 break;
933 default:
934 {
935 // added to avoid warnings
936 }
937 }
938 lcl_SetEditColor( rEngine, aColor );
939}
940
942 SCCOL& rOverX, SCROW& rOverY,
943 bool bVisRowChanged )
944{
945 bool bDoMerge = false;
946 bool bIsLeft = ( nX == nVisX1 );
947 bool bIsTop = ( nY == nVisY1 ) || bVisRowChanged;
948
949 bool bHOver;
950 bool bVOver;
951 bool bHidden;
952
953 if (!mpDoc->ColHidden(nX, nTab) && nX >= nX1 && nX <= nX2
954 && !mpDoc->RowHidden(nY, nTab) && nY >= nY1 && nY <= nY2)
955 {
956 ScCellInfo* pInfo = &pRowInfo[nArrY].cellInfo(nX);
957 bHOver = pInfo->bHOverlapped;
958 bVOver = pInfo->bVOverlapped;
959 }
960 else
961 {
962 ScMF nOverlap2 = mpDoc->GetAttr(nX, nY, nTab, ATTR_MERGE_FLAG)->GetValue();
963 bHOver = bool(nOverlap2 & ScMF::Hor);
964 bVOver = bool(nOverlap2 & ScMF::Ver);
965 }
966
967 if ( bHOver && bVOver )
968 bDoMerge = bIsLeft && bIsTop;
969 else if ( bHOver )
970 bDoMerge = bIsLeft;
971 else if ( bVOver )
972 bDoMerge = bIsTop;
973
974 rOverX = nX;
975 rOverY = nY;
976
977 while (bHOver) // nY constant
978 {
979 --rOverX;
980 bHidden = mpDoc->ColHidden(rOverX, nTab);
981 if ( !bDoMerge && !bHidden )
982 return false;
983
984 if (rOverX >= nX1 && !bHidden)
985 {
986 bHOver = pRowInfo[nArrY].cellInfo(rOverX).bHOverlapped;
987 bVOver = pRowInfo[nArrY].cellInfo(rOverX).bVOverlapped;
988 }
989 else
990 {
991 ScMF nOverlap = mpDoc->GetAttr(rOverX, rOverY, nTab, ATTR_MERGE_FLAG)->GetValue();
992 bHOver = bool(nOverlap & ScMF::Hor);
993 bVOver = bool(nOverlap & ScMF::Ver);
994 }
995 }
996
997 while (bVOver)
998 {
999 --rOverY;
1000 bHidden = mpDoc->RowHidden(rOverY, nTab);
1001 if ( !bDoMerge && !bHidden )
1002 return false;
1003
1004 if (nArrY>0)
1005 --nArrY; // local copy !
1006
1007 if (rOverX >= nX1 && rOverY >= nY1 &&
1008 !mpDoc->ColHidden(rOverX, nTab) &&
1009 !mpDoc->RowHidden(rOverY, nTab) &&
1010 pRowInfo[nArrY].nRowNo == rOverY)
1011 {
1012 bVOver = pRowInfo[nArrY].cellInfo(rOverX).bVOverlapped;
1013 }
1014 else
1015 {
1016 ScMF nOverlap = mpDoc->GetAttr( rOverX, rOverY, nTab, ATTR_MERGE_FLAG )->GetValue();
1017 bVOver = bool(nOverlap & ScMF::Ver);
1018 }
1019 }
1020
1021 return true;
1022}
1023
1024static bool StringDiffer( const ScPatternAttr*& rpOldPattern, const ScPatternAttr* pNewPattern )
1025{
1026 OSL_ENSURE( pNewPattern, "pNewPattern" );
1027
1028 if ( pNewPattern == rpOldPattern )
1029 return false;
1030 else if ( !rpOldPattern )
1031 return true;
1032 else if ( &pNewPattern->GetItem( ATTR_FONT ) != &rpOldPattern->GetItem( ATTR_FONT ) )
1033 return true;
1034 else if ( &pNewPattern->GetItem( ATTR_CJK_FONT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT ) )
1035 return true;
1036 else if ( &pNewPattern->GetItem( ATTR_CTL_FONT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT ) )
1037 return true;
1038 else if ( &pNewPattern->GetItem( ATTR_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_HEIGHT ) )
1039 return true;
1040 else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_HEIGHT ) )
1041 return true;
1042 else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_HEIGHT ) )
1043 return true;
1044 else if ( &pNewPattern->GetItem( ATTR_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_FONT_WEIGHT ) )
1045 return true;
1046 else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_WEIGHT ) )
1047 return true;
1048 else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_WEIGHT ) )
1049 return true;
1050 else if ( &pNewPattern->GetItem( ATTR_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_FONT_POSTURE ) )
1051 return true;
1052 else if ( &pNewPattern->GetItem( ATTR_CJK_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CJK_FONT_POSTURE ) )
1053 return true;
1054 else if ( &pNewPattern->GetItem( ATTR_CTL_FONT_POSTURE ) != &rpOldPattern->GetItem( ATTR_CTL_FONT_POSTURE ) )
1055 return true;
1056 else if ( &pNewPattern->GetItem( ATTR_FONT_UNDERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_UNDERLINE ) )
1057 return true;
1058 else if ( &pNewPattern->GetItem( ATTR_FONT_OVERLINE ) != &rpOldPattern->GetItem( ATTR_FONT_OVERLINE ) )
1059 return true;
1060 else if ( &pNewPattern->GetItem( ATTR_FONT_WORDLINE ) != &rpOldPattern->GetItem( ATTR_FONT_WORDLINE ) )
1061 return true;
1062 else if ( &pNewPattern->GetItem( ATTR_FONT_CROSSEDOUT ) != &rpOldPattern->GetItem( ATTR_FONT_CROSSEDOUT ) )
1063 return true;
1064 else if ( &pNewPattern->GetItem( ATTR_FONT_CONTOUR ) != &rpOldPattern->GetItem( ATTR_FONT_CONTOUR ) )
1065 return true;
1066 else if ( &pNewPattern->GetItem( ATTR_FONT_SHADOWED ) != &rpOldPattern->GetItem( ATTR_FONT_SHADOWED ) )
1067 return true;
1068 else if ( &pNewPattern->GetItem( ATTR_FONT_COLOR ) != &rpOldPattern->GetItem( ATTR_FONT_COLOR ) )
1069 return true;
1070 else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY ) )
1071 return true;
1072 else if ( &pNewPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_HOR_JUSTIFY_METHOD ) )
1073 return true;
1074 else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY ) )
1075 return true;
1076 else if ( &pNewPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) != &rpOldPattern->GetItem( ATTR_VER_JUSTIFY_METHOD ) )
1077 return true;
1078 else if ( &pNewPattern->GetItem( ATTR_STACKED ) != &rpOldPattern->GetItem( ATTR_STACKED ) )
1079 return true;
1080 else if ( &pNewPattern->GetItem( ATTR_LINEBREAK ) != &rpOldPattern->GetItem( ATTR_LINEBREAK ) )
1081 return true;
1082 else if ( &pNewPattern->GetItem( ATTR_MARGIN ) != &rpOldPattern->GetItem( ATTR_MARGIN ) )
1083 return true;
1084 else if ( &pNewPattern->GetItem( ATTR_ROTATE_VALUE ) != &rpOldPattern->GetItem( ATTR_ROTATE_VALUE ) )
1085 return true;
1086 else if ( &pNewPattern->GetItem( ATTR_FORBIDDEN_RULES ) != &rpOldPattern->GetItem( ATTR_FORBIDDEN_RULES ) )
1087 return true;
1088 else if ( &pNewPattern->GetItem( ATTR_FONT_EMPHASISMARK ) != &rpOldPattern->GetItem( ATTR_FONT_EMPHASISMARK ) )
1089 return true;
1090 else if ( &pNewPattern->GetItem( ATTR_FONT_RELIEF ) != &rpOldPattern->GetItem( ATTR_FONT_RELIEF ) )
1091 return true;
1092 else if ( &pNewPattern->GetItem( ATTR_BACKGROUND ) != &rpOldPattern->GetItem( ATTR_BACKGROUND ) )
1093 return true; // needed with automatic text color
1094 else
1095 {
1096 rpOldPattern = pNewPattern;
1097 return false;
1098 }
1099}
1100
1101static void lcl_CreateInterpretProgress( bool& bProgress, ScDocument* pDoc,
1102 const ScFormulaCell* pFCell )
1103{
1104 if ( !bProgress && pFCell->GetDirty() )
1105 {
1107 bProgress = true;
1108 }
1109}
1110
1111static bool IsAmbiguousScript( SvtScriptType nScript )
1112{
1113 return ( nScript != SvtScriptType::LATIN &&
1114 nScript != SvtScriptType::ASIAN &&
1115 nScript != SvtScriptType::COMPLEX );
1116}
1117
1118bool ScOutputData::IsEmptyCellText( const RowInfo* pThisRowInfo, SCCOL nX, SCROW nY )
1119{
1120 // pThisRowInfo may be NULL
1121
1122 bool bEmpty;
1123 if ( pThisRowInfo && nX <= nX2 )
1124 bEmpty = pThisRowInfo->basicCellInfo(nX).bEmptyCellText;
1125 else
1126 {
1127 ScRefCellValue aCell(*mpDoc, ScAddress(nX, nY, nTab));
1128 bEmpty = aCell.isEmpty();
1129 }
1130
1131 if ( !bEmpty && ( nX < nX1 || nX > nX2 || !pThisRowInfo ) )
1132 {
1133 // for the range nX1..nX2 in RowInfo, cell protection attribute is already evaluated
1134 // into bEmptyCellText in ScDocument::FillInfo / lcl_HidePrint (printfun)
1135
1136 bool bIsPrint = ( eType == OUTTYPE_PRINTER );
1137
1138 if ( bIsPrint || bTabProtected )
1139 {
1140 const ScProtectionAttr* pAttr =
1141 mpDoc->GetEffItem( nX, nY, nTab, ATTR_PROTECTION );
1142 if ( bIsPrint && pAttr->GetHidePrint() )
1143 bEmpty = true;
1144 else if ( bTabProtected )
1145 {
1146 if ( pAttr->GetHideCell() )
1147 bEmpty = true;
1148 else if ( mbShowFormulas && pAttr->GetHideFormula() )
1149 {
1151 bEmpty = true;
1152 }
1153 }
1154 }
1155 }
1156 return bEmpty;
1157}
1158
1160{
1161 rCell.assign(*mpDoc, ScAddress(nCol, nRow, nTabP));
1162 if (!rCell.isEmpty() && IsEmptyCellText(nullptr, nCol, nRow))
1163 rCell.clear();
1164}
1165
1167{
1168 // apply the same logic here as in DrawStrings/DrawEdit:
1169 // Stop at non-empty or merged or overlapped cell,
1170 // where a note is empty as well as a cell that's hidden by protection settings
1171
1172 ScRefCellValue aCell(*mpDoc, ScAddress(nX, nY, nTab));
1173 if (!aCell.isEmpty() && !IsEmptyCellText(nullptr, nX, nY))
1174 return false;
1175
1176 const ScPatternAttr* pPattern = mpDoc->GetPattern( nX, nY, nTab );
1177 return !(pPattern->GetItem(ATTR_MERGE).IsMerged() ||
1178 pPattern->GetItem(ATTR_MERGE_FLAG).IsOverlapped());
1179}
1180
1181// nX, nArrY: loop variables from DrawStrings / DrawEdit
1182// nPosX, nPosY: corresponding positions for nX, nArrY
1183// nCellX, nCellY: position of the cell that contains the text
1184// nNeeded: Text width, including margin
1185// rPattern: cell format at nCellX, nCellY
1186// nHorJustify: horizontal alignment (visual) to determine which cells to use for long strings
1187// bCellIsValue: if set, don't extend into empty cells
1188// bBreak: if set, don't extend, and don't set clip marks (but rLeftClip/rRightClip is set)
1189// bOverwrite: if set, also extend into non-empty cells (for rotated text)
1190// rParam output: various area parameters.
1191
1193 SCCOL nCellX, SCROW nCellY, tools::Long nNeeded,
1194 const ScPatternAttr& rPattern,
1195 sal_uInt16 nHorJustify, bool bCellIsValue,
1196 bool bBreak, bool bOverwrite,
1197 OutputAreaParam& rParam )
1198{
1199 // rThisRowInfo may be for a different row than nCellY, is still used for clip marks
1200 RowInfo& rThisRowInfo = pRowInfo[nArrY];
1201
1202 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
1203
1204 tools::Long nCellPosX = nPosX; // find nCellX position, starting at nX/nPosX
1205 SCCOL nCompCol = nX;
1206 while ( nCellX > nCompCol )
1207 {
1209 tools::Long nColWidth = ( nCompCol <= nX2 ) ?
1210 pRowInfo[0].basicCellInfo(nCompCol).nWidth :
1211 static_cast<tools::Long>( mpDoc->GetColWidth( nCompCol, nTab ) * mnPPTX );
1212 nCellPosX += nColWidth * nLayoutSign;
1213 ++nCompCol;
1214 }
1215 while ( nCellX < nCompCol )
1216 {
1217 --nCompCol;
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;
1222 }
1223
1224 tools::Long nCellPosY = nPosY; // find nCellY position, starting at nArrY/nPosY
1225 SCSIZE nCompArr = nArrY;
1226 SCROW nCompRow = pRowInfo[nCompArr].nRowNo;
1227 while ( nCellY > nCompRow )
1228 {
1229 if ( nCompArr + 1 < nArrCount )
1230 {
1231 nCellPosY += pRowInfo[nCompArr].nHeight;
1232 ++nCompArr;
1233 nCompRow = pRowInfo[nCompArr].nRowNo;
1234 }
1235 else
1236 {
1237 sal_uInt16 nDocHeight = mpDoc->GetRowHeight( nCompRow, nTab );
1238 if ( nDocHeight )
1239 nCellPosY += static_cast<tools::Long>( nDocHeight * mnPPTY );
1240 ++nCompRow;
1241 }
1242 }
1243 nCellPosY -= mpDoc->GetScaledRowHeight( nCellY, nCompRow-1, nTab, mnPPTY );
1244
1245 const ScMergeAttr* pMerge = &rPattern.GetItem( ATTR_MERGE );
1246 bool bMerged = pMerge->IsMerged();
1247 tools::Long nMergeCols = pMerge->GetColMerge();
1248 if ( nMergeCols == 0 )
1249 nMergeCols = 1;
1250 tools::Long nMergeRows = pMerge->GetRowMerge();
1251 if ( nMergeRows == 0 )
1252 nMergeRows = 1;
1253
1254 tools::Long nMergeSizeX = 0;
1255 for ( tools::Long i=0; i<nMergeCols; i++ )
1256 {
1257 tools::Long nColWidth = ( nCellX+i <= nX2 ) ?
1258 pRowInfo[0].basicCellInfo(nCellX+i).nWidth :
1259 static_cast<tools::Long>( mpDoc->GetColWidth( sal::static_int_cast<SCCOL>(nCellX+i), nTab ) * mnPPTX );
1260 nMergeSizeX += nColWidth;
1261 }
1262 tools::Long nMergeSizeY = 0;
1263 short nDirect = 0;
1264 if ( rThisRowInfo.nRowNo == nCellY )
1265 {
1266 // take first row's height from row info
1267 nMergeSizeY += rThisRowInfo.nHeight;
1268 nDirect = 1; // skip in loop
1269 }
1270 // following rows always from document
1271 nMergeSizeY += mpDoc->GetScaledRowHeight( nCellY+nDirect, nCellY+nMergeRows-1, nTab, mnPPTY);
1272
1273 --nMergeSizeX; // leave out the grid horizontally, also for alignment (align between grid lines)
1274
1275 rParam.mnColWidth = nMergeSizeX; // store the actual column width.
1276 rParam.mnLeftClipLength = rParam.mnRightClipLength = 0;
1277
1278 // construct the rectangles using logical left/right values (justify is called at the end)
1279
1280 // rAlignRect is the single cell or merged area, used for alignment.
1281
1282 rParam.maAlignRect.SetLeft( nCellPosX );
1283 rParam.maAlignRect.SetRight( nCellPosX + ( nMergeSizeX - 1 ) * nLayoutSign );
1284 rParam.maAlignRect.SetTop( nCellPosY );
1285 rParam.maAlignRect.SetBottom( nCellPosY + nMergeSizeY - 1 );
1286
1287 // rClipRect is all cells that are used for output.
1288 // For merged cells this is the same as rAlignRect, otherwise neighboring cells can also be used.
1289
1290 rParam.maClipRect = rParam.maAlignRect;
1291 if ( nNeeded > nMergeSizeX )
1292 {
1293 SvxCellHorJustify eHorJust = static_cast<SvxCellHorJustify>(nHorJustify);
1294
1295 tools::Long nMissing = nNeeded - nMergeSizeX;
1296 tools::Long nLeftMissing = 0;
1297 tools::Long nRightMissing = 0;
1298 switch ( eHorJust )
1299 {
1300 case SvxCellHorJustify::Left:
1301 nRightMissing = nMissing;
1302 break;
1303 case SvxCellHorJustify::Right:
1304 nLeftMissing = nMissing;
1305 break;
1306 case SvxCellHorJustify::Center:
1307 nLeftMissing = nMissing / 2;
1308 nRightMissing = nMissing - nLeftMissing;
1309 break;
1310 default:
1311 {
1312 // added to avoid warnings
1313 }
1314 }
1315
1316 // nLeftMissing, nRightMissing are logical, eHorJust values are visual
1317 if ( bLayoutRTL )
1318 ::std::swap( nLeftMissing, nRightMissing );
1319
1320 SCCOL nRightX = nCellX;
1321 SCCOL nLeftX = nCellX;
1322 if ( !bMerged && !bCellIsValue && !bBreak )
1323 {
1324 // look for empty cells into which the text can be extended
1325
1326 while ( nRightMissing > 0 && nRightX < mpDoc->MaxCol() && ( bOverwrite || IsAvailable( nRightX+1, nCellY ) ) )
1327 {
1328 ++nRightX;
1329 tools::Long nAdd = static_cast<tools::Long>( mpDoc->GetColWidth( nRightX, nTab ) * mnPPTX );
1330 nRightMissing -= nAdd;
1331 rParam.maClipRect.AdjustRight(nAdd * nLayoutSign );
1332
1333 if ( rThisRowInfo.nRowNo == nCellY && nRightX >= nX1 && nRightX <= nX2 )
1334 rThisRowInfo.cellInfo(nRightX-1).bHideGrid = true;
1335 }
1336
1337 while ( nLeftMissing > 0 && nLeftX > 0 && ( bOverwrite || IsAvailable( nLeftX-1, nCellY ) ) )
1338 {
1339 if ( rThisRowInfo.nRowNo == nCellY && nLeftX >= nX1 && nLeftX <= nX2 )
1340 rThisRowInfo.cellInfo(nLeftX-1).bHideGrid = true;
1341
1342 --nLeftX;
1343 tools::Long nAdd = static_cast<tools::Long>( mpDoc->GetColWidth( nLeftX, nTab ) * mnPPTX );
1344 nLeftMissing -= nAdd;
1345 rParam.maClipRect.AdjustLeft( -(nAdd * nLayoutSign) );
1346 }
1347 }
1348
1349 // Set flag and reserve space for clipping mark triangle,
1350 // even if rThisRowInfo isn't for nCellY (merged cells).
1351 if ( nRightMissing > 0 && bMarkClipped && nRightX >= nX1 && nRightX <= nX2 && !bBreak && !bCellIsValue )
1352 {
1353 rThisRowInfo.cellInfo(nRightX).nClipMark |= ScClipMark::Right;
1354 bAnyClipped = true;
1355 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
1356 rParam.maClipRect.AdjustRight( -(nMarkPixel * nLayoutSign) );
1357 }
1358 if ( nLeftMissing > 0 && bMarkClipped && nLeftX >= nX1 && nLeftX <= nX2 && !bBreak && !bCellIsValue )
1359 {
1360 rThisRowInfo.cellInfo(nLeftX).nClipMark |= ScClipMark::Left;
1361 bAnyClipped = true;
1362 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
1363 rParam.maClipRect.AdjustLeft(nMarkPixel * nLayoutSign );
1364 }
1365
1366 rParam.mbLeftClip = ( nLeftMissing > 0 );
1367 rParam.mbRightClip = ( nRightMissing > 0 );
1368 rParam.mnLeftClipLength = nLeftMissing;
1369 rParam.mnRightClipLength = nRightMissing;
1370 }
1371 else
1372 {
1373 rParam.mbLeftClip = rParam.mbRightClip = false;
1374
1375 // leave space for AutoFilter on screen
1376 // (for automatic line break: only if not formatting for printer, as in ScColumn::GetNeededSize)
1377
1378 if ( eType==OUTTYPE_WINDOW &&
1379 ( rPattern.GetItem(ATTR_MERGE_FLAG).GetValue() & (ScMF::Auto|ScMF::Button|ScMF::ButtonPopup) ) &&
1380 ( !bBreak || mpRefDevice == pFmtDevice ) )
1381 {
1382 // filter drop-down width depends on row height
1383 double fZoom = mpRefDevice ? static_cast<double>(mpRefDevice->GetMapMode().GetScaleY()) : 1.0;
1384 fZoom = fZoom > 1.0 ? fZoom : 1.0;
1385 const tools::Long nFilter = fZoom * DROPDOWN_BITMAP_SIZE;
1386 bool bFit = ( nNeeded + nFilter <= nMergeSizeX );
1387 if ( bFit )
1388 {
1389 // content fits even in the remaining area without the filter button
1390 // -> align within that remaining area
1391
1392 rParam.maAlignRect.AdjustRight( -(nFilter * nLayoutSign) );
1393 rParam.maClipRect.AdjustRight( -(nFilter * nLayoutSign) );
1394 }
1395 }
1396 }
1397
1398 // justify both rectangles for alignment calculation, use with DrawText etc.
1399
1400 rParam.maAlignRect.Normalize();
1401 rParam.maClipRect.Normalize();
1402}
1403
1404namespace {
1405
1406bool beginsWithRTLCharacter(const OUString& rStr)
1407{
1408 if (rStr.isEmpty())
1409 return false;
1410
1411 switch (ScGlobal::getCharClass().getCharacterDirection(rStr, 0))
1412 {
1413 case i18n::DirectionProperty_RIGHT_TO_LEFT:
1414 case i18n::DirectionProperty_RIGHT_TO_LEFT_ARABIC:
1415 case i18n::DirectionProperty_RIGHT_TO_LEFT_EMBEDDING:
1416 case i18n::DirectionProperty_RIGHT_TO_LEFT_OVERRIDE:
1417 return true;
1418 default:
1419 ;
1420 }
1421
1422 return false;
1423}
1424
1425}
1426
1433 bool bCellIsValue, const OUString& rText,
1434 const ScPatternAttr& rPattern, const SfxItemSet* pCondSet,
1435 const ScDocument* pDoc, SCTAB nTab, const bool bNumberFormatIsText )
1436{
1437 SvxCellHorJustify eHorJustContext = eInHorJust;
1438 bool bUseWritingDirection = false;
1439 if (eInHorJust == SvxCellHorJustify::Standard)
1440 {
1441 // fdo#32530: Default alignment depends on value vs
1442 // string, and the direction of the 1st letter.
1443 if (beginsWithRTLCharacter( rText)) //If language is RTL
1444 {
1445 if (bCellIsValue)
1446 eHorJustContext = bNumberFormatIsText ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
1447 else
1448 eHorJustContext = SvxCellHorJustify::Right;
1449 }
1450 else if (bCellIsValue) //If language is not RTL
1451 eHorJustContext = bNumberFormatIsText ? SvxCellHorJustify::Left : SvxCellHorJustify::Right;
1452 else
1453 bUseWritingDirection = true;
1454 }
1455
1456 if (bUseWritingDirection ||
1457 eInHorJust == SvxCellHorJustify::Block || eInHorJust == SvxCellHorJustify::Repeat)
1458 {
1459 SvxFrameDirection nDirection = lcl_GetValue<SvxFrameDirectionItem, SvxFrameDirection>(rPattern, ATTR_WRITINGDIR, pCondSet);
1460 if (nDirection == SvxFrameDirection::Horizontal_LR_TB || nDirection == SvxFrameDirection::Vertical_LR_TB)
1461 eHorJustContext = SvxCellHorJustify::Left;
1462 else if (nDirection == SvxFrameDirection::Environment)
1463 {
1464 SAL_WARN_IF( !pDoc, "sc.ui", "getAlignmentFromContext - pDoc==NULL");
1465 // fdo#73588: The content of the cell must also
1466 // begin with a RTL character to be right
1467 // aligned; otherwise, it should be left aligned.
1468 eHorJustContext = (pDoc && pDoc->IsLayoutRTL(nTab) && (beginsWithRTLCharacter( rText))) ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
1469 }
1470 else
1471 eHorJustContext = SvxCellHorJustify::Right;
1472 }
1473 return eHorJustContext;
1474}
1475
1476void ScOutputData::DrawStrings( bool bPixelToLogic )
1477{
1478 LayoutStrings(bPixelToLogic);
1479}
1480
1481void ScOutputData::LayoutStrings(bool bPixelToLogic)
1482{
1483 bool bOrigIsInLayoutStrings = mpDoc->IsInLayoutStrings();
1484 mpDoc->SetLayoutStrings(true);
1485 comphelper::ScopeGuard g([this, bOrigIsInLayoutStrings] {
1486 mpDoc->SetLayoutStrings(bOrigIsInLayoutStrings);
1487 });
1488
1489 OSL_ENSURE( mpDev == mpRefDevice ||
1490 mpDev->GetMapMode().GetMapUnit() == mpRefDevice->GetMapMode().GetMapUnit(),
1491 "LayoutStrings: different MapUnits ?!?!" );
1492
1493 sc::IdleSwitch aIdleSwitch(*mpDoc, false);
1494
1495 // Try to limit interpreting to only visible cells. Calling e.g. IsValue()
1496 // on a formula cell that needs interpreting would call Interpret()
1497 // for the entire formula group, which could be large.
1499
1500 vcl::PDFExtOutDevData* pPDFData = dynamic_cast< vcl::PDFExtOutDevData* >(mpDev->GetExtOutDevData() );
1501
1502 ScDrawStringsVars aVars( this, bPixelToLogic );
1503
1504 bool bProgress = false;
1505
1506 tools::Long nInitPosX = nScrX;
1507 if ( bLayoutRTL )
1508 nInitPosX += nMirrorW - 1; // pixels
1509 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
1510
1511 SCCOL nLastContentCol = mpDoc->MaxCol();
1512 if ( nX2 < mpDoc->MaxCol() )
1513 nLastContentCol = sal::static_int_cast<SCCOL>(
1514 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, mpDoc->MaxCol(), nY2, nTab, DIR_RIGHT ) );
1515 SCCOL nLoopStartX = nX1;
1516 if ( nX1 > 0 )
1517 --nLoopStartX; // start before nX1 for rest of long text to the left
1518
1519 // variables for GetOutputArea
1520 OutputAreaParam aAreaParam;
1521 bool bCellIsValue = false;
1522 tools::Long nNeededWidth = 0;
1523 const ScPatternAttr* pPattern = nullptr;
1524 const SfxItemSet* pCondSet = nullptr;
1525 const ScPatternAttr* pOldPattern = nullptr;
1526 const SfxItemSet* pOldCondSet = nullptr;
1527 SvtScriptType nOldScript = SvtScriptType::NONE;
1528
1529 // alternative pattern instances in case we need to modify the pattern
1530 // before processing the cell value.
1531 std::vector<std::unique_ptr<ScPatternAttr> > aAltPatterns;
1532
1533 KernArray aDX;
1534 tools::Long nPosY = nScrY;
1535 for (SCSIZE nArrY=1; nArrY+1<nArrCount; nArrY++)
1536 {
1537 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
1538 SCROW nY = pThisRowInfo->nRowNo;
1539 if (pThisRowInfo->bChanged)
1540 {
1541 tools::Long nPosX = nInitPosX;
1542 if ( nLoopStartX < nX1 )
1543 nPosX -= pRowInfo[0].basicCellInfo(nLoopStartX).nWidth * nLayoutSign;
1544 for (SCCOL nX=nLoopStartX; nX<=nX2; nX++)
1545 {
1546 bool bMergeEmpty = false;
1547 const ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
1548 bool bEmpty = nX < nX1 || pThisRowInfo->basicCellInfo(nX).bEmptyCellText;
1549
1550 SCCOL nCellX = nX; // position where the cell really starts
1551 SCROW nCellY = nY;
1552 bool bDoCell = false;
1553 bool bUseEditEngine = false;
1554
1555 // Part of a merged cell?
1556
1557 bool bOverlapped = (pInfo->bHOverlapped || pInfo->bVOverlapped);
1558 if ( bOverlapped )
1559 {
1560 bEmpty = true;
1561
1562 SCCOL nOverX; // start of the merged cells
1563 SCROW nOverY;
1564 bool bVisChanged = !pRowInfo[nArrY-1].bChanged;
1565 if (GetMergeOrigin( nX,nY, nArrY, nOverX,nOverY, bVisChanged ))
1566 {
1567 nCellX = nOverX;
1568 nCellY = nOverY;
1569 bDoCell = true;
1570 }
1571 else
1572 bMergeEmpty = true;
1573 }
1574
1575 // Rest of a long text further to the left?
1576
1577 if ( bEmpty && !bMergeEmpty && nX < nX1 && !bOverlapped )
1578 {
1579 SCCOL nTempX=nX1;
1580 while (nTempX > 0 && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1581 --nTempX;
1582
1583 if ( nTempX < nX1 &&
1584 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1586 {
1587 nCellX = nTempX;
1588 bDoCell = true;
1589 }
1590 }
1591
1592 // Rest of a long text further to the right?
1593
1594 if ( bEmpty && !bMergeEmpty && nX == nX2 && !bOverlapped )
1595 {
1596 // don't have to look further than nLastContentCol
1597
1598 SCCOL nTempX=nX;
1599 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
1600 ++nTempX;
1601
1602 if ( nTempX > nX &&
1603 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
1605 {
1606 nCellX = nTempX;
1607 bDoCell = true;
1608 }
1609 }
1610
1611 // normal visible cell
1612
1613 if (!bEmpty)
1614 bDoCell = true;
1615
1616 // don't output the cell that's being edited
1617
1618 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
1619 bDoCell = false;
1620
1621 // skip text in cell if data bar/icon set is set and only value selected
1622 if ( bDoCell )
1623 {
1624 if(pInfo->pDataBar && !pInfo->pDataBar->mbShowValue)
1625 bDoCell = false;
1626 if(pInfo->pIconSet && !pInfo->pIconSet->mbShowValue)
1627 bDoCell = false;
1628 }
1629
1630 // output the cell text
1631
1632 ScRefCellValue aCell;
1633 if (bDoCell)
1634 {
1635 if ( nCellY == nY && nCellX == nX && nCellX >= nX1 && nCellX <= nX2 )
1636 aCell = pThisRowInfo->cellInfo(nCellX).maCell;
1637 else
1638 GetVisibleCell( nCellX, nCellY, nTab, aCell ); // get from document
1639 if (aCell.isEmpty())
1640 bDoCell = false;
1641 else if (aCell.getType() == CELLTYPE_EDIT)
1642 bUseEditEngine = true;
1643 }
1644
1645 // Check if this cell is mis-spelled.
1646 if (bDoCell && !bUseEditEngine && aCell.getType() == CELLTYPE_STRING)
1647 {
1648 if (mpSpellCheckCxt && mpSpellCheckCxt->isMisspelled(nCellX, nCellY))
1649 bUseEditEngine = true;
1650 }
1651
1652 if (bDoCell && !bUseEditEngine)
1653 {
1654 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1655 {
1656 ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nCellX);
1657 pPattern = rCellInfo.pPatternAttr;
1658 pCondSet = rCellInfo.pConditionSet;
1659
1660 if ( !pPattern )
1661 {
1662 // #i68085# pattern from cell info for hidden columns is null,
1663 // test for null is quicker than using column flags
1664 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1665 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1666 }
1667 }
1668 else // get from document
1669 {
1670 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
1671 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
1672 }
1674 {
1675 aAltPatterns.push_back(std::make_unique<ScPatternAttr>(*pPattern));
1676 ScPatternAttr* pAltPattern = aAltPatterns.back().get();
1677 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
1678 {
1679 pAltPattern->SetStyleSheet(pPreviewStyle);
1680 }
1681 else if ( SfxItemSet* pFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab ) )
1682 {
1683 if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_FONT ) )
1684 pAltPattern->GetItemSet().Put( *pItem );
1685 if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_CJK_FONT ) )
1686 pAltPattern->GetItemSet().Put( *pItem );
1687 if ( const SvxFontItem* pItem = pFontSet->GetItemIfSet( ATTR_CTL_FONT ) )
1688 pAltPattern->GetItemSet().Put( *pItem );
1689 }
1690 pPattern = pAltPattern;
1691 }
1692
1693 if (aCell.hasNumeric() &&
1694 pPattern->GetItem(ATTR_LINEBREAK, pCondSet).GetValue())
1695 {
1696 // Disable line break when the cell content is numeric.
1697 aAltPatterns.push_back(std::make_unique<ScPatternAttr>(*pPattern));
1698 ScPatternAttr* pAltPattern = aAltPatterns.back().get();
1699 ScLineBreakCell aLineBreak(false);
1700 pAltPattern->GetItemSet().Put(aLineBreak);
1701 pPattern = pAltPattern;
1702 }
1703
1705 ScAddress(nCellX, nCellY, nTab),
1706 pPattern->GetNumberFormat(mpDoc->GetFormatTable(), pCondSet));
1707
1708 if (nScript == SvtScriptType::NONE)
1710
1711 if ( pPattern != pOldPattern || pCondSet != pOldCondSet ||
1712 nScript != nOldScript || mbSyntaxMode )
1713 {
1714 if ( StringDiffer(pOldPattern,pPattern) ||
1715 pCondSet != pOldCondSet || nScript != nOldScript || mbSyntaxMode )
1716 {
1717 aVars.SetPattern(pPattern, pCondSet, aCell, nScript);
1718 }
1719 else
1720 aVars.SetPatternSimple( pPattern, pCondSet );
1721 pOldPattern = pPattern;
1722 pOldCondSet = pCondSet;
1723 nOldScript = nScript;
1724 }
1725
1726 // use edit engine for rotated, stacked or mixed-script text
1727 if ( aVars.GetOrient() == SvxCellOrientation::Stacked ||
1728 aVars.IsRotated() || IsAmbiguousScript(nScript) )
1729 bUseEditEngine = true;
1730 }
1731 if (bDoCell && !bUseEditEngine)
1732 {
1733 bool bFormulaCell = (aCell.getType() == CELLTYPE_FORMULA);
1734 if ( bFormulaCell )
1735 lcl_CreateInterpretProgress(bProgress, mpDoc, aCell.getFormula());
1736 if ( aVars.SetText(aCell) )
1737 pOldPattern = nullptr;
1738 bUseEditEngine = aVars.HasEditCharacters() || (bFormulaCell && aCell.getFormula()->IsMultilineResult());
1739 }
1740 tools::Long nTotalMargin = 0;
1741 SvxCellHorJustify eOutHorJust = SvxCellHorJustify::Standard;
1742 if (bDoCell && !bUseEditEngine)
1743 {
1744 CellType eCellType = aCell.getType();
1745 bCellIsValue = ( eCellType == CELLTYPE_VALUE );
1746 if ( eCellType == CELLTYPE_FORMULA )
1747 {
1748 ScFormulaCell* pFCell = aCell.getFormula();
1749 bCellIsValue = pFCell->IsRunning() || pFCell->IsValue();
1750 }
1751
1752 const bool bNumberFormatIsText = lcl_isNumberFormatText( mpDoc, nCellX, nCellY, nTab );
1753 eOutHorJust = getAlignmentFromContext( aVars.GetHorJust(), bCellIsValue, aVars.GetString(),
1754 *pPattern, pCondSet, mpDoc, nTab, bNumberFormatIsText );
1755
1756 bool bBreak = ( aVars.GetLineBreak() || aVars.GetHorJust() == SvxCellHorJustify::Block );
1757 // #i111387# #o11817313# tdf#121040 disable automatic line breaks for all number formats
1758 // Must be synchronized with ScColumn::GetNeededSize()
1759 SvNumberFormatter* pFormatter = mpDoc->GetFormatTable();
1760 if (bBreak && bCellIsValue && (pFormatter->GetType(aVars.GetResultValueFormat()) == SvNumFormatType::NUMBER))
1761 bBreak = false;
1762
1763 bool bRepeat = aVars.IsRepeat() && !bBreak;
1764 bool bShrink = aVars.IsShrink() && !bBreak && !bRepeat;
1765
1766 nTotalMargin =
1767 static_cast<tools::Long>(aVars.GetLeftTotal() * mnPPTX) +
1768 static_cast<tools::Long>(aVars.GetMargin()->GetRightMargin() * mnPPTX);
1769
1770 nNeededWidth = aVars.GetTextSize().Width() + nTotalMargin;
1771
1772 // GetOutputArea gives justified rectangles
1773 GetOutputArea( nX, nArrY, nPosX, nPosY, nCellX, nCellY, nNeededWidth,
1774 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
1775 bCellIsValue || bRepeat || bShrink, bBreak, false,
1776 aAreaParam );
1777
1778 aVars.RepeatToFill( aAreaParam.mnColWidth - nTotalMargin );
1779 if ( bShrink )
1780 {
1781 if ( aVars.GetOrient() != SvxCellOrientation::Standard )
1782 {
1783 // Only horizontal scaling is handled here.
1784 // DrawEdit is used to vertically scale 90 deg rotated text.
1785 bUseEditEngine = true;
1786 }
1787 else if ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) // horizontal
1788 {
1789 tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1790 tools::Long nScaleSize = aVars.GetTextSize().Width(); // without margin
1791
1792 if ( nAvailable > 0 && nScaleSize > 0 ) // 0 if the text is empty (formulas, number formats)
1793 {
1794 tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
1795
1796 aVars.SetShrinkScale( nScale, nOldScript );
1797 tools::Long nNewSize = aVars.GetTextSize().Width();
1798
1799 sal_uInt16 nShrinkAgain = 0;
1800 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
1801 {
1802 // If the text is still too large, reduce the scale again by 10%, until it fits,
1803 // at most 7 times (it's less than 50% of the calculated scale then).
1804
1805 nScale = ( nScale * 9 ) / 10;
1806 aVars.SetShrinkScale( nScale, nOldScript );
1807 nNewSize = aVars.GetTextSize().Width();
1808 ++nShrinkAgain;
1809 }
1810 // If even at half the size the font still isn't rendered smaller,
1811 // fall back to normal clipping (showing ### for numbers).
1812 if ( nNewSize <= nAvailable )
1813 {
1814 // Reset relevant parameters.
1815 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1816 aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
1817 }
1818
1819 pOldPattern = nullptr;
1820 }
1821 }
1822 }
1823
1824 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip )
1825 {
1826 tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nTotalMargin;
1827 tools::Long nRepeatSize = aVars.GetTextSize().Width(); // without margin
1828 // When formatting for the printer, the text sizes don't always add up.
1829 // Round down (too few repetitions) rather than exceeding the cell size then:
1830 if ( pFmtDevice != mpRefDevice )
1831 ++nRepeatSize;
1832 if ( nRepeatSize > 0 )
1833 {
1834 tools::Long nRepeatCount = nAvailable / nRepeatSize;
1835 if ( nRepeatCount > 1 )
1836 {
1837 OUString aCellStr = aVars.GetString();
1838 OUStringBuffer aRepeated(aCellStr);
1839 for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
1840 aRepeated.append(aCellStr);
1841 aVars.SetAutoText( aRepeated.makeStringAndClear() );
1842 }
1843 }
1844 }
1845
1846 // use edit engine if automatic line breaks are needed
1847 if ( bBreak )
1848 {
1849 if ( aVars.GetOrient() == SvxCellOrientation::Standard )
1850 bUseEditEngine = ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip );
1851 else
1852 {
1853 tools::Long nHeight = aVars.GetTextSize().Height() +
1854 static_cast<tools::Long>(aVars.GetMargin()->GetTopMargin()*mnPPTY) +
1855 static_cast<tools::Long>(aVars.GetMargin()->GetBottomMargin()*mnPPTY);
1856 bUseEditEngine = ( nHeight > aAreaParam.maClipRect.GetHeight() );
1857 }
1858 }
1859 if (!bUseEditEngine)
1860 {
1861 bUseEditEngine =
1862 aVars.GetHorJust() == SvxCellHorJustify::Block &&
1863 aVars.GetHorJustMethod() == SvxCellJustifyMethod::Distribute;
1864 }
1865 }
1866 if (bUseEditEngine)
1867 {
1868 // mark the cell in ScCellInfo to be drawn in DrawEdit:
1869 // Cells to the left are marked directly, cells to the
1870 // right are handled by the flag for nX2
1871 SCCOL nMarkX = ( nCellX <= nX2 ) ? nCellX : nX2;
1872 RowInfo* pMarkRowInfo = ( nCellY == nY ) ? pThisRowInfo : &pRowInfo[0];
1873 pMarkRowInfo->basicCellInfo(nMarkX).bEditEngine = true;
1874 bDoCell = false; // don't draw here
1875 }
1876 if ( bDoCell )
1877 {
1878 if ( bCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
1879 {
1880 bool bHasHashText = false;
1881 if (mbShowFormulas)
1882 {
1883 aVars.SetHashText();
1884 bHasHashText = true;
1885 }
1886 else
1887 // Adjust the decimals to fit the available column width.
1888 bHasHashText = aVars.SetTextToWidthOrHash( aCell, aAreaParam.mnColWidth - nTotalMargin );
1889
1890 if ( bHasHashText )
1891 {
1892 tools::Long nMarkPixel = SC_CLIPMARK_SIZE * mnPPTX;
1893
1894 if ( eOutHorJust == SvxCellHorJustify::Left )
1895 {
1896 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1897 pRowInfo[nArrY].cellInfo(nCellX).nClipMark |= ScClipMark::Right;
1898 bAnyClipped = true;
1899 aAreaParam.maClipRect.AdjustRight( -(nMarkPixel * nLayoutSign) );
1900 }
1901 else if ( eOutHorJust == SvxCellHorJustify::Right )
1902 {
1903 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1904 pRowInfo[nArrY].cellInfo(nCellX).nClipMark |= ScClipMark::Left;
1905 bAnyClipped = true;
1906 aAreaParam.maClipRect.AdjustLeft(nMarkPixel * nLayoutSign);
1907 }
1908 else
1909 {
1910 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 )
1911 {
1912 pRowInfo[nArrY].cellInfo(nCellX).nClipMark |= ScClipMark::Right;
1913 pRowInfo[nArrY].cellInfo(nCellX).nClipMark |= ScClipMark::Left;
1914 }
1915 bAnyClipped = true;
1916 aAreaParam.maClipRect.AdjustRight( -(nMarkPixel * nLayoutSign) );
1917 aAreaParam.maClipRect.AdjustLeft(nMarkPixel * nLayoutSign);
1918 }
1919 }
1920
1921 nNeededWidth = aVars.GetTextSize().Width() +
1922 static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX ) +
1923 static_cast<tools::Long>( aVars.GetMargin()->GetRightMargin() * mnPPTX );
1924 if ( nNeededWidth <= aAreaParam.maClipRect.GetWidth() )
1925 {
1926 // Cell value is no longer clipped. Reset relevant parameters.
1927 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = false;
1928 aAreaParam.mnLeftClipLength = aAreaParam.mnRightClipLength = 0;
1929 }
1930 }
1931
1932 tools::Long nJustPosX = aAreaParam.maAlignRect.Left(); // "justified" - effect of alignment will be added
1933 tools::Long nJustPosY = aAreaParam.maAlignRect.Top();
1934 tools::Long nAvailWidth = aAreaParam.maAlignRect.GetWidth();
1935 tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight();
1936
1937 bool bOutside = ( aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW );
1938 // Take adjusted values of aAreaParam.mbLeftClip and aAreaParam.mbRightClip
1939 bool bVClip = AdjustAreaParamClipRect(aAreaParam);
1940 bool bHClip = aAreaParam.mbLeftClip || aAreaParam.mbRightClip;
1941
1942 // check horizontal space
1943
1944 if ( !bOutside )
1945 {
1946 bool bRightAdjusted = false; // to correct text width calculation later
1947 switch (eOutHorJust)
1948 {
1949 case SvxCellHorJustify::Left:
1950 nJustPosX += static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX );
1951 break;
1952 case SvxCellHorJustify::Right:
1953 nJustPosX += nAvailWidth - aVars.GetTextSize().Width() -
1954 static_cast<tools::Long>( aVars.GetRightTotal() * mnPPTX );
1955 bRightAdjusted = true;
1956 break;
1957 case SvxCellHorJustify::Center:
1958 nJustPosX += ( nAvailWidth - aVars.GetTextSize().Width() +
1959 static_cast<tools::Long>( aVars.GetLeftTotal() * mnPPTX ) -
1960 static_cast<tools::Long>( aVars.GetMargin()->GetRightMargin() * mnPPTX ) ) / 2;
1961 break;
1962 default:
1963 {
1964 // added to avoid warnings
1965 }
1966 }
1967
1968 tools::Long nTestClipHeight = aVars.GetTextSize().Height();
1969 switch (aVars.GetVerJust())
1970 {
1971 case SvxCellVerJustify::Top:
1972 case SvxCellVerJustify::Block:
1973 {
1974 tools::Long nTop = static_cast<tools::Long>( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1975 nJustPosY += nTop;
1976 nTestClipHeight += nTop;
1977 }
1978 break;
1979 case SvxCellVerJustify::Bottom:
1980 {
1981 tools::Long nBot = static_cast<tools::Long>( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1982 nJustPosY += nOutHeight - aVars.GetTextSize().Height() - nBot;
1983 nTestClipHeight += nBot;
1984 }
1985 break;
1986 case SvxCellVerJustify::Center:
1987 {
1988 tools::Long nTop = static_cast<tools::Long>( aVars.GetMargin()->GetTopMargin() * mnPPTY );
1989 tools::Long nBot = static_cast<tools::Long>( aVars.GetMargin()->GetBottomMargin() * mnPPTY );
1990 nJustPosY += ( nOutHeight + nTop -
1991 aVars.GetTextSize().Height() - nBot ) / 2;
1992 nTestClipHeight += std::abs( nTop - nBot );
1993 }
1994 break;
1995 default:
1996 {
1997 // added to avoid warnings
1998 }
1999 }
2000
2001 if ( nTestClipHeight > nOutHeight )
2002 {
2003 // no vertical clipping when printing cells with optimal height,
2004 // except when font size is from conditional formatting.
2005 if ( eType != OUTTYPE_PRINTER ||
2006 ( mpDoc->GetRowFlags( nCellY, nTab ) & CRFlags::ManualSize ) ||
2007 ( aVars.HasCondHeight() ) )
2008 bVClip = true;
2009 }
2010
2011 if ( bHClip || bVClip )
2012 {
2013 // only clip the affected dimension so that not all right-aligned
2014 // columns are cut off when performing a non-proportional resize
2015 if (!bHClip)
2016 {
2017 aAreaParam.maClipRect.SetLeft( nScrX );
2018 aAreaParam.maClipRect.SetRight( nScrX+nScrW );
2019 }
2020 if (!bVClip)
2021 {
2022 aAreaParam.maClipRect.SetTop( nScrY );
2023 aAreaParam.maClipRect.SetBottom( nScrY+nScrH );
2024 }
2025
2026 // aClipRect is not used after SetClipRegion/IntersectClipRegion,
2027 // so it can be modified here
2028 if (bPixelToLogic)
2029 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( aAreaParam.maClipRect );
2030
2031 if (bMetaFile)
2032 {
2033 mpDev->Push();
2034 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
2035 }
2036 else
2037 mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
2038 }
2039
2040 Point aURLStart( nJustPosX, nJustPosY ); // copy before modifying for orientation
2041
2042 switch (aVars.GetOrient())
2043 {
2044 case SvxCellOrientation::Standard:
2045 nJustPosY += aVars.GetAscent();
2046 break;
2047 case SvxCellOrientation::TopBottom:
2048 nJustPosX += aVars.GetTextSize().Width() - aVars.GetAscent();
2049 break;
2050 case SvxCellOrientation::BottomUp:
2051 nJustPosY += aVars.GetTextSize().Height();
2052 nJustPosX += aVars.GetAscent();
2053 break;
2054 default:
2055 {
2056 // added to avoid warnings
2057 }
2058 }
2059
2060 // When clipping, the visible part is now completely defined by the alignment,
2061 // there's no more special handling to show the right part of RTL text.
2062
2063 Point aDrawTextPos( nJustPosX, nJustPosY );
2064 if ( bPixelToLogic )
2065 {
2066 // undo text width adjustment in pixels
2067 if (bRightAdjusted)
2068 aDrawTextPos.AdjustX(aVars.GetTextSize().Width() );
2069
2070 aDrawTextPos = mpRefDevice->PixelToLogic( aDrawTextPos );
2071
2072 // redo text width adjustment in logic units
2073 if (bRightAdjusted)
2074 aDrawTextPos.AdjustX( -(aVars.GetOriginalWidth()) );
2075 }
2076
2077 // in Metafiles always use DrawTextArray to ensure that positions are
2078 // recorded (for non-proportional resize):
2079
2080 const OUString& aString = aVars.GetString();
2081 if (!aString.isEmpty())
2082 {
2083 // If the string is clipped, make it shorter for
2084 // better performance since drawing by HarfBuzz is
2085 // quite expensive especially for long string.
2086
2087 OUString aShort = aString;
2088
2089 // But never fiddle with numeric values.
2090 // (Which was the cause of tdf#86024).
2091 // The General automatic format output takes
2092 // care of this, or fixed width numbers either fit
2093 // or display as ###.
2094 if (!bCellIsValue)
2095 {
2096 double fVisibleRatio = 1.0;
2097 double fTextWidth = aVars.GetTextSize().Width();
2098 sal_Int32 nTextLen = aString.getLength();
2099 if (eOutHorJust == SvxCellHorJustify::Left && aAreaParam.mnRightClipLength > 0)
2100 {
2101 fVisibleRatio = (fTextWidth - aAreaParam.mnRightClipLength) / fTextWidth;
2102 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2103 {
2104 // Only show the left-end segment.
2105 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2106 aShort = aShort.copy(0, nShortLen);
2107 }
2108 }
2109 else if (eOutHorJust == SvxCellHorJustify::Right && aAreaParam.mnLeftClipLength > 0)
2110 {
2111 fVisibleRatio = (fTextWidth - aAreaParam.mnLeftClipLength) / fTextWidth;
2112 if (0.0 < fVisibleRatio && fVisibleRatio < 1.0)
2113 {
2114 // Only show the right-end segment.
2115 sal_Int32 nShortLen = fVisibleRatio*nTextLen + 1;
2116 aShort = aShort.copy(nTextLen-nShortLen);
2117
2118 // Adjust the text position after shortening of the string.
2119 double fShortWidth = aVars.GetFmtTextWidth(aShort);
2120 double fOffset = fTextWidth - fShortWidth;
2121 aDrawTextPos.Move(fOffset, 0);
2122 }
2123 }
2124 }
2125
2126 if (bMetaFile || pFmtDevice != mpDev || aZoomX != aZoomY)
2127 {
2128 size_t nLen = aShort.getLength();
2129 if (aDX.size() < nLen)
2130 aDX.resize(nLen, 0);
2131
2132 pFmtDevice->GetTextArray(aShort, &aDX);
2133
2134 if ( !mpRefDevice->GetConnectMetaFile() ||
2135 mpRefDevice->GetOutDevType() == OUTDEV_PRINTER )
2136 {
2137 double fMul = GetStretch();
2138 for (size_t i = 0; i < nLen; ++i)
2139 aDX.set(i, static_cast<sal_Int32>(aDX[i] / fMul + 0.5));
2140 }
2141
2142 mpDev->DrawTextArray(aDrawTextPos, aShort, aDX, {}, 0, nLen);
2143 }
2144 else
2145 {
2146 mpDev->DrawText(aDrawTextPos, aShort, 0, -1, nullptr, nullptr,
2147 aVars.GetLayoutGlyphs(aShort));
2148 }
2149 }
2150
2151 if ( bHClip || bVClip )
2152 {
2153 if (bMetaFile)
2154 mpDev->Pop();
2155 else
2156 mpDev->SetClipRegion();
2157 }
2158
2159 // PDF: whole-cell hyperlink from formula?
2160 bool bHasURL = pPDFData && aCell.getType() == CELLTYPE_FORMULA && aCell.getFormula()->IsHyperLinkCell();
2161 if (bHasURL)
2162 {
2163 tools::Rectangle aURLRect( aURLStart, aVars.GetTextSize() );
2164 lcl_DoHyperlinkResult(mpDev, aURLRect, aCell);
2165 }
2166 }
2167 }
2168 nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
2169 }
2170 }
2171 nPosY += pRowInfo[nArrY].nHeight;
2172 }
2173 if ( bProgress )
2175}
2176
2177std::unique_ptr<ScFieldEditEngine> ScOutputData::CreateOutputEditEngine()
2178{
2179 std::unique_ptr<ScFieldEditEngine> pEngine(new ScFieldEditEngine(mpDoc, mpDoc->GetEnginePool()));
2180 pEngine->SetUpdateLayout( false );
2181 // a RefDevice always has to be set, otherwise EditEngine would create a VirtualDevice
2182 pEngine->SetRefDevice( pFmtDevice );
2183 EEControlBits nCtrl = pEngine->GetControlWord();
2184 if ( bShowSpellErrors )
2185 nCtrl |= EEControlBits::ONLINESPELLING;
2186 if ( eType == OUTTYPE_PRINTER )
2187 nCtrl &= ~EEControlBits::MARKFIELDS;
2188 else
2189 nCtrl &= ~EEControlBits::MARKURLFIELDS; // URLs not shaded for output
2191 nCtrl &= ~EEControlBits::FORMAT100; // use the actual MapMode
2192 pEngine->SetControlWord( nCtrl );
2193 mpDoc->ApplyAsianEditSettings( *pEngine );
2194 pEngine->EnableAutoColor( mbUseStyleColor );
2195 pEngine->SetDefaultHorizontalTextDirection( mpDoc->GetEditTextDirection( nTab ) );
2196 return pEngine;
2197}
2198
2199static void lcl_ClearEdit( EditEngine& rEngine ) // text and attributes
2200{
2201 rEngine.SetUpdateLayout( false );
2202
2203 rEngine.SetText(OUString());
2204 // do not keep any para-attributes
2205 const SfxItemSet& rPara = rEngine.GetParaAttribs(0);
2206 if (rPara.Count())
2207 rEngine.SetParaAttribs( 0,
2208 SfxItemSet( *rPara.GetPool(), rPara.GetRanges() ) );
2209 rEngine.EnableSkipOutsideFormat(false);
2210}
2211
2212static bool lcl_SafeIsValue( ScRefCellValue& rCell )
2213{
2214 switch (rCell.getType())
2215 {
2216 case CELLTYPE_VALUE:
2217 return true;
2218 case CELLTYPE_FORMULA:
2219 {
2220 ScFormulaCell* pFCell = rCell.getFormula();
2221 if (pFCell->IsRunning() || pFCell->IsValue())
2222 return true;
2223 }
2224 break;
2225 default:
2226 {
2227 // added to avoid warnings
2228 }
2229 }
2230 return false;
2231}
2232
2233static void lcl_ScaleFonts( EditEngine& rEngine, tools::Long nPercent )
2234{
2235 bool bUpdateMode = rEngine.SetUpdateLayout( false );
2236
2237 sal_Int32 nParCount = rEngine.GetParagraphCount();
2238 for (sal_Int32 nPar=0; nPar<nParCount; nPar++)
2239 {
2240 std::vector<sal_Int32> aPortions;
2241 rEngine.GetPortions( nPar, aPortions );
2242
2243 sal_Int32 nStart = 0;
2244 for ( const sal_Int32 nEnd : aPortions )
2245 {
2246 ESelection aSel( nPar, nStart, nPar, nEnd );
2247 SfxItemSet aAttribs = rEngine.GetAttribs( aSel );
2248
2249 tools::Long nWestern = aAttribs.Get(EE_CHAR_FONTHEIGHT).GetHeight();
2250 tools::Long nCJK = aAttribs.Get(EE_CHAR_FONTHEIGHT_CJK).GetHeight();
2251 tools::Long nCTL = aAttribs.Get(EE_CHAR_FONTHEIGHT_CTL).GetHeight();
2252
2253 nWestern = ( nWestern * nPercent ) / 100;
2254 nCJK = ( nCJK * nPercent ) / 100;
2255 nCTL = ( nCTL * nPercent ) / 100;
2256
2257 aAttribs.Put( SvxFontHeightItem( nWestern, 100, EE_CHAR_FONTHEIGHT ) );
2258 aAttribs.Put( SvxFontHeightItem( nCJK, 100, EE_CHAR_FONTHEIGHT_CJK ) );
2259 aAttribs.Put( SvxFontHeightItem( nCTL, 100, EE_CHAR_FONTHEIGHT_CTL ) );
2260
2261 rEngine.QuickSetAttribs( aAttribs, aSel );
2262
2263 nStart = nEnd;
2264 }
2265 }
2266
2267 if ( bUpdateMode )
2268 rEngine.SetUpdateLayout( true );
2269}
2270
2271static tools::Long lcl_GetEditSize( EditEngine& rEngine, bool bWidth, bool bSwap, Degree100 nAttrRotate )
2272{
2273 if ( bSwap )
2274 bWidth = !bWidth;
2275
2276 if ( nAttrRotate )
2277 {
2278 tools::Long nRealWidth = static_cast<tools::Long>(rEngine.CalcTextWidth());
2279 tools::Long nRealHeight = rEngine.GetTextHeight();
2280
2281 // assuming standard mode, otherwise width isn't used
2282
2283 double nRealOrient = toRadians(nAttrRotate); // 1/100th degrees
2284 double nAbsCos = fabs( cos( nRealOrient ) );
2285 double nAbsSin = fabs( sin( nRealOrient ) );
2286 if ( bWidth )
2287 return static_cast<tools::Long>( nRealWidth * nAbsCos + nRealHeight * nAbsSin );
2288 else
2289 return static_cast<tools::Long>( nRealHeight * nAbsCos + nRealWidth * nAbsSin );
2290 }
2291 else if ( bWidth )
2292 return static_cast<tools::Long>(rEngine.CalcTextWidth());
2293 else
2294 return rEngine.GetTextHeight();
2295}
2296
2298 tools::Long nLeftM, tools::Long nTopM, tools::Long nRightM, tools::Long nBottomM,
2299 bool bWidth, SvxCellOrientation nOrient, Degree100 nAttrRotate, bool bPixelToLogic,
2300 tools::Long& rEngineWidth, tools::Long& rEngineHeight, tools::Long& rNeededPixel, bool& rLeftClip, bool& rRightClip )
2301{
2302 if ( !bWidth )
2303 {
2304 // vertical
2305
2306 tools::Long nScaleSize = bPixelToLogic ?
2307 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2308
2309 // Don't scale if it fits already.
2310 // Allowing to extend into the margin, to avoid scaling at optimal height.
2311 if ( nScaleSize <= rAlignRect.GetHeight() )
2312 return;
2313
2314 bool bSwap = ( nOrient == SvxCellOrientation::TopBottom || nOrient == SvxCellOrientation::BottomUp );
2315 tools::Long nAvailable = rAlignRect.GetHeight() - nTopM - nBottomM;
2316 tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
2317
2318 lcl_ScaleFonts( rEngine, nScale );
2319 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2320 tools::Long nNewSize = bPixelToLogic ?
2321 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2322
2323 sal_uInt16 nShrinkAgain = 0;
2324 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2325 {
2326 // further reduce, like in DrawStrings
2327 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2328 rEngineHeight = lcl_GetEditSize( rEngine, false, bSwap, nAttrRotate );
2329 nNewSize = bPixelToLogic ?
2330 mpRefDevice->LogicToPixel(Size(0,rEngineHeight)).Height() : rEngineHeight;
2331 ++nShrinkAgain;
2332 }
2333
2334 // sizes for further processing (alignment etc):
2335 rEngineWidth = lcl_GetEditSize( rEngine, true, bSwap, nAttrRotate );
2336 tools::Long nPixelWidth = bPixelToLogic ?
2337 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2338 rNeededPixel = nPixelWidth + nLeftM + nRightM;
2339 }
2340 else if ( rLeftClip || rRightClip )
2341 {
2342 // horizontal
2343
2344 tools::Long nAvailable = rAlignRect.GetWidth() - nLeftM - nRightM;
2345 tools::Long nScaleSize = rNeededPixel - nLeftM - nRightM; // without margin
2346
2347 if ( nScaleSize <= nAvailable )
2348 return;
2349
2350 tools::Long nScale = ( nAvailable * 100 ) / nScaleSize;
2351
2352 lcl_ScaleFonts( rEngine, nScale );
2353 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2354 tools::Long nNewSize = bPixelToLogic ?
2355 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2356
2357 sal_uInt16 nShrinkAgain = 0;
2358 while ( nNewSize > nAvailable && nShrinkAgain < SC_SHRINKAGAIN_MAX )
2359 {
2360 // further reduce, like in DrawStrings
2361 lcl_ScaleFonts( rEngine, 90 ); // reduce by 10%
2362 rEngineWidth = lcl_GetEditSize( rEngine, true, false, nAttrRotate );
2363 nNewSize = bPixelToLogic ?
2364 mpRefDevice->LogicToPixel(Size(rEngineWidth,0)).Width() : rEngineWidth;
2365 ++nShrinkAgain;
2366 }
2367 if ( nNewSize <= nAvailable )
2368 rLeftClip = rRightClip = false;
2369
2370 // sizes for further processing (alignment etc):
2371 rNeededPixel = nNewSize + nLeftM + nRightM;
2372 rEngineHeight = lcl_GetEditSize( rEngine, false, false, nAttrRotate );
2373 }
2374}
2375
2376ScOutputData::DrawEditParam::DrawEditParam(const ScPatternAttr* pPattern, const SfxItemSet* pCondSet, bool bCellIsValue) :
2377 meHorJustAttr( lcl_GetValue<SvxHorJustifyItem, SvxCellHorJustify>(*pPattern, ATTR_HOR_JUSTIFY, pCondSet) ),
2378 meHorJustContext( meHorJustAttr ),
2379 meHorJustResult( meHorJustAttr ),
2380 meVerJust( lcl_GetValue<SvxVerJustifyItem, SvxCellVerJustify>(*pPattern, ATTR_VER_JUSTIFY, pCondSet) ),
2381 meHorJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_HOR_JUSTIFY_METHOD, pCondSet) ),
2382 meVerJustMethod( lcl_GetValue<SvxJustifyMethodItem, SvxCellJustifyMethod>(*pPattern, ATTR_VER_JUSTIFY_METHOD, pCondSet) ),
2383 meOrient( pPattern->GetCellOrientation(pCondSet) ),
2384 mnArrY(0),
2385 mnX(0), mnCellX(0), mnCellY(0),
2386 mnPosX(0), mnPosY(0), mnInitPosX(0),
2387 mbBreak( (meHorJustAttr == SvxCellHorJustify::Block) || lcl_GetBoolValue(*pPattern, ATTR_LINEBREAK, pCondSet) ),
2388 mbCellIsValue(bCellIsValue),
2389 mbAsianVertical(false),
2390 mbPixelToLogic(false),
2391 mbHyphenatorSet(false),
2392 mpEngine(nullptr),
2393 mpPattern(pPattern),
2394 mpCondSet(pCondSet),
2395 mpPreviewFontSet(nullptr),
2396 mpOldPattern(nullptr),
2397 mpOldCondSet(nullptr),
2398 mpOldPreviewFontSet(nullptr),
2399 mpThisRowInfo(nullptr),
2400 mpMisspellRanges(nullptr)
2401{}
2402
2404 const ScDocument* pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool& rWrapFields)
2405{
2406 if (maCell.getType() == CELLTYPE_EDIT)
2407 {
2408 const EditTextObject* pData = maCell.getEditText();
2409 if (pData)
2410 {
2411 mpEngine->SetTextCurrentDefaults(*pData);
2412
2413 if ( mbBreak && !mbAsianVertical && pData->HasField() )
2414 {
2415 // Fields aren't wrapped, so clipping is enabled to prevent
2416 // a field from being drawn beyond the cell size
2417
2418 rWrapFields = true;
2419 }
2420 }
2421 else
2422 {
2423 OSL_FAIL("pData == 0");
2424 return false;
2425 }
2426 }
2427 else
2428 {
2429 sal_uInt32 nFormat = mpPattern->GetNumberFormat(
2430 pDoc->GetFormatTable(), mpCondSet );
2431 const Color* pColor;
2432 OUString aString = ScCellFormat::GetString( maCell,
2433 nFormat, &pColor,
2434 *pDoc->GetFormatTable(),
2435 *pDoc,
2436 bShowNullValues,
2437 bShowFormulas);
2438
2439 mpEngine->SetTextCurrentDefaults(aString);
2440 if ( pColor && !bSyntaxMode && !( bUseStyleColor && bForceAutoColor ) )
2441 lcl_SetEditColor( *mpEngine, *pColor );
2442 }
2443
2444 if (mpMisspellRanges)
2445 mpEngine->SetAllMisspellRanges(*mpMisspellRanges);
2446
2447 return true;
2448}
2449
2451{
2452 // syntax highlighting mode is ignored here
2453 // StringDiffer doesn't look at hyphenate, language items
2454
2455 if (mpPattern == mpOldPattern && mpCondSet == mpOldCondSet && mpPreviewFontSet == mpOldPreviewFontSet )
2456 return;
2457
2458 Color nConfBackColor = SC_MOD()->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
2459 bool bCellContrast = bUseStyleColor &&
2461
2462 auto pSet = std::make_unique<SfxItemSet>( mpEngine->GetEmptyItemSet() );
2463 mpPattern->FillEditItemSet( pSet.get(), mpCondSet );
2464 if ( mpPreviewFontSet )
2465 {
2466 if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_FONT ) )
2467 {
2468 // tdf#125054 adapt WhichID
2469 pSet->Put(*pItem, EE_CHAR_FONTINFO);
2470 }
2471 if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_CJK_FONT ) )
2472 {
2473 // tdf#125054 adapt WhichID
2474 pSet->Put(*pItem, EE_CHAR_FONTINFO_CJK);
2475 }
2476 if ( const SvxFontItem* pItem = mpPreviewFontSet->GetItemIfSet( ATTR_CTL_FONT ) )
2477 {
2478 // tdf#125054 adapt WhichID
2479 pSet->Put(*pItem, EE_CHAR_FONTINFO_CTL);
2480 }
2481 }
2482 bool bParaHyphenate = pSet->Get(EE_PARA_HYPHENATE).GetValue();
2483 mpEngine->SetDefaults( std::move(pSet) );
2484 mpOldPattern = mpPattern;
2485 mpOldCondSet = mpCondSet;
2486 mpOldPreviewFontSet = mpPreviewFontSet;
2487
2488 EEControlBits nControl = mpEngine->GetControlWord();
2489 if (meOrient == SvxCellOrientation::Stacked)
2490 nControl |= EEControlBits::ONECHARPERLINE;
2491 else
2492 nControl &= ~EEControlBits::ONECHARPERLINE;
2493 mpEngine->SetControlWord( nControl );
2494
2495 if ( !mbHyphenatorSet && bParaHyphenate )
2496 {
2497 // set hyphenator the first time it is needed
2498 css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
2499 mpEngine->SetHyphenator( xXHyphenator );
2500 mbHyphenatorSet = true;
2501 }
2502
2503 Color aBackCol = mpPattern->GetItem( ATTR_BACKGROUND, mpCondSet ).GetColor();
2504 if ( bUseStyleColor && ( aBackCol.IsTransparent() || bCellContrast ) )
2505 aBackCol = nConfBackColor;
2506 mpEngine->SetBackgroundColor( aBackCol );
2507}
2508
2509void ScOutputData::DrawEditParam::calcMargins(tools::Long& rTopM, tools::Long& rLeftM, tools::Long& rBottomM, tools::Long& rRightM, double nPPTX, double nPPTY) const
2510{
2511 const SvxMarginItem& rMargin = mpPattern->GetItem(ATTR_MARGIN, mpCondSet);
2512
2513 sal_uInt16 nIndent = 0;
2514 if (meHorJustAttr == SvxCellHorJustify::Left || meHorJustAttr == SvxCellHorJustify::Right)
2515 nIndent = lcl_GetValue<ScIndentItem, sal_uInt16>(*mpPattern, ATTR_INDENT, mpCondSet);
2516
2517 rLeftM = static_cast<tools::Long>(((rMargin.GetLeftMargin() + nIndent) * nPPTX));
2518 rTopM = static_cast<tools::Long>((rMargin.GetTopMargin() * nPPTY));
2519 rRightM = static_cast<tools::Long>((rMargin.GetRightMargin() * nPPTX));
2520 rBottomM = static_cast<tools::Long>((rMargin.GetBottomMargin() * nPPTY));
2521 if(meHorJustAttr == SvxCellHorJustify::Right)
2522 {
2523 rLeftM = static_cast<tools::Long>((rMargin.GetLeftMargin() * nPPTX));
2524 rRightM = static_cast<tools::Long>(((rMargin.GetRightMargin() + nIndent) * nPPTX));
2525 }
2526}
2527
2529 Size& rPaperSize, const tools::Rectangle& rAlignRect, double nPPTX, double nPPTY) const
2530{
2531 tools::Long nTopM, nLeftM, nBottomM, nRightM;
2532 calcMargins(nTopM, nLeftM, nBottomM, nRightM, nPPTX, nPPTY);
2533
2534 if (isVerticallyOriented())
2535 {
2536 rPaperSize.setWidth( rAlignRect.GetHeight() - nTopM - nBottomM );
2537 rPaperSize.setHeight( rAlignRect.GetWidth() - nLeftM - nRightM );
2538 }
2539 else
2540 {
2541 rPaperSize.setWidth( rAlignRect.GetWidth() - nLeftM - nRightM );
2542 rPaperSize.setHeight( rAlignRect.GetHeight() - nTopM - nBottomM );
2543 }
2544
2545 if (mbAsianVertical)
2546 {
2547 rPaperSize.setHeight( rAlignRect.GetHeight() - nTopM - nBottomM );
2548 // Subtract some extra value from the height or else the text would go
2549 // outside the cell area. The value of 5 is arbitrary, and is based
2550 // entirely on heuristics.
2551 rPaperSize.AdjustHeight( -5 );
2552 }
2553}
2554
2556{
2557 tools::Long nEngineWidth = 0;
2558 if (!mbBreak || meOrient == SvxCellOrientation::Stacked || mbAsianVertical)
2559 nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
2560
2561 tools::Long nEngineHeight = pEngine->GetTextHeight();
2562
2563 if (isVerticallyOriented())
2564 std::swap( nEngineWidth, nEngineHeight );
2565
2566 if (meOrient == SvxCellOrientation::Stacked)
2567 nEngineWidth = nEngineWidth * 11 / 10;
2568
2569 rWidth = nEngineWidth;
2570 rHeight = nEngineHeight;
2571}
2572
2574{
2575 return (mbBreak || (meOrient == SvxCellOrientation::Stacked) || mbAsianVertical);
2576}
2577
2579{
2580 if (maCell.getType() != CELLTYPE_FORMULA)
2581 return false;
2582
2583 return maCell.getFormula()->IsHyperLinkCell();
2584}
2585
2587{
2588 return (meOrient == SvxCellOrientation::TopBottom || meOrient == SvxCellOrientation::BottomUp);
2589}
2590
2592 Point& rLogicStart, tools::Long nCellWidth, tools::Long nEngineWidth, tools::Long nTopM, const OutputDevice* pRefDevice)
2593{
2594 OSL_ENSURE(isVerticallyOriented(), "Use this only for vertically oriented cell!");
2595
2596 if (mbPixelToLogic)
2597 rLogicStart = pRefDevice->PixelToLogic(rLogicStart);
2598
2599 if (!mbBreak)
2600 return;
2601
2602 // vertical adjustment is within the EditEngine
2603 if (mbPixelToLogic)
2604 rLogicStart.AdjustY(pRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
2605 else
2606 rLogicStart.AdjustY(nTopM );
2607
2608 switch (meHorJustResult)
2609 {
2610 case SvxCellHorJustify::Center:
2611 rLogicStart.AdjustX((nCellWidth - nEngineWidth) / 2 );
2612 break;
2613 case SvxCellHorJustify::Right:
2614 rLogicStart.AdjustX(nCellWidth - nEngineWidth );
2615 break;
2616 default:
2617 ; // do nothing
2618 }
2619}
2620
2622{
2623 if (isVerticallyOriented() || mbAsianVertical)
2624 {
2625 SvxAdjust eSvxAdjust = SvxAdjust::Left;
2626 switch (meVerJust)
2627 {
2628 case SvxCellVerJustify::Top:
2629 eSvxAdjust = (meOrient == SvxCellOrientation::TopBottom || mbAsianVertical) ?
2630 SvxAdjust::Left : SvxAdjust::Right;
2631 break;
2632 case SvxCellVerJustify::Center:
2633 eSvxAdjust = SvxAdjust::Center;
2634 break;
2635 case SvxCellVerJustify::Bottom:
2636 case SvxCellVerJustify::Standard:
2637 eSvxAdjust = (meOrient == SvxCellOrientation::TopBottom || mbAsianVertical) ?
2638 SvxAdjust::Right : SvxAdjust::Left;
2639 break;
2640 case SvxCellVerJustify::Block:
2641 eSvxAdjust = SvxAdjust::Block;
2642 break;
2643 }
2644
2645 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2646 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2647
2648 if (meHorJustResult == SvxCellHorJustify::Block)
2649 mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
2650 }
2651 else
2652 {
2653 // horizontal alignment now may depend on cell content
2654 // (for values with number formats with mixed script types)
2655 // -> always set adjustment
2656
2657 SvxAdjust eSvxAdjust = SvxAdjust::Left;
2658 if (meOrient == SvxCellOrientation::Stacked)
2659 eSvxAdjust = SvxAdjust::Center;
2660 else if (mbBreak)
2661 {
2662 if (meOrient == SvxCellOrientation::Standard)
2663 switch (meHorJustResult)
2664 {
2665 case SvxCellHorJustify::Repeat: // repeat is not yet implemented
2666 case SvxCellHorJustify::Standard:
2667 SAL_WARN("sc.ui","meHorJustResult does not match getAlignmentFromContext()");
2668 [[fallthrough]];
2669 case SvxCellHorJustify::Left:
2670 eSvxAdjust = SvxAdjust::Left;
2671 break;
2672 case SvxCellHorJustify::Center:
2673 eSvxAdjust = SvxAdjust::Center;
2674 break;
2675 case SvxCellHorJustify::Right:
2676 eSvxAdjust = SvxAdjust::Right;
2677 break;
2678 case SvxCellHorJustify::Block:
2679 eSvxAdjust = SvxAdjust::Block;
2680 break;
2681 }
2682 else
2683 switch (meVerJust)
2684 {
2685 case SvxCellVerJustify::Top:
2686 eSvxAdjust = SvxAdjust::Right;
2687 break;
2688 case SvxCellVerJustify::Center:
2689 eSvxAdjust = SvxAdjust::Center;
2690 break;
2691 case SvxCellVerJustify::Bottom:
2692 case SvxCellVerJustify::Standard:
2693 eSvxAdjust = SvxAdjust::Left;
2694 break;
2695 case SvxCellVerJustify::Block:
2696 eSvxAdjust = SvxAdjust::Block;
2697 break;
2698 }
2699 }
2700
2701 mpEngine->SetDefaultItem( SvxAdjustItem(eSvxAdjust, EE_PARA_JUST) );
2702
2703 if (mbAsianVertical)
2704 {
2705 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meVerJustMethod, EE_PARA_JUST_METHOD) );
2706 if (meHorJustResult == SvxCellHorJustify::Block)
2707 mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
2708 }
2709 else
2710 {
2711 mpEngine->SetDefaultItem( SvxJustifyMethodItem(meHorJustMethod, EE_PARA_JUST_METHOD) );
2712 if (meVerJust == SvxCellVerJustify::Block)
2713 mpEngine->SetDefaultItem( SvxVerJustifyItem(SvxCellVerJustify::Block, EE_PARA_VER_JUST) );
2714 }
2715 }
2716
2717 mpEngine->SetVertical(mbAsianVertical);
2718 if (maCell.getType() == CELLTYPE_EDIT)
2719 {
2720 // We need to synchronize the vertical mode in the EditTextObject
2721 // instance too. No idea why we keep this state in two separate
2722 // instances.
2723 const EditTextObject* pData = maCell.getEditText();
2724 if (pData)
2725 const_cast<EditTextObject*>(pData)->SetVertical(mbAsianVertical);
2726 }
2727}
2728
2730{
2731 if (meHorJustResult == SvxCellHorJustify::Right || meHorJustResult == SvxCellHorJustify::Center)
2732 {
2733 SvxAdjust eEditAdjust = (meHorJustResult == SvxCellHorJustify::Center) ?
2734 SvxAdjust::Center : SvxAdjust::Right;
2735
2736 const bool bPrevUpdateLayout = pEngine->SetUpdateLayout(false);
2737 pEngine->SetDefaultItem( SvxAdjustItem(eEditAdjust, EE_PARA_JUST) );
2738 pEngine->SetUpdateLayout(bPrevUpdateLayout);
2739 return true;
2740 }
2741 return false;
2742}
2743
2745{
2746 // PDF: whole-cell hyperlink from formula?
2747 vcl::PDFExtOutDevData* pPDFData = dynamic_cast<vcl::PDFExtOutDevData* >( pDev->GetExtOutDevData() );
2748 bool bHasURL = pPDFData && isHyperlinkCell();
2749 if (!bHasURL)
2750 return;
2751
2752 tools::Long nURLWidth = static_cast<tools::Long>(mpEngine->CalcTextWidth());
2753 tools::Long nURLHeight = mpEngine->GetTextHeight();
2754 if (mbBreak)
2755 {
2756 Size aPaper = mpEngine->GetPaperSize();
2757 if ( mbAsianVertical )
2758 nURLHeight = aPaper.Height();
2759 else
2760 nURLWidth = aPaper.Width();
2761 }
2762 if (isVerticallyOriented())
2763 std::swap( nURLWidth, nURLHeight );
2764 else if (mbAsianVertical)
2765 aURLStart.AdjustX( -nURLWidth );
2766
2767 tools::Rectangle aURLRect( aURLStart, Size( nURLWidth, nURLHeight ) );
2768 lcl_DoHyperlinkResult(pDev, aURLRect, maCell);
2769}
2770
2771// Returns true if the rect is clipped vertically
2773{
2774 if( rAreaParam.maClipRect.Left() < nScrX )
2775 {
2776 rAreaParam.maClipRect.SetLeft( nScrX );
2777 rAreaParam.mbLeftClip = true;
2778 }
2779 if( rAreaParam.maClipRect.Right() > nScrX + nScrW )
2780 {
2781 rAreaParam.maClipRect.SetRight( nScrX + nScrW );
2782 rAreaParam.mbRightClip = true;
2783 }
2784
2785 bool bVClip = false;
2786
2787 if( rAreaParam.maClipRect.Top() < nScrY )
2788 {
2789 rAreaParam.maClipRect.SetTop( nScrY );
2790 bVClip = true;
2791 }
2792 if( rAreaParam.maClipRect.Bottom() > nScrY + nScrH )
2793 {
2794 rAreaParam.maClipRect.SetBottom( nScrY + nScrH );
2795 bVClip = true;
2796 }
2797 return bVClip;
2798}
2799
2800// Doesn't handle clip marks - should be handled in advance using GetOutputArea
2802{
2803public:
2804 ClearableClipRegion( const tools::Rectangle& rRect, bool bClip, bool bSimClip,
2805 const VclPtr<OutputDevice>& pDev, bool bMetaFile )
2806 :mbMetaFile(bMetaFile)
2807 {
2808 if (!(bClip || bSimClip))
2809 return;
2810
2811 maRect = rRect;
2812 if (bClip) // for bSimClip only initialize aClipRect
2813 {
2814 mpDev.reset(pDev);
2815 if (mbMetaFile)
2816 {
2817 mpDev->Push();
2818 mpDev->IntersectClipRegion(maRect);
2819 }
2820 else
2821 mpDev->SetClipRegion(vcl::Region(maRect));
2822 }
2823 }
2824
2825 ~ClearableClipRegion() COVERITY_NOEXCEPT_FALSE
2826 {
2827 // Pop() or SetClipRegion() must only be called in case bClip was true
2828 // in the ctor, and only then mpDev is set.
2829 if (mpDev)
2830 {
2831 if (mbMetaFile)
2832 mpDev->Pop();
2833 else
2834 mpDev->SetClipRegion();
2835 }
2836 }
2837
2838 const tools::Rectangle& getRect() const { return maRect; }
2839
2840private:
2844};
2845
2846// Returns needed width in current units; sets rNeededPixel to needed width in pixels
2848 tools::Long& rNeededPixel, tools::Long nAddWidthPixels )
2849{
2850 rParam.mpEngine->SetTextCurrentDefaults( rSetString );
2851 tools::Long nEngineWidth = static_cast<tools::Long>( rParam.mpEngine->CalcTextWidth() );
2852 if ( rParam.mbPixelToLogic )
2853 rNeededPixel = mpRefDevice->LogicToPixel( Size( nEngineWidth, 0 ) ).Width();
2854 else
2855 rNeededPixel = nEngineWidth;
2856
2857 rNeededPixel += nAddWidthPixels;
2858
2859 return nEngineWidth;
2860}
2861
2863{
2864 OSL_ASSERT(rParam.meOrient == SvxCellOrientation::Standard);
2865 OSL_ASSERT(!rParam.mbAsianVertical);
2866
2867 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
2868
2869 bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
2870 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
2871 Degree100 nAttrRotate = lcl_GetValue<ScRotateValueItem, Degree100>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
2872
2873 if ( rParam.meHorJustAttr == SvxCellHorJustify::Repeat )
2874 {
2875 // ignore orientation/rotation if "repeat" is active
2876 rParam.meOrient = SvxCellOrientation::Standard;
2877 nAttrRotate = 0_deg100;
2878
2879 // #i31843# "repeat" with "line breaks" is treated as default alignment
2880 // (but rotation is still disabled).
2881 // Default again leads to context dependent alignment instead of
2882 // SvxCellHorJustify::Standard.
2883 if ( rParam.mbBreak )
2884 rParam.meHorJustResult = rParam.meHorJustContext;
2885 }
2886
2887 if (nAttrRotate)
2888 {
2891 return; // rotated is outputted separately
2892 }
2893
2894 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
2895
2898 tools::Long nTopM, nLeftM, nBottomM, nRightM;
2899 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
2900
2901 SCCOL nXForPos = rParam.mnX;
2902 if ( nXForPos < nX1 )
2903 {
2904 nXForPos = nX1;
2905 rParam.mnPosX = rParam.mnInitPosX;
2906 }
2907 SCSIZE nArrYForPos = rParam.mnArrY;
2908 if ( nArrYForPos < 1 )
2909 {
2910 nArrYForPos = 1;
2911 rParam.mnPosY = nScrY;
2912 }
2913
2914 OutputAreaParam aAreaParam;
2915
2916 // Initial page size - large for normal text, cell size for automatic line breaks
2917
2918 Size aPaperSize( 1000000, 1000000 );
2919 if (rParam.mbBreak)
2920 {
2921 // call GetOutputArea with nNeeded=0, to get only the cell width
2922
2924 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
2925 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2926 rParam.mbCellIsValue, true, false, aAreaParam );
2927
2929 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
2930 }
2931 if (rParam.mbPixelToLogic)
2932 {
2933 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
2934 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
2935 {
2936 // #i85342# screen display and formatting for printer,
2937 // use same GetEditArea call as in ScViewData::SetEditEngine
2938
2939 Fraction aFract(1,1);
2940 tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
2941 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
2942 aLogicSize.setWidth( aUtilRect.GetWidth() );
2943 }
2944 rParam.mpEngine->SetPaperSize(aLogicSize);
2945 }
2946 else
2947 rParam.mpEngine->SetPaperSize(aPaperSize);
2948
2949 // Fill the EditEngine (cell attributes and text)
2950
2951 // default alignment for asian vertical mode is top-right
2952 if ( rParam.mbAsianVertical && rParam.meVerJust == SvxCellVerJustify::Standard )
2953 rParam.meVerJust = SvxCellVerJustify::Top;
2954
2956 rParam.setAlignmentToEngine();
2957 // Don't format unnecessary parts if the text will be drawn from top (Standard will
2958 // act that way if text doesn't fit, see below).
2959 rParam.mpEngine->EnableSkipOutsideFormat(rParam.meVerJust==SvxCellVerJustify::Top
2960 || rParam.meVerJust==SvxCellVerJustify::Standard);
2961
2962 // Read content from cell
2963
2964 bool bWrapFields = false;
2966 // Failed to read cell content. Bail out.
2967 return;
2968
2969 if ( mbSyntaxMode )
2970 SetEditSyntaxColor(*rParam.mpEngine, rParam.maCell);
2971 else if ( mbUseStyleColor && mbForceAutoColor )
2972 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO );
2973
2974 rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
2975
2976 // Get final output area using the calculated width
2977
2978 tools::Long nEngineWidth, nEngineHeight;
2979 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
2980
2981 tools::Long nNeededPixel = nEngineWidth;
2982 if (rParam.mbPixelToLogic)
2983 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
2984 nNeededPixel += nLeftM + nRightM;
2985
2986 if (!rParam.mbBreak || bShrink)
2987 {
2988 // for break, the first GetOutputArea call is sufficient
2989 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
2990 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
2991 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
2992
2993 if ( bShrink )
2994 {
2995 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
2996 nLeftM, nTopM, nRightM, nBottomM, true,
2997 rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
2998 nEngineWidth, nEngineHeight, nNeededPixel,
2999 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3000 }
3001 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3002 {
3003 // First check if twice the space for the formatted text is available
3004 // (otherwise just keep it unchanged).
3005
3006 tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3007 tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3008 if ( nAvailable >= 2 * nFormatted )
3009 {
3010 // "repeat" is handled with unformatted text (for performance reasons)
3011 OUString aCellStr = rParam.mpEngine->GetText();
3012
3013 tools::Long nRepeatSize = 0;
3014 SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
3015 if ( pFmtDevice != mpRefDevice )
3016 ++nRepeatSize;
3017 if ( nRepeatSize > 0 )
3018 {
3019 tools::Long nRepeatCount = nAvailable / nRepeatSize;
3020 if ( nRepeatCount > 1 )
3021 {
3022 OUStringBuffer aRepeated(aCellStr);
3023 for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3024 aRepeated.append(aCellStr);
3025
3026 SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
3027 nNeededPixel, (nLeftM + nRightM ) );
3028
3029 nEngineHeight = rParam.mpEngine->GetTextHeight();
3030 }
3031 }
3032 }
3033 }
3034
3035
3036 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3037 {
3038 SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
3039 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
3040 ScCellInfo* pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
3041 SetClipMarks( aAreaParam, pClipMarkCell, eOutHorJust, true, nLayoutSign );
3042 }
3043
3044 if (eOutHorJust != SvxCellHorJustify::Left)
3045 {
3046 aPaperSize.setWidth( nNeededPixel + 1 );
3047 if (rParam.mbPixelToLogic)
3048 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3049 else
3050 rParam.mpEngine->SetPaperSize(aPaperSize);
3051 }
3052 }
3053
3054 tools::Long nStartX = aAreaParam.maAlignRect.Left();
3055 tools::Long nStartY = aAreaParam.maAlignRect.Top();
3057 tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3058 tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3059
3060 if (rParam.mbBreak)
3061 {
3062 // text with automatic breaks is aligned only within the
3063 // edit engine's paper size, the output of the whole area
3064 // is always left-aligned
3065
3066 nStartX += nLeftM;
3067 }
3068 else
3069 {
3070 if ( eOutHorJust == SvxCellHorJustify::Right )
3071 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3072 else if ( eOutHorJust == SvxCellHorJustify::Center )
3073 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3074 else
3075 nStartX += nLeftM;
3076 }
3077
3078 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3079 if (bOutside)
3080 return;
3081
3082 // Also take fields in a cell with automatic breaks into account: clip to cell width
3083 bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
3084 bool bSimClip = false;
3085
3086 Size aCellSize; // output area, excluding margins, in logical units
3087 if (rParam.mbPixelToLogic)
3088 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3089 else
3090 aCellSize = Size( nOutWidth, nOutHeight );
3091
3092 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3093 {
3094 const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
3095 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3096
3097 // Don't clip for text height when printing rows with optimal height,
3098 // except when font size is from conditional formatting.
3100 if ( eType != OUTTYPE_PRINTER ||
3101 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
3102 ( rParam.mpCondSet && SfxItemState::SET ==
3104 bClip = true;
3105 else
3106 bSimClip = true;
3107
3108 // Show clip marks if height is at least 5pt too small and
3109 // there are several lines of text.
3110 // Not for asian vertical text, because that would interfere
3111 // with the default right position of the text.
3112 // Only with automatic line breaks, to avoid having to find
3113 // the cells with the horizontal end of the text again.
3114 if ( nEngineHeight - aCellSize.Height() > 100 &&
3115 rParam.mbBreak && bMarkClipped &&
3116 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3117 {
3118 ScCellInfo* pClipMarkCell = nullptr;
3119 if ( bMerged )
3120 {
3121 // anywhere in the merged area...
3122 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
3123 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
3124 }
3125 else
3126 pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
3127
3128 pClipMarkCell->nClipMark |= ScClipMark::Right;
3129 bAnyClipped = true;
3130
3131 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
3132 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
3133 aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
3134
3135 // Standard is normally treated as Bottom, but if text height is clipped, then
3136 // Top looks better and also allows using EditEngine::EnableSkipOutsideFormat().
3137 if (rParam.meVerJust==SvxCellVerJustify::Standard)
3138 rParam.meVerJust=SvxCellVerJustify::Top;
3139 }
3140 }
3141
3142 Point aURLStart;
3143
3144 { // Clip marks are already handled in GetOutputArea
3145 ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
3146 : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
3147
3148 Point aLogicStart;
3149 if (rParam.mbPixelToLogic)
3150 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
3151 else
3152 aLogicStart = Point(nStartX, nStartY);
3153
3154 if (!rParam.mbBreak)
3155 {
3156 // horizontal alignment
3157 if (rParam.adjustHorAlignment(rParam.mpEngine))
3158 // reset adjustment for the next cell
3159 rParam.mpOldPattern = nullptr;
3160 }
3161
3162 if (rParam.meVerJust==SvxCellVerJustify::Bottom ||
3163 rParam.meVerJust==SvxCellVerJustify::Standard)
3164 {
3167
3168 if (rParam.mbPixelToLogic)
3169 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM +
3170 mpRefDevice->LogicToPixel(aCellSize).Height() -
3171 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
3172 )).Height() );
3173 else
3174 aLogicStart.AdjustY(nTopM + aCellSize.Height() - nEngineHeight );
3175 }
3176 else if (rParam.meVerJust==SvxCellVerJustify::Center)
3177 {
3178 if (rParam.mbPixelToLogic)
3179 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM + (
3180 mpRefDevice->LogicToPixel(aCellSize).Height() -
3181 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
3182 / 2)).Height() );
3183 else
3184 aLogicStart.AdjustY(nTopM + (aCellSize.Height() - nEngineHeight) / 2 );
3185 }
3186 else // top
3187 {
3188 if (rParam.mbPixelToLogic)
3189 aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
3190 else
3191 aLogicStart.AdjustY(nTopM );
3192 }
3193
3194 aURLStart = aLogicStart; // copy before modifying for orientation
3195
3196 // bMoveClipped handling has been replaced by complete alignment
3197 // handling (also extending to the left).
3198
3199 if (bSimClip)
3200 {
3201 // no hard clip, only draw the affected rows
3202 Point aDocStart = aClip.getRect().TopLeft();
3203 aDocStart -= aLogicStart;
3204 rParam.mpEngine->Draw(*mpDev, aClip.getRect(), aDocStart, false);
3205 }
3206 else
3207 {
3208 rParam.mpEngine->Draw(*mpDev, aLogicStart);
3209 }
3210 }
3211
3212 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3213}
3214
3216 SvxCellHorJustify eOutHorJust, bool bHasHashText,
3217 tools::Long nLayoutSign )
3218{
3219 if ( !bHasHashText )
3220 return;
3221
3222 tools::Long nMarkPixel = SC_CLIPMARK_SIZE * mnPPTX;
3223
3224 if ( eOutHorJust == SvxCellHorJustify::Left )
3225 {
3226 pClipMarkCell->nClipMark |= ScClipMark::Right;
3227 bAnyClipped = true;
3228 aAreaParam.maClipRect.AdjustRight( -( nMarkPixel * nLayoutSign ) );
3229 }
3230 else if ( eOutHorJust == SvxCellHorJustify::Right )
3231 {
3232 pClipMarkCell->nClipMark |= ScClipMark::Left;
3233 bAnyClipped = true;
3234 aAreaParam.maClipRect.AdjustLeft( nMarkPixel * nLayoutSign );
3235 }
3236 else
3237 {
3238 pClipMarkCell->nClipMark |= ScClipMark::Right;
3239 pClipMarkCell->nClipMark |= ScClipMark::Left;
3240 bAnyClipped = true;
3241 aAreaParam.maClipRect.AdjustRight( -( nMarkPixel * nLayoutSign ) );
3242 aAreaParam.maClipRect.AdjustLeft( nMarkPixel * nLayoutSign );
3243 }
3244
3245}
3246
3247void ScOutputData::ShowClipMarks( DrawEditParam& rParam, tools::Long nEngineWidth, const Size& aCellSize,
3248 bool bMerged, OutputAreaParam& aAreaParam, bool bTop)
3249{
3250 // Show clip marks if width is at least 5pt too small and
3251 // there are several lines of text.
3252 // Not for asian vertical text, because that would interfere
3253 // with the default right position of the text.
3254 // Only with automatic line breaks, to avoid having to find
3255 // the cells with the horizontal end of the text again.
3256 if (nEngineWidth - aCellSize.Width() <= 100 || !rParam.mbBreak || !bMarkClipped
3257 || (rParam.mpEngine->GetParagraphCount() <= 1 && rParam.mpEngine->GetLineCount(0) <= 1))
3258 return;
3259
3260 ScCellInfo* pClipMarkCell = nullptr;
3261 if (bMerged)
3262 {
3263 // anywhere in the merged area...
3264 SCCOL nClipX = (rParam.mnX < nX1) ? nX1 : rParam.mnX;
3265 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
3266 }
3267 else
3268 pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
3269
3270 bAnyClipped = true;
3271 bVertical = true;
3272 const tools::Long nMarkPixel = static_cast<tools::Long>(SC_CLIPMARK_SIZE * mnPPTX);
3273 if (bTop)
3274 {
3275 pClipMarkCell->nClipMark |= ScClipMark::Top;
3276 if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
3277 aAreaParam.maClipRect.AdjustTop(+nMarkPixel);
3278 }
3279 else
3280 {
3281 pClipMarkCell->nClipMark |= ScClipMark::Bottom;
3282 if (aAreaParam.maClipRect.Top() - nMarkPixel < aAreaParam.maClipRect.Bottom())
3283 aAreaParam.maClipRect.AdjustBottom(-nMarkPixel);
3284 }
3285}
3286
3288 OutputAreaParam& aAreaParam, tools::Long nEngineWidth,
3289 bool bWrapFields, bool bTop)
3290{
3291 // Also take fields in a cell with automatic breaks into account: clip to cell width
3292 bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
3293 bool bSimClip = false;
3294
3295 const Size& aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3296 if ( nEngineWidth >= aCellSize.Width() + aRefOne.Width() )
3297 {
3298 const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
3299 const bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3300
3301 // Don't clip for text height when printing rows with optimal height,
3302 // except when font size is from conditional formatting.
3304 if ( eType != OUTTYPE_PRINTER ||
3305 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
3306 ( rParam.mpCondSet && SfxItemState::SET ==
3308 bClip = true;
3309 else
3310 bSimClip = true;
3311
3312 ShowClipMarks( rParam, nEngineWidth, aCellSize, bMerged, aAreaParam, bTop);
3313 }
3314
3315 // Clip marks are already handled in GetOutputArea
3317 mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
3318 : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile));
3319}
3320
3322{
3323 OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
3324
3325 const bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
3326 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3327
3328 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3329
3332 tools::Long nTopM, nLeftM, nBottomM, nRightM;
3333 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3334
3335 SCCOL nXForPos = rParam.mnX;
3336 if ( nXForPos < nX1 )
3337 {
3338 nXForPos = nX1;
3339 rParam.mnPosX = rParam.mnInitPosX;
3340 }
3341 SCSIZE nArrYForPos = rParam.mnArrY;
3342 if ( nArrYForPos < 1 )
3343 {
3344 nArrYForPos = 1;
3345 rParam.mnPosY = nScrY;
3346 }
3347
3348 OutputAreaParam aAreaParam;
3349
3350 // Initial page size - large for normal text, cell size for automatic line breaks
3351
3352 Size aPaperSize( 1000000, 1000000 );
3353 if (rParam.mbBreak)
3354 {
3355 // call GetOutputArea with nNeeded=0, to get only the cell width
3356
3358 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3359 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3360 rParam.mbCellIsValue, true, false, aAreaParam );
3361
3363 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3364 }
3365 if (rParam.mbPixelToLogic)
3366 {
3367 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3368 rParam.mpEngine->SetPaperSize(aLogicSize);
3369 }
3370 else
3371 rParam.mpEngine->SetPaperSize(aPaperSize);
3372
3373 // Fill the EditEngine (cell attributes and text)
3374
3376 rParam.setAlignmentToEngine();
3377
3378 // Read content from cell
3379
3380 bool bWrapFields = false;
3382 // Failed to read cell content. Bail out.
3383 return;
3384
3385 if ( mbSyntaxMode )
3386 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3387 else if ( mbUseStyleColor && mbForceAutoColor )
3388 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO );
3389
3390 rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3391
3392 // Get final output area using the calculated width
3393
3394 tools::Long nEngineWidth, nEngineHeight;
3395 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3396
3397 tools::Long nNeededPixel = nEngineWidth;
3398 if (rParam.mbPixelToLogic)
3399 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3400 nNeededPixel += nLeftM + nRightM;
3401
3402 if (!rParam.mbBreak || bShrink)
3403 {
3404 // for break, the first GetOutputArea call is sufficient
3405 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3406 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3407 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3408
3409 if ( bShrink )
3410 {
3411 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3412 nLeftM, nTopM, nRightM, nBottomM, false,
3413 (rParam.meOrient), 0_deg100, rParam.mbPixelToLogic,
3414 nEngineWidth, nEngineHeight, nNeededPixel,
3415 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3416 }
3417 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3418 {
3419 // First check if twice the space for the formatted text is available
3420 // (otherwise just keep it unchanged).
3421
3422 const tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3423 const tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3424 if ( nAvailable >= 2 * nFormatted )
3425 {
3426 // "repeat" is handled with unformatted text (for performance reasons)
3427 OUString aCellStr = rParam.mpEngine->GetText();
3428
3429 tools::Long nRepeatSize = 0;
3430 SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
3431 if ( pFmtDevice != mpRefDevice )
3432 ++nRepeatSize;
3433 if ( nRepeatSize > 0 )
3434 {
3435 const tools::Long nRepeatCount = nAvailable / nRepeatSize;
3436 if ( nRepeatCount > 1 )
3437 {
3438 OUStringBuffer aRepeated(aCellStr);
3439 for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3440 aRepeated.append(aCellStr);
3441
3442 nEngineWidth = SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
3443 nNeededPixel, (nLeftM + nRightM ) );
3444
3445 nEngineHeight = rParam.mpEngine->GetTextHeight();
3446 }
3447 }
3448 }
3449 }
3450 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3451 {
3452 nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
3453
3454 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3455 }
3456 }
3457
3458 tools::Long nStartX = aAreaParam.maAlignRect.Left();
3459 const tools::Long nStartY = aAreaParam.maAlignRect.Top();
3460 const tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3461 const tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3462 const tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3463
3464 if (rParam.mbBreak)
3465 {
3466 // text with automatic breaks is aligned only within the
3467 // edit engine's paper size, the output of the whole area
3468 // is always left-aligned
3469
3470 nStartX += nLeftM;
3471 }
3472 else
3473 {
3474 if ( eOutHorJust == SvxCellHorJustify::Right )
3475 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3476 else if ( eOutHorJust == SvxCellHorJustify::Center )
3477 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3478 else
3479 nStartX += nLeftM;
3480 }
3481
3482 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3483 if (bOutside)
3484 return;
3485
3486 // output area, excluding margins, in logical units
3487 const Size& aCellSize = rParam.mbPixelToLogic
3488 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3489 : Size( nOutWidth, nOutHeight );
3490
3491 Point aURLStart;
3492
3493 {
3494 const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, true );
3495
3496 Point aLogicStart(nStartX, nStartY);
3497 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3498
3499 aURLStart = aLogicStart; // copy before modifying for orientation
3500
3501 if (rParam.meHorJustResult == SvxCellHorJustify::Block || rParam.mbBreak)
3502 {
3503 Size aPSize = rParam.mpEngine->GetPaperSize();
3504 aPSize.setWidth( aCellSize.Height() );
3505 rParam.mpEngine->SetPaperSize(aPSize);
3506 aLogicStart.AdjustY(
3507 rParam.mbBreak ? aPSize.Width() : nEngineHeight );
3508 }
3509 else
3510 {
3511 // Note that the "paper" is rotated 90 degrees to the left, so
3512 // paper's width is in vertical direction. Also, the whole text
3513 // is on a single line, as text wrap is not in effect.
3514
3515 // Set the paper width to be the width of the text.
3516 Size aPSize = rParam.mpEngine->GetPaperSize();
3517 aPSize.setWidth( rParam.mpEngine->CalcTextWidth() );
3518 rParam.mpEngine->SetPaperSize(aPSize);
3519
3520 tools::Long nGap = 0;
3521 tools::Long nTopOffset = 0;
3522 if (rParam.mbPixelToLogic)
3523 {
3524 nGap = mpRefDevice->LogicToPixel(aCellSize).Height() - mpRefDevice->LogicToPixel(aPSize).Width();
3525 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3526 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3527 }
3528 else
3529 {
3530 nGap = aCellSize.Height() - aPSize.Width();
3531 nTopOffset = nTopM;
3532 }
3533
3534 // First, align text to bottom.
3535 aLogicStart.AdjustY(aCellSize.Height() );
3536 aLogicStart.AdjustY(nTopOffset );
3537
3538 switch (rParam.meVerJust)
3539 {
3540 case SvxCellVerJustify::Standard:
3541 case SvxCellVerJustify::Bottom:
3542 // align to bottom (do nothing).
3543 break;
3544 case SvxCellVerJustify::Center:
3545 // center it.
3546 aLogicStart.AdjustY( -(nGap / 2) );
3547 break;
3548 case SvxCellVerJustify::Block:
3549 case SvxCellVerJustify::Top:
3550 // align to top
3551 aLogicStart.AdjustY( -nGap );
3552 break;
3553 default:
3554 ;
3555 }
3556 }
3557
3558 rParam.mpEngine->Draw(*mpDev, aLogicStart, 900_deg10);
3559 }
3560
3561 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3562}
3563
3565{
3566 OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
3567
3568 const bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
3569 const bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3570
3571 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3572
3575 tools::Long nTopM, nLeftM, nBottomM, nRightM;
3576 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3577
3578 SCCOL nXForPos = rParam.mnX;
3579 if ( nXForPos < nX1 )
3580 {
3581 nXForPos = nX1;
3582 rParam.mnPosX = rParam.mnInitPosX;
3583 }
3584 SCSIZE nArrYForPos = rParam.mnArrY;
3585 if ( nArrYForPos < 1 )
3586 {
3587 nArrYForPos = 1;
3588 rParam.mnPosY = nScrY;
3589 }
3590
3591 OutputAreaParam aAreaParam;
3592
3593 // Initial page size - large for normal text, cell size for automatic line breaks
3594
3595 Size aPaperSize( 1000000, 1000000 );
3596 if (rParam.hasLineBreak())
3597 {
3598 // call GetOutputArea with nNeeded=0, to get only the cell width
3599
3601 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3602 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3603 rParam.mbCellIsValue, true, false, aAreaParam );
3604
3606 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3607 }
3608 if (rParam.mbPixelToLogic)
3609 {
3610 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3611 rParam.mpEngine->SetPaperSize(aLogicSize);
3612 }
3613 else
3614 rParam.mpEngine->SetPaperSize(aPaperSize);
3615
3616 // Fill the EditEngine (cell attributes and text)
3617
3619 rParam.setAlignmentToEngine();
3620
3621 // Read content from cell
3622
3623 bool bWrapFields = false;
3625 // Failed to read cell content. Bail out.
3626 return;
3627
3628 if ( mbSyntaxMode )
3629 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3630 else if ( mbUseStyleColor && mbForceAutoColor )
3631 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO );
3632
3633 rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3634
3635 // Get final output area using the calculated width
3636
3637 tools::Long nEngineWidth, nEngineHeight;
3638 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3639
3640 tools::Long nNeededPixel = nEngineWidth;
3641 if (rParam.mbPixelToLogic)
3642 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3643 nNeededPixel += nLeftM + nRightM;
3644
3645 if (!rParam.mbBreak || bShrink)
3646 {
3647 // for break, the first GetOutputArea call is sufficient
3648 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3649 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3650 rParam.mbCellIsValue || bRepeat || bShrink, false, false, aAreaParam );
3651
3652 if ( bShrink )
3653 {
3654 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3655 nLeftM, nTopM, nRightM, nBottomM, false,
3656 rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
3657 nEngineWidth, nEngineHeight, nNeededPixel,
3658 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3659 }
3660 if ( bRepeat && !aAreaParam.mbLeftClip && !aAreaParam.mbRightClip && rParam.mpEngine->GetParagraphCount() == 1 )
3661 {
3662 // First check if twice the space for the formatted text is available
3663 // (otherwise just keep it unchanged).
3664
3665 const tools::Long nFormatted = nNeededPixel - nLeftM - nRightM; // without margin
3666 const tools::Long nAvailable = aAreaParam.maAlignRect.GetWidth() - nLeftM - nRightM;
3667 if ( nAvailable >= 2 * nFormatted )
3668 {
3669 // "repeat" is handled with unformatted text (for performance reasons)
3670 OUString aCellStr = rParam.mpEngine->GetText();
3671
3672 tools::Long nRepeatSize = 0;
3673 SetEngineTextAndGetWidth( rParam, aCellStr, nRepeatSize, 0 );
3674
3675 if ( pFmtDevice != mpRefDevice )
3676 ++nRepeatSize;
3677 if ( nRepeatSize > 0 )
3678 {
3679 const tools::Long nRepeatCount = nAvailable / nRepeatSize;
3680 if ( nRepeatCount > 1 )
3681 {
3682 OUStringBuffer aRepeated(aCellStr);
3683 for ( tools::Long nRepeat = 1; nRepeat < nRepeatCount; nRepeat++ )
3684 aRepeated.append(aCellStr);
3685
3686 nEngineWidth = SetEngineTextAndGetWidth( rParam, aRepeated.makeStringAndClear(),
3687 nNeededPixel, (nLeftM + nRightM ) );
3688
3689 nEngineHeight = rParam.mpEngine->GetTextHeight();
3690 }
3691 }
3692 }
3693 }
3694 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3695 {
3696 nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
3697
3698 // No clip marks if "###" doesn't fit (same as in DrawStrings)
3699 }
3700 }
3701
3702 tools::Long nStartX = aAreaParam.maAlignRect.Left();
3703 const tools::Long nStartY = aAreaParam.maAlignRect.Top();
3704 const tools::Long nCellWidth = aAreaParam.maAlignRect.GetWidth();
3705 const tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3706 const tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3707
3708 if (rParam.mbBreak)
3709 {
3710 // text with automatic breaks is aligned only within the
3711 // edit engine's paper size, the output of the whole area
3712 // is always left-aligned
3713
3714 nStartX += nLeftM;
3715 if (rParam.meHorJustResult == SvxCellHorJustify::Block)
3716 nStartX += aPaperSize.Height();
3717 }
3718 else
3719 {
3720 if ( eOutHorJust == SvxCellHorJustify::Right )
3721 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3722 else if ( eOutHorJust == SvxCellHorJustify::Center )
3723 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3724 else
3725 nStartX += nLeftM;
3726 }
3727
3728 const bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3729 if (bOutside)
3730 return;
3731
3732 // output area, excluding margins, in logical units
3733 const Size& aCellSize = rParam.mbPixelToLogic
3734 ? mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) )
3735 : Size( nOutWidth, nOutHeight );
3736
3737 Point aURLStart;
3738
3739 {
3740 const auto pClipRegion = Clip( rParam, aCellSize, aAreaParam, nEngineWidth, bWrapFields, false );
3741
3742 Point aLogicStart(nStartX, nStartY);
3743 rParam.calcStartPosForVertical(aLogicStart, aCellSize.Width(), nEngineWidth, nTopM, mpRefDevice);
3744
3745 aURLStart = aLogicStart; // copy before modifying for orientation
3746
3747 if (rParam.meHorJustResult != SvxCellHorJustify::Block)
3748 {
3749 aLogicStart.AdjustX(nEngineWidth );
3750 if (!rParam.mbBreak)
3751 {
3752 // Set the paper width to text size.
3753 Size aPSize = rParam.mpEngine->GetPaperSize();
3754 aPSize.setWidth( rParam.mpEngine->CalcTextWidth() );
3755 rParam.mpEngine->SetPaperSize(aPSize);
3756
3757 tools::Long nGap = 0;
3758 tools::Long nTopOffset = 0; // offset by top margin
3759 if (rParam.mbPixelToLogic)
3760 {
3761 nGap = mpRefDevice->LogicToPixel(aPSize).Width() - mpRefDevice->LogicToPixel(aCellSize).Height();
3762 nGap = mpRefDevice->PixelToLogic(Size(0, nGap)).Height();
3763 nTopOffset = mpRefDevice->PixelToLogic(Size(0,nTopM)).Height();
3764 }
3765 else
3766 {
3767 nGap = aPSize.Width() - aCellSize.Height();
3768 nTopOffset = nTopM;
3769 }
3770 aLogicStart.AdjustY(nTopOffset );
3771
3772 switch (rParam.meVerJust)
3773 {
3774 case SvxCellVerJustify::Standard:
3775 case SvxCellVerJustify::Bottom:
3776 // align to bottom
3777 aLogicStart.AdjustY( -nGap );
3778 break;
3779 case SvxCellVerJustify::Center:
3780 // center it.
3781 aLogicStart.AdjustY( -(nGap / 2) );
3782 break;
3783 case SvxCellVerJustify::Block:
3784 case SvxCellVerJustify::Top:
3785 // align to top (do nothing)
3786 default:
3787 ;
3788 }
3789 }
3790 }
3791
3792 // bMoveClipped handling has been replaced by complete alignment
3793 // handling (also extending to the left).
3794
3795 rParam.mpEngine->Draw(*mpDev, aLogicStart, 2700_deg10);
3796 }
3797
3798 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
3799}
3800
3802{
3803 OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
3804 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
3805
3806 bool bRepeat = (rParam.meHorJustAttr == SvxCellHorJustify::Repeat && !rParam.mbBreak);
3807 bool bShrink = !rParam.mbBreak && !bRepeat && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
3808
3809 rParam.mbAsianVertical =
3810 lcl_GetBoolValue(*rParam.mpPattern, ATTR_VERTICAL_ASIAN, rParam.mpCondSet);
3811
3812 if ( rParam.mbAsianVertical )
3813 {
3814 // in asian mode, use EditEngine::SetVertical instead of EEControlBits::ONECHARPERLINE
3815 rParam.meOrient = SvxCellOrientation::Standard;
3816 DrawEditAsianVertical(rParam);
3817 return;
3818 }
3819
3820 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
3821
3824 tools::Long nTopM, nLeftM, nBottomM, nRightM;
3825 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
3826
3827 SCCOL nXForPos = rParam.mnX;
3828 if ( nXForPos < nX1 )
3829 {
3830 nXForPos = nX1;
3831 rParam.mnPosX = rParam.mnInitPosX;
3832 }
3833 SCSIZE nArrYForPos = rParam.mnArrY;
3834 if ( nArrYForPos < 1 )
3835 {
3836 nArrYForPos = 1;
3837 rParam.mnPosY = nScrY;
3838 }
3839
3840 OutputAreaParam aAreaParam;
3841
3842 // Initial page size - large for normal text, cell size for automatic line breaks
3843
3844 Size aPaperSize( 1000000, 1000000 );
3845 // call GetOutputArea with nNeeded=0, to get only the cell width
3846
3848 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
3849 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3850 rParam.mbCellIsValue, true, false, aAreaParam );
3851
3853 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
3854
3855 if (rParam.mbPixelToLogic)
3856 {
3857 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
3858 if ( rParam.mbBreak && mpRefDevice != pFmtDevice )
3859 {
3860 // #i85342# screen display and formatting for printer,
3861 // use same GetEditArea call as in ScViewData::SetEditEngine
3862
3863 Fraction aFract(1,1);
3864 tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
3865 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
3866 aLogicSize.setWidth( aUtilRect.GetWidth() );
3867 }
3868 rParam.mpEngine->SetPaperSize(aLogicSize);
3869 }
3870 else
3871 rParam.mpEngine->SetPaperSize(aPaperSize);
3872
3873 // Fill the EditEngine (cell attributes and text)
3874
3876 rParam.setAlignmentToEngine();
3877
3878 // Read content from cell
3879
3880 bool bWrapFields = false;
3882 // Failed to read cell content. Bail out.
3883 return;
3884
3885 if ( mbSyntaxMode )
3886 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
3887 else if ( mbUseStyleColor && mbForceAutoColor )
3888 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO );
3889
3890 rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
3891
3892 // Get final output area using the calculated width
3893
3894 tools::Long nEngineWidth, nEngineHeight;
3895 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
3896
3897 tools::Long nNeededPixel = nEngineWidth;
3898 if (rParam.mbPixelToLogic)
3899 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
3900 nNeededPixel += nLeftM + nRightM;
3901
3902 if (bShrink)
3903 {
3904 // for break, the first GetOutputArea call is sufficient
3905 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
3906 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
3907 true, false, false, aAreaParam );
3908
3909 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
3910 nLeftM, nTopM, nRightM, nBottomM, true,
3911 rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
3912 nEngineWidth, nEngineHeight, nNeededPixel,
3913 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
3914
3915 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
3916 {
3917 nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
3918 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
3919 ScCellInfo* pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
3920 SetClipMarks( aAreaParam, pClipMarkCell, eOutHorJust, true, nLayoutSign );
3921 }
3922
3923 if ( eOutHorJust != SvxCellHorJustify::Left )
3924 {
3925 aPaperSize.setWidth( nNeededPixel + 1 );
3926 if (rParam.mbPixelToLogic)
3927 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
3928 else
3929 rParam.mpEngine->SetPaperSize(aPaperSize);
3930 }
3931 }
3932
3933 tools::Long nStartX = aAreaParam.maAlignRect.Left();
3934 tools::Long nStartY = aAreaParam.maAlignRect.Top();
3936 tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
3937 tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
3938
3939 if (rParam.mbBreak)
3940 {
3941 // text with automatic breaks is aligned only within the
3942 // edit engine's paper size, the output of the whole area
3943 // is always left-aligned
3944
3945 nStartX += nLeftM;
3946 }
3947 else
3948 {
3949 if ( eOutHorJust == SvxCellHorJustify::Right )
3950 nStartX -= nNeededPixel - nCellWidth + nRightM + 1;
3951 else if ( eOutHorJust == SvxCellHorJustify::Center )
3952 nStartX -= ( nNeededPixel - nCellWidth + nRightM + 1 - nLeftM ) / 2;
3953 else
3954 nStartX += nLeftM;
3955 }
3956
3957 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
3958 if (bOutside)
3959 return;
3960
3961 // Also take fields in a cell with automatic breaks into account: clip to cell width
3962 bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
3963 bool bSimClip = false;
3964
3965 Size aCellSize; // output area, excluding margins, in logical units
3966 if (rParam.mbPixelToLogic)
3967 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
3968 else
3969 aCellSize = Size( nOutWidth, nOutHeight );
3970
3971 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
3972 {
3973 const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
3974 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
3975
3976 // Don't clip for text height when printing rows with optimal height,
3977 // except when font size is from conditional formatting.
3979 if ( eType != OUTTYPE_PRINTER ||
3980 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
3981 ( rParam.mpCondSet && SfxItemState::SET ==
3983 bClip = true;
3984 else
3985 bSimClip = true;
3986
3987 // Show clip marks if height is at least 5pt too small and
3988 // there are several lines of text.
3989 // Not for asian vertical text, because that would interfere
3990 // with the default right position of the text.
3991 // Only with automatic line breaks, to avoid having to find
3992 // the cells with the horizontal end of the text again.
3993 if ( nEngineHeight - aCellSize.Height() > 100 &&
3994 rParam.mbBreak && bMarkClipped &&
3995 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
3996 {
3997 ScCellInfo* pClipMarkCell = nullptr;
3998 if ( bMerged )
3999 {
4000 // anywhere in the merged area...
4001 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4002 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
4003 }
4004 else
4005 pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
4006
4007 pClipMarkCell->nClipMark |= ScClipMark::Right;
4008 bAnyClipped = true;
4009
4010 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
4011 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4012 aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
4013 }
4014 }
4015
4016 Point aURLStart;
4017
4018 { // Clip marks are already handled in GetOutputArea
4019 ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
4020 : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
4021
4022 Point aLogicStart;
4023 if (rParam.mbPixelToLogic)
4024 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4025 else
4026 aLogicStart = Point(nStartX, nStartY);
4027
4028 if (rParam.meVerJust==SvxCellVerJustify::Bottom ||
4029 rParam.meVerJust==SvxCellVerJustify::Standard)
4030 {
4033
4034 if (rParam.mbPixelToLogic)
4035 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM +
4036 mpRefDevice->LogicToPixel(aCellSize).Height() -
4037 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
4038 )).Height() );
4039 else
4040 aLogicStart.AdjustY(nTopM + aCellSize.Height() - nEngineHeight );
4041 }
4042 else if (rParam.meVerJust==SvxCellVerJustify::Center)
4043 {
4044 if (rParam.mbPixelToLogic)
4045 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0, nTopM + (
4046 mpRefDevice->LogicToPixel(aCellSize).Height() -
4047 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height() )
4048 / 2)).Height() );
4049 else
4050 aLogicStart.AdjustY(nTopM + (aCellSize.Height() - nEngineHeight) / 2 );
4051 }
4052 else // top
4053 {
4054 if (rParam.mbPixelToLogic)
4055 aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
4056 else
4057 aLogicStart.AdjustY(nTopM );
4058 }
4059
4060 aURLStart = aLogicStart; // copy before modifying for orientation
4061
4062 Size aPaperLogic = rParam.mpEngine->GetPaperSize();
4063 aPaperLogic.setWidth( nEngineWidth );
4064 rParam.mpEngine->SetPaperSize(aPaperLogic);
4065
4066 // bMoveClipped handling has been replaced by complete alignment
4067 // handling (also extending to the left).
4068
4069 if (bSimClip)
4070 {
4071 // no hard clip, only draw the affected rows
4072 Point aDocStart = aClip.getRect().TopLeft();
4073 aDocStart -= aLogicStart;
4074 rParam.mpEngine->Draw(*mpDev, aClip.getRect(), aDocStart, false);
4075 }
4076 else
4077 {
4078 rParam.mpEngine->Draw(*mpDev, aLogicStart);
4079 }
4080 }
4081
4082 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4083}
4084
4086{
4087 // When in asian vertical orientation, the orientation value is STANDARD,
4088 // and the asian vertical boolean is true.
4089 OSL_ASSERT(rParam.meOrient == SvxCellOrientation::Standard);
4090 OSL_ASSERT(rParam.mbAsianVertical);
4091 OSL_ASSERT(rParam.meHorJustAttr != SvxCellHorJustify::Repeat);
4092
4093 Size aRefOne = mpRefDevice->PixelToLogic(Size(1,1));
4094
4095 bool bHidden = false;
4096 bool bShrink = !rParam.mbBreak && lcl_GetBoolValue(*rParam.mpPattern, ATTR_SHRINKTOFIT, rParam.mpCondSet);
4097 Degree100 nAttrRotate = lcl_GetValue<ScRotateValueItem, Degree100>(*rParam.mpPattern, ATTR_ROTATE_VALUE, rParam.mpCondSet);
4098
4099 if (nAttrRotate)
4100 {
4103 bHidden = true; // rotated is outputted separately
4104 }
4105
4106 // default alignment for asian vertical mode is top-right
4107 /* TODO: is setting meHorJustContext and meHorJustResult unconditionally to
4108 * SvxCellHorJustify::Right really wanted? Seems this was done all the time,
4109 * also before context was introduced and everything was attr only. */
4110 if ( rParam.meHorJustAttr == SvxCellHorJustify::Standard )
4111 rParam.meHorJustResult = rParam.meHorJustContext = SvxCellHorJustify::Right;
4112
4113 if (bHidden)
4114 return;
4115
4116 SvxCellHorJustify eOutHorJust = rParam.meHorJustContext;
4117
4120 tools::Long nTopM, nLeftM, nBottomM, nRightM;
4121 rParam.calcMargins(nTopM, nLeftM, nBottomM, nRightM, mnPPTX, mnPPTY);
4122
4123 SCCOL nXForPos = rParam.mnX;
4124 if ( nXForPos < nX1 )
4125 {
4126 nXForPos = nX1;
4127 rParam.mnPosX = rParam.mnInitPosX;
4128 }
4129 SCSIZE nArrYForPos = rParam.mnArrY;
4130 if ( nArrYForPos < 1 )
4131 {
4132 nArrYForPos = 1;
4133 rParam.mnPosY = nScrY;
4134 }
4135
4136 OutputAreaParam aAreaParam;
4137
4138 // Initial page size - large for normal text, cell size for automatic line breaks
4139
4140 Size aPaperSize( 1000000, 1000000 );
4141 // call GetOutputArea with nNeeded=0, to get only the cell width
4142
4144 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, 0,
4145 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4146 rParam.mbCellIsValue, true, false, aAreaParam );
4147
4149 rParam.calcPaperSize(aPaperSize, aAreaParam.maAlignRect, mnPPTX, mnPPTY);
4150
4151 if (rParam.mbPixelToLogic)
4152 {
4153 Size aLogicSize = mpRefDevice->PixelToLogic(aPaperSize);
4154 if ( rParam.mbBreak && !rParam.mbAsianVertical && mpRefDevice != pFmtDevice )
4155 {
4156 // #i85342# screen display and formatting for printer,
4157 // use same GetEditArea call as in ScViewData::SetEditEngine
4158
4159 Fraction aFract(1,1);
4160 tools::Rectangle aUtilRect = ScEditUtil( mpDoc, rParam.mnCellX, rParam.mnCellY, nTab, Point(0,0), pFmtDevice,
4161 HMM_PER_TWIPS, HMM_PER_TWIPS, aFract, aFract ).GetEditArea( rParam.mpPattern, false );
4162 aLogicSize.setWidth( aUtilRect.GetWidth() );
4163 }
4164 rParam.mpEngine->SetPaperSize(aLogicSize);
4165 }
4166 else
4167 rParam.mpEngine->SetPaperSize(aPaperSize);
4168
4169 // Fill the EditEngine (cell attributes and text)
4170
4171 // default alignment for asian vertical mode is top-right
4172 if ( rParam.meVerJust == SvxCellVerJustify::Standard )
4173 rParam.meVerJust = SvxCellVerJustify::Top;
4174
4176 rParam.setAlignmentToEngine();
4177
4178 // Read content from cell
4179
4180 bool bWrapFields = false;
4182 // Failed to read cell content. Bail out.
4183 return;
4184
4185 if ( mbSyntaxMode )
4186 SetEditSyntaxColor( *rParam.mpEngine, rParam.maCell );
4187 else if ( mbUseStyleColor && mbForceAutoColor )
4188 lcl_SetEditColor( *rParam.mpEngine, COL_AUTO );
4189
4190 rParam.mpEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
4191
4192 // Get final output area using the calculated width
4193
4194 tools::Long nEngineWidth, nEngineHeight;
4195 rParam.getEngineSize(rParam.mpEngine, nEngineWidth, nEngineHeight);
4196
4197 tools::Long nNeededPixel = nEngineWidth;
4198 if (rParam.mbPixelToLogic)
4199 nNeededPixel = mpRefDevice->LogicToPixel(Size(nNeededPixel,0)).Width();
4200 nNeededPixel += nLeftM + nRightM;
4201
4202 // for break, the first GetOutputArea call is sufficient
4203 GetOutputArea( nXForPos, nArrYForPos, rParam.mnPosX, rParam.mnPosY, rParam.mnCellX, rParam.mnCellY, nNeededPixel,
4204 *rParam.mpPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4205 rParam.mbCellIsValue || bShrink, false, false, aAreaParam );
4206
4207 if ( bShrink )
4208 {
4209 ShrinkEditEngine( *rParam.mpEngine, aAreaParam.maAlignRect,
4210 nLeftM, nTopM, nRightM, nBottomM, false,
4211 rParam.meOrient, 0_deg100, rParam.mbPixelToLogic,
4212 nEngineWidth, nEngineHeight, nNeededPixel,
4213 aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4214 }
4215 if ( rParam.mbCellIsValue && ( aAreaParam.mbLeftClip || aAreaParam.mbRightClip ) )
4216 {
4217 nEngineWidth = SetEngineTextAndGetWidth( rParam, "###", nNeededPixel, ( nLeftM + nRightM ) );
4218 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
4219 ScCellInfo* pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
4220 SetClipMarks( aAreaParam, pClipMarkCell, eOutHorJust, true, nLayoutSign );
4221 }
4222
4223 if (eOutHorJust != SvxCellHorJustify::Left)
4224 {
4225 aPaperSize.setWidth( nNeededPixel + 1 );
4226 if (rParam.mbPixelToLogic)
4227 rParam.mpEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4228 else
4229 rParam.mpEngine->SetPaperSize(aPaperSize);
4230 }
4231
4232 tools::Long nStartX = aAreaParam.maAlignRect.Left();
4233 tools::Long nStartY = aAreaParam.maAlignRect.Top();
4235 tools::Long nOutWidth = nCellWidth - 1 - nLeftM - nRightM;
4236 tools::Long nOutHeight = aAreaParam.maAlignRect.GetHeight() - nTopM - nBottomM;
4237
4238 // text with automatic breaks is aligned only within the
4239 // edit engine's paper size, the output of the whole area
4240 // is always left-aligned
4241
4242 nStartX += nLeftM;
4243
4244 bool bOutside = (aAreaParam.maClipRect.Right() < nScrX || aAreaParam.maClipRect.Left() >= nScrX + nScrW);
4245 if (bOutside)
4246 return;
4247
4248 // Also take fields in a cell with automatic breaks into account: clip to cell width
4249 bool bClip = AdjustAreaParamClipRect(aAreaParam) || aAreaParam.mbLeftClip || aAreaParam.mbRightClip || bWrapFields;
4250 bool bSimClip = false;
4251
4252 Size aCellSize; // output area, excluding margins, in logical units
4253 if (rParam.mbPixelToLogic)
4254 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4255 else
4256 aCellSize = Size( nOutWidth, nOutHeight );
4257
4258 if ( nEngineHeight >= aCellSize.Height() + aRefOne.Height() )
4259 {
4260 const ScMergeAttr* pMerge = &rParam.mpPattern->GetItem(ATTR_MERGE);
4261 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4262
4263 // Don't clip for text height when printing rows with optimal height,
4264 // except when font size is from conditional formatting.
4266 if ( eType != OUTTYPE_PRINTER ||
4267 ( mpDoc->GetRowFlags( rParam.mnCellY, nTab ) & CRFlags::ManualSize ) ||
4268 ( rParam.mpCondSet && SfxItemState::SET ==
4270 bClip = true;
4271 else
4272 bSimClip = true;
4273
4274 // Show clip marks if height is at least 5pt too small and
4275 // there are several lines of text.
4276 // Not for asian vertical text, because that would interfere
4277 // with the default right position of the text.
4278 // Only with automatic line breaks, to avoid having to find
4279 // the cells with the horizontal end of the text again.
4280 if ( nEngineHeight - aCellSize.Height() > 100 &&
4281 ( rParam.mbBreak || rParam.meOrient == SvxCellOrientation::Stacked ) &&
4282 !rParam.mbAsianVertical && bMarkClipped &&
4283 ( rParam.mpEngine->GetParagraphCount() > 1 || rParam.mpEngine->GetLineCount(0) > 1 ) )
4284 {
4285 ScCellInfo* pClipMarkCell = nullptr;
4286 if ( bMerged )
4287 {
4288 // anywhere in the merged area...
4289 SCCOL nClipX = ( rParam.mnX < nX1 ) ? nX1 : rParam.mnX;
4290 pClipMarkCell = &pRowInfo[(rParam.mnArrY != 0) ? rParam.mnArrY : 1].cellInfo(nClipX);
4291 }
4292 else
4293 pClipMarkCell = &rParam.mpThisRowInfo->cellInfo(rParam.mnX);
4294
4295 pClipMarkCell->nClipMark |= ScClipMark::Right;
4296 bAnyClipped = true;
4297
4298 tools::Long nMarkPixel = static_cast<tools::Long>( SC_CLIPMARK_SIZE * mnPPTX );
4299 if ( aAreaParam.maClipRect.Right() - nMarkPixel > aAreaParam.maClipRect.Left() )
4300 aAreaParam.maClipRect.AdjustRight( -nMarkPixel );
4301 }
4302 }
4303
4304 Point aURLStart;
4305
4306 { // Clip marks are already handled in GetOutputArea
4307 ClearableClipRegion aClip(rParam.mbPixelToLogic ? mpRefDevice->PixelToLogic(aAreaParam.maClipRect)
4308 : aAreaParam.maClipRect, bClip, bSimClip, mpDev, bMetaFile);
4309
4310 Point aLogicStart;
4311 if (rParam.mbPixelToLogic)
4312 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
4313 else
4314 aLogicStart = Point(nStartX, nStartY);
4315
4316 tools::Long nAvailWidth = aCellSize.Width();
4317 // space for AutoFilter is already handled in GetOutputArea
4318
4319 // horizontal alignment
4320
4321 if (rParam.meHorJustResult==SvxCellHorJustify::Right)
4322 aLogicStart.AdjustX(nAvailWidth - nEngineWidth );
4323 else if (rParam.meHorJustResult==SvxCellHorJustify::Center)
4324 aLogicStart.AdjustX((nAvailWidth - nEngineWidth) / 2 );
4325
4326 // paper size is subtracted below
4327 aLogicStart.AdjustX(nEngineWidth );
4328
4329 // vertical adjustment is within the EditEngine
4330 if (rParam.mbPixelToLogic)
4331 aLogicStart.AdjustY(mpRefDevice->PixelToLogic(Size(0,nTopM)).Height() );
4332 else
4333 aLogicStart.AdjustY(nTopM );
4334
4335 aURLStart = aLogicStart; // copy before modifying for orientation
4336
4337 // bMoveClipped handling has been replaced by complete alignment
4338 // handling (also extending to the left).
4339
4340 // with SetVertical, the start position is top left of
4341 // the whole output area, not the text itself
4342 aLogicStart.AdjustX( -(rParam.mpEngine->GetPaperSize().Width()) );
4343
4344 rParam.mpEngine->Draw(*mpDev, aLogicStart);
4345 }
4346
4347 rParam.adjustForHyperlinkInPDF(aURLStart, mpDev);
4348}
4349
4350void ScOutputData::DrawEdit(bool bPixelToLogic)
4351{
4352 std::unique_ptr<ScFieldEditEngine> pEngine;
4353 bool bHyphenatorSet = false;
4354 const ScPatternAttr* pOldPattern = nullptr;
4355 const SfxItemSet* pOldCondSet = nullptr;
4356 const SfxItemSet* pOldPreviewFontSet = nullptr;
4357 ScRefCellValue aCell;
4358
4359 tools::Long nInitPosX = nScrX;
4360 if ( bLayoutRTL )
4361 {
4362 nInitPosX += nMirrorW - 1;
4363 }
4364 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
4365
4367 SCCOL nLastContentCol = mpDoc->MaxCol();
4368 if ( nX2 < mpDoc->MaxCol() )
4369 nLastContentCol = sal::static_int_cast<SCCOL>(
4370 nLastContentCol - mpDoc->GetEmptyLinesInBlock( nX2+1, nY1, nTab, mpDoc->MaxCol(), nY2, nTab, DIR_RIGHT ) );
4371
4372 tools::Long nRowPosY = nScrY;
4373 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 of the rest of the merged
4374 {
4375 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4376
4377 if (nArrY==1) nRowPosY = nScrY; // positions before are calculated individually
4378
4379 if ( pThisRowInfo->bChanged || nArrY==0 )
4380 {
4381 tools::Long nPosX = 0;
4382 for (SCCOL nX=0; nX<=nX2; nX++) // due to overflow
4383 {
4384 std::unique_ptr< ScPatternAttr > pPreviewPattr;
4385 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4386
4387 if (pThisRowInfo->basicCellInfo(nX).bEditEngine)
4388 {
4389 SCROW nY = pThisRowInfo->nRowNo;
4390
4391 SCCOL nCellX = nX; // position where the cell really starts
4392 SCROW nCellY = nY;
4393 bool bDoCell = false;
4394
4395 tools::Long nPosY = nRowPosY;
4396 if ( nArrY == 0 )
4397 {
4398 nPosY = nScrY;
4399 nY = pRowInfo[1].nRowNo;
4400 SCCOL nOverX; // start of the merged cells
4401 SCROW nOverY;
4402 if (GetMergeOrigin( nX,nY, 1, nOverX,nOverY, true ))
4403 {
4404 nCellX = nOverX;
4405 nCellY = nOverY;
4406 bDoCell = true;
4407 }
4408 }
4409 else if ( nX == nX2 && pThisRowInfo->cellInfo(nX).maCell.isEmpty() )
4410 {
4411 // Rest of a long text further to the right?
4412
4413 SCCOL nTempX=nX;
4414 while (nTempX < nLastContentCol && IsEmptyCellText( pThisRowInfo, nTempX, nY ))
4415 ++nTempX;
4416
4417 if ( nTempX > nX &&
4418 !IsEmptyCellText( pThisRowInfo, nTempX, nY ) &&
4420 {
4421 nCellX = nTempX;
4422 bDoCell = true;
4423 }
4424 }
4425 else
4426 {
4427 bDoCell = true;
4428 }
4429
4430 if ( bDoCell && bEditMode && nCellX == nEditCol && nCellY == nEditRow )
4431 bDoCell = false;
4432
4433 const ScPatternAttr* pPattern = nullptr;
4434 const SfxItemSet* pCondSet = nullptr;
4435 if (bDoCell)
4436 {
4437 if ( nCellY == nY && nCellX >= nX1 && nCellX <= nX2 &&
4438 !mpDoc->ColHidden(nCellX, nTab) )
4439 {
4440 ScCellInfo& rCellInfo = pThisRowInfo->cellInfo(nCellX);
4441 pPattern = rCellInfo.pPatternAttr;
4442 pCondSet = rCellInfo.pConditionSet;
4443 aCell = rCellInfo.maCell;
4444 }
4445 else // get from document
4446 {
4447 pPattern = mpDoc->GetPattern( nCellX, nCellY, nTab );
4448 pCondSet = mpDoc->GetCondResult( nCellX, nCellY, nTab );
4449 GetVisibleCell( nCellX, nCellY, nTab, aCell );
4450 }
4451 if (aCell.isEmpty())
4452 bDoCell = false;
4453 }
4454 if (bDoCell)
4455 {
4456 if ( mpDoc->GetPreviewCellStyle() )
4457 {
4458 if ( ScStyleSheet* pPreviewStyle = mpDoc->GetPreviewCellStyle( nCellX, nCellY, nTab ) )
4459 {
4460 pPreviewPattr.reset( new ScPatternAttr(*pPattern) );
4461 pPreviewPattr->SetStyleSheet(pPreviewStyle);
4462 pPattern = pPreviewPattr.get();
4463 }
4464 }
4465 SfxItemSet* pPreviewFontSet = mpDoc->GetPreviewFont( nCellX, nCellY, nTab );
4466 if (!pEngine)
4467 pEngine = CreateOutputEditEngine();
4468 else
4469 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4470
4471 // fdo#32530: Check if the first character is RTL.
4472 OUString aStr = mpDoc->GetString(nCellX, nCellY, nTab);
4473
4474 DrawEditParam aParam(pPattern, pCondSet, lcl_SafeIsValue(aCell));
4475 const bool bNumberFormatIsText = lcl_isNumberFormatText( mpDoc, nCellX, nCellY, nTab );
4477 aParam.mbCellIsValue, aStr, *pPattern, pCondSet, mpDoc, nTab, bNumberFormatIsText);
4478 aParam.meHorJustResult = (aParam.meHorJustAttr == SvxCellHorJustify::Block) ?
4479 SvxCellHorJustify::Block : aParam.meHorJustContext;
4480 aParam.mbPixelToLogic = bPixelToLogic;
4481 aParam.mbHyphenatorSet = bHyphenatorSet;
4482 aParam.mpEngine = pEngine.get();
4483 aParam.maCell = aCell;
4484 aParam.mnArrY = nArrY;
4485 aParam.mnX = nX;
4486 aParam.mnCellX = nCellX;
4487 aParam.mnCellY = nCellY;
4488 aParam.mnPosX = nPosX;
4489 aParam.mnPosY = nPosY;
4490 aParam.mnInitPosX = nInitPosX;
4491 aParam.mpPreviewFontSet = pPreviewFontSet;
4492 aParam.mpOldPattern = pOldPattern;
4493 aParam.mpOldCondSet = pOldCondSet;
4494 aParam.mpOldPreviewFontSet = pOldPreviewFontSet;
4495 aParam.mpThisRowInfo = pThisRowInfo;
4496 if (mpSpellCheckCxt)
4497 aParam.mpMisspellRanges = mpSpellCheckCxt->getMisspellRanges(nCellX, nCellY);
4498
4499 if (aParam.meHorJustAttr == SvxCellHorJustify::Repeat)
4500 {
4501 // ignore orientation/rotation if "repeat" is active
4502 aParam.meOrient = SvxCellOrientation::Standard;
4503 }
4504 switch (aParam.meOrient)
4505 {
4506 case SvxCellOrientation::BottomUp:
4507 DrawEditBottomTop(aParam);
4508 break;
4509 case SvxCellOrientation::TopBottom:
4510 DrawEditTopBottom(aParam);
4511 break;
4512 case SvxCellOrientation::Stacked:
4513 // this can be vertically stacked or asian vertical.
4514 DrawEditStacked(aParam);
4515 break;
4516 default:
4517 DrawEditStandard(aParam);
4518 }
4519
4520 // Retrieve parameters for next iteration.
4521 pOldPattern = aParam.mpOldPattern;
4522 pOldCondSet = aParam.mpOldCondSet;
4523 pOldPreviewFontSet = aParam.mpOldPreviewFontSet;
4524 bHyphenatorSet = aParam.mbHyphenatorSet;
4525 }
4526 }
4527 nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
4528 }
4529 }
4530 nRowPosY += pRowInfo[nArrY].nHeight;
4531 }
4532
4533 pEngine.reset();
4534
4536 {
4537 DrawRotated(bPixelToLogic);
4538 }
4539}
4540
4541void ScOutputData::DrawRotated(bool bPixelToLogic)
4542{
4544 SCCOL nRotMax = nX2;
4545 for (SCSIZE nRotY=0; nRotY<nArrCount; nRotY++)
4546 if (pRowInfo[nRotY].nRotMaxCol != SC_ROTMAX_NONE && pRowInfo[nRotY].nRotMaxCol > nRotMax)
4547 nRotMax = pRowInfo[nRotY].nRotMaxCol;
4548
4549 ScModule* pScMod = SC_MOD();
4550 Color nConfBackColor = pScMod->GetColorConfig().GetColorValue(svtools::DOCCOLOR).nColor;
4551 bool bCellContrast = mbUseStyleColor &&
4553
4554 std::unique_ptr<ScFieldEditEngine> pEngine;
4555 bool bHyphenatorSet = false;
4556 const ScPatternAttr* pPattern;
4557 const SfxItemSet* pCondSet;
4558 const ScPatternAttr* pOldPattern = nullptr;
4559 const SfxItemSet* pOldCondSet = nullptr;
4560 ScRefCellValue aCell;
4561
4562 tools::Long nInitPosX = nScrX;
4563 if ( bLayoutRTL )
4564 {
4565 nInitPosX += nMirrorW - 1;
4566 }
4567 tools::Long nLayoutSign = bLayoutRTL ? -1 : 1;
4568
4569 tools::Long nRowPosY = nScrY;
4570 for (SCSIZE nArrY=0; nArrY+1<nArrCount; nArrY++) // 0 for the rest of the merged
4571 {
4572 RowInfo* pThisRowInfo = &pRowInfo[nArrY];
4573 tools::Long nCellHeight = static_cast<tools::Long>(pThisRowInfo->nHeight);
4574 if (nArrY==1) nRowPosY = nScrY; // positions before are calculated individually
4575
4576 if ( ( pThisRowInfo->bChanged || nArrY==0 ) && pThisRowInfo->nRotMaxCol != SC_ROTMAX_NONE )
4577 {
4578 tools::Long nPosX = 0;
4579 for (SCCOL nX=0; nX<=nRotMax; nX++)
4580 {
4581 if (nX==nX1) nPosX = nInitPosX; // positions before nX1 are calculated individually
4582
4583 const ScCellInfo* pInfo = &pThisRowInfo->cellInfo(nX);
4584 if ( pInfo->nRotateDir != ScRotateDir::NONE )
4585 {
4586 SCROW nY = pThisRowInfo->nRowNo;
4587
4588 bool bHidden = false;
4589 if (bEditMode)
4590 if ( nX == nEditCol && nY == nEditRow )
4591 bHidden = true;
4592
4593 if (!bHidden)
4594 {
4595 if (!pEngine)
4596 pEngine = CreateOutputEditEngine();
4597 else
4598 lcl_ClearEdit( *pEngine ); // also calls SetUpdateMode(sal_False)
4599
4600 tools::Long nPosY = nRowPosY;
4601
4603
4604 bool bFromDoc = false;
4605 pPattern = pInfo->pPatternAttr;
4606 pCondSet = pInfo->pConditionSet;
4607 if (!pPattern)
4608 {
4609 pPattern = mpDoc->GetPattern( nX, nY, nTab );
4610 bFromDoc = true;
4611 }
4612 aCell = pInfo->maCell;
4613 if (bFromDoc)
4614 pCondSet = mpDoc->GetCondResult( nX, nY, nTab );
4615
4616 if (aCell.isEmpty() && nX>nX2)
4617 GetVisibleCell( nX, nY, nTab, aCell );
4618
4619 if (aCell.isEmpty() || IsEmptyCellText(pThisRowInfo, nX, nY))
4620 bHidden = true; // nRotateDir is also set without a cell
4621
4623
4624 SvxCellHorJustify eHorJust =
4625 pPattern->GetItem(ATTR_HOR_JUSTIFY, pCondSet).GetValue();
4626 bool bBreak = ( eHorJust == SvxCellHorJustify::Block ) ||
4627 pPattern->GetItem(ATTR_LINEBREAK, pCondSet).GetValue();
4628 bool bRepeat = ( eHorJust == SvxCellHorJustify::Repeat && !bBreak );
4629 bool bShrink = !bBreak && !bRepeat &&
4630 pPattern->GetItem( ATTR_SHRINKTOFIT, pCondSet ).GetValue();
4631 SvxCellOrientation eOrient = pPattern->GetCellOrientation( pCondSet );
4632
4633 const ScMergeAttr* pMerge = &pPattern->GetItem(ATTR_MERGE);
4634 bool bMerged = pMerge->GetColMerge() > 1 || pMerge->GetRowMerge() > 1;
4635
4636 tools::Long nStartX = nPosX;
4637 tools::Long nStartY = nPosY;
4638 if (nX<nX1)
4639 {
4640 if ((bBreak || eOrient!=SvxCellOrientation::Standard) && !bMerged)
4641 bHidden = true;
4642 else
4643 {
4644 nStartX = nInitPosX;
4645 SCCOL nCol = nX1;
4646 while (nCol > nX)
4647 {
4648 --nCol;
4649 nStartX -= nLayoutSign * static_cast<tools::Long>(pRowInfo[0].basicCellInfo(nCol).nWidth);
4650 }
4651 }
4652 }
4653 tools::Long nCellStartX = nStartX;
4654
4655 // omit substitute representation of small text
4656
4657 if (!bHidden)
4658 {
4659 tools::Long nOutWidth = nCellWidth - 1;
4660 tools::Long nOutHeight = nCellHeight;
4661
4662 if ( bMerged )
4663 {
4664 SCCOL nCountX = pMerge->GetColMerge();
4665 for (SCCOL i=1; i<nCountX; i++)
4666 nOutWidth += mpDoc->GetColWidth(nX+i,nTab) * mnPPTX;
4667 SCROW nCountY = pMerge->GetRowMerge();
4668 nOutHeight += mpDoc->GetScaledRowHeight( nY+1, nY+nCountY-1, nTab, mnPPTY);
4669 }
4670
4671 SvxCellVerJustify eVerJust =
4672 pPattern->GetItem(ATTR_VER_JUSTIFY, pCondSet).GetValue();
4673
4674 // syntax mode is ignored here...
4675
4676 // StringDiffer doesn't look at hyphenate, language items
4677 if ( pPattern != pOldPattern || pCondSet != pOldCondSet )
4678 {
4679 auto pSet = std::make_unique<SfxItemSet>( pEngine->GetEmptyItemSet() );
4680 pPattern->FillEditItemSet( pSet.get(), pCondSet );
4681
4682 // adjustment for EditEngine
4683 SvxAdjust eSvxAdjust = SvxAdjust::Left;
4684 if (eOrient==SvxCellOrientation::Stacked)
4685 eSvxAdjust = SvxAdjust::Center;
4686 // adjustment for bBreak is omitted here
4687 pSet->Put( SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
4688
4689 bool bParaHyphenate = pSet->Get(EE_PARA_HYPHENATE).GetValue();
4690 pEngine->SetDefaults( std::move(pSet) );
4691 pOldPattern = pPattern;
4692 pOldCondSet = pCondSet;
4693
4694 EEControlBits nControl = pEngine->GetControlWord();
4695 if (eOrient==SvxCellOrientation::Stacked)
4696 nControl |= EEControlBits::ONECHARPERLINE;
4697 else
4698 nControl &= ~EEControlBits::ONECHARPERLINE;
4699 pEngine->SetControlWord( nControl );
4700
4701 if ( !bHyphenatorSet && bParaHyphenate )
4702 {
4703 // set hyphenator the first time it is needed
4704 css::uno::Reference<css::linguistic2::XHyphenator> xXHyphenator( LinguMgr::GetHyphenator() );
4705 pEngine->SetHyphenator( xXHyphenator );
4706 bHyphenatorSet = true;
4707 }
4708
4709 Color aBackCol =
4710 pPattern->GetItem( ATTR_BACKGROUND, pCondSet ).GetColor();
4711 if ( mbUseStyleColor && ( aBackCol.IsTransparent() || bCellContrast ) )
4712 aBackCol = nConfBackColor;
4713 pEngine->SetBackgroundColor( aBackCol );
4714 }
4715
4716 // margins
4717
4719
4720 const SvxMarginItem* pMargin =
4721 &pPattern->GetItem(ATTR_MARGIN, pCondSet);
4722 sal_uInt16 nIndent = 0;
4723 if ( eHorJust == SvxCellHorJustify::Left )
4724 nIndent = pPattern->GetItem(ATTR_INDENT, pCondSet).GetValue();
4725
4726 tools::Long nTotalHeight = nOutHeight; // without subtracting the margin
4727 if ( bPixelToLogic )
4728 nTotalHeight = mpRefDevice->PixelToLogic(Size(0,nTotalHeight)).Height();
4729
4730 tools::Long nLeftM = static_cast<tools::Long>( (pMargin->GetLeftMargin() + nIndent) * mnPPTX );
4731 tools::Long nTopM = static_cast<tools::Long>( pMargin->GetTopMargin() * mnPPTY );
4732 tools::Long nRightM = static_cast<tools::Long>( pMargin->GetRightMargin() * mnPPTX );
4733 tools::Long nBottomM = static_cast<tools::Long>( pMargin->GetBottomMargin() * mnPPTY );
4734 nStartX += nLeftM;
4735 nStartY += nTopM;
4736 nOutWidth -= nLeftM + nRightM;
4737 nOutHeight -= nTopM + nBottomM;
4738
4739 // rotate here already, to adjust paper size for page breaks
4740 Degree100 nAttrRotate;
4741 double nSin = 0.0;
4742 double nCos = 1.0;
4744 if ( eOrient == SvxCellOrientation::Standard )
4745 {
4746 nAttrRotate = pPattern->
4747 GetItem(ATTR_ROTATE_VALUE, pCondSet).GetValue();
4748 if ( nAttrRotate )
4749 {
4750 eRotMode = pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet).GetValue();
4751
4752 // tdf#143377 To use the same limits to avoid too big Skew
4753 // with TextOrientation in Calc, use 1/2 degree here, too.
4754 // This equals '50' in the notation here (100th degree)
4755 static const sal_Int32 nMinRad(50);
4756
4757 // bring nAttrRotate to the range [0..36000[
4758 nAttrRotate = Degree100(((nAttrRotate.get() % 36000) + 36000) % 36000);
4759
4760 // check for to be avoided extreme values and correct
4761 if (nAttrRotate < Degree100(nMinRad))
4762 {
4763 // range [0..50]
4764 nAttrRotate = Degree100(nMinRad);
4765 eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
4766 }
4767 else if (nAttrRotate > Degree100(36000 - nMinRad))
4768 {
4769 // range [35950..36000[
4770 nAttrRotate = Degree100(36000 - nMinRad);
4771 eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
4772 }
4773 else if (nAttrRotate > Degree100(18000 - nMinRad) && (nAttrRotate < Degree100(18000 + nMinRad)))
4774 {
4775 // range 50 around 18000, [17950..18050]
4776 nAttrRotate = (nAttrRotate > Degree100(18000))
4777 ? Degree100(18000 + nMinRad)
4778 : Degree100(18000 - nMinRad);
4779 eRotMode = SVX_ROTATE_MODE_STANDARD; // no overflow
4780 }
4781
4782 if ( bLayoutRTL )
4783 {
4784 // keep in range [0..36000[
4785 nAttrRotate = Degree100(36000 - nAttrRotate.get());
4786 }
4787
4788 double nRealOrient = toRadians(nAttrRotate); // 1/100 degree
4789 nCos = cos( nRealOrient );
4790
4791 // tdf#143377 new strategy: instead of using zero for nSin, which
4792 // would be the *correct* value, continue with the corrected maximum
4793 // allowed value which is then *not* zero. This is similar to
4794 // the behaviour before where (just due to numerical unprecisions)
4795 // nSin was also not zero (pure coincidence), but very close to it.
4796 // I checked and tried to make safe all places below that use
4797 // nSin and divide by it, but there is too much going on and that
4798 // would not be safe, so rely on the same values as before, but
4799 // now numerically limited to not get the Skew go havoc
4800 nSin = sin( nRealOrient );
4801 }
4802 }
4803
4804 Size aPaperSize( 1000000, 1000000 );
4805 if (eOrient==SvxCellOrientation::Stacked)
4806 aPaperSize.setWidth( nOutWidth ); // to center
4807 else if (bBreak)
4808 {
4809 if (nAttrRotate)
4810 {
4815 aPaperSize.setWidth( static_cast<tools::Long>(nOutHeight / fabs(nSin)) );
4816 }
4817 else if (eOrient == SvxCellOrientation::Standard)
4818 aPaperSize.setWidth( nOutWidth );
4819 else
4820 aPaperSize.setWidth( nOutHeight - 1 );
4821 }
4822 if (bPixelToLogic)
4823 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4824 else
4825 pEngine->SetPaperSize(aPaperSize); // scale is always 1
4826
4827 // read data from cell
4828
4829 if (aCell.getType() == CELLTYPE_EDIT)
4830 {
4831 if (aCell.getEditText())
4832 pEngine->SetTextCurrentDefaults(*aCell.getEditText());
4833 else
4834 {
4835 OSL_FAIL("pData == 0");
4836 }
4837 }
4838 else
4839 {
4840 sal_uInt32 nFormat = pPattern->GetNumberFormat(
4841 mpDoc->GetFormatTable(), pCondSet );
4842 const Color* pColor;
4843 OUString aString = ScCellFormat::GetString( aCell,
4844 nFormat, &pColor,
4846 *mpDoc,
4849
4850 pEngine->SetTextCurrentDefaults(aString);
4851 if ( pColor && !mbSyntaxMode && !( mbUseStyleColor && mbForceAutoColor ) )
4852 lcl_SetEditColor( *pEngine, *pColor );
4853 }
4854
4855 if ( mbSyntaxMode )
4856 {
4857 SetEditSyntaxColor(*pEngine, aCell);
4858 }
4859 else if ( mbUseStyleColor && mbForceAutoColor )
4860 lcl_SetEditColor( *pEngine, COL_AUTO );
4861
4862 pEngine->SetUpdateLayout( true ); // after SetText, before CalcTextWidth/GetTextHeight
4863
4864 tools::Long nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
4865 tools::Long nEngineHeight = pEngine->GetTextHeight();
4866
4867 if (nAttrRotate && bBreak)
4868 {
4869 double nAbsCos = fabs( nCos );
4870 double nAbsSin = fabs( nSin );
4871
4872 // adjust width of papersize for height of text
4873 int nSteps = 5;
4874 while (nSteps > 0)
4875 {
4876 // everything is in pixels
4877 tools::Long nEnginePixel = mpRefDevice->LogicToPixel(
4878 Size(0,nEngineHeight)).Height();
4879 tools::Long nEffHeight = nOutHeight - static_cast<tools::Long>(nEnginePixel * nAbsCos) + 2;
4880 tools::Long nNewWidth = static_cast<tools::Long>(nEffHeight / nAbsSin) + 2;
4881 bool bFits = ( nNewWidth >= aPaperSize.Width() );
4882 if ( bFits )
4883 nSteps = 0;
4884 else
4885 {
4886 if ( nNewWidth < 4 )
4887 {
4888 // can't fit -> fall back to using half height
4889 nEffHeight = nOutHeight / 2;
4890 nNewWidth = static_cast<tools::Long>(nEffHeight / nAbsSin) + 2;
4891 nSteps = 0;
4892 }
4893 else
4894 --nSteps;
4895
4896 // set paper width and get new text height
4897 aPaperSize.setWidth( nNewWidth );
4898 if (bPixelToLogic)
4899 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
4900 else
4901 pEngine->SetPaperSize(aPaperSize); // Scale is always 1
4902 //pEngine->QuickFormatDoc( sal_True );
4903
4904 nEngineWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
4905 nEngineHeight = pEngine->GetTextHeight();
4906 }
4907 }
4908 }
4909
4910 tools::Long nRealWidth = nEngineWidth;
4911 tools::Long nRealHeight = nEngineHeight;
4912
4913 // when rotated, adjust size
4914 if (nAttrRotate)
4915 {
4916 double nAbsCos = fabs( nCos );
4917 double nAbsSin = fabs( nSin );
4918
4919 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
4920 nEngineWidth = static_cast<tools::Long>( nRealWidth * nAbsCos +
4921 nRealHeight * nAbsSin );
4922 else
4923 nEngineWidth = static_cast<tools::Long>( nRealHeight / nAbsSin );
4925
4926 nEngineHeight = static_cast<tools::Long>( nRealHeight * nAbsCos +
4927 nRealWidth * nAbsSin );
4928 }
4929
4930 if (!nAttrRotate) // only rotated text here
4931 bHidden = true;
4932
4934
4935 if (!bHidden)
4936 {
4937 Size aClipSize( nScrX+nScrW-nStartX, nScrY+nScrH-nStartY );
4938
4939 // go on writing
4940
4941 Size aCellSize;
4942 if (bPixelToLogic)
4943 aCellSize = mpRefDevice->PixelToLogic( Size( nOutWidth, nOutHeight ) );
4944 else
4945 aCellSize = Size( nOutWidth, nOutHeight ); // scale is one
4946
4947 tools::Long nGridWidth = nEngineWidth;
4948 bool bNegative = false;
4949 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
4950 {
4951 nGridWidth = aCellSize.Width() +
4952 std::abs(static_cast<tools::Long>( aCellSize.Height() * nCos / nSin ));
4953 bNegative = ( pInfo->nRotateDir == ScRotateDir::Left );
4954 if ( bLayoutRTL )
4955 bNegative = !bNegative;
4956 }
4957
4958 // use GetOutputArea to hide the grid
4959 // (clip region is done manually below)
4960 OutputAreaParam aAreaParam;
4961
4962 SCCOL nCellX = nX;
4963 SCROW nCellY = nY;
4964 SvxCellHorJustify eOutHorJust = eHorJust;
4965 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
4966 eOutHorJust = bNegative ? SvxCellHorJustify::Right : SvxCellHorJustify::Left;
4967 tools::Long nNeededWidth = nGridWidth; // in pixel for GetOutputArea
4968 if ( bPixelToLogic )
4969 nNeededWidth = mpRefDevice->LogicToPixel(Size(nNeededWidth,0)).Width();
4970
4971 GetOutputArea( nX, nArrY, nCellStartX, nPosY, nCellX, nCellY, nNeededWidth,
4972 *pPattern, sal::static_int_cast<sal_uInt16>(eOutHorJust),
4973 false, false, true, aAreaParam );
4974
4975 if ( bShrink )
4976 {
4977 tools::Long nPixelWidth = bPixelToLogic ?
4978 mpRefDevice->LogicToPixel(Size(nEngineWidth,0)).Width() : nEngineWidth;
4979 tools::Long nNeededPixel = nPixelWidth + nLeftM + nRightM;
4980
4981 aAreaParam.mbLeftClip = aAreaParam.mbRightClip = true;
4982
4983 // always do height
4984 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
4985 false, eOrient, nAttrRotate, bPixelToLogic,
4986 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4987
4988 if ( eRotMode == SVX_ROTATE_MODE_STANDARD )
4989 {
4990 // do width only if rotating within the cell (standard mode)
4991 ShrinkEditEngine( *pEngine, aAreaParam.maAlignRect, nLeftM, nTopM, nRightM, nBottomM,
4992 true, eOrient, nAttrRotate, bPixelToLogic,
4993 nEngineWidth, nEngineHeight, nNeededPixel, aAreaParam.mbLeftClip, aAreaParam.mbRightClip );
4994 }
4995
4996 // nEngineWidth/nEngineHeight is updated in ShrinkEditEngine
4997 // (but width is only valid for standard mode)
4998 nRealWidth = static_cast<tools::Long>(pEngine->CalcTextWidth());
4999 nRealHeight = pEngine->GetTextHeight();
5000
5001 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5002 nEngineWidth = static_cast<tools::Long>( nRealHeight / fabs( nSin ) );
5003 }
5004
5005 tools::Long nClipStartX = nStartX;
5006 if (nX<nX1)
5007 {
5009
5010 if (nStartX<nScrX)
5011 {
5012 tools::Long nDif = nScrX - nStartX;
5013 nClipStartX = nScrX;
5014 aClipSize.AdjustWidth( -nDif );
5015 }
5016 }
5017
5018 tools::Long nClipStartY = nStartY;
5019 if (nArrY==0 && nClipStartY < nRowPosY )
5020 {
5021 tools::Long nDif = nRowPosY - nClipStartY;
5022 nClipStartY = nRowPosY;
5023 aClipSize.AdjustHeight( -nDif );
5024 }
5025
5026 if ( nAttrRotate /* && eRotMode != SVX_ROTATE_MODE_STANDARD */ )
5027 {
5028 // only clip rotated output text at the page border
5029 nClipStartX = nScrX;
5030 aClipSize.setWidth( nScrW );
5031 }
5032
5033 if (bPixelToLogic)
5034 aAreaParam.maClipRect = mpRefDevice->PixelToLogic( tools::Rectangle(
5035 Point(nClipStartX,nClipStartY), aClipSize ) );
5036 else
5037 aAreaParam.maClipRect = tools::Rectangle(Point(nClipStartX, nClipStartY),
5038 aClipSize ); // Scale = 1
5039
5040 if (bMetaFile)
5041 {
5042 mpDev->Push();
5043 mpDev->IntersectClipRegion( aAreaParam.maClipRect );
5044 }
5045 else
5046 mpDev->SetClipRegion( vcl::Region( aAreaParam.maClipRect ) );
5047
5048 Point aLogicStart;
5049 if (bPixelToLogic)
5050 aLogicStart = mpRefDevice->PixelToLogic( Point(nStartX,nStartY) );
5051 else
5052 aLogicStart = Point(nStartX, nStartY);
5053 if ( eOrient!=SvxCellOrientation::Standard || !bBreak )
5054 {
5055 tools::Long nAvailWidth = aCellSize.Width();
5056 if (eType==OUTTYPE_WINDOW &&
5057 eOrient!=SvxCellOrientation::Stacked &&
5058 pInfo->bAutoFilter)
5059 {
5060 // filter drop-down width depends on row height
5061 double fZoom = mpRefDevice ? static_cast<double>(mpRefDevice->GetMapMode().GetScaleY()) : 1.0;
5062 fZoom = fZoom > 1.0 ? fZoom : 1.0;
5063 if (bPixelToLogic)
5064 nAvailWidth -= mpRefDevice->PixelToLogic(Size(0,fZoom * DROPDOWN_BITMAP_SIZE)).Height();
5065 else
5066 nAvailWidth -= fZoom * DROPDOWN_BITMAP_SIZE;
5067 tools::Long nComp = nEngineWidth;
5068 if (nAvailWidth<nComp) nAvailWidth=nComp;
5069 }
5070
5071 // horizontal orientation
5072
5073 if (eOrient==SvxCellOrientation::Standard && !nAttrRotate)
5074 {
5075 if (eHorJust==SvxCellHorJustify::Right ||
5076 eHorJust==SvxCellHorJustify::Center)
5077 {
5078 pEngine->SetUpdateLayout( false );
5079
5080 SvxAdjust eSvxAdjust =
5081 (eHorJust==SvxCellHorJustify::Right) ?
5082 SvxAdjust::Right : SvxAdjust::Center;
5083 pEngine->SetDefaultItem(
5084 SvxAdjustItem( eSvxAdjust, EE_PARA_JUST ) );
5085
5086 aPaperSize.setWidth( nOutWidth );
5087 if (bPixelToLogic)
5088 pEngine->SetPaperSize(mpRefDevice->PixelToLogic(aPaperSize));
5089 else
5090 pEngine->SetPaperSize(aPaperSize);
5091
5092 pEngine->SetUpdateLayout( true );
5093 }
5094 }
5095 else
5096 {
5097 // rotated text is centered by default
5098 if (eHorJust==SvxCellHorJustify::Right)
5099 aLogicStart.AdjustX(nAvailWidth - nEngineWidth );
5100 else if (eHorJust==SvxCellHorJustify::Center ||
5101 eHorJust==SvxCellHorJustify::Standard)
5102 aLogicStart.AdjustX((nAvailWidth - nEngineWidth) / 2 );
5103 }
5104 }
5105
5106 if ( bLayoutRTL )
5107 {
5108 if (bPixelToLogic)
5109 aLogicStart.AdjustX( -(mpRefDevice->PixelToLogic(
5110 Size( nCellWidth, 0 ) ).Width()) );
5111 else
5112 aLogicStart.AdjustX( -nCellWidth );
5113 }
5114
5115 if ( eOrient==SvxCellOrientation::Standard ||
5116 eOrient==SvxCellOrientation::Stacked || !bBreak )
5117 {
5118 if (eVerJust==SvxCellVerJustify::Bottom ||
5119 eVerJust==SvxCellVerJustify::Standard)
5120 {
5121 if (bPixelToLogic)
5122 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0,
5123 mpRefDevice->LogicToPixel(aCellSize).Height() -
5124 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height()
5125 )).Height() );
5126 else
5127 aLogicStart.AdjustY(aCellSize.Height() - nEngineHeight );
5128 }
5129
5130 else if (eVerJust==SvxCellVerJustify::Center)
5131 {
5132 if (bPixelToLogic)
5133 aLogicStart.AdjustY(mpRefDevice->PixelToLogic( Size(0,(
5134 mpRefDevice->LogicToPixel(aCellSize).Height() -
5135 mpRefDevice->LogicToPixel(Size(0,nEngineHeight)).Height())
5136 / 2)).Height() );
5137 else
5138 aLogicStart.AdjustY((aCellSize.Height() - nEngineHeight) / 2 );
5139 }
5140 }
5141
5142 // TOPBOTTOM and BOTTOMTOP are handled in DrawStrings/DrawEdit
5143 OSL_ENSURE( eOrient == SvxCellOrientation::Standard && nAttrRotate,
5144 "DrawRotated: no rotation" );
5145
5146 Degree10 nOriVal = 0_deg10;
5147 if ( nAttrRotate )
5148 {
5149 // attribute is 1/100, Font 1/10 degrees
5150 nOriVal = to<Degree10>(nAttrRotate);
5151
5152 double nAddX = 0.0;
5153 double nAddY = 0.0;
5154 if ( nCos > 0.0 && eRotMode != SVX_ROTATE_MODE_STANDARD )
5155 {
5157 double nH = nRealHeight * nCos;
5158 nAddX += nH * ( nCos / fabs(nSin) );
5159 }
5160 if ( nCos < 0.0 && eRotMode == SVX_ROTATE_MODE_STANDARD )
5161 nAddX -= nRealWidth * nCos;
5162 if ( nSin < 0.0 )
5163 nAddX -= nRealHeight * nSin;
5164 if ( nSin > 0.0 )
5165 nAddY += nRealWidth * nSin;
5166 if ( nCos < 0.0 )
5167 nAddY -= nRealHeight * nCos;
5168
5169 if ( eRotMode != SVX_ROTATE_MODE_STANDARD )
5170 {
5172 double nSkew = nTotalHeight * nCos / fabs(nSin);
5173 if ( eRotMode == SVX_ROTATE_MODE_CENTER )
5174 nAddX -= nSkew * 0.5;
5175 if ( ( eRotMode == SVX_ROTATE_MODE_TOP && nSin > 0.0 ) ||
5176 ( eRotMode == SVX_ROTATE_MODE_BOTTOM && nSin < 0.0 ) )
5177 nAddX -= nSkew;
5178
5179 tools::Long nUp = 0;
5180 if ( eVerJust == SvxCellVerJustify::Center )
5181 nUp = ( aCellSize.Height() - nEngineHeight ) / 2;
5182 else if ( eVerJust == SvxCellVerJustify::Top )
5183 {
5184 if ( nSin > 0.0 )
5185 nUp = aCellSize.Height() - nEngineHeight;
5186 }
5187 else // BOTTOM / STANDARD
5188 {
5189 if ( nSin < 0.0 )
5190 nUp = aCellSize.Height() - nEngineHeight;
5191 }
5192 if ( nUp )
5193 nAddX += ( nUp * nCos / fabs(nSin) );
5194 }
5195
5196 aLogicStart.AdjustX(static_cast<tools::Long>(nAddX) );
5197 aLogicStart.AdjustY(static_cast<tools::Long>(nAddY) );
5198 }
5199
5200 // bSimClip is not used here (because nOriVal is set)
5201
5202 pEngine->Draw(*mpDev, aLogicStart, nOriVal);
5203
5204 if (bMetaFile)
5205 mpDev->Pop();
5206 else
5207 mpDev->SetClipRegion();
5208 }
5209 }
5210 }
5211 }
5212 nPosX += pRowInfo[0].basicCellInfo(nX).nWidth * nLayoutSign;
5213 }
5214 }
5215 nRowPosY += pRowInfo[nArrY].nHeight;
5216 }
5217}
5218
5219/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
size_t SCSIZE
size_t typedef to be able to find places where code was changed from USHORT to size_t and is used to ...
Definition: address.hxx:44
ScMF
Definition: attrib.hxx:34
@ Button
autofilter arrow
@ ButtonPopup
const StyleSettings & GetStyleSettings() const
static OutputDevice * GetDefaultDevice()
static const AllSettings & GetSettings()
~ClearableClipRegion() COVERITY_NOEXCEPT_FALSE
Definition: output2.cxx:2825
tools::Rectangle maRect
Definition: output2.cxx:2841
VclPtr< OutputDevice > mpDev
Definition: output2.cxx:2842
const tools::Rectangle & getRect() const
Definition: output2.cxx:2838
ClearableClipRegion(const tools::Rectangle &rRect, bool bClip, bool bSimClip, const VclPtr< OutputDevice > &pDev, bool bMetaFile)
Definition: output2.cxx:2804
bool IsTransparent() const
void GetPortions(sal_Int32 nPara, std::vector< sal_Int32 > &rList)
OUString GetText(LineEnd eEnd=LINEEND_LF) const
void SetText(const OUString &rStr)
bool SetUpdateLayout(bool bUpdate, bool bRestoring=false)
sal_Int32 GetParagraphCount() const
const Size & GetPaperSize() const
void EnableSkipOutsideFormat(bool set)
sal_uInt32 GetTextHeight() const
SfxItemSet GetAttribs(sal_Int32 nPara, sal_Int32 nStart, sal_Int32 nEnd, GetAttribsFlags nFlags=GetAttribsFlags::ALL) const
sal_uInt32 CalcTextWidth()
const SfxItemSet & GetEmptyItemSet() const
sal_Int32 GetLineCount(sal_Int32 nParagraph) const
void Draw(OutputDevice &rOutDev, const tools::Rectangle &rOutRect)
void SetPaperSize(const Size &rSize)
void QuickSetAttribs(const SfxItemSet &rSet, const ESelection &rSel)
virtual void SetParaAttribs(sal_Int32 nPara, const SfxItemSet &rSet)
const SfxItemSet & GetParaAttribs(sal_Int32 nPara) const
tools::Long GetDescent() const
tools::Long GetAscent() const
tools::Long GetInternalLeading() const
void resize(size_t nSize)
size_t size() const
void set(size_t nIndex, sal_Int32 nValue)
static css::uno::Reference< css::linguistic2::XHyphenator > GetHyphenator()
const css::i18n::LocaleDataItem2 & getLocaleItem() const
const Fraction & GetScaleX() const
const Fraction & GetScaleY() const
GDIMetaFile * GetConnectMetaFile() const
void SetFont(const vcl::Font &rNewFont)
SAL_WARN_UNUSED_RESULT Point PixelToLogic(const Point &rDevicePt) const
vcl::ExtOutDevData * GetExtOutDevData() const
void SetMapMode()
SAL_WARN_UNUSED_RESULT Point LogicToPixel(const Point &rLogicPt) const
FontMetric GetFontMetric() const
const MapMode & GetMapMode() const
tools::Long GetTextHeight() const
OutDevType GetOutDevType() const
void SetOverlineColor()
void SetTextLineColor()
void Move(tools::Long nHorzMove, tools::Long nVertMove)
tools::Long AdjustY(tools::Long nVertMove)
tools::Long AdjustX(tools::Long nHorzMove)
static SalLayoutGlyphsCache * self()
const SalLayoutGlyphs * GetLayoutGlyphs(VclPtr< const OutputDevice > outputDevice, const OUString &text, const vcl::text::TextLayoutCache *layoutCache=nullptr)
static OUString GetString(const ScRefCellValue &rCell, sal_uInt32 nFormat, const Color **ppColor, SvNumberFormatter &rFormatter, const ScDocument &rDoc, bool bNullVals=true, bool bFormula=false, bool bUseStarFormat=false)
Definition: cellform.cxx:31
SC_DLLPUBLIC SfxItemPool * GetEnginePool() const
Definition: documen2.cxx:478
SC_DLLPUBLIC sal_uInt16 GetRowHeight(SCROW nRow, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4161
SC_DLLPUBLIC sal_uInt32 GetNumberFormat(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3640
SC_DLLPUBLIC sal_uInt16 GetColWidth(SCCOL nCol, SCTAB nTab, bool bHiddenAsZero=true) const
Definition: document.cxx:4122
EEHorizontalTextDirection GetEditTextDirection(SCTAB nTab) const
Definition: documen8.cxx:355
tools::Long GetScaledRowHeight(SCROW nStartRow, SCROW nEndRow, SCTAB nTab, double fScale) const
Definition: document.cxx:4198
SC_DLLPUBLIC SCCOL MaxCol() const
Definition: document.hxx:892
const SfxPoolItem * GetEffItem(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: documen4.cxx:751
void SetLayoutStrings(bool bSet)
Definition: document.hxx:2636
bool IsInLayoutStrings() const
Definition: document.hxx:2635
SC_DLLPUBLIC bool RowHidden(SCROW nRow, SCTAB nTab, SCROW *pFirstRow=nullptr, SCROW *pLastRow=nullptr) const
Definition: document.cxx:4416
SC_DLLPUBLIC CRFlags GetRowFlags(SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4335
SC_DLLPUBLIC bool HasAttrib(SCCOL nCol1, SCROW nRow1, SCTAB nTab1, SCCOL nCol2, SCROW nRow2, SCTAB nTab2, HasAttrFlags nMask) const
Definition: document.cxx:5161
bool InterpretCellsIfNeeded(const ScRangeList &rRanges)
Definition: document.cxx:3897
SC_DLLPUBLIC SvtScriptType GetCellScriptType(const ScAddress &rPos, sal_uInt32 nNumberFormat, const ScRefCellValue *pCell=nullptr)
Definition: documen6.cxx:111
void ApplyAsianEditSettings(ScEditEngineDefaulter &rEngine)
Definition: documen9.cxx:662
SfxItemSet * GetPreviewFont()
Definition: document.hxx:1390
SC_DLLPUBLIC SvNumberFormatter * GetFormatTable() const
Definition: documen2.cxx:467
SC_DLLPUBLIC bool ColHidden(SCCOL nCol, SCTAB nTab, SCCOL *pFirstCol=nullptr, SCCOL *pLastCol=nullptr) const
Definition: document.cxx:4430
SC_DLLPUBLIC OUString GetString(SCCOL nCol, SCROW nRow, SCTAB nTab, const ScInterpreterContext *pContext=nullptr) const
Definition: document.cxx:3505
ScStyleSheet * GetPreviewCellStyle()
Definition: document.hxx:1394
SC_DLLPUBLIC CellType GetCellType(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:3736
SC_DLLPUBLIC bool IsLayoutRTL(SCTAB nTab) const
Definition: document.cxx:974
SC_DLLPUBLIC const SfxPoolItem * GetAttr(SCCOL nCol, SCROW nRow, SCTAB nTab, sal_uInt16 nWhich) const
Definition: document.cxx:4684
SC_DLLPUBLIC SCSIZE GetEmptyLinesInBlock(SCCOL nStartCol, SCROW nStartRow, SCTAB nStartTab, SCCOL nEndCol, SCROW nEndRow, SCTAB nEndTab, ScDirection eDir)
Definition: document.cxx:6067
SC_DLLPUBLIC const SfxItemSet * GetCondResult(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue *pCell=nullptr) const
Definition: documen4.cxx:791
SC_DLLPUBLIC const ScPatternAttr * GetPattern(SCCOL nCol, SCROW nRow, SCTAB nTab) const
Definition: document.cxx:4719
SvxCellOrientation eAttrOrient
Definition: output2.cxx:109
void SetPattern(const ScPatternAttr *pNew, const SfxItemSet *pSet, const ScRefCellValue &rCell, SvtScriptType nScript)
Definition: output2.cxx:304
sal_Int32 nRepeatPos
Definition: output2.cxx:136
bool HasEditCharacters() const
Definition: output2.cxx:812
bool GetLineBreak() const
Definition: output2.cxx:174
tools::Long nOriginalWidth
Definition: output2.cxx:119
const OUString & GetString() const
Definition: output2.cxx:165
ScOutputData * pOutput
Definition: output2.cxx:101
const SfxItemSet * pCondSet
Definition: output2.cxx:104
SvxCellVerJustify GetVerJust() const
Definition: output2.cxx:158
void SetHashText()
Definition: output2.cxx:568
tools::Long nSignWidth
Definition: output2.cxx:121
tools::Long GetDotWidth()
Definition: output2.cxx:762
tools::Long nExpWidth
Definition: output2.cxx:123
tools::Long GetSignWidth()
Definition: output2.cxx:753
Color aTextConfigColor
Definition: output2.cxx:135
bool IsRepeat() const
Definition: output2.cxx:175
void SetShrinkScale(tools::Long nScale, SvtScriptType nScript)
Definition: output2.cxx:238
SvxCellVerJustify eAttrVerJust
Definition: output2.cxx:111
tools::Long nMaxDigitWidth
Definition: output2.cxx:120
tools::Long GetAscent() const
Definition: output2.cxx:179
SvxCellOrientation GetOrient() const
Definition: output2.cxx:156
tools::Long GetOriginalWidth() const
Definition: output2.cxx:167
void SetPatternSimple(const ScPatternAttr *pNew, const SfxItemSet *pSet)
Definition: output2.cxx:459
sal_uInt16 nIndent
Definition: output2.cxx:114
bool HasCondHeight() const
Definition: output2.cxx:184
SvxCellJustifyMethod eAttrHorJustMethod
Definition: output2.cxx:112
void TextChanged()
Definition: output2.cxx:786
SvxCellHorJustify eAttrHorJust
Definition: output2.cxx:110
void RepeatToFill(tools::Long nColWidth)
Definition: output2.cxx:573
vcl::Font aFont
Definition: output2.cxx:106
void SetAutoText(const OUString &rAutoText)
Definition: output2.cxx:708
sal_uLong nValueFormat
Definition: output2.cxx:126
const SalLayoutGlyphs * GetLayoutGlyphs(const OUString &rString) const
Definition: output2.cxx:191
ScRefCellValue maLastCell
Definition: output2.cxx:125
tools::Long GetExpWidth()
Definition: output2.cxx:772
ScDrawStringsVars(ScOutputData *pData, bool bPTL)
Definition: output2.cxx:204
tools::Long GetMaxDigitWidth()
Definition: output2.cxx:738
Color aBackConfigColor
Definition: output2.cxx:134
const ScPatternAttr * pPattern
Definition: output2.cxx:103
OUString aString
Definition: output2.cxx:117
sal_uInt16 GetLeftTotal() const
Definition: output2.cxx:162
SvxCellHorJustify GetHorJust() const
Definition: output2.cxx:157
bool SetText(const ScRefCellValue &rCell)
Definition: output2.cxx:499
bool IsShrink() const
Definition: output2.cxx:176
tools::Long nAscentPixel
Definition: output2.cxx:108
const SvxMarginItem * pMargin
Definition: output2.cxx:113
const SvxMarginItem * GetMargin() const
Definition: output2.cxx:160
sal_uLong GetResultValueFormat() const
Definition: output2.cxx:172
sal_uInt16 GetRightTotal() const
Definition: output2.cxx:163
tools::Long nDotWidth
Definition: output2.cxx:122
bool SetTextToWidthOrHash(ScRefCellValue &rCell, tools::Long nWidth)
Definition: output2.cxx:602
SvxCellJustifyMethod GetHorJustMethod() const
Definition: output2.cxx:159
tools::Long GetFmtTextWidth(const OUString &rString)
Definition: output2.cxx:781
sal_Unicode nRepeatChar
Definition: output2.cxx:137
const Size & GetTextSize() const
Definition: output2.cxx:166
FontMetric aMetric
Definition: output2.cxx:107
bool IsRotated() const
Definition: output2.cxx:180
void SetTextCurrentDefaults(const EditTextObject &rTextObject)
SetText and apply defaults already set.
Definition: editutil.cxx:619
void SetDefaultItem(const SfxPoolItem &rItem)
Set the item in the default ItemSet which is created if it doesn't exist yet.
Definition: editutil.cxx:598
tools::Rectangle GetEditArea(const ScPatternAttr *pPattern, bool bForceToTop)
Definition: editutil.cxx:338
void GetURLResult(OUString &rURL, OUString &rCellText)
bool IsRunning() const
bool GetDirty() const
bool IsHyperLinkCell() const
FormulaError GetErrCode()
bool IsMultilineResult()
Determines whether or not the result string contains more than one paragraph.
static SC_DLLPUBLIC const LocaleDataWrapper & getLocaleData()
Definition: global.cxx:1055
static SC_DLLPUBLIC SvtScriptType GetDefaultScriptType()
Definition: global.cxx:900
static SC_DLLPUBLIC const CharClass & getCharClass()
Definition: global.cxx:1064
SCCOL GetColMerge() const
Definition: attrib.hxx:71
bool IsMerged() const
Definition: attrib.hxx:74
SCROW GetRowMerge() const
Definition: attrib.hxx:72
svtools::ColorConfig & GetColorConfig()
Definition: scmod.cxx:887
bool adjustHorAlignment(ScFieldEditEngine *pEngine)
Definition: output2.cxx:2729
bool readCellContent(const ScDocument *pDoc, bool bShowNullValues, bool bShowFormulas, bool bSyntaxMode, bool bUseStyleColor, bool bForceAutoColor, bool &rWrapFields)
Definition: output2.cxx:2403
void adjustForHyperlinkInPDF(Point aURLStart, const OutputDevice *pDev)
Definition: output2.cxx:2744
SvxCellOrientation meOrient
Definition: output.hxx:122
const SfxItemSet * mpCondSet
Definition: output.hxx:138
const std::vector< editeng::MisspellRanges > * mpMisspellRanges
Definition: output.hxx:144
bool isVerticallyOriented() const
When the text is vertically oriented, the text is either rotated 90 degrees to the right or 90 degree...
Definition: output2.cxx:2586
const SfxItemSet * mpPreviewFontSet
Definition: output.hxx:139
SvxCellHorJustify meHorJustAttr
alignment attribute
Definition: output.hxx:116
const ScPatternAttr * mpPattern
Definition: output.hxx:137
ScFieldEditEngine * mpEngine
Definition: output.hxx:135
ScRefCellValue maCell
Definition: output.hxx:136
void calcPaperSize(Size &rPaperSize, const tools::Rectangle &rAlignRect, double nPPTX, double nPPTY) const
Definition: output2.cxx:2528
const SfxItemSet * mpOldPreviewFontSet
Definition: output.hxx:142
DrawEditParam(const ScPatternAttr *pPattern, const SfxItemSet *pCondSet, bool bCellIsValue)
Definition: output2.cxx:2376
void getEngineSize(ScFieldEditEngine *pEngine, tools::Long &rWidth, tools::Long &rHeight) const
Definition: output2.cxx:2555
void setPatternToEngine(bool bUseStyleColor)
Definition: output2.cxx:2450
SvxCellHorJustify meHorJustResult
result for EditEngine
Definition: output.hxx:118
void calcStartPosForVertical(Point &rLogicStart, tools::Long nCellWidth, tools::Long nEngineWidth, tools::Long nTopM, const OutputDevice *pRefDevice)
Calculate offset position for vertically oriented (either top-bottom or bottom-top orientation) text.
Definition: output2.cxx:2591
SvxCellVerJustify meVerJust
Definition: output.hxx:119
const ScPatternAttr * mpOldPattern
Definition: output.hxx:140
bool isHyperlinkCell() const
Definition: output2.cxx:2578
void calcMargins(tools::Long &rTop, tools::Long &rLeft, tools::Long &rBottom, tools::Long &rRight, double nPPTX, double nPPTY) const
Definition: output2.cxx:2509
const SfxItemSet * mpOldCondSet
Definition: output.hxx:141
SvxCellHorJustify meHorJustContext
context depending on attribute, content and direction
Definition: output.hxx:117
void LayoutStrings(bool bPixelToLogic)
Draw all strings.
Definition: output2.cxx:1481
ScTableInfo & mrTabInfo
Definition: output.hxx:181
SCROW nY2
Definition: output.hxx:194
void DrawEditStacked(DrawEditParam &rParam)
Definition: output2.cxx:3801
tools::Long nScrY
Definition: output.hxx:187
SCTAB nTab
Definition: output.hxx:185
SCCOL nEditCol
Definition: output.hxx:210
VclPtr< OutputDevice > mpDev
Definition: output.hxx:178
Fraction aZoomY
Definition: output.hxx:203
VclPtr< OutputDevice > mpRefDevice
Definition: output.hxx:179
tools::Long nScrW
Definition: output.hxx:188
bool bVertical
Definition: output.hxx:236
tools::Long nScrH
Definition: output.hxx:189
bool bMetaFile
Definition: output.hxx:213
void GetOutputArea(SCCOL nX, SCSIZE nArrY, tools::Long nPosX, tools::Long nPosY, SCCOL nCellX, SCROW nCellY, tools::Long nNeeded, const ScPatternAttr &rPattern, sal_uInt16 nHorJustify, bool bCellIsValue, bool bBreak, bool bOverwrite, OutputAreaParam &rParam)
Definition: output2.cxx:1192
void SetSyntaxColor(vcl::Font *pFont, const ScRefCellValue &rCell)
Definition: output2.cxx:890
double mnPPTY
Definition: output.hxx:201
bool bEditMode
Definition: output.hxx:209
bool mbSyntaxMode
Definition: output.hxx:221
bool bMarkClipped
Definition: output.hxx:231
SCCOL nVisX1
Definition: output.hxx:195
tools::Long nMirrorW
Definition: output.hxx:190
bool mbForceAutoColor
Definition: output.hxx:219
SCCOL nX1
Definition: output.hxx:191
void DrawStrings(bool bPixelToLogic=false)
Definition: output2.cxx:1476
bool bAnyClipped
Definition: output.hxx:235
void DrawEditBottomTop(DrawEditParam &rParam)
Definition: output2.cxx:3321
SCROW nEditRow
Definition: output.hxx:211
double mnPPTX
Definition: output.hxx:200
bool GetMergeOrigin(SCCOL nX, SCROW nY, SCSIZE nArrY, SCCOL &rOverX, SCROW &rOverY, bool bVisRowChanged)
Definition: output2.cxx:941
bool AdjustAreaParamClipRect(OutputAreaParam &rAreaParam)
Definition: output2.cxx:2772
void SetClipMarks(OutputAreaParam &aAreaParam, ScCellInfo *pClipMarkCell, SvxCellHorJustify eOutHorJust, bool bHasHashText, tools::Long nLayoutSign)
Definition: output2.cxx:3215
bool IsAvailable(SCCOL nX, SCROW nY)
Definition: output2.cxx:1166
SCCOL nX2
Definition: output.hxx:193
ScOutputType eType
Definition: output.hxx:199
bool bShowSpellErrors
Definition: output.hxx:230
RowInfo * pRowInfo
Definition: output.hxx:182
VclPtr< OutputDevice > pFmtDevice
Definition: output.hxx:180
Fraction aZoomX
Definition: output.hxx:202
SCROW nVisY1
Definition: output.hxx:196
ScDocument * mpDoc
Definition: output.hxx:184
tools::Long SetEngineTextAndGetWidth(DrawEditParam &rParam, const OUString &rSetString, tools::Long &rNeededPixel, tools::Long nAddWidthPixels)
Definition: output2.cxx:2847
SCROW nY1
Definition: output.hxx:192
ClearableClipRegionPtr Clip(DrawEditParam &rParam, const Size &aCellSize, OutputAreaParam &aAreaParam, tools::Long nEngineWidth, bool bWrapFields, bool bTop)
Definition: output2.cxx:3287
bool bLayoutRTL
Definition: output.hxx:238
void DrawEditTopBottom(DrawEditParam &rParam)
Definition: output2.cxx:3564
bool mbUseStyleColor
Definition: output.hxx:218
SCSIZE nArrCount
Definition: output.hxx:183
void DrawEdit(bool bPixelToLogic)
Definition: output2.cxx:4350
tools::Long nScrX
Definition: output.hxx:186
std::optional< Color > mxValueColor
Definition: output.hxx:222
bool mbShowNullValues
Definition: output.hxx:228
std::unique_ptr< ScFieldEditEngine > CreateOutputEditEngine()
Definition: output2.cxx:2177
void DrawEditAsianVertical(DrawEditParam &rParam)
Definition: output2.cxx:4085
void GetVisibleCell(SCCOL nCol, SCROW nRow, SCTAB nTab, ScRefCellValue &rCell)
Definition: output2.cxx:1159
bool mbShowFormulas
Definition: output.hxx:229
void ShowClipMarks(DrawEditParam &rParam, tools::Long nEngineWidth, const Size &aCellSize, bool bMerged, OutputAreaParam &aAreaParam, bool bTop)
Definition: output2.cxx:3247
std::optional< Color > mxFormulaColor
Definition: output.hxx:224
const sc::SpellCheckContext * mpSpellCheckCxt
Definition: output.hxx:242
bool bTabProtected
Definition: output.hxx:237
std::optional< Color > mxTextColor
Definition: output.hxx:223
void ShrinkEditEngine(EditEngine &rEngine, const tools::Rectangle &rAlignRect, tools::Long nLeftM, tools::Long nTopM, tools::Long nRightM, tools::Long nBottomM, bool bWidth, SvxCellOrientation nOrient, Degree100 nAttrRotate, bool bPixelToLogic, tools::Long &rEngineWidth, tools::Long &rEngineHeight, tools::Long &rNeededPixel, bool &rLeftClip, bool &rRightClip)
Definition: output2.cxx:2297
void SetEditSyntaxColor(EditEngine &rEngine, const ScRefCellValue &rCell)
Definition: output2.cxx:919
void DrawRotated(bool bPixelToLogic)
Definition: output2.cxx:4541
bool IsEmptyCellText(const RowInfo *pThisRowInfo, SCCOL nX, SCROW nY)
Definition: output2.cxx:1118
double GetStretch() const
Definition: output2.cxx:839
void DrawEditStandard(DrawEditParam &rParam)
Definition: output2.cxx:2862
static void fillFont(vcl::Font &rFont, const SfxItemSet &rItemSet, ScAutoFontColorMode eAutoMode, const OutputDevice *pOutDev=nullptr, const Fraction *pScale=nullptr, const SfxItemSet *pCondSet=nullptr, SvtScriptType nScript=SvtScriptType::NONE, const Color *pBackConfigColor=nullptr, const Color *pTextConfigColor=nullptr)
Definition: patattr.cxx:250
void SetStyleSheet(ScStyleSheet *pNewStyle, bool bClearDirectFormat=true)
Definition: patattr.cxx:1306
sal_uInt32 GetNumberFormat(SvNumberFormatter *) const
Definition: patattr.cxx:1398
SfxItemSet & GetItemSet()
Definition: patattr.hxx:192
static void fillFontOnly(vcl::Font &rFont, const SfxItemSet &rItemSet, const OutputDevice *pOutDev=nullptr, const Fraction *pScale=nullptr, const SfxItemSet *pCondSet=nullptr, SvtScriptType nScript=SvtScriptType::NONE)
Static helper function to fill a font object from the passed item set.
Definition: patattr.cxx:266
const SfxPoolItem & GetItem(sal_uInt16 nWhichP) const
Definition: patattr.hxx:73
void FillEditItemSet(SfxItemSet *pEditSet, const SfxItemSet *pCondSet=nullptr) const
Converts all Calc items contained in the own item set to edit engine items and puts them into pEditSe...
Definition: patattr.cxx:868
static SvxCellOrientation GetCellOrientation(const SfxItemSet &rItemSet, const SfxItemSet *pCondSet)
Definition: patattr.cxx:188
static void DeleteInterpretProgress()
Definition: progress.cxx:152
static void CreateInterpretProgress(ScDocument *pDoc, bool bWait=true)
Definition: progress.cxx:132
bool GetHideFormula() const
Definition: attrib.hxx:150
bool GetHideCell() const
Definition: attrib.hxx:152
bool GetHidePrint() const
Definition: attrib.hxx:154
const WhichRangesContainer & GetRanges() const
SfxItemPool * GetPool() const
sal_uInt16 Count() const
SfxItemState GetItemState(sal_uInt16 nWhich, bool bSrchInParent=true, const SfxPoolItem **ppItem=nullptr) const
const SfxPoolItem * Put(const SfxPoolItem &rItem, sal_uInt16 nWhich)
const SfxPoolItem & Get(sal_uInt16 nWhich, bool bSrchInParent=true) const
constexpr tools::Long Height() const
tools::Long AdjustHeight(tools::Long n)
void setWidth(tools::Long nWidth)
tools::Long AdjustWidth(tools::Long n)
void setHeight(tools::Long nHeight)
constexpr tools::Long Width() const
bool GetHighContrastMode() const
SvNumFormatType GetType(sal_uInt32 nFIndex) const
const SvNumberformat * GetEntry(sal_uInt32 nKey) const
bool GetOutputString(double fNumber, sal_uInt16 nCharCount, OUString &rOutString) const
sal_Int16 GetRightMargin() const
sal_Int16 GetTopMargin() const
sal_Int16 GetBottomMargin() const
sal_Int16 GetLeftMargin() const
void reset(reference_type *pBody)
bool isMisspelled(SCCOL nCol, SCROW nRow) const
const std::vector< editeng::MisspellRanges > * getMisspellRanges(SCCOL nCol, SCROW nRow) const
ColorConfigValue GetColorValue(ColorConfigEntry eEntry, bool bSmart=true) const
bool HasCellRotation() const
constexpr tools::Long GetWidth() const
constexpr void SetLeft(tools::Long v)
constexpr void SetTop(tools::Long v)
constexpr tools::Long Top() const
constexpr Point TopLeft() const
constexpr void SetRight(tools::Long v)
constexpr tools::Long Right() const
tools::Long AdjustTop(tools::Long nVertMoveDelta)
tools::Long AdjustRight(tools::Long nHorzMoveDelta)
constexpr void SetBottom(tools::Long v)
constexpr tools::Long GetHeight() const
tools::Long AdjustBottom(tools::Long nVertMoveDelta)
tools::Long AdjustLeft(tools::Long nHorzMoveDelta)
constexpr tools::Long Left() const
constexpr tools::Long Bottom() const
tools::Long GetFontHeight() const
void SetOrientation(Degree10 nLineOrientation)
void SetColor(const Color &)
void SetFontHeight(tools::Long nHeight)
void SetKerning(FontKerning nKerning)
void SetAlignment(TextAlign)
std::vector< PDFExtOutDevBookmarkEntry > & GetBookmarks()
sal_Int32 CreateLink(const tools::Rectangle &rRect, OUString const &rAltText, sal_Int32 nPageNr=-1)
constexpr ::Color COL_AUTO(ColorTransparency, 0xFF, 0xFF, 0xFF, 0xFF)
constexpr double nPPTX
constexpr double nPPTY
double toRadians(D x)
URL aURL
float u
EEControlBits
constexpr TypedWhichId< SfxBoolItem > EE_PARA_HYPHENATE(EE_PARA_START+6)
constexpr TypedWhichId< SvxVerJustifyItem > EE_PARA_VER_JUST(EE_PARA_START+19)
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO_CJK(EE_CHAR_START+17)
constexpr TypedWhichId< SvxAdjustItem > EE_PARA_JUST(EE_PARA_START+16)
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT(EE_CHAR_START+2)
constexpr TypedWhichId< SvxColorItem > EE_CHAR_COLOR(EE_CHAR_START+0)
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT_CTL(EE_CHAR_START+20)
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO_CTL(EE_CHAR_START+18)
constexpr TypedWhichId< SvxJustifyMethodItem > EE_PARA_JUST_METHOD(EE_PARA_START+18)
constexpr TypedWhichId< SvxFontHeightItem > EE_CHAR_FONTHEIGHT_CJK(EE_CHAR_START+19)
constexpr TypedWhichId< SvxFontItem > EE_CHAR_FONTINFO(EE_CHAR_START+1)
static OString lcl_GetValue(sal_uInt8 nType, const XclExpString *pStr)
Definition: excrecds.cxx:580
const SCCOL SC_ROTMAX_NONE
Definition: fillinfo.hxx:189
const sal_uInt8 SC_CLIPMARK_SIZE
Definition: fillinfo.hxx:51
DocumentType eType
ALIGN_BASELINE
SvxFrameDirection
const sal_Unicode CHAR_RLM
Definition: global.hxx:71
CellType
Definition: global.hxx:272
@ CELLTYPE_EDIT
Definition: global.hxx:277
@ CELLTYPE_STRING
Definition: global.hxx:275
@ CELLTYPE_FORMULA
Definition: global.hxx:276
@ CELLTYPE_VALUE
Definition: global.hxx:274
const sal_Unicode CHAR_NBHY
Definition: global.hxx:72
const sal_Unicode CHAR_SHY
Definition: global.hxx:68
const sal_Unicode CHAR_NBSP
Definition: global.hxx:67
const sal_Unicode CHAR_LRM
Definition: global.hxx:70
const sal_Unicode CHAR_ZWSP
Definition: global.hxx:69
@ DIR_RIGHT
Definition: global.hxx:345
const sal_Unicode CHAR_WJ
Definition: global.hxx:73
sal_Int64 n
SvtScriptType
#define SAL_WARN_IF(condition, area, stream)
#define SAL_WARN(area, stream)
aStr
std::unique_ptr< sal_Int32[]> pData
const SfxPoolItem * GetItem(const SwTextAttr &rAttr, sal_uInt16 nWhich)
ItemType
OStringBuffer & padToLength(OStringBuffer &rBuffer, sal_Int32 nLength, char cFill='\0')
int i
constexpr Point convert(const Point &rPoint, o3tl::Length eFrom, o3tl::Length eTo)
const sal_Int32 nCellHeight
const sal_Int32 nCellWidth
long Long
const AutoFormatPatternEntry * mpPattern
OUTDEV_PRINTER
#define DRAWTEXT_MAX
Definition: output2.cxx:94
static void lcl_ScaleFonts(EditEngine &rEngine, tools::Long nPercent)
Definition: output2.cxx:2233
static SvxCellHorJustify getAlignmentFromContext(SvxCellHorJustify eInHorJust, bool bCellIsValue, const OUString &rText, const ScPatternAttr &rPattern, const SfxItemSet *pCondSet, const ScDocument *pDoc, SCTAB nTab, const bool bNumberFormatIsText)
Get left, right or centered alignment from RTL context.
Definition: output2.cxx:1432
static bool StringDiffer(const ScPatternAttr *&rpOldPattern, const ScPatternAttr *pNewPattern)
Definition: output2.cxx:1024
static tools::Long lcl_GetEditSize(EditEngine &rEngine, bool bWidth, bool bSwap, Degree100 nAttrRotate)
Definition: output2.cxx:2271
static bool lcl_SafeIsValue(ScRefCellValue &rCell)
Definition: output2.cxx:2212
constexpr auto HMM_PER_TWIPS
Definition: output2.cxx:97
static void lcl_DoHyperlinkResult(const OutputDevice *pDev, const tools::Rectangle &rRect, ScRefCellValue &rCell)
Definition: output2.cxx:867
static bool SameValue(const ScRefCellValue &rCell, const ScRefCellValue &rOldCell)
Definition: output2.cxx:493
static void lcl_ClearEdit(EditEngine &rEngine)
Definition: output2.cxx:2199
static bool lcl_isNumberFormatText(const ScDocument *pDoc, SCCOL nCellX, SCROW nCellY, SCTAB nTab)
Definition: output2.cxx:297
#define DROPDOWN_BITMAP_SIZE
Merge Autofilter width with column.cxx.
Definition: output2.cxx:92
static void lcl_SetEditColor(EditEngine &rEngine, const Color &rColor)
Definition: output2.cxx:910
const sal_uInt16 SC_SHRINKAGAIN_MAX
Definition: output2.cxx:96
static void lcl_CreateInterpretProgress(bool &bProgress, ScDocument *pDoc, const ScFormulaCell *pFCell)
Definition: output2.cxx:1101
static bool IsAmbiguousScript(SvtScriptType nScript)
Definition: output2.cxx:1111
std::unique_ptr< ClearableClipRegion, o3tl::default_delete< ClearableClipRegion > > ClearableClipRegionPtr
Definition: output.hxx:61
@ OUTTYPE_PRINTER
Definition: output.hxx:59
@ OUTTYPE_WINDOW
Definition: output.hxx:59
ScAutoFontColorMode
how to treat COL_AUTO in GetFont:
Definition: patattr.hxx:44
@ Print
black or white, depending on background
@ IgnoreAll
like DISPLAY, but ignore stored font and background colors
@ Display
from style settings, or black/white if needed
@ IgnoreBack
like DISPLAY, but ignore stored background color (use configured color)
@ IgnoreFont
like DISPLAY, but ignore stored font color (assume COL_AUTO)
SvxRotateMode
SVX_ROTATE_MODE_BOTTOM
SVX_ROTATE_MODE_STANDARD
SVX_ROTATE_MODE_CENTER
SVX_ROTATE_MODE_TOP
constexpr TypedWhichId< ScIndentItem > ATTR_INDENT(131)
constexpr TypedWhichId< SvxFontHeightItem > ATTR_FONT_HEIGHT(101)
constexpr TypedWhichId< SfxBoolItem > ATTR_VERTICAL_ASIAN(137)
constexpr TypedWhichId< SvxFontItem > ATTR_CJK_FONT(111)
constexpr TypedWhichId< ScMergeFlagAttr > ATTR_MERGE_FLAG(145)
constexpr TypedWhichId< SvxForbiddenRuleItem > ATTR_FORBIDDEN_RULES(128)
constexpr TypedWhichId< SvxPostureItem > ATTR_CTL_FONT_POSTURE(119)
constexpr TypedWhichId< SvxFontItem > ATTR_CTL_FONT(116)
constexpr TypedWhichId< SvxFontHeightItem > ATTR_CJK_FONT_HEIGHT(112)
constexpr TypedWhichId< SvxPostureItem > ATTR_FONT_POSTURE(103)
constexpr TypedWhichId< SvxWeightItem > ATTR_FONT_WEIGHT(102)
constexpr TypedWhichId< SvxColorItem > ATTR_FONT_COLOR(109)
constexpr TypedWhichId< SvxWeightItem > ATTR_CJK_FONT_WEIGHT(113)
constexpr TypedWhichId< SvxEmphasisMarkItem > ATTR_FONT_EMPHASISMARK(121)
constexpr TypedWhichId< ScShrinkToFitCell > ATTR_SHRINKTOFIT(140)
constexpr TypedWhichId< ScMergeAttr > ATTR_MERGE(144)
constexpr TypedWhichId< SvxShadowedItem > ATTR_FONT_SHADOWED(108)
constexpr TypedWhichId< SvxWordLineModeItem > ATTR_FONT_WORDLINE(123)
constexpr TypedWhichId< SvxContourItem > ATTR_FONT_CONTOUR(107)
constexpr TypedWhichId< SvxBrushItem > ATTR_BACKGROUND(148)
constexpr TypedWhichId< SvxOverlineItem > ATTR_FONT_OVERLINE(105)
constexpr TypedWhichId< ScRotateValueItem > ATTR_ROTATE_VALUE(135)
constexpr TypedWhichId< SvxJustifyMethodItem > ATTR_VER_JUSTIFY_METHOD(133)
constexpr TypedWhichId< SvxHorJustifyItem > ATTR_HOR_JUSTIFY(129)
constexpr TypedWhichId< SvxRotateModeItem > ATTR_ROTATE_MODE(136)
constexpr TypedWhichId< SvxJustifyMethodItem > ATTR_HOR_JUSTIFY_METHOD(130)
constexpr TypedWhichId< SvxCharReliefItem > ATTR_FONT_RELIEF(124)
constexpr TypedWhichId< SvxFrameDirectionItem > ATTR_WRITINGDIR(138)
constexpr TypedWhichId< SvxCrossedOutItem > ATTR_FONT_CROSSEDOUT(106)
constexpr TypedWhichId< SvxMarginItem > ATTR_MARGIN(143)
constexpr TypedWhichId< ScVerticalStackCell > ATTR_STACKED(134)
constexpr TypedWhichId< SvxVerJustifyItem > ATTR_VER_JUSTIFY(132)
constexpr TypedWhichId< SvxFontItem > ATTR_FONT(100)
constexpr TypedWhichId< ScProtectionAttr > ATTR_PROTECTION(149)
constexpr TypedWhichId< SvxWeightItem > ATTR_CTL_FONT_WEIGHT(118)
constexpr TypedWhichId< ScLineBreakCell > ATTR_LINEBREAK(139)
constexpr TypedWhichId< SvxPostureItem > ATTR_CJK_FONT_POSTURE(114)
constexpr TypedWhichId< SvxFontHeightItem > ATTR_CTL_FONT_HEIGHT(117)
constexpr TypedWhichId< SvxUnderlineItem > ATTR_FONT_UNDERLINE(104)
#define SC_MOD()
Definition: scmod.hxx:247
sal_uIntPtr sal_uLong
SCROW nRowNo
Definition: fillinfo.hxx:239
SCCOL nRotMaxCol
Definition: fillinfo.hxx:240
ScCellInfo & cellInfo(SCCOL nCol)
Definition: fillinfo.hxx:197
ScBasicCellInfo & basicCellInfo(SCCOL nCol)
Definition: fillinfo.hxx:210
sal_uInt16 nHeight
Definition: fillinfo.hxx:238
bool bChanged
Definition: fillinfo.hxx:245
sal_uInt16 nWidth
Definition: fillinfo.hxx:110
ScRotateDir nRotateDir
Definition: fillinfo.hxx:173
const SfxItemSet * pConditionSet
Definition: fillinfo.hxx:154
ScClipMark nClipMark
Definition: fillinfo.hxx:172
bool bHideGrid
Definition: fillinfo.hxx:183
ScRefCellValue maCell
Definition: fillinfo.hxx:151
bool bVOverlapped
Definition: fillinfo.hxx:177
const ScPatternAttr * pPatternAttr
Definition: fillinfo.hxx:153
bool bHOverlapped
Definition: fillinfo.hxx:176
const ScDataBarInfo * pDataBar
Definition: fillinfo.hxx:156
bool bAutoFilter
Definition: fillinfo.hxx:178
const ScIconSetInfo * pIconSet
Definition: fillinfo.hxx:157
bool mbShowValue
Definition: fillinfo.hxx:68
bool mbShowValue
Definition: fillinfo.hxx:96
bool mbLeftClip
length of the string getting cut off on the right.
Definition: output.hxx:109
tools::Rectangle maClipRect
Definition: output.hxx:105
tools::Long mnRightClipLength
length of the string getting cut off on the left.
Definition: output.hxx:108
tools::Rectangle maAlignRect
Definition: output.hxx:104
This is very similar to ScCellValue, except that it references the original value instead of copying ...
Definition: cellvalue.hxx:108
ScFormulaCell * getFormula() const
Definition: cellvalue.hxx:137
const EditTextObject * getEditText() const
Definition: cellvalue.hxx:136
double getDouble() const
Definition: cellvalue.hxx:134
bool isEmpty() const
Definition: cellvalue.cxx:667
bool hasNumeric() const
Definition: cellvalue.cxx:619
double getValue()
Definition: cellvalue.cxx:629
void assign(ScDocument &rDoc, const ScAddress &rPos)
Take cell value from specified position in specified document.
Definition: cellvalue.cxx:579
CellType getType() const
Definition: cellvalue.hxx:133
svx::frame::Array maArray
Definition: fillinfo.hxx:264
UNDERLYING_TYPE get() const
SvxCellJustifyMethod
SvxCellHorJustify
SvxCellVerJustify
SvxCellOrientation
SvxAdjust
sal_Int32 mnCellX
unsigned char sal_uInt8
sal_uInt16 sal_Unicode
sal_Int16 SCTAB
Definition: types.hxx:22
sal_Int16 SCCOL
Definition: types.hxx:21
sal_Int32 SCROW
Definition: types.hxx:17
#define SV_COUNTRY_LANGUAGE_OFFSET