| /************************************************************** |
| * |
| * 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 ); |
| } |