Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / wpf / src / Framework / MS / Internal / documents / TextBoxLine.cs / 1 / TextBoxLine.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// File: TextBoxLine.cs
//
// Description: TextLine wrapper used by TextBoxView.
//
//---------------------------------------------------------------------------
using System;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using MS.Internal;
using MS.Internal.PtsHost;
using MS.Internal.Text;
namespace System.Windows.Controls
{
///
/// TextLine wrapper used by TextBoxView.
///
internal class TextBoxLine : TextSource, IDisposable
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Constructor.
///
/// Owner of the line.
internal TextBoxLine(TextBoxView owner)
{
_owner = owner;
}
#endregion Constructors
// ------------------------------------------------------------------
//
// Public Methods
//
// -----------------------------------------------------------------
#region Public Methods
///
/// Free all resources associated with the line. Prepare it for reuse.
///
public void Dispose()
{
// Dispose text line
if (_line != null)
{
_line.Dispose();
_line = null;
}
}
///
/// Get a text run at specified text source position.
///
public override TextRun GetTextRun(int dcp)
{
TextRun run = null;
StaticTextPointer position = _owner.Host.TextContainer.CreateStaticPointerAtOffset(dcp);
switch (position.GetPointerContext(LogicalDirection.Forward))
{
case TextPointerContext.Text:
run = HandleText(position);
break;
case TextPointerContext.None:
run = new TextEndOfParagraph(_syntheticCharacterLength);
break;
case TextPointerContext.ElementStart:
case TextPointerContext.ElementEnd:
case TextPointerContext.EmbeddedElement:
default:
Invariant.Assert(false, "Unsupported position type.");
break;
}
Invariant.Assert(run != null, "TextRun has not been created.");
Invariant.Assert(run.Length > 0, "TextRun has to have positive length.");
return run;
}
///
/// Get text immediately before specified text source position.
///
public override TextSpan GetPrecedingText(int dcp)
{
CharacterBufferRange precedingText = CharacterBufferRange.Empty;
CultureInfo culture = null;
if (dcp > 0)
{
// Create TextPointer at dcp
ITextPointer position = _owner.Host.TextContainer.CreatePointerAtOffset(dcp, LogicalDirection.Backward);
// Return text in run. If it is at start of TextContainer this will return an empty string.
// Typically the caller requires just the preceding character. Worst case is the entire
// preceding sentence, which we approximate with a 128 char limit.
int runLength = Math.Min(128, position.GetTextRunLength(LogicalDirection.Backward));
char []text = new char[runLength];
position.GetTextInRun(LogicalDirection.Backward, text, 0, runLength);
precedingText = new CharacterBufferRange(text, 0, runLength);
culture = DynamicPropertyReader.GetCultureInfo((Control)_owner.Host);
}
return new TextSpan(
precedingText.Length, new CultureSpecificCharacterBufferRange(culture, precedingText));
}
///
/// TextFormatter to map a text source character index to a text effect character index
///
/// text source character index
/// the text effect index corresponding to the text effect character index
public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex)
{
return textSourceCharacterIndex;
}
#endregion Public Methods
//--------------------------------------------------------------------
//
// Internal Methods
//
//--------------------------------------------------------------------
#region Internal Methods
///
/// Create and format text line.
///
/// First character position for the line.
/// Width to pass to LS formatter.
/// Line wrapping width.
/// Line's properties.
/// Run cache.
/// Text formatter.
///
/// formatWidth/paragraphWidth is an attempt to work around bug 114719.
/// Unfortunately, Line Services cannot guarantee that once a line
/// has been measured, measuring the same content with the actual line
/// width will produce the same line.
///
/// For example, suppose we format dcp 0 with paragraphWidth = 100.
/// Suppose this results in a line from dcp 0 - 10, with width = 95.
///
/// We would expect that a call to FormatLine with dcp = 0,
/// paragraphWidth = 95 would result in the same 10 char line.
/// But in practice it might return a 9 char line.
///
/// The workaround is to pass in an explicit formatting width across
/// multiple calls, even if the paragraphWidth changes.
///
internal void Format(int dcp, double formatWidth, double paragraphWidth, LineProperties lineProperties, TextRunCache textRunCache, TextFormatter formatter)
{
_lineProperties = lineProperties;
_dcp = dcp;
_paragraphWidth = paragraphWidth;
// We must ignore TextAlignment here since formatWidth does not
// necessarilly equal paragraphWidth. We'll adjust on later calls.
lineProperties.IgnoreTextAlignment = (lineProperties.TextAlignment != TextAlignment.Justify);
try
{
_line = formatter.FormatLine(this, dcp, formatWidth, lineProperties, null, textRunCache);
}
finally
{
lineProperties.IgnoreTextAlignment = false;
}
}
///
/// Create and return visual node for the line.
///
internal DrawingVisual CreateVisual()
{
DrawingVisual visual = new DrawingVisual();
// Calculate shift in line offset to render trailing spaces or avoid clipping text.
double delta = CalculateXOffsetShift();
DrawingContext ctx = visual.RenderOpen();
_line.Draw(ctx, new Point(delta, 0), ((_lineProperties.FlowDirection == FlowDirection.RightToLeft) ? InvertAxes.Horizontal : InvertAxes.None));
ctx.Close();
return visual;
}
///
/// Retrieve bounds of an object/character at specified text position.
///
/// position of an object/character
/// flow direction of object/character
/// Bounds of an object/character
internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection)
{
return GetBoundsFromPosition(characterIndex, 1, out flowDirection);
}
///
/// Returns a collection of rectangles (Rect) that form the bounds of the region
/// specified between the start and end points.
///
/// Starting point of the region
/// Length in characters of the region
/// Offset of line in x direction, to be added to line bounds
/// Offset of line in y direction, to be added to line bounds
///
/// This function calls GetTextBounds for the line, and then checks if there are
/// text run bounds. If they exist, it uses those as the bounding rectangles. If not,
/// it returns the rectangle for the first (and only) element of the text bounds.
///
internal List GetRangeBounds(int cp, int cch, double xOffset, double yOffset)
{
List rectangles = new List();
// Adjust x offset for trailing spaces
double delta = CalculateXOffsetShift();
double adjustedXOffset = xOffset + delta;
IList textBounds = _line.GetTextBounds(cp, cch);
Invariant.Assert(textBounds.Count > 0);
for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++)
{
Rect rect = textBounds[boundIndex].Rectangle;
rect.X += adjustedXOffset;
rect.Y += yOffset;
rectangles.Add(rect);
}
return rectangles;
}
///
/// Retrieve text position index from the distance.
///
/// distance relative to the beginning of the line
/// Text position index
internal CharacterHit GetTextPositionFromDistance(double distance)
{
// Adjust distance to account for a line shift due to rendering of trailing spaces
double delta = CalculateXOffsetShift();
return _line.GetCharacterHitFromDistance(distance - delta);
}
///
/// Retrieve text position for next caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetNextCaretCharacterHit(CharacterHit index)
{
return _line.GetNextCaretCharacterHit(index);
}
///
/// Retrieve text position for previous caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index)
{
return _line.GetPreviousCaretCharacterHit(index);
}
///
/// Retrieve text position for backspace caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetBackspaceCaretCharacterHit(CharacterHit index)
{
return _line.GetBackspaceCaretCharacterHit(index);
}
///
/// Returns true of char hit is at caret unit boundary.
///
///
/// CharacterHit to be tested.
///
internal bool IsAtCaretCharacterHit(CharacterHit charHit)
{
return _line.IsAtCaretCharacterHit(charHit, _dcp);
}
#endregion Internal Methods
//-------------------------------------------------------------------
//
// Internal Properties
//
//--------------------------------------------------------------------
#region Internal Properties
///
/// Calculated width of the line.
///
internal double Width
{
get
{
if (IsWidthAdjusted)
{
// Trailing spaces add to width
return _line.WidthIncludingTrailingWhitespace;
}
else
{
return _line.Width;
}
}
}
///
/// Height of the line; line advance distance.
///
internal double Height { get { return _line.Height; } }
///
/// Is this the last line of the paragraph?
///
internal bool EndOfParagraph
{
get
{
// If there are no Newline characters, it is not the end of paragraph.
if (_line.NewlineLength == 0) { return false; }
// Since there are Newline characters in the line, do more expensive and
// accurate check.
IList> runs = _line.GetTextRunSpans();
return (((TextSpan)runs[runs.Count-1]).Value is TextEndOfParagraph);
}
}
///
/// Length of the line excluding any synthetic characters.
///
internal int Length
{
get { return _line.Length - (EndOfParagraph ? 1 : 0); }
}
///
/// Length of the line excluding any synthetic characters and line breaks.
///
internal int ContentLength { get { return _line.Length - _line.NewlineLength; } }
///
/// True if line ends in hard line break.
///
internal bool HasLineBreak
{
get
{
return (_line.NewlineLength > 0);
}
}
#endregion Internal Properties
//-------------------------------------------------------------------
//
// Private Methods
//
//-------------------------------------------------------------------
#region Private Methods
///
/// Fetch the next run at text position.
///
private TextRun HandleText(StaticTextPointer position)
{
// Calculate the end of the run by finding either:
// a) the next intersection of highlight ranges, or
// b) the natural end of this textrun
StaticTextPointer endOfRunPosition = _owner.Host.TextContainer.Highlights.GetNextPropertyChangePosition(position, LogicalDirection.Forward);
// Clamp the text run at an arbitrary limit, so we don't make
// an unbounded allocation.
if (position.GetOffsetToPosition(endOfRunPosition) > 4096)
{
endOfRunPosition = position.CreatePointer(4096);
}
// Factor in any speller error squiggles on the run.
TextDecorationCollection highlightDecorations = position.TextContainer.Highlights.GetHighlightValue(position, LogicalDirection.Forward, typeof(SpellerHighlightLayer)) as TextDecorationCollection;
TextRunProperties properties;
if (highlightDecorations == null)
{
properties = _lineProperties.DefaultTextRunProperties;
}
else
{
if (_spellerErrorProperties == null)
{
_spellerErrorProperties = new TextProperties((TextProperties)_lineProperties.DefaultTextRunProperties, highlightDecorations);
}
properties = _spellerErrorProperties;
}
// Get character buffer for the text run.
char[] textBuffer = new char[position.GetOffsetToPosition(endOfRunPosition)];
// Copy characters from text run into buffer. Note the actual number of characters copied,
// which may be different than the buffer's length. Buffer length only specifies the maximum
// number of characters
int charactersCopied = position.GetTextInRun(LogicalDirection.Forward, textBuffer, 0, textBuffer.Length);
// Create text run, using characters copied as length
return new TextCharacters(textBuffer, 0, charactersCopied, properties);
}
///
/// Retrieve bounds of an object/character at specified text index.
///
/// character index of an object/character
/// number of positions occupied by object/character
/// flow direction of object/character
/// Bounds of an object/character
private Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection)
{
Rect rect;
// Adjust x offset for trailing spaces
double delta = CalculateXOffsetShift();
IList textBounds = _line.GetTextBounds(cp, cch);
Invariant.Assert(textBounds != null && textBounds.Count == 1, "Expecting exactly one TextBounds for a single text position.");
IList runBounds = textBounds[0].TextRunBounds;
if (runBounds != null)
{
Invariant.Assert(runBounds.Count == 1, "Expecting exactly one TextRunBounds for a single text position.");
rect = runBounds[0].Rectangle;
}
else
{
rect = textBounds[0].Rectangle;
}
rect.X += delta;
flowDirection = textBounds[0].FlowDirection;
return rect;
}
///
/// Returns amount of shift for X-offset to render trailing spaces
/// and TextAlignment offset.
///
private double CalculateXOffsetShift()
{
double xOffset = 0;
if (_lineProperties.TextAlignmentInternal == TextAlignment.Right)
{
xOffset = _paragraphWidth - _line.Width;
}
else if (_lineProperties.TextAlignmentInternal == TextAlignment.Center)
{
xOffset = (_paragraphWidth - _line.Width) / 2;
}
if (IsXOffsetAdjusted)
{
if (_lineProperties.TextAlignmentInternal == TextAlignment.Center)
{
// Return trailing spaces length divided by two so line remains centered.
xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2;
}
else
{
xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace);
}
}
return xOffset;
}
#endregion Private Methods
//-------------------------------------------------------------------
//
// Private Properites
//
//--------------------------------------------------------------------
#region Private Properties
///
/// True if line's X-offset needs adjustment to render trailing spaces.
///
private bool IsXOffsetAdjusted
{
get
{
return ((_lineProperties.TextAlignmentInternal == TextAlignment.Right || _lineProperties.TextAlignmentInternal == TextAlignment.Center) && IsWidthAdjusted);
}
}
///
/// True if line's width is adjusted to include trailing spaces. For right and center alignment we need to
/// adjust line offset as well, but for left alignment we need to only make a width asjustment.
///
private bool IsWidthAdjusted
{
get
{
// Trailing spaces rendered only around hard breaks
return (HasLineBreak || EndOfParagraph);
}
}
#endregion Private Properties
//-------------------------------------------------------------------
//
// Private Fields
//
//--------------------------------------------------------------------
#region Private Fields
///
/// Owner of the line.
///
private readonly TextBoxView _owner;
///
/// Cached text line.
///
private TextLine _line;
///
/// Index of the first character in the line.
///
private int _dcp;
///
/// Properties of the line.
///
private LineProperties _lineProperties;
///
/// Properties of the line when covered by a spelling error squiggle.
///
private TextProperties _spellerErrorProperties;
///
/// Width of the enclosing paragraph, used for TextAlignment calculations.
///
private double _paragraphWidth;
///
/// TextEndOfParagraph character count.
///
private const int _syntheticCharacterLength = 1;
#endregion Private Fields
}
}
// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
// File: TextBoxLine.cs
//
// Description: TextLine wrapper used by TextBoxView.
//
//---------------------------------------------------------------------------
using System;
using System.Globalization;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
using MS.Internal;
using MS.Internal.PtsHost;
using MS.Internal.Text;
namespace System.Windows.Controls
{
///
/// TextLine wrapper used by TextBoxView.
///
internal class TextBoxLine : TextSource, IDisposable
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Constructor.
///
/// Owner of the line.
internal TextBoxLine(TextBoxView owner)
{
_owner = owner;
}
#endregion Constructors
// ------------------------------------------------------------------
//
// Public Methods
//
// -----------------------------------------------------------------
#region Public Methods
///
/// Free all resources associated with the line. Prepare it for reuse.
///
public void Dispose()
{
// Dispose text line
if (_line != null)
{
_line.Dispose();
_line = null;
}
}
///
/// Get a text run at specified text source position.
///
public override TextRun GetTextRun(int dcp)
{
TextRun run = null;
StaticTextPointer position = _owner.Host.TextContainer.CreateStaticPointerAtOffset(dcp);
switch (position.GetPointerContext(LogicalDirection.Forward))
{
case TextPointerContext.Text:
run = HandleText(position);
break;
case TextPointerContext.None:
run = new TextEndOfParagraph(_syntheticCharacterLength);
break;
case TextPointerContext.ElementStart:
case TextPointerContext.ElementEnd:
case TextPointerContext.EmbeddedElement:
default:
Invariant.Assert(false, "Unsupported position type.");
break;
}
Invariant.Assert(run != null, "TextRun has not been created.");
Invariant.Assert(run.Length > 0, "TextRun has to have positive length.");
return run;
}
///
/// Get text immediately before specified text source position.
///
public override TextSpan GetPrecedingText(int dcp)
{
CharacterBufferRange precedingText = CharacterBufferRange.Empty;
CultureInfo culture = null;
if (dcp > 0)
{
// Create TextPointer at dcp
ITextPointer position = _owner.Host.TextContainer.CreatePointerAtOffset(dcp, LogicalDirection.Backward);
// Return text in run. If it is at start of TextContainer this will return an empty string.
// Typically the caller requires just the preceding character. Worst case is the entire
// preceding sentence, which we approximate with a 128 char limit.
int runLength = Math.Min(128, position.GetTextRunLength(LogicalDirection.Backward));
char []text = new char[runLength];
position.GetTextInRun(LogicalDirection.Backward, text, 0, runLength);
precedingText = new CharacterBufferRange(text, 0, runLength);
culture = DynamicPropertyReader.GetCultureInfo((Control)_owner.Host);
}
return new TextSpan(
precedingText.Length, new CultureSpecificCharacterBufferRange(culture, precedingText));
}
///
/// TextFormatter to map a text source character index to a text effect character index
///
/// text source character index
/// the text effect index corresponding to the text effect character index
public override int GetTextEffectCharacterIndexFromTextSourceCharacterIndex(int textSourceCharacterIndex)
{
return textSourceCharacterIndex;
}
#endregion Public Methods
//--------------------------------------------------------------------
//
// Internal Methods
//
//--------------------------------------------------------------------
#region Internal Methods
///
/// Create and format text line.
///
/// First character position for the line.
/// Width to pass to LS formatter.
/// Line wrapping width.
/// Line's properties.
/// Run cache.
/// Text formatter.
///
/// formatWidth/paragraphWidth is an attempt to work around bug 114719.
/// Unfortunately, Line Services cannot guarantee that once a line
/// has been measured, measuring the same content with the actual line
/// width will produce the same line.
///
/// For example, suppose we format dcp 0 with paragraphWidth = 100.
/// Suppose this results in a line from dcp 0 - 10, with width = 95.
///
/// We would expect that a call to FormatLine with dcp = 0,
/// paragraphWidth = 95 would result in the same 10 char line.
/// But in practice it might return a 9 char line.
///
/// The workaround is to pass in an explicit formatting width across
/// multiple calls, even if the paragraphWidth changes.
///
internal void Format(int dcp, double formatWidth, double paragraphWidth, LineProperties lineProperties, TextRunCache textRunCache, TextFormatter formatter)
{
_lineProperties = lineProperties;
_dcp = dcp;
_paragraphWidth = paragraphWidth;
// We must ignore TextAlignment here since formatWidth does not
// necessarilly equal paragraphWidth. We'll adjust on later calls.
lineProperties.IgnoreTextAlignment = (lineProperties.TextAlignment != TextAlignment.Justify);
try
{
_line = formatter.FormatLine(this, dcp, formatWidth, lineProperties, null, textRunCache);
}
finally
{
lineProperties.IgnoreTextAlignment = false;
}
}
///
/// Create and return visual node for the line.
///
internal DrawingVisual CreateVisual()
{
DrawingVisual visual = new DrawingVisual();
// Calculate shift in line offset to render trailing spaces or avoid clipping text.
double delta = CalculateXOffsetShift();
DrawingContext ctx = visual.RenderOpen();
_line.Draw(ctx, new Point(delta, 0), ((_lineProperties.FlowDirection == FlowDirection.RightToLeft) ? InvertAxes.Horizontal : InvertAxes.None));
ctx.Close();
return visual;
}
///
/// Retrieve bounds of an object/character at specified text position.
///
/// position of an object/character
/// flow direction of object/character
/// Bounds of an object/character
internal Rect GetBoundsFromTextPosition(int characterIndex, out FlowDirection flowDirection)
{
return GetBoundsFromPosition(characterIndex, 1, out flowDirection);
}
///
/// Returns a collection of rectangles (Rect) that form the bounds of the region
/// specified between the start and end points.
///
/// Starting point of the region
/// Length in characters of the region
/// Offset of line in x direction, to be added to line bounds
/// Offset of line in y direction, to be added to line bounds
///
/// This function calls GetTextBounds for the line, and then checks if there are
/// text run bounds. If they exist, it uses those as the bounding rectangles. If not,
/// it returns the rectangle for the first (and only) element of the text bounds.
///
internal List GetRangeBounds(int cp, int cch, double xOffset, double yOffset)
{
List rectangles = new List();
// Adjust x offset for trailing spaces
double delta = CalculateXOffsetShift();
double adjustedXOffset = xOffset + delta;
IList textBounds = _line.GetTextBounds(cp, cch);
Invariant.Assert(textBounds.Count > 0);
for (int boundIndex = 0; boundIndex < textBounds.Count; boundIndex++)
{
Rect rect = textBounds[boundIndex].Rectangle;
rect.X += adjustedXOffset;
rect.Y += yOffset;
rectangles.Add(rect);
}
return rectangles;
}
///
/// Retrieve text position index from the distance.
///
/// distance relative to the beginning of the line
/// Text position index
internal CharacterHit GetTextPositionFromDistance(double distance)
{
// Adjust distance to account for a line shift due to rendering of trailing spaces
double delta = CalculateXOffsetShift();
return _line.GetCharacterHitFromDistance(distance - delta);
}
///
/// Retrieve text position for next caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetNextCaretCharacterHit(CharacterHit index)
{
return _line.GetNextCaretCharacterHit(index);
}
///
/// Retrieve text position for previous caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetPreviousCaretCharacterHit(CharacterHit index)
{
return _line.GetPreviousCaretCharacterHit(index);
}
///
/// Retrieve text position for backspace caret position.
///
/// CharacterHit for current position
/// Text position index
internal CharacterHit GetBackspaceCaretCharacterHit(CharacterHit index)
{
return _line.GetBackspaceCaretCharacterHit(index);
}
///
/// Returns true of char hit is at caret unit boundary.
///
///
/// CharacterHit to be tested.
///
internal bool IsAtCaretCharacterHit(CharacterHit charHit)
{
return _line.IsAtCaretCharacterHit(charHit, _dcp);
}
#endregion Internal Methods
//-------------------------------------------------------------------
//
// Internal Properties
//
//--------------------------------------------------------------------
#region Internal Properties
///
/// Calculated width of the line.
///
internal double Width
{
get
{
if (IsWidthAdjusted)
{
// Trailing spaces add to width
return _line.WidthIncludingTrailingWhitespace;
}
else
{
return _line.Width;
}
}
}
///
/// Height of the line; line advance distance.
///
internal double Height { get { return _line.Height; } }
///
/// Is this the last line of the paragraph?
///
internal bool EndOfParagraph
{
get
{
// If there are no Newline characters, it is not the end of paragraph.
if (_line.NewlineLength == 0) { return false; }
// Since there are Newline characters in the line, do more expensive and
// accurate check.
IList> runs = _line.GetTextRunSpans();
return (((TextSpan)runs[runs.Count-1]).Value is TextEndOfParagraph);
}
}
///
/// Length of the line excluding any synthetic characters.
///
internal int Length
{
get { return _line.Length - (EndOfParagraph ? 1 : 0); }
}
///
/// Length of the line excluding any synthetic characters and line breaks.
///
internal int ContentLength { get { return _line.Length - _line.NewlineLength; } }
///
/// True if line ends in hard line break.
///
internal bool HasLineBreak
{
get
{
return (_line.NewlineLength > 0);
}
}
#endregion Internal Properties
//-------------------------------------------------------------------
//
// Private Methods
//
//-------------------------------------------------------------------
#region Private Methods
///
/// Fetch the next run at text position.
///
private TextRun HandleText(StaticTextPointer position)
{
// Calculate the end of the run by finding either:
// a) the next intersection of highlight ranges, or
// b) the natural end of this textrun
StaticTextPointer endOfRunPosition = _owner.Host.TextContainer.Highlights.GetNextPropertyChangePosition(position, LogicalDirection.Forward);
// Clamp the text run at an arbitrary limit, so we don't make
// an unbounded allocation.
if (position.GetOffsetToPosition(endOfRunPosition) > 4096)
{
endOfRunPosition = position.CreatePointer(4096);
}
// Factor in any speller error squiggles on the run.
TextDecorationCollection highlightDecorations = position.TextContainer.Highlights.GetHighlightValue(position, LogicalDirection.Forward, typeof(SpellerHighlightLayer)) as TextDecorationCollection;
TextRunProperties properties;
if (highlightDecorations == null)
{
properties = _lineProperties.DefaultTextRunProperties;
}
else
{
if (_spellerErrorProperties == null)
{
_spellerErrorProperties = new TextProperties((TextProperties)_lineProperties.DefaultTextRunProperties, highlightDecorations);
}
properties = _spellerErrorProperties;
}
// Get character buffer for the text run.
char[] textBuffer = new char[position.GetOffsetToPosition(endOfRunPosition)];
// Copy characters from text run into buffer. Note the actual number of characters copied,
// which may be different than the buffer's length. Buffer length only specifies the maximum
// number of characters
int charactersCopied = position.GetTextInRun(LogicalDirection.Forward, textBuffer, 0, textBuffer.Length);
// Create text run, using characters copied as length
return new TextCharacters(textBuffer, 0, charactersCopied, properties);
}
///
/// Retrieve bounds of an object/character at specified text index.
///
/// character index of an object/character
/// number of positions occupied by object/character
/// flow direction of object/character
/// Bounds of an object/character
private Rect GetBoundsFromPosition(int cp, int cch, out FlowDirection flowDirection)
{
Rect rect;
// Adjust x offset for trailing spaces
double delta = CalculateXOffsetShift();
IList textBounds = _line.GetTextBounds(cp, cch);
Invariant.Assert(textBounds != null && textBounds.Count == 1, "Expecting exactly one TextBounds for a single text position.");
IList runBounds = textBounds[0].TextRunBounds;
if (runBounds != null)
{
Invariant.Assert(runBounds.Count == 1, "Expecting exactly one TextRunBounds for a single text position.");
rect = runBounds[0].Rectangle;
}
else
{
rect = textBounds[0].Rectangle;
}
rect.X += delta;
flowDirection = textBounds[0].FlowDirection;
return rect;
}
///
/// Returns amount of shift for X-offset to render trailing spaces
/// and TextAlignment offset.
///
private double CalculateXOffsetShift()
{
double xOffset = 0;
if (_lineProperties.TextAlignmentInternal == TextAlignment.Right)
{
xOffset = _paragraphWidth - _line.Width;
}
else if (_lineProperties.TextAlignmentInternal == TextAlignment.Center)
{
xOffset = (_paragraphWidth - _line.Width) / 2;
}
if (IsXOffsetAdjusted)
{
if (_lineProperties.TextAlignmentInternal == TextAlignment.Center)
{
// Return trailing spaces length divided by two so line remains centered.
xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace) / 2;
}
else
{
xOffset += (_line.Width - _line.WidthIncludingTrailingWhitespace);
}
}
return xOffset;
}
#endregion Private Methods
//-------------------------------------------------------------------
//
// Private Properites
//
//--------------------------------------------------------------------
#region Private Properties
///
/// True if line's X-offset needs adjustment to render trailing spaces.
///
private bool IsXOffsetAdjusted
{
get
{
return ((_lineProperties.TextAlignmentInternal == TextAlignment.Right || _lineProperties.TextAlignmentInternal == TextAlignment.Center) && IsWidthAdjusted);
}
}
///
/// True if line's width is adjusted to include trailing spaces. For right and center alignment we need to
/// adjust line offset as well, but for left alignment we need to only make a width asjustment.
///
private bool IsWidthAdjusted
{
get
{
// Trailing spaces rendered only around hard breaks
return (HasLineBreak || EndOfParagraph);
}
}
#endregion Private Properties
//-------------------------------------------------------------------
//
// Private Fields
//
//--------------------------------------------------------------------
#region Private Fields
///
/// Owner of the line.
///
private readonly TextBoxView _owner;
///
/// Cached text line.
///
private TextLine _line;
///
/// Index of the first character in the line.
///
private int _dcp;
///
/// Properties of the line.
///
private LineProperties _lineProperties;
///
/// Properties of the line when covered by a spelling error squiggle.
///
private TextProperties _spellerErrorProperties;
///
/// Width of the enclosing paragraph, used for TextAlignment calculations.
///
private double _paragraphWidth;
///
/// TextEndOfParagraph character count.
///
private const int _syntheticCharacterLength = 1;
#endregion Private Fields
}
}
// 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
- XmlAnyAttributeAttribute.cs
- ConfigurationSectionGroup.cs
- TransactedBatchingBehavior.cs
- XmlSchemaComplexContent.cs
- ElapsedEventArgs.cs
- TypeUtils.cs
- _WebProxyDataBuilder.cs
- FacetChecker.cs
- StronglyTypedResourceBuilder.cs
- SkinBuilder.cs
- UnauthorizedAccessException.cs
- UserControlBuildProvider.cs
- prompt.cs
- StrongNamePublicKeyBlob.cs
- SqlDataSourceTableQuery.cs
- MSAAWinEventWrap.cs
- BaseCodePageEncoding.cs
- KeyboardEventArgs.cs
- Button.cs
- WindowsListViewSubItem.cs
- Region.cs
- FrameworkTextComposition.cs
- COM2FontConverter.cs
- XmlSchemaAttributeGroup.cs
- ParseHttpDate.cs
- IntegerValidator.cs
- TabRenderer.cs
- AttributeQuery.cs
- NamedServiceModelExtensionCollectionElement.cs
- StylusPointPropertyInfo.cs
- JsonEncodingStreamWrapper.cs
- DataFormats.cs
- ApplicationBuildProvider.cs
- QueryValue.cs
- SecurityStateEncoder.cs
- HostingPreferredMapPath.cs
- DataGridViewButtonCell.cs
- CollectionViewGroup.cs
- EnumValidator.cs
- NativeMethods.cs
- WindowsListBox.cs
- CommandHelpers.cs
- SpecularMaterial.cs
- AppLevelCompilationSectionCache.cs
- __Error.cs
- ColorMatrix.cs
- SqlDeflator.cs
- Mappings.cs
- SoapReflectionImporter.cs
- DivideByZeroException.cs
- RenderDataDrawingContext.cs
- JsonGlobals.cs
- SemanticKeyElement.cs
- WebBrowserBase.cs
- ActivationArguments.cs
- SourceChangedEventArgs.cs
- AttributeQuery.cs
- VisualTreeUtils.cs
- TakeOrSkipQueryOperator.cs
- MsmqInputSessionChannelListener.cs
- HiddenFieldPageStatePersister.cs
- XmlCountingReader.cs
- SqlStatistics.cs
- DataGridViewCellLinkedList.cs
- Internal.cs
- Button.cs
- OleDbException.cs
- safemediahandle.cs
- CommentAction.cs
- DataGridViewCheckBoxColumn.cs
- ImageSourceConverter.cs
- ReadOnlyCollectionBase.cs
- XmlElement.cs
- KeyTime.cs
- TemplatePropertyEntry.cs
- GridViewItemAutomationPeer.cs
- XmlIterators.cs
- DataGridViewUtilities.cs
- DataGridViewCellEventArgs.cs
- SchemaLookupTable.cs
- SystemIPGlobalStatistics.cs
- CodeConditionStatement.cs
- DataContractJsonSerializerOperationFormatter.cs
- LingerOption.cs
- XPathNavigatorReader.cs
- ExtensionDataObject.cs
- ToolStripDropDownItem.cs
- WindowsTreeView.cs
- OleCmdHelper.cs
- CompilerGeneratedAttribute.cs
- StackOverflowException.cs
- CellQuery.cs
- GeometryCombineModeValidation.cs
- WebHttpEndpointElement.cs
- RemoteWebConfigurationHostStream.cs
- IntSecurity.cs
- DBParameter.cs
- TemplatingOptionsDialog.cs
- RectAnimation.cs
- DbModificationCommandTree.cs