/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* This file incorporates work covered by the following license notice:
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed
* with this work for additional information regarding copyright
* ownership. The ASF licenses this file to you under the Apache
* License, Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a copy of
* the License at http://www.apache.org/licenses/LICENSE-2.0 .
*/
#include <sal/config.h>
#include <o3tl/safeint.hxx>
#include <svx/svdmodel.hxx>
#include <svx/svdpage.hxx>
#include <drawdoc.hxx>
#include <fmtpdsc.hxx>
#include <swtable.hxx>
#include <rootfrm.hxx>
#include <pagefrm.hxx>
#include <dflyobj.hxx>
#include <frmtool.hxx>
#include "virtoutp.hxx"
#include <blink.hxx>
#include <sectfrm.hxx>
#include <notxtfrm.hxx>
#include <pagedesc.hxx>
#include <viewimp.hxx>
#include <hints.hxx>
#include <viewopt.hxx>
#include <set>
#include <IDocumentSettingAccess.hxx>
#include <IDocumentFieldsAccess.hxx>
#include <DocumentLayoutManager.hxx>
#include <ndindex.hxx>
SwLayVout *SwRootFrame::s_pVout = nullptr;
bool SwRootFrame::s_isInPaint = false;
bool SwRootFrame::s_isNoVirDev = false;
SwCache *SwFrame::mpCache = nullptr;
long FirstMinusSecond( long nFirst, long nSecond )
{ return nFirst - nSecond; }
long SecondMinusFirst( long nFirst, long nSecond )
{ return nSecond - nFirst; }
long SwIncrement( long nA, long nAdd )
{ return nA + nAdd; }
long SwDecrement( long nA, long nSub )
{ return nA - nSub; }
static SwRectFnCollection aHorizontal = {
/*.fnGetTop =*/&SwRect::Top_,
/*.fnGetBottom =*/&SwRect::Bottom_,
/*.fnGetLeft =*/&SwRect::Left_,
/*.fnGetRight =*/&SwRect::Right_,
/*.fnGetWidth =*/&SwRect::Width_,
/*.fnGetHeight =*/&SwRect::Height_,
/*.fnGetPos =*/&SwRect::TopLeft,
/*.fnGetSize =*/&SwRect::Size_,
/*.fnSetTop =*/&SwRect::Top_,
/*.fnSetBottom =*/&SwRect::Bottom_,
/*.fnSetLeft =*/&SwRect::Left_,
/*.fnSetRight =*/&SwRect::Right_,
/*.fnSetWidth =*/&SwRect::Width_,
/*.fnSetHeight =*/&SwRect::Height_,
/*.fnSubTop =*/&SwRect::SubTop,
/*.fnAddBottom =*/&SwRect::AddBottom,
/*.fnSubLeft =*/&SwRect::SubLeft,
/*.fnAddRight =*/&SwRect::AddRight,
/*.fnAddWidth =*/&SwRect::AddWidth,
/*.fnAddHeight =*/&SwRect::AddHeight,
/*.fnSetPosX =*/&SwRect::SetPosX,
/*.fnSetPosY =*/&SwRect::SetPosY,
/*.fnGetTopMargin =*/&SwFrame::GetTopMargin,
/*.fnGetBottomMargin =*/&SwFrame::GetBottomMargin,
/*.fnGetLeftMargin =*/&SwFrame::GetLeftMargin,
/*.fnGetRightMargin =*/&SwFrame::GetRightMargin,
/*.fnSetXMargins =*/&SwFrame::SetLeftRightMargins,
/*.fnSetYMargins =*/&SwFrame::SetTopBottomMargins,
/*.fnGetPrtTop =*/&SwFrame::GetPrtTop,
/*.fnGetPrtBottom =*/&SwFrame::GetPrtBottom,
/*.fnGetPrtLeft =*/&SwFrame::GetPrtLeft,
/*.fnGetPrtRight =*/&SwFrame::GetPrtRight,
/*.fnTopDist =*/&SwRect::GetTopDistance,
/*.fnBottomDist =*/&SwRect::GetBottomDistance,
/*.fnLeftDist =*/&SwRect::GetLeftDistance,
/*.fnRightDist =*/&SwRect::GetRightDistance,
/*.fnSetLimit =*/&SwFrame::SetMaxBottom,
/*.fnOverStep =*/&SwRect::OverStepBottom,
/*.fnSetPos =*/&SwRect::SetUpperLeftCorner,
/*.fnMakePos =*/&SwFrame::MakeBelowPos,
/*.fnXDiff =*/&FirstMinusSecond,
/*.fnYDiff =*/&FirstMinusSecond,
/*.fnXInc =*/&SwIncrement,
/*.fnYInc =*/&o3tl::saturating_add<long>,
/*.fnSetLeftAndWidth =*/&SwRect::SetLeftAndWidth,
/*.fnSetTopAndHeight =*/&SwRect::SetTopAndHeight
};
static SwRectFnCollection aVertical = {
/*.fnGetTop =*/&SwRect::Right_,
/*.fnGetBottom =*/&SwRect::Left_,
/*.fnGetLeft =*/&SwRect::Top_,
/*.fnGetRight =*/&SwRect::Bottom_,
/*.fnGetWidth =*/&SwRect::Height_,
/*.fnGetHeight =*/&SwRect::Width_,
/*.fnGetPos =*/&SwRect::TopRight,
/*.fnGetSize =*/&SwRect::SwappedSize,
/*.fnSetTop =*/&SwRect::Right_,
/*.fnSetBottom =*/&SwRect::Left_,
/*.fnSetLeft =*/&SwRect::Top_,
/*.fnSetRight =*/&SwRect::Bottom_,
/*.fnSetWidth =*/&SwRect::Height_,
/*.fnSetHeight =*/&SwRect::Width_,
/*.fnSubTop =*/&SwRect::AddRight,
/*.fnAddBottom =*/&SwRect::SubLeft,
/*.fnSubLeft =*/&SwRect::SubTop,
/*.fnAddRight =*/&SwRect::AddBottom,
/*.fnAddWidth =*/&SwRect::AddHeight,
/*.fnAddHeight =*/&SwRect::AddWidth,
/*.fnSetPosX =*/&SwRect::SetPosY,
/*.fnSetPosY =*/&SwRect::SetPosX,
/*.fnGetTopMargin =*/&SwFrame::GetRightMargin,
/*.fnGetBottomMargin =*/&SwFrame::GetLeftMargin,
/*.fnGetLeftMargin =*/&SwFrame::GetTopMargin,
/*.fnGetRightMargin =*/&SwFrame::GetBottomMargin,
/*.fnSetXMargins =*/&SwFrame::SetTopBottomMargins,
/*.fnSetYMargins =*/&SwFrame::SetRightLeftMargins,
/*.fnGetPrtTop =*/&SwFrame::GetPrtRight,
/*.fnGetPrtBottom =*/&SwFrame::GetPrtLeft,
/*.fnGetPrtLeft =*/&SwFrame::GetPrtTop,
/*.fnGetPrtRight =*/&SwFrame::GetPrtBottom,
/*.fnTopDist =*/&SwRect::GetRightDistance,
/*.fnBottomDist =*/&SwRect::GetLeftDistance,
/*.fnLeftDist =*/&SwRect::GetTopDistance,
/*.fnRightDist =*/&SwRect::GetBottomDistance,
/*.fnSetLimit =*/&SwFrame::SetMinLeft,
/*.fnOverStep =*/&SwRect::OverStepLeft,
/*.fnSetPos =*/&SwRect::SetUpperRightCorner,
/*.fnMakePos =*/&SwFrame::MakeLeftPos,
/*.fnXDiff =*/&FirstMinusSecond,
/*.fnYDiff =*/&SecondMinusFirst,
/*.fnXInc =*/&SwIncrement,
/*.fnYInc =*/&SwDecrement,
/*.fnSetLeftAndWidth =*/&SwRect::SetTopAndHeight,
/*.fnSetTopAndHeight =*/&SwRect::SetRightAndWidth
};
static SwRectFnCollection aVerticalLeftToRight = {
/*.fnGetTop =*/&SwRect::Left_,
/*.fnGetBottom =*/&SwRect::Right_,
/*.fnGetLeft =*/&SwRect::Top_,
/*.fnGetRight =*/&SwRect::Bottom_,
/*.fnGetWidth =*/&SwRect::Height_,
/*.fnGetHeight =*/&SwRect::Width_,
/*.fnGetPos =*/&SwRect::TopLeft,
/*.fnGetSize =*/&SwRect::SwappedSize,
/*.fnSetTop =*/&SwRect::Left_,
/*.fnSetBottom =*/&SwRect::Right_,
/*.fnSetLeft =*/&SwRect::Top_,
/*.fnSetRight =*/&SwRect::Bottom_,
/*.fnSetWidth =*/&SwRect::Height_,
/*.fnSetHeight =*/&SwRect::Width_,
/*.fnSubTop =*/&SwRect::SubLeft,
/*.fnAddBottom =*/&SwRect::AddRight,
/*.fnSubLeft =*/&SwRect::SubTop,
/*.fnAddRight =*/&SwRect::AddBottom,
/*.fnAddWidth =*/&SwRect::AddHeight,
/*.fnAddHeight =*/&SwRect::AddWidth,
/*.fnSetPosX =*/&SwRect::SetPosY,
/*.fnSetPosY =*/&SwRect::SetPosX,
/*.fnGetTopMargin =*/&SwFrame::GetLeftMargin,
/*.fnGetBottomMargin =*/&SwFrame::GetRightMargin,
/*.fnGetLeftMargin =*/&SwFrame::GetTopMargin,
/*.fnGetRightMargin =*/&SwFrame::GetBottomMargin,
/*.fnSetXMargins =*/&SwFrame::SetTopBottomMargins,
/*.fnSetYMargins =*/&SwFrame::SetLeftRightMargins,
/*.fnGetPrtTop =*/&SwFrame::GetPrtLeft,
/*.fnGetPrtBottom =*/&SwFrame::GetPrtRight,
/*.fnGetPrtLeft =*/&SwFrame::GetPrtTop,
/*.fnGetPrtRight =*/&SwFrame::GetPrtBottom,
/*.fnTopDist =*/&SwRect::GetLeftDistance,
/*.fnBottomDist =*/&SwRect::GetRightDistance,
/*.fnLeftDist =*/&SwRect::GetTopDistance,
/*.fnRightDist =*/&SwRect::GetBottomDistance,
/*.fnSetLimit =*/&SwFrame::SetMaxRight,
/*.fnOverStep =*/&SwRect::OverStepRight,
/*.fnSetPos =*/&SwRect::SetUpperLeftCorner,
/*.fnMakePos =*/&SwFrame::MakeRightPos,
/*.fnXDiff =*/&FirstMinusSecond,
/*.fnYDiff =*/&FirstMinusSecond,
/*.fnXInc =*/&SwIncrement,
/*.fnYInc =*/&SwIncrement,
/*.fnSetLeftAndWidth =*/&SwRect::SetTopAndHeight,
/*.fnSetTopAndHeight =*/&SwRect::SetLeftAndWidth
};
SwRectFn fnRectHori = &aHorizontal;
SwRectFn fnRectVert = &aVertical;
SwRectFn fnRectVertL2R = &aVerticalLeftToRight;
// #i65250#
sal_uInt32 SwFrame::mnLastFrameId=0;
void FrameInit()
{
SwRootFrame::s_pVout = new SwLayVout();
SwCache *pNew = new SwCache( 100
#ifdef DBG_UTIL
, "static SwBorderAttrs::pCache"
#endif
);
SwFrame::SetCache( pNew );
}
void FrameFinit()
{
#if OSL_DEBUG_LEVEL > 0
// The cache may only contain null pointers at this time.
for( size_t n = SwFrame::GetCachePtr()->size(); n; )
if( (*SwFrame::GetCachePtr())[ --n ] )
{
SwCacheObj* pObj = (*SwFrame::GetCachePtr())[ n ];
OSL_ENSURE( !pObj, "Who didn't deregister?");
}
#endif
delete SwRootFrame::s_pVout;
delete SwFrame::GetCachePtr();
}
// RootFrame::Everything that belongs to CurrShell
CurrShell::CurrShell( SwViewShell *pNew )
{
OSL_ENSURE( pNew, "insert 0-Shell?" );
pRoot = pNew->GetLayout();
if ( pRoot )
{
pPrev = pRoot->mpCurrShell;
pRoot->mpCurrShell = pNew;
pRoot->mpCurrShells->insert( this );
}
else
pPrev = nullptr;
}
CurrShell::~CurrShell()
{
if ( pRoot )
{
pRoot->mpCurrShells->erase( this );
if ( pPrev )
pRoot->mpCurrShell = pPrev;
if ( pRoot->mpCurrShells->empty() && pRoot->mpWaitingCurrShell )
{
pRoot->mpCurrShell = pRoot->mpWaitingCurrShell;
pRoot->mpWaitingCurrShell = nullptr;
}
}
}
void SetShell( SwViewShell *pSh )
{
SwRootFrame *pRoot = pSh->GetLayout();
if ( pRoot->mpCurrShells->empty() )
pRoot->mpCurrShell = pSh;
else
pRoot->mpWaitingCurrShell = pSh;
}
void SwRootFrame::DeRegisterShell( SwViewShell *pSh )
{
// Activate some shell if possible
if ( mpCurrShell == pSh )
{
mpCurrShell = nullptr;
for(SwViewShell& rShell : pSh->GetRingContainer())
{
if(&rShell != pSh)
{
mpCurrShell = &rShell;
break;
}
}
}
// Doesn't matter anymore
if ( mpWaitingCurrShell == pSh )
mpWaitingCurrShell = nullptr;
// Remove references
for ( SwCurrShells::iterator it = mpCurrShells->begin(); it != mpCurrShells->end(); ++it )
{
CurrShell *pC = *it;
if (pC->pPrev == pSh)
pC->pPrev = nullptr;
}
}
void InitCurrShells( SwRootFrame *pRoot )
{
pRoot->mpCurrShells.reset( new SwCurrShells );
}
/*
|* The RootFrame requests an own FrameFormat from the document, which it is
|* going to delete again in the dtor. The own FrameFormat is derived from
|* the passed FrameFormat.
|*/
SwRootFrame::SwRootFrame( SwFrameFormat *pFormat, SwViewShell * pSh ) :
SwLayoutFrame( pFormat->GetDoc()->MakeFrameFormat(
"Root", pFormat ), nullptr ),
maPagesArea(),
mnViewWidth( -1 ),
mnColumns( 0 ),
mbBookMode( false ),
mbSidebarChanged( false ),
mbNeedGrammarCheck( false ),
mbCheckSuperfluous( false ),
mbIdleFormat( true ),
mbBrowseWidthValid( false ),
mbTurboAllowed( true ),
mbAssertFlyPages( true ),
mbIsVirtPageNum( false ),
mbIsNewLayout( true ),
mbCallbackActionEnabled ( false ),
mbLayoutFreezed ( false ),
mbHideRedlines( false ),
mnBrowseWidth(MIN_BROWSE_WIDTH),
mpTurbo( nullptr ),
mpLastPage( nullptr ),
mpCurrShell( pSh ),
mpWaitingCurrShell( nullptr ),
mpDrawPage( nullptr ),
mnPhyPageNums( 0 ),
mnAccessibleShells( 0 )
{
mnFrameType = SwFrameType::Root;
setRootFrame( this );
}
void SwRootFrame::Init( SwFrameFormat* pFormat )
{
InitCurrShells( this );
IDocumentTimerAccess& rTimerAccess = pFormat->getIDocumentTimerAccess();
IDocumentLayoutAccess& rLayoutAccess = pFormat->getIDocumentLayoutAccess();
IDocumentFieldsAccess& rFieldsAccess = pFormat->getIDocumentFieldsAccess();
const IDocumentSettingAccess& rSettingAccess = pFormat->getIDocumentSettingAccess();
rTimerAccess.StopIdling();
// For creating the Flys by MakeFrames()
rLayoutAccess.SetCurrentViewShell( GetCurrShell() );
mbCallbackActionEnabled = false; // needs to be set to true before leaving!
SwDrawModel* pMd = pFormat->getIDocumentDrawModelAccess().GetDrawModel();
if ( pMd )
{
// Disable "multiple layout"
mpDrawPage = pMd->GetPage(0);
mpDrawPage->SetSize( getFrameArea().SSize() );
}
// Initialize the layout: create pages, link content with Content etc.
// First, initialize some stuff, then get hold of the first
// node (which will be needed for the PageDesc).
SwDoc* pDoc = pFormat->GetDoc();
SwNodeIndex aIndex( *pDoc->GetNodes().GetEndOfContent().StartOfSectionNode() );
SwContentNode *pNode = pDoc->GetNodes().GoNextSection( &aIndex, true, false );
// #123067# pNode = 0 can really happen
SwTableNode *pTableNd= pNode ? pNode->FindTableNode() : nullptr;
// Get hold of PageDesc (either via FrameFormat of the first node or the initial one).
SwPageDesc *pDesc = nullptr;
::boost::optional<sal_uInt16> oPgNum;
if ( pTableNd )
{
const SwFormatPageDesc &rDesc = pTableNd->GetTable().GetFrameFormat()->GetPageDesc();
pDesc = const_cast<SwPageDesc*>(rDesc.GetPageDesc());
//#19104# respect the page number offset!!
oPgNum = rDesc.GetNumOffset();
if (oPgNum)
mbIsVirtPageNum = true;
}
else if ( pNode )
{
const SwFormatPageDesc &rDesc = pNode->GetSwAttrSet().GetPageDesc();
pDesc = const_cast<SwPageDesc*>(rDesc.GetPageDesc());
//#19104# respect the page number offset!!
oPgNum = rDesc.GetNumOffset();
if (oPgNum)
mbIsVirtPageNum = true;
}
else
mbIsVirtPageNum = false;
if ( !pDesc )
pDesc = &pDoc->GetPageDesc( 0 );
const bool bOdd = !oPgNum || 0 != ( oPgNum.get() % 2 );
const bool bFirst = true;
// Even page numbers are supposed to be printed as left pages. So if a
// page number has been explicitly set for this first page, then we must
// insert a blank page before it to make it a left page.
const bool bInsertEmpty = !bOdd;
// Create a page and put it in the layout
SwPageFrame *pPage = ::InsertNewPage( *pDesc, this, bOdd, bFirst, bInsertEmpty, false, nullptr );
// Find the first page in the Bodytext section.
SwLayoutFrame *pLay = pPage->FindBodyCont();
while( pLay->Lower() )
pLay = static_cast<SwLayoutFrame*>(pLay->Lower());
SwNodeIndex aTmp( *pDoc->GetNodes().GetEndOfContent().StartOfSectionNode(), 1 );
::InsertCnt_( pLay, pDoc, aTmp.GetIndex(), true );
//Remove masters that haven't been replaced yet from the list.
RemoveMasterObjs( mpDrawPage );
if( rSettingAccess.get(DocumentSettingId::GLOBAL_DOCUMENT) )
rFieldsAccess.UpdateRefFields();
//b6433357: Update page fields after loading
if ( !mpCurrShell || !mpCurrShell->Imp()->IsUpdateExpFields() )
{
SwDocPosUpdate aMsgHint( pPage->getFrameArea().Top() );
rFieldsAccess.UpdatePageFields( &aMsgHint );
}
rTimerAccess.StartIdling();
mbCallbackActionEnabled = true;
SwViewShell *pViewSh = GetCurrShell();
if (pViewSh)
mbNeedGrammarCheck = pViewSh->GetViewOptions()->IsOnlineSpell();
}
void SwRootFrame::DestroyImpl()
{
mbTurboAllowed = false;
mpTurbo = nullptr;
if(pBlink)
pBlink->FrameDelete( this );
SwFrameFormat *pRegisteredInNonConst = static_cast<SwFrameFormat*>(GetDep());
if ( pRegisteredInNonConst )
{
SwDoc *pDoc = pRegisteredInNonConst->GetDoc();
pDoc->DelFrameFormat( pRegisteredInNonConst );
// do this before calling RemoveFootnotes() because footnotes
// can contain anchored objects
pDoc->GetDocumentLayoutManager().ClearSwLayouterEntries();
}
mpDestroy.reset();
// Remove references
for ( SwCurrShells::iterator it = mpCurrShells->begin(); it != mpCurrShells->end(); ++it )
(*it)->pRoot = nullptr;
mpCurrShells.reset();
// Some accessible shells are left => problems on second SwFrame::Destroy call
assert(0 == mnAccessibleShells);
// fdo#39510 crash on document close with footnotes
// Object ownership in writer and esp. in layout are a mess: Before the
// document/layout split SwDoc and SwRootFrame were essentially one object
// and magically/uncleanly worked around their common destruction by call
// to SwDoc::IsInDtor() -- even from the layout. As of now destruction of
// the layout proceeds forward through the frames. Since SwTextFootnote::DelFrames
// also searches backwards to find the master of footnotes, they must be
// considered to be owned by the SwRootFrame and also be destroyed here,
// before tearing down the (now footnote free) rest of the layout.
RemoveFootnotes(nullptr, false, true);
SwLayoutFrame::DestroyImpl();
}
SwRootFrame::~SwRootFrame()
{
}
void SwRootFrame::RemoveMasterObjs( SdrPage *pPg )
{
// Remove all master objects from the Page. But don't delete!
for( size_t i = pPg ? pPg->GetObjCount() : 0; i; )
{
SdrObject* pObj = pPg->GetObj( --i );
if( dynamic_cast< const SwFlyDrawObj *>( pObj ) != nullptr )
pPg->RemoveObject( i );
}
}
void SwRootFrame::AllCheckPageDescs() const
{
if ( !IsLayoutFreezed() )
CheckPageDescs( const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(Lower())) );
}
void SwRootFrame::AllInvalidateAutoCompleteWords() const
{
SwPageFrame *pPage = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(Lower()));
while ( pPage )
{
pPage->InvalidateAutoCompleteWords();
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
}
void SwRootFrame::AllAddPaintRect() const
{
GetCurrShell()->AddPaintRect( getFrameArea() );
}
void SwRootFrame::AllRemoveFootnotes()
{
RemoveFootnotes();
}
void SwRootFrame::AllInvalidateSmartTagsOrSpelling(bool bSmartTags) const
{
SwPageFrame *pPage = const_cast<SwPageFrame*>(static_cast<const SwPageFrame*>(Lower()));
while ( pPage )
{
if ( bSmartTags )
pPage->InvalidateSmartTags();
pPage->InvalidateSpelling();
pPage = static_cast<SwPageFrame*>(pPage->GetNext());
}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
↑ V1004 The 'pPg' pointer was used unsafely after it was verified against nullptr. Check lines: 515, 517.