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