public void WriteLineInfo(TextLayoutCommandStream output, Int32 lineWidth, Int32 lineHeight, Int32 lengthInCommands, Int32 lengthInGlyphs, Boolean terminatedByLineBreak, ref TextLayoutSettings settings) { var offset = 0; if (settings.Width.HasValue) { if ((settings.Flags & TextFlags.AlignRight) == TextFlags.AlignRight) { offset = (settings.Width.Value - lineWidth); } else if ((settings.Flags & TextFlags.AlignCenter) == TextFlags.AlignCenter) { offset = (settings.Width.Value - lineWidth) / 2; } } var outputStreamPosition = output.StreamPositionInObjects; output.Seek(lineInfoCommandIndex); unsafe { var ptr = (TextLayoutLineInfoCommand *)output.Data; ptr->Offset = offset; ptr->LineWidth = lineWidth; ptr->LineHeight = lineHeight; ptr->LengthInCommands = lengthInCommands; ptr->LengthInGlyphs = lengthInGlyphs; ptr->TerminatedByLineBreak = terminatedByLineBreak; } output.Seek(outputStreamPosition); minLineOffset = (minLineOffset.HasValue) ? Math.Min(minLineOffset.Value, offset) : offset; }
public void WriteBlockInfo(TextLayoutCommandStream output, Int32 blockWidth, Int32 blockHeight, Int32 lengthInLines, ref TextLayoutSettings settings) { var offset = 0; if (settings.Height.HasValue) { if ((settings.Flags & TextFlags.AlignBottom) == TextFlags.AlignBottom) { offset = (settings.Height.Value - blockHeight); } else if ((settings.Flags & TextFlags.AlignMiddle) == TextFlags.AlignMiddle) { offset = (settings.Height.Value - blockHeight) / 2; } } output.Seek(0); unsafe { var ptr = (TextLayoutBlockInfoCommand *)output.Data; ptr->Offset = offset; ptr->LengthInLines = lengthInLines; } output.Seek(output.Count); minBlockOffset = (minBlockOffset.HasValue) ? Math.Min(minBlockOffset.Value, offset) : offset; }
public void WriteLineInfo(TextLayoutCommandStream output, Int32 lineWidth, Int32 lineHeight, Int32 lengthInCommands, Int32 lengthInGlyphs, Boolean terminatedByLineBreak, ref TextLayoutSettings settings) { var offset = 0; if (settings.Width.HasValue) { if ((settings.Flags & TextFlags.AlignRight) == TextFlags.AlignRight) offset = (settings.Width.Value - lineWidth); else if ((settings.Flags & TextFlags.AlignCenter) == TextFlags.AlignCenter) offset = (settings.Width.Value - lineWidth) / 2; } var outputStreamPosition = output.StreamPositionInObjects; output.Seek(lineInfoCommandIndex); unsafe { var ptr = (TextLayoutLineInfoCommand*)output.Data; ptr->Offset = offset; ptr->LineWidth = lineWidth; ptr->LineHeight = lineHeight; ptr->LengthInCommands = lengthInCommands; ptr->LengthInGlyphs = lengthInGlyphs; ptr->TerminatedByLineBreak = terminatedByLineBreak; } output.Seek(outputStreamPosition); minLineOffset = (minLineOffset.HasValue) ? Math.Min(minLineOffset.Value, offset) : offset; }
public void WriteBlockInfo(TextLayoutCommandStream output, Int32 blockWidth, Int32 blockHeight, Int32 lengthInLines, ref TextLayoutSettings settings) { var offset = 0; if (settings.Height.HasValue) { if ((settings.Flags & TextFlags.AlignBottom) == TextFlags.AlignBottom) offset = (settings.Height.Value - blockHeight); else if ((settings.Flags & TextFlags.AlignMiddle) == TextFlags.AlignMiddle) offset = (settings.Height.Value - blockHeight) / 2; } output.Seek(0); unsafe { var ptr = (TextLayoutBlockInfoCommand*)output.Data; ptr->Offset = offset; ptr->LengthInLines = lengthInLines; } output.Seek(output.Count); minBlockOffset = (minBlockOffset.HasValue) ? Math.Min(minBlockOffset.Value, offset) : offset; }
private unsafe void FixHorizontalAlignmentForUnconstrainedLayout(TextLayoutCommandStream output, ref TextLayoutSettings settings) { output.Seek(0); while (output.SeekNextLine()) { var lineInfo = (TextLayoutLineInfoCommand *)output.InternalObjectStream.Data; if ((settings.Flags & TextFlags.AlignRight) == TextFlags.AlignRight) { lineInfo->Offset = (output.ActualWidth - lineInfo->LineWidth); } else if ((settings.Flags & TextFlags.AlignCenter) == TextFlags.AlignCenter) { lineInfo->Offset = (output.ActualWidth - lineInfo->LineWidth) / 2; } } }
public unsafe Boolean ReplaceLastBreakingSpaceWithLineBreak(TextLayoutCommandStream output, ref TextLayoutSettings settings) { if (!lineBreakCommand.HasValue || !lineBreakOffset.HasValue) { return(false); } var sizeBeforeBreak = brokenTextSizeBeforeBreak.Value; var sizeAfterBreak = brokenTextSizeAfterBreak.Value; var brokenCommandSize = Size2.Zero; var brokenCommandOffset = 0; var brokenCommandLength = 0; var newLineHeight = sizeAfterBreak.Height; if (newLineHeight == 0) { newLineHeight = settings.Font.GetFace(SpriteFontStyle.Regular).LineSpacing; } // Truncate the command which is being broken. output.Seek(lineBreakCommand.Value); unsafe { var cmd = (TextLayoutTextCommand *)output.Data; brokenCommandOffset = cmd->TextOffset; brokenCommandLength = cmd->TextLength; brokenCommandSize = cmd->Bounds.Size; cmd->TextLength = lineBreakOffset.Value; cmd->TextWidth = (Int16)sizeBeforeBreak.Width; cmd->TextHeight = (Int16)sizeBeforeBreak.Height; } output.SeekNextCommand(); // Insert a line break, a new line, and the second half of the truncated text. var part1Length = lineBreakOffset.Value; var part2Offset = brokenCommandOffset + (lineBreakOffset.Value + 1); var part2Length = brokenCommandLength - (part1Length + 1); var part2IsNotDegenerate = (part2Length > 0); var numberOfObjects = part2IsNotDegenerate ? 3 : 2; var numberOfBytes = sizeof(TextLayoutLineBreakCommand) + sizeof(TextLayoutLineInfoCommand) + (part2IsNotDegenerate ? sizeof(TextLayoutTextCommand) : 0); var insertionPosition = output.InternalObjectStream.PositionInObjects; output.InternalObjectStream.ReserveInsert(numberOfObjects, numberOfBytes); *(TextLayoutLineBreakCommand *)output.Data = new TextLayoutLineBreakCommand(1); output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutLineBreakCommand)); *(TextLayoutCommandType *)output.Data = TextLayoutCommandType.LineInfo; output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutLineInfoCommand)); if (part2IsNotDegenerate) { var textOffset = part2Offset; var textLength = part2Length; *(TextLayoutTextCommand *)output.InternalObjectStream.Data = new TextLayoutTextCommand(textOffset, textLength, 0, positionY + lineHeight, (Int16)sizeAfterBreak.Width, (Int16)sizeAfterBreak.Height); output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutTextCommand)); } // Add the line break command to the broken line. AdvanceLineToNextCommand(0, 0, 1, 1); // Recalculate the parameters for the broken line. output.Seek(LineInfoCommandIndex + 1); var brokenLineWidth = 0; var brokenLineHeight = 0; var brokenLineLengthInText = 0; var brokenLineLengthInCommands = 0; var cmdType = TextLayoutCommandType.None; while ((cmdType = *(TextLayoutCommandType *)output.Data) != TextLayoutCommandType.LineInfo) { switch (cmdType) { case TextLayoutCommandType.Text: { var cmd = (TextLayoutTextCommand *)output.Data; brokenLineWidth += cmd->TextWidth; brokenLineHeight = Math.Max(brokenLineHeight, cmd->TextHeight); brokenLineLengthInText += cmd->TextLength; } break; case TextLayoutCommandType.Icon: { var cmd = (TextLayoutIconCommand *)output.Data; brokenLineWidth += cmd->Bounds.Width; brokenLineHeight = Math.Max(brokenLineHeight, cmd->Bounds.Height); brokenLineLengthInText += 1; } break; case TextLayoutCommandType.LineBreak: { var cmd = (TextLayoutLineBreakCommand *)output.Data; brokenLineLengthInText += cmd->Length; } break; } brokenLineLengthInCommands++; output.SeekNextCommand(); } // Finalize the broken line. totalLength = (totalLength - lineLengthInText) + brokenLineLengthInText; lineWidth = brokenLineWidth; lineHeight = brokenLineHeight; lineLengthInText = brokenLineLengthInText; lineLengthInCommands = brokenLineLengthInCommands; FinalizeLine(output, ref settings); // Fixup token bounds and update parameters for new line. LineInfoCommandIndex = insertionPosition + 1; while (output.StreamPositionInObjects < output.Count) { var width = 0; var height = 0; var lengthInCommands = 0; var lengthInText = 0; switch (*(TextLayoutCommandType *)output.Data) { case TextLayoutCommandType.Text: { var cmd = (TextLayoutTextCommand *)output.Data; width = cmd->TextWidth; height = cmd->TextHeight; lengthInCommands = 1; lengthInText = cmd->TextLength; cmd->TextX = PositionX; cmd->TextY = PositionY; } break; case TextLayoutCommandType.Icon: { var cmd = (TextLayoutIconCommand *)output.Data; width = cmd->IconWidth; height = cmd->IconHeight; lengthInCommands = 1; lengthInText = 1; cmd->IconX = PositionX; cmd->IconY = PositionY; } break; case TextLayoutCommandType.LineBreak: { var cmd = (TextLayoutLineBreakCommand *)output.Data; lengthInText += cmd->Length; } break; } AdvanceLineToNextCommand(width, height, lengthInCommands, lengthInText); output.SeekNextCommand(); } return(true); }
private unsafe void FixHorizontalAlignmentForUnconstrainedLayout(TextLayoutCommandStream output, ref TextLayoutSettings settings) { output.Seek(0); while (output.SeekNextLine()) { var lineInfo = (TextLayoutLineInfoCommand*)output.InternalObjectStream.Data; if ((settings.Flags & TextFlags.AlignRight) == TextFlags.AlignRight) lineInfo->Offset = (output.ActualWidth - lineInfo->LineWidth); else if ((settings.Flags & TextFlags.AlignCenter) == TextFlags.AlignCenter) lineInfo->Offset = (output.ActualWidth - lineInfo->LineWidth) / 2; } }
public unsafe Boolean ReplaceLastBreakingSpaceWithLineBreak(TextLayoutCommandStream output, ref TextLayoutSettings settings) { if (!lineBreakCommand.HasValue || !lineBreakOffset.HasValue) return false; var sizeBeforeBreak = brokenTextSizeBeforeBreak.Value; var sizeAfterBreak = brokenTextSizeAfterBreak.Value; var brokenCommandSize = Size2.Zero; var brokenCommandOffset = 0; var brokenCommandLength = 0; var newLineHeight = sizeAfterBreak.Height; if (newLineHeight == 0) newLineHeight = settings.Font.GetFace(SpriteFontStyle.Regular).LineSpacing; // Truncate the command which is being broken. output.Seek(lineBreakCommand.Value); unsafe { var cmd = (TextLayoutTextCommand*)output.Data; brokenCommandOffset = cmd->TextOffset; brokenCommandLength = cmd->TextLength; brokenCommandSize = cmd->Bounds.Size; cmd->TextLength = lineBreakOffset.Value; cmd->TextWidth = (Int16)sizeBeforeBreak.Width; cmd->TextHeight = (Int16)sizeBeforeBreak.Height; } output.SeekNextCommand(); // Insert a line break, a new line, and the second half of the truncated text. var part1Length = lineBreakOffset.Value; var part2Offset = brokenCommandOffset + (lineBreakOffset.Value + 1); var part2Length = brokenCommandLength - (part1Length + 1); var part2IsNotDegenerate = (part2Length > 0); var numberOfObjects = part2IsNotDegenerate ? 3 : 2; var numberOfBytes = sizeof(TextLayoutLineBreakCommand) + sizeof(TextLayoutLineInfoCommand) + (part2IsNotDegenerate ? sizeof(TextLayoutTextCommand) : 0); var insertionPosition = output.InternalObjectStream.PositionInObjects; output.InternalObjectStream.ReserveInsert(numberOfObjects, numberOfBytes); *(TextLayoutLineBreakCommand*)output.Data = new TextLayoutLineBreakCommand(1); output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutLineBreakCommand)); *(TextLayoutCommandType*)output.Data = TextLayoutCommandType.LineInfo; output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutLineInfoCommand)); if (part2IsNotDegenerate) { var textOffset = part2Offset; var textLength = part2Length; *(TextLayoutTextCommand*)output.InternalObjectStream.Data = new TextLayoutTextCommand(textOffset, textLength, 0, positionY + lineHeight, (Int16)sizeAfterBreak.Width, (Int16)sizeAfterBreak.Height); output.InternalObjectStream.FinalizeObject(sizeof(TextLayoutTextCommand)); } // Add the line break command to the broken line. AdvanceLineToNextCommand(0, 0, 1, 1); // Recalculate the parameters for the broken line. output.Seek(LineInfoCommandIndex + 1); var brokenLineWidth = 0; var brokenLineHeight = 0; var brokenLineLengthInText = 0; var brokenLineLengthInCommands = 0; var cmdType = TextLayoutCommandType.None; while ((cmdType = *(TextLayoutCommandType*)output.Data) != TextLayoutCommandType.LineInfo) { switch (cmdType) { case TextLayoutCommandType.Text: { var cmd = (TextLayoutTextCommand*)output.Data; brokenLineWidth += cmd->TextWidth; brokenLineHeight = Math.Max(brokenLineHeight, cmd->TextHeight); brokenLineLengthInText += cmd->TextLength; } break; case TextLayoutCommandType.Icon: { var cmd = (TextLayoutIconCommand*)output.Data; brokenLineWidth += cmd->Bounds.Width; brokenLineHeight = Math.Max(brokenLineHeight, cmd->Bounds.Height); brokenLineLengthInText += 1; } break; case TextLayoutCommandType.LineBreak: { var cmd = (TextLayoutLineBreakCommand*)output.Data; brokenLineLengthInText += cmd->Length; } break; } brokenLineLengthInCommands++; output.SeekNextCommand(); } // Finalize the broken line. totalLength = (totalLength - lineLengthInText) + brokenLineLengthInText; lineWidth = brokenLineWidth; lineHeight = brokenLineHeight; lineLengthInText = brokenLineLengthInText; lineLengthInCommands = brokenLineLengthInCommands; FinalizeLine(output, ref settings); // Fixup token bounds and update parameters for new line. LineInfoCommandIndex = insertionPosition + 1; while (output.StreamPositionInObjects < output.Count) { var width = 0; var height = 0; var lengthInCommands = 0; var lengthInText = 0; switch (*(TextLayoutCommandType*)output.Data) { case TextLayoutCommandType.Text: { var cmd = (TextLayoutTextCommand*)output.Data; width = cmd->TextWidth; height = cmd->TextHeight; lengthInCommands = 1; lengthInText = cmd->TextLength; cmd->TextX = PositionX; cmd->TextY = PositionY; } break; case TextLayoutCommandType.Icon: { var cmd = (TextLayoutIconCommand*)output.Data; width = cmd->IconWidth; height = cmd->IconHeight; lengthInCommands = 1; lengthInText = 1; cmd->IconX = PositionX; cmd->IconY = PositionY; } break; case TextLayoutCommandType.LineBreak: { var cmd = (TextLayoutLineBreakCommand*)output.Data; lengthInText += cmd->Length; } break; } AdvanceLineToNextCommand(width, height, lengthInCommands, lengthInText); output.SeekNextCommand(); } return true; }