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