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 <hintids.hxx>
21 :
22 : #include <com/sun/star/i18n/ScriptType.hpp>
23 : #include <vcl/graph.hxx>
24 : #include <editeng/brushitem.hxx>
25 : #include <vcl/metric.hxx>
26 : #include <vcl/outdev.hxx>
27 : #include <viewopt.hxx>
28 : #include <SwPortionHandler.hxx>
29 : #include <porlay.hxx>
30 : #include <porfld.hxx>
31 : #include <inftxt.hxx>
32 : #include <blink.hxx>
33 : #include <frmtool.hxx>
34 : #include <viewsh.hxx>
35 : #include <docsh.hxx>
36 : #include <doc.hxx>
37 : #include <IDocumentSettingAccess.hxx>
38 : #include "rootfrm.hxx"
39 : #include <breakit.hxx>
40 : #include <porrst.hxx>
41 : #include <porftn.hxx>
42 : #include <accessibilityoptions.hxx>
43 : #include <editeng/lrspitem.hxx>
44 : #include <unicode/ubidi.h>
45 :
46 : using namespace ::com::sun::star;
47 :
48 23234 : SwLinePortion *SwFldPortion::Compress()
49 23234 : { return (GetLen() || !aExpand.isEmpty() || SwLinePortion::Compress()) ? this : 0; }
50 :
51 364 : SwFldPortion *SwFldPortion::Clone( const OUString &rExpand ) const
52 : {
53 : SwFont *pNewFnt;
54 364 : if( 0 != ( pNewFnt = pFnt ) )
55 : {
56 336 : pNewFnt = new SwFont( *pFnt );
57 : }
58 : // #i107143#
59 : // pass placeholder property to created <SwFldPortion> instance.
60 364 : SwFldPortion* pClone = new SwFldPortion( rExpand, pNewFnt, bPlaceHolder );
61 364 : pClone->SetNextOffset( nNextOffset );
62 364 : pClone->m_bNoLength = this->m_bNoLength;
63 364 : return pClone;
64 : }
65 :
66 0 : void SwFldPortion::TakeNextOffset( const SwFldPortion* pFld )
67 : {
68 : OSL_ENSURE( pFld, "TakeNextOffset: Missing Source" );
69 0 : nNextOffset = pFld->GetNextOffset();
70 0 : aExpand = aExpand.replaceAt( 0, nNextOffset, "" );
71 0 : bFollow = true;
72 0 : }
73 :
74 23286 : SwFldPortion::SwFldPortion( const OUString &rExpand, SwFont *pFont, bool bPlaceHold )
75 : : aExpand(rExpand), pFnt(pFont), nNextOffset(0), nNextScriptChg(COMPLETE_STRING), nViewWidth(0)
76 : , bFollow( false ), bLeft( false), bHide( false)
77 : , bCenter (false), bHasFollow( false )
78 : , bAnimated( false), bNoPaint( false)
79 : , bReplace( false), bPlaceHolder( bPlaceHold )
80 : , m_bNoLength( false )
81 23286 : , m_nAttrFldType(0)
82 : {
83 23286 : SetWhichPor( POR_FLD );
84 23286 : }
85 :
86 10 : SwFldPortion::SwFldPortion( const SwFldPortion& rFld )
87 : : SwExpandPortion( rFld )
88 : , aExpand( rFld.GetExp() )
89 10 : , nNextOffset( rFld.GetNextOffset() )
90 10 : , nNextScriptChg( rFld.GetNextScriptChg() )
91 : , nViewWidth( rFld.nViewWidth )
92 10 : , bFollow( rFld.IsFollow() )
93 10 : , bLeft( rFld.IsLeft() )
94 10 : , bHide( rFld.IsHide() )
95 10 : , bCenter( rFld.IsCenter() )
96 10 : , bHasFollow( rFld.HasFollow() )
97 : , bAnimated ( rFld.bAnimated )
98 : , bNoPaint( rFld.bNoPaint)
99 : , bReplace( rFld.bReplace )
100 : , bPlaceHolder( rFld.bPlaceHolder )
101 : , m_bNoLength( rFld.m_bNoLength )
102 80 : , m_nAttrFldType( rFld.m_nAttrFldType)
103 : {
104 10 : if ( rFld.HasFont() )
105 10 : pFnt = new SwFont( *rFld.GetFont() );
106 : else
107 0 : pFnt = 0;
108 :
109 10 : SetWhichPor( POR_FLD );
110 10 : }
111 :
112 52800 : SwFldPortion::~SwFldPortion()
113 : {
114 23296 : delete pFnt;
115 23296 : if( pBlink )
116 136 : pBlink->Delete( this );
117 29504 : }
118 :
119 1028 : sal_uInt16 SwFldPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
120 : {
121 : // even though this is const, nViewWidth should be computed at the very end:
122 1028 : SwFldPortion* pThis = (SwFldPortion*)this;
123 4112 : if( !Width() && rInf.OnWin() && !rInf.GetOpt().IsPagePreview() &&
124 3084 : !rInf.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
125 : {
126 1028 : if( !nViewWidth )
127 474 : pThis->nViewWidth = rInf.GetTxtSize(OUString(' ')).Width();
128 : }
129 : else
130 0 : pThis->nViewWidth = 0;
131 1028 : return nViewWidth;
132 : }
133 :
134 : // 8653: in keinem Fall nur SetLen(0);
135 :
136 : class SwFldSlot
137 : {
138 : const OUString *pOldTxt;
139 : OUString aTxt;
140 : sal_Int32 nIdx;
141 : sal_Int32 nLen;
142 : SwTxtFormatInfo *pInf;
143 : bool bOn;
144 : public:
145 : SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor );
146 : ~SwFldSlot();
147 : };
148 :
149 22944 : SwFldSlot::SwFldSlot( const SwTxtFormatInfo* pNew, const SwFldPortion *pPor )
150 : : pOldTxt(NULL)
151 : , nIdx(0)
152 : , nLen(0)
153 22944 : , pInf(NULL)
154 : {
155 22944 : bOn = pPor->GetExpTxt( *pNew, aTxt );
156 :
157 : // Der Text wird ausgetauscht...
158 22944 : if( bOn )
159 : {
160 22944 : pInf = (SwTxtFormatInfo*)pNew;
161 22944 : nIdx = pInf->GetIdx();
162 22944 : nLen = pInf->GetLen();
163 22944 : pOldTxt = &(pInf->GetTxt());
164 22944 : pInf->SetLen( aTxt.getLength() );
165 22944 : if( pPor->IsFollow() )
166 : {
167 8366 : pInf->SetFakeLineStart( nIdx > pInf->GetLineStart() );
168 8366 : pInf->SetIdx( 0 );
169 : }
170 : else
171 : {
172 14578 : aTxt = (*pOldTxt).replaceAt(nIdx, 1, aTxt);
173 : }
174 22944 : pInf->SetTxt( aTxt );
175 : }
176 22944 : }
177 :
178 45888 : SwFldSlot::~SwFldSlot()
179 : {
180 22944 : if( bOn )
181 : {
182 22944 : pInf->SetTxt( *pOldTxt );
183 22944 : pInf->SetIdx( nIdx );
184 22944 : pInf->SetLen( nLen );
185 22944 : pInf->SetFakeLineStart( false );
186 : }
187 22944 : }
188 :
189 22944 : void SwFldPortion::CheckScript( const SwTxtSizeInfo &rInf )
190 : {
191 22944 : OUString aTxt;
192 22944 : if( GetExpTxt( rInf, aTxt ) && !aTxt.isEmpty() && g_pBreakIt->GetBreakIter().is() )
193 : {
194 14402 : sal_uInt8 nActual = pFnt ? pFnt->GetActual() : rInf.GetFont()->GetActual();
195 14402 : sal_uInt16 nScript = g_pBreakIt->GetBreakIter()->getScriptType( aTxt, 0 );
196 14402 : sal_Int32 nChg = 0;
197 14402 : if( i18n::ScriptType::WEAK == nScript )
198 : {
199 6148 : nChg = g_pBreakIt->GetBreakIter()->endOfScript(aTxt,0,nScript);
200 6148 : if (nChg < aTxt.getLength() && nChg >= 0)
201 6030 : nScript = g_pBreakIt->GetBreakIter()->getScriptType( aTxt, nChg );
202 : }
203 :
204 : // nNextScriptChg will be evaluated during SwFldPortion::Format()
205 :
206 14402 : if (nChg < aTxt.getLength() && nChg >= 0)
207 14284 : nNextScriptChg = g_pBreakIt->GetBreakIter()->endOfScript( aTxt, nChg, nScript );
208 : else
209 118 : nNextScriptChg = aTxt.getLength();
210 :
211 : sal_uInt8 nTmp;
212 14402 : switch ( nScript ) {
213 14248 : case i18n::ScriptType::LATIN : nTmp = SW_LATIN; break;
214 0 : case i18n::ScriptType::ASIAN : nTmp = SW_CJK; break;
215 36 : case i18n::ScriptType::COMPLEX : nTmp = SW_CTL; break;
216 118 : default: nTmp = nActual;
217 : }
218 :
219 : // #i16354# Change script type for RTL text to CTL.
220 14402 : const SwScriptInfo& rSI = rInf.GetParaPortion()->GetScriptInfo();
221 : // #i98418#
222 26454 : const sal_uInt8 nFldDir = ( IsNumberPortion() || IsFtnNumPortion() ) ?
223 : rSI.GetDefaultDir() :
224 16988 : rSI.DirType( IsFollow() ? rInf.GetIdx() - 1 : rInf.GetIdx() );
225 :
226 14402 : bool bPerformUBA = UBIDI_LTR != nFldDir || i18n::ScriptType::COMPLEX == nScript;
227 14402 : if (bPerformUBA)
228 : {
229 36 : UErrorCode nError = U_ZERO_ERROR;
230 36 : UBiDi* pBidi = ubidi_openSized( aTxt.getLength(), 0, &nError );
231 36 : ubidi_setPara( pBidi, reinterpret_cast<const UChar *>(aTxt.getStr()), aTxt.getLength(), nFldDir, NULL, &nError );
232 : int32_t nEnd;
233 : UBiDiLevel nCurrDir;
234 36 : ubidi_getLogicalRun( pBidi, 0, &nEnd, &nCurrDir );
235 36 : ubidi_close( pBidi );
236 36 : const sal_Int32 nNextDirChg = nEnd;
237 36 : nNextScriptChg = std::min( nNextScriptChg, nNextDirChg );
238 :
239 : // #i89825# change the script type also to CTL
240 : // if there is no strong LTR char in the LTR run (numbers)
241 36 : if ( nCurrDir != UBIDI_RTL )
242 : {
243 0 : nCurrDir = UBIDI_RTL;
244 0 : for( sal_Int32 nCharIdx = 0; nCharIdx < nEnd; ++nCharIdx )
245 : {
246 0 : UCharDirection nCharDir = u_charDirection ( aTxt[ nCharIdx ]);
247 0 : if ( nCharDir == U_LEFT_TO_RIGHT ||
248 0 : nCharDir == U_LEFT_TO_RIGHT_EMBEDDING ||
249 : nCharDir == U_LEFT_TO_RIGHT_OVERRIDE )
250 : {
251 0 : nCurrDir = UBIDI_LTR;
252 0 : break;
253 : }
254 : }
255 : }
256 :
257 36 : if (nCurrDir == UBIDI_RTL)
258 : {
259 36 : nTmp = SW_CTL;
260 : //If we decided that this range was RTL after all and the
261 : //previous range was complex but clipped to the start of this
262 : //range, then extend it to be complex over the additional RTL
263 : //range
264 36 : if (nScript == i18n::ScriptType::COMPLEX)
265 36 : nNextScriptChg = nNextDirChg;
266 : }
267 : }
268 :
269 : // #i98418#
270 : // keep determined script type for footnote portions as preferred script type.
271 : // For footnote portions a font can not be created directly - see footnote
272 : // portion format method.
273 14402 : if ( IsFtnPortion() )
274 : {
275 278 : static_cast<SwFtnPortion*>(this)->SetPreferredScriptType( nTmp );
276 : }
277 14124 : else if ( nTmp != nActual )
278 : {
279 72 : if( !pFnt )
280 0 : pFnt = new SwFont( *rInf.GetFont() );
281 72 : pFnt->SetActual( nTmp );
282 : }
283 22944 : }
284 22944 : }
285 :
286 22944 : bool SwFldPortion::Format( SwTxtFormatInfo &rInf )
287 : {
288 : // Scope wegen aDiffTxt::DTOR!
289 : sal_Int32 nRest;
290 22944 : bool bFull = false;
291 22944 : bool bEOL = false;
292 22944 : const sal_Int32 nTxtRest = rInf.GetTxt().getLength() - rInf.GetIdx();
293 : {
294 22944 : SwFldSlot aDiffTxt( &rInf, this );
295 45888 : SwLayoutModeModifier aLayoutModeModifier( *rInf.GetOut() );
296 22944 : aLayoutModeModifier.SetAuto();
297 :
298 : // Field portion has to be split in several parts if
299 : // 1. There are script/direction changes inside the field
300 : // 2. There are portion breaks (tab, break) inside the field:
301 22944 : const sal_Int32 nOldFullLen = rInf.GetLen();
302 22944 : sal_Int32 nFullLen = rInf.ScanPortionEnd( rInf.GetIdx(), rInf.GetIdx() + nOldFullLen ) - rInf.GetIdx();
303 22944 : if ( nNextScriptChg < nFullLen )
304 : {
305 36 : nFullLen = nNextScriptChg;
306 36 : rInf.SetHookChar( 0 );
307 : }
308 22944 : rInf.SetLen( nFullLen );
309 :
310 22944 : if ( COMPLETE_STRING != rInf.GetUnderScorePos() &&
311 0 : rInf.GetUnderScorePos() > rInf.GetIdx() )
312 0 : rInf.SetUnderScorePos( rInf.GetIdx() );
313 :
314 22944 : if( pFnt )
315 16878 : pFnt->GoMagic( rInf.GetVsh(), pFnt->GetActual() );
316 :
317 45888 : SwFontSave aSave( rInf, pFnt );
318 :
319 : // 8674: Laenge muss 0 sein, bei bFull nach Format ist die Laenge
320 : // gesetzt und wird in nRest uebertragen. Ansonsten bleibt die
321 : // Laenge erhalten und wuerde auch in nRest einfliessen!
322 22944 : SetLen(0);
323 22944 : const sal_Int32 nFollow = IsFollow() ? 0 : 1;
324 :
325 : // So komisch es aussieht, die Abfrage auf GetLen() muss wegen der
326 : // ExpandPortions _hinter_ aDiffTxt (vgl. SoftHyphs)
327 : // false returnen wegen SetFull ...
328 22944 : if( !nFullLen )
329 : {
330 : // nicht Init(), weil wir Hoehe und Ascent brauchen
331 8682 : Width(0);
332 8682 : bFull = rInf.Width() <= rInf.GetPos().X();
333 : }
334 : else
335 : {
336 14262 : sal_Int32 nOldLineStart = rInf.GetLineStart();
337 14262 : if( IsFollow() )
338 382 : rInf.SetLineStart( 0 );
339 14262 : rInf.SetNotEOL( nFullLen == nOldFullLen && nTxtRest > nFollow );
340 :
341 : // the height depending on the fields font is set,
342 : // this is required for SwTxtGuess::Guess
343 14262 : Height( rInf.GetTxtHeight() + rInf.GetFont()->GetTopBorderSpace() +
344 14262 : rInf.GetFont()->GetBottomBorderSpace() );
345 : // If a kerning portion is inserted after our field portion,
346 : // the ascent and height must be known
347 14262 : SetAscent( rInf.GetAscent() + rInf.GetFont()->GetTopBorderSpace() );
348 14262 : bFull = SwTxtPortion::Format( rInf );
349 14262 : rInf.SetNotEOL( false );
350 14262 : rInf.SetLineStart( nOldLineStart );
351 : }
352 22944 : sal_Int32 nTmpLen = GetLen();
353 22944 : bEOL = !nTmpLen && nFollow && bFull;
354 22944 : nRest = nOldFullLen - nTmpLen;
355 :
356 : // Das Zeichen wird in der ersten Portion gehalten.
357 : // Unbedingt nach Format!
358 22944 : SetLen( (m_bNoLength) ? 0 : nFollow );
359 :
360 22944 : if( nRest )
361 : {
362 : // aExpand ist noch nicht gekuerzt worden, der neue Ofst
363 : // ergibt sich durch nRest.
364 8048 : sal_Int32 nNextOfst = aExpand.getLength() - nRest;
365 :
366 8048 : if ( IsQuoVadisPortion() )
367 0 : nNextOfst = nNextOfst + ((SwQuoVadisPortion*)this)->GetContTxt().getLength();
368 :
369 8048 : OUString aNew( aExpand.copy( nNextOfst ) );
370 8048 : aExpand = aExpand.copy( 0, nNextOfst );
371 :
372 : // These characters should not be contained in the follow
373 : // field portion. They are handled via the HookChar mechanism.
374 8048 : switch( aNew[0] )
375 : {
376 0 : case CH_BREAK : bFull = true;
377 : // no break
378 : case ' ' :
379 : case CH_TAB :
380 : case CHAR_HARDHYPHEN: // non-breaking hyphen
381 : case CHAR_SOFTHYPHEN:
382 : case CHAR_HARDBLANK:
383 : case CHAR_ZWSP :
384 : case CHAR_ZWNBSP :
385 : case CH_TXTATR_BREAKWORD:
386 : case CH_TXTATR_INWORD:
387 : {
388 7986 : aNew = aNew.copy( 1 );
389 7986 : ++nNextOfst;
390 7986 : break;
391 : }
392 : default: ;
393 : }
394 :
395 : // Even if there is no more text left for a follow field,
396 : // we have to build a follow field portion (without font),
397 : // otherwise the HookChar mechanism would not work.
398 8048 : SwFldPortion *pFld = Clone( aNew );
399 8048 : if( !aNew.isEmpty() && !pFld->GetFont() )
400 : {
401 28 : SwFont *pNewFnt = new SwFont( *rInf.GetFont() );
402 28 : pFld->SetFont( pNewFnt );
403 : }
404 8048 : pFld->SetFollow( true );
405 8048 : SetHasFollow( true );
406 : // In nNextOffset steht bei einem neuangelegten Feld zunaechst
407 : // der Offset, an dem es selbst im Originalstring beginnt.
408 : // Wenn beim Formatieren ein FollowFeld angelegt wird, wird
409 : // der Offset dieses FollowFelds in nNextOffset festgehalten.
410 8048 : nNextOffset = nNextOffset + nNextOfst;
411 8048 : pFld->SetNextOffset( nNextOffset );
412 8048 : rInf.SetRest( pFld );
413 22944 : }
414 : }
415 :
416 22944 : if( bEOL && rInf.GetLast() && !rInf.GetUnderflow() )
417 8 : rInf.GetLast()->FormatEOL( rInf );
418 22944 : return bFull;
419 : }
420 :
421 2408 : void SwFldPortion::Paint( const SwTxtPaintInfo &rInf ) const
422 : {
423 2408 : SwFontSave aSave( rInf, pFnt );
424 :
425 : OSL_ENSURE( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
426 2408 : if( Width() && ( !bPlaceHolder || rInf.GetOpt().IsShowPlaceHolderFields() ) )
427 : {
428 : // Dies ist eine freizuegige Auslegung der Hintergrundbelegung ...
429 1840 : rInf.DrawViewOpt( *this, POR_FLD );
430 1840 : SwExpandPortion::Paint( rInf );
431 2408 : }
432 2408 : }
433 :
434 54012 : bool SwFldPortion::GetExpTxt( const SwTxtSizeInfo &rInf, OUString &rTxt ) const
435 : {
436 54012 : rTxt = aExpand;
437 127654 : if( rTxt.isEmpty() && rInf.OnWin() &&
438 3084 : !rInf.GetOpt().IsPagePreview() && !rInf.GetOpt().IsReadonly() &&
439 56068 : SwViewOption::IsFieldShadings() &&
440 1028 : !HasFollow() )
441 1028 : rTxt = OUString(' ');
442 54012 : return true;
443 : }
444 :
445 112 : void SwFldPortion::HandlePortion( SwPortionHandler& rPH ) const
446 : {
447 112 : sal_Int32 nH = 0;
448 112 : if (pFnt)
449 92 : nH = pFnt->GetSize(pFnt->GetActual()).Height();
450 112 : rPH.Special( GetLen(), aExpand, GetWhichPor(), nH );
451 112 : if( GetWhichPor() == POR_FLD )
452 : {
453 2 : rPH.SetAttrFieldType(m_nAttrFldType);
454 : }
455 112 : }
456 :
457 0 : SwPosSize SwFldPortion::GetTxtSize( const SwTxtSizeInfo &rInf ) const
458 : {
459 0 : SwFontSave aSave( rInf, pFnt );
460 0 : SwPosSize aSize( SwExpandPortion::GetTxtSize( rInf ) );
461 0 : return aSize;
462 : }
463 :
464 0 : SwFldPortion *SwHiddenPortion::Clone(const OUString &rExpand ) const
465 : {
466 : SwFont *pNewFnt;
467 0 : if( 0 != ( pNewFnt = pFnt ) )
468 0 : pNewFnt = new SwFont( *pFnt );
469 0 : return new SwHiddenPortion( rExpand, pNewFnt );
470 : }
471 :
472 0 : void SwHiddenPortion::Paint( const SwTxtPaintInfo &rInf ) const
473 : {
474 0 : if( Width() )
475 : {
476 0 : SwFontSave aSave( rInf, pFnt );
477 0 : rInf.DrawViewOpt( *this, POR_HIDDEN );
478 0 : SwExpandPortion::Paint( rInf );
479 : }
480 0 : }
481 :
482 0 : bool SwHiddenPortion::GetExpTxt( const SwTxtSizeInfo &rInf, OUString &rTxt ) const
483 : {
484 : // Nicht auf IsHidden() abfragen !
485 0 : return SwFldPortion::GetExpTxt( rInf, rTxt );
486 : }
487 :
488 16810 : SwNumberPortion::SwNumberPortion( const OUString &rExpand,
489 : SwFont *pFont,
490 : const bool bLft,
491 : const bool bCntr,
492 : const sal_uInt16 nMinDst,
493 : const bool bLabelAlignmentPosAndSpaceModeActive )
494 : : SwFldPortion( rExpand, pFont ),
495 : nFixWidth(0),
496 : nMinDist( nMinDst ),
497 16810 : mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive )
498 : {
499 16810 : SetWhichPor( POR_NUMBER );
500 16810 : SetLeft( bLft );
501 16810 : SetHide( false );
502 16810 : SetCenter( bCntr );
503 16810 : }
504 :
505 0 : sal_Int32 SwNumberPortion::GetCrsrOfst( const sal_uInt16 ) const
506 : {
507 0 : return 0;
508 : }
509 :
510 8020 : SwFldPortion *SwNumberPortion::Clone( const OUString &rExpand ) const
511 : {
512 : SwFont *pNewFnt;
513 8020 : if( 0 != ( pNewFnt = pFnt ) )
514 7880 : pNewFnt = new SwFont( *pFnt );
515 :
516 16040 : return new SwNumberPortion( rExpand, pNewFnt, IsLeft(), IsCenter(),
517 16040 : nMinDist, mbLabelAlignmentPosAndSpaceModeActive );
518 : }
519 :
520 : // 5010: Wir sind in der Lage, mehrzeilige NumFelder anzulegen!
521 : // 3689: Fies ist, wenn man in der Dialogbox soviel Davor-Text
522 : // eingibt, bis die Zeile ueberlaeuft.
523 : // Man muss die Fly-Ausweichmanoever beachten!
524 :
525 16670 : bool SwNumberPortion::Format( SwTxtFormatInfo &rInf )
526 : {
527 16670 : SetHide( false );
528 16670 : const bool bFull = SwFldPortion::Format( rInf );
529 16670 : SetLen( 0 );
530 : // a numbering portion can be contained in a rotated portion!!!
531 16670 : nFixWidth = rInf.IsMulti() ? Height() : Width();
532 16670 : rInf.SetNumDone( !rInf.GetRest() );
533 16670 : if( rInf.IsNumDone() )
534 : {
535 : // SetAscent( rInf.GetAscent() );
536 : OSL_ENSURE( Height() && nAscent, "NumberPortions without Height | Ascent" );
537 :
538 8790 : long nDiff( 0 );
539 :
540 8790 : if ( !mbLabelAlignmentPosAndSpaceModeActive )
541 : {
542 1368 : if ( !rInf.GetTxtFrm()->GetTxtNode()->getIDocumentSettingAccess()->get(IDocumentSettingAccess::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING) &&
543 : // #i32902#
544 684 : !IsFtnNumPortion() )
545 : {
546 448 : nDiff = rInf.Left()
547 896 : + rInf.GetTxtFrm()->GetTxtNode()->
548 448 : GetSwAttrSet().GetLRSpace().GetTxtFirstLineOfst()
549 448 : - rInf.First()
550 448 : + rInf.ForcedLeftMargin();
551 : }
552 : else
553 : {
554 236 : nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
555 : }
556 : }
557 : // proposal from Juergen and Volkmar:
558 : // Der Textteil hinter der Numerierung sollte immer
559 : // mindestens beim linken Rand beginnen.
560 8790 : if( nDiff < 0 )
561 6 : nDiff = 0;
562 8784 : else if ( nDiff > rInf.X() )
563 586 : nDiff -= rInf.X();
564 : else
565 8198 : nDiff = 0;
566 :
567 8790 : if( nDiff < nFixWidth + nMinDist )
568 286 : nDiff = nFixWidth + nMinDist;
569 : // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
570 : // fieser Sonderfall: FlyFrm liegt in dem Bereich,
571 : // den wir uns gerade unter den Nagel reissen wollen.
572 : // Die NumberPortion wird als verborgen markiert.
573 17580 : const bool bFly = rInf.GetFly() ||
574 26370 : ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
575 8790 : if( nDiff > rInf.Width() )
576 : {
577 0 : nDiff = rInf.Width();
578 0 : if ( bFly )
579 0 : SetHide( true );
580 : }
581 :
582 : // A numbering portion can be inside a SwRotatedPortion. Then the
583 : // Height has to be changed
584 8790 : if ( rInf.IsMulti() )
585 : {
586 0 : if ( Height() < nDiff )
587 0 : Height( sal_uInt16( nDiff ) );
588 : }
589 8790 : else if( Width() < nDiff )
590 520 : Width( sal_uInt16(nDiff) );
591 : }
592 16670 : return bFull;
593 : }
594 :
595 0 : void SwNumberPortion::FormatEOL( SwTxtFormatInfo& )
596 : {
597 : /* Ein FormatEOL deutet daraufhin, dass der folgende Text
598 : * nicht mit auf die Zeile passte. Damit die Numerierung mitwandert,
599 : * wird diese NumberPortion verborgen.
600 : */
601 :
602 : // This caused trouble with flys anchored as characters.
603 : // If one of these is numbered but does not fit to the line,
604 : // it calls this function, causing a loop because both the number
605 : // portion and the fly portion go to the next line
606 : // SetHide( true );
607 0 : }
608 :
609 654 : void SwNumberPortion::Paint( const SwTxtPaintInfo &rInf ) const
610 : {
611 : /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
612 : * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
613 : */
614 :
615 654 : if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
616 : {
617 0 : SwLinePortion *pTmp = GetPortion();
618 0 : while ( pTmp && !pTmp->InTxtGrp() )
619 0 : pTmp = pTmp->GetPortion();
620 0 : if ( !pTmp )
621 654 : return;
622 : }
623 :
624 : // calculate the width of the number portion, including follows
625 654 : const sal_uInt16 nOldWidth = Width();
626 654 : sal_uInt16 nSumWidth = 0;
627 654 : sal_uInt16 nOffset = 0;
628 :
629 654 : const SwLinePortion* pTmp = this;
630 1452 : while ( pTmp && pTmp->InNumberGrp() )
631 : {
632 654 : nSumWidth = nSumWidth + pTmp->Width();
633 654 : if ( ((SwNumberPortion*)pTmp)->HasFollow() )
634 144 : pTmp = pTmp->GetPortion();
635 : else
636 : {
637 510 : nOffset = pTmp->Width() - ((SwNumberPortion*)pTmp)->nFixWidth;
638 510 : break;
639 : }
640 : }
641 :
642 : // The master portion takes care for painting the background of the
643 : // follow field portions
644 654 : if ( ! IsFollow() )
645 : {
646 654 : SwLinePortion *pThis = (SwLinePortion*)this;
647 654 : pThis->Width( nSumWidth );
648 654 : rInf.DrawViewOpt( *this, POR_NUMBER );
649 654 : pThis->Width( nOldWidth );
650 : }
651 :
652 654 : if( !aExpand.isEmpty() )
653 : {
654 654 : const SwFont *pTmpFnt = rInf.GetFont();
655 1308 : bool bPaintSpace = ( UNDERLINE_NONE != pTmpFnt->GetUnderline() ||
656 1308 : UNDERLINE_NONE != pTmpFnt->GetOverline() ||
657 1308 : STRIKEOUT_NONE != pTmpFnt->GetStrikeout() ) &&
658 654 : !pTmpFnt->IsWordLineMode();
659 654 : if( bPaintSpace && pFnt )
660 0 : bPaintSpace = ( UNDERLINE_NONE != pFnt->GetUnderline() ||
661 0 : UNDERLINE_NONE != pFnt->GetOverline() ||
662 0 : STRIKEOUT_NONE != pFnt->GetStrikeout() ) &&
663 0 : !pFnt->IsWordLineMode();
664 :
665 654 : SwFontSave aSave( rInf, pFnt );
666 :
667 654 : if( nFixWidth == Width() && ! HasFollow() )
668 90 : SwExpandPortion::Paint( rInf );
669 : else
670 : {
671 : // logical const: reset width
672 564 : SwLinePortion *pThis = (SwLinePortion*)this;
673 564 : bPaintSpace = bPaintSpace && nFixWidth < nOldWidth;
674 564 : sal_uInt16 nSpaceOffs = nFixWidth;
675 564 : pThis->Width( nFixWidth );
676 :
677 1128 : if( ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
678 0 : ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() ) )
679 564 : SwExpandPortion::Paint( rInf );
680 : else
681 : {
682 0 : SwTxtPaintInfo aInf( rInf );
683 0 : if( nOffset < nMinDist )
684 0 : nOffset = 0;
685 : else
686 : {
687 0 : if( IsCenter() )
688 : {
689 : /* #110778# a / 2 * 2 == a is not a tautology */
690 0 : sal_uInt16 nTmpOffset = nOffset;
691 0 : nOffset /= 2;
692 0 : if( nOffset < nMinDist )
693 0 : nOffset = nTmpOffset - nMinDist;
694 : }
695 : else
696 0 : nOffset = nOffset - nMinDist;
697 : }
698 0 : aInf.X( aInf.X() + nOffset );
699 0 : SwExpandPortion::Paint( aInf );
700 0 : if( bPaintSpace )
701 0 : nSpaceOffs = nSpaceOffs + nOffset;
702 : }
703 564 : if( bPaintSpace && nOldWidth > nSpaceOffs )
704 : {
705 0 : SwTxtPaintInfo aInf( rInf );
706 0 : aInf.X( aInf.X() + nSpaceOffs );
707 :
708 : // #i53199# Adjust position of underline:
709 0 : if ( rInf.GetUnderFnt() )
710 : {
711 0 : const Point aNewPos( aInf.GetPos().X(), rInf.GetUnderFnt()->GetPos().Y() );
712 0 : rInf.GetUnderFnt()->SetPos( aNewPos );
713 : }
714 :
715 0 : pThis->Width( nOldWidth - nSpaceOffs + 12 );
716 : {
717 0 : SwTxtSlot aDiffTxt( &aInf, this, true, false, " " );
718 0 : aInf.DrawText( *this, aInf.GetLen(), true );
719 0 : }
720 : }
721 564 : pThis->Width( nOldWidth );
722 654 : }
723 : }
724 : }
725 :
726 6100 : SwBulletPortion::SwBulletPortion( const sal_Unicode cBullet,
727 : const OUString& rBulletFollowedBy,
728 : SwFont *pFont,
729 : const bool bLft,
730 : const bool bCntr,
731 : const sal_uInt16 nMinDst,
732 : const bool bLabelAlignmentPosAndSpaceModeActive )
733 12200 : : SwNumberPortion( OUString(cBullet) + rBulletFollowedBy,
734 : pFont, bLft, bCntr, nMinDst,
735 18300 : bLabelAlignmentPosAndSpaceModeActive )
736 : {
737 6100 : SetWhichPor( POR_BULLET );
738 6100 : }
739 :
740 : #define GRFNUM_SECURE 10
741 :
742 140 : SwGrfNumPortion::SwGrfNumPortion(
743 : SwFrm*,
744 : const OUString& rGraphicFollowedBy,
745 : const SvxBrushItem* pGrfBrush,
746 : const SwFmtVertOrient* pGrfOrient, const Size& rGrfSize,
747 : const bool bLft, const bool bCntr, const sal_uInt16 nMinDst,
748 : const bool bLabelAlignmentPosAndSpaceModeActive ) :
749 : SwNumberPortion( rGraphicFollowedBy, NULL, bLft, bCntr, nMinDst,
750 : bLabelAlignmentPosAndSpaceModeActive ),
751 140 : pBrush( new SvxBrushItem(RES_BACKGROUND) ), nId( 0 )
752 : {
753 140 : SetWhichPor( POR_GRFNUM );
754 140 : SetAnimated( false );
755 140 : bReplace = false;
756 140 : if( pGrfBrush )
757 : {
758 140 : *pBrush = *pGrfBrush;
759 140 : const Graphic* pGraph = pGrfBrush->GetGraphic();
760 140 : if( pGraph )
761 140 : SetAnimated( pGraph->IsAnimated() );
762 : else
763 0 : bReplace = true;
764 : }
765 140 : if( pGrfOrient )
766 : {
767 0 : nYPos = pGrfOrient->GetPos();
768 0 : eOrient = pGrfOrient->GetVertOrient();
769 : }
770 : else
771 : {
772 140 : nYPos = 0;
773 140 : eOrient = text::VertOrientation::TOP;
774 : }
775 140 : Width( static_cast<sal_uInt16>(rGrfSize.Width() + 2 * GRFNUM_SECURE) );
776 140 : nFixWidth = Width();
777 140 : nGrfHeight = rGrfSize.Height() + 2 * GRFNUM_SECURE;
778 140 : Height( sal_uInt16(nGrfHeight) );
779 140 : bNoPaint = false;
780 140 : }
781 :
782 420 : SwGrfNumPortion::~SwGrfNumPortion()
783 : {
784 140 : if ( IsAnimated() )
785 : {
786 0 : Graphic* pGraph = ( (Graphic*) pBrush->GetGraphic() );
787 0 : if (pGraph)
788 0 : pGraph->StopAnimation( 0, nId );
789 : }
790 140 : delete pBrush;
791 280 : }
792 :
793 0 : void SwGrfNumPortion::StopAnimation( OutputDevice* pOut )
794 : {
795 0 : if ( IsAnimated() )
796 : {
797 0 : Graphic* pGraph = ( (Graphic*) pBrush->GetGraphic() );
798 0 : if (pGraph)
799 0 : pGraph->StopAnimation( pOut, nId );
800 : }
801 0 : }
802 :
803 140 : bool SwGrfNumPortion::Format( SwTxtFormatInfo &rInf )
804 : {
805 140 : SetHide( false );
806 : // Width( nFixWidth );
807 140 : sal_uInt16 nFollowedByWidth( 0 );
808 140 : if ( mbLabelAlignmentPosAndSpaceModeActive )
809 : {
810 140 : SwFldPortion::Format( rInf );
811 140 : nFollowedByWidth = Width();
812 140 : SetLen( 0 );
813 : }
814 140 : Width( nFixWidth + nFollowedByWidth );
815 140 : const bool bFull = rInf.Width() < rInf.X() + Width();
816 280 : const bool bFly = rInf.GetFly() ||
817 420 : ( rInf.GetLast() && rInf.GetLast()->IsFlyPortion() );
818 140 : SetAscent( static_cast<sal_uInt16>(GetRelPos() > 0 ? GetRelPos() : 0) );
819 140 : if( GetAscent() > Height() )
820 0 : Height( GetAscent() );
821 :
822 140 : if( bFull )
823 : {
824 0 : Width( rInf.Width() - (sal_uInt16)rInf.X() );
825 0 : if( bFly )
826 : {
827 0 : SetLen( 0 );
828 0 : SetNoPaint( true );
829 0 : rInf.SetNumDone( false );
830 0 : return true;
831 : }
832 : }
833 140 : rInf.SetNumDone( true );
834 : // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
835 : long nDiff = mbLabelAlignmentPosAndSpaceModeActive
836 : ? 0
837 140 : : rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
838 : // proposal by Juergen and Volkmar:
839 : // Der Textteil hinter der Numerierung sollte immer
840 : // mindestens beim linken Rand beginnen.
841 140 : if( nDiff < 0 )
842 0 : nDiff = 0;
843 140 : else if ( nDiff > rInf.X() )
844 0 : nDiff -= rInf.X();
845 140 : if( nDiff < nFixWidth + nMinDist )
846 140 : nDiff = nFixWidth + nMinDist;
847 : // 2739: Numerierung weicht Fly aus, kein nDiff in der zweiten Runde
848 : // fieser Sonderfall: FlyFrm liegt in dem Bereich,
849 : // den wir uns gerade unter den Nagel reissen wollen.
850 : // Die NumberPortion wird als verborgen markiert.
851 140 : if( nDiff > rInf.Width() )
852 : {
853 0 : nDiff = rInf.Width();
854 0 : if( bFly )
855 0 : SetHide( true );
856 : }
857 :
858 140 : if( Width() < nDiff )
859 0 : Width( sal_uInt16(nDiff) );
860 140 : return bFull;
861 : }
862 :
863 0 : void SwGrfNumPortion::Paint( const SwTxtPaintInfo &rInf ) const
864 : {
865 0 : if( DontPaint() )
866 0 : return;
867 : /* Eine verborgene NumberPortion wird nicht angezeigt, es sei denn, es gibt
868 : * Textportions in dieser Zeile oder es gibt ueberhaupt nur eine einzige Zeile.
869 : */
870 0 : if ( IsHide() && rInf.GetParaPortion() && rInf.GetParaPortion()->GetNext() )
871 : {
872 0 : SwLinePortion *pTmp = GetPortion();
873 0 : while ( pTmp && !pTmp->InTxtGrp() )
874 0 : pTmp = pTmp->GetPortion();
875 0 : if ( !pTmp )
876 0 : return;
877 : }
878 0 : Point aPos( rInf.X() + GRFNUM_SECURE, rInf.Y() - GetRelPos() + GRFNUM_SECURE );
879 0 : long nTmpWidth = std::max( (long)0, (long)(nFixWidth - 2 * GRFNUM_SECURE) );
880 0 : Size aSize( nTmpWidth, GetGrfHeight() - 2 * GRFNUM_SECURE );
881 :
882 0 : const bool bTmpLeft = mbLabelAlignmentPosAndSpaceModeActive ||
883 0 : ( IsLeft() && ! rInf.GetTxtFrm()->IsRightToLeft() ) ||
884 0 : ( ! IsLeft() && ! IsCenter() && rInf.GetTxtFrm()->IsRightToLeft() );
885 :
886 0 : if( nFixWidth < Width() && !bTmpLeft )
887 : {
888 0 : sal_uInt16 nOffset = Width() - nFixWidth;
889 0 : if( nOffset < nMinDist )
890 0 : nOffset = 0;
891 : else
892 : {
893 0 : if( IsCenter() )
894 : {
895 0 : nOffset /= 2;
896 0 : if( nOffset < nMinDist )
897 0 : nOffset = Width() - nFixWidth - nMinDist;
898 : }
899 : else
900 0 : nOffset = nOffset - nMinDist;
901 : }
902 0 : aPos.X() += nOffset;
903 : }
904 :
905 0 : if( bReplace )
906 : {
907 0 : const long nTmpH = GetPortion() ? GetPortion()->GetAscent() : 120;
908 0 : aSize = Size( nTmpH, nTmpH );
909 0 : aPos.Y() = rInf.Y() - nTmpH;
910 : }
911 0 : SwRect aTmp( aPos, aSize );
912 :
913 0 : bool bDraw = true;
914 :
915 0 : if ( IsAnimated() )
916 : {
917 0 : bDraw = !rInf.GetOpt().IsGraphic();
918 0 : if( !nId )
919 : {
920 0 : SetId( sal_IntPtr( rInf.GetTxtFrm() ) );
921 0 : rInf.GetTxtFrm()->SetAnimation();
922 : }
923 0 : if( aTmp.IsOver( rInf.GetPaintRect() ) && !bDraw )
924 : {
925 0 : rInf.NoteAnimation();
926 0 : const SwViewShell* pViewShell = rInf.GetVsh();
927 :
928 : // virtual device, not pdf export
929 0 : if( OUTDEV_VIRDEV == rInf.GetOut()->GetOutDevType() &&
930 0 : pViewShell && pViewShell->GetWin() )
931 : {
932 0 : Graphic* pGraph = (Graphic*)pBrush->GetGraphic();
933 0 : if (pGraph)
934 0 : pGraph->StopAnimation(0,nId);
935 0 : rInf.GetTxtFrm()->getRootFrm()->GetCurrShell()->InvalidateWindows( aTmp );
936 : }
937 :
938 0 : else if ( pViewShell &&
939 0 : !pViewShell->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
940 0 : !pViewShell->IsPreview() &&
941 : // #i9684# Stop animation during printing/pdf export.
942 0 : pViewShell->GetWin() )
943 : {
944 0 : Graphic* pGraph = (Graphic*)pBrush->GetGraphic();
945 0 : if (pGraph)
946 : {
947 : pGraph->StartAnimation(
948 0 : (OutputDevice*)rInf.GetOut(), aPos, aSize, nId );
949 : }
950 : }
951 :
952 : // pdf export, printing, preview, stop animations...
953 : else
954 0 : bDraw = true;
955 : }
956 0 : if( bDraw )
957 : {
958 :
959 0 : Graphic* pGraph = (Graphic*)pBrush->GetGraphic();
960 0 : if (pGraph)
961 0 : pGraph->StopAnimation( 0, nId );
962 : }
963 : }
964 :
965 0 : SwRect aRepaint( rInf.GetPaintRect() );
966 0 : const SwTxtFrm& rFrm = *rInf.GetTxtFrm();
967 0 : if( rFrm.IsVertical() )
968 : {
969 0 : rFrm.SwitchHorizontalToVertical( aTmp );
970 0 : rFrm.SwitchHorizontalToVertical( aRepaint );
971 : }
972 :
973 0 : if( rFrm.IsRightToLeft() )
974 : {
975 0 : rFrm.SwitchLTRtoRTL( aTmp );
976 0 : rFrm.SwitchLTRtoRTL( aRepaint );
977 : }
978 :
979 0 : if( bDraw && aTmp.HasArea() )
980 : {
981 0 : DrawGraphic( pBrush, (OutputDevice*)rInf.GetOut(),
982 0 : aTmp, aRepaint, bReplace ? GRFNUM_REPLACE : GRFNUM_YES );
983 : }
984 : }
985 :
986 140 : void SwGrfNumPortion::SetBase( long nLnAscent, long nLnDescent,
987 : long nFlyAsc, long nFlyDesc )
988 : {
989 140 : if ( GetOrient() != text::VertOrientation::NONE )
990 : {
991 140 : SetRelPos( 0 );
992 140 : if ( GetOrient() == text::VertOrientation::CENTER )
993 0 : SetRelPos( GetGrfHeight() / 2 );
994 140 : else if ( GetOrient() == text::VertOrientation::TOP )
995 140 : SetRelPos( GetGrfHeight() - GRFNUM_SECURE );
996 0 : else if ( GetOrient() == text::VertOrientation::BOTTOM )
997 : ;
998 0 : else if ( GetOrient() == text::VertOrientation::CHAR_CENTER )
999 0 : SetRelPos( ( GetGrfHeight() + nLnAscent - nLnDescent ) / 2 );
1000 0 : else if ( GetOrient() == text::VertOrientation::CHAR_TOP )
1001 0 : SetRelPos( nLnAscent );
1002 0 : else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM )
1003 0 : SetRelPos( GetGrfHeight() - nLnDescent );
1004 : else
1005 : {
1006 0 : if( GetGrfHeight() >= nFlyAsc + nFlyDesc )
1007 : {
1008 : // wenn ich genauso gross bin wie die Zeile, brauche ich mich
1009 : // nicht an der Zeile nicht weiter ausrichten, ich lasse
1010 : // dann auch den max. Ascent der Zeile unveraendert
1011 :
1012 0 : SetRelPos( nFlyAsc );
1013 : }
1014 0 : else if ( GetOrient() == text::VertOrientation::LINE_CENTER )
1015 0 : SetRelPos( ( GetGrfHeight() + nFlyAsc - nFlyDesc ) / 2 );
1016 0 : else if ( GetOrient() == text::VertOrientation::LINE_TOP )
1017 0 : SetRelPos( nFlyAsc );
1018 0 : else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM )
1019 0 : SetRelPos( GetGrfHeight() - nFlyDesc );
1020 : }
1021 : }
1022 140 : }
1023 :
1024 0 : void SwTxtFrm::StopAnimation( OutputDevice* pOut )
1025 : {
1026 : OSL_ENSURE( HasAnimation(), "SwTxtFrm::StopAnimation: Which Animation?" );
1027 0 : if( HasPara() )
1028 : {
1029 0 : SwLineLayout *pLine = GetPara();
1030 0 : while( pLine )
1031 : {
1032 0 : SwLinePortion *pPor = pLine->GetPortion();
1033 0 : while( pPor )
1034 : {
1035 0 : if( pPor->IsGrfNumPortion() )
1036 0 : ((SwGrfNumPortion*)pPor)->StopAnimation( pOut );
1037 : // Die Numerierungsportion sitzt immer vor dem ersten Zeichen,
1038 : // deshalb koennen wir abbrechen, sobald wir eine Portion mit
1039 : // einer Laenge > 0 erreicht haben.
1040 0 : pPor = pPor->GetLen() ? 0 : pPor->GetPortion();
1041 : }
1042 0 : pLine = pLine->GetLen() ? 0 : pLine->GetNext();
1043 : }
1044 : }
1045 0 : }
1046 :
1047 : // initializes the script array and clears the width array
1048 0 : SwCombinedPortion::SwCombinedPortion( const OUString &rTxt )
1049 : : SwFldPortion( rTxt )
1050 : , nUpPos(0)
1051 : , nLowPos(0)
1052 0 : , nProportion(55)
1053 : {
1054 0 : SetLen(1);
1055 0 : SetWhichPor( POR_COMBINED );
1056 0 : if( aExpand.getLength() > 6 )
1057 0 : aExpand = aExpand.copy( 0, 6 );
1058 : // Initialization of the scripttype array,
1059 : // the arrays of width and position are filled by the format function
1060 0 : if( g_pBreakIt->GetBreakIter().is() )
1061 : {
1062 0 : sal_uInt8 nScr = SW_SCRIPTS;
1063 0 : for( sal_Int32 i = 0; i < rTxt.getLength(); ++i )
1064 : {
1065 0 : switch ( g_pBreakIt->GetBreakIter()->getScriptType( rTxt, i ) ) {
1066 0 : case i18n::ScriptType::LATIN : nScr = SW_LATIN; break;
1067 0 : case i18n::ScriptType::ASIAN : nScr = SW_CJK; break;
1068 0 : case i18n::ScriptType::COMPLEX : nScr = SW_CTL; break;
1069 : }
1070 0 : aScrType[i] = nScr;
1071 : }
1072 : }
1073 : else
1074 : {
1075 0 : for( int i = 0; i < 6; ++i )
1076 0 : aScrType[i] = 0;
1077 : }
1078 0 : memset( &aWidth, 0, sizeof(aWidth) );
1079 0 : }
1080 :
1081 0 : void SwCombinedPortion::Paint( const SwTxtPaintInfo &rInf ) const
1082 : {
1083 : OSL_ENSURE( GetLen() <= 1, "SwFldPortion::Paint: rest-portion polution?" );
1084 0 : if( Width() )
1085 : {
1086 0 : rInf.DrawBackBrush( *this );
1087 0 : rInf.DrawViewOpt( *this, POR_FLD );
1088 :
1089 : // do we have to repaint a post it portion?
1090 0 : if( rInf.OnWin() && pPortion && !pPortion->Width() )
1091 0 : pPortion->PrePaint( rInf, this );
1092 :
1093 0 : const sal_Int32 nCount = aExpand.getLength();
1094 0 : if( !nCount )
1095 0 : return;
1096 : OSL_ENSURE( nCount < 7, "Too much combined characters" );
1097 :
1098 : // the first character of the second row
1099 0 : const sal_Int32 nTop = ( nCount + 1 ) / 2;
1100 :
1101 0 : SwFont aTmpFont( *rInf.GetFont() );
1102 0 : aTmpFont.SetProportion( nProportion ); // a smaller font
1103 0 : SwFontSave aFontSave( rInf, &aTmpFont );
1104 :
1105 0 : Point aOldPos = rInf.GetPos();
1106 0 : Point aOutPos( aOldPos.X(), aOldPos.Y() - nUpPos );// Y of the first row
1107 0 : for( sal_Int32 i = 0 ; i < nCount; ++i )
1108 : {
1109 0 : if( i == nTop ) // change the row
1110 0 : aOutPos.Y() = aOldPos.Y() + nLowPos; // Y of the second row
1111 0 : aOutPos.X() = aOldPos.X() + aPos[i]; // X position
1112 0 : const sal_uInt8 nAct = aScrType[i]; // script type
1113 0 : aTmpFont.SetActual( nAct );
1114 : // if there're more than 4 characters to display, we choose fonts
1115 : // with 2/3 of the original font width.
1116 0 : if( aWidth[ nAct ] )
1117 : {
1118 0 : Size aTmpSz = aTmpFont.GetSize( nAct );
1119 0 : if( aTmpSz.Width() != aWidth[ nAct ] )
1120 : {
1121 0 : aTmpSz.Width() = aWidth[ nAct ];
1122 0 : aTmpFont.SetSize( aTmpSz, nAct );
1123 : }
1124 : }
1125 0 : ((SwTxtPaintInfo&)rInf).SetPos( aOutPos );
1126 0 : rInf.DrawText( aExpand, *this, i, 1 );
1127 : }
1128 : // rInf is const, so we have to take back our manipulations
1129 0 : ((SwTxtPaintInfo&)rInf).SetPos( aOldPos );
1130 : }
1131 : }
1132 :
1133 0 : bool SwCombinedPortion::Format( SwTxtFormatInfo &rInf )
1134 : {
1135 0 : const sal_Int32 nCount = aExpand.getLength();
1136 0 : if( !nCount )
1137 : {
1138 0 : Width( 0 );
1139 0 : return false;
1140 : }
1141 :
1142 : OSL_ENSURE( nCount < 7, "Too much combined characters" );
1143 : // If there are leading "weak"-scripttyped characters in this portion,
1144 : // they get the actual scripttype.
1145 0 : for( sal_Int32 i = 0; i < nCount && SW_SCRIPTS == aScrType[i]; ++i )
1146 0 : aScrType[i] = rInf.GetFont()->GetActual();
1147 0 : if( nCount > 4 )
1148 : {
1149 : // more than four? Ok, then we need the 2/3 font width
1150 0 : for( sal_Int32 i = 0; i < aExpand.getLength(); ++i )
1151 : {
1152 : OSL_ENSURE( aScrType[i] < SW_SCRIPTS, "Combined: Script fault" );
1153 0 : if( !aWidth[ aScrType[i] ] )
1154 : {
1155 0 : rInf.GetOut()->SetFont( rInf.GetFont()->GetFnt( aScrType[i] ) );
1156 0 : aWidth[ aScrType[i] ] =
1157 0 : static_cast<sal_uInt16>(2 * rInf.GetOut()->GetFontMetric().GetSize().Width() / 3);
1158 : }
1159 : }
1160 : }
1161 :
1162 0 : const sal_Int32 nTop = ( nCount + 1 ) / 2; // the first character of the second line
1163 0 : SwViewShell *pSh = rInf.GetTxtFrm()->getRootFrm()->GetCurrShell();
1164 0 : SwFont aTmpFont( *rInf.GetFont() );
1165 0 : SwFontSave aFontSave( rInf, &aTmpFont );
1166 0 : nProportion = 55;
1167 : // In nMainAscent/Descent we store the ascent and descent
1168 : // of the original surrounding font
1169 : sal_uInt16 nMaxDescent, nMaxAscent, nMaxWidth;
1170 0 : sal_uInt16 nMainDescent = rInf.GetFont()->GetHeight( pSh, *rInf.GetOut() );
1171 0 : const sal_uInt16 nMainAscent = rInf.GetFont()->GetAscent( pSh, *rInf.GetOut() );
1172 0 : nMainDescent = nMainDescent - nMainAscent;
1173 : // we start with a 50% font, but if we notice that the combined portion
1174 : // becomes bigger than the surrounding font, we check 45% and maybe 40%.
1175 0 : do
1176 : {
1177 0 : nProportion -= 5;
1178 0 : aTmpFont.SetProportion( nProportion );
1179 0 : memset( &aPos, 0, sizeof(aPos) );
1180 0 : nMaxDescent = 0;
1181 0 : nMaxAscent = 0;
1182 0 : nMaxWidth = 0;
1183 0 : nUpPos = nLowPos = 0;
1184 :
1185 : // Now we get the width of all characters.
1186 : // The ascent and the width of the first line are stored in the
1187 : // ascent member of the portion, the descent in nLowPos.
1188 : // The ascent, descent and width of the second line are stored in the
1189 : // local nMaxAscent, nMaxDescent and nMaxWidth variables.
1190 0 : for( sal_Int32 i = 0; i < nCount; ++i )
1191 : {
1192 0 : sal_uInt8 nScrp = aScrType[i];
1193 0 : aTmpFont.SetActual( nScrp );
1194 0 : if( aWidth[ nScrp ] )
1195 : {
1196 0 : Size aFontSize( aTmpFont.GetSize( nScrp ) );
1197 0 : aFontSize.Width() = aWidth[ nScrp ];
1198 0 : aTmpFont.SetSize( aFontSize, nScrp );
1199 : }
1200 :
1201 0 : SwDrawTextInfo aDrawInf( pSh, *rInf.GetOut(), 0, aExpand, i, 1 );
1202 0 : Size aSize = aTmpFont._GetTxtSize( aDrawInf );
1203 0 : const sal_uInt16 nAsc = aTmpFont.GetAscent( pSh, *rInf.GetOut() );
1204 0 : aPos[ i ] = (sal_uInt16)aSize.Width();
1205 0 : if( i == nTop ) // enter the second line
1206 : {
1207 0 : nLowPos = nMaxDescent;
1208 0 : Height( nMaxDescent + nMaxAscent );
1209 0 : Width( nMaxWidth );
1210 0 : SetAscent( nMaxAscent );
1211 0 : nMaxAscent = 0;
1212 0 : nMaxDescent = 0;
1213 0 : nMaxWidth = 0;
1214 : }
1215 0 : nMaxWidth = nMaxWidth + aPos[ i ];
1216 0 : if( nAsc > nMaxAscent )
1217 0 : nMaxAscent = nAsc;
1218 0 : if( aSize.Height() - nAsc > nMaxDescent )
1219 0 : nMaxDescent = static_cast<sal_uInt16>(aSize.Height() - nAsc);
1220 0 : }
1221 : // for one or two characters we double the width of the portion
1222 0 : if( nCount < 3 )
1223 : {
1224 0 : nMaxWidth *= 2;
1225 0 : Width( 2*Width() );
1226 0 : if( nCount < 2 )
1227 : {
1228 0 : Height( nMaxAscent + nMaxDescent );
1229 0 : nLowPos = nMaxDescent;
1230 : }
1231 : }
1232 0 : Height( Height() + nMaxDescent + nMaxAscent );
1233 0 : nUpPos = nMaxAscent;
1234 0 : SetAscent( Height() - nMaxDescent - nLowPos );
1235 0 : } while( nProportion > 40 && ( GetAscent() > nMainAscent ||
1236 0 : Height() - GetAscent() > nMainDescent ) );
1237 : // if the combined portion is smaller than the surrounding text,
1238 : // the portion grows. This looks better, if there's a character background.
1239 0 : if( GetAscent() < nMainAscent )
1240 : {
1241 0 : Height( Height() + nMainAscent - GetAscent() );
1242 0 : SetAscent( nMainAscent );
1243 : }
1244 0 : if( Height() < nMainAscent + nMainDescent )
1245 0 : Height( nMainAscent + nMainDescent );
1246 :
1247 : // We calculate the x positions of the characters in both lines..
1248 0 : sal_uInt16 nTopDiff = 0;
1249 0 : sal_uInt16 nBotDiff = 0;
1250 0 : if( nMaxWidth > Width() )
1251 : {
1252 0 : nTopDiff = ( nMaxWidth - Width() ) / 2;
1253 0 : Width( nMaxWidth );
1254 : }
1255 : else
1256 0 : nBotDiff = ( Width() - nMaxWidth ) / 2;
1257 0 : switch( nTop)
1258 : {
1259 0 : case 3: aPos[1] = aPos[0] + nTopDiff; // no break
1260 0 : case 2: aPos[nTop-1] = Width() - aPos[nTop-1];
1261 : }
1262 0 : aPos[0] = 0;
1263 0 : switch( nCount )
1264 : {
1265 0 : case 5: aPos[4] = aPos[3] + nBotDiff; // no break
1266 0 : case 3: aPos[nTop] = nBotDiff; break;
1267 0 : case 6: aPos[4] = aPos[3] + nBotDiff; // no break
1268 0 : case 4: aPos[nTop] = 0; // no break
1269 0 : case 2: aPos[nCount-1] = Width() - aPos[nCount-1];
1270 : }
1271 :
1272 : // Does the combined portion fit the line?
1273 0 : const bool bFull = rInf.Width() < rInf.X() + Width();
1274 0 : if( bFull )
1275 : {
1276 0 : if( rInf.GetLineStart() == rInf.GetIdx() && (!rInf.GetLast()->InFldGrp()
1277 0 : || !((SwFldPortion*)rInf.GetLast())->IsFollow() ) )
1278 0 : Width( (sal_uInt16)( rInf.Width() - rInf.X() ) );
1279 : else
1280 : {
1281 0 : Truncate();
1282 0 : Width( 0 );
1283 0 : SetLen( 0 );
1284 0 : if( rInf.GetLast() )
1285 0 : rInf.GetLast()->FormatEOL( rInf );
1286 : }
1287 : }
1288 0 : return bFull;
1289 : }
1290 :
1291 0 : sal_uInt16 SwCombinedPortion::GetViewWidth( const SwTxtSizeInfo &rInf ) const
1292 : {
1293 0 : if( !GetLen() ) // for the dummy part at the end of the line, where
1294 0 : return 0; // the combined portion doesn't fit.
1295 0 : return SwFldPortion::GetViewWidth( rInf );
1296 : }
1297 :
1298 0 : SwFldPortion *SwFieldFormDropDownPortion::Clone(const OUString &rExpand) const
1299 : {
1300 0 : return new SwFieldFormDropDownPortion(rExpand);
1301 270 : }
1302 :
1303 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|