Beispiel #1
0
        /// <summary>
        /// Called by a DrawingContext returned from Open or Append when the content
        /// created by it needs to be committed (because DrawingContext.Close/Dispose
        /// was called)
        /// </summary>
        /// <param name="rootDrawingGroupChildren">
        ///     Collection containing the Drawing elements created by a DrawingContext
        ///     returned from Open or Append.
        /// </param>
        internal void Close(DrawingCollection rootDrawingGroupChildren)
        {
            WritePreamble();

            Debug.Assert(_open);
            Debug.Assert(rootDrawingGroupChildren != null);

            if (!_openedForAppend)
            {
                // Clear out the previous contents by replacing the current collection with
                // the new collection.
                //
                // When more than one element exists in rootDrawingGroupChildren, the
                // DrawingContext had to create this new collection anyways.  To behave
                // consistently between the one-element and many-element cases,
                // we always set Children to a new DrawingCollection instance during Close().
                //
                // Doing this also avoids having to protect against exceptions being thrown
                // from user-code, which could be executed if a Changed event was fired when
                // we tried to add elements to a pre-existing collection.
                //
                // The collection created by the DrawingContext will no longer be
                // used after the DrawingContext is closed, so we can take ownership
                // of the reference here to avoid any more unneccesary copies.
                Children = rootDrawingGroupChildren;
            }
            else
            {
                //
                //
                // Append the collection to the current Children collection
                //
                //
                DrawingCollection children = Children;

                //
                // Ensure that we can Append to the Children collection
                //

                if (children == null)
                {
                    throw new InvalidOperationException(SR.Get(SRID.DrawingGroup_CannotAppendToNullCollection));
                }

                if (children.IsFrozen)
                {
                    throw new InvalidOperationException(SR.Get(SRID.DrawingGroup_CannotAppendToFrozenCollection));
                }

                // Append the new collection to our current Children.
                //
                // TransactionalAppend rolls-back the Append operation in the event
                // an exception is thrown from the Changed event.
                children.TransactionalAppend(rootDrawingGroupChildren);
            }

            // This DrawingGroup is no longer open
            _open = false;
        }
Beispiel #2
0
            internal Enumerator(DrawingCollection list)
            {
                Debug.Assert(list != null, "list may not be null.");

                _list    = list;
                _version = list._version;
                _index   = -1;
                _current = default(Drawing);
            }
Beispiel #3
0
        /// <summary>
        /// Appends the entire input DrawingCollection, while only firing a single set of
        /// public events.  If an exception is thrown from the public events, the
        /// Append operation is rolled back.
        /// </summary>
        internal void TransactionalAppend(DrawingCollection collectionToAppend)
        {
            // Use appendCount to avoid inconsistencies & runaway loops when
            // this == collectionToAppend, and to ensure collectionToAppend.Count
            // is only evaluated once.
            int appendCount = collectionToAppend.Count;

            // First, append the collection
            for (int i = 0; i < appendCount; i++)
            {
                AddWithoutFiringPublicEvents(collectionToAppend.Internal_GetItem(i));
            }

            // Fire the public Changed event after all the elements have been added.
            //
            // If an exception is thrown, then the Append operation is rolled-back without
            // firing additional events.
            try
            {
                FireChanged();
            }
            catch (Exception)
            {
                // Compute the number of elements that existed before the append
                int beforeAppendCount = Count - appendCount;

                // Remove the appended elements in reverse order without firing Changed events.

                for (int i = Count - 1;                 // Start at the current last index
                     i >= beforeAppendCount;            // Until the previous last index
                     i--                                // Move to the preceding index
                     )
                {
                    RemoveAtWithoutFiringPublicEvents(i);
                }

                // Avoid firing WritePostscript events (e.g., OnChanged) after rolling-back
                // the current operation.
                //
                // This ensures that only a single set of events is fired for both exceptional &
                // typical cases, and it's likely that firing events would cause another exception.

                throw;
            }
        }
Beispiel #4
0
        /// <summary>
        /// Implementation of Freezable.GetCurrentValueAsFrozenCore()
        /// </summary>
        protected override void GetCurrentValueAsFrozenCore(Freezable source)
        {
            DrawingCollection sourceDrawingCollection = (DrawingCollection)source;

            base.GetCurrentValueAsFrozenCore(source);

            int count = sourceDrawingCollection._collection.Count;

            _collection = new FrugalStructList <Drawing>(count);

            for (int i = 0; i < count; i++)
            {
                Drawing newValue = (Drawing)sourceDrawingCollection._collection[i].GetCurrentValueAsFrozen();
                OnFreezablePropertyChanged(/* oldValue = */ null, newValue);
                _collection.Add(newValue);
                OnInsert(newValue);
            }
        }
Beispiel #5
0
        internal override DUCE.ResourceHandle AddRefOnChannelCore(DUCE.Channel channel)
        {
            if (_duceResource.CreateOrAddRefOnChannel(this, channel, System.Windows.Media.Composition.DUCE.ResourceType.TYPE_DRAWINGGROUP))
            {
                Geometry vClipGeometry = ClipGeometry;
                if (vClipGeometry != null)
                {
                    ((DUCE.IResource)vClipGeometry).AddRefOnChannel(channel);
                }
                Brush vOpacityMask = OpacityMask;
                if (vOpacityMask != null)
                {
                    ((DUCE.IResource)vOpacityMask).AddRefOnChannel(channel);
                }
                Transform vTransform = Transform;
                if (vTransform != null)
                {
                    ((DUCE.IResource)vTransform).AddRefOnChannel(channel);
                }
                GuidelineSet vGuidelineSet = GuidelineSet;
                if (vGuidelineSet != null)
                {
                    ((DUCE.IResource)vGuidelineSet).AddRefOnChannel(channel);
                }

                DrawingCollection vChildren = Children;

                if (vChildren != null)
                {
                    int count = vChildren.Count;
                    for (int i = 0; i < count; i++)
                    {
                        ((DUCE.IResource)vChildren.Internal_GetItem(i)).AddRefOnChannel(channel);
                    }
                }
                AddRefOnChannelAnimations(channel);


                UpdateResource(channel, true /* skip "on channel" check - we already know that we're on channel */);
            }

            return(_duceResource.GetHandle(channel));
        }
Beispiel #6
0
        internal override void ReleaseOnChannelCore(DUCE.Channel channel)
        {
            Debug.Assert(_duceResource.IsOnChannel(channel));

            if (_duceResource.ReleaseOnChannel(channel))
            {
                Geometry vClipGeometry = ClipGeometry;
                if (vClipGeometry != null)
                {
                    ((DUCE.IResource)vClipGeometry).ReleaseOnChannel(channel);
                }
                Brush vOpacityMask = OpacityMask;
                if (vOpacityMask != null)
                {
                    ((DUCE.IResource)vOpacityMask).ReleaseOnChannel(channel);
                }
                Transform vTransform = Transform;
                if (vTransform != null)
                {
                    ((DUCE.IResource)vTransform).ReleaseOnChannel(channel);
                }
                GuidelineSet vGuidelineSet = GuidelineSet;
                if (vGuidelineSet != null)
                {
                    ((DUCE.IResource)vGuidelineSet).ReleaseOnChannel(channel);
                }

                DrawingCollection vChildren = Children;

                if (vChildren != null)
                {
                    int count = vChildren.Count;
                    for (int i = 0; i < count; i++)
                    {
                        ((DUCE.IResource)vChildren.Internal_GetItem(i)).ReleaseOnChannel(channel);
                    }
                }
                ReleaseOnChannelAnimations(channel);
            }
        }
Beispiel #7
0
        /// <summary>
        /// Calls methods on the DrawingContext that are equivalent to the
        /// Drawing with the Drawing's current value.
        /// </summary>
        internal override void WalkCurrentValue(DrawingContextWalker ctx)
        {
            int popCount = 0;

            // We avoid unneccessary ShouldStopWalking checks based on assumptions
            // about when ShouldStopWalking is set.  Guard that assumption with an
            // assertion.
            //
            // ShouldStopWalking is currently only set during a hit-test walk after
            // an object has been hit.  Because a DrawingGroup can't be hit until after
            // the first Drawing is tested, this method doesn't check ShouldStopWalking
            // until after the first child.
            //
            // We don't need to add this check to other Drawing subclasses for
            // the same reason -- if the Drawing being tested isn't a DrawingGroup,
            // they are always the 'first child'.
            //
            // If this assumption is ever broken then the ShouldStopWalking
            // check should be done on the first child -- including in the
            // WalkCurrentValue method of other Drawing subclasses.
            Debug.Assert(!ctx.ShouldStopWalking);

            //
            // Draw the transform property
            //

            // Avoid calling PushTransform if the base value is set to the default and
            // no animations have been set on the property.
            if (!IsBaseValueDefault(DrawingGroup.TransformProperty) ||
                (null != AnimationStorage.GetStorage(this, DrawingGroup.TransformProperty)))
            {
                ctx.PushTransform(Transform);

                popCount++;
            }

            //
            // Draw the clip property
            //

            // Avoid calling PushClip if the base value is set to the default and
            // no animations have been set on the property.
            if (!IsBaseValueDefault(DrawingGroup.ClipGeometryProperty) ||
                (null != AnimationStorage.GetStorage(this, DrawingGroup.ClipGeometryProperty)))
            {
                ctx.PushClip(ClipGeometry);

                popCount++;
            }

            //
            // Draw the opacity property
            //

            // Avoid calling PushOpacity if the base value is set to the default and
            // no animations have been set on the property.
            if (!IsBaseValueDefault(DrawingGroup.OpacityProperty) ||
                (null != AnimationStorage.GetStorage(this, DrawingGroup.OpacityProperty)))
            {
                // Push the current value of the opacity property, which
                // is what Opacity returns.
                ctx.PushOpacity(Opacity);

                popCount++;
            }

            // Draw the opacity mask property
            //
            if (OpacityMask != null)
            {
                ctx.PushOpacityMask(OpacityMask);
                popCount++;
            }

            //
            // Draw the effect property
            //

            // Push the current value of the effect property, which
            // is what BitmapEffect returns.
            if (BitmapEffect != null)
            {
                // Disable warning about obsolete method.  This code must remain active
                // until we can remove the public BitmapEffect APIs.
                #pragma warning disable 0618
                ctx.PushEffect(BitmapEffect, BitmapEffectInput);
                #pragma warning restore 0618
                popCount++;
            }

            //
            // Draw the Children collection
            //

            // Get the current value of the children collection
            DrawingCollection collection = Children;

            // Call Walk on each child
            if (collection != null)
            {
                for (int i = 0; i < collection.Count; i++)
                {
                    Drawing drawing = collection.Internal_GetItem(i);
                    if (drawing != null)
                    {
                        drawing.WalkCurrentValue(ctx);

                        // Don't visit the remaining children if the previous
                        // child caused us to stop walking.
                        if (ctx.ShouldStopWalking)
                        {
                            break;
                        }
                    }
                }
            }

            //
            // Call Pop() for every Push
            //
            // Avoid placing this logic in a finally block because if an exception is
            // thrown, the Walk is simply aborted.  There is no requirement to Walk
            // through Pop instructions when an exception is thrown.
            //

            for (int i = 0; i < popCount; i++)
            {
                ctx.Pop();
            }
        }
Beispiel #8
0
        //------------------------------------------------------
        //
        //  Public Properties
        //
        //------------------------------------------------------

        private static void ChildrenPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            // The first change to the default value of a mutable collection property (e.g. GeometryGroup.Children)
            // will promote the property value from a default value to a local value. This is technically a sub-property
            // change because the collection was changed and not a new collection set (GeometryGroup.Children.
            // Add versus GeometryGroup.Children = myNewChildrenCollection). However, we never marshalled
            // the default value to the compositor. If the property changes from a default value, the new local value
            // needs to be marshalled to the compositor. We detect this scenario with the second condition
            // e.OldValueSource != e.NewValueSource. Specifically in this scenario the OldValueSource will be
            // Default and the NewValueSource will be Local.
            if (e.IsASubPropertyChange &&
                (e.OldValueSource == e.NewValueSource))
            {
                return;
            }


            DrawingGroup target = ((DrawingGroup)d);


            // If this is both non-null and mutable, we need to unhook the Changed event.
            DrawingCollection oldCollection = null;
            DrawingCollection newCollection = null;

            if ((e.OldValueSource != BaseValueSourceInternal.Default) || e.IsOldValueModified)
            {
                oldCollection = (DrawingCollection)e.OldValue;
                if ((oldCollection != null) && !oldCollection.IsFrozen)
                {
                    oldCollection.ItemRemoved  -= target.ChildrenItemRemoved;
                    oldCollection.ItemInserted -= target.ChildrenItemInserted;
                }
            }

            // If this is both non-null and mutable, we need to hook the Changed event.
            if ((e.NewValueSource != BaseValueSourceInternal.Default) || e.IsNewValueModified)
            {
                newCollection = (DrawingCollection)e.NewValue;
                if ((newCollection != null) && !newCollection.IsFrozen)
                {
                    newCollection.ItemInserted += target.ChildrenItemInserted;
                    newCollection.ItemRemoved  += target.ChildrenItemRemoved;
                }
            }
            if (oldCollection != newCollection && target.Dispatcher != null)
            {
                using (CompositionEngineLock.Acquire())
                {
                    DUCE.IResource targetResource = (DUCE.IResource)target;
                    int            channelCount   = targetResource.GetChannelCount();

                    for (int channelIndex = 0; channelIndex < channelCount; channelIndex++)
                    {
                        DUCE.Channel channel = targetResource.GetChannel(channelIndex);
                        Debug.Assert(!channel.IsOutOfBandChannel);
                        Debug.Assert(!targetResource.GetHandle(channel).IsNull);
                        // resource shouldn't be null because
                        // 1) If the field is one of our collections, we don't allow null elements
                        // 2) Codegen already made sure the collection contains DUCE.IResources
                        // ... so we'll Assert it

                        if (newCollection != null)
                        {
                            int count = newCollection.Count;
                            for (int i = 0; i < count; i++)
                            {
                                DUCE.IResource resource = newCollection.Internal_GetItem(i) as DUCE.IResource;
                                Debug.Assert(resource != null);
                                resource.AddRefOnChannel(channel);
                            }
                        }

                        if (oldCollection != null)
                        {
                            int count = oldCollection.Count;
                            for (int i = 0; i < count; i++)
                            {
                                DUCE.IResource resource = oldCollection.Internal_GetItem(i) as DUCE.IResource;
                                Debug.Assert(resource != null);
                                resource.ReleaseOnChannel(channel);
                            }
                        }
                    }
                }
            }
            target.PropertyChanged(ChildrenProperty);
        }
Beispiel #9
0
        //------------------------------------------------------
        //
        //  Internal Methods
        //
        //------------------------------------------------------

        #region Internal Methods

        internal override void UpdateResource(DUCE.Channel channel, bool skipOnChannelCheck)
        {
            // If we're told we can skip the channel check, then we must be on channel
            Debug.Assert(!skipOnChannelCheck || _duceResource.IsOnChannel(channel));

            if (skipOnChannelCheck || _duceResource.IsOnChannel(channel))
            {
                base.UpdateResource(channel, skipOnChannelCheck);

                // Read values of properties into local variables
                DrawingCollection vChildren     = Children;
                Geometry          vClipGeometry = ClipGeometry;
                Brush             vOpacityMask  = OpacityMask;
                Transform         vTransform    = Transform;
                GuidelineSet      vGuidelineSet = GuidelineSet;

                // Obtain handles for properties that implement DUCE.IResource
                DUCE.ResourceHandle hClipGeometry = vClipGeometry != null ? ((DUCE.IResource)vClipGeometry).GetHandle(channel) : DUCE.ResourceHandle.Null;
                DUCE.ResourceHandle hOpacityMask  = vOpacityMask != null ? ((DUCE.IResource)vOpacityMask).GetHandle(channel) : DUCE.ResourceHandle.Null;
                DUCE.ResourceHandle hTransform;
                if (vTransform == null ||
                    Object.ReferenceEquals(vTransform, Transform.Identity)
                    )
                {
                    hTransform = DUCE.ResourceHandle.Null;
                }
                else
                {
                    hTransform = ((DUCE.IResource)vTransform).GetHandle(channel);
                }
                DUCE.ResourceHandle hGuidelineSet = vGuidelineSet != null ? ((DUCE.IResource)vGuidelineSet).GetHandle(channel) : DUCE.ResourceHandle.Null;

                // Obtain handles for animated properties
                DUCE.ResourceHandle hOpacityAnimations = GetAnimationResourceHandle(OpacityProperty, channel);

                // Store the count of this resource's contained collections in local variables.
                int ChildrenCount = (vChildren == null) ? 0 : vChildren.Count;

                // Pack & send command packet
                DUCE.MILCMD_DRAWINGGROUP data;
                unsafe
                {
                    data.Type          = MILCMD.MilCmdDrawingGroup;
                    data.Handle        = _duceResource.GetHandle(channel);
                    data.ChildrenSize  = (uint)(sizeof(DUCE.ResourceHandle) * ChildrenCount);
                    data.hClipGeometry = hClipGeometry;
                    if (hOpacityAnimations.IsNull)
                    {
                        data.Opacity = Opacity;
                    }
                    data.hOpacityAnimations = hOpacityAnimations;
                    data.hOpacityMask       = hOpacityMask;
                    data.hTransform         = hTransform;
                    data.hGuidelineSet      = hGuidelineSet;
                    data.EdgeMode           = (EdgeMode)GetValue(RenderOptions.EdgeModeProperty);
                    data.bitmapScalingMode  = (BitmapScalingMode)GetValue(RenderOptions.BitmapScalingModeProperty);
                    data.ClearTypeHint      = (ClearTypeHint)GetValue(RenderOptions.ClearTypeHintProperty);

                    channel.BeginCommand(
                        (byte *)&data,
                        sizeof(DUCE.MILCMD_DRAWINGGROUP),
                        (int)(data.ChildrenSize)
                        );


                    // Copy this collection's elements (or their handles) to reserved data
                    for (int i = 0; i < ChildrenCount; i++)
                    {
                        DUCE.ResourceHandle resource = ((DUCE.IResource)vChildren.Internal_GetItem(i)).GetHandle(channel);;
                        channel.AppendCommandData(
                            (byte *)&resource,
                            sizeof(DUCE.ResourceHandle)
                            );
                    }

                    channel.EndCommand();
                }
            }
        }
Beispiel #10
0
        /// <summary>
        /// Called by the base class during Close/Dispose when the content created by
        /// the DrawingDrawingContext needs to be committed.
        /// </summary>
        /// <param name="rootDrawingGroupChildren">
        ///     Collection containing the Drawing elements created with this
        ///     DrawingContext.
        /// </param>
        /// <remarks>
        ///     This will only be called once (at most) per instance.
        /// </remarks>
        protected override void CloseCore(DrawingCollection rootDrawingGroupChildren)
        {
            Debug.Assert(null != _drawingGroup);

            _drawingGroup.Close(rootDrawingGroupChildren);
        }