1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #include <hintids.hxx>
22 #include <com/sun/star/i18n/ScriptType.hpp>
23 #include <com/sun/star/i18n/XBreakIterator.hpp>
24 #include <vcl/graph.hxx>
25 #include <editeng/brushitem.hxx>
26 #include <vcl/metric.hxx>
27 #include <vcl/outdev.hxx>
28 #include <viewopt.hxx>
29 #include <SwPortionHandler.hxx>
33 #include <fmtornt.hxx>
35 #include <frmtool.hxx>
38 #include <IDocumentSettingAccess.hxx>
39 #include <rootfrm.hxx>
40 #include <breakit.hxx>
42 #include <accessibilityoptions.hxx>
43 #include <editeng/lrspitem.hxx>
44 #include <unicode/ubidi.h>
45 #include <bookmark.hxx>
47 using namespace ::com::sun::star
;
49 SwLinePortion
*SwFieldPortion::Compress()
50 { return (GetLen() || !m_aExpand
.isEmpty() || SwLinePortion::Compress()) ? this : nullptr; }
52 SwFieldPortion
*SwFieldPortion::Clone( const OUString
&rExpand
) const
54 std::unique_ptr
<SwFont
> pNewFnt
;
57 pNewFnt
.reset(new SwFont( *m_pFont
));
60 // pass placeholder property to created <SwFieldPortion> instance.
61 SwFieldPortion
* pClone
= new SwFieldPortion( rExpand
, std::move(pNewFnt
), m_bPlaceHolder
);
62 pClone
->SetNextOffset( m_nNextOffset
);
63 pClone
->m_bNoLength
= m_bNoLength
;
67 void SwFieldPortion::TakeNextOffset( const SwFieldPortion
* pField
)
69 OSL_ENSURE( pField
, "TakeNextOffset: Missing Source" );
70 m_nNextOffset
= pField
->GetNextOffset();
71 m_aExpand
= m_aExpand
.replaceAt(0, sal_Int32(m_nNextOffset
), u
"");
75 SwFieldPortion::SwFieldPortion(const OUString
&rExpand
, std::unique_ptr
<SwFont
> pFont
, bool bPlaceHold
, TextFrameIndex
const nFieldLen
)
76 : m_aExpand(rExpand
), m_pFont(std::move(pFont
)), m_nNextOffset(0)
77 , m_nNextScriptChg(COMPLETE_STRING
), m_nFieldLen(nFieldLen
), m_nViewWidth(0)
78 , m_bFollow( false ), m_bLeft( false), m_bHide( false)
79 , m_bCenter (false), m_bHasFollow( false )
80 , m_bAnimated( false), m_bNoPaint( false)
81 , m_bReplace( false), m_bPlaceHolder( bPlaceHold
)
82 , m_bNoLength( false )
85 SetWhichPor( PortionType::Field
);
88 SwFieldPortion::SwFieldPortion( const SwFieldPortion
& rField
)
89 : SwExpandPortion( rField
)
90 , m_aExpand( rField
.GetExp() )
91 , m_nNextOffset( rField
.GetNextOffset() )
92 , m_nNextScriptChg( rField
.m_nNextScriptChg
)
93 , m_nFieldLen(rField
.m_nFieldLen
)
94 , m_nViewWidth( rField
.m_nViewWidth
)
95 , m_bFollow( rField
.IsFollow() )
96 , m_bLeft( rField
.IsLeft() )
97 , m_bHide( rField
.IsHide() )
98 , m_bCenter( rField
.IsCenter() )
99 , m_bHasFollow( rField
.HasFollow() )
100 , m_bAnimated ( rField
.m_bAnimated
)
101 , m_bNoPaint( rField
.m_bNoPaint
)
102 , m_bReplace( rField
.m_bReplace
)
103 , m_bPlaceHolder( rField
.m_bPlaceHolder
)
104 , m_bNoLength( rField
.m_bNoLength
)
105 , m_nAttrFieldType( rField
.m_nAttrFieldType
)
107 if ( rField
.HasFont() )
108 m_pFont
.reset( new SwFont( *rField
.GetFont() ) );
110 SetWhichPor( PortionType::Field
);
113 SwFieldPortion::~SwFieldPortion()
118 sal_uInt16
SwFieldPortion::GetViewWidth( const SwTextSizeInfo
&rInf
) const
120 // even though this is const, nViewWidth should be computed at the very end:
121 SwFieldPortion
* pThis
= const_cast<SwFieldPortion
*>(this);
122 if( !Width() && rInf
.OnWin() && !rInf
.GetOpt().IsPagePreview() &&
123 !rInf
.GetOpt().IsReadonly() && SwViewOption::IsFieldShadings() )
126 pThis
->m_nViewWidth
= rInf
.GetTextSize(OUString(' ')).Width();
129 pThis
->m_nViewWidth
= 0;
136 * Never just use SetLen(0)
140 std::shared_ptr
<vcl::text::TextLayoutCache
> m_pOldCachedVclData
;
141 const OUString
*pOldText
;
145 SwTextFormatInfo
*pInf
;
148 SwFieldSlot( const SwTextFormatInfo
* pNew
, const SwFieldPortion
*pPor
);
154 SwFieldSlot::SwFieldSlot( const SwTextFormatInfo
* pNew
, const SwFieldPortion
*pPor
)
160 bOn
= pPor
->GetExpText( *pNew
, aText
);
162 // The text will be replaced ...
166 pInf
= const_cast<SwTextFormatInfo
*>(pNew
);
167 nIdx
= pInf
->GetIdx();
168 nLen
= pInf
->GetLen();
169 pOldText
= &(pInf
->GetText());
170 m_pOldCachedVclData
= pInf
->GetCachedVclData();
171 pInf
->SetLen(TextFrameIndex(aText
.getLength()));
172 pInf
->SetCachedVclData(nullptr);
173 if( pPor
->IsFollow() )
175 pInf
->SetFakeLineStart( nIdx
> pInf
->GetLineStart() );
176 pInf
->SetIdx(TextFrameIndex(0));
180 TextFrameIndex
nEnd(pOldText
->getLength());
183 sal_Int32
const nFieldLen(pPor
->GetFieldLen());
184 aText
= (*pOldText
).replaceAt(sal_Int32(nIdx
), nFieldLen
, aText
);
186 else if (nIdx
== nEnd
)
187 aText
= *pOldText
+ aText
;
189 SAL_WARN("sw.core", "SwFieldSlot bad SwFieldPortion index.");
191 pInf
->SetText( aText
);
194 SwFieldSlot::~SwFieldSlot()
198 pInf
->SetCachedVclData(m_pOldCachedVclData
);
199 pInf
->SetText( *pOldText
);
200 pInf
->SetIdx( nIdx
);
201 pInf
->SetLen( nLen
);
202 pInf
->SetFakeLineStart( false );
206 void SwFieldPortion::CheckScript( const SwTextSizeInfo
&rInf
)
209 if (!GetExpText(rInf
, aText
) || aText
.isEmpty())
212 SwFontScript nActual
= m_pFont
? m_pFont
->GetActual() : rInf
.GetFont()->GetActual();
213 sal_uInt16 nScript
= g_pBreakIt
->GetBreakIter()->getScriptType( aText
, 0 );
215 if( i18n::ScriptType::WEAK
== nScript
)
217 nChg
= g_pBreakIt
->GetBreakIter()->endOfScript(aText
,0,nScript
);
218 if (nChg
< aText
.getLength() && nChg
>= 0)
219 nScript
= g_pBreakIt
->GetBreakIter()->getScriptType( aText
, nChg
);
222 // nNextScriptChg will be evaluated during SwFieldPortion::Format()
224 if (nChg
< aText
.getLength() && nChg
>= 0)
225 m_nNextScriptChg
= TextFrameIndex(
226 g_pBreakIt
->GetBreakIter()->endOfScript(aText
, nChg
, nScript
));
228 m_nNextScriptChg
= TextFrameIndex(aText
.getLength());
232 case i18n::ScriptType::LATIN
: nTmp
= SwFontScript::Latin
; break;
233 case i18n::ScriptType::ASIAN
: nTmp
= SwFontScript::CJK
; break;
234 case i18n::ScriptType::COMPLEX
: nTmp
= SwFontScript::CTL
; break;
235 default: nTmp
= nActual
;
238 // #i16354# Change script type for RTL text to CTL.
239 const SwScriptInfo
& rSI
= rInf
.GetParaPortion()->GetScriptInfo();
241 const sal_uInt8 nFieldDir
= (IsNumberPortion() || IsFootnoteNumPortion())
242 ? rSI
.GetDefaultDir()
243 : rSI
.DirType(IsFollow() ? rInf
.GetIdx() - m_nFieldLen
: rInf
.GetIdx());
246 UErrorCode nError
= U_ZERO_ERROR
;
247 UBiDi
* pBidi
= ubidi_openSized( aText
.getLength(), 0, &nError
);
248 ubidi_setPara( pBidi
, reinterpret_cast<const UChar
*>(aText
.getStr()), aText
.getLength(), nFieldDir
, nullptr, &nError
);
251 ubidi_getLogicalRun( pBidi
, 0, &nEnd
, &nCurrDir
);
252 ubidi_close( pBidi
);
253 const TextFrameIndex
nNextDirChg(nEnd
);
254 m_nNextScriptChg
= std::min( m_nNextScriptChg
, nNextDirChg
);
256 // #i89825# change the script type also to CTL
257 // if there is no strong LTR char in the LTR run (numbers)
258 if (nCurrDir
!= UBIDI_RTL
&&
259 (UBIDI_LTR
!= nFieldDir
|| i18n::ScriptType::COMPLEX
== nScript
))
261 nCurrDir
= UBIDI_RTL
;
262 for( sal_Int32 nCharIdx
= 0; nCharIdx
< nEnd
; ++nCharIdx
)
264 UCharDirection nCharDir
= u_charDirection ( aText
[ nCharIdx
]);
265 if ( nCharDir
== U_LEFT_TO_RIGHT
||
266 nCharDir
== U_LEFT_TO_RIGHT_EMBEDDING
||
267 nCharDir
== U_LEFT_TO_RIGHT_OVERRIDE
)
269 nCurrDir
= UBIDI_LTR
;
275 if (nCurrDir
== UBIDI_RTL
)
277 nTmp
= SwFontScript::CTL
;
278 // If we decided that this range was RTL after all and the
279 // previous range was complex but clipped to the start of this
280 // range, then extend it to be complex over the additional RTL range
281 if (nScript
== i18n::ScriptType::COMPLEX
)
282 m_nNextScriptChg
= nNextDirChg
;
287 // keep determined script type for footnote portions as preferred script type.
288 // For footnote portions a font can not be created directly - see footnote
289 // portion format method.
290 if ( IsFootnotePortion() )
292 static_cast<SwFootnotePortion
*>(this)->SetPreferredScriptType( nTmp
);
294 else if ( nTmp
!= nActual
)
297 m_pFont
.reset( new SwFont( *rInf
.GetFont() ) );
298 m_pFont
->SetActual( nTmp
);
303 bool SwFieldPortion::Format( SwTextFormatInfo
&rInf
)
305 // Scope wegen aDiffText::DTOR!
308 TextFrameIndex
const nTextRest
= TextFrameIndex(rInf
.GetText().getLength()) - rInf
.GetIdx();
310 TextFrameIndex nRest
;
311 SwFieldSlot
aDiffText( &rInf
, this );
312 SwLayoutModeModifier
aLayoutModeModifier( *rInf
.GetOut() );
313 aLayoutModeModifier
.SetAuto();
315 // Field portion has to be split in several parts if
316 // 1. There are script/direction changes inside the field
317 // 2. There are portion breaks (tab, break) inside the field:
318 const TextFrameIndex nOldFullLen
= rInf
.GetLen();
319 TextFrameIndex nFullLen
= rInf
.ScanPortionEnd(rInf
.GetIdx(), rInf
.GetIdx() + nOldFullLen
) - rInf
.GetIdx();
320 if ( m_nNextScriptChg
< nFullLen
)
322 nFullLen
= m_nNextScriptChg
;
323 rInf
.SetHookChar( 0 );
325 rInf
.SetLen( nFullLen
);
327 if (TextFrameIndex(COMPLETE_STRING
) != rInf
.GetUnderScorePos() &&
328 rInf
.GetUnderScorePos() > rInf
.GetIdx() )
329 rInf
.SetUnderScorePos( rInf
.GetIdx() );
332 m_pFont
->AllocFontCacheId( rInf
.GetVsh(), m_pFont
->GetActual() );
334 SwFontSave
aSave( rInf
, m_pFont
.get() );
336 // Length must be 0: the length is set for bFull after format
337 // and passed along in nRest. Or else the old length would be
338 // retained and be used for nRest!
339 SetLen(TextFrameIndex(0));
340 TextFrameIndex
const nFollow(IsFollow() ? TextFrameIndex(0) : m_nFieldLen
);
342 // As odd is may seem: the query for GetLen() must return false due
343 // to the ExpandPortions _after_ aDiffText (see SoftHyphs), caused
347 // Don't Init(), as we need height and ascent
349 bFull
= rInf
.Width() <= rInf
.GetPos().X();
353 TextFrameIndex
const nOldLineStart
= rInf
.GetLineStart();
355 rInf
.SetLineStart(TextFrameIndex(0));
356 rInf
.SetNotEOL( nFullLen
== nOldFullLen
&& nTextRest
> nFollow
);
358 // the height depending on the fields font is set,
359 // this is required for SwTextGuess::Guess
360 Height( rInf
.GetTextHeight() + rInf
.GetFont()->GetTopBorderSpace() +
361 rInf
.GetFont()->GetBottomBorderSpace() );
362 // If a kerning portion is inserted after our field portion,
363 // the ascent and height must be known
364 SetAscent( rInf
.GetAscent() + rInf
.GetFont()->GetTopBorderSpace() );
365 bFull
= SwTextPortion::Format( rInf
);
366 rInf
.SetNotEOL( false );
367 rInf
.SetLineStart( nOldLineStart
);
369 TextFrameIndex
const nTmpLen
= GetLen();
370 bEOL
= !nTmpLen
&& nFollow
&& bFull
;
371 nRest
= nOldFullLen
- nTmpLen
;
373 // The char is held in the first position
374 // Unconditionally after format!
375 SetLen( m_bNoLength
? TextFrameIndex(0) : nFollow
);
379 // aExpand has not yet been shortened; the new Ofst is a
381 TextFrameIndex nNextOfst
= TextFrameIndex(m_aExpand
.getLength()) - nRest
;
383 if ( IsQuoVadisPortion() )
384 nNextOfst
= nNextOfst
+ TextFrameIndex(static_cast<SwQuoVadisPortion
*>(this)->GetContText().getLength());
386 OUString
aNew( m_aExpand
.copy(sal_Int32(nNextOfst
)) );
387 m_aExpand
= m_aExpand
.copy(0, sal_Int32(nNextOfst
));
389 // These characters should not be contained in the follow
390 // field portion. They are handled via the HookChar mechanism.
391 const sal_Unicode nNew
= !aNew
.isEmpty() ? aNew
[0] : 0;
394 case CH_BREAK
: bFull
= true;
398 case CHAR_HARDHYPHEN
: // non-breaking hyphen
399 case CHAR_SOFTHYPHEN
:
403 case CH_TXTATR_BREAKWORD
:
404 case CH_TXTATR_INWORD
:
406 aNew
= aNew
.copy( 1 );
413 // Even if there is no more text left for a follow field,
414 // we have to build a follow field portion (without font),
415 // otherwise the HookChar mechanism would not work.
416 SwFieldPortion
*pField
= Clone( aNew
);
417 if( !aNew
.isEmpty() && !pField
->GetFont() )
419 pField
->SetFont( std::make_unique
<SwFont
>( *rInf
.GetFont() ) );
421 pField
->SetFollow( true );
422 SetHasFollow( true );
424 // For a newly created field, nNextOffset contains the Offset
425 // of its start of the original string
426 // If a FollowField is created when formatting, this FollowField's
427 // Offset is being held in nNextOffset
428 m_nNextOffset
= m_nNextOffset
+ nNextOfst
;
429 pField
->SetNextOffset( m_nNextOffset
);
430 rInf
.SetRest( pField
);
434 if( bEOL
&& rInf
.GetLast() && !rInf
.GetUnderflow() )
435 rInf
.GetLast()->FormatEOL( rInf
);
439 void SwFieldPortion::Paint( const SwTextPaintInfo
&rInf
) const
441 SwFontSave
aSave( rInf
, m_pFont
.get() );
443 // OSL_ENSURE(GetLen() <= TextFrameIndex(1), "SwFieldPortion::Paint: rest-portion pollution?");
444 if( Width() && ( !m_bPlaceHolder
|| rInf
.GetOpt().IsShowPlaceHolderFields() ) )
446 // A very liberal use of the background
447 rInf
.DrawViewOpt( *this, PortionType::Field
);
448 SwExpandPortion::Paint( rInf
);
452 bool SwFieldPortion::GetExpText( const SwTextSizeInfo
&rInf
, OUString
&rText
) const
455 if( rText
.isEmpty() && rInf
.OnWin() &&
456 !rInf
.GetOpt().IsPagePreview() && !rInf
.GetOpt().IsReadonly() &&
457 SwViewOption::IsFieldShadings() &&
463 void SwFieldPortion::HandlePortion( SwPortionHandler
& rPH
) const
469 nH
= m_pFont
->GetSize(m_pFont
->GetActual()).Height();
470 nW
= m_pFont
->GetSize(m_pFont
->GetActual()).Width();
472 rPH
.Special( GetLen(), m_aExpand
, GetWhichPor(), nH
, nW
, m_pFont
.get() );
475 SwPosSize
SwFieldPortion::GetTextSize( const SwTextSizeInfo
&rInf
) const
477 SwFontSave
aSave( rInf
, m_pFont
.get() );
478 SwPosSize
aSize( SwExpandPortion::GetTextSize( rInf
) );
482 SwFieldPortion
*SwHiddenPortion::Clone(const OUString
&rExpand
) const
484 std::unique_ptr
<SwFont
> pNewFnt
;
486 pNewFnt
.reset(new SwFont( *m_pFont
));
487 return new SwHiddenPortion( rExpand
, std::move(pNewFnt
) );
490 void SwHiddenPortion::Paint( const SwTextPaintInfo
&rInf
) const
494 SwFontSave
aSave( rInf
, m_pFont
.get() );
495 rInf
.DrawViewOpt( *this, PortionType::Hidden
);
496 SwExpandPortion::Paint( rInf
);
500 bool SwHiddenPortion::GetExpText( const SwTextSizeInfo
&rInf
, OUString
&rText
) const
502 // Do not query for IsHidden()!
503 return SwFieldPortion::GetExpText( rInf
, rText
);
506 SwNumberPortion::SwNumberPortion( const OUString
&rExpand
,
507 std::unique_ptr
<SwFont
> pFont
,
510 const sal_uInt16 nMinDst
,
511 const bool bLabelAlignmentPosAndSpaceModeActive
)
512 : SwFieldPortion( rExpand
, std::move(pFont
) ),
514 m_nMinDist( nMinDst
),
515 mbLabelAlignmentPosAndSpaceModeActive( bLabelAlignmentPosAndSpaceModeActive
)
517 SetWhichPor( PortionType::Number
);
523 TextFrameIndex
SwNumberPortion::GetModelPositionForViewPoint(const sal_uInt16
) const
525 return TextFrameIndex(0);
528 SwFieldPortion
*SwNumberPortion::Clone( const OUString
&rExpand
) const
530 std::unique_ptr
<SwFont
> pNewFnt
;
532 pNewFnt
.reset(new SwFont( *m_pFont
));
534 return new SwNumberPortion( rExpand
, std::move(pNewFnt
), IsLeft(), IsCenter(),
535 m_nMinDist
, mbLabelAlignmentPosAndSpaceModeActive
);
539 * We can create multiple NumFields
540 * Tricky, if one enters enough previous-text in the dialog box
541 * to cause the line to overflow
542 * We need to keep the Fly's evasion tactics in mind
544 bool SwNumberPortion::Format( SwTextFormatInfo
&rInf
)
547 const bool bFull
= SwFieldPortion::Format( rInf
);
548 SetLen(TextFrameIndex(0));
549 // a numbering portion can be contained in a rotated portion!!!
550 m_nFixWidth
= rInf
.IsMulti() ? Height() : Width();
551 rInf
.SetNumDone( !rInf
.GetRest() );
552 if( rInf
.IsNumDone() )
554 // SetAscent( rInf.GetAscent() );
555 OSL_ENSURE( Height() && mnAscent
, "NumberPortions without Height | Ascent" );
557 tools::Long
nDiff( 0 );
559 if ( !mbLabelAlignmentPosAndSpaceModeActive
)
561 if (!rInf
.GetTextFrame()->GetDoc().getIDocumentSettingAccess().get(DocumentSettingId::IGNORE_FIRST_LINE_INDENT_IN_NUMBERING
) &&
563 !IsFootnoteNumPortion() )
566 + rInf
.GetTextFrame()->GetTextNodeForParaProps()->
567 GetSwAttrSet().GetLRSpace().GetTextFirstLineOffset()
569 + rInf
.ForcedLeftMargin();
573 nDiff
= rInf
.Left() - rInf
.First() + rInf
.ForcedLeftMargin();
576 // The text part of the numbering should always at least
577 // start at the left margin
580 else if ( nDiff
> rInf
.X() )
585 if( nDiff
< m_nFixWidth
+ m_nMinDist
)
586 nDiff
= m_nFixWidth
+ m_nMinDist
;
588 // Numbering evades the Fly, no nDiff in the second round
589 // Tricky special case: FlyFrame is in an Area we're just about to
591 // The NumberPortion is marked as hidden
592 const bool bFly
= rInf
.GetFly() ||
593 ( rInf
.GetLast() && rInf
.GetLast()->IsFlyPortion() );
594 if( nDiff
> rInf
.Width() )
596 nDiff
= rInf
.Width();
601 // A numbering portion can be inside a SwRotatedPortion. Then the
602 // Height has to be changed
603 if ( rInf
.IsMulti() )
605 if ( Height() < nDiff
)
608 else if( Width() < nDiff
)
616 * A FormatEOL indicates that the subsequent text did not fit onto
617 * the line anymore. In order for the Numbering to follow through,
618 * we hide this NumberPortion
620 void SwNumberPortion::FormatEOL( SwTextFormatInfo
& )
623 // This caused trouble with flys anchored as characters.
624 // If one of these is numbered but does not fit to the line,
625 // it calls this function, causing a loop because both the number
626 // portion and the fly portion go to the next line
632 * A hidden NumberPortion is not displayed, unless there are TextPortions in
633 * this line or there's just one line at all
635 void SwNumberPortion::Paint( const SwTextPaintInfo
&rInf
) const
637 if ( IsHide() && rInf
.GetParaPortion() && rInf
.GetParaPortion()->GetNext() )
639 SwLinePortion
*pTmp
= GetNextPortion();
640 while ( pTmp
&& !pTmp
->InTextGrp() )
641 pTmp
= pTmp
->GetNextPortion();
646 // calculate the width of the number portion, including follows
647 const sal_uInt16 nOldWidth
= Width();
648 sal_uInt16 nSumWidth
= 0;
649 sal_uInt16 nOffset
= 0;
651 const SwLinePortion
* pTmp
= this;
652 while ( pTmp
&& pTmp
->InNumberGrp() )
654 nSumWidth
= nSumWidth
+ pTmp
->Width();
655 if ( static_cast<const SwNumberPortion
*>(pTmp
)->HasFollow() )
656 pTmp
= pTmp
->GetNextPortion();
659 nOffset
= pTmp
->Width() - static_cast<const SwNumberPortion
*>(pTmp
)->m_nFixWidth
;
664 // The master portion takes care for painting the background of the
665 // follow field portions
668 SwNumberPortion
*pThis
= const_cast<SwNumberPortion
*>(this);
669 pThis
->Width( nSumWidth
);
670 rInf
.DrawViewOpt( *this, PortionType::Number
);
671 pThis
->Width( nOldWidth
);
674 if( m_aExpand
.isEmpty() )
677 const SwFont
*pTmpFnt
= rInf
.GetFont();
678 bool bPaintSpace
= ( LINESTYLE_NONE
!= pTmpFnt
->GetUnderline() ||
679 LINESTYLE_NONE
!= pTmpFnt
->GetOverline() ||
680 STRIKEOUT_NONE
!= pTmpFnt
->GetStrikeout() ) &&
681 !pTmpFnt
->IsWordLineMode();
682 if( bPaintSpace
&& m_pFont
)
683 bPaintSpace
= ( LINESTYLE_NONE
!= m_pFont
->GetUnderline() ||
684 LINESTYLE_NONE
!= m_pFont
->GetOverline() ||
685 STRIKEOUT_NONE
!= m_pFont
->GetStrikeout() ) &&
686 !m_pFont
->IsWordLineMode();
688 SwFontSave
aSave( rInf
, m_pFont
.get() );
690 if( m_nFixWidth
== Width() && ! HasFollow() )
691 SwExpandPortion::Paint( rInf
);
694 // logical const: reset width
695 SwNumberPortion
*pThis
= const_cast<SwNumberPortion
*>(this);
696 bPaintSpace
= bPaintSpace
&& m_nFixWidth
< nOldWidth
;
697 sal_uInt16 nSpaceOffs
= m_nFixWidth
;
698 pThis
->Width( m_nFixWidth
);
700 if( ( IsLeft() && ! rInf
.GetTextFrame()->IsRightToLeft() ) ||
701 ( ! IsLeft() && ! IsCenter() && rInf
.GetTextFrame()->IsRightToLeft() ) )
702 SwExpandPortion::Paint( rInf
);
705 SwTextPaintInfo
aInf( rInf
);
706 if( nOffset
< m_nMinDist
)
712 /* #110778# a / 2 * 2 == a is not a tautology */
713 sal_uInt16 nTmpOffset
= nOffset
;
715 if( nOffset
< m_nMinDist
)
716 nOffset
= nTmpOffset
- m_nMinDist
;
719 nOffset
= nOffset
- m_nMinDist
;
721 aInf
.X( aInf
.X() + nOffset
);
722 SwExpandPortion::Paint( aInf
);
724 nSpaceOffs
= nSpaceOffs
+ nOffset
;
726 if( bPaintSpace
&& nOldWidth
> nSpaceOffs
)
728 SwTextPaintInfo
aInf( rInf
);
729 aInf
.X( aInf
.X() + nSpaceOffs
);
731 // #i53199# Adjust position of underline:
732 if ( rInf
.GetUnderFnt() )
734 const Point
aNewPos( aInf
.GetPos().X(), rInf
.GetUnderFnt()->GetPos().Y() );
735 rInf
.GetUnderFnt()->SetPos( aNewPos
);
738 pThis
->Width( nOldWidth
- nSpaceOffs
+ 12 );
740 SwTextSlot
aDiffText( &aInf
, this, true, false, " " );
741 aInf
.DrawText( *this, aInf
.GetLen(), true );
744 pThis
->Width( nOldWidth
);
748 SwBulletPortion::SwBulletPortion( const sal_UCS4 cBullet
,
749 std::u16string_view rBulletFollowedBy
,
750 std::unique_ptr
<SwFont
> pFont
,
753 const sal_uInt16 nMinDst
,
754 const bool bLabelAlignmentPosAndSpaceModeActive
)
755 : SwNumberPortion( OUString(&cBullet
, 1) + rBulletFollowedBy
,
756 std::move(pFont
), bLft
, bCntr
, nMinDst
,
757 bLabelAlignmentPosAndSpaceModeActive
)
759 SetWhichPor( PortionType::Bullet
);
762 #define GRFNUM_SECURE 10
764 SwGrfNumPortion::SwGrfNumPortion(
765 const OUString
& rGraphicFollowedBy
,
766 const SvxBrushItem
* pGrfBrush
, OUString
const & referer
,
767 const SwFormatVertOrient
* pGrfOrient
, const Size
& rGrfSize
,
768 const bool bLft
, const bool bCntr
, const sal_uInt16 nMinDst
,
769 const bool bLabelAlignmentPosAndSpaceModeActive
) :
770 SwNumberPortion( rGraphicFollowedBy
, nullptr, bLft
, bCntr
, nMinDst
,
771 bLabelAlignmentPosAndSpaceModeActive
),
772 m_pBrush( new SvxBrushItem(RES_BACKGROUND
) ), m_nId( 0 )
774 SetWhichPor( PortionType::GrfNum
);
775 SetAnimated( false );
779 m_pBrush
.reset(pGrfBrush
->Clone());
780 const Graphic
* pGraph
= pGrfBrush
->GetGraphic(referer
);
782 SetAnimated( pGraph
->IsAnimated() );
788 m_nYPos
= pGrfOrient
->GetPos();
789 m_eOrient
= pGrfOrient
->GetVertOrient();
794 m_eOrient
= text::VertOrientation::TOP
;
796 Width( rGrfSize
.Width() + 2 * GRFNUM_SECURE
);
797 m_nFixWidth
= Width();
798 m_nGrfHeight
= rGrfSize
.Height() + 2 * GRFNUM_SECURE
;
799 Height( sal_uInt16(m_nGrfHeight
) );
803 SwGrfNumPortion::~SwGrfNumPortion()
807 Graphic
* pGraph
= const_cast<Graphic
*>(m_pBrush
->GetGraphic());
809 pGraph
->StopAnimation( nullptr, m_nId
);
814 void SwGrfNumPortion::StopAnimation( const OutputDevice
* pOut
)
818 Graphic
* pGraph
= const_cast<Graphic
*>(m_pBrush
->GetGraphic());
820 pGraph
->StopAnimation( pOut
, m_nId
);
824 bool SwGrfNumPortion::Format( SwTextFormatInfo
&rInf
)
827 // Width( nFixWidth );
828 sal_uInt16
nFollowedByWidth( 0 );
829 if ( mbLabelAlignmentPosAndSpaceModeActive
)
831 SwFieldPortion::Format( rInf
);
832 nFollowedByWidth
= Width();
833 SetLen(TextFrameIndex(0));
835 Width( m_nFixWidth
+ nFollowedByWidth
);
836 const bool bFull
= rInf
.Width() < rInf
.X() + Width();
837 const bool bFly
= rInf
.GetFly() ||
838 ( rInf
.GetLast() && rInf
.GetLast()->IsFlyPortion() );
839 SetAscent( GetRelPos() > 0 ? GetRelPos() : 0 );
840 if( GetAscent() > Height() )
841 Height( GetAscent() );
845 Width( rInf
.Width() - rInf
.X() );
848 SetLen(TextFrameIndex(0));
850 rInf
.SetNumDone( false );
854 rInf
.SetNumDone( true );
855 // long nDiff = rInf.Left() - rInf.First() + rInf.ForcedLeftMargin();
856 tools::Long nDiff
= mbLabelAlignmentPosAndSpaceModeActive
858 : rInf
.Left() - rInf
.First() + rInf
.ForcedLeftMargin();
859 // The TextPortion should at least always start on the
863 else if ( nDiff
> rInf
.X() )
865 if( nDiff
< m_nFixWidth
+ m_nMinDist
)
866 nDiff
= m_nFixWidth
+ m_nMinDist
;
868 // Numbering evades Fly, no nDiff in the second round
869 // Tricky special case: FlyFrame is in the Area we were just
870 // about to get a hold of.
871 // The NumberPortion is marked as hidden
872 if( nDiff
> rInf
.Width() )
874 nDiff
= rInf
.Width();
879 if( Width() < nDiff
)
886 * A hidden NumberPortion is not displayed, unless there are TextPortions in
887 * this line or there's only one line at all
889 void SwGrfNumPortion::Paint( const SwTextPaintInfo
&rInf
) const
893 if ( IsHide() && rInf
.GetParaPortion() && rInf
.GetParaPortion()->GetNext() )
895 SwLinePortion
*pTmp
= GetNextPortion();
896 while ( pTmp
&& !pTmp
->InTextGrp() )
897 pTmp
= pTmp
->GetNextPortion();
901 Point
aPos( rInf
.X() + GRFNUM_SECURE
, rInf
.Y() - GetRelPos() + GRFNUM_SECURE
);
902 tools::Long nTmpWidth
= std::max( tools::Long(0), static_cast<tools::Long
>(m_nFixWidth
- 2 * GRFNUM_SECURE
) );
903 Size
aSize( nTmpWidth
, GetGrfHeight() - 2 * GRFNUM_SECURE
);
905 const bool bTmpLeft
= mbLabelAlignmentPosAndSpaceModeActive
||
906 ( IsLeft() && ! rInf
.GetTextFrame()->IsRightToLeft() ) ||
907 ( ! IsLeft() && ! IsCenter() && rInf
.GetTextFrame()->IsRightToLeft() );
909 if( m_nFixWidth
< Width() && !bTmpLeft
)
911 sal_uInt16 nOffset
= Width() - m_nFixWidth
;
912 if( nOffset
< m_nMinDist
)
919 if( nOffset
< m_nMinDist
)
920 nOffset
= Width() - m_nFixWidth
- m_nMinDist
;
923 nOffset
= nOffset
- m_nMinDist
;
925 aPos
.AdjustX(nOffset
);
930 const tools::Long nTmpH
= GetNextPortion() ? GetNextPortion()->GetAscent() : 120;
931 aSize
= Size( nTmpH
, nTmpH
);
932 aPos
.setY( rInf
.Y() - nTmpH
);
934 SwRect
aTmp( aPos
, aSize
);
940 bDraw
= !rInf
.GetOpt().IsGraphic();
943 SetId( reinterpret_cast<sal_IntPtr
>( rInf
.GetTextFrame() ) );
944 rInf
.GetTextFrame()->SetAnimation();
946 if( aTmp
.Overlaps( rInf
.GetPaintRect() ) && !bDraw
)
948 rInf
.NoteAnimation();
949 const SwViewShell
* pViewShell
= rInf
.GetVsh();
951 // virtual device, not pdf export
952 if( OUTDEV_VIRDEV
== rInf
.GetOut()->GetOutDevType() &&
953 pViewShell
&& pViewShell
->GetWin() )
955 Graphic
* pGraph
= const_cast<Graphic
*>(m_pBrush
->GetGraphic());
957 pGraph
->StopAnimation(nullptr,m_nId
);
958 rInf
.GetTextFrame()->getRootFrame()->GetCurrShell()->InvalidateWindows( aTmp
);
961 else if ( pViewShell
&&
962 !pViewShell
->GetAccessibilityOptions()->IsStopAnimatedGraphics() &&
963 !pViewShell
->IsPreview() &&
964 // #i9684# Stop animation during printing/pdf export.
965 pViewShell
->GetWin() )
967 Graphic
* pGraph
= const_cast<Graphic
*>(m_pBrush
->GetGraphic());
970 const OutputDevice
* pOut
= rInf
.GetOut();
972 pGraph
->StartAnimation(
973 *const_cast<OutputDevice
*>(pOut
), aPos
, aSize
, m_nId
);
977 // pdf export, printing, preview, stop animations...
984 Graphic
* pGraph
= const_cast<Graphic
*>(m_pBrush
->GetGraphic());
986 pGraph
->StopAnimation( nullptr, m_nId
);
990 SwRect
aRepaint( rInf
.GetPaintRect() );
991 const SwTextFrame
& rFrame
= *rInf
.GetTextFrame();
992 if( rFrame
.IsVertical() )
994 rFrame
.SwitchHorizontalToVertical( aTmp
);
995 rFrame
.SwitchHorizontalToVertical( aRepaint
);
998 if( rFrame
.IsRightToLeft() )
1000 rFrame
.SwitchLTRtoRTL( aTmp
);
1001 rFrame
.SwitchLTRtoRTL( aRepaint
);
1004 if( bDraw
&& aTmp
.HasArea() )
1006 const OutputDevice
* pOut
= rInf
.GetOut();
1008 DrawGraphic( m_pBrush
.get(), *const_cast<OutputDevice
*>(pOut
),
1009 aTmp
, aRepaint
, m_bReplace
? GRFNUM_REPLACE
: GRFNUM_YES
);
1013 void SwGrfNumPortion::SetBase( tools::Long nLnAscent
, tools::Long nLnDescent
,
1014 tools::Long nFlyAsc
, tools::Long nFlyDesc
)
1016 if ( GetOrient() == text::VertOrientation::NONE
)
1020 if ( GetOrient() == text::VertOrientation::CENTER
)
1021 SetRelPos( GetGrfHeight() / 2 );
1022 else if ( GetOrient() == text::VertOrientation::TOP
)
1023 SetRelPos( GetGrfHeight() - GRFNUM_SECURE
);
1024 else if ( GetOrient() == text::VertOrientation::BOTTOM
)
1026 else if ( GetOrient() == text::VertOrientation::CHAR_CENTER
)
1027 SetRelPos( ( GetGrfHeight() + nLnAscent
- nLnDescent
) / 2 );
1028 else if ( GetOrient() == text::VertOrientation::CHAR_TOP
)
1029 SetRelPos( nLnAscent
);
1030 else if ( GetOrient() == text::VertOrientation::CHAR_BOTTOM
)
1031 SetRelPos( GetGrfHeight() - nLnDescent
);
1034 if( GetGrfHeight() >= nFlyAsc
+ nFlyDesc
)
1036 // If I'm as large as the line, I do not need to adjust
1037 // at the line; I'll leave the max. ascent unchanged
1038 SetRelPos( nFlyAsc
);
1040 else if ( GetOrient() == text::VertOrientation::LINE_CENTER
)
1041 SetRelPos( ( GetGrfHeight() + nFlyAsc
- nFlyDesc
) / 2 );
1042 else if ( GetOrient() == text::VertOrientation::LINE_TOP
)
1043 SetRelPos( nFlyAsc
);
1044 else if ( GetOrient() == text::VertOrientation::LINE_BOTTOM
)
1045 SetRelPos( GetGrfHeight() - nFlyDesc
);
1049 void SwTextFrame::StopAnimation( const OutputDevice
* pOut
)
1051 OSL_ENSURE( HasAnimation(), "SwTextFrame::StopAnimation: Which Animation?" );
1055 SwLineLayout
*pLine
= GetPara();
1058 SwLinePortion
*pPor
= pLine
->GetNextPortion();
1061 if( pPor
->IsGrfNumPortion() )
1062 static_cast<SwGrfNumPortion
*>(pPor
)->StopAnimation( pOut
);
1063 // The NumberPortion is always at the first char,
1064 // which means we can cancel as soon as we've reached a portion
1065 // with a length > 0
1066 pPor
= pPor
->GetLen() ? nullptr : pPor
->GetNextPortion();
1068 pLine
= pLine
->GetLen() ? nullptr : pLine
->GetNext();
1073 * Initializes the script array and clears the width array
1075 SwCombinedPortion::SwCombinedPortion( const OUString
&rText
)
1076 : SwFieldPortion( rText
)
1077 , m_aWidth
{ static_cast<sal_uInt16
>(0),
1078 static_cast<sal_uInt16
>(0),
1079 static_cast<sal_uInt16
>(0) }
1084 SetLen(TextFrameIndex(1));
1085 SetWhichPor( PortionType::Combined
);
1086 if( m_aExpand
.getLength() > 6 )
1087 m_aExpand
= m_aExpand
.copy( 0, 6 );
1089 // Initialization of the scripttype array,
1090 // the arrays of width and position are filled by the format function
1091 assert(g_pBreakIt
&& g_pBreakIt
->GetBreakIter().is());
1093 SwFontScript nScr
= SW_SCRIPTS
;
1094 for( sal_Int32 i
= 0; i
< rText
.getLength(); ++i
)
1096 switch ( g_pBreakIt
->GetBreakIter()->getScriptType( rText
, i
) ) {
1097 case i18n::ScriptType::LATIN
: nScr
= SwFontScript::Latin
; break;
1098 case i18n::ScriptType::ASIAN
: nScr
= SwFontScript::CJK
; break;
1099 case i18n::ScriptType::COMPLEX
: nScr
= SwFontScript::CTL
; break;
1101 m_aScrType
[i
] = nScr
;
1105 void SwCombinedPortion::Paint( const SwTextPaintInfo
&rInf
) const
1107 OSL_ENSURE(GetLen() <= TextFrameIndex(1), "SwFieldPortion::Paint: rest-portion pollution?");
1111 rInf
.DrawBackBrush( *this );
1112 rInf
.DrawViewOpt( *this, PortionType::Field
);
1114 // do we have to repaint a post it portion?
1115 if( rInf
.OnWin() && mpNextPortion
&& !mpNextPortion
->Width() )
1116 mpNextPortion
->PrePaint( rInf
, this );
1118 const sal_Int32 nCount
= m_aExpand
.getLength();
1121 OSL_ENSURE( nCount
< 7, "Too much combined characters" );
1123 // the first character of the second row
1124 const sal_Int32 nTop
= ( nCount
+ 1 ) / 2;
1126 SwFont
aTmpFont( *rInf
.GetFont() );
1127 aTmpFont
.SetProportion( m_nProportion
); // a smaller font
1128 SwFontSave
aFontSave( rInf
, &aTmpFont
);
1130 Point aOldPos
= rInf
.GetPos();
1131 Point
aOutPos( aOldPos
.X(), aOldPos
.Y() - m_nUpPos
);// Y of the first row
1132 for( sal_Int32 i
= 0 ; i
< nCount
; ++i
)
1134 if( i
== nTop
) // change the row
1135 aOutPos
.setY( aOldPos
.Y() + m_nLowPos
); // Y of the second row
1136 aOutPos
.setX( aOldPos
.X() + m_aPos
[i
] ); // X position
1137 const SwFontScript nAct
= m_aScrType
[i
]; // script type
1138 aTmpFont
.SetActual( nAct
);
1140 // if there're more than 4 characters to display, we choose fonts
1141 // with 2/3 of the original font width.
1142 if( m_aWidth
[ nAct
] )
1144 Size aTmpSz
= aTmpFont
.GetSize( nAct
);
1145 if( aTmpSz
.Width() != m_aWidth
[ nAct
] )
1147 aTmpSz
.setWidth( m_aWidth
[ nAct
] );
1148 aTmpFont
.SetSize( aTmpSz
, nAct
);
1151 const_cast<SwTextPaintInfo
&>(rInf
).SetPos( aOutPos
);
1152 rInf
.DrawText(m_aExpand
, *this, TextFrameIndex(i
), TextFrameIndex(1));
1154 // rInf is const, so we have to take back our manipulations
1155 const_cast<SwTextPaintInfo
&>(rInf
).SetPos( aOldPos
);
1159 bool SwCombinedPortion::Format( SwTextFormatInfo
&rInf
)
1161 const sal_Int32 nCount
= m_aExpand
.getLength();
1168 OSL_ENSURE( nCount
< 7, "Too much combined characters" );
1170 // If there are leading "weak"-scripttyped characters in this portion,
1171 // they get the actual scripttype.
1172 for( sal_Int32 i
= 0; i
< nCount
&& SW_SCRIPTS
== m_aScrType
[i
]; ++i
)
1173 m_aScrType
[i
] = rInf
.GetFont()->GetActual();
1176 // more than four? Ok, then we need the 2/3 font width
1177 for( sal_Int32 i
= 0; i
< m_aExpand
.getLength(); ++i
)
1179 OSL_ENSURE( m_aScrType
[i
] < SW_SCRIPTS
, "Combined: Script fault" );
1180 if( !m_aWidth
[ m_aScrType
[i
] ] )
1182 rInf
.GetOut()->SetFont( rInf
.GetFont()->GetFnt( m_aScrType
[i
] ) );
1183 m_aWidth
[ m_aScrType
[i
] ] =
1184 o3tl::narrowing
<sal_uInt16
>(2 * rInf
.GetOut()->GetFontMetric().GetFontSize().Width() / 3);
1189 const sal_Int32 nTop
= ( nCount
+ 1 ) / 2; // the first character of the second line
1190 SwViewShell
*pSh
= rInf
.GetTextFrame()->getRootFrame()->GetCurrShell();
1191 SwFont
aTmpFont( *rInf
.GetFont() );
1192 SwFontSave
aFontSave( rInf
, &aTmpFont
);
1194 // In nMainAscent/Descent we store the ascent and descent
1195 // of the original surrounding font
1196 sal_uInt16 nMaxDescent
, nMaxAscent
, nMaxWidth
;
1197 sal_uInt16 nMainDescent
= rInf
.GetFont()->GetHeight( pSh
, *rInf
.GetOut() );
1198 const sal_uInt16 nMainAscent
= rInf
.GetFont()->GetAscent( pSh
, *rInf
.GetOut() );
1199 nMainDescent
= nMainDescent
- nMainAscent
;
1200 // we start with a 50% font, but if we notice that the combined portion
1201 // becomes bigger than the surrounding font, we check 45% and maybe 40%.
1205 aTmpFont
.SetProportion( m_nProportion
);
1206 memset( &m_aPos
, 0, sizeof(m_aPos
) );
1210 m_nUpPos
= m_nLowPos
= 0;
1212 // Now we get the width of all characters.
1213 // The ascent and the width of the first line are stored in the
1214 // ascent member of the portion, the descent in nLowPos.
1215 // The ascent, descent and width of the second line are stored in the
1216 // local nMaxAscent, nMaxDescent and nMaxWidth variables.
1217 for( sal_Int32 i
= 0; i
< nCount
; ++i
)
1219 SwFontScript nScrp
= m_aScrType
[i
];
1220 aTmpFont
.SetActual( nScrp
);
1221 if( m_aWidth
[ nScrp
] )
1223 Size
aFontSize( aTmpFont
.GetSize( nScrp
) );
1224 aFontSize
.setWidth( m_aWidth
[ nScrp
] );
1225 aTmpFont
.SetSize( aFontSize
, nScrp
);
1228 SwDrawTextInfo
aDrawInf(pSh
, *rInf
.GetOut(), m_aExpand
, i
, 1);
1229 Size aSize
= aTmpFont
.GetTextSize_( aDrawInf
);
1230 const sal_uInt16 nAsc
= aTmpFont
.GetAscent( pSh
, *rInf
.GetOut() );
1231 m_aPos
[ i
] = o3tl::narrowing
<sal_uInt16
>(aSize
.Width());
1232 if( i
== nTop
) // enter the second line
1234 m_nLowPos
= nMaxDescent
;
1235 Height( nMaxDescent
+ nMaxAscent
);
1237 SetAscent( nMaxAscent
);
1242 nMaxWidth
= nMaxWidth
+ m_aPos
[ i
];
1243 if( nAsc
> nMaxAscent
)
1245 if( aSize
.Height() - nAsc
> nMaxDescent
)
1246 nMaxDescent
= aSize
.Height() - nAsc
;
1248 // for one or two characters we double the width of the portion
1255 Height( nMaxAscent
+ nMaxDescent
);
1256 m_nLowPos
= nMaxDescent
;
1259 Height( Height() + nMaxDescent
+ nMaxAscent
);
1260 m_nUpPos
= nMaxAscent
;
1261 SetAscent( Height() - nMaxDescent
- m_nLowPos
);
1262 } while( m_nProportion
> 40 && ( GetAscent() > nMainAscent
||
1263 Height() - GetAscent() > nMainDescent
) );
1264 // if the combined portion is smaller than the surrounding text,
1265 // the portion grows. This looks better, if there's a character background.
1266 if( GetAscent() < nMainAscent
)
1268 Height( Height() + nMainAscent
- GetAscent() );
1269 SetAscent( nMainAscent
);
1271 if( Height() < nMainAscent
+ nMainDescent
)
1272 Height( nMainAscent
+ nMainDescent
);
1274 // We calculate the x positions of the characters in both lines...
1275 sal_uInt16 nTopDiff
= 0;
1276 sal_uInt16 nBotDiff
= 0;
1277 if( nMaxWidth
> Width() )
1279 nTopDiff
= ( nMaxWidth
- Width() ) / 2;
1283 nBotDiff
= ( Width() - nMaxWidth
) / 2;
1286 case 3: m_aPos
[1] = m_aPos
[0] + nTopDiff
;
1288 case 2: m_aPos
[nTop
-1] = Width() - m_aPos
[nTop
-1];
1293 case 5: m_aPos
[4] = m_aPos
[3] + nBotDiff
;
1295 case 3: m_aPos
[nTop
] = nBotDiff
; break;
1296 case 6: m_aPos
[4] = m_aPos
[3] + nBotDiff
;
1298 case 4: m_aPos
[nTop
] = 0;
1300 case 2: m_aPos
[nCount
-1] = Width() - m_aPos
[nCount
-1];
1303 // Does the combined portion fit the line?
1304 const bool bFull
= rInf
.Width() < rInf
.X() + Width();
1307 if( rInf
.GetLineStart() == rInf
.GetIdx() && (!rInf
.GetLast()->InFieldGrp()
1308 || !static_cast<SwFieldPortion
*>(rInf
.GetLast())->IsFollow() ) )
1309 Width( rInf
.Width() - rInf
.X() );
1314 SetLen(TextFrameIndex(0));
1315 if( rInf
.GetLast() )
1316 rInf
.GetLast()->FormatEOL( rInf
);
1322 sal_uInt16
SwCombinedPortion::GetViewWidth( const SwTextSizeInfo
&rInf
) const
1324 if( !GetLen() ) // for the dummy part at the end of the line, where
1325 return 0; // the combined portion doesn't fit.
1326 return SwFieldPortion::GetViewWidth( rInf
);
1329 SwFieldPortion
*SwFieldFormDropDownPortion::Clone(const OUString
&rExpand
) const
1331 return new SwFieldFormDropDownPortion(m_pFieldMark
, rExpand
);
1334 void SwFieldFormDropDownPortion::Paint( const SwTextPaintInfo
&rInf
) const
1336 SwFieldPortion::Paint( rInf
);
1338 ::sw::mark::DropDownFieldmark
* pDropDownField
= dynamic_cast< ::sw::mark::DropDownFieldmark
* >(m_pFieldMark
);
1342 rInf
.CalcRect( *this, &aPaintArea
);
1343 pDropDownField
->SetPortionPaintArea(aPaintArea
);
1347 SwFieldPortion
*SwFieldFormDatePortion::Clone(const OUString
&/*rExpand*/) const
1349 return new SwFieldFormDatePortion(m_pFieldMark
, m_bStart
);
1352 void SwFieldFormDatePortion::Paint( const SwTextPaintInfo
&rInf
) const
1354 SwFieldPortion::Paint( rInf
);
1356 ::sw::mark::DateFieldmark
* pDateField
= dynamic_cast< ::sw::mark::DateFieldmark
* >(m_pFieldMark
);
1360 rInf
.CalcRect( *this, &aPaintArea
);
1362 pDateField
->SetPortionPaintAreaStart(aPaintArea
);
1364 pDateField
->SetPortionPaintAreaEnd(aPaintArea
);
1368 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */