Glyph.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. //Apache2, 2017-present, WinterDev
  2. //Apache2, 2014-2016, Samuel Carlsson, WinterDev
  3. using System;
  4. using System.Text;
  5. namespace Typography.OpenFont
  6. {
  7. public class Glyph
  8. {
  9. /// <summary>
  10. /// glyph info has only essential layout detail (this is our extension)
  11. /// </summary>
  12. readonly bool _onlyLayoutEssMode;
  13. bool _hasOrgAdvWidth; //FOUND in all mode
  14. internal Glyph(
  15. GlyphPointF[] glyphPoints,
  16. ushort[] contourEndPoints,
  17. Bounds bounds,
  18. byte[] glyphInstructions,
  19. ushort index)
  20. {
  21. //create from TTF
  22. #if DEBUG
  23. this.dbugId = s_debugTotalId++;
  24. if (this.dbugId == 444)
  25. {
  26. }
  27. #endif
  28. this.GlyphPoints = glyphPoints;
  29. EndPoints = contourEndPoints;
  30. Bounds = bounds;
  31. GlyphInstructions = glyphInstructions;
  32. GlyphIndex = index;
  33. }
  34. public ushort GlyphIndex { get; } //FOUND in all mode
  35. public Bounds Bounds { get; internal set; } //FOUND in all mode
  36. public ushort OriginalAdvanceWidth { get; private set; } //FOUND in all mode
  37. internal ushort BitmapGlyphAdvanceWidth { get; set; } //FOUND in all mode
  38. //TrueTypeFont
  39. public ushort[] EndPoints { get; private set; } //NULL in _onlyLayoutEssMode
  40. public GlyphPointF[] GlyphPoints { get; private set; } //NULL in _onlyLayoutEssMode
  41. internal byte[] GlyphInstructions { get; set; } //NULL in _onlyLayoutEssMode
  42. public bool HasGlyphInstructions => this.GlyphInstructions != null; //FALSE n _onlyLayoutEssMode
  43. //
  44. public GlyphClassKind GlyphClass { get; internal set; } //FOUND in all mode
  45. internal ushort MarkClassDef { get; set; } //FOUND in all mode
  46. public short MinX => Bounds.XMin;
  47. public short MaxX => Bounds.XMax;
  48. public short MinY => Bounds.YMin;
  49. public short MaxY => Bounds.YMax;
  50. public static bool HasOriginalAdvancedWidth(Glyph glyph) => glyph._hasOrgAdvWidth;
  51. public static void SetOriginalAdvancedWidth(Glyph glyph, ushort advW)
  52. {
  53. glyph.OriginalAdvanceWidth = advW;
  54. glyph._hasOrgAdvWidth = true;
  55. }
  56. /// <summary>
  57. /// TrueType outline, offset glyph points
  58. /// </summary>
  59. /// <param name="glyph"></param>
  60. /// <param name="dx"></param>
  61. /// <param name="dy"></param>
  62. internal static void TtfOffsetXY(Glyph glyph, short dx, short dy)
  63. {
  64. //change data on current glyph
  65. GlyphPointF[] glyphPoints = glyph.GlyphPoints;
  66. for (int i = glyphPoints.Length - 1; i >= 0; --i)
  67. {
  68. glyphPoints[i] = glyphPoints[i].Offset(dx, dy);
  69. }
  70. //-------------------------
  71. Bounds orgBounds = glyph.Bounds;
  72. glyph.Bounds = new Bounds(
  73. (short)(orgBounds.XMin + dx),
  74. (short)(orgBounds.YMin + dy),
  75. (short)(orgBounds.XMax + dx),
  76. (short)(orgBounds.YMax + dy));
  77. }
  78. /// <summary>
  79. ///TrueType outline, transform normal
  80. /// </summary>
  81. /// <param name="glyph"></param>
  82. /// <param name="m00"></param>
  83. /// <param name="m01"></param>
  84. /// <param name="m10"></param>
  85. /// <param name="m11"></param>
  86. internal static void TtfTransformWith2x2Matrix(Glyph glyph, float m00, float m01, float m10, float m11)
  87. {
  88. //http://stackoverflow.com/questions/13188156/whats-the-different-between-vector2-transform-and-vector2-transformnormal-i
  89. //http://www.technologicalutopia.com/sourcecode/xnageometry/vector2.cs.htm
  90. //change data on current glyph
  91. float new_xmin = 0;
  92. float new_ymin = 0;
  93. float new_xmax = 0;
  94. float new_ymax = 0;
  95. GlyphPointF[] glyphPoints = glyph.GlyphPoints;
  96. for (int i = 0; i < glyphPoints.Length; ++i)
  97. {
  98. GlyphPointF p = glyphPoints[i];
  99. float x = p.P.X;
  100. float y = p.P.Y;
  101. float newX, newY;
  102. //please note that this is transform normal***
  103. glyphPoints[i] = new GlyphPointF(
  104. newX = (float)Math.Round((x * m00) + (y * m10)),
  105. newY = (float)Math.Round((x * m01) + (y * m11)),
  106. p.onCurve);
  107. //short newX = xs[i] = (short)Math.Round((x * m00) + (y * m10));
  108. //short newY = ys[i] = (short)Math.Round((x * m01) + (y * m11));
  109. //------
  110. if (newX < new_xmin)
  111. {
  112. new_xmin = newX;
  113. }
  114. if (newX > new_xmax)
  115. {
  116. new_xmax = newX;
  117. }
  118. //------
  119. if (newY < new_ymin)
  120. {
  121. new_ymin = newY;
  122. }
  123. if (newY > new_ymax)
  124. {
  125. new_ymax = newY;
  126. }
  127. }
  128. //TODO: review here
  129. glyph.Bounds = new Bounds(
  130. (short)new_xmin, (short)new_ymin,
  131. (short)new_xmax, (short)new_ymax);
  132. }
  133. /// <summary>
  134. /// TrueType outline glyph clone
  135. /// </summary>
  136. /// <param name="original"></param>
  137. /// <param name="newGlyphIndex"></param>
  138. /// <returns></returns>
  139. internal static Glyph TtfOutlineGlyphClone(Glyph original, ushort newGlyphIndex)
  140. {
  141. //for true type instruction glyph***
  142. return new Glyph(
  143. Utils.CloneArray(original.GlyphPoints),
  144. Utils.CloneArray(original.EndPoints),
  145. original.Bounds,
  146. original.GlyphInstructions != null ? Utils.CloneArray(original.GlyphInstructions) : null,
  147. newGlyphIndex);
  148. }
  149. /// <summary>
  150. /// append data from src to dest, dest data will changed***
  151. /// </summary>
  152. /// <param name="src"></param>
  153. /// <param name="dest"></param>
  154. internal static void TtfAppendGlyph(Glyph dest, Glyph src)
  155. {
  156. int org_dest_len = dest.EndPoints.Length;
  157. #if DEBUG
  158. int src_contour_count = src.EndPoints.Length;
  159. #endif
  160. if (org_dest_len == 0)
  161. {
  162. //org is empty glyph
  163. dest.GlyphPoints = Utils.ConcatArray(dest.GlyphPoints, src.GlyphPoints);
  164. dest.EndPoints = Utils.ConcatArray(dest.EndPoints, src.EndPoints);
  165. }
  166. else
  167. {
  168. ushort org_last_point = (ushort)(dest.EndPoints[org_dest_len - 1] + 1); //since start at 0
  169. dest.GlyphPoints = Utils.ConcatArray(dest.GlyphPoints, src.GlyphPoints);
  170. dest.EndPoints = Utils.ConcatArray(dest.EndPoints, src.EndPoints);
  171. //offset latest append contour end points
  172. int newlen = dest.EndPoints.Length;
  173. for (int i = org_dest_len; i < newlen; ++i)
  174. {
  175. dest.EndPoints[i] += (ushort)org_last_point;
  176. }
  177. }
  178. //calculate new bounds
  179. Bounds destBound = dest.Bounds;
  180. Bounds srcBound = src.Bounds;
  181. short newXmin = (short)Math.Min(destBound.XMin, srcBound.XMin);
  182. short newYMin = (short)Math.Min(destBound.YMin, srcBound.YMin);
  183. short newXMax = (short)Math.Max(destBound.XMax, srcBound.XMax);
  184. short newYMax = (short)Math.Max(destBound.YMax, srcBound.YMax);
  185. dest.Bounds = new Bounds(newXmin, newYMin, newXMax, newYMax);
  186. }
  187. #if DEBUG
  188. public readonly int dbugId;
  189. static int s_debugTotalId;
  190. public override string ToString()
  191. {
  192. var stbuilder = new StringBuilder();
  193. if (IsCffGlyph)
  194. {
  195. stbuilder.Append("cff");
  196. stbuilder.Append(",index=" + GlyphIndex);
  197. stbuilder.Append(",name=" + _cff1GlyphData.Name);
  198. }
  199. else
  200. {
  201. stbuilder.Append("ttf");
  202. stbuilder.Append(",index=" + GlyphIndex);
  203. stbuilder.Append(",class=" + GlyphClass.ToString());
  204. if (MarkClassDef != 0)
  205. {
  206. stbuilder.Append(",mark_class=" + MarkClassDef);
  207. }
  208. }
  209. return stbuilder.ToString();
  210. }
  211. #endif
  212. //--------------------
  213. //cff
  214. internal readonly CFF.Cff1GlyphData _cff1GlyphData; //NULL in _onlyLayoutEssMode
  215. internal Glyph(CFF.Cff1GlyphData cff1Glyph, ushort glyphIndex)
  216. {
  217. #if DEBUG
  218. this.dbugId = s_debugTotalId++;
  219. cff1Glyph.dbugGlyphIndex = glyphIndex;
  220. #endif
  221. //create from CFF
  222. _cff1GlyphData = cff1Glyph;
  223. this.GlyphIndex = glyphIndex;
  224. }
  225. public bool IsCffGlyph => _cff1GlyphData != null;
  226. public CFF.Cff1GlyphData GetCff1GlyphData() => _cff1GlyphData;
  227. //TODO: review here again
  228. public MathGlyphs.MathGlyphInfo MathGlyphInfo { get; internal set; } //FOUND in all mode (if font has this data)
  229. uint _streamLen; //FOUND in all mode (if font has this data)
  230. ushort _imgFormat; //FOUND in all mode (if font has this data)
  231. internal Glyph(ushort glyphIndex, uint streamOffset, uint streamLen, ushort imgFormat)
  232. {
  233. //_bmpGlyphSource = bmpGlyphSource;
  234. BitmapStreamOffset = streamOffset;
  235. _streamLen = streamLen;
  236. _imgFormat = imgFormat;
  237. this.GlyphIndex = glyphIndex;
  238. }
  239. internal uint BitmapStreamOffset { get; private set; }
  240. internal uint BitmapFormat => _imgFormat;
  241. private Glyph(ushort glyphIndex)
  242. {
  243. //for Clone_NO_BuildingInstructions()
  244. _onlyLayoutEssMode = true;
  245. GlyphIndex = glyphIndex;
  246. }
  247. internal static void CopyExistingGlyphInfo(Glyph src, Glyph dst)
  248. {
  249. dst.Bounds = src.Bounds;
  250. dst._hasOrgAdvWidth = src._hasOrgAdvWidth;
  251. dst.OriginalAdvanceWidth = src.OriginalAdvanceWidth;
  252. dst.BitmapGlyphAdvanceWidth = src.BitmapGlyphAdvanceWidth;
  253. dst.GlyphClass = src.GlyphClass;
  254. dst.MarkClassDef = src.MarkClassDef;
  255. //ttf: NO EndPoints, GlyphPoints, HasGlyphInstructions
  256. //cff: NO _cff1GlyphData
  257. //math-font:
  258. dst.MathGlyphInfo = src.MathGlyphInfo;
  259. dst.BitmapStreamOffset = src.BitmapStreamOffset;
  260. dst._streamLen = src._streamLen;
  261. dst._imgFormat = src._imgFormat;
  262. }
  263. internal static Glyph Clone_NO_BuildingInstructions(Glyph src)
  264. {
  265. //a new glyph has only detail about glyph layout
  266. //NO information about glyph building instructions
  267. //1. if src if ttf
  268. //2. if src is cff
  269. //3. if src is svg
  270. //4. if src is bitmap
  271. Glyph newclone = new Glyph(src.GlyphIndex);
  272. CopyExistingGlyphInfo(src, newclone);
  273. return newclone;
  274. }
  275. }
  276. //https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
  277. public enum GlyphClassKind : byte
  278. {
  279. //1 Base glyph (single character, spacing glyph)
  280. //2 Ligature glyph (multiple character, spacing glyph)
  281. //3 Mark glyph (non-spacing combining glyph)
  282. //4 Component glyph (part of single character, spacing glyph)
  283. //
  284. // The font developer does not have to classify every glyph in the font,
  285. //but any glyph not assigned a class value falls into Class zero (0).
  286. //For instance, class values might be useful for the Arabic glyphs in a font, but not for the Latin glyphs.
  287. //Then the GlyphClassDef table will list only Arabic glyphs, and-by default-the Latin glyphs will be assigned to Class 0.
  288. //Component glyphs can be put together to generate ligatures.
  289. //A ligature can be generated by creating a glyph in the font that references the component glyphs,
  290. //or outputting the component glyphs in the desired sequence.
  291. //Component glyphs are not used in defining any GSUB or GPOS formats.
  292. //
  293. Zero = 0,//class0, classZero
  294. /// <summary>
  295. /// Base glyph (single character, spacing glyph)
  296. /// </summary>
  297. Base,
  298. /// <summary>
  299. /// Ligature glyph (multiple character, spacing glyph)
  300. /// </summary>
  301. Ligature,
  302. /// <summary>
  303. /// Mark glyph (non-spacing combining glyph)
  304. /// </summary>
  305. Mark,
  306. /// <summary>
  307. /// Component glyph (part of single character, spacing glyph)
  308. /// </summary>
  309. Component
  310. }
  311. }