private PTS.FSRECT GetRect()
        {
            PTS.FSRECT rect;
            // There are 3 cases when calculating page rect:
            // (1) PTS page is not created - return empty rect.
            // (2) PTS page    - use page PTS APIs to get page rectangle.
            // (3) PTS subpage - use subpage PTS APIs to get page rectangle.
            if (IsEmpty)
            {
                // (1) PTS page is not created - empty rect.
                rect = new PTS.FSRECT();
            }
            else
            {
                // (2) PTS page - use page PTS APIs to get page rectangle.
                PTS.FSPAGEDETAILS pageDetails;
                PTS.Validate(PTS.FsQueryPageDetails(PtsContext.Context, _ptsPage.Value, out pageDetails));

                // There are 2 different types of PTS page and calculated rectangle depends on it:
                // (a) simple page (contains only one track) - get rectanglefrom the track.
                // (b) complex page (contains header, page body, footnotes and footer) - get bounding 
                //     box of each segment and union them.
                if (PTS.ToBoolean(pageDetails.fSimple))
                {
                    // (a) simple page (contains only one track) - get rectanglefrom the track.
                    rect = pageDetails.u.simple.trackdescr.fsrc;
                }
                else
                {
                    // (b) complex page (contains header, page body, footnotes and footer) - get rectangle 
                    //     of each segment and union them.
                    //ErrorHandler.Assert(!PTS.ToBoolean(pageDetails.u.complex.fTopBottomHeaderFooter) || this.PresenterCache.CurrentPresenter.IsBottomless, ErrorHandler.NotSupportedHeadersFooters);
                    //ErrorHandler.Assert(!PTS.ToBoolean(pageDetails.u.complex.fJustified) || this.PresenterCache.CurrentPresenter.IsBottomless, ErrorHandler.NotSupportedVerticalJustify);
                    ErrorHandler.Assert(pageDetails.u.complex.cFootnoteColumns == 0, ErrorHandler.NotSupportedFootnotes);

                    // Since header/footer and footnotes are not supported yet, use page body rectangle
                    rect = pageDetails.u.complex.fsrcPageBody;
                }
            }
            return rect;
        }
        internal override void UpdateViewport(ref PTS.FSRECT viewport)
        { 
            // Query subpage details 
            PTS.FSSUBPAGEDETAILS subpageDetails;
            PTS.Validate(PTS.FsQuerySubpageDetails(PtsContext.Context, _paraHandle.Value, out subpageDetails)); 

            PTS.FSRECT viewportSubpage = new PTS.FSRECT();

            viewportSubpage.u = viewport.u - ContentRect.u; 
            viewportSubpage.v = viewport.v - ContentRect.v;
            viewportSubpage.du = viewport.du; 
            viewportSubpage.dv = viewport.dv; 

            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the subpage.
            // (1) simple subpage (contains only one track)
            // (2) complex subpage (contains columns)
            if (PTS.ToBoolean(subpageDetails.fSimple)) 
            {
                PtsHelper.UpdateViewportTrack(PtsContext, ref subpageDetails.u.simple.trackdescr, ref viewportSubpage); 
            } 
            else
            { 
                // (2) complex page (contains columns)
                // cBasicColumns == 0, means that subpage content is empty
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage) 
                {
                    // Retrieve description for each column. 
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc);
 
                    emptySubpage = (arrayColumnDesc.Length == 0);
                    if (!emptySubpage)
                    {
                        for (int index = 0; index < arrayColumnDesc.Length; index++) 
                        {
                            PtsHelper.UpdateViewportTrack(PtsContext, ref arrayColumnDesc[index], ref viewportSubpage); 
                        } 
                    }
                } 
            }
        }
        internal override void ValidateVisual(PTS.FSKUPDATE fskupdInherited) 
        { 
            // Floater is always reported as NEW. Override PTS inherited value.
            fskupdInherited = PTS.FSKUPDATE.fskupdNew; 

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

            // Obtain all mbd info 
            MbpInfo mbp = MbpInfo.FromElement(Paragraph.Element); 

            if(ThisFlowDirection != PageFlowDirection) 
            {
                mbp.MirrorBP();
            }
 
            Brush backgroundBrush = (Brush)Paragraph.Element.GetValue(TextElement.BackgroundProperty);
            Visual.DrawBackgroundAndBorder(backgroundBrush, mbp.BorderBrush, mbp.Border, _rect.FromTextDpi(), IsFirstChunk, IsLastChunk); 
 

            ContainerVisual pageContentVisual; 
            ContainerVisual floatingElementsVisual;

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

            // Subpage content may be simple or complex - 
            // depending of set of features used in the content of the subpage.
            // (1) simple subpage (contains only one track) 
            // (2) complex subpage (contains columns) 
            if (PTS.ToBoolean(subpageDetails.fSimple))
            { 
                // (1) simple subpage (contains only one track)
                PTS.FSKUPDATE fskupd = subpageDetails.u.simple.trackdescr.fsupdinf.fskupd;
                if (fskupd == PTS.FSKUPDATE.fskupdInherited)
                { 
                    fskupd = fskupdInherited;
                } 
                VisualCollection visualChildren = pageContentVisual.Children; 
                if (fskupd == PTS.FSKUPDATE.fskupdNew)
                { 
                    visualChildren.Clear();
                    visualChildren.Add(new ContainerVisual());
                }
                // For complex subpage SectionVisual is added. So, when morphing 
                // complex subpage to simple one, remove SectionVisual.
                else if (visualChildren.Count == 1 && !(visualChildren[0] is ContainerVisual)) 
                { 
                    visualChildren.Clear();
                    visualChildren.Add(new ContainerVisual()); 
                }
                Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is ContainerVisual);
                ContainerVisual trackVisual = (ContainerVisual)visualChildren[0];
 
                PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref subpageDetails.u.simple.trackdescr);
            } 
            else 
            {
                // (2) complex page (contains columns) 
                // cBasicColumns == 0, means that subpage content is empty
                bool emptySubpage = (subpageDetails.u.complex.cBasicColumns == 0);
                if (!emptySubpage)
                { 
                    // Retrieve description for each column.
                    PTS.FSTRACKDESCRIPTION[] arrayColumnDesc; 
                    PtsHelper.TrackListFromSubpage(PtsContext, _paraHandle.Value, ref subpageDetails, out arrayColumnDesc); 

                    emptySubpage = (arrayColumnDesc.Length == 0); 
                    if (!emptySubpage)
                    {
                        PTS.FSKUPDATE fskupd = fskupdInherited;
                        ErrorHandler.Assert(fskupd != PTS.FSKUPDATE.fskupdShifted, ErrorHandler.UpdateShiftedNotValid); 
                        Debug.Assert(fskupd != PTS.FSKUPDATE.fskupdNoChange);
 
                        // For complex subpage SectionVisual is added. So, when morphing 
                        // simple subpage to complex one, remove ParagraphVisual.
                        VisualCollection visualChildren = pageContentVisual.Children; 
                        if (visualChildren.Count == 0)
                        {
                            visualChildren.Add(new SectionVisual());
                        } 
                        else if (!(visualChildren[0] is SectionVisual))
                        { 
                            visualChildren.Clear(); 
                            visualChildren.Add(new SectionVisual());
                        } 
                        Debug.Assert(visualChildren.Count == 1 && visualChildren[0] is SectionVisual);
                        SectionVisual sectionVisual = (SectionVisual)visualChildren[0];

                        // Draw column rules. 
                        ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(Paragraph.Element);
                        sectionVisual.DrawColumnRules(ref arrayColumnDesc, TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.v), TextDpi.FromTextDpi(subpageDetails.u.complex.fsrc.dv), columnProperties); 
 
                        visualChildren = sectionVisual.Children;
                        if (fskupd == PTS.FSKUPDATE.fskupdNew) 
                        {
                            visualChildren.Clear();
                            for (int index = 0; index < arrayColumnDesc.Length; index++)
                            { 
                                visualChildren.Add(new ContainerVisual());
                            } 
                        } 
                        ErrorHandler.Assert(visualChildren.Count == arrayColumnDesc.Length, ErrorHandler.ColumnVisualCountMismatch);
 
                        for (int index = 0; index < arrayColumnDesc.Length; index++)
                        {
                            ContainerVisual trackVisual = (ContainerVisual)visualChildren[index];
 
                            PtsHelper.UpdateTrackVisuals(PtsContext, trackVisual.Children, fskupdInherited, ref arrayColumnDesc[index]);
                        } 
                    } 
                }
                if (emptySubpage) 
                {
                    // There is no content, remove all existing visuals.
                    _visual.Children.Clear();
                } 
            }
 
            pageContentVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi(); 
            floatingElementsVisual.Offset = new PTS.FSVECTOR(ContentRect.u, ContentRect.v).FromTextDpi();
 
            PTS.FSRECT clipRect = new PTS.FSRECT(_paddingRect.u - _contentRect.u, _paddingRect.v - _contentRect.v, _paddingRect.du, _paddingRect.dv);
            PtsHelper.ClipChildrenToRect(_visual, clipRect.FromTextDpi());

            PtsHelper.UpdateFloatingElementVisuals(floatingElementsVisual, _pageContextOfThisPage.FloatingElementList); 
        }
        internal void GetFigureProperties(
            FigureParaClient paraClient,        // IN:
            int fInTextLine,                    // IN:  it is attached to text line
            uint fswdir,                        // IN:  current direction
            int fBottomUndefined,               // IN:  bottom of page is not defined
            out int dur,                        // OUT: width of figure
            out int dvr,                        // OUT: height of figure
            out PTS.FSFIGUREPROPS fsfigprops,   // OUT: figure attributes
            out int cPolygons,                  // OUT: number of polygons
            out int cVertices,                  // OUT: total number of vertices in all polygons
            out int durDistTextLeft,            // OUT: distance to text from MinU side
            out int durDistTextRight,           // OUT: distance to text from MaxU side
            out int dvrDistTextTop,             // OUT: distance to text from MinV side
            out int dvrDistTextBottom)          // OUT: distance to text from MaxV side
        {
            Invariant.Assert(StructuralCache.CurrentFormatContext.FinitePage);

            uint fswdirPara = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));

            IntPtr pfsFigureContent;
            PTS.FSBBOX fsbbox;
            int cColumns;
            int dvrTopSpace;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            IntPtr pmcsclientOut;
            MbpInfo mbp;

            Figure element = (Figure)Element;

            // Initialize the subpage size. PTS subpage margin is always set to 0 for Figures.
            // If width on figure is specified, use the specified value.
            // Border and padding of the figure is extracted from available subpage width.
            // We use StructuralCache.CurrentFormatContext's page dimensions as limiting values for figure MBP
            mbp = MbpInfo.FromElement(Element);            
            // We do not mirror margin as it's used to dist text left and right, and is unnecessary.

            durDistTextLeft = durDistTextRight = dvrDistTextTop = dvrDistTextBottom = 0;
            
            // Calculate specified width. IsAuto flag is needed because Auto is formatted the same way as column and will
            // not return Double.NaN.
            bool isWidthAuto;
            double specifiedWidth = FigureHelper.CalculateFigureWidth(StructuralCache, element, 
                                                                      element.Width, 
                                                                      out isWidthAuto);


            double anchorLimitedWidth = LimitTotalWidthFromAnchor(specifiedWidth, TextDpi.FromTextDpi(mbp.MarginLeft + mbp.MarginRight));
            int subpageWidth = Math.Max(1, TextDpi.ToTextDpi(anchorLimitedWidth) - (mbp.BPLeft + mbp.BPRight));

            // Calculate figure height, IsAuto flag is used as specifiedHeight will never be NaN.
            bool isHeightAuto;
            double specifiedHeight = FigureHelper.CalculateFigureHeight(StructuralCache, element, 
                                                                        element.Height,
                                                                        out isHeightAuto);

            double anchorLimitedHeight = LimitTotalHeightFromAnchor(specifiedHeight, TextDpi.FromTextDpi(mbp.MarginTop + mbp.MarginBottom));
            int subpageHeight = Math.Max(1, TextDpi.ToTextDpi(anchorLimitedHeight) - (mbp.BPTop + mbp.BPBottom));

            // Initialize column info. Figure always has just 1 column.
            cColumns = 1;
            columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
            columnInfoCollection[0].durBefore = 0;
            columnInfoCollection[0].durWidth = subpageWidth;

            // Create subpage
            {
                PTS.FSFMTR fsfmtr;
                IntPtr brParaOut;
                PTS.FSRECT marginRect = new PTS.FSRECT(0, 0, subpageWidth, subpageHeight);

                CreateSubpageFiniteHelper(PtsContext, IntPtr.Zero, PTS.False, _mainTextSegment.Handle, IntPtr.Zero, PTS.False, PTS.True, 
                    fswdir, subpageWidth, subpageHeight, ref marginRect,
                    cColumns, columnInfoCollection, PTS.False, 
                    out fsfmtr, out pfsFigureContent, out brParaOut, out dvr, out fsbbox, out pmcsclientOut, 
                    out dvrTopSpace);

                if(brParaOut != IntPtr.Zero)
                {
                    PTS.Validate(PTS.FsDestroySubpageBreakRecord(PtsContext.Context, brParaOut));
                }
            }

            // PTS subpage does not support autosizing, but Figure needs to autosize to its
            // content. To workaround this problem, second format of subpage is performed, if 
            // necessary. It means that if the width of bounding box is smaller than subpage's
            // width, second formatting is performed.

            if(PTS.ToBoolean(fsbbox.fDefined))
            {
                if (fsbbox.fsrc.du < subpageWidth && isWidthAuto)
                {
                    // There is a need to reformat PTS subpage, so destroy any resourcces allocated by PTS
                    // during previous formatting.
                    if (pfsFigureContent != IntPtr.Zero)
                    {
                        PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, pfsFigureContent), PtsContext);
                    }
                    if (pmcsclientOut != IntPtr.Zero)
                    {
                        MarginCollapsingState mcs = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                        PTS.ValidateHandle(mcs);
                        mcs.Dispose();
                        pmcsclientOut = IntPtr.Zero;
                    }
                    // Create subpage with new width.
                    subpageWidth = fsbbox.fsrc.du + 1; // add 1/300px to avoid rounding errors
                    columnInfoCollection[0].durWidth = subpageWidth;

                    // Create subpage
                    PTS.FSFMTR fsfmtr;
                    IntPtr brParaOut;
                    PTS.FSRECT marginRect = new PTS.FSRECT(0, 0, subpageWidth, subpageHeight);

                    CreateSubpageFiniteHelper(PtsContext, IntPtr.Zero, PTS.False, _mainTextSegment.Handle, IntPtr.Zero, PTS.False, PTS.True, 
                        fswdir, subpageWidth, subpageHeight, ref marginRect,
                        cColumns, columnInfoCollection, PTS.False, 
                        out fsfmtr, out pfsFigureContent, out brParaOut, out dvr, out fsbbox, out pmcsclientOut, 
                        out dvrTopSpace);

                    if(brParaOut != IntPtr.Zero)
                    {
                        PTS.Validate(PTS.FsDestroySubpageBreakRecord(PtsContext.Context, brParaOut));
                    }
                }
            }
            else
            {
                subpageWidth = TextDpi.ToTextDpi(TextDpi.MinWidth);
            }


            // Get the size of the figure. For height PTS already reports calculated value.
            // But width is the same as subpage width. Include margins in dur since we are not using
            // distance to text anymore.
            dur = subpageWidth + mbp.MBPLeft + mbp.MBPRight;

            // Destroy objects created by PTS, but not used here.
            if (pmcsclientOut != IntPtr.Zero)
            {
                MarginCollapsingState mcs = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                PTS.ValidateHandle(mcs);
                mcs.Dispose();
                pmcsclientOut = IntPtr.Zero;
            }

            dvr += mbp.MBPTop + mbp.MBPBottom;
            if(!isHeightAuto)
            { 
                // Replace height with explicit height if specified, adding margins in addition to height 
                // Border and padding are included in specified height but margins are external
                dvr = TextDpi.ToTextDpi(anchorLimitedHeight) + mbp.MarginTop + mbp.MarginBottom;
            }

            FigureHorizontalAnchor horzAnchor = element.HorizontalAnchor;
            FigureVerticalAnchor vertAnchor = element.VerticalAnchor;

            fsfigprops.fskrefU = (PTS.FSKREF)(((int)horzAnchor) / 3);
            fsfigprops.fskrefV = (PTS.FSKREF)(((int)vertAnchor) / 3);
            fsfigprops.fskalfU = (PTS.FSKALIGNFIG)(((int)horzAnchor) % 3);
            fsfigprops.fskalfV = (PTS.FSKALIGNFIG)(((int)vertAnchor) % 3);

            // PTS does not allow to anchor delayed figures to 'Character'
            if (!PTS.ToBoolean(fInTextLine))
            {
                if (fsfigprops.fskrefU == PTS.FSKREF.fskrefChar)
                {
                    fsfigprops.fskrefU = PTS.FSKREF.fskrefMargin;
                    fsfigprops.fskalfU = PTS.FSKALIGNFIG.fskalfMin;
                }
                if (fsfigprops.fskrefV == PTS.FSKREF.fskrefChar)
                {
                    fsfigprops.fskrefV = PTS.FSKREF.fskrefMargin;
                    fsfigprops.fskalfV = PTS.FSKALIGNFIG.fskalfMin;
                }
            }

            // Always wrap text on both sides of the floater.
            fsfigprops.fskwrap       = PTS.WrapDirectionToFskwrap(element.WrapDirection);
            fsfigprops.fNonTextPlane = PTS.False;
            fsfigprops.fAllowOverlap = PTS.False;
            fsfigprops.fDelayable = PTS.FromBoolean(element.CanDelayPlacement);

            // Tight wrap is disabled for now.
            cPolygons = cVertices = 0;

            // Update handle to PTS subpage.
            ((FigureParaClient)paraClient).SubpageHandle = pfsFigureContent;
        }
Beispiel #5
0
        internal int CalcFigurePosition(
            IntPtr pfsclient,                   // IN:  client opaque data
            IntPtr pfsparaclientFigure,         // IN:
            IntPtr nmpFigure,                   // IN:  figure's name
            uint fswdir,                        // IN:  current direction
            ref PTS.FSRECT fsrcPage,            // IN:  page rectangle
            ref PTS.FSRECT fsrcMargin,          // IN:  rectangle within page margins
            ref PTS.FSRECT fsrcTrack,           // IN:  track rectangle
            ref PTS.FSRECT fsrcFigurePreliminary,// IN:  prelim figure rect calculated from figure props
            int fMustPosition,                  // IN:  must find position in this track?
            int fInTextLine,                    // IN:  it is attached to text line
            out int fPushToNextTrack,           // OUT: push to next track?
            out PTS.FSRECT fsrcFlow,            // OUT: FlowAround rectangle
            out PTS.FSRECT fsrcOverlap,         // OUT: Overlap rectangle
            out PTS.FSBBOX fsbbox,              // OUT: bbox
            out PTS.FSRECT fsrcSearch)          // OUT: search area for overlap
        {
            int fserr = PTS.fserrNone;
            try
            {
                FigureParagraph para = PtsContext.HandleToObject(nmpFigure) as FigureParagraph;
                PTS.ValidateHandle(para);
                FigureParaClient paraClient = PtsContext.HandleToObject(pfsparaclientFigure) as FigureParaClient;
                PTS.ValidateHandle(paraClient);
                para.CalcFigurePosition(paraClient, fswdir, ref fsrcPage, ref fsrcMargin, ref fsrcTrack, 
                    ref fsrcFigurePreliminary, fMustPosition, fInTextLine, out fPushToNextTrack, out fsrcFlow, 
                    out fsrcOverlap, out fsbbox, out fsrcSearch);
            }
            catch (Exception e)
            {
                fPushToNextTrack = 0; fsrcFlow = fsrcOverlap = fsrcSearch = new PTS.FSRECT(); fsbbox = new PTS.FSBBOX();
                PtsContext.CallbackException = e;
                fserr = PTS.fserrCallbackException;
            }
            catch
            {
                fPushToNextTrack = 0; fsrcFlow = fsrcOverlap = fsrcSearch = new PTS.FSRECT(); fsbbox = new PTS.FSBBOX();
                PtsContext.CallbackException = new System.Exception("Caught a non CLS Exception");
                fserr = PTS.fserrCallbackException;
            }

            return fserr;
        }
Beispiel #6
0
        internal override List<Rect> GetRectangles(ContentElement e, int start, int length) 
        { 
            List<Rect> rectangles = new List<Rect>();
            Debug.Assert(Paragraph.Element as ContentElement != e); 

            PTS.FSTEXTDETAILS textDetails;
            PTS.Validate(PTS.FsQueryTextDetails(PtsContext.Context, _paraHandle.Value, out textDetails));
 
            // There are 3 different types of text paragraphs:
            // (a) full with simple lines 
            // (b) full with composite lines - when figures/floaters are present 
            // (c) cached - when using ParaChache
            if (textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdFull) 
            {
                // Check figures and floaters
                if (textDetails.u.full.cAttachedObjects > 0)
                { 
                    PTS.FSATTACHEDOBJECTDESCRIPTION[] arrayAttachedObjectDesc;
                    PtsHelper.AttachedObjectListFromParagraph(PtsContext, _paraHandle.Value, textDetails.u.full.cAttachedObjects, out arrayAttachedObjectDesc); 
 
                    for (int index = 0; index < arrayAttachedObjectDesc.Length; index++)
                    { 
                        PTS.FSATTACHEDOBJECTDESCRIPTION attachedObjectDesc = arrayAttachedObjectDesc[index];

                        BaseParaClient paraClient = PtsContext.HandleToObject(attachedObjectDesc.pfsparaclient) as BaseParaClient;
                        PTS.ValidateHandle(paraClient); 

                        if (start < paraClient.Paragraph.ParagraphEndCharacterPosition) 
                        { 
                            rectangles = paraClient.GetRectangles(e, start, length);
                            Invariant.Assert(rectangles != null); 
                            if (rectangles.Count != 0)
                            {
                                break;
                            } 
                        }
                    } 
                } 

                // If no success with figures and floaters, check in line 
                if (rectangles.Count == 0 && textDetails.u.full.cLines > 0)
                {
                    if (!PTS.ToBoolean(textDetails.u.full.fLinesComposite))
                    { 
                        // (a) full with simple lines
                        rectangles = GetRectanglesInSimpleLines(e, start, length, ref textDetails.u.full); 
                    } 
                    else
                    { 
                        // (b) full with complex lines
                        rectangles = GetRectanglesInCompositeLines(e, start, length, ref textDetails.u.full);
                    }
 
                    // Ensure these are specified in page coordinates.
                    if(rectangles.Count > 0 && ThisFlowDirection != PageFlowDirection) 
                    { 
                        PTS.FSRECT pageRect = _pageContext.PageRect;
 
                        for(int index = 0; index < rectangles.Count; index++)
                        {
                            PTS.FSRECT rectTransform = new PTS.FSRECT(rectangles[index]);
                            PTS.Validate(PTS.FsTransformRectangle(PTS.FlowDirectionToFswdir(ThisFlowDirection), ref pageRect, ref rectTransform, PTS.FlowDirectionToFswdir(PageFlowDirection), out rectTransform)); 
                            rectangles[index] = rectTransform.FromTextDpi();
                        } 
                    } 
                }
 
            }
            else
            {
                // (c) cached - when using ParaChache 
                Debug.Assert(textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdCached);
                Debug.Assert(false, "Should not get here. ParaCache is not currently used."); 
            } 

            Invariant.Assert(rectangles != null); 
            return rectangles;
        }
Beispiel #7
0
        internal Rect GetRectangleFromTextPosition(ITextPointer position)
        { 
            Rect rect = System.Windows.Rect.Empty;
 
            int cp = Paragraph.StructuralCache.TextContainer.Start.GetOffsetToPosition((TextPointer)position); 
            int dcp = cp - Paragraph.ParagraphStartCharacterPosition;
            int originalDcp = dcp; 
            if (position.LogicalDirection == LogicalDirection.Backward && dcp > 0)
            {
                --dcp;
            } 

            // Query paragraph details 
            PTS.FSTEXTDETAILS textDetails; 
            PTS.Validate(PTS.FsQueryTextDetails(PtsContext.Context, _paraHandle.Value, out textDetails));
 
            // There are 3 different types of text paragraphs:
            // (a) full with simple lines
            // (b) full with composite lines - when figures/floaters are present
            // (c) cached - when using ParaChache 
            if (textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdFull)
            { 
                if (textDetails.u.full.cLines > 0) 
                {
                    int vrBaseline = 0; 

                    if (!PTS.ToBoolean(textDetails.u.full.fLinesComposite))
                    {
                        // (a) full with simple lines 
                        RectFromDcpSimpleLines(dcp, originalDcp, position.LogicalDirection, position.GetPointerContext(position.LogicalDirection), ref textDetails.u.full, ref rect, ref vrBaseline);
                    } 
                    else 
                    {
                        // (b) full with composite lines - when figures/floaters are present 
                        RectFromDcpCompositeLines(dcp, originalDcp, position.LogicalDirection, position.GetPointerContext(position.LogicalDirection), ref textDetails.u.full, ref rect, ref vrBaseline);
                    }
                }
            } 
            else
            { 
                // (c) cached - when using ParaChache 
                Debug.Assert(textDetails.fsktd == PTS.FSKTEXTDETAILS.fsktdCached);
                Debug.Assert(false, "Should not get here. ParaCache is not currently used."); 
            }

            // Mirror back to page flow direction
            if(ThisFlowDirection != PageFlowDirection) 
            {
                PTS.FSRECT pageRect = _pageContext.PageRect; 
                PTS.FSRECT rectTransform = new PTS.FSRECT(rect); 
                PTS.Validate(PTS.FsTransformRectangle(PTS.FlowDirectionToFswdir(ThisFlowDirection), ref pageRect, ref rectTransform, PTS.FlowDirectionToFswdir(PageFlowDirection), out rectTransform));
                rect = rectTransform.FromTextDpi(); 
            }

            return rect;
        } 
Beispiel #8
0
        private ReadOnlyCollection<LineResult> LineResultsFromCompositeLines(ref PTS.FSTEXTDETAILSFULL textDetails) 
        {
            ErrorHandler.Assert(!PTS.ToBoolean(textDetails.fDropCapPresent), ErrorHandler.NotSupportedDropCap);

            // Get list of complex composite lines. 
            PTS.FSLINEDESCRIPTIONCOMPOSITE [] arrayLineDesc;
            PtsHelper.LineListCompositeFromTextPara(PtsContext, _paraHandle.Value, ref textDetails, out arrayLineDesc); 
 
            List<LineResult> lines = new List<LineResult>(arrayLineDesc.Length);
 
            // Get lines information
            for (int index = 0; index < arrayLineDesc.Length; index++)
            {
                PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc = arrayLineDesc[index]; 
                if (lineDesc.cElements == 0) { continue; }
 
                // Get list of line elements. 
                PTS.FSLINEELEMENT [] arrayLineElement;
                PtsHelper.LineElementListFromCompositeLine(PtsContext, ref lineDesc, out arrayLineElement); 

                for (int elIndex = 0; elIndex < arrayLineElement.Length; elIndex++)
                {
                    PTS.FSLINEELEMENT element = arrayLineElement[elIndex]; 

                    // Create line info 
                    Rect lbox = new Rect(TextDpi.FromTextDpi(element.urBBox), TextDpi.FromTextDpi(lineDesc.vrStart), 
                                         TextDpi.FromTextDpi(element.durBBox), TextDpi.FromTextDpi(element.dvrAscent + element.dvrDescent));
 
                    // Mirror layout box to page flow direction
                    if(ThisFlowDirection != PageFlowDirection)
                    {
                        PTS.FSRECT pageRect = _pageContext.PageRect; 
                        PTS.FSRECT rectTransform = new PTS.FSRECT(lbox);
                        PTS.Validate(PTS.FsTransformRectangle(PTS.FlowDirectionToFswdir(ThisFlowDirection), ref pageRect, ref rectTransform, PTS.FlowDirectionToFswdir(PageFlowDirection), out rectTransform)); 
                        lbox = rectTransform.FromTextDpi(); 
                    }
 
                    lines.Add(new TextParaLineResult(this, element.dcpFirst, element.dcpLim - element.dcpFirst,
                        lbox, TextDpi.FromTextDpi(element.dvrAscent)));
                }
            } 

            if (lines.Count != 0) 
            { 
                // Hide EOP character
                TextParaLineResult lastLineResult = (TextParaLineResult)lines[lines.Count - 1]; 
                if (HasEOP && lastLineResult.DcpLast > Paragraph.Cch)
                {
                    ErrorHandler.Assert(lastLineResult.DcpLast - Line.SyntheticCharacterLength == Paragraph.Cch, ErrorHandler.ParagraphCharacterCountMismatch);
                    lastLineResult.DcpLast -= Line.SyntheticCharacterLength; 
                }
            } 
 
            return (lines.Count > 0) ? new ReadOnlyCollection<LineResult>(lines) : null;
        } 
Beispiel #9
0
        // ------------------------------------------------------------------ 
        //  Returns rectangles for a single composite line correcsponding to the
        //  given dcp range. Includes trailing whitespaces.
        //  Params:
        //      dcpRangeStart     - range's cp start position. Adjusted for 
        //                          line's cp range.
        //      cchRange          - nuber of cps in the range. 
        //      lineTopSpace      - the value that line's height should 
        //                          be extended to at the top.
        //      lineRightSpace    - the value that line's width should 
        //                          be extended to at the right.
        //      lineDesc          - line description.
        //      lineIndex         - line index.
        //      elemDesc          - element description. 
        //      visibleRect       - visibility rectangle. It is Ok to return
        //                          null if the line is not visible. 
        //      hasAttachedObjects- Attached objects are present 
        //  Returns:
        //      null              - if line is not visible 
        //      rectangles        - otherwise.
        // -----------------------------------------------------------------
        private List<Rect> RectanglesFromDcpRangeOfCompositeLineElement(
            int dcpRangeStart, 
            int cchRange,
            double lineTopSpace, 
            double lineRightSpace, 
            ref PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc,
            int lineIndex, 
            ref PTS.FSLINEELEMENT elemDesc,
            int elemIndex,
            Rect visibleRect)
        { 
            List<Rect> rectangles = null;
 
            Rect elementRect = new PTS.FSRECT(elemDesc.urBBox, lineDesc.vrStart, elemDesc.durBBox, lineDesc.dvrAscent + lineDesc.dvrDescent).FromTextDpi(); 

            //  width has to be adjusted to include trailing whitespaces... 
            LineVisual lineVisual = FetchLineVisualComposite(lineIndex, elemIndex);
            if (lineVisual != null)
            {
                elementRect.Width = Math.Max(lineVisual.WidthIncludingTrailingWhitespace, 0); 
            }
 
            elementRect.Y = elementRect.Y - lineTopSpace; 
            elementRect.Height = elementRect.Height + lineTopSpace;
            elementRect.Width = elementRect.Width + lineRightSpace; 

            // Ignore horizontal offset because TextBox page width != extent width.
            // It's ok to include content that doesn't strictly intersect -- this
            // is a perf optimization and the edge cases won't significantly hurt us. 
            Rect testRect = elementRect;
            testRect.X = visibleRect.X; 
 
            if (testRect.IntersectsWith(visibleRect))
            { 
                // Check whether the line is fully selected - we don't need to reformat it in this case
                if (dcpRangeStart == elemDesc.dcpFirst && elemDesc.dcpLim <= (dcpRangeStart + cchRange))
                {
                    rectangles = new List<Rect>(1); 
                    rectangles.Add(elementRect);
                } 
                else 
                {
                    // Create and format line 
                    Line line = new Line(Paragraph.StructuralCache.TextFormatterHost, this, Paragraph.ParagraphStartCharacterPosition);
                    Line.FormattingContext ctx = new Line.FormattingContext(false, PTS.ToBoolean(elemDesc.fClearOnLeft), PTS.ToBoolean(elemDesc.fClearOnRight), TextParagraph.TextRunCache);
                    if (IsOptimalParagraph)
                    { 
                        ctx.LineFormatLengthTarget = elemDesc.dcpLim - elemDesc.dcpFirst;
                    } 
                    TextParagraph.FormatLineCore(line, elemDesc.pfsbreakreclineclient, ctx, elemDesc.dcpFirst, elemDesc.dur, PTS.ToBoolean(lineDesc.fTreatedAsFirst), elemDesc.dcpFirst); 
                    Invariant.Assert(line.SafeLength == elemDesc.dcpLim - elemDesc.dcpFirst, "Line length is out of [....]");
 
                    double duOffset = TextDpi.FromTextDpi(elemDesc.urStart);
                    double dvOffset = TextDpi.FromTextDpi(lineDesc.vrStart);

                    rectangles = line.GetRangeBounds(dcpRangeStart, cchRange, duOffset, dvOffset); 

                    if (!DoubleUtil.IsZero(lineTopSpace)) 
                    { 
                        for (int i = 0, count = rectangles.Count; i < count; ++i)
                        { 
                            Rect r = rectangles[i];
                            r.Y = r.Y - lineTopSpace;
                            r.Height = r.Height + lineTopSpace;
                            rectangles[i] = r; 
                        }
                    } 
 
                    if (!DoubleUtil.IsZero(lineRightSpace))
                    { 
                        // add the rect representing end-of-line / end-of-para
                        rectangles.Add(
                            new Rect(
                                duOffset + TextDpi.FromTextDpi(line.Start + line.Width), 
                                dvOffset - lineTopSpace,
                                lineRightSpace, 
                                TextDpi.FromTextDpi(line.Height) + lineTopSpace 
                                )
                            ); 
                    }

                    //  dispose of the line
                    line.Dispose(); 
                }
            } 
 
            return (rectangles);
        } 
        /// <summary> 
        /// Arranges content.
        /// </summary>
        /// <param name="arrangeSize">Size that element should use to arrange itself and its children.</param>
        /// <param name="viewport">Viewport for visible content.</param> 
        internal void Arrange(Size arrangeSize, Rect viewport)
        { 
            Invariant.Assert(_document.StructuralCache.DtrList == null || _document.StructuralCache.DtrList.Length == 0 || 
                             (_document.StructuralCache.DtrList.Length == 1 && _document.StructuralCache.BackgroundFormatInfo.DoesFinalDTRCoverRestOfText));
 
            // Arrange the content and create visual tree.
            _documentPage.Arrange(arrangeSize);
            _documentPage.EnsureValidVisuals();
            _arrangedAfterFormat = true; 

            // Render content only for the current viewport. 
            if (viewport.IsEmpty) 
            {
                viewport = new Rect(0, 0, arrangeSize.Width, _document.StructuralCache.BackgroundFormatInfo.ViewportHeight); 
            }
            PTS.FSRECT fsrectViewport = new PTS.FSRECT(viewport);
            _documentPage.UpdateViewport(ref fsrectViewport, true);
 
            _isContentFormatValid = true;
        } 
        internal void FormatCellFinite(Size subpageSize, IntPtr breakRecordIn, bool isEmptyOk, uint fswdir, 
                                       PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn,
                                       out PTS.FSFMTR fsfmtr, out int dvrUsed, out IntPtr breakRecordOut)
        {
            IntPtr pfspara;
            PTS.FSBBOX fsbbox;
            IntPtr pmcsclientOut;
            PTS.FSKCLEAR fskclearOut;
            int dvrTopSpace;
            PTS.FSPAP fspap;

            if(CellParagraph.StructuralCache.DtrList != null && breakRecordIn != null)
            {
                CellParagraph.InvalidateStructure(TextContainerHelper.GetCPFromElement(CellParagraph.StructuralCache.TextContainer, CellParagraph.Element, ElementEdge.BeforeStart));
            }

            // Ensures segment is created for paragraph
            fspap = new PTS.FSPAP();
            CellParagraph.GetParaProperties(ref fspap);

            PTS.FSRECT rectCell;

            rectCell = new PTS.FSRECT();

            rectCell.u = rectCell.v = 0;

            rectCell.du = TextDpi.ToTextDpi(subpageSize.Width);
            rectCell.dv = TextDpi.ToTextDpi(subpageSize.Height);

            // Suppress top space if cell is broken, but not otherwise
            bool suppressTopSpace = (breakRecordIn != IntPtr.Zero) ? true : false;

            CellParagraph.FormatParaFinite(this, breakRecordIn,
                                           PTS.FromBoolean(true),
                                           IntPtr.Zero,
                                           PTS.FromBoolean(isEmptyOk),
                                           PTS.FromBoolean(suppressTopSpace),
                                           fswdir,
                                           ref rectCell,
                                           null,
                                           PTS.FSKCLEAR.fskclearNone,
                                           fsksuppresshardbreakbeforefirstparaIn,
                                           out fsfmtr,
                                           out pfspara,
                                           out breakRecordOut,
                                           out dvrUsed,
                                           out fsbbox,
                                           out pmcsclientOut,
                                           out fskclearOut,
                                           out dvrTopSpace);

            if (pmcsclientOut != IntPtr.Zero)
            {
                MarginCollapsingState mcs = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                PTS.ValidateHandle(mcs);
                dvrUsed += mcs.Margin;
                mcs.Dispose();
                pmcsclientOut = IntPtr.Zero;
            }
            _paraHandle.Value = pfspara;
        }
        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);
        }
        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);
        }
Beispiel #14
0
        //-------------------------------------------------------------------
        // Update the viewport
        //-------------------------------------------------------------------
        internal void UpdateViewport(ref PTS.FSRECT viewport, bool drawBackground)
        {
            Rect contentViewport;

            // Transform point to PtsPage coordinate system.
            // NOTE: TransformToAncestor is safe (will never throw an exception).
            GeneralTransform transform = this.PageVisual.Child.TransformToAncestor(this.PageVisual);
            transform = transform.Inverse;

            contentViewport = viewport.FromTextDpi();
            if (transform != null)
            {
                contentViewport = transform.TransformBounds(contentViewport);
            }

            if(!IsDisposed)
            {
                // Draw background
                if (drawBackground)
                {
                    this.PageVisual.DrawBackground((Brush)_structuralCache.PropertyOwner.GetValue(FlowDocument.BackgroundProperty), contentViewport);
                }

                using (_structuralCache.SetDocumentVisualValidationContext(this))
                {
                    PTS.FSRECT contentViewportTextDpi = new PTS.FSRECT(contentViewport);
                    _ptsPage.UpdateViewport(ref contentViewportTextDpi);

                    _structuralCache.DetectInvalidOperation();
                }

                ValidateTextView();
            }
        }
        internal override void FormatFloaterContentFinite(
            FloaterBaseParaClient paraClient,       // IN:
            IntPtr pbrkrecIn,                   // IN:  break record---use if !IntPtr.Zero
            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:  direction of Track
            int fAtMaxWidth,                    // IN:  formating is at full width of column
            int durAvailable,                   // IN:  width of available space
            int dvrAvailable,                   // IN:  height of available space
            PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn,
                                                // IN: suppress breaks at track start?
            out PTS.FSFMTR fsfmtr,              // OUT: result of formatting
            out IntPtr pfsFloatContent,         // OUT: opaque for PTS pointer pointer to formatted content
            out IntPtr pbrkrecOut,              // OUT: pointer to the floater content break record
            out int durFloaterWidth,            // OUT: floater width
            out int dvrFloaterHeight,           // OUT: floater height
            out PTS.FSBBOX fsbbox,              // OUT: floater bbox
            out int cPolygons,                  // OUT: number of polygons
            out int cVertices)                  // OUT: total number of vertices in all polygons
        {
            uint fswdirPara = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));

            int subpageWidth, subpageHeight;
            int dvrTopSpace;
            int cColumns;
            PTS.FSRECT fsrcSubpageMargin;
            PTS.FSCOLUMNINFO[] columnInfoCollection;
            IntPtr pmcsclientOut;
            double specifiedWidth;
            MbpInfo mbp;

            Invariant.Assert(paraClient is FloaterParaClient);

            // If horizontal alignment is Stretch and we are not formatting at max width,
            // we cannot proceed.
            if (IsFloaterRejected(PTS.ToBoolean(fAtMaxWidth), TextDpi.FromTextDpi(durAvailable)))
            {
                durFloaterWidth = dvrFloaterHeight = 0;
                cPolygons = cVertices = 0;
                fsfmtr = new PTS.FSFMTR();
                fsfmtr.kstop = PTS.FSFMTRKSTOP.fmtrNoProgressOutOfSpace;
                fsfmtr.fContainsItemThatStoppedBeforeFootnote = PTS.False;
                fsfmtr.fForcedProgress = PTS.False;
                fsbbox = new PTS.FSBBOX();
                fsbbox.fDefined = PTS.False;
                pbrkrecOut = IntPtr.Zero;
                pfsFloatContent = IntPtr.Zero;
            }
            else
            {
                // When formatting bottomless page, PTS may format paragraphs as finite. This happens
                // in case of multiple columns. In this case make sure that height is not too big.
                if (!StructuralCache.CurrentFormatContext.FinitePage)
                {
                    if (Double.IsInfinity(StructuralCache.CurrentFormatContext.PageHeight))
                    {
                        if (dvrAvailable > PTS.dvBottomUndefined / 2)
                        {
                            dvrAvailable = Math.Min(dvrAvailable, PTS.dvBottomUndefined / 2);
                            fEmptyOk = PTS.False;
                        }
                    }
                    else
                    {
                        dvrAvailable = Math.Min(dvrAvailable, TextDpi.ToTextDpi(StructuralCache.CurrentFormatContext.PageHeight));
                    }
                }

                // Initialize the subpage size. PTS subpage margin is always set to 0 for Floaters.
                // If width on floater is specified, use the specified value.
                // Margin, border and padding of the floater is extracted from available subpage height
                mbp = MbpInfo.FromElement(Element);
                
                // We do not mirror margin as it's used to dist text left and right, and is unnecessary.
                // Clip Floater.Width to available width
                specifiedWidth = CalculateWidth(TextDpi.FromTextDpi(durAvailable));
                AdjustDurAvailable(specifiedWidth, ref durAvailable, out subpageWidth);
                subpageHeight = Math.Max(1, dvrAvailable - (mbp.MBPTop + mbp.MBPBottom));
                fsrcSubpageMargin = new PTS.FSRECT();
                fsrcSubpageMargin.du = subpageWidth;
                fsrcSubpageMargin.dv = subpageHeight;

                // Initialize column info. Floater always has just 1 column.
                cColumns = 1;
                columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns];
                columnInfoCollection[0].durBefore = 0;
                columnInfoCollection[0].durWidth = subpageWidth;

                // Format subpage
                CreateSubpageFiniteHelper(PtsContext, pbrkrecIn, fBRFromPreviousPage, _mainTextSegment.Handle,
                    footnoteRejector, fEmptyOk, PTS.True, fswdir, subpageWidth, subpageHeight,
                    ref fsrcSubpageMargin, cColumns, columnInfoCollection, PTS.False, fsksuppresshardbreakbeforefirstparaIn,
                    out fsfmtr, out pfsFloatContent, 
                    out pbrkrecOut, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace);

                // Initialize subpage metrics
                if (fsfmtr.kstop >= PTS.FSFMTRKSTOP.fmtrNoProgressOutOfSpace)   // No progress or collision
                {
                    Debug.Assert(pmcsclientOut == IntPtr.Zero);
                    durFloaterWidth = dvrFloaterHeight = 0;
                    cPolygons = cVertices = 0;
                    //pbrkrecpara = IntPtr.Zero;
                }
                else
                {
                    // PTS subpage does not support autosizing, but Floater needs to autosize to its
                    // content. To workaround this problem, second format of subpage is performed, if 
                    // necessary. It means that if the width of bounding box is smaller than subpage's
                    // width, second formatting is performed.
                    // However, if HorizontalAlignment is set to Stretch we should not reformat because floater
                    // should be at max width
                    if (PTS.ToBoolean(fsbbox.fDefined))
                    {
                        if(fsbbox.fsrc.du < subpageWidth && Double.IsNaN(specifiedWidth) && HorizontalAlignment != HorizontalAlignment.Stretch)
                        {
                            // There is a need to reformat PTS subpage, so destroy any resourcces allocated by PTS
                            // during previous formatting.
                            if (pfsFloatContent != IntPtr.Zero)
                            {
                                PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, pfsFloatContent), PtsContext);
                                pfsFloatContent = IntPtr.Zero;
                            }
                            if (pbrkrecOut != IntPtr.Zero)
                            {
                                PTS.Validate(PTS.FsDestroySubpageBreakRecord(PtsContext.Context, pbrkrecOut), PtsContext);
                                pbrkrecOut = IntPtr.Zero;
                            }
                            if (pmcsclientOut != IntPtr.Zero)
                            {
                                MarginCollapsingState mcs = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                                PTS.ValidateHandle(mcs);
                                mcs.Dispose();
                                pmcsclientOut = IntPtr.Zero;
                            }
                            // Create subpage with new width.
                            subpageWidth = fsbbox.fsrc.du + 1; // add 1/300px to avoid rounding errors 
                            fsrcSubpageMargin.du = subpageWidth;
                            fsrcSubpageMargin.dv = subpageHeight;
                            columnInfoCollection[0].durWidth = subpageWidth;
                            CreateSubpageFiniteHelper(PtsContext, pbrkrecIn, fBRFromPreviousPage, _mainTextSegment.Handle,
                                 footnoteRejector, fEmptyOk, PTS.True, fswdir, subpageWidth, subpageHeight,
                                ref fsrcSubpageMargin, cColumns, columnInfoCollection, PTS.False, fsksuppresshardbreakbeforefirstparaIn,
                                out fsfmtr, out pfsFloatContent,
                                out pbrkrecOut, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace);
                        }
                    }
                    else
                    {
                        subpageWidth = TextDpi.ToTextDpi(TextDpi.MinWidth);
                    }

                    // Destroy objects created by PTS, but not used here.
                    if (pmcsclientOut != IntPtr.Zero)
                    {
                        MarginCollapsingState mcs = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                        PTS.ValidateHandle(mcs);
                        mcs.Dispose();
                        pmcsclientOut = IntPtr.Zero;
                    }

                    // Get the size of the floater. For height PTS already reports calculated value.
                    // But width is the same as subpage width. Add margin values here since we do not use 
                    // distance to text anymore
                    durFloaterWidth = subpageWidth + mbp.MBPLeft + mbp.MBPRight;

                    // Add back all MBP values since we do not use dist to text
                    dvrFloaterHeight += mbp.MBPTop + mbp.MBPBottom;
                    // Check if floater width fits in available width. It may exceed available width because borders and
                    // padding are added.


                    fsbbox.fsrc.u = 0;
                    fsbbox.fsrc.v = 0;
                    fsbbox.fsrc.du = durFloaterWidth;
                    fsbbox.fsrc.dv = dvrFloaterHeight;
                    fsbbox.fDefined = PTS.True;

                    // Tight wrap is disabled for now.
                    cPolygons = cVertices = 0;

                    if(durFloaterWidth > durAvailable || dvrFloaterHeight > dvrAvailable)
                    {
                        if(PTS.ToBoolean(fEmptyOk))
                        {
                            // Get rid of any previous formatting 
                            if (pfsFloatContent != IntPtr.Zero)
                            {
                                PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, pfsFloatContent), PtsContext);
                                pfsFloatContent = IntPtr.Zero;
                            }
                            if (pbrkrecOut != IntPtr.Zero)
                            {
                                PTS.Validate(PTS.FsDestroySubpageBreakRecord(PtsContext.Context, pbrkrecOut), PtsContext);
                                pbrkrecOut = IntPtr.Zero;
                            }
                            cPolygons = cVertices = 0;
                            fsfmtr.kstop = PTS.FSFMTRKSTOP.fmtrNoProgressOutOfSpace;
                        }
                        else
                        {
                            fsfmtr.fForcedProgress = PTS.True;
                        }
                    }
                }
            }

            // Update handle to PTS subpage.
            ((FloaterParaClient)paraClient).SubpageHandle = pfsFloatContent;
        }
        internal void UpdateBottomlessPara(
            IntPtr pfspara,                     // IN:  pointer to the para data
            ContainerParaClient paraClient,     // IN:
            int iArea,                          // IN:  column-span area index
            IntPtr pfsgeom,                     // IN:  pointer to geometry
            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
        {
            uint fswdirSubtrack = PTS.FlowDirectionToFswdir(((FlowDirection)Element.GetValue(FrameworkElement.FlowDirectionProperty)));

            Debug.Assert(iArea == 0);

            // Top margin collapsing.
            int marginTop;
            MarginCollapsingState mcsContainer;

            MbpInfo mbp = MbpInfo.FromElement(Element);
            MarginCollapsingState.CollapseTopMargin(PtsContext, mbp, mcs, out mcsContainer, out marginTop);
            if (PTS.ToBoolean(fSuppressTopSpace))
            {
                marginTop = 0;
            }

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

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

                urTrack = fsrcToFillSubtrack.u;
                durTrack = fsrcToFillSubtrack.du;
                mbp.MirrorMargin();
            }

            // Take into accound MBPs and modify subtrack metrics,
            // and make sure that subtrack is at least 1 unit wide (cannot measure at width <= 0)
            int urSubtrack, durSubtrack, vrSubtrack;
            int dvrSubTrackTopSpace = 0;
            urSubtrack  = Math.Max(Math.Min(urTrack + mbp.MBPLeft, urTrack + durTrack - 1), urTrack);
            durSubtrack = Math.Max(durTrack - (mbp.MBPLeft + mbp.MBPRight), 0);
            vrSubtrack  = vrTrack + (marginTop + mbp.BPTop);

            // Format subtrack
            try
            {
                PTS.Validate(PTS.FsUpdateBottomlessSubtrack(PtsContext.Context, pfspara, this.Handle, iArea,
                    pfsgeom, fSuppressTopSpace, fswdirSubtrack, urSubtrack, durSubtrack, vrSubtrack, 
                    (mcsContainer != null) ? mcsContainer.Handle : IntPtr.Zero, fskclearIn, fInterruptable, 
                    out fsfmtrbl, out dvrUsed, out fsbbox, out pmcsclientOut, 
                    out fskclearOut, out dvrSubTrackTopSpace, out fPageBecomesUninterruptable), PtsContext);
            }
            finally
            {
                // Destroy top margin collapsing state (not needed anymore).
                if (mcsContainer != null)
                {
                    mcsContainer.Dispose();
                    mcsContainer = null;
                }
            }

            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)
                {
                    mcsContainer = PtsContext.HandleToObject(pmcsclientOut) as MarginCollapsingState;
                    PTS.ValidateHandle(mcsContainer);
                    pmcsclientOut = IntPtr.Zero;
                }
                int marginBottom;
                MarginCollapsingState mcsNew;
                MarginCollapsingState.CollapseBottomMargin(PtsContext, mbp, mcsContainer, out mcsNew, out marginBottom);
                pmcsclientOut = (mcsNew != null) ? mcsNew.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 (mcsContainer != null)
                {
                    mcsContainer.Dispose();
                    mcsContainer = null;
                }

                // Take into accound MBPs and modify subtrack metrics
                dvrTopSpace = (mbp.BPTop != 0) ? marginTop : dvrSubTrackTopSpace;
                dvrUsed += (vrSubtrack - vrTrack) + marginBottom + mbp.BPBottom;
            }
            else
            {
                Debug.Assert(pmcsclientOut == IntPtr.Zero);
                pfspara = IntPtr.Zero;
                dvrTopSpace = 0;
            }

            // Adjust fsbbox to account for margins
            fsbbox.fsrc.u -= mbp.MBPLeft;
            fsbbox.fsrc.du += mbp.MBPLeft + mbp.MBPRight;
            if(fswdirSubtrack != fswdir)
            {
                PTS.FSRECT pageRect = StructuralCache.CurrentFormatContext.PageRect;
                PTS.Validate(PTS.FsTransformBbox(fswdirSubtrack, 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);
        }