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