/* -*- 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 .
*/
staticvoid
lcl_PaintTransparentFormControls(SwViewShell const & rShell, SwRect const& rRect)
{ // Direct paint has been performed: the background of transparent child // windows has been painted, so need to paint the child windows now. if (rShell.GetWin())
{
vcl::Window& rWindow = *(rShell.GetWin()); const tools::Rectangle aRectanglePixel(rShell.GetOut()->LogicToPixel(rRect.SVRect()));
PaintTransparentChildren(rWindow, aRectanglePixel);
}
}
// #i72754# 2nd set of Pre/PostPaints // This time it uses the lock counter (mPrePostPaintRegions empty/non-empty) to allow only one activation // and deactivation and mpPrePostOutDev to remember the OutDev from the BeginDrawLayers // call. That way, all places where paint take place can be handled the same way, even // when calling other paint methods. This is the case at the places where SW paints // buffered into VDevs to avoid flicker. It is in general problematic and should be // solved once using the BufferedOutput functionality of the DrawView.
void SwViewShell::PrePaint()
{ // forward PrePaint event from VCL Window to DrawingLayer if(HasDrawView())
{
Imp()->GetDrawView()->PrePaint();
}
}
void SwViewShell::DLPrePaint2(const vcl::Region& rRegion)
{ if(mPrePostPaintRegions.empty())
{
mPrePostPaintRegions.push( rRegion ); // #i75172# ensure DrawView to use DrawingLayer bufferings if ( !HasDrawView() )
MakeDrawView();
// Prefer window; if not available, get mpOut (e.g. printer) constbool bWindow = GetWin() && !comphelper::LibreOfficeKit::isActive() && !isOutputToWindow();
mpPrePostOutDev = bWindow ? GetWin()->GetOutDev() : GetOut();
// #i74769# use SdrPaintWindow now direct
mpTargetPaintWindow = Imp()->GetDrawView()->BeginDrawLayers(mpPrePostOutDev, rRegion);
assert(mpTargetPaintWindow && "BeginDrawLayers: Got no SdrPaintWindow (!)");
// #i74769# if prerender, save OutDev and redirect to PreRenderDevice if(mpTargetPaintWindow->GetPreRenderDevice())
{
mpBufferedOut = mpOut;
mpOut = &(mpTargetPaintWindow->GetTargetOutputDevice());
} elseif (isOutputToWindow()) // In case mpOut is used without buffering and we're not printing, need to set clipping.
mpOut->SetClipRegion(rRegion);
// remember original paint MapMode for wrapped FlyFrame paints
maPrePostMapMode = mpOut->GetMapMode();
} else
{ // region needs to be updated to the given one if( mPrePostPaintRegions.top() != rRegion )
Imp()->GetDrawView()->UpdateDrawLayersRegion(mpPrePostOutDev, rRegion);
mPrePostPaintRegions.push( rRegion );
}
}
// #i74769# use SdrPaintWindow now direct
SwViewObjectContactRedirector aSwRedirector(*this);
Imp()->GetDrawView()->EndDrawLayers(*mpTargetPaintWindow, bPaintFormLayer, &aSwRedirector);
mpTargetPaintWindow = nullptr;
}
} // end of Pre/PostPaints
if ( bIsShellForCheckViewLayout )
GetLayout()->CheckViewLayout( GetViewOptions(), &maVisArea );
//If we don't call Paints, we wait for the Paint of the system. //Then the clipping is set correctly; e.g. shifting of a Draw object if ( Imp()->HasPaintRegion() ||
maInvalidRect.HasArea() ||
bExtraData )
{ if ( !mnLockPaint )
{
SolarMutexGuard aGuard;
bool bPaintsFromSystem = maInvalidRect.HasArea();
GetWin()->PaintImmediately(); if ( maInvalidRect.HasArea() )
{ if ( bPaintsFromSystem )
Imp()->AddPaintRect( maInvalidRect );
//JP 27.11.97: what hid the selection, must also Show it, // else we get Paint errors! // e.g. additional mode, page half visible vertically, in the // middle a selection and with another cursor jump to left // right border. Without ShowCursor the selection disappears. bool bShowCursor = oRegion && dynamic_cast<const SwCursorShell*>(this) != nullptr; if( bShowCursor ) static_cast<SwCursorShell*>(this)->HideCursors();
if ( oRegion )
{
SwRootFrame* pCurrentLayout = GetLayout();
while ( !oRegion->empty() )
{
SwRect aRect( oRegion->back() );
oRegion->pop_back();
if (GetWin()->SupportsDoubleBuffering())
InvalidateWindows(aRect); else
{ // #i75172# begin DrawingLayer paint // need to do begin/end DrawingLayer preparation for each single rectangle of the // repaint region. I already tried to prepare only once for the whole Region. This // seems to work (and does technically) but fails with transparent objects. Since the // region given to BeginDrawLayers() defines the clip region for DrawingLayer paint, // transparent objects in the single rectangles will indeed be painted multiple times. if (!comphelper::LibreOfficeKit::isActive())
{
DLPrePaint2(vcl::Region(aRect.SVRect()));
}
if ( bPaintsFromSystem )
PaintDesktop(*GetOut(), aRect); if (!comphelper::LibreOfficeKit::isActive())
pCurrentLayout->PaintSwFrame( *mpOut, aRect ); else
pCurrentLayout->GetCurrShell()->InvalidateWindows(aRect);
// #i75172# end DrawingLayer paint if (!comphelper::LibreOfficeKit::isActive())
{
DLPostPaint2(true);
}
}
//We artificially end the action here to enable the automatic scrollbars //to adjust themselves correctly //EndAction sends a Notify, and that must call Start-/EndAction to //adjust the scrollbars correctly
--mnStartAction;
UISizeNotify();
++mnStartAction;
Imp()->UnlockPaint(); if (mpOut->IsLineColor())
pVout->SetLineColor( mpOut->GetLineColor() ); else
pVout->SetLineColor(); if (mpOut->IsFillColor())
pVout->SetFillColor( mpOut->GetFillColor() ); else
pVout->SetFillColor();
// #i72754# start Pre/PostPaint encapsulation before mpOut is changed to the buffering VDev const vcl::Region aRepaintRegion(VisArea().SVRect());
DLPrePaint2(aRepaintRegion);
namespace
{
std::string_view to_string(LockPaintReason eReason)
{ switch(eReason)
{ case LockPaintReason::ViewLayout: return"ViewLayout"; case LockPaintReason::OuterResize: return"OuterResize"; case LockPaintReason::Undo: return"Undo"; case LockPaintReason::Redo: return"Redo"; case LockPaintReason::OutlineFolding: return"OutlineFolding"; case LockPaintReason::EndSdrCreate: return"EndSdrCreate"; case LockPaintReason::SwLayIdle: return"SwLayIdle"; case LockPaintReason::InvalidateLayout: return"InvalidateLayout"; case LockPaintReason::StartDrag: return"StartDrag"; case LockPaintReason::DataChanged: return"DataChanged"; case LockPaintReason::InsertFrame: return"InsertFrame"; case LockPaintReason::GotoPage: return"GotoPage"; case LockPaintReason::InsertGraphic: return"InsertGraphic"; case LockPaintReason::SetZoom: return"SetZoom"; case LockPaintReason::ExampleFrame: return"ExampleFram";
} return"";
};
}
void SwViewShell::InvalidateAll(std::vector<LockPaintReason>& rReasons)
{
assert(!rReasons.empty() && "there must be a reason to InvalidateAll");
for (constauto& reason : rReasons)
SAL_INFO("sw.core", "InvalidateAll because of: " << to_string(reason));
if (comphelper::LibreOfficeKit::isActive())
{ // https://github.com/CollaboraOnline/online/issues/6379 // ditch OuterResize as a reason to invalidate all in the online case
std::erase(rReasons, LockPaintReason::OuterResize);
}
if (!rReasons.empty())
GetWin()->Invalidate(InvalidateFlags::Children);
rReasons.clear();
}
if(comphelper::LibreOfficeKit::isActive())
{ // If we are inside tiled painting, invalidations are ignored. // Ignore them right now to save work, but also to avoid the problem // that this state could be reset before FlushPendingLOKInvalidateTiles() // gets called. if(comphelper::LibreOfficeKit::isTiledPainting()) return; // First collect all invalidations and perform them only later, // otherwise the number of Invalidate() calls would be at least // O(n^2) if not worse. The problem is that if any change in a document // is made, SwEditShell::EndAllAction() is called, which calls EndAction() // for every view. And every view does it own handling of paint rectangles, // and then calls InvalidateWindows() based on that. On then this code // would call Invalidate() for all views for each rectangle. // So collect the rectangles, avoid duplicates (which there usually will // be many because of the repetitions), FlushPendingLOKInvalidateTiles() // will collect all rectangles from all related views, compress them // and only with those relatively few rectangle it'd call Invalidate() // for all views.
Imp()->AddPendingLOKInvalidation(rRect); return;
}
for(SwViewShell& rSh : GetRingContainer())
{ if ( rSh.GetWin() )
{ if ( rSh.IsPreview() )
::RepaintPagePreview( &rSh, rRect ); // In case of tiled rendering, invalidation is wanted even if // the rectangle is outside the visual area. elseif ( rSh.VisArea().Overlaps( rRect ) || comphelper::LibreOfficeKit::isActive() )
rSh.GetWin()->Invalidate( rRect.SVRect() );
}
}
}
void SwViewShell::FlushPendingLOKInvalidateTiles()
{
assert(comphelper::LibreOfficeKit::isActive());
SwRegionRects rects; for(SwViewShell& rSh : GetRingContainer())
{
std::vector<SwRect> tmpRects = rSh.Imp()->TakePendingLOKInvalidations();
rects.insert( rects.end(), tmpRects.begin(), tmpRects.end());
}
rects.Compress( SwRegionRects::CompressFuzzy ); if(rects.empty()) return; // This is basically the loop from SwViewShell::InvalidateWindows(). for(SwViewShell& rSh : GetRingContainer())
{ if ( rSh.GetWin() )
{ if ( rSh.IsPreview() )
{ for( const SwRect& rect : rects )
::RepaintPagePreview( &rSh, rect );
} else
{ for( const SwRect& rect : rects )
rSh.GetWin()->Invalidate( rect.SVRect() );
}
}
}
}
const SwRect& SwViewShell::VisArea() const
{ // when using the tiled rendering, consider the entire document as our // visible area return comphelper::LibreOfficeKit::isActive()? GetLayout()->getFrameArea(): maVisArea;
}
sal_uInt16 SwViewShell::GetNumPages() const
{ //It is possible that no layout exists when the method from //root-Ctor is called. return GetLayout() ? GetLayout()->GetPageNum() : 0;
}
/** * Forces update of each field. * It notifies all fields with pNewHt. If that is 0 (default), the field * type is sent (???). * @param[in] bCloseDB Passed in to GetDoc()->UpdateFields. [TODO] Purpose???
*/ void SwViewShell::UpdateFields(bool bCloseDB, bool bSetModified)
{
CurrShell aCurr( this );
/** update all charts for which any table exists */ void SwViewShell::UpdateAllCharts()
{
CurrShell aCurr( this ); // Start-/EndAction handled in the SwDoc-Method!
GetDoc()->UpdateAllCharts();
}
//No idle when printing is going on. for(const SwViewShell& rSh : GetRingContainer())
{ if ( !rSh.GetWin() ) return;
}
CurrShell aCurr( this );
#ifdef DBG_UTIL // If Test5 has been set, the IdleFormatter is disabled. if( mpOpt->IsTest5() ) return; #endif
{ // Preserve top of the text frame cache.
SwSaveSetLRUOfst aSaveLRU; // #125243# there are lots of stacktraces indicating that Imp() returns NULL // this SwViewShell seems to be invalid - but it's not clear why // this return is only a workaround!
OSL_ENSURE(Imp(), "SwViewShell already deleted?"); if(!Imp()) return;
SwLayIdle aIdle( GetLayout(), Imp() );
}
}
/** local method to invalidate/re-calculate positions of floating screen * objects (Writer fly frame and drawing objects), which are anchored * to paragraph or to character. #i11860#
*/ staticvoid lcl_InvalidateAllObjPos( SwViewShell &_rSh )
{
_rSh.StartAction();
/** Sets if paragraph and table spacing is added at bottom of table cells. * #106629# * @param[in] (bool) setting of the new value
*/ void SwViewShell::SetAddParaSpacingToTableCells( bool _bAddParaSpacingToTableCells )
{
IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess(); if (rIDSA.get(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells
|| rIDSA.get(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS) != _bAddParaSpacingToTableCells)
{
SwWait aWait( *GetDoc()->GetDocShell(), true );
rIDSA.set(DocumentSettingId::ADD_PARA_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells ); // note: the dialog can't change the value to indeterminate, so only false/false and true/true
rIDSA.set(DocumentSettingId::ADD_PARA_LINE_SPACING_TO_TABLE_CELLS, _bAddParaSpacingToTableCells ); const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
lcl_InvalidateAllContent( *this, nInv );
}
}
/** * Sets if former formatting of text lines with proportional line spacing should used. * #i11859# * @param[in] (bool) setting of the new value
*/ void SwViewShell::SetUseFormerLineSpacing( bool _bUseFormerLineSpacing )
{
IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess(); if ( rIDSA.get(DocumentSettingId::OLD_LINE_SPACING) != _bUseFormerLineSpacing )
{
SwWait aWait( *GetDoc()->GetDocShell(), true );
rIDSA.set(DocumentSettingId::OLD_LINE_SPACING, _bUseFormerLineSpacing ); const SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea;
lcl_InvalidateAllContent( *this, nInv );
}
}
/** * Sets IDocumentSettingAccess if former object positioning should be used. * #i11860# * @param[in] (bool) setting the new value
*/ void SwViewShell::SetUseFormerObjectPositioning( bool _bUseFormerObjPos )
{
IDocumentSettingAccess& rIDSA = getIDocumentSettingAccess(); if ( rIDSA.get(DocumentSettingId::USE_FORMER_OBJECT_POS) != _bUseFormerObjPos )
{
SwWait aWait( *GetDoc()->GetDocShell(), true );
rIDSA.set(DocumentSettingId::USE_FORMER_OBJECT_POS, _bUseFormerObjPos );
lcl_InvalidateAllObjPos( *this );
}
}
// we go for safe: get rid of the old font information, // when the printer resolution or zoom factor changes. // Init() and Reformat() are the safest locations.
pFntCache->Flush( );
void SwViewShell::CalcLayout()
{ // extremely likely to be a Bad Idea to call this without StartAction // (except the Page Preview apparently only has a non-subclassed ViewShell)
assert((typeid(*this) == typeid(SwViewShell)) || mnStartAction);
CurrShell aCurr( this );
SwWait aWait( *GetDoc()->GetDocShell(), true );
// Preserve top of the text frame cache.
SwSaveSetLRUOfst aSaveLRU;
//switch on Progress when none is running yet. constbool bEndProgress = SfxProgress::GetActiveProgress( GetDoc()->GetDocShell() ) == nullptr; if ( bEndProgress )
{
tools::Long nEndPage = GetLayout()->GetPageNum();
nEndPage += nEndPage * 10 / 100;
::StartProgress( STR_STATSTR_REFORMAT, 0, nEndPage, GetDoc()->GetDocShell() );
}
//the SetNewFieldLst() on the Doc was cut off and must be fetched again //(see flowfrm.cxx, txtfld.cxx) if ( aAction.IsExpFields() )
{
aAction.Reset();
aAction.SetPaint( false );
aAction.SetStatBar( true );
aAction.SetReschedule( true );
// Is someone spuriously rescheduling again?
SAL_WARN_IF(mbInEndAction, "sw.core", "Scrolling during EndAction");
//First get the old visible page, so we don't have to look //for it afterwards. const SwFrame *pOldPage = Imp()->GetFirstVisPage(GetWin()->GetOutDev());
//When there a PaintRegion still exists and the VisArea has changed, //the PaintRegion is at least by now obsolete. The PaintRegion can //have been created by RootFrame::PaintSwFrame. if ( !mbInEndAction &&
Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea() )
Imp()->DeletePaintRegion();
CurrShell aCurr( this );
bool bScrolled = false;
SwPostItMgr* pPostItMgr = GetPostItMgr();
if ( bFull )
GetWin()->Invalidate(); else
{ //Calculate amount to be scrolled. const tools::Long nXDiff = aPrevArea.Left() - VisArea().Left(); const tools::Long nYDiff = aPrevArea.Top() - VisArea().Top();
if( !nXDiff && !GetViewOptions()->getBrowseMode() &&
(!Imp()->HasDrawView() || !Imp()->GetDrawView()->IsGridVisible() ) )
{ // If possible, don't scroll the application background // (PaintDesktop). Also limit the left and right side of // the scroll range to the pages. const SwPageFrame *pPage = static_cast<SwPageFrame*>(GetLayout()->Lower()); if ( pPage->getFrameArea().Top() > pOldPage->getFrameArea().Top() )
pPage = static_cast<const SwPageFrame*>(pOldPage);
SwRect aBoth( VisArea() );
aBoth.Union( aPrevArea ); const SwTwips nBottom = aBoth.Bottom();
SwTwips nMinLeft = SAL_MAX_INT32;
SwTwips nMaxRight= 0;
{ // #i75172# To get a clean repaint, a new ObjectContact is needed here. Without, the // repaint would not be correct since it would use the wrong DrawPage visible region. // This repaint IS about painting something currently outside the visible part (!). // For that purpose, AddDeviceToPaintView is used which creates a new SdrPageViewWindow // and all the necessary stuff. It's not cheap, but necessary here. Alone because repaint // target really is NOT the current window. // Also will automatically NOT use PreRendering and overlay (since target is VirtualDevice) if(!HasDrawView())
MakeDrawView();
SdrView* pDrawView = GetDrawView();
pDrawView->AddDeviceToPaintView(*pVout, nullptr);
// clear mpWin during DLPrePaint2 to get paint preparation for mpOut, but set it again // immediately afterwards. There are many decisions in SW which imply that Printing // is used when mpWin == 0 (wrong but widely used).
vcl::Window* pOldWin = mpWin;
mpWin = nullptr;
DLPrePaint2(vcl::Region(aRect.SVRect()));
mpWin = pOldWin;
// end paint and destroy ObjectContact again
DLPostPaint2(true);
pDrawView->DeleteDeviceFromPaintView(*pVout);
}
mpOut = pOld;
maVisArea = aOldVis;
//Now shift in parts and copy the new Pixel from the virtual device.
// ?????????????????????? // or is it better to get the scrollfactor from the User // as option? // ??????????????????????
tools::Long lMaDelta = aPixSz.Height(); if ( std::abs(lYDiff) > ( maVisArea.Height() / 3 ) )
lMaDelta *= 6; else
lMaDelta *= 2;
//Catch exceptions, so that it doesn't look so surprising. //Can e.g. happen during Idle. //Unfortunately we must at any rate Paint the rectangles next to the pages, //as these are not painted at VisPortChgd. bool bBorderOnly = false; const SwRootFrame *pRoot = GetLayout(); if ( rRect.Top() > pRoot->getFrameArea().Bottom() )
{ const SwFrame *pPg = pRoot->Lower(); while ( pPg && pPg->GetNext() )
pPg = pPg->GetNext(); if ( !pPg || !pPg->getFrameArea().Overlaps( VisArea() ) )
bBorderOnly = true;
}
// PaintDesktop is split in two, this part is also used by PreviewPage void SwViewShell::PaintDesktop_(const SwRegionRects &rRegion)
{ if (DrawAppBackgroundBitmap(GetOut(), rRegion.GetOrigin())) return;
// OD 2004-04-23 #116347#
GetOut()->Push( vcl::PushFlags::FILLCOLOR|vcl::PushFlags::LINECOLOR );
GetOut()->SetLineColor();
for ( auto &rRgn : rRegion )
{ const tools::Rectangle aRectangle(rRgn.SVRect());
// #i93170# // Here we have a real Problem. On the one hand we have the buffering for paint // and overlay which needs an embracing pair of DLPrePaint2/DLPostPaint2 calls, // on the other hand the MapMode is not set correctly when this code is executed. // This is done in the users of this method, for each SWpage before painting it. // Since the MapMode is not correct here, the call to DLPostPaint2 will paint // existing FormControls due to the current MapMode.
// There are basically three solutions for this:
// (1) Set the MapMode correct, move the background painting to the users of // this code
// (2) Do no DLPrePaint2/DLPostPaint2 here; no SdrObjects are allowed to lie in // the desktop region. Disadvantage: the desktop will not be part of the // buffers, e.g. overlay. Thus, as soon as overlay will be used over the // desktop, it will not work.
// (3) expand DLPostPaint2 with a flag to signal if FormControl paints shall // be done or not
// Currently, (3) will be the best possible solution. It will keep overlay and // buffering intact and work without MapMode for single pages. In the medium // to long run, (1) will need to be used and the bool bPaintFormLayer needs // to be removed again
// #i68597# inform Drawinglayer about display change
DLPrePaint2(vcl::Region(aRectangle));
// #i75172# needed to move line/Fill color setters into loop since DLPrePaint2 // may exchange GetOut(), that's it's purpose. This happens e.g. at print preview.
GetOut()->SetFillColor( GetViewOptions()->GetAppBackgroundColor());
GetOut()->SetLineColor();
GetOut()->DrawRect(aRectangle);
if ( bRet )
{ //Unfortunately Start/EndAction won't help here, as the Paint originated //from GUI and so Clipping has been set against getting through. //Ergo: do it all yourself (see ImplEndAction()) if ( Imp()->HasPaintRegion() && Imp()->GetPaintRegion()->GetOrigin() != VisArea())
Imp()->DeletePaintRegion();
SwLayAction aAction( GetLayout(), Imp() );
aAction.SetComplete( false ); // We increment the action counter to avoid a recursive call of actions // e.g. from a SwFEShell::RequestObjectResize(..) in bug 95829. // A recursive call of actions is no good idea because the inner action // can't format frames which are locked by the outer action. This may // cause and endless loop.
++mnStartAction;
aAction.Action(GetWin()->GetOutDev());
--mnStartAction;
std::optional<SwRegionRects> oRegion = Imp()->TakePaintRegion(); if ( oRegion && aAction.IsBrowseActionStop() )
{ //only of interest when something has changed in the visible range bool bAllNoOverlap = std::all_of(oRegion->begin(), oRegion->end(), [this](const SwRect &rTmp) { return rTmp.Overlaps( VisArea() );
}); if ( bAllNoOverlap )
oRegion.reset();
}
if ( oRegion )
{
oRegion->LimitToOrigin();
oRegion->Compress( SwRegionRects::CompressFuzzy );
bRet = false; if ( !oRegion->empty() )
{
SwRegionRects aRegion( rRect ); for ( const SwRect &rTmp : *oRegion )
{ if ( !rRect.Contains( rTmp ) )
{
InvalidateWindows( rTmp ); if ( rTmp.Overlaps( VisArea() ) )
{ aRegion -= rTmp;
bRet = true;
}
}
} if ( bRet )
{ for ( size_t i = 0; i < aRegion.size(); ++i )
GetWin()->Invalidate( aRegion[i].SVRect() );
if ( rRect != VisArea() )
{ //rRect == VisArea is the special case for new or //Shift-Ctrl-R, when it shouldn't be necessary to //hold the rRect again in Document coordinates. if ( maInvalidRect.IsEmpty() )
maInvalidRect = rRect; else
maInvalidRect.Union( rRect );
}
}
} else
bRet = false;
} else
bRet = false;
} return bRet;
}
namespace
{ /// Similar to comphelper::FlagRestorationGuard, but for vcl::RenderContext. class RenderContextGuard
{
std::unique_ptr<SdrPaintWindow> m_TemporaryPaintWindow;
SdrPageWindow* m_pPatchedPageWindow;
SdrPaintWindow* m_pPreviousPaintWindow = nullptr;
if ( SwRootFrame::IsInPaint() )
{ //During the publication of a page at printing the Paint is buffered.
SwPaintQueue::Add( this, SwRect( rRect ) ); return;
}
//With !nStartAction I try to protect me against erroneous code at other places. //Hopefully it will not lead to problems!? if ( mbPaintWorks && !mnStartAction )
{ if( GetWin() && GetWin()->IsVisible() )
{
SwRect aRect( rRect ); if ( mbPaintInProgress ) //Guard against double Paints!
{
GetWin()->Invalidate( rRect ); return;
}
mbPaintInProgress = true;
CurrShell aCurr( this );
SwRootFrame::SetNoVirDev( true );
//We don't want to Clip to and from, we trust that all are limited //to the rectangle and only need to calculate the clipping once. //The ClipRect is removed here once and not recovered, as externally //no one needs it anymore anyway. //Not when we paint a Metafile. if( !GetOut()->GetConnectMetaFile() && GetOut()->IsClipRegion())
GetOut()->SetClipRegion();
if ( IsPreview() )
{ //When useful, process or destroy the old InvalidRect. if ( aRect.Contains( maInvalidRect ) )
ResetInvalidRect();
SwViewShell::sbLstAct = true;
GetLayout()->PaintSwFrame( rRenderContext, aRect );
SwViewShell::sbLstAct = false;
} else
{ //When one of the visible pages still has anything entered for //Repaint, Repaint must be triggered. if ( !CheckInvalidForPaint( aRect ) )
{ // --> OD 2009-08-12 #i101192# // start Pre/PostPaint encapsulation to avoid screen blinking const vcl::Region aRepaintRegion(aRect.SVRect());
DLPrePaint2(aRepaintRegion);
// <--
PaintDesktop(rRenderContext, aRect);
//When useful, process or destroy the old InvalidRect. if ( aRect.Contains( maInvalidRect ) )
ResetInvalidRect();
SwViewShell::sbLstAct = true;
GetLayout()->PaintSwFrame( rRenderContext, aRect );
SwViewShell::sbLstAct = false; // --> OD 2009-08-12 #i101192# // end Pre/PostPaint encapsulation
DLPostPaint2(true); // <--
}
}
SwRootFrame::SetNoVirDev( false );
mbPaintInProgress = false;
UISizeNotify();
}
} else
{ if ( maInvalidRect.IsEmpty() )
maInvalidRect = SwRect( rRect ); else
maInvalidRect.Union( SwRect( rRect ) );
void SwViewShell::PaintTile(VirtualDevice &rDevice, int contextWidth, int contextHeight, int tilePosX, int tilePosY, tools::Long tileWidth, tools::Long tileHeight)
{ // SwViewShell's output device setup // TODO clean up SwViewShell's approach to output devices (the many of // them - mpBufferedOut, mpOut, mpWin, ...)
OutputDevice *pSaveOut = mpOut;
comphelper::LibreOfficeKit::setTiledPainting(true);
mpOut = &rDevice;
// resizes the virtual device so to contain the entries context
rDevice.SetOutputSizePixel(Size(contextWidth, contextHeight), /*bErase*/false);
// setup the output device to draw the tile
MapMode aMapMode(rDevice.GetMapMode());
aMapMode.SetMapUnit(MapUnit::MapTwip);
aMapMode.SetOrigin(Point(-tilePosX, -tilePosY));
// Scaling. Must convert from pixels to twips. We know // that VirtualDevices use a DPI of 96. const Fraction scale = conversionFract(o3tl::Length::px, o3tl::Length::twip);
Fraction scaleX = Fraction(contextWidth, tileWidth) * scale;
Fraction scaleY = Fraction(contextHeight, tileHeight) * scale;
aMapMode.SetScaleX(scaleX);
aMapMode.SetScaleY(scaleY);
rDevice.SetMapMode(aMapMode);
// Update scaling of SwEditWin and its sub-widgets, needed for comments.
sal_uInt16 nOldZoomValue = 0; if (GetWin() && GetWin()->GetMapMode().GetScaleX() != scaleX)
{ double fScale = double(scaleX);
SwViewOption aOption(*GetViewOptions());
nOldZoomValue = aOption.GetZoom();
aOption.SetZoom(fScale * 100);
ApplyViewOptions(aOption); // Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
GetWin()->EnableMapMode(false);
}
// Make the requested area visible -- we can't use MakeVisible as that will // only scroll the contents, but won't zoom/resize if needed. // Without this, items/text that are outside the visible area (in the SwView) // won't be painted when rendering tiles (at least when using either the // tiledrendering app, or the gtktiledviewer) -- although ultimately we // probably want to fix things so that the SwView's area doesn't affect // tiled rendering?
VisPortChgd(SwRect(aOutRect));
// Invoke SwLayAction if layout is not yet ready.
CheckInvalidForPaint(SwRect(aOutRect));
// draw - works in logic coordinates
Paint(rDevice, aOutRect);
SwPostItMgr* pPostItMgr = GetPostItMgr(); if (GetViewOptions()->IsPostIts() && pPostItMgr)
pPostItMgr->PaintTile(rDevice);
// SwViewShell's output device tear down
// A view shell can get a PaintTile call for a tile at a zoom level // different from the one, the related client really is. // In such a case it is better to reset the current scale value to // the original one, since such a value should be in synchronous with // the zoom level in the client (see setClientZoom). // At present the zoom value returned by GetViewOptions()->GetZoom() is // used in SwXTextDocument methods (postMouseEvent and setGraphicSelection) // for passing the correct mouse position to an edited chart (if any). if (nOldZoomValue !=0)
{
SwViewOption aOption(*GetViewOptions());
aOption.SetZoom(nOldZoomValue);
ApplyViewOptions(aOption);
// Changing the zoom value doesn't always trigger the updating of // the client ole object area, so we call it directly. if (SfxViewShell* pNotifySh = GetSfxViewShell())
{ if (SfxInPlaceClient* pIPClient = pNotifySh->GetIPClient())
{
pIPClient->VisAreaChanged();
}
}
// Make sure the map mode (disabled in SwXTextDocument::initializeForTiledRendering()) is still disabled.
GetWin()->EnableMapMode(false);
}
// When the Layout doesn't have a height yet, nothing is formatted. // That leads to problems with Invalidate, e.g. when setting up a new View // the content is inserted and formatted (regardless of empty VisArea). // Therefore the pages must be roused for formatting. if( !GetLayout()->getFrameArea().Height() )
{
SwFrame* pPage = GetLayout()->Lower(); while( pPage )
{
pPage->InvalidateSize_();
pPage = pPage->GetNext();
} return;
}
SwPageFrame *pPg = static_cast<SwPageFrame*>(GetLayout()->Lower()); do
{ pPg->InvalidateSize();
pPg->InvalidatePrt_();
pPg->InvaPercentLowers(); if ( bSizeChanged )
{
pPg->PrepareHeader();
pPg->PrepareFooter();
}
pPg = static_cast<SwPageFrame*>(pPg->GetNext());
} while ( pPg );
// When the size ratios in browse mode change, // the Position and PrtArea of the Content and Tab frames must be Invalidated.
SwInvalidateFlags nInv = SwInvalidateFlags::PrtArea | SwInvalidateFlags::Table | SwInvalidateFlags::Pos; // In case of layout or mode change, the ContentFrames need a size-Invalidate // because of printer/screen formatting. if ( bSizeChanged )
nInv |= SwInvalidateFlags::Size | SwInvalidateFlags::Direction;
// With one layout per view it is no longer necessary // to sync these "layout related" view options // But as long as we have to disable "multiple layout"
for(SwViewShell& rSh : GetRingContainer())
{ if(&rSh == this) continue;
SwViewOption aOpt( *rSh.GetViewOptions() );
aOpt.SyncLayoutRelatedViewOptions(rOpt); if ( !(aOpt == *rSh.GetViewOptions()) )
rSh.ImplApplyViewOptions( aOpt );
} // End of disabled multiple window
// bReformat becomes true, if ... // - fieldnames apply or not ... // ( - SwEndPortion must _no_ longer be generated. ) // - Of course, the screen is something completely different than the printer ... boolconst isToggleFieldNames(mpOpt->IsFieldName() != rOpt.IsFieldName()); boolconst isToggleLayoutHide{isToggleFieldNames
|| mpOpt->IsParagraph() != rOpt.IsParagraph()
|| mpOpt->IsShowHiddenChar() != rOpt.IsShowHiddenChar()};
// The map mode is changed, minima/maxima will be attended by UI if( mpOpt->GetZoom() != rOpt.GetZoom() && !IsPreview() )
{
MapMode aMode( pMyWin->GetMapMode() );
Fraction aNewFactor( rOpt.GetZoom(), 100 );
aMode.SetScaleX( aNewFactor );
aMode.SetScaleY( aNewFactor );
pMyWin->SetMapMode( aMode ); // if not a reference device (printer) is used for formatting, // but the screen, new formatting is needed for zoomfactor changes. if (mpOpt->getBrowseMode() || mpOpt->IsWhitespaceHidden())
bReformat = true;
}
if( bBrowseModeChanged || bHideWhitespaceModeChanged )
{ // #i44963# Good occasion to check if page sizes in // page descriptions are still set to (LONG_MAX, LONG_MAX) (html import)
mxDoc->CheckDefaultPageFormat();
InvalidateLayout( true );
}
pMyWin->Invalidate(); if ( bReformat )
{ // Nothing helps, we need to send all ContentFrames a // Prepare, we format anew:
SwViewShell::StartAction();
Reformat();
SwViewShell::EndAction();
}
if (isToggleFieldNames)
{ for(SwViewShell& rSh : GetRingContainer())
{ if (SwCursorShell *const pSh = dynamic_cast<SwCursorShell *>(&rSh))
{ if ((mpOpt->IsFieldName() && pSh->CursorInsideInputField())
|| IsCursorInFieldmarkHidden(*pSh->GetCursor(),
pSh->GetLayout()->GetFieldmarkMode()))
{ // move cursor out of field
pSh->Left(1, SwCursorSkipMode::Chars);
}
}
} // the layout changes but SetModified() wasn't called so do it here:
mxDoc->GetDocumentLayoutManager().ClearSwLayouterEntries();
}
void SwViewShell::SetUIOptions( const SwViewOption &rOpt )
{
mpOpt->SetUIOptions(rOpt); //the API-Flag of the view options is set but never reset //it is required to set scroll bars in readonly documents if(rOpt.IsStarOneSetting())
mpOpt->SetStarOneSetting(true);
mpOpt->SetSymbolFont(rOpt.GetSymbolFont());
}
void SwViewShell::SetReadonlyOption(bool bSet)
{ //JP 01.02.99: at readonly flag query properly // and if need be format; Bug 61335
// Are we switching from readonly to edit? if( bSet == mpOpt->IsReadonly() ) return;
// so that the flags can be queried properly.
mpOpt->SetReadonly( false );
void SwViewShell::ApplyAccessibilityOptions()
{ if (comphelper::IsFuzzing()) return; if (mpOpt->IsPagePreview() && !officecfg::Office::Common::Accessibility::IsForPagePreviews::get())
{
mpAccOptions->SetAlwaysAutoColor(false);
mpAccOptions->SetStopAnimatedGraphics(false);
} else
{
mpAccOptions->SetAlwaysAutoColor(officecfg::Office::Common::Accessibility::IsAutomaticFontColor::get()); // tdf#161765: Let user choose which animation settings to use: OS's / LO's // New options: "System"/"No"/"Yes". // Do respect OS's animation setting if the user has selected the option "System"
mpAccOptions->SetStopAnimatedGraphics(! MiscSettings::IsAnimatedGraphicAllowed());
// Form view // Always set this option, not only if document is read-only:
mpOpt->SetSelectionInReadonly(officecfg::Office::Common::Accessibility::IsSelectionInReadonly::get());
}
} #endif// ENABLE_WASM_STRIP_ACCESSIBILITY
¤ 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.0.43Bemerkung:
(vorverarbeitet am 2026-05-05)
¤
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.