metrodevice.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ DotNET / DotNET / 8.0 / untmp / WIN_WINDOWS / lh_tools_devdiv_wpf / Windows / wcp / Print / Reach / AlphaFlattener / metrodevice.cs / 2 / metrodevice.cs

                            //------------------------------------------------------------------------------ 
//  Microsoft Printing
//  Copyright (c) Microsoft Corporation, 2004
//
//  File:       MetroDevice.cs 
//
//  History: 
//      [....]: 09/24/2004  Created 
//-----------------------------------------------------------------------------
 
using System;
using System.Diagnostics;
using System.Collections;              // for ArrayList
using System.Windows;                  // for Rect                        WindowsBase.dll 
using System.Windows.Media;            // for Geometry, Brush, ImageData. PresentationCore.dll
using System.Windows.Media.Imaging; 
using System.Windows.Shapes;           // for Glyphs                      PresentationFramework.dll 

using System.Windows.Xps.Serialization; 
using System.Printing;
using System.Printing.Interop;
using System.Security.Permissions;
using System.Security; 
using System.Drawing.Printing;
 
namespace Microsoft.Internal.AlphaFlattener 
{
    ///  
    ///
    /// 
    internal class MetroDevice0
    { 
        [Flags]
        private enum DeviceState 
        { 
            NoChange       = 0,
            Init           = 1, 
            DocStarted     = 2,
            PageStarted    = 4
        };
 
        private enum PushType
        { 
            Opacity, 
            Clip,
            Transform 
        };

        private DeviceState     _state;
 
        private CanvasPrimitive _page;          // Page
        private CanvasPrimitive _root;          // Current root 
        private BrushProxy      _opacityMask;   // Current layer OpacityMask 
        private double          _opacity;       // Current layer Opacity
        private Geometry        _clip;          // Current layer Clip 

        private Stack           _stack;

#if UNIT_TEST 
        static private bool     s_first = true;
#endif 
        ///  
        ///
        ///  
        public MetroDevice0()
        {
#if UNIT_TEST
            if (s_first) 
            {
                s_first = false; 
 
                RectangleIntersection.UnitTest();
            } 
#endif

            _state = DeviceState.Init;
        } 

        private void AssertState(DeviceState state, DeviceState next) 
        { 
            if ((_state & state) != state)
            { 
                throw new InvalidOperationException();
            }

            if (next != DeviceState.NoChange) 
            {
                _state = next; 
            } 
        }
 
        /// 
        ///
        /// 
        public void StartDocument() 
        {
            AssertState(DeviceState.Init, DeviceState.DocStarted); 
        } 

        ///  
        ///
        /// 
        public void EndDocument()
        { 
            AssertState(DeviceState.DocStarted, DeviceState.Init);
        } 
 

        ///  
        ///
        /// 
        public void AbortDocument()
        { 
            _state = DeviceState.Init;
        } 
 
        /// 
        /// 
        /// 
        public bool StartPage()
        {
            AssertState(DeviceState.DocStarted, DeviceState.PageStarted); 

            _page = new CanvasPrimitive(); 
            _root = _page; 
            _stack = new Stack();
 
            _opacity     = 1;
            _opacityMask = null;
            _clip        = null;
 
            return true;
        } 
 
        /// 
        /// Start Tree/alpha flattening and send result to ILegacyDevice interface 
        /// 
        public void FlushPage(ILegacyDevice sink, double width, double height, Nullable outputQuality)
        {
            AssertState(DeviceState.PageStarted, DeviceState.DocStarted); 

            if (_stack.Count != 0) 
            { 
                throw new InvalidOperationException();
            } 

            if (sink != null)
            {
                Flattener.Convert(_root, sink, width, height, 96, 96, outputQuality); 
            }
        } 
 
        public void DrawGeometry(Brush brush, Pen pen, Geometry geometry)
        { 
            // Ignore total transparent primitive
            if (Utility.IsTransparent(_opacity) || ((brush == null) && (pen == null || pen.Brush == null)) || (geometry == null))
            {
                return; 
            }
 
            // Split if having both pen and brush 
            if ((brush != null) && (pen != null))
            // if (!Utility.IsOpaque(_opacity) || (_opacityMask != null)) 
            {
                // Push a canvas to handle geometry with brush + pen properly
                Push(Matrix.Identity, null, 1.0, null, Rect.Empty, false);
 
                DrawGeometry(brush, null, geometry);
                DrawGeometry(null, pen, geometry); 
 
                Pop();
 
                return;
            }

            AssertState(DeviceState.PageStarted, DeviceState.NoChange); 

            GeometryPrimitive g = new GeometryPrimitive(); 
 
            g.Geometry    = geometry;
            g.Clip        = _clip; 
            g.Opacity     = _opacity;
            g.OpacityMask = _opacityMask;

            int needBounds = 0; // 1 for fill, 2 for stroke 

            if (brush != null) 
            { 
                // Fix bug 1427695: Need bounds for non-SolidColorBrushes to enable rebuilding Brush from BrushProxy.
                if (!(brush is SolidColorBrush)) 
                {
                    needBounds |= 1;
                }
            } 

            if ((pen != null) && (pen.Brush != null)) 
            { 
                if (!(pen.Brush is SolidColorBrush))
                { 
                    needBounds |= 2;
                }
            }
 
            if (g.OpacityMask != null)
            { 
                if (g.OpacityMask.BrushList == null && !(g.OpacityMask.Brush is SolidColorBrush)) 
                {
                    if (pen != null) 
                    {
                        needBounds |= 2;
                    }
                    else 
                    {
                        needBounds |= 1; 
                    } 
                }
            } 

            Rect bounds = g.GetRectBounds((needBounds & 1) != 0);

            if (brush != null) 
            {
                g.Brush = BrushProxy.CreateBrush(brush, bounds); 
            } 

            if ((needBounds & 2) != 0) 
            {
                bounds = geometry.GetRenderBounds(pen);
            }
 
            if ((pen != null) && (pen.Brush != null))
            { 
                g.Pen = PenProxy.CreatePen(pen, bounds); 
            }
 
            if (g.OpacityMask != null)
            {
                if (!g.OpacityMask.MakeBrushAbsolute(bounds))
                { 
                    // Fix bug 1463955: Brush has become empty; replace with transparent brush.
                    g.OpacityMask = BrushProxy.CreateColorBrush(Colors.Transparent); 
                } 
            }
 
            // Optimization: Unfold primitive DrawingBrush when possible to avoid rasterizing it.
            Primitive primitive = g.UnfoldDrawingBrush();

            if (primitive != null) 
            {
                _root.Children.Add(primitive); 
            } 
        }
 
        public void DrawImage(ImageSource image, Rect rectangle)
        {
            if (image == null)
                return; 

            AssertState(DeviceState.PageStarted, DeviceState.NoChange); 
 
            ImagePrimitive g = new ImagePrimitive();
 
            g.Image   = new ImageProxy((BitmapSource)image);

            g.DstRect     = rectangle;
            g.Clip        = _clip; 
            g.Opacity     = _opacity;
            g.OpacityMask = _opacityMask; 
 
            _root.Children.Add(g);
        } 

        public void DrawGlyphRun(Brush foreground, GlyphRun glyphRun)
        {
            if (foreground == null) 
                return;
 
            AssertState(DeviceState.PageStarted, DeviceState.NoChange); 

            GlyphPrimitive g = new GlyphPrimitive(); 

            bool needBounds = false;

            if (foreground != null && !(foreground is SolidColorBrush)) 
            {
                needBounds = true; 
            } 

            g.GlyphRun    = glyphRun; 
            g.Brush       = BrushProxy.CreateBrush(foreground, g.GetRectBounds(needBounds));
            g.Clip        = _clip;
            g.Opacity     = _opacity;
            g.OpacityMask = _opacityMask; 

            // Optimization: Unfold primitive DrawingBrush when possible to avoid rasterizing it. 
            Primitive primitive = g.UnfoldDrawingBrush(); 

            if (primitive != null) 
            {
                _root.Children.Add(primitive);
            }
        } 

        public void Push(Matrix transform, Geometry clip, double opacity, Brush opacityMask, Rect maskBounds, bool onePrimitive) 
        { 
            AssertState(DeviceState.PageStarted, DeviceState.NoChange);
 
            opacity = Utility.NormalizeOpacity(opacity);

            if (!Utility.IsValid(transform))
            { 
                // treat as invisible subtree
                opacity = 0.0; 
                transform = Matrix.Identity; 
            }
 
            _stack.Push(_root);
            _stack.Push(_clip);
            _stack.Push(_opacity);
            _stack.Push(_opacityMask); 

            bool noTrans = transform.IsIdentity; 
 
            if (onePrimitive && noTrans && (opacityMask == null))
            { 
                bool empty;

                _clip        = Utility.Intersect(_clip, clip, Matrix.Identity, out empty);
                _opacity    *= opacity; 
                _opacityMask = null;
 
                if (empty) 
                {
                    _opacity = 0; 
                }
            }
            else
            { 
                CanvasPrimitive c = new CanvasPrimitive();
 
                if (noTrans) 
                {
                    c.Transform = Matrix.Identity; 
                }
                else
                {
                    c.Transform = transform; 

                    Matrix invertTransform = transform; 
                    invertTransform.Invert(); 

                    _clip = Utility.TransformGeometry(_clip, invertTransform); // transform inherited clip to this level 
                }

                bool empty;
 
                c.Clip    = Utility.Intersect(clip, _clip, Matrix.Identity, out empty); // Combined with inherited attributes
                c.Opacity = opacity * _opacity; 
 
                if (empty)
                { 
                    c.Opacity = 0; // Invisible
                }

                if (opacityMask != null) 
                {
                    double op; 
 
                    if (Utility.ExtractOpacityMaskOpacity(opacityMask, out op, maskBounds))
                    { 
                        c.Opacity = opacity * _opacity * op;
                    }
                    else
                    { 
                        c.OpacityMask = BrushProxy.CreateOpacityMaskBrush(opacityMask, maskBounds);
                    } 
                } 

                _root.Children.Add(c); 

                _root = c;

                _clip        = null; 
                _opacity     = 1.0;
                _opacityMask = null; 
            } 
        }
 
        public void Pop()
        {
            AssertState(DeviceState.PageStarted, DeviceState.NoChange);
 
            _opacityMask = _stack.Pop() as BrushProxy;
            _opacity     = (double) _stack.Pop(); 
            _clip        = _stack.Pop() as Geometry; 
            _root        = _stack.Pop() as CanvasPrimitive;
        } 

#if COMMENT
        void Comment(string message)
        { 
        }
#endif 
    } 

    ///  
    /// Main interface to NGCSerializationManager, and glue flatteners and GDIExporter together
    ///
    /// 1) Implements IMetroDrawingContext interface
    /// 2) Passes drawing primitives to MetroDevice0 to build a primitive tree 
    /// 3) In FlushPage, calls tree flattener to flat primitive tree to a linear display list
    /// 4) In FlushPage, calls alpha flattener to resolve transparency and send down result on the fly to GDIExporter which implements the ILegacyDevice interface 
    /// 5) In FlushPage, calls GDIExporter.EndPage to finish printing a page 
    /// 6) Supporting Testing hook to serialize alpha flattening result
    ///  
    internal class MetroToGdiConverter : IMetroDrawingContext
    {
        static protected object         s_TestingHook;
 
        protected  MetroDevice0         m_Flattener;
        protected  ILegacyDevice        m_GDIExporter; 
        protected  PrintQueue           m_PrintQueue; 
        protected  PrintTicketConverter m_Converter; // Expensive to create, cache it
 
        /// 
        ///     Critical   : Information got by calling GetDevmode
        /// 
        [SecurityCritical] 
        protected  byte[]             m_Devmode;
 
        // settings captured from current PrintTicket 
        protected  double             m_PageWidth;
        protected  double             m_PageHeight; 

        protected Nullable m_OutputQuality;

        public MetroToGdiConverter(PrintQueue queue) 
        {
            if (queue == null) 
                throw new ArgumentNullException("queue"); 

            m_PrintQueue  = queue; 
            m_Flattener   = new MetroDevice0();
            m_GDIExporter = queue.GetLegacyDevice();
        }
 
        /// 
        ///     Critical   : It asserts PrintingPermission 
        ///  
        [SecurityCritical]
        private byte[] GetDevmode(PrintTicket ticket) 
        {
            Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXGETDEVMODEGUID);

            (new PrintingPermission(PrintingPermissionLevel.DefaultPrinting)).Assert(); // BlessedAssert 

            byte[] result = null; 
 
            try
            { 
                if (m_Converter == null)
                {
                    m_Converter = new PrintTicketConverter(m_PrintQueue.FullName, m_PrintQueue.ClientPrintSchemaVersion);
                } 

                result = m_Converter.ConvertPrintTicketToDevMode(ticket, BaseDevModeType.UserDefault); 
            } 
            finally
            { 
                PrintingPermission.RevertAssert();
            }

            Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXGETDEVMODEGUID); 

            return result; 
        } 

        ///  
        /// Captures settings from complete PrintTickets.
        /// 
        /// 
        ///  
        /// PrintTicket changes are communicated through StartDocument and StartPage, which receive
        /// complete tickets (the merge of tickets at all levels). Lack of change is indicated by 
        /// null. Here we capture settings from PrintTicket for use in flattening and by GDIExporter. 
        /// 
        private void CaptureTicketSettings(PrintTicket ticket) 
        {
            if (ticket == null)
            {
                // ticket has not changed since last capture; keep existing settings 
            }
            else 
            { 
                m_OutputQuality = ticket.OutputQuality;
 
                //
                // Fix bug: 1396328, 1394678: Incorrect page dimensions used for clipping.
                //
                // PrintTicket contains the application-requested page dimensions. The printer 
                // may print to a page of different dimensions; that information is returned in
                // PrintCapabilities, and is what we need to use for clipping. 
                // 
                PrintCapabilities capabilities = m_PrintQueue.GetPrintCapabilities(ticket);
 
                m_PageWidth = capabilities.OrientedPageMediaWidth.GetValueOrDefault(816);
                m_PageHeight = capabilities.OrientedPageMediaHeight.GetValueOrDefault(1056);
            }
        } 

        ///  
        ///     Critical   : It calls GetDevmode and give away the print job id 
        /// 
        /// WasTreatAsSafe: DEVMODE is passed to GDI, not leaked 
        [SecurityCritical]
        public int StartDocument(string jobName, PrintTicket ticket)
        {
            int jobIdentifier = 0; 

            Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXSTARTDOCGUID); 
 
            if (ticket == null)
            { 
                ticket = m_PrintQueue.UserPrintTicket;
            }

            CaptureTicketSettings(ticket); 

            m_Flattener.StartDocument(); 
 
            if (s_TestingHook == null)
            { 
                m_Devmode = GetDevmode(ticket);

                jobIdentifier = m_GDIExporter.StartDocument(m_PrintQueue.FullName, jobName, Configuration.OutputFile, m_Devmode);
            } 

            Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXSTARTDOCGUID); 
 
            return jobIdentifier;
        } 

        public void EndDocument()
        {
            Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXENDDOCGUID); 

            m_Flattener.EndDocument(); 
 
            if (s_TestingHook == null)
            { 
                m_GDIExporter.EndDocument();
            }

            if (m_Converter != null) 
            {
                m_Converter.Dispose(); 
                m_Converter = null; 
            }
 
            Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXENDDOCGUID);
        }

 
        /// 
        ///     Critical   : It calls GetDevmode 
        ///     TreatAsSafe: DEVMODE is passed to GDI, not leaked 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        public void CreateDeviceContext(string jobName, PrintTicket ticket)
        {
            if (ticket == null)
            { 
                ticket = m_PrintQueue.UserPrintTicket;
            } 
 
            CaptureTicketSettings(ticket);
 
            m_Devmode = GetDevmode(ticket);

            m_GDIExporter.CreateDeviceContext(m_PrintQueue.FullName, jobName, m_Devmode);
        } 

        public void DeleteDeviceContext() 
        { 
            m_GDIExporter.DeleteDeviceContext();
        } 

        public void StartDocumentWithoutCreatingDC(String jobName)
        {
            m_Flattener.StartDocument(); 

            String printerName = m_PrintQueue.FullName; 
 
            m_GDIExporter.StartDocumentWithoutCreatingDC(printerName, jobName, Configuration.OutputFile);
        } 

        public string ExtEscGetName()
        {
            return m_GDIExporter.ExtEscGetName(); 
        }
 
        public bool ExtEscMXDWPassThru() 
        {
            return m_GDIExporter.ExtEscMXDWPassThru(); 
        }

        public void AbortDocument()
        { 
            m_Flattener.AbortDocument();
 
            m_GDIExporter.EndDocument(); 

            if (m_Converter != null) 
            {
                m_Converter.Dispose();
                m_Converter = null;
            } 
        }
 
        ///  
        ///     Critical   : It calls GetDevmode
        ///     TreatAsSafe: DEVMODE is passed to GDI, not leaked 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public void StartPage(PrintTicket ticket)
        { 
            Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXSTARTPAGEGUID);
 
            CaptureTicketSettings(ticket); 

            if (m_Flattener.StartPage()) 
            {
                if (s_TestingHook == null)
                {
                    if (ticket != null) 
                    {
                        m_GDIExporter.StartPage(GetDevmode(ticket), Configuration.RasterizationDPI); 
                    } 
                    else
                    { 
                        m_GDIExporter.StartPage(null, Configuration.RasterizationDPI);
                    }
                }
            } 

            Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXSTARTPAGEGUID); 
        } 

        public void FlushPage() 
        {
            Toolbox.StartEvent(Toolbox.DRXFLUSHPAGEGUID);

            ILegacyDevice ioc = m_GDIExporter; 

            if (s_TestingHook != null) 
            { 
                DrawingContext dc = s_TestingHook as DrawingContext;
 
                if (dc != null)
                {
                    // Send alpha flattening output to a DrawingContext for testing
                    ioc = new OutputContext(dc); 
                }
            } 
 
            m_Flattener.FlushPage(ioc, m_PageWidth, m_PageHeight, m_OutputQuality);
 
            if (s_TestingHook == null)
            {
                Toolbox.StartEvent(MS.Utility.EventTraceGuidId.DRXENDPAGEGUID);
                m_GDIExporter.EndPage(); 
                Toolbox.EndEvent(MS.Utility.EventTraceGuidId.DRXENDPAGEGUID);
            } 
 
            Toolbox.EndEvent(Toolbox.DRXFLUSHPAGEGUID);
        } 

        void IMetroDrawingContext.DrawGeometry(Brush brush, Pen pen, Geometry geometry)
        {
            m_Flattener.DrawGeometry(brush, pen, geometry); 
        }
 
        void IMetroDrawingContext.DrawImage(ImageSource image, Rect rectangle) 
        {
            m_Flattener.DrawImage(image, rectangle); 
        }

        void IMetroDrawingContext.DrawGlyphRun(Brush foreground, GlyphRun glyphRun)
        { 
            m_Flattener.DrawGlyphRun(foreground, glyphRun);
        } 
 
        void IMetroDrawingContext.Push(
            Matrix transform, 
            Geometry clip,
            double opacity,
            Brush opacityMask,
            Rect maskBounds, 
            bool onePrimitive,
 
            // serialization attributes 
            String nameAttr,
            Visual node, 
            Uri navigateUri,
            EdgeMode edgeMode
            )
        { 
            m_Flattener.Push(transform, clip, opacity, opacityMask, maskBounds, onePrimitive);
        } 
 
        void IMetroDrawingContext.Pop()
        { 
            m_Flattener.Pop();
        }

        void IMetroDrawingContext.Comment(string message) 
        {
        } 
 
        /// 
        /// Called before StartDocument to by-pass GDIExporter and send result to DrawingContext 
        /// 
        /// 
        static public void TestingHook(Object obj)
        { 
            if (obj != null)
            { 
                s_TestingHook = obj as DrawingContext; 
            }
        } 
    }
} // end of namespace

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK