Bug Summary

File:home/maarten/src/libreoffice/core/include/rtl/ref.hxx
Warning:line 192, column 9
Use of memory after it is freed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name output2.cxx -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mframe-pointer=all -fmath-errno -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/11.0.0 -isystem /usr/include/libxml2 -D BOOST_ERROR_CODE_HEADER_ONLY -D BOOST_SYSTEM_NO_DEPRECATED -D CPPU_ENV=gcc3 -D LINUX -D OSL_DEBUG_LEVEL=1 -D SAL_LOG_INFO -D SAL_LOG_WARN -D UNIX -D UNX -D X86_64 -D _PTHREADS -D _REENTRANT -D SC_DLLIMPLEMENTATION -D SC_INFO_OSVERSION="LINUX" -D SYSTEM_LIBXML -D EXCEPTIONS_ON -D LIBO_INTERNAL_ONLY -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/liborcus/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/mdds/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/i18n -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/icu/source/common -I /home/maarten/src/libreoffice/core/external/clew/source/include -I /home/maarten/src/libreoffice/core/external/boost/include -I /home/maarten/src/libreoffice/core/workdir/UnpackedTarball/boost -I /home/maarten/src/libreoffice/core/sc/source/core/inc -I /home/maarten/src/libreoffice/core/sc/source/filter/inc -I /home/maarten/src/libreoffice/core/sc/source/ui/inc -I /home/maarten/src/libreoffice/core/sc/inc -I /home/maarten/src/libreoffice/core/workdir/SdiTarget/sc/sdi -I /home/maarten/src/libreoffice/core/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include -I /usr/lib/jvm/java-11-openjdk-11.0.9.10-0.0.ea.fc33.x86_64/include/linux -I /home/maarten/src/libreoffice/core/config_host -I /home/maarten/src/libreoffice/core/workdir/CustomTarget/officecfg/registry -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/udkapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/offapi/normal -I /home/maarten/src/libreoffice/core/workdir/UnoApiHeadersTarget/oovbaapi/normal -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/10/../../../../include/c++/10/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/11.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wno-missing-braces -std=c++17 -fdeprecated-macro -fdebug-compilation-dir /home/maarten/src/libreoffice/core -ferror-limit 19 -fvisibility hidden -fvisibility-inlines-hidden -stack-protector 2 -fgnuc-version=4.2.1 -fcxx-exceptions -fexceptions -debug-info-kind=constructor -analyzer-output=html -faddrsig -o /home/maarten/tmp/wis/scan-build-libreoffice/output/report/2020-10-07-141433-9725-1 -x c++ /home/maarten/src/libreoffice/core/sc/source/ui/view/output2.cxx

/home/maarten/src/libreoffice/core/sc/source/ui/view/output2.cxx

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

/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx

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#ifndef INCLUDED_VCL_PTR_HXX
21#define INCLUDED_VCL_PTR_HXX
22
23#include <sal/config.h>
24
25#include <rtl/ref.hxx>
26
27#include <utility>
28#include <type_traits>
29
30#ifdef DBG_UTIL
31#ifndef _WIN32
32#include <vcl/vclmain.hxx>
33#endif
34#endif
35
36class VclReferenceBase;
37
38namespace vcl::detail {
39
40template<typename>
41constexpr bool isIncompleteOrDerivedFromVclReferenceBase(...) { return true; }
42
43template<typename T> constexpr bool isIncompleteOrDerivedFromVclReferenceBase(
44 int (*)[sizeof(T)])
45{ return std::is_base_of<VclReferenceBase, T>::value; }
46
47} // namespace vcl::detail
48
49/**
50 * A thin wrapper around rtl::Reference to implement the acquire and dispose semantics we want for references to vcl::Window subclasses.
51 *
52 * For more details on the design please see vcl/README.lifecycle
53 *
54 * @param reference_type must be a subclass of vcl::Window
55 */
56template <class reference_type>
57class VclPtr
58{
59 static_assert(
60 vcl::detail::isIncompleteOrDerivedFromVclReferenceBase<reference_type>(
61 nullptr),
62 "template argument type must be derived from VclReferenceBase");
63
64 ::rtl::Reference<reference_type> m_rInnerRef;
65
66public:
67 /** Constructor...
68 */
69 VclPtr()
70 : m_rInnerRef()
71 {}
72
73 /** Constructor...
74 */
75 VclPtr (reference_type * pBody)
76 : m_rInnerRef(pBody)
77 {}
78
79 /** Constructor... that doesn't take a ref.
80 */
81 VclPtr (reference_type * pBody, __sal_NoAcquire)
82 : m_rInnerRef(pBody, SAL_NO_ACQUIRE)
83 {}
84
85 /** Up-casting conversion constructor: Copies interface reference.
86
87 Does not work for up-casts to ambiguous bases. For the special case of
88 up-casting to Reference< XInterface >, see the corresponding conversion
89 operator.
90
91 @param rRef another reference
92 */
93 template< class derived_type >
94 VclPtr(
95 const VclPtr< derived_type > & rRef,
96 typename std::enable_if<
97 std::is_base_of<reference_type, derived_type>::value, int>::type
98 = 0 )
99 : m_rInnerRef( static_cast<reference_type*>(rRef) )
100 {
101 }
102
103#if defined(DBG_UTIL) && !defined(_WIN32)
104 virtual ~VclPtr()
105 {
106 assert(m_rInnerRef.get() == nullptr || vclmain::isAlive())(static_cast <bool> (m_rInnerRef.get() == nullptr || vclmain
::isAlive()) ? void (0) : __assert_fail ("m_rInnerRef.get() == nullptr || vclmain::isAlive()"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 106, __extension__ __PRETTY_FUNCTION__))
;
107 // We can be one of the intermediate counts, but if we are the last
108 // VclPtr keeping this object alive, then something forgot to call dispose().
109 assert((!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1)(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
110 && "someone forgot to call dispose()")(static_cast <bool> ((!m_rInnerRef.get() || m_rInnerRef
->isDisposed() || m_rInnerRef->getRefCount() > 1) &&
"someone forgot to call dispose()") ? void (0) : __assert_fail
("(!m_rInnerRef.get() || m_rInnerRef->isDisposed() || m_rInnerRef->getRefCount() > 1) && \"someone forgot to call dispose()\""
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 110, __extension__ __PRETTY_FUNCTION__))
;
111 }
112 VclPtr(VclPtr const &) = default;
113 VclPtr(VclPtr &&) = default;
114 VclPtr & operator =(VclPtr const &) = default;
115 VclPtr & operator =(VclPtr &&) = default;
116#endif
117
118 /**
119 * A construction helper for VclPtr. Since VclPtr types are created
120 * with a reference-count of one - to help fit into the existing
121 * code-flow; this helps us to construct them easily.
122 *
123 * For more details on the design please see vcl/README.lifecycle
124 *
125 * @tparam reference_type must be a subclass of vcl::Window
126 */
127 template<typename... Arg> [[nodiscard]] static VclPtr< reference_type > Create(Arg &&... arg)
128 {
129 return VclPtr< reference_type >( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE );
130 }
131
132 /** Probably most common used: handle->someBodyOp().
133 */
134 reference_type * operator->() const
135 {
136 return m_rInnerRef.get();
137 }
138
139 /** Get the body. Can be used instead of operator->().
140 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
141 are the same.
142 */
143 reference_type * get() const
144 {
145 return m_rInnerRef.get();
146 }
147
148 void set(reference_type *pBody)
149 {
150 m_rInnerRef.set(pBody);
151 }
152
153 void reset(reference_type *pBody)
154 {
155 m_rInnerRef.set(pBody);
36
Calling 'Reference::set'
40
Returning from 'Reference::set'
156 }
157
158 /** Up-casting copy assignment operator.
159
160 Does not work for up-casts to ambiguous bases.
161
162 @param rRef another reference
163 */
164 template<typename derived_type>
165 typename std::enable_if<
166 std::is_base_of<reference_type, derived_type>::value,
167 VclPtr &>::type
168 operator =(VclPtr<derived_type> const & rRef)
169 {
170 m_rInnerRef.set(rRef.get());
171 return *this;
172 }
173
174 VclPtr & operator =(reference_type * pBody)
175 {
176 m_rInnerRef.set(pBody);
177 return *this;
178 }
179
180 operator reference_type * () const
181 {
182 return m_rInnerRef.get();
68
Calling 'Reference::get'
183 }
184
185 explicit operator bool () const
186 {
187 return m_rInnerRef.get() != nullptr;
188 }
189
190 void clear()
191 {
192 m_rInnerRef.clear();
193 }
194
195 void reset()
196 {
197 m_rInnerRef.clear();
198 }
199
200 void disposeAndClear()
201 {
202 // hold it alive for the lifetime of this method
203 ::rtl::Reference<reference_type> aTmp(m_rInnerRef);
204 m_rInnerRef.clear(); // we should use some 'swap' method ideally ;-)
205 if (aTmp.get()) {
206 aTmp->disposeOnce();
207 }
208 }
209
210 /** Needed to place VclPtr's into STL collection.
211 */
212 bool operator< (const VclPtr<reference_type> & handle) const
213 {
214 return (m_rInnerRef < handle.m_rInnerRef);
215 }
216}; // class VclPtr
217
218template<typename T1, typename T2>
219inline bool operator ==(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
220 return p1.get() == p2.get();
221}
222
223template<typename T> inline bool operator ==(VclPtr<T> const & p1, T const * p2)
224{
225 return p1.get() == p2;
226}
227
228template<typename T> inline bool operator ==(VclPtr<T> const & p1, T * p2) {
229 return p1.get() == p2;
230}
231
232template<typename T> inline bool operator ==(T const * p1, VclPtr<T> const & p2)
233{
234 return p1 == p2.get();
235}
236
237template<typename T> inline bool operator ==(T * p1, VclPtr<T> const & p2) {
238 return p1 == p2.get();
239}
240
241template<typename T1, typename T2>
242inline bool operator !=(VclPtr<T1> const & p1, VclPtr<T2> const & p2) {
243 return !(p1 == p2);
244}
245
246template<typename T> inline bool operator !=(VclPtr<T> const & p1, T const * p2)
247{
248 return !(p1 == p2);
249}
250
251template<typename T> inline bool operator !=(VclPtr<T> const & p1, T * p2) {
252 return !(p1 == p2);
253}
254
255template<typename T> inline bool operator !=(T const * p1, VclPtr<T> const & p2)
256{
257 return !(p1 == p2);
258}
259
260template<typename T> inline bool operator !=(T * p1, VclPtr<T> const & p2) {
261 return !(p1 == p2);
262}
263
264/**
265 * A construction helper for a temporary VclPtr. Since VclPtr types
266 * are created with a reference-count of one - to help fit into
267 * the existing code-flow; this helps us to construct them easily.
268 * see also VclPtr::Create and ScopedVclPtr
269 *
270 * For more details on the design please see vcl/README.lifecycle
271 *
272 * @param reference_type must be a subclass of vcl::Window
273 */
274template <class reference_type>
275class SAL_WARN_UNUSED__attribute__((warn_unused)) VclPtrInstance final : public VclPtr<reference_type>
276{
277public:
278 template<typename... Arg> VclPtrInstance(Arg &&... arg)
279 : VclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
280 {
281 }
282
283 /**
284 * Override and disallow this, to prevent people accidentally calling it and actually
285 * getting VclPtr::Create and getting a naked VclPtr<> instance
286 */
287 template<typename... Arg> static VclPtrInstance< reference_type > Create(Arg &&... ) = delete;
288};
289
290template <class reference_type>
291class ScopedVclPtr : public VclPtr<reference_type>
292{
293public:
294 /** Constructor...
295 */
296 ScopedVclPtr()
297 : VclPtr<reference_type>()
298 {}
299
300 /** Constructor
301 */
302 ScopedVclPtr (reference_type * pBody)
303 : VclPtr<reference_type>(pBody)
304 {}
305
306 /** Copy constructor...
307 */
308 ScopedVclPtr (const VclPtr<reference_type> & handle)
309 : VclPtr<reference_type>(handle)
310 {}
311
312 /**
313 Assignment that releases the last reference.
314 */
315 void disposeAndReset(reference_type *pBody)
316 {
317 if (pBody != this->get()) {
318 VclPtr<reference_type>::disposeAndClear();
319 VclPtr<reference_type>::set(pBody);
320 }
321 }
322
323 /**
324 Assignment that releases the last reference.
325 */
326 ScopedVclPtr<reference_type>& operator = (reference_type * pBody)
327 {
328 disposeAndReset(pBody);
329 return *this;
330 }
331
332 /** Up-casting conversion constructor: Copies interface reference.
333
334 Does not work for up-casts to ambiguous bases. For the special case of
335 up-casting to Reference< XInterface >, see the corresponding conversion
336 operator.
337
338 @param rRef another reference
339 */
340 template< class derived_type >
341 ScopedVclPtr(
342 const VclPtr< derived_type > & rRef,
343 typename std::enable_if<
344 std::is_base_of<reference_type, derived_type>::value, int>::type
345 = 0 )
346 : VclPtr<reference_type>( rRef )
347 {
348 }
349
350 /** Up-casting assignment operator.
351
352 Does not work for up-casts to ambiguous bases.
353
354 @param rRef another VclPtr
355 */
356 template<typename derived_type>
357 typename std::enable_if<
358 std::is_base_of<reference_type, derived_type>::value,
359 ScopedVclPtr &>::type
360 operator =(VclPtr<derived_type> const & rRef)
361 {
362 disposeAndReset(rRef.get());
363 return *this;
364 }
365
366 /**
367 * Override and disallow this, to prevent people accidentally calling it and actually
368 * getting VclPtr::Create and getting a naked VclPtr<> instance
369 */
370 template<typename... Arg> static ScopedVclPtr< reference_type > Create(Arg &&... ) = delete;
371
372 ~ScopedVclPtr()
373 {
374 VclPtr<reference_type>::disposeAndClear();
375 assert(VclPtr<reference_type>::get() == nullptr)(static_cast <bool> (VclPtr<reference_type>::get(
) == nullptr) ? void (0) : __assert_fail ("VclPtr<reference_type>::get() == nullptr"
, "/home/maarten/src/libreoffice/core/include/vcl/vclptr.hxx"
, 375, __extension__ __PRETTY_FUNCTION__))
; // make sure there are no lingering references
376 }
377
378private:
379 // Most likely we don't want this default copy-constructor.
380 ScopedVclPtr (const ScopedVclPtr<reference_type> &) = delete;
381 // And certainly we don't want a default assignment operator.
382 ScopedVclPtr<reference_type>& operator = (const ScopedVclPtr<reference_type> &) = delete;
383 // And disallow reset as that doesn't call disposeAndClear on the original reference
384 void reset() = delete;
385 void reset(reference_type *pBody) = delete;
386
387protected:
388 ScopedVclPtr (reference_type * pBody, __sal_NoAcquire)
389 : VclPtr<reference_type>(pBody, SAL_NO_ACQUIRE)
390 {}
391};
392
393/**
394 * A construction helper for ScopedVclPtr. Since VclPtr types are created
395 * with a reference-count of one - to help fit into the existing
396 * code-flow; this helps us to construct them easily.
397 *
398 * For more details on the design please see vcl/README.lifecycle
399 *
400 * @param reference_type must be a subclass of vcl::Window
401 */
402#if defined _MSC_VER
403#pragma warning(push)
404#pragma warning(disable: 4521) // " multiple copy constructors specified"
405#endif
406template <class reference_type>
407class SAL_WARN_UNUSED__attribute__((warn_unused)) ScopedVclPtrInstance final : public ScopedVclPtr<reference_type>
408{
409public:
410 template<typename... Arg> ScopedVclPtrInstance(Arg &&... arg)
411 : ScopedVclPtr<reference_type>( new reference_type(std::forward<Arg>(arg)...), SAL_NO_ACQUIRE )
412 {
413 }
414
415 /**
416 * Override and disallow this, to prevent people accidentally calling it and actually
417 * getting VclPtr::Create and getting a naked VclPtr<> instance
418 */
419 template<typename... Arg> static ScopedVclPtrInstance< reference_type > Create(Arg &&...) = delete;
420
421private:
422 // Prevent the above perfect forwarding ctor from hijacking (accidental)
423 // attempts at ScopedVclPtrInstance copy construction (where the hijacking
424 // would typically lead to somewhat obscure error messages); both non-const
425 // and const variants are needed here, as the ScopedVclPtr base class has a
426 // const--variant copy ctor, so the implicitly declared copy ctor for
427 // ScopedVclPtrInstance would also be the const variant, so non-const copy
428 // construction attempts would be hijacked by the perfect forwarding ctor;
429 // but if we only declared a non-const variant here, the const variant would
430 // no longer be implicitly declared (as there would already be an explicitly
431 // declared copy ctor), so const copy construction attempts would then be
432 // hijacked by the perfect forwarding ctor:
433 ScopedVclPtrInstance(ScopedVclPtrInstance &) = delete;
434 ScopedVclPtrInstance(ScopedVclPtrInstance const &) = delete;
435};
436#if defined _MSC_VER
437#pragma warning(pop)
438#endif
439
440#endif // INCLUDED_VCL_PTR_HXX
441
442/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/rtl/ref.hxx

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#ifndef INCLUDED_RTL_REF_HXX
21#define INCLUDED_RTL_REF_HXX
22
23#include "sal/config.h"
24
25#include <cassert>
26#include <cstddef>
27#include <functional>
28#ifdef LIBO_INTERNAL_ONLY1
29#include <type_traits>
30#endif
31
32#include "sal/types.h"
33
34namespace rtl
35{
36
37/** Template reference class for reference type.
38*/
39template <class reference_type>
40class Reference
41{
42 /** The <b>reference_type</b> body pointer.
43 */
44 reference_type * m_pBody;
45
46
47public:
48 /** Constructor...
49 */
50 Reference()
51 : m_pBody (NULL__null)
52 {}
53
54
55 /** Constructor...
56 */
57 Reference (reference_type * pBody, __sal_NoAcquire)
58 : m_pBody (pBody)
59 {
60 }
61
62 /** Constructor...
63 */
64 Reference (reference_type * pBody)
65 : m_pBody (pBody)
66 {
67 if (m_pBody)
68 m_pBody->acquire();
69 }
70
71 /** Copy constructor...
72 */
73 Reference (const Reference<reference_type> & handle)
74 : m_pBody (handle.m_pBody)
75 {
76 if (m_pBody)
77 m_pBody->acquire();
78 }
79
80#ifdef LIBO_INTERNAL_ONLY1
81 /** Move constructor...
82 */
83 Reference (Reference<reference_type> && handle) noexcept
84 : m_pBody (handle.m_pBody)
85 {
86 handle.m_pBody = nullptr;
87 }
88#endif
89
90#if defined LIBO_INTERNAL_ONLY1
91 /** Up-casting conversion constructor: Copies interface reference.
92
93 Does not work for up-casts to ambiguous bases.
94
95 @param rRef another reference
96 */
97 template< class derived_type >
98 inline Reference(
99 const Reference< derived_type > & rRef,
100 std::enable_if_t<std::is_base_of_v<reference_type, derived_type>, int> = 0 )
101 : m_pBody (rRef.get())
102 {
103 if (m_pBody)
104 m_pBody->acquire();
105 }
106#endif
107
108 /** Destructor...
109 */
110 ~Reference() COVERITY_NOEXCEPT_FALSE
111 {
112 if (m_pBody
57.1
Field 'm_pBody' is non-null
57.1
Field 'm_pBody' is non-null
57.1
Field 'm_pBody' is non-null
57.1
Field 'm_pBody' is non-null
)
58
Taking true branch
113 m_pBody->release();
59
Calling 'VclReferenceBase::release'
63
Returning; memory was released
114 }
115
116 /** Set...
117 Similar to assignment.
118 */
119 Reference<reference_type> &
120 SAL_CALL set (reference_type * pBody)
121 {
122 if (pBody)
37
Assuming 'pBody' is non-null
38
Taking true branch
123 pBody->acquire();
124 reference_type * const pOld = m_pBody;
125 m_pBody = pBody;
126 if (pOld
38.1
'pOld' is null
38.1
'pOld' is null
38.1
'pOld' is null
38.1
'pOld' is null
)
39
Taking false branch
127 pOld->release();
128 return *this;
129 }
130
131 /** Assignment.
132 Unbinds this instance from its body (if bound) and
133 bind it to the body represented by the handle.
134 */
135 Reference<reference_type> &
136 SAL_CALL operator= (const Reference<reference_type> & handle)
137 {
138 return set( handle.m_pBody );
139 }
140
141#ifdef LIBO_INTERNAL_ONLY1
142 /** Assignment.
143 * Unbinds this instance from its body (if bound),
144 * bind it to the body represented by the handle, and
145 * set the body represented by the handle to nullptr.
146 */
147 Reference<reference_type> &
148 operator= (Reference<reference_type> && handle)
149 {
150 // self-movement guts ourself
151 if (m_pBody)
152 m_pBody->release();
153 m_pBody = handle.m_pBody;
154 handle.m_pBody = nullptr;
155 return *this;
156 }
157#endif
158
159 /** Assignment...
160 */
161 Reference<reference_type> &
162 SAL_CALL operator= (reference_type * pBody)
163 {
164 return set( pBody );
165 }
166
167 /** Unbind the body from this handle.
168 Note that for a handle representing a large body,
169 "handle.clear().set(new body());" _might_
170 perform a little bit better than "handle.set(new body());",
171 since in the second case two large objects exist in memory
172 (the old body and the new body).
173 */
174 Reference<reference_type> & SAL_CALL clear()
175 {
176 if (m_pBody)
177 {
178 reference_type * const pOld = m_pBody;
179 m_pBody = NULL__null;
180 pOld->release();
181 }
182 return *this;
183 }
184
185
186 /** Get the body. Can be used instead of operator->().
187 I.e. handle->someBodyOp() and handle.get()->someBodyOp()
188 are the same.
189 */
190 reference_type * SAL_CALL get() const
191 {
192 return m_pBody;
69
Use of memory after it is freed
193 }
194
195
196 /** Probably most common used: handle->someBodyOp().
197 */
198 reference_type * SAL_CALL operator->() const
199 {
200 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 200, __extension__ __PRETTY_FUNCTION__))
;
201 return m_pBody;
202 }
203
204
205 /** Allows (*handle).someBodyOp().
206 */
207 reference_type & SAL_CALL operator*() const
208 {
209 assert(m_pBody != NULL)(static_cast <bool> (m_pBody != __null) ? void (0) : __assert_fail
("m_pBody != NULL", "/home/maarten/src/libreoffice/core/include/rtl/ref.hxx"
, 209, __extension__ __PRETTY_FUNCTION__))
;
210 return *m_pBody;
211 }
212
213
214 /** Returns True if the handle does point to a valid body.
215 */
216 bool SAL_CALL is() const
217 {
218 return (m_pBody != NULL__null);
219 }
220
221#if defined LIBO_INTERNAL_ONLY1
222 /** Returns True if the handle does point to a valid body.
223 */
224 explicit operator bool() const
225 {
226 return is();
227 }
228#endif
229
230 /** Returns True if this points to pBody.
231 */
232 bool SAL_CALL operator== (const reference_type * pBody) const
233 {
234 return (m_pBody == pBody);
235 }
236
237
238 /** Returns True if handle points to the same body.
239 */
240 bool
241 SAL_CALL operator== (const Reference<reference_type> & handle) const
242 {
243 return (m_pBody == handle.m_pBody);
244 }
245
246
247 /** Needed to place References into STL collection.
248 */
249 bool
250 SAL_CALL operator!= (const Reference<reference_type> & handle) const
251 {
252 return (m_pBody != handle.m_pBody);
253 }
254
255
256 /** Needed to place References into STL collection.
257 */
258 bool
259 SAL_CALL operator< (const Reference<reference_type> & handle) const
260 {
261 return (m_pBody < handle.m_pBody);
262 }
263
264
265 /** Needed to place References into STL collection.
266 */
267 bool
268 SAL_CALL operator> (const Reference<reference_type> & handle) const
269 {
270 return (m_pBody > handle.m_pBody);
271 }
272};
273
274} // namespace rtl
275
276#if defined LIBO_INTERNAL_ONLY1
277namespace std
278{
279
280/// @cond INTERNAL
281/**
282 Make rtl::Reference hashable by default for use in STL containers.
283
284 @since LibreOffice 6.3
285*/
286template<typename T>
287struct hash<::rtl::Reference<T>>
288{
289 std::size_t operator()(::rtl::Reference<T> const & s) const
290 { return std::size_t(s.get()); }
291};
292/// @endcond
293
294}
295
296#endif
297
298#endif /* ! INCLUDED_RTL_REF_HXX */
299
300/* vim:set shiftwidth=4 softtabstop=4 expandtab: */

/home/maarten/src/libreoffice/core/include/vcl/vclreferencebase.hxx

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#ifndef INCLUDED_VCL_Reference_HXX
20#define INCLUDED_VCL_Reference_HXX
21
22#include <vcl/dllapi.h>
23#include <osl/interlck.h>
24
25class VCL_DLLPUBLIC__attribute__ ((visibility("default"))) VclReferenceBase
26{
27 mutable oslInterlockedCount mnRefCnt;
28
29 template<typename T> friend class VclPtr;
30
31public:
32 void acquire() const
33 {
34 osl_atomic_increment(&mnRefCnt)__sync_add_and_fetch((&mnRefCnt), 1);
35 }
36
37 void release() const
38 {
39 if (osl_atomic_decrement(&mnRefCnt)__sync_sub_and_fetch((&mnRefCnt), 1) == 0)
60
Assuming the condition is true
61
Taking true branch
40 delete this;
62
Memory is released
41 }
42#ifdef DBG_UTIL
43#ifndef _WIN32
44 sal_Int32 getRefCount() const { return mnRefCnt; }
45#endif
46#endif
47
48
49private:
50 VclReferenceBase(const VclReferenceBase&) = delete;
51 VclReferenceBase& operator=(const VclReferenceBase&) = delete;
52
53 bool mbDisposed : 1;
54
55protected:
56 VclReferenceBase();
57protected:
58 virtual ~VclReferenceBase();
59
60protected:
61 virtual void dispose();
62
63public:
64 void disposeOnce();
65 bool isDisposed() const { return mbDisposed; }
66
67};
68#endif