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