| /************************************************************** |
| * |
| * 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 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_svx.hxx" |
| #include <svx/sdr/overlay/overlaymanager.hxx> |
| #include <basegfx/point/b2dpoint.hxx> |
| #include <basegfx/range/b2drange.hxx> |
| #include <tools/gen.hxx> |
| #include <vcl/salbtype.hxx> |
| #include <vcl/outdev.hxx> |
| #include <vcl/window.hxx> |
| #include <svx/sdr/overlay/overlayobject.hxx> |
| #include <basegfx/matrix/b2dhommatrix.hxx> |
| #include <drawinglayer/processor2d/processor2dtools.hxx> |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| using namespace com::sun::star; |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| |
| namespace sdr |
| { |
| namespace overlay |
| { |
| void OverlayManager::ImpDrawMembers(const basegfx::B2DRange& rRange, OutputDevice& rDestinationDevice) const |
| { |
| const sal_uInt32 nSize(maOverlayObjects.size()); |
| |
| if(nSize) |
| { |
| const sal_uInt16 nOriginalAA(rDestinationDevice.GetAntialiasing()); |
| const bool bIsAntiAliasing(getDrawinglayerOpt().IsAntiAliasing()); |
| |
| // create processor |
| drawinglayer::processor2d::BaseProcessor2D* pProcessor = drawinglayer::processor2d::createProcessor2DFromOutputDevice( |
| rDestinationDevice, |
| getCurrentViewInformation2D()); |
| |
| if(pProcessor) |
| { |
| for(OverlayObjectVector::const_iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++) |
| { |
| OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)"); |
| const OverlayObject& rCandidate = **aIter; |
| |
| if(rCandidate.isVisible()) |
| { |
| const drawinglayer::primitive2d::Primitive2DSequence& rSequence = rCandidate.getOverlayObjectPrimitive2DSequence(); |
| |
| if(rSequence.hasElements()) |
| { |
| if(rRange.overlaps(rCandidate.getBaseRange())) |
| { |
| if(bIsAntiAliasing && rCandidate.allowsAntiAliase()) |
| { |
| rDestinationDevice.SetAntialiasing(nOriginalAA | ANTIALIASING_ENABLE_B2DDRAW); |
| } |
| else |
| { |
| rDestinationDevice.SetAntialiasing(nOriginalAA & ~ANTIALIASING_ENABLE_B2DDRAW); |
| } |
| |
| pProcessor->process(rSequence); |
| } |
| } |
| } |
| } |
| |
| delete pProcessor; |
| } |
| |
| // restore AA settings |
| rDestinationDevice.SetAntialiasing(nOriginalAA); |
| } |
| } |
| |
| void OverlayManager::ImpStripeDefinitionChanged() |
| { |
| const sal_uInt32 nSize(maOverlayObjects.size()); |
| |
| if(nSize) |
| { |
| for(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++) |
| { |
| OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)"); |
| OverlayObject& rCandidate = **aIter; |
| 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) |
| : Scheduler(), |
| rmOutputDevice(rOutputDevice), |
| maOverlayObjects(), |
| maStripeColorA(Color(COL_BLACK)), |
| maStripeColorB(Color(COL_WHITE)), |
| mnStripeLengthPixel(5), |
| maDrawinglayerOpt(), |
| maViewTransformation(), |
| maViewInformation2D(), |
| mfDiscreteOne(0.0) |
| { |
| // set Property 'ReducedDisplayQuality' to true to allow simpler interaction |
| // visualisations |
| static bool bUseReducedDisplayQualityForDrag(true); |
| |
| if(bUseReducedDisplayQualityForDrag) |
| { |
| uno::Sequence< beans::PropertyValue > xProperties(1); |
| xProperties[0].Name = rtl::OUString(RTL_CONSTASCII_USTRINGPARAM("ReducedDisplayQuality")); |
| xProperties[0].Value <<= true; |
| maViewInformation2D = drawinglayer::geometry::ViewInformation2D(xProperties); |
| } |
| } |
| |
| const drawinglayer::geometry::ViewInformation2D 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* a 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(); |
| pThis->maViewInformation2D = drawinglayer::geometry::ViewInformation2D( |
| maViewInformation2D.getObjectTransformation(), |
| maViewTransformation, |
| aViewRange, |
| maViewInformation2D.getVisualizedPage(), |
| maViewInformation2D.getViewTime(), |
| maViewInformation2D.getExtendedInformationSequence()); |
| 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 = 0; |
| } |
| |
| 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(OverlayObjectVector::iterator aIter(maOverlayObjects.begin()); aIter != maOverlayObjects.end(); aIter++) |
| { |
| OSL_ENSURE(*aIter, "Corrupted OverlayObject List (!)"); |
| OverlayObject& rCandidate = **aIter; |
| impApplyRemoveActions(rCandidate); |
| } |
| |
| // erase vector |
| maOverlayObjects.clear(); |
| } |
| } |
| |
| void OverlayManager::completeRedraw(const Region& rRegion, OutputDevice* pPreRenderDevice) const |
| { |
| if(!rRegion.IsEmpty() && maOverlayObjects.size()) |
| { |
| // check for changed MapModes. That may influence the |
| // logical size of pixel based OverlayObjects (like BitmapHandles) |
| //ImpCheckMapModeChange(); |
| |
| // paint members |
| const Rectangle aRegionBoundRect(rRegion.GetBoundRect()); |
| const basegfx::B2DRange aRegionRange( |
| aRegionBoundRect.Left(), aRegionBoundRect.Top(), |
| aRegionBoundRect.Right(), aRegionBoundRect.Bottom()); |
| |
| OutputDevice& rTarget = (pPreRenderDevice) ? *pPreRenderDevice : getOutputDevice(); |
| ImpDrawMembers(aRegionRange, rTarget); |
| } |
| } |
| |
| void OverlayManager::flush() |
| { |
| // default has nothing to do |
| } |
| |
| // #i68597# part of content gets copied, react on it |
| void OverlayManager::copyArea(const Point& /*rDestPt*/, const Point& /*rSrcPt*/, const Size& /*rSrcSize*/) |
| { |
| // unbuffered versions do nothing here |
| } |
| |
| void OverlayManager::restoreBackground(const Region& /*rRegion*/) const |
| { |
| // unbuffered versions do nothing here |
| } |
| |
| void OverlayManager::add(OverlayObject& rOverlayObject) |
| { |
| OSL_ENSURE(0 == 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); |
| } |
| } |
| |
| void OverlayManager::invalidateRange(const basegfx::B2DRange& rRange) |
| { |
| if(OUTDEV_WINDOW == getOutputDevice().GetOutDevType()) |
| { |
| if(getDrawinglayerOpt().IsAntiAliasing()) |
| { |
| // assume AA needs one pixel more and invalidate one pixel more |
| const double fDiscreteOne(getDiscreteOne()); |
| const Rectangle aInvalidateRectangle( |
| (sal_Int32)floor(rRange.getMinX() - fDiscreteOne), |
| (sal_Int32)floor(rRange.getMinY() - fDiscreteOne), |
| (sal_Int32)ceil(rRange.getMaxX() + fDiscreteOne), |
| (sal_Int32)ceil(rRange.getMaxY() + fDiscreteOne)); |
| |
| // simply invalidate |
| ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_NOERASE); |
| } |
| else |
| { |
| // #i77674# transform to rectangle. Use floor/ceil to get all covered |
| // discrete pixels, see #i75163# and OverlayManagerBuffered::invalidateRange |
| const Rectangle aInvalidateRectangle( |
| (sal_Int32)floor(rRange.getMinX()), (sal_Int32)floor(rRange.getMinY()), |
| (sal_Int32)ceil(rRange.getMaxX()), (sal_Int32)ceil(rRange.getMaxY())); |
| |
| // simply invalidate |
| ((Window&)getOutputDevice()).Invalidate(aInvalidateRectangle, INVALIDATE_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 overlay |
| } // end of namespace sdr |
| |
| ////////////////////////////////////////////////////////////////////////////// |
| // eof |