diff options
Diffstat (limited to 'svx/source/sdr/contact/viewobjectcontact.cxx')
-rw-r--r-- | svx/source/sdr/contact/viewobjectcontact.cxx | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/svx/source/sdr/contact/viewobjectcontact.cxx b/svx/source/sdr/contact/viewobjectcontact.cxx new file mode 100644 index 000000000000..9afe66ba5494 --- /dev/null +++ b/svx/source/sdr/contact/viewobjectcontact.cxx @@ -0,0 +1,441 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/************************************************************************* + * + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * Copyright 2000, 2010 Oracle and/or its affiliates. + * + * OpenOffice.org - a multi-platform office productivity suite + * + * This file is part of OpenOffice.org. + * + * OpenOffice.org is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License version 3 + * only, as published by the Free Software Foundation. + * + * OpenOffice.org is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License version 3 for more details + * (a copy is included in the LICENSE file that accompanied this code). + * + * You should have received a copy of the GNU Lesser General Public License + * version 3 along with OpenOffice.org. If not, see + * <http://www.openoffice.org/license.html> + * for a copy of the LGPLv3 License. + * + ************************************************************************/ + +// MARKER(update_precomp.py): autogen include statement, do not remove +#include "precompiled_svx.hxx" +#include <svx/sdr/contact/viewobjectcontact.hxx> +#include <svx/sdr/contact/viewcontact.hxx> +#include <svx/sdr/contact/objectcontact.hxx> +#include <svx/sdr/contact/displayinfo.hxx> +#include <vcl/region.hxx> +#include <svx/sdr/animation/objectanimator.hxx> +#include <svx/sdr/animation/animationstate.hxx> +#include <svx/sdr/contact/viewobjectcontactredirector.hxx> +#include <basegfx/numeric/ftools.hxx> +#include <basegfx/color/bcolor.hxx> +#include <drawinglayer/primitive2d/modifiedcolorprimitive2d.hxx> +#include <basegfx/tools/canvastools.hxx> +#include <drawinglayer/primitive2d/animatedprimitive2d.hxx> +#include <drawinglayer/processor2d/baseprocessor2d.hxx> +#include <svx/sdr/primitive2d/svx_primitivetypes2d.hxx> +#include <svx/sdr/contact/viewobjectcontactredirector.hxx> + +////////////////////////////////////////////////////////////////////////////// + +using namespace com::sun::star; + +////////////////////////////////////////////////////////////////////////////// + +namespace +{ + // animated extractor + + // Necessary to filter a sequence of animated primitives from + // a sequence of primitives to find out if animated or not. The decision for + // what to decompose is hard-coded and only done for knowingly animated primitives + // to not decompose too deeply and unnecessarily. This implies that the list + // which is view-specific needs to be expanded by hand when new animated objects + // are added. This may eventually be changed to a dynamically configurable approach + // if necessary. + class AnimatedExtractingProcessor2D : public drawinglayer::processor2d::BaseProcessor2D + { + protected: + // the found animated primitives + drawinglayer::primitive2d::Primitive2DSequence maPrimitive2DSequence; + + // bitfield + // text animation allowed? + unsigned mbTextAnimationAllowed : 1; + + // graphic animation allowed? + unsigned mbGraphicAnimationAllowed : 1; + + // as tooling, the process() implementation takes over API handling and calls this + // virtual render method when the primitive implementation is BasePrimitive2D-based. + virtual void processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate); + + public: + AnimatedExtractingProcessor2D( + const drawinglayer::geometry::ViewInformation2D& rViewInformation, + bool bTextAnimationAllowed, + bool bGraphicAnimationAllowed); + virtual ~AnimatedExtractingProcessor2D(); + + // data access + const drawinglayer::primitive2d::Primitive2DSequence& getPrimitive2DSequence() const { return maPrimitive2DSequence; } + bool isTextAnimationAllowed() const { return mbTextAnimationAllowed; } + bool isGraphicAnimationAllowed() const { return mbGraphicAnimationAllowed; } + }; + + AnimatedExtractingProcessor2D::AnimatedExtractingProcessor2D( + const drawinglayer::geometry::ViewInformation2D& rViewInformation, + bool bTextAnimationAllowed, + bool bGraphicAnimationAllowed) + : drawinglayer::processor2d::BaseProcessor2D(rViewInformation), + maPrimitive2DSequence(), + mbTextAnimationAllowed(bTextAnimationAllowed), + mbGraphicAnimationAllowed(bGraphicAnimationAllowed) + { + } + + AnimatedExtractingProcessor2D::~AnimatedExtractingProcessor2D() + { + } + + void AnimatedExtractingProcessor2D::processBasePrimitive2D(const drawinglayer::primitive2d::BasePrimitive2D& rCandidate) + { + // known implementation, access directly + switch(rCandidate.getPrimitive2DID()) + { + // add and accept animated primitives directly, no need to decompose + case PRIMITIVE2D_ID_ANIMATEDSWITCHPRIMITIVE2D : + case PRIMITIVE2D_ID_ANIMATEDBLINKPRIMITIVE2D : + case PRIMITIVE2D_ID_ANIMATEDINTERPOLATEPRIMITIVE2D : + { + const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& rSwitchPrimitive = static_cast< const drawinglayer::primitive2d::AnimatedSwitchPrimitive2D& >(rCandidate); + + if((rSwitchPrimitive.isTextAnimation() && isTextAnimationAllowed()) + || (rSwitchPrimitive.isGraphicAnimation() && isGraphicAnimationAllowed())) + { + const drawinglayer::primitive2d::Primitive2DReference xReference(const_cast< drawinglayer::primitive2d::BasePrimitive2D* >(&rCandidate)); + drawinglayer::primitive2d::appendPrimitive2DReferenceToPrimitive2DSequence(maPrimitive2DSequence, xReference); + } + break; + } + + // decompose animated gifs where SdrGrafPrimitive2D produces a GraphicPrimitive2D + // which then produces the animation infos (all when used/needed) + case PRIMITIVE2D_ID_SDRGRAFPRIMITIVE2D : + case PRIMITIVE2D_ID_GRAPHICPRIMITIVE2D : + + // decompose SdrObjects with evtl. animated text + case PRIMITIVE2D_ID_SDRCAPTIONPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRCONNECTORPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRCUSTOMSHAPEPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRELLIPSEPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRELLIPSESEGMENTPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRMEASUREPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRPATHPRIMITIVE2D : + case PRIMITIVE2D_ID_SDRRECTANGLEPRIMITIVE2D : + + // decompose evtl. animated text contained in MaskPrimitive2D + // or group rimitives + case PRIMITIVE2D_ID_MASKPRIMITIVE2D : + case PRIMITIVE2D_ID_GROUPPRIMITIVE2D : + { + process(rCandidate.get2DDecomposition(getViewInformation2D())); + break; + } + + default : + { + // nothing to do for the rest + break; + } + } + } +} // end of anonymous namespace + +////////////////////////////////////////////////////////////////////////////// + +namespace sdr +{ + namespace contact + { + ViewObjectContact::ViewObjectContact(ObjectContact& rObjectContact, ViewContact& rViewContact) + : mrObjectContact(rObjectContact), + mrViewContact(rViewContact), + maObjectRange(), + mxPrimitive2DSequence(), + mpPrimitiveAnimation(0), + mbLazyInvalidate(false) + { + // make the ViewContact remember me + mrViewContact.AddViewObjectContact(*this); + + // make the ObjectContact remember me + mrObjectContact.AddViewObjectContact(*this); + } + + ViewObjectContact::~ViewObjectContact() + { + // invalidate in view + if(!maObjectRange.isEmpty()) + { + GetObjectContact().InvalidatePartOfView(maObjectRange); + } + + // delete PrimitiveAnimation + if(mpPrimitiveAnimation) + { + delete mpPrimitiveAnimation; + mpPrimitiveAnimation = 0; + } + + // take care of remebered ObjectContact. Remove from + // OC first. The VC removal (below) CAN trigger a StopGettingViewed() + // which (depending of it's implementation) may destroy other OCs. This + // can trigger the deletion of the helper OC of a page visualising object + // which IS the OC of this object. Eventually StopGettingViewed() needs + // to get asynchron later + GetObjectContact().RemoveViewObjectContact(*this); + + // take care of remebered ViewContact + GetViewContact().RemoveViewObjectContact(*this); + } + + const basegfx::B2DRange& ViewObjectContact::getObjectRange() const + { + if(maObjectRange.isEmpty()) + { + // if range is not computed (new or LazyInvalidate objects), force it + const DisplayInfo aDisplayInfo; + const drawinglayer::primitive2d::Primitive2DSequence xSequence(getPrimitive2DSequence(aDisplayInfo)); + + if(xSequence.hasElements()) + { + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); + const_cast< ViewObjectContact* >(this)->maObjectRange = + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xSequence, rViewInformation2D); + } + } + + return maObjectRange; + } + + void ViewObjectContact::ActionChanged() + { + if(!mbLazyInvalidate) + { + // set local flag + mbLazyInvalidate = true; + + // force ObjectRange + getObjectRange(); + + if(!maObjectRange.isEmpty()) + { + // invalidate current valid range + GetObjectContact().InvalidatePartOfView(maObjectRange); + + // reset ObjectRange, it needs to be recalculated + maObjectRange.reset(); + } + + // register at OC for lazy invalidate + GetObjectContact().setLazyInvalidate(*this); + } + } + + void ViewObjectContact::triggerLazyInvalidate() + { + if(mbLazyInvalidate) + { + // reset flag + mbLazyInvalidate = false; + + // force ObjectRange + getObjectRange(); + + if(!maObjectRange.isEmpty()) + { + // invalidate current valid range + GetObjectContact().InvalidatePartOfView(maObjectRange); + } + } + } + + // Take some action when new objects are inserted + void ViewObjectContact::ActionChildInserted(ViewContact& rChild) + { + // force creation of the new VOC and trigger it's refresh, so it + // will take part in LazyInvalidate immediately + rChild.GetViewObjectContact(GetObjectContact()).ActionChanged(); + + // forward action to ObjectContact + // const ViewObjectContact& rChildVOC = rChild.GetViewObjectContact(GetObjectContact()); + // GetObjectContact().InvalidatePartOfView(rChildVOC.getObjectRange()); + } + + void ViewObjectContact::checkForPrimitive2DAnimations() + { + // remove old one + if(mpPrimitiveAnimation) + { + delete mpPrimitiveAnimation; + mpPrimitiveAnimation = 0; + } + + // check for animated primitives + if(mxPrimitive2DSequence.hasElements()) + { + const bool bTextAnimationAllowed(GetObjectContact().IsTextAnimationAllowed()); + const bool bGraphicAnimationAllowed(GetObjectContact().IsGraphicAnimationAllowed()); + + if(bTextAnimationAllowed || bGraphicAnimationAllowed) + { + AnimatedExtractingProcessor2D aAnimatedExtractor(GetObjectContact().getViewInformation2D(), + bTextAnimationAllowed, bGraphicAnimationAllowed); + aAnimatedExtractor.process(mxPrimitive2DSequence); + + if(aAnimatedExtractor.getPrimitive2DSequence().hasElements()) + { + // dervied primitiveList is animated, setup new PrimitiveAnimation + mpPrimitiveAnimation = new sdr::animation::PrimitiveAnimation(*this, aAnimatedExtractor.getPrimitive2DSequence()); + } + } + } + } + + drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::createPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const + { + // get the view-independent Primitive from the viewContact + drawinglayer::primitive2d::Primitive2DSequence xRetval(GetViewContact().getViewIndependentPrimitive2DSequence()); + + if(xRetval.hasElements()) + { + // handle GluePoint + if(!GetObjectContact().isOutputToPrinter() && GetObjectContact().AreGluePointsVisible()) + { + const drawinglayer::primitive2d::Primitive2DSequence xGlue(GetViewContact().createGluePointPrimitive2DSequence()); + + if(xGlue.hasElements()) + { + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xRetval, xGlue); + } + } + + // handle ghosted + if(isPrimitiveGhosted(rDisplayInfo)) + { + const basegfx::BColor aRGBWhite(1.0, 1.0, 1.0); + const basegfx::BColorModifier aBColorModifier(aRGBWhite, 0.5, basegfx::BCOLORMODIFYMODE_INTERPOLATE); + const drawinglayer::primitive2d::Primitive2DReference xReference(new drawinglayer::primitive2d::ModifiedColorPrimitive2D(xRetval, aBColorModifier)); + xRetval = drawinglayer::primitive2d::Primitive2DSequence(&xReference, 1); + } + } + + return xRetval; + } + + drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequence(const DisplayInfo& rDisplayInfo) const + { + drawinglayer::primitive2d::Primitive2DSequence xNewPrimitiveSequence; + + // take care of redirectors and create new list + ViewObjectContactRedirector* pRedirector = GetObjectContact().GetViewObjectContactRedirector(); + + if(pRedirector) + { + xNewPrimitiveSequence = pRedirector->createRedirectedPrimitive2DSequence(*this, rDisplayInfo); + } + else + { + xNewPrimitiveSequence = createPrimitive2DSequence(rDisplayInfo); + } + + // local up-to-date checks. New list different from local one? + if(!drawinglayer::primitive2d::arePrimitive2DSequencesEqual(mxPrimitive2DSequence, xNewPrimitiveSequence)) + { + // has changed, copy content + const_cast< ViewObjectContact* >(this)->mxPrimitive2DSequence = xNewPrimitiveSequence; + + // check for animated stuff + const_cast< ViewObjectContact* >(this)->checkForPrimitive2DAnimations(); + + // always update object range when PrimitiveSequence changes + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); + const_cast< ViewObjectContact* >(this)->maObjectRange = + drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(mxPrimitive2DSequence, rViewInformation2D); + } + + // return current Primitive2DSequence + return mxPrimitive2DSequence; + } + + bool ViewObjectContact::isPrimitiveVisible(const DisplayInfo& /*rDisplayInfo*/) const + { + // default: always visible + return true; + } + + bool ViewObjectContact::isPrimitiveGhosted(const DisplayInfo& rDisplayInfo) const + { + // default: standard check + return (GetObjectContact().DoVisualizeEnteredGroup() && !GetObjectContact().isOutputToPrinter() && rDisplayInfo.IsGhostedDrawModeActive()); + } + + drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceHierarchy(DisplayInfo& rDisplayInfo) const + { + drawinglayer::primitive2d::Primitive2DSequence xRetval; + + // check model-view visibility + if(isPrimitiveVisible(rDisplayInfo)) + { + xRetval = getPrimitive2DSequence(rDisplayInfo); + + if(xRetval.hasElements()) + { + // get ranges + const drawinglayer::geometry::ViewInformation2D& rViewInformation2D(GetObjectContact().getViewInformation2D()); + const basegfx::B2DRange aObjectRange(drawinglayer::primitive2d::getB2DRangeFromPrimitive2DSequence(xRetval, rViewInformation2D)); + const basegfx::B2DRange aViewRange(rViewInformation2D.getViewport()); + + // check geometrical visibility + if(!aViewRange.isEmpty() && !aViewRange.overlaps(aObjectRange)) + { + // not visible, release + xRetval.realloc(0); + } + } + } + + return xRetval; + } + + drawinglayer::primitive2d::Primitive2DSequence ViewObjectContact::getPrimitive2DSequenceSubHierarchy(DisplayInfo& rDisplayInfo) const + { + const sal_uInt32 nSubHierarchyCount(GetViewContact().GetObjectCount()); + drawinglayer::primitive2d::Primitive2DSequence xSeqRetval; + + for(sal_uInt32 a(0); a < nSubHierarchyCount; a++) + { + const ViewObjectContact& rCandidate(GetViewContact().GetViewContact(a).GetViewObjectContact(GetObjectContact())); + + drawinglayer::primitive2d::appendPrimitive2DSequenceToPrimitive2DSequence(xSeqRetval, rCandidate.getPrimitive2DSequenceHierarchy(rDisplayInfo)); + } + + return xSeqRetval; + } + } // end of namespace contact +} // end of namespace sdr + +////////////////////////////////////////////////////////////////////////////// +// eof + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |