Code:
/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / MS / Internal / PtsHost / PtsHelper.cs / 1305600 / PtsHelper.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// File: PtsHelper.cs
//
// Description: Helper services to query PTS objects.
//
// History:
// 05/05/2003 : [....] - moving from Avalon branch.
//
//---------------------------------------------------------------------------
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Documents;
using MS.Internal.Text;
using MS.Internal.Documents;
using MS.Internal.PtsHost.UnsafeNativeMethods;
namespace MS.Internal.PtsHost
{
// ---------------------------------------------------------------------
// Helper services to query PTS objects.
// ---------------------------------------------------------------------
internal static class PtsHelper
{
// ------------------------------------------------------------------
//
// Visual Helpers
//
// -----------------------------------------------------------------
#region Visual Helpers
// ------------------------------------------------------------------
// Update mirroring transform.
// ------------------------------------------------------------------
internal static void UpdateMirroringTransform(FlowDirection parentFD, FlowDirection childFD, ContainerVisual visualChild, double width)
{
// Set mirroring transform if necessary, or clear it just in case it was set in the previous
// format process.
if (parentFD != childFD)
{
MatrixTransform transform = new MatrixTransform(-1.0, 0.0, 0.0, 1.0, width, 0.0);
visualChild.Transform = transform;
visualChild.SetValue(FrameworkElement.FlowDirectionProperty, childFD);
}
else
{
visualChild.Transform = null;
visualChild.ClearValue(FrameworkElement.FlowDirectionProperty);
}
}
// -----------------------------------------------------------------
// Clips visual children to a specified rect
// ------------------------------------------------------------------
internal static void ClipChildrenToRect(ContainerVisual visual, Rect rect)
{
VisualCollection visualChildren = visual.Children;
for(int index = 0; index < visualChildren.Count; index++)
{
((ContainerVisual)visualChildren[index]).Clip = new RectangleGeometry(rect);
}
}
// -----------------------------------------------------------------
// Syncs a floating element para list with a visual collection
// -----------------------------------------------------------------
internal static void UpdateFloatingElementVisuals(ContainerVisual visual, List floatingElementList)
{
VisualCollection visualChildren = visual.Children;
int visualIndex = 0;
if(floatingElementList == null || floatingElementList.Count == 0)
{
visualChildren.Clear();
}
else
{
for(int index = 0; index < floatingElementList.Count; index++)
{
Visual paraVisual = floatingElementList[index].Visual;
while(visualIndex < visualChildren.Count && visualChildren[visualIndex] != paraVisual)
{
visualChildren.RemoveAt(visualIndex);
}
if(visualIndex == visualChildren.Count)
{
visualChildren.Add(paraVisual);
}
visualIndex++;
}
if(visualChildren.Count > floatingElementList.Count)
{
visualChildren.RemoveRange(floatingElementList.Count, visualChildren.Count - floatingElementList.Count);
}
}
}
#endregion Visual Helpers
// -----------------------------------------------------------------
//
// Arrange Helpers
//
// ------------------------------------------------------------------
#region Arrange Helpers
//-------------------------------------------------------------------
// Arrange PTS track.
//--------------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical functions: ParaListFromTrack and ArrangeParaList.
///
[SecurityCritical]
internal static void ArrangeTrack(
PtsContext ptsContext,
ref PTS.FSTRACKDESCRIPTION trackDesc,
uint fswdirTrack)
{
// There is possibility to get empty track. (example: large figures)
if (trackDesc.pfstrack != IntPtr.Zero)
{
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, trackDesc.pfstrack, out trackDetails));
// There is possibility to get empty track.
if (trackDetails.cParas != 0)
{
// Get list of paragraphs
PTS.FSPARADESCRIPTION[] arrayParaDesc;
ParaListFromTrack(ptsContext, trackDesc.pfstrack, ref trackDetails, out arrayParaDesc);
// Arrange paragraphs
ArrangeParaList(ptsContext, trackDesc.fsrc, arrayParaDesc, fswdirTrack);
}
}
}
// ------------------------------------------------------------------
// Arrange para list.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function BaseParaClient.Arrange.
/// b) calls Critical function PTS.FsTransformRectangle
///
[SecurityCritical]
internal static void ArrangeParaList(
PtsContext ptsContext,
PTS.FSRECT rcTrackContent,
PTS.FSPARADESCRIPTION [] arrayParaDesc,
uint fswdirTrack)
{
// For each paragraph, do following:
// (1) Retrieve ParaClient object
// (2) Arrange and update paragraph metrics
int dvrPara = 0;
for (int index = 0; index < arrayParaDesc.Length; index++)
{
// (1) Retrieve ParaClient object
BaseParaClient paraClient = ptsContext.HandleToObject(arrayParaDesc[index].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
// Convert to appropriate page coordinates.
if(index == 0)
{
uint fswdirPage = PTS.FlowDirectionToFswdir(paraClient.PageFlowDirection);
if(fswdirTrack != fswdirPage)
{
PTS.FSRECT pageRect = paraClient.Paragraph.StructuralCache.CurrentArrangeContext.PageContext.PageRect;
PTS.Validate(PTS.FsTransformRectangle(fswdirTrack, ref pageRect, ref rcTrackContent, fswdirPage, out rcTrackContent));
}
}
// (2) Arrange and update paragraph metrics
int dvrTopSpace = arrayParaDesc[index].dvrTopSpace;
PTS.FSRECT rcPara = rcTrackContent;
rcPara.v += dvrPara + dvrTopSpace;
rcPara.dv = arrayParaDesc[index].dvrUsed - dvrTopSpace;
paraClient.Arrange(arrayParaDesc[index].pfspara, rcPara, dvrTopSpace, fswdirTrack);
dvrPara += arrayParaDesc[index].dvrUsed;
}
}
#endregion Arrange Helpers
// ------------------------------------------------------------------
//
// Update Visual Helpers
//
// -----------------------------------------------------------------
#region Update Visual Helpers
//-------------------------------------------------------------------
// Update PTS track (column) visuals.
//-------------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical function ParaListFromTrack.
///
[SecurityCritical]
internal static void UpdateTrackVisuals(
PtsContext ptsContext,
VisualCollection visualCollection,
PTS.FSKUPDATE fskupdInherited,
ref PTS.FSTRACKDESCRIPTION trackDesc)
{
PTS.FSKUPDATE fskupd = trackDesc.fsupdinf.fskupd;
if (trackDesc.fsupdinf.fskupd == PTS.FSKUPDATE.fskupdInherited)
{
fskupd = fskupdInherited;
}
// If there is no change, visual information is valid
if (fskupd == PTS.FSKUPDATE.fskupdNoChange) { return; }
ErrorHandler.Assert(fskupd != PTS.FSKUPDATE.fskupdShifted, ErrorHandler.UpdateShiftedNotValid);
bool emptyTrack = (trackDesc.pfstrack == IntPtr.Zero);
if (!emptyTrack)
{
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, trackDesc.pfstrack, out trackDetails));
emptyTrack = (trackDetails.cParas == 0);
if (!emptyTrack)
{
// Get list of paragraphs
PTS.FSPARADESCRIPTION[] arrayParaDesc;
ParaListFromTrack(ptsContext, trackDesc.pfstrack, ref trackDetails, out arrayParaDesc);
// Update visuals for list of paragraphs
UpdateParaListVisuals(ptsContext, visualCollection, fskupd, arrayParaDesc);
}
}
// There is possibility to get empty track. (example: large figures)
if (emptyTrack)
{
// There is no content, remove all existing children visuals.
visualCollection.Clear();
}
}
// ------------------------------------------------------------------
// Update visuals for list of paragraphs.
// -----------------------------------------------------------------
internal static void UpdateParaListVisuals(
PtsContext ptsContext,
VisualCollection visualCollection,
PTS.FSKUPDATE fskupdInherited,
PTS.FSPARADESCRIPTION [] arrayParaDesc)
{
// For each paragraph, do following:
// (1) Retrieve ParaClient object
// (3) Update visual, if necessary
for (int index = 0; index < arrayParaDesc.Length; index++)
{
// (1) Retrieve ParaClient object
BaseParaClient paraClient = ptsContext.HandleToObject(arrayParaDesc[index].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
// (2) Update visual, if necessary
PTS.FSKUPDATE fskupd = arrayParaDesc[index].fsupdinf.fskupd;
if (fskupd == PTS.FSKUPDATE.fskupdInherited)
{
fskupd = fskupdInherited;
}
if (fskupd == PTS.FSKUPDATE.fskupdNew)
{
// Disconnect visual from its old parent, if necessary.
Visual currentParent = VisualTreeHelper.GetParent(paraClient.Visual) as Visual;
if(currentParent != null)
{
ContainerVisual parent = currentParent as ContainerVisual;
Invariant.Assert(parent != null, "parent should always derives from ContainerVisual");
parent.Children.Remove(paraClient.Visual);
}
// New paragraph - insert new visual node
visualCollection.Insert(index, paraClient.Visual);
paraClient.ValidateVisual(fskupd);
}
else
{
// Remove visuals for non-existing paragraphs
while (visualCollection[index] != paraClient.Visual)
{
visualCollection.RemoveAt(index);
Invariant.Assert(index < visualCollection.Count);
}
if(fskupd == PTS.FSKUPDATE.fskupdChangeInside || fskupd == PTS.FSKUPDATE.fskupdShifted)
{
paraClient.ValidateVisual(fskupd);
}
}
}
// Remove obsolete visuals
if (arrayParaDesc.Length < visualCollection.Count)
{
visualCollection.RemoveRange(arrayParaDesc.Length, visualCollection.Count - arrayParaDesc.Length);
}
}
#endregion Update Visual Helpers
#region Update Viewport Helpers
//--------------------------------------------------------------------
// Update viewport for track
//--------------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical function ParaListFromTrack.
///
[SecurityCritical]
internal static void UpdateViewportTrack(
PtsContext ptsContext,
ref PTS.FSTRACKDESCRIPTION trackDesc,
ref PTS.FSRECT viewport)
{
// There is possibility to get empty track. (example: large figures)
if (trackDesc.pfstrack != IntPtr.Zero)
{
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, trackDesc.pfstrack, out trackDetails));
// There is possibility to get empty track.
if (trackDetails.cParas != 0)
{
// Get list of paragraphs
PTS.FSPARADESCRIPTION[] arrayParaDesc;
ParaListFromTrack(ptsContext, trackDesc.pfstrack, ref trackDetails, out arrayParaDesc);
// Arrange paragraphs
UpdateViewportParaList(ptsContext, arrayParaDesc, ref viewport);
}
}
}
// -----------------------------------------------------------------
// Update viewport for para list
// ------------------------------------------------------------------
internal static void UpdateViewportParaList(
PtsContext ptsContext,
PTS.FSPARADESCRIPTION [] arrayParaDesc,
ref PTS.FSRECT viewport)
{
for (int index = 0; index < arrayParaDesc.Length; index++)
{
// (1) Retrieve ParaClient object
BaseParaClient paraClient = ptsContext.HandleToObject(arrayParaDesc[index].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
paraClient.UpdateViewport(ref viewport);
}
}
#endregion Arrange Helpers
// -----------------------------------------------------------------
//
// HitTest Helpers
//
// -----------------------------------------------------------------
#region HitTest Helpers
// -----------------------------------------------------------------
// Hit tests to the correct IInputElement within the track that the
// mouse is over.
// ------------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical function ParaListFromTrack.
///
[SecurityCritical]
internal static IInputElement InputHitTestTrack(
PtsContext ptsContext,
PTS.FSPOINT pt,
ref PTS.FSTRACKDESCRIPTION trackDesc)
{
// There is possibility to get empty track. (example: large figures)
if (trackDesc.pfstrack == IntPtr.Zero) { return null; }
IInputElement ie = null;
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, trackDesc.pfstrack, out trackDetails));
// There might be possibility to get empty track, skip the track
// in such case.
if (trackDetails.cParas != 0)
{
// Get list of paragraphs
PTS.FSPARADESCRIPTION[] arrayParaDesc;
ParaListFromTrack(ptsContext, trackDesc.pfstrack, ref trackDetails, out arrayParaDesc);
// Hittest list of paragraphs
ie = InputHitTestParaList(ptsContext, pt, ref trackDesc.fsrc, arrayParaDesc);
}
return ie;
}
// -----------------------------------------------------------------
// Hit tests to the correct IInputElement within the list of
// paragraphs that the mouse is over.
// ------------------------------------------------------------------
internal static IInputElement InputHitTestParaList(
PtsContext ptsContext,
PTS.FSPOINT pt,
ref PTS.FSRECT rcTrack, // track's rectangle
PTS.FSPARADESCRIPTION [] arrayParaDesc)
{
IInputElement ie = null;
for (int index = 0; index < arrayParaDesc.Length && ie == null; index++)
{
BaseParaClient paraClient = ptsContext.HandleToObject(arrayParaDesc[index].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
if(paraClient.Rect.Contains(pt))
{
ie = paraClient.InputHitTest(pt);
}
}
return ie;
}
#endregion HitTest Helpers
// ------------------------------------------------------------------
//
// GetRectangles Helpers
//
// -----------------------------------------------------------------
#region GetRectangles Helpers
// ------------------------------------------------------------------
// Returns ArrayList of rectangles for the ContentElement e within
// the specified track. If e is not found or if track contains nothing,
// returns empty list
//
// start: int representing start offset of e
// length: int representing number of positions occupied by e
// -----------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical function ParaListFromTrack.
///
[SecurityCritical]
internal static List GetRectanglesInTrack(
PtsContext ptsContext,
ContentElement e,
int start,
int length,
ref PTS.FSTRACKDESCRIPTION trackDesc)
{
List rectangles = new List();
// There is possibility to get empty track. (example: large figures)
if (trackDesc.pfstrack == IntPtr.Zero)
{
// TRack is empty. Return empty list.
return rectangles;
}
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, trackDesc.pfstrack, out trackDetails));
// There might be possibility to get empty track, skip the track
// in such case.
if (trackDetails.cParas != 0)
{
// Get list of paragraphs
PTS.FSPARADESCRIPTION[] arrayParaDesc;
ParaListFromTrack(ptsContext, trackDesc.pfstrack, ref trackDetails, out arrayParaDesc);
// Check list of paragraphs for element
rectangles = GetRectanglesInParaList(ptsContext, e, start, length, arrayParaDesc);
}
return rectangles;
}
// -----------------------------------------------------------------
// Returns ArrayList of rectangles for the ContentElement e within the
// list of paragraphs. If the element is not found, returns empty list.
// start: int representing start offset of e
// length: int representing number of positions occupied by e
// -----------------------------------------------------------------
internal static List GetRectanglesInParaList(
PtsContext ptsContext,
ContentElement e,
int start,
int length,
PTS.FSPARADESCRIPTION[] arrayParaDesc)
{
List rectangles = new List();
for (int index = 0; index < arrayParaDesc.Length; index++)
{
BaseParaClient paraClient = ptsContext.HandleToObject(arrayParaDesc[index].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
if (start < paraClient.Paragraph.ParagraphEndCharacterPosition)
{
// Element lies within the paraClient boundaries.
rectangles = paraClient.GetRectangles(e, start, length);
// Rectangles collection should not be null for consistency
Invariant.Assert(rectangles != null);
if (rectangles.Count != 0)
{
// Element cannot span more than one para client in the same track, so we stop
// if the element is found and the rectangles are calculated
break;
}
}
}
return rectangles;
}
// ------------------------------------------------------------------
// Returns List of rectangles offset by x/y values.
// -----------------------------------------------------------------
internal static List OffsetRectangleList(List rectangleList, double xOffset, double yOffset)
{
List offsetRectangles = new List(rectangleList.Count);
for(int index = 0; index < rectangleList.Count; index++)
{
Rect rect = rectangleList[index];
rect.X += xOffset;
rect.Y += yOffset;
offsetRectangles.Add(rect);
}
return offsetRectangles;
}
#endregion GetRectangles Helpers
// ------------------------------------------------------------------
//
// Query Helpers
//
// ------------------------------------------------------------------
#region Query Helpers
// -----------------------------------------------------------------
// Retrieve section list from page.
// ------------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryPageSectionList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void SectionListFromPage(
PtsContext ptsContext,
IntPtr page,
ref PTS.FSPAGEDETAILS pageDetails,
out PTS.FSSECTIONDESCRIPTION [] arraySectionDesc)
{
arraySectionDesc = new PTS.FSSECTIONDESCRIPTION [pageDetails.u.complex.cSections];
int sectionCount;
fixed (PTS.FSSECTIONDESCRIPTION* rgSectionDesc = arraySectionDesc)
{
PTS.Validate(PTS.FsQueryPageSectionList(ptsContext.Context, page, pageDetails.u.complex.cSections,
rgSectionDesc, out sectionCount));
}
ErrorHandler.Assert(pageDetails.u.complex.cSections == sectionCount, ErrorHandler.PTSObjectsCountMismatch);
}
// -----------------------------------------------------------------
// Retrieve track (column) list from subpage.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQuerySubpageBasicColumnList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void TrackListFromSubpage(
PtsContext ptsContext,
IntPtr subpage,
ref PTS.FSSUBPAGEDETAILS subpageDetails,
out PTS.FSTRACKDESCRIPTION [] arrayTrackDesc)
{
arrayTrackDesc = new PTS.FSTRACKDESCRIPTION [subpageDetails.u.complex.cBasicColumns];
int trackCount;
fixed (PTS.FSTRACKDESCRIPTION* rgTrackDesc = arrayTrackDesc)
{
PTS.Validate(PTS.FsQuerySubpageBasicColumnList(ptsContext.Context, subpage, subpageDetails.u.complex.cBasicColumns,
rgTrackDesc, out trackCount));
}
ErrorHandler.Assert(subpageDetails.u.complex.cBasicColumns == trackCount, ErrorHandler.PTSObjectsCountMismatch);
}
// -----------------------------------------------------------------
// Retrieve track (column) list from section.
// ------------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQuerySectionBasicColumnList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void TrackListFromSection(
PtsContext ptsContext,
IntPtr section,
ref PTS.FSSECTIONDETAILS sectionDetails,
out PTS.FSTRACKDESCRIPTION [] arrayTrackDesc)
{
//
Debug.Assert(sectionDetails.u.withpagenotes.cSegmentDefinedColumnSpanAreas == 0);
Debug.Assert(sectionDetails.u.withpagenotes.cHeightDefinedColumnSpanAreas == 0);
arrayTrackDesc = new PTS.FSTRACKDESCRIPTION[sectionDetails.u.withpagenotes.cBasicColumns];
int trackCount;
fixed (PTS.FSTRACKDESCRIPTION* rgTrackDesc = arrayTrackDesc)
{
PTS.Validate(PTS.FsQuerySectionBasicColumnList(ptsContext.Context, section, sectionDetails.u.withpagenotes.cBasicColumns,
rgTrackDesc, out trackCount));
}
ErrorHandler.Assert(sectionDetails.u.withpagenotes.cBasicColumns == trackCount, ErrorHandler.PTSObjectsCountMismatch);
}
// -----------------------------------------------------------------
// Retrieve paragraph list from the track.
// ------------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryTrackParaList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void ParaListFromTrack(
PtsContext ptsContext,
IntPtr track,
ref PTS.FSTRACKDETAILS trackDetails,
out PTS.FSPARADESCRIPTION [] arrayParaDesc)
{
arrayParaDesc = new PTS.FSPARADESCRIPTION [trackDetails.cParas];
int paraCount;
fixed (PTS.FSPARADESCRIPTION* rgParaDesc = arrayParaDesc)
{
PTS.Validate(PTS.FsQueryTrackParaList(ptsContext.Context, track, trackDetails.cParas,
rgParaDesc, out paraCount));
}
ErrorHandler.Assert(trackDetails.cParas == paraCount, ErrorHandler.PTSObjectsCountMismatch);
}
// ------------------------------------------------------------------
// Retrieve paragraph list from the track.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQuerySubtrackParaList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void ParaListFromSubtrack(
PtsContext ptsContext,
IntPtr subtrack,
ref PTS.FSSUBTRACKDETAILS subtrackDetails,
out PTS.FSPARADESCRIPTION [] arrayParaDesc)
{
arrayParaDesc = new PTS.FSPARADESCRIPTION [subtrackDetails.cParas];
int paraCount;
fixed (PTS.FSPARADESCRIPTION* rgParaDesc = arrayParaDesc)
{
PTS.Validate(PTS.FsQuerySubtrackParaList(ptsContext.Context, subtrack, subtrackDetails.cParas,
rgParaDesc, out paraCount));
}
ErrorHandler.Assert(subtrackDetails.cParas == paraCount, ErrorHandler.PTSObjectsCountMismatch);
}
// ------------------------------------------------------------------
// Retrieve simple line list from the full text paragraph.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryLineListSingle,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void LineListSimpleFromTextPara(
PtsContext ptsContext,
IntPtr para,
ref PTS.FSTEXTDETAILSFULL textDetails,
out PTS.FSLINEDESCRIPTIONSINGLE [] arrayLineDesc)
{
arrayLineDesc = new PTS.FSLINEDESCRIPTIONSINGLE [textDetails.cLines];
int lineCount;
fixed (PTS.FSLINEDESCRIPTIONSINGLE* rgLineDesc = arrayLineDesc)
{
PTS.Validate(PTS.FsQueryLineListSingle(ptsContext.Context, para, textDetails.cLines,
rgLineDesc, out lineCount));
}
ErrorHandler.Assert(textDetails.cLines == lineCount, ErrorHandler.PTSObjectsCountMismatch);
}
// -----------------------------------------------------------------
// Retrieve composite line list from the full text paragraph.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryLineListComposite,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void LineListCompositeFromTextPara(
PtsContext ptsContext,
IntPtr para,
ref PTS.FSTEXTDETAILSFULL textDetails,
out PTS.FSLINEDESCRIPTIONCOMPOSITE [] arrayLineDesc)
{
arrayLineDesc = new PTS.FSLINEDESCRIPTIONCOMPOSITE [textDetails.cLines];
int lineCount;
fixed (PTS.FSLINEDESCRIPTIONCOMPOSITE* rgLineDesc = arrayLineDesc)
{
PTS.Validate(PTS.FsQueryLineListComposite(ptsContext.Context, para, textDetails.cLines,
rgLineDesc, out lineCount));
}
ErrorHandler.Assert(textDetails.cLines == lineCount, ErrorHandler.PTSObjectsCountMismatch);
}
// ------------------------------------------------------------------
// Retrieve line elements list from the composite line.
// -----------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryLineCompositeElementList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void LineElementListFromCompositeLine(
PtsContext ptsContext,
ref PTS.FSLINEDESCRIPTIONCOMPOSITE lineDesc,
out PTS.FSLINEELEMENT [] arrayLineElement)
{
arrayLineElement = new PTS.FSLINEELEMENT [lineDesc.cElements];
int lineElementCount;
fixed (PTS.FSLINEELEMENT* rgLineElement = arrayLineElement)
{
PTS.Validate(PTS.FsQueryLineCompositeElementList(ptsContext.Context, lineDesc.pline, lineDesc.cElements,
rgLineElement, out lineElementCount));
}
ErrorHandler.Assert(lineDesc.cElements == lineElementCount, ErrorHandler.PTSObjectsCountMismatch);
}
// ------------------------------------------------------------------
// Retrieve attached object list from the paragraph.
// ------------------------------------------------------------------
///
/// Critical, because:
/// a) calls Critical function PTS.FsQueryAttachedObjectList,
/// b) it is unsafe method.
///
[SecurityCritical]
internal static unsafe void AttachedObjectListFromParagraph(
PtsContext ptsContext,
IntPtr para,
int cAttachedObject,
out PTS.FSATTACHEDOBJECTDESCRIPTION [] arrayAttachedObjectDesc)
{
arrayAttachedObjectDesc = new PTS.FSATTACHEDOBJECTDESCRIPTION [cAttachedObject];
int attachedObjectCount;
fixed (PTS.FSATTACHEDOBJECTDESCRIPTION* rgAttachedObjectDesc = arrayAttachedObjectDesc)
{
PTS.Validate(PTS.FsQueryAttachedObjectList(ptsContext.Context, para, cAttachedObject, rgAttachedObjectDesc, out attachedObjectCount));
}
ErrorHandler.Assert(cAttachedObject == attachedObjectCount, ErrorHandler.PTSObjectsCountMismatch);
}
#endregion Query Helpers
// -----------------------------------------------------------------
//
// Misc Helpers
//
// ------------------------------------------------------------------
#region Misc Helpers
// -----------------------------------------------------------------
// Retrieve TextContentRange from PTS track.
// -----------------------------------------------------------------
///
/// Critical:
/// a) calls Critical function PTS.FsQueryTrackDetails.
/// b) calls Critical function ParaListFromTrack.
///
[SecurityCritical]
internal static TextContentRange TextContentRangeFromTrack(
PtsContext ptsContext,
IntPtr pfstrack)
{
// Get track details
PTS.FSTRACKDETAILS trackDetails;
PTS.Validate(PTS.FsQueryTrackDetails(ptsContext.Context, pfstrack, out trackDetails));
// Combine ranges from all nested paragraphs.
TextContentRange textContentRange = new TextContentRange();
if (trackDetails.cParas != 0)
{
PTS.FSPARADESCRIPTION[] arrayParaDesc;
PtsHelper.ParaListFromTrack(ptsContext, pfstrack, ref trackDetails, out arrayParaDesc);
// Merge TextContentRanges for all paragraphs
BaseParaClient paraClient;
for (int i = 0; i < arrayParaDesc.Length; i++)
{
paraClient = ptsContext.HandleToObject(arrayParaDesc[i].pfsparaclient) as BaseParaClient;
PTS.ValidateHandle(paraClient);
textContentRange.Merge(paraClient.GetTextContentRange());
}
}
return textContentRange;
}
// -----------------------------------------------------------------
// Calculates a page margin adjustment to eliminate free space if column width is not flexible
// ------------------------------------------------------------------
internal static double CalculatePageMarginAdjustment(StructuralCache structuralCache, double pageMarginWidth)
{
double pageMarginAdjustment = 0.0;
DependencyObject o = structuralCache.Section.Element;
if(o is FlowDocument)
{
ColumnPropertiesGroup columnProperties = new ColumnPropertiesGroup(o);
if(!columnProperties.IsColumnWidthFlexible)
{
double lineHeight = DynamicPropertyReader.GetLineHeightValue(o);
double pageFontSize = (double)structuralCache.PropertyOwner.GetValue(Block.FontSizeProperty);
FontFamily pageFontFamily = (FontFamily)structuralCache.PropertyOwner.GetValue(Block.FontFamilyProperty);
int ccol = PtsHelper.CalculateColumnCount(columnProperties, lineHeight, pageMarginWidth, pageFontSize, pageFontFamily, true);
double columnWidth;
double freeSpace;
double gap;
GetColumnMetrics(columnProperties, pageMarginWidth,
pageFontSize, pageFontFamily, true, ccol,
ref lineHeight, out columnWidth, out freeSpace, out gap);
pageMarginAdjustment = freeSpace;
}
}
return pageMarginAdjustment;
}
// -----------------------------------------------------------------
// Calculate column count based on column properties.
// If column width is Auto column count is calculated by assuming
// ColumnWidth as 20*FontSize
// ------------------------------------------------------------------
internal static int CalculateColumnCount(
ColumnPropertiesGroup columnProperties,
double lineHeight,
double pageWidth,
double pageFontSize,
FontFamily pageFontFamily,
bool enableColumns)
{
int columns = 1;
double gap;
double rule = columnProperties.ColumnRuleWidth;
if (enableColumns)
{
if (columnProperties.ColumnGapAuto)
{
gap = 1 * lineHeight;
}
else
{
gap = columnProperties.ColumnGap;
}
if (!columnProperties.ColumnWidthAuto)
{
// Column count is ignored in this case
double column = columnProperties.ColumnWidth;
columns = (int)((pageWidth + gap) / (column + gap));
}
else
{
// Column width is assumed to be 20*FontSize
double column = 20 * pageFontSize;
columns = (int)((pageWidth + gap) / (column + gap));
}
}
return Math.Max(1, Math.Min(PTS.Restrictions.tscColumnRestriction-1, columns)); // at least 1 column is required
}
// ------------------------------------------------------------------
// GetColumnMetrics
// -----------------------------------------------------------------
internal static void GetColumnMetrics(ColumnPropertiesGroup columnProperties,
double pageWidth,
double pageFontSize,
FontFamily pageFontFamily,
bool enableColumns,
int cColumns,
ref double lineHeight,
out double columnWidth,
out double freeSpace,
out double gapSpace)
{
double rule = columnProperties.ColumnRuleWidth;
if (!enableColumns)
{
Invariant.Assert(cColumns == 1);
columnWidth = pageWidth;
gapSpace = 0;
lineHeight = 0;
freeSpace = 0;
}
else
{
// For FlowDocument, calculate default column width
if (columnProperties.ColumnWidthAuto)
{
columnWidth = 20 * pageFontSize;
}
else
{
columnWidth = columnProperties.ColumnWidth;
}
if (columnProperties.ColumnGapAuto)
{
gapSpace = 1 * lineHeight;
}
else
{
gapSpace = columnProperties.ColumnGap;
}
}
columnWidth = Math.Max(1, Math.Min(columnWidth, pageWidth));
freeSpace = pageWidth - (cColumns * columnWidth) - (cColumns - 1) * gapSpace;
freeSpace = Math.Max(0, freeSpace);
}
// ------------------------------------------------------------------
// Get columns info
// -----------------------------------------------------------------
///
/// Critical, because it is unsafe method.
///
[SecurityCritical]
internal static unsafe void GetColumnsInfo(
ColumnPropertiesGroup columnProperties,
double lineHeight,
double pageWidth,
double pageFontSize,
FontFamily pageFontFamily,
int cColumns,
PTS.FSCOLUMNINFO* pfscolinfo,
bool enableColumns)
{
Debug.Assert(cColumns > 0, "At least one column is required.");
double columnWidth;
double freeSpace;
double gap;
double rule = columnProperties.ColumnRuleWidth;
GetColumnMetrics(columnProperties, pageWidth,
pageFontSize, pageFontFamily, enableColumns, cColumns,
ref lineHeight, out columnWidth, out freeSpace, out gap);
// Set columns information
if (!columnProperties.IsColumnWidthFlexible)
{
// All columns have the declared width
// ColumnGap is flexible and is increased based on ColumnSpaceDistribution policy
// (ColumnGap is effectively min)
for (int i = 0; i < cColumns; i++)
{
// Today there is no way to change the default value of ColumnSpaceDistribution.
// If column widths are not flexible, always allocate unused space on the right side.
pfscolinfo[i].durBefore = TextDpi.ToTextDpi((i == 0) ? 0 : gap);
pfscolinfo[i].durWidth = TextDpi.ToTextDpi(columnWidth);
// ColumnWidth has to be > 0 and SpaceBefore has to be >= 0
pfscolinfo[i].durBefore = Math.Max(0, pfscolinfo[i].durBefore);
pfscolinfo[i].durWidth = Math.Max(1, pfscolinfo[i].durWidth);
}
}
else
{
// ColumnGap is honored
// ColumnWidth is effectively min, and space is distributed according to ColumnSpaceDistribution policy
for (int i = 0; i < cColumns; i++)
{
if (columnProperties.ColumnSpaceDistribution == ColumnSpaceDistribution.Right)
{
pfscolinfo[i].durWidth = TextDpi.ToTextDpi((i == cColumns - 1) ? columnWidth + freeSpace : columnWidth);
}
else if (columnProperties.ColumnSpaceDistribution == ColumnSpaceDistribution.Left)
{
pfscolinfo[i].durWidth = TextDpi.ToTextDpi((i == 0) ? columnWidth + freeSpace : columnWidth);
}
else
{
pfscolinfo[i].durWidth = TextDpi.ToTextDpi(columnWidth + (freeSpace / cColumns));
}
// If calculated column width is greater than the page width, set it to page width to
// avoid clipping
if (pfscolinfo[i].durWidth > TextDpi.ToTextDpi(pageWidth))
{
pfscolinfo[i].durWidth = TextDpi.ToTextDpi(pageWidth);
}
pfscolinfo[i].durBefore = TextDpi.ToTextDpi((i == 0) ? 0 : gap);
// ColumnWidth has to be > 0 and SpaceBefore has to be >= 0
pfscolinfo[i].durBefore = Math.Max(0, pfscolinfo[i].durBefore);
pfscolinfo[i].durWidth = Math.Max(1, pfscolinfo[i].durWidth);
}
}
}
#endregion Misc Helpers
}
}
// 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
- CompositeFontParser.cs
- AuthorizationSection.cs
- ComboBoxItem.cs
- KeyValueSerializer.cs
- WebPartDescription.cs
- PersistenceProviderElement.cs
- AutomationIdentifier.cs
- KeyNotFoundException.cs
- ResourceDefaultValueAttribute.cs
- ApplicationId.cs
- Regex.cs
- x509utils.cs
- CellParaClient.cs
- ZipIOFileItemStream.cs
- ClientData.cs
- PasswordRecoveryAutoFormat.cs
- XpsFilter.cs
- ImageSourceConverter.cs
- UmAlQuraCalendar.cs
- RectAnimation.cs
- DispatchWrapper.cs
- FilePrompt.cs
- PropertyEntry.cs
- ReplyAdapterChannelListener.cs
- SafeFileMappingHandle.cs
- Compiler.cs
- GeneralTransform3DTo2DTo3D.cs
- TextDocumentView.cs
- MetaForeignKeyColumn.cs
- HideDisabledControlAdapter.cs
- CustomLineCap.cs
- ClientUrlResolverWrapper.cs
- ItemCollection.cs
- PKCS1MaskGenerationMethod.cs
- Attributes.cs
- WebPartVerbCollection.cs
- Int16Animation.cs
- FixUp.cs
- PassportAuthenticationEventArgs.cs
- LayoutEditorPart.cs
- JsonWriterDelegator.cs
- RawMouseInputReport.cs
- IncrementalReadDecoders.cs
- SmiEventSink_DeferedProcessing.cs
- ChannelServices.cs
- ActivityDesignerHelper.cs
- RegexGroupCollection.cs
- LinqDataSourceUpdateEventArgs.cs
- Html32TextWriter.cs
- FormViewAutoFormat.cs
- RequestCachePolicy.cs
- CleanUpVirtualizedItemEventArgs.cs
- RTLAwareMessageBox.cs
- EntityWrapper.cs
- DispatcherEventArgs.cs
- DataReceivedEventArgs.cs
- Context.cs
- QuadraticEase.cs
- MouseDevice.cs
- ProcessThread.cs
- BuildProvidersCompiler.cs
- XsltLoader.cs
- ColumnPropertiesGroup.cs
- ControlType.cs
- UIElementIsland.cs
- FunctionParameter.cs
- SystemWebSectionGroup.cs
- WindowsFormsSectionHandler.cs
- SmiConnection.cs
- SmiRecordBuffer.cs
- securestring.cs
- SmiXetterAccessMap.cs
- HotCommands.cs
- ClientSponsor.cs
- IpcClientManager.cs
- UnsafeNativeMethods.cs
- BindingExpression.cs
- SweepDirectionValidation.cs
- LineServicesCallbacks.cs
- Menu.cs
- FontFamilyConverter.cs
- MenuEventArgs.cs
- TokenizerHelper.cs
- Timeline.cs
- FactoryGenerator.cs
- ClassHandlersStore.cs
- DBSchemaRow.cs
- CharEntityEncoderFallback.cs
- TextBlockAutomationPeer.cs
- StatusBarPanel.cs
- EnglishPluralizationService.cs
- WebPartEventArgs.cs
- RelationshipConstraintValidator.cs
- InstanceContextManager.cs
- EntityDataSourceUtil.cs
- BitmapEffectrendercontext.cs
- FormDesigner.cs
- Subset.cs
- CustomTypeDescriptor.cs
- FrameDimension.cs