| File: System\Windows\Media\DrawingVisual.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\PresentationCore\PresentationCore.csproj (PresentationCore) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // using System.Windows.Media.Composition; namespace System.Windows.Media { /// <summary> /// A DrawingVisual is a Visual that can be used to render Vector graphics on the screen. /// The content is persistet by the System. /// </summary> public class DrawingVisual : ContainerVisual { // bbox in inner coordinate space. Note that this bbox does not // contain the childrens extent. private IDrawingContent _content; /// <summary> /// HitTestCore implements precise hit testing against render contents /// </summary> protected override HitTestResult HitTestCore(PointHitTestParameters hitTestParameters) { ArgumentNullException.ThrowIfNull(hitTestParameters); if (_content != null) { if (_content.HitTestPoint(hitTestParameters.HitPoint)) { return new PointHitTestResult(this, hitTestParameters.HitPoint); } } return null; } /// <summary> /// HitTestCore implements precise hit testing against render contents /// </summary> protected override GeometryHitTestResult HitTestCore(GeometryHitTestParameters hitTestParameters) { ArgumentNullException.ThrowIfNull(hitTestParameters); if ((_content != null) && GetHitTestBounds().IntersectsWith(hitTestParameters.Bounds)) { IntersectionDetail intersectionDetail; intersectionDetail = _content.HitTestGeometry(hitTestParameters.InternalHitGeometry); Debug.Assert(intersectionDetail != IntersectionDetail.NotCalculated); if (intersectionDetail != IntersectionDetail.Empty) { return new GeometryHitTestResult(this, intersectionDetail); } } return null; } /// <summary> /// Opens the DrawingVisual for rendering. The returned DrawingContext can be used to /// render into the DrawingVisual. /// </summary> public DrawingContext RenderOpen() { VerifyAPIReadWrite(); return new VisualDrawingContext(this); } /// <summary> /// Called from the DrawingContext when the DrawingContext is closed. /// </summary> internal override void RenderClose(IDrawingContent newContent) { IDrawingContent oldContent; // // First cleanup the old content and the state associate with this node // related to it's content. // oldContent = _content; _content = null; if (oldContent != null) { // // Remove the notification handlers. // oldContent.PropagateChangedHandler(ContentsChangedHandler, adding: false); // // Disconnect the old content from this visual. // DisconnectAttachedResource( VisualProxyFlags.IsContentConnected, ((DUCE.IResource)oldContent)); } // // Prepare the new content. // // Propagate notification handlers. newContent?.PropagateChangedHandler(ContentsChangedHandler, adding: true); _content = newContent; // // Mark the visual dirty on all channels and propagate // the flags up the parent chain. // SetFlagsOnAllChannels(true, VisualProxyFlags.IsContentDirty); PropagateFlags( this, VisualFlags.IsSubtreeDirtyForPrecompute, VisualProxyFlags.IsSubtreeDirtyForRender); } /// <summary> /// Overriding this function to release DUCE resources during Dispose and during removal of a subtree. /// </summary> internal override void FreeContent(DUCE.Channel channel) { Debug.Assert(_proxy.IsOnChannel(channel)); if (_content != null) { if (CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)) { DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), DUCE.ResourceHandle.Null, channel); SetFlags( channel, false, VisualProxyFlags.IsContentConnected); ((DUCE.IResource)_content).ReleaseOnChannel(channel); } } // Call the base method too base.FreeContent(channel); } /// <summary> /// Returns the bounding box of the content. /// </summary> internal override Rect GetContentBounds() { if (_content != null) { Rect resultRect = Rect.Empty; MediaContext mediaContext = MediaContext.From(Dispatcher); BoundsDrawingContextWalker ctx = mediaContext.AcquireBoundsDrawingContextWalker(); resultRect = _content.GetContentBounds(ctx); mediaContext.ReleaseBoundsDrawingContextWalker(ctx); return resultRect; } else { return Rect.Empty; } } /// <summary> /// WalkContent - method which walks the content (if present) and calls out to the /// supplied DrawingContextWalker. /// </summary> /// <param name="walker"> /// DrawingContextWalker - the target of the calls which occur during /// the content walk. /// </param> internal void WalkContent(DrawingContextWalker walker) { VerifyAPIReadOnly(); _content?.WalkContent(walker); } /// <summary> /// RenderContent is implemented by derived classes to hook up their /// content. The implementer of this function can assert that the _hCompNode /// is valid on a channel when the function is executed. /// </summary> internal override void RenderContent(RenderContext ctx, bool isOnChannel) { DUCE.Channel channel = ctx.Channel; Debug.Assert(!CheckFlagsAnd(channel, VisualProxyFlags.IsContentConnected)); Debug.Assert(_proxy.IsOnChannel(channel)); // // Create the content on the channel. // if (_content != null) { DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), ((DUCE.IResource)_content).AddRefOnChannel(channel), channel); SetFlags( channel, true, VisualProxyFlags.IsContentConnected); } else if (isOnChannel) /*_content == null*/ { DUCE.CompositionNode.SetContent( _proxy.GetHandle(channel), DUCE.ResourceHandle.Null, channel); } } /// <summary> /// GetDrawing - Returns the drawing content of this Visual. /// </summary> /// <remarks> /// Changes to this DrawingGroup will not be propagated to the Visual's content. /// This method is called by both the Drawing property, and VisualTreeHelper.GetDrawing() /// </remarks> internal override DrawingGroup GetDrawing() { // Need to determine if Visual.Drawing should return mutable content VerifyAPIReadOnly(); DrawingGroup drawingGroupContent = null; // Convert our content to a DrawingGroup, if content exists if (_content != null) { drawingGroupContent = DrawingServices.DrawingGroupFromRenderData((RenderData) _content); } return drawingGroupContent; } /// <summary> /// Drawing - Returns the drawing content of this Visual. /// </summary> /// <remarks> /// Changes to this DrawingGroup will not propagated to the Visual's content. /// </remarks> public DrawingGroup Drawing { get { return GetDrawing(); } } } }