/* -*- 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 .
*/
namespace sdr::overlay
{ void OverlayManagerBuffered::ImpPrepareBufferDevice()
{ // compare size of mpBufferDevice with size of visible area if(mpBufferDevice->GetOutputSizePixel() != getOutputDevice().GetOutputSizePixel())
{ // set new buffer size, copy as much content as possible (use bool parameter for vcl). // Newly uncovered regions will be repainted.
mpBufferDevice->SetOutputSizePixel(getOutputDevice().GetOutputSizePixel(), false);
}
// compare the MapModes for zoom/scroll changes if(mpBufferDevice->GetMapMode() != getOutputDevice().GetMapMode())
{ constbool bZoomed(
mpBufferDevice->GetMapMode().GetScaleX() != getOutputDevice().GetMapMode().GetScaleX()
|| mpBufferDevice->GetMapMode().GetScaleY() != getOutputDevice().GetMapMode().GetScaleY());
if(bScrolled)
{ // get pixel bounds (tdf#149322 do subtraction in logic units before converting result back to pixel) const Point aLogicOriginDiff(rOriginNew - rOriginOld); const Size aPixelOriginDiff(mpBufferDevice->LogicToPixel(Size(aLogicOriginDiff.X(), aLogicOriginDiff.Y()))); const Point aDestinationOffsetPixel(aPixelOriginDiff.Width(), aPixelOriginDiff.Height()); const Size aOutputSizePixel(mpBufferDevice->GetOutputSizePixel());
// remember and switch off MapMode constbool bMapModeWasEnabled(mpBufferDevice->IsMapModeEnabled());
mpBufferDevice->EnableMapMode(false);
// Ensure buffer is valid
ImpPrepareBufferDevice();
// build region which needs to be copied
vcl::Region aRegion(rSource.LogicToPixel(rRegion));
// limit to PaintRegion if it's a window. This will be evtl. the expanded one, // but always the exact redraw area if(OUTDEV_WINDOW == rSource.GetOutDevType())
{
vcl::Window& rWindow = *rSource.GetOwnerWindow();
vcl::Region aPaintRegionPixel = rWindow.LogicToPixel(rWindow.GetPaintRegion());
aRegion.Intersect(aPaintRegionPixel);
// #i72754# Make sure content is completely rendered, the window // will be used as source of a DrawOutDev soon
rWindow.GetOutDev()->Flush();
}
// also limit to buffer size const tools::Rectangle aBufferDeviceRectanglePixel(Point(), mpBufferDevice->GetOutputSizePixel());
aRegion.Intersect(aBufferDeviceRectanglePixel);
// MapModes off constbool bMapModeWasEnabledDest(rSource.IsMapModeEnabled()); constbool bMapModeWasEnabledSource(mpBufferDevice->IsMapModeEnabled());
rSource.EnableMapMode(false);
mpBufferDevice->EnableMapMode(false);
// prepare to iterate over the rectangles from the region in pixels
RectangleVector aRectangles;
aRegion.GetRegionRectangles(aRectangles);
for(constauto& rRect : aRectangles)
{ // for each rectangle, save the area const Point aTopLeft(rRect.TopLeft()); const Size aSize(rRect.GetSize());
IMPL_LINK_NOARG(OverlayManagerBuffered, ImpBufferTimerHandler, Timer*, void)
{ //Resolves: fdo#46728 ensure this exists until end of scope
rtl::Reference<OverlayManager> xKeepAlive(this);
// stop timer
maBufferIdle.Stop();
if(maBufferRememberedRangePixel.isEmpty()) // nothing to refresh, done return;
if (maMapModeLastCompleteRedraw == MapMode()) // there was no CompleteRedraw yet, done return;
// in calc i stumbled over the situation that MapModes for OutDevs // were different for ::CompleteRedraw and this timer-based refresh, // probably due to Calc's massive MapMode changes - as soon as an // overlay invalidate happened the next reschedule in calc *will* // trigger this refresh, despite what MapMode may be set at the // target device currently. // These updates only make sense in combination with the saved // background, so this is an error (and happens only in Calc due // to these always changing MapModes). // Thus it is plausible to remember the MapMode of the last full // CompleteRedraw and force local usage to it. const MapMode aPrevMapMode(getOutputDevice().GetMapMode()); constbool bPatchMapMode(aPrevMapMode != maMapModeLastCompleteRedraw); if (bPatchMapMode)
getOutputDevice().SetMapMode(maMapModeLastCompleteRedraw);
// truncate aRegionRectanglePixel to destination pixel size, more does // not need to be prepared since destination is a buffer for a window. So, // maximum size indirectly shall be limited to getOutputDevice().GetOutputSizePixel() if(aRegionRectanglePixel.Left() < 0)
{
aRegionRectanglePixel.SetLeft( 0 );
}
// paint overlay content for remembered region, use // method from base class directly
mpOutputBufferDevice->EnableMapMode();
OverlayManager::ImpDrawMembers(aBufferRememberedRangeLogic, *mpOutputBufferDevice);
mpOutputBufferDevice->EnableMapMode(false);
// copy to output
{ constbool bMapModeWasEnabledDest(getOutputDevice().IsMapModeEnabled());
getOutputDevice().EnableMapMode(false);
// VCL hack for transparent child windows // Problem is e.g. a radiobutton form control in life mode. The used window // is a transparence vcl childwindow. This flag only allows the parent window to // paint into the child windows area, but there is no mechanism which takes // care for a repaint of the child window. A transparent child window is NOT // a window which always keeps it's content consistent over the parent, but it's // more like just a paint flag for the parent. // To get the update, the windows in question are updated manually here. if(bTargetIsWindow)
{
vcl::Window& rWindow = *mrOutputDevice.GetOwnerWindow();
if(!maBufferRememberedRangePixel.isEmpty())
{ // Restore all rectangles for remembered region from buffer
ImpRestoreBackground();
}
}
void OverlayManagerBuffered::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const
{ // remember MapMode of last full completeRedraw to // have it available in timer-based updates (see // ImpBufferTimerHandler)
maMapModeLastCompleteRedraw = getOutputDevice().GetMapMode();
if(!rRegion.IsEmpty())
{ // save new background const_cast<OverlayManagerBuffered*>(this)->ImpSaveBackground(rRegion, pPreRenderDevice);
}
if (maMapModeLastCompleteRedraw == MapMode()) // there was no CompleteRedraw yet, done return;
// buffered output, do not invalidate but use the timer // to trigger a timer event for refresh
maBufferIdle.Start();
// tdf#166520 need to also use MapModeLastCompleteRedraw for // the invalidates -> Calc is just completely unstable using // MapModes at any Window. The one remembered at full // repaint has to be the DrawingLayer one - overlay works // in DrawingLayer coordinates/MapMode(s) const MapMode aPrevMapMode(getOutputDevice().GetMapMode()); constbool bPatchMapMode(aPrevMapMode != maMapModeLastCompleteRedraw); if (bPatchMapMode)
getOutputDevice().SetMapMode(maMapModeLastCompleteRedraw);
// add the discrete range to the remembered region // #i75163# use double precision and floor/ceil rounding to get overlapped pixel region, even // when the given logic region has a width/height of 0.0. This does NOT work with LogicToPixel // since it just transforms the top left and bottom right points equally without taking // discrete pixel coverage into account. An empty B2DRange and thus empty logic Rectangle translated // to an also empty discrete pixel rectangle - what is wrong.
basegfx::B2DRange aDiscreteRange(rRange);
aDiscreteRange.transform(getOutputDevice().GetViewTransformation());
if(getCurrentViewInformation2D().getUseAntiAliasing())
{ // assume AA needs one pixel more and invalidate one pixel more constdouble fDiscreteOne(getDiscreteOne()); const basegfx::B2IPoint aTopLeft( static_cast<sal_Int32>(floor(aDiscreteRange.getMinX() - fDiscreteOne)), static_cast<sal_Int32>(floor(aDiscreteRange.getMinY() - fDiscreteOne))); const basegfx::B2IPoint aBottomRight( static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxX() + fDiscreteOne)), static_cast<sal_Int32>(ceil(aDiscreteRange.getMaxY() + fDiscreteOne)));
// restore evtl. temporarily patched MapMode (see explanation // above) if (bPatchMapMode)
getOutputDevice().SetMapMode(aPrevMapMode);
}
} // end of namespace
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.