/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PopLink"/>. /// </summary> private void ProcessPopLinkToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { output.WritePopLink(); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PopStyle"/>. /// </summary> private void ProcessPopStyleToken(TextLayoutCommandStream output, ref Boolean bold, ref Boolean italic, ref TextParserToken token, ref LayoutState state, ref Int32 index) { output.WritePopStyle(); state.AdvanceLineToNextCommand(); PopStyle(ref bold, ref italic); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PushLink"/>. /// </summary> private void ProcessPushLinkToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var pushedLinkTargetIndex = RegisterLinkTargetWithCommandStream(output, token.Text); output.WritePushLink(new TextLayoutLinkCommand(pushedLinkTargetIndex)); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PushColor"/>. /// </summary> private void ProcessPushColorToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var pushedColor = ParseColor(token.Text); output.WritePushColor(new TextLayoutColorCommand(pushedColor)); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PushGlyphShader"/>. /// </summary> private void ProcessPushGlyphShaderToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var pushedGlyphShader = default(GlyphShader); var pushedGlyphShaderIndex = RegisterGlyphShaderWithCommandStream(output, token.Text, out pushedGlyphShader); output.WritePushGlyphShader(new TextLayoutGlyphShaderCommand(pushedGlyphShaderIndex)); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.Custom"/>. /// </summary> private void ProcessCustomCommandToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var commandID = (token.TokenType - TextParserTokenType.Custom); var commandValue = token.Text.IsEmpty ? default(Int32) : StringSegmentConversion.ParseInt32(token.Text); output.WriteCustomCommand(new TextLayoutCustomCommand(commandID, commandValue)); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PushStyle"/>. /// </summary> private void ProcessPushStyleToken(TextLayoutCommandStream output, ref Boolean bold, ref Boolean italic, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var pushedStyle = default(TextStyle); var pushedStyleIndex = RegisterStyleWithCommandStream(output, token.Text, out pushedStyle); output.WritePushStyle(new TextLayoutStyleCommand(pushedStyleIndex)); state.AdvanceLineToNextCommand(); PushStyle(pushedStyle, ref bold, ref italic); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PushFont"/>. /// </summary> private void ProcessPushFontToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { var pushedFont = default(SpriteFont); var pushedFontIndex = RegisterFontWithCommandStream(output, token.Text, out pushedFont); output.WritePushFont(new TextLayoutFontCommand(pushedFontIndex)); state.AdvanceLineToNextCommand(); PushFont(pushedFont); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.Text"/>. /// </summary> private Boolean ProcessTextToken(TextParserTokenStream input, TextLayoutCommandStream output, SpriteFontFace currentFontFace, ref TextParserToken token, ref LayoutState state, ref TextLayoutSettings settings, ref Int32 index) { if (token.IsNewLine) { state.AdvanceLayoutToNextLineWithBreak(output, token.SourceLength, ref settings); index++; } else { if (!AccumulateText(input, output, currentFontFace, ref index, ref state, ref settings)) { return(false); } } return(true); }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.Icon"/>. /// </summary> private Boolean ProcessIconToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref TextLayoutSettings settings, ref Int32 index) { var icon = default(TextIconInfo); var iconIndex = RegisterIconWithCommandStream(output, token.Text, out icon); var iconSize = MeasureToken(null, token.TokenType, token.Text); if (state.PositionX + iconSize.Width > (settings.Width ?? Int32.MaxValue)) { state.AdvanceLayoutToNextLine(output, ref settings); } if (state.PositionY + iconSize.Height > (settings.Height ?? Int32.MaxValue)) { return(false); } output.WriteIcon(new TextLayoutIconCommand(iconIndex, state.PositionX, state.PositionY, (Int16)iconSize.Width, (Int16)iconSize.Height)); state.AdvanceLineToNextCommand(iconSize.Width, iconSize.Height, 1, 1); index++; return(true); }
/// <summary> /// Adds an item to the token stream. /// </summary> /// <param name="item">The item to add to the token stream.</param> internal void Add(TextParserToken item) { tokens.Add(item); }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.Icon"/>. /// </summary> private Boolean ProcessIconToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref TextLayoutSettings settings, ref Int32 index) { var icon = default(TextIconInfo); var iconIndex = RegisterIconWithCommandStream(output, token.Text, out icon); var iconSize = MeasureToken(null, token.TokenType, token.Text); if (state.PositionX + iconSize.Width > (settings.Width ?? Int32.MaxValue)) state.AdvanceLayoutToNextLine(output, ref settings); if (state.PositionY + iconSize.Height > (settings.Height ?? Int32.MaxValue)) return false; output.WriteIcon(new TextLayoutIconCommand(iconIndex, state.PositionX, state.PositionY, (Int16)iconSize.Width, (Int16)iconSize.Height)); state.AdvanceLineToNextCommand(iconSize.Width, iconSize.Height, 1, 1); index++; return true; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.PopGlyphShader"/>. /// </summary> private void ProcessPopGlyphShaderToken(TextLayoutCommandStream output, ref TextParserToken token, ref LayoutState state, ref Int32 index) { output.WritePopGlyphShader(); state.AdvanceLineToNextCommand(); index++; }
/// <summary> /// Processes a parser token with type <see cref="TextParserTokenType.Text"/>. /// </summary> private Boolean ProcessTextToken(TextParserTokenStream input, TextLayoutCommandStream output, SpriteFontFace currentFontFace, ref TextParserToken token, ref LayoutState state, ref TextLayoutSettings settings, ref Int32 index) { if (token.IsNewLine) { state.AdvanceLayoutToNextLineWithBreak(output, token.SourceLength, ref settings); index++; } else { if (!AccumulateText(input, output, currentFontFace, ref index, ref state, ref settings)) return false; } return true; }
/// <summary> /// Adds a <see cref="TextLayoutCommandType.ChangeSourceString"/> or <see cref="TextLayoutCommandType.ChangeSourceStringBuilder"/> command to the output /// stream if it is necessary to do so for the specified parser token. /// </summary> private Boolean EmitChangeSourceIfNecessary(TextParserTokenStream input, TextLayoutCommandStream output, ref TextParserToken token) { if (!IsSegmentForCurrentSource(token.Text)) { var isFirstSource = (sourceString == null && sourceStringBuilder == null); sourceString = token.Text.SourceString; sourceStringBuilder = token.Text.SourceStringBuilder; // NOTE: To save memory, we can elide the first change source command if it's just going to change to the input source. if (!isFirstSource || input.SourceText.SourceString != sourceString || input.SourceText.SourceStringBuilder != sourceStringBuilder) { if (sourceString != null) { var sourceIndex = output.RegisterSourceString(sourceString); output.WriteChangeSourceString(new TextLayoutSourceStringCommand(sourceIndex)); } else { var sourceIndex = output.RegisterSourceStringBuilder(sourceStringBuilder); output.WriteChangeSourceStringBuilder(new TextLayoutSourceStringBuilderCommand(sourceIndex)); } return true; } } return false; }
/// <summary> /// Calculates the size of the specified parser token when rendered according to the current layout state. /// </summary> /// <param name="font">The current font face.</param> /// <param name="tokenType">The type of the current token.</param> /// <param name="tokenText">The text of the current token.</param> /// <param name="tokenNext">The next token after the current token, excluding command tokens.</param> /// <returns>The size of the specified token in pixels.</returns> private Size2 MeasureToken(SpriteFontFace font, TextParserTokenType tokenType, StringSegment tokenText, TextParserToken? tokenNext = null) { switch (tokenType) { case TextParserTokenType.Icon: { TextIconInfo icon; if (!registeredIcons.TryGetValue(tokenText, out icon)) throw new InvalidOperationException(UltravioletStrings.UnrecognizedIcon.Format(tokenText)); return new Size2(icon.Width ?? icon.Icon.Controller.Width, icon.Height ?? icon.Icon.Controller.Height); } case TextParserTokenType.Text: { var size = font.MeasureString(tokenText); if (tokenNext.HasValue) { var tokenNextValue = tokenNext.GetValueOrDefault(); if (tokenNextValue.TokenType == TextParserTokenType.Text && !tokenNextValue.Text.IsEmpty && !tokenNextValue.IsNewLine) { var charLast = tokenText[tokenText.Length - 1]; var charNext = tokenNextValue.Text[0]; var kerning = font.Kerning.Get(charLast, charNext); return new Size2(size.Width + kerning, size.Height); } } return size; } } return Size2.Zero; }
/// <summary> /// Adds a <see cref="TextLayoutCommandType.ChangeSourceString"/> or <see cref="TextLayoutCommandType.ChangeSourceStringBuilder"/> command to the output /// stream if it is necessary to do so for the specified parser token. /// </summary> private Boolean EmitChangeSourceIfNecessary(TextParserTokenStream input, TextLayoutCommandStream output, ref TextParserToken token) { if (!IsSegmentForCurrentSource(token.Text)) { var isFirstSource = (sourceString == null && sourceStringBuilder == null); sourceString = token.Text.SourceString; sourceStringBuilder = token.Text.SourceStringBuilder; // NOTE: To save memory, we can elide the first change source command if it's just going to change to the input source. if (!isFirstSource || input.SourceText.SourceString != sourceString || input.SourceText.SourceStringBuilder != sourceStringBuilder) { if (sourceString != null) { var sourceIndex = output.RegisterSourceString(sourceString); output.WriteChangeSourceString(new TextLayoutSourceStringCommand(sourceIndex)); } else { var sourceIndex = output.RegisterSourceStringBuilder(sourceStringBuilder); output.WriteChangeSourceStringBuilder(new TextLayoutSourceStringBuilderCommand(sourceIndex)); } return(true); } } return(false); }