/* -*- 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 #include #include #include #include #include #include #include #include #include #include "virtoutp.hxx" #include #include #include #include #include #include #include #include #include #include #include #include SwLayVout *SwRootFrame::s_pVout = nullptr; bool SwRootFrame::s_isInPaint = false; bool SwRootFrame::s_isNoVirDev = false; SwCache *SwFrame::mpCache = nullptr; static long FirstMinusSecond( long nFirst, long nSecond ) { return nFirst - nSecond; } static long SecondMinusFirst( long nFirst, long nSecond ) { return nSecond - nFirst; } static long SwIncrement( long nA, long nAdd ) { return nA + nAdd; } static 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, /*.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 }; /** * This is the same as horizontal, but rotated counter-clockwise by 90 degrees. * This means logical top is physical left, bottom is right, left is bottom, * finally right is top. Values map from logical to physical. */ static SwRectFnCollection aVerticalLeftToRightBottomToTop = { /*.fnGetTop =*/&SwRect::Left_, /*.fnGetBottom =*/&SwRect::Right_, /*.fnGetLeft =*/&SwRect::Bottom_, /*.fnGetRight =*/&SwRect::Top_, /*.fnGetWidth =*/&SwRect::Height_, /*.fnGetHeight =*/&SwRect::Width_, /*.fnGetPos =*/&SwRect::BottomLeft, /*.fnGetSize =*/&SwRect::SwappedSize, /*.fnSetTop =*/&SwRect::Left_, /*.fnSetBottom =*/&SwRect::Right_, /*.fnSetLeft =*/&SwRect::Bottom_, /*.fnSetRight =*/&SwRect::Top_, /*.fnSetWidth =*/&SwRect::Height_, /*.fnSetHeight =*/&SwRect::Width_, /*.fnSubTop =*/&SwRect::SubLeft, /*.fnAddBottom =*/&SwRect::AddRight, /*.fnSubLeft =*/&SwRect::AddBottom, /*.fnAddRight =*/&SwRect::SubTop, /*.fnAddWidth =*/&SwRect::AddHeight, /*.fnAddHeight =*/&SwRect::AddWidth, /*.fnSetPosX =*/&SwRect::SetPosY, /*.fnSetPosY =*/&SwRect::SetPosX, /*.fnGetTopMargin =*/&SwFrame::GetLeftMargin, /*.fnGetBottomMargin =*/&SwFrame::GetRightMargin, /*.fnGetLeftMargin =*/&SwFrame::GetBottomMargin, /*.fnGetRightMargin =*/&SwFrame::GetTopMargin, /*.fnSetXMargins =*/&SwFrame::SetTopBottomMargins, /*.fnSetYMargins =*/&SwFrame::SetLeftRightMargins, /*.fnGetPrtTop =*/&SwFrame::GetPrtLeft, /*.fnGetPrtBottom =*/&SwFrame::GetPrtRight, /*.fnGetPrtLeft =*/&SwFrame::GetPrtBottom, /*.fnGetPrtRight =*/&SwFrame::GetPrtTop, /*.fnTopDist =*/&SwRect::GetLeftDistance, /*.fnBottomDist =*/&SwRect::GetRightDistance, /*.fnLeftDist =*/&SwRect::GetBottomDistance, /*.fnRightDist =*/&SwRect::GetTopDistance, /*.fnSetLimit =*/&SwFrame::SetMaxRight, /*.fnOverStep =*/&SwRect::OverStepRight, /*.fnSetPos =*/&SwRect::SetLowerLeftCorner, /*.fnMakePos =*/&SwFrame::MakeRightPos, /*.fnXDiff =*/&SecondMinusFirst, /*.fnYDiff =*/&FirstMinusSecond, /*.fnXInc =*/&SwDecrement, /*.fnYInc =*/&SwIncrement, /*.fnSetLeftAndWidth =*/&SwRect::SetBottomAndHeight, /*.fnSetTopAndHeight =*/&SwRect::SetLeftAndWidth }; SwRectFn fnRectHori = &aHorizontal; SwRectFn fnRectVert = &aVertical; SwRectFn fnRectVertL2R = &aVerticalLeftToRight; SwRectFn fnRectVertL2RB2T = &aVerticalLeftToRightBottomToTop; // #i65250# sal_uInt32 SwFrameAreaDefinition::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 ( CurrShell *pC : *mpCurrShells ) { 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(pFormat->GetDoc()->GetDocumentRedlineManager().IsHideRedlines()), 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; ::std::optional oPgNum; if ( pTableNd ) { const SwFormatPageDesc &rDesc = pTableNd->GetTable().GetFrameFormat()->GetPageDesc(); pDesc = const_cast(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(rDesc.GetPageDesc()); //#19104# respect the page number offset!! oPgNum = rDesc.GetNumOffset(); if (oPgNum) mbIsVirtPageNum = true; } else mbIsVirtPageNum = false; if ( !pDesc ) pDesc = &pDoc->GetPageDesc( 0 ); // Create a page and put it in the layout // The first page is always a right-page and always a first-page SwPageFrame *pPage = ::InsertNewPage(*pDesc, this, true, true, false, false, nullptr, true); // Find the first page in the Bodytext section. SwLayoutFrame *pLay = pPage->FindBodyCont(); while( pLay->Lower() ) pLay = static_cast(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; SwFrameFormat *pRegisteredInNonConst = static_cast(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 ( auto& rpCurrShell : *mpCurrShells ) rpCurrShell->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(static_cast(Lower())) ); } void SwRootFrame::AllInvalidateAutoCompleteWords() const { SwPageFrame *pPage = const_cast(static_cast(Lower())); while ( pPage ) { pPage->InvalidateAutoCompleteWords(); pPage = static_cast(pPage->GetNext()); } } void SwRootFrame::AllAddPaintRect() const { GetCurrShell()->AddPaintRect( getFrameArea() ); } void SwRootFrame::AllRemoveFootnotes() { RemoveFootnotes(); } void SwRootFrame::AllInvalidateSmartTagsOrSpelling(bool bSmartTags) const { SwPageFrame *pPage = const_cast(static_cast(Lower())); while ( pPage ) { if ( bSmartTags ) pPage->InvalidateSmartTags(); pPage->InvalidateSpelling(); pPage = static_cast(pPage->GetNext()); } } /* vim:set shiftwidth=4 softtabstop=4 expandtab: */