|
//---------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// Description: FloaterParagraph class provides a wrapper floater objects.
//
// History:
// 11/04/2004 : Microsoft - 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
//-------------------------------------------------------------------
///<SecurityNote>
/// Critical - as this calls Critical functions PTS.FsDestroySubpage,
/// CreateSubpageFiniteHelper and Critical setter for paraClient.SubpageHandle.
/// This takes the unvalidated parameter footnoteRejector.
/// </SecurityNote>
[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, StructuralCache.TextFormatterHost.PixelsPerDip);
// 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
//-------------------------------------------------------------------
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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, StructuralCache.TextFormatterHost.PixelsPerDip);
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();
}
}
/// <summary>
/// Update number of characters consumed by the main text segment.
/// </summary>
internal void UpdateSegmentLastFormatPositions()
{
_mainTextSegment.UpdateLastFormatPositions();
}
#endregion Internal Methods
//-------------------------------------------------------------------
//
// Private Methods
//
//-------------------------------------------------------------------
#region Private Methods
/// <summary>
/// Adjust the width available for the Floater.
/// </summary>
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, StructuralCache.TextFormatterHost.PixelsPerDip);
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.
//-------------------------------------------------------------------
/// <SecurityNote>
/// 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.
/// </SecurityNote>
[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.
//-------------------------------------------------------------------
/// <SecurityNote>
/// Critical, because:
/// a) calls Critical function PTS.FsCreateSubpageBottomless and passes
/// pointer parameters directly that'll be written to,
/// b) it is unsafe method.
/// </SecurityNote>
[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();
}
/// <summary>
/// Invalidates main text segment for bottomless pages if DTR list for this para is non-null.
/// </summary>
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
|