public TextCharacters(ReadOnlySlice <char> text, int offsetToFirstCharacter, int length, TextRunProperties properties) { Text = text.Skip(offsetToFirstCharacter).Take(length); TextSourceLength = length; Properties = properties; }
private static IType MakeRecursiveGenericTypeImpl( IType type, IReadOnlyList <IType> recursiveGenericArguments, ref int offset) { var parentType = type.Parent.TypeOrNull; if (parentType != null) { parentType = MakeRecursiveGenericTypeImpl( parentType, recursiveGenericArguments, ref offset); if (parentType is TypeSpecialization) { type = IndirectTypeSpecialization.Create(type, (TypeSpecialization)parentType); } } if (offset >= recursiveGenericArguments.Count) { return(type); } else { var parameterCount = type.GenericParameters.Count; var slice = new ReadOnlySlice <IType>( recursiveGenericArguments, offset, parameterCount); offset += parameterCount; return(type.MakeGenericType(slice.ToArray())); } }
/// <summary> /// Initializes a new instance of the <see cref="TextLayout" /> class. /// </summary> /// <param name="text">The text.</param> /// <param name="typeface">The typeface.</param> /// <param name="fontSize">Size of the font.</param> /// <param name="foreground">The foreground.</param> /// <param name="textAlignment">The text alignment.</param> /// <param name="textWrapping">The text wrapping.</param> /// <param name="textTrimming">The text trimming.</param> /// <param name="textDecorations">The text decorations.</param> /// <param name="maxWidth">The maximum width.</param> /// <param name="maxHeight">The maximum height.</param> /// <param name="lineHeight">The height of each line of text.</param> /// <param name="maxLines">The maximum number of text lines.</param> /// <param name="textStyleOverrides">The text style overrides.</param> public TextLayout( string text, Typeface typeface, double fontSize, IBrush foreground, TextAlignment textAlignment = TextAlignment.Left, TextWrapping textWrapping = TextWrapping.NoWrap, TextTrimming textTrimming = TextTrimming.None, TextDecorationCollection textDecorations = null, double maxWidth = double.PositiveInfinity, double maxHeight = double.PositiveInfinity, double lineHeight = double.NaN, int maxLines = 0, IReadOnlyList <ValueSpan <TextRunProperties> > textStyleOverrides = null) { _text = string.IsNullOrEmpty(text) ? new ReadOnlySlice <char>() : new ReadOnlySlice <char>(text.AsMemory()); _paragraphProperties = CreateTextParagraphProperties(typeface, fontSize, foreground, textAlignment, textWrapping, textTrimming, textDecorations, lineHeight); _textStyleOverrides = textStyleOverrides; LineHeight = lineHeight; MaxWidth = maxWidth; MaxHeight = maxHeight; MaxLines = maxLines; UpdateLayout(); }
/// <summary> /// Initializes a new instance of the <see cref="GlyphRun"/> class by specifying properties of the class. /// </summary> /// <param name="glyphTypeface">The glyph typeface.</param> /// <param name="fontRenderingEmSize">The rendering em size.</param> /// <param name="glyphIndices">The glyph indices.</param> /// <param name="glyphAdvances">The glyph advances.</param> /// <param name="glyphOffsets">The glyph offsets.</param> /// <param name="characters">The characters.</param> /// <param name="glyphClusters">The glyph clusters.</param> /// <param name="biDiLevel">The bidi level.</param> public GlyphRun( GlyphTypeface glyphTypeface, double fontRenderingEmSize, ReadOnlySlice <char> characters, IReadOnlyList <ushort> glyphIndices, IReadOnlyList <double>?glyphAdvances = null, IReadOnlyList <Vector>?glyphOffsets = null, IReadOnlyList <int>?glyphClusters = null, int biDiLevel = 0) { _glyphTypeface = glyphTypeface; FontRenderingEmSize = fontRenderingEmSize; Characters = characters; _glyphIndices = glyphIndices; GlyphAdvances = glyphAdvances; GlyphOffsets = glyphOffsets; GlyphClusters = glyphClusters; BiDiLevel = biDiLevel; }
public FormattedTextSource(ReadOnlySlice <char> text, TextStyle defaultStyle, IReadOnlyList <TextStyleRun> textStyleOverrides) { _text = text; _defaultStyle = defaultStyle; _textStyleOverrides = textStyleOverrides; }
public ShapeableTextCharacters(ReadOnlySlice <char> text, TextRunProperties properties, sbyte biDiLevel) { TextSourceLength = text.Length; Text = text; Properties = properties; BidiLevel = biDiLevel; }
public FormattedTextSource(ReadOnlySlice <char> text, TextRunProperties defaultProperties, IReadOnlyList <ValueSpan <TextRunProperties> > textModifier) { _text = text; _defaultProperties = defaultProperties; _textModifier = textModifier; }
internal static IReadOnlyList <string> CheckArgumentTypes( ReadOnlySlice <ValueTag> arguments, IReadOnlyList <Parameter> parameters, MethodBody body) { var errors = new List <string>(); int paramCount = parameters.Count; for (int i = 0; i < paramCount; i++) { var paramType = parameters[i].Type; var argType = body.Implementation.GetValueType(arguments[i]); if (!paramType.Equals(argType)) { errors.Add( string.Format( "Argument of type '{0}' was provided where an " + "argument of type '{1}' was expected.", paramType.FullName, argType.FullName)); } } return(errors); }
/// <summary> /// Initializes a new instance of the <see cref="GlyphRun"/> class by specifying properties of the class. /// </summary> /// <param name="glyphTypeface">The glyph typeface.</param> /// <param name="fontRenderingEmSize">The rendering em size.</param> /// <param name="glyphIndices">The glyph indices.</param> /// <param name="glyphAdvances">The glyph advances.</param> /// <param name="glyphOffsets">The glyph offsets.</param> /// <param name="characters">The characters.</param> /// <param name="glyphClusters">The glyph clusters.</param> /// <param name="biDiLevel">The bidi level.</param> /// <param name="bounds">The bound.</param> public GlyphRun( GlyphTypeface glyphTypeface, double fontRenderingEmSize, ReadOnlySlice <ushort> glyphIndices, ReadOnlySlice <double> glyphAdvances = default, ReadOnlySlice <Vector> glyphOffsets = default, ReadOnlySlice <char> characters = default, ReadOnlySlice <ushort> glyphClusters = default, int biDiLevel = 0, Rect?bounds = null) { GlyphTypeface = glyphTypeface; FontRenderingEmSize = fontRenderingEmSize; GlyphIndices = glyphIndices; GlyphAdvances = glyphAdvances; GlyphOffsets = glyphOffsets; Characters = characters; GlyphClusters = glyphClusters; BiDiLevel = biDiLevel; Initialize(bounds); }
public ShapedBuffer ShapeText(ReadOnlySlice <char> text, TextShaperOptions options) { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; var bidiLevel = options.BidLevel; var culture = options.Culture; using (var buffer = new Buffer()) { buffer.AddUtf16(text.Buffer.Span, text.Start, text.Length); MergeBreakPair(buffer); buffer.GuessSegmentProperties(); buffer.Direction = (bidiLevel & 1) == 0 ? Direction.LeftToRight : Direction.RightToLeft; buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture); var font = ((HarfBuzzGlyphTypefaceImpl)typeface.PlatformImpl).Font; font.Shape(buffer); if (buffer.Direction == Direction.RightToLeft) { buffer.Reverse(); } font.GetScale(out var scaleX, out _); var textScale = fontRenderingEmSize / scaleX; var bufferLength = buffer.Length; var shapedBuffer = new ShapedBuffer(text, bufferLength, typeface, fontRenderingEmSize, bidiLevel); var glyphInfos = buffer.GetGlyphInfoSpan(); var glyphPositions = buffer.GetGlyphPositionSpan(); for (var i = 0; i < bufferLength; i++) { var sourceInfo = glyphInfos[i]; var glyphIndex = (ushort)sourceInfo.Codepoint; var glyphCluster = (int)sourceInfo.Cluster; var glyphAdvance = GetGlyphAdvance(glyphPositions, i, textScale); var glyphOffset = GetGlyphOffset(glyphPositions, i, textScale); var targetInfo = new Media.TextFormatting.GlyphInfo(glyphIndex, glyphCluster, glyphAdvance, glyphOffset); shapedBuffer[i] = targetInfo; } return(shapedBuffer); } }
public GlyphRun ShapeText(ReadOnlySlice <char> text, TextFormat textFormat) { var glyphTypeface = textFormat.Typeface.GlyphTypeface; var glyphIndices = new ushort[text.Length]; var height = textFormat.FontMetrics.LineHeight; var width = 0.0; for (var i = 0; i < text.Length;) { var index = i; var codepoint = Codepoint.ReadAt(text, i, out var count); i += count; var glyph = glyphTypeface.GetGlyph(codepoint); glyphIndices[index] = glyph; width += glyphTypeface.GetGlyphAdvance(glyph); } return(new GlyphRun(glyphTypeface, textFormat.FontRenderingEmSize, glyphIndices, characters: text, bounds: new Rect(0, 0, width, height))); }
internal ShapedBuffer(ReadOnlySlice <char> text, ArraySlice <GlyphInfo> glyphInfos, GlyphTypeface glyphTypeface, double fontRenderingEmSize, sbyte bidiLevel) { Text = text; GlyphInfos = glyphInfos; GlyphTypeface = glyphTypeface; FontRenderingEmSize = fontRenderingEmSize; BidiLevel = bidiLevel; }
internal Processor(ReadOnlySlice <char> buffer) { _buffer = buffer; _codeUnitLengthOfCurrentScalar = 0; CurrentCodepoint = Codepoint.ReplacementCodepoint; CurrentType = GraphemeBreakClass.Other; CurrentCodeUnitOffset = 0; }
public ShapedBuffer ShapeText(ReadOnlySlice <char> text, TextShaperOptions options) { var typeface = options.Typeface; var fontRenderingEmSize = options.FontRenderingEmSize; var bidiLevel = options.BidiLevel; return(new ShapedBuffer(text, text.Length, typeface, fontRenderingEmSize, bidiLevel)); }
public FormattableTextSource(string text, TextStyle defaultStyle, ReadOnlySlice <TextStyleRun> textStyleRuns) { _text = text.AsMemory(); _defaultStyle = defaultStyle; _textStyleRuns = textStyleRuns; }
public GlyphRun ShapeText(ReadOnlySlice <char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture) { using (var buffer = new Buffer()) { FillBuffer(buffer, text); buffer.Language = new Language(culture ?? CultureInfo.CurrentCulture); buffer.GuessSegmentProperties(); var glyphTypeface = typeface.GlyphTypeface; var font = ((HarfBuzzGlyphTypefaceImpl)glyphTypeface.PlatformImpl).Font; font.Shape(buffer); font.GetScale(out var scaleX, out _); var textScale = fontRenderingEmSize / scaleX; var bufferLength = buffer.Length; var glyphInfos = buffer.GetGlyphInfoSpan(); var glyphPositions = buffer.GetGlyphPositionSpan(); var glyphIndices = new ushort[bufferLength]; var clusters = new ushort[bufferLength]; double[] glyphAdvances = null; Vector[] glyphOffsets = null; for (var i = 0; i < bufferLength; i++) { glyphIndices[i] = (ushort)glyphInfos[i].Codepoint; clusters[i] = (ushort)glyphInfos[i].Cluster; if (!glyphTypeface.IsFixedPitch) { SetAdvance(glyphPositions, i, textScale, ref glyphAdvances); } SetOffset(glyphPositions, i, textScale, ref glyphOffsets); } return(new GlyphRun(glyphTypeface, fontRenderingEmSize, new ReadOnlySlice <ushort>(glyphIndices), new ReadOnlySlice <double>(glyphAdvances), new ReadOnlySlice <Vector>(glyphOffsets), text, new ReadOnlySlice <ushort>(clusters), buffer.Direction == Direction.LeftToRight ? 0 : 1)); } }
public LineBreakEnumerator(ReadOnlySlice <char> text) { _text = text; _pos = 0; _lastPos = 0; _curClass = null; _nextClass = null; Current = default; }
/// <summary> /// Reads the <see cref="Codepoint"/> at specified position. /// </summary> /// <param name="text">The buffer to read from.</param> /// <param name="index">The index to read at.</param> /// <param name="count">The count of character that were read.</param> /// <returns></returns> public static Codepoint ReadAt(ReadOnlySlice <char> text, int index, out int count) { count = 1; if (index > text.End) { return(ReplacementCodepoint); } var code = text[index]; ushort hi, low; //# High surrogate if (0xD800 <= code && code <= 0xDBFF) { hi = code; if (index + 1 == text.Length) { return(ReplacementCodepoint); } low = text[index + 1]; if (0xDC00 <= low && low <= 0xDFFF) { count = 2; return(new Codepoint((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)); } return(ReplacementCodepoint); } //# Low surrogate if (0xDC00 <= code && code <= 0xDFFF) { if (index == 0) { return(ReplacementCodepoint); } hi = text[index - 1]; low = code; if (0xD800 <= hi && hi <= 0xDBFF) { count = 2; return(new Codepoint((hi - 0xD800) * 0x400 + (low - 0xDC00) + 0x10000)); } return(ReplacementCodepoint); } return(new Codepoint(code)); }
/// <summary> /// Construct a text trailing word ellipsis collapsing properties. /// </summary> /// <param name="ellipsis">Text used as collapsing symbol.</param> /// <param name="width">width in which collapsing is constrained to.</param> /// <param name="textRunProperties">text run properties of ellipsis symbol.</param> public TextTrailingWordEllipsis( ReadOnlySlice <char> ellipsis, double width, TextRunProperties textRunProperties ) { Width = width; Symbol = new TextCharacters(ellipsis, textRunProperties); }
public GlyphRun ShapeText(ReadOnlySlice <char> text, Typeface typeface, double fontRenderingEmSize, CultureInfo culture) { return(new GlyphRun(new GlyphTypeface(typeface), 10, new ReadOnlySlice <ushort>(new ushort[] { 1, 2, 3 }), new ReadOnlySlice <double>(new double[] { 1, 2, 3 }), new ReadOnlySlice <Vector>(new Vector[] { new Vector(1, 1), new Vector(2, 2), new Vector(3, 3) }), text, new ReadOnlySlice <ushort>(new ushort[] { 1, 2, 3 }))); }
public FormattableTextSource(string text, TextRunProperties defaultStyle, ReadOnlySlice <ValueSpan <TextRunProperties> > styleSpans) { _text = text.AsMemory(); _defaultStyle = defaultStyle; _styleSpans = styleSpans; }
/// <summary> /// Tries to get a shapeable length that is supported by the specified typeface. /// </summary> /// <param name="text">The text.</param> /// <param name="typeface">The typeface that is used to find matching characters.</param> /// <param name="defaultTypeface"></param> /// <param name="length">The shapeable length.</param> /// <param name="script"></param> /// <returns></returns> protected static bool TryGetShapeableLength( ReadOnlySlice <char> text, Typeface typeface, Typeface?defaultTypeface, out int length, out Script script) { length = 0; script = Script.Unknown; if (text.Length == 0) { return(false); } var font = typeface.GlyphTypeface; var defaultFont = defaultTypeface?.GlyphTypeface; var enumerator = new GraphemeEnumerator(text); while (enumerator.MoveNext()) { var currentGrapheme = enumerator.Current; var currentScript = currentGrapheme.FirstCodepoint.Script; if (currentScript != Script.Common && defaultFont != null && defaultFont.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } //Stop at the first missing glyph if (!currentGrapheme.FirstCodepoint.IsBreakChar && !font.TryGetGlyph(currentGrapheme.FirstCodepoint, out _)) { break; } if (currentScript != script) { if (script is Script.Unknown || currentScript != Script.Common && script is Script.Common or Script.Inherited) { script = currentScript; } else { if (currentScript != Script.Inherited && currentScript != Script.Common) { break; } } } length += currentGrapheme.Text.Length; }
public void Should_Skip() { var buffer = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var slice = new ReadOnlySlice <int>(buffer); var skipped = slice.Skip(2); var expected = buffer.Skip(2); Assert.Equal(expected, skipped); }
public void Should_Take() { var buffer = new[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; var slice = new ReadOnlySlice <int>(buffer); var taken = slice.Take(8); var expected = buffer.Take(8); Assert.Equal(expected, taken); }
private static GlyphRun CreateGlyphRun(double[] glyphAdvances, ushort[] glyphClusters, int bidiLevel = 0) { var count = glyphAdvances.Length; var glyphIndices = new ushort[count]; var start = bidiLevel == 0 ? glyphClusters[0] : glyphClusters[glyphClusters.Length - 1]; var characters = new ReadOnlySlice <char>(new char[count], start, count); return(new GlyphRun(new GlyphTypeface(new MockGlyphTypeface()), 10, glyphIndices, glyphAdvances, glyphClusters: glyphClusters, characters: characters, biDiLevel: bidiLevel)); }
/// <summary> /// Creates a shapeable text run with unique properties. /// </summary> /// <param name="text">The text to create text runs from.</param> /// <param name="defaultProperties">The default text run properties.</param> /// <returns>A list of shapeable text runs.</returns> private ShapeableTextCharacters CreateShapeableRun(ReadOnlySlice <char> text, TextRunProperties defaultProperties) { var defaultTypeface = defaultProperties.Typeface; var currentTypeface = defaultTypeface; if (TryGetRunProperties(text, currentTypeface, defaultTypeface, out var count)) { return(new ShapeableTextCharacters(text.Take(count), new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize, defaultProperties.TextDecorations, defaultProperties.ForegroundBrush))); } var codepoint = Codepoint.ReadAt(text, count, out _); //ToDo: Fix FontFamily fallback var matchFound = FontManager.Current.TryMatchCharacter(codepoint, defaultTypeface.Style, defaultTypeface.Weight, defaultTypeface.FontFamily, defaultProperties.CultureInfo, out currentTypeface); if (matchFound && TryGetRunProperties(text, currentTypeface, defaultTypeface, out count)) { //Fallback found return(new ShapeableTextCharacters(text.Take(count), new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize, defaultProperties.TextDecorations, defaultProperties.ForegroundBrush))); } // no fallback found currentTypeface = defaultTypeface; var glyphTypeface = currentTypeface.GlyphTypeface; var enumerator = new GraphemeEnumerator(text); while (enumerator.MoveNext()) { var grapheme = enumerator.Current; if (!grapheme.FirstCodepoint.IsWhiteSpace && glyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _)) { break; } count += grapheme.Text.Length; } return(new ShapeableTextCharacters(text.Take(count), new GenericTextRunProperties(currentTypeface, defaultProperties.FontRenderingEmSize, defaultProperties.TextDecorations, defaultProperties.ForegroundBrush))); }
public TextRun GetTextRun(int textSourceIndex) { if (_styleSpans.IsEmpty) { return(new TextEndOfParagraph()); } var currentSpan = _styleSpans[0]; _styleSpans = _styleSpans.Skip(1); return(new TextCharacters(_text.AsSlice(currentSpan.Start, currentSpan.Length), _defaultStyle)); }
public TextRun GetTextRun(int textSourceIndex) { if (_textStyleRuns.IsEmpty) { return(new TextEndOfParagraph()); } var styleRun = _textStyleRuns[0]; _textStyleRuns = _textStyleRuns.Skip(1); return(new TextCharacters(_text.AsSlice(styleRun.TextPointer.Start, styleRun.TextPointer.Length), _defaultStyle)); }
/// <summary> /// Creates a text style run with unique properties. /// </summary> /// <param name="text">The text to create text runs from.</param> /// <param name="defaultStyle"></param> /// <returns>A list of text runs.</returns> protected TextStyleRun CreateShapableTextStyleRun(ReadOnlySlice <char> text, TextStyle defaultStyle) { var defaultTypeface = defaultStyle.TextFormat.Typeface; var currentTypeface = defaultTypeface; if (TryGetRunProperties(text, currentTypeface, defaultTypeface, out var count)) { return(new TextStyleRun(new TextPointer(text.Start, count), new TextStyle(currentTypeface, defaultStyle.TextFormat.FontRenderingEmSize, defaultStyle.Foreground, defaultStyle.TextDecorations))); } var codepoint = Codepoint.ReadAt(text, count, out _); //ToDo: Fix FontFamily fallback currentTypeface = FontManager.Current.MatchCharacter(codepoint, defaultTypeface.Weight, defaultTypeface.Style); if (currentTypeface != null && TryGetRunProperties(text, currentTypeface, defaultTypeface, out count)) { //Fallback found return(new TextStyleRun(new TextPointer(text.Start, count), new TextStyle(currentTypeface, defaultStyle.TextFormat.FontRenderingEmSize, defaultStyle.Foreground, defaultStyle.TextDecorations))); } // no fallback found currentTypeface = defaultTypeface; var glyphTypeface = currentTypeface.GlyphTypeface; var enumerator = new GraphemeEnumerator(text); while (enumerator.MoveNext()) { var grapheme = enumerator.Current; if (!grapheme.FirstCodepoint.IsWhiteSpace && glyphTypeface.TryGetGlyph(grapheme.FirstCodepoint, out _)) { break; } count += grapheme.Text.Length; } return(new TextStyleRun(new TextPointer(text.Start, count), new TextStyle(currentTypeface, defaultStyle.TextFormat.FontRenderingEmSize, defaultStyle.Foreground, defaultStyle.TextDecorations))); }
/// <summary> /// Moves to the next <see cref="Codepoint"/>. /// </summary> /// <returns></returns> public bool MoveNext() { if (_text.IsEmpty) { Current = Codepoint.ReplacementCodepoint; return(false); } Current = Codepoint.ReadAt(_text, 0, out var count); _text = _text.Skip(count); return(true); }