| File: Serialization\Manager\NGCSerializationManager.cs | Web Access |
| Project: src\wpf\src\Microsoft.DotNet.Wpf\src\ReachFramework\ReachFramework.csproj (ReachFramework) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Xml; using System.Windows.Xps.Packaging; using System.Windows.Media; using System.Printing; using MS.Utility; using Microsoft.Internal.AlphaFlattener; // // Ngc = Next Generation Converter. It means to convert the avalon element tree // to the downlevel GDI primitives. // namespace System.Windows.Xps.Serialization { /// <summary> /// NgcSerializationManager is a class to help print avalon content (element tree) to traditional printer /// </summary> //[CLSCompliant(false)] internal sealed class NgcSerializationManager : PackageSerializationManager { #region Constructor /// <summary> /// This constructor take PrintQueue parameter /// </summary> /// <exception cref="ArgumentNullException">queue is NULL.</exception> public NgcSerializationManager( PrintQueue queue, bool isBatchMode ): base() { ArgumentNullException.ThrowIfNull(queue); _printQueue = queue; this._isBatchMode = isBatchMode; this._isSimulating = false; this._printTicketManager = new NgcPrintTicketManager(_printQueue); } #endregion Construtor #region PackageSerializationManager override /// <summary> /// The function will serializer the avalon content to the printer spool file. /// SaveAsXaml is not a propriate name. Maybe it should be "Print" /// </summary> /// <exception cref="ArgumentNullException">serializedObject is NULL.</exception> /// <exception cref="XpsSerializationException">serializedObject is not a supported type.</exception> public override void SaveAsXaml( Object serializedObject ) { Toolbox.EmitEvent(EventTrace.Event.WClientDRXSaveXpsBegin); ArgumentNullException.ThrowIfNull(serializedObject); if (!IsSerializedObjectTypeSupported(serializedObject)) { throw new XpsSerializationException(SR.ReachSerialization_NotSupported); } if(_isBatchMode && !_isSimulating) { XpsSerializationPrintTicketRequiredEventArgs printTicketEvent = new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentSequencePrintTicket, 0); OnNGCSerializationPrintTicketRequired(printTicketEvent); StartDocument(null,true); _isSimulating = true; } if(_isBatchMode) { StartPage(); } if(!_isBatchMode && IsDocumentSequencePrintTicketRequired(serializedObject)) { XpsSerializationPrintTicketRequiredEventArgs printTicketEvent = new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentSequencePrintTicket, 0); OnNGCSerializationPrintTicketRequired(printTicketEvent); } ReachSerializer reachSerializer = GetSerializer(serializedObject); if(reachSerializer != null) { // // Call top-level type serializer, it will walk through the contents and // all CLR and DP properties of the object and invoke the proper serializer // and typeconverter respectively // reachSerializer.SerializeObject(serializedObject); if(_isBatchMode) { EndPage(); } } else { throw new XpsSerializationException(SR.ReachSerialization_NoSerializer); } Toolbox.EmitEvent(EventTrace.Event.WClientDRXSaveXpsEnd); } /// <summary> /// /// </summary> public void Cancel( ) { if(_startDocCnt != 0 ) { _device.AbortDocument(); _startDocCnt = 0; } } /// <summary> /// /// </summary> public void Commit( ) { if(_isBatchMode && _isSimulating) { EndDocument(); } else { // // throw the appropariate exception // } } /// <summary> /// /// </summary> public event XpsSerializationPrintTicketRequiredEventHandler XpsSerializationPrintTicketRequired; /// <summary> /// /// </summary> public event XpsSerializationProgressChangedEventHandler XpsSerializationProgressChanged; /// <summary> /// This function GetXmlNSForType and the other four XML writer functiosn (like AcquireXmlWriter) /// and the two stream function (like ReleaseResourceStream) should be removed from /// the base PackageSerializationManager class. /// </summary> internal override String GetXmlNSForType( Type objectType ) { return null; } /// <summary> /// /// </summary> internal override ReachSerializer GetSerializer( Object serializedObject ) { ReachSerializer reachSerializer = null; if((reachSerializer = base.GetSerializer(serializedObject)) == null) { reachSerializer = this.SerializersCacheManager.GetSerializer(serializedObject); } return reachSerializer; } /// <summary> /// /// </summary> internal override Type GetSerializerType( Type objectType ) { Type serializerType = null; if((serializerType = base.GetSerializerType(objectType)) == null) { if (typeof(System.Windows.Documents.FixedDocumentSequence).IsAssignableFrom(objectType)) { serializerType = typeof(NgcDocumentSequenceSerializer); } else if (typeof(System.Windows.Documents.DocumentReferenceCollection).IsAssignableFrom(objectType)) { serializerType = typeof(NgcDocumentReferenceCollectionSerializer); } else if (typeof(System.Windows.Documents.FixedDocument).IsAssignableFrom(objectType)) { serializerType = typeof(NgcFixedDocumentSerializer); } else if(typeof(System.Windows.Documents.PageContentCollection).IsAssignableFrom(objectType)) { serializerType = typeof(NGCReachPageContentCollectionSerializer); } else if(typeof(System.Windows.Documents.PageContent).IsAssignableFrom(objectType)) { serializerType = typeof(NGCReachPageContentSerializer); } else if(typeof(System.Windows.Controls.UIElementCollection).IsAssignableFrom(objectType)) { serializerType = typeof(NGCReachUIElementCollectionSerializer); } else if(typeof(System.Windows.Documents.FixedPage).IsAssignableFrom(objectType)) { serializerType = typeof(NgcFixedPageSerializer); } else if (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(objectType)) { serializerType = typeof(NgcDocumentPaginatorSerializer); } else if (typeof(System.Windows.Documents.DocumentPage).IsAssignableFrom(objectType)) { serializerType = typeof(NgcDocumentPageSerializer); } else if (typeof(System.Windows.Media.Visual).IsAssignableFrom(objectType)) { serializerType = typeof(NgcReachVisualSerializer); } } return serializerType; } internal override XmlWriter AcquireXmlWriter( Type writerType ) { return null; } internal override void ReleaseXmlWriter( Type writerType ) { return; } internal override XpsResourceStream AcquireResourceStream( Type resourceType ) { return null; } internal override XpsResourceStream AcquireResourceStream( Type resourceType, String resourceID ) { return null; } internal override void ReleaseResourceStream( Type resourceType ) { return; } internal override void ReleaseResourceStream( Type resourceType, String resourceID ) { return; } internal override void AddRelationshipToCurrentPage( Uri targetUri, string relationshipName ) { return; } internal override XpsResourcePolicy ResourcePolicy { get { return null; } } internal override BasePackagingPolicy PackagingPolicy { get { return null; } } #endregion PackageSerializationManager override #region Internal Properties /// <summary> /// /// </summary> internal PrintQueue PrintQueue { get { return _printQueue; } } internal String JobName { set { if (_jobName == null) { _jobName = value; } } get { return _jobName; } } internal Size PageSize { set { _pageSize = value; } get { return _pageSize; } } #endregion Internal Properties #region Internal Methods internal void StartDocument( Object o, bool documentPrintTicketRequired ) { if(documentPrintTicketRequired) { XpsSerializationPrintTicketRequiredEventArgs e = new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedDocumentPrintTicket, 0); OnNGCSerializationPrintTicketRequired(e); } if( _startDocCnt == 0 ) { JobName = _printQueue.CurrentJobSettings.Description; if(JobName == null) { JobName = NgcSerializerUtil.InferJobName(o); } _device = new MetroToGdiConverter(PrintQueue); if (!_isSimulating) { JobIdentifier = _device.StartDocument(_jobName, _printTicketManager.ConsumeActivePrintTicket(true)); } } _startDocCnt++; } /// <summary> /// /// </summary> /// internal void EndDocument() { if( _startDocCnt == 1 ) { _device.EndDocument(); // // Inform any potential listeners that the document has been printed // XpsSerializationProgressChangedEventArgs e = new XpsSerializationProgressChangedEventArgs(XpsWritingProgressChangeLevel.FixedDocumentWritingProgress, 0, 0, null); OnNGCSerializationProgressChagned(e); } _startDocCnt--; } /// <summary> /// /// </summary> /// internal bool StartPage() { bool bManulStartDoc = false; if (_startDocCnt == 0) { StartDocument(null,true); bManulStartDoc = true; } if(!_isStartPage) { if (!_isPrintTicketMerged) { XpsSerializationPrintTicketRequiredEventArgs e = new XpsSerializationPrintTicketRequiredEventArgs(PrintTicketLevel.FixedPagePrintTicket, 0); OnNGCSerializationPrintTicketRequired(e); } _device.StartPage(_printTicketManager.ConsumeActivePrintTicket(true)); _isStartPage = true; } return bManulStartDoc; } /// <summary> /// /// </summary> /// internal void EndPage() { if (_isStartPage) { try { _device.FlushPage(); } catch (PrintingCanceledException ) { _device.EndDocument(); throw; } } _isStartPage = false; _isPrintTicketMerged = false; // // Inform any potential listeners that the page has been printed // XpsSerializationProgressChangedEventArgs e = new XpsSerializationProgressChangedEventArgs(XpsWritingProgressChangeLevel.FixedPageWritingProgress, 0, 0, null); OnNGCSerializationProgressChagned(e); } internal void OnNGCSerializationPrintTicketRequired( object operationState ) { XpsSerializationPrintTicketRequiredEventArgs e = operationState as XpsSerializationPrintTicketRequiredEventArgs; if(XpsSerializationPrintTicketRequired != null) { e.Modified = true; if (e.PrintTicketLevel == PrintTicketLevel.FixedPagePrintTicket) { _isPrintTicketMerged = true; } XpsSerializationPrintTicketRequired(this,e); _printTicketManager.ConstructPrintTicketTree(e); } } internal void OnNGCSerializationProgressChagned( object operationState ) { XpsSerializationProgressChangedEventArgs e = operationState as XpsSerializationProgressChangedEventArgs; if(XpsSerializationProgressChanged != null) { XpsSerializationProgressChanged(this,e); } } /// <summary> /// /// </summary> /// internal void WalkVisual( Visual visual ) { bool bManulStartDoc = false; bool bManulStartpage = false; if (_startDocCnt == 0) { StartDocument(visual,true); bManulStartDoc = true; } if (!_isStartPage) { StartPage(); bManulStartpage = true; } // // Call VisualTreeFlattener to flatten the visual on IMetroDrawingContext // Toolbox.EmitEvent(EventTrace.Event.WClientDRXLoadPrimitiveBegin); VisualTreeFlattener.Walk(visual, _device, PageSize, new TreeWalkProgress()); Toolbox.EmitEvent(EventTrace.Event.WClientDRXLoadPrimitiveEnd); if (bManulStartpage) { EndPage(); } if (bManulStartDoc) { EndDocument(); } } internal PrintTicket GetActivePrintTicket() { return _printTicketManager.ActivePrintTicket; } internal bool IsPrintTicketEventHandlerEnabled { get { if(XpsSerializationPrintTicketRequired!=null) { return true; } else { return false; } } } private bool IsSerializedObjectTypeSupported( Object serializedObject ) { bool isSupported = false; Type serializedObjectType = serializedObject.GetType(); if(_isBatchMode) { if((typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) && (serializedObjectType != typeof(System.Windows.Documents.FixedPage))) { isSupported = true; } } else { if ( (serializedObjectType == typeof(System.Windows.Documents.FixedDocumentSequence)) || (serializedObjectType == typeof(System.Windows.Documents.FixedDocument)) || (serializedObjectType == typeof(System.Windows.Documents.FixedPage)) || (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(serializedObjectType)) || (typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) ) { isSupported = true; } } return isSupported; } private bool IsDocumentSequencePrintTicketRequired( Object serializedObject ) { bool isRequired = false; Type serializedObjectType = serializedObject.GetType(); if ((serializedObjectType == typeof(System.Windows.Documents.FixedDocument)) || (serializedObjectType == typeof(System.Windows.Documents.FixedPage)) || (typeof(System.Windows.Documents.DocumentPaginator).IsAssignableFrom(serializedObjectType)) || (typeof(System.Windows.Media.Visual).IsAssignableFrom(serializedObjectType)) ) { isRequired = true; } return isRequired; } #endregion Internal Methods #region Private Member private PrintQueue _printQueue; private int _startDocCnt; private bool _isStartPage; private MetroToGdiConverter _device; private String _jobName; private bool _isBatchMode; private bool _isSimulating; private NgcPrintTicketManager _printTicketManager; private bool _isPrintTicketMerged; private Size _pageSize = new Size(816,1056); #endregion Private Member }; internal sealed class NgcPrintTicketManager { #region constructor public NgcPrintTicketManager( PrintQueue printQueue ) { this._printQueue = printQueue; this._fdsPrintTicket = null; this._fdPrintTicket = null; this._fpPrintTicket = null; this._rootPrintTicket = null; this._activePrintTicket = null; this._isActiveUpdated = false; this.m_validatedPrintTicketCache = new MS.Internal.Printing.MostFrequentlyUsedCache<string, PrintTicket>(s_PrintTicketCacheMaxCount); } #endregion constructor #region Public Methods public void ConstructPrintTicketTree( XpsSerializationPrintTicketRequiredEventArgs args ) { switch(args.PrintTicketLevel) { case PrintTicketLevel.FixedDocumentSequencePrintTicket: { if(args.PrintTicket != null) { _fdsPrintTicket = args.PrintTicket; _rootPrintTicket = _fdsPrintTicket; } else { _rootPrintTicket = new PrintTicket(_printQueue.UserPrintTicket.GetXmlStream()); } _activePrintTicket = _rootPrintTicket; _isActiveUpdated = true; break; } case PrintTicketLevel.FixedDocumentPrintTicket: { if(args.PrintTicket != null) { _fdPrintTicket = args.PrintTicket; if(_fdsPrintTicket!=null) { // // we have to merge the 2 print tickets // _rootPrintTicket = _printQueue. MergeAndValidatePrintTicket(_fdsPrintTicket, _fdPrintTicket). ValidatedPrintTicket; } else { _rootPrintTicket = _fdPrintTicket; } } else { _fdPrintTicket = null; _rootPrintTicket = _fdsPrintTicket; } if(_rootPrintTicket == null) { _rootPrintTicket = new PrintTicket(_printQueue.UserPrintTicket.GetXmlStream()); } _activePrintTicket = _rootPrintTicket; _isActiveUpdated = true; break; } case PrintTicketLevel.FixedPagePrintTicket: { if(args.PrintTicket != null) { _fpPrintTicket = args.PrintTicket; // The NULL check might not be needed but just in case... String printTicketPairXMLStr = (_rootPrintTicket == null ? "" : _rootPrintTicket.ToXmlString()) + (_fpPrintTicket == null ? "" : _fpPrintTicket.ToXmlString()); PrintTicket newActivePrintTicket; if (!m_validatedPrintTicketCache.TryGetValue(printTicketPairXMLStr, out newActivePrintTicket)) { // // we have to merge the 2 print tickets // newActivePrintTicket = _printQueue. MergeAndValidatePrintTicket(_rootPrintTicket, _fpPrintTicket). ValidatedPrintTicket; m_validatedPrintTicketCache.CacheValue(printTicketPairXMLStr, newActivePrintTicket); } // Ensure cache values are immutable. _activePrintTicket = newActivePrintTicket.Clone (); _isActiveUpdated = true; } else { if(_fpPrintTicket != null) { _fpPrintTicket = null; _activePrintTicket = _rootPrintTicket; _isActiveUpdated = true; } } break; } default: { break; } } } public PrintTicket ConsumeActivePrintTicket( bool consumePrintTicket ) { PrintTicket printTicket = null; if (_activePrintTicket == null && _rootPrintTicket == null) { _activePrintTicket = new PrintTicket(_printQueue.UserPrintTicket.GetXmlStream()); _rootPrintTicket = _activePrintTicket; printTicket = _activePrintTicket; } else if (_isActiveUpdated) { printTicket = _activePrintTicket; if (consumePrintTicket) { _isActiveUpdated = false; } } return printTicket; } #endregion Public Methods #region Public Properties public PrintTicket ActivePrintTicket { get { //Call Consume Active Print Ticket with false flag, to get the current print ticket but do not consume it //so it can be retrieved again return ConsumeActivePrintTicket(false); } } #endregion Public Properties #region Private Members // duplicated code with metrodevice.cs is bad // PrintTicket XML Strings start at 4KB so we don't want the keys // from chewing all memory. Limit to a small amount. private const int s_PrintTicketCacheMaxCount = 10; // Key = Pair of PrintTicket's whose XML (as strings) are concatenated // Value = PrintTicket // // 1. Dictionary keys and values must never be: // - null // - mutated // 2. Only cache per-page calculations because cache entries are preciously // limited. private MS.Internal.Printing.MostFrequentlyUsedCache<string, PrintTicket> m_validatedPrintTicketCache; private PrintQueue _printQueue; private PrintTicket _fdsPrintTicket; private PrintTicket _fdPrintTicket; private PrintTicket _fpPrintTicket; private PrintTicket _rootPrintTicket; private PrintTicket _activePrintTicket; private bool _isActiveUpdated; #endregion Private Members } internal sealed class MXDWSerializationManager { #region constructor public MXDWSerializationManager( PrintQueue queue ) { this._jobName = null; this._gdiDevice = null; this._mxdwFileName = null; _printQueue = queue; _jobName = _printQueue.CurrentJobSettings.Description; if(_jobName == null) { _jobName = NgcSerializerUtil.InferJobName(null); } _gdiDevice = new MetroToGdiConverter(_printQueue); GdiDevice.CreateDeviceContext(_jobName, InferPrintTicket()); _isPassThruSupported = GdiDevice.ExtEscMXDWPassThru(); GdiDevice.DeleteDeviceContext(); } #endregion constructor public void EnablePassThru( ) { GdiDevice.CreateDeviceContext(_jobName, InferPrintTicket()); GdiDevice.ExtEscMXDWPassThru(); GdiDevice.StartDocumentWithoutCreatingDC(_jobName); _mxdwFileName = GdiDevice.ExtEscGetName(); } public String MxdwFileName { get { return _mxdwFileName; } } public bool IsPassThruSupported { get { return _isPassThruSupported; } } public void Commit( ) { GdiDevice.EndDocument(); } private PrintTicket InferPrintTicket( ) { PrintTicket printTicket = new PrintTicket(_printQueue.UserPrintTicket.GetXmlStream()); return printTicket; } private MetroToGdiConverter GdiDevice { get { return _gdiDevice; } } private PrintQueue _printQueue; private MetroToGdiConverter _gdiDevice; private String _jobName; private String _mxdwFileName; private bool _isPassThruSupported; }; }