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 <editeng/lspcitem.hxx>
21 #include <editeng/adjustitem.hxx>
22 #include <editeng/escapementitem.hxx>
23 #include <editeng/lrspitem.hxx>
24 #include <editeng/pgrditem.hxx>
25 #include <editeng/fontitem.hxx>
26 #include <vcl/svapp.hxx>
27 #include <comphelper/scopeguard.hxx>
30 #include <viewopt.hxx>
32 #include <pagefrm.hxx>
34 #include <SwPortionHandler.hxx>
37 #include "txtpaint.hxx"
38 #include <swfntcch.hxx>
39 #include <tgrditem.hxx>
40 #include <pagedesc.hxx>
42 #include "redlnitr.hxx"
43 #include "atrhndl.hxx"
44 #include <rootfrm.hxx>
45 #include <formatlinebreak.hxx>
46 #include <txatbase.hxx>
48 #include <IDocumentRedlineAccess.hxx>
49 #include <IDocumentSettingAccess.hxx>
50 #include <IDocumentDeviceAccess.hxx>
51 #include <IDocumentLayoutAccess.hxx>
54 #include <swtypes.hxx>
55 #include <strings.hrc>
56 #include <flyfrms.hxx>
57 #include <bodyfrm.hxx>
59 SwTmpEndPortion::SwTmpEndPortion( const SwLinePortion
&rPortion
,
60 const FontLineStyle eUL
,
61 const FontStrikeout eStrkout
,
63 m_eUnderline( eUL
), m_eStrikeout( eStrkout
), m_aColor( rCol
)
65 Height( rPortion
.Height() );
66 SetAscent( rPortion
.GetAscent() );
67 SetWhichPor( PortionType::TempEnd
);
70 void SwTmpEndPortion::Paint( const SwTextPaintInfo
&rInf
) const
72 if (!(rInf
.OnWin() && rInf
.GetOpt().IsParagraph()))
75 const SwFont
* pOldFnt
= rInf
.GetFont();
77 SwFont
aFont(*pOldFnt
);
79 const SwDoc
& rDoc
= rInf
.GetTextFrame()->GetDoc();
80 if (aFont
.IsSymbol(rDoc
.getIDocumentLayoutAccess().GetCurrentViewShell()))
82 const SvxFontItem
& rFontItem
= rDoc
.GetDefault(RES_CHRATR_FONT
);
83 aFont
.SetName( rFontItem
.GetFamilyName(), SwFontScript::Latin
);
84 aFont
.SetStyleName( rFontItem
.GetStyleName(), SwFontScript::Latin
);
85 aFont
.SetFamily( rFontItem
.GetFamily(), SwFontScript::Latin
);
86 aFont
.SetPitch( rFontItem
.GetPitch(), SwFontScript::Latin
);
87 aFont
.SetCharSet( rFontItem
.GetCharSet(), SwFontScript::Latin
);
89 // Paint strikeout/underline based on redline color and settings
90 // (with an extra pilcrow in the background, because there is
91 // no SetStrikeoutColor(), also SetUnderColor() doesn't work()).
92 if ( m_eUnderline
!= LINESTYLE_NONE
|| m_eStrikeout
!= STRIKEOUT_NONE
)
94 aFont
.SetColor( m_aColor
);
95 aFont
.SetUnderline( m_eUnderline
);
96 aFont
.SetStrikeout( m_eStrikeout
);
98 const_cast<SwTextPaintInfo
&>(rInf
).SetFont(&aFont
);
100 // draw the pilcrow with strikeout/underline in redline color
101 rInf
.DrawText(CH_PAR
, *this);
105 aFont
.SetColor( SwViewOption::GetCurrentViewOptions().GetNonPrintingCharacterColor() );
106 aFont
.SetStrikeout( STRIKEOUT_NONE
);
107 aFont
.SetUnderline( LINESTYLE_NONE
);
108 const_cast<SwTextPaintInfo
&>(rInf
).SetFont(&aFont
);
111 rInf
.DrawText(CH_PAR
, *this);
113 const_cast<SwTextPaintInfo
&>(rInf
).SetFont(const_cast<SwFont
*>(pOldFnt
));
116 SwBreakPortion::SwBreakPortion( const SwLinePortion
&rPortion
, const SwTextAttr
* pAttr
)
117 : SwLinePortion( rPortion
)
119 mnLineLength
= TextFrameIndex(1);
120 m_eRedline
= RedlineType::None
;
121 SetWhichPor( PortionType::Break
);
123 m_eClear
= SwLineBreakClear::NONE
;
124 if (pAttr
&& pAttr
->Which() == RES_TXTATR_LINEBREAK
)
126 m_eClear
= pAttr
->GetLineBreak().GetValue();
131 TextFrameIndex
SwBreakPortion::GetModelPositionForViewPoint(const SwTwips
) const
133 return TextFrameIndex(0);
136 SwTwips
SwBreakPortion::GetViewWidth(const SwTextSizeInfo
&) const { return 0; }
138 SwLinePortion
*SwBreakPortion::Compress()
139 { return (GetNextPortion() && GetNextPortion()->InTextGrp() ? nullptr : this); }
141 void SwBreakPortion::Paint( const SwTextPaintInfo
&rInf
) const
143 if( !(rInf
.OnWin() && rInf
.GetOpt().IsLineBreak()) )
146 // Reduce height to text height for the duration of the print, so the vertical height will look
147 // correct for the line break character, even for clearing breaks.
148 SwTwips nHeight
= Height();
149 SwTwips nVertPosOffset
= (nHeight
- m_nTextHeight
) / 2;
150 auto pPortion
= const_cast<SwBreakPortion
*>(this);
151 pPortion
->Height(m_nTextHeight
, false);
152 if (rInf
.GetTextFrame()->IsVertical())
154 // Compensate for the offset done in SwTextCursor::AdjustBaseLine() for the vertical case.
155 const_cast<SwTextPaintInfo
&>(rInf
).Y(rInf
.Y() + nVertPosOffset
);
157 comphelper::ScopeGuard
g(
158 [pPortion
, nHeight
, &rInf
, nVertPosOffset
]
160 if (rInf
.GetTextFrame()->IsVertical())
162 const_cast<SwTextPaintInfo
&>(rInf
).Y(rInf
.Y() - nVertPosOffset
);
164 pPortion
->Height(nHeight
, false);
167 rInf
.DrawLineBreak( *this );
170 if (m_eRedline
== RedlineType::None
)
173 sal_Int16 nNoBreakWidth
= rInf
.GetTextSize(S_NOBREAK_FOR_REDLINE
).Width();
174 if ( nNoBreakWidth
> 0 )
176 // approximate portion size with multiple no-break spaces
177 // and draw these spaces (at least a single one) by DrawText
178 // painting the requested redline underline/strikeout
179 sal_Int16 nSpaces
= (LINE_BREAK_WIDTH
+ nNoBreakWidth
/2) / nNoBreakWidth
;
180 OUStringBuffer
aBuf(S_NOBREAK_FOR_REDLINE
);
181 for (sal_Int16 i
= 1; i
< nSpaces
; ++i
)
182 aBuf
.append(S_NOBREAK_FOR_REDLINE
);
184 const SwFont
* pOldFnt
= rInf
.GetFont();
186 SwFont
aFont(*pOldFnt
);
188 if (m_eRedline
== RedlineType::Delete
)
189 aFont
.SetUnderline( LINESTYLE_NONE
);
191 aFont
.SetStrikeout( STRIKEOUT_NONE
);
193 const_cast<SwTextPaintInfo
&>(rInf
).SetFont(&aFont
);
195 rInf
.DrawText(aBuf
.makeStringAndClear(), *this);
197 const_cast<SwTextPaintInfo
&>(rInf
).SetFont(const_cast<SwFont
*>(pOldFnt
));
201 bool SwBreakPortion::Format( SwTextFormatInfo
&rInf
)
203 const SwLinePortion
*pRoot
= rInf
.GetRoot();
205 Height( pRoot
->Height() );
206 m_nTextHeight
= Height();
208 // See if this is a clearing break. If so, calculate how much we need to "jump down" so the next
209 // line can again use the full text width.
210 SwLineBreakClear eClear
= m_eClear
;
211 if (rInf
.GetTextFrame()->IsRightToLeft() && eClear
!= SwLineBreakClear::ALL
)
213 // RTL ignores left/right breaks.
214 eClear
= SwLineBreakClear::NONE
;
216 if (eClear
!= SwLineBreakClear::NONE
)
218 SwTextFly
& rTextFly
= rInf
.GetTextFly();
221 SwTwips nHeight
= rTextFly
.GetMaxBottom(*this, rInf
) - rInf
.Y();
222 if (nHeight
> Height())
224 Height(nHeight
, /*bText=*/false);
229 SetAscent( pRoot
->GetAscent() );
230 if (rInf
.GetIdx() + TextFrameIndex(1) == TextFrameIndex(rInf
.GetText().getLength()))
231 rInf
.SetNewLine( true );
235 void SwBreakPortion::HandlePortion( SwPortionHandler
& rPH
) const
237 rPH
.Text( GetLen(), GetWhichPor() );
240 void SwBreakPortion::dumpAsXml(xmlTextWriterPtr pWriter
, const OUString
& rText
, TextFrameIndex
&
243 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwBreakPortion"));
244 dumpAsXmlAttributes(pWriter
, rText
, nOffset
);
247 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("text-height"),
248 BAD_CAST(OString::number(m_nTextHeight
).getStr()));
250 (void)xmlTextWriterEndElement(pWriter
);
253 SwLineBreakClear
SwBreakPortion::GetClear() const { return m_eClear
; }
255 SwKernPortion::SwKernPortion( SwLinePortion
&rPortion
, short nKrn
,
256 bool bBG
, bool bGK
) :
257 m_nKern( nKrn
), m_bBackground( bBG
), m_bGridKern( bGK
)
259 Height( rPortion
.Height() );
260 SetAscent( rPortion
.GetAscent() );
261 mnLineLength
= TextFrameIndex(0);
262 SetWhichPor( PortionType::Kern
);
265 rPortion
.Insert( this );
268 SwKernPortion::SwKernPortion( const SwLinePortion
& rPortion
) :
269 m_nKern( 0 ), m_bBackground( false ), m_bGridKern( true )
271 Height( rPortion
.Height() );
272 SetAscent( rPortion
.GetAscent() );
274 mnLineLength
= TextFrameIndex(0);
275 SetWhichPor( PortionType::Kern
);
278 void SwKernPortion::Paint( const SwTextPaintInfo
&rInf
) const
283 // bBackground is set for Kerning Portions between two fields
285 rInf
.DrawViewOpt( *this, PortionType::Field
);
287 rInf
.DrawBackBrush( *this );
288 if (GetJoinBorderWithNext() ||GetJoinBorderWithPrev())
289 rInf
.DrawBorder( *this );
291 // do we have to repaint a post it portion?
292 if( rInf
.OnWin() && mpNextPortion
&& !mpNextPortion
->Width() )
293 mpNextPortion
->PrePaint( rInf
, this );
295 if( rInf
.GetFont()->IsPaintBlank() )
298 rInf
.CalcRect( *this, &aClipRect
);
299 SwSaveClip
aClip( const_cast<OutputDevice
*>(rInf
.GetOut()) );
300 aClip
.ChgClip( aClipRect
);
301 rInf
.DrawText(u
" "_ustr
, *this, TextFrameIndex(0), TextFrameIndex(2), true );
305 void SwKernPortion::FormatEOL( SwTextFormatInfo
&rInf
)
310 if( rInf
.GetLast() == this )
311 rInf
.SetLast( FindPrevPortion( rInf
.GetRoot() ) );
316 rInf
.GetLast()->FormatEOL( rInf
);
319 SwArrowPortion::SwArrowPortion( const SwLinePortion
&rPortion
) :
322 Height( rPortion
.Height() );
323 SetAscent( rPortion
.GetAscent() );
324 mnLineLength
= TextFrameIndex(0);
325 SetWhichPor( PortionType::Arrow
);
328 SwArrowPortion::SwArrowPortion( const SwTextPaintInfo
&rInf
)
331 Height(rInf
.GetTextFrame()->getFramePrintArea().Height());
332 m_aPos
.setX( rInf
.GetTextFrame()->getFrameArea().Left() +
333 rInf
.GetTextFrame()->getFramePrintArea().Right() );
334 m_aPos
.setY( rInf
.GetTextFrame()->getFrameArea().Top() +
335 rInf
.GetTextFrame()->getFramePrintArea().Bottom() );
336 SetWhichPor( PortionType::Arrow
);
339 void SwArrowPortion::Paint( const SwTextPaintInfo
&rInf
) const
341 const_cast<SwArrowPortion
*>(this)->m_aPos
= rInf
.GetPos();
344 SwLinePortion
*SwArrowPortion::Compress() { return this; }
346 SwTwips
SwTextFrame::EmptyHeight() const
349 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
350 if ( auto pCrSh
= dynamic_cast<SwCursorShell
*>( pSh
) ) {
351 // this is called during formatting so avoid recursive layout
352 SwContentFrame
const*const pCurrFrame
= pCrSh
->GetCurrFrame(false);
353 if (pCurrFrame
==static_cast<SwContentFrame
const *>(this)) {
362 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTextFrame::EmptyHeight with swapped frame" );
364 std::unique_ptr
<SwFont
> pFnt
;
365 const SwTextNode
& rTextNode
= *GetTextNodeForParaProps();
366 const IDocumentSettingAccess
* pIDSA
= rTextNode
.getIDocumentSettingAccess();
367 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
368 if ( rTextNode
.HasSwAttrSet() )
370 const SwAttrSet
*pAttrSet
= &( rTextNode
.GetSwAttrSet() );
371 pFnt
.reset(new SwFont( pAttrSet
, pIDSA
));
375 SwFontAccess
aFontAccess( &rTextNode
.GetAnyFormatColl(), pSh
);
376 pFnt
.reset(new SwFont( aFontAccess
.Get()->GetFont() ));
377 pFnt
->CheckFontCacheId( pSh
, pFnt
->GetActual() );
381 pFnt
->SetVertical( 2700_deg10
);
383 OutputDevice
* pOut
= pSh
? pSh
->GetOut() : nullptr;
384 if ( !pOut
|| !pSh
->GetViewOptions()->getBrowseMode() ||
385 pSh
->GetViewOptions()->IsPrtFormat() )
387 pOut
= rTextNode
.getIDocumentDeviceAccess().getReferenceDevice(true);
390 const IDocumentRedlineAccess
& rIDRA
= rTextNode
.getIDocumentRedlineAccess();
391 if (IDocumentRedlineAccess::IsShowChanges(rIDRA
.GetRedlineFlags())
392 && !getRootFrame()->IsHideRedlines())
394 const SwRedlineTable::size_type nRedlPos
= rIDRA
.GetRedlinePos( rTextNode
, RedlineType::Any
);
395 if( SwRedlineTable::npos
!= nRedlPos
)
397 SwAttrHandler aAttrHandler
;
398 aAttrHandler
.Init(rTextNode
.GetSwAttrSet(),
399 *rTextNode
.getIDocumentSettingAccess());
400 SwRedlineItr
aRedln( rTextNode
, *pFnt
, aAttrHandler
,
401 nRedlPos
, SwRedlineItr::Mode::Show
);
407 nRet
= IsVertical() ?
408 getFramePrintArea().SSize().Width() + 1 :
409 getFramePrintArea().SSize().Height() + 1;
412 pFnt
->SetFntChg( true );
413 pFnt
->ChgPhysFnt( pSh
, *pOut
);
414 nRet
= pFnt
->GetHeight( pSh
, *pOut
);
419 bool SwTextFrame::FormatEmpty()
421 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTextFrame::FormatEmpty with swapped frame" );
423 bool bCollapse
= EmptyHeight( ) == 1 && IsCollapse( );
425 // sw_redlinehide: just disable FormatEmpty optimisation for now
426 // Split fly frames: non-last parts of the anchor want this optimization to clear the old
428 SwFlyAtContentFrame
* pNonLastSplitFlyDrawObj
= HasNonLastSplitFlyDrawObj();
429 bool bHasNonLastSplitFlyDrawObj
= pNonLastSplitFlyDrawObj
!= nullptr;
431 if (pNonLastSplitFlyDrawObj
&& pNonLastSplitFlyDrawObj
->IsWrapOnAllPages())
433 // Split fly: the anchor is non-empty on all pages in the "wrap on all pages" case.
434 bHasNonLastSplitFlyDrawObj
= false;
437 if ((HasFollow() && !bHasNonLastSplitFlyDrawObj
) || GetMergedPara() || (GetTextNodeFirst()->GetpSwpHints() && !bHasNonLastSplitFlyDrawObj
) ||
438 nullptr != GetTextNodeForParaProps()->GetNumRule() ||
439 GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
440 IsInFootnote() || ( HasPara() && GetPara()->IsPrepMustFit() ) )
442 const SwAttrSet
& aSet
= GetTextNodeForParaProps()->GetSwAttrSet();
443 const SvxAdjust nAdjust
= aSet
.GetAdjust().GetAdjust();
444 if( !bCollapse
&& ( ( ( ! IsRightToLeft() && ( SvxAdjust::Left
!= nAdjust
) ) ||
445 ( IsRightToLeft() && ( SvxAdjust::Right
!= nAdjust
) ) ) ||
446 aSet
.GetRegister().GetValue() ) )
448 const SvxLineSpacingItem
&rSpacing
= aSet
.GetLineSpacing();
449 if( !bCollapse
&& ( SvxLineSpaceRule::Min
== rSpacing
.GetLineSpaceRule() ||
450 SvxLineSpaceRule::Fix
== rSpacing
.GetLineSpaceRule() ||
451 aSet
.GetFirstLineIndent().IsAutoFirst()))
456 SwTextFly
aTextFly( this );
458 bool bFirstFlyCheck
= 0 != getFramePrintArea().Height();
459 if ( !bCollapse
&& bFirstFlyCheck
&&
460 aTextFly
.IsOn() && aTextFly
.IsAnyObj( aRect
) && !bHasNonLastSplitFlyDrawObj
)
463 if (IsEmptyWithSplitFly())
465 // We don't want this optimization in case the paragraph is not really empty, because it has
466 // a fly frame and it also needs space for the empty paragraph in a next line.
470 // only need to check one node because of early return on GetMerged()
471 for (SwContentIndex
const* pIndex
= GetTextNodeFirst()->GetFirstIndex();
472 pIndex
; pIndex
= pIndex
->GetNext())
474 if (!pIndex
->GetOwner() || pIndex
->GetOwner()->GetOwnerType() != SwContentIndexOwnerType::Mark
)
476 auto const pMark
= static_cast<sw::mark::MarkBase
const*>(pIndex
->GetOwner());
477 if (dynamic_cast<const sw::mark::Bookmark
*>(pMark
) != nullptr)
478 { // need bookmark portions!
483 SwTwips nHeight
= EmptyHeight();
485 if (aSet
.GetParaGrid().GetValue() &&
488 SwTextGridItem
const*const pGrid(GetGridItem(FindPageFrame()));
490 nHeight
= pGrid
->GetBaseHeight() + pGrid
->GetRubyHeight();
493 SwRectFnSet
aRectFnSet(this);
494 SwTwips nChg
= nHeight
- aRectFnSet
.GetHeight(getFramePrintArea());
495 const SwBodyFrame
* pBody
= FindBodyFrame();
496 if (pNonLastSplitFlyDrawObj
&& pBody
)
498 // See if we need to increase the text frame height due to split flys. This is necessary for
499 // anchors of inner floating tables, where moving to a next page moves indirectly, so we
500 // want a correct text frame height.
501 SwTwips nFrameBottom
= aRectFnSet
.GetBottom(getFrameArea()) + nChg
;
502 SwTwips nFlyBottom
= aRectFnSet
.GetBottom(pNonLastSplitFlyDrawObj
->getFrameArea());
503 SwTwips nBodyBottom
= aRectFnSet
.GetBottom(pBody
->getFrameArea());
504 if (nFlyBottom
> nBodyBottom
)
506 // This is the legacy case where flys may overlap with footer frames.
507 nFlyBottom
= nBodyBottom
;
509 if (pNonLastSplitFlyDrawObj
->isFrameAreaPositionValid() && nFlyBottom
> nFrameBottom
)
511 nChg
+= (nFlyBottom
- nFrameBottom
);
516 SetUndersized( false );
519 if (GetHasRotatedPortions())
522 SetHasRotatedPortions(false);
531 if( !bCollapse
&& !bFirstFlyCheck
&&
532 aTextFly
.IsOn() && aTextFly
.IsAnyObj( aRect
) )
535 // #i35635# - call method <HideAndShowObjects()>
536 // to assure that objects anchored at the empty paragraph are
537 // correctly visible resp. invisible.
538 HideAndShowObjects();
542 bool SwTextFrame::FillRegister( SwTwips
& rRegStart
, sal_uInt16
& rRegDiff
)
544 const SwFrame
*pFrame
= this;
546 while( !( ( SwFrameType::Body
| SwFrameType::Fly
)
547 & pFrame
->GetType() ) && pFrame
->GetUpper() )
548 pFrame
= pFrame
->GetUpper();
549 if( ( SwFrameType::Body
| SwFrameType::Fly
) & pFrame
->GetType() )
551 SwRectFnSet
aRectFnSet(pFrame
);
552 rRegStart
= aRectFnSet
.GetPrtTop(*pFrame
);
553 pFrame
= pFrame
->FindPageFrame();
554 if( pFrame
->IsPageFrame() )
556 SwPageDesc
* pDesc
= const_cast<SwPageFrame
*>(static_cast<const SwPageFrame
*>(pFrame
))->FindPageDesc();
559 rRegDiff
= pDesc
->GetRegHeight();
562 const SwTextFormatColl
*pFormat
= pDesc
->GetRegisterFormatColl();
565 const SvxLineSpacingItem
&rSpace
= pFormat
->GetLineSpacing();
566 if( SvxLineSpaceRule::Fix
== rSpace
.GetLineSpaceRule() )
568 rRegDiff
= rSpace
.GetLineHeight();
569 pDesc
->SetRegHeight( rRegDiff
);
570 pDesc
->SetRegAscent( ( 4 * rRegDiff
) / 5 );
574 SwViewShell
*pSh
= getRootFrame()->GetCurrShell();
575 SwFontAccess
aFontAccess( pFormat
, pSh
);
576 SwFont
aFnt( aFontAccess
.Get()->GetFont() );
578 OutputDevice
*pOut
= nullptr;
579 if( !pSh
|| !pSh
->GetViewOptions()->getBrowseMode() ||
580 pSh
->GetViewOptions()->IsPrtFormat() )
581 pOut
= GetDoc().getIDocumentDeviceAccess().getReferenceDevice( true );
584 pOut
= pSh
->GetWin()->GetOutDev();
587 pOut
= Application::GetDefaultDevice();
589 MapMode
aOldMap( pOut
->GetMapMode() );
590 pOut
->SetMapMode( MapMode( MapUnit::MapTwip
) );
592 aFnt
.ChgFnt( pSh
, *pOut
);
593 rRegDiff
= aFnt
.GetHeight( pSh
, *pOut
);
594 sal_uInt16 nNetHeight
= rRegDiff
;
596 switch( rSpace
.GetLineSpaceRule() )
598 case SvxLineSpaceRule::Auto
:
600 case SvxLineSpaceRule::Min
:
602 if( rRegDiff
< rSpace
.GetLineHeight() )
603 rRegDiff
= rSpace
.GetLineHeight();
607 OSL_FAIL( ": unknown LineSpaceRule" );
609 switch( rSpace
.GetInterLineSpaceRule() )
611 case SvxInterLineSpaceRule::Off
:
613 case SvxInterLineSpaceRule::Prop
:
615 tools::Long nTmp
= rSpace
.GetPropLineSpace();
617 nTmp
= nTmp
? 50 : 100;
622 rRegDiff
= o3tl::narrowing
<sal_uInt16
>(nTmp
);
623 nNetHeight
= rRegDiff
;
626 case SvxInterLineSpaceRule::Fix
:
628 rRegDiff
= rRegDiff
+ rSpace
.GetInterLineSpace();
629 nNetHeight
= rRegDiff
;
632 default: OSL_FAIL( ": unknown InterLineSpaceRule" );
634 pDesc
->SetRegHeight( rRegDiff
);
635 pDesc
->SetRegAscent( rRegDiff
- nNetHeight
+
636 aFnt
.GetAscent( pSh
, *pOut
) );
637 pOut
->SetMapMode( aOldMap
);
641 const tools::Long nTmpDiff
= pDesc
->GetRegAscent() - rRegDiff
;
642 if ( aRectFnSet
.IsVert() )
643 rRegStart
-= nTmpDiff
;
645 rRegStart
+= nTmpDiff
;
649 return ( 0 != rRegDiff
);
652 void SwHiddenTextPortion::Paint( const SwTextPaintInfo
& rInf
) const
655 OutputDevice
* pOut
= const_cast<OutputDevice
*>(rInf
.GetOut());
656 Color
aCol( rInf
.GetOpt().GetFieldShadingsColor() );
657 Color
aOldColor( pOut
->GetFillColor() );
658 pOut
->SetFillColor( aCol
);
659 Point
aPos( rInf
.GetPos() );
660 aPos
.AdjustY( -150 );
662 SwRect
aRect( aPos
, Size( 100, 200 ) );
663 pOut
->DrawRect( aRect
.SVRect() );
664 pOut
->SetFillColor( aOldColor
);
670 bool SwHiddenTextPortion::Format( SwTextFormatInfo
&rInf
)
673 rInf
.GetTextFrame()->HideFootnotes( rInf
.GetIdx(), rInf
.GetIdx() + GetLen() );
678 bool SwControlCharPortion::DoPaint(SwTextPaintInfo
const& rTextPaintInfo
,
679 OUString
& rOutString
, SwFont
& rTmpFont
, int &) const
681 if (mcChar
== CHAR_WJ
|| !rTextPaintInfo
.GetOpt().IsViewMetaChars())
689 rOutString
= "/"; break;
691 // rText = sal_Unicode(0x2514); break;
693 // rText = sal_Unicode(0x2518); break;
699 rTmpFont
.SetEscapement( CHAR_ZWSP
== mcChar
? DFLT_ESC_AUTO_SUB
: -25 );
700 rTmpFont
.SetColor( SwViewOption::GetCurrentViewOptions().GetNonPrintingCharacterColor() );
701 const sal_uInt16 nProp
= 40;
702 rTmpFont
.SetProportion( nProp
); // a smaller font
707 bool SwBookmarkPortion::DoPaint(SwTextPaintInfo
const& rTextPaintInfo
,
708 OUString
& rOutString
, SwFont
& rFont
, int & rDeltaY
) const
710 // custom color is visible without field shading, too
711 if (!rTextPaintInfo
.GetOpt().IsShowBookmarks())
716 rOutString
= OUStringChar(mcChar
);
718 // init font: we want OpenSymbol to ensure it doesn't look too crazy;
719 // thin and a bit higher than the surrounding text
720 auto const nOrigAscent(rFont
.GetAscent(rTextPaintInfo
.GetVsh(), *rTextPaintInfo
.GetOut()));
721 rFont
.SetName(u
"OpenSymbol"_ustr
, rFont
.GetActual());
722 Size
aSize(rFont
.GetSize(rFont
.GetActual()));
723 // use also the external leading (line gap) of the portion, but don't use
724 // 100% of it because i can't figure out how to baseline align that
725 assert(aSize
.Height() != 0);
726 auto const nFactor
= aSize
.Height() > 0 ? (Height() * 95) / aSize
.Height() : Height();
727 rFont
.SetProportion(nFactor
);
728 rFont
.SetWeight(WEIGHT_THIN
, rFont
.GetActual());
729 rFont
.SetColor(rTextPaintInfo
.GetOpt().GetFieldShadingsColor());
730 // reset these to default...
731 rFont
.SetAlign(ALIGN_BASELINE
);
732 rFont
.SetUnderline(LINESTYLE_NONE
);
733 rFont
.SetOverline(LINESTYLE_NONE
);
734 rFont
.SetStrikeout(STRIKEOUT_NONE
);
735 rFont
.SetOutline(false);
736 rFont
.SetShadow(false);
737 rFont
.SetTransparent(false);
738 rFont
.SetEmphasisMark(FontEmphasisMark::NONE
);
739 rFont
.SetEscapement(0);
740 rFont
.SetPitch(PITCH_DONTKNOW
, rFont
.GetActual());
741 rFont
.SetRelief(FontRelief::NONE
);
743 // adjust Y position to account for different baselines of the fonts
744 auto const nOSAscent(rFont
.GetAscent(rTextPaintInfo
.GetVsh(), *rTextPaintInfo
.GetOut()));
745 rDeltaY
= nOSAscent
- nOrigAscent
;
750 void SwControlCharPortion::Paint( const SwTextPaintInfo
&rInf
) const
752 if ( !Width() ) // is only set during prepaint mode
755 rInf
.DrawViewOpt(*this, GetWhichPor());
758 SwFont
aTmpFont( *rInf
.GetFont() );
762 && !rInf
.GetOpt().IsPagePreview()
763 && !rInf
.GetOpt().IsReadonly()
764 && DoPaint(rInf
, aOutString
, aTmpFont
, deltaY
)))
767 SwFontSave
aFontSave( rInf
, &aTmpFont
);
769 if ( !mnHalfCharWidth
)
770 mnHalfCharWidth
= rInf
.GetTextSize( aOutString
).Width() / 2;
772 Point aOldPos
= rInf
.GetPos();
773 Point
aNewPos( aOldPos
);
774 auto const deltaX((Width() / 2) - mnHalfCharWidth
);
775 switch (rInf
.GetFont()->GetOrientation(rInf
.GetTextFrame()->IsVertical()).get())
778 aNewPos
.AdjustX(deltaX
);
779 aNewPos
.AdjustY(deltaY
);
782 aNewPos
.AdjustY(-deltaX
);
783 aNewPos
.AdjustX(deltaY
);
786 aNewPos
.AdjustY(deltaX
);
787 aNewPos
.AdjustX(-deltaY
);
793 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aNewPos
);
795 rInf
.DrawText( aOutString
, *this );
797 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aOldPos
);
800 void SwBookmarkPortion::Paint( const SwTextPaintInfo
&rInf
) const
802 if ( !Width() ) // is only set during prepaint mode
805 rInf
.DrawViewOpt(*this, GetWhichPor());
808 SwFont
aTmpFont( *rInf
.GetFont() );
812 && !rInf
.GetOpt().IsPagePreview()
813 && !rInf
.GetOpt().IsReadonly()
814 && DoPaint(rInf
, aOutString
, aTmpFont
, deltaY
)))
817 SwFontSave
aFontSave( rInf
, &aTmpFont
);
819 if ( !mnHalfCharWidth
)
820 mnHalfCharWidth
= rInf
.GetTextSize( aOutString
).Width() / 2;
822 Point aOldPos
= rInf
.GetPos();
823 Point
aNewPos( aOldPos
);
824 auto const deltaX((Width() / 2) - mnHalfCharWidth
);
825 switch (rInf
.GetFont()->GetOrientation(rInf
.GetTextFrame()->IsVertical()).get())
828 aNewPos
.AdjustX(deltaX
);
829 aNewPos
.AdjustY(deltaY
);
832 aNewPos
.AdjustY(-deltaX
);
833 aNewPos
.AdjustX(deltaY
);
836 aNewPos
.AdjustY(deltaX
);
837 aNewPos
.AdjustX(-deltaY
);
844 // draw end marks before the character position
845 if ( m_nStart
== 0 || m_nEnd
== 0 )
847 // single type boundary marks are there outside of the bookmark text
851 aNewPos
.AdjustX(mnHalfCharWidth
* -2 * (m_aColors
.size() - 1));
853 else if ( m_nStart
!= 0 && m_nEnd
!= 0 )
854 // both end and start boundary marks: adjust them around the bookmark position
857 aNewPos
.AdjustX(mnHalfCharWidth
* -(2 * m_nEnd
- 1 + m_nPoint
) );
859 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aNewPos
);
861 for ( const auto& it
: m_aColors
)
863 // set bold for custom colored bookmark symbol
864 // and draw multiple symbols showing all custom colors
865 aTmpFont
.SetWeight( COL_TRANSPARENT
== std::get
<1>(it
) ? WEIGHT_THIN
: WEIGHT_BOLD
, aTmpFont
.GetActual() );
866 aTmpFont
.SetColor( COL_TRANSPARENT
== std::get
<1>(it
) ? rInf
.GetOpt().GetFieldShadingsColor() : std::get
<1>(it
) );
867 aOutString
= OUString(std::get
<0>(it
) == SwScriptInfo::MarkKind::Start
? '[' : ']');
869 // MarkKind::Point: drawn I-beam (e.g. U+2336) as overlapping ][
870 if ( std::get
<0>(it
) == SwScriptInfo::MarkKind::Point
)
872 aNewPos
.AdjustX(-mnHalfCharWidth
* 5/16);
873 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aNewPos
);
874 rInf
.DrawText( aOutString
, *this );
876 // when the overlapping vertical lines are 50 pixel width on the screen,
877 // this distance (half width * 5/8) still results precise overlapping
878 aNewPos
.AdjustX(mnHalfCharWidth
* 5/8);
879 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aNewPos
);
880 aOutString
= OUString('[');
882 rInf
.DrawText( aOutString
, *this );
883 // place the next symbol after the previous one
884 // TODO: fix orientation and start/end
885 aNewPos
.AdjustX(mnHalfCharWidth
* 2);
886 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aNewPos
);
889 const_cast< SwTextPaintInfo
& >( rInf
).SetPos( aOldPos
);
892 void SwBookmarkPortion::HandlePortion( SwPortionHandler
& rPH
) const
895 for ( const auto& it
: m_aColors
)
897 aStr
.append("#" + std::get
<2>(it
) + " " + SwResId(STR_BOOKMARK_DEF_NAME
));
898 switch (std::get
<0>(it
))
900 case SwScriptInfo::MarkKind::Point
:
902 case SwScriptInfo::MarkKind::Start
:
903 aStr
.append(" " + SwResId(STR_CAPTION_BEGINNING
));
905 case SwScriptInfo::MarkKind::End
:
906 aStr
.append(" " + SwResId(STR_CAPTION_END
));
911 rPH
.Special( GetLen(), aStr
.makeStringAndClear(), GetWhichPor() );
914 void SwBookmarkPortion::dumpAsXml(xmlTextWriterPtr pWriter
, const OUString
& rText
, TextFrameIndex
& nOffset
) const
916 (void)xmlTextWriterStartElement(pWriter
, BAD_CAST("SwBookmarkPortion"));
917 dumpAsXmlAttributes(pWriter
, rText
, nOffset
);
920 if (!m_aColors
.empty())
923 for (const auto& rColor
: m_aColors
)
925 aStr
.append("#" + std::get
<2>(rColor
) + " " + SwResId(STR_BOOKMARK_DEF_NAME
));
926 switch (std::get
<0>(rColor
))
928 case SwScriptInfo::MarkKind::Point
:
930 case SwScriptInfo::MarkKind::Start
:
931 aStr
.append(" " + SwResId(STR_CAPTION_BEGINNING
));
933 case SwScriptInfo::MarkKind::End
:
934 aStr
.append(" " + SwResId(STR_CAPTION_END
));
938 (void)xmlTextWriterWriteAttribute(pWriter
, BAD_CAST("colors"),
939 BAD_CAST(aStr
.makeStringAndClear().toUtf8().getStr()));
942 (void)xmlTextWriterEndElement(pWriter
);
945 bool SwControlCharPortion::Format( SwTextFormatInfo
&rInf
)
947 const SwLinePortion
* pRoot
= rInf
.GetRoot();
949 Height( pRoot
->Height() );
950 SetAscent( pRoot
->GetAscent() );
955 SwTwips
SwControlCharPortion::GetViewWidth(const SwTextSizeInfo
& rInf
) const
958 mnViewWidth
= rInf
.GetTextSize(OUString(' ')).Width();
963 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */