SubpageParagraph.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / PtsHost / SubpageParagraph.cs / 1305600 / SubpageParagraph.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
// File: SubpageParagraph.cs 
//
// Description: SubpageParagraph represents a PTS subpage. 
// 
// History:
//  25/08/2004 : [....] - 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; 
            }
            GC.SuppressFinalize(this);
        }
 
        #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 : [....] - 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; 
            }
            GC.SuppressFinalize(this);
        }
 
        #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