1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 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/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 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 . 18 */ 19 20 #include <ndtxt.hxx> 21 #include <flyfrm.hxx> 22 #include <paratr.hxx> 23 #include <vcl/outdev.hxx> 24 #include <editeng/paravertalignitem.hxx> 25 26 #include "pormulti.hxx" 27 #include <pagefrm.hxx> 28 #include <pagedesc.hxx> 29 #include <tgrditem.hxx> 30 #include "porfld.hxx" 31 32 #include "itrtxt.hxx" 33 #include <txtfrm.hxx> 34 #include "porfly.hxx" 35 36 void SwTextIter::CtorInitTextIter( SwTextFrame *pNewFrame, SwTextInfo *pNewInf ) 37 { 38 SwTextNode *pNode = pNewFrame->GetTextNode(); 39 40 assert(pNewFrame->GetPara()); 41 42 CtorInitAttrIter( *pNode, pNewFrame->GetPara()->GetScriptInfo(), pNewFrame ); 43 44 m_pFrame = pNewFrame; 45 m_pInf = pNewInf; 46 m_aLineInf.CtorInitLineInfo( pNode->GetSwAttrSet(), *pNode ); 47 m_nFrameStart = m_pFrame->getFrameArea().Pos().Y() + m_pFrame->getFramePrintArea().Pos().Y(); 48 SwTextIter::Init(); 49 50 // Order is important: only execute FillRegister if GetValue!=0 51 m_bRegisterOn = pNode->GetSwAttrSet().GetRegister().GetValue() 52 && m_pFrame->FillRegister( m_nRegStart, m_nRegDiff ); 53 } 54 55 void SwTextIter::Init() 56 { 57 m_pCurr = m_pInf->GetParaPortion(); 58 m_nStart = m_pInf->GetTextStart(); 59 m_nY = m_nFrameStart; 60 m_bPrev = true; 61 m_pPrev = nullptr; 62 m_nLineNr = 1; 63 } 64 65 void SwTextIter::CalcAscentAndHeight( sal_uInt16 &rAscent, sal_uInt16 &rHeight ) const 66 { 67 rHeight = GetLineHeight(); 68 rAscent = m_pCurr->GetAscent() + rHeight - m_pCurr->Height(); 69 } 70 71 SwLineLayout *SwTextIter::GetPrev_() 72 { 73 m_pPrev = nullptr; 74 m_bPrev = true; 75 SwLineLayout *pLay = m_pInf->GetParaPortion(); 76 if( m_pCurr == pLay ) 77 return nullptr; 78 while( pLay->GetNext() != m_pCurr ) 79 pLay = pLay->GetNext(); 80 return m_pPrev = pLay; 81 } 82 83 const SwLineLayout *SwTextIter::GetPrev() 84 { 85 if(! m_bPrev) 86 GetPrev_(); 87 return m_pPrev; 88 } 89 90 const SwLineLayout *SwTextIter::Prev() 91 { 92 if( !m_bPrev ) 93 GetPrev_(); 94 if( m_pPrev ) 95 { 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; 103 } 104 else 105 return nullptr; 106 } 107 108 const SwLineLayout *SwTextIter::Next() 109 { 110 if(m_pCurr->GetNext()) 111 { 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 return m_pCurr = m_pCurr->GetNext(); 119 } 120 else 121 return nullptr; 122 } 123 124 const SwLineLayout *SwTextIter::NextLine() 125 { 126 const SwLineLayout *pNext = Next(); 127 while( pNext && pNext->IsDummy() && pNext->GetNext() ) 128 { 129 pNext = Next(); 130 } 131 return pNext; 132 } 133 134 const SwLineLayout *SwTextIter::GetNextLine() const 135 { 136 const SwLineLayout *pNext = m_pCurr->GetNext(); 137 while( pNext && pNext->IsDummy() && pNext->GetNext() ) 138 { 139 pNext = pNext->GetNext(); 140 } 141 return pNext; 142 } 143 144 const SwLineLayout *SwTextIter::GetPrevLine() 145 { 146 const SwLineLayout *pRoot = m_pInf->GetParaPortion(); 147 if( pRoot == m_pCurr ) 148 return nullptr; 149 const SwLineLayout *pLay = pRoot; 150 151 while( pLay->GetNext() != m_pCurr ) 152 pLay = pLay->GetNext(); 153 154 if( pLay->IsDummy() ) 155 { 156 const SwLineLayout *pTmp = pRoot; 157 pLay = pRoot->IsDummy() ? nullptr : pRoot; 158 while( pTmp->GetNext() != m_pCurr ) 159 { 160 if( !pTmp->IsDummy() ) 161 pLay = pTmp; 162 pTmp = pTmp->GetNext(); 163 } 164 } 165 166 // If nothing has changed, then there are only dummy's 167 return pLay; 168 } 169 170 const SwLineLayout *SwTextIter::PrevLine() 171 { 172 const SwLineLayout *pMyPrev = Prev(); 173 if( !pMyPrev ) 174 return nullptr; 175 176 const SwLineLayout *pLast = pMyPrev; 177 while( pMyPrev && pMyPrev->IsDummy() ) 178 { 179 pLast = pMyPrev; 180 pMyPrev = Prev(); 181 } 182 return pMyPrev ? pMyPrev : pLast; 183 } 184 185 void SwTextIter::Bottom() 186 { 187 while( Next() ) 188 { 189 // nothing 190 } 191 } 192 193 void SwTextIter::CharToLine(const sal_Int32 nChar) 194 { 195 while( m_nStart + m_pCurr->GetLen() <= nChar && Next() ) 196 ; 197 while( m_nStart > nChar && Prev() ) 198 ; 199 } 200 201 // 1170: takes into account ambiguities: 202 const SwLineLayout *SwTextCursor::CharCursorToLine( const sal_Int32 nPosition ) 203 { 204 CharToLine( nPosition ); 205 if( nPosition != m_nStart ) 206 bRightMargin = false; 207 bool bPrevious = bRightMargin && m_pCurr->GetLen() && GetPrev() && 208 GetPrev()->GetLen(); 209 if( bPrevious && nPosition && CH_BREAK == GetInfo().GetChar( nPosition-1 ) ) 210 bPrevious = false; 211 return bPrevious ? PrevLine() : m_pCurr; 212 } 213 214 sal_uInt16 SwTextCursor::AdjustBaseLine( const SwLineLayout& rLine, 215 const SwLinePortion* pPor, 216 sal_uInt16 nPorHeight, sal_uInt16 nPorAscent, 217 const bool bAutoToCentered ) const 218 { 219 if ( pPor ) 220 { 221 nPorHeight = pPor->Height(); 222 nPorAscent = pPor->GetAscent(); 223 } 224 225 sal_uInt16 nOfst = rLine.GetRealHeight() - rLine.Height(); 226 227 SwTextGridItem const*const pGrid(GetGridItem(m_pFrame->FindPageFrame())); 228 229 if ( pGrid && GetInfo().SnapToGrid() && pGrid->IsSquaredMode() ) 230 { 231 const sal_uInt16 nRubyHeight = pGrid->GetRubyHeight(); 232 const bool bRubyTop = ! pGrid->GetRubyTextBelow(); 233 234 if ( GetInfo().IsMulti() ) 235 // we are inside the GetCharRect recursion for multi portions 236 // we center the portion in its surrounding line 237 nOfst = ( m_pCurr->Height() - nPorHeight ) / 2 + nPorAscent; 238 else 239 { 240 // We have to take care for ruby portions. 241 // The ruby portion is NOT centered 242 nOfst = nOfst + nPorAscent; 243 244 if ( ! pPor || ! pPor->IsMultiPortion() || 245 ! static_cast<const SwMultiPortion*>(pPor)->IsRuby() ) 246 { 247 // Portions which are bigger than on grid distance are 248 // centered inside the whole line. 249 250 //for text refactor 251 const sal_uInt16 nLineNet = rLine.Height() - nRubyHeight; 252 //const sal_uInt16 nLineNet = ( nPorHeight > nGridWidth ) ? 253 // rLine.Height() - nRubyHeight : 254 // nGridWidth; 255 nOfst += ( nLineNet - nPorHeight ) / 2; 256 if ( bRubyTop ) 257 nOfst += nRubyHeight; 258 } 259 } 260 } 261 else 262 { 263 switch ( GetLineInfo().GetVertAlign() ) { 264 case SvxParaVertAlignItem::Align::Top : 265 nOfst = nOfst + nPorAscent; 266 break; 267 case SvxParaVertAlignItem::Align::Center : 268 OSL_ENSURE( rLine.Height() >= nPorHeight, "Portion height > Line height"); 269 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent; 270 break; 271 case SvxParaVertAlignItem::Align::Bottom : 272 nOfst += rLine.Height() - nPorHeight + nPorAscent; 273 break; 274 case SvxParaVertAlignItem::Align::Automatic : 275 if ( bAutoToCentered || GetInfo().GetTextFrame()->IsVertical() ) 276 { 277 if( GetInfo().GetTextFrame()->IsVertLR() ) 278 nOfst += rLine.Height() - ( rLine.Height() - nPorHeight ) / 2 - nPorAscent; 279 else 280 nOfst += ( rLine.Height() - nPorHeight ) / 2 + nPorAscent; 281 break; 282 } 283 SAL_FALLTHROUGH; 284 case SvxParaVertAlignItem::Align::Baseline : 285 // base line 286 nOfst = nOfst + rLine.GetAscent(); 287 break; 288 } 289 } 290 291 return nOfst; 292 } 293 294 void SwTextIter::TwipsToLine( const SwTwips y) 295 { 296 while( m_nY + GetLineHeight() <= y && Next() ) 297 ; 298 while( m_nY > y && Prev() ) 299 ; 300 } 301 302 // Local helper function to check, if pCurr needs a field rest portion: 303 static bool lcl_NeedsFieldRest( const SwLineLayout* pCurr ) 304 { 305 const SwLinePortion *pPor = pCurr->GetPortion(); 306 bool bRet = false; 307 while( pPor && !bRet ) 308 { 309 bRet = pPor->InFieldGrp() && static_cast<const SwFieldPortion*>(pPor)->HasFollow(); 310 if( !pPor->GetPortion() || !pPor->GetPortion()->InFieldGrp() ) 311 break; 312 pPor = pPor->GetPortion(); 313 } 314 return bRet; 315 } 316 317 void SwTextIter::TruncLines( bool bNoteFollow ) 318 { 319 SwLineLayout *pDel = m_pCurr->GetNext(); 320 const sal_Int32 nEnd = m_nStart + m_pCurr->GetLen(); 321 322 if( pDel ) 323 { 324 m_pCurr->SetNext( nullptr ); 325 if( GetHints() && bNoteFollow ) 326 { 327 GetInfo().GetParaPortion()->SetFollowField( pDel->IsRest() || 328 lcl_NeedsFieldRest( m_pCurr ) ); 329 330 // bug 88534: wrong positioning of flys 331 SwTextFrame* pFollow = GetTextFrame()->GetFollow(); 332 if ( pFollow && ! pFollow->IsLocked() && 333 nEnd == pFollow->GetOfst() ) 334 { 335 sal_Int32 nRangeEnd = nEnd; 336 SwLineLayout* pLine = pDel; 337 338 // determine range to be searched for flys anchored as characters 339 while ( pLine ) 340 { 341 nRangeEnd = nRangeEnd + pLine->GetLen(); 342 pLine = pLine->GetNext(); 343 } 344 345 SwpHints* pTmpHints = GetTextFrame()->GetTextNode()->GetpSwpHints(); 346 347 // examine hints in range nEnd - (nEnd + nRangeChar) 348 for( size_t i = 0; i < pTmpHints->Count(); ++i ) 349 { 350 const SwTextAttr* pHt = pTmpHints->Get( i ); 351 if( RES_TXTATR_FLYCNT == pHt->Which() ) 352 { 353 // check, if hint is in our range 354 const sal_uInt16 nTmpPos = pHt->GetStart(); 355 if ( nEnd <= nTmpPos && nTmpPos < nRangeEnd ) 356 pFollow->InvalidateRange_( 357 SwCharRange( nTmpPos, nTmpPos ) ); 358 } 359 } 360 } 361 } 362 delete pDel; 363 } 364 if( m_pCurr->IsDummy() && 365 !m_pCurr->GetLen() && 366 m_nStart < GetTextFrame()->GetText().getLength() ) 367 m_pCurr->SetRealHeight( 1 ); 368 if( GetHints() ) 369 m_pFrame->RemoveFootnote( nEnd ); 370 } 371 372 void SwTextIter::CntHyphens( sal_uInt8 &nEndCnt, sal_uInt8 &nMidCnt) const 373 { 374 nEndCnt = 0; 375 nMidCnt = 0; 376 if ( m_bPrev && m_pPrev && !m_pPrev->IsEndHyph() && !m_pPrev->IsMidHyph() ) 377 return; 378 SwLineLayout *pLay = m_pInf->GetParaPortion(); 379 if( m_pCurr == pLay ) 380 return; 381 while( pLay != m_pCurr ) 382 { 383 if ( pLay->IsEndHyph() ) 384 nEndCnt++; 385 else 386 nEndCnt = 0; 387 if ( pLay->IsMidHyph() ) 388 nMidCnt++; 389 else 390 nMidCnt = 0; 391 pLay = pLay->GetNext(); 392 } 393 } 394 395 // Change current output device to formatting device, this has to be done before 396 // formatting. 397 SwHookOut::SwHookOut( SwTextSizeInfo& rInfo ) : 398 pInf( &rInfo ), 399 pOut( rInfo.GetOut() ), 400 bOnWin( rInfo.OnWin() ) 401 { 402 OSL_ENSURE( rInfo.GetRefDev(), "No reference device for text formatting" ); 403 404 // set new values 405 rInfo.SetOut( rInfo.GetRefDev() ); 406 rInfo.SetOnWin( false ); 407 } 408 409 SwHookOut::~SwHookOut() 410 { 411 pInf->SetOut( pOut ); 412 pInf->SetOnWin( bOnWin ); 413 } 414 415 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 416
