diff options
Diffstat (limited to 'sw/source/core/text/itrtxt.cxx')
-rw-r--r-- | sw/source/core/text/itrtxt.cxx | 465 |
1 files changed, 465 insertions, 0 deletions
diff --git a/sw/source/core/text/itrtxt.cxx b/sw/source/core/text/itrtxt.cxx new file mode 100644 index 000000000..1d1eed3e0 --- /dev/null +++ b/sw/source/core/text/itrtxt.cxx @@ -0,0 +1,465 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + +#include <ndtxt.hxx> +#include <txatbase.hxx> +#include <paratr.hxx> +#include <vcl/outdev.hxx> +#include <editeng/paravertalignitem.hxx> + +#include "pormulti.hxx" +#include <pagefrm.hxx> +#include <tgrditem.hxx> +#include "porfld.hxx" +#include "porrst.hxx" + +#include "itrtxt.hxx" +#include <txtfrm.hxx> + +void SwTextIter::CtorInitTextIter( SwTextFrame *pNewFrame, SwTextInfo *pNewInf ) +{ + assert(pNewFrame->GetPara()); + + CtorInitAttrIter( *pNewFrame->GetTextNodeFirst(), pNewFrame->GetPara()->GetScriptInfo(), pNewFrame ); + + SwTextNode const*const pNode = pNewFrame->GetTextNodeForParaProps(); + + m_pFrame = pNewFrame; + m_pInf = pNewInf; + m_aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode ); + m_nFrameStart = m_pFrame->getFrameArea().Pos().Y() + m_pFrame->getFramePrintArea().Pos().Y(); + SwTextIter::Init(); + + // Order is important: only execute FillRegister if GetValue!=0 + m_bRegisterOn = pNode->GetSwAttrSet().GetRegister().GetValue() + && m_pFrame->FillRegister( m_nRegStart, m_nRegDiff ); +} + +void SwTextIter::Init() +{ + m_pCurr = m_pInf->GetParaPortion(); + m_nStart = m_pInf->GetTextStart(); + m_nY = m_nFrameStart; + m_bPrev = true; + m_pPrev = nullptr; + m_nLineNr = 1; +} + +void SwTextIter::CalcAscentAndHeight( SwTwips &rAscent, SwTwips &rHeight ) const +{ + rHeight = GetLineHeight(); + rAscent = m_pCurr->GetAscent() + rHeight - m_pCurr->Height(); +} + +SwLineLayout *SwTextIter::GetPrev_() +{ + m_pPrev = nullptr; + m_bPrev = true; + SwLineLayout *pLay = m_pInf->GetParaPortion(); + if( m_pCurr == pLay ) + return nullptr; + while( pLay->GetNext() != m_pCurr ) + pLay = pLay->GetNext(); + m_pPrev = pLay; + return m_pPrev; +} + +const SwLineLayout *SwTextIter::GetPrev() +{ + if(! m_bPrev) + GetPrev_(); + return m_pPrev; +} + +const SwLineLayout *SwTextIter::Prev() +{ + if( !m_bPrev ) + GetPrev_(); + if( m_pPrev ) + { + m_bPrev = false; + m_pCurr = m_pPrev; + m_nStart = m_nStart - m_pCurr->GetLen(); + m_nY = m_nY - GetLineHeight(); + if( !m_pCurr->IsDummy() && !(--m_nLineNr) ) + ++m_nLineNr; + return m_pCurr; + } + else + return nullptr; +} + +const SwLineLayout *SwTextIter::Next() +{ + if(m_pCurr->GetNext()) + { + m_pPrev = m_pCurr; + m_bPrev = true; + m_nStart = m_nStart + m_pCurr->GetLen(); + m_nY += GetLineHeight(); + if( m_pCurr->GetLen() || ( m_nLineNr>1 && !m_pCurr->IsDummy() ) ) + ++m_nLineNr; + m_pCurr = m_pCurr->GetNext(); + return m_pCurr; + } + else + return nullptr; +} + +const SwLineLayout *SwTextIter::NextLine() +{ + const SwLineLayout *pNext = Next(); + while( pNext && pNext->IsDummy() && pNext->GetNext() ) + { + pNext = Next(); + } + return pNext; +} + +const SwLineLayout *SwTextIter::GetNextLine() const +{ + const SwLineLayout *pNext = m_pCurr->GetNext(); + while( pNext && pNext->IsDummy() && pNext->GetNext() ) + { + pNext = pNext->GetNext(); + } + return pNext; +} + +const SwLineLayout *SwTextIter::GetPrevLine() +{ + const SwLineLayout *pRoot = m_pInf->GetParaPortion(); + if( pRoot == m_pCurr ) + return nullptr; + const SwLineLayout *pLay = pRoot; + + while( pLay->GetNext() != m_pCurr ) + pLay = pLay->GetNext(); + + if( pLay->IsDummy() ) + { + const SwLineLayout *pTmp = pRoot; + pLay = pRoot->IsDummy() ? nullptr : pRoot; + while( pTmp->GetNext() != m_pCurr ) + { + if( !pTmp->IsDummy() ) + pLay = pTmp; + pTmp = pTmp->GetNext(); + } + } + + // If nothing has changed, then there are only dummy's + return pLay; +} + +const SwLineLayout *SwTextIter::PrevLine() +{ + const SwLineLayout *pMyPrev = Prev(); + if( !pMyPrev ) + return nullptr; + + const SwLineLayout *pLast = pMyPrev; + while( pMyPrev && pMyPrev->IsDummy() ) + { + pLast = pMyPrev; + pMyPrev = Prev(); + } + return pMyPrev ? pMyPrev : pLast; +} + +void SwTextIter::Bottom() +{ + while( Next() ) + { + // nothing + } +} + +void SwTextIter::CharToLine(TextFrameIndex const nChar) +{ + while( m_nStart + m_pCurr->GetLen() <= nChar && Next() ) + ; + while( m_nStart > nChar && Prev() ) + ; +} + +// 1170: takes into account ambiguities: +const SwLineLayout *SwTextCursor::CharCursorToLine(TextFrameIndex const nPosition) +{ + CharToLine( nPosition ); + if( nPosition != m_nStart ) + s_bRightMargin = false; + bool bPrevious = s_bRightMargin && m_pCurr->GetLen() && GetPrev() && + GetPrev()->GetLen(); + if (bPrevious && nPosition && CH_BREAK == GetInfo().GetChar(nPosition - TextFrameIndex(1))) + bPrevious = false; + return bPrevious ? PrevLine() : m_pCurr; +} + +SwTwips SwTextCursor::AdjustBaseLine( const SwLineLayout& rLine, + const SwLinePortion* pPor, + SwTwips nPorHeight, SwTwips nPorAscent, + const bool bAutoToCentered ) const +{ + if ( pPor ) + { + nPorHeight = pPor->Height(); + nPorAscent = pPor->GetAscent(); + } + + SwTwips nOfst = rLine.GetRealHeight() - rLine.Height(); + + SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame())); + + if ( pGrid && GetInfo().SnapToGrid() && pGrid->IsSquaredMode() ) + { + const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight(); + const bool bRubyTop = ! pGrid->GetRubyTextBelow(); + + if ( GetInfo().IsMulti() ) + // we are inside the GetCharRect recursion for multi portions + // we center the portion in its surrounding line + nOfst = ( m_pCurr->Height() - nPorHeight ) / 2 + nPorAscent; + else + { + // We have to take care for ruby portions. + // The ruby portion is NOT centered + nOfst = nOfst + nPorAscent; + + if ( ! pPor || ! pPor->IsMultiPortion() || + ! static_cast<const SwMultiPortion*>(pPor)->IsRuby() ) + { + // Portions which are bigger than on grid distance are + // centered inside the whole line. + + //for text refactor + const sal_uInt16 nLineNet = rLine.Height() - nRubyHeight; + //const sal_uInt16 nLineNet = ( nPorHeight > nGridWidth ) ? + // rLine.Height() - nRubyHeight : + // nGridWidth; + nOfst += ( nLineNet - nPorHeight ) / 2; + if ( bRubyTop ) + nOfst += nRubyHeight; + } + } + } + else + { + switch ( GetLineInfo().GetVertAlign() ) { + case SvxParaVertAlignItem::Align::Top : + nOfst = nOfst + nPorAscent; + break; + case SvxParaVertAlignItem::Align::Center : + OSL_ENSURE( rLine.Height() >= nPorHeight, "Portion height > Line height"); + nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent; + break; + case SvxParaVertAlignItem::Align::Bottom : + nOfst += rLine.Height() - nPorHeight + nPorAscent; + break; + case SvxParaVertAlignItem::Align::Automatic : + if ( bAutoToCentered || GetInfo().GetTextFrame()->IsVertical() ) + { + // Vertical text has these cases to calculate the baseline: + // - Implicitly TB and RL: the origo is the top right corner, offset is the + // ascent. + // - (Implicitly TB and) LR: the origo is the top left corner, offset is the + // descent. + // - BT and LR: the origo is the bottom left corner, offset is the ascent. + if (GetInfo().GetTextFrame()->IsVertLR() && !GetInfo().GetTextFrame()->IsVertLRBT()) + nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent; + else + { + SwTwips nLineHeight = 0; + bool bHadClearingBreak = false; + if (GetInfo().GetTextFrame()->IsVertical()) + { + // Ignore the height of clearing break portions in the automatic + // alignment case. + const SwLinePortion* pLinePor = rLine.GetFirstPortion(); + while (pLinePor) + { + bool bClearingBreak = false; + if (pLinePor->IsBreakPortion()) + { + auto pBreakPortion = static_cast<const SwBreakPortion*>(pLinePor); + bClearingBreak = pBreakPortion->GetClear() != SwLineBreakClear::NONE; + if (bClearingBreak) + { + bHadClearingBreak = true; + } + } + if (!bClearingBreak && pLinePor->Height() > nLineHeight) + { + nLineHeight = pLinePor->Height(); + } + pLinePor = pLinePor->GetNextPortion(); + } + } + + if (!bHadClearingBreak) + { + nLineHeight = rLine.Height(); + } + + nOfst += ( nLineHeight - nPorHeight ) / 2 + nPorAscent; + } + break; + } + [[fallthrough]]; + case SvxParaVertAlignItem::Align::Baseline : + // base line + if (pPor && pPor->GetHangingBaseline()) + { + nOfst += rLine.GetAscent() // Romn baseline of the line. + - rLine.GetHangingBaseline() // Hanging baseline of the line. + + pPor->GetHangingBaseline(); // Romn baseline of the portion. + } + else + nOfst = nOfst + rLine.GetAscent(); + break; + } + } + + return nOfst; +} + +void SwTextIter::TwipsToLine( const SwTwips y) +{ + while( m_nY + GetLineHeight() <= y && Next() ) + ; + while( m_nY > y && Prev() ) + ; +} + +// Local helper function to check, if pCurr needs a field rest portion: +static bool lcl_NeedsFieldRest( const SwLineLayout* pCurr ) +{ + const SwLinePortion *pPor = pCurr->GetNextPortion(); + bool bRet = false; + while( pPor && !bRet ) + { + bRet = pPor->InFieldGrp() && static_cast<const SwFieldPortion*>(pPor)->HasFollow(); + if( !pPor->GetNextPortion() || !pPor->GetNextPortion()->InFieldGrp() ) + break; + pPor = pPor->GetNextPortion(); + } + return bRet; +} + +void SwTextIter::TruncLines( bool bNoteFollow ) +{ + SwLineLayout *pDel = m_pCurr->GetNext(); + TextFrameIndex const nEnd = m_nStart + m_pCurr->GetLen(); + + if( pDel ) + { + m_pCurr->SetNext( nullptr ); + if (MaybeHasHints() && bNoteFollow) + { + GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() || + lcl_NeedsFieldRest( m_pCurr ) ); + + // bug 88534: wrong positioning of flys + SwTextFrame* pFollow = GetTextFrame()->GetFollow(); + if ( pFollow && ! pFollow->IsLocked() && + nEnd == pFollow->GetOffset() ) + { + TextFrameIndex nRangeEnd = nEnd; + SwLineLayout* pLine = pDel; + + // determine range to be searched for flys anchored as characters + while ( pLine ) + { + nRangeEnd = nRangeEnd + pLine->GetLen(); + pLine = pLine->GetNext(); + } + + // examine hints in range nEnd - (nEnd + nRangeChar) + SwTextNode const* pNode(nullptr); + sw::MergedAttrIter iter(*GetTextFrame()); + for (SwTextAttr const* pHt = iter.NextAttr(&pNode); pHt; pHt = iter.NextAttr(&pNode)) + { + if( RES_TXTATR_FLYCNT == pHt->Which() ) + { + // check if hint is in our range + TextFrameIndex const nTmpPos( + GetTextFrame()->MapModelToView(pNode, pHt->GetStart())); + if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd ) + pFollow->InvalidateRange_( + SwCharRange( nTmpPos, nTmpPos ) ); + } + } + } + } + delete pDel; + } + if( m_pCurr->IsDummy() && + !m_pCurr->GetLen() && + m_nStart < TextFrameIndex(GetTextFrame()->GetText().getLength())) + { + m_pCurr->SetRealHeight( 1 ); + } + if (MaybeHasHints()) + m_pFrame->RemoveFootnote( nEnd ); +} + +void SwTextIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const +{ + nEndCnt = 0; + nMidCnt = 0; + if ( m_bPrev && m_pPrev && !m_pPrev->IsEndHyph() && !m_pPrev->IsMidHyph() ) + return; + SwLineLayout *pLay = m_pInf->GetParaPortion(); + if( m_pCurr == pLay ) + return; + while( pLay != m_pCurr ) + { + if ( pLay->IsEndHyph() ) + nEndCnt++; + else + nEndCnt = 0; + if ( pLay->IsMidHyph() ) + nMidCnt++; + else + nMidCnt = 0; + pLay = pLay->GetNext(); + } +} + +// Change current output device to formatting device, this has to be done before +// formatting. +SwHookOut::SwHookOut( SwTextSizeInfo& rInfo ) : + pInf( &rInfo ), + pOut( rInfo.GetOut() ), + bOnWin( rInfo.OnWin() ) +{ + OSL_ENSURE( rInfo.GetRefDev(), "No reference device for text formatting" ); + + // set new values + rInfo.SetOut( rInfo.GetRefDev() ); + rInfo.SetOnWin( false ); +} + +SwHookOut::~SwHookOut() +{ + pInf->SetOut( pOut ); + pInf->SetOnWin( bOnWin ); +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |