android: Update app-specific/MIME type icons
[LibreOffice.git] / sw / source / core / text / itrtxt.cxx
blob1d1eed3e0837cab0e4f45e87ca2b1faf2bc88940
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 <ndtxt.hxx>
21 #include <txatbase.hxx>
22 #include <paratr.hxx>
23 #include <vcl/outdev.hxx>
24 #include <editeng/paravertalignitem.hxx>
26 #include "pormulti.hxx"
27 #include <pagefrm.hxx>
28 #include <tgrditem.hxx>
29 #include "porfld.hxx"
30 #include "porrst.hxx"
32 #include "itrtxt.hxx"
33 #include <txtfrm.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();
43 m_pFrame = pNewFrame;
44 m_pInf = pNewInf;
45 m_aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode );
46 m_nFrameStart = m_pFrame->getFrameArea().Pos().Y() + m_pFrame->getFramePrintArea().Pos().Y();
47 SwTextIter::Init();
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();
58 m_nY = m_nFrameStart;
59 m_bPrev = true;
60 m_pPrev = nullptr;
61 m_nLineNr = 1;
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_()
72 m_pPrev = nullptr;
73 m_bPrev = true;
74 SwLineLayout *pLay = m_pInf->GetParaPortion();
75 if( m_pCurr == pLay )
76 return nullptr;
77 while( pLay->GetNext() != m_pCurr )
78 pLay = pLay->GetNext();
79 m_pPrev = pLay;
80 return m_pPrev;
83 const SwLineLayout *SwTextIter::GetPrev()
85 if(! m_bPrev)
86 GetPrev_();
87 return m_pPrev;
90 const SwLineLayout *SwTextIter::Prev()
92 if( !m_bPrev )
93 GetPrev_();
94 if( m_pPrev )
96 m_bPrev = false;
97 m_pCurr = m_pPrev;
98 m_nStart = m_nStart - m_pCurr->GetLen();
99 m_nY = m_nY - GetLineHeight();
100 if( !m_pCurr->IsDummy() && !(--m_nLineNr) )
101 ++m_nLineNr;
102 return m_pCurr;
104 else
105 return nullptr;
108 const SwLineLayout *SwTextIter::Next()
110 if(m_pCurr->GetNext())
112 m_pPrev = m_pCurr;
113 m_bPrev = true;
114 m_nStart = m_nStart + m_pCurr->GetLen();
115 m_nY += GetLineHeight();
116 if( m_pCurr->GetLen() || ( m_nLineNr>1 && !m_pCurr->IsDummy() ) )
117 ++m_nLineNr;
118 m_pCurr = m_pCurr->GetNext();
119 return m_pCurr;
121 else
122 return nullptr;
125 const SwLineLayout *SwTextIter::NextLine()
127 const SwLineLayout *pNext = Next();
128 while( pNext && pNext->IsDummy() && pNext->GetNext() )
130 pNext = Next();
132 return pNext;
135 const SwLineLayout *SwTextIter::GetNextLine() const
137 const SwLineLayout *pNext = m_pCurr->GetNext();
138 while( pNext && pNext->IsDummy() && pNext->GetNext() )
140 pNext = pNext->GetNext();
142 return pNext;
145 const SwLineLayout *SwTextIter::GetPrevLine()
147 const SwLineLayout *pRoot = m_pInf->GetParaPortion();
148 if( pRoot == m_pCurr )
149 return nullptr;
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() )
162 pLay = pTmp;
163 pTmp = pTmp->GetNext();
167 // If nothing has changed, then there are only dummy's
168 return pLay;
171 const SwLineLayout *SwTextIter::PrevLine()
173 const SwLineLayout *pMyPrev = Prev();
174 if( !pMyPrev )
175 return nullptr;
177 const SwLineLayout *pLast = pMyPrev;
178 while( pMyPrev && pMyPrev->IsDummy() )
180 pLast = pMyPrev;
181 pMyPrev = Prev();
183 return pMyPrev ? pMyPrev : pLast;
186 void SwTextIter::Bottom()
188 while( Next() )
190 // nothing
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() &&
209 GetPrev()->GetLen();
210 if (bPrevious && nPosition && CH_BREAK == GetInfo().GetChar(nPosition - TextFrameIndex(1)))
211 bPrevious = false;
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
220 if ( pPor )
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;
239 else
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.
251 //for text refactor
252 const sal_uInt16 nLineNet = rLine.Height() - nRubyHeight;
253 //const sal_uInt16 nLineNet = ( nPorHeight > nGridWidth ) ?
254 // rLine.Height() - nRubyHeight :
255 // nGridWidth;
256 nOfst += ( nLineNet - nPorHeight ) / 2;
257 if ( bRubyTop )
258 nOfst += nRubyHeight;
262 else
264 switch ( GetLineInfo().GetVertAlign() ) {
265 case SvxParaVertAlignItem::Align::Top :
266 nOfst = nOfst + nPorAscent;
267 break;
268 case SvxParaVertAlignItem::Align::Center :
269 OSL_ENSURE( rLine.Height() >= nPorHeight, "Portion height > Line height");
270 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
271 break;
272 case SvxParaVertAlignItem::Align::Bottom :
273 nOfst += rLine.Height() - nPorHeight + nPorAscent;
274 break;
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
280 // ascent.
281 // - (Implicitly TB and) LR: the origo is the top left corner, offset is the
282 // descent.
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;
286 else
288 SwTwips nLineHeight = 0;
289 bool bHadClearingBreak = false;
290 if (GetInfo().GetTextFrame()->IsVertical())
292 // Ignore the height of clearing break portions in the automatic
293 // alignment case.
294 const SwLinePortion* pLinePor = rLine.GetFirstPortion();
295 while (pLinePor)
297 bool bClearingBreak = false;
298 if (pLinePor->IsBreakPortion())
300 auto pBreakPortion = static_cast<const SwBreakPortion*>(pLinePor);
301 bClearingBreak = pBreakPortion->GetClear() != SwLineBreakClear::NONE;
302 if (bClearingBreak)
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;
322 break;
324 [[fallthrough]];
325 case SvxParaVertAlignItem::Align::Baseline :
326 // base line
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.
333 else
334 nOfst = nOfst + rLine.GetAscent();
335 break;
339 return nOfst;
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();
354 bool bRet = false;
355 while( pPor && !bRet )
357 bRet = pPor->InFieldGrp() && static_cast<const SwFieldPortion*>(pPor)->HasFollow();
358 if( !pPor->GetNextPortion() || !pPor->GetNextPortion()->InFieldGrp() )
359 break;
360 pPor = pPor->GetNextPortion();
362 return bRet;
365 void SwTextIter::TruncLines( bool bNoteFollow )
367 SwLineLayout *pDel = m_pCurr->GetNext();
368 TextFrameIndex const nEnd = m_nStart + m_pCurr->GetLen();
370 if( pDel )
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
387 while ( pLine )
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 ) );
410 delete pDel;
412 if( m_pCurr->IsDummy() &&
413 !m_pCurr->GetLen() &&
414 m_nStart < TextFrameIndex(GetTextFrame()->GetText().getLength()))
416 m_pCurr->SetRealHeight( 1 );
418 if (MaybeHasHints())
419 m_pFrame->RemoveFootnote( nEnd );
422 void SwTextIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const
424 nEndCnt = 0;
425 nMidCnt = 0;
426 if ( m_bPrev && m_pPrev && !m_pPrev->IsEndHyph() && !m_pPrev->IsMidHyph() )
427 return;
428 SwLineLayout *pLay = m_pInf->GetParaPortion();
429 if( m_pCurr == pLay )
430 return;
431 while( pLay != m_pCurr )
433 if ( pLay->IsEndHyph() )
434 nEndCnt++;
435 else
436 nEndCnt = 0;
437 if ( pLay->IsMidHyph() )
438 nMidCnt++;
439 else
440 nMidCnt = 0;
441 pLay = pLay->GetNext();
445 // Change current output device to formatting device, this has to be done before
446 // formatting.
447 SwHookOut::SwHookOut( SwTextSizeInfo& rInfo ) :
448 pInf( &rInfo ),
449 pOut( rInfo.GetOut() ),
450 bOnWin( rInfo.OnWin() )
452 OSL_ENSURE( rInfo.GetRefDev(), "No reference device for text formatting" );
454 // set new values
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: */