android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / text / porrst.cxx
blobbd3589b25676a3b83759f71dcdc428857a5424fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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 <vcl/svapp.hxx>
26 #include <comphelper/scopeguard.hxx>
28 #include <viewsh.hxx>
29 #include <viewopt.hxx>
30 #include <ndtxt.hxx>
31 #include <pagefrm.hxx>
32 #include <paratr.hxx>
33 #include <SwPortionHandler.hxx>
34 #include "porrst.hxx"
35 #include "inftxt.hxx"
36 #include "txtpaint.hxx"
37 #include <swfntcch.hxx>
38 #include <tgrditem.hxx>
39 #include <pagedesc.hxx>
40 #include <frmatr.hxx>
41 #include "redlnitr.hxx"
42 #include "atrhndl.hxx"
43 #include <rootfrm.hxx>
44 #include <formatlinebreak.hxx>
45 #include <txatbase.hxx>
47 #include <IDocumentRedlineAccess.hxx>
48 #include <IDocumentSettingAccess.hxx>
49 #include <IDocumentDeviceAccess.hxx>
51 #include <crsrsh.hxx>
52 #include <swtypes.hxx>
53 #include <strings.hrc>
54 #include <flyfrms.hxx>
55 #include <bodyfrm.hxx>
57 SwTmpEndPortion::SwTmpEndPortion( const SwLinePortion &rPortion,
58 const FontLineStyle eUL,
59 const FontStrikeout eStrkout,
60 const Color& rCol ) :
61 m_eUnderline( eUL ), m_eStrikeout( eStrkout ), m_aColor( rCol )
63 Height( rPortion.Height() );
64 SetAscent( rPortion.GetAscent() );
65 SetWhichPor( PortionType::TempEnd );
68 void SwTmpEndPortion::Paint( const SwTextPaintInfo &rInf ) const
70 if (!(rInf.OnWin() && rInf.GetOpt().IsParagraph()))
71 return;
73 const SwFont* pOldFnt = rInf.GetFont();
75 SwFont aFont(*pOldFnt);
77 // Paint strikeout/underline based on redline color and settings
78 // (with an extra pilcrow in the background, because there is
79 // no SetStrikeoutColor(), also SetUnderColor() doesn't work()).
80 if ( m_eUnderline != LINESTYLE_NONE || m_eStrikeout != STRIKEOUT_NONE )
82 aFont.SetColor( m_aColor );
83 aFont.SetUnderline( m_eUnderline );
84 aFont.SetStrikeout( m_eStrikeout );
86 const_cast<SwTextPaintInfo&>(rInf).SetFont(&aFont);
88 // draw the pilcrow with strikeout/underline in redline color
89 rInf.DrawText(CH_PAR, *this);
93 aFont.SetColor( NON_PRINTING_CHARACTER_COLOR );
94 aFont.SetStrikeout( STRIKEOUT_NONE );
95 aFont.SetUnderline( LINESTYLE_NONE );
96 const_cast<SwTextPaintInfo&>(rInf).SetFont(&aFont);
98 // draw the pilcrow
99 rInf.DrawText(CH_PAR, *this);
101 const_cast<SwTextPaintInfo&>(rInf).SetFont(const_cast<SwFont*>(pOldFnt));
104 SwBreakPortion::SwBreakPortion( const SwLinePortion &rPortion, const SwTextAttr* pAttr )
105 : SwLinePortion( rPortion )
107 mnLineLength = TextFrameIndex(1);
108 m_eRedline = RedlineType::None;
109 SetWhichPor( PortionType::Break );
111 m_eClear = SwLineBreakClear::NONE;
112 if (pAttr && pAttr->Which() == RES_TXTATR_LINEBREAK)
114 m_eClear = pAttr->GetLineBreak().GetValue();
116 m_nTextHeight = 0;
119 TextFrameIndex SwBreakPortion::GetModelPositionForViewPoint(const sal_uInt16) const
121 return TextFrameIndex(0);
124 sal_uInt16 SwBreakPortion::GetViewWidth( const SwTextSizeInfo & ) const
125 { return 0; }
127 SwLinePortion *SwBreakPortion::Compress()
128 { return (GetNextPortion() && GetNextPortion()->InTextGrp() ? nullptr : this); }
130 void SwBreakPortion::Paint( const SwTextPaintInfo &rInf ) const
132 if( !(rInf.OnWin() && rInf.GetOpt().IsLineBreak()) )
133 return;
135 // Reduce height to text height for the duration of the print, so the vertical height will look
136 // correct for the line break character, even for clearing breaks.
137 SwTwips nHeight = Height();
138 SwTwips nVertPosOffset = (nHeight - m_nTextHeight) / 2;
139 auto pPortion = const_cast<SwBreakPortion*>(this);
140 pPortion->Height(m_nTextHeight, false);
141 if (rInf.GetTextFrame()->IsVertical())
143 // Compensate for the offset done in SwTextCursor::AdjustBaseLine() for the vertical case.
144 const_cast<SwTextPaintInfo&>(rInf).Y(rInf.Y() + nVertPosOffset);
146 comphelper::ScopeGuard g(
147 [pPortion, nHeight, &rInf, nVertPosOffset]
149 if (rInf.GetTextFrame()->IsVertical())
151 const_cast<SwTextPaintInfo&>(rInf).Y(rInf.Y() - nVertPosOffset);
153 pPortion->Height(nHeight, false);
156 rInf.DrawLineBreak( *this );
158 // paint redlining
159 if (m_eRedline == RedlineType::None)
160 return;
162 sal_Int16 nNoBreakWidth = rInf.GetTextSize(S_NOBREAK_FOR_REDLINE).Width();
163 if ( nNoBreakWidth > 0 )
165 // approximate portion size with multiple no-break spaces
166 // and draw these spaces (at least a single one) by DrawText
167 // painting the requested redline underline/strikeout
168 sal_Int16 nSpaces = (LINE_BREAK_WIDTH + nNoBreakWidth/2) / nNoBreakWidth;
169 OUStringBuffer aBuf(S_NOBREAK_FOR_REDLINE);
170 for (sal_Int16 i = 1; i < nSpaces; ++i)
171 aBuf.append(S_NOBREAK_FOR_REDLINE);
173 const SwFont* pOldFnt = rInf.GetFont();
175 SwFont aFont(*pOldFnt);
177 if (m_eRedline == RedlineType::Delete)
178 aFont.SetUnderline( LINESTYLE_NONE );
179 else
180 aFont.SetStrikeout( STRIKEOUT_NONE );
182 const_cast<SwTextPaintInfo&>(rInf).SetFont(&aFont);
184 rInf.DrawText(aBuf.makeStringAndClear(), *this);
186 const_cast<SwTextPaintInfo&>(rInf).SetFont(const_cast<SwFont*>(pOldFnt));
190 bool SwBreakPortion::Format( SwTextFormatInfo &rInf )
192 const SwLinePortion *pRoot = rInf.GetRoot();
193 Width( 0 );
194 Height( pRoot->Height() );
195 m_nTextHeight = Height();
197 // See if this is a clearing break. If so, calculate how much we need to "jump down" so the next
198 // line can again use the full text width.
199 SwLineBreakClear eClear = m_eClear;
200 if (rInf.GetTextFrame()->IsRightToLeft() && eClear != SwLineBreakClear::ALL)
202 // RTL ignores left/right breaks.
203 eClear = SwLineBreakClear::NONE;
205 if (eClear != SwLineBreakClear::NONE)
207 SwTextFly& rTextFly = rInf.GetTextFly();
208 if (rTextFly.IsOn())
210 SwTwips nHeight = rTextFly.GetMaxBottom(*this, rInf) - rInf.Y();
211 if (nHeight > Height())
213 Height(nHeight, /*bText=*/false);
218 SetAscent( pRoot->GetAscent() );
219 if (rInf.GetIdx() + TextFrameIndex(1) == TextFrameIndex(rInf.GetText().getLength()))
220 rInf.SetNewLine( true );
221 return true;
224 void SwBreakPortion::HandlePortion( SwPortionHandler& rPH ) const
226 rPH.Text( GetLen(), GetWhichPor() );
229 void SwBreakPortion::dumpAsXml(xmlTextWriterPtr pWriter, const OUString& rText, TextFrameIndex&
230 nOffset) const
232 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwBreakPortion"));
233 dumpAsXmlAttributes(pWriter, rText, nOffset);
234 nOffset += GetLen();
236 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("text-height"),
237 BAD_CAST(OString::number(m_nTextHeight).getStr()));
239 (void)xmlTextWriterEndElement(pWriter);
242 SwLineBreakClear SwBreakPortion::GetClear() const { return m_eClear; }
244 SwKernPortion::SwKernPortion( SwLinePortion &rPortion, short nKrn,
245 bool bBG, bool bGK ) :
246 m_nKern( nKrn ), m_bBackground( bBG ), m_bGridKern( bGK )
248 Height( rPortion.Height() );
249 SetAscent( rPortion.GetAscent() );
250 mnLineLength = TextFrameIndex(0);
251 SetWhichPor( PortionType::Kern );
252 if( m_nKern > 0 )
253 Width( m_nKern );
254 rPortion.Insert( this );
257 SwKernPortion::SwKernPortion( const SwLinePortion& rPortion ) :
258 m_nKern( 0 ), m_bBackground( false ), m_bGridKern( true )
260 Height( rPortion.Height() );
261 SetAscent( rPortion.GetAscent() );
263 mnLineLength = TextFrameIndex(0);
264 SetWhichPor( PortionType::Kern );
267 void SwKernPortion::Paint( const SwTextPaintInfo &rInf ) const
269 if( !Width() )
270 return;
272 // bBackground is set for Kerning Portions between two fields
273 if ( m_bBackground )
274 rInf.DrawViewOpt( *this, PortionType::Field );
276 rInf.DrawBackBrush( *this );
277 if (GetJoinBorderWithNext() ||GetJoinBorderWithPrev())
278 rInf.DrawBorder( *this );
280 // do we have to repaint a post it portion?
281 if( rInf.OnWin() && mpNextPortion && !mpNextPortion->Width() )
282 mpNextPortion->PrePaint( rInf, this );
284 if( rInf.GetFont()->IsPaintBlank() )
286 SwRect aClipRect;
287 rInf.CalcRect( *this, &aClipRect );
288 SwSaveClip aClip( const_cast<OutputDevice*>(rInf.GetOut()) );
289 aClip.ChgClip( aClipRect );
290 rInf.DrawText(" ", *this, TextFrameIndex(0), TextFrameIndex(2), true );
294 void SwKernPortion::FormatEOL( SwTextFormatInfo &rInf )
296 if ( m_bGridKern )
297 return;
299 if( rInf.GetLast() == this )
300 rInf.SetLast( FindPrevPortion( rInf.GetRoot() ) );
301 if( m_nKern < 0 )
302 Width( -m_nKern );
303 else
304 Width( 0 );
305 rInf.GetLast()->FormatEOL( rInf );
308 SwArrowPortion::SwArrowPortion( const SwLinePortion &rPortion ) :
309 m_bLeft( true )
311 Height( rPortion.Height() );
312 SetAscent( rPortion.GetAscent() );
313 mnLineLength = TextFrameIndex(0);
314 SetWhichPor( PortionType::Arrow );
317 SwArrowPortion::SwArrowPortion( const SwTextPaintInfo &rInf )
318 : m_bLeft( false )
320 Height( o3tl::narrowing<sal_uInt16>(rInf.GetTextFrame()->getFramePrintArea().Height()) );
321 m_aPos.setX( rInf.GetTextFrame()->getFrameArea().Left() +
322 rInf.GetTextFrame()->getFramePrintArea().Right() );
323 m_aPos.setY( rInf.GetTextFrame()->getFrameArea().Top() +
324 rInf.GetTextFrame()->getFramePrintArea().Bottom() );
325 SetWhichPor( PortionType::Arrow );
328 void SwArrowPortion::Paint( const SwTextPaintInfo &rInf ) const
330 const_cast<SwArrowPortion*>(this)->m_aPos = rInf.GetPos();
333 SwLinePortion *SwArrowPortion::Compress() { return this; }
335 SwTwips SwTextFrame::EmptyHeight() const
337 if (IsCollapse()) {
338 SwViewShell *pSh = getRootFrame()->GetCurrShell();
339 if ( auto pCrSh = dynamic_cast<SwCursorShell*>( pSh ) ) {
340 // this is called during formatting so avoid recursive layout
341 SwContentFrame const*const pCurrFrame = pCrSh->GetCurrFrame(false);
342 if (pCurrFrame==static_cast<SwContentFrame const *>(this)) {
343 // do nothing
344 } else {
345 return 1;
347 } else {
348 return 1;
351 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTextFrame::EmptyHeight with swapped frame" );
353 std::unique_ptr<SwFont> pFnt;
354 const SwTextNode& rTextNode = *GetTextNodeForParaProps();
355 const IDocumentSettingAccess* pIDSA = rTextNode.getIDocumentSettingAccess();
356 SwViewShell *pSh = getRootFrame()->GetCurrShell();
357 if ( rTextNode.HasSwAttrSet() )
359 const SwAttrSet *pAttrSet = &( rTextNode.GetSwAttrSet() );
360 pFnt.reset(new SwFont( pAttrSet, pIDSA ));
362 else
364 SwFontAccess aFontAccess( &rTextNode.GetAnyFormatColl(), pSh);
365 pFnt.reset(new SwFont( aFontAccess.Get()->GetFont() ));
366 pFnt->CheckFontCacheId( pSh, pFnt->GetActual() );
369 if ( IsVertical() )
370 pFnt->SetVertical( 2700_deg10 );
372 OutputDevice* pOut = pSh ? pSh->GetOut() : nullptr;
373 if ( !pOut || !pSh->GetViewOptions()->getBrowseMode() ||
374 pSh->GetViewOptions()->IsPrtFormat() )
376 pOut = rTextNode.getIDocumentDeviceAccess().getReferenceDevice(true);
379 const IDocumentRedlineAccess& rIDRA = rTextNode.getIDocumentRedlineAccess();
380 if (IDocumentRedlineAccess::IsShowChanges(rIDRA.GetRedlineFlags())
381 && !getRootFrame()->IsHideRedlines())
383 const SwRedlineTable::size_type nRedlPos = rIDRA.GetRedlinePos( rTextNode, RedlineType::Any );
384 if( SwRedlineTable::npos != nRedlPos )
386 SwAttrHandler aAttrHandler;
387 aAttrHandler.Init(rTextNode.GetSwAttrSet(),
388 *rTextNode.getIDocumentSettingAccess());
389 SwRedlineItr aRedln( rTextNode, *pFnt, aAttrHandler,
390 nRedlPos, SwRedlineItr::Mode::Show);
394 SwTwips nRet;
395 if( !pOut )
396 nRet = IsVertical() ?
397 getFramePrintArea().SSize().Width() + 1 :
398 getFramePrintArea().SSize().Height() + 1;
399 else
401 pFnt->SetFntChg( true );
402 pFnt->ChgPhysFnt( pSh, *pOut );
403 nRet = pFnt->GetHeight( pSh, *pOut );
405 return nRet;
408 bool SwTextFrame::FormatEmpty()
410 OSL_ENSURE( ! IsVertical() || ! IsSwapped(),"SwTextFrame::FormatEmpty with swapped frame" );
412 bool bCollapse = EmptyHeight( ) == 1 && IsCollapse( );
414 // sw_redlinehide: just disable FormatEmpty optimisation for now
415 // Split fly frames: non-last parts of the anchor want this optimization to clear the old
416 // content.
417 SwFlyAtContentFrame* pNonLastSplitFlyDrawObj = HasNonLastSplitFlyDrawObj();
418 bool bHasNonLastSplitFlyDrawObj = pNonLastSplitFlyDrawObj != nullptr;
419 if ((HasFollow() && !bHasNonLastSplitFlyDrawObj) || GetMergedPara() || (GetTextNodeFirst()->GetpSwpHints() && !bHasNonLastSplitFlyDrawObj) ||
420 nullptr != GetTextNodeForParaProps()->GetNumRule() ||
421 GetTextNodeFirst()->HasHiddenCharAttribute(true) ||
422 IsInFootnote() || ( HasPara() && GetPara()->IsPrepMustFit() ) )
423 return false;
424 const SwAttrSet& aSet = GetTextNodeForParaProps()->GetSwAttrSet();
425 const SvxAdjust nAdjust = aSet.GetAdjust().GetAdjust();
426 if( !bCollapse && ( ( ( ! IsRightToLeft() && ( SvxAdjust::Left != nAdjust ) ) ||
427 ( IsRightToLeft() && ( SvxAdjust::Right != nAdjust ) ) ) ||
428 aSet.GetRegister().GetValue() ) )
429 return false;
430 const SvxLineSpacingItem &rSpacing = aSet.GetLineSpacing();
431 if( !bCollapse && ( SvxLineSpaceRule::Min == rSpacing.GetLineSpaceRule() ||
432 SvxLineSpaceRule::Fix == rSpacing.GetLineSpaceRule() ||
433 aSet.GetFirstLineIndent().IsAutoFirst()))
435 return false;
438 SwTextFly aTextFly( this );
439 SwRect aRect;
440 bool bFirstFlyCheck = 0 != getFramePrintArea().Height();
441 if ( !bCollapse && bFirstFlyCheck &&
442 aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) && !bHasNonLastSplitFlyDrawObj )
443 return false;
445 if (IsEmptyWithSplitFly())
447 // We don't want this optimization in case the paragraph is not really empty, because it has
448 // a fly frame and it also needs space for the empty paragraph in a next line.
449 return false;
452 // only need to check one node because of early return on GetMerged()
453 for (SwContentIndex const* pIndex = GetTextNodeFirst()->GetFirstIndex();
454 pIndex; pIndex = pIndex->GetNext())
456 sw::mark::IMark const*const pMark = pIndex->GetMark();
457 if (dynamic_cast<const sw::mark::IBookmark*>(pMark) != nullptr)
458 { // need bookmark portions!
459 return false;
463 SwTwips nHeight = EmptyHeight();
465 if (aSet.GetParaGrid().GetValue() &&
466 IsInDocBody() )
468 SwTextGridItem const*const pGrid(GetGridItem(FindPageFrame()));
469 if ( pGrid )
470 nHeight = pGrid->GetBaseHeight() + pGrid->GetRubyHeight();
473 SwRectFnSet aRectFnSet(this);
474 SwTwips nChg = nHeight - aRectFnSet.GetHeight(getFramePrintArea());
475 const SwBodyFrame* pBody = FindBodyFrame();
476 if (pNonLastSplitFlyDrawObj && pBody)
478 // See if we need to increase the text frame height due to split flys. This is necessary for
479 // anchors of inner floating tables, where moving to a next page moves indirectly, so we
480 // want a correct text frame height.
481 SwTwips nFrameBottom = aRectFnSet.GetBottom(getFrameArea()) + nChg;
482 SwTwips nFlyBottom = aRectFnSet.GetBottom(pNonLastSplitFlyDrawObj->getFrameArea());
483 SwTwips nBodyBottom = aRectFnSet.GetBottom(pBody->getFrameArea());
484 if (nFlyBottom > nBodyBottom)
486 // This is the legacy case where flys may overlap with footer frames.
487 nFlyBottom = nBodyBottom;
489 if (pNonLastSplitFlyDrawObj->isFrameAreaPositionValid() && nFlyBottom > nFrameBottom)
491 nChg += (nFlyBottom - nFrameBottom);
495 if( !nChg )
496 SetUndersized( false );
497 AdjustFrame( nChg );
499 if (GetHasRotatedPortions())
501 ClearPara();
502 SetHasRotatedPortions(false);
505 RemoveFromCache();
506 if( !IsEmpty() )
508 SetEmpty( true );
509 SetCompletePaint();
511 if( !bCollapse && !bFirstFlyCheck &&
512 aTextFly.IsOn() && aTextFly.IsAnyObj( aRect ) )
513 return false;
515 // #i35635# - call method <HideAndShowObjects()>
516 // to assure that objects anchored at the empty paragraph are
517 // correctly visible resp. invisible.
518 HideAndShowObjects();
519 return true;
522 bool SwTextFrame::FillRegister( SwTwips& rRegStart, sal_uInt16& rRegDiff )
524 const SwFrame *pFrame = this;
525 rRegDiff = 0;
526 while( !( ( SwFrameType::Body | SwFrameType::Fly )
527 & pFrame->GetType() ) && pFrame->GetUpper() )
528 pFrame = pFrame->GetUpper();
529 if( ( SwFrameType::Body| SwFrameType::Fly ) & pFrame->GetType() )
531 SwRectFnSet aRectFnSet(pFrame);
532 rRegStart = aRectFnSet.GetPrtTop(*pFrame);
533 pFrame = pFrame->FindPageFrame();
534 if( pFrame->IsPageFrame() )
536 SwPageDesc* pDesc = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(pFrame))->FindPageDesc();
537 if( pDesc )
539 rRegDiff = pDesc->GetRegHeight();
540 if( !rRegDiff )
542 const SwTextFormatColl *pFormat = pDesc->GetRegisterFormatColl();
543 if( pFormat )
545 const SvxLineSpacingItem &rSpace = pFormat->GetLineSpacing();
546 if( SvxLineSpaceRule::Fix == rSpace.GetLineSpaceRule() )
548 rRegDiff = rSpace.GetLineHeight();
549 pDesc->SetRegHeight( rRegDiff );
550 pDesc->SetRegAscent( ( 4 * rRegDiff ) / 5 );
552 else
554 SwViewShell *pSh = getRootFrame()->GetCurrShell();
555 SwFontAccess aFontAccess( pFormat, pSh );
556 SwFont aFnt( aFontAccess.Get()->GetFont() );
558 OutputDevice *pOut = nullptr;
559 if( !pSh || !pSh->GetViewOptions()->getBrowseMode() ||
560 pSh->GetViewOptions()->IsPrtFormat() )
561 pOut = GetDoc().getIDocumentDeviceAccess().getReferenceDevice( true );
563 if( pSh && !pOut )
564 pOut = pSh->GetWin()->GetOutDev();
566 if( !pOut )
567 pOut = Application::GetDefaultDevice();
569 MapMode aOldMap( pOut->GetMapMode() );
570 pOut->SetMapMode( MapMode( MapUnit::MapTwip ) );
572 aFnt.ChgFnt( pSh, *pOut );
573 rRegDiff = aFnt.GetHeight( pSh, *pOut );
574 sal_uInt16 nNetHeight = rRegDiff;
576 switch( rSpace.GetLineSpaceRule() )
578 case SvxLineSpaceRule::Auto:
579 break;
580 case SvxLineSpaceRule::Min:
582 if( rRegDiff < rSpace.GetLineHeight() )
583 rRegDiff = rSpace.GetLineHeight();
584 break;
586 default:
587 OSL_FAIL( ": unknown LineSpaceRule" );
589 switch( rSpace.GetInterLineSpaceRule() )
591 case SvxInterLineSpaceRule::Off:
592 break;
593 case SvxInterLineSpaceRule::Prop:
595 tools::Long nTmp = rSpace.GetPropLineSpace();
596 if( nTmp < 50 )
597 nTmp = nTmp ? 50 : 100;
598 nTmp *= rRegDiff;
599 nTmp /= 100;
600 if( !nTmp )
601 ++nTmp;
602 rRegDiff = o3tl::narrowing<sal_uInt16>(nTmp);
603 nNetHeight = rRegDiff;
604 break;
606 case SvxInterLineSpaceRule::Fix:
608 rRegDiff = rRegDiff + rSpace.GetInterLineSpace();
609 nNetHeight = rRegDiff;
610 break;
612 default: OSL_FAIL( ": unknown InterLineSpaceRule" );
614 pDesc->SetRegHeight( rRegDiff );
615 pDesc->SetRegAscent( rRegDiff - nNetHeight +
616 aFnt.GetAscent( pSh, *pOut ) );
617 pOut->SetMapMode( aOldMap );
621 const tools::Long nTmpDiff = pDesc->GetRegAscent() - rRegDiff;
622 if ( aRectFnSet.IsVert() )
623 rRegStart -= nTmpDiff;
624 else
625 rRegStart += nTmpDiff;
629 return ( 0 != rRegDiff );
632 void SwHiddenTextPortion::Paint( const SwTextPaintInfo & rInf) const
634 #ifdef DBG_UTIL
635 OutputDevice* pOut = const_cast<OutputDevice*>(rInf.GetOut());
636 Color aCol( rInf.GetOpt().GetFieldShadingsColor() );
637 Color aOldColor( pOut->GetFillColor() );
638 pOut->SetFillColor( aCol );
639 Point aPos( rInf.GetPos() );
640 aPos.AdjustY( -150 );
641 aPos.AdjustX( -25 );
642 SwRect aRect( aPos, Size( 100, 200 ) );
643 pOut->DrawRect( aRect.SVRect() );
644 pOut->SetFillColor( aOldColor );
645 #else
646 (void)rInf;
647 #endif
650 bool SwHiddenTextPortion::Format( SwTextFormatInfo &rInf )
652 Width( 0 );
653 rInf.GetTextFrame()->HideFootnotes( rInf.GetIdx(), rInf.GetIdx() + GetLen() );
655 return false;
658 bool SwControlCharPortion::DoPaint(SwTextPaintInfo const& rTextPaintInfo,
659 OUString & rOutString, SwFont & rTmpFont, int &) const
661 if (mcChar == CHAR_WJ || !rTextPaintInfo.GetOpt().IsFieldShadings())
663 return false;
666 switch (mcChar)
668 case CHAR_ZWSP:
669 rOutString = "/"; break;
670 // case CHAR_LRM :
671 // rText = sal_Unicode(0x2514); break;
672 // case CHAR_RLM :
673 // rText = sal_Unicode(0x2518); break;
674 default:
675 assert(false);
676 break;
679 rTmpFont.SetEscapement( CHAR_ZWSP == mcChar ? DFLT_ESC_AUTO_SUB : -25 );
680 const sal_uInt16 nProp = 40;
681 rTmpFont.SetProportion( nProp ); // a smaller font
683 return true;
686 bool SwBookmarkPortion::DoPaint(SwTextPaintInfo const& rTextPaintInfo,
687 OUString & rOutString, SwFont & rFont, int & rDeltaY) const
689 // custom color is visible without field shading, too
690 if (!rTextPaintInfo.GetOpt().IsShowBookmarks())
692 return false;
695 rOutString = OUStringChar(mcChar);
697 // init font: we want OpenSymbol to ensure it doesn't look too crazy;
698 // thin and a bit higher than the surrounding text
699 auto const nOrigAscent(rFont.GetAscent(rTextPaintInfo.GetVsh(), *rTextPaintInfo.GetOut()));
700 rFont.SetName("OpenSymbol", rFont.GetActual());
701 Size aSize(rFont.GetSize(rFont.GetActual()));
702 // use also the external leading (line gap) of the portion, but don't use
703 // 100% of it because i can't figure out how to baseline align that
704 assert(aSize.Height() != 0);
705 auto const nFactor = aSize.Height() > 0 ? (Height() * 95) / aSize.Height() : Height();
706 rFont.SetProportion(nFactor);
707 rFont.SetWeight(WEIGHT_THIN, rFont.GetActual());
708 rFont.SetColor(rTextPaintInfo.GetOpt().GetFieldShadingsColor());
709 // reset these to default...
710 rFont.SetAlign(ALIGN_BASELINE);
711 rFont.SetUnderline(LINESTYLE_NONE);
712 rFont.SetOverline(LINESTYLE_NONE);
713 rFont.SetStrikeout(STRIKEOUT_NONE);
714 rFont.SetOutline(false);
715 rFont.SetShadow(false);
716 rFont.SetTransparent(false);
717 rFont.SetEmphasisMark(FontEmphasisMark::NONE);
718 rFont.SetEscapement(0);
719 rFont.SetPitch(PITCH_DONTKNOW, rFont.GetActual());
720 rFont.SetRelief(FontRelief::NONE);
722 // adjust Y position to account for different baselines of the fonts
723 auto const nOSAscent(rFont.GetAscent(rTextPaintInfo.GetVsh(), *rTextPaintInfo.GetOut()));
724 rDeltaY = nOSAscent - nOrigAscent;
726 return true;
729 void SwControlCharPortion::Paint( const SwTextPaintInfo &rInf ) const
731 if ( !Width() ) // is only set during prepaint mode
732 return;
734 rInf.DrawViewOpt(*this, GetWhichPor());
736 int deltaY(0);
737 SwFont aTmpFont( *rInf.GetFont() );
738 OUString aOutString;
740 if (!(rInf.OnWin()
741 && !rInf.GetOpt().IsPagePreview()
742 && !rInf.GetOpt().IsReadonly()
743 && DoPaint(rInf, aOutString, aTmpFont, deltaY)))
744 return;
746 SwFontSave aFontSave( rInf, &aTmpFont );
748 if ( !mnHalfCharWidth )
749 mnHalfCharWidth = rInf.GetTextSize( aOutString ).Width() / 2;
751 Point aOldPos = rInf.GetPos();
752 Point aNewPos( aOldPos );
753 auto const deltaX((Width() / 2) - mnHalfCharWidth);
754 switch (rInf.GetFont()->GetOrientation(rInf.GetTextFrame()->IsVertical()).get())
756 case 0:
757 aNewPos.AdjustX(deltaX);
758 aNewPos.AdjustY(deltaY);
759 break;
760 case 900:
761 aNewPos.AdjustY(-deltaX);
762 aNewPos.AdjustX(deltaY);
763 break;
764 case 2700:
765 aNewPos.AdjustY(deltaX);
766 aNewPos.AdjustX(-deltaY);
767 break;
768 default:
769 assert(false);
770 break;
772 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
774 rInf.DrawText( aOutString, *this );
776 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aOldPos );
779 void SwBookmarkPortion::Paint( const SwTextPaintInfo &rInf ) const
781 if ( !Width() ) // is only set during prepaint mode
782 return;
784 rInf.DrawViewOpt(*this, GetWhichPor());
786 int deltaY(0);
787 SwFont aTmpFont( *rInf.GetFont() );
788 OUString aOutString;
790 if (!(rInf.OnWin()
791 && !rInf.GetOpt().IsPagePreview()
792 && !rInf.GetOpt().IsReadonly()
793 && DoPaint(rInf, aOutString, aTmpFont, deltaY)))
794 return;
796 SwFontSave aFontSave( rInf, &aTmpFont );
798 if ( !mnHalfCharWidth )
799 mnHalfCharWidth = rInf.GetTextSize( aOutString ).Width() / 2;
801 Point aOldPos = rInf.GetPos();
802 Point aNewPos( aOldPos );
803 auto const deltaX((Width() / 2) - mnHalfCharWidth);
804 switch (rInf.GetFont()->GetOrientation(rInf.GetTextFrame()->IsVertical()).get())
806 case 0:
807 aNewPos.AdjustX(deltaX);
808 aNewPos.AdjustY(deltaY);
809 break;
810 case 900:
811 aNewPos.AdjustY(-deltaX);
812 aNewPos.AdjustX(deltaY);
813 break;
814 case 2700:
815 aNewPos.AdjustY(deltaX);
816 aNewPos.AdjustX(-deltaY);
817 break;
818 default:
819 assert(false);
820 break;
823 // draw end marks before the character position
824 if ( m_nStart == 0 || m_nEnd == 0 )
826 // single type boundary marks are there outside of the bookmark text
827 // some |text| here
828 // [[ ]]
829 if (m_nStart > 1)
830 aNewPos.AdjustX(static_cast<tools::Long>(mnHalfCharWidth) * -2 * (m_oColors.size() - 1));
832 else if ( m_nStart != 0 && m_nEnd != 0 )
833 // both end and start boundary marks: adjust them around the bookmark position
834 // |te|xt|
835 // ]] [[
836 aNewPos.AdjustX(static_cast<tools::Long>(mnHalfCharWidth) * -(2 * m_nEnd - 1 + m_nPoint) );
838 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
840 for ( const auto& it : m_oColors )
842 // set bold for custom colored bookmark symbol
843 // and draw multiple symbols showing all custom colors
844 aTmpFont.SetWeight( COL_TRANSPARENT == std::get<1>(it) ? WEIGHT_THIN : WEIGHT_BOLD, aTmpFont.GetActual() );
845 aTmpFont.SetColor( COL_TRANSPARENT == std::get<1>(it) ? rInf.GetOpt().GetFieldShadingsColor() : std::get<1>(it) );
846 aOutString = OUString(std::get<0>(it) == SwScriptInfo::MarkKind::Start ? '[' : ']');
848 // MarkKind::Point: drawn I-beam (e.g. U+2336) as overlapping ][
849 if ( std::get<0>(it) == SwScriptInfo::MarkKind::Point )
851 aNewPos.AdjustX(-mnHalfCharWidth * 5/16);
852 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
853 rInf.DrawText( aOutString, *this );
855 // when the overlapping vertical lines are 50 pixel width on the screen,
856 // this distance (half width * 5/8) still results precise overlapping
857 aNewPos.AdjustX(mnHalfCharWidth * 5/8);
858 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
859 aOutString = OUString('[');
861 rInf.DrawText( aOutString, *this );
862 // place the next symbol after the previous one
863 // TODO: fix orientation and start/end
864 aNewPos.AdjustX(mnHalfCharWidth * 2);
865 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aNewPos );
868 const_cast< SwTextPaintInfo& >( rInf ).SetPos( aOldPos );
871 void SwBookmarkPortion::HandlePortion( SwPortionHandler& rPH ) const
873 OUStringBuffer aStr;
874 for ( const auto& it : m_oColors )
876 aStr.append("#" + std::get<2>(it) + " " + SwResId(STR_BOOKMARK_DEF_NAME));
877 switch (std::get<0>(it))
879 case SwScriptInfo::MarkKind::Point:
880 break;
881 case SwScriptInfo::MarkKind::Start:
882 aStr.append(" " + SwResId(STR_CAPTION_BEGINNING));
883 break;
884 case SwScriptInfo::MarkKind::End:
885 aStr.append(" " + SwResId(STR_CAPTION_END));
886 break;
890 rPH.Special( GetLen(), aStr.makeStringAndClear(), GetWhichPor() );
893 void SwBookmarkPortion::dumpAsXml(xmlTextWriterPtr pWriter, const OUString& rText, TextFrameIndex& nOffset) const
895 (void)xmlTextWriterStartElement(pWriter, BAD_CAST("SwBookmarkPortion"));
896 dumpAsXmlAttributes(pWriter, rText, nOffset);
897 nOffset += GetLen();
899 if (!m_oColors.empty())
901 OUStringBuffer aStr;
902 for (const auto& rColor : m_oColors)
904 aStr.append("#" + std::get<2>(rColor) + " " + SwResId(STR_BOOKMARK_DEF_NAME));
905 switch (std::get<0>(rColor))
907 case SwScriptInfo::MarkKind::Point:
908 break;
909 case SwScriptInfo::MarkKind::Start:
910 aStr.append(" " + SwResId(STR_CAPTION_BEGINNING));
911 break;
912 case SwScriptInfo::MarkKind::End:
913 aStr.append(" " + SwResId(STR_CAPTION_END));
914 break;
917 (void)xmlTextWriterWriteAttribute(pWriter, BAD_CAST("colors"),
918 BAD_CAST(aStr.makeStringAndClear().toUtf8().getStr()));
921 (void)xmlTextWriterEndElement(pWriter);
924 bool SwControlCharPortion::Format( SwTextFormatInfo &rInf )
926 const SwLinePortion* pRoot = rInf.GetRoot();
927 Width( 0 );
928 Height( pRoot->Height() );
929 SetAscent( pRoot->GetAscent() );
931 return false;
934 sal_uInt16 SwControlCharPortion::GetViewWidth( const SwTextSizeInfo& rInf ) const
936 if( !mnViewWidth )
937 mnViewWidth = rInf.GetTextSize(OUString(' ')).Width();
939 return mnViewWidth;
942 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */