SubpageParaClient.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / MS / Internal / PtsHost / SubpageParaClient.cs / 1 / SubpageParaClient.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: SubpageParaClient.cs 
//
// Description: SubpageParaClient is responsible for handling display 
//              related data of subpages. 
//
// History: 
//  25/08/2004 : grzegorz - created.
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Documents; 
using MS.Internal.Documents;
using MS.Internal.Text; 
 
using MS.Internal.PtsHost.UnsafeNativeMethods;
 
namespace MS.Internal.PtsHost
{
    // ---------------------------------------------------------------------
    // SubpageParaClient is responsible for handling display related data 
    // of subpages.
    // --------------------------------------------------------------------- 
    internal class SubpageParaClient : BaseParaClient 
    {
        // ------------------------------------------------------------------ 
        // Constructor.
        //
        //      paragraph - Paragraph associated with this object.
        // ----------------------------------------------------------------- 
        internal SubpageParaClient(SubpageParagraph paragraph) : base(paragraph)
        { 
        } 

        ///  
        /// Dispose.
        /// 
        /// 
        /// This method is called by PTS to notify that this para client is not is use anymore. 
        /// 
        ///  
        /// Critical - as this calls the Critical function PTS.FsDestroySubpage.  This 
        ///            also calls the setter for _paraHandle.Value but is just set to zero.
        /// Safe - as the parameters passed in, PtsContext.Context and _paraHandle are 
        ///        both marked Critical for set.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public override void Dispose() 
        {
            _visual = null; 
 
            if (_paraHandle.Value != IntPtr.Zero)
            { 
                PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, _paraHandle.Value));
                _paraHandle.Value = IntPtr.Zero;
            }
 
            base.Dispose();
        } 
 

        // ------------------------------------------------------------------ 
        // Arrange paragraph.
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and 
        ///            some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void OnArrange()
        {
            base.OnArrange(); 

            ((SubpageParagraph)Paragraph).UpdateSegmentLastFormatPositions(); 
 
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));

            MbpInfo mbp = MbpInfo.FromElement(Paragraph.Element);
 
            if(ThisFlowDirection != PageFlowDirection)
            { 
                mbp.MirrorBP(); 
            }
 
            if (!IsFirstChunk)
            {
                mbp.Border = new Thickness(mbp.Border.Left, 0.0, mbp.Border.Right, mbp.Border.Bottom);
                mbp.Padding = new Thickness(mbp.Padding.Left, 0.0, mbp.Padding.Right, mbp.Padding.Bottom); 
            }
 
            if (!IsLastChunk) 
            {
                mbp.Border = new Thickness(mbp.Border.Left, mbp.Border.Top, mbp.Border.Right, 0.0); 
                mbp.Padding = new Thickness(mbp.Padding.Left, mbp.Padding.Top, mbp.Padding.Right, 0.0);
            }

 
            _contentRect.u = _rect.u + mbp.BPLeft;
            _contentRect.du = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.du - mbp.BPRight - mbp.BPLeft); 
            _contentRect.v = _rect.v + mbp.BPTop; 
            _contentRect.dv = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.dv - mbp.BPBottom - mbp.BPTop);
 
            _paddingRect.u = _rect.u + mbp.BorderLeft;
            _paddingRect.du = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.du - mbp.BorderRight - mbp.BorderLeft);
            _paddingRect.v = _rect.v + mbp.BorderTop;
            _paddingRect.dv = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.dv - mbp.BorderBottom - mbp.BorderTop); 

            // Arrange subpage content. Subpage content may be simple or complex - 
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track)
            // (2) complex subpage (contains columns) 
            if (PTS.ToBoolean(subpageDetails.fSimple))
            {
                _pageContextOfThisPage.PageRect = new PTS.FSRECT(subpageDetails.u.simple.trackdescr.fsrc);
 
                // (1) simple subpage (contains only one track)
 
                // Exceptions don't need to pop, as the top level arrange context will be nulled out if thrown. 
                Paragraph.StructuralCache.CurrentArrangeContext.PushNewPageData(_pageContextOfThisPage, subpageDetails.u.simple.trackdescr.fsrc,
                                                                                Paragraph.StructuralCache.CurrentArrangeContext.FinitePage); 

                PtsHelper.ArrangeTrack(PtsContext, ref subpageDetails.u.simple.trackdescr, subpageDetails.u.simple.fswdir);

                Paragraph.StructuralCache.CurrentArrangeContext.PopPageData(); 
            }
            else 
            { 
                _pageContextOfThisPage.PageRect = new PTS.FSRECT(subpageDetails.u.complex.fsrc);
 
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0)
                { 
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                    // Arrange each track 
                    for (int index = 0; index < arrayColumnDesc.Length; index++)
                    {
                        // Exceptions don't need to pop, as the top level arrange context will be nulled out if thrown.
                        Paragraph.StructuralCache.CurrentArrangeContext.PushNewPageData(_pageContextOfThisPage, arrayColumnDesc[index].fsrc, 
                                                                                        Paragraph.StructuralCache.CurrentArrangeContext.FinitePage);
 
                        PtsHelper.ArrangeTrack(PtsContext, ref arrayColumnDesc[index], subpageDetails.u.complex.fswdir); 

                        Paragraph.StructuralCache.CurrentArrangeContext.PopPageData(); 
                    }
                }
            }
        } 

        // ----------------------------------------------------------------- 
        // Hit tests to the correct IInputElement within the paragraph 
        // that the mouse is over.
        // ------------------------------------------------------------------ 
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails
        ///            and some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override IInputElement InputHitTest(PTS.FSPOINT pt) 
        {
            IInputElement ie = null;

            if(_pageContextOfThisPage.FloatingElementList != null) 
            {
                for(int index = 0; index < _pageContextOfThisPage.FloatingElementList.Count && ie == null; index++) 
                { 
                    BaseParaClient floatingElement = _pageContextOfThisPage.FloatingElementList[index];
 
                    ie = floatingElement.InputHitTest(pt);
                }
            }
 
            if(ie == null)
            { 
                if(Rect.Contains(pt)) 
                {
                    if(ContentRect.Contains(pt)) 
                    {
                        pt = new PTS.FSPOINT(pt.u - ContentRect.u, pt.v - ContentRect.v);

                        // Query subpage details 
                        PTS.FSSUBPAGEDETAILS subpageDetails;
                        PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails)); 
 
                        // Hittest subpage content. Subpage content may be simple or complex -
                        // depending of set of features used in the content of the page. 
                        // (1) simple subpage (contains only one track)
                        // (2) complex subpage (contains columns)
                        if (PTS.ToBoolean(subpageDetails.fSimple))
                        { 
                            ie = PtsHelper.InputHitTestTrack(PtsContext, pt, ref subpageDetails.u.simple.trackdescr);
                        } 
                        else 
                        {
                            // (2) complex page (contains columns) 
                            // cBasicColumns == 0, means that subpage content is empty
                            if (subpageDetails.u.complex.cBasicColumns != 0)
                            {
                                // Retrieve description for each column. 
                                PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                                PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 
 
                                // Arrange each track
                                for (int index = 0; index < arrayColumnDesc.Length && ie == null; index++) 
                                {
                                    ie = PtsHelper.InputHitTestTrack(PtsContext, pt, ref arrayColumnDesc[index]);
                                }
                            } 
                        }
                    } 
 
                    if(ie == null)
                    { 
                        ie = Paragraph.Element as IInputElement;
                    }
                }
            } 

            return ie; 
        } 

        // ----------------------------------------------------------------- 
        // Gets ArrayList of rectangles for ContentElement e if it is
        // found
        // start: int representing start offset of e.
        // length: int representing number of positions occupied by e. 
        // -----------------------------------------------------------------
        ///  
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and 
        ///            some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override List GetRectangles(ContentElement e, int start, int length)
        { 
            List rectangles = new List(); 
            if (Paragraph.Element as ContentElement == e)
            { 
                // We have found the element. Return rectangles for this paragraph.
                GetRectanglesForParagraphElement(out rectangles);
            }
            else 
            {
                // Query subpage details 
                PTS.FSSUBPAGEDETAILS subpageDetails; 
                PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
                // Check subpage content. Subpage content may be simple or complex -
                // depending of set of features used in the content of the page.
                // (1) simple subpage (contains only one track)
                // (2) complex subpage (contains columns) 
                if (PTS.ToBoolean(subpageDetails.fSimple))
                { 
                    // (1) simple subpage (contains only one track) 
                    rectangles = PtsHelper.GetRectanglesInTrack(PtsContext, e, start, length, ref subpageDetails.u.simple.trackdescr);
                } 
                else
                {
                    // (2) complex page (contains columns)
                    // cBasicColumns == 0, means that subpage content is empty 
                    if (subpageDetails.u.complex.cBasicColumns != 0)
                    { 
                        // Retrieve description for each column. 
                        PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                        PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                        // Arrange each track
                        for (int index = 0; index < arrayColumnDesc.Length; index++)
                        { 
                            List trackRectangles = PtsHelper.GetRectanglesInTrack(PtsContext, e, start, length, ref arrayColumnDesc[index]);
                            Invariant.Assert(trackRectangles != null); 
                            if (trackRectangles.Count != 0) 
                            {
                                rectangles.AddRange(trackRectangles); 
                            }
                        }
                    }
                } 

                rectangles = PtsHelper.OffsetRectangleList(rectangles, TextDpi.FromTextDpi(ContentRect.u), TextDpi.FromTextDpi(ContentRect.v)); 
            } 

            // Rectangles must be non-null 
            Invariant.Assert(rectangles != null);
            return rectangles;
        }
 
        // -----------------------------------------------------------------
        // Validate visual node associated with paragraph. 
        // 
        //      fskupdInherited - inherited update info
        //      fswdir - inherited flow direction 
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and
        ///            some PtsHelper functions. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void ValidateVisual(PTS.FSKUPDATE fskupdInherited)
        {
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            // Draw border and background info. 
            MbpInfo mbpInfo = MbpInfo.FromElement(Paragraph.Element);
 
            if(ThisFlowDirection != PageFlowDirection)
            {
                mbpInfo.MirrorBP();
            } 

            Brush backgroundBrush = (Brush)Paragraph.Element.GetValue(TextElement.BackgroundProperty); 
            Visual.DrawBackgroundAndBorder(backgroundBrush, mbpInfo.BorderBrush, mbpInfo.Border, _rect.FromTextDpi(), IsFirstChunk, IsLastChunk); 

            ContainerVisual pageContentVisual; 
            ContainerVisual floatingElementsVisual;

            if(_visual.Children.Count != 2)
            { 
                _visual.Children.Clear();
                _visual.Children.Add(new ContainerVisual()); 
                _visual.Children.Add(new ContainerVisual()); 
            }
 
            pageContentVisual = (ContainerVisual)_visual.Children[0];
            floatingElementsVisual = (ContainerVisual)_visual.Children[1];

 
            // Subpage content may be simple or complex -
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                // (1) simple subpage (contains only one track)
                PTS.FSKUPDATE fskupd = subpageDetails.u.simple.trackdescr.fsupdinf.fskupd;
                if (fskupd == PTS.FSKUPDATE.fskupdInherited) 
                {
                    fskupd = fskupdInherited; 
                } 
                VisualCollection visualChildren = pageContentVisual.Children;
                if (fskupd == PTS.FSKUPDATE.fskupdNew) 
                {
                    visualChildren.Clear();
                    visualChildren.Add(new ContainerVisual());
                } 
                // For complex subpage SectionVisual is added. So, when morphing
                // complex subpage to simple one, remove SectionVisual. 
                else if (visualChildren.Count == 1 && visualChildren[0] is SectionVisual) 
                {
                    visualChildren.Clear(); 
                    visualChildren.Add(new ContainerVisual());
                }
                Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is ContainerVisual);
                ContainerVisual trackVisual = (ContainerVisual)visualChildren[0]; 

                PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref subpageDetails.u.simple.trackdescr); 
            } 
            else
            { 
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage) 
                {
                    // Retrieve description for each column. 
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);
 
                    emptySubpage = (arrayColumnDesc.Length == 0);
                    if (!emptySubpage)
                    {
                        PTS.FSKUPDATE fskupd = fskupdInherited; 
                        ErrorHandler.Assert(fskupd != PTS.FSKUPDATE.fskupdShifted, ErrorHandler.UpdateShiftedNotValid);
                        Debug.Assert(fskupd != PTS.FSKUPDATE.fskupdNoChange); 
 
                        // For complex subpage SectionVisual is added. So, when morphing
                        // simple subpage to complex one, remove ParagraphVisual. 
                        VisualCollection visualChildren = pageContentVisual.Children;
                        if (visualChildren.Count == 0)
                        {
                            visualChildren.Add(new SectionVisual()); 
                        }
                        else if (!(visualChildren[0] is SectionVisual)) 
                        { 
                            visualChildren.Clear();
                            visualChildren.Add(new SectionVisual()); 
                        }
                        Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is SectionVisual);
                        SectionVisual sectionVisual = (SectionVisual)visualChildren[0];
 
                        // Draw column rules.
                        ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(Paragraph.Element); 
                        sectionVisual.DrawColumnRules(ref arrayColumnDesc, TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.v), TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.dv), columnProperties); 

                        visualChildren = sectionVisual.Children; 
                        if (fskupd == PTS.FSKUPDATE.fskupdNew)
                        {
                            visualChildren.Clear();
                            for (int index = 0; index < arrayColumnDesc.Length; index++) 
                            {
                                visualChildren.Add(new ContainerVisual()); 
                            } 
                        }
                        ErrorHandler.Assert(visualChildren.Count == arrayColumnDesc.Length, ErrorHandler.ColumnVisualCountMismatch); 
                        for (int index = 0; index < arrayColumnDesc.Length; index++)
                        {
                            ContainerVisual trackVisual = (ContainerVisual)visualChildren[index];
 
                            PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref arrayColumnDesc[index]);
                        } 
                    } 
                }
                if (emptySubpage) 
                {
                    // There is no content, remove all existing visuals.
                    _visual.Children.Clear();
                } 
            }
 
            pageContentVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi(); 
            floatingElementsVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi();
 
            PTS.FSRECT clipRect = new PTS.FSRECT(_paddingRect.u - _contentRect.u, _paddingRect.v - _contentRect.v, _paddingRect.du, _paddingRect.dv);
            PtsHelper.ClipChildrenToRect(_visual, clipRect.FromTextDpi());
            PtsHelper.UpdateFloatingElementVisuals(floatingElementsVisual, _pageContextOfThisPage.FloatingElementList);
 
        }
 
 
        // -----------------------------------------------------------------
        // Updates viewport 
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical functions PTS.FsQuerySubpageDetails,
        ///            and PtsHelper.TrackListFromSubpage. 
        /// Safe - The IntPtr parameters passed to PTS.FsQuerySubpageDetails are SecurityCriticalDataForSet
        ///        which ensures that partial trust code won't be able to set it to a random value. 
        ///        The subpageDetails parameter passed to other methods is generated securely in this function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void UpdateViewport(ref PTS.FSRECT viewport)
        {
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            PTS.FSRECT viewportSubpage = new PTS.FSRECT(); 

            viewportSubpage.u = viewport.u - ContentRect.u; 
            viewportSubpage.v = viewport.v - ContentRect.v;
            viewportSubpage.du = viewport.du;
            viewportSubpage.dv = viewport.dv;
 
            // Subpage content may be simple or complex -
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                PtsHelper.UpdateViewportTrack(PtsContext, ref subpageDetails.u.simple.trackdescr, ref viewportSubpage);
            }
            else 
            {
                // (2) complex page (contains columns) 
                // cBasicColumns == 0, means that subpage content is empty 
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage) 
                {
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                    emptySubpage = (arrayColumnDesc.Length == 0); 
                    if (!emptySubpage) 
                    {
                        for (int index = 0; index < arrayColumnDesc.Length; index++) 
                        {
                            PtsHelper.UpdateViewportTrack(PtsContext, ref arrayColumnDesc[index], ref viewportSubpage);
                        }
                    } 
                }
            } 
        } 

 
        // ------------------------------------------------------------------
        // Create paragraph result representing this paragraph.
        // -----------------------------------------------------------------
        internal override ParagraphResult CreateParagraphResult() 
        {
            return new SubpageParagraphResult(this); 
        } 

        // ------------------------------------------------------------------ 
        // Return TextContentRange for the content of the paragraph.
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override TextContentRange GetTextContentRange()
        {
            TextContentRange textContentRange;
 
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails)); 

            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the page.
            // (1) simple subpage (contains only one track)
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                // (1) simple subpage (contains only one track) 
                textContentRange = PtsHelper.TextContentRangeFromTrack(PtsContext, subpageDetails.u.simple.trackdescr.pfstrack); 
            }
            else 
            {
                textContentRange = new TextContentRange();

                // (2) complex page (contains columns) 
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0) 
                { 
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);

                    // Arrange each track
                    for (int index = 0; index < arrayColumnDesc.Length; index++) 
                    {
                        // Merge TextContentRanges for all columns 
                        textContentRange.Merge(PtsHelper.TextContentRangeFromTrack(PtsContext, arrayColumnDesc[index].pfstrack)); 
                    }
                } 
            }

            TextElement elementOwner = this.Paragraph.Element as TextElement;
            // If the first paragraph is the first paragraph in the container and it is the first chunk, 
            // include start position of this element.
            if (_isFirstChunk) 
            { 
                textContentRange.Merge(TextContainerHelper.GetTextContentRangeForTextElementEdge(
                    elementOwner, ElementEdge.BeforeStart)); 
            }

            // If the last paragraph is the last paragraph in the container and it is the last chunk,
            // include end position of this element. 
            if (_isLastChunk)
            { 
                textContentRange.Merge(TextContainerHelper.GetTextContentRangeForTextElementEdge( 
                    elementOwner, ElementEdge.AfterEnd));
            } 

            Invariant.Assert(textContentRange != null);
            return textContentRange;
        } 

        ///  
        /// Returns a new collection of ColumnResults for the subpage. Will always 
        /// have at least one column.
        ///  
        /// 
        /// True if any column in the subpage has text content, i.e. does not contain only figures/floaters
        /// 
        ///  
        /// Critical - as this calls the Critical functions PTS.FsQuerySubpageDetails
        ///            and PTS.FsQueryTrackDetails. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal ReadOnlyCollection GetColumnResults(out bool hasTextContent)
        { 
            List columnResults = new List(0);
            Vector contentOffset = new Vector(); 
 
            // hasTextContent is set to true if any of the columns in the subpage has text content. This is determined by checking the columns'
            // paragraph collections 
            hasTextContent = false;

            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the page.
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple))
            {
                // (1) simple subpage (contains only one track) 
                PTS.FSTRACKDETAILS trackDetails;
                PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, subpageDetails.u.simple.trackdescr.pfstrack, out trackDetails)); 
                if (trackDetails.cParas > 0) 
                {
                    columnResults = new List(1); 
                    ColumnResult columnResult = new ColumnResult(this, ref subpageDetails.u.simple.trackdescr, contentOffset);
                    columnResults.Add(columnResult);
                    if (columnResult.HasTextContent)
                    { 
                        hasTextContent = true;
                    } 
                } 
            }
            else 
            {
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0) 
                {
                    // Retrieve description for each column. 
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);
 
                    columnResults = new List(subpageDetails.u.complex.cBasicColumns);
                    for (int i = 0; i < arrayColumnDesc.Length; i++)
                    {
                        PTS.FSTRACKDETAILS trackDetails; 
                        PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, arrayColumnDesc[i].pfstrack, out trackDetails));
                        if (trackDetails.cParas > 0) 
                        { 
                            ColumnResult columnResult = new ColumnResult(this, ref arrayColumnDesc[i], contentOffset);
                            columnResults.Add(columnResult); 
                            if (columnResult.HasTextContent)
                            {
                                hasTextContent = true;
                            } 
                        }
                    } 
                } 
            }
 
            return new ReadOnlyCollection(columnResults);
        }

        // ----------------------------------------------------------------- 
        // Returns a collection of ParagraphResults for the column's paragraphs.
        // 
        //      pfstrack - Pointer to PTS track representing a column. 
        //      parentOffset - Parent offset from the top of the page.
        //      hasTextContent - true if any of the children paras has text content 
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical function PTS.FsQueryTrackDetails.
        ///  
        [SecurityCritical]
        internal ReadOnlyCollection GetParagraphResultsFromColumn(IntPtr pfstrack, Vector parentOffset, out bool hasTextContent) 
        { 
            // Get track details
            PTS.FSTRACKDETAILS trackDetails; 
            PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, pfstrack, out trackDetails));
            hasTextContent = false;

            if (trackDetails.cParas == 0) { return null; } 

            PTS.FSPARADESCRIPTION[] arrayParaDesc; 
            PtsHelper.ParaListFromTrack(PtsContext, pfstrack, ref trackDetails, out arrayParaDesc); 

            List paragraphResults = new List(arrayParaDesc.Length); 
            for (int i = 0; i < arrayParaDesc.Length; i++)
            {
                BaseParaClient paraClient = PtsContext.HandleToObject(arrayParaDesc[i].pfsparaclient) as BaseParaClient;
                PTS.ValidateHandle(paraClient); 
                ParagraphResult paragraphResult = paraClient.CreateParagraphResult();
                if (paragraphResult.HasTextContent) 
                { 
                    hasTextContent = true;
                } 
                paragraphResults.Add(paragraphResult);
            }
            return new ReadOnlyCollection(paragraphResults);
        } 

        // ------------------------------------------------------------------ 
        // Retrieves text range for contents of the column represented by 
        // 'pfstrack'.
        // 
        //      pfstrack - Pointer to PTS track representing a column.
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical function PTS.FsQueryTrackDetails. 
        /// 
        [SecurityCritical] 
        internal TextContentRange GetTextContentRangeFromColumn(IntPtr pfstrack) 
        {
            // Get track details 
            PTS.FSTRACKDETAILS trackDetails;
            PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, pfstrack, out trackDetails));

            // Combine ranges from all nested paragraphs. 
            TextContentRange textContentRange = new TextContentRange();
            if (trackDetails.cParas != 0) 
            { 
                PTS.FSPARADESCRIPTION[] arrayParaDesc;
                PtsHelper.ParaListFromTrack(PtsContext, pfstrack, ref trackDetails, out arrayParaDesc); 

                // Merge TextContentRanges for all paragraphs
                BaseParaClient paraClient;
                for (int i = 0; i < arrayParaDesc.Length; i++) 
                {
                    paraClient = PtsContext.HandleToObject(arrayParaDesc[i].pfsparaclient) as BaseParaClient; 
                    PTS.ValidateHandle(paraClient); 
                    textContentRange.Merge(paraClient.GetTextContentRange());
                } 
            }
            return textContentRange;
        }
 
        // ------------------------------------------------------------------
        // Update information about first/last chunk. 
        // ------------------------------------------------------------------ 
        internal void SetChunkInfo(bool isFirstChunk, bool isLastChunk)
        { 
            _isFirstChunk = isFirstChunk;
            _isLastChunk = isLastChunk;
        }
 
        // -----------------------------------------------------------------
        // Is this the first chunk of paginated content. 
        // ------------------------------------------------------------------ 
        internal override bool IsFirstChunk { get { return _isFirstChunk; } }
        private bool _isFirstChunk; 

        // -----------------------------------------------------------------
        // Is this the last chunk of paginated content.
        // ----------------------------------------------------------------- 
        internal override bool IsLastChunk { get { return _isLastChunk; } }
        private bool _isLastChunk; 
 
        // Floating element list
        internal ReadOnlyCollection FloatingElementResults 
        {
            get
            {
                List floatingElements = new List(0); 
                List floatingElementList = _pageContextOfThisPage.FloatingElementList;
                if (floatingElementList != null) 
                { 

                    for (int i = 0; i < floatingElementList.Count; i++) 
                    {
                        ParagraphResult paragraphResult = floatingElementList[i].CreateParagraphResult();
                        floatingElements.Add(paragraphResult);
                    } 
                }
                return new ReadOnlyCollection(floatingElements); 
            } 
        }
 
        // -----------------------------------------------------------------
        // Rect of content in page coordinate system
        // ------------------------------------------------------------------
        internal PTS.FSRECT ContentRect { get { return _contentRect; } } 

        private PTS.FSRECT _contentRect; 
        private PTS.FSRECT _paddingRect; 

        private PageContext _pageContextOfThisPage = new PageContext(); 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: SubpageParaClient.cs 
//
// Description: SubpageParaClient is responsible for handling display 
//              related data of subpages. 
//
// History: 
//  25/08/2004 : grzegorz - created.
//
//---------------------------------------------------------------------------
 
using System;
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections;
using System.Diagnostics; 
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Documents; 
using MS.Internal.Documents;
using MS.Internal.Text; 
 
using MS.Internal.PtsHost.UnsafeNativeMethods;
 
namespace MS.Internal.PtsHost
{
    // ---------------------------------------------------------------------
    // SubpageParaClient is responsible for handling display related data 
    // of subpages.
    // --------------------------------------------------------------------- 
    internal class SubpageParaClient : BaseParaClient 
    {
        // ------------------------------------------------------------------ 
        // Constructor.
        //
        //      paragraph - Paragraph associated with this object.
        // ----------------------------------------------------------------- 
        internal SubpageParaClient(SubpageParagraph paragraph) : base(paragraph)
        { 
        } 

        ///  
        /// Dispose.
        /// 
        /// 
        /// This method is called by PTS to notify that this para client is not is use anymore. 
        /// 
        ///  
        /// Critical - as this calls the Critical function PTS.FsDestroySubpage.  This 
        ///            also calls the setter for _paraHandle.Value but is just set to zero.
        /// Safe - as the parameters passed in, PtsContext.Context and _paraHandle are 
        ///        both marked Critical for set.
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        public override void Dispose() 
        {
            _visual = null; 
 
            if (_paraHandle.Value != IntPtr.Zero)
            { 
                PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, _paraHandle.Value));
                _paraHandle.Value = IntPtr.Zero;
            }
 
            base.Dispose();
        } 
 

        // ------------------------------------------------------------------ 
        // Arrange paragraph.
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and 
        ///            some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        protected override void OnArrange()
        {
            base.OnArrange(); 

            ((SubpageParagraph)Paragraph).UpdateSegmentLastFormatPositions(); 
 
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));

            MbpInfo mbp = MbpInfo.FromElement(Paragraph.Element);
 
            if(ThisFlowDirection != PageFlowDirection)
            { 
                mbp.MirrorBP(); 
            }
 
            if (!IsFirstChunk)
            {
                mbp.Border = new Thickness(mbp.Border.Left, 0.0, mbp.Border.Right, mbp.Border.Bottom);
                mbp.Padding = new Thickness(mbp.Padding.Left, 0.0, mbp.Padding.Right, mbp.Padding.Bottom); 
            }
 
            if (!IsLastChunk) 
            {
                mbp.Border = new Thickness(mbp.Border.Left, mbp.Border.Top, mbp.Border.Right, 0.0); 
                mbp.Padding = new Thickness(mbp.Padding.Left, mbp.Padding.Top, mbp.Padding.Right, 0.0);
            }

 
            _contentRect.u = _rect.u + mbp.BPLeft;
            _contentRect.du = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.du - mbp.BPRight - mbp.BPLeft); 
            _contentRect.v = _rect.v + mbp.BPTop; 
            _contentRect.dv = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.dv - mbp.BPBottom - mbp.BPTop);
 
            _paddingRect.u = _rect.u + mbp.BorderLeft;
            _paddingRect.du = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.du - mbp.BorderRight - mbp.BorderLeft);
            _paddingRect.v = _rect.v + mbp.BorderTop;
            _paddingRect.dv = Math.Max(TextDpi.ToTextDpi(TextDpi.MinWidth), _rect.dv - mbp.BorderBottom - mbp.BorderTop); 

            // Arrange subpage content. Subpage content may be simple or complex - 
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track)
            // (2) complex subpage (contains columns) 
            if (PTS.ToBoolean(subpageDetails.fSimple))
            {
                _pageContextOfThisPage.PageRect = new PTS.FSRECT(subpageDetails.u.simple.trackdescr.fsrc);
 
                // (1) simple subpage (contains only one track)
 
                // Exceptions don't need to pop, as the top level arrange context will be nulled out if thrown. 
                Paragraph.StructuralCache.CurrentArrangeContext.PushNewPageData(_pageContextOfThisPage, subpageDetails.u.simple.trackdescr.fsrc,
                                                                                Paragraph.StructuralCache.CurrentArrangeContext.FinitePage); 

                PtsHelper.ArrangeTrack(PtsContext, ref subpageDetails.u.simple.trackdescr, subpageDetails.u.simple.fswdir);

                Paragraph.StructuralCache.CurrentArrangeContext.PopPageData(); 
            }
            else 
            { 
                _pageContextOfThisPage.PageRect = new PTS.FSRECT(subpageDetails.u.complex.fsrc);
 
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0)
                { 
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                    // Arrange each track 
                    for (int index = 0; index < arrayColumnDesc.Length; index++)
                    {
                        // Exceptions don't need to pop, as the top level arrange context will be nulled out if thrown.
                        Paragraph.StructuralCache.CurrentArrangeContext.PushNewPageData(_pageContextOfThisPage, arrayColumnDesc[index].fsrc, 
                                                                                        Paragraph.StructuralCache.CurrentArrangeContext.FinitePage);
 
                        PtsHelper.ArrangeTrack(PtsContext, ref arrayColumnDesc[index], subpageDetails.u.complex.fswdir); 

                        Paragraph.StructuralCache.CurrentArrangeContext.PopPageData(); 
                    }
                }
            }
        } 

        // ----------------------------------------------------------------- 
        // Hit tests to the correct IInputElement within the paragraph 
        // that the mouse is over.
        // ------------------------------------------------------------------ 
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails
        ///            and some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function. 
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal override IInputElement InputHitTest(PTS.FSPOINT pt) 
        {
            IInputElement ie = null;

            if(_pageContextOfThisPage.FloatingElementList != null) 
            {
                for(int index = 0; index < _pageContextOfThisPage.FloatingElementList.Count && ie == null; index++) 
                { 
                    BaseParaClient floatingElement = _pageContextOfThisPage.FloatingElementList[index];
 
                    ie = floatingElement.InputHitTest(pt);
                }
            }
 
            if(ie == null)
            { 
                if(Rect.Contains(pt)) 
                {
                    if(ContentRect.Contains(pt)) 
                    {
                        pt = new PTS.FSPOINT(pt.u - ContentRect.u, pt.v - ContentRect.v);

                        // Query subpage details 
                        PTS.FSSUBPAGEDETAILS subpageDetails;
                        PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails)); 
 
                        // Hittest subpage content. Subpage content may be simple or complex -
                        // depending of set of features used in the content of the page. 
                        // (1) simple subpage (contains only one track)
                        // (2) complex subpage (contains columns)
                        if (PTS.ToBoolean(subpageDetails.fSimple))
                        { 
                            ie = PtsHelper.InputHitTestTrack(PtsContext, pt, ref subpageDetails.u.simple.trackdescr);
                        } 
                        else 
                        {
                            // (2) complex page (contains columns) 
                            // cBasicColumns == 0, means that subpage content is empty
                            if (subpageDetails.u.complex.cBasicColumns != 0)
                            {
                                // Retrieve description for each column. 
                                PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                                PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 
 
                                // Arrange each track
                                for (int index = 0; index < arrayColumnDesc.Length && ie == null; index++) 
                                {
                                    ie = PtsHelper.InputHitTestTrack(PtsContext, pt, ref arrayColumnDesc[index]);
                                }
                            } 
                        }
                    } 
 
                    if(ie == null)
                    { 
                        ie = Paragraph.Element as IInputElement;
                    }
                }
            } 

            return ie; 
        } 

        // ----------------------------------------------------------------- 
        // Gets ArrayList of rectangles for ContentElement e if it is
        // found
        // start: int representing start offset of e.
        // length: int representing number of positions occupied by e. 
        // -----------------------------------------------------------------
        ///  
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and 
        ///            some PtsHelper functions.
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function.
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override List GetRectangles(ContentElement e, int start, int length)
        { 
            List rectangles = new List(); 
            if (Paragraph.Element as ContentElement == e)
            { 
                // We have found the element. Return rectangles for this paragraph.
                GetRectanglesForParagraphElement(out rectangles);
            }
            else 
            {
                // Query subpage details 
                PTS.FSSUBPAGEDETAILS subpageDetails; 
                PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
                // Check subpage content. Subpage content may be simple or complex -
                // depending of set of features used in the content of the page.
                // (1) simple subpage (contains only one track)
                // (2) complex subpage (contains columns) 
                if (PTS.ToBoolean(subpageDetails.fSimple))
                { 
                    // (1) simple subpage (contains only one track) 
                    rectangles = PtsHelper.GetRectanglesInTrack(PtsContext, e, start, length, ref subpageDetails.u.simple.trackdescr);
                } 
                else
                {
                    // (2) complex page (contains columns)
                    // cBasicColumns == 0, means that subpage content is empty 
                    if (subpageDetails.u.complex.cBasicColumns != 0)
                    { 
                        // Retrieve description for each column. 
                        PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                        PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                        // Arrange each track
                        for (int index = 0; index < arrayColumnDesc.Length; index++)
                        { 
                            List trackRectangles = PtsHelper.GetRectanglesInTrack(PtsContext, e, start, length, ref arrayColumnDesc[index]);
                            Invariant.Assert(trackRectangles != null); 
                            if (trackRectangles.Count != 0) 
                            {
                                rectangles.AddRange(trackRectangles); 
                            }
                        }
                    }
                } 

                rectangles = PtsHelper.OffsetRectangleList(rectangles, TextDpi.FromTextDpi(ContentRect.u), TextDpi.FromTextDpi(ContentRect.v)); 
            } 

            // Rectangles must be non-null 
            Invariant.Assert(rectangles != null);
            return rectangles;
        }
 
        // -----------------------------------------------------------------
        // Validate visual node associated with paragraph. 
        // 
        //      fskupdInherited - inherited update info
        //      fswdir - inherited flow direction 
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails and
        ///            some PtsHelper functions. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void ValidateVisual(PTS.FSKUPDATE fskupdInherited)
        {
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            // Draw border and background info. 
            MbpInfo mbpInfo = MbpInfo.FromElement(Paragraph.Element);
 
            if(ThisFlowDirection != PageFlowDirection)
            {
                mbpInfo.MirrorBP();
            } 

            Brush backgroundBrush = (Brush)Paragraph.Element.GetValue(TextElement.BackgroundProperty); 
            Visual.DrawBackgroundAndBorder(backgroundBrush, mbpInfo.BorderBrush, mbpInfo.Border, _rect.FromTextDpi(), IsFirstChunk, IsLastChunk); 

            ContainerVisual pageContentVisual; 
            ContainerVisual floatingElementsVisual;

            if(_visual.Children.Count != 2)
            { 
                _visual.Children.Clear();
                _visual.Children.Add(new ContainerVisual()); 
                _visual.Children.Add(new ContainerVisual()); 
            }
 
            pageContentVisual = (ContainerVisual)_visual.Children[0];
            floatingElementsVisual = (ContainerVisual)_visual.Children[1];

 
            // Subpage content may be simple or complex -
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                // (1) simple subpage (contains only one track)
                PTS.FSKUPDATE fskupd = subpageDetails.u.simple.trackdescr.fsupdinf.fskupd;
                if (fskupd == PTS.FSKUPDATE.fskupdInherited) 
                {
                    fskupd = fskupdInherited; 
                } 
                VisualCollection visualChildren = pageContentVisual.Children;
                if (fskupd == PTS.FSKUPDATE.fskupdNew) 
                {
                    visualChildren.Clear();
                    visualChildren.Add(new ContainerVisual());
                } 
                // For complex subpage SectionVisual is added. So, when morphing
                // complex subpage to simple one, remove SectionVisual. 
                else if (visualChildren.Count == 1 && visualChildren[0] is SectionVisual) 
                {
                    visualChildren.Clear(); 
                    visualChildren.Add(new ContainerVisual());
                }
                Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is ContainerVisual);
                ContainerVisual trackVisual = (ContainerVisual)visualChildren[0]; 

                PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref subpageDetails.u.simple.trackdescr); 
            } 
            else
            { 
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage) 
                {
                    // Retrieve description for each column. 
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);
 
                    emptySubpage = (arrayColumnDesc.Length == 0);
                    if (!emptySubpage)
                    {
                        PTS.FSKUPDATE fskupd = fskupdInherited; 
                        ErrorHandler.Assert(fskupd != PTS.FSKUPDATE.fskupdShifted, ErrorHandler.UpdateShiftedNotValid);
                        Debug.Assert(fskupd != PTS.FSKUPDATE.fskupdNoChange); 
 
                        // For complex subpage SectionVisual is added. So, when morphing
                        // simple subpage to complex one, remove ParagraphVisual. 
                        VisualCollection visualChildren = pageContentVisual.Children;
                        if (visualChildren.Count == 0)
                        {
                            visualChildren.Add(new SectionVisual()); 
                        }
                        else if (!(visualChildren[0] is SectionVisual)) 
                        { 
                            visualChildren.Clear();
                            visualChildren.Add(new SectionVisual()); 
                        }
                        Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is SectionVisual);
                        SectionVisual sectionVisual = (SectionVisual)visualChildren[0];
 
                        // Draw column rules.
                        ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(Paragraph.Element); 
                        sectionVisual.DrawColumnRules(ref arrayColumnDesc, TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.v), TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.dv), columnProperties); 

                        visualChildren = sectionVisual.Children; 
                        if (fskupd == PTS.FSKUPDATE.fskupdNew)
                        {
                            visualChildren.Clear();
                            for (int index = 0; index < arrayColumnDesc.Length; index++) 
                            {
                                visualChildren.Add(new ContainerVisual()); 
                            } 
                        }
                        ErrorHandler.Assert(visualChildren.Count == arrayColumnDesc.Length, ErrorHandler.ColumnVisualCountMismatch); 
                        for (int index = 0; index < arrayColumnDesc.Length; index++)
                        {
                            ContainerVisual trackVisual = (ContainerVisual)visualChildren[index];
 
                            PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref arrayColumnDesc[index]);
                        } 
                    } 
                }
                if (emptySubpage) 
                {
                    // There is no content, remove all existing visuals.
                    _visual.Children.Clear();
                } 
            }
 
            pageContentVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi(); 
            floatingElementsVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi();
 
            PTS.FSRECT clipRect = new PTS.FSRECT(_paddingRect.u - _contentRect.u, _paddingRect.v - _contentRect.v, _paddingRect.du, _paddingRect.dv);
            PtsHelper.ClipChildrenToRect(_visual, clipRect.FromTextDpi());
            PtsHelper.UpdateFloatingElementVisuals(floatingElementsVisual, _pageContextOfThisPage.FloatingElementList);
 
        }
 
 
        // -----------------------------------------------------------------
        // Updates viewport 
        // ------------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical functions PTS.FsQuerySubpageDetails,
        ///            and PtsHelper.TrackListFromSubpage. 
        /// Safe - The IntPtr parameters passed to PTS.FsQuerySubpageDetails are SecurityCriticalDataForSet
        ///        which ensures that partial trust code won't be able to set it to a random value. 
        ///        The subpageDetails parameter passed to other methods is generated securely in this function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override void UpdateViewport(ref PTS.FSRECT viewport)
        {
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            PTS.FSRECT viewportSubpage = new PTS.FSRECT(); 

            viewportSubpage.u = viewport.u - ContentRect.u; 
            viewportSubpage.v = viewport.v - ContentRect.v;
            viewportSubpage.du = viewport.du;
            viewportSubpage.dv = viewport.dv;
 
            // Subpage content may be simple or complex -
            // depending of set of features used in the content of the subpage. 
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                PtsHelper.UpdateViewportTrack(PtsContext, ref subpageDetails.u.simple.trackdescr, ref viewportSubpage);
            }
            else 
            {
                // (2) complex page (contains columns) 
                // cBasicColumns == 0, means that subpage content is empty 
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage) 
                {
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc;
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                    emptySubpage = (arrayColumnDesc.Length == 0); 
                    if (!emptySubpage) 
                    {
                        for (int index = 0; index < arrayColumnDesc.Length; index++) 
                        {
                            PtsHelper.UpdateViewportTrack(PtsContext, ref arrayColumnDesc[index], ref viewportSubpage);
                        }
                    } 
                }
            } 
        } 

 
        // ------------------------------------------------------------------
        // Create paragraph result representing this paragraph.
        // -----------------------------------------------------------------
        internal override ParagraphResult CreateParagraphResult() 
        {
            return new SubpageParagraphResult(this); 
        } 

        // ------------------------------------------------------------------ 
        // Return TextContentRange for the content of the paragraph.
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls the Critical function PTS.FsQuerySubpageDetails. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context
        ///        is marked Critical for set and _paraHandle is readonly data for this 
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe] 
        internal override TextContentRange GetTextContentRange()
        {
            TextContentRange textContentRange;
 
            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails)); 

            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the page.
            // (1) simple subpage (contains only one track)
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                // (1) simple subpage (contains only one track) 
                textContentRange = PtsHelper.TextContentRangeFromTrack(PtsContext, subpageDetails.u.simple.trackdescr.pfstrack); 
            }
            else 
            {
                textContentRange = new TextContentRange();

                // (2) complex page (contains columns) 
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0) 
                { 
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);

                    // Arrange each track
                    for (int index = 0; index < arrayColumnDesc.Length; index++) 
                    {
                        // Merge TextContentRanges for all columns 
                        textContentRange.Merge(PtsHelper.TextContentRangeFromTrack(PtsContext, arrayColumnDesc[index].pfstrack)); 
                    }
                } 
            }

            TextElement elementOwner = this.Paragraph.Element as TextElement;
            // If the first paragraph is the first paragraph in the container and it is the first chunk, 
            // include start position of this element.
            if (_isFirstChunk) 
            { 
                textContentRange.Merge(TextContainerHelper.GetTextContentRangeForTextElementEdge(
                    elementOwner, ElementEdge.BeforeStart)); 
            }

            // If the last paragraph is the last paragraph in the container and it is the last chunk,
            // include end position of this element. 
            if (_isLastChunk)
            { 
                textContentRange.Merge(TextContainerHelper.GetTextContentRangeForTextElementEdge( 
                    elementOwner, ElementEdge.AfterEnd));
            } 

            Invariant.Assert(textContentRange != null);
            return textContentRange;
        } 

        ///  
        /// Returns a new collection of ColumnResults for the subpage. Will always 
        /// have at least one column.
        ///  
        /// 
        /// True if any column in the subpage has text content, i.e. does not contain only figures/floaters
        /// 
        ///  
        /// Critical - as this calls the Critical functions PTS.FsQuerySubpageDetails
        ///            and PTS.FsQueryTrackDetails. 
        /// Safe - as this can't be used to pass random parameters.  PtsContext.Context 
        ///        is marked Critical for set and _paraHandle is readonly data for this
        ///        function. 
        /// 
        [SecurityCritical, SecurityTreatAsSafe]
        internal ReadOnlyCollection GetColumnResults(out bool hasTextContent)
        { 
            List columnResults = new List(0);
            Vector contentOffset = new Vector(); 
 
            // hasTextContent is set to true if any of the columns in the subpage has text content. This is determined by checking the columns'
            // paragraph collections 
            hasTextContent = false;

            // Query subpage details
            PTS.FSSUBPAGEDETAILS subpageDetails; 
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails));
 
            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the page.
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple))
            {
                // (1) simple subpage (contains only one track) 
                PTS.FSTRACKDETAILS trackDetails;
                PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, subpageDetails.u.simple.trackdescr.pfstrack, out trackDetails)); 
                if (trackDetails.cParas > 0) 
                {
                    columnResults = new List(1); 
                    ColumnResult columnResult = new ColumnResult(this, ref subpageDetails.u.simple.trackdescr, contentOffset);
                    columnResults.Add(columnResult);
                    if (columnResult.HasTextContent)
                    { 
                        hasTextContent = true;
                    } 
                } 
            }
            else 
            {
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                if (subpageDetails.u.complex.cBasicColumns != 0) 
                {
                    // Retrieve description for each column. 
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);
 
                    columnResults = new List(subpageDetails.u.complex.cBasicColumns);
                    for (int i = 0; i < arrayColumnDesc.Length; i++)
                    {
                        PTS.FSTRACKDETAILS trackDetails; 
                        PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, arrayColumnDesc[i].pfstrack, out trackDetails));
                        if (trackDetails.cParas > 0) 
                        { 
                            ColumnResult columnResult = new ColumnResult(this, ref arrayColumnDesc[i], contentOffset);
                            columnResults.Add(columnResult); 
                            if (columnResult.HasTextContent)
                            {
                                hasTextContent = true;
                            } 
                        }
                    } 
                } 
            }
 
            return new ReadOnlyCollection(columnResults);
        }

        // ----------------------------------------------------------------- 
        // Returns a collection of ParagraphResults for the column's paragraphs.
        // 
        //      pfstrack - Pointer to PTS track representing a column. 
        //      parentOffset - Parent offset from the top of the page.
        //      hasTextContent - true if any of the children paras has text content 
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical function PTS.FsQueryTrackDetails.
        ///  
        [SecurityCritical]
        internal ReadOnlyCollection GetParagraphResultsFromColumn(IntPtr pfstrack, Vector parentOffset, out bool hasTextContent) 
        { 
            // Get track details
            PTS.FSTRACKDETAILS trackDetails; 
            PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, pfstrack, out trackDetails));
            hasTextContent = false;

            if (trackDetails.cParas == 0) { return null; } 

            PTS.FSPARADESCRIPTION[] arrayParaDesc; 
            PtsHelper.ParaListFromTrack(PtsContext, pfstrack, ref trackDetails, out arrayParaDesc); 

            List paragraphResults = new List(arrayParaDesc.Length); 
            for (int i = 0; i < arrayParaDesc.Length; i++)
            {
                BaseParaClient paraClient = PtsContext.HandleToObject(arrayParaDesc[i].pfsparaclient) as BaseParaClient;
                PTS.ValidateHandle(paraClient); 
                ParagraphResult paragraphResult = paraClient.CreateParagraphResult();
                if (paragraphResult.HasTextContent) 
                { 
                    hasTextContent = true;
                } 
                paragraphResults.Add(paragraphResult);
            }
            return new ReadOnlyCollection(paragraphResults);
        } 

        // ------------------------------------------------------------------ 
        // Retrieves text range for contents of the column represented by 
        // 'pfstrack'.
        // 
        //      pfstrack - Pointer to PTS track representing a column.
        // -----------------------------------------------------------------
        /// 
        /// Critical - as this calls Critical function PTS.FsQueryTrackDetails. 
        /// 
        [SecurityCritical] 
        internal TextContentRange GetTextContentRangeFromColumn(IntPtr pfstrack) 
        {
            // Get track details 
            PTS.FSTRACKDETAILS trackDetails;
            PTS.Validate(PTS.FsQueryTrackDetails(PtsContext.Context, pfstrack, out trackDetails));

            // Combine ranges from all nested paragraphs. 
            TextContentRange textContentRange = new TextContentRange();
            if (trackDetails.cParas != 0) 
            { 
                PTS.FSPARADESCRIPTION[] arrayParaDesc;
                PtsHelper.ParaListFromTrack(PtsContext, pfstrack, ref trackDetails, out arrayParaDesc); 

                // Merge TextContentRanges for all paragraphs
                BaseParaClient paraClient;
                for (int i = 0; i < arrayParaDesc.Length; i++) 
                {
                    paraClient = PtsContext.HandleToObject(arrayParaDesc[i].pfsparaclient) as BaseParaClient; 
                    PTS.ValidateHandle(paraClient); 
                    textContentRange.Merge(paraClient.GetTextContentRange());
                } 
            }
            return textContentRange;
        }
 
        // ------------------------------------------------------------------
        // Update information about first/last chunk. 
        // ------------------------------------------------------------------ 
        internal void SetChunkInfo(bool isFirstChunk, bool isLastChunk)
        { 
            _isFirstChunk = isFirstChunk;
            _isLastChunk = isLastChunk;
        }
 
        // -----------------------------------------------------------------
        // Is this the first chunk of paginated content. 
        // ------------------------------------------------------------------ 
        internal override bool IsFirstChunk { get { return _isFirstChunk; } }
        private bool _isFirstChunk; 

        // -----------------------------------------------------------------
        // Is this the last chunk of paginated content.
        // ----------------------------------------------------------------- 
        internal override bool IsLastChunk { get { return _isLastChunk; } }
        private bool _isLastChunk; 
 
        // Floating element list
        internal ReadOnlyCollection FloatingElementResults 
        {
            get
            {
                List floatingElements = new List(0); 
                List floatingElementList = _pageContextOfThisPage.FloatingElementList;
                if (floatingElementList != null) 
                { 

                    for (int i = 0; i < floatingElementList.Count; i++) 
                    {
                        ParagraphResult paragraphResult = floatingElementList[i].CreateParagraphResult();
                        floatingElements.Add(paragraphResult);
                    } 
                }
                return new ReadOnlyCollection(floatingElements); 
            } 
        }
 
        // -----------------------------------------------------------------
        // Rect of content in page coordinate system
        // ------------------------------------------------------------------
        internal PTS.FSRECT ContentRect { get { return _contentRect; } } 

        private PTS.FSRECT _contentRect; 
        private PTS.FSRECT _paddingRect; 

        private PageContext _pageContextOfThisPage = new PageContext(); 
    }
}

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