|
//-----------------------------------------------------------------------
//
// Microsoft Windows Client Platform
// Copyright (C) Microsoft Corporation, 2001
//
// File: FormatSettings.cs
//
// Contents: Settings to format text
//
// Created: 2-25-2004 Worachai Chaoweeraprasit (wchao)
//
//------------------------------------------------------------------------
using System;
using System.Diagnostics;
using System.Security;
using System.Windows;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Media.TextFormatting;
namespace MS.Internal.TextFormatting
{
/// <summary>
/// Text formatting state
/// </summary>
internal sealed class FormatSettings
{
private TextFormatterImp _formatter; // formatter object
private TextSource _textSource; // client text source for main text
private TextRunCacheImp _runCache; // run cache owned by client
private ParaProp _pap; // current paragraph properties
private DigitState _digitState; // current number substitution properties
private TextLineBreak _previousLineBreak; // break of previous line
private int _maxLineWidth; // Max line width of the line being built. Only used in Optimal paragraph for the moment
private int _textIndent; // Distance from line start to where text starts
private TextFormattingMode _textFormattingMode;
private bool _isSideways;
internal FormatSettings(
TextFormatterImp formatter,
TextSource textSource,
TextRunCacheImp runCache,
ParaProp pap,
TextLineBreak previousLineBreak,
bool isSingleLineFormatting,
TextFormattingMode textFormattingMode,
bool isSideways
)
{
_isSideways = isSideways;
_textFormattingMode = textFormattingMode;
_formatter = formatter;
_textSource = textSource;
_runCache = runCache;
_pap = pap;
_digitState = new DigitState();
_previousLineBreak = previousLineBreak;
_maxLineWidth = Constants.IdealInfiniteWidth;
if (isSingleLineFormatting)
{
// Apply text indent on each line in single line mode
_textIndent = _pap.Indent;
}
}
internal TextFormattingMode TextFormattingMode
{
get
{
return _textFormattingMode;
}
}
internal bool IsSideways
{
get
{
return _isSideways;
}
}
/// <summary>
/// Current formatter
/// </summary>
internal TextFormatterImp Formatter
{
get { return _formatter; }
}
/// <summary>
/// Current source
/// </summary>
internal TextSource TextSource
{
get { return _textSource; }
}
/// <summary>
/// Break of previous line
/// </summary>
internal TextLineBreak PreviousLineBreak
{
get { return _previousLineBreak; }
}
/// <summary>
/// paragraph properties
/// </summary>
internal ParaProp Pap
{
get { return _pap; }
}
/// <summary>
/// Max width of the line being built. In optimal break mode, client may format
/// breakpoints for the line with max width different from the paragraph width.
/// </summary>
internal int MaxLineWidth
{
get { return _maxLineWidth; }
}
/// <summary>
/// Update formatting parameters at line start
/// </summary>
internal void UpdateSettingsForCurrentLine(
int maxLineWidth,
TextLineBreak previousLineBreak,
bool isFirstLineInPara
)
{
_previousLineBreak = previousLineBreak;
_digitState = new DigitState(); // reset digit state
_maxLineWidth = Math.Max(maxLineWidth, 0);
if (isFirstLineInPara)
{
_textIndent = _pap.Indent;
}
else
{
// Do not apply text indentation to all but the first line in para
_textIndent = 0;
}
}
/// <summary>
/// Calculate formatting width from specified constraint width
/// </summary>
internal int GetFormatWidth(int finiteFormatWidth)
{
// LS does not support no wrap, for such case, we would need to
// simulate formatting a line within an infinite paragraph width
// while still keeping the last legit boundary for trimming purpose.
return _pap.Wrap ? finiteFormatWidth : Constants.IdealInfiniteWidth;
}
/// <summary>
/// Calculate finite formatting width from specified constraint width
/// </summary>
internal int GetFiniteFormatWidth(int paragraphWidth)
{
// indent is part of our text line but not of LS line
// paragraph width == 0 means format width is unlimited
int formatWidth = (paragraphWidth <= 0 ? Constants.IdealInfiniteWidth : paragraphWidth);
formatWidth = formatWidth - _pap.ParagraphIndent;
// sanitize the format width value before passing to LS
formatWidth = Math.Max(formatWidth, 0);
formatWidth = Math.Min(formatWidth, Constants.IdealInfiniteWidth);
return formatWidth;
}
/// <summary>
/// Fetch text run and character string associated with it
/// </summary>
/// <SecurityNote>
/// Critical: This code has unsafe code block that uses pointers.
/// TreatAsSafe: This code does not expose the pointers.
/// </SecurityNote>
[SecurityCritical, SecurityTreatAsSafe]
internal CharacterBufferRange FetchTextRun(
int cpFetch,
int cpFirst,
out TextRun textRun,
out int runLength
)
{
int offsetToFirstCp;
textRun = _runCache.FetchTextRun(this, cpFetch, cpFirst, out offsetToFirstCp, out runLength);
CharacterBufferRange charString;
switch (TextRunInfo.GetRunType(textRun))
{
case Plsrun.Text:
{
CharacterBufferReference charBufferRef = textRun.CharacterBufferReference;
charString = new CharacterBufferRange(
charBufferRef.CharacterBuffer,
charBufferRef.OffsetToFirstChar + offsetToFirstCp,
runLength
);
break;
}
case Plsrun.InlineObject:
Debug.Assert(offsetToFirstCp == 0);
unsafe
{
charString = new CharacterBufferRange((char*) TextStore.PwchObjectReplacement, 1);
}
break;
case Plsrun.LineBreak:
Debug.Assert(offsetToFirstCp == 0);
unsafe
{
//
// Line break is to be represented as "Line Separator" such that
// it doesn't terminate the optimal paragraph formatting session, but still breaks the line
// unambiguously.
//
charString = new CharacterBufferRange((char*) TextStore.PwchLineSeparator, 1);
}
break;
case Plsrun.ParaBreak:
Debug.Assert(offsetToFirstCp == 0);
unsafe
{
//
// Paragraph break is special as it also terminates the paragraph.
// It should be represented as "Paragraph Separator" such that it will be correctly handled
// in Bidi and Optimal paragraph formatting.
//
charString = new CharacterBufferRange((char*) TextStore.PwchParaSeparator, 1);
}
break;
case Plsrun.Hidden:
unsafe
{
charString = new CharacterBufferRange((char*) TextStore.PwchHidden, 1);
}
break;
default:
charString = CharacterBufferRange.Empty;
break;
}
return charString;
}
/// <summary>
/// Get text immediately preceding cpLimit.
/// </summary>
internal TextSpan<CultureSpecificCharacterBufferRange> GetPrecedingText(int cpLimit)
{
return _runCache.GetPrecedingText(_textSource, cpLimit);
}
/// <summary>
/// Current number substitution propeties
/// </summary>
internal DigitState DigitState
{
get { return _digitState; }
}
/// <summary>
/// Distance from line start to where text starts
/// </summary>
internal int TextIndent
{
get { return _textIndent; }
}
}
}
|