diff options
Diffstat (limited to 'svx/source/svdraw/sdrpaintwindow.cxx')
-rw-r--r-- | svx/source/svdraw/sdrpaintwindow.cxx | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/svx/source/svdraw/sdrpaintwindow.cxx b/svx/source/svdraw/sdrpaintwindow.cxx new file mode 100644 index 000000000..6c3b328ba --- /dev/null +++ b/svx/source/svdraw/sdrpaintwindow.cxx @@ -0,0 +1,346 @@ +/* -*- 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 <comphelper/lok.hxx> +#include <osl/diagnose.h> +#include <svx/sdrpaintwindow.hxx> +#include <sdr/overlay/overlaymanagerbuffered.hxx> +#include <svx/svdpntv.hxx> +#include <vcl/gdimtf.hxx> +#include <vcl/svapp.hxx> +#include <vcl/settings.hxx> +#include <vcl/window.hxx> +#include <svtools/optionsdrawinglayer.hxx> +#include <set> +#include <vector> + +namespace { + +//rhbz#1007697 do this in two loops, one to collect the candidates +//and another to update them because updating a candidate can +//trigger the candidate to be deleted, so asking for its +//sibling after that is going to fail hard +class CandidateMgr +{ + std::vector<VclPtr<vcl::Window> > m_aCandidates; + std::set<VclPtr<vcl::Window> > m_aDeletedCandidates; + DECL_LINK(WindowEventListener, VclWindowEvent&, void); +public: + void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect); + ~CandidateMgr(); +}; + +} + +IMPL_LINK(CandidateMgr, WindowEventListener, VclWindowEvent&, rEvent, void) +{ + vcl::Window* pWindow = rEvent.GetWindow(); + if (rEvent.GetId() == VclEventId::ObjectDying) + { + m_aDeletedCandidates.insert(pWindow); + } +} + +CandidateMgr::~CandidateMgr() +{ + for (VclPtr<vcl::Window>& pCandidate : m_aCandidates) + { + if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end()) + continue; + pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener)); + } +} + +void PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect) +{ + if (!rWindow.IsChildTransparentModeEnabled()) + return; + + CandidateMgr aManager; + aManager.PaintTransparentChildren(rWindow, rPixelRect); +} + +void CandidateMgr::PaintTransparentChildren(vcl::Window const & rWindow, tools::Rectangle const& rPixelRect) +{ + vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild ); + while (pCandidate) + { + if (pCandidate->IsPaintTransparent()) + { + const tools::Rectangle aCandidatePosSizePixel( + pCandidate->GetPosPixel(), + pCandidate->GetSizePixel()); + + if (aCandidatePosSizePixel.Overlaps(rPixelRect)) + { + m_aCandidates.emplace_back(pCandidate); + pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener)); + } + } + pCandidate = pCandidate->GetWindow( GetWindowType::Next ); + } + + for (const auto& rpCandidate : m_aCandidates) + { + pCandidate = rpCandidate.get(); + if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end()) + continue; + //rhbz#1007697 this can cause the window itself to be + //deleted. So we are listening to see if that happens + //and if so, then skip the update + pCandidate->Invalidate(InvalidateFlags::NoTransparent|InvalidateFlags::Children); + // important: actually paint the child here! + if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end()) + continue; + pCandidate->PaintImmediately(); + } +} + +SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal) +: mpOutputDevice(&rOriginal), + mpPreRenderDevice(VclPtr<VirtualDevice>::Create()) +{ +} + +SdrPreRenderDevice::~SdrPreRenderDevice() +{ + mpPreRenderDevice.disposeAndClear(); +} + +void SdrPreRenderDevice::PreparePreRenderDevice() +{ + // compare size of mpPreRenderDevice with size of visible area + if(mpPreRenderDevice->GetOutputSizePixel() != mpOutputDevice->GetOutputSizePixel()) + { + mpPreRenderDevice->SetOutputSizePixel(mpOutputDevice->GetOutputSizePixel()); + } + + // Also compare the MapModes for zoom/scroll changes + if(mpPreRenderDevice->GetMapMode() != mpOutputDevice->GetMapMode()) + { + mpPreRenderDevice->SetMapMode(mpOutputDevice->GetMapMode()); + } + + // #i29186# + mpPreRenderDevice->SetDrawMode(mpOutputDevice->GetDrawMode()); + mpPreRenderDevice->SetSettings(mpOutputDevice->GetSettings()); +} + +void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion) +{ + // region to pixels + const vcl::Region aRegionPixel(mpOutputDevice->LogicToPixel(rExpandedRegion)); + //RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects()); + //Rectangle aRegionRectanglePixel; + + // MapModes off + bool bMapModeWasEnabledDest(mpOutputDevice->IsMapModeEnabled()); + bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled()); + mpOutputDevice->EnableMapMode(false); + mpPreRenderDevice->EnableMapMode(false); + + RectangleVector aRectangles; + aRegionPixel.GetRegionRectangles(aRectangles); + + for(const auto& rRect : aRectangles) + { + // for each rectangle, copy the area + const Point aTopLeft(rRect.TopLeft()); + const Size aSize(rRect.GetSize()); + + mpOutputDevice->DrawOutDev( + aTopLeft, aSize, + aTopLeft, aSize, + *mpPreRenderDevice); + } + + mpOutputDevice->EnableMapMode(bMapModeWasEnabledDest); + mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource); +} + +void SdrPaintView::InitOverlayManager(rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager) +{ + Color aColA(SvtOptionsDrawinglayer::GetStripeColorA()); + Color aColB(SvtOptionsDrawinglayer::GetStripeColorB()); + + if (Application::GetSettings().GetStyleSettings().GetHighContrastMode()) + { + aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor(); + aColB.Invert(); + } + + xOverlayManager->setStripeColorA(aColA); + xOverlayManager->setStripeColorB(aColB); + xOverlayManager->setStripeLengthPixel(SvtOptionsDrawinglayer::GetStripeLength()); +} + +rtl::Reference<sdr::overlay::OverlayManager> SdrPaintView::CreateOverlayManager(OutputDevice& rOutputDevice) const +{ + rtl::Reference<sdr::overlay::OverlayManager> xOverlayManager; + // is it a window? + if (OUTDEV_WINDOW == rOutputDevice.GetOutDevType()) + { + vcl::Window* pWindow = rOutputDevice.GetOwnerWindow(); + // decide which OverlayManager to use + if (IsBufferedOverlayAllowed() && !pWindow->SupportsDoubleBuffering()) + { + // buffered OverlayManager, buffers its background and refreshes from there + // for pure overlay changes (no system redraw). The 3rd parameter specifies + // whether that refresh itself will use a 2nd vdev to avoid flickering. + // Also hand over the old OverlayManager if existent; this means to take over + // the registered OverlayObjects from it + xOverlayManager = sdr::overlay::OverlayManagerBuffered::create(rOutputDevice); + } + else + { + // unbuffered OverlayManager, just invalidates places where changes + // take place + // Also hand over the old OverlayManager if existent; this means to take over + // the registered OverlayObjects from it + xOverlayManager = sdr::overlay::OverlayManager::create(rOutputDevice); + } + + OSL_ENSURE(xOverlayManager.is(), "SdrPaintWindow::SdrPaintWindow: Could not allocate an overlayManager (!)"); + + // Request a repaint so that the buffered overlay manager fills + // its buffer properly. This is a workaround for missing buffer + // updates. + if (!comphelper::LibreOfficeKit::isActive()) + { + pWindow->Invalidate(); + } + + InitOverlayManager(xOverlayManager); + } + return xOverlayManager; +} + +void SdrPaintWindow::impCreateOverlayManager() +{ + // not yet one created? + if(!mxOverlayManager.is()) + mxOverlayManager = mrPaintView.CreateOverlayManager(GetOutputDevice()); +} + +SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut, vcl::Window* pWindow) +: mpOutputDevice(&rOut), + mpWindow(pWindow), + mrPaintView(rNewPaintView), + mbTemporaryTarget(false), // #i72889# + mbOutputToWindow(OUTDEV_WINDOW == mpOutputDevice->GetOutDevType()), + mpPatched(nullptr) +{ +} + +SdrPaintWindow::~SdrPaintWindow() +{ + mxOverlayManager.clear(); + + DestroyPreRenderDevice(); +} + +rtl::Reference< sdr::overlay::OverlayManager > const & SdrPaintWindow::GetOverlayManager() const +{ + if(!mxOverlayManager.is()) + { + // Create buffered overlay manager by default. + const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager(); + } + + return mxOverlayManager; +} + +tools::Rectangle SdrPaintWindow::GetVisibleArea() const +{ + Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel()); + return GetOutputDevice().PixelToLogic(tools::Rectangle(Point(0,0), aVisSizePixel)); +} + +bool SdrPaintWindow::OutputToRecordingMetaFile() const +{ + GDIMetaFile* pMetaFile = mpOutputDevice->GetConnectMetaFile(); + return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause()); +} + +void SdrPaintWindow::PreparePreRenderDevice() +{ + const bool bPrepareBufferedOutput( + mrPaintView.IsBufferedOutputAllowed() + && !OutputToPrinter() + && !mpOutputDevice->IsVirtual() + && !OutputToRecordingMetaFile()); + + if(bPrepareBufferedOutput) + { + if(!mpPreRenderDevice) + { + mpPreRenderDevice.reset(new SdrPreRenderDevice(*mpOutputDevice)); + } + } + else + { + DestroyPreRenderDevice(); + } + + if(mpPreRenderDevice) + { + mpPreRenderDevice->PreparePreRenderDevice(); + } +} + +void SdrPaintWindow::DestroyPreRenderDevice() +{ + mpPreRenderDevice.reset(); +} + +void SdrPaintWindow::OutputPreRenderDevice(const vcl::Region& rExpandedRegion) +{ + if(mpPreRenderDevice) + { + mpPreRenderDevice->OutputPreRenderDevice(rExpandedRegion); + } +} + +// #i73602# add flag if buffer shall be used +void SdrPaintWindow::DrawOverlay(const vcl::Region& rRegion) +{ + // ## force creation of OverlayManager since the first repaint needs to + // save the background to get a controlled start into overlay mechanism + impCreateOverlayManager(); + + if(mxOverlayManager.is() && !OutputToPrinter()) + { + if(mpPreRenderDevice) + { + mxOverlayManager->completeRedraw(rRegion, &mpPreRenderDevice->GetPreRenderDevice()); + } + else + { + mxOverlayManager->completeRedraw(rRegion); + } + } +} + + +void SdrPaintWindow::SetRedrawRegion(const vcl::Region& rNew) +{ + maRedrawRegion = rNew; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |