GlyphIndexList.cs 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. //MIT, 2016-present, WinterDev
  2. using System.Collections.Generic;
  3. using Typography.OpenFont.Tables;
  4. namespace Typography.TextLayout
  5. {
  6. /// <summary>
  7. /// impl replaceable glyph index list
  8. /// </summary>
  9. class GlyphIndexList : IGlyphIndexList
  10. {
  11. List<ushort> _glyphIndices = new List<ushort>();
  12. List<int> _inputCodePointIndexList = new List<int>();
  13. ushort _originalCodePointOffset = 0;
  14. List<GlyphIndexToUserCodePoint> _mapGlyphIndexToUserCodePoint = new List<GlyphIndexToUserCodePoint>();
  15. /// <summary>
  16. /// map from glyph index to original user char
  17. /// </summary>
  18. readonly struct GlyphIndexToUserCodePoint
  19. {
  20. /// <summary>
  21. /// offset from start layout char
  22. /// </summary>
  23. public readonly ushort o_codepoint_charOffset;
  24. public readonly ushort len;
  25. #if DEBUG
  26. public readonly short dbug_glyphIndex;
  27. #endif
  28. public GlyphIndexToUserCodePoint(ushort o_user_charOffset, ushort len)
  29. {
  30. this.len = len;
  31. this.o_codepoint_charOffset = o_user_charOffset;
  32. #if DEBUG
  33. this.dbug_glyphIndex = 0;
  34. #endif
  35. }
  36. #if DEBUG
  37. public override string ToString()
  38. {
  39. return "codepoint_offset: " + o_codepoint_charOffset + " : len" + len;
  40. }
  41. #endif
  42. }
  43. public void Clear()
  44. {
  45. _glyphIndices.Clear();
  46. _originalCodePointOffset = 0;
  47. _inputCodePointIndexList.Clear();
  48. _mapGlyphIndexToUserCodePoint.Clear();
  49. }
  50. /// <summary>
  51. /// add codepoint index and its glyph index
  52. /// </summary>
  53. /// <param name="codePointIndex">index to codepoint element in code point array</param>
  54. /// <param name="glyphIndex">map to glyphindex</param>
  55. public void AddGlyph(int codePointIndex, ushort glyphIndex)
  56. {
  57. //so we can monitor what substituion process
  58. _inputCodePointIndexList.Add(codePointIndex);
  59. _glyphIndices.Add(glyphIndex);
  60. var glyphIndexToCharMap = new GlyphIndexToUserCodePoint(_originalCodePointOffset, 1);
  61. #if DEBUG
  62. //glyphIndexToCharMap.dbug_glyphIndex = glyphIndex;
  63. #endif
  64. _mapGlyphIndexToUserCodePoint.Add(glyphIndexToCharMap);
  65. _originalCodePointOffset++;
  66. }
  67. /// <summary>
  68. /// glyph count may be more or less than original user char list (from substitution process)
  69. /// </summary>
  70. public int Count => _glyphIndices.Count;
  71. //
  72. public ushort this[int index] => _glyphIndices[index];
  73. //
  74. public void GetGlyphIndexAndMap(int index, out ushort glyphIndex, out ushort input_codepointOffset, out ushort input_mapLen)
  75. {
  76. glyphIndex = _glyphIndices[index];
  77. GlyphIndexToUserCodePoint glyphIndexToUserCodePoint = _mapGlyphIndexToUserCodePoint[index];
  78. input_codepointOffset = glyphIndexToUserCodePoint.o_codepoint_charOffset;
  79. input_mapLen = glyphIndexToUserCodePoint.len;
  80. }
  81. /// <summary>
  82. /// remove:add_new 1:1
  83. /// </summary>
  84. /// <param name="index"></param>
  85. /// <param name="newGlyphIndex"></param>
  86. public void Replace(int index, ushort newGlyphIndex)
  87. {
  88. _glyphIndices[index] = newGlyphIndex;
  89. }
  90. #if DEBUG
  91. List<GlyphIndexToUserCodePoint> _tmpGlypIndexBackup = new List<GlyphIndexToUserCodePoint>();
  92. #endif
  93. /// <summary>
  94. /// remove:add_new >=1:1
  95. /// </summary>
  96. /// <param name="index"></param>
  97. /// <param name="removeLen"></param>
  98. /// <param name="newGlyphIndex"></param>
  99. public void Replace(int index, int removeLen, ushort newGlyphIndex)
  100. {
  101. //eg f-i ligation
  102. //original f glyph and i glyph are removed
  103. //and then replace with a single glyph
  104. _glyphIndices.RemoveRange(index, removeLen);
  105. _glyphIndices.Insert(index, newGlyphIndex);
  106. //------------------------------------------------
  107. GlyphIndexToUserCodePoint firstRemove = _mapGlyphIndexToUserCodePoint[index];
  108. #if DEBUG
  109. _tmpGlypIndexBackup.Clear();
  110. int endAt = index + removeLen;
  111. for (int i = index; i < endAt; ++i)
  112. {
  113. _tmpGlypIndexBackup.Add(_mapGlyphIndexToUserCodePoint[i]);
  114. }
  115. _tmpGlypIndexBackup.Clear();
  116. #endif
  117. //TODO: check if removeLen > ushort.Max
  118. GlyphIndexToUserCodePoint newMap = new GlyphIndexToUserCodePoint(firstRemove.o_codepoint_charOffset, (ushort)removeLen);
  119. #if DEBUG
  120. //newMap.dbug_glyphIndex = newGlyphIndex;
  121. #endif
  122. //------------------------------------------------
  123. _mapGlyphIndexToUserCodePoint.RemoveRange(index, removeLen);
  124. _mapGlyphIndexToUserCodePoint.Insert(index, newMap);
  125. }
  126. /// <summary>
  127. /// remove: add_new 1:>=1
  128. /// </summary>
  129. /// <param name="index"></param>
  130. /// <param name="newGlyphIndices"></param>
  131. public void Replace(int index, ushort[] newGlyphIndices)
  132. {
  133. _glyphIndices.RemoveAt(index);
  134. _glyphIndices.InsertRange(index, newGlyphIndices);
  135. GlyphIndexToUserCodePoint cur = _mapGlyphIndexToUserCodePoint[index];
  136. _mapGlyphIndexToUserCodePoint.RemoveAt(index);
  137. //insert
  138. int j = newGlyphIndices.Length;
  139. for (int i = 0; i < j; ++i)
  140. {
  141. var newglyph = new GlyphIndexToUserCodePoint(cur.o_codepoint_charOffset, 1);
  142. #if DEBUG
  143. //newglyph.dbug_glyphIndex = newGlyphIndices[i];
  144. #endif
  145. //may point to the same user char
  146. _mapGlyphIndexToUserCodePoint.Insert(index, newglyph);
  147. }
  148. }
  149. public void CreateMapFromUserCodePointToGlyphIndices(List<UserCodePointToGlyphIndex> mapUserCodePointToGlyphIndex)
  150. {
  151. //(optional)
  152. //this method should be called after we finish the substitution process
  153. //--------------------------------------
  154. int codePointCount = _inputCodePointIndexList.Count;
  155. for (int i = 0; i < codePointCount; ++i)
  156. {
  157. //
  158. var codePointToGlyphIndexMap = new UserCodePointToGlyphIndex();
  159. //set index that point to original codePointIndex
  160. codePointToGlyphIndexMap.userCodePointIndex = _inputCodePointIndexList[i];
  161. //
  162. mapUserCodePointToGlyphIndex.Add(codePointToGlyphIndexMap);
  163. }
  164. //--------------------------------------
  165. //then fill the user-codepoint with glyph information information
  166. int glyphIndexCount = _glyphIndices.Count;
  167. for (int i = 0; i < glyphIndexCount; ++i)
  168. {
  169. GlyphIndexToUserCodePoint glyphIndexToUserCodePoint = _mapGlyphIndexToUserCodePoint[i];
  170. //
  171. UserCodePointToGlyphIndex charToGlyphIndexMap = mapUserCodePointToGlyphIndex[glyphIndexToUserCodePoint.o_codepoint_charOffset];
  172. charToGlyphIndexMap.AppendData((ushort)(i + 1), (glyphIndexToUserCodePoint.len));
  173. //replace with the changed value
  174. mapUserCodePointToGlyphIndex[glyphIndexToUserCodePoint.o_codepoint_charOffset] = charToGlyphIndexMap;
  175. }
  176. }
  177. }
  178. }