Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Core / CSharp / MS / Internal / TextFormatting / TextFormatterImp.cs / 1 / TextFormatterImp.cs
//+------------------------------------------------------------------------
//
// Microsoft Windows Client Platform
// Copyright (C) Microsoft Corporation
//
// File: TextFormatterImp.cs
//
// Contents: Text formatter implementation
//
// Created: 2-25-2003 Worachai Chaoweeraprasit (wchao)
//
//-----------------------------------------------------------------------
using System;
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media.TextFormatting;
using MS.Utility;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.Shaping;
#if !OPTIMALBREAK_API
using MS.Internal.PresentationCore;
#endif
namespace MS.Internal.TextFormatting
{
///
/// Implementation of TextFormatter
///
internal sealed class TextFormatterImp : TextFormatter
{
private FrugalStructList _contextList; // LS context free list
private double _toIdeal; // scaling factor from client's real space to LS ideal resolution
private double _toReal; // scaling factor from LS ideal resolution to client's real space
private bool _multipleContextProhibited; // prohibit multiple contexts within the same formatter
private GlyphingCache _glyphingCache; // Glyphing cache for font linking process
private const int MaxGlyphingCacheCapacity = 16;
///
/// Construct an instance of TextFormatter implementation
///
internal TextFormatterImp() : this(null)
{}
///
/// Construct an instance of TextFormatter implementation with the specified context
///
///
///
/// TextFormatter created via this special ctor takes a specified context and uses it as the only known
/// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only
/// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
/// version of PTLS.
///
internal TextFormatterImp(TextFormatterContext soleContext)
{
_toIdeal = Constants.DefaultRealToIdeal;
_toReal = Constants.DefaultIdealToReal;
if (soleContext != null)
_contextList.Add(soleContext);
_multipleContextProhibited = (_contextList.Count != 0);
}
///
/// Finalizing text formatter
///
~TextFormatterImp()
{
CleanupInternal();
}
///
/// Release all unmanaged LS contexts
///
public override void Dispose()
{
CleanupInternal();
base.Dispose();
GC.SuppressFinalize(this);
}
///
/// Release all unmanaged LS contexts
///
private void CleanupInternal()
{
for (int i = 0; i < _contextList.Count; i++)
{
_contextList[i].Destroy();
}
_contextList.Clear();
}
///
/// Client to format a text line that fills a paragraph in the document.
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// object representing a line of text that client interacts with.
public override TextLine FormatLine(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
0, // lineLength
paragraphWidth,
paragraphProperties,
previousLineBreak,
new TextRunCache() // local cache, only live within this call
);
}
///
/// Client to format a text line that fills a paragraph in the document.
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
public override TextLine FormatLine(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
0, // lineLength
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache
);
}
///
/// Client to reconstruct a previously formatted text line
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// character length of the line
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
#if OPTIMALBREAK_API
public override TextLine RecreateLine(
#else
internal override TextLine RecreateLine(
#endif
TextSource textSource,
int firstCharIndex,
int lineLength,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
lineLength,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache
);
}
///
/// Format and produce a text line either with or without previously known
/// line break point.
///
private TextLine FormatLineInternal(
TextSource textSource,
int firstCharIndex,
int lineLength,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
{
EventTrace.EventProvider.TraceEvent(
EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID),
EventType.StartEvent,
"TextFormatterImp.FormatLineInternal Start"
);
}
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache,
(lineLength != 0), // Do optimal break if break is given
true // isSingleLineFormatting
);
TextLine textLine = null;
if ( !settings.Pap.AlwaysCollapsible
&& previousLineBreak == null
&& lineLength <= 0
)
{
// simple text line.
textLine = SimpleTextLine.Create(
settings,
firstCharIndex,
RealToIdealFloor(paragraphWidth)
) as TextLine;
}
if (textLine == null)
{
// content is complex, creating complex line
textLine = new TextMetrics.FullTextLine(
settings,
firstCharIndex,
lineLength,
RealToIdealFloor(paragraphWidth),
LineFlags.None
) as TextLine;
}
if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
{
EventTrace.EventProvider.TraceEvent(
EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID),
EventType.EndEvent,
"TextFormatterImp.FormatLineInternal End"
);
}
return textLine;
}
///
/// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// min max paragraph width
public override MinMaxParagraphWidth FormatMinMaxParagraphWidth(
TextSource textSource,
int firstCharIndex,
TextParagraphProperties paragraphProperties
)
{
return FormatMinMaxParagraphWidth(
textSource,
firstCharIndex,
paragraphProperties,
new TextRunCache() // local cache, only live within this call
);
}
///
/// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// an object representing content cache of the client.
/// min max paragraph width
public override MinMaxParagraphWidth FormatMinMaxParagraphWidth(
TextSource textSource,
int firstCharIndex,
TextParagraphProperties paragraphProperties,
TextRunCache textRunCache
)
{
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
0, // infinite paragraphWidth
paragraphProperties,
null, // always format the whole paragraph - no previousLineBreak
textRunCache,
false, // optimalBreak
true // isSingleLineFormatting
);
// create specialized line specifically for min/max calculation
TextMetrics.FullTextLine line = new TextMetrics.FullTextLine(
settings,
firstCharIndex,
0, // lineLength
0, // paragraph width has no significant meaning in min/max calculation
(LineFlags.KeepState | LineFlags.MinMax)
);
// line width in this case is the width of a line when the entire paragraph is laid out
// as a single long line.
MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width);
line.Dispose();
return minMax;
}
///
/// Client to cache information about a paragraph to be used during optimal paragraph line formatting
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// text formatting state at the point where the previous line in the paragraph
/// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous
/// line; this parameter can be null, and will always be null for the first line in a paragraph.
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
#if OPTIMALBREAK_API
public override TextParagraphCache CreateParagraphCache(
#else
internal override TextParagraphCache CreateParagraphCache(
#endif
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache,
true, // optimalBreak
false // !isSingleLineFormatting
);
//
// Optimal paragraph formatting session specific check
//
if (!settings.Pap.Wrap && settings.Pap.OptimalBreak)
{
// Optimal paragraph must wrap.
throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap));
}
// create paragraph content cache object
return new TextParagraphCache(
settings,
firstCharIndex,
RealToIdeal(paragraphWidth)
);
}
///
/// Validate all the relevant text formatting initial settings and package them
///
private FormatSettings PrepareFormatSettings(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache,
bool useOptimalBreak,
bool isSingleLineFormatting
)
{
VerifyTextFormattingArguments(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
textRunCache
);
if (textRunCache.Imp == null)
{
// No run cache object available, create one
textRunCache.Imp = new TextRunCacheImp();
}
// initialize formatting settings
return new FormatSettings(
this,
textSource,
textRunCache.Imp,
new ParaProp(this, paragraphProperties, useOptimalBreak),
previousLineBreak,
isSingleLineFormatting
);
}
///
/// Verify all text formatting arguments
///
private void VerifyTextFormattingArguments(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextRunCache textRunCache
)
{
if (textSource == null)
throw new ArgumentNullException("textSource");
if (textRunCache == null)
throw new ArgumentNullException("textRunCache");
if (paragraphProperties == null)
throw new ArgumentNullException("paragraphProperties");
if (paragraphProperties.DefaultTextRunProperties == null)
throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties");
if (paragraphProperties.DefaultTextRunProperties.Typeface == null)
throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface");
if (DoubleUtil.IsNaN(paragraphWidth))
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN));
if (double.IsInfinity(paragraphWidth))
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity));
double realInfiniteWidth = IdealToReal(Constants.InfiniteWidth);
if ( paragraphWidth < 0
|| paragraphWidth > realInfiniteWidth)
{
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth));
}
double realMaxFontRenderingEmSize = realInfiniteWidth / Constants.GreatestMutiplierOfEm;
if ( paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0
|| paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize)
{
throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize));
}
if (paragraphProperties.Indent > realInfiniteWidth)
throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth));
if (paragraphProperties.LineHeight > realInfiniteWidth)
throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth));
if ( paragraphProperties.DefaultIncrementalTab < 0
|| paragraphProperties.DefaultIncrementalTab > realInfiniteWidth)
{
throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth));
}
}
///
/// Validate the input character hit
///
internal static void VerifyCaretCharacterHit(
CharacterHit characterHit,
int cpFirst,
int cchLength
)
{
if ( characterHit.FirstCharacterIndex < cpFirst
|| characterHit.FirstCharacterIndex > cpFirst + cchLength)
{
throw new ArgumentOutOfRangeException("First", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength));
}
if (characterHit.TrailingLength < 0)
{
throw new ArgumentOutOfRangeException("Length", SR.Get(SRID.ParameterCannotBeNegative));
}
}
///
/// Acquire a free TextFormatter context for complex line operation
///
/// object that becomes the owner of LS context once acquired
/// matching PLOC
/// Active LS context
///
/// Critical - this sets the owner of the context
/// Safe - this doesn't expose critical info
///
[SecurityCritical, SecurityTreatAsSafe]
internal TextFormatterContext AcquireContext(
object owner,
IntPtr ploc
)
{
Invariant.Assert(owner != null);
TextFormatterContext context = null;
int c;
int contextCount = _contextList.Count;
for (c = 0; c < contextCount; c++)
{
context = (TextFormatterContext)_contextList[c];
if (ploc == IntPtr.Zero)
{
if(context.Owner == null)
break;
}
else if (ploc == context.Ploc.Value)
{
// LS requires that we use the exact same context for line
// destruction or hittesting (part of the reason is that LS
// actually caches some run info in the context). So here
// we use the actual PLSC as the context signature so we
// locate the one we want.
Debug.Assert(context.Owner == null);
break;
}
}
if (c == contextCount)
{
if (contextCount == 0 || !_multipleContextProhibited)
{
// no free one exists, create a new one
context = new TextFormatterContext();
_contextList.Add(context);
}
else
{
// This instance of TextFormatter only allows a single context, reentering the
// same TextFormatter in this case is not allowed.
//
// This requirement is currently enforced only during optimal break computation.
// Client implementing nesting of optimal break content inside another must create
// a separate TextFormatter instance for each content in different nesting level.
throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited));
}
}
Debug.Assert(context != null);
context.Owner = owner;
return context;
}
///
/// Create an anti-inversion transform from the inversion flags.
/// The result is used to correct glyph bitmap on an output to
/// a drawing surface with the specified inversions applied on.
///
internal static MatrixTransform CreateAntiInversionTransform(
InvertAxes inversion,
double paragraphWidth,
double lineHeight
)
{
if (inversion == InvertAxes.None)
{
// avoid creating unncessary pressure on GC when anti-transform is not needed.
return null;
}
double m11 = 1;
double m22 = 1;
double offsetX = 0;
double offsetY = 0;
if ((inversion & InvertAxes.Horizontal) != 0)
{
m11 = -m11;
offsetX = paragraphWidth;
}
if ((inversion & InvertAxes.Vertical) != 0)
{
m22 = -m22;
offsetY = lineHeight;
}
return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY);
}
///
/// Scale LS ideal resolution value to real value
///
internal double IdealToReal(int i)
{
return i * _toReal;
}
///
/// Scale real value to LS ideal resolution
///
internal int RealToIdeal(double i)
{
return (int) Math.Round(i * _toIdeal);
}
///
/// Scale the real value to LS ideal resolution
/// Use the floor value of the scale value
///
///
/// Using Math.Round may result in a line larger than
/// the actual given paragraph width. For example,
/// round tripping 100.112 with factor 300 becomes 100.1133...
/// Using floor to ensure we never go beyond paragraph width
///
internal int RealToIdealFloor(double i)
{
return (int) Math.Floor(i * _toIdeal);
}
///
/// Ideal to real value scaling factor
///
internal double ToReal
{
get { return _toReal; }
}
///
/// Real to ideal value scaling factor
///
internal double ToIdeal
{
get { return _toIdeal; }
}
///
/// Return the GlyphingCache associated with this TextFormatterImp object.
/// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is
/// used to display it.
///
internal GlyphingCache GlyphingCache
{
get
{
if (_glyphingCache == null)
{
_glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity);
}
return _glyphingCache;
}
}
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//+------------------------------------------------------------------------
//
// Microsoft Windows Client Platform
// Copyright (C) Microsoft Corporation
//
// File: TextFormatterImp.cs
//
// Contents: Text formatter implementation
//
// Created: 2-25-2003 Worachai Chaoweeraprasit (wchao)
//
//-----------------------------------------------------------------------
using System;
using System.Security;
using System.Windows;
using System.Windows.Media;
using System.Windows.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows.Media.TextFormatting;
using MS.Utility;
using SR=MS.Internal.PresentationCore.SR;
using SRID=MS.Internal.PresentationCore.SRID;
using MS.Internal.Shaping;
#if !OPTIMALBREAK_API
using MS.Internal.PresentationCore;
#endif
namespace MS.Internal.TextFormatting
{
///
/// Implementation of TextFormatter
///
internal sealed class TextFormatterImp : TextFormatter
{
private FrugalStructList _contextList; // LS context free list
private double _toIdeal; // scaling factor from client's real space to LS ideal resolution
private double _toReal; // scaling factor from LS ideal resolution to client's real space
private bool _multipleContextProhibited; // prohibit multiple contexts within the same formatter
private GlyphingCache _glyphingCache; // Glyphing cache for font linking process
private const int MaxGlyphingCacheCapacity = 16;
///
/// Construct an instance of TextFormatter implementation
///
internal TextFormatterImp() : this(null)
{}
///
/// Construct an instance of TextFormatter implementation with the specified context
///
///
///
/// TextFormatter created via this special ctor takes a specified context and uses it as the only known
/// context within its entire lifetime. It prohibits reentering of TextFormatter during formatting as only
/// one context is allowed. This restriction is critical to the optimal break algorithm supported by the current
/// version of PTLS.
///
internal TextFormatterImp(TextFormatterContext soleContext)
{
_toIdeal = Constants.DefaultRealToIdeal;
_toReal = Constants.DefaultIdealToReal;
if (soleContext != null)
_contextList.Add(soleContext);
_multipleContextProhibited = (_contextList.Count != 0);
}
///
/// Finalizing text formatter
///
~TextFormatterImp()
{
CleanupInternal();
}
///
/// Release all unmanaged LS contexts
///
public override void Dispose()
{
CleanupInternal();
base.Dispose();
GC.SuppressFinalize(this);
}
///
/// Release all unmanaged LS contexts
///
private void CleanupInternal()
{
for (int i = 0; i < _contextList.Count; i++)
{
_contextList[i].Destroy();
}
_contextList.Clear();
}
///
/// Client to format a text line that fills a paragraph in the document.
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// object representing a line of text that client interacts with.
public override TextLine FormatLine(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
0, // lineLength
paragraphWidth,
paragraphProperties,
previousLineBreak,
new TextRunCache() // local cache, only live within this call
);
}
///
/// Client to format a text line that fills a paragraph in the document.
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
public override TextLine FormatLine(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
0, // lineLength
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache
);
}
///
/// Client to reconstruct a previously formatted text line
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// character length of the line
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// LineBreak property of the previous text line, or null if this is the first line in the paragraph
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
#if OPTIMALBREAK_API
public override TextLine RecreateLine(
#else
internal override TextLine RecreateLine(
#endif
TextSource textSource,
int firstCharIndex,
int lineLength,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
return FormatLineInternal(
textSource,
firstCharIndex,
lineLength,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache
);
}
///
/// Format and produce a text line either with or without previously known
/// line break point.
///
private TextLine FormatLineInternal(
TextSource textSource,
int firstCharIndex,
int lineLength,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
{
EventTrace.EventProvider.TraceEvent(
EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID),
EventType.StartEvent,
"TextFormatterImp.FormatLineInternal Start"
);
}
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache,
(lineLength != 0), // Do optimal break if break is given
true // isSingleLineFormatting
);
TextLine textLine = null;
if ( !settings.Pap.AlwaysCollapsible
&& previousLineBreak == null
&& lineLength <= 0
)
{
// simple text line.
textLine = SimpleTextLine.Create(
settings,
firstCharIndex,
RealToIdealFloor(paragraphWidth)
) as TextLine;
}
if (textLine == null)
{
// content is complex, creating complex line
textLine = new TextMetrics.FullTextLine(
settings,
firstCharIndex,
lineLength,
RealToIdealFloor(paragraphWidth),
LineFlags.None
) as TextLine;
}
if (EventTrace.IsEnabled(EventTrace.Flags.performance, EventTrace.Level.verbose))
{
EventTrace.EventProvider.TraceEvent(
EventTrace.GuidFromId(EventTraceGuidId.GENERICSTRINGGUID),
EventType.EndEvent,
"TextFormatterImp.FormatLineInternal End"
);
}
return textLine;
}
///
/// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// min max paragraph width
public override MinMaxParagraphWidth FormatMinMaxParagraphWidth(
TextSource textSource,
int firstCharIndex,
TextParagraphProperties paragraphProperties
)
{
return FormatMinMaxParagraphWidth(
textSource,
firstCharIndex,
paragraphProperties,
new TextRunCache() // local cache, only live within this call
);
}
///
/// Client to ask for the possible smallest and largest paragraph width that can fully contain the passing text content
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// an object representing content cache of the client.
/// min max paragraph width
public override MinMaxParagraphWidth FormatMinMaxParagraphWidth(
TextSource textSource,
int firstCharIndex,
TextParagraphProperties paragraphProperties,
TextRunCache textRunCache
)
{
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
0, // infinite paragraphWidth
paragraphProperties,
null, // always format the whole paragraph - no previousLineBreak
textRunCache,
false, // optimalBreak
true // isSingleLineFormatting
);
// create specialized line specifically for min/max calculation
TextMetrics.FullTextLine line = new TextMetrics.FullTextLine(
settings,
firstCharIndex,
0, // lineLength
0, // paragraph width has no significant meaning in min/max calculation
(LineFlags.KeepState | LineFlags.MinMax)
);
// line width in this case is the width of a line when the entire paragraph is laid out
// as a single long line.
MinMaxParagraphWidth minMax = new MinMaxParagraphWidth(line.MinWidth, line.Width);
line.Dispose();
return minMax;
}
///
/// Client to cache information about a paragraph to be used during optimal paragraph line formatting
///
/// an object representing text layout clients text source for TextFormatter.
/// character index to specify where in the source text the line starts
/// width of paragraph in which the line fills
/// properties that can change from one paragraph to the next, such as text flow direction, text alignment, or indentation.
/// text formatting state at the point where the previous line in the paragraph
/// was broken by the text formatting process, as specified by the TextLine.LineBreak property for the previous
/// line; this parameter can be null, and will always be null for the first line in a paragraph.
/// an object representing content cache of the client.
/// object representing a line of text that client interacts with.
#if OPTIMALBREAK_API
public override TextParagraphCache CreateParagraphCache(
#else
internal override TextParagraphCache CreateParagraphCache(
#endif
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache
)
{
// prepare formatting settings
FormatSettings settings = PrepareFormatSettings(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
previousLineBreak,
textRunCache,
true, // optimalBreak
false // !isSingleLineFormatting
);
//
// Optimal paragraph formatting session specific check
//
if (!settings.Pap.Wrap && settings.Pap.OptimalBreak)
{
// Optimal paragraph must wrap.
throw new ArgumentException(SR.Get(SRID.OptimalParagraphMustWrap));
}
// create paragraph content cache object
return new TextParagraphCache(
settings,
firstCharIndex,
RealToIdeal(paragraphWidth)
);
}
///
/// Validate all the relevant text formatting initial settings and package them
///
private FormatSettings PrepareFormatSettings(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextLineBreak previousLineBreak,
TextRunCache textRunCache,
bool useOptimalBreak,
bool isSingleLineFormatting
)
{
VerifyTextFormattingArguments(
textSource,
firstCharIndex,
paragraphWidth,
paragraphProperties,
textRunCache
);
if (textRunCache.Imp == null)
{
// No run cache object available, create one
textRunCache.Imp = new TextRunCacheImp();
}
// initialize formatting settings
return new FormatSettings(
this,
textSource,
textRunCache.Imp,
new ParaProp(this, paragraphProperties, useOptimalBreak),
previousLineBreak,
isSingleLineFormatting
);
}
///
/// Verify all text formatting arguments
///
private void VerifyTextFormattingArguments(
TextSource textSource,
int firstCharIndex,
double paragraphWidth,
TextParagraphProperties paragraphProperties,
TextRunCache textRunCache
)
{
if (textSource == null)
throw new ArgumentNullException("textSource");
if (textRunCache == null)
throw new ArgumentNullException("textRunCache");
if (paragraphProperties == null)
throw new ArgumentNullException("paragraphProperties");
if (paragraphProperties.DefaultTextRunProperties == null)
throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties");
if (paragraphProperties.DefaultTextRunProperties.Typeface == null)
throw new ArgumentNullException("paragraphProperties.DefaultTextRunProperties.Typeface");
if (DoubleUtil.IsNaN(paragraphWidth))
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeNaN));
if (double.IsInfinity(paragraphWidth))
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterValueCannotBeInfinity));
double realInfiniteWidth = IdealToReal(Constants.InfiniteWidth);
if ( paragraphWidth < 0
|| paragraphWidth > realInfiniteWidth)
{
throw new ArgumentOutOfRangeException("paragraphWidth", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth));
}
double realMaxFontRenderingEmSize = realInfiniteWidth / Constants.GreatestMutiplierOfEm;
if ( paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize < 0
|| paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize > realMaxFontRenderingEmSize)
{
throw new ArgumentOutOfRangeException("paragraphProperties.DefaultTextRunProperties.FontRenderingEmSize", SR.Get(SRID.ParameterMustBeBetween, 0, realMaxFontRenderingEmSize));
}
if (paragraphProperties.Indent > realInfiniteWidth)
throw new ArgumentOutOfRangeException("paragraphProperties.Indent", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth));
if (paragraphProperties.LineHeight > realInfiniteWidth)
throw new ArgumentOutOfRangeException("paragraphProperties.LineHeight", SR.Get(SRID.ParameterCannotBeGreaterThan, realInfiniteWidth));
if ( paragraphProperties.DefaultIncrementalTab < 0
|| paragraphProperties.DefaultIncrementalTab > realInfiniteWidth)
{
throw new ArgumentOutOfRangeException("paragraphProperties.DefaultIncrementalTab", SR.Get(SRID.ParameterMustBeBetween, 0, realInfiniteWidth));
}
}
///
/// Validate the input character hit
///
internal static void VerifyCaretCharacterHit(
CharacterHit characterHit,
int cpFirst,
int cchLength
)
{
if ( characterHit.FirstCharacterIndex < cpFirst
|| characterHit.FirstCharacterIndex > cpFirst + cchLength)
{
throw new ArgumentOutOfRangeException("First", SR.Get(SRID.ParameterMustBeBetween, cpFirst, cpFirst + cchLength));
}
if (characterHit.TrailingLength < 0)
{
throw new ArgumentOutOfRangeException("Length", SR.Get(SRID.ParameterCannotBeNegative));
}
}
///
/// Acquire a free TextFormatter context for complex line operation
///
/// object that becomes the owner of LS context once acquired
/// matching PLOC
/// Active LS context
///
/// Critical - this sets the owner of the context
/// Safe - this doesn't expose critical info
///
[SecurityCritical, SecurityTreatAsSafe]
internal TextFormatterContext AcquireContext(
object owner,
IntPtr ploc
)
{
Invariant.Assert(owner != null);
TextFormatterContext context = null;
int c;
int contextCount = _contextList.Count;
for (c = 0; c < contextCount; c++)
{
context = (TextFormatterContext)_contextList[c];
if (ploc == IntPtr.Zero)
{
if(context.Owner == null)
break;
}
else if (ploc == context.Ploc.Value)
{
// LS requires that we use the exact same context for line
// destruction or hittesting (part of the reason is that LS
// actually caches some run info in the context). So here
// we use the actual PLSC as the context signature so we
// locate the one we want.
Debug.Assert(context.Owner == null);
break;
}
}
if (c == contextCount)
{
if (contextCount == 0 || !_multipleContextProhibited)
{
// no free one exists, create a new one
context = new TextFormatterContext();
_contextList.Add(context);
}
else
{
// This instance of TextFormatter only allows a single context, reentering the
// same TextFormatter in this case is not allowed.
//
// This requirement is currently enforced only during optimal break computation.
// Client implementing nesting of optimal break content inside another must create
// a separate TextFormatter instance for each content in different nesting level.
throw new InvalidOperationException(SR.Get(SRID.TextFormatterReentranceProhibited));
}
}
Debug.Assert(context != null);
context.Owner = owner;
return context;
}
///
/// Create an anti-inversion transform from the inversion flags.
/// The result is used to correct glyph bitmap on an output to
/// a drawing surface with the specified inversions applied on.
///
internal static MatrixTransform CreateAntiInversionTransform(
InvertAxes inversion,
double paragraphWidth,
double lineHeight
)
{
if (inversion == InvertAxes.None)
{
// avoid creating unncessary pressure on GC when anti-transform is not needed.
return null;
}
double m11 = 1;
double m22 = 1;
double offsetX = 0;
double offsetY = 0;
if ((inversion & InvertAxes.Horizontal) != 0)
{
m11 = -m11;
offsetX = paragraphWidth;
}
if ((inversion & InvertAxes.Vertical) != 0)
{
m22 = -m22;
offsetY = lineHeight;
}
return new MatrixTransform(m11, 0, 0, m22, offsetX, offsetY);
}
///
/// Scale LS ideal resolution value to real value
///
internal double IdealToReal(int i)
{
return i * _toReal;
}
///
/// Scale real value to LS ideal resolution
///
internal int RealToIdeal(double i)
{
return (int) Math.Round(i * _toIdeal);
}
///
/// Scale the real value to LS ideal resolution
/// Use the floor value of the scale value
///
///
/// Using Math.Round may result in a line larger than
/// the actual given paragraph width. For example,
/// round tripping 100.112 with factor 300 becomes 100.1133...
/// Using floor to ensure we never go beyond paragraph width
///
internal int RealToIdealFloor(double i)
{
return (int) Math.Floor(i * _toIdeal);
}
///
/// Ideal to real value scaling factor
///
internal double ToReal
{
get { return _toReal; }
}
///
/// Real to ideal value scaling factor
///
internal double ToIdeal
{
get { return _toIdeal; }
}
///
/// Return the GlyphingCache associated with this TextFormatterImp object.
/// GlyphingCache stores the mapping from Unicode scalar value to the physical font that is
/// used to display it.
///
internal GlyphingCache GlyphingCache
{
get
{
if (_glyphingCache == null)
{
_glyphingCache = new GlyphingCache(MaxGlyphingCacheCapacity);
}
return _glyphingCache;
}
}
}
}
// 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
- ControllableStoryboardAction.cs
- RsaSecurityTokenAuthenticator.cs
- PropertyChangedEventManager.cs
- BamlBinaryReader.cs
- ProcessModelInfo.cs
- Brush.cs
- TripleDES.cs
- DbBuffer.cs
- ScriptRegistrationManager.cs
- ResourceDisplayNameAttribute.cs
- CommandID.cs
- ImageIndexConverter.cs
- DataSourceCacheDurationConverter.cs
- Socket.cs
- CodePageUtils.cs
- DbConnectionPoolOptions.cs
- QuotedStringFormatReader.cs
- EnumDataContract.cs
- StylusPointCollection.cs
- DesignerForm.cs
- ConditionalAttribute.cs
- PropertyItemInternal.cs
- DataGridColumnReorderingEventArgs.cs
- AttachedAnnotation.cs
- PartBasedPackageProperties.cs
- DataGridViewRowHeaderCell.cs
- FlowDocumentReader.cs
- EventProviderTraceListener.cs
- CallTemplateAction.cs
- ContextQuery.cs
- MsdtcClusterUtils.cs
- RestHandlerFactory.cs
- ObjectQueryState.cs
- _ScatterGatherBuffers.cs
- ZipIOExtraFieldPaddingElement.cs
- XPathDocument.cs
- XsltSettings.cs
- SqlNode.cs
- ThicknessAnimationUsingKeyFrames.cs
- FlowchartDesigner.Helpers.cs
- WorkerRequest.cs
- DesignerView.xaml.cs
- SchemaCollectionPreprocessor.cs
- Icon.cs
- KeyboardInputProviderAcquireFocusEventArgs.cs
- StrongNamePublicKeyBlob.cs
- CustomError.cs
- UIElementPropertyUndoUnit.cs
- AnyReturnReader.cs
- XNodeNavigator.cs
- translator.cs
- BaseAsyncResult.cs
- ToggleButtonAutomationPeer.cs
- ConfigurationSchemaErrors.cs
- FileSystemEventArgs.cs
- ThreadExceptionDialog.cs
- ClrPerspective.cs
- SingleAnimationUsingKeyFrames.cs
- Vars.cs
- WindowsEditBox.cs
- SystemDiagnosticsSection.cs
- SimpleApplicationHost.cs
- dataobject.cs
- ProxyWebPartManager.cs
- ByteFacetDescriptionElement.cs
- EntityClientCacheEntry.cs
- AxHost.cs
- FigureHelper.cs
- RegexInterpreter.cs
- TypeBuilder.cs
- ConfigurationException.cs
- AspNetSynchronizationContext.cs
- MonitoringDescriptionAttribute.cs
- ConditionalAttribute.cs
- RenderContext.cs
- SystemMulticastIPAddressInformation.cs
- objectresult_tresulttype.cs
- Application.cs
- ChannelTracker.cs
- PrintingPermissionAttribute.cs
- ArrayExtension.cs
- DetailsViewUpdatedEventArgs.cs
- FtpCachePolicyElement.cs
- ProcessModule.cs
- SelectingProviderEventArgs.cs
- ToolboxItem.cs
- Keyboard.cs
- RangeValuePatternIdentifiers.cs
- HMACSHA1.cs
- UriScheme.cs
- ZoomComboBox.cs
- Visitors.cs
- PinProtectionHelper.cs
- ListBoxItemAutomationPeer.cs
- MetadataUtil.cs
- CallTemplateAction.cs
- Themes.cs
- Splitter.cs
- ManualResetEvent.cs
- Clipboard.cs