gosu 1.4.1 → 1.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/dependencies/SDL_sound/SDL_sound.c +21 -63
  3. data/dependencies/SDL_sound/SDL_sound.h +2 -2
  4. data/dependencies/SDL_sound/SDL_sound_aiff.c +26 -23
  5. data/dependencies/SDL_sound/SDL_sound_au.c +8 -8
  6. data/dependencies/SDL_sound/SDL_sound_coreaudio.c +4 -5
  7. data/dependencies/SDL_sound/SDL_sound_flac.c +28 -30
  8. data/dependencies/SDL_sound/SDL_sound_internal.h +4 -4
  9. data/dependencies/SDL_sound/SDL_sound_modplug.c +1 -1
  10. data/dependencies/SDL_sound/SDL_sound_mp3.c +19 -23
  11. data/dependencies/SDL_sound/SDL_sound_raw.c +5 -6
  12. data/dependencies/SDL_sound/SDL_sound_shn.c +4 -4
  13. data/dependencies/SDL_sound/SDL_sound_voc.c +15 -15
  14. data/dependencies/SDL_sound/SDL_sound_vorbis.c +14 -7
  15. data/dependencies/SDL_sound/SDL_sound_wav.c +17 -17
  16. data/dependencies/SDL_sound/dr_flac.h +10840 -4779
  17. data/dependencies/SDL_sound/dr_mp3.h +2793 -1004
  18. data/dependencies/SDL_sound/libmodplug/fastmix.c +5 -0
  19. data/dependencies/SDL_sound/libmodplug/load_669.c +1 -1
  20. data/dependencies/SDL_sound/libmodplug/load_amf.c +1 -0
  21. data/dependencies/SDL_sound/libmodplug/load_ams.c +38 -22
  22. data/dependencies/SDL_sound/libmodplug/load_it.c +18 -14
  23. data/dependencies/SDL_sound/libmodplug/load_mdl.c +18 -9
  24. data/dependencies/SDL_sound/libmodplug/load_med.c +7 -6
  25. data/dependencies/SDL_sound/libmodplug/load_mt2.c +36 -17
  26. data/dependencies/SDL_sound/libmodplug/load_okt.c +51 -24
  27. data/dependencies/SDL_sound/libmodplug/load_psm.c +4 -2
  28. data/dependencies/SDL_sound/libmodplug/load_s3m.c +4 -4
  29. data/dependencies/SDL_sound/libmodplug/load_ult.c +4 -3
  30. data/dependencies/SDL_sound/libmodplug/load_xm.c +5 -5
  31. data/dependencies/SDL_sound/libmodplug/snd_fx.c +8 -1
  32. data/dependencies/SDL_sound/libmodplug/sndfile.c +21 -4
  33. data/dependencies/SDL_sound/stb_vorbis.h +10 -18
  34. data/dependencies/mojoAL/mojoal.c +260 -6
  35. data/dependencies/stb/stb_image.h +208 -73
  36. data/dependencies/stb/stb_image_write.h +57 -23
  37. data/dependencies/stb/stb_truetype.h +345 -279
  38. data/dependencies/utf8proc/utf8proc.c +37 -18
  39. data/dependencies/utf8proc/utf8proc.h +17 -5
  40. data/dependencies/utf8proc/utf8proc_data.h +12012 -10089
  41. data/ext/gosu/extconf.rb +6 -3
  42. data/include/Gosu/Buttons.hpp +103 -103
  43. data/include/Gosu/Directories.hpp +31 -24
  44. data/include/Gosu/Font.hpp +4 -2
  45. data/include/Gosu/Gosu.hpp +5 -8
  46. data/include/Gosu/IO.hpp +0 -3
  47. data/include/Gosu/Input.hpp +7 -1
  48. data/include/Gosu/Math.hpp +0 -3
  49. data/include/Gosu/TextInput.hpp +3 -3
  50. data/include/Gosu/Timing.hpp +3 -6
  51. data/include/Gosu/Version.hpp +1 -1
  52. data/include/Gosu/Window.hpp +3 -2
  53. data/rdoc/gosu.rb +16 -2
  54. data/src/Audio.cpp +2 -2
  55. data/src/AudioFileAudioToolbox.cpp +1 -1
  56. data/src/AudioFileSDLSound.cpp +1 -1
  57. data/src/AudioImpl.cpp +0 -7
  58. data/src/AudioImpl.hpp +1 -3
  59. data/src/BitmapIO.cpp +23 -2
  60. data/src/BlockAllocator.cpp +1 -1
  61. data/src/DirectoriesApple.cpp +25 -24
  62. data/src/DirectoriesUnix.cpp +14 -12
  63. data/src/DirectoriesWin.cpp +26 -30
  64. data/src/FileUnix.cpp +1 -1
  65. data/src/FileWin.cpp +1 -1
  66. data/src/Font.cpp +13 -3
  67. data/src/Graphics.cpp +1 -1
  68. data/src/Image.cpp +10 -15
  69. data/src/Input.cpp +16 -1
  70. data/src/InputUIKit.cpp +1 -1
  71. data/src/Macro.cpp +1 -1
  72. data/src/RubyGosu.cxx +76 -34
  73. data/src/TextInput.cpp +1 -1
  74. data/src/TimingApple.cpp +2 -2
  75. data/src/TimingUnix.cpp +3 -7
  76. data/src/TimingWin.cpp +1 -2
  77. data/src/TrueTypeFont.cpp +1 -1
  78. data/src/Window.cpp +5 -4
  79. data/src/WindowUIKit.cpp +1 -1
  80. metadata +3 -3
@@ -1,5 +1,5 @@
1
- // stb_truetype.h - v1.24 - public domain
2
- // authored from 2009-2020 by Sean Barrett / RAD Game Tools
1
+ // stb_truetype.h - v1.26 - public domain
2
+ // authored from 2009-2021 by Sean Barrett / RAD Game Tools
3
3
  //
4
4
  // =======================================================================
5
5
  //
@@ -58,6 +58,8 @@
58
58
  //
59
59
  // VERSION HISTORY
60
60
  //
61
+ // 1.26 (2021-08-28) fix broken rasterizer
62
+ // 1.25 (2021-07-11) many fixes
61
63
  // 1.24 (2020-02-05) fix warning
62
64
  // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
63
65
  // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
@@ -270,8 +272,8 @@
270
272
  //// SAMPLE PROGRAMS
271
273
  ////
272
274
  //
273
- // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless
274
- //
275
+ // Incomplete text-in-3d-api example, which draws quads properly aligned to be lossless.
276
+ // See "tests/truetype_demo_win32.c" for a complete version.
275
277
  #if 0
276
278
  #define STB_TRUETYPE_IMPLEMENTATION // force following include to generate implementation
277
279
  #include "stb_truetype.h"
@@ -297,6 +299,8 @@ void my_stbtt_initfont(void)
297
299
  void my_stbtt_print(float x, float y, char *text)
298
300
  {
299
301
  // assume orthographic projection with units = screen pixels, origin at top left
302
+ glEnable(GL_BLEND);
303
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
300
304
  glEnable(GL_TEXTURE_2D);
301
305
  glBindTexture(GL_TEXTURE_2D, ftex);
302
306
  glBegin(GL_QUADS);
@@ -304,10 +308,10 @@ void my_stbtt_print(float x, float y, char *text)
304
308
  if (*text >= 32 && *text < 128) {
305
309
  stbtt_aligned_quad q;
306
310
  stbtt_GetBakedQuad(cdata, 512,512, *text-32, &x,&y,&q,1);//1=opengl & d3d10+,0=d3d9
307
- glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y0);
308
- glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y0);
309
- glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y1);
310
- glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y1);
311
+ glTexCoord2f(q.s0,q.t0); glVertex2f(q.x0,q.y0);
312
+ glTexCoord2f(q.s1,q.t0); glVertex2f(q.x1,q.y0);
313
+ glTexCoord2f(q.s1,q.t1); glVertex2f(q.x1,q.y1);
314
+ glTexCoord2f(q.s0,q.t1); glVertex2f(q.x0,q.y1);
311
315
  }
312
316
  ++text;
313
317
  }
@@ -853,6 +857,7 @@ STBTT_DEF int stbtt_GetGlyphShape(const stbtt_fontinfo *info, int glyph_index, s
853
857
  STBTT_DEF void stbtt_FreeShape(const stbtt_fontinfo *info, stbtt_vertex *vertices);
854
858
  // frees the data allocated above
855
859
 
860
+ STBTT_DEF unsigned char *stbtt_FindSVGDoc(const stbtt_fontinfo *info, int gl);
856
861
  STBTT_DEF int stbtt_GetCodepointSVG(const stbtt_fontinfo *info, int unicode_codepoint, const char **svg);
857
862
  STBTT_DEF int stbtt_GetGlyphSVG(const stbtt_fontinfo *info, int gl, const char **svg);
858
863
  // fills svg with the character's SVG data.
@@ -1539,12 +1544,12 @@ STBTT_DEF int stbtt_FindGlyphIndex(const stbtt_fontinfo *info, int unicode_codep
1539
1544
  search += 2;
1540
1545
 
1541
1546
  {
1542
- stbtt_uint16 offset, start;
1547
+ stbtt_uint16 offset, start, last;
1543
1548
  stbtt_uint16 item = (stbtt_uint16) ((search - endCount) >> 1);
1544
1549
 
1545
- STBTT_assert(unicode_codepoint <= ttUSHORT(data + endCount + 2*item));
1546
1550
  start = ttUSHORT(data + index_map + 14 + segcount*2 + 2 + 2*item);
1547
- if (unicode_codepoint < start)
1551
+ last = ttUSHORT(data + endCount + 2*item);
1552
+ if (unicode_codepoint < start || unicode_codepoint > last)
1548
1553
  return 0;
1549
1554
 
1550
1555
  offset = ttUSHORT(data + index_map + 14 + segcount*6 + 2 + 2*item);
@@ -1871,7 +1876,7 @@ static int stbtt__GetGlyphShapeTT(const stbtt_fontinfo *info, int glyph_index, s
1871
1876
  if (comp_verts) STBTT_free(comp_verts, info->userdata);
1872
1877
  return 0;
1873
1878
  }
1874
- if (num_vertices > 0) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
1879
+ if (num_vertices > 0 && vertices) STBTT_memcpy(tmp, vertices, num_vertices*sizeof(stbtt_vertex));
1875
1880
  STBTT_memcpy(tmp+num_vertices, comp_verts, comp_num_verts*sizeof(stbtt_vertex));
1876
1881
  if (vertices) STBTT_free(vertices, info->userdata);
1877
1882
  vertices = tmp;
@@ -2134,7 +2139,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
2134
2139
  subrs = stbtt__cid_get_glyph_subrs(info, glyph_index);
2135
2140
  has_subrs = 1;
2136
2141
  }
2137
- // fallthrough
2142
+ // FALLTHROUGH
2138
2143
  case 0x1D: // callgsubr
2139
2144
  if (sp < 1) return STBTT__CSERR("call(g|)subr stack");
2140
2145
  v = (int) s[--sp];
@@ -2239,7 +2244,7 @@ static int stbtt__run_charstring(const stbtt_fontinfo *info, int glyph_index, st
2239
2244
  } break;
2240
2245
 
2241
2246
  default:
2242
- if (b0 != 255 && b0 != 28 && (b0 < 32 || b0 > 254))
2247
+ if (b0 != 255 && b0 != 28 && b0 < 32)
2243
2248
  return STBTT__CSERR("reserved operator");
2244
2249
 
2245
2250
  // push immediate
@@ -2351,7 +2356,7 @@ STBTT_DEF int stbtt_GetKerningTable(const stbtt_fontinfo *info, stbtt_kerningent
2351
2356
  return length;
2352
2357
  }
2353
2358
 
2354
- static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2359
+ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2355
2360
  {
2356
2361
  stbtt_uint8 *data = info->data + info->kern;
2357
2362
  stbtt_uint32 needle, straw;
@@ -2381,243 +2386,225 @@ static int stbtt__GetGlyphKernInfoAdvance(const stbtt_fontinfo *info, int glyph
2381
2386
  return 0;
2382
2387
  }
2383
2388
 
2384
- static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2385
- {
2386
- stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2387
- switch(coverageFormat) {
2388
- case 1: {
2389
- stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2390
-
2391
- // Binary search.
2392
- stbtt_int32 l=0, r=glyphCount-1, m;
2393
- int straw, needle=glyph;
2394
- while (l <= r) {
2395
- stbtt_uint8 *glyphArray = coverageTable + 4;
2396
- stbtt_uint16 glyphID;
2397
- m = (l + r) >> 1;
2398
- glyphID = ttUSHORT(glyphArray + 2 * m);
2399
- straw = glyphID;
2400
- if (needle < straw)
2401
- r = m - 1;
2402
- else if (needle > straw)
2403
- l = m + 1;
2404
- else {
2405
- return m;
2406
- }
2389
+ static stbtt_int32 stbtt__GetCoverageIndex(stbtt_uint8 *coverageTable, int glyph)
2390
+ {
2391
+ stbtt_uint16 coverageFormat = ttUSHORT(coverageTable);
2392
+ switch (coverageFormat) {
2393
+ case 1: {
2394
+ stbtt_uint16 glyphCount = ttUSHORT(coverageTable + 2);
2395
+
2396
+ // Binary search.
2397
+ stbtt_int32 l=0, r=glyphCount-1, m;
2398
+ int straw, needle=glyph;
2399
+ while (l <= r) {
2400
+ stbtt_uint8 *glyphArray = coverageTable + 4;
2401
+ stbtt_uint16 glyphID;
2402
+ m = (l + r) >> 1;
2403
+ glyphID = ttUSHORT(glyphArray + 2 * m);
2404
+ straw = glyphID;
2405
+ if (needle < straw)
2406
+ r = m - 1;
2407
+ else if (needle > straw)
2408
+ l = m + 1;
2409
+ else {
2410
+ return m;
2407
2411
  }
2408
- } break;
2409
-
2410
- case 2: {
2411
- stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2412
- stbtt_uint8 *rangeArray = coverageTable + 4;
2413
-
2414
- // Binary search.
2415
- stbtt_int32 l=0, r=rangeCount-1, m;
2416
- int strawStart, strawEnd, needle=glyph;
2417
- while (l <= r) {
2418
- stbtt_uint8 *rangeRecord;
2419
- m = (l + r) >> 1;
2420
- rangeRecord = rangeArray + 6 * m;
2421
- strawStart = ttUSHORT(rangeRecord);
2422
- strawEnd = ttUSHORT(rangeRecord + 2);
2423
- if (needle < strawStart)
2424
- r = m - 1;
2425
- else if (needle > strawEnd)
2426
- l = m + 1;
2427
- else {
2428
- stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2429
- return startCoverageIndex + glyph - strawStart;
2430
- }
2412
+ }
2413
+ break;
2414
+ }
2415
+
2416
+ case 2: {
2417
+ stbtt_uint16 rangeCount = ttUSHORT(coverageTable + 2);
2418
+ stbtt_uint8 *rangeArray = coverageTable + 4;
2419
+
2420
+ // Binary search.
2421
+ stbtt_int32 l=0, r=rangeCount-1, m;
2422
+ int strawStart, strawEnd, needle=glyph;
2423
+ while (l <= r) {
2424
+ stbtt_uint8 *rangeRecord;
2425
+ m = (l + r) >> 1;
2426
+ rangeRecord = rangeArray + 6 * m;
2427
+ strawStart = ttUSHORT(rangeRecord);
2428
+ strawEnd = ttUSHORT(rangeRecord + 2);
2429
+ if (needle < strawStart)
2430
+ r = m - 1;
2431
+ else if (needle > strawEnd)
2432
+ l = m + 1;
2433
+ else {
2434
+ stbtt_uint16 startCoverageIndex = ttUSHORT(rangeRecord + 4);
2435
+ return startCoverageIndex + glyph - strawStart;
2431
2436
  }
2432
- } break;
2437
+ }
2438
+ break;
2439
+ }
2433
2440
 
2434
- default: {
2435
- // There are no other cases.
2436
- STBTT_assert(0);
2437
- } break;
2438
- }
2441
+ default: return -1; // unsupported
2442
+ }
2439
2443
 
2440
- return -1;
2444
+ return -1;
2441
2445
  }
2442
2446
 
2443
2447
  static stbtt_int32 stbtt__GetGlyphClass(stbtt_uint8 *classDefTable, int glyph)
2444
2448
  {
2445
- stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2446
- switch(classDefFormat)
2447
- {
2448
- case 1: {
2449
- stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2450
- stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2451
- stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2452
-
2453
- if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2454
- return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2455
-
2456
- classDefTable = classDef1ValueArray + 2 * glyphCount;
2457
- } break;
2458
-
2459
- case 2: {
2460
- stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2461
- stbtt_uint8 *classRangeRecords = classDefTable + 4;
2462
-
2463
- // Binary search.
2464
- stbtt_int32 l=0, r=classRangeCount-1, m;
2465
- int strawStart, strawEnd, needle=glyph;
2466
- while (l <= r) {
2467
- stbtt_uint8 *classRangeRecord;
2468
- m = (l + r) >> 1;
2469
- classRangeRecord = classRangeRecords + 6 * m;
2470
- strawStart = ttUSHORT(classRangeRecord);
2471
- strawEnd = ttUSHORT(classRangeRecord + 2);
2472
- if (needle < strawStart)
2473
- r = m - 1;
2474
- else if (needle > strawEnd)
2475
- l = m + 1;
2476
- else
2477
- return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
2478
- }
2449
+ stbtt_uint16 classDefFormat = ttUSHORT(classDefTable);
2450
+ switch (classDefFormat)
2451
+ {
2452
+ case 1: {
2453
+ stbtt_uint16 startGlyphID = ttUSHORT(classDefTable + 2);
2454
+ stbtt_uint16 glyphCount = ttUSHORT(classDefTable + 4);
2455
+ stbtt_uint8 *classDef1ValueArray = classDefTable + 6;
2479
2456
 
2480
- classDefTable = classRangeRecords + 6 * classRangeCount;
2481
- } break;
2457
+ if (glyph >= startGlyphID && glyph < startGlyphID + glyphCount)
2458
+ return (stbtt_int32)ttUSHORT(classDef1ValueArray + 2 * (glyph - startGlyphID));
2459
+ break;
2460
+ }
2482
2461
 
2483
- default: {
2484
- // There are no other cases.
2485
- STBTT_assert(0);
2486
- } break;
2487
- }
2462
+ case 2: {
2463
+ stbtt_uint16 classRangeCount = ttUSHORT(classDefTable + 2);
2464
+ stbtt_uint8 *classRangeRecords = classDefTable + 4;
2465
+
2466
+ // Binary search.
2467
+ stbtt_int32 l=0, r=classRangeCount-1, m;
2468
+ int strawStart, strawEnd, needle=glyph;
2469
+ while (l <= r) {
2470
+ stbtt_uint8 *classRangeRecord;
2471
+ m = (l + r) >> 1;
2472
+ classRangeRecord = classRangeRecords + 6 * m;
2473
+ strawStart = ttUSHORT(classRangeRecord);
2474
+ strawEnd = ttUSHORT(classRangeRecord + 2);
2475
+ if (needle < strawStart)
2476
+ r = m - 1;
2477
+ else if (needle > strawEnd)
2478
+ l = m + 1;
2479
+ else
2480
+ return (stbtt_int32)ttUSHORT(classRangeRecord + 4);
2481
+ }
2482
+ break;
2483
+ }
2488
2484
 
2489
- return -1;
2485
+ default:
2486
+ return -1; // Unsupported definition type, return an error.
2487
+ }
2488
+
2489
+ // "All glyphs not assigned to a class fall into class 0". (OpenType spec)
2490
+ return 0;
2490
2491
  }
2491
2492
 
2492
2493
  // Define to STBTT_assert(x) if you want to break on unimplemented formats.
2493
2494
  #define STBTT_GPOS_TODO_assert(x)
2494
2495
 
2495
- static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2496
- {
2497
- stbtt_uint16 lookupListOffset;
2498
- stbtt_uint8 *lookupList;
2499
- stbtt_uint16 lookupCount;
2500
- stbtt_uint8 *data;
2501
- stbtt_int32 i;
2502
-
2503
- if (!info->gpos) return 0;
2504
-
2505
- data = info->data + info->gpos;
2506
-
2507
- if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2508
- if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2509
-
2510
- lookupListOffset = ttUSHORT(data+8);
2511
- lookupList = data + lookupListOffset;
2512
- lookupCount = ttUSHORT(lookupList);
2513
-
2514
- for (i=0; i<lookupCount; ++i) {
2515
- stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2516
- stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2517
-
2518
- stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2519
- stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2520
- stbtt_uint8 *subTableOffsets = lookupTable + 6;
2521
- switch(lookupType) {
2522
- case 2: { // Pair Adjustment Positioning Subtable
2523
- stbtt_int32 sti;
2524
- for (sti=0; sti<subTableCount; sti++) {
2525
- stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2526
- stbtt_uint8 *table = lookupTable + subtableOffset;
2527
- stbtt_uint16 posFormat = ttUSHORT(table);
2528
- stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2529
- stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2530
- if (coverageIndex == -1) continue;
2531
-
2532
- switch (posFormat) {
2533
- case 1: {
2534
- stbtt_int32 l, r, m;
2535
- int straw, needle;
2536
- stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2537
- stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2538
- stbtt_int32 valueRecordPairSizeInBytes = 2;
2539
- stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2540
- stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2541
- stbtt_uint8 *pairValueTable = table + pairPosOffset;
2542
- stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2543
- stbtt_uint8 *pairValueArray = pairValueTable + 2;
2544
- // TODO: Support more formats.
2545
- STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2546
- if (valueFormat1 != 4) return 0;
2547
- STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2548
- if (valueFormat2 != 0) return 0;
2549
-
2550
- STBTT_assert(coverageIndex < pairSetCount);
2551
- STBTT__NOTUSED(pairSetCount);
2552
-
2553
- needle=glyph2;
2554
- r=pairValueCount-1;
2555
- l=0;
2556
-
2557
- // Binary search.
2558
- while (l <= r) {
2559
- stbtt_uint16 secondGlyph;
2560
- stbtt_uint8 *pairValue;
2561
- m = (l + r) >> 1;
2562
- pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2563
- secondGlyph = ttUSHORT(pairValue);
2564
- straw = secondGlyph;
2565
- if (needle < straw)
2566
- r = m - 1;
2567
- else if (needle > straw)
2568
- l = m + 1;
2569
- else {
2570
- stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2571
- return xAdvance;
2572
- }
2573
- }
2574
- } break;
2575
-
2576
- case 2: {
2577
- stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2578
- stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2579
-
2580
- stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2581
- stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2582
- int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2583
- int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2584
-
2585
- stbtt_uint16 class1Count = ttUSHORT(table + 12);
2586
- stbtt_uint16 class2Count = ttUSHORT(table + 14);
2587
- STBTT_assert(glyph1class < class1Count);
2588
- STBTT_assert(glyph2class < class2Count);
2589
-
2590
- // TODO: Support more formats.
2591
- STBTT_GPOS_TODO_assert(valueFormat1 == 4);
2592
- if (valueFormat1 != 4) return 0;
2593
- STBTT_GPOS_TODO_assert(valueFormat2 == 0);
2594
- if (valueFormat2 != 0) return 0;
2595
-
2596
- if (glyph1class >= 0 && glyph1class < class1Count && glyph2class >= 0 && glyph2class < class2Count) {
2597
- stbtt_uint8 *class1Records = table + 16;
2598
- stbtt_uint8 *class2Records = class1Records + 2 * (glyph1class * class2Count);
2599
- stbtt_int16 xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2600
- return xAdvance;
2601
- }
2602
- } break;
2603
-
2604
- default: {
2605
- // There are no other cases.
2606
- STBTT_assert(0);
2607
- break;
2608
- };
2609
- }
2610
- }
2611
- break;
2612
- };
2496
+ static stbtt_int32 stbtt__GetGlyphGPOSInfoAdvance(const stbtt_fontinfo *info, int glyph1, int glyph2)
2497
+ {
2498
+ stbtt_uint16 lookupListOffset;
2499
+ stbtt_uint8 *lookupList;
2500
+ stbtt_uint16 lookupCount;
2501
+ stbtt_uint8 *data;
2502
+ stbtt_int32 i, sti;
2503
+
2504
+ if (!info->gpos) return 0;
2505
+
2506
+ data = info->data + info->gpos;
2507
+
2508
+ if (ttUSHORT(data+0) != 1) return 0; // Major version 1
2509
+ if (ttUSHORT(data+2) != 0) return 0; // Minor version 0
2510
+
2511
+ lookupListOffset = ttUSHORT(data+8);
2512
+ lookupList = data + lookupListOffset;
2513
+ lookupCount = ttUSHORT(lookupList);
2514
+
2515
+ for (i=0; i<lookupCount; ++i) {
2516
+ stbtt_uint16 lookupOffset = ttUSHORT(lookupList + 2 + 2 * i);
2517
+ stbtt_uint8 *lookupTable = lookupList + lookupOffset;
2518
+
2519
+ stbtt_uint16 lookupType = ttUSHORT(lookupTable);
2520
+ stbtt_uint16 subTableCount = ttUSHORT(lookupTable + 4);
2521
+ stbtt_uint8 *subTableOffsets = lookupTable + 6;
2522
+ if (lookupType != 2) // Pair Adjustment Positioning Subtable
2523
+ continue;
2524
+
2525
+ for (sti=0; sti<subTableCount; sti++) {
2526
+ stbtt_uint16 subtableOffset = ttUSHORT(subTableOffsets + 2 * sti);
2527
+ stbtt_uint8 *table = lookupTable + subtableOffset;
2528
+ stbtt_uint16 posFormat = ttUSHORT(table);
2529
+ stbtt_uint16 coverageOffset = ttUSHORT(table + 2);
2530
+ stbtt_int32 coverageIndex = stbtt__GetCoverageIndex(table + coverageOffset, glyph1);
2531
+ if (coverageIndex == -1) continue;
2532
+
2533
+ switch (posFormat) {
2534
+ case 1: {
2535
+ stbtt_int32 l, r, m;
2536
+ int straw, needle;
2537
+ stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2538
+ stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2539
+ if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2540
+ stbtt_int32 valueRecordPairSizeInBytes = 2;
2541
+ stbtt_uint16 pairSetCount = ttUSHORT(table + 8);
2542
+ stbtt_uint16 pairPosOffset = ttUSHORT(table + 10 + 2 * coverageIndex);
2543
+ stbtt_uint8 *pairValueTable = table + pairPosOffset;
2544
+ stbtt_uint16 pairValueCount = ttUSHORT(pairValueTable);
2545
+ stbtt_uint8 *pairValueArray = pairValueTable + 2;
2546
+
2547
+ if (coverageIndex >= pairSetCount) return 0;
2548
+
2549
+ needle=glyph2;
2550
+ r=pairValueCount-1;
2551
+ l=0;
2552
+
2553
+ // Binary search.
2554
+ while (l <= r) {
2555
+ stbtt_uint16 secondGlyph;
2556
+ stbtt_uint8 *pairValue;
2557
+ m = (l + r) >> 1;
2558
+ pairValue = pairValueArray + (2 + valueRecordPairSizeInBytes) * m;
2559
+ secondGlyph = ttUSHORT(pairValue);
2560
+ straw = secondGlyph;
2561
+ if (needle < straw)
2562
+ r = m - 1;
2563
+ else if (needle > straw)
2564
+ l = m + 1;
2565
+ else {
2566
+ stbtt_int16 xAdvance = ttSHORT(pairValue + 2);
2567
+ return xAdvance;
2568
+ }
2569
+ }
2570
+ } else
2571
+ return 0;
2572
+ break;
2573
+ }
2574
+
2575
+ case 2: {
2576
+ stbtt_uint16 valueFormat1 = ttUSHORT(table + 4);
2577
+ stbtt_uint16 valueFormat2 = ttUSHORT(table + 6);
2578
+ if (valueFormat1 == 4 && valueFormat2 == 0) { // Support more formats?
2579
+ stbtt_uint16 classDef1Offset = ttUSHORT(table + 8);
2580
+ stbtt_uint16 classDef2Offset = ttUSHORT(table + 10);
2581
+ int glyph1class = stbtt__GetGlyphClass(table + classDef1Offset, glyph1);
2582
+ int glyph2class = stbtt__GetGlyphClass(table + classDef2Offset, glyph2);
2583
+
2584
+ stbtt_uint16 class1Count = ttUSHORT(table + 12);
2585
+ stbtt_uint16 class2Count = ttUSHORT(table + 14);
2586
+ stbtt_uint8 *class1Records, *class2Records;
2587
+ stbtt_int16 xAdvance;
2588
+
2589
+ if (glyph1class < 0 || glyph1class >= class1Count) return 0; // malformed
2590
+ if (glyph2class < 0 || glyph2class >= class2Count) return 0; // malformed
2591
+
2592
+ class1Records = table + 16;
2593
+ class2Records = class1Records + 2 * (glyph1class * class2Count);
2594
+ xAdvance = ttSHORT(class2Records + 2 * glyph2class);
2595
+ return xAdvance;
2596
+ } else
2597
+ return 0;
2598
+ break;
2599
+ }
2613
2600
 
2614
2601
  default:
2615
- // TODO: Implement other stuff.
2616
- break;
2617
- }
2618
- }
2602
+ return 0; // Unsupported position format
2603
+ }
2604
+ }
2605
+ }
2619
2606
 
2620
- return 0;
2607
+ return 0;
2621
2608
  }
2622
2609
 
2623
2610
  STBTT_DEF int stbtt_GetGlyphKernAdvance(const stbtt_fontinfo *info, int g1, int g2)
@@ -3075,6 +3062,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg
3075
3062
  }
3076
3063
  }
3077
3064
 
3065
+ static float stbtt__sized_trapezoid_area(float height, float top_width, float bottom_width)
3066
+ {
3067
+ STBTT_assert(top_width >= 0);
3068
+ STBTT_assert(bottom_width >= 0);
3069
+ return (top_width + bottom_width) / 2.0f * height;
3070
+ }
3071
+
3072
+ static float stbtt__position_trapezoid_area(float height, float tx0, float tx1, float bx0, float bx1)
3073
+ {
3074
+ return stbtt__sized_trapezoid_area(height, tx1 - tx0, bx1 - bx0);
3075
+ }
3076
+
3077
+ static float stbtt__sized_triangle_area(float height, float width)
3078
+ {
3079
+ return height * width / 2;
3080
+ }
3081
+
3078
3082
  static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill, int len, stbtt__active_edge *e, float y_top)
3079
3083
  {
3080
3084
  float y_bottom = y_top+1;
@@ -3129,13 +3133,13 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
3129
3133
  float height;
3130
3134
  // simple case, only spans one pixel
3131
3135
  int x = (int) x_top;
3132
- height = sy1 - sy0;
3136
+ height = (sy1 - sy0) * e->direction;
3133
3137
  STBTT_assert(x >= 0 && x < len);
3134
- scanline[x] += e->direction * (1-((x_top - x) + (x_bottom-x))/2) * height;
3135
- scanline_fill[x] += e->direction * height; // everything right of this pixel is filled
3138
+ scanline[x] += stbtt__position_trapezoid_area(height, x_top, x+1.0f, x_bottom, x+1.0f);
3139
+ scanline_fill[x] += height; // everything right of this pixel is filled
3136
3140
  } else {
3137
3141
  int x,x1,x2;
3138
- float y_crossing, step, sign, area;
3142
+ float y_crossing, y_final, step, sign, area;
3139
3143
  // covers 2+ pixels
3140
3144
  if (x_top > x_bottom) {
3141
3145
  // flip scanline vertically; signed area is the same
@@ -3148,29 +3152,79 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
3148
3152
  dy = -dy;
3149
3153
  t = x0, x0 = xb, xb = t;
3150
3154
  }
3155
+ STBTT_assert(dy >= 0);
3156
+ STBTT_assert(dx >= 0);
3151
3157
 
3152
3158
  x1 = (int) x_top;
3153
3159
  x2 = (int) x_bottom;
3154
3160
  // compute intersection with y axis at x1+1
3155
- y_crossing = (x1+1 - x0) * dy + y_top;
3161
+ y_crossing = y_top + dy * (x1+1 - x0);
3162
+
3163
+ // compute intersection with y axis at x2
3164
+ y_final = y_top + dy * (x2 - x0);
3165
+
3166
+ // x1 x_top x2 x_bottom
3167
+ // y_top +------|-----+------------+------------+--------|---+------------+
3168
+ // | | | | | |
3169
+ // | | | | | |
3170
+ // sy0 | Txxxxx|............|............|............|............|
3171
+ // y_crossing | *xxxxx.......|............|............|............|
3172
+ // | | xxxxx..|............|............|............|
3173
+ // | | /- xx*xxxx........|............|............|
3174
+ // | | dy < | xxxxxx..|............|............|
3175
+ // y_final | | \- | xx*xxx.........|............|
3176
+ // sy1 | | | | xxxxxB...|............|
3177
+ // | | | | | |
3178
+ // | | | | | |
3179
+ // y_bottom +------------+------------+------------+------------+------------+
3180
+ //
3181
+ // goal is to measure the area covered by '.' in each pixel
3182
+
3183
+ // if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
3184
+ // @TODO: maybe test against sy1 rather than y_bottom?
3185
+ if (y_crossing > y_bottom)
3186
+ y_crossing = y_bottom;
3156
3187
 
3157
3188
  sign = e->direction;
3158
- // area of the rectangle covered from y0..y_crossing
3189
+
3190
+ // area of the rectangle covered from sy0..y_crossing
3159
3191
  area = sign * (y_crossing-sy0);
3160
- // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
3161
- scanline[x1] += area * (1-((x_top - x1)+(x1+1-x1))/2);
3162
3192
 
3163
- step = sign * dy;
3193
+ // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
3194
+ scanline[x1] += stbtt__sized_triangle_area(area, x1+1 - x_top);
3195
+
3196
+ // check if final y_crossing is blown up; no test case for this
3197
+ if (y_final > y_bottom) {
3198
+ y_final = y_bottom;
3199
+ dy = (y_final - y_crossing ) / (x2 - (x1+1)); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
3200
+ }
3201
+
3202
+ // in second pixel, area covered by line segment found in first pixel
3203
+ // is always a rectangle 1 wide * the height of that line segment; this
3204
+ // is exactly what the variable 'area' stores. it also gets a contribution
3205
+ // from the line segment within it. the THIRD pixel will get the first
3206
+ // pixel's rectangle contribution, the second pixel's rectangle contribution,
3207
+ // and its own contribution. the 'own contribution' is the same in every pixel except
3208
+ // the leftmost and rightmost, a trapezoid that slides down in each pixel.
3209
+ // the second pixel's contribution to the third pixel will be the
3210
+ // rectangle 1 wide times the height change in the second pixel, which is dy.
3211
+
3212
+ step = sign * dy * 1; // dy is dy/dx, change in y for every 1 change in x,
3213
+ // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
3214
+ // so the area advances by 'step' every time
3215
+
3164
3216
  for (x = x1+1; x < x2; ++x) {
3165
- scanline[x] += area + step/2;
3217
+ scanline[x] += area + step/2; // area of trapezoid is 1*step/2
3166
3218
  area += step;
3167
3219
  }
3168
- y_crossing += dy * (x2 - (x1+1));
3169
-
3170
- STBTT_assert(STBTT_fabs(area) <= 1.01f);
3220
+ STBTT_assert(STBTT_fabs(area) <= 1.01f); // accumulated error from area += step unless we round step down
3221
+ STBTT_assert(sy1 > y_final-0.01f);
3171
3222
 
3172
- scanline[x2] += area + sign * (1-((x2-x2)+(x_bottom-x2))/2) * (sy1-y_crossing);
3223
+ // area covered in the last pixel is the rectangle from all the pixels to the left,
3224
+ // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
3225
+ scanline[x2] += area + sign * stbtt__position_trapezoid_area(sy1-y_final, (float) x2, x2+1.0f, x_bottom, x2+1.0f);
3173
3226
 
3227
+ // the rest of the line is filled based on the total height of the line segment in this pixel
3174
3228
  scanline_fill[x2] += sign * (sy1-sy0);
3175
3229
  }
3176
3230
  } else {
@@ -3178,6 +3232,9 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
3178
3232
  // clipping logic. since this does not match the intended use
3179
3233
  // of this library, we use a different, very slow brute
3180
3234
  // force implementation
3235
+ // note though that this does happen some of the time because
3236
+ // x_top and x_bottom can be extrapolated at the top & bottom of
3237
+ // the shape and actually lie outside the bounding box
3181
3238
  int x;
3182
3239
  for (x=0; x < len; ++x) {
3183
3240
  // cases:
@@ -4414,15 +4471,14 @@ static int stbtt__compute_crossings_x(float x, float y, int nverts, stbtt_vertex
4414
4471
  float y_frac;
4415
4472
  int winding = 0;
4416
4473
 
4417
- orig[0] = x;
4418
- orig[1] = y;
4419
-
4420
4474
  // make sure y never passes through a vertex of the shape
4421
4475
  y_frac = (float) STBTT_fmod(y, 1.0f);
4422
4476
  if (y_frac < 0.01f)
4423
4477
  y += 0.01f;
4424
4478
  else if (y_frac > 0.99f)
4425
4479
  y -= 0.01f;
4480
+
4481
+ orig[0] = x;
4426
4482
  orig[1] = y;
4427
4483
 
4428
4484
  // test a ray from (-infinity,y) to (x,y)
@@ -4484,35 +4540,35 @@ static float stbtt__cuberoot( float x )
4484
4540
  return (float) STBTT_pow( x,1.0f/3.0f);
4485
4541
  }
4486
4542
 
4487
- // x^3 + c*x^2 + b*x + a = 0
4543
+ // x^3 + a*x^2 + b*x + c = 0
4488
4544
  static int stbtt__solve_cubic(float a, float b, float c, float* r)
4489
4545
  {
4490
- float s = -a / 3;
4491
- float p = b - a*a / 3;
4492
- float q = a * (2*a*a - 9*b) / 27 + c;
4546
+ float s = -a / 3;
4547
+ float p = b - a*a / 3;
4548
+ float q = a * (2*a*a - 9*b) / 27 + c;
4493
4549
  float p3 = p*p*p;
4494
- float d = q*q + 4*p3 / 27;
4495
- if (d >= 0) {
4496
- float z = (float) STBTT_sqrt(d);
4497
- float u = (-q + z) / 2;
4498
- float v = (-q - z) / 2;
4499
- u = stbtt__cuberoot(u);
4500
- v = stbtt__cuberoot(v);
4501
- r[0] = s + u + v;
4502
- return 1;
4503
- } else {
4504
- float u = (float) STBTT_sqrt(-p/3);
4505
- float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4506
- float m = (float) STBTT_cos(v);
4550
+ float d = q*q + 4*p3 / 27;
4551
+ if (d >= 0) {
4552
+ float z = (float) STBTT_sqrt(d);
4553
+ float u = (-q + z) / 2;
4554
+ float v = (-q - z) / 2;
4555
+ u = stbtt__cuberoot(u);
4556
+ v = stbtt__cuberoot(v);
4557
+ r[0] = s + u + v;
4558
+ return 1;
4559
+ } else {
4560
+ float u = (float) STBTT_sqrt(-p/3);
4561
+ float v = (float) STBTT_acos(-STBTT_sqrt(-27/p3) * q / 2) / 3; // p3 must be negative, since d is negative
4562
+ float m = (float) STBTT_cos(v);
4507
4563
  float n = (float) STBTT_cos(v-3.141592/2)*1.732050808f;
4508
- r[0] = s + u * 2 * m;
4509
- r[1] = s - u * (m + n);
4510
- r[2] = s - u * (m - n);
4564
+ r[0] = s + u * 2 * m;
4565
+ r[1] = s - u * (m + n);
4566
+ r[2] = s - u * (m - n);
4511
4567
 
4512
4568
  //STBTT_assert( STBTT_fabs(((r[0]+a)*r[0]+b)*r[0]+c) < 0.05f); // these asserts may not be safe at all scales, though they're in bezier t parameter units so maybe?
4513
4569
  //STBTT_assert( STBTT_fabs(((r[1]+a)*r[1]+b)*r[1]+c) < 0.05f);
4514
4570
  //STBTT_assert( STBTT_fabs(((r[2]+a)*r[2]+b)*r[2]+c) < 0.05f);
4515
- return 3;
4571
+ return 3;
4516
4572
  }
4517
4573
  }
4518
4574
 
@@ -4589,18 +4645,17 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
4589
4645
  for (i=0; i < num_verts; ++i) {
4590
4646
  float x0 = verts[i].x*scale_x, y0 = verts[i].y*scale_y;
4591
4647
 
4592
- // check against every point here rather than inside line/curve primitives -- @TODO: wrong if multiple 'moves' in a row produce a garbage point, and given culling, probably more efficient to do within line/curve
4593
- float dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4594
- if (dist2 < min_dist*min_dist)
4595
- min_dist = (float) STBTT_sqrt(dist2);
4596
-
4597
- if (verts[i].type == STBTT_vline) {
4648
+ if (verts[i].type == STBTT_vline && precompute[i] != 0.0f) {
4598
4649
  float x1 = verts[i-1].x*scale_x, y1 = verts[i-1].y*scale_y;
4599
4650
 
4651
+ float dist,dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4652
+ if (dist2 < min_dist*min_dist)
4653
+ min_dist = (float) STBTT_sqrt(dist2);
4654
+
4600
4655
  // coarse culling against bbox
4601
4656
  //if (sx > STBTT_min(x0,x1)-min_dist && sx < STBTT_max(x0,x1)+min_dist &&
4602
4657
  // sy > STBTT_min(y0,y1)-min_dist && sy < STBTT_max(y0,y1)+min_dist)
4603
- float dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4658
+ dist = (float) STBTT_fabs((x1-x0)*(y0-sy) - (y1-y0)*(x0-sx)) * precompute[i];
4604
4659
  STBTT_assert(i != 0);
4605
4660
  if (dist < min_dist) {
4606
4661
  // check position along line
@@ -4627,7 +4682,8 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
4627
4682
  float ax = x1-x0, ay = y1-y0;
4628
4683
  float bx = x0 - 2*x1 + x2, by = y0 - 2*y1 + y2;
4629
4684
  float mx = x0 - sx, my = y0 - sy;
4630
- float res[3],px,py,t,it;
4685
+ float res[3] = {0.f,0.f,0.f};
4686
+ float px,py,t,it,dist2;
4631
4687
  float a_inv = precompute[i];
4632
4688
  if (a_inv == 0.0) { // if a_inv is 0, it's 2nd degree so use quadratic formula
4633
4689
  float a = 3*(ax*bx + ay*by);
@@ -4654,6 +4710,10 @@ STBTT_DEF unsigned char * stbtt_GetGlyphSDF(const stbtt_fontinfo *info, float sc
4654
4710
  float d = (mx*ax+my*ay) * a_inv;
4655
4711
  num = stbtt__solve_cubic(b, c, d, res);
4656
4712
  }
4713
+ dist2 = (x0-sx)*(x0-sx) + (y0-sy)*(y0-sy);
4714
+ if (dist2 < min_dist*min_dist)
4715
+ min_dist = (float) STBTT_sqrt(dist2);
4716
+
4657
4717
  if (num >= 1 && res[0] >= 0.0f && res[0] <= 1.0f) {
4658
4718
  t = res[0], it = 1.0f - t;
4659
4719
  px = it*it*x0 + 2*t*it*x1 + t*t*x2;
@@ -4913,6 +4973,12 @@ STBTT_DEF int stbtt_CompareUTF8toUTF16_bigendian(const char *s1, int len1, const
4913
4973
 
4914
4974
  // FULL VERSION HISTORY
4915
4975
  //
4976
+ // 1.25 (2021-07-11) many fixes
4977
+ // 1.24 (2020-02-05) fix warning
4978
+ // 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
4979
+ // 1.22 (2019-08-11) minimize missing-glyph duplication; fix kerning if both 'GPOS' and 'kern' are defined
4980
+ // 1.21 (2019-02-25) fix warning
4981
+ // 1.20 (2019-02-07) PackFontRange skips missing codepoints; GetScaleFontVMetrics()
4916
4982
  // 1.19 (2018-02-11) OpenType GPOS kerning (horizontal only), STBTT_fmod
4917
4983
  // 1.18 (2018-01-29) add missing function
4918
4984
  // 1.17 (2017-07-23) make more arguments const; doc fix