BreakRecordTable.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 / PtsHost / BreakRecordTable.cs / 1 / BreakRecordTable.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// Description: BreakRecordTable manages cached informaion bout pages and 
//              break records of FlowDocument contnet.
// 
// History: 
//  01/24/2004 : [....] - Created
// 
//---------------------------------------------------------------------------

using System;                           // WeakReference, ...
using System.Collections.Generic;       // List 
using System.Collections.ObjectModel;   // ReadOnlyCollection
using System.Windows.Documents;         // FlowDocument, TextPointer 
using MS.Internal.Documents;            // TextDocumentView 

namespace MS.Internal.PtsHost 
{
    /// 
    /// BreakRecordTable manages cached informaion bout pages and break
    /// records of FlowDocument contnet. 
    /// 
    internal sealed class BreakRecordTable 
    { 
        //-------------------------------------------------------------------
        // 
        //  Constructors
        //
        //-------------------------------------------------------------------
 
        #region Constructors
 
        ///  
        /// Constructor.
        ///  
        /// Ownder of the BreakRecordTable.
        internal BreakRecordTable(FlowDocumentPaginator owner)
        {
            _owner = owner; 
            _breakRecords = new List();
        } 
 
        #endregion Constructors
 
        //--------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        //-------------------------------------------------------------------
 
        #region Internal Methods 

        ///  
        /// Retrieves input BreakRecord for given PageNumber.
        /// 
        /// 
        /// Page index indicating which input BreakRecord should be retrieved. 
        /// Input BreakRecord for given PageNumber.
        internal PageBreakRecord GetPageBreakRecord(int pageNumber) 
        { 
            PageBreakRecord breakRecord = null;
 
            Invariant.Assert(pageNumber >= 0 && pageNumber <= _breakRecords.Count, "Invalid PageNumber.");

            // Input BreakRecord for the first page is always NULL.
            // For the rest of pages, go to the entry preceding requested index and 
            // return the output BreakRecord.
            if (pageNumber > 0) 
            { 
                Invariant.Assert(_breakRecords[pageNumber - 1] != null, "Invalid BreakRecordTable entry.");
                breakRecord = _breakRecords[pageNumber - 1].BreakRecord; 
                Invariant.Assert(breakRecord != null, "BreakRecord can be null only for the first page.");
            }
            return breakRecord;
        } 

        ///  
        /// Retrieves cached DocumentPage for given PageNumber. 
        /// 
        ///  
        /// Page index indicating which cached DocumentPage should be retrieved.
        /// 
        /// Cached DocumentPage for given PageNumber.
        internal FlowDocumentPage GetCachedDocumentPage(int pageNumber) 
        {
            WeakReference pageRef; 
            FlowDocumentPage documentPage = null; 

            if (pageNumber < _breakRecords.Count) 
            {
                Invariant.Assert(_breakRecords[pageNumber] != null, "Invalid BreakRecordTable entry.");
                pageRef = _breakRecords[pageNumber].DocumentPage;
                if (pageRef != null) 
                {
                    documentPage = pageRef.Target as FlowDocumentPage; 
                    if (documentPage != null && documentPage.IsDisposed) 
                    {
                        documentPage = null; 
                    }
                }
            }
            return documentPage; 
        }
 
        ///  
        /// Retrieves PageNumber for specified ContentPosition.
        ///  
        /// 
        /// Represents content position for which PageNumber is requested.
        /// Starting index for search process.
        ///  
        /// Returns true, if successfull. 'pageNumber' is updated with actual
        ///     page number that contains specified ContentPosition. 
        /// Returns false, if BreakRecordTable is missing information about 
        /// page that contains specified ContentPosition. 'pageNumber'
        /// is updated with the last investigated page number. 
        /// 
        internal bool GetPageNumberForContentPosition(TextPointer contentPosition, ref int pageNumber)
        {
            bool foundPageNumber = false; 
            ReadOnlyCollection textSegments;
 
            Invariant.Assert(pageNumber >= 0 && pageNumber <= _breakRecords.Count, "Invalid PageNumber."); 

            // Iterate through entries in the BreakRecordTable (starting from specified index) 
            // and look for page that contains specified ContentPosition.
            // NOTE: For each cached page collection of TextSegments is stored to
            // optimize this search.
            while (pageNumber < _breakRecords.Count) 
            {
                Invariant.Assert(_breakRecords[pageNumber] != null, "Invalid BreakRecordTable entry."); 
                textSegments = _breakRecords[pageNumber].TextSegments; 
                if (textSegments != null)
                { 
                    if (TextDocumentView.Contains(contentPosition, textSegments))
                    {
                        foundPageNumber = true;
                        break; 
                    }
                } 
                else 
                {
                    // There is no information about this page. 
                    break;
                }
                ++pageNumber;
            } 
            return foundPageNumber;
        } 
 
        /// 
        /// Layout of entire content has been affected. 
        /// 
        internal void OnInvalidateLayout()
        {
            if (_breakRecords.Count > 0) 
            {
                // Destroy all affected BreakRecords. 
                InvalidateBreakRecords(0, _breakRecords.Count); 

                // Initiate the next async operation. 
                _owner.InitiateNextAsyncOperation();

                // Raise PagesChanged event. Start with the first page and set
                // count to Int.Max/2, because somebody might want to display a page 
                // that wasn't available before, but will be right now.
                _owner.OnPagesChanged(0, int.MaxValue/2); 
            } 
        }
 
        /// 
        /// Layout for specified range has been affected.
        /// 
        /// Start of the affected content range. 
        /// End of the affected content range.
        internal void OnInvalidateLayout(ITextPointer start, ITextPointer end) 
        { 
            int pageStart, pageCount;
 
            if (_breakRecords.Count > 0)
            {
                // Get range of affected pages and dispose them
                GetAffectedPages(start, end, out pageStart, out pageCount); 

                // Currently there is no possibility to do partial invalidation 
                // of BreakRecordTable, so always extend pageCount to the end 
                // of BreakRecordTable.
                pageCount = _breakRecords.Count - pageStart; 
                if (pageCount > 0)
                {
                    // Destroy all affected BreakRecords.
                    InvalidateBreakRecords(pageStart, pageCount); 

                    // Initiate the next async operation. 
                    _owner.InitiateNextAsyncOperation(); 

                    // Raise PagesChanged event. Start with the first affected page and set 
                    // count to Int.Max/2, because somebody might want to display a page
                    // that wasn't available before, but will be right now.
                    _owner.OnPagesChanged(pageStart, int.MaxValue/2);
                } 
            }
        } 
 
        /// 
        /// Rendering of entire content has been affected. 
        /// 
        internal void OnInvalidateRender()
        {
            if (_breakRecords.Count > 0) 
            {
                // Dispose all existing pages. 
                DisposePages(0, _breakRecords.Count); 

                // Raise PagesChanged event. Start with the first page and set 
                // count to this.Count (number of pages have not been changed).
                _owner.OnPagesChanged(0, _breakRecords.Count);
            }
        } 

        ///  
        /// Rendering for specified range has been affected. 
        /// 
        /// Start of the affected content range. 
        /// End of the affected content range.
        internal void OnInvalidateRender(ITextPointer start, ITextPointer end)
        {
            int pageStart, pageCount; 

            if (_breakRecords.Count > 0) 
            { 
                // Get range of affected pages and dispose them.
                GetAffectedPages(start, end, out pageStart, out pageCount); 
                if (pageCount > 0)
                {
                    // Dispose all affected pages.
                    DisposePages(pageStart, pageCount); 

                    // Raise PagesChanged event. 
                    _owner.OnPagesChanged(pageStart, pageCount); 
                }
            } 
        }

        /// 
        /// Updates entry of BreakRecordTable with new data. 
        /// 
        /// Index of the entry to update. 
        /// DocumentPage object that has been just created. 
        /// Output BreakRecord for created page.
        /// Last content position that can affect the output break record. 
        internal void UpdateEntry(int pageNumber, FlowDocumentPage page, PageBreakRecord brOut, TextPointer dependentMax)
        {
            ITextView textView;
            BreakRecordTableEntry entry; 
            bool isClean;
 
            Invariant.Assert(pageNumber >= 0 && pageNumber <= _breakRecords.Count, "The previous BreakRecord does not exist."); 
            Invariant.Assert(page != null && page != DocumentPage.Missing, "Cannot update BRT with an invalid document page.");
 
            // Get TextView for DocumentPage. This TextView is used to access list of
            // content ranges. Those serve as optimalization in finding affeceted pages.
            textView = (ITextView)((IServiceProvider)page).GetService(typeof(ITextView));
            Invariant.Assert(textView != null, "Cannot access ITextView for FlowDocumentPage."); 

            // Get current state of BreakRecordTable 
            isClean = this.IsClean; 

            // Add new entry into BreakRecordTable 
            entry = new BreakRecordTableEntry();
            entry.BreakRecord = brOut;
            entry.DocumentPage = new WeakReference(page);
            entry.TextSegments = textView.TextSegments; 
            entry.DependentMax = dependentMax;
            if (pageNumber == _breakRecords.Count) 
            { 
                _breakRecords.Add(entry);
 
                // Raise PaginationProgress event only if we did not have valid
                // entry for specified page number.
                _owner.OnPaginationProgress(pageNumber, 1);
            } 
            else
            { 
                // If old Page and/or BreakRecord are not changing, do not dispose them. 
                if (_breakRecords[pageNumber].BreakRecord != null &&
                    _breakRecords[pageNumber].BreakRecord != entry.BreakRecord) 
                {
                    _breakRecords[pageNumber].BreakRecord.Dispose();
                }
                if (_breakRecords[pageNumber].DocumentPage != null && 
                    _breakRecords[pageNumber].DocumentPage.Target != null &&
                    _breakRecords[pageNumber].DocumentPage.Target != entry.DocumentPage.Target) 
                { 
                    ((FlowDocumentPage)_breakRecords[pageNumber].DocumentPage.Target).Dispose();
                } 
                _breakRecords[pageNumber] = entry;
            }

            // Raise PaginationCompleted event only if the BreakRecordTable just 
            // become clean.
            if (!isClean && this.IsClean) 
            { 
                _owner.OnPaginationCompleted();
            } 
        }

        /// 
        /// Determines whenever input BreakRecord for given page number exists. 
        /// 
        /// Page index. 
        /// true, if BreakRecord for given page number exists. 
        internal bool HasPageBreakRecord(int pageNumber)
        { 
            Invariant.Assert(pageNumber >= 0, "Page number cannot be negative.");

            // For the first page, the input break record is always NULL.
            // For the rest of pages, it exists if the preceding entry has 
            // non-NULL output BreakRecord.
            if (pageNumber == 0) 
                return true; 
            if (pageNumber > _breakRecords.Count)
                return false; 
            Invariant.Assert(_breakRecords[pageNumber - 1] != null, "Invalid BreakRecordTable entry.");
            return (_breakRecords[pageNumber - 1].BreakRecord != null);
        }
 
        #endregion Internal Methods
 
        //-------------------------------------------------------------------- 
        //
        //  Internal Properties 
        //
        //--------------------------------------------------------------------

        #region Internal Properties 

        ///  
        /// Current count reflecting number of known pages. 
        /// 
        internal int Count 
        {
            get { return _breakRecords.Count; }
        }
 
        /// 
        /// Whether BreakRecordTable is clean. 
        ///  
        internal bool IsClean
        { 
            get
            {
                if (_breakRecords.Count == 0)
                    return false; 
                Invariant.Assert(_breakRecords[_breakRecords.Count - 1] != null, "Invalid BreakRecordTable entry.");
                return (_breakRecords[_breakRecords.Count - 1].BreakRecord == null); 
            } 
        }
 
        #endregion Internal Properties

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

        #region Private Methods 

        /// 
        /// Dispose all alive pages for specified range.
        ///  
        /// Index of the first page to dispose.
        /// Number of pages to dispose. 
        private void DisposePages(int start, int count) 
        {
            WeakReference pageRef; 
            int index = start + count - 1;  // Start from the end of BreakRecordTable

            Invariant.Assert(start >= 0 && start < _breakRecords.Count, "Invalid starting index for BreakRecordTable invalidation.");
            Invariant.Assert(start + count <= _breakRecords.Count, "Partial invalidation of BreakRecordTable is not allowed."); 

            while (index >= start) 
            { 
                Invariant.Assert(_breakRecords[index] != null, "Invalid BreakRecordTable entry.");
                pageRef = _breakRecords[index].DocumentPage; 
                if (pageRef != null && pageRef.Target != null)
                {
                    ((FlowDocumentPage)pageRef.Target).Dispose();
                } 
                _breakRecords[index].DocumentPage = null;
                index--; 
            } 
        }
 
        /// 
        /// Destroy BreakRecordsTable entries for specified range.
        /// 
        /// Index of the first entry to destroy. 
        /// Nmber of entries to destroy.
        private void InvalidateBreakRecords(int start, int count) 
        { 
            WeakReference pageRef;
            int index = start + count - 1;  // Start from the end of BreakRecordTable 

            Invariant.Assert(start >= 0 && start < _breakRecords.Count, "Invalid starting index for BreakRecordTable invalidation.");
            Invariant.Assert(start + count == _breakRecords.Count, "Partial invalidation of BreakRecordTable is not allowed.");
 
            while (index >= start)
            { 
                Invariant.Assert(_breakRecords[index] != null, "Invalid BreakRecordTable entry."); 
                // Dispose Page and BreakRecord before removing the entry.
                pageRef = _breakRecords[index].DocumentPage; 
                if (pageRef != null && pageRef.Target != null)
                {
                    ((FlowDocumentPage)pageRef.Target).Dispose();
                } 
                if (_breakRecords[start].BreakRecord != null)
                { 
                    _breakRecords[start].BreakRecord.Dispose(); 
                }
                // Remov the entry. 
                _breakRecords.RemoveAt(index);
                index--;
            }
        } 

        ///  
        /// Retrieves indices of affected pages by specified content range. 
        /// 
        /// Content change start position. 
        /// Content change end position.
        /// The first affected page.
        /// Number of affected pages.
        private void GetAffectedPages(ITextPointer start, ITextPointer end, out int pageStart, out int pageCount) 
        {
            bool affects; 
            ReadOnlyCollection textSegments; 
            TextPointer dependentMax;
 
            // Find the first affected page.
            pageStart = 0;
            while (pageStart < _breakRecords.Count)
            { 
                Invariant.Assert(_breakRecords[pageStart] != null, "Invalid BreakRecordTable entry.");
 
                // If the start position is before last position affecting the output break record, 
                // this page is affected.
                dependentMax = _breakRecords[pageStart].DependentMax; 
                if (dependentMax != null)
                {
                    if (start.CompareTo(dependentMax) <= 0)
                        break; 
                }
 
                textSegments = _breakRecords[pageStart].TextSegments; 
                if (textSegments != null)
                { 
                    affects = false;
                    foreach (TextSegment textSegment in textSegments)
                    {
                        if (start.CompareTo(textSegment.End) <= 0) 
                        {
                            affects = true; 
                            break; 
                        }
                    } 
                    if (affects)
                        break;
                }
                else 
                {
                    // There is no information about this page, so assume that it is 
                    // affected. 
                    break;
                } 
                ++pageStart;
            }
            // Find the last affected page
            // For now assume that all following pages are affected. 
            pageCount = _breakRecords.Count - pageStart;
        } 
 
        #endregion Private Methods
 
        //-------------------------------------------------------------------
        //
        //  Private Fields
        // 
        //-------------------------------------------------------------------
 
        #region Private Fields 

        ///  
        /// Owner of the BreakRecordTable.
        /// 
        private FlowDocumentPaginator _owner;
 
        /// 
        /// Array of entries in the BreakRecordTable. 
        ///  
        private List _breakRecords;
 
        /// 
        /// BreakRecordTableEntry
        /// 
        private class BreakRecordTableEntry 
        {
            public PageBreakRecord BreakRecord; 
            public ReadOnlyCollection TextSegments; 
            public WeakReference DocumentPage;
            public TextPointer DependentMax; 
        }

        #endregion Private Fields
    } 
}

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