FlowDocumentFormatter.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 / Framework / MS / Internal / documents / FlowDocumentFormatter.cs / 1 / FlowDocumentFormatter.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: FlowDocumentFormatter.cs 
//
// Description: Bottomless content formatter associated with FlowDocument. 
// 
// History:
//  11/07/2005 : [....] - created. 
//
//---------------------------------------------------------------------------

using System;                       // Object 
using System.Windows;               // Size
using System.Windows.Documents;     // FlowDocument 
using System.Windows.Media;         // Visual 
using System.Windows.Threading;     // DispatcherOperationCallback
using MS.Internal.PtsHost;          // FlowDocumentPage 
using MS.Internal.PtsHost.UnsafeNativeMethods;  // PTS

namespace MS.Internal.Documents
{ 
    /// 
    /// Bottomless content formatter associated with FlowDocument. 
    ///  
    internal class FlowDocumentFormatter : IFlowDocumentFormatter
    { 
        //-------------------------------------------------------------------
        //
        //  Constructors
        // 
        //-------------------------------------------------------------------
 
        #region Constructors 

        ///  
        /// Constructor
        /// 
        internal FlowDocumentFormatter(FlowDocument document)
        { 
            _document = document;
            _documentPage = new FlowDocumentPage(_document.StructuralCache); 
        } 

        #endregion Constructors 

        //--------------------------------------------------------------------
        //
        //  Internal Methods 
        //
        //------------------------------------------------------------------- 
 
        #region Internal Methods
 
        /// 
        /// Formatts content.
        /// 
        /// Constraint size. 
        internal void Format(Size constraint)
        { 
            Thickness pageMargin; 
            Size pageSize;
 
            // Reentrancy check.
            if (_document.StructuralCache.IsFormattingInProgress)
            {
                throw new InvalidOperationException(SR.Get(SRID.FlowDocumentFormattingReentrancy)); 
            }
            if (_document.StructuralCache.IsContentChangeInProgress) 
            { 
                throw new InvalidOperationException(SR.Get(SRID.TextContainerChangingReentrancyInvalid));
            } 

            // Check if we can continue with formatting without nuking incremental udpate info.
            if (_document.StructuralCache.IsFormattedOnce)
            { 
                if (!_lastFormatSuccessful)
                { 
                    // We cannot resolve update info if last formatting was unsuccessful. 
                    _document.StructuralCache.InvalidateFormatCache(true);
                } 
                if (!_arrangedAfterFormat && (!_document.StructuralCache.ForceReformat || !_document.StructuralCache.NukeStructure))
                {
                    // Need to clear update info by running arrange process.
                    // This is necessary, because Format may be called more than once 
                    // before Arrange is called. But PTS is not able to merge update info.
                    // To protect against loosing incremental changes delta, need 
                    // to arrange the page and create all necessary visuals. 
                    _documentPage.Arrange(_documentPage.ContentSize);
                    _documentPage.EnsureValidVisuals(); 
                }
            }
            _arrangedAfterFormat = false;
            _lastFormatSuccessful = false; 
            _isContentFormatValid = false;
 
            pageSize = ComputePageSize(constraint); 
            pageMargin = ComputePageMargin();
 
            // Disable processing of the queue during blocking operations to prevent unrelated reentrancy.
            using (_document.Dispatcher.DisableProcessing())
            {
                _document.StructuralCache.IsFormattingInProgress = true; // Set reentrancy flag. 
                try
                { 
                    _document.StructuralCache.BackgroundFormatInfo.ViewportHeight = constraint.Height; 
                    _documentPage.FormatBottomless(pageSize, pageMargin);
                } 
                finally
                {
                    _document.StructuralCache.IsFormattingInProgress = false; // Clear reentrancy flag.
                } 
            }
            _lastFormatSuccessful = true; 
        } 

        ///  
        /// Arranges content.
        /// 
        /// Size that element should use to arrange itself and its children.
        /// Viewport for visible content. 
        internal void Arrange(Size arrangeSize, Rect viewport)
        { 
            Invariant.Assert(_document.StructuralCache.DtrList == null || _document.StructuralCache.DtrList.Length == 0 || 
                             (_document.StructuralCache.DtrList.Length == 1 && _document.StructuralCache.BackgroundFormatInfo.DoesFinalDTRCoverRestOfText));
 
            // Arrange the content and create visual tree.
            _documentPage.Arrange(arrangeSize);
            _documentPage.EnsureValidVisuals();
            _arrangedAfterFormat = true; 

            // Render content only for the current viewport. 
            if (viewport.IsEmpty) 
            {
                viewport = new Rect(0, 0, arrangeSize.Width, _document.StructuralCache.BackgroundFormatInfo.ViewportHeight); 
            }
            PTS.FSRECT fsrectViewport = new PTS.FSRECT(viewport);
            _documentPage.UpdateViewport(ref fsrectViewport, true);
 
            _isContentFormatValid = true;
        } 
 
        #endregion Internal Methods
 
        //--------------------------------------------------------------------
        //
        //  Internal Properties
        // 
        //--------------------------------------------------------------------
 
        #region Internal Properties 

        ///  
        /// DocumentPage representing formatted content.
        /// 
        internal FlowDocumentPage DocumentPage
        { 
            get
            { 
                return _documentPage; 
            }
        } 

        #endregion Internal Properties

        //------------------------------------------------------------------- 
        //
        //  Internal Events 
        // 
        //--------------------------------------------------------------------
 
        #region Internal Events

        /// 
        /// Fired when content has been invalidated. 
        /// 
        internal event EventHandler ContentInvalidated; 
 
        /// 
        /// Fired when formatter has been suspended. 
        /// 
        internal event EventHandler Suspended;

        #endregion Internal Events 

        //------------------------------------------------------------------- 
        // 
        //  Private Methods
        // 
        //-------------------------------------------------------------------

        #region Private Methods
 
        /// 
        /// Compute size for the page. 
        ///  
        private Size ComputePageSize(Size constraint)
        { 
            double max, min;
            Size pageSize = new Size(_document.PageWidth, double.PositiveInfinity);
            if (DoubleUtil.IsNaN(pageSize.Width))
            { 
                pageSize.Width = constraint.Width;
                max = _document.MaxPageWidth; 
                if (pageSize.Width > max) 
                {
                    pageSize.Width = max; 
                }
                min = _document.MinPageWidth;
                if (pageSize.Width < min)
                { 
                    pageSize.Width = min;
                } 
            } 
            // If the width is Double.PositiveInfinity, crop it to predefined value.
            if (double.IsPositiveInfinity(pageSize.Width)) 
            {
                pageSize.Width = _defaultWidth;
            }
            return pageSize; 
        }
 
        ///  
        /// Compute margin for the page.
        ///  
        private Thickness ComputePageMargin()
        {
            double lineHeight = MS.Internal.Text.DynamicPropertyReader.GetLineHeightValue(_document);
            Thickness pageMargin = _document.PagePadding; 

            // If Padding value is 'Auto', treat it as 1*LineHeight. 
            if (DoubleUtil.IsNaN(pageMargin.Left)) 
            {
                pageMargin.Left = lineHeight; 
            }
            if (DoubleUtil.IsNaN(pageMargin.Top))
            {
                pageMargin.Top = lineHeight; 
            }
            if (DoubleUtil.IsNaN(pageMargin.Right)) 
            { 
                pageMargin.Right = lineHeight;
            } 
            if (DoubleUtil.IsNaN(pageMargin.Bottom))
            {
                pageMargin.Bottom = lineHeight;
            } 
            return pageMargin;
        } 
 
        #endregion Private Methods
 
        //-------------------------------------------------------------------
        //
        //  Private Fields
        // 
        //--------------------------------------------------------------------
 
        #region Private Fields 

        ///  
        /// FlowDocument associated with the paginator.
        /// 
        private readonly FlowDocument _document;
 
        /// 
        /// DocumentPage representing formatted content. 
        ///  
        private FlowDocumentPage _documentPage;
 
        /// 
        /// Whether Arrange was called after formatting.
        /// 
        private bool _arrangedAfterFormat; 

        ///  
        /// Whether last formatting was succesful. 
        /// 
        private bool _lastFormatSuccessful; 

        /// 
        /// Width used when no width is specified.
        ///  
        private const double _defaultWidth = 500.0;
 
        ///  
        /// Whether the current format for the content is valid
        ///  
        private bool _isContentFormatValid = false;

        #endregion Private Fields
 
        //-------------------------------------------------------------------
        // 
        //  IFlowDocumentFormatter Members 
        //
        //-------------------------------------------------------------------- 

        #region IFlowDocumentFormatter Members

        ///  
        /// Responds to change affecting entire content of associated FlowDocument.
        ///  
        /// Whether change affects layout. 
        void IFlowDocumentFormatter.OnContentInvalidated(bool affectsLayout)
        { 
            // If change happens before we've been arranged, we need to do a full reformat
            if (affectsLayout)
            {
                if(!_arrangedAfterFormat) 
                {
                    _document.StructuralCache.InvalidateFormatCache(true); 
                } 
                _isContentFormatValid = false;
            } 

            if (ContentInvalidated != null)
            {
                ContentInvalidated(this, EventArgs.Empty); 
            }
        } 
 
        /// 
        /// Responds to change affecting entire content of associated FlowDocument. 
        /// 
        /// Whether change affects layout.
        /// Start of the affected content range.
        /// End of the affected content range. 
        void IFlowDocumentFormatter.OnContentInvalidated(bool affectsLayout, ITextPointer start, ITextPointer end)
        { 
            ((IFlowDocumentFormatter)this).OnContentInvalidated(affectsLayout); 
        }
 
        /// 
        /// Suspend formatting.
        /// 
        void IFlowDocumentFormatter.Suspend() 
        {
            if (Suspended != null) 
            { 
                Suspended(this, EventArgs.Empty);
            } 
        }

        /// 
        /// Is layout data in a valid state. 
        /// 
        bool IFlowDocumentFormatter.IsLayoutDataValid 
        { 
            get
            { 
                // Layout is clean only when the page is calculated and it
                // is in the clean state - there are no pending changes that affect layout.
                //
                // Hittest can be called with invalid arrange. This happens in 
                // following situation:
                //   Something is causing to call InvalidateTree and eventually 
                //   InvalidateAllProperties will be called in such case. In responce 
                //   to that following properties are invalidated:
                //   * ClipToBounds - invalidates arrange 
                //   * IsEnabled - calls MouseDevice.Synchronize and it will eventually
                //     do hittesting.
                //
                // OR 
                //   TextContainer sends Changing event, which invalidates measure,
                //   but we have not yet received a matching Changed event. 
                // 
                // So, it is possible to receive hittesting request on dirty layout.
                bool layoutValid = _documentPage != null && 
                    _document.StructuralCache.IsFormattedOnce &&
                    !_document.StructuralCache.ForceReformat &&
                    _isContentFormatValid &&
                    !_document.StructuralCache.IsContentChangeInProgress && 
                    !_document.StructuralCache.IsFormattingInProgress;
 
                return layoutValid; 
            }
        } 


        #endregion IFlowDocumentFormatter Members
    } 
}

// 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