/* -*- 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 .
*/
namespace { // FIXME: would likely better be a member of SwRootFrame instead of a global flag bool isFlyCreationSuppressed = false;
} namespace sw {
FlyCreationSuppressor::FlyCreationSuppressor(bool wasAlreadySuppressedAllowed)
: m_wasAlreadySuppressed(isFlyCreationSuppressed)
{
(void)wasAlreadySuppressedAllowed;
assert(wasAlreadySuppressedAllowed || !isFlyCreationSuppressed);
isFlyCreationSuppressed = true;
}
FlyCreationSuppressor::~FlyCreationSuppressor()
{
isFlyCreationSuppressed = m_wasAlreadySuppressed;
}
}
if ( !pFlow->IsFollow() )
{ if ( !mpFrame->GetIndPrev() )
{ if ( mbInvaKeep )
{
SwFrame *pPre = pFlow->FindPrevIgnoreHidden(); if ( pPre && pPre->IsFlowFrame() )
{ // 1. pPre wants to keep with me: bool bInvalidPrePos = SwFlowFrame::CastFlowFrame(pPre)->IsKeep(pPre->GetAttrSet()->GetKeep(), pPre->GetBreakItem())
&& pPre->GetIndPrev();
// 2. pPre is a table and the last row wants to keep with me: if ( !bInvalidPrePos && pPre->IsTabFrame() )
{
SwTabFrame* pPreTab = static_cast<SwTabFrame*>(pPre); if ( pPreTab->GetFormat()->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::TABLE_ROW_KEEP) )
{
SwRowFrame* pLastRow = static_cast<SwRowFrame*>(pPreTab->GetLastLower()); if ( pLastRow && pLastRow->ShouldRowKeepWithNext() )
bInvalidPrePos = true;
}
}
if ( pNxt )
{
pNxt->InvalidatePos(); if (pNxt->IsTextFrame() && static_cast<SwTextFrame*>(pNxt)->IsUndersized())
{ // tdf#137523 it could have more space at new pos
pNxt->InvalidateSize();
pNxt->Prepare(PrepareHint::AdjustSizeWithoutFormatting);
}
} else
{ // #104100# - correct condition for setting retouche // flag for vertical layout. if( mpFrame->IsRetoucheFrame() &&
aRectFnSet.TopDist( maFrame, aRectFnSet.GetTop(mpFrame->getFrameArea()) ) > 0 )
{
mpFrame->SetRetouche();
}
// A fresh follow frame does not have to be invalidated, because // it is already formatted: if ( mbHadFollow || !mpFrame->IsContentFrame() || !static_cast<SwContentFrame*>(mpFrame)->GetFollow() )
{ if ( !mpFrame->IsTabFrame() || !static_cast<SwTabFrame*>(mpFrame)->GetFollow() )
mpFrame->InvalidateNextPos();
}
}
}
//For each resize of the background graphics is a repaint necessary. constbool bPrtWidth =
aRectFnSet.GetWidth(maPrt) != aRectFnSet.GetWidth(mpFrame->getFramePrintArea()); constbool bPrtHeight =
aRectFnSet.GetHeight(maPrt)!=aRectFnSet.GetHeight(mpFrame->getFramePrintArea()); if ( bPrtWidth || bPrtHeight )
{ bool bUseNewFillProperties(false); if (mpFrame->supportsFullDrawingLayerFillAttributeSet())
{
drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(mpFrame->getSdrAllFillAttributesHelper()); if(aFillAttributes && aFillAttributes->isUsed())
{
bUseNewFillProperties = true; // use SetCompletePaint if needed if(aFillAttributes->needCompleteRepaint())
{
mpFrame->SetCompletePaint();
}
}
} if (!bUseNewFillProperties)
{ const SvxGraphicPosition ePos = mpFrame->GetAttrSet()->GetBackground().GetGraphicPos(); if(GPOS_NONE != ePos && GPOS_TILED != ePos)
mpFrame->SetCompletePaint();
}
} else
{ // #97597# - consider case that *only* margins between // frame and printing area has changed. Then, frame has to be repainted, // in order to force paint of the margin areas. if ( !bAbsP && (bChgWidth || bChgHeight) )
{
mpFrame->SetCompletePaint();
}
}
// Notification of anchored objects if ( mpFrame->GetDrawObjs() )
{ const SwSortedObjs &rObjs = *mpFrame->GetDrawObjs();
SwPageFrame* pPageFrame = nullptr; for (SwAnchoredObject* pObj : rObjs)
{ // OD 2004-03-31 #i26791# - no general distinction between // Writer fly frames and drawing objects bool bNotify = false; bool bNotifySize = false;
SwContact* pContact = ::GetUserCall( pObj->GetDrawObj() ); if (!pContact) continue; constbool bAnchoredAsChar = pContact->ObjAnchoredAsChar(); if ( !bAnchoredAsChar )
{ // Notify object, which aren't anchored as-character:
// always notify objects, if frame position has changed // or if the object is to-page|to-fly anchored. if ( bAbsP ||
pContact->ObjAnchoredAtPage() ||
pContact->ObjAnchoredAtFly() )
{
bNotify = true;
// assure that to-fly anchored Writer fly frames are // registered at the correct page frame, if frame // position has changed. if ( bAbsP && pContact->ObjAnchoredAtFly() &&
pObj->DynCastFlyFrame() != nullptr )
{ // determine to-fly anchored Writer fly frame
SwFlyFrame* pFlyFrame = static_cast<SwFlyFrame*>(pObj); // determine page frame of to-fly anchored // Writer fly frame
SwPageFrame* pFlyPageFrame = pFlyFrame->FindPageFrame(); // determine page frame, if needed. if ( !pPageFrame )
{
pPageFrame = mpFrame->FindPageFrame();
} if ( pPageFrame != pFlyPageFrame )
{
OSL_ENSURE( pFlyPageFrame, "~SwFrameNotify: Fly from Nowhere" ); if( pFlyPageFrame )
pFlyPageFrame->MoveFly( pFlyFrame, pPageFrame ); else
pPageFrame->AppendFlyToPage( pFlyFrame );
}
}
} // otherwise the objects are notified in dependence to // its positioning and alignment else
{ const SwFormatVertOrient& rVert =
pContact->GetFormat()->GetVertOrient(); if ( ( rVert.GetVertOrient() == text::VertOrientation::CENTER ||
rVert.GetVertOrient() == text::VertOrientation::BOTTOM ||
rVert.GetRelationOrient() == text::RelOrientation::PRINT_AREA ) &&
( bChgHeight || bPrtHeight ) )
{
bNotify = true;
} if ( !bNotify )
{ const SwFormatHoriOrient& rHori =
pContact->GetFormat()->GetHoriOrient(); if ( ( rHori.GetHoriOrient() != text::HoriOrientation::NONE ||
rHori.GetRelationOrient()== text::RelOrientation::PRINT_AREA ||
rHori.GetRelationOrient()== text::RelOrientation::FRAME ) &&
( bChgWidth || bPrtWidth || bChgFlyBasePos ) )
{
bNotify = true;
}
}
}
} elseif ( bPrtWidth )
{ // Notify as-character anchored objects, if printing area // width has changed.
bNotify = true;
bNotifySize = true;
}
// perform notification via the corresponding invalidations if ( bNotify )
{ if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
{ if ( bNotifySize )
pFlyFrame->InvalidateSize_(); // #115759# - no invalidation of // position for as-character anchored objects. if ( !bAnchoredAsChar )
{
pFlyFrame->InvalidatePos_();
}
pFlyFrame->Invalidate_();
} elseif ( dynamic_cast<const SwAnchoredDrawObject*>( pObj) != nullptr )
{ // #115759# - no invalidation of // position for as-character anchored objects. if ( !bAnchoredAsChar )
{
pObj->InvalidateObjPos();
}
} else
{
OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - unknown anchored object type." );
}
}
}
}
} #if !ENABLE_WASM_STRIP_ACCESSIBILITY elseif( mpFrame->IsTextFrame() && mbValidSize != mpFrame->isFrameAreaSizeValid() )
{
SwRootFrame *pRootFrame = mpFrame->getRootFrame(); if( pRootFrame && pRootFrame->IsAnyShellAccessible() &&
pRootFrame->GetCurrShell() )
{
pRootFrame->GetCurrShell()->Imp()->InvalidateAccessibleFrameContent( mpFrame );
}
} #endif
// #i9046# Automatic frame width
SwFlyFrame* pFly = nullptr; // #i35879# Do not trust the inf flags. pFrame does not // necessarily have to have an upper! if ( mpFrame->IsFlyFrame() || nullptr == ( pFly = mpFrame->ImplFindFlyFrame() )) return;
// #i61999# // no invalidation of columned Writer fly frames, because automatic // width doesn't make sense for such Writer fly frames.
SwFrame* pLower = pFly->Lower(); if ( !pLower || pLower->IsColumnFrame() ) return;
// This could be optimized. Basically the fly frame only has to // be invalidated, if the first line of pFrame (if pFrame is a content // frame, for other frame types it's the print area) has changed its // size and pFrame was responsible for the current width of pFly. On // the other hand, this is only rarely used and re-calculation of // the fly frame does not cause too much trouble. So we keep it this // way: if ( SwFrameSize::Fixed != rFrameSz.GetWidthSizeType() )
{ // #i50668#, #i50998# - invalidation of position // of as-character anchored fly frames not needed and can cause // layout loops if ( dynamic_cast<const SwFlyInContentFrame*>( pFly) == nullptr )
{
pFly->InvalidatePos();
}
pFly->InvalidateSize();
}
}
// OD 2004-05-11 #i28701# - local method to invalidate the position of all // frames inclusive its floating screen objects, which are lowers of the given // layout frame staticvoid lcl_InvalidatePosOfLowers( SwLayoutFrame& _rLayoutFrame )
{ if( _rLayoutFrame.IsFlyFrame() && _rLayoutFrame.GetDrawObjs() )
{
_rLayoutFrame.InvalidateObjs( false );
}
if ( pLay->IsRowFrame() )
{
bInvaPercent = true;
tools::Long nNew = aRectFnSet.GetHeight(pLay->getFramePrintArea()); if( nNew != aRectFnSet.GetHeight(maPrt) ) static_cast<SwRowFrame*>(pLay)->AdjustCells( nNew, true); if( aRectFnSet.GetWidth(pLay->getFramePrintArea())
!= aRectFnSet.GetWidth(maPrt) ) static_cast<SwRowFrame*>(pLay)->AdjustCells( 0, false );
} else
{ //Proportional adoption of the internal. //1. If the formatted is no Fly //2. If he contains no columns //3. If the Fly has a fixed height and the columns // are next to be. // Hoehe danebenliegen. //4. Never at SectionFrames. bool bLow; if( pLay->IsFlyFrame() )
{ if ( pLay->Lower() )
{
bLow = !pLay->Lower()->IsColumnFrame() ||
aRectFnSet.GetHeight(pLay->Lower()->getFrameArea())
!= aRectFnSet.GetHeight(pLay->getFramePrintArea());
} else
bLow = false;
} elseif( pLay->IsSctFrame() )
{ if ( pLay->Lower() )
{ if( pLay->Lower()->IsColumnFrame() && pLay->Lower()->GetNext() )
bLow = pLay->Lower()->getFrameArea().Height() != pLay->getFramePrintArea().Height(); else
bLow = pLay->getFramePrintArea().Width() != maPrt.Width();
} else
bLow = false;
} elseif( pLay->IsFooterFrame() && !pLay->HasFixSize() )
bLow = pLay->getFramePrintArea().Width() != maPrt.Width(); else
bLow = true;
bInvaPercent = bLow; if ( bLow )
{
pLay->ChgLowersProp( maPrt.SSize() );
} // If the PrtArea has been extended, it might be possible that the chain of parts // can take another frame. As a result, the "possible right one" needs to be // invalidated. This only pays off if this or its Uppers are moveable sections. // A PrtArea has been extended if width or height are larger than before. if ( (pLay->getFramePrintArea().Height() > maPrt.Height() ||
pLay->getFramePrintArea().Width() > maPrt.Width()) &&
(pLay->IsMoveable() || pLay->IsFlyFrame()) )
{
SwFrame *pTmpFrame = pLay->Lower(); if ( pTmpFrame && pTmpFrame->IsFlowFrame() )
{ while ( pTmpFrame->GetNext() )
pTmpFrame = pTmpFrame->GetNext();
pTmpFrame->InvalidateNextPos();
}
}
}
bNotify = true; //EXPENSIVE!! But how we do it more elegant? if( bInvaPercent )
pLay->InvaPercentLowers( pLay->getFramePrintArea().Height() - maPrt.Height() );
} if ( pLay->IsTabFrame() ) //So that _only_ the shadow is drawn while resizing. static_cast<SwTabFrame*>(pLay)->SetComplete(); else
{ const SwViewShell *pSh = pLay->getRootFrame()->GetCurrShell(); if( !( pSh && pSh->GetViewOptions()->getBrowseMode() ) ||
!(pLay->GetType() & (SwFrameType::Body | SwFrameType::Page)) ) //Thereby the subordinates are retouched clean. //Example problem: Take the Flys with the handles and downsize. //Not for body and page, otherwise it flickers when loading HTML.
pLay->SetCompletePaint();
}
} //Notify Lower if the position has changed. constbool bPrtPos = aRectFnSet.PosDiff( maPrt, pLay->getFramePrintArea() ); constbool bPos = bPrtPos || aRectFnSet.PosDiff( maFrame, pLay->getFrameArea() ); constbool bSize = pLay->getFrameArea().SSize() != maFrame.SSize();
//Inform the Follower if the SSize has changed. if ( bSize )
{ if( pLay->GetNext() )
{ if ( pLay->GetNext()->IsLayoutFrame() )
pLay->GetNext()->InvalidatePos_(); else
pLay->GetNext()->InvalidatePos();
} elseif( pLay->IsSctFrame() )
pLay->InvalidateNextPos();
}
SwFrame* pLower = pLay->Lower(); if ( !IsLowersComplete() &&
!(pLay->GetType()&(SwFrameType::Fly|SwFrameType::Section) &&
pLower && pLower->IsColumnFrame()) &&
(bPos || bNotify) &&
!(pLay->GetType() & (SwFrameType::Row|SwFrameType::Tab|SwFrameType::FootnoteContainer|SwFrameType::Page|SwFrameType::Root)))
{ // #i44016# - force unlock of position of lower objects. // #i43913# - no unlock of position of objects, // if <pLay> is a cell frame, and its table frame resp. its parent table // frame is locked. // #i47458# - force unlock of position of lower objects, // only if position of layout frame has changed. bool bUnlockPosOfObjs( bPos ); if ( bUnlockPosOfObjs && pLay->IsCellFrame() )
{
SwTabFrame* pTabFrame( pLay->FindTabFrame() ); if ( pTabFrame &&
( pTabFrame->IsJoinLocked() ||
( pTabFrame->IsFollow() &&
pTabFrame->FindMaster()->IsJoinLocked() ) ) )
{
bUnlockPosOfObjs = false;
}
} // #i49383# - check for footnote frame, if unlock // of position of lower objects is allowed. elseif ( bUnlockPosOfObjs && pLay->IsFootnoteFrame() )
{
bUnlockPosOfObjs = static_cast<SwFootnoteFrame*>(pLay)->IsUnlockPosOfLowerObjs();
} // #i51303# - no unlock of object positions for sections elseif ( bUnlockPosOfObjs && pLay->IsSctFrame() )
{
bUnlockPosOfObjs = false;
}
pLay->NotifyLowerObjs( bUnlockPosOfObjs );
} if ( bPos && pLay->IsFootnoteFrame() && pLay->Lower() )
{ // OD 2004-05-11 #i28701#
::lcl_InvalidatePosOfLowers( *pLay );
} if( ( bPos || bSize ) && pLay->IsFlyFrame() && static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()
&& static_cast<SwFlyFrame*>(pLay)->GetAnchorFrame()->IsFlyFrame() ) static_cast<SwFlyFrame*>(pLay)->AnchorFrame()->InvalidateSize();
}
SwFlyNotify::SwFlyNotify( SwFlyFrame *pFlyFrame ) :
SwLayNotify( pFlyFrame ), // #115759# - keep correct page frame - the page frame // the Writer fly frame is currently registered at.
m_pOldPage( pFlyFrame->GetPageFrame() ),
m_aFrameAndSpace( pFlyFrame->GetObjRectWithSpaces() )
{
}
void SwFlyNotify::ImplDestroy()
{
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(mpFrame); if ( pFly->IsNotifyBack() )
{
SwViewShell *pSh = pFly->getRootFrame()->GetCurrShell();
SwViewShellImp *pImp = pSh ? pSh->Imp() : nullptr; if ( !pImp || !pImp->IsAction() || !pImp->GetLayAction().IsAgain() )
{ //If in the LayAction the IsAgain is set it can be //that the old page is destroyed in the meantime!
::Notify( pFly, m_pOldPage, m_aFrameAndSpace, &maPrt ); // #i35640# - additional notify anchor text frame, // if Writer fly frame has changed its page if ( pFly->GetAnchorFrame()->IsTextFrame() &&
pFly->GetPageFrame() != m_pOldPage )
{
pFly->AnchorFrame()->Prepare( PrepareHint::FlyFrameLeave );
}
}
pFly->ResetNotifyBack();
} if (pFly->IsForceNotifyNewBackground())
{
pFly->NotifyBackground(pFly->FindPageFrame(), pFly->GetObjRectWithSpaces(), PrepareHint::FlyFrameArrive);
pFly->SetForceNotifyNewBackground(false);
}
//Have the size or the position changed, //so should the view know this.
SwRectFnSet aRectFnSet(pFly); constbool bPosChgd = aRectFnSet.PosDiff( maFrame, pFly->getFrameArea() ); constbool bFrameChgd = pFly->getFrameArea().SSize() != maFrame.SSize(); constbool bPrtChgd = maPrt != pFly->getFramePrintArea(); if ( bPosChgd || bFrameChgd || bPrtChgd )
{
pFly->NotifyDrawObj();
} if ( bPosChgd && maFrame.Pos().X() != FAR_AWAY )
{ // OD 2004-05-10 #i28701# - no direct move of lower Writer fly frames. // reason: New positioning and alignment (e.g. to-paragraph anchored, // but aligned at page) are introduced. // <SwLayNotify::~SwLayNotify()> takes care of invalidation of lower // floating screen objects by calling method <SwLayoutFrame::NotifyLowerObjs()>.
if ( pFly->IsFlyAtContentFrame() )
{
SwFrame *pNxt = pFly->AnchorFrame()->FindNext(); while (pNxt)
{
pNxt->InvalidatePos(); if (!pNxt->IsSctFrame())
{ break;
} // invalidating pos of a section frame doesn't have much // effect, so try again with its lower
pNxt = static_cast<SwSectionFrame*>(pNxt)->Lower();
}
}
// OD 2004-05-13 #i28701# // #i45180# - no adjustment of layout process flags and // further notifications/invalidations, if format is called by grow/shrink if ( !pFly->ConsiderObjWrapInfluenceOnObjPos() ) return; if (pFly->IsFlyFreeFrame())
{ if (static_cast<SwFlyFreeFrame*>(pFly)->IsNoMoveOnCheckClip()) return;
}
// #i54138# - suppress restart of the layout process // on changed frame height. // Note: It doesn't seem to be necessary and can cause layout loops. if ( bPosChgd )
{ // indicate a restart of the layout process
pFly->SetRestartLayoutProcess( true );
} else
{ // lock position
pFly->LockPosition();
}
if ( pFly->ConsiderForTextWrap() ) return;
// indicate that object has to be considered for text wrap
pFly->SetConsiderForTextWrap( true ); // invalidate 'background' in order to allow its 'background' // to wrap around it.
pFly->NotifyBackground( pFly->GetPageFrame(),
pFly->GetObjRectWithSpaces(),
PrepareHint::FlyFrameArrive ); // invalidate position of anchor frame in order to force // a re-format of the anchor frame, which also causes a // re-format of the invalid previous frames of the anchor frame.
pFly->AnchorFrame()->InvalidatePos();
}
// OD 2004-02-26 #i25029# if ( mbInvalidatePrevPrtArea && mbBordersJoinedWithPrev &&
pCnt->IsTextFrame() &&
!pCnt->IsFollow() && !pCnt->GetIndPrev() )
{ // determine previous frame
SwFrame* pPrevFrame = pCnt->FindPrev(); // skip empty section frames and hidden text frames
{ while (pPrevFrame && pPrevFrame->IsHiddenNow())
{
pPrevFrame = pPrevFrame->FindPrev();
}
}
// Invalidate printing area of found previous frame if ( pPrevFrame )
{ if ( pPrevFrame->IsSctFrame() )
{ if ( pCnt->IsInSct() )
{ // Note: found previous frame is a section frame and // <pCnt> is also inside a section. // Thus due to <mbBordersJoinedWithPrev>, // <pCnt> had joined its borders/shadow with the // last content of the found section. // Invalidate printing area of last content in found section.
SwFrame* pLstContentOfSctFrame = static_cast<SwSectionFrame*>(pPrevFrame)->FindLastContent(); if ( pLstContentOfSctFrame )
{
pLstContentOfSctFrame->InvalidatePrt();
}
}
} else
{
pPrevFrame->InvalidatePrt();
}
}
}
if ( pCnt->IsNoTextFrame() )
{ //Active PlugIn's or OLE-Objects should know something of the change //thereby they move their window appropriate.
SwViewShell *pSh = pCnt->getRootFrame()->GetCurrShell(); if ( pSh )
{
SwOLENode *const pNd(static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetOLENode()); if (nullptr != pNd &&
(pNd->GetOLEObj().IsOleRef() ||
pNd->IsOLESizeInvalid()) )
{ constbool bNoTextFramePrtAreaChanged =
( maPrt.SSize().Width() != 0 &&
maPrt.SSize().Height() != 0 ) &&
maPrt.SSize() != pCnt->getFramePrintArea().SSize();
OSL_ENSURE( pCnt->IsInFly(), "OLE not in FlyFrame" );
SwFlyFrame *pFly = pCnt->FindFlyFrame();
svt::EmbeddedObjectRef& xObj = pNd->GetOLEObj().GetObject();
SwFEShell *pFESh = nullptr; for(SwViewShell& rCurrentShell : pSh->GetRingContainer())
{ if ( dynamic_cast<const SwCursorShell*>( &rCurrentShell) != nullptr )
{
pFESh = static_cast<SwFEShell*>(&rCurrentShell); // #108369#: Here used to be the condition if (!bFirst). // I think this should mean "do not call CalcAndSetScale" // if the frame is formatted for the first time. // Unfortunately this is not valid anymore since the // SwNoTextFrame already gets a width during CalcLowerPreps. // Nevertheless, the indention of !bFirst seemed to be // to assure that the OLE objects have already been notified // if necessary before calling CalcAndSetScale. // So I replaced !bFirst by !IsOLESizeInvalid. There is // one additional problem specific to the word import: // The layout is calculated _before_ calling PrtOLENotify, // and the OLE objects are not invalidated during import. // Therefore I added the condition !IsUpdateExpField, // have a look at the occurrence of CalcLayout in // uiview/view.cxx. if ( !pNd->IsOLESizeInvalid() &&
!pSh->GetDoc()->getIDocumentState().IsUpdateExpField() )
pFESh->CalcAndSetScale( xObj,
&pFly->getFramePrintArea(), &pFly->getFrameArea(),
bNoTextFramePrtAreaChanged );
}
}
SwDoc& rDoc = pCnt->IsTextFrame()
? static_cast<SwTextFrame*>(pCnt)->GetDoc()
: static_cast<SwNoTextFrame*>(pCnt)->GetNode()->GetDoc(); if ( !rDoc.GetSpzFrameFormats()->empty() &&
rDoc.DoesContainAtPageObjWithContentAnchor() && !rDoc.getIDocumentState().IsNewDoc() )
{ // If certain import filters for foreign file format import // AT_PAGE anchored objects, the corresponding page number is // typically not known. In this case the content position is // stored at which the anchored object is found in the // imported document. // When this content is formatted it is the time at which // the page is known. Thus, this data can be corrected now.
if (FrameContainsNode(*pCnt, rAnch.GetAnchorNode()->GetIndex()))
{
OSL_FAIL( "<SwContentNotify::~SwContentNotify()> - to page anchored object with content position." ); if ( !pPage )
{
pPage = pCnt->FindPageFrame();
}
SwFormatAnchor aAnch( rAnch );
aAnch.SetAnchor( nullptr );
aAnch.SetPageNum( pPage->GetPhyPageNum() );
pFormat->SetFormatAttr( aAnch ); if ( RES_DRAWFRMFMT != pFormat->Which() )
{
pFormat->MakeFrames();
}
}
}
}
}
// OD 12.01.2004 #i11859# - invalidate printing area of following frame, // if height of last line has changed. if ( pCnt->IsTextFrame() && mbChkHeightOfLastLine )
{ if ( mnHeightOfLastLine != static_cast<SwTextFrame*>(pCnt)->GetHeightOfLastLine() )
{
pCnt->InvalidateNextPrtArea();
}
}
// #i43255# - move code to invalidate at-character // anchored objects due to a change of its anchor character from // method <SwTextFrame::Format(..)>. if ( !pCnt->IsTextFrame() ) return;
staticbool IsShown(SwNodeOffset const nIndex, const SwFormatAnchor & rAnch,
std::vector<sw::Extent>::const_iterator const*const pIter,
std::vector<sw::Extent>::const_iterator const*const pEnd,
SwTextNode const*const pFirstNode, SwTextNode const*const pLastNode)
{
assert(!pIter || *pIter == *pEnd || (*pIter)->pNode->GetIndex() == nIndex);
SwNode* pAnchorNode = rAnch.GetAnchorNode(); if (pAnchorNode->GetIndex() != nIndex)
{ returnfalse;
} if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_PARA)
{ return pIter == nullptr // not merged
|| pIter != pEnd // at least one char visible in node
|| !IsSelectFrameAnchoredAtPara(*rAnch.GetContentAnchor(),
SwPosition(*pFirstNode, 0),
SwPosition(*pLastNode, pLastNode->Len()));
} if (pIter)
{ // note: frames are not sorted by anchor position.
assert(pEnd);
assert(pFirstNode);
assert(pLastNode);
assert(rAnch.GetAnchorId() != RndStdIds::FLY_AT_FLY); if (*pIter == *pEnd && rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
{ // tdf#149595 special case - it *could* be shown if first == last return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(),
SwPosition(*pFirstNode, 0),
SwPosition(*pLastNode, pLastNode->Len()));
} for (auto iter = *pIter; iter != *pEnd; ++iter)
{
assert(iter->nStart != iter->nEnd); // TODO possible?
assert(iter->pNode->GetIndex() == nIndex); if (rAnch.GetAnchorContentOffset() < iter->nStart)
{ returnfalse;
} if (rAnch.GetAnchorId() == RndStdIds::FLY_AT_CHAR)
{ // if there is an extent then obviously the node was not // deleted fully... // show if start <= pos <= end // *or* if first-node/0 *and* not StartOfSection // *or* if last-node/Len *and* not EndOfSection
// first determine the extent to compare to, then // construct start/end positions for the deletion *before* the // extent and compare once. // the interesting corner cases are on the edge of the extent! // no need to check for > the last extent because those // are never visible. if (rAnch.GetAnchorContentOffset() <= iter->nEnd)
{ if (iter->nStart == 0)
{ returntrue;
} else
{
SwPosition const start(
iter == *pIter
? *pFirstNode // simplification
: *iter->pNode,
iter == *pIter // first extent?
? iter->pNode == pFirstNode
? 0 // at start of 1st node
: pFirstNode->Len() // previous node; simplification but should get right result
: (iter-1)->nEnd); // previous extent
SwPosition const end(*iter->pNode, iter->nStart); return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(), start, end);
}
} elseif (iter == *pEnd - 1) // special case: after last extent
{ if (iter->nEnd == iter->pNode->Len())
{ returntrue; // special case: end of node
} else
{
SwPosition const start(*iter->pNode, iter->nEnd);
SwPosition const end(
*pLastNode, // simplification
iter->pNode == pLastNode
? iter->pNode->Len()
: 0); return !IsDestroyFrameAnchoredAtChar(*rAnch.GetContentAnchor(), start, end);
}
}
} else
{
assert(rAnch.GetAnchorId() == RndStdIds::FLY_AS_CHAR); // for AS_CHAR obviously must be < if (rAnch.GetAnchorContentOffset() < iter->nEnd)
{ returntrue;
}
}
} returnfalse;
} else
{ returntrue;
}
}
void AppendAllObjs(const sw::FrameFormats<sw::SpzFrameFormat*>* pTable, const SwFrame* pSib)
{ //Connecting of all Objects, which are described in the SpzTable with the //layout.
boost::circular_buffer<SwFrameFormat*> vFormatsToConnect(pTable->size()); for(constauto& pFormat : *pTable)
{ constauto& rAnch = pFormat->GetAnchor(); // Formats can still remain, because we neither use character bound // frames nor objects which are anchored to character bounds. if ((rAnch.GetAnchorId() != RndStdIds::FLY_AT_PAGE) && (rAnch.GetAnchorId() != RndStdIds::FLY_AS_CHAR))
{ const SwNode* pAnchorNode = rAnch.GetAnchorNode(); // formats in header/footer have no dependencies if(pAnchorNode && pFormat->GetDoc().IsInHeaderFooter(*pAnchorNode))
pFormat->MakeFrames(); else
vFormatsToConnect.push_back(pFormat);
}
} const SwRootFrame* pRoot = pSib ? pSib->getRootFrame() : nullptr; const SwFrameFormat* pFirstRequeued(nullptr); while(!vFormatsToConnect.empty())
{
SwFrameFormat* pFormat = vFormatsToConnect.front(); bool isConnected(false);
pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot)); if(!isConnected)
{
pFormat->MakeFrames();
pFormat->CallSwClientNotify(sw::GetObjectConnectedHint(isConnected, pRoot));
} // do this *before* push_back! the circular_buffer can be "full"!
vFormatsToConnect.pop_front(); if (!isConnected)
{ if(pFirstRequeued == pFormat) // If nothing happens anymore we can stop. break; if(!pFirstRequeued)
pFirstRequeued = pFormat;
assert(!vFormatsToConnect.full());
vFormatsToConnect.push_back(pFormat);
} else
{
pFirstRequeued = nullptr;
}
}
}
namespace sw {
void RecreateStartTextFrames(SwTextNode & rNode)
{
std::vector<SwTextFrame*> frames;
SwIterator<SwTextFrame, SwTextNode, sw::IteratorMode::UnwrapMulti> aIter(rNode); for (SwTextFrame* pFrame = aIter.First(); pFrame; pFrame = aIter.Next())
{ if (pFrame->getRootFrame()->HasMergedParas())
{
frames.push_back(pFrame);
}
} auto eMode(sw::FrameMode::Existing); for (SwTextFrame * pFrame : frames)
{ // SplitNode could have moved the original frame to the start node // & created a new one on end, or could have created new frame on // start node... grab start node's frame and recreate MergedPara.
SwTextNode & rFirstNode(pFrame->GetMergedPara()
? *pFrame->GetMergedPara()->pFirstNode
: rNode);
assert(rFirstNode.GetIndex() <= rNode.GetIndex()); // clear old one first to avoid DelFrames confusing updates & asserts...
pFrame->SetMergedPara(nullptr);
pFrame->SetMergedPara(sw::CheckParaRedlineMerge(
*pFrame, rFirstNode, eMode));
eMode = sw::FrameMode::New; // Existing is not idempotent! // note: this may or may not delete frames on the end node
}
}
} // namespace sw
/** local method to set 'working' position for newly inserted frames
// move position by one SwTwip in text flow direction in order to get // notifications for a new calculated position after its formatting. if ( aRectFnSet.IsVert() )
{
aFrm.Pos().AdjustX( -1 );
} else
{
aFrm.Pos().AdjustY(1 );
}
}
//In the generation of the Layout bPages=true will be handed over. //Then will be new pages generated all x paragraphs already times in advance. //On breaks and/or pagedescriptorchanges the corresponding will be generated //immediately. //The advantage is, that on one hand already a nearly realistic number of //pages are created, but above all there are no almost endless long chain //of paragraphs, which must be moved expensively until it reaches a tolerable //reduced level. //We'd like to think that 20 Paragraphs fit on one page. //So that it does not become in extreme situations so violent we calculate depending //on the node something to it. //If in the DocStatistic a usable given pagenumber //(Will be cared for while writing), so it will be presumed that this will be //number of pages. constbool bStartPercent = bPages && !nEndIndex;
//If the layout will be created (bPages == true) we do head on the progress //Flys and DrawObjects are not connected immediately, this //happens only at the end of the function. if ( bPages )
{ // Attention: the SwLayHelper class uses references to the content-, // page-, layout-frame etc. and may change them!
pPageMaker.reset(new SwLayHelper( rDoc, pFrame, pPrv, pPage, pLay,
pActualSection, nIndex, SwNodeOffset(0) == nEndIndex )); if( bStartPercent )
{ const sal_uLong nPageCount = pPageMaker->CalcPageCount(); if( nPageCount )
bObjsDirect = false;
}
}
if( pLay->IsInSct() &&
( pLay->IsSctFrame() || pLay->GetUpper() ) ) // Hereby will newbies // be intercepted, of which flags could not determined yet, // for e.g. while inserting a table
{
SwSectionFrame* pSct = pLay->FindSctFrame(); // If content will be inserted in a footnote, which in a column area, // the column area it is not allowed to be broken up. // Only if in the inner of the footnote lies an area, is this a candidate // for pActualSection. // The same applies for areas in tables, if inside the table will be // something inserted, it's only allowed to break up areas, which // lies in the inside also. if( ( !pLay->IsInFootnote() || pSct->IsInFootnote() ) &&
( !pLay->IsInTab() || pSct->IsInTab() ) )
{
pActualSection.reset(new SwActualSection(nullptr, pSct, pSct->GetSection()->GetFormat()->GetSectionNode())); // tdf#132236 for SwUndoDelete: find outer sections whose start // nodes aren't contained in the range but whose end nodes are, // because section frames may need to be created for them
SwActualSection * pUpperSection(pActualSection.get()); while (pUpperSection->GetSectionNode()->EndOfSectionIndex() < nEndIndex)
{
SwStartNode *const pStart(pUpperSection->GetSectionNode()->StartOfSectionNode()); if (!pStart->IsSectionNode())
{ break;
} // note: these don't have a section frame, check it in EndNode case! autoconst pTmp(new SwActualSection(nullptr, nullptr, static_cast<SwSectionNode*>(pStart)));
pUpperSection->SetUpper(pTmp);
pUpperSection = pTmp;
}
OSL_ENSURE( !pLay->Lower() || !pLay->Lower()->IsColumnFrame(), "InsertCnt_: Wrong Call" );
}
}
//If a section is "open", the pActualSection points to an SwActualSection. //If the page breaks, for "open" sections a follow will created. //For nested sections (which have, however, not a nested layout), //the SwActualSection class has a member, which points to an upper(section). //When the "inner" section finishes, the upper will used instead.
std::vector<SwSectionFrame *> newHiddenSections;
// Do not consider the end node. The caller (Section/MakeFrames()) has to // ensure that the end of this range is positioned before EndIndex! for ( ; nEndIndex == SwNodeOffset(0) || nIndex < nEndIndex; ++nIndex)
{
assert(pLayout);
SwNode *pNd = rDoc.GetNodes()[nIndex]; if ( pNd->IsContentNode() )
{
SwContentNode* pNode = static_cast<SwContentNode*>(pNd); if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
{ if (pNd->IsTextNode()
&& pNd->GetRedlineMergeFlag() == SwNode::Merge::NonFirst)
{ // must have a frame already
assert(static_cast<SwTextFrame*>(pNode->getLayoutFrame(pLayout))->GetMergedPara());
} continue; // skip it
}
pFrame = pNode->IsTextNode()
? sw::MakeTextFrame(*pNode->GetTextNode(), pLay, eMode)
: pNode->MakeFrame(pLay); if (pPageMaker && !pLay->IsHiddenNow())
pPageMaker->CheckInsert( nIndex );
pFrame->InsertBehind( pLay, pPrv ); if (!pPrv)
{ if (SwSectionFrame *const pSection = pLay->FindSctFrame())
{ if (pSection->ContainsAny() == pFrame)
{ // tdf#146258 section PrtArea depends on paragraph upper margin
pSection->InvalidatePrt();
}
}
} // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for next paragraph will change // and relation CONTENT_FLOWS_TO for previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY if ( pFrame->IsTextFrame() )
{
SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() ); // no notification, if <SwViewShell> is in construction if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() &&
pFrame->FindPageFrame() != nullptr)
{ auto pNext = pFrame->FindNextCnt( true ); auto pPrev = pFrame->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr ); // #i68958# // The information flags of the text frame are validated // in methods <FindNextCnt(..)> and <FindPrevCnt(..)>. // The information flags have to be invalidated, because // it is possible, that the one of its upper frames // isn't inserted into the layout.
pFrame->InvalidateInfFlags();
}
} #endif // OD 12.08.2003 #i17969# - consider horizontal/vertical layout // for setting position at newly inserted frame
lcl_SetPos( *pFrame, *pLay );
pPrv = pFrame;
if ( !pTable->empty() && bObjsDirect && !isFlyCreationSuppressed )
{
AppendObjs( pTable, nIndex, pFrame, pPage, rDoc ); // tdf#165351 from SwCellFrame ctor, this may set inf flags // before the SwCellFrame has an upper, so reset here
pFrame->InvalidateInfFlags();
}
} elseif ( pNd->IsTableNode() )
{ //Should we have encountered a table?
SwTableNode *pTableNode = static_cast<SwTableNode*>(pNd); if (pLayout->IsHideRedlines())
{ // in the problematic case, there can be only 1 redline...
SwPosition const tmp(*pNd);
SwRangeRedline const*const pRedline(
rDoc.getIDocumentRedlineAccess().GetRedline(tmp, nullptr)); // pathology: redline that starts on a TableNode; cannot // be created in UI but by import filters... if (pRedline
&& pRedline->GetType() == RedlineType::Delete
&& &pRedline->Start()->GetNode() == pNd)
{
SAL_WARN("sw.pageframe", "skipping table frame creation on bizarre redline"); while (true)
{
pTableNode->GetNodes()[nIndex]->SetRedlineMergeFlag(SwNode::Merge::Hidden); if (nIndex == pTableNode->EndOfSectionIndex())
{ break;
}
++nIndex;
} continue;
}
} if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
{
assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
nIndex = pTableNode->EndOfSectionIndex(); continue; // skip it
}
pFrame = pTableNode->MakeFrame( pLay );
pFrame->InvalidateInfFlags();
// skip tables deleted with track changes if ( !static_cast<SwTabFrame*>(pFrame)->Lower() )
{
nIndex = pTableNode->EndOfSectionIndex(); continue; // skip it
}
// #108116# loading may produce table structures that GCLines // needs to clean up. To keep table formulas correct, change // all table formulas to internal (BOXPTR) representation.
pTableNode->GetTable().SwitchFormulasToInternalRepresentation();
pTableNode->GetTable().GCLines();
pFrame->InsertBehind( pLay, pPrv ); if (pPage) // would null in SwCellFrame ctor
{ // tdf#134931 call ResetTurbo(); not sure if Paste() would be
pFrame->InvalidatePage(pPage); // better than InsertBehind()?
} // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for next paragraph will change // and relation CONTENT_FLOWS_TO for previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY
{
SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() ); // no notification, if <SwViewShell> is in construction if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() &&
pFrame->FindPageFrame() != nullptr)
{ auto pNext = pFrame->FindNextCnt( true ); auto pPrev = pFrame->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr );
}
} #endif if ( bObjsDirect && !pTable->empty() ) static_cast<SwTabFrame*>(pFrame)->RegistFlys(); // OD 12.08.2003 #i17969# - consider horizontal/vertical layout // for setting position at newly inserted frame
lcl_SetPos( *pFrame, *pLay );
pPrv = pFrame; //Set the index to the endnode of the table section.
nIndex = pTableNode->EndOfSectionIndex();
} elseif ( pNd->IsSectionNode() )
{ if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
{
assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden); continue; // skip it
}
SwSectionNode *pNode = static_cast<SwSectionNode*>(pNd);
{ if (pActualSection)
pActualSection->SetLastPos(pPrv);
pFrame = pNode->MakeFrame(pLay, pNode->GetSection().CalcHiddenFlag());
pActualSection.reset( new SwActualSection( pActualSection.release(), static_cast<SwSectionFrame*>(pFrame), pNode ) ); if ( pActualSection->GetUpper() )
{ //Insert behind the Upper, the "Follow" of the Upper will be //generated at the EndNode.
SwSectionFrame *pTmp = pActualSection->GetUpper()->GetSectionFrame();
pFrame->InsertBehind( pTmp->GetUpper(), pTmp ); // OD 25.03.2003 #108339# - direct initialization of section // after insertion in the layout static_cast<SwSectionFrame*>(pFrame)->Init();
} else
{
pFrame->InsertBehind( pLay, pPrv ); // OD 25.03.2003 #108339# - direct initialization of section // after insertion in the layout static_cast<SwSectionFrame*>(pFrame)->Init();
// #i33963# // Do not trust the IsInFootnote flag. If we are currently // building up a table, the upper of pPrv may be a cell // frame, but the cell frame does not have an upper yet. if( pPrv && nullptr != pPrv->ImplFindFootnoteFrame() )
{ if( pPrv->IsSctFrame() )
pPrv = static_cast<SwSectionFrame*>(pPrv)->ContainsContent(); if( pPrv && pPrv->IsTextFrame() ) static_cast<SwTextFrame*>(pPrv)->Prepare( PrepareHint::QuoVadis, nullptr, false );
}
}
if (nIndex + 1 == nEndIndex // tdf#136452 may also be needed at end of section
|| pNode->EndOfSectionIndex() - 1 == nEndIndex)
{ // tdf#131684 tdf#132236 fix upper of frame moved in // SwUndoDelete; can't be done there unfortunately // because empty section frames are deleted here
SwFrame *const pNext( // if there's a parent section, it has been split // into 2 SwSectionFrame already :(
( pFrame->GetNext()
&& pFrame->GetNext()->IsSctFrame()
&& pActualSection->GetUpper()
&& pActualSection->GetUpper()->GetSectionNode() == static_cast<SwSectionFrame const*>(pFrame->GetNext())->GetSection()->GetFormat()->GetSectionNode())
? static_cast<SwSectionFrame *>(pFrame->GetNext())->ContainsContent()
: pFrame->GetNext()); if (pNext
&& pNext->IsTextFrame()
&& static_cast<SwTextFrame*>(pNext)->GetTextNodeFirst() == rDoc.GetNodes()[nEndIndex]
&& (pNext->GetUpper() == pFrame->GetUpper()
|| pFrame->GetNext()->IsSctFrame())) // checked above
{
pNext->Cut();
pNext->InvalidateInfFlags(); // mbInfSct changed // could have columns
SwSectionFrame *const pSection(static_cast<SwSectionFrame*>(pFrame));
assert(!pSection->Lower() || pSection->Lower()->IsLayoutFrame());
SwLayoutFrame *const pParent(pSection->Lower() ? pSection->GetNextLayoutLeaf() : pSection);
assert(!pParent->Lower()); // paste invalidates, section could have indent...
pNext->Paste(pParent, nullptr);
}
} // #i27138# // notify accessibility paragraphs objects about changed // CONTENT_FLOWS_FROM/_TO relation. // Relation CONTENT_FLOWS_FROM for next paragraph will change // and relation CONTENT_FLOWS_TO for previous paragraph will change. #if !ENABLE_WASM_STRIP_ACCESSIBILITY
{
SwViewShell* pViewShell( pFrame->getRootFrame()->GetCurrShell() ); // no notification, if <SwViewShell> is in construction if ( pViewShell && !pViewShell->IsInConstructor() &&
pViewShell->GetLayout() &&
pViewShell->GetLayout()->IsAnyShellAccessible() &&
pFrame->FindPageFrame() != nullptr)
{ auto pNext = pFrame->FindNextCnt( true ); auto pPrev = pFrame->FindPrevCnt();
pViewShell->InvalidateAccessibleParaFlowRelation(
pNext ? pNext->DynCastTextFrame() : nullptr,
pPrev ? pPrev->DynCastTextFrame() : nullptr );
}
} #endif
pFrame->CheckDirChange();
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout // for setting position at newly inserted frame
lcl_SetPos( *pFrame, *pLay );
// OD 20.11.2002 #105405# - no page, no invalidate. if ( pPage )
{ // OD 18.09.2002 #100522# // invalidate page in order to force format and paint of // inserted section frame
pFrame->InvalidatePage( pPage );
// OD 14.11.2002 #104684# - invalidate page content in order to // force format and paint of section content.
pPage->InvalidateContent();
}
pLay = static_cast<SwLayoutFrame*>(pFrame); if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
pLay = pLay->GetNextLayoutLeaf();
pPrv = nullptr;
}
} elseif ( pNd->IsEndNode() && pNd->StartOfSectionNode()->IsSectionNode() )
{ if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
{
assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden); continue; // skip it
} if (pLayout->HasMergedParas() && !pNd->StartOfSectionNode()->IsCreateFrameWhenHidingRedlines())
{ // tdf#135014 section break in fieldmark (start inside, end outside)
assert(pNd->StartOfSectionNode()->GetRedlineMergeFlag() == SwNode::Merge::Hidden); continue; // skip it
}
assert(pActualSection && "Section end without section start?");
//Close the section, where appropriate activate the surrounding //section again. if (pActualSection)
{
assert(pActualSection->GetSectionNode() == pNd->StartOfSectionNode());
pActualSection.reset(pActualSection->GetUpper());
}
pLay = pLay->FindSctFrame(); if ( pActualSection )
{ //Could be, that the last SectionFrame remains empty. //Then now is the time to remove them. if ( !pLay->ContainsContent() )
{
SwFrame *pTmpFrame = pLay;
pLay = pTmpFrame->GetUpper();
pPrv = pTmpFrame->GetPrev();
pTmpFrame->RemoveFromLayout();
SwFrame::DestroyFrame(pTmpFrame);
} else
{ if (pLay->IsHiddenNow())
{
newHiddenSections.push_back(static_cast<SwSectionFrame*>(pLay));
}
pPrv = pLay;
pLay = pLay->GetUpper();
}
// new section frame if (SwSectionFrame* pOuterSectionFrame = pActualSection->GetSectionFrame())
{ // Splitting moves the trailing content to the next frame
pFrame = pOuterSectionFrame->SplitSect(pActualSection->GetLastPos(), pPrv);
// We don't want to leave empty parts back. if (! pOuterSectionFrame->IsColLocked() &&
! pOuterSectionFrame->ContainsContent() )
{
pOuterSectionFrame->DelEmpty( true );
SwFrame::DestroyFrame(pOuterSectionFrame);
} elseif (pOuterSectionFrame->IsHiddenNow())
{
newHiddenSections.push_back(pOuterSectionFrame);
}
} else
{
pFrame = pActualSection->GetSectionNode()->MakeFrame(
pLay, pActualSection->GetSectionNode()->GetSection().IsHiddenFlag());
pFrame->InsertBehind( pLay, pPrv ); static_cast<SwSectionFrame*>(pFrame)->Init();
// OD 12.08.2003 #i17969# - consider horizontal/vertical layout // for setting position at newly inserted frame
lcl_SetPos( *pFrame, *pLay );
}
pLay = static_cast<SwLayoutFrame*>(pFrame); if ( pLay->Lower() && pLay->Lower()->IsLayoutFrame() )
pLay = pLay->GetNextLayoutLeaf();
pPrv = nullptr;
} else
{ if (pLay->IsHiddenNow())
{
newHiddenSections.push_back(static_cast<SwSectionFrame*>(pLay));
} //Nothing more with sections, it goes on right behind //the SectionFrame.
pPrv = pLay;
pLay = pLay->GetUpper();
}
} elseif( pNd->IsStartNode() &&
SwFlyStartNode == static_cast<SwStartNode*>(pNd)->GetStartNodeType() )
{ if (pLayout->HasMergedParas() && !pNd->IsCreateFrameWhenHidingRedlines())
{
assert(pNd->GetRedlineMergeFlag() == SwNode::Merge::Hidden);
assert(false); // actually a fly-section can't be deleted? continue; // skip it
} if ( !pTable->empty() && bObjsDirect && !isFlyCreationSuppressed )
{
SwFlyFrame* pFly = pLay->FindFlyFrame(); if( pFly )
AppendObjs( pTable, nIndex, pFly, pPage, rDoc );
}
} else
{
assert(!pLayout->HasMergedParas()
|| pNd->GetRedlineMergeFlag() != SwNode::Merge::Hidden); // Neither Content nor table nor section, so we are done. break;
}
}
if ( pActualSection )
{ // Might happen that an empty (Follow-)Section is left over. if ( !(pLay = pActualSection->GetSectionFrame())->ContainsContent() )
{
pLay->RemoveFromLayout();
SwFrame::DestroyFrame(pLay);
}
pActualSection.reset();
}
if ( bPages ) // let the Flys connect to each other
{ if ( !isFlyCreationSuppressed )
AppendAllObjs( pTable, pLayout );
bObjsDirect = true;
}
// do it after AppendAllObjs() for (SwSectionFrame * pNew : newHiddenSections)
{ for (SwFlowFrame * pSect = pNew; pSect; pSect = pSect->GetPrecede())
{ // flys were created visible; section may be paginated so iterate
pSect->GetFrame().HideAndShowObjects();
}
}
SwNodeOffset nEndIdx = rEndIdx.GetIndex(); // TODO for multiple layouts there should be a loop here
SwNode* pNd = rDoc.GetNodes().FindPrvNxtFrameNode( rSttIdx,
rDoc.GetNodes()[ nEndIdx-1 ],
rDoc.getIDocumentLayoutAccess().GetCurrentLayout()); if ( pNd )
{ bool bAfter = *pNd < rSttIdx;
SwNode2Layout aNode2Layout( *pNd, rSttIdx.GetIndex() );
sw::FrameMode eMode = sw::FrameMode::Existing;
::std::vector<SwFrame*> frames; while (SwFrame* pFrame = aNode2Layout.NextFrame())
{ // tdf#150500 new frames may be created that end up merged on pNd // so copy the currently existing ones; they shouldn't get deleted
frames.push_back(pFrame);
} for (SwFrame *const pFrame : frames)
{
SwLayoutFrame *pUpper = pFrame->GetUpper();
SwFootnoteFrame* pFootnoteFrame = pUpper->FindFootnoteFrame(); bool bOldLock, bOldFootnote; if( pFootnoteFrame )
{
bOldFootnote = pFootnoteFrame->IsColLocked();
pFootnoteFrame->ColLock();
} else
bOldFootnote = true;
SwSectionFrame* pSct = pUpper->FindSctFrame(); // Inside of footnotes only those areas are interesting that are inside of them. But // not the ones (e.g. column areas) in which are the footnote containers positioned. // #109767# Table frame is in section, insert section in cell frame. if( pSct && ((pFootnoteFrame && !pSct->IsInFootnote()) || pUpper->IsCellFrame()) )
pSct = nullptr; if( pSct )
{ // to prevent pTmp->MoveFwd from destroying the SectionFrame
bOldLock = pSct->IsColLocked();
pSct->ColLock();
} else
bOldLock = true;
// If pFrame cannot be moved, it is not possible to move it to the next page. This applies // also for frames (in the first column of a frame pFrame is moveable) and column // sections of tables (also here pFrame is moveable). bool bMoveNext = nEndIdx - rSttIdx.GetIndex() > SwNodeOffset(120); bool bAllowMove = !pFrame->IsInFly() && pFrame->IsMoveable() &&
(!pFrame->IsInTab() || pFrame->IsTabFrame() ); if ( bMoveNext && bAllowMove )
{
SwFrame *pMove = pFrame;
SwFrame *pPrev = pFrame->GetPrev();
SwFlowFrame *pTmp = SwFlowFrame::CastFlowFrame( pMove );
assert(pTmp);
if ( bAfter )
{ // The rest of this page should be empty. Thus, the following one has to move to // the next page (it might also be located in the following column).
assert(!pTmp->HasFollow() && "prev. node's frame is not last");
pPrev = pFrame; // If the surrounding SectionFrame has a "next" one, // so this one needs to be moved as well.
pMove = pFrame->GetIndNext();
SwColumnFrame* pCol = static_cast<SwColumnFrame*>(pFrame->FindColFrame()); if( pCol )
pCol = static_cast<SwColumnFrame*>(pCol->GetNext()); do
{ if( pCol && !pMove )
{ // No successor so far, look into the next column
pMove = pCol->ContainsAny(); if( pCol->GetNext() )
pCol = static_cast<SwColumnFrame*>(pCol->GetNext()); elseif( pCol->IsInSct() )
{ // If there is no following column but we are in a column frame, // there might be (page) columns outside of it.
pCol = static_cast<SwColumnFrame*>(pCol->FindSctFrame()->FindColFrame()); if( pCol )
pCol = static_cast<SwColumnFrame*>(pCol->GetNext());
} else
pCol = nullptr;
} // skip invalid SectionFrames while( pMove && pMove->IsSctFrame() &&
!static_cast<SwSectionFrame*>(pMove)->GetSection() )
pMove = pMove->GetNext();
} while( !pMove && pCol );
/* All calc methods calculate a safety distance in addition to the values given by the attributes. * This safety distance is only added when working with borders and/or shadows to prevent that * e.g. borders are painted over.
*/
bool bGutterAtTop = m_rAttrSet.GetDoc().getIDocumentSettingAccess().get(
DocumentSettingId::GUTTER_AT_TOP); if (bGutterAtTop && m_xLR)
{ // Decrease the print area: the top space is the sum of top and gutter margins.
m_nTop += m_xLR->GetGutterMargin();
}
if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING)) { // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left // and right border are painted on the right respectively left. if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
nRight = CalcLeftLine(); else
nRight = CalcRightLine();
} // for paragraphs, "left" is "before text" and "right" is "after text" if (pCaller->IsTextFrame())
{ // tdf#163913: Only apply the fixed-width part of the margin here. // Font-relative margins will be applied as an adjustment later on. if (pCaller->IsRightToLeft())
{
nRight += m_pTextLeftMargin->ResolveLeftFixedPart(*m_pFirstLineIndent);
} else
{
nRight += m_pRightMargin->ResolveRightFixedPart();
}
} else
nRight += m_xLR->ResolveRight({});
// correction: retrieve left margin for numbering in R2L-layout if ( pCaller->IsTextFrame() && pCaller->IsRightToLeft() )
{
nRight += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
}
if (pCaller->IsPageFrame())
{ constauto pPageFrame = static_cast<const SwPageFrame*>(pCaller); bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
DocumentSettingId::GUTTER_AT_TOP); if (!bGutterAtTop)
{ bool bRtlGutter = pPageFrame->GetAttrSet()->GetItem<SfxBoolItem>(RES_RTL_GUTTER)->GetValue();
tools::Long nGutterMargin = bRtlGutter ? m_xLR->GetGutterMargin() : m_xLR->GetRightGutterMargin(); // Decrease the print area: the right space is the sum of right and right gutter // margins.
nRight += nGutterMargin;
}
}
if (!pCaller->IsTextFrame() || !static_cast<const SwTextFrame*>(pCaller)->GetDoc().GetDocumentSettingManager().get(DocumentSettingId::INVERT_BORDER_SPACING))
{ // OD 23.01.2003 #106895# - for cell frame in R2L text direction the left // and right border are painted on the right respectively left. if ( pCaller->IsCellFrame() && pCaller->IsRightToLeft() )
nLeft = CalcRightLine(); else
nLeft = CalcLeftLine();
}
// for paragraphs, "left" is "before text" and "right" is "after text"
// tdf#163913: Only apply the fixed-width part of the margin here. // Font-relative margins will be applied as an adjustment later on. if (pCaller->IsTextFrame() && pCaller->IsRightToLeft())
{
nLeft += m_pRightMargin->ResolveRightFixedPart();
} else
{ if (pCaller->IsTextFrame())
{
nLeft += m_pTextLeftMargin->ResolveLeftFixedPart(*m_pFirstLineIndent);
} else
{
nLeft += m_xLR->ResolveLeft({});
}
}
// correction: do not retrieve left margin for numbering in R2L-layout if ( pCaller->IsTextFrame() && !pCaller->IsRightToLeft() )
{
nLeft += static_cast<const SwTextFrame*>(pCaller)->GetTextNodeForParaProps()->GetLeftMarginWithNum();
}
if (pCaller->IsPageFrame())
{ constauto pPageFrame = static_cast<const SwPageFrame*>(pCaller); bool bGutterAtTop = pPageFrame->GetFormat()->getIDocumentSettingAccess().get(
DocumentSettingId::GUTTER_AT_TOP); if (!bGutterAtTop)
{ bool bRtlGutter = pPageFrame->GetAttrSet()->GetItem<SfxBoolItem>(RES_RTL_GUTTER)->GetValue();
tools::Long nGutterMargin = bRtlGutter ? m_xLR->GetRightGutterMargin() : m_xLR->GetGutterMargin(); // Decrease the print area: the left space is the sum of left and gutter margins.
nLeft += nGutterMargin;
}
}
return nLeft;
}
/* Calculated values for borders and shadows. * It might be that a distance is wanted even without lines. This will be * considered here and not by the attribute (e.g. bBorderDist for cells).
*/
/* The borders of neighboring paragraphs are condensed by following algorithm: * * 1. No top border if the predecessor has the same top border and (3) applies. * In addition, the paragraph needs to have a border at least one side (left/right/bottom). * 2. No bottom border if the successor has the same bottom border and (3) applies. * In addition, the paragraph needs to have a border at least one side (left/right/top). * 3. The borders on the left and right side are identical between the current and the * pre-/succeeding paragraph.
*/
// OD 21.05.2003 #108789# - method to determine, if borders are joined with // previous frame. Calculated value saved in cached value <m_bJoinedWithPrev> // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame> void SwBorderAttrs::CalcJoinedWithPrev( const SwFrame& _rFrame, const SwFrame* _pPrevFrame ) const
{ // set default
m_bJoinedWithPrev = false;
if ( _rFrame.IsTextFrame() )
{ // text frame can potentially join with previous text frame, if // corresponding attribute set is set at previous text frame. // OD 2004-02-26 #i25029# - If parameter <_pPrevFrame> is set, take this // one as previous frame. const SwFrame* pPrevFrame = _pPrevFrame ? _pPrevFrame : _rFrame.GetPrev(); // OD 2004-02-13 #i25029# - skip hidden text frames. while (pPrevFrame && pPrevFrame->IsHiddenNow())
{
pPrevFrame = pPrevFrame->GetPrev();
} if ( pPrevFrame && pPrevFrame->IsTextFrame() &&
pPrevFrame->GetAttrSet()->GetParaConnectBorder().GetValue()
)
{
m_bJoinedWithPrev = JoinWithCmp( _rFrame, *pPrevFrame );
}
}
// valid cache status, if demanded // OD 2004-02-26 #i25029# - Do not validate cache, if parameter <_pPrevFrame> // is set.
m_bCachedJoinedWithPrev = m_bCacheGetLine && !_pPrevFrame;
}
// OD 21.05.2003 #108789# - method to determine, if borders are joined with // next frame. Calculated value saved in cached value <m_bJoinedWithNext> void SwBorderAttrs::CalcJoinedWithNext( const SwFrame& _rFrame ) const
{ // set default
m_bJoinedWithNext = false;
if ( _rFrame.IsTextFrame() )
{ // text frame can potentially join with next text frame, if // corresponding attribute set is set at current text frame. // OD 2004-02-13 #i25029# - get next frame, but skip hidden text frames. const SwFrame* pNextFrame = _rFrame.GetNext(); while (pNextFrame && pNextFrame->IsHiddenNow())
{
pNextFrame = pNextFrame->GetNext();
} if ( pNextFrame && pNextFrame->IsTextFrame() &&
_rFrame.GetAttrSet()->GetParaConnectBorder().GetValue()
)
{
m_bJoinedWithNext = JoinWithCmp( _rFrame, *pNextFrame );
}
}
// valid cache status, if demanded
m_bCachedJoinedWithNext = m_bCacheGetLine;
}
// OD 21.05.2003 #108789# - accessor for cached values <m_bJoinedWithPrev> // OD 2004-02-26 #i25029# - add 2nd parameter <_pPrevFrame>, which is passed to // method <_CalcJoindWithPrev(..)>. bool SwBorderAttrs::JoinedWithPrev( const SwFrame& _rFrame, const SwFrame* _pPrevFrame ) const
{ if ( !m_bCachedJoinedWithPrev || _pPrevFrame )
{ // OD 2004-02-26 #i25029# - pass <_pPrevFrame> as 2nd parameter
CalcJoinedWithPrev( _rFrame, _pPrevFrame );
}
static sw::BorderCacheOwner const* GetBorderCacheOwner(SwFrame const& rFrame)
{ return rFrame.IsContentFrame()
? static_cast<sw::BorderCacheOwner const*>(rFrame.IsTextFrame() // sw_redlinehide: presumably this caches the border attrs at the model level and can be shared across different layouts so we want the ParaProps node here
? static_cast<const SwTextFrame&>(rFrame).GetTextNodeForParaProps()
: static_cast<const SwNoTextFrame&>(rFrame).GetNode())
: static_cast<sw::BorderCacheOwner const*>(static_cast<const SwLayoutFrame&>(rFrame).GetFormat());
}
const SwSortedObjs *pObjs = m_pPage->GetSortedObjs(); if ( !pObjs->size() ) return;
sal_uInt32 nOrd = 0;
(*pObjs)[0]->GetDrawObj()->GetOrdNum(); // force updating for (SwAnchoredObject* i : *pObjs)
{ const SdrObject* pObj = i->GetDrawObj(); if ( dynamic_cast<const SwVirtFlyDrawObj*>( pObj) == nullptr ) continue;
sal_uInt32 nTmp = pObj->GetOrdNumDirect(); if ( nTmp < nCurOrd && nTmp >= nOrd )
{
nOrd = nTmp;
m_pCurrent = pObj;
}
}
}
/// Keep and restore the substructure of a layout frame for an action. // New algorithm: // Do not look at each neighbor one by one to set all pointers correctly. // It is sufficient to detach a part of a chain and check if another chain needs to be added // when attaching it again. Only the pointers necessary for the chain connection need to be // adjusted. The correction happens in RestoreContent(). In between all access is restricted. // During this action, the Flys are detached from the page.
// #115759# - 'remove' also drawing object from page and // at-fly anchored objects from page staticvoid lcl_RemoveObjsFromPage( SwFrame* _pFrame )
{
OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_RemoveObjsFromPage." );
SwSortedObjs &rObjs = *_pFrame->GetDrawObjs(); for (SwAnchoredObject* pObj : rObjs)
{ // #115759# - reset member, at which the anchored // object orients its vertical position
pObj->ClearVertPosOrientFrame(); // #i43913#
pObj->ResetLayoutProcessBools(); // #115759# - remove also lower objects of as-character // anchored Writer fly frames from page if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
{ // #115759# - remove also direct lowers of Writer // fly frame from page if ( pFlyFrame->GetDrawObjs() )
{
::lcl_RemoveObjsFromPage( pFlyFrame );
}
SwContentFrame* pCnt = pFlyFrame->ContainsContent(); while ( pCnt )
{ if ( pCnt->GetDrawObjs() )
::lcl_RemoveObjsFromPage( pCnt );
pCnt = pCnt->GetNextContentFrame();
} if ( pFlyFrame->IsFlyFreeFrame() )
{ // #i28701# - use new method <GetPageFrame()> if (SwPageFrame *pPg = pFlyFrame->GetPageFrame())
pPg->RemoveFlyFromPage(pFlyFrame);
}
} // #115759# - remove also drawing objects from page elseif ( auto pDrawObj = dynamic_cast<SwAnchoredDrawObject*>( pObj) )
{ if (pObj->GetFrameFormat()->GetAnchor().GetAnchorId() != RndStdIds::FLY_AS_CHAR)
{ if (SwPageFrame *pPg = pObj->GetPageFrame())
pPg->RemoveDrawObjFromPage( *pDrawObj );
}
}
}
}
// Tables should be saved as a whole, exception: // The contents of a section or a cell inside a table should be saved if ( pSav->IsInTab() && !( ( pLay->IsSctFrame() || pLay->IsCellFrame() ) && pLay->IsInTab() ) ) while ( !pSav->IsTabFrame() )
pSav = pSav->GetUpper();
if( pSav->IsInSct() )
{ // search the upmost section inside of pLay
SwFrame* pSect = pLay->FindSctFrame();
SwFrame *pTmp = pSav; do
{
pSav = pTmp;
pTmp = (pSav && pSav->GetUpper()) ? pSav->GetUpper()->FindSctFrame() : nullptr;
} while ( pTmp != pSect );
}
SwFrame *pFloat = pSav; if( !pStart )
pStart = pSav; bool bGo = pStart == pSav; do
{ if( bGo )
pFloat->GetUpper()->m_pLower = nullptr; // detach the chain part
// search the end of the chain part, remove Flys on the way do
{ if( bGo )
{ if ( pFloat->IsContentFrame() )
{ if ( pFloat->GetDrawObjs() )
::lcl_RemoveObjsFromPage( static_cast<SwContentFrame*>(pFloat) );
} elseif ( pFloat->IsTabFrame() || pFloat->IsSctFrame() )
{
SwContentFrame *pCnt = static_cast<SwLayoutFrame*>(pFloat)->ContainsContent(); if( pCnt )
{ do
{ if ( pCnt->GetDrawObjs() )
::lcl_RemoveObjsFromPage( pCnt );
pCnt = pCnt->GetNextContentFrame();
} while ( pCnt && static_cast<SwLayoutFrame*>(pFloat)->IsAnLower( pCnt ) );
}
} else {
OSL_ENSURE( !pFloat, "new FloatFrame?" );
}
} if ( pFloat->GetNext() )
{ if( bGo )
pFloat->mpUpper = nullptr;
pFloat = pFloat->GetNext(); if( !bGo && pFloat == pStart )
{
bGo = true;
pFloat->mpPrev->mpNext = nullptr;
pFloat->mpPrev = nullptr;
}
} else break;
} while ( pFloat );
// search next chain part and connect both chains
SwFrame *pTmp = pFloat ? pFloat->FindNext() : nullptr; if (bGo && pFloat)
pFloat->mpUpper = nullptr;
// #115759# - add also drawing objects to page and at-fly // anchored objects to page staticvoid lcl_AddObjsToPage( SwFrame* _pFrame, SwPageFrame* _pPage )
{
OSL_ENSURE( _pFrame->GetDrawObjs(), "no DrawObjs in lcl_AddObjsToPage." );
SwSortedObjs &rObjs = *_pFrame->GetDrawObjs(); for (SwAnchoredObject* pObj : rObjs)
{ // #115759# - unlock position of anchored object // in order to get the object's position calculated.
pObj->UnlockPosition(); // #115759# - add also lower objects of as-character // anchored Writer fly frames from page if ( auto pFlyFrame = pObj->DynCastFlyFrame() )
{ if (pFlyFrame->IsFlyFreeFrame())
{
_pPage->AppendFlyToPage( pFlyFrame );
}
pFlyFrame->InvalidatePos_();
pFlyFrame->InvalidateSize_();
pFlyFrame->InvalidatePage( _pPage );
// #115759# - add also at-fly anchored objects // to page if ( pFlyFrame->GetDrawObjs() )
{
::lcl_AddObjsToPage( pFlyFrame, _pPage );
}
void RestoreContent( SwFrame *pSav, SwLayoutFrame *pParent, SwFrame *pSibling )
{
assert(pSav && pParent && "no Save or Parent provided for RestoreContent.");
SwRectFnSet aRectFnSet(pParent);
// If there are already FlowFrames below the new parent, so add the chain (starting with pSav) // after the last one. The parts are inserted and invalidated if needed. // On the way, the Flys of the ContentFrames are registered at the page.
SwPageFrame *pPage = pParent->FindPageFrame();
if ( pPage )
pPage->InvalidatePage( pPage );
// determine predecessor and establish connection or initialize
pSav->mpPrev = pSibling;
SwFrame* pNxt; if ( pSibling )
{
pNxt = pSibling->mpNext;
pSibling->mpNext = pSav;
pSibling->InvalidatePrt_();
pSibling->InvalidatePage( pPage );
SwFlowFrame *pFlowFrame = dynamic_cast<SwFlowFrame*>(pSibling); if (pFlowFrame && pFlowFrame->GetFollow())
pSibling->Prepare( PrepareHint::Clear, nullptr, false );
} else
{ pNxt = pParent->m_pLower;
pParent->m_pLower = pSav;
pSav->mpUpper = pParent; // set here already, so that it is explicit when invalidating
if ( pSav->IsContentFrame() ) static_cast<SwContentFrame*>(pSav)->InvalidatePage( pPage ); else
{ // pSav might be an empty SectFrame
SwContentFrame* pCnt = pParent->ContainsContent(); if( pCnt )
pCnt->InvalidatePage( pPage );
}
}
// the parent needs to grow appropriately
SwTwips nGrowVal = 0;
SwFrame* pLast; do
{ pSav->mpUpper = pParent;
nGrowVal += aRectFnSet.GetHeight(pSav->getFrameArea());
pSav->InvalidateAll_();
// register Flys, if TextFrames than also invalidate appropriately if ( pSav->IsContentFrame() )
{ if ( pSav->IsTextFrame() && static_cast<SwTextFrame*>(pSav)->GetCacheIdx() != USHRT_MAX ) static_cast<SwTextFrame*>(pSav)->Init(); // I am its friend
if ( pPage && pSav->GetDrawObjs() )
::lcl_AddObjsToPage( static_cast<SwContentFrame*>(pSav), pPage );
} else
{ SwContentFrame *pBlub = static_cast<SwLayoutFrame*>(pSav)->ContainsContent(); if( pBlub )
{ do
{ if ( pPage && pBlub->GetDrawObjs() )
::lcl_AddObjsToPage( pBlub, pPage ); if( pBlub->IsTextFrame() && static_cast<SwTextFrame*>(pBlub)->HasFootnote() && static_cast<SwTextFrame*>(pBlub)->GetCacheIdx() != USHRT_MAX ) static_cast<SwTextFrame*>(pBlub)->Init(); // I am its friend
pBlub = pBlub->GetNextContentFrame();
} while ( pBlub && static_cast<SwLayoutFrame*>(pSav)->IsAnLower( pBlub ));
}
}
pLast = pSav;
pSav = pSav->GetNext();
bool IsRightPageByNumber(SwRootFrame const& rLayout, sal_uInt16 const nPageNum)
{
assert(rLayout.GetLower()); // unfortunately can only get SwPageDesc, not SwFormatPageDesc here... autoconst nFirstVirtPageNum(rLayout.GetLower()->GetVirtPageNum()); boolconst isFirstPageOfLayoutOdd(nFirstVirtPageNum % 2 == 1); return ((nPageNum % 2) == 1) == isFirstPageOfLayoutOdd;
}
} // namespace sw
SwPageFrame * InsertNewPage( SwPageDesc &rDesc, SwFrame *pUpper, boolconst isRightPage, boolconst bFirst, bool bInsertEmpty, boolconst bFootnote,
SwFrame *pSibling, boolconst bVeryFirstPage )
{
assert(pUpper);
assert(pUpper->IsRootFrame());
assert(!pSibling || static_cast<SwLayoutFrame const*>(pUpper)->Lower() != pSibling); // currently no insert before 1st page
SwPageFrame *pRet;
SwDoc& rDoc = static_cast<SwLayoutFrame*>(pUpper)->GetFormat()->GetDoc(); if (bFirst)
{ if (rDesc.IsFirstShared())
{ // We need to fallback to left or right page format, decide it now. // FIXME: is this still needed? if (isRightPage)
{
rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetHeader() );
rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetFooter() ); // fdo#60250 copy margins for mirrored pages
rDesc.GetFirstMaster().SetFormatAttr( rDesc.GetMaster().GetLRSpace() );
} else
{
rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetHeader() );
rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetFooter() );
rDesc.GetFirstLeft().SetFormatAttr( rDesc.GetLeft().GetLRSpace() );
}
}
}
SwFrameFormat *pFormat(isRightPage ? rDesc.GetRightFormat(bFirst) : rDesc.GetLeftFormat(bFirst)); // If there is no FrameFormat for this page, add an empty page if ( !pFormat )
{
pFormat = isRightPage ? rDesc.GetLeftFormat(bVeryFirstPage) : rDesc.GetRightFormat(bVeryFirstPage);
OSL_ENSURE( pFormat, "Descriptor without any format?!" );
bInsertEmpty = !bInsertEmpty;
} if( bInsertEmpty )
{
SwPageDesc *pTmpDesc = pSibling && pSibling->GetPrev() ? static_cast<SwPageFrame*>(pSibling->GetPrev())->GetPageDesc() : &rDesc;
pRet = new SwPageFrame( rDoc.GetEmptyPageFormat(), pUpper, pTmpDesc );
SAL_INFO( "sw.pageframe", "InsertNewPage - insert empty p: " << pRet << " d: " << pTmpDesc );
pRet->Paste( pUpper, pSibling );
pRet->PreparePage( bFootnote );
}
pRet = new SwPageFrame( pFormat, pUpper, &rDesc );
SAL_INFO( "sw.pageframe", "InsertNewPage p: " << pRet << " d: " << &rDesc << " f: " << pFormat );
pRet->Paste( pUpper, pSibling );
pRet->PreparePage( bFootnote ); if ( pRet->GetNext() )
SwRootFrame::AssertPageFlys( pRet ); return pRet;
}
/* The following two methods search the layout structure recursively and * register all Flys at the page that have a Frame in this structure as an anchor.
*/
const SwFlyFrame* pFly = pAnch->FindFlyFrame(); if ( pFly &&
pObj->GetDrawObj()->GetOrdNum() < pFly->GetVirtDrawObj()->GetOrdNum() &&
pObj->GetDrawObj()->getSdrPageFromSdrObject() )
{ //#i119945# set pFly's OrdNum to pObj's. So when pFly is removed by Undo, the original OrdNum will not be changed.
pObj->DrawObj()->getSdrPageFromSdrObject()->SetObjectOrdNum( pFly->GetVirtDrawObj()->GetOrdNumDirect(),
pObj->GetDrawObj()->GetOrdNumDirect() );
}
}
}
/// Notify the background based on the difference between old and new rectangle void Notify( SwFlyFrame *pFly, SwPageFrame *pOld, const SwRect &rOld, const SwRect* pOldPrt )
{ const SwRect aFrame( pFly->GetObjRectWithSpaces() ); if ( rOld.Pos() != aFrame.Pos() )
{ // changed position, invalidate old and new area if (rOld.HasArea()
&& rOld.Left() + pFly->GetFormat()->GetLRSpace().ResolveLeft({}) < FAR_AWAY)
{
pFly->NotifyBackground( pOld, rOld, PrepareHint::FlyFrameLeave );
}
pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PrepareHint::FlyFrameArrive );
} elseif ( rOld.SSize() != aFrame.SSize() )
{ // changed size, invalidate the area that was left or is now overlapped // For simplicity, we purposely invalidate a Twip even if not needed.
if (eHint == PrepareHint::FlyFrameArrive)
{
SwTwips nLower = pTextFrame->GetLowerMarginForFlyIntersect(); if (nLower > 0)
{
aCntPrt.AddBottom(nLower);
}
}
if ( eHint == PrepareHint::FlyFrameAttributesChanged )
{ // #i35640# - use given rectangle <rRect> instead // of current bound rectangle if ( aCntPrt.Overlaps( rRect ) )
pCnt->Prepare( PrepareHint::FlyFrameAttributesChanged );
} // #i23129# - only invalidate, if the text frame // printing area overlaps with the given rectangle. elseif ( aCntPrt.Overlaps( rRect ) )
pCnt->Prepare( eHint, static_cast<void*>(&aCntPrt.Intersection_( rRect )) ); if ( !pCnt->GetDrawObjs() ) return;
const SwSortedObjs &rObjs = *pCnt->GetDrawObjs(); for (SwAnchoredObject* pObj : rObjs)
{ if ( auto pFly = pObj->DynCastFlyFrame() )
{ if ( pFly->IsFlyInContentFrame() )
{
SwContentFrame *pContent = pFly->ContainsContent(); while ( pContent )
{
::lcl_NotifyContent( pThis, pContent, rRect, eHint );
pContent = pContent->GetNextContentFrame();
}
}
}
}
}
void Notify_Background( const SdrObject* pObj,
SwPageFrame* pPage, const SwRect& rRect, const PrepareHint eHint, constbool bInva )
{ // If the frame was positioned correctly for the first time, do not inform the old area if ( eHint == PrepareHint::FlyFrameLeave && rRect.Top() == FAR_AWAY ) return;
// Only the Flys following this anchor are reacting. Thus, those do not // need to be processed. // An exception is LEAVE, since the Fly might come "from above". // If the anchor is positioned on the previous page, the whole page // needs to be processed (47722). // OD 2004-05-13 #i28701# - If the wrapping style has to be considered // on the object positioning, the complete area has to be processed, // because content frames before the anchor frame also have to consider // the object for the text wrapping. // #i3317# - The complete area has always been // processed.
{
pCnt = pArea->ContainsContent();
}
}
SwFrame *pLastTab = nullptr;
bool isValidTableBeforeAnchor(false); while ( pCnt && pArea && pArea->IsAnLower( pCnt ) )
{
::lcl_NotifyContent( pObj, pCnt, rRect, eHint ); if ( pCnt->IsInTab() )
{
SwTabFrame *pTab = pCnt->FindTabFrame(); if ( pTab != pLastTab )
{
pLastTab = pTab;
isValidTableBeforeAnchor = false; if (PrepareHint::FlyFrameArrive == eHint
&& pFlyFrame // TODO: do it for draw objects too?
&& pTab->IsFollow() // table starts on previous page? // "through" means they will actually overlap anyway
&& css::text::WrapTextMode_THROUGH != pFlyFrame->GetFormat()->GetSurround().GetSurround() // if it's anchored in footer it can't move to other page
&& !pAnchor->FindFooterOrHeader())
{
SwFrame * pTmp(pAnchor->GetPrev()); while (pTmp)
{ if (pTmp == pTab)
{ // tdf#99460 the table shouldn't be moved by the fly
isValidTableBeforeAnchor = true; break;
}
pTmp = pTmp->GetPrev();
}
} // #i40606# - use <GetLastBoundRect()> // instead of <GetCurrentBoundRect()>, because a recalculation // of the bounding rectangle isn't intended here. if (!isValidTableBeforeAnchor
&& (pTab->getFrameArea().Overlaps(SwRect(pObj->GetLastBoundRect())) ||
pTab->getFrameArea().Overlaps(rRect)))
{ if ( !pFlyFrame || !pFlyFrame->IsLowerOf( pTab ) )
pTab->InvalidatePrt();
}
}
SwLayoutFrame* pCell = pCnt->GetUpper(); // #i40606# - use <GetLastBoundRect()> // instead of <GetCurrentBoundRect()>, because a recalculation // of the bounding rectangle isn't intended here. if (!isValidTableBeforeAnchor && pCell->IsCellFrame() &&
( pCell->getFrameArea().Overlaps( SwRect(pObj->GetLastBoundRect()) ) ||
pCell->getFrameArea().Overlaps( rRect ) ) )
{ const SwFormatVertOrient &rOri = pCell->GetFormat()->GetVertOrient(); if ( text::VertOrientation::NONE != rOri.GetVertOrient() )
pCell->InvalidatePrt();
}
}
pCnt = pCnt->GetNextContentFrame();
} // #128702# - make code robust if ( pPage && pPage->GetSortedObjs() )
{
pObj->GetOrdNum(); const SwSortedObjs &rObjs = *pPage->GetSortedObjs(); for (SwAnchoredObject* pAnchoredObj : rObjs)
{ if ( pAnchoredObj->DynCastFlyFrame() != nullptr )
{ if( pAnchoredObj->GetDrawObj() == pObj ) continue;
SwFlyFrame *pFly = static_cast<SwFlyFrame*>(pAnchoredObj); if ( pFly->getFrameArea().Top() == FAR_AWAY ) continue;
if ( !pFlyFrame ||
(!pFly->IsLowerOf( pFlyFrame ) &&
pFly->GetVirtDrawObj()->GetOrdNumDirect() < pObj->GetOrdNumDirect()))
{
pCnt = pFly->ContainsContent(); while ( pCnt )
{
::lcl_NotifyContent( pObj, pCnt, rRect, eHint );
pCnt = pCnt->GetNextContentFrame();
}
} if( pFly->IsFlyLayFrame() )
{
SwFrame* pLower = pFly->Lower(); if( pLower && pLower->IsColumnFrame() &&
pFly->getFrameArea().Bottom() >= rRect.Top() &&
pFly->getFrameArea().Top() <= rRect.Bottom() &&
pFly->getFrameArea().Right() >= rRect.Left() &&
pFly->getFrameArea().Left() <= rRect.Right() )
{
pFly->InvalidateSize();
}
} // Flys above myself might sidestep if they have an automatic // alignment. This happens independently of my attributes since // this might have been changed as well. elseif ( pFly->IsFlyAtContentFrame() &&
pObj->GetOrdNumDirect() <
pFly->GetVirtDrawObj()->GetOrdNumDirect() &&
pFlyFrame && !pFly->IsLowerOf( pFlyFrame ) )
{ const SwFormatHoriOrient &rH = pFly->GetFormat()->GetHoriOrient(); if ( text::HoriOrientation::NONE != rH.GetHoriOrient() &&
text::HoriOrientation::CENTER != rH.GetHoriOrient() &&
( !pFly->IsAutoPos() || text::RelOrientation::CHAR != rH.GetRelationOrient() ) &&
(pFly->getFrameArea().Bottom() >= rRect.Top() &&
pFly->getFrameArea().Top() <= rRect.Bottom()) )
pFly->InvalidatePos();
}
}
}
} if ( pFlyFrame && pAnchor->GetUpper() && pAnchor->IsInTab() )//MA_FLY_HEIGHT
pAnchor->GetUpper()->InvalidateSize();
// The border cannot be calculated based on PrtArea and Frame, since both can be invalid.
SwBorderAttrAccess aAccess( SwFrame::GetCache(), pCell ); const SwBorderAttrs &rAttrs = *aAccess.Get();
nHeight += rAttrs.CalcTop() + rAttrs.CalcBottom();
if (pViewPosAndCalcFrame->second)
{ // tdf#108118 prevent recursion
DisableCallbackAction a(*pTmpFrame->getRootFrame()); // - format parent Writer // fly frame, if it isn't been formatted yet. // Note: The Writer fly frame could be the frame itself.
SwFlyFrame* pFlyFrame( pTmpFrame->FindFlyFrame() ); if ( pFlyFrame &&
pFlyFrame->getFrameArea().Pos().X() == FAR_AWAY &&
pFlyFrame->getFrameArea().Pos().Y() == FAR_AWAY )
{
SwObjectFormatter::FormatObj( *pFlyFrame );
}
pTmpFrame->Calc(pLayout ? pLayout->GetCurrShell()->GetOut() : nullptr);
}
// aIter.IsChanged checks if the current pTmpFrame has been deleted while // it is the current iterator // FrameHolder watches for deletion of the current pMinFrame if( aIter.IsChanged() || ( aHolder.IsSet() && !aHolder.GetFrame() ) )
{ // restart iteration
bClientIterChanged = true; break;
}
// for Flys go via the parent if the Fly is not yet "formatted" if (!pViewPosAndCalcFrame->second &&
pTmpFrame->GetType() & SwFrameType::Fly && static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame() &&
FAR_AWAY == pTmpFrame->getFrameArea().Pos().getX() &&
FAR_AWAY == pTmpFrame->getFrameArea().Pos().getY() )
aCalcRect = static_cast<SwFlyFrame*>(pTmpFrame)->GetAnchorFrame()->getFrameArea(); else
aCalcRect = pTmpFrame->getFrameArea();
if (aCalcRect.Contains(pViewPosAndCalcFrame->first))
{
pMinFrame = pTmpFrame; break;
}
// Point not in rectangle. Compare distances: const Point aCalcRectCenter = aCalcRect.Center(); const Point aDiff = aCalcRectCenter - pViewPosAndCalcFrame->first; const sal_uInt64 nCurrentDist = CalcCurrentDist(aDiff.getX(), aDiff.getY()); if ( !pMinFrame || nCurrentDist < nMinDist )
{
pMinFrame = pTmpFrame;
nMinDist = nCurrentDist;
}
} else
{ // if no pViewPosAndCalcFrame is provided, take the first one
pMinFrame = pTmpFrame; break;
}
}
}
} while( bClientIterChanged );
if( pPos && pMinFrame && pMinFrame->IsTextFrame() )
{
SwTextFrame * pAtPos(static_cast<SwTextFrame*>(pMinFrame)->GetFrameAtPos(*pPos)); if (!pViewPosAndCalcFrame)
{ return pAtPos;
}
TextFrameIndex nPos(pAtPos->MapModelToViewPos(*pPos));
SwPageFrame const*const pPage(pAtPos->getRootFrame()->GetPageAtPos(
pViewPosAndCalcFrame->first, nullptr, true));
SwFrame * pOnPage(pAtPos); // if all else fails return first one
++nPos; // follow field portions are on follow frames that have mnOffset // already incremented past the field, need to check that index too while (pAtPos && pAtPos->GetOffset() <= nPos)
{ if (pAtPos->getFrameArea().Contains(pViewPosAndCalcFrame->first))
{ return pAtPos;
} if (pAtPos->FindPageFrame() == pPage)
{
pOnPage = pAtPos;
}
pAtPos = pAtPos->GetFollow();
} return pOnPage;
}
const SwFrame* pLowerFrame = Lower(); while ( pLowerFrame )
{ // Note: independent on text direction page header and page footer are // always at top respectively at bottom of the page frame. if ( pLowerFrame->IsHeaderFrame() )
{
aPrtWithoutHeaderFooter.AddTop( pLowerFrame->getFrameArea().Height() );
} if ( pLowerFrame->IsFooterFrame() )
{
aPrtWithoutHeaderFooter.AddBottom( - pLowerFrame->getFrameArea().Height() );
}
pLowerFrame = pLowerFrame->GetNext();
}
return aPrtWithoutHeaderFooter;
}
/** method to determine the spacing values of a frame
OD 2004-03-10 #i28701# OD 2009-08-28 #i102458# Add output parameter <obIsLineSpacingProportional>
*/ void GetSpacingValuesOfFrame( const SwFrame& rFrame,
SwTwips& onLowerSpacing,
SwTwips& onLineSpacing, bool& obIsLineSpacingProportional, bool bIdenticalStyles )
{ if ( !rFrame.IsFlowFrame() )
{
onLowerSpacing = 0;
onLineSpacing = 0;
} else
{ const SvxULSpaceItem& rULSpace = rFrame.GetAttrSet()->GetULSpace(); // check contextual spacing if the style of actual and next paragraphs are identical if (bIdenticalStyles)
onLowerSpacing = (rULSpace.GetContext() ? 0 : rULSpace.GetLower()); else
onLowerSpacing = rULSpace.GetLower();
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.