1
0

BiDiData.cs 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. // Copyright (c) Six Labors.
  2. // Licensed under the Apache License, Version 2.0.
  3. // Ported from: https://github.com/SixLabors/Fonts/
  4. using System;
  5. using Avalonia.Utilities;
  6. namespace Avalonia.Media.TextFormatting.Unicode
  7. {
  8. /// <summary>
  9. /// Represents a unicode string and all associated attributes
  10. /// for each character required for the bidirectional Unicode algorithm
  11. /// </summary>
  12. internal class BidiData
  13. {
  14. private ArrayBuilder<BidiClass> _classes;
  15. private ArrayBuilder<BidiPairedBracketType> _pairedBracketTypes;
  16. private ArrayBuilder<int> _pairedBracketValues;
  17. private ArrayBuilder<BidiClass> _savedClasses;
  18. private ArrayBuilder<BidiPairedBracketType> _savedPairedBracketTypes;
  19. private ArrayBuilder<sbyte> _tempLevelBuffer;
  20. public BidiData(sbyte paragraphEmbeddingLevel)
  21. {
  22. ParagraphEmbeddingLevel = paragraphEmbeddingLevel;
  23. }
  24. public sbyte ParagraphEmbeddingLevel { get; private set; }
  25. public bool HasBrackets { get; private set; }
  26. public bool HasEmbeddings { get; private set; }
  27. public bool HasIsolates { get; private set; }
  28. /// <summary>
  29. /// Gets the length of the data held by the BidiData
  30. /// </summary>
  31. public int Length{get; private set; }
  32. /// <summary>
  33. /// Gets the bidi character type of each code point
  34. /// </summary>
  35. public ArraySlice<BidiClass> Classes { get; private set; }
  36. /// <summary>
  37. /// Gets the paired bracket type for each code point
  38. /// </summary>
  39. public ArraySlice<BidiPairedBracketType> PairedBracketTypes { get; private set; }
  40. /// <summary>
  41. /// Gets the paired bracket value for code point
  42. /// </summary>
  43. /// <remarks>
  44. /// The paired bracket values are the code points
  45. /// of each character where the opening code point
  46. /// is replaced with the closing code point for easier
  47. /// matching. Also, bracket code points are mapped
  48. /// to their canonical equivalents
  49. /// </remarks>
  50. public ArraySlice<int> PairedBracketValues { get; private set; }
  51. /// <summary>
  52. /// Appends text to the bidi data.
  53. /// </summary>
  54. /// <param name="text">The text to process.</param>
  55. public void Append(CharacterBufferRange text)
  56. {
  57. _classes.Add(text.Length);
  58. _pairedBracketTypes.Add(text.Length);
  59. _pairedBracketValues.Add(text.Length);
  60. // Resolve the BidiCharacterType, paired bracket type and paired
  61. // bracket values for all code points
  62. int i = Length;
  63. var codePointEnumerator = new CodepointEnumerator(text);
  64. while (codePointEnumerator.MoveNext())
  65. {
  66. var codepoint = codePointEnumerator.Current;
  67. // Look up BiDiClass
  68. var dir = codepoint.BiDiClass;
  69. _classes[i] = dir;
  70. switch (dir)
  71. {
  72. case BidiClass.LeftToRightEmbedding:
  73. case BidiClass.LeftToRightOverride:
  74. case BidiClass.RightToLeftEmbedding:
  75. case BidiClass.RightToLeftOverride:
  76. case BidiClass.PopDirectionalFormat:
  77. {
  78. HasEmbeddings = true;
  79. break;
  80. }
  81. case BidiClass.LeftToRightIsolate:
  82. case BidiClass.RightToLeftIsolate:
  83. case BidiClass.FirstStrongIsolate:
  84. case BidiClass.PopDirectionalIsolate:
  85. {
  86. HasIsolates = true;
  87. break;
  88. }
  89. }
  90. // Lookup paired bracket types
  91. var pbt = codepoint.PairedBracketType;
  92. _pairedBracketTypes[i] = pbt;
  93. if (pbt == BidiPairedBracketType.Open)
  94. {
  95. // Opening bracket types can never have a null pairing.
  96. codepoint.TryGetPairedBracket(out var paired);
  97. _pairedBracketValues[i] = (int)Codepoint.GetCanonicalType(paired).Value;
  98. HasBrackets = true;
  99. }
  100. else if (pbt == BidiPairedBracketType.Close)
  101. {
  102. _pairedBracketValues[i] = (int)Codepoint.GetCanonicalType(codepoint).Value;
  103. HasBrackets = true;
  104. }
  105. i++;
  106. }
  107. Length = i;
  108. Classes = _classes.AsSlice(0, Length);
  109. PairedBracketTypes = _pairedBracketTypes.AsSlice(0, Length);
  110. PairedBracketValues = _pairedBracketValues.AsSlice(0, Length);
  111. }
  112. /// <summary>
  113. /// Save the Types and PairedBracketTypes of this BiDiData
  114. /// </summary>
  115. /// <remarks>
  116. /// This is used when processing embedded style runs with
  117. /// BiDiClass overrides. Text layout process saves the data,
  118. /// overrides the style runs to neutral, processes the bidi
  119. /// data for the entire paragraph and then restores this data
  120. /// before processing the embedded runs.
  121. /// </remarks>
  122. public void SaveTypes()
  123. {
  124. // Capture the types data
  125. _savedClasses.Clear();
  126. _savedClasses.Add(_classes.AsSlice());
  127. _savedPairedBracketTypes.Clear();
  128. _savedPairedBracketTypes.Add(_pairedBracketTypes.AsSlice());
  129. }
  130. /// <summary>
  131. /// Restore the data saved by SaveTypes
  132. /// </summary>
  133. public void RestoreTypes()
  134. {
  135. _classes.Clear();
  136. _classes.Add(_savedClasses.AsSlice());
  137. _pairedBracketTypes.Clear();
  138. _pairedBracketTypes.Add(_savedPairedBracketTypes.AsSlice());
  139. }
  140. /// <summary>
  141. /// Gets a temporary level buffer. Used by the text layout process when
  142. /// resolving style runs with different BiDiClass.
  143. /// </summary>
  144. /// <param name="length">Length of the required ExpandableBuffer</param>
  145. /// <returns>An uninitialized level ExpandableBuffer</returns>
  146. public ArraySlice<sbyte> GetTempLevelBuffer(int length)
  147. {
  148. _tempLevelBuffer.Clear();
  149. return _tempLevelBuffer.Add(length, false);
  150. }
  151. }
  152. }