Files
libreoffice/svx/source/svdraw/sdrpaintwindow.cxx
Noel Grandin bb7ce3137d convert INVALIDATE constants to scoped enum
fixing a bug in Window::ImplMoveAllInvalidateRegions, and improving the
IDL docs for XWindowPeer

Change-Id: Idb774ac913945db2ac7c492c11cf86c370624c3d
2015-05-26 08:30:18 +02:00

357 lines
12 KiB
C++

/* -*- 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/random.hxx>
#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 <set>
#include <vector>
//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, VclSimpleEvent*);
public:
void PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect);
~CandidateMgr();
};
IMPL_LINK(CandidateMgr, WindowEventListener, VclSimpleEvent*, pEvent)
{
VclWindowEvent* pWinEvent = dynamic_cast< VclWindowEvent* >( pEvent );
if (pWinEvent)
{
vcl::Window* pWindow = pWinEvent->GetWindow();
if (pWinEvent->GetId() == VCLEVENT_OBJECT_DYING)
{
m_aDeletedCandidates.insert(pWindow);
}
}
return 0;
}
CandidateMgr::~CandidateMgr()
{
for (auto aI = m_aCandidates.begin(); aI != m_aCandidates.end(); ++aI)
{
VclPtr<vcl::Window> pCandidate = *aI;
if (m_aDeletedCandidates.find(pCandidate) != m_aDeletedCandidates.end())
continue;
pCandidate->RemoveEventListener(LINK(this, CandidateMgr, WindowEventListener));
}
}
void PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
{
if (!rWindow.IsChildTransparentModeEnabled())
return;
CandidateMgr aManager;
aManager.PaintTransparentChildren(rWindow, rPixelRect);
}
void CandidateMgr::PaintTransparentChildren(vcl::Window & rWindow, Rectangle const& rPixelRect)
{
vcl::Window * pCandidate = rWindow.GetWindow( GetWindowType::FirstChild );
while (pCandidate)
{
if (pCandidate->IsPaintTransparent())
{
const Rectangle aCandidatePosSizePixel(
pCandidate->GetPosPixel(),
pCandidate->GetSizePixel());
if (aCandidatePosSizePixel.IsOver(rPixelRect))
{
m_aCandidates.push_back(pCandidate);
pCandidate->AddEventListener(LINK(this, CandidateMgr, WindowEventListener));
}
}
pCandidate = pCandidate->GetWindow( GetWindowType::Next );
}
for (auto aI = m_aCandidates.begin(); aI != m_aCandidates.end(); ++aI)
{
pCandidate = *aI;
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->Update();
}
}
SdrPreRenderDevice::SdrPreRenderDevice(OutputDevice& rOriginal)
: mrOutputDevice(rOriginal),
mpPreRenderDevice(VclPtr<VirtualDevice>::Create())
{
}
SdrPreRenderDevice::~SdrPreRenderDevice()
{
mpPreRenderDevice.disposeAndClear();
}
void SdrPreRenderDevice::PreparePreRenderDevice()
{
// compare size of mpPreRenderDevice with size of visible area
if(mpPreRenderDevice->GetOutputSizePixel() != mrOutputDevice.GetOutputSizePixel())
{
mpPreRenderDevice->SetOutputSizePixel(mrOutputDevice.GetOutputSizePixel());
}
// Also compare the MapModes for zoom/scroll changes
if(mpPreRenderDevice->GetMapMode() != mrOutputDevice.GetMapMode())
{
mpPreRenderDevice->SetMapMode(mrOutputDevice.GetMapMode());
}
// #i29186#
mpPreRenderDevice->SetDrawMode(mrOutputDevice.GetDrawMode());
mpPreRenderDevice->SetSettings(mrOutputDevice.GetSettings());
}
void SdrPreRenderDevice::OutputPreRenderDevice(const vcl::Region& rExpandedRegion)
{
// region to pixels
const vcl::Region aRegionPixel(mrOutputDevice.LogicToPixel(rExpandedRegion));
//RegionHandle aRegionHandle(aRegionPixel.BeginEnumRects());
//Rectangle aRegionRectanglePixel;
// MapModes off
bool bMapModeWasEnabledDest(mrOutputDevice.IsMapModeEnabled());
bool bMapModeWasEnabledSource(mpPreRenderDevice->IsMapModeEnabled());
mrOutputDevice.EnableMapMode(false);
mpPreRenderDevice->EnableMapMode(false);
RectangleVector aRectangles;
aRegionPixel.GetRegionRectangles(aRectangles);
for(RectangleVector::const_iterator aRectIter(aRectangles.begin()); aRectIter != aRectangles.end(); ++aRectIter)
{
// for each rectangle, copy the area
const Point aTopLeft(aRectIter->TopLeft());
const Size aSize(aRectIter->GetSize());
mrOutputDevice.DrawOutDev(
aTopLeft, aSize,
aTopLeft, aSize,
*mpPreRenderDevice.get());
#ifdef DBG_UTIL
// #i74769#
static bool bDoPaintForVisualControlRegion(false);
if(bDoPaintForVisualControlRegion)
{
int nR = comphelper::rng::uniform_int_distribution(0, 0x7F-1);
int nG = comphelper::rng::uniform_int_distribution(0, 0x7F-1);
int nB = comphelper::rng::uniform_int_distribution(0, 0x7F-1);
const Color aColor(((((nR|0x80)<<8L)|(nG|0x80))<<8L)|(nB|0x80));
mrOutputDevice.SetLineColor(aColor);
mrOutputDevice.SetFillColor();
mrOutputDevice.DrawRect(*aRectIter);
}
#endif
}
mrOutputDevice.EnableMapMode(bMapModeWasEnabledDest);
mpPreRenderDevice->EnableMapMode(bMapModeWasEnabledSource);
}
void SdrPaintWindow::impCreateOverlayManager()
{
// not yet one created?
if(!mxOverlayManager.is())
{
// is it a window?
if(OUTDEV_WINDOW == GetOutputDevice().GetOutDevType())
{
// decide which OverlayManager to use
if(GetPaintView().IsBufferedOverlayAllowed() && mbUseBuffer)
{
// 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
mxOverlayManager = sdr::overlay::OverlayManagerBuffered::create(GetOutputDevice(), GetPaintView().GetModel(), true);
}
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
mxOverlayManager = sdr::overlay::OverlayManager::create(GetOutputDevice(), GetPaintView().GetModel());
}
OSL_ENSURE(mxOverlayManager.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.
vcl::Window* pWindow = dynamic_cast<vcl::Window*>(&GetOutputDevice());
if (pWindow != NULL)
pWindow->Invalidate();
Color aColA(GetPaintView().getOptionsDrawinglayer().GetStripeColorA());
Color aColB(GetPaintView().getOptionsDrawinglayer().GetStripeColorB());
if(Application::GetSettings().GetStyleSettings().GetHighContrastMode())
{
aColA = aColB = Application::GetSettings().GetStyleSettings().GetHighlightColor();
aColB.Invert();
}
mxOverlayManager->setStripeColorA(aColA);
mxOverlayManager->setStripeColorB(aColB);
mxOverlayManager->setStripeLengthPixel(GetPaintView().getOptionsDrawinglayer().GetStripeLength());
}
}
}
SdrPaintWindow::SdrPaintWindow(SdrPaintView& rNewPaintView, OutputDevice& rOut)
: mrOutputDevice(rOut),
mrPaintView(rNewPaintView),
mpPreRenderDevice(0L),
mbTemporaryTarget(false), // #i72889#
mbUseBuffer(true)
{
}
SdrPaintWindow::~SdrPaintWindow()
{
mxOverlayManager.clear();
DestroyPreRenderDevice();
}
rtl::Reference< sdr::overlay::OverlayManager > SdrPaintWindow::GetOverlayManager() const
{
if(!mxOverlayManager.is())
{
// Create buffered overlay manager by default.
const_cast< SdrPaintWindow* >(this)->impCreateOverlayManager();
}
return mxOverlayManager;
}
Rectangle SdrPaintWindow::GetVisibleArea() const
{
Size aVisSizePixel(GetOutputDevice().GetOutputSizePixel());
return Rectangle(GetOutputDevice().PixelToLogic(Rectangle(Point(0,0), aVisSizePixel)));
}
bool SdrPaintWindow::OutputToRecordingMetaFile() const
{
GDIMetaFile* pMetaFile = mrOutputDevice.GetConnectMetaFile();
return (pMetaFile && pMetaFile->IsRecord() && !pMetaFile->IsPause());
}
void SdrPaintWindow::PreparePreRenderDevice()
{
const bool bPrepareBufferedOutput(
mrPaintView.IsBufferedOutputAllowed()
&& !OutputToPrinter()
&& !OutputToVirtualDevice()
&& !OutputToRecordingMetaFile());
if(bPrepareBufferedOutput)
{
if(!mpPreRenderDevice)
{
mpPreRenderDevice = new SdrPreRenderDevice(mrOutputDevice);
}
}
else
{
DestroyPreRenderDevice();
}
if(mpPreRenderDevice)
{
mpPreRenderDevice->PreparePreRenderDevice();
}
}
void SdrPaintWindow::DestroyPreRenderDevice()
{
if(mpPreRenderDevice)
{
delete mpPreRenderDevice;
mpPreRenderDevice = 0L;
}
}
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: */