From 267c6f2ac71f92999e969232431ba04678e7437e Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Mon, 15 Apr 2024 07:54:39 +0200 Subject: Adding upstream version 4:24.2.0. Signed-off-by: Daniel Baumann --- svx/source/sdr/overlay/overlaymanager.cxx | 362 ++++++++++++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 svx/source/sdr/overlay/overlaymanager.cxx (limited to 'svx/source/sdr/overlay/overlaymanager.cxx') diff --git a/svx/source/sdr/overlay/overlaymanager.cxx b/svx/source/sdr/overlay/overlaymanager.cxx new file mode 100644 index 0000000000..21d3a5458c --- /dev/null +++ b/svx/source/sdr/overlay/overlaymanager.cxx @@ -0,0 +1,362 @@ +/* -*- 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +using namespace com::sun::star; + + +namespace sdr::overlay +{ + void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const + { + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(!nSize) + return; + + const AntialiasingFlags nOriginalAA(rDestinationDevice.GetAntialiasing()); + const bool bIsAntiAliasing(getCurrentViewInformation2D().getUseAntiAliasing()); + // tdf#150622 for High Contrast we typically force colors to a single pair Fore/Back, + // but it seems reasonable to allow overlays to use the selection color + // taken from the system High Contrast settings + const DrawModeFlags nOriginalDrawMode(rDestinationDevice.GetDrawMode()); + + // create processor + std::unique_ptr pProcessor(drawinglayer::processor2d::createProcessor2DFromOutputDevice( + rDestinationDevice, + getCurrentViewInformation2D())); + + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + const OverlayObject& rCandidate = *rpOverlayObject; + + if(rCandidate.isVisible()) + { + const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence(); + + if(!rSequence.empty()) + { + if(rRange.overlaps(rCandidate.getBaseRange())) + { + if(bIsAntiAliasing && rCandidate.allowsAntiAliase()) + { + rDestinationDevice.SetAntialiasing(nOriginalAA | AntialiasingFlags::Enable); + } + else + { + rDestinationDevice.SetAntialiasing(nOriginalAA & ~AntialiasingFlags::Enable); + } + + const bool bIsHighContrastSelection = rCandidate.isHighContrastSelection(); + if (bIsHighContrastSelection) + { + // overrule DrawMode settings + rDestinationDevice.SetDrawMode(nOriginalDrawMode | DrawModeFlags::SettingsForSelection); + } + + pProcessor->process(rSequence); + + if (bIsHighContrastSelection) + { + // restore DrawMode settings + rDestinationDevice.SetDrawMode(nOriginalDrawMode); + } + } + } + } + } + + pProcessor.reset(); + + // restore AA settings + rDestinationDevice.SetAntialiasing(nOriginalAA); + } + + void OverlayManager::ImpStripeDefinitionChanged() + { + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(nSize) + { + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + OverlayObject& rCandidate = *rpOverlayObject; + rCandidate.stripeDefinitionHasChanged(); + } + } + } + + double OverlayManager::getDiscreteOne() const + { + if(basegfx::fTools::equalZero(mfDiscreteOne)) + { + const basegfx::B2DVector aDiscreteInLogic(getOutputDevice().GetInverseViewTransformation() * basegfx::B2DVector(1.0, 0.0)); + const_cast< OverlayManager* >(this)->mfDiscreteOne = aDiscreteInLogic.getLength(); + } + + return mfDiscreteOne; + } + + OverlayManager::OverlayManager(OutputDevice& rOutputDevice) + : mrOutputDevice(rOutputDevice), + maStripeColorA(COL_BLACK), + maStripeColorB(COL_WHITE), + mnStripeLengthPixel(5), + mfDiscreteOne(0.0) + { + // Set Property 'ReducedDisplayQuality' to true to allow simpler interaction + // visualisations. Note: Currently will use reduced quality for 3d scene soft renderer + uno::Sequence< beans::PropertyValue > xProperties{ + comphelper::makePropertyValue("ReducedDisplayQuality", true) + }; + maViewInformation2D = drawinglayer::geometry::createViewInformation2D(xProperties); + } + + rtl::Reference OverlayManager::create(OutputDevice& rOutputDevice) + { + return rtl::Reference(new OverlayManager(rOutputDevice)); + } + + drawinglayer::geometry::ViewInformation2D const & OverlayManager::getCurrentViewInformation2D() const + { + if(getOutputDevice().GetViewTransformation() != maViewTransformation) + { + basegfx::B2DRange aViewRange(maViewInformation2D.getViewport()); + + if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType()) + { + const Size aOutputSizePixel(getOutputDevice().GetOutputSizePixel()); + + // only set when we *have* an output size, else let aViewRange + // stay on empty + if(aOutputSizePixel.Width() && aOutputSizePixel.Height()) + { + aViewRange = basegfx::B2DRange(0.0, 0.0, aOutputSizePixel.getWidth(), aOutputSizePixel.getHeight()); + aViewRange.transform(getOutputDevice().GetInverseViewTransformation()); + } + } + + OverlayManager* pThis = const_cast< OverlayManager* >(this); + + pThis->maViewTransformation = getOutputDevice().GetViewTransformation(); + drawinglayer::geometry::ViewInformation2D aViewInformation(maViewInformation2D); + aViewInformation.setViewTransformation(maViewTransformation); + aViewInformation.setViewport(aViewRange); + pThis->maViewInformation2D = aViewInformation; + + pThis->mfDiscreteOne = 0.0; + } + + return maViewInformation2D; + } + + void OverlayManager::impApplyRemoveActions(OverlayObject& rTarget) + { + // handle evtl. animation + if(rTarget.allowsAnimation()) + { + // remove from event chain + RemoveEvent(&rTarget); + } + + // make invisible + invalidateRange(rTarget.getBaseRange()); + + // clear manager + rTarget.mpOverlayManager = nullptr; + } + + void OverlayManager::impApplyAddActions(OverlayObject& rTarget) + { + // set manager + rTarget.mpOverlayManager = this; + + // make visible + invalidateRange(rTarget.getBaseRange()); + + // handle evtl. animation + if(rTarget.allowsAnimation()) + { + // Trigger at current time to get alive. This will do the + // object-specific next time calculation and hand over adding + // again to the scheduler to the animated object, too. This works for + // a paused or non-paused animator. + rTarget.Trigger(GetTime()); + } + } + + OverlayManager::~OverlayManager() + { + // The OverlayManager is not the owner of the OverlayObjects + // and thus will not delete them, but remove them. Profit here + // from knowing that all will be removed + const sal_uInt32 nSize(maOverlayObjects.size()); + + if(nSize) + { + for(const auto& rpOverlayObject : maOverlayObjects) + { + OSL_ENSURE(rpOverlayObject, "Corrupted OverlayObject List (!)"); + OverlayObject& rCandidate = *rpOverlayObject; + impApplyRemoveActions(rCandidate); + } + + // erase vector + maOverlayObjects.clear(); + } + } + + void OverlayManager::completeRedraw(const vcl::Region& rRegion, OutputDevice* pPreRenderDevice) const + { + if(rRegion.IsEmpty() || maOverlayObjects.empty()) + return; + + // check for changed MapModes. That may influence the + // logical size of pixel based OverlayObjects (like BitmapHandles) + //ImpCheckMapModeChange(); + + // paint members + const tools::Rectangle aRegionBoundRect(rRegion.GetBoundRect()); + const basegfx::B2DRange aRegionRange = vcl::unotools::b2DRectangleFromRectangle(aRegionBoundRect); + + OutputDevice& rTarget = pPreRenderDevice ? *pPreRenderDevice : getOutputDevice(); + ImpDrawMembers(aRegionRange, rTarget); + } + + void OverlayManager::flush() + { + // default has nothing to do + } + + void OverlayManager::add(OverlayObject& rOverlayObject) + { + OSL_ENSURE(nullptr == rOverlayObject.mpOverlayManager, "OverlayObject is added twice to an OverlayManager (!)"); + + // add to the end of chain to preserve display order in paint + maOverlayObjects.push_back(&rOverlayObject); + + // execute add actions + impApplyAddActions(rOverlayObject); + } + + void OverlayManager::remove(OverlayObject& rOverlayObject) + { + OSL_ENSURE(rOverlayObject.mpOverlayManager == this, "OverlayObject is removed from wrong OverlayManager (!)"); + + // execute remove actions + impApplyRemoveActions(rOverlayObject); + + // remove from vector + const OverlayObjectVector::iterator aFindResult = ::std::find(maOverlayObjects.begin(), maOverlayObjects.end(), &rOverlayObject); + const bool bFound(aFindResult != maOverlayObjects.end()); + OSL_ENSURE(bFound, "OverlayObject NOT found at OverlayManager (!)"); + + if(bFound) + { + maOverlayObjects.erase(aFindResult); + } + } + + tools::Rectangle OverlayManager::RangeToInvalidateRectangle(const basegfx::B2DRange& rRange) const + { + if (rRange.isEmpty()) { + return {}; + } + if (getCurrentViewInformation2D().getUseAntiAliasing()) + { + // assume AA needs one pixel more and invalidate one pixel more + const double fDiscreteOne(getDiscreteOne()); + const tools::Rectangle aInvalidateRectangle( + static_cast(floor(rRange.getMinX() - fDiscreteOne)), + static_cast(floor(rRange.getMinY() - fDiscreteOne)), + static_cast(ceil(rRange.getMaxX() + fDiscreteOne)), + static_cast(ceil(rRange.getMaxY() + fDiscreteOne))); + return aInvalidateRectangle; + } + else + { + // #i77674# transform to rectangle. Use floor/ceil to get all covered + // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange + const tools::Rectangle aInvalidateRectangle( + static_cast(floor(rRange.getMinX())), static_cast(floor(rRange.getMinY())), + static_cast(ceil(rRange.getMaxX())), static_cast(ceil(rRange.getMaxY()))); + return aInvalidateRectangle; + } + } + + void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange) + { + if (OUTDEV_WINDOW == getOutputDevice().GetOutDevType()) + { + tools::Rectangle aInvalidateRectangle(RangeToInvalidateRectangle(rRange)); + // simply invalidate + getOutputDevice().GetOwnerWindow()->Invalidate(aInvalidateRectangle, InvalidateFlags::NoErase); + } + } + + // stripe support ColA + void OverlayManager::setStripeColorA(Color aNew) + { + if(aNew != maStripeColorA) + { + maStripeColorA = aNew; + ImpStripeDefinitionChanged(); + } + } + + // stripe support ColB + void OverlayManager::setStripeColorB(Color aNew) + { + if(aNew != maStripeColorB) + { + maStripeColorB = aNew; + ImpStripeDefinitionChanged(); + } + } + + // stripe support StripeLengthPixel + void OverlayManager::setStripeLengthPixel(sal_uInt32 nNew) + { + if(nNew != mnStripeLengthPixel) + { + mnStripeLengthPixel = nNew; + ImpStripeDefinitionChanged(); + } + } + +} // end of namespace + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ -- cgit v1.2.3