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