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

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: SubpageParagraph.cs 
//
// Description: SubpageParagraph represents a PTS subpage. 
// 
// History:
//  25/08/2004 : grzegorz - created. 
//
//---------------------------------------------------------------------------
#pragma warning disable 1634, 1691  // avoid generating warnings about unknown
                                    // message numbers and unknown pragmas for PRESharp contol 

using System; 
using System.Diagnostics; 
using System.Security;
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using MS.Internal.Documents; 
using MS.Internal.Text;
 
using MS.Internal.PtsHost.UnsafeNativeMethods; 

namespace MS.Internal.PtsHost 
{
    // ---------------------------------------------------------------------
    // SubpageParagraph represents a PTS subpage.
    // --------------------------------------------------------------------- 
    internal class SubpageParagraph : BaseParagraph
    { 
        //-------------------------------------------------------------------- 
        //
        //  Constructors 
        //
        //-------------------------------------------------------------------

        #region Constructors 

        // ------------------------------------------------------------------ 
        // Constructor. 
        //
        //      element - Element associated with paragraph. 
        //      structuralCache - Content's structural cache
        // ------------------------------------------------------------------
        internal SubpageParagraph(DependencyObject element, StructuralCache structuralCache)
            : base(element, structuralCache) 
        {
        } 
 
        // -----------------------------------------------------------------
        // IDisposable.Dispose 
        // ------------------------------------------------------------------
        public override void Dispose()
        {
            base.Dispose(); 

            if(_mainTextSegment != null) 
            { 
                _mainTextSegment.Dispose();
                _mainTextSegment = null; 
            }
        }

        #endregion Constructors 

        //------------------------------------------------------------------- 
        // 
        //  PTS callbacks
        // 
        //-------------------------------------------------------------------

        #region PTS callbacks
 
        //-------------------------------------------------------------------
        // GetParaProperties 
        //-------------------------------------------------------------------- 
        internal override void GetParaProperties(
            ref PTS.FSPAP fspap)                // OUT: paragraph properties 
        {
            GetParaProperties(ref fspap, false);
            fspap.idobj = PtsHost.SubpageParagraphId;
            // Create the main text segment 
            if (_mainTextSegment == null)
            { 
                _mainTextSegment = new ContainerParagraph(_element, _structuralCache); 
            }
        } 

        //-------------------------------------------------------------------
        // CreateParaclient
        //-------------------------------------------------------------------- 
        internal override void CreateParaclient(
            out IntPtr paraClientHandle)        // OUT: opaque to PTS paragraph client 
        { 
            SubpageParaClient paraClient;
 
#pragma warning disable 6518
            // Disable PRESharp warning 6518. SubpageParaClient is an UnmamangedHandle, that adds itself
            // to HandleMapper that holds a reference to it. PTS manages lifetime of this object, and
            // calls DestroyParaclient to get rid of it. DestroyParaclient will call Dispose() on the object 
            // and remove it from HandleMapper.
            paraClient =  new SubpageParaClient(this); 
            paraClientHandle = paraClient.Handle; 
#pragma warning restore 6518
        } 

        //--------------------------------------------------------------------
        // FormatParaFinite
        //------------------------------------------------------------------- 
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsCreateSubpageFinite and 
        ///        passes pointer parameter footnoteRejector without validation.
        ///     b) calls Critical function GetColumnsInfo, 
        ///     c) calls Critical function PTS.FsTransformRectangle
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method.
        ///  
        [SecurityCritical]
        internal unsafe void FormatParaFinite( 
            SubpageParaClient paraClient,       // IN: 
            IntPtr pbrkrecIn,                   // IN:  break record---use if !NULL
            int fBRFromPreviousPage,            // IN:  break record was created on previous page 
            IntPtr footnoteRejector,            // IN:
            int fEmptyOk,                       // IN:  is it OK not to add anything?
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            ref PTS.FSRECT fsrcToFill,          // IN:  rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied 
            PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn,
                                                // IN: suppress breaks at track start? 
            out PTS.FSFMTR fsfmtr,              // OUT: result of formatting the paragraph
            out IntPtr pfspara,                 // OUT: pointer to the para data
            out IntPtr pbrkrecOut,              // OUT: pointer to the para break record
            out int dvrUsed,                    // OUT: vertical space used by the para 
            out PTS.FSBBOX fsbbox,              // OUT: para BBox
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom 
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph 
            out int dvrTopSpace)                // OUT: top space due to collapsed margin
        { 
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));

            int subpageWidth, subpageHeight;
            int cColumns; 
            int marginTop, marginBottom;
            MbpInfo mbp; 
            MarginCollapsingState mcsSubpage, mcsBottom; 
            PTS.FSRECT fsrcSubpageMargin;
            PTS.FSCOLUMNINFO [] columnInfoCollection; 

            // Currently it is possible to get MCS and BR in following situation:
            // At the end of the page there is a paragraph with delayed figure, so the figure
            // gets delayed to the next page. But part of the next paragraph fits in the page, 
            // so it gets broken. PTS creates BR with delayed figure and broken para.
            // PTS will format the next page starting from delayed figure, which can produce MCS. 
            // So when the next paragraph is continued from BR, it has MCS. 
            // This problem is currently investigated by PTS team: PTSLS bug 915.
            // For now, MCS gets ignored here. 
            //Debug.Assert(pbrkrecIn == IntPtr.Zero || mcs == null, "Broken paragraph cannot have margin collapsing state.");
            if (mcs != null && pbrkrecIn != IntPtr.Zero)
            {
                mcs = null; 
            }
 
            // Initialize the subpage size and its margin. 
            fsrcSubpageMargin = new PTS.FSRECT();
            subpageWidth = fsrcToFill.du; 
            subpageHeight = fsrcToFill.dv;

            // Set clear property
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock); 
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty));
 
            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0)
            marginTop = 0; 
            mcsSubpage = null;

            // Get MBP info. Since subpage height and width must be at least 1, the max size for MBP is subpage dimensions less 1
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir) 
            { 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFill, fswdirSubpage, out fsrcToFill)); 
                mbp.MirrorMargin();
            }

            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight)); 
            if (pbrkrecIn == IntPtr.Zero)
            { 
                // Top margin collapsing. If suppresing top space, top margin is always 0. 
                MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop);
                if (PTS.ToBoolean(fSuppressTopSpace)) 
                {
                    marginTop = 0;
                }
                subpageHeight = Math.Max(1, subpageHeight - (marginTop + mbp.BPTop)); 
                // Destroy top margin collapsing state (not needed anymore).
                if (mcsSubpage != null) 
                { 
                    mcsSubpage.Dispose();
                    mcsSubpage = null; 
                }
            }
            else
            { 
                Debug.Assert(fSuppressTopSpace == 1, "Top space should be always suppressed at the top of broken paragraph.");
            } 
            fsrcSubpageMargin.du = subpageWidth; 
            fsrcSubpageMargin.dv = subpageHeight;
 
            // Initialize column info
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element);
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element);
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty); 
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty);
 
            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we 
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            {
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false); 
            }
 
            // Format subpage 
            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.FromTextDpi(subpageHeight)),
                                                                 new Thickness(), 
                                                                 false,
                                                                 true);

            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) 
            {
                PTS.Validate(PTS.FsCreateSubpageFinite(PtsContext.Context, pbrkrecIn, fBRFromPreviousPage, _mainTextSegment.Handle, 
                    footnoteRejector, fEmptyOk, fSuppressTopSpace, fswdir, subpageWidth, subpageHeight, 
                    ref fsrcSubpageMargin, cColumns, rgColumnInfo, PTS.False,
                    0, null, null, 0, null, null, PTS.FromBoolean(false), 
                    fsksuppresshardbreakbeforefirstparaIn,
                    out fsfmtr, out pfspara, out pbrkrecOut, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace), PtsContext);
            }
 
            StructuralCache.CurrentFormatContext.PopPageData();
 
            fskclearOut = PTS.FSKCLEAR.fskclearNone; 

            if (PTS.ToBoolean(fsbbox.fDefined)) 
            {
                // Workaround for PTS bug 860: get max of the page rect and
                // bounding box of the page.
                dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v); 
                fsrcToFill.du = Math.Max(fsrcToFill.du, fsbbox.fsrc.du + fsbbox.fsrc.u);
            } 
 
            if (pbrkrecIn == IntPtr.Zero) // if first chunk
            { 
                // Take into account MBPs and modify subpage metrics
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace;
                dvrUsed += (marginTop + mbp.BPTop);
            } 

            if (pmcsclientOut != IntPtr.Zero) 
            { 
                mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                PTS.ValidateHandle(mcsSubpage); 
                pmcsclientOut = IntPtr.Zero;
            }

            // Initialize subpage metrics 
            if (fsfmtr.kstop >= PTS.FSFMTRKSTOP.fmtrNoProgressOutOfSpace)   // No progress or collision
            { 
                dvrUsed = dvrTopSpace = 0; 
                //pbrkrecOut = IntPtr.Zero;
                //pfspara = IntPtr.Zero; 
                //pmcsclientOut = IntPtr.Zero;
            }
            else
            { 
                if (fsfmtr.kstop == PTS.FSFMTRKSTOP.fmtrGoalReached)
                { 
                    // Bottom margin collapsing: 
                    // (a) retrieve mcs from the subpage
                    // (b) do margin collapsing; create a new margin collapsing state 
                    // There is no bottom margin collapsing if paragraph will be continued (output break record is not null).
                    MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                    pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero;
 
                    if (pmcsclientOut == IntPtr.Zero) // if last chunk
                        dvrUsed += marginBottom + mbp.BPBottom; 
                } 

                // Update bounding box 
                fsbbox.fsrc.u = fsrcToFill.u + mbp.MarginLeft;
                fsbbox.fsrc.v = fsrcToFill.v + dvrTopSpace;
                fsbbox.fsrc.du = Math.Max(fsrcToFill.du - (mbp.MarginLeft + mbp.MarginRight), 0);
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0); 
            }
 
            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect; 
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox));
            }

 
            // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
            // If necessary, new MCS is created and passed back to PTS (see above). 
            if (mcsSubpage != null) 
            {
                mcsSubpage.Dispose(); 
                mcsSubpage = null;
            }

 
            // Update information about first/last chunk
            paraClient.SetChunkInfo(pbrkrecIn == IntPtr.Zero, pbrkrecOut == IntPtr.Zero); 
        } 

        //-------------------------------------------------------------------- 
        // FormatParaBottomless
        //-------------------------------------------------------------------
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsCreateSubpageBottomless.
        ///     b) calls Critical function GetColumnsInfo, 
        ///     c) calls Critical function PTS.FsTransformRectangle 
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method. 
        /// Safe, because:
        ///     a) doesn't take any pointer parameter that'll be passed directly.
        ///     b) All Critical data are either Critical for set or generated in the function.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe void FormatParaBottomless( 
            SubpageParaClient paraClient,       // IN: 
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            int urTrack,                        // IN:  ur of bottomless rectangle to fill
            int durTrack,                       // IN:  dur of bottomless rectangle to fill
            int vrTrack,                        // IN:  vr of bottomless rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied
            int fInterruptable,                 // IN:  formatting can be interrupted 
            out PTS.FSFMTRBL fsfmtrbl,          // OUT: result of formatting the paragraph 
            out IntPtr pfspara,                 // OUT: pointer to the para data
            out int dvrUsed,                    // OUT: vertical space used by the para 
            out PTS.FSBBOX fsbbox,              // OUT: para BBox
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph
            out int dvrTopSpace,                // OUT: top space due to collapsed margin 
            out int fPageBecomesUninterruptable)// OUT: interruption is prohibited from now on
        { 
            int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; 
            int cColumns;
            int marginTop, marginBottom; 
            MbpInfo mbp;
            MarginCollapsingState mcsSubpage, mcsBottom;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty))); 

            // Initialize the subpage size and its margin. 
            subpageWidth = durTrack; 
            urSubpageMargin = vrSubpageMargin = 0;
 

            // Set clear property
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock);
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty)); 

            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0) 
            // NOTE: Do not suppress top space for bottomles pages.
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir)
            {
                PTS.FSRECT fsrcToFillSubpage = new PTS.FSRECT(urTrack, 0, durTrack, 0); 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFillSubpage, fswdirSubpage, out fsrcToFillSubpage)); 
 
                urTrack = fsrcToFillSubpage.u;
                durTrack = fsrcToFillSubpage.du; 

                mbp.MirrorMargin();
            }
 
            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight));
            MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop); 
            // Destroy top margin collapsing state (not needed anymore). 
            if (mcsSubpage != null)
            { 
                mcsSubpage.Dispose();
                mcsSubpage = null;
            }
            durSubpageMargin = subpageWidth; 

            // Initialize column info 
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element); 
            // For bottomles spara, limit line height to the height of the current format context in structural cache.
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element); 
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty);
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty);

            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we 
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns]; 
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            { 
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false);
            }

            // Create subpage 

            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.MaxWidth), 
                                                                 new Thickness(), 
                                                                 false,
                                                                 false); 

            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            {
                PTS.Validate(PTS.FsCreateSubpageBottomless(PtsContext.Context, _mainTextSegment.Handle, fSuppressTopSpace, 
                    fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin,
                    cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.FromBoolean(_isInterruptible), 
                    out fsfmtrbl, out pfspara, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace, 
                    out fPageBecomesUninterruptable), PtsContext);
            } 

            StructuralCache.CurrentFormatContext.PopPageData();

            fskclearOut = PTS.FSKCLEAR.fskclearNone; 

            if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision) 
            { 
                // Bottom margin collapsing:
                // (1) retrieve mcs from the subtrack 
                // (2) do margin collapsing; create a new margin collapsing state
                if (pmcsclientOut != IntPtr.Zero)
                {
                    mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState; 
                    PTS.ValidateHandle(mcsSubpage);
                    pmcsclientOut = IntPtr.Zero; 
                } 
                MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero; 

                // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
                // If necessary, new MCS is created and passed back to PTS.
                if (mcsSubpage != null) 
                {
                    mcsSubpage.Dispose(); 
                    mcsSubpage = null; 
                }
 
                if (PTS.ToBoolean(fsbbox.fDefined))
                {
                    // Workaround for PTS bug 860: get max of the page rect and
                    // bounding box of the page. 
                    dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v);
                    durTrack = Math.Max(durTrack, fsbbox.fsrc.du + fsbbox.fsrc.u); 
                } 

                // Take into account MBPs and modify subtrack metrics 
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace;
                dvrUsed += (marginTop + mbp.BPTop) + (marginBottom + mbp.BPBottom);

                // Update bounding box 
                fsbbox.fsrc.u = urTrack + mbp.MarginLeft;
                fsbbox.fsrc.v = vrTrack + dvrTopSpace; 
                fsbbox.fsrc.du = Math.Max(durTrack - (mbp.MarginLeft + mbp.MarginRight), 0); 
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0);
            } 
            else
            {
                Debug.Assert(pmcsclientOut == IntPtr.Zero);
                pfspara = IntPtr.Zero; 
                dvrUsed = dvrTopSpace = 0;
            } 
 

            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox));
            } 

            // Update information about first/last chunk. In bottomless scenario 
            // paragraph is not broken, so there is only one chunk. 
            paraClient.SetChunkInfo(true, true);
        } 

        //-------------------------------------------------------------------
        // UpdateBottomlessPara
        //------------------------------------------------------------------- 
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsUpdateBottomlessSubpage. 
        ///     b) calls Critical function GetColumnsInfo,
        ///     c) calls Critical function PTS.FsTransformRectangle 
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method.
        /// 
        [SecurityCritical] 
        internal unsafe void UpdateBottomlessPara(
            IntPtr pfspara,                     // IN:  pointer to the para data 
            SubpageParaClient paraClient,       // IN: 
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            int urTrack,                        // IN:  u of bootomless rectangle to fill
            int durTrack,                       // IN:  du of bootomless rectangle to fill
            int vrTrack,                        // IN:  v of bootomless rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied
            int fInterruptable,                 // IN:  formatting can be interrupted 
            out PTS.FSFMTRBL fsfmtrbl,          // OUT: result of formatting the paragraph 
            out int dvrUsed,                    // OUT: vertical space used by the para
            out PTS.FSBBOX fsbbox,              // OUT: para BBox 
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph
            out int dvrTopSpace,                // OUT: top space due to collapsed margin
            out int fPageBecomesUninterruptable)// OUT: interruption is prohibited from now on 
        {
            int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; 
            int cColumns; 
            int marginTop, marginBottom;
            MbpInfo mbp; 
            MarginCollapsingState mcsSubpage, mcsBottom;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));
 
            // Initialize the subpage size and its margin.
            subpageWidth = durTrack; 
            urSubpageMargin = vrSubpageMargin = 0; 

            // Set clear property 
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock);
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty));

            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0)
            // NOTE: Do not suppress top space for bottomles pages. 
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT fsrcToFillSubpage = new PTS.FSRECT(urTrack, 0, durTrack, 0);
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFillSubpage, fswdirSubpage, out fsrcToFillSubpage)); 

                urTrack = fsrcToFillSubpage.u; 
                durTrack = fsrcToFillSubpage.du; 

                mbp.MirrorMargin(); 
            }

            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight));
            MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop); 
            // Destroy top margin collapsing state (not needed anymore).
            if (mcsSubpage != null) 
            { 
                mcsSubpage.Dispose();
                mcsSubpage = null; 
            }
            durSubpageMargin = subpageWidth;

            // Initialize column info 
            // For bottomles spara, limit line height to the height of the current format context in structural cache.
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element); 
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element); 
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty);
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty); 

            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) 
            { 
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false);
            } 

            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.MaxWidth),
                                                                 new Thickness(),
                                                                 true, 
                                                                 false);
 
            // Create subpage 
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            { 
                PTS.Validate(PTS.FsUpdateBottomlessSubpage(PtsContext.Context, pfspara, _mainTextSegment.Handle, fSuppressTopSpace,
                    fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin,
                    cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.FromBoolean(true),
                    out fsfmtrbl, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace, 
                    out fPageBecomesUninterruptable), PtsContext);
            } 
 
            StructuralCache.CurrentFormatContext.PopPageData();
 
            fskclearOut = PTS.FSKCLEAR.fskclearNone;

            if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision)
            { 
                // Bottom margin collapsing:
                // (1) retrieve mcs from the subtrack 
                // (2) do margin collapsing; create a new margin collapsing state 
                if (pmcsclientOut != IntPtr.Zero)
                { 
                    mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                    PTS.ValidateHandle(mcsSubpage);
                    pmcsclientOut = IntPtr.Zero;
                } 
                MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero; 
 
                // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
                // If necessary, new MCS is created and passed back to PTS. 
                if (mcsSubpage != null)
                {
                    mcsSubpage.Dispose();
                    mcsSubpage = null; 
                }
 
                if (PTS.ToBoolean(fsbbox.fDefined)) 
                {
                    // Workaround for PTS bug 860: get max of the page rect and 
                    // bounding box of the page.
                    dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v);
                    durTrack = Math.Max(durTrack, fsbbox.fsrc.du + fsbbox.fsrc.u);
                } 

                // Take into account MBPs and modify subtrack metrics 
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace; 
                dvrUsed += (marginTop + mbp.BPTop) + (marginBottom + mbp.BPBottom);
 
                // Update bounding box
                fsbbox.fsrc.u = urTrack + mbp.MarginLeft;
                fsbbox.fsrc.v = vrTrack + dvrTopSpace;
                fsbbox.fsrc.du = Math.Max(durTrack - (mbp.MarginLeft + mbp.MarginRight), 0); 
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0);
            } 
            else 
            {
                Debug.Assert(pmcsclientOut == IntPtr.Zero); 
                pfspara = IntPtr.Zero;
                dvrUsed = dvrTopSpace = 0;
            }
 

            if(fswdirSubpage != fswdir) 
            { 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox)); 
            }

            // Update information about first/last chunk. In bottomless scenario
            // paragraph is not broken, so there is only one chunk. 
            paraClient.SetChunkInfo(true, true);
        } 
 
        #endregion PTS callbacks
 
        // ------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        // -----------------------------------------------------------------
 
        #region Internal Methods 

        // ------------------------------------------------------------------ 
        // Clear previously accumulated update info.
        // ------------------------------------------------------------------
        internal override void ClearUpdateInfo()
        { 
            if (_mainTextSegment != null)
            { 
                _mainTextSegment.ClearUpdateInfo(); 
            }
            base.ClearUpdateInfo(); 
        }

        // -----------------------------------------------------------------
        // Invalidate content's structural cache. 
        //
        //      startPosition - Position to start invalidation from. 
        // 
        // Returns: 'true' if entire paragraph is invalid.
        // ------------------------------------------------------------------ 
        internal override bool InvalidateStructure(int startPosition)
        {
            Debug.Assert(ParagraphEndCharacterPosition >= startPosition);
            if (_mainTextSegment != null) 
            {
                if (_mainTextSegment.InvalidateStructure(startPosition)) 
                { 
                    _mainTextSegment.Dispose();
                    _mainTextSegment = null; 
                }
            }
            return (_mainTextSegment == null);
        } 

        // ----------------------------------------------------------------- 
        // Invalidate accumulated format caches. 
        // -----------------------------------------------------------------
        internal override void InvalidateFormatCache() 
        {
            if (_mainTextSegment != null)
            {
                _mainTextSegment.InvalidateFormatCache(); 
            }
        } 
 
        /// 
        /// Update number of characters consumed by the main text segment. 
        /// 
        internal void UpdateSegmentLastFormatPositions()
        {
            _mainTextSegment.UpdateLastFormatPositions(); 
        }
 
        #endregion Internal Methods 

        //------------------------------------------------------------------- 
        //
        //  Private Fields
        //
        //-------------------------------------------------------------------- 

        #region Private Fields 
 
        //-------------------------------------------------------------------
        // Main text segment. 
        //--------------------------------------------------------------------
        private BaseParagraph _mainTextSegment;
        protected bool _isInterruptible = true;
 
        #endregion Private Fields
    } 
} 

#pragma warning enable 1634, 1691 


// 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: SubpageParagraph.cs 
//
// Description: SubpageParagraph represents a PTS subpage. 
// 
// History:
//  25/08/2004 : grzegorz - created. 
//
//---------------------------------------------------------------------------
#pragma warning disable 1634, 1691  // avoid generating warnings about unknown
                                    // message numbers and unknown pragmas for PRESharp contol 

using System; 
using System.Diagnostics; 
using System.Security;
using System.Windows; 
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using MS.Internal.Documents; 
using MS.Internal.Text;
 
using MS.Internal.PtsHost.UnsafeNativeMethods; 

namespace MS.Internal.PtsHost 
{
    // ---------------------------------------------------------------------
    // SubpageParagraph represents a PTS subpage.
    // --------------------------------------------------------------------- 
    internal class SubpageParagraph : BaseParagraph
    { 
        //-------------------------------------------------------------------- 
        //
        //  Constructors 
        //
        //-------------------------------------------------------------------

        #region Constructors 

        // ------------------------------------------------------------------ 
        // Constructor. 
        //
        //      element - Element associated with paragraph. 
        //      structuralCache - Content's structural cache
        // ------------------------------------------------------------------
        internal SubpageParagraph(DependencyObject element, StructuralCache structuralCache)
            : base(element, structuralCache) 
        {
        } 
 
        // -----------------------------------------------------------------
        // IDisposable.Dispose 
        // ------------------------------------------------------------------
        public override void Dispose()
        {
            base.Dispose(); 

            if(_mainTextSegment != null) 
            { 
                _mainTextSegment.Dispose();
                _mainTextSegment = null; 
            }
        }

        #endregion Constructors 

        //------------------------------------------------------------------- 
        // 
        //  PTS callbacks
        // 
        //-------------------------------------------------------------------

        #region PTS callbacks
 
        //-------------------------------------------------------------------
        // GetParaProperties 
        //-------------------------------------------------------------------- 
        internal override void GetParaProperties(
            ref PTS.FSPAP fspap)                // OUT: paragraph properties 
        {
            GetParaProperties(ref fspap, false);
            fspap.idobj = PtsHost.SubpageParagraphId;
            // Create the main text segment 
            if (_mainTextSegment == null)
            { 
                _mainTextSegment = new ContainerParagraph(_element, _structuralCache); 
            }
        } 

        //-------------------------------------------------------------------
        // CreateParaclient
        //-------------------------------------------------------------------- 
        internal override void CreateParaclient(
            out IntPtr paraClientHandle)        // OUT: opaque to PTS paragraph client 
        { 
            SubpageParaClient paraClient;
 
#pragma warning disable 6518
            // Disable PRESharp warning 6518. SubpageParaClient is an UnmamangedHandle, that adds itself
            // to HandleMapper that holds a reference to it. PTS manages lifetime of this object, and
            // calls DestroyParaclient to get rid of it. DestroyParaclient will call Dispose() on the object 
            // and remove it from HandleMapper.
            paraClient =  new SubpageParaClient(this); 
            paraClientHandle = paraClient.Handle; 
#pragma warning restore 6518
        } 

        //--------------------------------------------------------------------
        // FormatParaFinite
        //------------------------------------------------------------------- 
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsCreateSubpageFinite and 
        ///        passes pointer parameter footnoteRejector without validation.
        ///     b) calls Critical function GetColumnsInfo, 
        ///     c) calls Critical function PTS.FsTransformRectangle
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method.
        ///  
        [SecurityCritical]
        internal unsafe void FormatParaFinite( 
            SubpageParaClient paraClient,       // IN: 
            IntPtr pbrkrecIn,                   // IN:  break record---use if !NULL
            int fBRFromPreviousPage,            // IN:  break record was created on previous page 
            IntPtr footnoteRejector,            // IN:
            int fEmptyOk,                       // IN:  is it OK not to add anything?
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            ref PTS.FSRECT fsrcToFill,          // IN:  rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied 
            PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn,
                                                // IN: suppress breaks at track start? 
            out PTS.FSFMTR fsfmtr,              // OUT: result of formatting the paragraph
            out IntPtr pfspara,                 // OUT: pointer to the para data
            out IntPtr pbrkrecOut,              // OUT: pointer to the para break record
            out int dvrUsed,                    // OUT: vertical space used by the para 
            out PTS.FSBBOX fsbbox,              // OUT: para BBox
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom 
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph 
            out int dvrTopSpace)                // OUT: top space due to collapsed margin
        { 
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));

            int subpageWidth, subpageHeight;
            int cColumns; 
            int marginTop, marginBottom;
            MbpInfo mbp; 
            MarginCollapsingState mcsSubpage, mcsBottom; 
            PTS.FSRECT fsrcSubpageMargin;
            PTS.FSCOLUMNINFO [] columnInfoCollection; 

            // Currently it is possible to get MCS and BR in following situation:
            // At the end of the page there is a paragraph with delayed figure, so the figure
            // gets delayed to the next page. But part of the next paragraph fits in the page, 
            // so it gets broken. PTS creates BR with delayed figure and broken para.
            // PTS will format the next page starting from delayed figure, which can produce MCS. 
            // So when the next paragraph is continued from BR, it has MCS. 
            // This problem is currently investigated by PTS team: PTSLS bug 915.
            // For now, MCS gets ignored here. 
            //Debug.Assert(pbrkrecIn == IntPtr.Zero || mcs == null, "Broken paragraph cannot have margin collapsing state.");
            if (mcs != null && pbrkrecIn != IntPtr.Zero)
            {
                mcs = null; 
            }
 
            // Initialize the subpage size and its margin. 
            fsrcSubpageMargin = new PTS.FSRECT();
            subpageWidth = fsrcToFill.du; 
            subpageHeight = fsrcToFill.dv;

            // Set clear property
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock); 
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty));
 
            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0)
            marginTop = 0; 
            mcsSubpage = null;

            // Get MBP info. Since subpage height and width must be at least 1, the max size for MBP is subpage dimensions less 1
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir) 
            { 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFill, fswdirSubpage, out fsrcToFill)); 
                mbp.MirrorMargin();
            }

            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight)); 
            if (pbrkrecIn == IntPtr.Zero)
            { 
                // Top margin collapsing. If suppresing top space, top margin is always 0. 
                MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop);
                if (PTS.ToBoolean(fSuppressTopSpace)) 
                {
                    marginTop = 0;
                }
                subpageHeight = Math.Max(1, subpageHeight - (marginTop + mbp.BPTop)); 
                // Destroy top margin collapsing state (not needed anymore).
                if (mcsSubpage != null) 
                { 
                    mcsSubpage.Dispose();
                    mcsSubpage = null; 
                }
            }
            else
            { 
                Debug.Assert(fSuppressTopSpace == 1, "Top space should be always suppressed at the top of broken paragraph.");
            } 
            fsrcSubpageMargin.du = subpageWidth; 
            fsrcSubpageMargin.dv = subpageHeight;
 
            // Initialize column info
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element);
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element);
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty); 
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty);
 
            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we 
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            {
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false); 
            }
 
            // Format subpage 
            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.FromTextDpi(subpageHeight)),
                                                                 new Thickness(), 
                                                                 false,
                                                                 true);

            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) 
            {
                PTS.Validate(PTS.FsCreateSubpageFinite(PtsContext.Context, pbrkrecIn, fBRFromPreviousPage, _mainTextSegment.Handle, 
                    footnoteRejector, fEmptyOk, fSuppressTopSpace, fswdir, subpageWidth, subpageHeight, 
                    ref fsrcSubpageMargin, cColumns, rgColumnInfo, PTS.False,
                    0, null, null, 0, null, null, PTS.FromBoolean(false), 
                    fsksuppresshardbreakbeforefirstparaIn,
                    out fsfmtr, out pfspara, out pbrkrecOut, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace), PtsContext);
            }
 
            StructuralCache.CurrentFormatContext.PopPageData();
 
            fskclearOut = PTS.FSKCLEAR.fskclearNone; 

            if (PTS.ToBoolean(fsbbox.fDefined)) 
            {
                // Workaround for PTS bug 860: get max of the page rect and
                // bounding box of the page.
                dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v); 
                fsrcToFill.du = Math.Max(fsrcToFill.du, fsbbox.fsrc.du + fsbbox.fsrc.u);
            } 
 
            if (pbrkrecIn == IntPtr.Zero) // if first chunk
            { 
                // Take into account MBPs and modify subpage metrics
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace;
                dvrUsed += (marginTop + mbp.BPTop);
            } 

            if (pmcsclientOut != IntPtr.Zero) 
            { 
                mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                PTS.ValidateHandle(mcsSubpage); 
                pmcsclientOut = IntPtr.Zero;
            }

            // Initialize subpage metrics 
            if (fsfmtr.kstop >= PTS.FSFMTRKSTOP.fmtrNoProgressOutOfSpace)   // No progress or collision
            { 
                dvrUsed = dvrTopSpace = 0; 
                //pbrkrecOut = IntPtr.Zero;
                //pfspara = IntPtr.Zero; 
                //pmcsclientOut = IntPtr.Zero;
            }
            else
            { 
                if (fsfmtr.kstop == PTS.FSFMTRKSTOP.fmtrGoalReached)
                { 
                    // Bottom margin collapsing: 
                    // (a) retrieve mcs from the subpage
                    // (b) do margin collapsing; create a new margin collapsing state 
                    // There is no bottom margin collapsing if paragraph will be continued (output break record is not null).
                    MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                    pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero;
 
                    if (pmcsclientOut == IntPtr.Zero) // if last chunk
                        dvrUsed += marginBottom + mbp.BPBottom; 
                } 

                // Update bounding box 
                fsbbox.fsrc.u = fsrcToFill.u + mbp.MarginLeft;
                fsbbox.fsrc.v = fsrcToFill.v + dvrTopSpace;
                fsbbox.fsrc.du = Math.Max(fsrcToFill.du - (mbp.MarginLeft + mbp.MarginRight), 0);
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0); 
            }
 
            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect; 
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox));
            }

 
            // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
            // If necessary, new MCS is created and passed back to PTS (see above). 
            if (mcsSubpage != null) 
            {
                mcsSubpage.Dispose(); 
                mcsSubpage = null;
            }

 
            // Update information about first/last chunk
            paraClient.SetChunkInfo(pbrkrecIn == IntPtr.Zero, pbrkrecOut == IntPtr.Zero); 
        } 

        //-------------------------------------------------------------------- 
        // FormatParaBottomless
        //-------------------------------------------------------------------
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsCreateSubpageBottomless.
        ///     b) calls Critical function GetColumnsInfo, 
        ///     c) calls Critical function PTS.FsTransformRectangle 
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method. 
        /// Safe, because:
        ///     a) doesn't take any pointer parameter that'll be passed directly.
        ///     b) All Critical data are either Critical for set or generated in the function.
        ///  
        [SecurityCritical, SecurityTreatAsSafe]
        internal unsafe void FormatParaBottomless( 
            SubpageParaClient paraClient,       // IN: 
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            int urTrack,                        // IN:  ur of bottomless rectangle to fill
            int durTrack,                       // IN:  dur of bottomless rectangle to fill
            int vrTrack,                        // IN:  vr of bottomless rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied
            int fInterruptable,                 // IN:  formatting can be interrupted 
            out PTS.FSFMTRBL fsfmtrbl,          // OUT: result of formatting the paragraph 
            out IntPtr pfspara,                 // OUT: pointer to the para data
            out int dvrUsed,                    // OUT: vertical space used by the para 
            out PTS.FSBBOX fsbbox,              // OUT: para BBox
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph
            out int dvrTopSpace,                // OUT: top space due to collapsed margin 
            out int fPageBecomesUninterruptable)// OUT: interruption is prohibited from now on
        { 
            int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; 
            int cColumns;
            int marginTop, marginBottom; 
            MbpInfo mbp;
            MarginCollapsingState mcsSubpage, mcsBottom;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty))); 

            // Initialize the subpage size and its margin. 
            subpageWidth = durTrack; 
            urSubpageMargin = vrSubpageMargin = 0;
 

            // Set clear property
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock);
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty)); 

            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0) 
            // NOTE: Do not suppress top space for bottomles pages.
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir)
            {
                PTS.FSRECT fsrcToFillSubpage = new PTS.FSRECT(urTrack, 0, durTrack, 0); 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFillSubpage, fswdirSubpage, out fsrcToFillSubpage)); 
 
                urTrack = fsrcToFillSubpage.u;
                durTrack = fsrcToFillSubpage.du; 

                mbp.MirrorMargin();
            }
 
            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight));
            MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop); 
            // Destroy top margin collapsing state (not needed anymore). 
            if (mcsSubpage != null)
            { 
                mcsSubpage.Dispose();
                mcsSubpage = null;
            }
            durSubpageMargin = subpageWidth; 

            // Initialize column info 
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element); 
            // For bottomles spara, limit line height to the height of the current format context in structural cache.
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element); 
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty);
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty);

            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we 
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns]; 
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            { 
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false);
            }

            // Create subpage 

            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.MaxWidth), 
                                                                 new Thickness(), 
                                                                 false,
                                                                 false); 

            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            {
                PTS.Validate(PTS.FsCreateSubpageBottomless(PtsContext.Context, _mainTextSegment.Handle, fSuppressTopSpace, 
                    fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin,
                    cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.FromBoolean(_isInterruptible), 
                    out fsfmtrbl, out pfspara, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace, 
                    out fPageBecomesUninterruptable), PtsContext);
            } 

            StructuralCache.CurrentFormatContext.PopPageData();

            fskclearOut = PTS.FSKCLEAR.fskclearNone; 

            if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision) 
            { 
                // Bottom margin collapsing:
                // (1) retrieve mcs from the subtrack 
                // (2) do margin collapsing; create a new margin collapsing state
                if (pmcsclientOut != IntPtr.Zero)
                {
                    mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState; 
                    PTS.ValidateHandle(mcsSubpage);
                    pmcsclientOut = IntPtr.Zero; 
                } 
                MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero; 

                // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
                // If necessary, new MCS is created and passed back to PTS.
                if (mcsSubpage != null) 
                {
                    mcsSubpage.Dispose(); 
                    mcsSubpage = null; 
                }
 
                if (PTS.ToBoolean(fsbbox.fDefined))
                {
                    // Workaround for PTS bug 860: get max of the page rect and
                    // bounding box of the page. 
                    dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v);
                    durTrack = Math.Max(durTrack, fsbbox.fsrc.du + fsbbox.fsrc.u); 
                } 

                // Take into account MBPs and modify subtrack metrics 
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace;
                dvrUsed += (marginTop + mbp.BPTop) + (marginBottom + mbp.BPBottom);

                // Update bounding box 
                fsbbox.fsrc.u = urTrack + mbp.MarginLeft;
                fsbbox.fsrc.v = vrTrack + dvrTopSpace; 
                fsbbox.fsrc.du = Math.Max(durTrack - (mbp.MarginLeft + mbp.MarginRight), 0); 
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0);
            } 
            else
            {
                Debug.Assert(pmcsclientOut == IntPtr.Zero);
                pfspara = IntPtr.Zero; 
                dvrUsed = dvrTopSpace = 0;
            } 
 

            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox));
            } 

            // Update information about first/last chunk. In bottomless scenario 
            // paragraph is not broken, so there is only one chunk. 
            paraClient.SetChunkInfo(true, true);
        } 

        //-------------------------------------------------------------------
        // UpdateBottomlessPara
        //------------------------------------------------------------------- 
        /// 
        /// Critical, because: 
        ///     a) calls Critical function PTS.FsUpdateBottomlessSubpage. 
        ///     b) calls Critical function GetColumnsInfo,
        ///     c) calls Critical function PTS.FsTransformRectangle 
        ///     d) calls Critical function PTS.FsTransformBbox
        ///     e) it is unsafe method.
        /// 
        [SecurityCritical] 
        internal unsafe void UpdateBottomlessPara(
            IntPtr pfspara,                     // IN:  pointer to the para data 
            SubpageParaClient paraClient,       // IN: 
            int fSuppressTopSpace,              // IN:  suppress empty space at the top of the page
            uint fswdir,                        // IN:  current direction 
            int urTrack,                        // IN:  u of bootomless rectangle to fill
            int durTrack,                       // IN:  du of bootomless rectangle to fill
            int vrTrack,                        // IN:  v of bootomless rectangle to fill
            MarginCollapsingState mcs,          // IN:  input margin collapsing state 
            PTS.FSKCLEAR fskclearIn,            // IN:  clear property that must be satisfied
            int fInterruptable,                 // IN:  formatting can be interrupted 
            out PTS.FSFMTRBL fsfmtrbl,          // OUT: result of formatting the paragraph 
            out int dvrUsed,                    // OUT: vertical space used by the para
            out PTS.FSBBOX fsbbox,              // OUT: para BBox 
            out IntPtr pmcsclientOut,           // OUT: margin collapsing state at the bottom
            out PTS.FSKCLEAR fskclearOut,       // OUT: ClearIn for the next paragraph
            out int dvrTopSpace,                // OUT: top space due to collapsed margin
            out int fPageBecomesUninterruptable)// OUT: interruption is prohibited from now on 
        {
            int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; 
            int cColumns; 
            int marginTop, marginBottom;
            MbpInfo mbp; 
            MarginCollapsingState mcsSubpage, mcsBottom;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            uint fswdirSubpage = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));
 
            // Initialize the subpage size and its margin.
            subpageWidth = durTrack; 
            urSubpageMargin = vrSubpageMargin = 0; 

            // Set clear property 
            Invariant.Assert(Element is TableCell || Element is AnchoredBlock);
            fskclearIn = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty));

            // Take into account MBPs and modify subpage metrics, 
            // and make sure that subpage is at least 1 unit wide (cannot measure at width <= 0)
            // NOTE: Do not suppress top space for bottomles pages. 
            mbp = MbpInfo.FromElement(Element); 

            if(fswdirSubpage != fswdir) 
            {
                PTS.FSRECT fsrcToFillSubpage = new PTS.FSRECT(urTrack, 0, durTrack, 0);
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformRectangle(fswdir, ref pageRect, ref fsrcToFillSubpage, fswdirSubpage, out fsrcToFillSubpage)); 

                urTrack = fsrcToFillSubpage.u; 
                durTrack = fsrcToFillSubpage.du; 

                mbp.MirrorMargin(); 
            }

            subpageWidth = Math.Max(1, subpageWidth - (mbp.MBPLeft + mbp.MBPRight));
            MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsSubpage, out marginTop); 
            // Destroy top margin collapsing state (not needed anymore).
            if (mcsSubpage != null) 
            { 
                mcsSubpage.Dispose();
                mcsSubpage = null; 
            }
            durSubpageMargin = subpageWidth;

            // Initialize column info 
            // For bottomles spara, limit line height to the height of the current format context in structural cache.
            ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(_element); 
            double lineHeight = DynamicPropertyReader.GetLineHeightValue(_element); 
            double pageFontSize = (double)_structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty);
            FontFamily pageFontFamily = (FontFamily)_structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty); 

            // Get columns info, setting ownerIsFlowDocument flag to false. A flow document should not be formatted as a subpage and we
            // do not want default column widths to be set on TableCells and floaters
            cColumns = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, false); 
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) 
            { 
                PtsHelper.GetColumnsInfo(columnProperties, lineHeight, TextDpi.FromTextDpi(subpageWidth), pageFontSize, pageFontFamily, cColumns, rgColumnInfo, false);
            } 

            StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(subpageWidth), TextDpi.MaxWidth),
                                                                 new Thickness(),
                                                                 true, 
                                                                 false);
 
            // Create subpage 
            fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection)
            { 
                PTS.Validate(PTS.FsUpdateBottomlessSubpage(PtsContext.Context, pfspara, _mainTextSegment.Handle, fSuppressTopSpace,
                    fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin,
                    cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.FromBoolean(true),
                    out fsfmtrbl, out dvrUsed, out fsbbox, out pmcsclientOut, out dvrTopSpace, 
                    out fPageBecomesUninterruptable), PtsContext);
            } 
 
            StructuralCache.CurrentFormatContext.PopPageData();
 
            fskclearOut = PTS.FSKCLEAR.fskclearNone;

            if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision)
            { 
                // Bottom margin collapsing:
                // (1) retrieve mcs from the subtrack 
                // (2) do margin collapsing; create a new margin collapsing state 
                if (pmcsclientOut != IntPtr.Zero)
                { 
                    mcsSubpage = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                    PTS.ValidateHandle(mcsSubpage);
                    pmcsclientOut = IntPtr.Zero;
                } 
                MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsSubpage, out mcsBottom, out marginBottom);
                pmcsclientOut = (mcsBottom != null) ? mcsBottom.Handle : IntPtr.Zero; 
 
                // Since MCS returned by PTS is never passed back, destroy MCS provided by PTS.
                // If necessary, new MCS is created and passed back to PTS. 
                if (mcsSubpage != null)
                {
                    mcsSubpage.Dispose();
                    mcsSubpage = null; 
                }
 
                if (PTS.ToBoolean(fsbbox.fDefined)) 
                {
                    // Workaround for PTS bug 860: get max of the page rect and 
                    // bounding box of the page.
                    dvrUsed = Math.Max(dvrUsed, fsbbox.fsrc.dv + fsbbox.fsrc.v);
                    durTrack = Math.Max(durTrack, fsbbox.fsrc.du + fsbbox.fsrc.u);
                } 

                // Take into account MBPs and modify subtrack metrics 
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrTopSpace; 
                dvrUsed += (marginTop + mbp.BPTop) + (marginBottom + mbp.BPBottom);
 
                // Update bounding box
                fsbbox.fsrc.u = urTrack + mbp.MarginLeft;
                fsbbox.fsrc.v = vrTrack + dvrTopSpace;
                fsbbox.fsrc.du = Math.Max(durTrack - (mbp.MarginLeft + mbp.MarginRight), 0); 
                fsbbox.fsrc.dv = Math.Max(dvrUsed - dvrTopSpace, 0);
            } 
            else 
            {
                Debug.Assert(pmcsclientOut == IntPtr.Zero); 
                pfspara = IntPtr.Zero;
                dvrUsed = dvrTopSpace = 0;
            }
 

            if(fswdirSubpage != fswdir) 
            { 
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformBbox(fswdirSubpage, ref pageRect, ref fsbbox, fswdir, out fsbbox)); 
            }

            // Update information about first/last chunk. In bottomless scenario
            // paragraph is not broken, so there is only one chunk. 
            paraClient.SetChunkInfo(true, true);
        } 
 
        #endregion PTS callbacks
 
        // ------------------------------------------------------------------
        //
        //  Internal Methods
        // 
        // -----------------------------------------------------------------
 
        #region Internal Methods 

        // ------------------------------------------------------------------ 
        // Clear previously accumulated update info.
        // ------------------------------------------------------------------
        internal override void ClearUpdateInfo()
        { 
            if (_mainTextSegment != null)
            { 
                _mainTextSegment.ClearUpdateInfo(); 
            }
            base.ClearUpdateInfo(); 
        }

        // -----------------------------------------------------------------
        // Invalidate content's structural cache. 
        //
        //      startPosition - Position to start invalidation from. 
        // 
        // Returns: 'true' if entire paragraph is invalid.
        // ------------------------------------------------------------------ 
        internal override bool InvalidateStructure(int startPosition)
        {
            Debug.Assert(ParagraphEndCharacterPosition >= startPosition);
            if (_mainTextSegment != null) 
            {
                if (_mainTextSegment.InvalidateStructure(startPosition)) 
                { 
                    _mainTextSegment.Dispose();
                    _mainTextSegment = null; 
                }
            }
            return (_mainTextSegment == null);
        } 

        // ----------------------------------------------------------------- 
        // Invalidate accumulated format caches. 
        // -----------------------------------------------------------------
        internal override void InvalidateFormatCache() 
        {
            if (_mainTextSegment != null)
            {
                _mainTextSegment.InvalidateFormatCache(); 
            }
        } 
 
        /// 
        /// Update number of characters consumed by the main text segment. 
        /// 
        internal void UpdateSegmentLastFormatPositions()
        {
            _mainTextSegment.UpdateLastFormatPositions(); 
        }
 
        #endregion Internal Methods 

        //------------------------------------------------------------------- 
        //
        //  Private Fields
        //
        //-------------------------------------------------------------------- 

        #region Private Fields 
 
        //-------------------------------------------------------------------
        // Main text segment. 
        //--------------------------------------------------------------------
        private BaseParagraph _mainTextSegment;
        protected bool _isInterruptible = true;
 
        #endregion Private Fields
    } 
} 

#pragma warning enable 1634, 1691 


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