mirror of
https://github.com/ZuneDev/ZuneShell.dll.git
synced 2026-07-27 13:11:51 -07:00
1494 lines
55 KiB
C#
1494 lines
55 KiB
C#
// Decompiled with JetBrains decompiler
|
|
// Type: Microsoft.Iris.ViewItems.Text
|
|
// Assembly: UIX, Version=4.8.0.0, Culture=neutral, PublicKeyToken=ddd0da4d3e678217
|
|
// MVID: A56C6C9D-B7F6-46A9-8BDE-B3D9B8D60B11
|
|
// Assembly location: C:\Program Files\Zune\UIX.dll
|
|
|
|
using Microsoft.Iris.Drawing;
|
|
using Microsoft.Iris.InputHandlers;
|
|
using Microsoft.Iris.Layout;
|
|
using Microsoft.Iris.Layouts;
|
|
using Microsoft.Iris.Markup;
|
|
using Microsoft.Iris.OS;
|
|
using Microsoft.Iris.Render;
|
|
using Microsoft.Iris.Render.Extensions;
|
|
using Microsoft.Iris.RenderAPI.Drawing;
|
|
using Microsoft.Iris.Session;
|
|
using Microsoft.Iris.UI;
|
|
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using System.Xml;
|
|
|
|
namespace Microsoft.Iris.ViewItems
|
|
{
|
|
internal class Text : ViewItem, ILayout
|
|
{
|
|
private const float c_scaleEpsilon = 0.01f;
|
|
private const float c_lineSpacingDefault = 0.0f;
|
|
private const float c_characterSpacingDefault = 0.0f;
|
|
private const bool c_enableKerningDefault = false;
|
|
private uint _bits;
|
|
private TextFlow _flow;
|
|
private float _lastLineExtentLeft;
|
|
private float _lastLineExtentRight;
|
|
private Size _textSize;
|
|
private Size _slotSize;
|
|
private int _lineAlignmentOffset;
|
|
private string _content;
|
|
private Font _font;
|
|
private Color _textColor;
|
|
private Color _textHighlightColor;
|
|
private Color _backHighlightColor;
|
|
private char _passwordChar;
|
|
private float _scale;
|
|
private LineAlignment _lineAlignment;
|
|
private float _fadeSize;
|
|
private int _maxLines;
|
|
private int _lastVisibleRun;
|
|
private TextBounds _boundsType;
|
|
private bool _disableIme;
|
|
private TextStyle _textStyle;
|
|
private IDictionary _namedStyles;
|
|
private RichText _richTextRasterizer;
|
|
private TextEditingHandler _externalEditingHandler;
|
|
private string _parsedContent;
|
|
private ArrayList _parsedContentMarkedRanges;
|
|
private ArrayList _fragments;
|
|
private TextFlowRenderingHelper _renderingHelper;
|
|
private static Font s_defaultFont = new Font("Arial", 24f);
|
|
private static RichText s_sharedOversampledRasterizer;
|
|
private static RichText s_sharedNonOversampledRasterizer;
|
|
private static SimpleText s_sharedSimpleTextRasterizer;
|
|
private static bool s_simpleTextMeasureAvailable;
|
|
private Vector<float> _recentScaleChanges;
|
|
private float _lineSpacing;
|
|
private float _characterSpacing;
|
|
private bool _enableKerning;
|
|
private static char[] s_whitespaceChars = new char[3]
|
|
{
|
|
' ',
|
|
'\r',
|
|
'\n'
|
|
};
|
|
|
|
public Text()
|
|
{
|
|
Layout = this;
|
|
_font = s_defaultFont;
|
|
_textColor = Color.Black;
|
|
_textHighlightColor = Color.White;
|
|
_backHighlightColor = Color.Black;
|
|
_scale = 1f;
|
|
_fadeSize = 32f;
|
|
_maxLines = int.MaxValue;
|
|
_passwordChar = '•';
|
|
_lineAlignment = LineAlignment.Near;
|
|
_richTextRasterizer = SharedNonOversampledRasterizer;
|
|
_renderingHelper = new TextFlowRenderingHelper();
|
|
ContributesToWidth = true;
|
|
TextFitsWidth = true;
|
|
TextFitsHeight = true;
|
|
SetClipped(false);
|
|
MarkScaleDirty();
|
|
if (s_simpleTextMeasureAvailable)
|
|
return;
|
|
ClearBit(Bits.FastMeasurePossible);
|
|
SetBit(Bits.FastMeasureValid);
|
|
}
|
|
|
|
public Text(UIClass ownerUI)
|
|
: this()
|
|
{
|
|
}
|
|
|
|
protected override void OnDispose()
|
|
{
|
|
DisposeFlow();
|
|
UnregisterFragmentUsage();
|
|
base.OnDispose();
|
|
}
|
|
|
|
private void DisposeFlow()
|
|
{
|
|
if (_flow == null)
|
|
return;
|
|
_flow.Dispose(this);
|
|
_flow = null;
|
|
}
|
|
|
|
public static void Initialize()
|
|
{
|
|
}
|
|
|
|
public static void Uninitialize()
|
|
{
|
|
if (s_sharedOversampledRasterizer != null)
|
|
{
|
|
s_sharedOversampledRasterizer.Dispose();
|
|
s_sharedOversampledRasterizer = null;
|
|
}
|
|
if (s_sharedNonOversampledRasterizer != null)
|
|
{
|
|
s_sharedNonOversampledRasterizer.Dispose();
|
|
s_sharedNonOversampledRasterizer = null;
|
|
}
|
|
if (s_sharedSimpleTextRasterizer == null)
|
|
return;
|
|
s_sharedSimpleTextRasterizer.Dispose();
|
|
s_sharedSimpleTextRasterizer = null;
|
|
}
|
|
|
|
private static SimpleText SharedSimpleTextRasterizer
|
|
{
|
|
get
|
|
{
|
|
if (s_sharedSimpleTextRasterizer == null)
|
|
s_sharedSimpleTextRasterizer = new SimpleText();
|
|
return s_sharedSimpleTextRasterizer;
|
|
}
|
|
}
|
|
|
|
private static RichText SharedOversampledRasterizer
|
|
{
|
|
get
|
|
{
|
|
if (s_sharedOversampledRasterizer == null)
|
|
{
|
|
s_sharedOversampledRasterizer = new RichText(true);
|
|
s_sharedOversampledRasterizer.Oversample = true;
|
|
s_simpleTextMeasureAvailable = NativeApi.SpSimpleTextIsAvailable();
|
|
}
|
|
return s_sharedOversampledRasterizer;
|
|
}
|
|
}
|
|
|
|
private static RichText SharedNonOversampledRasterizer
|
|
{
|
|
get
|
|
{
|
|
if (s_sharedNonOversampledRasterizer == null)
|
|
{
|
|
s_sharedNonOversampledRasterizer = new RichText(true);
|
|
s_simpleTextMeasureAvailable = NativeApi.SpSimpleTextIsAvailable();
|
|
}
|
|
return s_sharedNonOversampledRasterizer;
|
|
}
|
|
}
|
|
|
|
public string Content
|
|
{
|
|
get => _content;
|
|
set
|
|
{
|
|
if (!(_content != value))
|
|
return;
|
|
if (value != null && value.Length > 3)
|
|
{
|
|
_content = value.TrimEnd(s_whitespaceChars);
|
|
char ch1 = value[value.Length - 1];
|
|
char ch2 = value[value.Length - 2];
|
|
if (ch1 == ' ' && ch2 != ' ')
|
|
_content += ch1;
|
|
}
|
|
else
|
|
_content = value;
|
|
_parsedContent = null;
|
|
_parsedContentMarkedRanges = null;
|
|
OnDisplayedContentChange();
|
|
FireNotification(NotificationID.Content);
|
|
}
|
|
}
|
|
|
|
public void MarkScaleDirty() => SetBit(Bits.ScaleDirty);
|
|
|
|
private bool InMeasure
|
|
{
|
|
get => GetBit(Bits.InMeasure);
|
|
set => SetBit(Bits.InMeasure, value);
|
|
}
|
|
|
|
public void OnDisplayedContentChange()
|
|
{
|
|
if (InMeasure)
|
|
return;
|
|
MarkTextLayoutInvalid();
|
|
MarkPaintInvalid();
|
|
ForceContentChange();
|
|
}
|
|
|
|
public Font Font
|
|
{
|
|
get => _font;
|
|
set
|
|
{
|
|
if (_font == value)
|
|
return;
|
|
_font = value;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
ForceContentChange();
|
|
FireNotification(NotificationID.Font);
|
|
}
|
|
}
|
|
|
|
public Color Color
|
|
{
|
|
get => _textColor;
|
|
set
|
|
{
|
|
if (!(_textColor != value))
|
|
return;
|
|
_textColor = value;
|
|
if (KeepFlowAlive)
|
|
{
|
|
MarkPaintInvalid();
|
|
}
|
|
else
|
|
{
|
|
MarkLayoutInvalid();
|
|
if (HasEverPainted)
|
|
KeepFlowAlive = true;
|
|
}
|
|
FireNotification(NotificationID.Color);
|
|
}
|
|
}
|
|
|
|
public Color HighlightColor
|
|
{
|
|
get => _backHighlightColor;
|
|
set
|
|
{
|
|
if (!(_backHighlightColor != value))
|
|
return;
|
|
_backHighlightColor = value;
|
|
MarkPaintInvalid();
|
|
FireNotification(NotificationID.HighlightColor);
|
|
}
|
|
}
|
|
|
|
public Color TextHighlightColor
|
|
{
|
|
get => _textHighlightColor;
|
|
set
|
|
{
|
|
if (!(TextHighlightColor != value))
|
|
return;
|
|
_textHighlightColor = value;
|
|
MarkPaintInvalid();
|
|
FireNotification(NotificationID.TextHighlightColor);
|
|
}
|
|
}
|
|
|
|
public TextSharpness TextSharpness
|
|
{
|
|
get => !_richTextRasterizer.Oversample ? TextSharpness.Sharp : TextSharpness.Soft;
|
|
set
|
|
{
|
|
if (TextSharpness == value)
|
|
return;
|
|
bool flag = false;
|
|
switch (value)
|
|
{
|
|
case TextSharpness.Sharp:
|
|
flag = false;
|
|
break;
|
|
case TextSharpness.Soft:
|
|
flag = true;
|
|
break;
|
|
}
|
|
if (_richTextRasterizer == s_sharedNonOversampledRasterizer && flag)
|
|
_richTextRasterizer = SharedOversampledRasterizer;
|
|
else if (_richTextRasterizer == s_sharedOversampledRasterizer && !flag)
|
|
_richTextRasterizer = SharedNonOversampledRasterizer;
|
|
else
|
|
_richTextRasterizer.Oversample = flag;
|
|
MarkTextLayoutInvalid();
|
|
ForceContentChange();
|
|
FireNotification(NotificationID.TextSharpness);
|
|
}
|
|
}
|
|
|
|
public bool WordWrap
|
|
{
|
|
get => GetBit(Bits.WordWrap);
|
|
set
|
|
{
|
|
if (WordWrap == value)
|
|
return;
|
|
SetBit(Bits.WordWrap, value);
|
|
if (value)
|
|
KeepFlowAlive = true;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
UpdateWordWrapForExternalRasterizer();
|
|
FireNotification(NotificationID.WordWrap);
|
|
}
|
|
}
|
|
|
|
public bool UsePasswordMask
|
|
{
|
|
get => GetBit(Bits.PasswordMasked);
|
|
set
|
|
{
|
|
if (UsePasswordMask == value)
|
|
return;
|
|
SetBit(Bits.PasswordMasked, value);
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.UsePasswordMask);
|
|
}
|
|
}
|
|
|
|
public char PasswordMask
|
|
{
|
|
get => _passwordChar;
|
|
set
|
|
{
|
|
if (_passwordChar == value)
|
|
return;
|
|
_passwordChar = value;
|
|
if (UsePasswordMask)
|
|
{
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
}
|
|
FireNotification(NotificationID.PasswordMask);
|
|
}
|
|
}
|
|
|
|
public int MaximumLines
|
|
{
|
|
get => _maxLines;
|
|
set
|
|
{
|
|
if (_maxLines == value)
|
|
return;
|
|
_maxLines = value;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.MaximumLines);
|
|
}
|
|
}
|
|
|
|
public LineAlignment LineAlignment
|
|
{
|
|
get => _lineAlignment;
|
|
set
|
|
{
|
|
if (_lineAlignment == value)
|
|
return;
|
|
_lineAlignment = value;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.LineAlignment);
|
|
}
|
|
}
|
|
|
|
public float LineSpacing
|
|
{
|
|
get => !GetBit(Bits.LineSpacingSet) ? 0.0f : _lineSpacing;
|
|
set
|
|
{
|
|
if (LineSpacing == (double)value)
|
|
return;
|
|
_lineSpacing = value;
|
|
SetBit(Bits.LineSpacingSet);
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.LineSpacing);
|
|
}
|
|
}
|
|
|
|
public float CharacterSpacing
|
|
{
|
|
get => !GetBit(Bits.CharacterSpacingSet) ? 0.0f : _characterSpacing;
|
|
set
|
|
{
|
|
if (CharacterSpacing == (double)value)
|
|
return;
|
|
_characterSpacing = value;
|
|
SetBit(Bits.CharacterSpacingSet);
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.CharacterSpacing);
|
|
}
|
|
}
|
|
|
|
public bool EnableKerning
|
|
{
|
|
get => GetBit(Bits.EnableKerningSet) && _enableKerning;
|
|
set
|
|
{
|
|
if (EnableKerning == value)
|
|
return;
|
|
_enableKerning = value;
|
|
SetBit(Bits.EnableKerningSet);
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
FireNotification(NotificationID.EnableKerning);
|
|
}
|
|
}
|
|
|
|
public float FadeSize
|
|
{
|
|
get => _fadeSize;
|
|
set
|
|
{
|
|
if (_fadeSize == (double)value)
|
|
return;
|
|
_fadeSize = value;
|
|
InvalidateGradients();
|
|
FireNotification(NotificationID.FadeSize);
|
|
}
|
|
}
|
|
|
|
public TextStyle Style
|
|
{
|
|
get => _textStyle;
|
|
set
|
|
{
|
|
if (_textStyle == value)
|
|
return;
|
|
_textStyle = value;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
ForceContentChange();
|
|
FireNotification(NotificationID.Style);
|
|
}
|
|
}
|
|
|
|
public IDictionary NamedStyles
|
|
{
|
|
get => _namedStyles;
|
|
set
|
|
{
|
|
if (_namedStyles == value)
|
|
return;
|
|
_namedStyles = value;
|
|
MarkPaintInvalid();
|
|
MarkTextLayoutInvalid();
|
|
ForceContentChange();
|
|
FireNotification(NotificationID.NamedStyles);
|
|
}
|
|
}
|
|
|
|
public IList Fragments => _fragments;
|
|
|
|
public bool DisableIme
|
|
{
|
|
get => _disableIme;
|
|
set
|
|
{
|
|
if (_disableIme == value)
|
|
return;
|
|
_disableIme = value;
|
|
FireNotification(NotificationID.DisableIme);
|
|
}
|
|
}
|
|
|
|
public Rectangle LastLineBounds => _flow != null ? _flow.GetLastLineBounds(_lineAlignmentOffset) : new Rectangle(_textSize);
|
|
|
|
public int NumberOfLines
|
|
{
|
|
get
|
|
{
|
|
if (_flow == null)
|
|
return 1;
|
|
return _flow.Count < 1 ? 0 : _flow[_flow.Count - 1].Line;
|
|
}
|
|
}
|
|
|
|
public int NumberOfVisibleLines
|
|
{
|
|
get
|
|
{
|
|
if (_flow == null)
|
|
return 1;
|
|
return _flow.FirstFitRunOnFinalLine == null ? 0 : _flow.FirstFitRunOnFinalLine.Line;
|
|
}
|
|
}
|
|
|
|
public bool ContributesToWidth
|
|
{
|
|
get => GetBit(Bits.ContributesToWidth);
|
|
set
|
|
{
|
|
if (ContributesToWidth == value)
|
|
return;
|
|
SetBit(Bits.ContributesToWidth, value);
|
|
FireNotification(NotificationID.ContributesToWidth);
|
|
MarkLayoutInvalid();
|
|
}
|
|
}
|
|
|
|
public TextBounds BoundsType
|
|
{
|
|
get => _boundsType;
|
|
set
|
|
{
|
|
if (_boundsType == value)
|
|
return;
|
|
_boundsType = value;
|
|
MarkLayoutInvalid();
|
|
FireNotification(NotificationID.BoundsType);
|
|
}
|
|
}
|
|
|
|
public bool Clipped => GetBit(Bits.Clipped);
|
|
|
|
private void SetClipped(bool value)
|
|
{
|
|
if (GetBit(Bits.Clipped) == value)
|
|
return;
|
|
SetBit(Bits.Clipped, value);
|
|
FireNotification(NotificationID.Clipped);
|
|
}
|
|
|
|
public RichText ExternalRasterizer
|
|
{
|
|
set
|
|
{
|
|
if (_richTextRasterizer == value)
|
|
return;
|
|
bool oversample = _richTextRasterizer.Oversample;
|
|
_richTextRasterizer = value;
|
|
if (value != null)
|
|
{
|
|
_richTextRasterizer.Oversample = oversample;
|
|
MarkScaleDirty();
|
|
}
|
|
else
|
|
_richTextRasterizer = !oversample ? SharedNonOversampledRasterizer : SharedOversampledRasterizer;
|
|
MarkTextLayoutInvalid();
|
|
}
|
|
}
|
|
|
|
public TextEditingHandler ExternalEditingHandler
|
|
{
|
|
set
|
|
{
|
|
if (_externalEditingHandler == value)
|
|
return;
|
|
_externalEditingHandler = value;
|
|
UpdateWordWrapForExternalRasterizer();
|
|
}
|
|
}
|
|
|
|
private void UpdateWordWrapForExternalRasterizer()
|
|
{
|
|
if (_externalEditingHandler == null)
|
|
return;
|
|
_externalEditingHandler.WordWrap = WordWrap;
|
|
}
|
|
|
|
public ItemAlignment DefaultChildAlignment => ItemAlignment.Default;
|
|
|
|
public bool IsViewDependent(ViewItem node) => GetBit(Bits.ViewDependent);
|
|
|
|
public void GetInitialChildrenRequests(out int more) => more = 0;
|
|
|
|
Size ILayout.Measure(ILayoutNode layoutNode, Size constraint)
|
|
{
|
|
Size zero = Size.Zero;
|
|
InMeasure = true;
|
|
LineAlignment alignment = RichText.ReverseAlignment(_lineAlignment, UISession.IsRtl);
|
|
if (!TextLayoutInvalid && _flow != null && (!WordWrap && alignment == LineAlignment.Near) && (TextFitsWidth && constraint.Width >= _textSize.Width && (TextFitsHeight && constraint.Height >= _textSize.Height)))
|
|
{
|
|
Size size = Size.Min(_textSize, constraint);
|
|
InMeasure = false;
|
|
return size;
|
|
}
|
|
int boundingWidth = constraint.Width;
|
|
if (!ContributesToWidth)
|
|
{
|
|
boundingWidth = 16777215;
|
|
layoutNode.LayoutContributesToWidth = false;
|
|
}
|
|
MeasureText(boundingWidth, constraint.Height, alignment);
|
|
if (alignment != LineAlignment.Near && _flow.Bounds.Width < boundingWidth && _flow.Bounds.Height >= 0)
|
|
MeasureText(_flow.Bounds.Width, _flow.Bounds.Height, alignment);
|
|
bool flag1 = false;
|
|
bool flag2 = false;
|
|
if (_flow.Count > 0)
|
|
{
|
|
Size naturalSize = GetNaturalSize();
|
|
flag1 = naturalSize.Width > boundingWidth;
|
|
flag2 = naturalSize.Height > constraint.Height;
|
|
}
|
|
int x = 0;
|
|
int y = 0;
|
|
if (_flow.Bounds.Left < 0)
|
|
x = -_flow.Bounds.Left;
|
|
if (_flow.Bounds.Top < 0)
|
|
y = -_flow.Bounds.Top;
|
|
Point point1 = new Point(x, y);
|
|
ClipToHeight = false;
|
|
int num1 = -1;
|
|
int num2 = 0;
|
|
int val1_1 = 0;
|
|
int val1_2 = 0;
|
|
int num3 = MaximumLines;
|
|
if (num3 == 0)
|
|
num3 = int.MaxValue;
|
|
int index;
|
|
for (index = 0; index < _flow.Count; ++index)
|
|
{
|
|
TextRun run = _flow[index];
|
|
if (run.Line > num3)
|
|
{
|
|
flag2 = true;
|
|
break;
|
|
}
|
|
if (BoundsType != TextBounds.Full)
|
|
{
|
|
if (run.Line != num1)
|
|
{
|
|
num2 += val1_1 + val1_2;
|
|
val1_1 = 0;
|
|
val1_2 = 0;
|
|
num1 = run.Line;
|
|
}
|
|
Point offsetPoint = point1;
|
|
offsetPoint.Y -= num2;
|
|
if ((BoundsType & TextBounds.AlignToAscender) != TextBounds.Full)
|
|
{
|
|
val1_1 = Math.Max(val1_1, run.AscenderInset);
|
|
offsetPoint.Y -= run.AscenderInset;
|
|
}
|
|
if ((BoundsType & TextBounds.AlignToBaseline) != TextBounds.Full)
|
|
val1_2 = Math.Max(val1_2, run.BaselineInset);
|
|
run.ApplyOffset(offsetPoint);
|
|
}
|
|
int num4 = (BoundsType & TextBounds.AlignToBaseline) != TextBounds.Full ? run.BaselineInset : 0;
|
|
if (run.LayoutBounds.Bottom - num4 > constraint.Height)
|
|
{
|
|
if (run.Line == 1)
|
|
ClipToHeight = true;
|
|
else
|
|
break;
|
|
}
|
|
_flow.AddFit(run);
|
|
}
|
|
_lastVisibleRun = index - 1;
|
|
TextFitsWidth = WordWrap || !flag1;
|
|
TextFitsHeight = !flag2;
|
|
if (!TextFitsHeight && _flow.HasVisibleRuns)
|
|
{
|
|
_lastLineExtentLeft = _flow.FirstFitRunOnFinalLine.LayoutBounds.Left;
|
|
_lastLineExtentRight = _flow.LastFitRun.LayoutBounds.Right;
|
|
}
|
|
else
|
|
_lastLineExtentLeft = _lastLineExtentRight = 0.0f;
|
|
InvalidateGradients();
|
|
if (UpdateFragmentsAfterLayout)
|
|
((ViewItem)layoutNode).MarkLayoutOutputDirty(true);
|
|
Point point2 = new Point(_flow.Bounds.Location.X + point1.X, _flow.Bounds.Location.Y + point1.Y);
|
|
_textSize = new Size(_flow.Bounds.Width + point2.X, _flow.FitBounds.Height + point2.Y - (val1_1 + val1_2));
|
|
Size constraint1 = Size.Min(_textSize, constraint);
|
|
DefaultLayout.Measure(layoutNode, constraint1);
|
|
FireNotification(NotificationID.LastLineBounds);
|
|
InMeasure = false;
|
|
return constraint1;
|
|
}
|
|
|
|
void ILayout.Arrange(ILayoutNode layoutNode, LayoutSlot slot)
|
|
{
|
|
_slotSize = slot.Bounds;
|
|
if (!ContributesToWidth)
|
|
TextFitsWidth = _textSize.Width <= slot.Bounds.Width;
|
|
_lineAlignmentOffset = 0;
|
|
if (TextFitsWidth)
|
|
{
|
|
if (LineAlignment == LineAlignment.Center)
|
|
_lineAlignmentOffset = (_slotSize.Width - _textSize.Width) / 2;
|
|
else if (LineAlignment == LineAlignment.Far)
|
|
_lineAlignmentOffset = _slotSize.Width - _textSize.Width;
|
|
}
|
|
bool flag1 = false;
|
|
if (_flow != null)
|
|
{
|
|
Rectangle view = slot.View;
|
|
Size size = view.Size;
|
|
bool flag2 = _textSize.Width > size.Width || _textSize.Height > size.Height;
|
|
flag1 = ((flag1 ? 1 : 0) | (!KeepFlowAlive ? 0 : (flag2 ? 1 : 0))) != 0;
|
|
_flow.ResetVisibleTracking();
|
|
if (flag1)
|
|
{
|
|
bool flag3 = false;
|
|
for (int index = 0; index <= _lastVisibleRun; ++index)
|
|
{
|
|
TextRun textRun = _flow[index];
|
|
bool flag4 = !textRun.LayoutBounds.IsEmpty && textRun.LayoutBounds.IntersectsWith(view);
|
|
if (!flag3 && textRun.Visible != flag4)
|
|
{
|
|
MarkPaintInvalid();
|
|
UpdateFragmentsAfterLayout = true;
|
|
flag3 = true;
|
|
}
|
|
if (flag4)
|
|
_flow.AddVisible(index);
|
|
else
|
|
textRun.Visible = false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for (int index = 0; index <= _lastVisibleRun; ++index)
|
|
{
|
|
TextRun textRun = _flow[index];
|
|
if (!textRun.LayoutBounds.IsEmpty)
|
|
{
|
|
if (!textRun.Visible)
|
|
MarkPaintInvalid();
|
|
_flow.AddVisible(index);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
KeepFlowAlive |= flag1;
|
|
SetBit(Bits.ViewDependent, flag1);
|
|
DefaultLayout.Arrange(layoutNode, slot);
|
|
}
|
|
|
|
private Size GetNaturalSize()
|
|
{
|
|
if (!FastMeasurePossible)
|
|
return _richTextRasterizer.GetNaturalBounds();
|
|
return _flow.Count == 1 ? _flow[0].NaturalExtent : Size.Zero;
|
|
}
|
|
|
|
private void MeasureText(int boundingWidth, int boundingHeight, LineAlignment alignment)
|
|
{
|
|
if (FastMeasurePossible)
|
|
DoFastMeasure(boundingWidth, boundingHeight, alignment);
|
|
else
|
|
DoRichEditMeasure(boundingWidth, boundingHeight, alignment);
|
|
}
|
|
|
|
private void DoFastMeasure(int boundingWidth, int boundingHeight, LineAlignment alignment)
|
|
{
|
|
TextStyle effectiveTextStyle = GetEffectiveTextStyle();
|
|
Size constraint = new Size(boundingWidth, boundingHeight);
|
|
DisposeFlow();
|
|
_flow = SharedSimpleTextRasterizer.Measure(_content, alignment, effectiveTextStyle, constraint);
|
|
_flow.DeclareOwner(this);
|
|
}
|
|
|
|
private void DoRichEditMeasure(int boundingWidth, int boundingHeight, LineAlignment alignment)
|
|
{
|
|
TextMeasureParams measureParams = new TextMeasureParams();
|
|
measureParams.Initialize();
|
|
float width = Math.Min(boundingWidth, 4095f);
|
|
float height = Math.Min(boundingHeight, 8191f);
|
|
measureParams.SetConstraint(new SizeF(width, height));
|
|
TextStyle effectiveTextStyle = GetEffectiveTextStyle();
|
|
string empty = string.Empty;
|
|
string content;
|
|
if (!UsedForEditing)
|
|
{
|
|
content = Content;
|
|
if (_namedStyles != null)
|
|
{
|
|
if (_parsedContent == null && content != null)
|
|
{
|
|
_parsedContentMarkedRanges = new ArrayList();
|
|
_parsedContent = ParseMarkedUpText(content, _parsedContentMarkedRanges);
|
|
}
|
|
content = _parsedContent;
|
|
}
|
|
measureParams.SetWordWrap(WordWrap);
|
|
}
|
|
else
|
|
content = _richTextRasterizer.SimpleContent;
|
|
measureParams.SetEditMode(UsedForEditing);
|
|
if (UsePasswordMask)
|
|
measureParams.SetPasswordChar(_passwordChar);
|
|
measureParams.SetFormat(alignment, effectiveTextStyle);
|
|
if ((_boundsType & TextBounds.TrimLeftSideBearing) != TextBounds.Full && _lineAlignment == LineAlignment.Near)
|
|
measureParams.TrimLeftSideBearing();
|
|
if (!UsedForEditing || GetBit(Bits.ScaleDirty))
|
|
{
|
|
ClearBit(Bits.ScaleDirty);
|
|
measureParams.SetScale(_scale);
|
|
}
|
|
if (_parsedContent != null)
|
|
ApplyContentFormatting(ref measureParams);
|
|
DisposeFlow();
|
|
_flow = _richTextRasterizer.Measure(content, ref measureParams);
|
|
measureParams.Dispose();
|
|
_flow.DeclareOwner(this);
|
|
UpdateFragmentsAfterLayout = true;
|
|
}
|
|
|
|
private bool FastMeasurePossible
|
|
{
|
|
get
|
|
{
|
|
if (!GetBit(Bits.FastMeasureValid))
|
|
{
|
|
bool flag = UsingSharedRasterizer && !WordWrap && (_namedStyles == null && _scale == 1.0) && (TextSharpness == TextSharpness.Sharp && !UsePasswordMask) && !Zone.Session.IsRtl;
|
|
if (flag)
|
|
flag = SharedSimpleTextRasterizer.CanMeasure(Content, GetEffectiveTextStyle());
|
|
SetBit(Bits.FastMeasurePossible, flag);
|
|
SetBit(Bits.FastMeasureValid);
|
|
}
|
|
return GetBit(Bits.FastMeasurePossible);
|
|
}
|
|
}
|
|
|
|
internal TextStyle GetEffectiveTextStyle()
|
|
{
|
|
TextStyle textStyle = new TextStyle();
|
|
Font font = _font ?? s_defaultFont;
|
|
textStyle.FontFace = font.FontName;
|
|
textStyle.FontSize = font.FontSize;
|
|
if (font.AltFontSize != (double)font.FontSize)
|
|
textStyle.AltFontSize = font.AltFontSize;
|
|
if ((font.FontStyle & FontStyles.Bold) != FontStyles.None)
|
|
textStyle.Bold = true;
|
|
if ((font.FontStyle & FontStyles.Italic) != FontStyles.None)
|
|
textStyle.Italic = true;
|
|
if ((font.FontStyle & FontStyles.Underline) != FontStyles.None)
|
|
textStyle.Underline = true;
|
|
textStyle.Color = _textColor;
|
|
if (GetBit(Bits.LineSpacingSet))
|
|
textStyle.LineSpacing = LineSpacing;
|
|
if (GetBit(Bits.CharacterSpacingSet))
|
|
textStyle.CharacterSpacing = CharacterSpacing;
|
|
if (GetBit(Bits.EnableKerningSet))
|
|
textStyle.EnableKerning = EnableKerning;
|
|
if (_textStyle != null)
|
|
textStyle.Add(_textStyle);
|
|
return textStyle;
|
|
}
|
|
|
|
protected override void OnLayoutComplete(ViewItem sender)
|
|
{
|
|
ArrayList arrayList = null;
|
|
if (UpdateFragmentsAfterLayout)
|
|
{
|
|
if (_namedStyles != null)
|
|
arrayList = AnnotateFragments();
|
|
bool flag = false;
|
|
if (_fragments != null || arrayList != null)
|
|
flag = TextLayoutInvalid || !AreFragmentListsEquivalent(_fragments, arrayList);
|
|
if (flag)
|
|
{
|
|
UnregisterFragmentUsage();
|
|
_fragments = arrayList;
|
|
RegisterFragmentUsage();
|
|
FireNotification(NotificationID.Fragments);
|
|
}
|
|
else if (_fragments != null)
|
|
{
|
|
for (int index = 0; index < _fragments.Count; ++index)
|
|
((TextFragment)_fragments[index]).NotifyPaintInvalid();
|
|
}
|
|
ResetMarkedRanges();
|
|
UpdateFragmentsAfterLayout = false;
|
|
}
|
|
SetClipped(!TextFitsWidth || !TextFitsHeight);
|
|
TextLayoutInvalid = false;
|
|
base.OnLayoutComplete(sender);
|
|
}
|
|
|
|
private static bool AreFragmentListsEquivalent(IList lhsFragments, IList rhsFragments)
|
|
{
|
|
int num1 = lhsFragments != null ? lhsFragments.Count : 0;
|
|
int num2 = rhsFragments != null ? rhsFragments.Count : 0;
|
|
if (num1 != num2)
|
|
return false;
|
|
for (int index = 0; index < num1; ++index)
|
|
{
|
|
if (!((TextFragment)lhsFragments[index]).IsLayoutEquivalentTo((TextFragment)rhsFragments[index]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
private void ApplyContentFormatting(ref TextMeasureParams measureParams)
|
|
{
|
|
if (_parsedContentMarkedRanges == null || _namedStyles == null)
|
|
return;
|
|
if (!UsingSharedRasterizer)
|
|
{
|
|
ErrorManager.ReportError("Text: Complex formatting unsupported on text that is editable");
|
|
}
|
|
else
|
|
{
|
|
measureParams.AllocateFormattedRanges(_parsedContentMarkedRanges.Count, _namedStyles.Count);
|
|
TextStyle[] array = new TextStyle[_namedStyles.Count];
|
|
int index1 = 0;
|
|
foreach (TextStyle style in _namedStyles.Values)
|
|
{
|
|
measureParams.SetFormattedRangeStyle(index1, style);
|
|
array[index1] = style;
|
|
++index1;
|
|
}
|
|
TextMeasureParams.FormattedRange[] formattedRanges = measureParams.FormattedRanges;
|
|
for (int index2 = 0; index2 < _parsedContentMarkedRanges.Count; ++index2)
|
|
{
|
|
Microsoft.Iris.ViewItems.Text.MarkedRange contentMarkedRange = (Microsoft.Iris.ViewItems.Text.MarkedRange)_parsedContentMarkedRanges[index2];
|
|
if (_namedStyles.Contains(contentMarkedRange.tagName))
|
|
{
|
|
TextStyle namedStyle = _namedStyles[contentMarkedRange.tagName] as TextStyle;
|
|
contentMarkedRange.cachedStyle = namedStyle;
|
|
if (namedStyle != null)
|
|
{
|
|
formattedRanges[index2].FirstCharacter = contentMarkedRange.firstCharacter;
|
|
formattedRanges[index2].LastCharacter = contentMarkedRange.lastCharacter;
|
|
formattedRanges[index2].Color = contentMarkedRange.RangeIDAsColor;
|
|
formattedRanges[index2].StyleIndex = Array.IndexOf<TextStyle>(array, namedStyle);
|
|
}
|
|
}
|
|
else
|
|
contentMarkedRange.cachedStyle = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
private ArrayList AnnotateFragments()
|
|
{
|
|
ArrayList arrayList = null;
|
|
if (_parsedContentMarkedRanges != null && _flow != null)
|
|
{
|
|
for (int firstVisibleIndex = _flow.FirstVisibleIndex; firstVisibleIndex <= _flow.LastVisibleIndex; ++firstVisibleIndex)
|
|
{
|
|
TextRun textRun = _flow[firstVisibleIndex];
|
|
textRun.IsFragment = false;
|
|
if (textRun.RunColor.A != byte.MaxValue)
|
|
{
|
|
Microsoft.Iris.ViewItems.Text.MarkedRange markedRange = null;
|
|
for (int index = 0; index < _parsedContentMarkedRanges.Count; ++index)
|
|
{
|
|
Microsoft.Iris.ViewItems.Text.MarkedRange contentMarkedRange = (Microsoft.Iris.ViewItems.Text.MarkedRange)_parsedContentMarkedRanges[index];
|
|
if (contentMarkedRange.RangeIDAsColor == textRun.RunColor)
|
|
{
|
|
textRun.OverrideColor = contentMarkedRange.GetEffectiveColor(Color.Transparent);
|
|
markedRange = contentMarkedRange;
|
|
break;
|
|
}
|
|
}
|
|
if (markedRange != null && markedRange.IsInFragment)
|
|
{
|
|
textRun.IsFragment = true;
|
|
if (markedRange.fragment == null)
|
|
{
|
|
markedRange.fragment = new TextFragment(markedRange.tagName, markedRange.attributes, this);
|
|
if (arrayList == null)
|
|
arrayList = new ArrayList();
|
|
arrayList.Add(markedRange.fragment);
|
|
}
|
|
markedRange.fragment.InternalRuns.Add(new TextRunData(textRun, IsOnLastLine(textRun), this, _lineAlignmentOffset));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return arrayList;
|
|
}
|
|
|
|
private void RegisterFragmentUsage()
|
|
{
|
|
if (_fragments == null)
|
|
return;
|
|
foreach (TextFragment fragment in _fragments)
|
|
{
|
|
if (fragment.Runs != null)
|
|
{
|
|
foreach (TextRunData run in fragment.Runs)
|
|
run.Run.RegisterUsage(this);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void UnregisterFragmentUsage()
|
|
{
|
|
if (_fragments == null)
|
|
return;
|
|
foreach (TextFragment fragment in _fragments)
|
|
{
|
|
if (fragment.Runs != null)
|
|
{
|
|
foreach (TextRunData run in fragment.Runs)
|
|
run.Run.UnregisterUsage(this);
|
|
}
|
|
}
|
|
_fragments = null;
|
|
}
|
|
|
|
private void ResetMarkedRanges()
|
|
{
|
|
if (_parsedContentMarkedRanges == null)
|
|
return;
|
|
for (int index = 0; index < _parsedContentMarkedRanges.Count; ++index)
|
|
((Microsoft.Iris.ViewItems.Text.MarkedRange)_parsedContentMarkedRanges[index]).fragment = null;
|
|
}
|
|
|
|
private static string ParseMarkedUpText(string content, ArrayList markedRanges)
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
ArrayList arrayList = new ArrayList();
|
|
uint num = 0;
|
|
try
|
|
{
|
|
using (ManagedXmlReader nativeXmlReader = new ManagedXmlReader(content, true))
|
|
{
|
|
MarkedRange markedRange1 = null;
|
|
XmlNodeType nodeType;
|
|
while (nativeXmlReader.Read(out nodeType))
|
|
{
|
|
switch (nodeType)
|
|
{
|
|
case XmlNodeType.Element:
|
|
if (!nativeXmlReader.IsEmptyElement)
|
|
{
|
|
string name = nativeXmlReader.Name;
|
|
MarkedRange markedRange2 = new MarkedRange();
|
|
markedRange2.tagName = name;
|
|
markedRange2.firstCharacter = stringBuilder.Length;
|
|
markedRange2.lastCharacter = int.MaxValue;
|
|
markedRange2.rangeID = ++num;
|
|
arrayList.Add(markedRange2);
|
|
markedRanges.Add(markedRange2);
|
|
markedRange2.parentRange = markedRange1;
|
|
markedRange1 = markedRange2;
|
|
while (nativeXmlReader.ReadAttribute())
|
|
{
|
|
if (markedRange1.attributes == null)
|
|
markedRange1.attributes = new Dictionary<object, object>();
|
|
markedRange1.attributes[nativeXmlReader.Name] = nativeXmlReader.Value;
|
|
}
|
|
continue;
|
|
}
|
|
continue;
|
|
case XmlNodeType.Text:
|
|
case XmlNodeType.CDATA:
|
|
case XmlNodeType.Whitespace:
|
|
string str = nativeXmlReader.Value;
|
|
if (str.IndexOf("\r\n", StringComparison.Ordinal) >= 0)
|
|
str = str.Replace("\r\n", "\r");
|
|
stringBuilder.Append(str);
|
|
continue;
|
|
case XmlNodeType.EndElement:
|
|
string name1 = nativeXmlReader.Name;
|
|
for (int index = arrayList.Count - 1; index >= 0; --index)
|
|
{
|
|
MarkedRange markedRange2 = (MarkedRange)arrayList[index];
|
|
markedRange2.lastCharacter = stringBuilder.Length;
|
|
arrayList.RemoveAt(index);
|
|
if (markedRange2.tagName == name1)
|
|
break;
|
|
}
|
|
if (markedRange1 != null)
|
|
{
|
|
markedRange1 = markedRange1.parentRange;
|
|
continue;
|
|
}
|
|
continue;
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
catch (XmlException ex)
|
|
{
|
|
markedRanges.Clear();
|
|
stringBuilder = null;
|
|
}
|
|
if (stringBuilder == null)
|
|
return content;
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
public void CreateFadeGradientsHelper(
|
|
ref IGradient gradientClipLeftRight,
|
|
ref IGradient gradientMultiLine)
|
|
{
|
|
bool flag1 = true;
|
|
if (TextFitsWidth && TextFitsHeight)
|
|
flag1 = false;
|
|
float fadeSize = FadeSize;
|
|
if (!flag1 || fadeSize <= 0.0)
|
|
return;
|
|
if (!WordWrap)
|
|
{
|
|
if (TextFitsWidth)
|
|
return;
|
|
float num = 0.0f;
|
|
float flPosition = 0.0f;
|
|
LineAlignment lineAlignment = LineAlignment;
|
|
if (lineAlignment == LineAlignment.Center)
|
|
{
|
|
flPosition = num = fadeSize;
|
|
}
|
|
else
|
|
{
|
|
bool flag2 = lineAlignment == LineAlignment.Near;
|
|
if (UISession.IsRtl)
|
|
flag2 = !flag2;
|
|
if (flag2)
|
|
num = fadeSize;
|
|
else
|
|
flPosition = fadeSize;
|
|
}
|
|
IGradient gradient = UISession.RenderSession.CreateGradient(this);
|
|
gradient.Orientation = Orientation.Horizontal;
|
|
if (flPosition > 0.0)
|
|
{
|
|
gradient.AddValue(-1f, 0.0f, RelativeSpace.Min);
|
|
gradient.AddValue(flPosition, 1f, RelativeSpace.Min);
|
|
}
|
|
if (num > 0.0)
|
|
{
|
|
gradient.AddValue(_slotSize.Width - num, 1f, RelativeSpace.Min);
|
|
gradient.AddValue(_slotSize.Width + 1, 0.0f, RelativeSpace.Min);
|
|
}
|
|
gradientClipLeftRight = gradient;
|
|
}
|
|
else
|
|
{
|
|
if (TextFitsHeight)
|
|
return;
|
|
float flPosition1 = 0.0f;
|
|
float flPosition2 = 0.0f;
|
|
if (!UISession.IsRtl)
|
|
{
|
|
if (_flow.LastFitRun != null)
|
|
{
|
|
flPosition2 = _flow.LastFitRun.LayoutBounds.Width;
|
|
flPosition1 = flPosition2 - fadeSize;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
flPosition2 = 0.0f;
|
|
flPosition1 = flPosition2 + fadeSize;
|
|
}
|
|
IGradient gradient = UISession.RenderSession.CreateGradient(this);
|
|
gradient.ColorMask = new ColorF(byte.MaxValue, 0, 0, 0);
|
|
gradient.Orientation = Orientation.Horizontal;
|
|
gradient.AddValue(flPosition1, 1f, RelativeSpace.Min);
|
|
gradient.AddValue(flPosition2, 0.0f, RelativeSpace.Min);
|
|
gradientMultiLine = gradient;
|
|
}
|
|
}
|
|
|
|
private bool UsingSharedRasterizer => !_richTextRasterizer.HasCallbacks;
|
|
|
|
private bool UsedForEditing => _externalEditingHandler != null;
|
|
|
|
private void ResetCachedScaleState()
|
|
{
|
|
IgnoreEffectiveScaleChanges = false;
|
|
_recentScaleChanges = null;
|
|
}
|
|
|
|
private void CreateVisuals(IVisualContainer topVisual, IRenderSession renderSession)
|
|
{
|
|
VisualOrder nOrder = VisualOrder.First;
|
|
IGradient gradientClipLeftRight = null;
|
|
IGradient gradientMultiLine = null;
|
|
CreateFadeGradientsHelper(ref gradientClipLeftRight, ref gradientMultiLine);
|
|
TextRun textRun = UISession.IsRtl ? _flow.FirstFitRunOnFinalLine : _flow.LastFitRun;
|
|
for (int firstVisibleIndex = _flow.FirstVisibleIndex; firstVisibleIndex <= _flow.LastVisibleIndex; ++firstVisibleIndex)
|
|
{
|
|
TextRun run = _flow[firstVisibleIndex];
|
|
if (run.Visible && !run.IsFragment)
|
|
{
|
|
Color effectiveColor = GetEffectiveColor(run);
|
|
IImage imageForRun = GetImageForRun(UISession, run, effectiveColor);
|
|
if (imageForRun != null)
|
|
{
|
|
float x = run.RenderBounds.Left + _lineAlignmentOffset;
|
|
if (run.Highlighted)
|
|
{
|
|
RectangleF lineBound = (RectangleF)_flow.LineBounds[run.Line - 1];
|
|
ISprite sprite = renderSession.CreateSprite(this, this);
|
|
sprite.Effect = EffectManager.CreateColorFillEffect(this, _backHighlightColor);
|
|
sprite.Effect.UnregisterUsage(this);
|
|
sprite.Position = new Vector3(x, lineBound.Top, 0.0f);
|
|
sprite.Size = new Vector2(run.RenderBounds.Width, lineBound.Height);
|
|
topVisual.AddChild(sprite, null, nOrder);
|
|
sprite.UnregisterUsage(this);
|
|
run.HighlightSprite = sprite;
|
|
}
|
|
ISprite sprite1 = renderSession.CreateSprite(this, this);
|
|
sprite1.Effect = EffectClass.CreateImageRenderEffectWithFallback(Effect, this, imageForRun);
|
|
sprite1.Effect.UnregisterUsage(this);
|
|
sprite1.Position = new Vector3(x, run.RenderBounds.Top, 0.0f);
|
|
sprite1.Size = new Vector2(run.RenderBounds.Width, run.RenderBounds.Height);
|
|
if (gradientMultiLine != null && run == textRun)
|
|
sprite1.AddGradient(gradientMultiLine);
|
|
topVisual.AddChild(sprite1, null, nOrder);
|
|
sprite1.UnregisterUsage(this);
|
|
run.TextSprite = sprite1;
|
|
}
|
|
}
|
|
}
|
|
topVisual.RemoveAllGradients();
|
|
if (gradientClipLeftRight != null)
|
|
topVisual.AddGradient(gradientClipLeftRight);
|
|
gradientClipLeftRight?.UnregisterUsage(this);
|
|
gradientMultiLine?.UnregisterUsage(this);
|
|
}
|
|
|
|
private Color GetEffectiveColor(TextRun run)
|
|
{
|
|
Color color = _textColor;
|
|
if (run.Highlighted)
|
|
color = _textHighlightColor;
|
|
else if (run.OverrideColor != Color.Transparent)
|
|
color = run.OverrideColor;
|
|
else if (run.Link && _externalEditingHandler != null && _externalEditingHandler.LinkColor != Color.Transparent)
|
|
color = _externalEditingHandler.LinkColor;
|
|
else if (_textStyle != null && _textStyle.HasColor)
|
|
color = _textStyle.Color;
|
|
return color;
|
|
}
|
|
|
|
protected override void DisposeAllContent()
|
|
{
|
|
base.DisposeAllContent();
|
|
DisposeContent(true);
|
|
}
|
|
|
|
protected virtual void DisposeContent(bool removeFromTree)
|
|
{
|
|
if (removeFromTree)
|
|
VisualContainer.RemoveAllChildren();
|
|
Effect?.DoneWithRenderEffects(this);
|
|
if (_flow == null)
|
|
return;
|
|
_flow.ClearSprites();
|
|
}
|
|
|
|
protected override void OnPaint(bool visible)
|
|
{
|
|
DisposeAllContent();
|
|
base.OnPaint(visible);
|
|
ResetCachedScaleState();
|
|
if (_flow == null)
|
|
{
|
|
if (_content == null && UsingSharedRasterizer)
|
|
return;
|
|
MarkTextLayoutInvalid();
|
|
}
|
|
else
|
|
{
|
|
CreateVisuals(VisualContainer, UISession.RenderSession);
|
|
if (!KeepFlowAlive)
|
|
DisposeFlow();
|
|
HasEverPainted = true;
|
|
}
|
|
}
|
|
|
|
private bool IsOnLastLine(TextRun run) => _flow.IsOnLastLine(run);
|
|
|
|
private void InvalidateGradients()
|
|
{
|
|
_renderingHelper.InvalidateGradients();
|
|
MarkPaintInvalid();
|
|
}
|
|
|
|
protected override void OnEffectiveScaleChange()
|
|
{
|
|
float y = ComputeEffectiveScale().Y;
|
|
if (!ScaleDifferenceIsGreaterThanThreshold(y, _scale))
|
|
return;
|
|
Vector<float> vector = _recentScaleChanges;
|
|
if (!IgnoreEffectiveScaleChanges && vector != null)
|
|
{
|
|
foreach (float newScale in vector)
|
|
{
|
|
if (!ScaleDifferenceIsGreaterThanThreshold(y, newScale))
|
|
{
|
|
IgnoreEffectiveScaleChanges = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (IgnoreEffectiveScaleChanges)
|
|
return;
|
|
if (vector == null)
|
|
vector = new Vector<float>(4);
|
|
vector.Add(y);
|
|
_recentScaleChanges = vector;
|
|
MarkTextLayoutInvalid();
|
|
_scale = y;
|
|
MarkScaleDirty();
|
|
}
|
|
|
|
private bool ScaleDifferenceIsGreaterThanThreshold(float oldScale, float newScale) => Math.Abs(oldScale - newScale) > 0.00999999977648258;
|
|
|
|
private void MarkTextLayoutInvalid()
|
|
{
|
|
TextLayoutInvalid = true;
|
|
if (s_simpleTextMeasureAvailable)
|
|
ClearBit(Bits.FastMeasureValid);
|
|
DisposeFlow();
|
|
MarkLayoutInvalid();
|
|
}
|
|
|
|
internal static IImage GetImageForRun(UISession session, TextRun run, Color textColor)
|
|
{
|
|
if (string.IsNullOrEmpty(run.Content))
|
|
return null;
|
|
string str = "aa";
|
|
bool flag = false;
|
|
RichTextInfoKey richTextInfoKey = new RichTextInfoKey(run, str, flag, textColor);
|
|
ImageCache instance = TextImageCache.Instance;
|
|
ImageCacheItem imageCacheItem = instance.Lookup(richTextInfoKey);
|
|
if (imageCacheItem == null)
|
|
{
|
|
imageCacheItem = new TextImageItem(session.RenderSession, run, str, flag, textColor);
|
|
instance.Add(richTextInfoKey, imageCacheItem);
|
|
}
|
|
return imageCacheItem.RenderImage;
|
|
}
|
|
|
|
public override string ToString()
|
|
{
|
|
StringBuilder stringBuilder = new StringBuilder();
|
|
stringBuilder.Append(base.ToString());
|
|
if (_content != null)
|
|
{
|
|
stringBuilder.Append(" (Content=\"");
|
|
stringBuilder.Append(_content);
|
|
stringBuilder.Append("\")");
|
|
}
|
|
return stringBuilder.ToString();
|
|
}
|
|
|
|
private bool TextFitsWidth
|
|
{
|
|
get => GetBit(Bits.TextFitsWidth);
|
|
set => SetBit(Bits.TextFitsWidth, value);
|
|
}
|
|
|
|
private bool TextFitsHeight
|
|
{
|
|
get => GetBit(Bits.TextFitsHeight);
|
|
set => SetBit(Bits.TextFitsHeight, value);
|
|
}
|
|
|
|
private bool ClipToHeight
|
|
{
|
|
get => GetBit(Bits.ClipToHeight);
|
|
set => SetBit(Bits.ClipToHeight, value);
|
|
}
|
|
|
|
private bool KeepFlowAlive
|
|
{
|
|
get => GetBit(Bits.KeepFlowAlive);
|
|
set => SetBit(Bits.KeepFlowAlive, value);
|
|
}
|
|
|
|
private bool HasEverPainted
|
|
{
|
|
get => GetBit(Bits.HasEverPainted);
|
|
set => SetBit(Bits.HasEverPainted, value);
|
|
}
|
|
|
|
private bool TextLayoutInvalid
|
|
{
|
|
get => GetBit(Bits.TextLayoutInvalid);
|
|
set => SetBit(Bits.TextLayoutInvalid, value);
|
|
}
|
|
|
|
private bool UpdateFragmentsAfterLayout
|
|
{
|
|
get => GetBit(Bits.UpdateFragmentsAfterLayout);
|
|
set => SetBit(Bits.UpdateFragmentsAfterLayout, value);
|
|
}
|
|
|
|
private bool IgnoreEffectiveScaleChanges
|
|
{
|
|
get => GetBit(Bits.IgnoreEffectiveScaleChanges);
|
|
set => SetBit(Bits.IgnoreEffectiveScaleChanges, value);
|
|
}
|
|
|
|
private bool GetBit(Bits lookupBit) => ((Bits)_bits & lookupBit) != 0;
|
|
|
|
private void SetBit(Bits changeBit, bool value) => _bits = value ? (uint)((Bits)_bits | changeBit) : (uint)((Bits)_bits & ~changeBit);
|
|
|
|
private void SetBit(Bits changeBit)
|
|
{
|
|
Text text = this;
|
|
text._bits = (uint)((Bits)text._bits | changeBit);
|
|
}
|
|
|
|
private void ClearBit(Bits changeBit)
|
|
{
|
|
Text text = this;
|
|
text._bits = (uint)((Bits)text._bits & ~changeBit);
|
|
}
|
|
|
|
private class MarkedRange
|
|
{
|
|
public string tagName;
|
|
public int firstCharacter;
|
|
public int lastCharacter;
|
|
public uint rangeID;
|
|
public Dictionary<object, object> attributes;
|
|
public MarkedRange parentRange;
|
|
public TextStyle cachedStyle;
|
|
public TextFragment fragment;
|
|
private static uint s_rangeIDIndicator = 1073741824;
|
|
|
|
public Color RangeIDAsColor => new Color(s_rangeIDIndicator | rangeID);
|
|
|
|
public Color GetEffectiveColor(Color defaultColor)
|
|
{
|
|
if (cachedStyle != null && cachedStyle.HasColor)
|
|
return cachedStyle.Color;
|
|
return parentRange != null ? parentRange.GetEffectiveColor(defaultColor) : defaultColor;
|
|
}
|
|
|
|
public bool IsInFragment
|
|
{
|
|
get
|
|
{
|
|
bool flag = false;
|
|
for (MarkedRange markedRange = this; markedRange != null; markedRange = markedRange.parentRange)
|
|
{
|
|
TextStyle cachedStyle = markedRange.cachedStyle;
|
|
if (cachedStyle != null && cachedStyle.Fragment)
|
|
{
|
|
flag = true;
|
|
break;
|
|
}
|
|
}
|
|
return flag;
|
|
}
|
|
}
|
|
}
|
|
|
|
private new enum Bits : uint
|
|
{
|
|
TextFitsWidth = 1,
|
|
TextFitsHeight = 2,
|
|
ClipToHeight = 4,
|
|
WordWrap = 8,
|
|
PasswordMasked = 16, // 0x00000010
|
|
KeepFlowAlive = 32, // 0x00000020
|
|
TextLayoutInvalid = 64, // 0x00000040
|
|
UpdateFragmentsAfterLayout = 128, // 0x00000080
|
|
IgnoreEffectiveScaleChanges = 256, // 0x00000100
|
|
Clipped = 512, // 0x00000200
|
|
InMeasure = 1024, // 0x00000400
|
|
FastMeasureValid = 2048, // 0x00000800
|
|
FastMeasurePossible = 4096, // 0x00001000
|
|
ContributesToWidth = 8192, // 0x00002000
|
|
ScaleDirty = 16384, // 0x00004000
|
|
HasEverPainted = 32768, // 0x00008000
|
|
LineSpacingSet = 65536, // 0x00010000
|
|
CharacterSpacingSet = 131072, // 0x00020000
|
|
EnableKerningSet = 262144, // 0x00040000
|
|
ViewDependent = 524288, // 0x00080000
|
|
}
|
|
}
|
|
}
|