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 .
21 #include <txatbase.hxx>
23 #include <vcl/outdev.hxx>
24 #include <editeng/paravertalignitem.hxx>
26 #include "pormulti.hxx"
27 #include <pagefrm.hxx>
28 #include <tgrditem.hxx>
35 void SwTextIter::CtorInitTextIter( SwTextFrame
*pNewFrame
, SwTextInfo
*pNewInf
)
37 assert(pNewFrame
->GetPara());
39 CtorInitAttrIter( *pNewFrame
->GetTextNodeFirst(), pNewFrame
->GetPara()->GetScriptInfo(), pNewFrame
);
41 SwTextNode
const*const pNode
= pNewFrame
->GetTextNodeForParaProps();
45 m_aLineInf
.CtorInitLineInfo( pNode
->GetSwAttrSet(), *pNode
);
46 m_nFrameStart
= m_pFrame
->getFrameArea().Pos().Y() + m_pFrame
->getFramePrintArea().Pos().Y();
49 // Order is important: only execute FillRegister if GetValue!=0
50 m_bRegisterOn
= pNode
->GetSwAttrSet().GetRegister().GetValue()
51 && m_pFrame
->FillRegister( m_nRegStart
, m_nRegDiff
);
54 void SwTextIter::Init()
56 m_pCurr
= m_pInf
->GetParaPortion();
57 m_nStart
= m_pInf
->GetTextStart();
64 void SwTextIter::CalcAscentAndHeight( SwTwips
&rAscent
, SwTwips
&rHeight
) const
66 rHeight
= GetLineHeight();
67 rAscent
= m_pCurr
->GetAscent() + rHeight
- m_pCurr
->Height();
70 SwLineLayout
*SwTextIter::GetPrev_()
74 SwLineLayout
*pLay
= m_pInf
->GetParaPortion();
77 while( pLay
->GetNext() != m_pCurr
)
78 pLay
= pLay
->GetNext();
83 const SwLineLayout
*SwTextIter::GetPrev()
90 const SwLineLayout
*SwTextIter::Prev()
98 m_nStart
= m_nStart
- m_pCurr
->GetLen();
99 m_nY
= m_nY
- GetLineHeight();
100 if( !m_pCurr
->IsDummy() && !(--m_nLineNr
) )
108 const SwLineLayout
*SwTextIter::Next()
110 if(m_pCurr
->GetNext())
114 m_nStart
= m_nStart
+ m_pCurr
->GetLen();
115 m_nY
+= GetLineHeight();
116 if( m_pCurr
->GetLen() || ( m_nLineNr
>1 && !m_pCurr
->IsDummy() ) )
118 m_pCurr
= m_pCurr
->GetNext();
125 const SwLineLayout
*SwTextIter::NextLine()
127 const SwLineLayout
*pNext
= Next();
128 while( pNext
&& pNext
->IsDummy() && pNext
->GetNext() )
135 const SwLineLayout
*SwTextIter::GetNextLine() const
137 const SwLineLayout
*pNext
= m_pCurr
->GetNext();
138 while( pNext
&& pNext
->IsDummy() && pNext
->GetNext() )
140 pNext
= pNext
->GetNext();
145 const SwLineLayout
*SwTextIter::GetPrevLine()
147 const SwLineLayout
*pRoot
= m_pInf
->GetParaPortion();
148 if( pRoot
== m_pCurr
)
150 const SwLineLayout
*pLay
= pRoot
;
152 while( pLay
->GetNext() != m_pCurr
)
153 pLay
= pLay
->GetNext();
155 if( pLay
->IsDummy() )
157 const SwLineLayout
*pTmp
= pRoot
;
158 pLay
= pRoot
->IsDummy() ? nullptr : pRoot
;
159 while( pTmp
->GetNext() != m_pCurr
)
161 if( !pTmp
->IsDummy() )
163 pTmp
= pTmp
->GetNext();
167 // If nothing has changed, then there are only dummy's
171 const SwLineLayout
*SwTextIter::PrevLine()
173 const SwLineLayout
*pMyPrev
= Prev();
177 const SwLineLayout
*pLast
= pMyPrev
;
178 while( pMyPrev
&& pMyPrev
->IsDummy() )
183 return pMyPrev
? pMyPrev
: pLast
;
186 void SwTextIter::Bottom()
194 void SwTextIter::CharToLine(TextFrameIndex
const nChar
)
196 while( m_nStart
+ m_pCurr
->GetLen() <= nChar
&& Next() )
198 while( m_nStart
> nChar
&& Prev() )
202 // 1170: takes into account ambiguities:
203 const SwLineLayout
*SwTextCursor::CharCursorToLine(TextFrameIndex
const nPosition
)
205 CharToLine( nPosition
);
206 if( nPosition
!= m_nStart
)
207 s_bRightMargin
= false;
208 bool bPrevious
= s_bRightMargin
&& m_pCurr
->GetLen() && GetPrev() &&
210 if (bPrevious
&& nPosition
&& CH_BREAK
== GetInfo().GetChar(nPosition
- TextFrameIndex(1)))
212 return bPrevious
? PrevLine() : m_pCurr
;
215 SwTwips
SwTextCursor::AdjustBaseLine( const SwLineLayout
& rLine
,
216 const SwLinePortion
* pPor
,
217 SwTwips nPorHeight
, SwTwips nPorAscent
,
218 const bool bAutoToCentered
) const
222 nPorHeight
= pPor
->Height();
223 nPorAscent
= pPor
->GetAscent();
226 SwTwips nOfst
= rLine
.GetRealHeight() - rLine
.Height();
228 SwTextGridItem
const*const pGrid(GetGridItem(m_pFrame
->FindPageFrame()));
230 if ( pGrid
&& GetInfo().SnapToGrid() && pGrid
->IsSquaredMode() )
232 const sal_uInt16 nRubyHeight
= pGrid
->GetRubyHeight();
233 const bool bRubyTop
= ! pGrid
->GetRubyTextBelow();
235 if ( GetInfo().IsMulti() )
236 // we are inside the GetCharRect recursion for multi portions
237 // we center the portion in its surrounding line
238 nOfst
= ( m_pCurr
->Height() - nPorHeight
) / 2 + nPorAscent
;
241 // We have to take care for ruby portions.
242 // The ruby portion is NOT centered
243 nOfst
= nOfst
+ nPorAscent
;
245 if ( ! pPor
|| ! pPor
->IsMultiPortion() ||
246 ! static_cast<const SwMultiPortion
*>(pPor
)->IsRuby() )
248 // Portions which are bigger than on grid distance are
249 // centered inside the whole line.
252 const sal_uInt16 nLineNet
= rLine
.Height() - nRubyHeight
;
253 //const sal_uInt16 nLineNet = ( nPorHeight > nGridWidth ) ?
254 // rLine.Height() - nRubyHeight :
256 nOfst
+= ( nLineNet
- nPorHeight
) / 2;
258 nOfst
+= nRubyHeight
;
264 switch ( GetLineInfo().GetVertAlign() ) {
265 case SvxParaVertAlignItem::Align::Top
:
266 nOfst
= nOfst
+ nPorAscent
;
268 case SvxParaVertAlignItem::Align::Center
:
269 OSL_ENSURE( rLine
.Height() >= nPorHeight
, "Portion height > Line height");
270 nOfst
+= ( rLine
.Height() - nPorHeight
) / 2 + nPorAscent
;
272 case SvxParaVertAlignItem::Align::Bottom
:
273 nOfst
+= rLine
.Height() - nPorHeight
+ nPorAscent
;
275 case SvxParaVertAlignItem::Align::Automatic
:
276 if ( bAutoToCentered
|| GetInfo().GetTextFrame()->IsVertical() )
278 // Vertical text has these cases to calculate the baseline:
279 // - Implicitly TB and RL: the origo is the top right corner, offset is the
281 // - (Implicitly TB and) LR: the origo is the top left corner, offset is the
283 // - BT and LR: the origo is the bottom left corner, offset is the ascent.
284 if (GetInfo().GetTextFrame()->IsVertLR() && !GetInfo().GetTextFrame()->IsVertLRBT())
285 nOfst
+= rLine
.Height() - ( rLine
.Height() - nPorHeight
) / 2 - nPorAscent
;
288 SwTwips nLineHeight
= 0;
289 bool bHadClearingBreak
= false;
290 if (GetInfo().GetTextFrame()->IsVertical())
292 // Ignore the height of clearing break portions in the automatic
294 const SwLinePortion
* pLinePor
= rLine
.GetFirstPortion();
297 bool bClearingBreak
= false;
298 if (pLinePor
->IsBreakPortion())
300 auto pBreakPortion
= static_cast<const SwBreakPortion
*>(pLinePor
);
301 bClearingBreak
= pBreakPortion
->GetClear() != SwLineBreakClear::NONE
;
304 bHadClearingBreak
= true;
307 if (!bClearingBreak
&& pLinePor
->Height() > nLineHeight
)
309 nLineHeight
= pLinePor
->Height();
311 pLinePor
= pLinePor
->GetNextPortion();
315 if (!bHadClearingBreak
)
317 nLineHeight
= rLine
.Height();
320 nOfst
+= ( nLineHeight
- nPorHeight
) / 2 + nPorAscent
;
325 case SvxParaVertAlignItem::Align::Baseline
:
327 if (pPor
&& pPor
->GetHangingBaseline())
329 nOfst
+= rLine
.GetAscent() // Romn baseline of the line.
330 - rLine
.GetHangingBaseline() // Hanging baseline of the line.
331 + pPor
->GetHangingBaseline(); // Romn baseline of the portion.
334 nOfst
= nOfst
+ rLine
.GetAscent();
342 void SwTextIter::TwipsToLine( const SwTwips y
)
344 while( m_nY
+ GetLineHeight() <= y
&& Next() )
346 while( m_nY
> y
&& Prev() )
350 // Local helper function to check, if pCurr needs a field rest portion:
351 static bool lcl_NeedsFieldRest( const SwLineLayout
* pCurr
)
353 const SwLinePortion
*pPor
= pCurr
->GetNextPortion();
355 while( pPor
&& !bRet
)
357 bRet
= pPor
->InFieldGrp() && static_cast<const SwFieldPortion
*>(pPor
)->HasFollow();
358 if( !pPor
->GetNextPortion() || !pPor
->GetNextPortion()->InFieldGrp() )
360 pPor
= pPor
->GetNextPortion();
365 void SwTextIter::TruncLines( bool bNoteFollow
)
367 SwLineLayout
*pDel
= m_pCurr
->GetNext();
368 TextFrameIndex
const nEnd
= m_nStart
+ m_pCurr
->GetLen();
372 m_pCurr
->SetNext( nullptr );
373 if (MaybeHasHints() && bNoteFollow
)
375 GetInfo().GetParaPortion()->SetFollowField( pDel
->IsRest() ||
376 lcl_NeedsFieldRest( m_pCurr
) );
378 // bug 88534: wrong positioning of flys
379 SwTextFrame
* pFollow
= GetTextFrame()->GetFollow();
380 if ( pFollow
&& ! pFollow
->IsLocked() &&
381 nEnd
== pFollow
->GetOffset() )
383 TextFrameIndex nRangeEnd
= nEnd
;
384 SwLineLayout
* pLine
= pDel
;
386 // determine range to be searched for flys anchored as characters
389 nRangeEnd
= nRangeEnd
+ pLine
->GetLen();
390 pLine
= pLine
->GetNext();
393 // examine hints in range nEnd - (nEnd + nRangeChar)
394 SwTextNode
const* pNode(nullptr);
395 sw::MergedAttrIter
iter(*GetTextFrame());
396 for (SwTextAttr
const* pHt
= iter
.NextAttr(&pNode
); pHt
; pHt
= iter
.NextAttr(&pNode
))
398 if( RES_TXTATR_FLYCNT
== pHt
->Which() )
400 // check if hint is in our range
401 TextFrameIndex
const nTmpPos(
402 GetTextFrame()->MapModelToView(pNode
, pHt
->GetStart()));
403 if ( nEnd
<= nTmpPos
&& nTmpPos
< nRangeEnd
)
404 pFollow
->InvalidateRange_(
405 SwCharRange( nTmpPos
, nTmpPos
) );
412 if( m_pCurr
->IsDummy() &&
413 !m_pCurr
->GetLen() &&
414 m_nStart
< TextFrameIndex(GetTextFrame()->GetText().getLength()))
416 m_pCurr
->SetRealHeight( 1 );
419 m_pFrame
->RemoveFootnote( nEnd
);
422 void SwTextIter::CntHyphens( sal_uInt8
&nEndCnt
, sal_uInt8
&nMidCnt
) const
426 if ( m_bPrev
&& m_pPrev
&& !m_pPrev
->IsEndHyph() && !m_pPrev
->IsMidHyph() )
428 SwLineLayout
*pLay
= m_pInf
->GetParaPortion();
429 if( m_pCurr
== pLay
)
431 while( pLay
!= m_pCurr
)
433 if ( pLay
->IsEndHyph() )
437 if ( pLay
->IsMidHyph() )
441 pLay
= pLay
->GetNext();
445 // Change current output device to formatting device, this has to be done before
447 SwHookOut::SwHookOut( SwTextSizeInfo
& rInfo
) :
449 pOut( rInfo
.GetOut() ),
450 bOnWin( rInfo
.OnWin() )
452 OSL_ENSURE( rInfo
.GetRefDev(), "No reference device for text formatting" );
455 rInfo
.SetOut( rInfo
.GetRefDev() );
456 rInfo
.SetOnWin( false );
459 SwHookOut::~SwHookOut()
461 pInf
->SetOut( pOut
);
462 pInf
->SetOnWin( bOnWin
);
465 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */