| /************************************************************** |
| * |
| * 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/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 : |
| |
| // #121194# With Graphic as Bitmap FillStyle, also check |
| // for primitives filled with animated graphics |
| case PRIMITIVE2D_ID_POLYPOLYGONGRAPHICPRIMITIVE2D: |
| case PRIMITIVE2D_ID_FILLGRAPHICPRIMITIVE2D: |
| case PRIMITIVE2D_ID_TRANSFORMPRIMITIVE2D: |
| |
| // 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::BColorModifierSharedPtr aBColorModifier( |
| new basegfx::BColorModifier_interpolate( |
| aRGBWhite, |
| 0.5)); |
| 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 |