summaryrefslogtreecommitdiff
path: root/svx/source/sdr/contact/viewobjectcontact.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'svx/source/sdr/contact/viewobjectcontact.cxx')
-rw-r--r--svx/source/sdr/contact/viewobjectcontact.cxx441
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: */