/* -*- 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.
--> --------------------
--> maximum size reached
--> --------------------
Messung V0.5
¤ Dauer der Verarbeitung: 0.13 Sekunden
(vorverarbeitet)
¤
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.