/// <inheritdoc/> public override void AppendTo(ShapedStringBuilder builder, UltravioletFontFace fontFace, Int32 start, Int32 length, Int32 sourceIndexOffset = 0) { Contract.Require(builder, nameof(builder)); Contract.Require(fontFace, nameof(fontFace)); Contract.EnsureRange(start >= 0 && start < rawstr.Length, nameof(start)); Contract.EnsureRange(length >= 0 && start + length <= rawstr.Length, nameof(length)); Contract.EnsureNotDisposed(this, Disposed); unsafe { Shape(fontFace, out var glyphInfo, out var glyphPosition, out var glyphCount); var end = start + length; for (var i = 0; i < glyphCount; i++) { var cluster = (Int32)glyphInfo->cluster; if (cluster >= start) { if (cluster >= end) { break; } CreateShapedChar(glyphInfo, glyphPosition, sourceIndexOffset + cluster, out var sc); builder.Append(sc); } glyphInfo++; glyphPosition++; } } }
/// <summary> /// Performs shaping on the native buffer using the specified font.. /// </summary> private unsafe void Shape(UltravioletFontFace fontFace, out hb_glyph_info_t *infos, out hb_glyph_position_t *positions, out UInt32 count) { ValidateUnicodeProperties(); var ftFontFace = fontFace as FreeTypeFontFace; if (ftFontFace == null) { throw new NotSupportedException(FreeTypeStrings.TextShaperRequiresFreeTypeFont); } PopulateNativeBuffer(); if (lastUsedFont != ftFontFace && lastUsedFontNative != IntPtr.Zero) { hb_font_destroy(lastUsedFontNative); lastUsedFont = null; lastUsedFontNative = IntPtr.Zero; } var fontNative = (lastUsedFontNative == IntPtr.Zero) ? hb_ft_font_create(ftFontFace.NativePointer, IntPtr.Zero) : lastUsedFontNative; var fontLoadFlags = ftFontFace.IsStroked ? FT_LOAD_NO_BITMAP : FT_LOAD_COLOR; hb_ft_font_set_load_flags(fontNative, fontLoadFlags); lastUsedFont = ftFontFace; lastUsedFontNative = fontNative; hb_shape(fontNative, native, IntPtr.Zero, 0); var glyphCount = 0u; infos = (hb_glyph_info_t *)hb_buffer_get_glyph_infos(native, (IntPtr)(&glyphCount)); positions = (hb_glyph_position_t *)hb_buffer_get_glyph_positions(native, IntPtr.Zero); count = glyphCount; }
/// <summary> /// Gets the absolute position of the text when rendered. /// </summary> /// <param name="font">The font with which the command is being rendered.</param> /// <param name="x">The x-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="y">The y-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="lineHeight">The height of the line of text that is being rendered.</param> /// <returns>A <see cref="Vector2"/> that describes the absolute position of the text.</returns> public Vector2 GetAbsolutePositionVector(UltravioletFontFace font, Single x, Single y, Int32 lineHeight) { var lineHeightSansDescender = lineHeight + font.Descender; var textHeightSansDescender = textHeight + font.Descender; return(new Vector2(x + textX, (y - font.Descender) + textY + ((lineHeightSansDescender - textHeightSansDescender) / 2))); }
/// <summary> /// Gets the absolute bounds of the text when rendered. /// </summary> /// <param name="font">The font with which the command is being rendered.</param> /// <param name="x">The x-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="y">The y-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="lineHeight">The height of the line of text that is being rendered.</param> /// <returns>A <see cref="Rectangle"/> that describes the absolute bounds of the text.</returns> public Rectangle GetAbsoluteBounds(UltravioletFontFace font, Int32 x, Int32 y, Int32 lineHeight) { var lineHeightSansDescender = lineHeight + font.Descender; var textHeightSansDescender = textHeight + font.Descender; return(new Rectangle(x + textX, (y - font.Descender) + textY + ((lineHeightSansDescender - textHeightSansDescender) / 2), textWidth, textHeight)); }
/// <summary> /// Gets the absolute position of the text when rendered. /// </summary> /// <param name="font">The font with which the command is being rendered.</param> /// <param name="x">The x-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="y">The y-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="lineHeight">The height of the line of text that is being rendered.</param> /// <returns>A <see cref="Point2"/> that describes the absolute position of the text.</returns> public Point2 GetAbsolutePosition(UltravioletFontFace font, Int32 x, Int32 y, Int32 lineHeight) { var lineHeightSansDescender = lineHeight + font.Descender; var textHeightSansDescender = textHeight + font.Descender; return(new Point2(x + textX, (y - font.Descender) + textY + ((lineHeightSansDescender - textHeightSansDescender) / 2))); }
/// <summary> /// Appends the contents of the specified <see cref="TextShaper"/> to the end of the /// current <see cref="ShapedStringBuilder"/> instance. /// </summary> /// <param name="shaper">The <see cref="TextShaper"/> instance from which to append values.</param> /// <param name="fontFace">The font face with which to shape the string.</param> /// <returns>A reference to this instance after the append operation has completed.</returns> public ShapedStringBuilder Append(TextShaper shaper, UltravioletFontFace fontFace) { Contract.Require(shaper, nameof(shaper)); shaper.AppendTo(this, fontFace); return(this); }
/// <summary> /// Gets the absolute bounds of the text when rendered. /// </summary> /// <param name="font">The font with which the command is being rendered.</param> /// <param name="x">The x-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="y">The y-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="lineWidth">The width of the line of text that is being rendered.</param> /// <param name="lineHeight">The height of the line of text that is being rendered.</param> /// <param name="direction">The direction in which the text is oriented.</param> /// <returns>A <see cref="Rectangle"/> that describes the absolute bounds of the text.</returns> public Rectangle GetAbsoluteBounds(UltravioletFontFace font, Int32 x, Int32 y, Int32 lineWidth, Int32 lineHeight, TextDirection direction) { var lineHeightSansDescender = lineHeight + font.Descender; var textHeightSansDescender = TextHeight + font.Descender; var absX = (direction == TextDirection.RightToLeft) ? (x + lineWidth) - (TextX + TextWidth) : x + TextX; var absY = (y - font.Descender) + TextY + ((lineHeightSansDescender - textHeightSansDescender) / 2); return(new Rectangle(absX, absY, TextWidth, TextHeight)); }
/// <summary> /// Gets the absolute position of the text when rendered. /// </summary> /// <param name="font">The font with which the command is being rendered.</param> /// <param name="x">The x-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="y">The y-coordinate of the top-left corner of the line of text that is being rendered.</param> /// <param name="lineWidth">The width of the line of text that is being rendered.</param> /// <param name="lineHeight">The height of the line of text that is being rendered.</param> /// <param name="direction">The direction in which the text is oriented.</param> /// <returns>A <see cref="Vector2"/> that describes the absolute position of the text.</returns> public Vector2 GetAbsolutePositionVector(UltravioletFontFace font, Single x, Single y, Int32 lineWidth, Int32 lineHeight, TextDirection direction) { var lineHeightSansDescender = lineHeight + font.Descender; var textHeightSansDescender = TextHeight + font.Descender; var absX = (direction == TextDirection.RightToLeft) ? (x + lineWidth) - (TextX + TextWidth) : x + TextX; var absY = (y - font.Descender) + TextY + ((lineHeightSansDescender - textHeightSansDescender) / 2); return(new Vector2(absX, absY)); }
/// <summary> /// Initializes a new instance of the <see cref="TextLayoutToken"/> structure. /// </summary> /// <param name="text">The token's text.</param> /// <param name="bounds">The token's bounds relative to its layout region.</param> /// <param name="fontFace">The token's font face.</param> /// <param name="icon">The token's icon.</param> /// <param name="glyphShader">The token's glyph shader.</param> /// <param name="color">The token's color.</param> internal TextLayoutToken(StringSegment text, Rectangle bounds, UltravioletFontFace fontFace, TextIconInfo?icon, GlyphShader glyphShader, Color?color) { this.text = text; this.bounds = bounds; this.fontFace = fontFace; this.icon = icon; this.glyphShader = glyphShader; this.color = color; }
/// <summary> /// Initializes a new instance of the <see cref="ShapedString"/> class. /// </summary> /// <param name="fontFace">The font face with which the string was created.</param> /// <param name="language">The name of the language which this string contains.</param> /// <param name="script">A <see cref="TextScript"/> value specifying which script which this string contains.</param> /// <param name="direction">A <see cref="TextDirection"/> value specifying the direction in which this string should be written.</param> /// <param name="value">An array of <see cref="ShapedChar"/> values.</param> /// <param name="startIndex">The starting position within <paramref name="value"/>.</param> /// <param name="count">The number of characters within <paramref name="value"/> to use.</param> public ShapedString(UltravioletFontFace fontFace, String language, TextScript script, TextDirection direction, ShapedChar[] value, Int32 startIndex, Int32 count) { Contract.Require(fontFace, nameof(fontFace)); Contract.Require(language, nameof(language)); Contract.Require(value, nameof(value)); this.FontFace = fontFace; this.Language = language; this.Script = script; this.Direction = direction; this.buffer = CreateShapedString(value, startIndex, count); }
/// <summary> /// Initializes a new instance of the <see cref="ShapedString"/> class. /// </summary> /// <param name="fontFace">The font face with which the string was created.</param> /// <param name="language">The name of the language which this string contains.</param> /// <param name="script">A <see cref="TextScript"/> value specifying which script which this string contains.</param> /// <param name="direction">A <see cref="TextDirection"/> value specifying the direction in which this string should be written.</param> /// <param name="value">An array of <see cref="ShapedChar"/> values.</param> public ShapedString(UltravioletFontFace fontFace, String language, TextScript script, TextDirection direction, ShapedChar[] value) { Contract.Require(fontFace, nameof(fontFace)); Contract.Require(language, nameof(language)); Contract.Require(value, nameof(value)); this.FontFace = fontFace; this.Language = language; this.Script = script; this.Direction = direction; this.buffer = CreateShapedString(value, 0, value?.Length ?? 0); }
/// <inheritdoc/> public override ShapedString CreateShapedString(UltravioletFontFace fontFace, Int32 start, Int32 length, Int32 sourceIndexOffset = 0) { Contract.Require(fontFace, nameof(fontFace)); Contract.EnsureRange(start >= 0 && start < rawstr.Length, nameof(start)); Contract.EnsureRange(length >= 0 && start + length <= rawstr.Length, nameof(length)); Contract.EnsureNotDisposed(this, Disposed); unsafe { Shape(fontFace, out var glyphInfo, out var glyphPosition, out var glyphCount); var end = start + length; var chars = new ShapedChar[glyphCount]; var charsCount = 0; for (var i = 0; i < glyphCount; i++) { var cluster = (Int32)glyphInfo->cluster; if (cluster >= start) { if (cluster >= end) { break; } switch (rawstr[cluster]) { case '\n': chars[i] = new ShapedChar('\n', sourceIndexOffset + cluster, Int16.MaxValue, Int16.MaxValue, Int16.MaxValue); break; case '\t': chars[i] = new ShapedChar('\t', sourceIndexOffset + cluster, Int16.MaxValue, Int16.MaxValue, Int16.MaxValue); break; default: CreateShapedChar(glyphInfo, glyphPosition, sourceIndexOffset + cluster, out chars[i]); break; } charsCount++; } glyphInfo++; glyphPosition++; } return(new ShapedString(fontFace, GetLanguage(), GetScript(), GetDirection(), chars, 0, charsCount)); } }
/// <inheritdoc/> public override void AppendTo(ShapedStringBuilder builder, UltravioletFontFace fontFace, Int32 sourceIndexOffset = 0) => AppendTo(builder, fontFace, 0, rawstr.Length, sourceIndexOffset);
/// <summary> /// Converts the value of the current <see cref="ShapedStringBuilder"/> to a new <see cref="ShapedString"/> instance. /// </summary> /// <param name="fontFace">The font face with which the string was created.</param> /// <param name="language">The name of the language which this string contains.</param> /// <param name="script">A <see cref="TextScript"/> value specifying which script which this string contains.</param> /// <param name="direction">A <see cref="TextDirection"/> value specifying the direction in which this string should be written.</param> /// <returns>The <see cref="ShapedString"/> instance which was created.</returns> public ShapedString ToShapedString(UltravioletFontFace fontFace, String language, TextScript script, TextDirection direction) => new ShapedString(fontFace, language, script, direction, buffer, 0, length);
/// <summary> /// Appends the contents of a subset of this shaping buffer to the specified <see cref="ShapedStringBuilder"/> instance. /// </summary> /// <param name="builder">The <see cref="ShapedStringBuilder"/> instance to which to append this shaper's contents.</param> /// <param name="fontFace">The font face with which to shape the string.</param> /// <param name="start">The offset of the character in the original string which corresponds to the beginning of the shaped substring.</param> /// <param name="length">The number of characters in the raw substring from which to create the shaped substring.</param> /// <param name="sourceIndexOffset">The offset which is applied to the source indices assigned to shaped characters in the resulting string.</param> public abstract void AppendTo(ShapedStringBuilder builder, UltravioletFontFace fontFace, Int32 start, Int32 length, Int32 sourceIndexOffset = 0);
/// <summary> /// Creates a new <see cref="ShapedString"/> instance from a subset of the current contents of the shaping buffer. /// </summary> /// <param name="fontFace">The font face with which to shape the string.</param> /// <param name="start">The offset of the character in the original string which corresponds to the beginning of the shaped substring.</param> /// <param name="length">The number of characters in the raw substring from which to create the shaped substring.</param> /// <param name="sourceIndexOffset">The offset which is applied to the source indices assigned to shaped characters in the resulting string.</param> /// <returns>A new shaped string instance.</returns> public abstract ShapedString CreateShapedString(UltravioletFontFace fontFace, Int32 start, Int32 length, Int32 sourceIndexOffset = 0);
/// <inheritdoc/> public override ShapedString CreateShapedString(UltravioletFontFace fontFace, Int32 sourceIndexOffset = 0) => CreateShapedString(fontFace, 0, rawstr.Length, sourceIndexOffset);