GlyphTableClass.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. using System;
  2. using System.Collections;
  3. using System.Drawing;
  4. using System.Runtime.InteropServices;
  5. //#pragma warning disable CS3001, CS3002, CS3003, CS1591
  6. namespace FastReport.Fonts
  7. {
  8. /// <summary>
  9. /// Table with encoded glyphs' outline
  10. /// </summary>
  11. public class GlyphTableClass : TrueTypeTable
  12. {
  13. #region "Type definitions"
  14. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  15. public struct GlyphHeader
  16. {
  17. [FieldOffset(0)]
  18. public short numberOfContours;
  19. [FieldOffset(2)]
  20. public short xMin;
  21. [FieldOffset(4)]
  22. public short yMin;
  23. [FieldOffset(6)]
  24. public short xMax;
  25. [FieldOffset(8)]
  26. public short yMax;
  27. }
  28. [StructLayout(LayoutKind.Explicit, Pack = 1)]
  29. public struct CompositeGlyphHeader
  30. {
  31. [FieldOffset(0)]
  32. public ushort flags; // component flag
  33. [FieldOffset(2)]
  34. public ushort glyphIndex; // glyph index of component
  35. }
  36. public enum CompositeFlags
  37. {
  38. ARG_1_AND_2_ARE_WORDS = 0x0001, // If this is set, the arguments are words; otherwise, they are bytes.
  39. ARGS_ARE_XY_VALUES = 0x0002, // If this is set, the arguments are xy values; otherwise, they are points.
  40. ROUND_XY_TO_GRID = 0x0004, // For the xy values if the preceding is true.
  41. WE_HAVE_A_SCALE = 0x0008, // This indicates that there is a simple scale for the component. Otherwise, scale = 1.0.
  42. RESERVED = 0x0010, // This bit is reserved. Set it to 0.
  43. MORE_COMPONENTS = 0x0020, // Indicates at least one more glyph after this one.
  44. WE_HAVE_AN_X_AND_Y_SCALE = 0x0040, // The x direction will use a different scale from the y direction.
  45. WE_HAVE_A_TWO_BY_TWO = 0x0080, // There is a 2 by 2 transformation that will be used to scale the component.
  46. WE_HAVE_INSTRUCTIONS = 0x0100, // Following the last component are instructions for the composite character.
  47. USE_MY_METRICS = 0x0200, // If set, this forces the aw and lsb (and rsb) for the composite to be equal to those from this original glyph. This works for hinted and unhinted characters.
  48. OVERLAP_COMPOUND = 0x0400, // Used by Apple in GX fonts.
  49. SCALED_COMPONENT_OFFSET = 0x0800, // Composite designed to have the component offset scaled (designed for Apple rasterizer).
  50. UNSCALED_COMPONENT_OFFSET = 0x10000 // Composite designed not to have the component offset scaled (designed for the Microsoft TrueType rasterizer).
  51. }
  52. #endregion
  53. //IntPtr glyph_table_ptr;
  54. long glyph_table_ptr;
  55. internal override void Load(FontStream font)
  56. {
  57. font.Position = this.Offset;
  58. glyph_table_ptr = this.Offset;
  59. }
  60. // Strean position must point to glyph's header. Caller responsible for that
  61. internal GlyphHeader GetGlyphHeader(FontStream stream /*, int glyph_offset*/)
  62. {
  63. GlyphHeader gheader;
  64. // IntPtr glyph_ptr = Increment(glyph_table_ptr, glyph_offset);
  65. gheader = new GlyphHeader(); /// Marshal.PtrToStructure(glyph_ptr, typeof(GlyphHeader));
  66. gheader.numberOfContours = stream.ReadInt16(); // SwapInt16(gheader.numberOfContours);
  67. gheader.xMin = stream.ReadInt16(); // SwapInt16(gheader.xMin);
  68. gheader.yMin = stream.ReadInt16(); // SwapInt16(gheader.yMin);
  69. gheader.xMax = stream.ReadInt16(); // SwapInt16(gheader.xMax);
  70. gheader.yMax = stream.ReadInt16(); // SwapInt16(gheader.yMax);
  71. return gheader;
  72. }
  73. /////////////////////////////////////////////////////////////////////////////////////////////////
  74. // Return list of glyph indexes of composite glyph
  75. /////////////////////////////////////////////////////////////////////////////////////////////////
  76. public ArrayList CheckGlyph(FontStream stream, int glyph_offset, int glyph_size)
  77. {
  78. ArrayList CompositeIndexes = new ArrayList();
  79. //IntPtr glyph_ptr = Increment(glyph_table_ptr, glyph_offset);
  80. stream.Position = this.Offset + glyph_offset;
  81. GlyphHeader gheader = GetGlyphHeader(stream/*, glyph_offset*/);
  82. if (gheader.numberOfContours < 0)
  83. {
  84. CompositeGlyphHeader cgh;
  85. //IntPtr composite_header_ptr = Increment(glyph_ptr, Marshal.SizeOf(gheader));
  86. // long composite_header_ptr = glyph_ptr + 10; // Marshal.SizeOf(gheader));
  87. do
  88. {
  89. cgh = new CompositeGlyphHeader(); // Marshal.PtrToStructure(composite_header_ptr, typeof(CompositeGlyphHeader));
  90. cgh.flags = stream.ReadUInt16(); // SwapUInt16(cgh.flags);
  91. cgh.glyphIndex = stream.ReadUInt16(); // SwapUInt16(cgh.glyphIndex);
  92. CompositeIndexes.Add(cgh.glyphIndex);
  93. // composite_header_ptr = Increment(composite_header_ptr, Marshal.SizeOf(cgh));
  94. int x, y;
  95. if ((cgh.flags & (ushort)CompositeFlags.ARG_1_AND_2_ARE_WORDS) != 0)
  96. {
  97. x = stream.ReadInt16(); // SwapInt16(Marshal.ReadInt16(composite_header_ptr));
  98. y = stream.ReadInt16(); // SwapInt16(Marshal.ReadInt16(composite_header_ptr));
  99. }
  100. else
  101. {
  102. x = stream.ReadByte(); // Marshal.ReadByte(composite_header_ptr);
  103. y = stream.ReadByte(); // Marshal.ReadByte(composite_header_ptr);
  104. }
  105. if ((cgh.flags & (ushort)CompositeFlags.WE_HAVE_A_SCALE) != 0)
  106. {
  107. ushort scale = stream.ReadUInt16();
  108. //composite_header_ptr = Increment(composite_header_ptr, 2);
  109. //F2Dot14 scale; /* Format 2.14 */
  110. }
  111. else if ((cgh.flags & (ushort)CompositeFlags.WE_HAVE_AN_X_AND_Y_SCALE) != 0)
  112. {
  113. uint a_and_y_scale = stream.ReadUInt32();
  114. //composite_header_ptr = Increment(composite_header_ptr, 4);
  115. //F2Dot14 xscale; /* Format 2.14 */
  116. //F2Dot14 yscale; /* Format 2.14 */
  117. }
  118. else if ((cgh.flags & (ushort)CompositeFlags.WE_HAVE_A_TWO_BY_TWO) != 0)
  119. {
  120. ushort xscale = stream.ReadUInt16();
  121. ushort scale01 = stream.ReadUInt16();
  122. ushort scale10 = stream.ReadUInt16();
  123. ushort yscale = stream.ReadUInt16();
  124. //composite_header_ptr = Increment(composite_header_ptr, 8);
  125. //F2Dot14 xscale; /* Format 2.14 */
  126. //F2Dot14 scale01; /* Format 2.14 */
  127. //F2Dot14 scale10; /* Format 2.14 */
  128. //F2Dot14 yscale; /* Format 2.14 */
  129. }
  130. }
  131. while ((cgh.flags & (ushort)CompositeFlags.MORE_COMPONENTS) != 0);
  132. if ((cgh.flags & (ushort)CompositeFlags.WE_HAVE_INSTRUCTIONS) != 0)
  133. {
  134. ushort num_instr = stream.ReadUInt16(); // ((ushort)Marshal.PtrToStructure(composite_header_ptr, typeof(ushort)));
  135. //composite_header_ptr = Increment(composite_header_ptr, 2 + num_instr);
  136. byte[] instr = new byte[num_instr];
  137. for (int i = 0; i < num_instr; i++)
  138. instr[i] = stream.ReadByte(); //BYTE instr[numInstr]
  139. }
  140. }
  141. else
  142. {
  143. ; // Simple glyph
  144. }
  145. return CompositeIndexes;
  146. }
  147. //private IntPtr ReadRawByte(IntPtr ptr, out byte val)
  148. //{
  149. // val = (byte)Marshal.ReadByte(ptr);
  150. // return Increment(ptr, 1);
  151. //}
  152. internal enum GlyphFlags
  153. {
  154. ON_CURVE = 0x01, // If set, the point is on the curve; otherwise, it is off the curve.
  155. X_SHORT = 0x02, // If set, the corresponding x-coordinate is 1 byte long. If not set, 2 bytes.
  156. Y_SHORT = 0x04, // If set, the corresponding y-coordinate is 1 byte long. If not set, 2 bytes.
  157. REPEAT = 0x08, // If set, the next byte specifies the number of additional times this set of flags is to be repeated. In this way, the number of flags listed can be smaller than the number of points in a character.
  158. X_SAME = 0x10, // This flag has two meanings, depending on how the x-Short Vector flag is set. If x-Short Vector is set, this bit describes the sign of the value, with 1 equalling positive and 0 negative. If the x-Short Vector bit is not set and this bit is set, then the current x-coordinate is the same as the previous x-coordinate. If the x-Short Vector bit is not set and this bit is also not set, the current x-coordinate is a signed 16-bit delta vector.
  159. Y_SAME = 0x20, // This flag has two meanings, depending on how the y-Short Vector flag is set. If y-Short Vector is set, this bit describes the sign of the value, with 1 equalling positive and 0 negative. If the y-Short Vector bit is not set and this bit is set, then the current y-coordinate is the same as the previous y-coordinate. If the y-Short Vector bit is not set and this bit is also not set, the current y-coordinate is a signed 16-bit delta vector. }
  160. X_POSITIVE = 0x10,
  161. Y_POSITIVE = 0x20
  162. }
  163. internal class GlyphPoint
  164. {
  165. public float x;
  166. public float y;
  167. public bool on_curve;
  168. public bool end_of_contour;
  169. public PointF Point { get { return new PointF(x, y); } }
  170. }
  171. const ushort F2Dot14 = 0x4000;
  172. /////////////////////////////////////////////////////////////////////////////////////////////////
  173. // Return Graphics path of Glyph
  174. /////////////////////////////////////////////////////////////////////////////////////////////////
  175. public FastGraphicsPath GetGlyph(
  176. FontStream stream,
  177. int glyph_offset,
  178. ushort glyph_data_size,
  179. float font_rsize,
  180. PointF position,
  181. IndexToLocationClass index_to_location,
  182. FontHeaderClass font_header,
  183. out GlyphHeader gheader)
  184. {
  185. if (glyph_data_size == 0)
  186. {
  187. // IntPtr glyph_ptr1 = Increment(glyph_table_ptr, glyph_offset);
  188. stream.Position = glyph_table_ptr + glyph_offset;
  189. gheader = new GlyphHeader(); // Marshal.PtrToStructure(glyph_ptr1, typeof(GlyphHeader));
  190. gheader.numberOfContours = stream.ReadInt16();
  191. gheader.xMin = stream.ReadInt16();
  192. gheader.yMin = stream.ReadInt16();
  193. gheader.xMax = stream.ReadInt16();
  194. gheader.yMax = stream.ReadInt16();
  195. //space is example have size 0
  196. return new FastGraphicsPath(FastFillMode.Alternate);
  197. }
  198. //IntPtr glyph_ptr = Increment(glyph_table_ptr, glyph_offset);
  199. stream.Position = glyph_table_ptr + glyph_offset;
  200. gheader = new GlyphHeader(); // Marshal.PtrToStructure(glyph_ptr, typeof(GlyphHeader));
  201. gheader.numberOfContours = stream.ReadInt16(); // SwapInt16(gheader.numberOfContours);
  202. gheader.xMin = stream.ReadInt16(); // SwapInt16(gheader.xMin);
  203. gheader.yMin = stream.ReadInt16(); // SwapInt16(gheader.yMin);
  204. gheader.xMax = stream.ReadInt16(); // SwapInt16(gheader.xMax);
  205. gheader.yMax = stream.ReadInt16(); // SwapInt16(gheader.yMax);
  206. ushort instructions_count;
  207. if (gheader.numberOfContours < 0)
  208. {
  209. FastGraphicsPath result = new FastGraphicsPath(FastFillMode.Alternate);
  210. // IntPtr c_glyph_ptr = Increment(glyph_ptr, Marshal.SizeOf(typeof(GlyphHeader)));
  211. CompositeGlyphHeader cgheader;
  212. short argument1 = 0;
  213. short argument2 = 0;
  214. float m00 = 1;
  215. float m01 = 0;
  216. float m02 = 0;
  217. float m10 = 0;
  218. float m11 = 1;
  219. float m12 = 0;
  220. ushort arg1arg2;
  221. do
  222. {
  223. cgheader = new CompositeGlyphHeader(); // Marshal.PtrToStructure(c_glyph_ptr, typeof(CompositeGlyphHeader));
  224. cgheader.flags = stream.ReadUInt16(); // SwapUInt16(cgheader.flags);
  225. cgheader.glyphIndex = stream.ReadUInt16(); // SwapUInt16(cgheader.glyphIndex);
  226. long keep_stream_position = stream.Position;
  227. uint location;
  228. //ushort i2l_idx = this.cmap_table.GetGlyphIndex((ushort)ch);
  229. ushort length = index_to_location.GetGlyph(cgheader.glyphIndex, font_header, out location);
  230. FastGraphicsPath aPath = GetGlyph(stream, (int)location, length, font_rsize, Point.Empty, index_to_location, font_header, out gheader);
  231. // c_glyph_ptr = Increment(c_glyph_ptr, Marshal.SizeOf(typeof(CompositeGlyphHeader)));
  232. stream.Position = keep_stream_position;
  233. if ((cgheader.flags & 0x1) > 0)
  234. {
  235. argument1 = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  236. argument2 = stream.ReadInt16();
  237. //read short x2
  238. }
  239. else
  240. {
  241. arg1arg2 = stream.ReadUInt16(); // (ushort)Marshal.PtrToStructure(c_glyph_ptr, typeof(ushort));
  242. argument1 = (sbyte)(arg1arg2 >> 8);
  243. argument2 = (sbyte)(arg1arg2 & 0xFF);
  244. //unk what to do with sign
  245. //read ushort
  246. }
  247. if ((cgheader.flags & 0x2) > 0)
  248. {
  249. //ARGS_ARE_XY_VALUES
  250. m02 = argument1 / font_rsize;
  251. m12 = -argument2 / font_rsize;
  252. }
  253. else
  254. {
  255. //ARGS_ARE_XY_A_NOT_VALUES
  256. //unk what to do
  257. }
  258. short scale;
  259. if ((cgheader.flags & 0x8) > 0)
  260. {
  261. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  262. float fScale = scale / (float)F2Dot14;
  263. m00 = fScale;
  264. m11 = fScale;
  265. }
  266. else if ((cgheader.flags & 0x40) > 0)
  267. {
  268. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  269. float fXScale = scale / (float)F2Dot14;
  270. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  271. float fYScale = scale / (float)F2Dot14;
  272. m00 = fXScale;
  273. m11 = fYScale;
  274. }
  275. else if ((cgheader.flags & 0x80) > 0)
  276. {
  277. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  278. float f00Scale = scale / (float)F2Dot14;
  279. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  280. float f01Scale = scale / (float)F2Dot14;
  281. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  282. float f10Scale = scale / (float)F2Dot14;
  283. scale = stream.ReadInt16(); // (short)Marshal.PtrToStructure(c_glyph_ptr, typeof(short));
  284. float f11Scale = scale / (float)F2Dot14;
  285. m00 = f00Scale;
  286. m11 = f11Scale;
  287. m01 = f01Scale;
  288. m10 = f10Scale;
  289. }
  290. aPath.Transform(m00, m01, m10, m11, m02 + position.X, m12 + position.Y);
  291. result.AddPath(aPath, false);
  292. } while ((cgheader.flags & 0x20) > 0);
  293. if ((cgheader.flags & 0x100) > 0)
  294. {
  295. ushort aInstructions_count = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(c_glyph_ptr, typeof(ushort)));
  296. byte[] aInstructions = new byte[aInstructions_count];
  297. //Marshal.Copy(c_glyph_ptr, aInstructions, 0, (int)aInstructions.Length);
  298. for (int i = 0; i < aInstructions_count; i++)
  299. aInstructions[i] = stream.ReadByte();
  300. //ptr = Increment(ptr, instructions.Length);
  301. }
  302. return result;
  303. }
  304. ushort[] endPtsOfContours = new ushort[gheader.numberOfContours];
  305. // IntPtr ptr = Increment(glyph_ptr, Marshal.SizeOf(gheader));
  306. for (int i = 0; i < endPtsOfContours.Length; i++)
  307. endPtsOfContours[i] = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(ptr, typeof(ushort)));
  308. instructions_count = stream.ReadUInt16(); // SwapUInt16((ushort)Marshal.PtrToStructure(ptr, typeof(ushort)));
  309. byte[] instructions = new byte[instructions_count];
  310. for (int i = 0; i < instructions.Length; i++)
  311. instructions[i] = stream.ReadByte();
  312. // Marshal.Copy(ptr, instructions, 0, (int)instructions.Length);
  313. // ptr = Increment(ptr, instructions.Length);
  314. int number_of_points = endPtsOfContours[endPtsOfContours.Length - 1] + 1;
  315. byte[] flags = new byte[number_of_points];
  316. GlyphPoint[] points = new GlyphPoint[number_of_points];
  317. byte repeatCount = 0;
  318. byte repeatFlag = 0;
  319. for (int i = 0; i < number_of_points; i++)
  320. {
  321. if (repeatCount > 0)
  322. {
  323. flags[i] = repeatFlag;
  324. repeatCount--;
  325. }
  326. else
  327. {
  328. //ptr = ReadRawByte(ptr, out flags[i]);
  329. flags[i] = stream.ReadByte();
  330. if ((flags[i] & (byte)GlyphFlags.REPEAT) != 0)
  331. {
  332. // ptr = ReadRawByte(ptr, out repeatCount);
  333. repeatCount = stream.ReadByte();
  334. repeatFlag = flags[i];
  335. }
  336. }
  337. points[i] = new GlyphPoint();
  338. points[i].on_curve = (flags[i] & (byte)GlyphFlags.ON_CURVE) != 0;
  339. }
  340. for (int i = 0; i < endPtsOfContours.Length; i++)
  341. {
  342. points[endPtsOfContours[i]].end_of_contour = true;
  343. }
  344. short last = 0;
  345. for (int i = 0; i < number_of_points; i++)
  346. {
  347. byte val;
  348. bool sign = (flags[i] & (byte)GlyphFlags.X_POSITIVE) != 0;
  349. if ((flags[i] & (byte)GlyphFlags.X_SHORT) != 0)
  350. {
  351. val = stream.ReadByte(); // Marshal.ReadByte(ptr);
  352. last += (short)(sign ? val : -val);
  353. }
  354. else
  355. {
  356. if (!sign)
  357. {
  358. last += stream.ReadInt16(); // SwapInt16(Marshal.ReadInt16(ptr));
  359. }
  360. }
  361. points[i].x = last / font_rsize;
  362. }
  363. last = 0;
  364. for (int i = 0; i < number_of_points; i++)
  365. {
  366. byte val;
  367. bool sign = (flags[i] & (byte)GlyphFlags.Y_POSITIVE) != 0;
  368. if ((flags[i] & (byte)GlyphFlags.Y_SHORT) != 0)
  369. {
  370. val = stream.ReadByte(); // Marshal.ReadByte(ptr);
  371. last += (short)(sign ? val : -val);
  372. }
  373. else
  374. {
  375. if (!sign)
  376. {
  377. last += stream.ReadInt16(); // SwapInt16(Marshal.ReadInt16(ptr));
  378. }
  379. }
  380. points[i].y = last / font_rsize;
  381. }
  382. // Draw glyphs outline
  383. bool start_new_contour = true;
  384. int idx = 0;
  385. FastGraphicsPath path = new FastGraphicsPath(FastFillMode.Winding);
  386. GlyphPoint first_point;
  387. first_point = points[idx];
  388. start_new_contour = true;
  389. PointF beg, first, end, next, implied;
  390. bool curent_on_curve, next_on_curve;
  391. first = beg = new PointF(points[0].Point.X + position.X, position.Y - points[0].Point.Y);
  392. for (idx = 0; idx < points.Length; idx++)
  393. {
  394. curent_on_curve = points[idx].on_curve;
  395. if (idx + 1 < points.Length)
  396. {
  397. next = new PointF(points[idx + 1].Point.X + position.X, position.Y - points[idx + 1].Point.Y);
  398. next_on_curve = points[idx + 1].on_curve;
  399. }
  400. else
  401. {
  402. next = new PointF(points[0].Point.X + position.X, position.Y - points[0].Point.Y);
  403. next_on_curve = points[0].on_curve;
  404. }
  405. if (start_new_contour == true)
  406. {
  407. path.StartFigure();
  408. first = beg;
  409. start_new_contour = false;
  410. }
  411. if (points[idx].end_of_contour)
  412. {
  413. start_new_contour = true;
  414. //path.CloseFigure();
  415. implied = new PointF(points[idx].Point.X + position.X, position.Y - points[idx].Point.Y);
  416. end = first;
  417. if (curent_on_curve)
  418. {
  419. //end = next;
  420. path.AddLine(beg, end);
  421. }
  422. else
  423. {
  424. AddSpline(path, beg, implied, end, position);
  425. }
  426. beg = next;
  427. continue;
  428. }
  429. ////////////////////////////////////////////////////////////////////
  430. if (curent_on_curve) //
  431. {
  432. if (next_on_curve) //
  433. {
  434. end = next;
  435. path.AddLine(beg, end);
  436. beg = end;
  437. }
  438. else
  439. {
  440. //
  441. }
  442. }
  443. else //
  444. {
  445. implied = new PointF(points[idx].Point.X + position.X, position.Y - points[idx].Point.Y);
  446. if (next_on_curve) //
  447. {
  448. end = next;
  449. AddSpline(path, beg, implied, end, position);
  450. beg = end;
  451. }
  452. else
  453. {
  454. float X = position.X + ((points[idx + 1].x - points[idx].x) / 2) + points[idx].x;
  455. float Y = position.Y - (((points[idx + 1].y - points[idx].y) / 2) + points[idx].y);
  456. end = new PointF(X, Y);
  457. AddSpline(path, beg, implied, end, position);
  458. beg = end;
  459. }
  460. }
  461. }
  462. return path;
  463. }
  464. private void AddSpline(FastGraphicsPath path, PointF pntStart, PointF pntB, PointF pntEnd, PointF position)
  465. {
  466. // Start and end points are unmodified.
  467. PointF pnt1 = pntStart; // Ïåðâàÿ êîíòðîëüíàÿ òî÷êà Áåçüå
  468. pnt1.X += (2.0f / 3.0f) * (pntB.X - pntStart.X);
  469. pnt1.Y += (2.0f / 3.0f) * (pntB.Y - pntStart.Y);
  470. PointF pnt2 = pntB; // Âòîðàÿ êîíòðîëüíàÿ òî÷êà Áåçüå
  471. pnt2.X += (pntEnd.X - pntB.X) / 3.0f;
  472. pnt2.Y += (pntEnd.Y - pntB.Y) / 3.0f;
  473. path.AddBezier(pntStart, pnt1, pnt2, pntEnd);
  474. }
  475. public GlyphTableClass(TrueTypeTable src) : base(src)
  476. {
  477. }
  478. //internal GlyphTableClass(GlyphTableClass parent, IntPtr glyphs) : base(parent)
  479. //{
  480. // glyph_table_ptr = glyphs;
  481. //}
  482. public long GlypsPtr { get { return glyph_table_ptr; } }
  483. }
  484. }
  485. #pragma warning restore