Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / MS / Internal / PtsHost / FloaterParagraph.cs / 1 / FloaterParagraph.cs
//---------------------------------------------------------------------------- // // Copyright (C) Microsoft Corporation. All rights reserved. // // Description: FloaterParagraph class provides a wrapper floater objects. // // History: // 11/04/2004 : grzegorz - created. // //--------------------------------------------------------------------------- #pragma warning disable 1634, 1691 // avoid generating warnings about unknown // message numbers and unknown pragmas for PRESharp contol using System; using System.Diagnostics; using System.Security; // SecurityCritical using System.Windows; using System.Windows.Documents; using MS.Internal.Documents; using MS.Internal.Text; using MS.Internal.PtsHost.UnsafeNativeMethods; namespace MS.Internal.PtsHost { // --------------------------------------------------------------------- // FloaterParagraph class provides a wrapper floater objects. // --------------------------------------------------------------------- internal sealed class FloaterParagraph : FloaterBaseParagraph { //-------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors // ------------------------------------------------------------------ // Constructor. // // element - Element associated with paragraph. // structuralCache - Content's structural cache // ------------------------------------------------------------------ internal FloaterParagraph(TextElement element, StructuralCache structuralCache) : base(element, structuralCache) { } // ----------------------------------------------------------------- // UpdGetParaChange - Floater paragraph is always new // ------------------------------------------------------------------ internal override void UpdGetParaChange( out PTS.FSKCHANGE fskch, // OUT: kind of change out int fNoFurtherChanges) // OUT: no changes after? { base.UpdGetParaChange(out fskch, out fNoFurtherChanges); fskch = PTS.FSKCHANGE.fskchNew; } // ----------------------------------------------------------------- // IDisposable.Dispose // ----------------------------------------------------------------- public override void Dispose() { base.Dispose(); if (_mainTextSegment != null) { _mainTextSegment.Dispose(); _mainTextSegment = null; } } #endregion Constructors //------------------------------------------------------------------- // // PTS callbacks // //-------------------------------------------------------------------- #region PTS callbacks //------------------------------------------------------------------- // CreateParaclient //-------------------------------------------------------------------- internal override void CreateParaclient( out IntPtr paraClientHandle) // OUT: opaque to PTS paragraph client { #pragma warning disable 6518 // Disable PRESharp warning 6518. FloaterParaClient 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. FloaterParaClient paraClient = new FloaterParaClient(this); paraClientHandle = paraClient.Handle; #pragma warning restore 6518 // Create the main text segment if (_mainTextSegment == null) { _mainTextSegment = new ContainerParagraph(Element, StructuralCache); } } internal override void CollapseMargin( BaseParaClient paraClient, // IN: MarginCollapsingState mcs, // IN: input margin collapsing state uint fswdir, // IN: current direction (of the track, in which margin collapsing is happening) bool suppressTopSpace, // IN: suppress empty space at the top of page out int dvr) // OUT: dvr, calculated based on margin collapsing state { // Floaters are not participating in margin collapsing. // Top space is always suppressed dvr = 0; } //-------------------------------------------------------------------- // GetFloaterProperties //------------------------------------------------------------------- internal override void GetFloaterProperties( uint fswdirTrack, // IN: direction of track out PTS.FSFLOATERPROPS fsfloaterprops) // OUT: properties of the floater { fsfloaterprops = new PTS.FSFLOATERPROPS(); fsfloaterprops.fFloat = PTS.True; // Floater fsfloaterprops.fskclear = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty)); // Get floater alignment from HorizontalAlignment of the floater element. switch (HorizontalAlignment) { case HorizontalAlignment.Right: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignMax; break; case HorizontalAlignment.Center: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignCenter; break; case HorizontalAlignment.Left: default: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignMin; break; } fsfloaterprops.fskwr = PTS.WrapDirectionToFskwrap(WrapDirection); // Always delay floaters if there is no progress. fsfloaterprops.fDelayNoProgress = PTS.True; } //-------------------------------------------------------------------- // FormatFloaterContentFinite //------------------------------------------------------------------- ////// Critical - as this calls Critical functions PTS.FsDestroySubpage, /// CreateSubpageFiniteHelper and Critical setter for paraClient.SubpageHandle. /// This takes the unvalidated parameter footnoteRejector. /// [SecurityCritical] 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; } //------------------------------------------------------------------- // FormatFloaterContentBottomless //------------------------------------------------------------------- ////// Critical - as this calls Critical functions PTS.FsDestroySubpage, /// CreateSubpageBottomlessHelper and setter for SubpageHandle. /// Safe - as the parameters passed in are either generated in this function /// or they are Critical for set. /// [SecurityCritical, SecurityTreatAsSafe] internal override void FormatFloaterContentBottomless( FloaterBaseParaClient paraClient, // IN: 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 out PTS.FSFMTRBL fsfmtrbl, // OUT: result of formatting out IntPtr pfsFloatContent, // OUT: opaque for PTS pointer pointer to formatted content 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))); Invariant.Assert(paraClient is FloaterParaClient); int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; int dvrTopSpace, fPageBecomesUninterruptable; int cColumns; PTS.FSCOLUMNINFO[] columnInfoCollection; IntPtr pmcsclientOut; MbpInfo mbp; double specifiedWidth; // If horizontal alignment is Stretch and we are not formatting at max width, // we cannot proceed. if (IsFloaterRejected(PTS.ToBoolean(fAtMaxWidth), TextDpi.FromTextDpi(durAvailable))) { // Set foater width, height to be greater than available values to signal to PTS that floater does not fit in the space durFloaterWidth = durAvailable + 1; dvrFloaterHeight = dvrAvailable + 1; cPolygons = cVertices = 0; fsfmtrbl = PTS.FSFMTRBL.fmtrblInterrupted; fsbbox = new PTS.FSBBOX(); fsbbox.fDefined = PTS.False; pfsFloatContent = IntPtr.Zero; } else { // 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 width. mbp = MbpInfo.FromElement(Element); specifiedWidth = CalculateWidth(TextDpi.FromTextDpi(durAvailable)); AdjustDurAvailable(specifiedWidth, ref durAvailable, out subpageWidth); durSubpageMargin = subpageWidth; urSubpageMargin = vrSubpageMargin = 0; // Initialize column info. Floater always has just 1 column. cColumns = 1; columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns]; columnInfoCollection[0].durBefore = 0; columnInfoCollection[0].durWidth = subpageWidth; // Create subpage InvalidateMainTextSegment(); CreateSubpageBottomlessHelper(PtsContext, _mainTextSegment.Handle, PTS.True, fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin, cColumns, columnInfoCollection, out fsfmtrbl, out pfsFloatContent, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace, out fPageBecomesUninterruptable); if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision) { // 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 full column 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); } 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 = durSubpageMargin = fsbbox.fsrc.du + 1; // add 1/300px to avoid rounding errors columnInfoCollection[0].durWidth = subpageWidth; CreateSubpageBottomlessHelper(PtsContext, _mainTextSegment.Handle, PTS.True, fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin, cColumns, columnInfoCollection, out fsfmtrbl, out pfsFloatContent, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace, out fPageBecomesUninterruptable); } } 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. durFloaterWidth = subpageWidth + mbp.MBPLeft + mbp.MBPRight; dvrFloaterHeight += mbp.MBPTop + mbp.MBPBottom; // Check if floater width fits in available width. It may exceed available width because borders // and padding are added. if ( dvrFloaterHeight > dvrAvailable || (durFloaterWidth > durAvailable && !PTS.ToBoolean(fAtMaxWidth)) ) { // Get rid of any previous formatting if (pfsFloatContent != IntPtr.Zero) { PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, pfsFloatContent), PtsContext); } Debug.Assert(pmcsclientOut == IntPtr.Zero); cPolygons = cVertices = 0; pfsFloatContent = IntPtr.Zero; } else { // Width and height are OK, format floater // Adjust bounding box to cover entire floater. fsbbox.fsrc.u = 0; fsbbox.fsrc.v = 0; fsbbox.fsrc.du = durFloaterWidth; fsbbox.fsrc.dv = dvrFloaterHeight; // Tight wrap is disabled for now. cPolygons = cVertices = 0; } } else { Debug.Assert(pmcsclientOut == IntPtr.Zero); durFloaterWidth = dvrFloaterHeight = 0; cPolygons = cVertices = 0; pfsFloatContent = IntPtr.Zero; } } // Update handle to PTS subpage. ((FloaterParaClient)paraClient).SubpageHandle = pfsFloatContent; } //-------------------------------------------------------------------- // UpdateBottomlessFloaterContent //------------------------------------------------------------------- internal override void UpdateBottomlessFloaterContent( FloaterBaseParaClient paraClient, // IN: 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 IntPtr pfsFloatContent, // IN: floater content (in UIElementParagraph, this is an alias to the paraClient) out PTS.FSFMTRBL fsfmtrbl, // OUT: result of formatting 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 { fsfmtrbl = default(PTS.FSFMTRBL); durFloaterWidth = dvrFloaterHeight = cPolygons = cVertices = 0; fsbbox = new PTS.FSBBOX(); Invariant.Assert(false, "No appropriate handling for update in attached object floater."); } //-------------------------------------------------------------------- // GetMCSClientAfterFloater //-------------------------------------------------------------------- internal override void GetMCSClientAfterFloater( uint fswdirTrack, // IN: direction of Track MarginCollapsingState mcs, // IN: input margin collapsing state out IntPtr pmcsclientOut) // OUT: MCSCLIENT that floater will return to track { // Floaters margins are added during formatting. if (mcs != null) { pmcsclientOut = mcs.Handle; } else { pmcsclientOut = IntPtr.Zero; } } #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 Methods // //------------------------------------------------------------------- #region Private Methods ////// Adjust the width available for the Floater. /// private void AdjustDurAvailable(double specifiedWidth, ref int durAvailable, out int subpageWidth) { // If width on floater is specified, use the specified value. // Use page size from current format context to limit MBP MbpInfo mbp = MbpInfo.FromElement(Element); if (!Double.IsNaN(specifiedWidth)) { TextDpi.EnsureValidPageWidth(ref specifiedWidth); // If specified width is greater than available width, do not exceed available width int durSpecified = TextDpi.ToTextDpi(specifiedWidth); if ((durSpecified + mbp.MarginRight + mbp.MarginLeft) <= durAvailable) { // Set durAvailable to durSpecified plus margins, which will be added later. // Set subpage width to specified width less border and padding durAvailable = durSpecified + mbp.MarginLeft + mbp.MarginRight; subpageWidth = Math.Max(1, durSpecified - (mbp.BPLeft + mbp.BPRight)); } else { // Use durAvailable, less MBP to set subpage width. We cannot set figure to specified width subpageWidth = Math.Max(1, durAvailable - (mbp.MBPLeft + mbp.MBPRight)); } } else { // No width specified. Use durAvailable, less MBP to set subpage width. subpageWidth = Math.Max(1, durAvailable - (mbp.MBPLeft + mbp.MBPRight)); } } //-------------------------------------------------------------------- // CreateSubpageFiniteHelper // NOTE: This helper is useful for debugging the caller of this function // because the debugger cannot show local variables in unsafe methods. //------------------------------------------------------------------- ////// Critical, because: /// a) calls Critical function PTS.FsCreateSubpageFinite and passes /// pointer parameters directly that'll be written to, /// b) calls the Critical constructor of SubpageBreakRecord, /// c) it is unsafe method. /// [SecurityCritical] private unsafe void CreateSubpageFiniteHelper( PtsContext ptsContext, // IN: ptr to FS context IntPtr brParaIn, // IN: break record---use if !NULL int fFromPreviousPage, // IN: break record was created on previous page IntPtr nSeg, // IN: name of the segment to start from-if pointer to break rec is NULL IntPtr pFtnRej, // IN: pftnrej int fEmptyOk, // IN: fEmptyOK int fSuppressTopSpace, // IN: fSuppressTopSpace uint fswdir, // IN: fswdir int lWidth, // IN: width of subpage int lHeight, // IN: height of subpage ref PTS.FSRECT rcMargin, // IN: rectangle within subpage margins int cColumns, // IN: number of columns PTS.FSCOLUMNINFO[] columnInfoCollection, // IN: array of column info int fApplyColumnBalancing, // IN: apply column balancing? PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn, // IN: suppress breaks at track start? out PTS.FSFMTR fsfmtr, // OUT: why formatting was stopped out IntPtr pSubPage, // OUT: ptr to the subpage out IntPtr brParaOut, // OUT: break record of the subpage out int dvrUsed, // OUT: dvrUsed out PTS.FSBBOX fsBBox, // OUT: subpage bbox out IntPtr pfsMcsClient, // OUT: margin collapsing state at the bottom out int topSpace) // OUT: top space due to collapsed margins { // Exceptions don't need to pop, as the top level measure context will be nulled out if thrown. StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(lWidth), TextDpi.FromTextDpi(lHeight)), new Thickness(), false, true); fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) { PTS.Validate(PTS.FsCreateSubpageFinite(ptsContext.Context, brParaIn, fFromPreviousPage, nSeg, pFtnRej, fEmptyOk, fSuppressTopSpace, fswdir, lWidth, lHeight, ref rcMargin, cColumns, rgColumnInfo, PTS.False, 0, null, null, 0, null, null, PTS.False, fsksuppresshardbreakbeforefirstparaIn, out fsfmtr, out pSubPage, out brParaOut, out dvrUsed, out fsBBox, out pfsMcsClient, out topSpace), ptsContext); } StructuralCache.CurrentFormatContext.PopPageData(); } //------------------------------------------------------------------- // CreateSubpageBottomlessHelper // NOTE: This helper is useful for debugging the caller of this function // because the debugger cannot show local variables in unsafe methods. //------------------------------------------------------------------- ////// Critical, because: /// a) calls Critical function PTS.FsCreateSubpageBottomless and passes /// pointer parameters directly that'll be written to, /// b) it is unsafe method. /// [SecurityCritical] private unsafe void CreateSubpageBottomlessHelper( PtsContext ptsContext, // IN: ptr to FS context IntPtr nSeg, // IN: name of the segment to start from int fSuppressTopSpace, // IN: suppress top space? uint fswdir, // IN: fswdir int lWidth, // IN: width of subpage int urMargin, // IN: ur of margin int durMargin, // IN: dur of margin int vrMargin, // IN: vr of margin int cColumns, // IN: number of columns PTS.FSCOLUMNINFO[] columnInfoCollection, // IN: array of column info out PTS.FSFMTRBL pfsfmtr, // OUT: why formatting was stopped out IntPtr ppSubPage, // OUT: ptr to the subpage out int pdvrUsed, // OUT: dvrUsed out PTS.FSBBOX pfsBBox, // OUT: subpage bbox out IntPtr pfsMcsClient, // OUT: margin collapsing state at the bottom out int pTopSpace, // OUT: top space due to collapsed margins out int fPageBecomesUninterruptible)// OUT: interruption is prohibited from now on { // Exceptions don't need to pop, as the top level measure context will be nulled out if thrown. StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(lWidth), TextDpi.MaxWidth), new Thickness(), false, false); fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) { PTS.Validate(PTS.FsCreateSubpageBottomless(ptsContext.Context, nSeg, fSuppressTopSpace, fswdir, lWidth, urMargin, durMargin, vrMargin, cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.False, out pfsfmtr, out ppSubPage, out pdvrUsed, out pfsBBox, out pfsMcsClient, out pTopSpace, out fPageBecomesUninterruptible), ptsContext); } StructuralCache.CurrentFormatContext.PopPageData(); } ////// Invalidates main text segment for bottomless pages if DTR list for this para is non-null. /// private void InvalidateMainTextSegment() { DtrList dtrs = StructuralCache.DtrsFromRange(ParagraphStartCharacterPosition, LastFormatCch); if (dtrs != null && dtrs.Length > 0) { _mainTextSegment.InvalidateStructure(dtrs[0].StartIndex); } } //-------------------------------------------------------------------- // HorizontalAlignment // Returns the horizontal alignment of this floater. Either calculated from the Floater or Figure properties. //------------------------------------------------------------------- private HorizontalAlignment HorizontalAlignment { get { if(Element is Floater) { return ((Floater)Element).HorizontalAlignment; } Figure figure = (Figure) Element; FigureHorizontalAnchor horizontalAnchor = figure.HorizontalAnchor; if(horizontalAnchor == FigureHorizontalAnchor.PageLeft || horizontalAnchor == FigureHorizontalAnchor.ContentLeft || horizontalAnchor == FigureHorizontalAnchor.ColumnLeft) { return HorizontalAlignment.Left; } else if(horizontalAnchor == FigureHorizontalAnchor.PageRight || horizontalAnchor == FigureHorizontalAnchor.ContentRight || horizontalAnchor == FigureHorizontalAnchor.ColumnRight) { return HorizontalAlignment.Right; } else if(horizontalAnchor == FigureHorizontalAnchor.PageCenter || horizontalAnchor == FigureHorizontalAnchor.ContentCenter || horizontalAnchor == FigureHorizontalAnchor.ColumnCenter) { return HorizontalAlignment.Center; } else { Debug.Assert(false, "Unknown type of anchor."); return HorizontalAlignment.Center; } } } //-------------------------------------------------------------------- // WrapDirection // Returns the wrap direction of this floater. Either calculated from the Floater or Figure properties. //-------------------------------------------------------------------- private WrapDirection WrapDirection { get { if(Element is Floater) { // Wrap text on both sides of the floater in all cases except where alignment is stretch, in which // case text must not be wrapped on either side if (HorizontalAlignment == HorizontalAlignment.Stretch) { return WrapDirection.None; } else { return WrapDirection.Both; } } else { Figure figure = (Figure) Element; return figure.WrapDirection; } } } //------------------------------------------------------------------- // Calculates the width of a floater - Returns NaN for auto sized floaters //-------------------------------------------------------------------- private double CalculateWidth(double spaceAvailable) { if(Element is Floater) { return (double)((Floater)Element).Width; } else { bool isWidthAuto; double desiredSize = FigureHelper.CalculateFigureWidth(StructuralCache, (Figure)Element, ((Figure)Element).Width, out isWidthAuto); if(isWidthAuto) { return Double.NaN; } return Math.Min(desiredSize, spaceAvailable); } } //------------------------------------------------------------------- // Determines whether a floater should be rejected or not //------------------------------------------------------------------- private bool IsFloaterRejected(bool fAtMaxWidth, double availableSpace) { if(fAtMaxWidth) { return false; } if(Element is Floater && HorizontalAlignment != HorizontalAlignment.Stretch) { return false; } else if(Element is Figure) { FigureLength figureLength = ((Figure)Element).Width; if(figureLength.IsAuto) { return false; } if(figureLength.IsAbsolute && figureLength.Value < availableSpace) { return false; } } return true; } #endregion Private Methods //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields // ----------------------------------------------------------------- // Main text segment. // ------------------------------------------------------------------ private BaseParagraph _mainTextSegment; #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. // // Description: FloaterParagraph class provides a wrapper floater objects. // // History: // 11/04/2004 : grzegorz - created. // //--------------------------------------------------------------------------- #pragma warning disable 1634, 1691 // avoid generating warnings about unknown // message numbers and unknown pragmas for PRESharp contol using System; using System.Diagnostics; using System.Security; // SecurityCritical using System.Windows; using System.Windows.Documents; using MS.Internal.Documents; using MS.Internal.Text; using MS.Internal.PtsHost.UnsafeNativeMethods; namespace MS.Internal.PtsHost { // --------------------------------------------------------------------- // FloaterParagraph class provides a wrapper floater objects. // --------------------------------------------------------------------- internal sealed class FloaterParagraph : FloaterBaseParagraph { //-------------------------------------------------------------------- // // Constructors // //------------------------------------------------------------------- #region Constructors // ------------------------------------------------------------------ // Constructor. // // element - Element associated with paragraph. // structuralCache - Content's structural cache // ------------------------------------------------------------------ internal FloaterParagraph(TextElement element, StructuralCache structuralCache) : base(element, structuralCache) { } // ----------------------------------------------------------------- // UpdGetParaChange - Floater paragraph is always new // ------------------------------------------------------------------ internal override void UpdGetParaChange( out PTS.FSKCHANGE fskch, // OUT: kind of change out int fNoFurtherChanges) // OUT: no changes after? { base.UpdGetParaChange(out fskch, out fNoFurtherChanges); fskch = PTS.FSKCHANGE.fskchNew; } // ----------------------------------------------------------------- // IDisposable.Dispose // ----------------------------------------------------------------- public override void Dispose() { base.Dispose(); if (_mainTextSegment != null) { _mainTextSegment.Dispose(); _mainTextSegment = null; } } #endregion Constructors //------------------------------------------------------------------- // // PTS callbacks // //-------------------------------------------------------------------- #region PTS callbacks //------------------------------------------------------------------- // CreateParaclient //-------------------------------------------------------------------- internal override void CreateParaclient( out IntPtr paraClientHandle) // OUT: opaque to PTS paragraph client { #pragma warning disable 6518 // Disable PRESharp warning 6518. FloaterParaClient 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. FloaterParaClient paraClient = new FloaterParaClient(this); paraClientHandle = paraClient.Handle; #pragma warning restore 6518 // Create the main text segment if (_mainTextSegment == null) { _mainTextSegment = new ContainerParagraph(Element, StructuralCache); } } internal override void CollapseMargin( BaseParaClient paraClient, // IN: MarginCollapsingState mcs, // IN: input margin collapsing state uint fswdir, // IN: current direction (of the track, in which margin collapsing is happening) bool suppressTopSpace, // IN: suppress empty space at the top of page out int dvr) // OUT: dvr, calculated based on margin collapsing state { // Floaters are not participating in margin collapsing. // Top space is always suppressed dvr = 0; } //-------------------------------------------------------------------- // GetFloaterProperties //------------------------------------------------------------------- internal override void GetFloaterProperties( uint fswdirTrack, // IN: direction of track out PTS.FSFLOATERPROPS fsfloaterprops) // OUT: properties of the floater { fsfloaterprops = new PTS.FSFLOATERPROPS(); fsfloaterprops.fFloat = PTS.True; // Floater fsfloaterprops.fskclear = PTS.WrapDirectionToFskclear((WrapDirection)Element.GetValue(Block.ClearFloatersProperty)); // Get floater alignment from HorizontalAlignment of the floater element. switch (HorizontalAlignment) { case HorizontalAlignment.Right: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignMax; break; case HorizontalAlignment.Center: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignCenter; break; case HorizontalAlignment.Left: default: fsfloaterprops.fskfloatalignment = PTS.FSKFLOATALIGNMENT.fskfloatalignMin; break; } fsfloaterprops.fskwr = PTS.WrapDirectionToFskwrap(WrapDirection); // Always delay floaters if there is no progress. fsfloaterprops.fDelayNoProgress = PTS.True; } //-------------------------------------------------------------------- // FormatFloaterContentFinite //------------------------------------------------------------------- ////// Critical - as this calls Critical functions PTS.FsDestroySubpage, /// CreateSubpageFiniteHelper and Critical setter for paraClient.SubpageHandle. /// This takes the unvalidated parameter footnoteRejector. /// [SecurityCritical] 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; } //------------------------------------------------------------------- // FormatFloaterContentBottomless //------------------------------------------------------------------- ////// Critical - as this calls Critical functions PTS.FsDestroySubpage, /// CreateSubpageBottomlessHelper and setter for SubpageHandle. /// Safe - as the parameters passed in are either generated in this function /// or they are Critical for set. /// [SecurityCritical, SecurityTreatAsSafe] internal override void FormatFloaterContentBottomless( FloaterBaseParaClient paraClient, // IN: 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 out PTS.FSFMTRBL fsfmtrbl, // OUT: result of formatting out IntPtr pfsFloatContent, // OUT: opaque for PTS pointer pointer to formatted content 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))); Invariant.Assert(paraClient is FloaterParaClient); int subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin; int dvrTopSpace, fPageBecomesUninterruptable; int cColumns; PTS.FSCOLUMNINFO[] columnInfoCollection; IntPtr pmcsclientOut; MbpInfo mbp; double specifiedWidth; // If horizontal alignment is Stretch and we are not formatting at max width, // we cannot proceed. if (IsFloaterRejected(PTS.ToBoolean(fAtMaxWidth), TextDpi.FromTextDpi(durAvailable))) { // Set foater width, height to be greater than available values to signal to PTS that floater does not fit in the space durFloaterWidth = durAvailable + 1; dvrFloaterHeight = dvrAvailable + 1; cPolygons = cVertices = 0; fsfmtrbl = PTS.FSFMTRBL.fmtrblInterrupted; fsbbox = new PTS.FSBBOX(); fsbbox.fDefined = PTS.False; pfsFloatContent = IntPtr.Zero; } else { // 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 width. mbp = MbpInfo.FromElement(Element); specifiedWidth = CalculateWidth(TextDpi.FromTextDpi(durAvailable)); AdjustDurAvailable(specifiedWidth, ref durAvailable, out subpageWidth); durSubpageMargin = subpageWidth; urSubpageMargin = vrSubpageMargin = 0; // Initialize column info. Floater always has just 1 column. cColumns = 1; columnInfoCollection = new PTS.FSCOLUMNINFO[cColumns]; columnInfoCollection[0].durBefore = 0; columnInfoCollection[0].durWidth = subpageWidth; // Create subpage InvalidateMainTextSegment(); CreateSubpageBottomlessHelper(PtsContext, _mainTextSegment.Handle, PTS.True, fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin, cColumns, columnInfoCollection, out fsfmtrbl, out pfsFloatContent, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace, out fPageBecomesUninterruptable); if (fsfmtrbl != PTS.FSFMTRBL.fmtrblCollision) { // 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 full column 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); } 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 = durSubpageMargin = fsbbox.fsrc.du + 1; // add 1/300px to avoid rounding errors columnInfoCollection[0].durWidth = subpageWidth; CreateSubpageBottomlessHelper(PtsContext, _mainTextSegment.Handle, PTS.True, fswdir, subpageWidth, urSubpageMargin, durSubpageMargin, vrSubpageMargin, cColumns, columnInfoCollection, out fsfmtrbl, out pfsFloatContent, out dvrFloaterHeight, out fsbbox, out pmcsclientOut, out dvrTopSpace, out fPageBecomesUninterruptable); } } 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. durFloaterWidth = subpageWidth + mbp.MBPLeft + mbp.MBPRight; dvrFloaterHeight += mbp.MBPTop + mbp.MBPBottom; // Check if floater width fits in available width. It may exceed available width because borders // and padding are added. if ( dvrFloaterHeight > dvrAvailable || (durFloaterWidth > durAvailable && !PTS.ToBoolean(fAtMaxWidth)) ) { // Get rid of any previous formatting if (pfsFloatContent != IntPtr.Zero) { PTS.Validate(PTS.FsDestroySubpage(PtsContext.Context, pfsFloatContent), PtsContext); } Debug.Assert(pmcsclientOut == IntPtr.Zero); cPolygons = cVertices = 0; pfsFloatContent = IntPtr.Zero; } else { // Width and height are OK, format floater // Adjust bounding box to cover entire floater. fsbbox.fsrc.u = 0; fsbbox.fsrc.v = 0; fsbbox.fsrc.du = durFloaterWidth; fsbbox.fsrc.dv = dvrFloaterHeight; // Tight wrap is disabled for now. cPolygons = cVertices = 0; } } else { Debug.Assert(pmcsclientOut == IntPtr.Zero); durFloaterWidth = dvrFloaterHeight = 0; cPolygons = cVertices = 0; pfsFloatContent = IntPtr.Zero; } } // Update handle to PTS subpage. ((FloaterParaClient)paraClient).SubpageHandle = pfsFloatContent; } //-------------------------------------------------------------------- // UpdateBottomlessFloaterContent //------------------------------------------------------------------- internal override void UpdateBottomlessFloaterContent( FloaterBaseParaClient paraClient, // IN: 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 IntPtr pfsFloatContent, // IN: floater content (in UIElementParagraph, this is an alias to the paraClient) out PTS.FSFMTRBL fsfmtrbl, // OUT: result of formatting 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 { fsfmtrbl = default(PTS.FSFMTRBL); durFloaterWidth = dvrFloaterHeight = cPolygons = cVertices = 0; fsbbox = new PTS.FSBBOX(); Invariant.Assert(false, "No appropriate handling for update in attached object floater."); } //-------------------------------------------------------------------- // GetMCSClientAfterFloater //-------------------------------------------------------------------- internal override void GetMCSClientAfterFloater( uint fswdirTrack, // IN: direction of Track MarginCollapsingState mcs, // IN: input margin collapsing state out IntPtr pmcsclientOut) // OUT: MCSCLIENT that floater will return to track { // Floaters margins are added during formatting. if (mcs != null) { pmcsclientOut = mcs.Handle; } else { pmcsclientOut = IntPtr.Zero; } } #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 Methods // //------------------------------------------------------------------- #region Private Methods ////// Adjust the width available for the Floater. /// private void AdjustDurAvailable(double specifiedWidth, ref int durAvailable, out int subpageWidth) { // If width on floater is specified, use the specified value. // Use page size from current format context to limit MBP MbpInfo mbp = MbpInfo.FromElement(Element); if (!Double.IsNaN(specifiedWidth)) { TextDpi.EnsureValidPageWidth(ref specifiedWidth); // If specified width is greater than available width, do not exceed available width int durSpecified = TextDpi.ToTextDpi(specifiedWidth); if ((durSpecified + mbp.MarginRight + mbp.MarginLeft) <= durAvailable) { // Set durAvailable to durSpecified plus margins, which will be added later. // Set subpage width to specified width less border and padding durAvailable = durSpecified + mbp.MarginLeft + mbp.MarginRight; subpageWidth = Math.Max(1, durSpecified - (mbp.BPLeft + mbp.BPRight)); } else { // Use durAvailable, less MBP to set subpage width. We cannot set figure to specified width subpageWidth = Math.Max(1, durAvailable - (mbp.MBPLeft + mbp.MBPRight)); } } else { // No width specified. Use durAvailable, less MBP to set subpage width. subpageWidth = Math.Max(1, durAvailable - (mbp.MBPLeft + mbp.MBPRight)); } } //-------------------------------------------------------------------- // CreateSubpageFiniteHelper // NOTE: This helper is useful for debugging the caller of this function // because the debugger cannot show local variables in unsafe methods. //------------------------------------------------------------------- ////// Critical, because: /// a) calls Critical function PTS.FsCreateSubpageFinite and passes /// pointer parameters directly that'll be written to, /// b) calls the Critical constructor of SubpageBreakRecord, /// c) it is unsafe method. /// [SecurityCritical] private unsafe void CreateSubpageFiniteHelper( PtsContext ptsContext, // IN: ptr to FS context IntPtr brParaIn, // IN: break record---use if !NULL int fFromPreviousPage, // IN: break record was created on previous page IntPtr nSeg, // IN: name of the segment to start from-if pointer to break rec is NULL IntPtr pFtnRej, // IN: pftnrej int fEmptyOk, // IN: fEmptyOK int fSuppressTopSpace, // IN: fSuppressTopSpace uint fswdir, // IN: fswdir int lWidth, // IN: width of subpage int lHeight, // IN: height of subpage ref PTS.FSRECT rcMargin, // IN: rectangle within subpage margins int cColumns, // IN: number of columns PTS.FSCOLUMNINFO[] columnInfoCollection, // IN: array of column info int fApplyColumnBalancing, // IN: apply column balancing? PTS.FSKSUPPRESSHARDBREAKBEFOREFIRSTPARA fsksuppresshardbreakbeforefirstparaIn, // IN: suppress breaks at track start? out PTS.FSFMTR fsfmtr, // OUT: why formatting was stopped out IntPtr pSubPage, // OUT: ptr to the subpage out IntPtr brParaOut, // OUT: break record of the subpage out int dvrUsed, // OUT: dvrUsed out PTS.FSBBOX fsBBox, // OUT: subpage bbox out IntPtr pfsMcsClient, // OUT: margin collapsing state at the bottom out int topSpace) // OUT: top space due to collapsed margins { // Exceptions don't need to pop, as the top level measure context will be nulled out if thrown. StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(lWidth), TextDpi.FromTextDpi(lHeight)), new Thickness(), false, true); fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) { PTS.Validate(PTS.FsCreateSubpageFinite(ptsContext.Context, brParaIn, fFromPreviousPage, nSeg, pFtnRej, fEmptyOk, fSuppressTopSpace, fswdir, lWidth, lHeight, ref rcMargin, cColumns, rgColumnInfo, PTS.False, 0, null, null, 0, null, null, PTS.False, fsksuppresshardbreakbeforefirstparaIn, out fsfmtr, out pSubPage, out brParaOut, out dvrUsed, out fsBBox, out pfsMcsClient, out topSpace), ptsContext); } StructuralCache.CurrentFormatContext.PopPageData(); } //------------------------------------------------------------------- // CreateSubpageBottomlessHelper // NOTE: This helper is useful for debugging the caller of this function // because the debugger cannot show local variables in unsafe methods. //------------------------------------------------------------------- ////// Critical, because: /// a) calls Critical function PTS.FsCreateSubpageBottomless and passes /// pointer parameters directly that'll be written to, /// b) it is unsafe method. /// [SecurityCritical] private unsafe void CreateSubpageBottomlessHelper( PtsContext ptsContext, // IN: ptr to FS context IntPtr nSeg, // IN: name of the segment to start from int fSuppressTopSpace, // IN: suppress top space? uint fswdir, // IN: fswdir int lWidth, // IN: width of subpage int urMargin, // IN: ur of margin int durMargin, // IN: dur of margin int vrMargin, // IN: vr of margin int cColumns, // IN: number of columns PTS.FSCOLUMNINFO[] columnInfoCollection, // IN: array of column info out PTS.FSFMTRBL pfsfmtr, // OUT: why formatting was stopped out IntPtr ppSubPage, // OUT: ptr to the subpage out int pdvrUsed, // OUT: dvrUsed out PTS.FSBBOX pfsBBox, // OUT: subpage bbox out IntPtr pfsMcsClient, // OUT: margin collapsing state at the bottom out int pTopSpace, // OUT: top space due to collapsed margins out int fPageBecomesUninterruptible)// OUT: interruption is prohibited from now on { // Exceptions don't need to pop, as the top level measure context will be nulled out if thrown. StructuralCache.CurrentFormatContext.PushNewPageData(new Size(TextDpi.FromTextDpi(lWidth), TextDpi.MaxWidth), new Thickness(), false, false); fixed (PTS.FSCOLUMNINFO* rgColumnInfo = columnInfoCollection) { PTS.Validate(PTS.FsCreateSubpageBottomless(ptsContext.Context, nSeg, fSuppressTopSpace, fswdir, lWidth, urMargin, durMargin, vrMargin, cColumns, rgColumnInfo, 0, null, null, 0, null, null, PTS.False, out pfsfmtr, out ppSubPage, out pdvrUsed, out pfsBBox, out pfsMcsClient, out pTopSpace, out fPageBecomesUninterruptible), ptsContext); } StructuralCache.CurrentFormatContext.PopPageData(); } ////// Invalidates main text segment for bottomless pages if DTR list for this para is non-null. /// private void InvalidateMainTextSegment() { DtrList dtrs = StructuralCache.DtrsFromRange(ParagraphStartCharacterPosition, LastFormatCch); if (dtrs != null && dtrs.Length > 0) { _mainTextSegment.InvalidateStructure(dtrs[0].StartIndex); } } //-------------------------------------------------------------------- // HorizontalAlignment // Returns the horizontal alignment of this floater. Either calculated from the Floater or Figure properties. //------------------------------------------------------------------- private HorizontalAlignment HorizontalAlignment { get { if(Element is Floater) { return ((Floater)Element).HorizontalAlignment; } Figure figure = (Figure) Element; FigureHorizontalAnchor horizontalAnchor = figure.HorizontalAnchor; if(horizontalAnchor == FigureHorizontalAnchor.PageLeft || horizontalAnchor == FigureHorizontalAnchor.ContentLeft || horizontalAnchor == FigureHorizontalAnchor.ColumnLeft) { return HorizontalAlignment.Left; } else if(horizontalAnchor == FigureHorizontalAnchor.PageRight || horizontalAnchor == FigureHorizontalAnchor.ContentRight || horizontalAnchor == FigureHorizontalAnchor.ColumnRight) { return HorizontalAlignment.Right; } else if(horizontalAnchor == FigureHorizontalAnchor.PageCenter || horizontalAnchor == FigureHorizontalAnchor.ContentCenter || horizontalAnchor == FigureHorizontalAnchor.ColumnCenter) { return HorizontalAlignment.Center; } else { Debug.Assert(false, "Unknown type of anchor."); return HorizontalAlignment.Center; } } } //-------------------------------------------------------------------- // WrapDirection // Returns the wrap direction of this floater. Either calculated from the Floater or Figure properties. //-------------------------------------------------------------------- private WrapDirection WrapDirection { get { if(Element is Floater) { // Wrap text on both sides of the floater in all cases except where alignment is stretch, in which // case text must not be wrapped on either side if (HorizontalAlignment == HorizontalAlignment.Stretch) { return WrapDirection.None; } else { return WrapDirection.Both; } } else { Figure figure = (Figure) Element; return figure.WrapDirection; } } } //------------------------------------------------------------------- // Calculates the width of a floater - Returns NaN for auto sized floaters //-------------------------------------------------------------------- private double CalculateWidth(double spaceAvailable) { if(Element is Floater) { return (double)((Floater)Element).Width; } else { bool isWidthAuto; double desiredSize = FigureHelper.CalculateFigureWidth(StructuralCache, (Figure)Element, ((Figure)Element).Width, out isWidthAuto); if(isWidthAuto) { return Double.NaN; } return Math.Min(desiredSize, spaceAvailable); } } //------------------------------------------------------------------- // Determines whether a floater should be rejected or not //------------------------------------------------------------------- private bool IsFloaterRejected(bool fAtMaxWidth, double availableSpace) { if(fAtMaxWidth) { return false; } if(Element is Floater && HorizontalAlignment != HorizontalAlignment.Stretch) { return false; } else if(Element is Figure) { FigureLength figureLength = ((Figure)Element).Width; if(figureLength.IsAuto) { return false; } if(figureLength.IsAbsolute && figureLength.Value < availableSpace) { return false; } } return true; } #endregion Private Methods //------------------------------------------------------------------- // // Private Fields // //-------------------------------------------------------------------- #region Private Fields // ----------------------------------------------------------------- // Main text segment. // ------------------------------------------------------------------ private BaseParagraph _mainTextSegment; #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
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DesigntimeLicenseContext.cs
- EventLogger.cs
- DragDropHelper.cs
- LocalizabilityAttribute.cs
- BypassElement.cs
- UntypedNullExpression.cs
- SamlSecurityToken.cs
- HandleValueEditor.cs
- DataControlFieldCollection.cs
- TypeNameConverter.cs
- _AutoWebProxyScriptHelper.cs
- QueryInterceptorAttribute.cs
- PersonalizationStateQuery.cs
- PolyBezierSegmentFigureLogic.cs
- WorkflowDesignerMessageFilter.cs
- CodeCatchClause.cs
- Floater.cs
- FunctionDescription.cs
- CodeAccessPermission.cs
- PageCodeDomTreeGenerator.cs
- QueryOutputWriter.cs
- InputBinder.cs
- HorizontalAlignConverter.cs
- ResXResourceReader.cs
- DictionaryChange.cs
- TransferRequestHandler.cs
- FamilyCollection.cs
- FusionWrap.cs
- _NestedSingleAsyncResult.cs
- EntityDescriptor.cs
- CounterSampleCalculator.cs
- relpropertyhelper.cs
- QilLiteral.cs
- SplitterPanel.cs
- RuntimeConfig.cs
- HwndSource.cs
- SecureEnvironment.cs
- RegisteredHiddenField.cs
- XmlException.cs
- EventLogEntry.cs
- SchemaImporter.cs
- WebCategoryAttribute.cs
- TextContainerHelper.cs
- ServiceHostFactory.cs
- MissingManifestResourceException.cs
- CrossContextChannel.cs
- SEHException.cs
- DiscoveryClientReferences.cs
- PersonalizationStateInfoCollection.cs
- SQlBooleanStorage.cs
- StrokeCollection2.cs
- SupportsEventValidationAttribute.cs
- NativeMethodsCLR.cs
- WebPartDisplayMode.cs
- KeyValueSerializer.cs
- PKCS1MaskGenerationMethod.cs
- TextTrailingCharacterEllipsis.cs
- ImageListImage.cs
- ResetableIterator.cs
- QueryRewriter.cs
- XmlSchemaGroupRef.cs
- ZipIOZip64EndOfCentralDirectoryLocatorBlock.cs
- BaseComponentEditor.cs
- XPathScanner.cs
- VirtualDirectoryMapping.cs
- PageFunction.cs
- DbCommandDefinition.cs
- ProtocolsConfigurationHandler.cs
- Configuration.cs
- Rijndael.cs
- BitmapEffect.cs
- TypeDelegator.cs
- OutputCacheSettingsSection.cs
- WmfPlaceableFileHeader.cs
- AnnotationComponentChooser.cs
- DataMemberAttribute.cs
- DrawTreeNodeEventArgs.cs
- WriterOutput.cs
- SerializerProvider.cs
- ExceptionHelpers.cs
- DBConcurrencyException.cs
- LinkLabel.cs
- ConfigurationHelpers.cs
- TriState.cs
- UnionCqlBlock.cs
- RemoteWebConfigurationHostStream.cs
- CompositeControlDesigner.cs
- XComponentModel.cs
- UserControl.cs
- DiffuseMaterial.cs
- mediaeventargs.cs
- ItemList.cs
- MetadataArtifactLoaderCompositeFile.cs
- TypefaceMap.cs
- ApplyImportsAction.cs
- TemplatePropertyEntry.cs
- PointUtil.cs
- AppDomain.cs
- FlowThrottle.cs
- UrlMappingsSection.cs