blob: 98a9350e7f4339a35daa3c705411d93af1b50a8d [file] [log] [blame]
/**************************************************************
*
* 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
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sw.hxx"
#include "ndtxt.hxx"
#include "flyfrm.hxx"
#include "paratr.hxx"
#include "errhdl.hxx"
#include <vcl/outdev.hxx>
#include <editeng/paravertalignitem.hxx>
#include "pormulti.hxx"
#include <pagefrm.hxx>
#include <pagedesc.hxx> // SwPageDesc
#include <tgrditem.hxx>
#include <porfld.hxx>
#include "txtcfg.hxx"
#include "itrtxt.hxx"
#include "txtfrm.hxx"
#include "porfly.hxx"
#if OSL_DEBUG_LEVEL > 1
# include "txtfrm.hxx" // GetFrmID,
#endif
/*************************************************************************
* SwTxtIter::CtorInitTxtIter()
*************************************************************************/
void SwTxtIter::CtorInitTxtIter( SwTxtFrm *pNewFrm, SwTxtInfo *pNewInf )
{
#ifdef DBGTXT
// nStopAt laesst sich vom CV bearbeiten.
static MSHORT nStopAt = 0;
if( nStopAt == pNewFrm->GetFrmId() )
{
int i = pNewFrm->GetFrmId();
}
#endif
SwTxtNode *pNode = pNewFrm->GetTxtNode();
ASSERT( pNewFrm->GetPara(), "No paragraph" );
CtorInitAttrIter( *pNode, pNewFrm->GetPara()->GetScriptInfo(), pNewFrm );
pFrm = pNewFrm;
pInf = pNewInf;
// --> OD 2008-01-17 #newlistlevelattrs#
aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode );
// <--
nFrameStart = pFrm->Frm().Pos().Y() + pFrm->Prt().Pos().Y();
SwTxtIter::Init();
if( pNode->GetSwAttrSet().GetRegister().GetValue() )
bRegisterOn = pFrm->FillRegister( nRegStart, nRegDiff );
else
bRegisterOn = sal_False;
}
/*************************************************************************
* SwTxtIter::Init()
*************************************************************************/
void SwTxtIter::Init()
{
pCurr = pInf->GetParaPortion();
nStart = pInf->GetTxtStart();
nY = nFrameStart;
bPrev = sal_True;
pPrev = 0;
nLineNr = 1;
}
/*************************************************************************
* SwTxtIter::_GetHeightAndAscent()
*************************************************************************/
void SwTxtIter::CalcAscentAndHeight( KSHORT &rAscent, KSHORT &rHeight ) const
{
rHeight = GetLineHeight();
rAscent = pCurr->GetAscent() + rHeight - pCurr->Height();
}
/*************************************************************************
* SwTxtIter::_GetPrev()
*************************************************************************/
SwLineLayout *SwTxtIter::_GetPrev()
{
pPrev = 0;
bPrev = sal_True;
SwLineLayout *pLay = pInf->GetParaPortion();
if( pCurr == pLay )
return 0;
while( pLay->GetNext() != pCurr )
pLay = pLay->GetNext();
return pPrev = pLay;
}
/*************************************************************************
* SwTxtIter::GetPrev()
*************************************************************************/
const SwLineLayout *SwTxtIter::GetPrev()
{
if(! bPrev)
_GetPrev();
return pPrev;
}
/*************************************************************************
* SwTxtIter::Prev()
*************************************************************************/
const SwLineLayout *SwTxtIter::Prev()
{
if( !bPrev )
_GetPrev();
if( pPrev )
{
bPrev = sal_False;
pCurr = pPrev;
nStart = nStart - pCurr->GetLen();
nY = nY - GetLineHeight();
if( !pCurr->IsDummy() && !(--nLineNr) )
++nLineNr;
return pCurr;
}
else
return 0;
}
/*************************************************************************
* SwTxtIter::Next()
*************************************************************************/
const SwLineLayout *SwTxtIter::Next()
{
if(pCurr->GetNext())
{
pPrev = pCurr;
bPrev = sal_True;
nStart = nStart + pCurr->GetLen();
nY += GetLineHeight();
if( pCurr->GetLen() || ( nLineNr>1 && !pCurr->IsDummy() ) )
++nLineNr;
return pCurr = pCurr->GetNext();
}
else
return 0;
}
/*************************************************************************
* SwTxtIter::NextLine()
*************************************************************************/
const SwLineLayout *SwTxtIter::NextLine()
{
const SwLineLayout *pNext = Next();
while( pNext && pNext->IsDummy() && pNext->GetNext() )
{
DBG_LOOP;
pNext = Next();
}
return pNext;
}
/*************************************************************************
* SwTxtIter::GetNextLine()
*************************************************************************/
const SwLineLayout *SwTxtIter::GetNextLine() const
{
const SwLineLayout *pNext = pCurr->GetNext();
while( pNext && pNext->IsDummy() && pNext->GetNext() )
{
DBG_LOOP;
pNext = pNext->GetNext();
}
return (SwLineLayout*)pNext;
}
/*************************************************************************
* SwTxtIter::GetPrevLine()
*************************************************************************/
const SwLineLayout *SwTxtIter::GetPrevLine()
{
const SwLineLayout *pRoot = pInf->GetParaPortion();
if( pRoot == pCurr )
return 0;
const SwLineLayout *pLay = pRoot;
while( pLay->GetNext() != pCurr )
pLay = pLay->GetNext();
if( pLay->IsDummy() )
{
const SwLineLayout *pTmp = pRoot;
pLay = pRoot->IsDummy() ? 0 : pRoot;
while( pTmp->GetNext() != pCurr )
{
if( !pTmp->IsDummy() )
pLay = pTmp;
pTmp = pTmp->GetNext();
}
}
// Wenn sich nichts getan hat, dann gibt es nur noch Dummys
return (SwLineLayout*)pLay;
}
/*************************************************************************
* SwTxtIter::PrevLine()
*************************************************************************/
const SwLineLayout *SwTxtIter::PrevLine()
{
const SwLineLayout *pMyPrev = Prev();
if( !pMyPrev )
return 0;
const SwLineLayout *pLast = pMyPrev;
while( pMyPrev && pMyPrev->IsDummy() )
{
DBG_LOOP;
pLast = pMyPrev;
pMyPrev = Prev();
}
return (SwLineLayout*)(pMyPrev ? pMyPrev : pLast);
}
/*************************************************************************
* SwTxtIter::Bottom()
*************************************************************************/
void SwTxtIter::Bottom()
{
while( Next() )
{
DBG_LOOP;
}
}
/*************************************************************************
* SwTxtIter::CharToLine()
*************************************************************************/
void SwTxtIter::CharToLine(const xub_StrLen nChar)
{
while( nStart + pCurr->GetLen() <= nChar && Next() )
;
while( nStart > nChar && Prev() )
;
}
/*************************************************************************
* SwTxtIter::CharCrsrToLine()
*************************************************************************/
// 1170: beruecksichtigt Mehrdeutigkeiten:
const SwLineLayout *SwTxtCursor::CharCrsrToLine( const xub_StrLen nPosition )
{
CharToLine( nPosition );
if( nPosition != nStart )
bRightMargin = sal_False;
sal_Bool bPrevious = bRightMargin && pCurr->GetLen() && GetPrev() &&
GetPrev()->GetLen();
if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) )
bPrevious = sal_False;
return bPrevious ? PrevLine() : pCurr;
}
/*************************************************************************
* SwTxtCrsr::AdjustBaseLine()
*************************************************************************/
sal_uInt16 SwTxtCursor::AdjustBaseLine( const SwLineLayout& rLine,
const SwLinePortion* pPor,
sal_uInt16 nPorHeight, sal_uInt16 nPorAscent,
const sal_Bool bAutoToCentered ) const
{
if ( pPor )
{
nPorHeight = pPor->Height();
nPorAscent = pPor->GetAscent();
}
sal_uInt16 nOfst = rLine.GetRealHeight() - rLine.Height();
GETGRID( pFrm->FindPageFrm() )
const sal_Bool bHasGrid = pGrid && GetInfo().SnapToGrid();
if ( bHasGrid )
{
const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight();
const sal_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 = ( 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() ||
! ((SwMultiPortion*)pPor)->IsRuby() )
{
// Portions which are bigger than on grid distance are
// centered inside the whole line.
//for text refactor
const sal_uInt16 nLineNetto = rLine.Height() - nRubyHeight;
//const sal_uInt16 nLineNetto = ( nPorHeight > nGridWidth ) ?
// rLine.Height() - nRubyHeight :
// nGridWidth;
nOfst += ( nLineNetto - nPorHeight ) / 2;
if ( bRubyTop )
nOfst = nOfst + nRubyHeight;
}
}
}
else
{
switch ( GetLineInfo().GetVertAlign() ) {
case SvxParaVertAlignItem::TOP :
nOfst = nOfst + nPorAscent;
break;
case SvxParaVertAlignItem::CENTER :
ASSERT( rLine.Height() >= nPorHeight, "Portion height > Line height");
nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
break;
case SvxParaVertAlignItem::BOTTOM :
nOfst += rLine.Height() - nPorHeight + nPorAscent;
break;
case SvxParaVertAlignItem::AUTOMATIC :
if ( bAutoToCentered || GetInfo().GetTxtFrm()->IsVertical() )
{
//Badaa: 2008-04-18 * Support for Classical Mongolian Script (SCMS) joint with Jiayanmin
if( GetInfo().GetTxtFrm()->IsVertLR() )
nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent;
else
nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent;
break;
}
case SvxParaVertAlignItem::BASELINE :
// base line
nOfst = nOfst + rLine.GetAscent();
break;
}
}
return nOfst;
}
/*************************************************************************
* SwTxtIter::TwipsToLine()
*************************************************************************/
const SwLineLayout *SwTxtIter::TwipsToLine( const SwTwips y)
{
while( nY + GetLineHeight() <= y && Next() )
;
while( nY > y && Prev() )
;
return pCurr;
}
//
// Local helper function to check, if pCurr needs a field rest portion:
//
sal_Bool lcl_NeedsFieldRest( const SwLineLayout* pCurr )
{
const SwLinePortion *pPor = pCurr->GetPortion();
sal_Bool bRet = sal_False;
while( pPor && !bRet )
{
bRet = pPor->InFldGrp() && ((SwFldPortion*)pPor)->HasFollow();
if( !pPor->GetPortion() || !pPor->GetPortion()->InFldGrp() )
break;
pPor = pPor->GetPortion();
}
return bRet;
}
/*************************************************************************
* SwTxtIter::TruncLines()
*************************************************************************/
void SwTxtIter::TruncLines( sal_Bool bNoteFollow )
{
SwLineLayout *pDel = pCurr->GetNext();
const xub_StrLen nEnd = nStart + pCurr->GetLen();
if( pDel )
{
pCurr->SetNext( 0 );
if( GetHints() && bNoteFollow )
{
GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() ||
lcl_NeedsFieldRest( pCurr ) );
// bug 88534: wrong positioning of flys
SwTxtFrm* pFollow = GetTxtFrm()->GetFollow();
if ( pFollow && ! pFollow->IsLocked() &&
nEnd == pFollow->GetOfst() )
{
xub_StrLen nRangeEnd = nEnd;
SwLineLayout* pLine = pDel;
// determine range to be searched for flys anchored as characters
while ( pLine )
{
nRangeEnd = nRangeEnd + pLine->GetLen();
pLine = pLine->GetNext();
}
SwpHints* pTmpHints = GetTxtFrm()->GetTxtNode()->GetpSwpHints();
// examine hints in range nEnd - (nEnd + nRangeChar)
for( sal_uInt16 i = 0; i < pTmpHints->Count(); i++ )
{
const SwTxtAttr* pHt = pTmpHints->GetTextHint( i );
if( RES_TXTATR_FLYCNT == pHt->Which() )
{
// check, if hint is in our range
const sal_uInt16 nTmpPos = *pHt->GetStart();
if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd )
pFollow->_InvalidateRange(
SwCharRange( nTmpPos, nTmpPos ), 0 );
}
}
}
}
delete pDel;
}
if( pCurr->IsDummy() &&
!pCurr->GetLen() &&
nStart < GetTxtFrm()->GetTxt().Len() )
pCurr->SetRealHeight( 1 );
if( GetHints() )
pFrm->RemoveFtn( nEnd );
}
/*************************************************************************
* SwTxtIter::CntHyphens()
*************************************************************************/
void SwTxtIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const
{
nEndCnt = 0;
nMidCnt = 0;
if ( bPrev && pPrev && !pPrev->IsEndHyph() && !pPrev->IsMidHyph() )
return;
SwLineLayout *pLay = pInf->GetParaPortion();
if( pCurr == pLay )
return;
while( pLay != pCurr )
{
DBG_LOOP;
if ( pLay->IsEndHyph() )
nEndCnt++;
else
nEndCnt = 0;
if ( pLay->IsMidHyph() )
nMidCnt++;
else
nMidCnt = 0;
pLay = pLay->GetNext();
}
}
/*************************************************************************
* SwHookOut
*
* Change current output device to formatting device, this has to be done before
* formatting.
*************************************************************************/
SwHookOut::SwHookOut( SwTxtSizeInfo& rInfo ) :
pInf( &rInfo ),
pOut( rInfo.GetOut() ),
bOnWin( rInfo.OnWin() )
{
ASSERT( rInfo.GetRefDev(), "No reference device for text formatting" )
// set new values
rInfo.SetOut( rInfo.GetRefDev() );
rInfo.SetOnWin( sal_False );
}
SwHookOut::~SwHookOut()
{
pInf->SetOut( pOut );
pInf->SetOnWin( bOnWin );
}