Browse Source

Update HarfBuzz to 7.1.0

Pedro J. Estébanez 2 years ago
parent
commit
abc13dbd0b
100 changed files with 7066 additions and 2097 deletions
  1. 13 9
      COPYRIGHT.txt
  2. 13 6
      modules/text_server_adv/SCsub
  3. 14 6
      modules/text_server_adv/gdextension_build/SConstruct
  4. 4 2
      thirdparty/README.md
  5. 12 8
      thirdparty/harfbuzz/COPYING
  6. 55 22
      thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh
  7. 607 45
      thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh
  8. 5 6
      thirdparty/harfbuzz/src/OT/Color/COLR/colrv1-closure.hh
  9. 7 7
      thirdparty/harfbuzz/src/OT/Color/CPAL/CPAL.hh
  10. 49 20
      thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh
  11. 29 4
      thirdparty/harfbuzz/src/OT/Color/svg/svg.hh
  12. 1 0
      thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh
  13. 918 0
      thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh
  14. 6 6
      thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh
  15. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh
  16. 2 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh
  17. 2 2
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh
  18. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh
  19. 54 29
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh
  20. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh
  21. 28 11
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh
  22. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh
  23. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh
  24. 2 4
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh
  25. 6 6
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh
  26. 21 17
      thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh
  27. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh
  28. 11 3
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh
  29. 3 3
      thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh
  30. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh
  31. 3 3
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh
  32. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh
  33. 4 4
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh
  34. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh
  35. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh
  36. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh
  37. 2 2
      thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh
  38. 6 6
      thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh
  39. 1 1
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh
  40. 12 4
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh
  41. 3 3
      thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh
  42. 116 42
      thirdparty/harfbuzz/src/OT/glyf/Glyph.hh
  43. 6 4
      thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh
  44. 5 5
      thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh
  45. 2 10
      thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh
  46. 16 15
      thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh
  47. 16 2
      thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh
  48. 70 44
      thirdparty/harfbuzz/src/OT/glyf/glyf.hh
  49. 77 19
      thirdparty/harfbuzz/src/OT/glyf/path-builder.hh
  50. 589 0
      thirdparty/harfbuzz/src/OT/name/name.hh
  51. 12 5
      thirdparty/harfbuzz/src/graph/graph.hh
  52. 3 3
      thirdparty/harfbuzz/src/graph/serialize.hh
  53. 0 119
      thirdparty/harfbuzz/src/graph/test-classdef-graph.cc
  54. 68 37
      thirdparty/harfbuzz/src/hb-aat-layout-common.hh
  55. 6 4
      thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
  56. 43 14
      thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
  57. 11 3
      thirdparty/harfbuzz/src/hb-aat-layout.cc
  58. 3 1
      thirdparty/harfbuzz/src/hb-aat-layout.hh
  59. 100 30
      thirdparty/harfbuzz/src/hb-aat-map.cc
  60. 35 10
      thirdparty/harfbuzz/src/hb-aat-map.hh
  61. 80 8
      thirdparty/harfbuzz/src/hb-algs.hh
  62. 3 0
      thirdparty/harfbuzz/src/hb-array.hh
  63. 33 8
      thirdparty/harfbuzz/src/hb-atomic.hh
  64. 18 8
      thirdparty/harfbuzz/src/hb-bit-page.hh
  65. 5 0
      thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
  66. 11 7
      thirdparty/harfbuzz/src/hb-bit-set.hh
  67. 3 3
      thirdparty/harfbuzz/src/hb-blob.cc
  68. 1 1
      thirdparty/harfbuzz/src/hb-blob.h
  69. 185 187
      thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
  70. 692 0
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh
  71. 332 0
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh
  72. 0 917
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
  73. 12 9
      thirdparty/harfbuzz/src/hb-buffer-serialize.cc
  74. 2 2
      thirdparty/harfbuzz/src/hb-buffer-verify.cc
  75. 33 5
      thirdparty/harfbuzz/src/hb-buffer.cc
  76. 1 1
      thirdparty/harfbuzz/src/hb-buffer.h
  77. 44 26
      thirdparty/harfbuzz/src/hb-buffer.hh
  78. 5 2
      thirdparty/harfbuzz/src/hb-cache.hh
  79. 869 0
      thirdparty/harfbuzz/src/hb-cairo-utils.cc
  80. 107 0
      thirdparty/harfbuzz/src/hb-cairo-utils.hh
  81. 1010 0
      thirdparty/harfbuzz/src/hb-cairo.cc
  82. 99 0
      thirdparty/harfbuzz/src/hb-cairo.h
  83. 3 13
      thirdparty/harfbuzz/src/hb-cff-interp-common.hh
  84. 1 2
      thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh
  85. 1 3
      thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh
  86. 2 1
      thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh
  87. 9 4
      thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
  88. 0 26
      thirdparty/harfbuzz/src/hb-common.cc
  89. 26 0
      thirdparty/harfbuzz/src/hb-common.h
  90. 7 1
      thirdparty/harfbuzz/src/hb-config.hh
  91. 0 1
      thirdparty/harfbuzz/src/hb-coretext.cc
  92. 2 0
      thirdparty/harfbuzz/src/hb-cplusplus.hh
  93. 10 6
      thirdparty/harfbuzz/src/hb-debug.hh
  94. 2 1
      thirdparty/harfbuzz/src/hb-deprecated.h
  95. 4 8
      thirdparty/harfbuzz/src/hb-directwrite.cc
  96. 63 2
      thirdparty/harfbuzz/src/hb-draw.cc
  97. 25 10
      thirdparty/harfbuzz/src/hb-draw.h
  98. 246 0
      thirdparty/harfbuzz/src/hb-face-builder.cc
  99. 32 216
      thirdparty/harfbuzz/src/hb-face.cc
  100. 6 0
      thirdparty/harfbuzz/src/hb-face.h

+ 13 - 9
COPYRIGHT.txt

@@ -227,19 +227,23 @@ License: Expat
 
 
 Files: ./thirdparty/harfbuzz/
 Files: ./thirdparty/harfbuzz/
 Comment: HarfBuzz text shaping library
 Comment: HarfBuzz text shaping library
-Copyright: 2010-2020, Google, Inc.
- 2018-2020, Ebrahim Byagowi
- 2019-2020, Facebook, Inc.
- 2012, Mozilla Foundation
+Copyright: 2010-2022, Google, Inc.
+ 2015-2020, Ebrahim Byagowi
+ 2019,2020, Facebook, Inc.
+ 2012, 2015, Mozilla Foundation
  2011, Codethink Limited
  2011, Codethink Limited
  2008, 2010, Nokia Corporation and/or its subsidiary(-ies)
  2008, 2010, Nokia Corporation and/or its subsidiary(-ies)
  2009, Keith Stribley
  2009, Keith Stribley
- 2009, Martin Hosken and SIL International
+ 2011, Martin Hosken and SIL International
  2007, Chris Wilson
  2007, Chris Wilson
- 2005-2006, 2020-2021, Behdad Esfahbod
- 2005, David Turner
- 2004, 2007-2010, Red Hat, Inc.
- 1998-2004, David Turner and Werner Lemberg
+ 2005-2006, 2020-2023, Behdad Esfahbod
+ 2004, 2007-2010, 2013, 2021-2023, Red Hat, Inc.
+ 1998-2005, David Turner and Werner Lemberg
+ 2016, Igalia, S.L.
+ 2022, Matthias Clasen
+ 2018, 2021, Khaled Hosny
+ 2018-2020, Adobe, Inc.
+ 2013-2015, Alexei Podtelezhnikov
 License: HarfBuzz
 License: HarfBuzz
 
 
 Files: ./thirdparty/icu4c/
 Files: ./thirdparty/icu4c/

+ 13 - 6
modules/text_server_adv/SCsub

@@ -53,16 +53,19 @@ if env["builtin_harfbuzz"]:
         "src/hb-buffer-serialize.cc",
         "src/hb-buffer-serialize.cc",
         "src/hb-buffer-verify.cc",
         "src/hb-buffer-verify.cc",
         "src/hb-buffer.cc",
         "src/hb-buffer.cc",
+        # "src/hb-cairo-utils.cc",
+        # "src/hb-cairo.cc",
         "src/hb-common.cc",
         "src/hb-common.cc",
-        #'src/hb-coretext.cc',
-        #'src/hb-directwrite.cc',
+        # "src/hb-coretext.cc",
+        # "src/hb-directwrite.cc",
         "src/hb-draw.cc",
         "src/hb-draw.cc",
+        "src/hb-face-builder.cc",
         "src/hb-face.cc",
         "src/hb-face.cc",
         "src/hb-fallback-shape.cc",
         "src/hb-fallback-shape.cc",
         "src/hb-font.cc",
         "src/hb-font.cc",
-        #'src/hb-gdi.cc',
-        #'src/hb-glib.cc',
-        #'src/hb-gobject-structs.cc',
+        # "src/hb-gdi.cc",
+        # "src/hb-glib.cc",
+        # "src/hb-gobject-structs.cc",
         "src/hb-icu.cc",
         "src/hb-icu.cc",
         "src/hb-map.cc",
         "src/hb-map.cc",
         "src/hb-number.cc",
         "src/hb-number.cc",
@@ -94,6 +97,9 @@ if env["builtin_harfbuzz"]:
         "src/hb-ot-shape.cc",
         "src/hb-ot-shape.cc",
         "src/hb-ot-tag.cc",
         "src/hb-ot-tag.cc",
         "src/hb-ot-var.cc",
         "src/hb-ot-var.cc",
+        "src/hb-outline.cc",
+        "src/hb-paint-extents.cc",
+        "src/hb-paint.cc",
         "src/hb-set.cc",
         "src/hb-set.cc",
         "src/hb-shape-plan.cc",
         "src/hb-shape-plan.cc",
         "src/hb-shape.cc",
         "src/hb-shape.cc",
@@ -104,12 +110,13 @@ if env["builtin_harfbuzz"]:
         "src/hb-subset-cff1.cc",
         "src/hb-subset-cff1.cc",
         "src/hb-subset-cff2.cc",
         "src/hb-subset-cff2.cc",
         "src/hb-subset-input.cc",
         "src/hb-subset-input.cc",
+        "src/hb-subset-instancer-solver.cc",
         "src/hb-subset-plan.cc",
         "src/hb-subset-plan.cc",
         "src/hb-subset-repacker.cc",
         "src/hb-subset-repacker.cc",
         "src/hb-subset.cc",
         "src/hb-subset.cc",
         "src/hb-ucd.cc",
         "src/hb-ucd.cc",
         "src/hb-unicode.cc",
         "src/hb-unicode.cc",
-        #'src/hb-uniscribe.cc'
+        # "src/hb-uniscribe.cc",
     ]
     ]
 
 
     if freetype_enabled:
     if freetype_enabled:

+ 14 - 6
modules/text_server_adv/gdextension_build/SConstruct

@@ -290,16 +290,19 @@ thirdparty_harfbuzz_sources = [
     "src/hb-buffer-serialize.cc",
     "src/hb-buffer-serialize.cc",
     "src/hb-buffer-verify.cc",
     "src/hb-buffer-verify.cc",
     "src/hb-buffer.cc",
     "src/hb-buffer.cc",
+    # "src/hb-cairo-utils.cc",
+    # "src/hb-cairo.cc",
     "src/hb-common.cc",
     "src/hb-common.cc",
-    #'src/hb-coretext.cc',
-    #'src/hb-directwrite.cc',
+    # "src/hb-coretext.cc",
+    # "src/hb-directwrite.cc",
     "src/hb-draw.cc",
     "src/hb-draw.cc",
+    "src/hb-face-builder.cc",
     "src/hb-face.cc",
     "src/hb-face.cc",
     "src/hb-fallback-shape.cc",
     "src/hb-fallback-shape.cc",
     "src/hb-font.cc",
     "src/hb-font.cc",
-    #'src/hb-gdi.cc',
-    #'src/hb-glib.cc',
-    #'src/hb-gobject-structs.cc',
+    # "src/hb-gdi.cc",
+    # "src/hb-glib.cc",
+    # "src/hb-gobject-structs.cc",
     "src/hb-icu.cc",
     "src/hb-icu.cc",
     "src/hb-map.cc",
     "src/hb-map.cc",
     "src/hb-number.cc",
     "src/hb-number.cc",
@@ -331,6 +334,9 @@ thirdparty_harfbuzz_sources = [
     "src/hb-ot-shape.cc",
     "src/hb-ot-shape.cc",
     "src/hb-ot-tag.cc",
     "src/hb-ot-tag.cc",
     "src/hb-ot-var.cc",
     "src/hb-ot-var.cc",
+    "src/hb-outline.cc",
+    "src/hb-paint-extents.cc",
+    "src/hb-paint.cc",
     "src/hb-set.cc",
     "src/hb-set.cc",
     "src/hb-shape-plan.cc",
     "src/hb-shape-plan.cc",
     "src/hb-shape.cc",
     "src/hb-shape.cc",
@@ -341,11 +347,13 @@ thirdparty_harfbuzz_sources = [
     "src/hb-subset-cff1.cc",
     "src/hb-subset-cff1.cc",
     "src/hb-subset-cff2.cc",
     "src/hb-subset-cff2.cc",
     "src/hb-subset-input.cc",
     "src/hb-subset-input.cc",
+    "src/hb-subset-instancer-solver.cc",
     "src/hb-subset-plan.cc",
     "src/hb-subset-plan.cc",
+    "src/hb-subset-repacker.cc",
     "src/hb-subset.cc",
     "src/hb-subset.cc",
     "src/hb-ucd.cc",
     "src/hb-ucd.cc",
     "src/hb-unicode.cc",
     "src/hb-unicode.cc",
-    #'src/hb-uniscribe.cc'
+    # "src/hb-uniscribe.cc",
 ]
 ]
 
 
 if env["freetype_enabled"]:
 if env["freetype_enabled"]:

+ 4 - 2
thirdparty/README.md

@@ -248,13 +248,15 @@ Files extracted from upstream source:
 ## harfbuzz
 ## harfbuzz
 
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 6.0.0 (afcae83a064843d71d47624bc162e121cc56c08b, 2022)
+- Version: 7.1.0 (60841e26187576bff477c1a09ee2ffe544844abc, 2023)
 - License: MIT
 - License: MIT
 
 
 Files extracted from upstream source:
 Files extracted from upstream source:
 
 
-- the `src` folder
 - `AUTHORS`, `COPYING`, `THANKS`
 - `AUTHORS`, `COPYING`, `THANKS`
+- from the `src` folder, recursively
+  - all the `*.c`, `*.cc`, `*.h`, `*.hh` files
+  - _except_ `main.cc`, `harfbuzz*.cc`, `failing-alloc.c`, `test*.cc`
 
 
 
 
 ## icu4c
 ## icu4c

+ 12 - 8
thirdparty/harfbuzz/COPYING

@@ -2,19 +2,23 @@ HarfBuzz is licensed under the so-called "Old MIT" license.  Details follow.
 For parts of HarfBuzz that are licensed under different licenses see individual
 For parts of HarfBuzz that are licensed under different licenses see individual
 files names COPYING in subdirectories where applicable.
 files names COPYING in subdirectories where applicable.
 
 
-Copyright © 2010,2011,2012,2013,2014,2015,2016,2017,2018,2019,2020  Google, Inc.
-Copyright © 2018,2019,2020  Ebrahim Byagowi
+Copyright © 2010-2022  Google, Inc.
+Copyright © 2015-2020  Ebrahim Byagowi
 Copyright © 2019,2020  Facebook, Inc.
 Copyright © 2019,2020  Facebook, Inc.
-Copyright © 2012  Mozilla Foundation
+Copyright © 2012,2015  Mozilla Foundation
 Copyright © 2011  Codethink Limited
 Copyright © 2011  Codethink Limited
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
 Copyright © 2009  Keith Stribley
 Copyright © 2009  Keith Stribley
-Copyright © 2009  Martin Hosken and SIL International
+Copyright © 2011  Martin Hosken and SIL International
 Copyright © 2007  Chris Wilson
 Copyright © 2007  Chris Wilson
-Copyright © 2005,2006,2020,2021  Behdad Esfahbod
-Copyright © 2005  David Turner
-Copyright © 2004,2007,2008,2009,2010  Red Hat, Inc.
-Copyright © 1998-2004  David Turner and Werner Lemberg
+Copyright © 2005,2006,2020,2021,2022,2023  Behdad Esfahbod
+Copyright © 2004,2007,2008,2009,2010,2013,2021,2022,2023  Red Hat, Inc.
+Copyright © 1998-2005  David Turner and Werner Lemberg
+Copyright © 2016  Igalia S.L.
+Copyright © 2022  Matthias Clasen
+Copyright © 2018,2021  Khaled Hosny
+Copyright © 2018,2019,2020  Adobe, Inc
+Copyright © 2013-2015  Alexei Podtelezhnikov
 
 
 For full copyright notices consult the individual files in the package.
 For full copyright notices consult the individual files in the package.
 
 

+ 55 - 22
thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh → thirdparty/harfbuzz/src/OT/Color/CBDT/CBDT.hh

@@ -24,10 +24,11 @@
  * Google Author(s): Seigo Nonaka, Calder Kitagawa
  * Google Author(s): Seigo Nonaka, Calder Kitagawa
  */
  */
 
 
-#ifndef HB_OT_COLOR_CBDT_TABLE_HH
-#define HB_OT_COLOR_CBDT_TABLE_HH
+#ifndef OT_COLOR_CBDT_CBDT_HH
+#define OT_COLOR_CBDT_CBDT_HH
 
 
-#include "hb-open-type.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-paint.hh"
 
 
 /*
 /*
  * CBLC -- Color Bitmap Location
  * CBLC -- Color Bitmap Location
@@ -80,12 +81,15 @@ struct SmallGlyphMetrics
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
-  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents) const
+  void get_extents (hb_font_t *font, hb_glyph_extents_t *extents, bool scale) const
   {
   {
-    extents->x_bearing = font->em_scale_x (bearingX);
-    extents->y_bearing = font->em_scale_y (bearingY);
-    extents->width = font->em_scale_x (width);
-    extents->height = font->em_scale_y (-static_cast<int>(height));
+    extents->x_bearing = bearingX;
+    extents->y_bearing = bearingY;
+    extents->width = width;
+    extents->height = -static_cast<int> (height);
+
+    if (scale)
+      font->scale_glyph_extents (extents);
   }
   }
 
 
   HBUINT8	height;
   HBUINT8	height;
@@ -307,7 +311,7 @@ struct IndexSubtable
     }
     }
   }
   }
 
 
-  bool get_extents (hb_glyph_extents_t *extents HB_UNUSED) const
+  bool get_extents (hb_glyph_extents_t *extents HB_UNUSED, bool scale HB_UNUSED) const
   {
   {
     switch (u.header.indexFormat)
     switch (u.header.indexFormat)
     {
     {
@@ -504,8 +508,8 @@ struct IndexSubtableRecord
     return num_missing;
     return num_missing;
   }
   }
 
 
-  bool get_extents (hb_glyph_extents_t *extents, const void *base) const
-  { return (base+offsetToSubtable).get_extents (extents); }
+  bool get_extents (hb_glyph_extents_t *extents, const void *base, bool scale) const
+  { return (base+offsetToSubtable).get_extents (extents, scale); }
 
 
   bool get_image_data (unsigned int  gid,
   bool get_image_data (unsigned int  gid,
 		       const void   *base,
 		       const void   *base,
@@ -833,7 +837,7 @@ struct CBDT
     }
     }
 
 
     bool
     bool
-    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
+    get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents, bool scale = true) const
     {
     {
       const void *base;
       const void *base;
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
       const BitmapSizeTable &strike = this->cblc->choose_strike (font);
@@ -841,7 +845,7 @@ struct CBDT
       if (!subtable_record || !strike.ppemX || !strike.ppemY)
       if (!subtable_record || !strike.ppemX || !strike.ppemY)
 	return false;
 	return false;
 
 
-      if (subtable_record->get_extents (extents, base))
+      if (subtable_record->get_extents (extents, base, scale))
 	return true;
 	return true;
 
 
       unsigned int image_offset = 0, image_length = 0, image_format = 0;
       unsigned int image_offset = 0, image_length = 0, image_format = 0;
@@ -858,26 +862,29 @@ struct CBDT
 	if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
 	if (unlikely (image_length < GlyphBitmapDataFormat17::min_size))
 	  return false;
 	  return false;
 	auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
 	auto &glyphFormat17 = StructAtOffset<GlyphBitmapDataFormat17> (this->cbdt, image_offset);
-	glyphFormat17.glyphMetrics.get_extents (font, extents);
+	glyphFormat17.glyphMetrics.get_extents (font, extents, scale);
 	break;
 	break;
       }
       }
       case 18: {
       case 18: {
 	if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
 	if (unlikely (image_length < GlyphBitmapDataFormat18::min_size))
 	  return false;
 	  return false;
 	auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
 	auto &glyphFormat18 = StructAtOffset<GlyphBitmapDataFormat18> (this->cbdt, image_offset);
-	glyphFormat18.glyphMetrics.get_extents (font, extents);
+	glyphFormat18.glyphMetrics.get_extents (font, extents, scale);
 	break;
 	break;
       }
       }
       default: return false; /* TODO: Support other image formats. */
       default: return false; /* TODO: Support other image formats. */
       }
       }
 
 
       /* Convert to font units. */
       /* Convert to font units. */
-      float x_scale = upem / (float) strike.ppemX;
-      float y_scale = upem / (float) strike.ppemY;
-      extents->x_bearing = roundf (extents->x_bearing * x_scale);
-      extents->y_bearing = roundf (extents->y_bearing * y_scale);
-      extents->width = roundf (extents->width * x_scale);
-      extents->height = roundf (extents->height * y_scale);
+      if (scale)
+      {
+	float x_scale = upem / (float) strike.ppemX;
+	float y_scale = upem / (float) strike.ppemY;
+	extents->x_bearing = roundf (extents->x_bearing * x_scale);
+	extents->y_bearing = roundf (extents->y_bearing * y_scale);
+	extents->width = roundf (extents->width * x_scale);
+	extents->height = roundf (extents->height * y_scale);
+      }
 
 
       return true;
       return true;
     }
     }
@@ -934,6 +941,32 @@ struct CBDT
 
 
     bool has_data () const { return cbdt.get_length (); }
     bool has_data () const { return cbdt.get_length (); }
 
 
+    bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      hb_glyph_extents_t extents;
+      hb_glyph_extents_t pixel_extents;
+      hb_blob_t *blob = reference_png (font, glyph);
+
+      if (unlikely (blob == hb_blob_get_empty ()))
+        return false;
+
+      if (unlikely (!hb_font_get_glyph_extents (font, glyph, &extents)))
+        return false;
+
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+        return false;
+
+      bool ret = funcs->image (data,
+			       blob,
+			       pixel_extents.width, -pixel_extents.height,
+			       HB_PAINT_IMAGE_FORMAT_PNG,
+			       font->slant_xy,
+			       &extents);
+
+      hb_blob_destroy (blob);
+      return ret;
+    }
+
     private:
     private:
     hb_blob_ptr_t<CBLC> cblc;
     hb_blob_ptr_t<CBLC> cblc;
     hb_blob_ptr_t<CBDT> cbdt;
     hb_blob_ptr_t<CBDT> cbdt;
@@ -994,4 +1027,4 @@ struct CBDT_accelerator_t : CBDT::accelerator_t {
 
 
 } /* namespace OT */
 } /* namespace OT */
 
 
-#endif /* HB_OT_COLOR_CBDT_TABLE_HH */
+#endif /* OT_COLOR_CBDT_CBDT_HH */

+ 607 - 45
thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh → thirdparty/harfbuzz/src/OT/Color/COLR/COLR.hh

@@ -25,12 +25,14 @@
  * Google Author(s): Calder Kitagawa
  * Google Author(s): Calder Kitagawa
  */
  */
 
 
-#ifndef HB_OT_COLOR_COLR_TABLE_HH
-#define HB_OT_COLOR_COLR_TABLE_HH
+#ifndef OT_COLOR_COLR_COLR_HH
+#define OT_COLOR_COLR_COLR_HH
 
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-var-common.hh"
+#include "../../../hb.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-ot-var-common.hh"
+#include "../../../hb-paint.hh"
+#include "../../../hb-paint-extents.hh"
 
 
 /*
 /*
  * COLR -- Color
  * COLR -- Color
@@ -38,13 +40,82 @@
  */
  */
 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
 
 
-#ifndef HB_COLRV1_MAX_NESTING_LEVEL
-#define HB_COLRV1_MAX_NESTING_LEVEL	16
-#endif
+
+namespace OT {
+struct hb_paint_context_t;
+}
 
 
 namespace OT {
 namespace OT {
 
 
 struct COLR;
 struct COLR;
+
+struct Paint;
+
+struct hb_paint_context_t :
+       hb_dispatch_context_t<hb_paint_context_t>
+{
+  template <typename T>
+  return_t dispatch (const T &obj) { obj.paint_glyph (this); return hb_empty_t (); }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  const COLR* get_colr_table () const
+  { return reinterpret_cast<const COLR *> (base); }
+
+public:
+  const void *base;
+  hb_paint_funcs_t *funcs;
+  void *data;
+  hb_font_t *font;
+  unsigned int palette_index;
+  hb_color_t foreground;
+  VarStoreInstancer &instancer;
+  int depth_left = HB_MAX_NESTING_LEVEL;
+  int edge_count = HB_COLRV1_MAX_EDGE_COUNT;
+
+  hb_paint_context_t (const void *base_,
+		      hb_paint_funcs_t *funcs_,
+		      void *data_,
+                      hb_font_t *font_,
+                      unsigned int palette_,
+                      hb_color_t foreground_,
+		      VarStoreInstancer &instancer_) :
+    base (base_),
+    funcs (funcs_),
+    data (data_),
+    font (font_),
+    palette_index (palette_),
+    foreground (foreground_),
+    instancer (instancer_)
+  { }
+
+  hb_color_t get_color (unsigned int color_index, float alpha, hb_bool_t *is_foreground)
+  {
+    hb_color_t color = foreground;
+
+    *is_foreground = true;
+
+    if (color_index != 0xffff)
+    {
+      if (!funcs->custom_palette_color (data, color_index, &color))
+      {
+	unsigned int clen = 1;
+	hb_face_t *face = hb_font_get_face (font);
+
+	hb_ot_color_palette_get_colors (face, palette_index, color_index, &clen, &color);
+      }
+
+      *is_foreground = false;
+    }
+
+    return HB_COLOR (hb_color_get_blue (color),
+                     hb_color_get_green (color),
+                     hb_color_get_red (color),
+                     hb_color_get_alpha (color) * alpha);
+  }
+
+  inline void recurse (const Paint &paint);
+};
+
 struct hb_colrv1_closure_context_t :
 struct hb_colrv1_closure_context_t :
        hb_dispatch_context_t<hb_colrv1_closure_context_t>
        hb_dispatch_context_t<hb_colrv1_closure_context_t>
 {
 {
@@ -98,7 +169,7 @@ struct hb_colrv1_closure_context_t :
                                hb_set_t *glyphs_,
                                hb_set_t *glyphs_,
                                hb_set_t *layer_indices_,
                                hb_set_t *layer_indices_,
                                hb_set_t *palette_indices_,
                                hb_set_t *palette_indices_,
-                               unsigned nesting_level_left_ = HB_COLRV1_MAX_NESTING_LEVEL) :
+                               unsigned nesting_level_left_ = HB_MAX_NESTING_LEVEL) :
                           base (base_),
                           base (base_),
                           glyphs (glyphs_),
                           glyphs (glyphs_),
                           layer_indices (layer_indices_),
                           layer_indices (layer_indices_),
@@ -160,6 +231,8 @@ struct BaseGlyphRecord
 template <typename T>
 template <typename T>
 struct Variable
 struct Variable
 {
 {
+  static constexpr bool is_variable = true;
+
   Variable<T>* copy (hb_serialize_context_t *c) const
   Variable<T>* copy (hb_serialize_context_t *c) const
   {
   {
     TRACE_SERIALIZE (this);
     TRACE_SERIALIZE (this);
@@ -182,6 +255,23 @@ struct Variable
     return_trace (c->check_struct (this) && value.sanitize (c));
     return_trace (c->check_struct (this) && value.sanitize (c));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    value.paint_glyph (c, varIdxBase);
+  }
+
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *stop,
+		       const VarStoreInstancer &instancer) const
+  {
+    value.get_color_stop (c, stop, varIdxBase, instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return value.get_extend ();
+  }
+
   protected:
   protected:
   T      value;
   T      value;
   public:
   public:
@@ -193,6 +283,8 @@ struct Variable
 template <typename T>
 template <typename T>
 struct NoVariable
 struct NoVariable
 {
 {
+  static constexpr bool is_variable = false;
+
   static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
   static constexpr uint32_t varIdxBase = VarIdx::NO_VARIATION;
 
 
   NoVariable<T>* copy (hb_serialize_context_t *c) const
   NoVariable<T>* copy (hb_serialize_context_t *c) const
@@ -216,6 +308,23 @@ struct NoVariable
     return_trace (c->check_struct (this) && value.sanitize (c));
     return_trace (c->check_struct (this) && value.sanitize (c));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    value.paint_glyph (c, varIdxBase);
+  }
+
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *stop,
+		       const VarStoreInstancer &instancer) const
+  {
+    value.get_color_stop (c, stop, VarIdx::NO_VARIATION, instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return value.get_extend ();
+  }
+
   T      value;
   T      value;
   public:
   public:
   DEFINE_SIZE_STATIC (T::static_size);
   DEFINE_SIZE_STATIC (T::static_size);
@@ -233,7 +342,7 @@ struct ColorStop
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (*this);
     auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
   }
 
 
@@ -243,6 +352,17 @@ struct ColorStop
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
+  void get_color_stop (hb_paint_context_t *c,
+                       hb_color_stop_t *out,
+		       uint32_t varIdx,
+		       const VarStoreInstancer &instancer) const
+  {
+    out->offset = stopOffset.to_float(instancer (varIdx, 0));
+    out->color = c->get_color (paletteIndex,
+                               alpha.to_float (instancer (varIdx, 1)),
+                               &out->is_foreground);
+  }
+
   F2DOT14	stopOffset;
   F2DOT14	stopOffset;
   HBUINT16	paletteIndex;
   HBUINT16	paletteIndex;
   F2DOT14	alpha;
   F2DOT14	alpha;
@@ -294,6 +414,52 @@ struct ColorLine
                   stops.sanitize (c));
                   stops.sanitize (c));
   }
   }
 
 
+  /* get up to count stops from start */
+  unsigned int
+  get_color_stops (hb_paint_context_t *c,
+                   unsigned int start,
+		   unsigned int *count,
+		   hb_color_stop_t *color_stops,
+		   const VarStoreInstancer &instancer) const
+  {
+    unsigned int len = stops.len;
+
+    if (count && color_stops)
+    {
+      unsigned int i;
+      for (i = 0; i < *count && start + i < len; i++)
+        stops[start + i].get_color_stop (c, &color_stops[i], instancer);
+      *count = i;
+    }
+
+    return len;
+  }
+
+  HB_INTERNAL static unsigned int static_get_color_stops (hb_color_line_t *color_line,
+							  void *color_line_data,
+							  unsigned int start,
+							  unsigned int *count,
+							  hb_color_stop_t *color_stops,
+							  void *user_data)
+  {
+    const ColorLine *thiz = (const ColorLine *) color_line_data;
+    hb_paint_context_t *c = (hb_paint_context_t *) user_data;
+    return thiz->get_color_stops (c, start, count, color_stops, c->instancer);
+  }
+
+  hb_paint_extend_t get_extend () const
+  {
+    return (hb_paint_extend_t) (unsigned int) extend;
+  }
+
+  HB_INTERNAL static hb_paint_extend_t static_get_extend (hb_color_line_t *color_line,
+							  void *color_line_data,
+							  void *user_data)
+  {
+    const ColorLine *thiz = (const ColorLine *) color_line_data;
+    return thiz->get_extend ();
+  }
+
   Extend	extend;
   Extend	extend;
   Array16Of<Var<ColorStop>>	stops;
   Array16Of<Var<ColorStop>>	stops;
   public:
   public:
@@ -357,6 +523,17 @@ struct Affine2x3
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    c->funcs->push_transform (c->data,
+			      xx.to_float (c->instancer (varIdxBase, 0)),
+			      yx.to_float (c->instancer (varIdxBase, 1)),
+                              xy.to_float (c->instancer (varIdxBase, 2)),
+			      yy.to_float (c->instancer (varIdxBase, 3)),
+                              dx.to_float (c->instancer (varIdxBase, 4)),
+			      dy.to_float (c->instancer (varIdxBase, 5)));
+  }
+
   F16DOT16 xx;
   F16DOT16 xx;
   F16DOT16 yx;
   F16DOT16 yx;
   F16DOT16 xy;
   F16DOT16 xy;
@@ -376,7 +553,7 @@ struct PaintColrLayers
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (this);
     auto *out = c->serializer->embed (this);
     if (unlikely (!out)) return_trace (false);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
+    return_trace (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers.get (firstLayerIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
 
 
     return_trace (true);
     return_trace (true);
@@ -388,6 +565,8 @@ struct PaintColrLayers
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
+  inline void paint_glyph (hb_paint_context_t *c) const;
+
   HBUINT8	format; /* format = 1 */
   HBUINT8	format; /* format = 1 */
   HBUINT8	numLayers;
   HBUINT8	numLayers;
   HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
   HBUINT32	firstLayerIndex;  /* index into COLRv1::layerList */
@@ -405,7 +584,7 @@ struct PaintSolid
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     auto *out = c->serializer->embed (*this);
     auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     if (unlikely (!out)) return_trace (false);
-    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+    return_trace (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes.get (paletteIndex),
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
                                                HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
   }
 
 
@@ -415,6 +594,17 @@ struct PaintSolid
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    hb_bool_t is_foreground;
+    hb_color_t color;
+
+    color = c->get_color (paletteIndex,
+                          alpha.to_float (c->instancer (varIdxBase, 0)),
+                          &is_foreground);
+    c->funcs->color (c->data, is_foreground, color);
+  }
+
   HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
   HBUINT8	format; /* format = 2(noVar) or 3(Var)*/
   HBUINT16	paletteIndex;
   HBUINT16	paletteIndex;
   F2DOT14	alpha;
   F2DOT14	alpha;
@@ -443,6 +633,23 @@ struct PaintLinearGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->linear_gradient (c->data, &cl,
+			       x0 + c->instancer (varIdxBase, 0),
+			       y0 + c->instancer (varIdxBase, 1),
+			       x1 + c->instancer (varIdxBase, 2),
+			       y1 + c->instancer (varIdxBase, 3),
+			       x2 + c->instancer (varIdxBase, 4),
+			       y2 + c->instancer (varIdxBase, 5));
+  }
+
   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
   HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
                                             * table) to ColorLine subtable. */
                                             * table) to ColorLine subtable. */
@@ -477,6 +684,23 @@ struct PaintRadialGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->radial_gradient (c->data, &cl,
+			       x0 + c->instancer (varIdxBase, 0),
+			       y0 + c->instancer (varIdxBase, 1),
+			       radius0 + c->instancer (varIdxBase, 2),
+			       x1 + c->instancer (varIdxBase, 3),
+			       y1 + c->instancer (varIdxBase, 4),
+			       radius1 + c->instancer (varIdxBase, 5));
+  }
+
   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
   HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
                                             * table) to ColorLine subtable. */
                                             * table) to ColorLine subtable. */
@@ -511,6 +735,21 @@ struct PaintSweepGradient
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
     return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    hb_color_line_t cl = {
+      (void *) &(this+colorLine),
+      (this+colorLine).static_get_color_stops, c,
+      (this+colorLine).static_get_extend, nullptr
+    };
+
+    c->funcs->sweep_gradient (c->data, &cl,
+			      centerX + c->instancer (varIdxBase, 0),
+			      centerY + c->instancer (varIdxBase, 1),
+                              (startAngle.to_float (c->instancer (varIdxBase, 2)) + 1) * (float) M_PI,
+                              (endAngle.to_float   (c->instancer (varIdxBase, 3)) + 1) * (float) M_PI);
+  }
+
   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
   HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
   Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
                                             * table) to ColorLine subtable. */
                                             * table) to ColorLine subtable. */
@@ -522,8 +761,6 @@ struct PaintSweepGradient
   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
   DEFINE_SIZE_STATIC (4 + 2 * FWORD::static_size + 2 * F2DOT14::static_size);
 };
 };
 
 
-struct Paint;
-
 // Paint a non-COLR glyph, filled as indicated by paint.
 // Paint a non-COLR glyph, filled as indicated by paint.
 struct PaintGlyph
 struct PaintGlyph
 {
 {
@@ -548,6 +785,17 @@ struct PaintGlyph
     return_trace (c->check_struct (this) && paint.sanitize (c, this));
     return_trace (c->check_struct (this) && paint.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    c->funcs->push_inverse_root_transform (c->data, c->font);
+    c->funcs->push_clip_glyph (c->data, gid, c->font);
+    c->funcs->push_root_transform (c->data, c->font);
+    c->recurse (this+paint);
+    c->funcs->pop_transform (c->data);
+    c->funcs->pop_clip (c->data);
+    c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 10 */
   HBUINT8		format; /* format = 10 */
   Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
   Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
   HBUINT16		gid;
   HBUINT16		gid;
@@ -575,6 +823,8 @@ struct PaintColrGlyph
     return_trace (c->check_struct (this));
     return_trace (c->check_struct (this));
   }
   }
 
 
+  inline void paint_glyph (hb_paint_context_t *c) const;
+
   HBUINT8	format; /* format = 11 */
   HBUINT8	format; /* format = 11 */
   HBUINT16	gid;
   HBUINT16	gid;
   public:
   public:
@@ -603,6 +853,13 @@ struct PaintTransform
                   transform.sanitize (c, this));
                   transform.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    (this+transform).paint_glyph (c);
+    c->recurse (this+src);
+    c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8			format; /* format = 12(noVar) or 13 (Var) */
   HBUINT8			format; /* format = 12(noVar) or 13 (Var) */
   Offset24To<Paint>		src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
   Offset24To<Paint>		src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
   Offset24To<Var<Affine2x3>>	transform;
   Offset24To<Var<Affine2x3>>	transform;
@@ -629,6 +886,16 @@ struct PaintTranslate
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float ddx = dx + c->instancer (varIdxBase, 0);
+    float ddy = dy + c->instancer (varIdxBase, 1);
+
+    bool p1 = c->funcs->push_translate (c->data, ddx, ddy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
   HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
   FWORD		dx;
   FWORD		dx;
@@ -656,6 +923,16 @@ struct PaintScale
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
+    float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
+
+    bool p1 = c->funcs->push_scale (c->data, sx, sy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
   HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScale table) to Paint subtable. */
   F2DOT14		scaleX;
   F2DOT14		scaleX;
@@ -683,6 +960,22 @@ struct PaintScaleAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float sx = scaleX.to_float (c->instancer (varIdxBase, 0));
+    float sy = scaleY.to_float (c->instancer (varIdxBase, 1));
+    float tCenterX = centerX + c->instancer (varIdxBase, 2);
+    float tCenterY = centerY + c->instancer (varIdxBase, 3);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_scale (c->data, sx, sy);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 18 (noVar) or 19(Var) */
   HBUINT8		format; /* format = 18 (noVar) or 19(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleAroundCenter table) to Paint subtable. */
   F2DOT14	scaleX;
   F2DOT14	scaleX;
@@ -712,6 +1005,15 @@ struct PaintScaleUniform
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float s = scale.to_float (c->instancer (varIdxBase, 0));
+
+    bool p1 = c->funcs->push_scale (c->data, s, s);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 20 (noVar) or 21(Var) */
   HBUINT8		format; /* format = 20 (noVar) or 21(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniform table) to Paint subtable. */
   F2DOT14		scale;
   F2DOT14		scale;
@@ -738,6 +1040,21 @@ struct PaintScaleUniformAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float s = scale.to_float (c->instancer (varIdxBase, 0));
+    float tCenterX = centerX + c->instancer (varIdxBase, 1);
+    float tCenterY = centerY + c->instancer (varIdxBase, 2);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_scale (c->data, s, s);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 22 (noVar) or 23(Var) */
   HBUINT8		format; /* format = 22 (noVar) or 23(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintScaleUniformAroundCenter table) to Paint subtable. */
   F2DOT14	scale;
   F2DOT14	scale;
@@ -766,6 +1083,15 @@ struct PaintRotate
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float a = angle.to_float (c->instancer (varIdxBase, 0));
+
+    bool p1 = c->funcs->push_rotate (c->data, a);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 24 (noVar) or 25(Var) */
   HBUINT8		format; /* format = 24 (noVar) or 25(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
   F2DOT14		angle;
   F2DOT14		angle;
@@ -792,6 +1118,21 @@ struct PaintRotateAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float a = angle.to_float (c->instancer (varIdxBase, 0));
+    float tCenterX = centerX + c->instancer (varIdxBase, 1);
+    float tCenterY = centerY + c->instancer (varIdxBase, 2);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_rotate (c->data, a);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 26 (noVar) or 27(Var) */
   HBUINT8		format; /* format = 26 (noVar) or 27(Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintRotateAroundCenter table) to Paint subtable. */
   F2DOT14	angle;
   F2DOT14	angle;
@@ -820,6 +1161,16 @@ struct PaintSkew
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
+    float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
+
+    bool p1 = c->funcs->push_skew (c->data, sx, sy);
+    c->recurse (this+src);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 28(noVar) or 29 (Var) */
   HBUINT8		format; /* format = 28(noVar) or 29 (Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
   F2DOT14		xSkewAngle;
   F2DOT14		xSkewAngle;
@@ -847,6 +1198,22 @@ struct PaintSkewAroundCenter
     return_trace (c->check_struct (this) && src.sanitize (c, this));
     return_trace (c->check_struct (this) && src.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c, uint32_t varIdxBase) const
+  {
+    float sx = xSkewAngle.to_float(c->instancer (varIdxBase, 0));
+    float sy = ySkewAngle.to_float(c->instancer (varIdxBase, 1));
+    float tCenterX = centerX + c->instancer (varIdxBase, 2);
+    float tCenterY = centerY + c->instancer (varIdxBase, 3);
+
+    bool p1 = c->funcs->push_translate (c->data, +tCenterX, +tCenterY);
+    bool p2 = c->funcs->push_skew (c->data, sx, sy);
+    bool p3 = c->funcs->push_translate (c->data, -tCenterX, -tCenterY);
+    c->recurse (this+src);
+    if (p3) c->funcs->pop_transform (c->data);
+    if (p2) c->funcs->pop_transform (c->data);
+    if (p1) c->funcs->pop_transform (c->data);
+  }
+
   HBUINT8		format; /* format = 30(noVar) or 31 (Var) */
   HBUINT8		format; /* format = 30(noVar) or 31 (Var) */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintSkewAroundCenter table) to Paint subtable. */
   F2DOT14	xSkewAngle;
   F2DOT14	xSkewAngle;
@@ -879,6 +1246,14 @@ struct PaintComposite
                   backdrop.sanitize (c, this));
                   backdrop.sanitize (c, this));
   }
   }
 
 
+  void paint_glyph (hb_paint_context_t *c) const
+  {
+    c->recurse (this+backdrop);
+    c->funcs->push_group (c->data);
+    c->recurse (this+src);
+    c->funcs->pop_group (c->data, (hb_paint_composite_mode_t) (int) mode);
+  }
+
   HBUINT8		format; /* format = 32 */
   HBUINT8		format; /* format = 32 */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
   Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
   CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
   CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
@@ -948,8 +1323,8 @@ struct ClipBox
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
@@ -1084,7 +1459,7 @@ struct ClipList
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
     if (!c->serializer->check_assign (out->format, format, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
 
 
-    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
+    const hb_set_t& glyphset = c->plan->_glyphset_colred;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
     const hb_map_t &glyph_map = *c->plan->glyph_map;
 
 
     hb_map_t new_gid_offset_map;
     hb_map_t new_gid_offset_map;
@@ -1142,7 +1517,7 @@ struct Paint
   {
   {
     TRACE_SANITIZE (this);
     TRACE_SANITIZE (this);
 
 
-    if (unlikely (!c->check_start_recursion (HB_COLRV1_MAX_NESTING_LEVEL)))
+    if (unlikely (!c->check_start_recursion (HB_MAX_NESTING_LEVEL)))
       return_trace (c->no_dispatch_return_value ());
       return_trace (c->no_dispatch_return_value ());
 
 
     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
     return_trace (c->end_recursion (this->dispatch (c, std::forward<Ts> (ds)...)));
@@ -1151,8 +1526,8 @@ struct Paint
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.paintformat1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.paintformat2, std::forward<Ts> (ds)...));
@@ -1194,35 +1569,35 @@ struct Paint
   union {
   union {
   HBUINT8					format;
   HBUINT8					format;
   PaintColrLayers				paintformat1;
   PaintColrLayers				paintformat1;
-  PaintSolid					paintformat2;
+  NoVariable<PaintSolid>			paintformat2;
   Variable<PaintSolid>				paintformat3;
   Variable<PaintSolid>				paintformat3;
-  PaintLinearGradient<NoVariable>		paintformat4;
+  NoVariable<PaintLinearGradient<NoVariable>>	paintformat4;
   Variable<PaintLinearGradient<Variable>>	paintformat5;
   Variable<PaintLinearGradient<Variable>>	paintformat5;
-  PaintRadialGradient<NoVariable>		paintformat6;
+  NoVariable<PaintRadialGradient<NoVariable>>	paintformat6;
   Variable<PaintRadialGradient<Variable>>	paintformat7;
   Variable<PaintRadialGradient<Variable>>	paintformat7;
-  PaintSweepGradient<NoVariable>		paintformat8;
+  NoVariable<PaintSweepGradient<NoVariable>>	paintformat8;
   Variable<PaintSweepGradient<Variable>>	paintformat9;
   Variable<PaintSweepGradient<Variable>>	paintformat9;
   PaintGlyph					paintformat10;
   PaintGlyph					paintformat10;
   PaintColrGlyph				paintformat11;
   PaintColrGlyph				paintformat11;
   PaintTransform<NoVariable>			paintformat12;
   PaintTransform<NoVariable>			paintformat12;
   PaintTransform<Variable>			paintformat13;
   PaintTransform<Variable>			paintformat13;
-  PaintTranslate				paintformat14;
+  NoVariable<PaintTranslate>			paintformat14;
   Variable<PaintTranslate>			paintformat15;
   Variable<PaintTranslate>			paintformat15;
-  PaintScale					paintformat16;
+  NoVariable<PaintScale>			paintformat16;
   Variable<PaintScale>				paintformat17;
   Variable<PaintScale>				paintformat17;
-  PaintScaleAroundCenter			paintformat18;
+  NoVariable<PaintScaleAroundCenter>		paintformat18;
   Variable<PaintScaleAroundCenter>		paintformat19;
   Variable<PaintScaleAroundCenter>		paintformat19;
-  PaintScaleUniform				paintformat20;
+  NoVariable<PaintScaleUniform>			paintformat20;
   Variable<PaintScaleUniform>			paintformat21;
   Variable<PaintScaleUniform>			paintformat21;
-  PaintScaleUniformAroundCenter			paintformat22;
+  NoVariable<PaintScaleUniformAroundCenter>	paintformat22;
   Variable<PaintScaleUniformAroundCenter>	paintformat23;
   Variable<PaintScaleUniformAroundCenter>	paintformat23;
-  PaintRotate					paintformat24;
+  NoVariable<PaintRotate>			paintformat24;
   Variable<PaintRotate>				paintformat25;
   Variable<PaintRotate>				paintformat25;
-  PaintRotateAroundCenter			paintformat26;
+  NoVariable<PaintRotateAroundCenter>		paintformat26;
   Variable<PaintRotateAroundCenter>		paintformat27;
   Variable<PaintRotateAroundCenter>		paintformat27;
-  PaintSkew					paintformat28;
+  NoVariable<PaintSkew>				paintformat28;
   Variable<PaintSkew>				paintformat29;
   Variable<PaintSkew>				paintformat29;
-  PaintSkewAroundCenter				paintformat30;
+  NoVariable<PaintSkewAroundCenter>		paintformat30;
   Variable<PaintSkewAroundCenter>		paintformat31;
   Variable<PaintSkewAroundCenter>		paintformat31;
   PaintComposite				paintformat32;
   PaintComposite				paintformat32;
   } u;
   } u;
@@ -1269,7 +1644,7 @@ struct BaseGlyphList : SortedArray32Of<BaseGlyphPaintRecord>
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     auto *out = c->serializer->start_embed (this);
     auto *out = c->serializer->start_embed (this);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
     if (unlikely (!c->serializer->extend_min (out)))  return_trace (false);
-    const hb_set_t* glyphset = c->plan->_glyphset_colred;
+    const hb_set_t* glyphset = &c->plan->_glyphset_colred;
 
 
     for (const auto& _ : as_array ())
     for (const auto& _ : as_array ())
     {
     {
@@ -1323,7 +1698,14 @@ struct COLR
 {
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
 
 
-  bool has_data () const { return numBaseGlyphs; }
+  bool has_v0_data () const { return numBaseGlyphs; }
+  bool has_v1_data () const
+  {
+    if (version == 1)
+      return (this+baseGlyphList).len > 0;
+
+    return false;
+  }
 
 
   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
   unsigned int get_glyph_layers (hb_codepoint_t       glyph,
 				 unsigned int         start_offset,
 				 unsigned int         start_offset,
@@ -1503,7 +1885,7 @@ struct COLR
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
 
 
     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
     const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
-    const hb_set_t& glyphset = *c->plan->_glyphset_colred;
+    const hb_set_t& glyphset = c->plan->_glyphset_colred;
 
 
     auto base_it =
     auto base_it =
     + hb_range (c->plan->num_output_glyphs ())
     + hb_range (c->plan->num_output_glyphs ())
@@ -1552,7 +1934,7 @@ struct COLR
 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
 				  if (unlikely (!c->plan->new_gid_for_old_gid (out_layers[i].glyphId, &new_gid)))
 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
 				    return hb_pair_t<bool, hb_vector_t<LayerRecord>> (false, out_layers);
 				  out_layers[i].glyphId = new_gid;
 				  out_layers[i].glyphId = new_gid;
-				  out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
+				  out_layers[i].colorIdx = c->plan->colr_palettes.get (layers[i].colorIdx);
 				}
 				}
 
 
 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@@ -1585,10 +1967,23 @@ struct COLR
     colr_prime->layerList.serialize_subset (c, layerList, this);
     colr_prime->layerList.serialize_subset (c, layerList, this);
     colr_prime->clipList.serialize_subset (c, clipList, this);
     colr_prime->clipList.serialize_subset (c, clipList, this);
     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
     colr_prime->varIdxMap.serialize_copy (c->serializer, varIdxMap, this);
-    //TODO: subset varStore once it's implemented in fonttools
+    colr_prime->varStore.serialize_copy (c->serializer, varStore, this);
     return_trace (true);
     return_trace (true);
   }
   }
 
 
+  const Paint *get_base_glyph_paint (hb_codepoint_t glyph) const
+  {
+    const BaseGlyphList &baseglyph_paintrecords = this+baseGlyphList;
+    const BaseGlyphPaintRecord* record = get_base_glyph_paintrecord (glyph);
+    if (record)
+    {
+      const Paint &paint = &baseglyph_paintrecords+record->paint;
+      return &paint;
+    }
+    else
+      return nullptr;
+  }
+
   bool
   bool
   get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
   get_extents (hb_font_t *font, hb_codepoint_t glyph, hb_glyph_extents_t *extents) const
   {
   {
@@ -1599,14 +1994,138 @@ struct COLR
 				 this+varIdxMap,
 				 this+varIdxMap,
 				 hb_array (font->coords, font->num_coords));
 				 hb_array (font->coords, font->num_coords));
 
 
-    if ((this+clipList).get_extents (glyph,
-				     extents,
-				     instancer))
+    if (get_clip (glyph, extents, instancer))
     {
     {
-      extents->x_bearing = font->em_scale_x (extents->x_bearing);
-      extents->y_bearing = font->em_scale_x (extents->y_bearing);
-      extents->width = font->em_scale_x (extents->width);
-      extents->height = font->em_scale_x (extents->height);
+      font->scale_glyph_extents (extents);
+      return true;
+    }
+
+    auto *extents_funcs = hb_paint_extents_get_funcs ();
+    hb_paint_extents_context_t extents_data;
+    bool ret = paint_glyph (font, glyph, extents_funcs, &extents_data, 0, HB_COLOR(0,0,0,0));
+
+    hb_extents_t e = extents_data.get_extents ();
+    if (e.is_void ())
+    {
+      extents->x_bearing = 0;
+      extents->y_bearing = 0;
+      extents->width = 0;
+      extents->height = 0;
+    }
+    else
+    {
+      extents->x_bearing = e.xmin;
+      extents->y_bearing = e.ymax;
+      extents->width = e.xmax - e.xmin;
+      extents->height = e.ymin - e.ymax;
+    }
+
+    return ret;
+  }
+
+  bool
+  has_paint_for_glyph (hb_codepoint_t glyph) const
+  {
+    if (version == 1)
+    {
+      const Paint *paint = get_base_glyph_paint (glyph);
+
+      return paint != nullptr;
+    }
+
+    return false;
+  }
+
+  bool get_clip (hb_codepoint_t glyph,
+		 hb_glyph_extents_t *extents,
+		 const VarStoreInstancer instancer) const
+  {
+    return (this+clipList).get_extents (glyph,
+					extents,
+					instancer);
+  }
+
+  bool
+  paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data, unsigned int palette_index, hb_color_t foreground, bool clip = true) const
+  {
+    VarStoreInstancer instancer (this+varStore,
+	                         this+varIdxMap,
+	                         hb_array (font->coords, font->num_coords));
+    hb_paint_context_t c (this, funcs, data, font, palette_index, foreground, instancer);
+
+    if (version == 1)
+    {
+      const Paint *paint = get_base_glyph_paint (glyph);
+      if (paint)
+      {
+        // COLRv1 glyph
+
+	VarStoreInstancer instancer (this+varStore,
+				     this+varIdxMap,
+				     hb_array (font->coords, font->num_coords));
+
+	bool is_bounded = true;
+	if (clip)
+	{
+	  hb_glyph_extents_t extents;
+	  if (get_clip (glyph, &extents, instancer))
+	  {
+	    font->scale_glyph_extents (&extents);
+	    c.funcs->push_clip_rectangle (c.data,
+					  extents.x_bearing,
+					  extents.y_bearing + extents.height,
+					  extents.x_bearing + extents.width,
+					  extents.y_bearing);
+	  }
+	  else
+	  {
+	    auto *extents_funcs = hb_paint_extents_get_funcs ();
+	    hb_paint_extents_context_t extents_data;
+
+	    paint_glyph (font, glyph,
+			 extents_funcs, &extents_data,
+			 palette_index, foreground,
+			 false);
+
+	    hb_extents_t extents = extents_data.get_extents ();
+	    is_bounded = extents_data.is_bounded ();
+
+	    c.funcs->push_clip_rectangle (c.data,
+					  extents.xmin,
+					  extents.ymin,
+					  extents.xmax,
+					  extents.ymax);
+	  }
+	}
+
+	c.funcs->push_root_transform (c.data, font);
+
+	if (is_bounded)
+	  c.recurse (*paint);
+
+	c.funcs->pop_transform (c.data);
+
+	if (clip)
+	  c.funcs->pop_clip (c.data);
+
+        return true;
+      }
+    }
+
+    const BaseGlyphRecord *record = get_base_glyph_record (glyph);
+    if (record && ((hb_codepoint_t) record->glyphId == glyph))
+    {
+      // COLRv0 glyph
+      for (const auto &r : (this+layersZ).as_array (numLayers)
+			   .sub_array (record->firstLayerIdx, record->numLayers))
+      {
+        hb_bool_t is_foreground;
+        hb_color_t color = c.get_color (r.colorIdx, 1., &is_foreground);
+        c.funcs->push_clip_glyph (c.data, r.glyphId, c.font);
+        c.funcs->color (c.data, is_foreground, color);
+        c.funcs->pop_clip (c.data);
+      }
+
       return true;
       return true;
     }
     }
 
 
@@ -1635,7 +2154,50 @@ struct COLR_accelerator_t : COLR::accelerator_t {
   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
   COLR_accelerator_t (hb_face_t *face) : COLR::accelerator_t (face) {}
 };
 };
 
 
-} /* namespace OT */
+void
+hb_paint_context_t::recurse (const Paint &paint)
+{
+  if (unlikely (depth_left <= 0 || edge_count <= 0)) return;
+  depth_left--;
+  edge_count--;
+  paint.dispatch (this);
+  depth_left++;
+}
+
+void PaintColrLayers::paint_glyph (hb_paint_context_t *c) const
+{
+  const LayerList &paint_offset_lists = c->get_colr_table ()->get_layerList ();
+  for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+  {
+    const Paint &paint = paint_offset_lists.get_paint (i);
+    c->funcs->push_group (c->data);
+    c->recurse (paint);
+    c->funcs->pop_group (c->data, HB_PAINT_COMPOSITE_MODE_SRC_OVER);
+  }
+}
+
+void PaintColrGlyph::paint_glyph (hb_paint_context_t *c) const
+{
+  const COLR *colr_table = c->get_colr_table ();
+  const Paint *paint = colr_table->get_base_glyph_paint (gid);
 
 
+  hb_glyph_extents_t extents = {0};
+  bool has_clip_box = colr_table->get_clip (gid, &extents, c->instancer);
+
+  if (has_clip_box)
+    c->funcs->push_clip_rectangle (c->data,
+				   extents.x_bearing,
+				   extents.y_bearing + extents.height,
+				   extents.x_bearing + extents.width,
+				   extents.y_bearing);
+
+  if (paint)
+    c->recurse (*paint);
+
+  if (has_clip_box)
+    c->funcs->pop_clip (c->data);
+}
+
+} /* namespace OT */
 
 
-#endif /* HB_OT_COLOR_COLR_TABLE_HH */
+#endif /* OT_COLOR_COLR_COLR_HH */

+ 5 - 6
thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh → thirdparty/harfbuzz/src/OT/Color/COLR/colrv1-closure.hh

@@ -24,12 +24,11 @@
  *
  *
  */
  */
 
 
-#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
-#define HB_OT_COLR_COLRV1_CLOSURE_HH
+#ifndef OT_COLOR_COLR_COLRV1_CLOSURE_HH
+#define OT_COLOR_COLR_COLRV1_CLOSURE_HH
 
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
-#include "hb-ot-color-colr-table.hh"
+#include "../../../hb-open-type.hh"
+#include "COLR.hh"
 
 
 /*
 /*
  * COLR -- Color
  * COLR -- Color
@@ -105,4 +104,4 @@ HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) cons
 } /* namespace OT */
 } /* namespace OT */
 
 
 
 
-#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */
+#endif /* OT_COLOR_COLR_COLRV1_CLOSURE_HH */

+ 7 - 7
thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh → thirdparty/harfbuzz/src/OT/Color/CPAL/CPAL.hh

@@ -25,12 +25,12 @@
  * Google Author(s): Sascha Brawer
  * Google Author(s): Sascha Brawer
  */
  */
 
 
-#ifndef HB_OT_COLOR_CPAL_TABLE_HH
-#define HB_OT_COLOR_CPAL_TABLE_HH
+#ifndef OT_COLOR_CPAL_CPAL_HH
+#define OT_COLOR_CPAL_CPAL_HH
 
 
-#include "hb-open-type.hh"
-#include "hb-ot-color.h"
-#include "hb-ot-name.h"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-ot-color.h"
+#include "../../../hb-ot-name.h"
 
 
 
 
 /*
 /*
@@ -239,7 +239,7 @@ struct CPAL
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     if (!numPalettes) return_trace (false);
     if (!numPalettes) return_trace (false);
 
 
-    const hb_map_t *color_index_map = c->plan->colr_palettes;
+    const hb_map_t *color_index_map = &c->plan->colr_palettes;
     if (color_index_map->is_empty ()) return_trace (false);
     if (color_index_map->is_empty ()) return_trace (false);
 
 
     hb_set_t retained_color_indices;
     hb_set_t retained_color_indices;
@@ -319,4 +319,4 @@ struct CPAL
 } /* namespace OT */
 } /* namespace OT */
 
 
 
 
-#endif /* HB_OT_COLOR_CPAL_TABLE_HH */
+#endif /* OT_COLOR_CPAL_CPAL_HH */

+ 49 - 20
thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh → thirdparty/harfbuzz/src/OT/Color/sbix/sbix.hh

@@ -25,11 +25,11 @@
  * Google Author(s): Calder Kitagawa
  * Google Author(s): Calder Kitagawa
  */
  */
 
 
-#ifndef HB_OT_COLOR_SBIX_TABLE_HH
-#define HB_OT_COLOR_SBIX_TABLE_HH
+#ifndef OT_COLOR_SBIX_SBIX_HH
+#define OT_COLOR_SBIX_SBIX_HH
 
 
-#include "hb-open-type.hh"
-#include "hb-ot-layout-common.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-paint.hh"
 
 
 /*
 /*
  * sbix -- Standard Bitmap Graphics
  * sbix -- Standard Bitmap Graphics
@@ -213,10 +213,11 @@ struct sbix
 
 
     bool get_extents (hb_font_t          *font,
     bool get_extents (hb_font_t          *font,
 		      hb_codepoint_t      glyph,
 		      hb_codepoint_t      glyph,
-		      hb_glyph_extents_t *extents) const
+		      hb_glyph_extents_t *extents,
+		      bool                scale = true) const
     {
     {
       /* We only support PNG right now, and following function checks type. */
       /* We only support PNG right now, and following function checks type. */
-      return get_png_extents (font, glyph, extents);
+      return get_png_extents (font, glyph, extents, scale);
     }
     }
 
 
     hb_blob_t *reference_png (hb_font_t      *font,
     hb_blob_t *reference_png (hb_font_t      *font,
@@ -231,6 +232,37 @@ struct sbix
 						  num_glyphs, available_ppem);
 						  num_glyphs, available_ppem);
     }
     }
 
 
+    bool paint_glyph (hb_font_t *font, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      if (!has_data ())
+        return false;
+
+      int x_offset = 0, y_offset = 0;
+      unsigned int strike_ppem = 0;
+      hb_blob_t *blob = reference_png (font, glyph, &x_offset, &y_offset, &strike_ppem);
+      hb_glyph_extents_t extents;
+      hb_glyph_extents_t pixel_extents;
+
+      if (blob == hb_blob_get_empty ())
+        return false;
+
+      if (!hb_font_get_glyph_extents (font, glyph, &extents))
+        return false;
+
+      if (unlikely (!get_extents (font, glyph, &pixel_extents, false)))
+        return false;
+
+      bool ret = funcs->image (data,
+			       blob,
+			       pixel_extents.width, -pixel_extents.height,
+			       HB_PAINT_IMAGE_FORMAT_PNG,
+			       font->slant_xy,
+			       &extents);
+
+      hb_blob_destroy (blob);
+      return ret;
+    }
+
     private:
     private:
 
 
     const SBIXStrike &choose_strike (hb_font_t *font) const
     const SBIXStrike &choose_strike (hb_font_t *font) const
@@ -285,7 +317,8 @@ struct sbix
 
 
     bool get_png_extents (hb_font_t          *font,
     bool get_png_extents (hb_font_t          *font,
 			  hb_codepoint_t      glyph,
 			  hb_codepoint_t      glyph,
-			  hb_glyph_extents_t *extents) const
+			  hb_glyph_extents_t *extents,
+			  bool                scale = true) const
     {
     {
       /* Following code is safe to call even without data.
       /* Following code is safe to call even without data.
        * But faster to short-circuit. */
        * But faster to short-circuit. */
@@ -310,22 +343,18 @@ struct sbix
       extents->height    = -1 * png.IHDR.height;
       extents->height    = -1 * png.IHDR.height;
 
 
       /* Convert to font units. */
       /* Convert to font units. */
-      if (strike_ppem)
+      if (strike_ppem && scale)
       {
       {
 	float scale = font->face->get_upem () / (float) strike_ppem;
 	float scale = font->face->get_upem () / (float) strike_ppem;
-	extents->x_bearing = font->em_scalef_x (extents->x_bearing * scale);
-	extents->y_bearing = font->em_scalef_y (extents->y_bearing * scale);
-	extents->width = font->em_scalef_x (extents->width * scale);
-	extents->height = font->em_scalef_y (extents->height * scale);
-      }
-      else
-      {
-	extents->x_bearing = font->em_scale_x (extents->x_bearing);
-	extents->y_bearing = font->em_scale_y (extents->y_bearing);
-	extents->width = font->em_scale_x (extents->width);
-	extents->height = font->em_scale_y (extents->height);
+	extents->x_bearing = roundf (extents->x_bearing * scale);
+	extents->y_bearing = roundf (extents->y_bearing * scale);
+	extents->width = roundf (extents->width * scale);
+	extents->height = roundf (extents->height * scale);
       }
       }
 
 
+      if (scale)
+	font->scale_glyph_extents (extents);
+
       hb_blob_destroy (blob);
       hb_blob_destroy (blob);
 
 
       return strike_ppem;
       return strike_ppem;
@@ -420,4 +449,4 @@ struct sbix_accelerator_t : sbix::accelerator_t {
 
 
 } /* namespace OT */
 } /* namespace OT */
 
 
-#endif /* HB_OT_COLOR_SBIX_TABLE_HH */
+#endif /* OT_COLOR_SBIX_SBIX_HH */

+ 29 - 4
thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh → thirdparty/harfbuzz/src/OT/Color/svg/svg.hh

@@ -22,10 +22,12 @@
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  */
  */
 
 
-#ifndef HB_OT_COLOR_SVG_TABLE_HH
-#define HB_OT_COLOR_SVG_TABLE_HH
+#ifndef OT_COLOR_SVG_SVG_HH
+#define OT_COLOR_SVG_SVG_HH
 
 
-#include "hb-open-type.hh"
+#include "../../../hb-open-type.hh"
+#include "../../../hb-blob.hh"
+#include "../../../hb-paint.hh"
 
 
 /*
 /*
  * SVG -- SVG (Scalable Vector Graphics)
  * SVG -- SVG (Scalable Vector Graphics)
@@ -91,8 +93,31 @@ struct SVG
 
 
     bool has_data () const { return table->has_data (); }
     bool has_data () const { return table->has_data (); }
 
 
+    bool paint_glyph (hb_font_t *font HB_UNUSED, hb_codepoint_t glyph, hb_paint_funcs_t *funcs, void *data) const
+    {
+      if (!has_data ())
+        return false;
+
+      hb_blob_t *blob = reference_blob_for_glyph (glyph);
+
+      if (blob == hb_blob_get_empty ())
+        return false;
+
+      funcs->image (data,
+		    blob,
+		    0, 0,
+		    HB_PAINT_IMAGE_FORMAT_SVG,
+		    font->slant_xy,
+		    nullptr);
+
+      hb_blob_destroy (blob);
+      return true;
+    }
+
     private:
     private:
     hb_blob_ptr_t<SVG> table;
     hb_blob_ptr_t<SVG> table;
+    public:
+    DEFINE_SIZE_STATIC (sizeof (hb_blob_ptr_t<SVG>));
   };
   };
 
 
   const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
   const SVGDocumentIndexEntry &get_glyph_entry (hb_codepoint_t glyph_id) const
@@ -123,4 +148,4 @@ struct SVG_accelerator_t : SVG::accelerator_t {
 } /* namespace OT */
 } /* namespace OT */
 
 
 
 
-#endif /* HB_OT_COLOR_SVG_TABLE_HH */
+#endif /* OT_COLOR_SVG_SVG_HH */

+ 1 - 0
thirdparty/harfbuzz/src/OT/Layout/Common/Coverage.hh

@@ -147,6 +147,7 @@ struct Coverage
     TRACE_SUBSET (this);
     TRACE_SUBSET (this);
     auto it =
     auto it =
     + iter ()
     + iter ()
+    | hb_take (c->plan->source->get_num_glyphs ())
     | hb_filter (c->plan->glyph_map_gsub)
     | hb_filter (c->plan->glyph_map_gsub)
     | hb_map_retains_sorting (c->plan->glyph_map_gsub)
     | hb_map_retains_sorting (c->plan->glyph_map_gsub)
     ;
     ;

+ 918 - 0
thirdparty/harfbuzz/src/OT/Layout/GDEF/GDEF.hh

@@ -0,0 +1,918 @@
+/*
+ * Copyright © 2007,2008,2009  Red Hat, Inc.
+ * Copyright © 2010,2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef OT_LAYOUT_GDEF_GDEF_HH
+#define OT_LAYOUT_GDEF_GDEF_HH
+
+#include "../../../hb-ot-layout-common.hh"
+
+#include "../../../hb-font.hh"
+
+
+namespace OT {
+
+
+/*
+ * Attachment List Table
+ */
+
+/* Array of contour point indices--in increasing numerical order */
+struct AttachPoint : Array16Of<HBUINT16>
+{
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    return_trace (out->serialize (c->serializer, + iter ()));
+  }
+};
+
+struct AttachList
+{
+  unsigned int get_attach_points (hb_codepoint_t glyph_id,
+				  unsigned int start_offset,
+				  unsigned int *point_count /* IN/OUT */,
+				  unsigned int *point_array /* OUT */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (index == NOT_COVERED)
+    {
+      if (point_count)
+	*point_count = 0;
+      return 0;
+    }
+
+    const AttachPoint &points = this+attachPoint[index];
+
+    if (point_count)
+    {
+      + points.as_array ().sub_array (start_offset, point_count)
+      | hb_sink (hb_array (point_array, *point_count))
+      ;
+    }
+
+    return points.len;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, attachPoint)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->attachPoint, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && attachPoint.sanitize (c, this));
+  }
+
+  protected:
+  Offset16To<Coverage>
+		coverage;		/* Offset to Coverage table -- from
+					 * beginning of AttachList table */
+  Array16OfOffset16To<AttachPoint>
+		attachPoint;		/* Array of AttachPoint tables
+					 * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, attachPoint);
+};
+
+/*
+ * Ligature Caret Table
+ */
+
+struct CaretValueFormat1
+{
+  friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
+
+  private:
+  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction) const
+  {
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? font->em_scale_x (coordinate) : font->em_scale_y (coordinate);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 1 */
+  FWORD		coordinate;		/* X or Y value, in design units */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat2
+{
+  friend struct CaretValue;
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    return_trace (true);
+  }
+
+  private:
+  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction, hb_codepoint_t glyph_id) const
+  {
+    hb_position_t x, y;
+    font->get_glyph_contour_point_for_origin (glyph_id, caretValuePoint, direction, &x, &y);
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ? x : y;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 2 */
+  HBUINT16	caretValuePoint;	/* Contour point index on glyph */
+  public:
+  DEFINE_SIZE_STATIC (4);
+};
+
+struct CaretValueFormat3
+{
+  friend struct CaretValue;
+
+  hb_position_t get_caret_value (hb_font_t *font, hb_direction_t direction,
+				 const VariationStore &var_store) const
+  {
+    return HB_DIRECTION_IS_HORIZONTAL (direction) ?
+	   font->em_scale_x (coordinate) + (this+deviceTable).get_x_delta (font, var_store) :
+	   font->em_scale_y (coordinate) + (this+deviceTable).get_y_delta (font, var_store);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!out)) return_trace (false);
+    if (!c->serializer->embed (caretValueFormat)) return_trace (false);
+    if (!c->serializer->embed (coordinate)) return_trace (false);
+
+    unsigned varidx = (this+deviceTable).get_variation_index ();
+    if (c->plan->layout_variation_idx_delta_map.has (varidx))
+    {
+      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (varidx));
+      if (delta != 0)
+      {
+        if (!c->serializer->check_assign (out->coordinate, coordinate + delta, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+          return_trace (false);
+      }
+    }
+
+    if (c->plan->all_axes_pinned)
+      return_trace (c->serializer->check_assign (out->caretValueFormat, 1, HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+    if (!c->serializer->embed (deviceTable))
+      return_trace (false);
+
+    return_trace (out->deviceTable.serialize_copy (c->serializer, deviceTable, this, c->serializer->to_bias (out),
+						   hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { (this+deviceTable).collect_variation_indices (c); }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && deviceTable.sanitize (c, this));
+  }
+
+  protected:
+  HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
+  FWORD		coordinate;		/* X or Y value, in design units */
+  Offset16To<Device>
+		deviceTable;		/* Offset to Device table for X or Y
+					 * value--from beginning of CaretValue
+					 * table */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct CaretValue
+{
+  hb_position_t get_caret_value (hb_font_t *font,
+				 hb_direction_t direction,
+				 hb_codepoint_t glyph_id,
+				 const VariationStore &var_store) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.get_caret_value (font, direction);
+    case 2: return u.format2.get_caret_value (font, direction, glyph_id);
+    case 3: return u.format3.get_caret_value (font, direction, var_store);
+    default:return 0;
+    }
+  }
+
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
+    TRACE_DISPATCH (this, u.format);
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.format3, std::forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    switch (u.format) {
+    case 1:
+    case 2:
+      return;
+    case 3:
+      u.format3.collect_variation_indices (c);
+      return;
+    default: return;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    case 2: return_trace (u.format2.sanitize (c));
+    case 3: return_trace (u.format3.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT16		format;		/* Format identifier */
+  CaretValueFormat1	format1;
+  CaretValueFormat2	format2;
+  CaretValueFormat3	format3;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+struct LigGlyph
+{
+  unsigned get_lig_carets (hb_font_t            *font,
+			   hb_direction_t        direction,
+			   hb_codepoint_t        glyph_id,
+			   const VariationStore &var_store,
+			   unsigned              start_offset,
+			   unsigned             *caret_count /* IN/OUT */,
+			   hb_position_t        *caret_array /* OUT */) const
+  {
+    if (caret_count)
+    {
+      + carets.as_array ().sub_array (start_offset, caret_count)
+      | hb_map (hb_add (this))
+      | hb_map ([&] (const CaretValue &value) { return value.get_caret_value (font, direction, glyph_id, var_store); })
+      | hb_sink (hb_array (caret_array, *caret_count))
+      ;
+    }
+
+    return carets.len;
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    + hb_iter (carets)
+    | hb_apply (subset_offset_array (c, out->carets, this))
+    ;
+
+    return_trace (bool (out->carets));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    for (const Offset16To<CaretValue>& offset : carets.iter ())
+      (this+offset).collect_variation_indices (c);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (carets.sanitize (c, this));
+  }
+
+  protected:
+  Array16OfOffset16To<CaretValue>
+		carets;			/* Offset array of CaretValue tables
+					 * --from beginning of LigGlyph table
+					 * --in increasing coordinate order */
+  public:
+  DEFINE_SIZE_ARRAY (2, carets);
+};
+
+struct LigCaretList
+{
+  unsigned int get_lig_carets (hb_font_t *font,
+			       hb_direction_t direction,
+			       hb_codepoint_t glyph_id,
+			       const VariationStore &var_store,
+			       unsigned int start_offset,
+			       unsigned int *caret_count /* IN/OUT */,
+			       hb_position_t *caret_array /* OUT */) const
+  {
+    unsigned int index = (this+coverage).get_coverage (glyph_id);
+    if (index == NOT_COVERED)
+    {
+      if (caret_count)
+	*caret_count = 0;
+      return 0;
+    }
+    const LigGlyph &lig_glyph = this+ligGlyph[index];
+    return lig_glyph.get_lig_carets (font, direction, glyph_id, var_store, start_offset, caret_count, caret_array);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    hb_sorted_vector_t<hb_codepoint_t> new_coverage;
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (subset_offset_array (c, out->ligGlyph, this), hb_second)
+    | hb_map (hb_first)
+    | hb_map (glyph_map)
+    | hb_sink (new_coverage)
+    ;
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
+    return_trace (bool (new_coverage));
+  }
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  {
+    + hb_zip (this+coverage, ligGlyph)
+    | hb_filter (c->glyph_set, hb_first)
+    | hb_map (hb_second)
+    | hb_map (hb_add (this))
+    | hb_apply ([c] (const LigGlyph& _) { _.collect_variation_indices (c); })
+    ;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this) && ligGlyph.sanitize (c, this));
+  }
+
+  protected:
+  Offset16To<Coverage>
+		coverage;		/* Offset to Coverage table--from
+					 * beginning of LigCaretList table */
+  Array16OfOffset16To<LigGlyph>
+		ligGlyph;		/* Array of LigGlyph tables
+					 * in Coverage Index order */
+  public:
+  DEFINE_SIZE_ARRAY (4, ligGlyph);
+};
+
+
+struct MarkGlyphSetsFormat1
+{
+  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return (this+coverage[set_index]).get_coverage (glyph_id) != NOT_COVERED; }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+    out->format = format;
+
+    bool ret = true;
+    for (const Offset32To<Coverage>& offset : coverage.iter ())
+    {
+      auto *o = out->coverage.serialize_append (c->serializer);
+      if (unlikely (!o))
+      {
+	ret = false;
+	break;
+      }
+
+      //not using o->serialize_subset (c, offset, this, out) here because
+      //OTS doesn't allow null offset.
+      //See issue: https://github.com/khaledhosny/ots/issues/172
+      c->serializer->push ();
+      c->dispatch (this+offset);
+      c->serializer->add_link (*o, c->serializer->pop_pack ());
+    }
+
+    return_trace (ret && out->coverage.len);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (coverage.sanitize (c, this));
+  }
+
+  protected:
+  HBUINT16	format;			/* Format identifier--format = 1 */
+  Array16Of<Offset32To<Coverage>>
+		coverage;		/* Array of long offsets to mark set
+					 * coverage tables */
+  public:
+  DEFINE_SIZE_ARRAY (4, coverage);
+};
+
+struct MarkGlyphSets
+{
+  bool covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  {
+    switch (u.format) {
+    case 1: return u.format1.covers (set_index, glyph_id);
+    default:return false;
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    switch (u.format) {
+    case 1: return_trace (u.format1.subset (c));
+    default:return_trace (false);
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (!u.format.sanitize (c)) return_trace (false);
+    switch (u.format) {
+    case 1: return_trace (u.format1.sanitize (c));
+    default:return_trace (true);
+    }
+  }
+
+  protected:
+  union {
+  HBUINT16		format;		/* Format identifier */
+  MarkGlyphSetsFormat1	format1;
+  } u;
+  public:
+  DEFINE_SIZE_UNION (2, format);
+};
+
+
+/*
+ * GDEF -- Glyph Definition
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/gdef
+ */
+
+
+template <typename Types>
+struct GDEFVersion1_2
+{
+  friend struct GDEF;
+
+  protected:
+  FixedVersion<>version;		/* Version of the GDEF table--currently
+					 * 0x00010003u */
+  typename Types::template OffsetTo<ClassDef>
+		glyphClassDef;		/* Offset to class definition table
+					 * for glyph type--from beginning of
+					 * GDEF header (may be Null) */
+  typename Types::template OffsetTo<AttachList>
+		attachList;		/* Offset to list of glyphs with
+					 * attachment points--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<LigCaretList>
+		ligCaretList;		/* Offset to list of positioning points
+					 * for ligature carets--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<ClassDef>
+		markAttachClassDef;	/* Offset to class definition table for
+					 * mark attachment type--from beginning
+					 * of GDEF header (may be Null) */
+  typename Types::template OffsetTo<MarkGlyphSets>
+		markGlyphSetsDef;	/* Offset to the table of mark set
+					 * definitions--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010002. */
+  Offset32To<VariationStore>
+		varStore;		/* Offset to the table of Item Variation
+					 * Store--from beginning of GDEF
+					 * header (may be NULL).  Introduced
+					 * in version 0x00010003. */
+  public:
+  DEFINE_SIZE_MIN (4 + 4 * Types::size);
+
+  unsigned int get_size () const
+  {
+    return min_size +
+	   (version.to_int () >= 0x00010002u ? markGlyphSetsDef.static_size : 0) +
+	   (version.to_int () >= 0x00010003u ? varStore.static_size : 0);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (version.sanitize (c) &&
+		  glyphClassDef.sanitize (c, this) &&
+		  attachList.sanitize (c, this) &&
+		  ligCaretList.sanitize (c, this) &&
+		  markAttachClassDef.sanitize (c, this) &&
+		  (version.to_int () < 0x00010002u || markGlyphSetsDef.sanitize (c, this)) &&
+		  (version.to_int () < 0x00010003u || varStore.sanitize (c, this)));
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (*this);
+    if (unlikely (!out)) return_trace (false);
+
+    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this, nullptr, false, true);
+    bool subset_attachlist = out->attachList.serialize_subset (c, attachList, this);
+    bool subset_ligcaretlist = out->ligCaretList.serialize_subset (c, ligCaretList, this);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
+
+    bool subset_markglyphsetsdef = false;
+    if (version.to_int () >= 0x00010002u)
+    {
+      subset_markglyphsetsdef = out->markGlyphSetsDef.serialize_subset (c, markGlyphSetsDef, this);
+    }
+
+    bool subset_varstore = false;
+    if (version.to_int () >= 0x00010003u)
+    {
+      if (c->plan->all_axes_pinned)
+        out->varStore = 0;
+      else
+        subset_varstore = out->varStore.serialize_subset (c, varStore, this, c->plan->gdef_varstore_inner_maps.as_array ());
+    }
+
+    if (subset_varstore)
+    {
+      out->version.minor = 3;
+    } else if (subset_markglyphsetsdef) {
+      out->version.minor = 2;
+    } else  {
+      out->version.minor = 0;
+    }
+
+    return_trace (subset_glyphclassdef || subset_attachlist ||
+		  subset_ligcaretlist || subset_markattachclassdef ||
+		  (out->version.to_int () >= 0x00010002u && subset_markglyphsetsdef) ||
+		  (out->version.to_int () >= 0x00010003u && subset_varstore));
+  }
+};
+
+struct GDEF
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_GDEF;
+
+  enum GlyphClasses {
+    UnclassifiedGlyph	= 0,
+    BaseGlyph		= 1,
+    LigatureGlyph	= 2,
+    MarkGlyph		= 3,
+    ComponentGlyph	= 4
+  };
+
+  unsigned int get_size () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.get_size ();
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.get_size ();
+#endif
+    default: return u.version.static_size;
+    }
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    if (unlikely (!u.version.sanitize (c))) return_trace (false);
+    switch (u.version.major) {
+    case 1: return_trace (u.version1.sanitize (c));
+#ifndef HB_NO_BEYOND_64K
+    case 2: return_trace (u.version2.sanitize (c));
+#endif
+    default: return_trace (true);
+    }
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.subset (c);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.subset (c);
+#endif
+    default: return false;
+    }
+  }
+
+  bool has_glyph_classes () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.glyphClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.glyphClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_glyph_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.glyphClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.glyphClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.attachList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.attachList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const AttachList &get_attach_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.attachList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.attachList;
+#endif
+    default: return Null(AttachList);
+    }
+  }
+  bool has_lig_carets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.ligCaretList != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.ligCaretList != 0;
+#endif
+    default: return false;
+    }
+  }
+  const LigCaretList &get_lig_caret_list () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.ligCaretList;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.ligCaretList;
+#endif
+    default: return Null(LigCaretList);
+    }
+  }
+  bool has_mark_attachment_types () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version1.markAttachClassDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markAttachClassDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const ClassDef &get_mark_attach_class_def () const
+  {
+    switch (u.version.major) {
+    case 1: return this+u.version1.markAttachClassDef;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markAttachClassDef;
+#endif
+    default: return Null(ClassDef);
+    }
+  }
+  bool has_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u && u.version1.markGlyphSetsDef != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.markGlyphSetsDef != 0;
+#endif
+    default: return false;
+    }
+  }
+  const MarkGlyphSets &get_mark_glyph_sets () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010002u ? this+u.version1.markGlyphSetsDef : Null(MarkGlyphSets);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.markGlyphSetsDef;
+#endif
+    default: return Null(MarkGlyphSets);
+    }
+  }
+  bool has_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u && u.version1.varStore != 0;
+#ifndef HB_NO_BEYOND_64K
+    case 2: return u.version2.varStore != 0;
+#endif
+    default: return false;
+    }
+  }
+  const VariationStore &get_var_store () const
+  {
+    switch (u.version.major) {
+    case 1: return u.version.to_int () >= 0x00010003u ? this+u.version1.varStore : Null(VariationStore);
+#ifndef HB_NO_BEYOND_64K
+    case 2: return this+u.version2.varStore;
+#endif
+    default: return Null(VariationStore);
+    }
+  }
+
+
+  bool has_data () const { return u.version.to_int (); }
+  unsigned int get_glyph_class (hb_codepoint_t glyph) const
+  { return get_glyph_class_def ().get_class (glyph); }
+  void get_glyphs_in_class (unsigned int klass, hb_set_t *glyphs) const
+  { get_glyph_class_def ().collect_class (glyphs, klass); }
+
+  unsigned int get_mark_attachment_type (hb_codepoint_t glyph) const
+  { return get_mark_attach_class_def ().get_class (glyph); }
+
+  unsigned int get_attach_points (hb_codepoint_t glyph_id,
+				  unsigned int start_offset,
+				  unsigned int *point_count /* IN/OUT */,
+				  unsigned int *point_array /* OUT */) const
+  { return get_attach_list ().get_attach_points (glyph_id, start_offset, point_count, point_array); }
+
+  unsigned int get_lig_carets (hb_font_t *font,
+			       hb_direction_t direction,
+			       hb_codepoint_t glyph_id,
+			       unsigned int start_offset,
+			       unsigned int *caret_count /* IN/OUT */,
+			       hb_position_t *caret_array /* OUT */) const
+  { return get_lig_caret_list ().get_lig_carets (font,
+						 direction, glyph_id, get_var_store(),
+						 start_offset, caret_count, caret_array); }
+
+  bool mark_set_covers (unsigned int set_index, hb_codepoint_t glyph_id) const
+  { return get_mark_glyph_sets ().covers (set_index, glyph_id); }
+
+  /* glyph_props is a 16-bit integer where the lower 8-bit have bits representing
+   * glyph class and other bits, and high 8-bit the mark attachment type (if any).
+   * Not to be confused with lookup_props which is very similar. */
+  unsigned int get_glyph_props (hb_codepoint_t glyph) const
+  {
+    unsigned int klass = get_glyph_class (glyph);
+
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH == (unsigned int) LookupFlag::IgnoreBaseGlyphs), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE == (unsigned int) LookupFlag::IgnoreLigatures), "");
+    static_assert (((unsigned int) HB_OT_LAYOUT_GLYPH_PROPS_MARK == (unsigned int) LookupFlag::IgnoreMarks), "");
+
+    switch (klass) {
+    default:			return HB_OT_LAYOUT_GLYPH_CLASS_UNCLASSIFIED;
+    case BaseGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH;
+    case LigatureGlyph:		return HB_OT_LAYOUT_GLYPH_PROPS_LIGATURE;
+    case MarkGlyph:
+	  klass = get_mark_attachment_type (glyph);
+	  return HB_OT_LAYOUT_GLYPH_PROPS_MARK | (klass << 8);
+    }
+  }
+
+  HB_INTERNAL bool is_blocklisted (hb_blob_t *blob,
+				   hb_face_t *face) const;
+
+  struct accelerator_t
+  {
+    accelerator_t (hb_face_t *face)
+    {
+      table = hb_sanitize_context_t ().reference_table<GDEF> (face);
+      if (unlikely (table->is_blocklisted (table.get_blob (), face)))
+      {
+	hb_blob_destroy (table.get_blob ());
+	table = hb_blob_get_empty ();
+      }
+    }
+    ~accelerator_t () { table.destroy (); }
+
+    hb_blob_ptr_t<GDEF> table;
+  };
+
+  void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
+  { get_lig_caret_list ().collect_variation_indices (c); }
+
+  void remap_layout_variation_indices (const hb_set_t *layout_variation_indices,
+				       hb_hashmap_t<unsigned, hb_pair_t<unsigned, int>> *layout_variation_idx_delta_map /* OUT */) const
+  {
+    if (!has_var_store ()) return;
+    if (layout_variation_indices->is_empty ()) return;
+
+    unsigned new_major = 0, new_minor = 0;
+    unsigned last_major = (layout_variation_indices->get_min ()) >> 16;
+    for (unsigned idx : layout_variation_indices->iter ())
+    {
+      uint16_t major = idx >> 16;
+      if (major >= get_var_store ().get_sub_table_count ()) break;
+      if (major != last_major)
+      {
+	new_minor = 0;
+	++new_major;
+      }
+
+      unsigned new_idx = (new_major << 16) + new_minor;
+      if (!layout_variation_idx_delta_map->has (idx))
+        continue;
+      int delta = hb_second (layout_variation_idx_delta_map->get (idx));
+
+      layout_variation_idx_delta_map->set (idx, hb_pair_t<unsigned, int> (new_idx, delta));
+      ++new_minor;
+      last_major = major;
+    }
+  }
+
+  protected:
+  union {
+  FixedVersion<>		version;	/* Version identifier */
+  GDEFVersion1_2<SmallTypes>	version1;
+#ifndef HB_NO_BEYOND_64K
+  GDEFVersion1_2<MediumTypes>	version2;
+#endif
+  } u;
+  public:
+  DEFINE_SIZE_MIN (4);
+};
+
+struct GDEF_accelerator_t : GDEF::accelerator_t {
+  GDEF_accelerator_t (hb_face_t *face) : GDEF::accelerator_t (face) {}
+};
+
+} /* namespace OT */
+
+
+#endif /* OT_LAYOUT_GDEF_GDEF_HH */

+ 6 - 6
thirdparty/harfbuzz/src/OT/Layout/GPOS/AnchorFormat3.hh

@@ -51,9 +51,9 @@ struct AnchorFormat3
     if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
     if (unlikely (!c->serializer->embed (yCoordinate))) return_trace (false);
 
 
     unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
     unsigned x_varidx = xDeviceTable ? (this+xDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
-    if (c->plan->layout_variation_idx_delta_map->has (x_varidx))
+    if (c->plan->layout_variation_idx_delta_map.has (x_varidx))
     {
     {
-      int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (x_varidx));
+      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (x_varidx));
       if (delta != 0)
       if (delta != 0)
       {
       {
         if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
         if (!c->serializer->check_assign (out->xCoordinate, xCoordinate + delta,
@@ -63,9 +63,9 @@ struct AnchorFormat3
     }
     }
 
 
     unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
     unsigned y_varidx = yDeviceTable ? (this+yDeviceTable).get_variation_index () : HB_OT_LAYOUT_NO_VARIATIONS_INDEX;
-    if (c->plan->layout_variation_idx_delta_map->has (y_varidx))
+    if (c->plan->layout_variation_idx_delta_map.has (y_varidx))
     {
     {
-      int delta = hb_second (c->plan->layout_variation_idx_delta_map->get (y_varidx));
+      int delta = hb_second (c->plan->layout_variation_idx_delta_map.get (y_varidx));
       if (delta != 0)
       if (delta != 0)
       {
       {
         if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
         if (!c->serializer->check_assign (out->yCoordinate, yCoordinate + delta,
@@ -80,8 +80,8 @@ struct AnchorFormat3
     if (!c->serializer->embed (xDeviceTable)) return_trace (false);
     if (!c->serializer->embed (xDeviceTable)) return_trace (false);
     if (!c->serializer->embed (yDeviceTable)) return_trace (false);
     if (!c->serializer->embed (yDeviceTable)) return_trace (false);
 
 
-    out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
-    out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, c->plan->layout_variation_idx_delta_map);
+    out->xDeviceTable.serialize_copy (c->serializer, xDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
+    out->yDeviceTable.serialize_copy (c->serializer, yDeviceTable, this, 0, hb_serialize_context_t::Head, &c->plan->layout_variation_idx_delta_map);
     return_trace (out);
     return_trace (out);
   }
   }
 
 

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePos.hh

@@ -19,8 +19,8 @@ struct CursivePos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     default:return_trace (c->default_return_value ());

+ 2 - 2
thirdparty/harfbuzz/src/OT/Layout/GPOS/CursivePosFormat1.hh

@@ -143,7 +143,7 @@ struct CursivePosFormat1
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "cursive attaching glyph at %d to glyph at %d",
+			  "cursive attaching glyph at %u to glyph at %u",
 			  i, j);
 			  i, j);
     }
     }
 
 
@@ -241,7 +241,7 @@ struct CursivePosFormat1
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "cursive attached glyph at %d to glyph at %d",
+			  "cursive attached glyph at %u to glyph at %u",
 			  i, j);
 			  i, j);
     }
     }
 
 

+ 2 - 2
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkArray.hh

@@ -42,7 +42,7 @@ struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Cove
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "attaching mark glyph at %d to glyph at %d",
+			  "attaching mark glyph at %u to glyph at %u",
 			  c->buffer->idx, glyph_pos);
 			  c->buffer->idx, glyph_pos);
     }
     }
 
 
@@ -56,7 +56,7 @@ struct MarkArray : Array16Of<MarkRecord>        /* Array of MarkRecords--in Cove
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "attached mark glyph at %d to glyph at %d",
+			  "attached mark glyph at %u to glyph at %u",
 			  c->buffer->idx, glyph_pos);
 			  c->buffer->idx, glyph_pos);
     }
     }
 
 

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePos.hh

@@ -22,8 +22,8 @@ struct MarkBasePos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 54 - 29
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkBasePosFormat1.hh

@@ -90,6 +90,25 @@ struct MarkBasePosFormat1_2
 
 
   const Coverage &get_coverage () const { return this+markCoverage; }
   const Coverage &get_coverage () const { return this+markCoverage; }
 
 
+  static inline bool accept (hb_buffer_t *buffer, unsigned idx)
+  {
+    /* We only want to attach to the first of a MultipleSubst sequence.
+     * https://github.com/harfbuzz/harfbuzz/issues/740
+     * Reject others...
+     * ...but stop if we find a mark in the MultipleSubst sequence:
+     * https://github.com/harfbuzz/harfbuzz/issues/1020 */
+    return !_hb_glyph_info_multiplied (&buffer->info[idx]) ||
+	   0 == _hb_glyph_info_get_lig_comp (&buffer->info[idx]) ||
+	   (idx == 0 ||
+	    _hb_glyph_info_is_mark (&buffer->info[idx - 1]) ||
+	    !_hb_glyph_info_multiplied (&buffer->info[idx - 1]) ||
+	    _hb_glyph_info_get_lig_id (&buffer->info[idx]) !=
+	    _hb_glyph_info_get_lig_id (&buffer->info[idx - 1]) ||
+	    _hb_glyph_info_get_lig_comp (&buffer->info[idx]) !=
+	    _hb_glyph_info_get_lig_comp (&buffer->info[idx - 1]) + 1
+	    );
+  }
+
   bool apply (hb_ot_apply_context_t *c) const
   bool apply (hb_ot_apply_context_t *c) const
   {
   {
     TRACE_APPLY (this);
     TRACE_APPLY (this);
@@ -97,48 +116,54 @@ struct MarkBasePosFormat1_2
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     unsigned int mark_index = (this+markCoverage).get_coverage  (buffer->cur().codepoint);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
 
-    /* Now we search backwards for a non-mark glyph */
+    /* Now we search backwards for a non-mark glyph.
+     * We don't use skippy_iter.prev() to avoid O(n^2) behavior. */
+
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    do {
-      unsigned unsafe_from;
-      if (!skippy_iter.prev (&unsafe_from))
+
+    if (c->last_base_until > buffer->idx)
+    {
+      c->last_base_until = 0;
+      c->last_base = -1;
+    }
+    unsigned j;
+    for (j = buffer->idx; j > c->last_base_until; j--)
+    {
+      auto match = skippy_iter.match (buffer->info[j - 1]);
+      if (match == skippy_iter.MATCH)
+      {
+        // https://github.com/harfbuzz/harfbuzz/issues/4124
+	if (!accept (buffer, j - 1) &&
+	    NOT_COVERED == (this+baseCoverage).get_coverage  (buffer->info[j - 1].codepoint))
+	  match = skippy_iter.SKIP;
+      }
+      if (match == skippy_iter.MATCH)
       {
       {
-        buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
-        return_trace (false);
+	c->last_base = (signed) j - 1;
+	break;
       }
       }
+    }
+    c->last_base_until = buffer->idx;
+    if (c->last_base == -1)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
+      return_trace (false);
+    }
 
 
-      /* We only want to attach to the first of a MultipleSubst sequence.
-       * https://github.com/harfbuzz/harfbuzz/issues/740
-       * Reject others...
-       * ...but stop if we find a mark in the MultipleSubst sequence:
-       * https://github.com/harfbuzz/harfbuzz/issues/1020 */
-      if (!_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx]) ||
-          0 == _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) ||
-          (skippy_iter.idx == 0 ||
-           _hb_glyph_info_is_mark (&buffer->info[skippy_iter.idx - 1]) ||
-           !_hb_glyph_info_multiplied (&buffer->info[skippy_iter.idx - 1]) ||
-           _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx]) !=
-           _hb_glyph_info_get_lig_id (&buffer->info[skippy_iter.idx - 1]) ||
-           _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx]) !=
-           _hb_glyph_info_get_lig_comp (&buffer->info[skippy_iter.idx - 1]) + 1
-           ))
-        break;
-      skippy_iter.reject ();
-    } while (true);
+    unsigned idx = (unsigned) c->last_base;
 
 
     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
     /* Checking that matched glyph is actually a base glyph by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+    //if (!_hb_glyph_info_is_base_glyph (&buffer->info[idx])) { return_trace (false); }
 
 
-    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[skippy_iter.idx].codepoint);
+    unsigned int base_index = (this+baseCoverage).get_coverage  (buffer->info[idx].codepoint);
     if (base_index == NOT_COVERED)
     if (base_index == NOT_COVERED)
     {
     {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
       return_trace (false);
       return_trace (false);
     }
     }
 
 
-    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, skippy_iter.idx));
+    return_trace ((this+markArray).apply (c, mark_index, base_index, this+baseArray, classCount, idx));
   }
   }
 
 
   bool subset (hb_subset_context_t *c) const
   bool subset (hb_subset_context_t *c) const

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPos.hh

@@ -22,8 +22,8 @@ struct MarkLigPos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 28 - 11
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkLigPosFormat1.hh

@@ -100,24 +100,41 @@ struct MarkLigPosFormat1_2
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
     if (likely (mark_index == NOT_COVERED)) return_trace (false);
 
 
     /* Now we search backwards for a non-mark glyph */
     /* Now we search backwards for a non-mark glyph */
+
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
     hb_ot_apply_context_t::skipping_iterator_t &skippy_iter = c->iter_input;
-    skippy_iter.reset (buffer->idx, 1);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
     skippy_iter.set_lookup_props (LookupFlag::IgnoreMarks);
-    unsigned unsafe_from;
-    if (!skippy_iter.prev (&unsafe_from))
+
+    if (c->last_base_until > buffer->idx)
     {
     {
-      buffer->unsafe_to_concat_from_outbuffer (unsafe_from, buffer->idx + 1);
+      c->last_base_until = 0;
+      c->last_base = -1;
+    }
+    unsigned j;
+    for (j = buffer->idx; j > c->last_base_until; j--)
+    {
+      auto match = skippy_iter.match (buffer->info[j - 1]);
+      if (match == skippy_iter.MATCH)
+      {
+	c->last_base = (signed) j - 1;
+	break;
+      }
+    }
+    c->last_base_until = buffer->idx;
+    if (c->last_base == -1)
+    {
+      buffer->unsafe_to_concat_from_outbuffer (0, buffer->idx + 1);
       return_trace (false);
       return_trace (false);
     }
     }
 
 
+    unsigned idx = (unsigned) c->last_base;
+
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
     /* Checking that matched glyph is actually a ligature by GDEF is too strong; disabled */
-    //if (!_hb_glyph_info_is_ligature (&buffer->info[skippy_iter.idx])) { return_trace (false); }
+    //if (!_hb_glyph_info_is_ligature (&buffer->info[idx])) { return_trace (false); }
 
 
-    unsigned int j = skippy_iter.idx;
-    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[j].codepoint);
+    unsigned int lig_index = (this+ligatureCoverage).get_coverage  (buffer->info[idx].codepoint);
     if (lig_index == NOT_COVERED)
     if (lig_index == NOT_COVERED)
     {
     {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
       return_trace (false);
       return_trace (false);
     }
     }
 
 
@@ -128,7 +145,7 @@ struct MarkLigPosFormat1_2
     unsigned int comp_count = lig_attach.rows;
     unsigned int comp_count = lig_attach.rows;
     if (unlikely (!comp_count))
     if (unlikely (!comp_count))
     {
     {
-      buffer->unsafe_to_concat_from_outbuffer (skippy_iter.idx, buffer->idx + 1);
+      buffer->unsafe_to_concat_from_outbuffer (idx, buffer->idx + 1);
       return_trace (false);
       return_trace (false);
     }
     }
 
 
@@ -137,7 +154,7 @@ struct MarkLigPosFormat1_2
      * can directly use the component index.  If not, we attach the mark
      * can directly use the component index.  If not, we attach the mark
      * glyph to the last component of the ligature. */
      * glyph to the last component of the ligature. */
     unsigned int comp_index;
     unsigned int comp_index;
-    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[j]);
+    unsigned int lig_id = _hb_glyph_info_get_lig_id (&buffer->info[idx]);
     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     unsigned int mark_id = _hb_glyph_info_get_lig_id (&buffer->cur());
     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     unsigned int mark_comp = _hb_glyph_info_get_lig_comp (&buffer->cur());
     if (lig_id && lig_id == mark_id && mark_comp > 0)
     if (lig_id && lig_id == mark_id && mark_comp > 0)
@@ -145,7 +162,7 @@ struct MarkLigPosFormat1_2
     else
     else
       comp_index = comp_count - 1;
       comp_index = comp_count - 1;
 
 
-    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, j));
+    return_trace ((this+markArray).apply (c, mark_index, comp_index, lig_attach, classCount, idx));
   }
   }
 
 
   bool subset (hb_subset_context_t *c) const
   bool subset (hb_subset_context_t *c) const

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/MarkMarkPos.hh

@@ -22,8 +22,8 @@ struct MarkMarkPos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPos.hh

@@ -25,8 +25,8 @@ struct PairPos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

+ 2 - 4
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat1.hh

@@ -43,7 +43,7 @@ struct PairPosFormat1_3
     {
     {
       valueFormat,
       valueFormat,
       len1,
       len1,
-      1 + len1 + len2
+      PairSet::get_size (len1, len2)
     };
     };
 
 
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
     return_trace (coverage.sanitize (c, this) && pairSet.sanitize (c, this, &closure));
@@ -177,9 +177,7 @@ struct PairPosFormat1_3
 
 
   hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
   hb_pair_t<unsigned, unsigned> compute_effective_value_formats (const hb_set_t& glyphset) const
   {
   {
-    unsigned len1 = valueFormat[0].get_len ();
-    unsigned len2 = valueFormat[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+    unsigned record_size = PairSet::get_size (valueFormat);
 
 
     unsigned format1 = 0;
     unsigned format1 = 0;
     unsigned format2 = 0;
     unsigned format2 = 0;

+ 6 - 6
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairPosFormat2.hh

@@ -49,7 +49,7 @@ struct PairPosFormat2_4
 
 
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len1 = valueFormat1.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
     unsigned int len2 = valueFormat2.get_len ();
-    unsigned int stride = len1 + len2;
+    unsigned int stride = HBUINT16::static_size * (len1 + len2);
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int record_size = valueFormat1.get_size () + valueFormat2.get_size ();
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
     unsigned int count = (unsigned int) class1Count * (unsigned int) class2Count;
     return_trace (c->check_range ((const void *) values,
     return_trace (c->check_range ((const void *) values,
@@ -220,7 +220,7 @@ struct PairPosFormat2_4
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "try kerning glyphs at %d,%d",
+			  "try kerning glyphs at %u,%u",
 			  c->buffer->idx, skippy_iter.idx);
 			  c->buffer->idx, skippy_iter.idx);
     }
     }
 
 
@@ -231,14 +231,14 @@ struct PairPosFormat2_4
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "kerned glyphs at %d,%d",
+			    "kerned glyphs at %u,%u",
 			    c->buffer->idx, skippy_iter.idx);
 			    c->buffer->idx, skippy_iter.idx);
       }
       }
 
 
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "tried kerning glyphs at %d,%d",
+			  "tried kerning glyphs at %u,%u",
 			  c->buffer->idx, skippy_iter.idx);
 			  c->buffer->idx, skippy_iter.idx);
     }
     }
 
 
@@ -298,8 +298,8 @@ struct PairPosFormat2_4
       for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
       for (unsigned class2_idx : + hb_range ((unsigned) class2Count) | hb_filter (klass2_map))
       {
       {
         unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
         unsigned idx = (class1_idx * (unsigned) class2Count + class2_idx) * (len1 + len2);
-        valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], c->plan->layout_variation_idx_delta_map);
-        valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], c->plan->layout_variation_idx_delta_map);
+        valueFormat1.copy_values (c->serializer, out->valueFormat1, this, &values[idx], &c->plan->layout_variation_idx_delta_map);
+        valueFormat2.copy_values (c->serializer, out->valueFormat2, this, &values[idx + len1], &c->plan->layout_variation_idx_delta_map);
       }
       }
     }
     }
 
 

+ 21 - 17
thirdparty/harfbuzz/src/OT/Layout/GPOS/PairSet.hh

@@ -24,11 +24,22 @@ struct PairSet
   public:
   public:
   DEFINE_SIZE_MIN (2);
   DEFINE_SIZE_MIN (2);
 
 
+  static unsigned get_size (unsigned len1, unsigned len2)
+  {
+    return Types::HBGlyphID::static_size + Value::static_size * (len1 + len2);
+  }
+  static unsigned get_size (const ValueFormat valueFormats[2])
+  {
+    unsigned len1 = valueFormats[0].get_len ();
+    unsigned len2 = valueFormats[1].get_len ();
+    return get_size (len1, len2);
+  }
+
   struct sanitize_closure_t
   struct sanitize_closure_t
   {
   {
     const ValueFormat *valueFormats;
     const ValueFormat *valueFormats;
     unsigned int len1; /* valueFormats[0].get_len() */
     unsigned int len1; /* valueFormats[0].get_len() */
-    unsigned int stride; /* 1 + len1 + len2 */
+    unsigned int stride; /* bytes */
   };
   };
 
 
   bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
   bool sanitize (hb_sanitize_context_t *c, const sanitize_closure_t *closure) const
@@ -37,7 +48,6 @@ struct PairSet
     if (!(c->check_struct (this)
     if (!(c->check_struct (this)
        && c->check_range (&firstPairValueRecord,
        && c->check_range (&firstPairValueRecord,
                           len,
                           len,
-                          HBUINT16::static_size,
                           closure->stride))) return_trace (false);
                           closure->stride))) return_trace (false);
 
 
     unsigned int count = len;
     unsigned int count = len;
@@ -49,9 +59,7 @@ struct PairSet
   bool intersects (const hb_set_t *glyphs,
   bool intersects (const hb_set_t *glyphs,
                    const ValueFormat *valueFormats) const
                    const ValueFormat *valueFormats) const
   {
   {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+    unsigned record_size = get_size (valueFormats);
 
 
     const PairValueRecord *record = &firstPairValueRecord;
     const PairValueRecord *record = &firstPairValueRecord;
     unsigned int count = len;
     unsigned int count = len;
@@ -67,9 +75,7 @@ struct PairSet
   void collect_glyphs (hb_collect_glyphs_context_t *c,
   void collect_glyphs (hb_collect_glyphs_context_t *c,
                        const ValueFormat *valueFormats) const
                        const ValueFormat *valueFormats) const
   {
   {
-    unsigned int len1 = valueFormats[0].get_len ();
-    unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+    unsigned record_size = get_size (valueFormats);
 
 
     const PairValueRecord *record = &firstPairValueRecord;
     const PairValueRecord *record = &firstPairValueRecord;
     c->input->add_array (&record->secondGlyph, len, record_size);
     c->input->add_array (&record->secondGlyph, len, record_size);
@@ -78,9 +84,7 @@ struct PairSet
   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
   void collect_variation_indices (hb_collect_variation_indices_context_t *c,
                                   const ValueFormat *valueFormats) const
                                   const ValueFormat *valueFormats) const
   {
   {
-    unsigned len1 = valueFormats[0].get_len ();
-    unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size * (1 + len1 + len2);
+    unsigned record_size = get_size (valueFormats);
 
 
     const PairValueRecord *record = &firstPairValueRecord;
     const PairValueRecord *record = &firstPairValueRecord;
     unsigned count = len;
     unsigned count = len;
@@ -101,7 +105,7 @@ struct PairSet
     hb_buffer_t *buffer = c->buffer;
     hb_buffer_t *buffer = c->buffer;
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len1 = valueFormats[0].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
     unsigned int len2 = valueFormats[1].get_len ();
-    unsigned int record_size = HBUINT16::static_size * (1 + len1 + len2);
+    unsigned record_size = get_size (len1, len2);
 
 
     const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
     const PairValueRecord *record = hb_bsearch (buffer->info[pos].codepoint,
                                                 &firstPairValueRecord,
                                                 &firstPairValueRecord,
@@ -112,7 +116,7 @@ struct PairSet
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "try kerning glyphs at %d,%d",
+			    "try kerning glyphs at %u,%u",
 			    c->buffer->idx, pos);
 			    c->buffer->idx, pos);
       }
       }
 
 
@@ -123,14 +127,14 @@ struct PairSet
 	if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
 	if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
 	{
 	{
 	  c->buffer->message (c->font,
 	  c->buffer->message (c->font,
-			      "kerned glyphs at %d,%d",
+			      "kerned glyphs at %u,%u",
 			      c->buffer->idx, pos);
 			      c->buffer->idx, pos);
 	}
 	}
 
 
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "tried kerning glyphs at %d,%d",
+			    "tried kerning glyphs at %u,%u",
 			    c->buffer->idx, pos);
 			    c->buffer->idx, pos);
       }
       }
 
 
@@ -168,7 +172,7 @@ struct PairSet
 
 
     unsigned len1 = valueFormats[0].get_len ();
     unsigned len1 = valueFormats[0].get_len ();
     unsigned len2 = valueFormats[1].get_len ();
     unsigned len2 = valueFormats[1].get_len ();
-    unsigned record_size = HBUINT16::static_size + Value::static_size * (len1 + len2);
+    unsigned record_size = get_size (len1, len2);
 
 
     typename PairValueRecord::context_t context =
     typename PairValueRecord::context_t context =
     {
     {
@@ -177,7 +181,7 @@ struct PairSet
       newFormats,
       newFormats,
       len1,
       len1,
       &glyph_map,
       &glyph_map,
-      c->plan->layout_variation_idx_delta_map
+      &c->plan->layout_variation_idx_delta_map
     };
     };
 
 
     const PairValueRecord *record = &firstPairValueRecord;
     const PairValueRecord *record = &firstPairValueRecord;

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePos.hh

@@ -72,8 +72,8 @@ struct SinglePos
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

+ 11 - 3
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat1.hh

@@ -28,7 +28,15 @@ struct SinglePosFormat1
     TRACE_SANITIZE (this);
     TRACE_SANITIZE (this);
     return_trace (c->check_struct (this) &&
     return_trace (c->check_struct (this) &&
                   coverage.sanitize (c, this) &&
                   coverage.sanitize (c, this) &&
+                  /* The coverage  table may use a range to represent a set
+                   * of glyphs, which means a small number of bytes can
+                   * generate a large glyph set. Manually modify the
+                   * sanitizer max ops to take this into account.
+                   *
+                   * Note: This check *must* be right after coverage sanitize. */
+                  c->check_ops ((this + coverage).get_population () >> 1) &&
                   valueFormat.sanitize_value (c, this, values));
                   valueFormat.sanitize_value (c, this, values));
+
   }
   }
 
 
   bool intersects (const hb_set_t *glyphs) const
   bool intersects (const hb_set_t *glyphs) const
@@ -63,7 +71,7 @@ struct SinglePosFormat1
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "positioning glyph at %d",
+			  "positioning glyph at %u",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -72,7 +80,7 @@ struct SinglePosFormat1
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "positioned glyph at %d",
+			  "positioned glyph at %u",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -144,7 +152,7 @@ struct SinglePosFormat1
     ;
     ;
 
 
     bool ret = bool (it);
     bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+    SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
     return_trace (ret);
     return_trace (ret);
   }
   }
 };
 };

+ 3 - 3
thirdparty/harfbuzz/src/OT/Layout/GPOS/SinglePosFormat2.hh

@@ -73,7 +73,7 @@ struct SinglePosFormat2
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "positioning glyph at %d",
+			  "positioning glyph at %u",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -84,7 +84,7 @@ struct SinglePosFormat2
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "positioned glyph at %d",
+			  "positioned glyph at %u",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -163,7 +163,7 @@ struct SinglePosFormat2
     ;
     ;
 
 
     bool ret = bool (it);
     bool ret = bool (it);
-    SinglePos_serialize (c->serializer, this, it, c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
+    SinglePos_serialize (c->serializer, this, it, &c->plan->layout_variation_idx_delta_map, c->plan->all_axes_pinned);
     return_trace (ret);
     return_trace (ret);
   }
   }
 };
 };

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GPOS/ValueFormat.hh

@@ -371,7 +371,7 @@ struct ValueFormat : HBUINT16
     for (unsigned int i = 0; i < count; i++) {
     for (unsigned int i = 0; i < count; i++) {
       if (!sanitize_value_devices (c, base, values))
       if (!sanitize_value_devices (c, base, values))
         return_trace (false);
         return_trace (false);
-      values += stride;
+      values = &StructAtOffset<const Value> (values, stride);
     }
     }
 
 
     return_trace (true);
     return_trace (true);

+ 3 - 3
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSet.hh

@@ -61,7 +61,7 @@ struct AlternateSet
     {
     {
       c->buffer->sync_so_far ();
       c->buffer->sync_so_far ();
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replacing glyph at %d (alternate substitution)",
+			  "replacing glyph at %u (alternate substitution)",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -70,8 +70,8 @@ struct AlternateSet
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replaced glyph at %d (alternate substitution)",
-			  c->buffer->idx - 1);
+			  "replaced glyph at %u (alternate substitution)",
+			  c->buffer->idx - 1u);
     }
     }
 
 
     return_trace (true);
     return_trace (true);

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/AlternateSubst.hh

@@ -23,8 +23,8 @@ struct AlternateSubst
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 4 - 4
thirdparty/harfbuzz/src/OT/Layout/GSUB/Ligature.hh

@@ -69,7 +69,7 @@ struct Ligature
       {
       {
 	c->buffer->sync_so_far ();
 	c->buffer->sync_so_far ();
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replacing glyph at %d (ligature substitution)",
+			    "replacing glyph at %u (ligature substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 
@@ -78,8 +78,8 @@ struct Ligature
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replaced glyph at %d (ligature substitution)",
-			    c->buffer->idx - 1);
+			    "replaced glyph at %u (ligature substitution)",
+			    c->buffer->idx - 1u);
       }
       }
 
 
       return_trace (true);
       return_trace (true);
@@ -138,7 +138,7 @@ struct Ligature
     {
     {
       c->buffer->sync_so_far ();
       c->buffer->sync_so_far ();
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "ligated glyph at %d",
+			  "ligated glyph at %u",
 			  pos);
 			  pos);
     }
     }
 
 

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/LigatureSubst.hh

@@ -23,8 +23,8 @@ struct LigatureSubst
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/MultipleSubst.hh

@@ -24,8 +24,8 @@ struct MultipleSubst
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
 #ifndef HB_NO_BEYOND_64K
 #ifndef HB_NO_BEYOND_64K

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubst.hh

@@ -20,8 +20,8 @@ struct ReverseChainSingleSubst
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     default:return_trace (c->default_return_value ());
     default:return_trace (c->default_return_value ());

+ 2 - 2
thirdparty/harfbuzz/src/OT/Layout/GSUB/ReverseChainSingleSubstFormat1.hh

@@ -135,7 +135,7 @@ struct ReverseChainSingleSubstFormat1
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replacing glyph at %d (reverse chaining substitution)",
+			    "replacing glyph at %u (reverse chaining substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 
@@ -144,7 +144,7 @@ struct ReverseChainSingleSubstFormat1
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replaced glyph at %d (reverse chaining substitution)",
+			    "replaced glyph at %u (reverse chaining substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 

+ 6 - 6
thirdparty/harfbuzz/src/OT/Layout/GSUB/Sequence.hh

@@ -44,7 +44,7 @@ struct Sequence
       {
       {
 	c->buffer->sync_so_far ();
 	c->buffer->sync_so_far ();
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replacing glyph at %d (multiple substitution)",
+			    "replacing glyph at %u (multiple substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 
@@ -53,8 +53,8 @@ struct Sequence
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
       {
       {
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "replaced glyph at %d (multiple subtitution)",
-			    c->buffer->idx - 1);
+			    "replaced glyph at %u (multiple subtitution)",
+			    c->buffer->idx - 1u);
       }
       }
 
 
       return_trace (true);
       return_trace (true);
@@ -67,7 +67,7 @@ struct Sequence
       {
       {
 	c->buffer->sync_so_far ();
 	c->buffer->sync_so_far ();
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "deleting glyph at %d (multiple substitution)",
+			    "deleting glyph at %u (multiple substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 
@@ -77,7 +77,7 @@ struct Sequence
       {
       {
 	c->buffer->sync_so_far ();
 	c->buffer->sync_so_far ();
 	c->buffer->message (c->font,
 	c->buffer->message (c->font,
-			    "deleted glyph at %d (multiple substitution)",
+			    "deleted glyph at %u (multiple substitution)",
 			    c->buffer->idx);
 			    c->buffer->idx);
       }
       }
 
 
@@ -88,7 +88,7 @@ struct Sequence
     {
     {
       c->buffer->sync_so_far ();
       c->buffer->sync_so_far ();
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "multiplying glyph at %d",
+			  "multiplying glyph at %u",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 

+ 1 - 1
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubst.hh

@@ -27,8 +27,8 @@ struct SingleSubst
   template <typename context_t, typename ...Ts>
   template <typename context_t, typename ...Ts>
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
   {
   {
+    if (unlikely (!c->may_dispatch (this, &u.format))) return c->no_dispatch_return_value ();
     TRACE_DISPATCH (this, u.format);
     TRACE_DISPATCH (this, u.format);
-    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
     switch (u.format) {
     switch (u.format) {
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 1: return_trace (c->dispatch (u.format1, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));
     case 2: return_trace (c->dispatch (u.format2, std::forward<Ts> (ds)...));

+ 12 - 4
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat1.hh

@@ -25,7 +25,15 @@ struct SingleSubstFormat1_3
   bool sanitize (hb_sanitize_context_t *c) const
   bool sanitize (hb_sanitize_context_t *c) const
   {
   {
     TRACE_SANITIZE (this);
     TRACE_SANITIZE (this);
-    return_trace (coverage.sanitize (c, this) && deltaGlyphID.sanitize (c));
+    return_trace (c->check_struct (this) &&
+                  coverage.sanitize (c, this) &&
+                  /* The coverage  table may use a range to represent a set
+                   * of glyphs, which means a small number of bytes can
+                   * generate a large glyph set. Manually modify the
+                   * sanitizer max ops to take this into account.
+                   *
+                   * Note: This check *must* be right after coverage sanitize. */
+                  c->check_ops ((this + coverage).get_population () >> 1));
   }
   }
 
 
   hb_codepoint_t get_mask () const
   hb_codepoint_t get_mask () const
@@ -103,7 +111,7 @@ struct SingleSubstFormat1_3
     {
     {
       c->buffer->sync_so_far ();
       c->buffer->sync_so_far ();
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replacing glyph at %d (single substitution)",
+			  "replacing glyph at %u (single substitution)",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -112,8 +120,8 @@ struct SingleSubstFormat1_3
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replaced glyph at %d (single substitution)",
-			  c->buffer->idx - 1);
+			  "replaced glyph at %u (single substitution)",
+			  c->buffer->idx - 1u);
     }
     }
 
 
     return_trace (true);
     return_trace (true);

+ 3 - 3
thirdparty/harfbuzz/src/OT/Layout/GSUB/SingleSubstFormat2.hh

@@ -87,7 +87,7 @@ struct SingleSubstFormat2_4
     {
     {
       c->buffer->sync_so_far ();
       c->buffer->sync_so_far ();
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replacing glyph at %d (single substitution)",
+			  "replacing glyph at %u (single substitution)",
 			  c->buffer->idx);
 			  c->buffer->idx);
     }
     }
 
 
@@ -96,8 +96,8 @@ struct SingleSubstFormat2_4
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     if (HB_BUFFER_MESSAGE_MORE && c->buffer->messaging ())
     {
     {
       c->buffer->message (c->font,
       c->buffer->message (c->font,
-			  "replaced glyph at %d (single substitution)",
-			  c->buffer->idx - 1);
+			  "replaced glyph at %u (single substitution)",
+			  c->buffer->idx - 1u);
     }
     }
 
 
     return_trace (true);
     return_trace (true);

+ 116 - 42
thirdparty/harfbuzz/src/OT/glyf/Glyph.hh

@@ -18,11 +18,6 @@ struct glyf_accelerator_t;
 namespace glyf_impl {
 namespace glyf_impl {
 
 
 
 
-#ifndef HB_GLYF_MAX_POINTS
-#define HB_GLYF_MAX_POINTS 10000
-#endif
-
-
 enum phantom_point_index_t
 enum phantom_point_index_t
 {
 {
   PHANTOM_LEFT   = 0,
   PHANTOM_LEFT   = 0,
@@ -85,28 +80,38 @@ struct Glyph
   }
   }
 
 
   void update_mtx (const hb_subset_plan_t *plan,
   void update_mtx (const hb_subset_plan_t *plan,
-                   int xMin, int yMax,
+                   int xMin, int xMax,
+                   int yMin, int yMax,
                    const contour_point_vector_t &all_points) const
                    const contour_point_vector_t &all_points) const
   {
   {
     hb_codepoint_t new_gid = 0;
     hb_codepoint_t new_gid = 0;
     if (!plan->new_gid_for_old_gid (gid, &new_gid))
     if (!plan->new_gid_for_old_gid (gid, &new_gid))
       return;
       return;
 
 
+    if (type != EMPTY)
+    {
+      plan->bounds_width_map.set (new_gid, xMax - xMin);
+      plan->bounds_height_map.set (new_gid, yMax - yMin);
+    }
+
     unsigned len = all_points.length;
     unsigned len = all_points.length;
     float leftSideX = all_points[len - 4].x;
     float leftSideX = all_points[len - 4].x;
     float rightSideX = all_points[len - 3].x;
     float rightSideX = all_points[len - 3].x;
     float topSideY = all_points[len - 2].y;
     float topSideY = all_points[len - 2].y;
     float bottomSideY = all_points[len - 1].y;
     float bottomSideY = all_points[len - 1].y;
 
 
-    int hori_aw = roundf (rightSideX - leftSideX);
+    signed hori_aw = roundf (rightSideX - leftSideX);
     if (hori_aw < 0) hori_aw = 0;
     if (hori_aw < 0) hori_aw = 0;
     int lsb = roundf (xMin - leftSideX);
     int lsb = roundf (xMin - leftSideX);
-    plan->hmtx_map->set (new_gid, hb_pair (hori_aw, lsb));
+    plan->hmtx_map.set (new_gid, hb_pair ((unsigned) hori_aw, lsb));
+    //flag value should be computed using non-empty glyphs
+    if (type != EMPTY && lsb != xMin)
+      plan->head_maxp_info.allXMinIsLsb = false;
 
 
-    int vert_aw = roundf (topSideY - bottomSideY);
+    signed vert_aw = roundf (topSideY - bottomSideY);
     if (vert_aw < 0) vert_aw = 0;
     if (vert_aw < 0) vert_aw = 0;
     int tsb = roundf (topSideY - yMax);
     int tsb = roundf (topSideY - yMax);
-    plan->vmtx_map->set (new_gid, hb_pair (vert_aw, tsb));
+    plan->vmtx_map.set (new_gid, hb_pair ((unsigned) vert_aw, tsb));
   }
   }
 
 
   bool compile_header_bytes (const hb_subset_plan_t *plan,
   bool compile_header_bytes (const hb_subset_plan_t *plan,
@@ -114,7 +119,7 @@ struct Glyph
                              hb_bytes_t &dest_bytes /* OUT */) const
                              hb_bytes_t &dest_bytes /* OUT */) const
   {
   {
     GlyphHeader *glyph_header = nullptr;
     GlyphHeader *glyph_header = nullptr;
-    if (type != EMPTY && all_points.length > 4)
+    if (!plan->pinned_at_default && type != EMPTY && all_points.length >= 4)
     {
     {
       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
       glyph_header = (GlyphHeader *) hb_calloc (1, GlyphHeader::static_size);
       if (unlikely (!glyph_header)) return false;
       if (unlikely (!glyph_header)) return false;
@@ -138,18 +143,33 @@ struct Glyph
       yMax = hb_max (yMax, y);
       yMax = hb_max (yMax, y);
     }
     }
 
 
-    update_mtx (plan, roundf (xMin), roundf (yMax), all_points);
+    update_mtx (plan, roundf (xMin), roundf (xMax), roundf (yMin), roundf (yMax), all_points);
+ 
+    int rounded_xMin = roundf (xMin);
+    int rounded_xMax = roundf (xMax);
+    int rounded_yMin = roundf (yMin);
+    int rounded_yMax = roundf (yMax);
+
+    if (type != EMPTY)
+    {
+      plan->head_maxp_info.xMin = hb_min (plan->head_maxp_info.xMin, rounded_xMin);
+      plan->head_maxp_info.yMin = hb_min (plan->head_maxp_info.yMin, rounded_yMin);
+      plan->head_maxp_info.xMax = hb_max (plan->head_maxp_info.xMax, rounded_xMax);
+      plan->head_maxp_info.yMax = hb_max (plan->head_maxp_info.yMax, rounded_yMax);
+    }
 
 
-    /*for empty glyphs: all_points only include phantom points.
-     *just update metrics and then return */
+    /* when pinned at default, no need to compile glyph header
+     * and for empty glyphs: all_points only include phantom points.
+     * just update metrics and then return */
     if (!glyph_header)
     if (!glyph_header)
       return true;
       return true;
 
 
     glyph_header->numberOfContours = header->numberOfContours;
     glyph_header->numberOfContours = header->numberOfContours;
-    glyph_header->xMin = roundf (xMin);
-    glyph_header->yMin = roundf (yMin);
-    glyph_header->xMax = roundf (xMax);
-    glyph_header->yMax = roundf (yMax);
+
+    glyph_header->xMin = rounded_xMin;
+    glyph_header->yMin = rounded_yMin;
+    glyph_header->xMax = rounded_xMax;
+    glyph_header->yMax = rounded_yMax;
 
 
     dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
     dest_bytes = hb_bytes_t ((const char *)glyph_header, GlyphHeader::static_size);
     return true;
     return true;
@@ -162,34 +182,54 @@ struct Glyph
                                   hb_bytes_t &dest_end /* OUT */)
                                   hb_bytes_t &dest_end /* OUT */)
   {
   {
     contour_point_vector_t all_points, deltas;
     contour_point_vector_t all_points, deltas;
-    if (!get_points (font, glyf, all_points, &deltas, false, false))
+    unsigned composite_contours = 0;
+    head_maxp_info_t *head_maxp_info_p = &plan->head_maxp_info;
+    unsigned *composite_contours_p = &composite_contours;
+
+    // don't compute head/maxp values when glyph has no contours(type is EMPTY)
+    // also ignore .notdef glyph when --notdef-outline is not enabled
+    if (type == EMPTY ||
+        (gid == 0 && !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)))
+    {
+      head_maxp_info_p = nullptr;
+      composite_contours_p = nullptr;
+    }
+
+    if (!get_points (font, glyf, all_points, &deltas, head_maxp_info_p, composite_contours_p, false, false))
       return false;
       return false;
 
 
     // .notdef, set type to empty so we only update metrics and don't compile bytes for
     // .notdef, set type to empty so we only update metrics and don't compile bytes for
     // it
     // it
     if (gid == 0 &&
     if (gid == 0 &&
         !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
         !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+    {
       type = EMPTY;
       type = EMPTY;
-
-    switch (type) {
-    case COMPOSITE:
-      if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
-                                                                      deltas,
-                                                                      dest_end))
-        return false;
-      break;
-    case SIMPLE:
-      if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
-                                                                   plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
-                                                                   dest_end))
-        return false;
-      break;
-    default:
-      /* set empty bytes for empty glyph
-       * do not use source glyph's pointers */
       dest_start = hb_bytes_t ();
       dest_start = hb_bytes_t ();
       dest_end = hb_bytes_t ();
       dest_end = hb_bytes_t ();
-      break;
+    }
+
+    //dont compile bytes when pinned at default, just recalculate bounds
+    if (!plan->pinned_at_default) {
+      switch (type) {
+      case COMPOSITE:
+        if (!CompositeGlyph (*header, bytes).compile_bytes_with_deltas (dest_start,
+                                                                        deltas,
+                                                                        dest_end))
+          return false;
+        break;
+      case SIMPLE:
+        if (!SimpleGlyph (*header, bytes).compile_bytes_with_deltas (all_points,
+                                                                     plan->flags & HB_SUBSET_FLAGS_NO_HINTING,
+                                                                     dest_end))
+          return false;
+        break;
+      default:
+        /* set empty bytes for empty glyph
+         * do not use source glyph's pointers */
+        dest_start = hb_bytes_t ();
+        dest_end = hb_bytes_t ();
+        break;
+      }
     }
     }
 
 
     if (!compile_header_bytes (plan, all_points, dest_start))
     if (!compile_header_bytes (plan, all_points, dest_start))
@@ -208,13 +248,25 @@ struct Glyph
   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
   bool get_points (hb_font_t *font, const accelerator_t &glyf_accelerator,
 		   contour_point_vector_t &all_points /* OUT */,
 		   contour_point_vector_t &all_points /* OUT */,
 		   contour_point_vector_t *deltas = nullptr, /* OUT */
 		   contour_point_vector_t *deltas = nullptr, /* OUT */
+		   head_maxp_info_t * head_maxp_info = nullptr, /* OUT */
+		   unsigned *composite_contours = nullptr, /* OUT */
 		   bool shift_points_hori = true,
 		   bool shift_points_hori = true,
 		   bool use_my_metrics = true,
 		   bool use_my_metrics = true,
 		   bool phantom_only = false,
 		   bool phantom_only = false,
 		   hb_array_t<int> coords = hb_array_t<int> (),
 		   hb_array_t<int> coords = hb_array_t<int> (),
-		   unsigned int depth = 0) const
+		   unsigned int depth = 0,
+		   unsigned *edge_count = nullptr) const
   {
   {
     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
     if (unlikely (depth > HB_MAX_NESTING_LEVEL)) return false;
+    unsigned stack_edge_count = 0;
+    if (!edge_count) edge_count = &stack_edge_count;
+    if (unlikely (*edge_count > HB_GLYF_MAX_EDGE_COUNT)) return false;
+    (*edge_count)++;
+    
+    if (head_maxp_info)
+    {
+      head_maxp_info->maxComponentDepth = hb_max (head_maxp_info->maxComponentDepth, depth);
+    }
 
 
     if (!coords)
     if (!coords)
       coords = hb_array (font->coords, font->num_coords);
       coords = hb_array (font->coords, font->num_coords);
@@ -226,6 +278,10 @@ struct Glyph
 
 
     switch (type) {
     switch (type) {
     case SIMPLE:
     case SIMPLE:
+      if (depth == 0 && head_maxp_info)
+        head_maxp_info->maxContours = hb_max (head_maxp_info->maxContours, (unsigned) header->numberOfContours);
+      if (depth > 0 && composite_contours)
+        *composite_contours += (unsigned) header->numberOfContours;
       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
       if (unlikely (!SimpleGlyph (*header, bytes).get_contour_points (points, phantom_only)))
 	return false;
 	return false;
       break;
       break;
@@ -301,6 +357,8 @@ struct Glyph
 
 
     switch (type) {
     switch (type) {
     case SIMPLE:
     case SIMPLE:
+      if (depth == 0 && head_maxp_info)
+        head_maxp_info->maxPoints = hb_max (head_maxp_info->maxPoints, points.length - 4);
       if (!inplace)
       if (!inplace)
 	all_points.extend (points.as_array ());
 	all_points.extend (points.as_array ());
       break;
       break;
@@ -311,17 +369,19 @@ struct Glyph
       for (auto &item : get_composite_iterator ())
       for (auto &item : get_composite_iterator ())
       {
       {
         comp_points.reset ();
         comp_points.reset ();
-
 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 				       .get_points (font,
 				       .get_points (font,
 						    glyf_accelerator,
 						    glyf_accelerator,
 						    comp_points,
 						    comp_points,
 						    deltas,
 						    deltas,
+						    head_maxp_info,
+						    composite_contours,
 						    shift_points_hori,
 						    shift_points_hori,
 						    use_my_metrics,
 						    use_my_metrics,
 						    phantom_only,
 						    phantom_only,
 						    coords,
 						    coords,
-						    depth + 1)))
+						    depth + 1,
+						    edge_count)))
 	  return false;
 	  return false;
 
 
 	/* Copy phantom points from component if USE_MY_METRICS flag set */
 	/* Copy phantom points from component if USE_MY_METRICS flag set */
@@ -357,6 +417,13 @@ struct Glyph
 	comp_index++;
 	comp_index++;
       }
       }
 
 
+      if (head_maxp_info && depth == 0)
+      {
+        if (composite_contours)
+          head_maxp_info->maxCompositeContours = hb_max (head_maxp_info->maxCompositeContours, *composite_contours);
+        head_maxp_info->maxCompositePoints = hb_max (head_maxp_info->maxCompositePoints, all_points.length);
+        head_maxp_info->maxComponentElements = hb_max (head_maxp_info->maxComponentElements, comp_index);
+      }
       all_points.extend (phantoms);
       all_points.extend (phantoms);
     } break;
     } break;
 #ifndef HB_NO_VAR_COMPOSITES
 #ifndef HB_NO_VAR_COMPOSITES
@@ -370,7 +437,11 @@ struct Glyph
 
 
         comp_points.reset ();
         comp_points.reset ();
 
 
-	coord_setter_t coord_setter (coords);
+	auto component_coords = coords;
+	if (item.is_reset_unspecified_axes ())
+	  component_coords = hb_array<int> ();
+
+	coord_setter_t coord_setter (component_coords);
 	item.set_variations (coord_setter, record_points);
 	item.set_variations (coord_setter, record_points);
 
 
 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
 	if (unlikely (!glyf_accelerator.glyph_for_gid (item.get_gid ())
@@ -378,11 +449,14 @@ struct Glyph
 						    glyf_accelerator,
 						    glyf_accelerator,
 						    comp_points,
 						    comp_points,
 						    deltas,
 						    deltas,
+						    head_maxp_info,
+						    nullptr,
 						    shift_points_hori,
 						    shift_points_hori,
 						    use_my_metrics,
 						    use_my_metrics,
 						    phantom_only,
 						    phantom_only,
 						    coord_setter.get_coords (),
 						    coord_setter.get_coords (),
-						    depth + 1)))
+						    depth + 1,
+						    edge_count)))
 	  return false;
 	  return false;
 
 
 	/* Apply component transformation */
 	/* Apply component transformation */

+ 6 - 4
thirdparty/harfbuzz/src/OT/glyf/GlyphHeader.hh

@@ -21,10 +21,12 @@ struct GlyphHeader
     /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
     /* extents->x_bearing = hb_min (glyph_header.xMin, glyph_header.xMax); */
     int lsb = hb_min (xMin, xMax);
     int lsb = hb_min (xMin, xMax);
     (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
     (void) glyf_accelerator.hmtx->get_leading_bearing_without_var_unscaled (gid, &lsb);
-    extents->x_bearing = font->em_scale_x (lsb);
-    extents->y_bearing = font->em_scale_y (hb_max (yMin, yMax));
-    extents->width     = font->em_scale_x (hb_max (xMin, xMax) - hb_min (xMin, xMax));
-    extents->height    = font->em_scale_y (hb_min (yMin, yMax) - hb_max (yMin, yMax));
+    extents->x_bearing = lsb;
+    extents->y_bearing = hb_max (yMin, yMax);
+    extents->width     = hb_max (xMin, xMax) - hb_min (xMin, xMax);
+    extents->height    = hb_min (yMin, yMax) - hb_max (yMin, yMax);
+
+    font->scale_glyph_extents (extents);
 
 
     return true;
     return true;
   }
   }

+ 5 - 5
thirdparty/harfbuzz/src/OT/glyf/SimpleGlyph.hh

@@ -20,7 +20,7 @@ struct SimpleGlyph
     FLAG_X_SAME         = 0x10,
     FLAG_X_SAME         = 0x10,
     FLAG_Y_SAME         = 0x20,
     FLAG_Y_SAME         = 0x20,
     FLAG_OVERLAP_SIMPLE = 0x40,
     FLAG_OVERLAP_SIMPLE = 0x40,
-    FLAG_RESERVED2      = 0x80
+    FLAG_CUBIC          = 0x80
   };
   };
 
 
   const GlyphHeader &header;
   const GlyphHeader &header;
@@ -184,7 +184,7 @@ struct SimpleGlyph
     if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
     if (unlikely (!bytes.check_range (&endPtsOfContours[num_contours]))) return false;
     unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
     unsigned int num_points = endPtsOfContours[num_contours - 1] + 1;
 
 
-    points_.alloc (num_points + 4); // Allocate for phantom points, to avoid a possible copy
+    points_.alloc (num_points + 4, true); // Allocate for phantom points, to avoid a possible copy
     if (!points_.resize (num_points)) return false;
     if (!points_.resize (num_points)) return false;
     if (phantom_only) return true;
     if (phantom_only) return true;
 
 
@@ -272,9 +272,9 @@ struct SimpleGlyph
     unsigned num_points = all_points.length - 4;
     unsigned num_points = all_points.length - 4;
 
 
     hb_vector_t<uint8_t> flags, x_coords, y_coords;
     hb_vector_t<uint8_t> flags, x_coords, y_coords;
-    if (unlikely (!flags.alloc (num_points))) return false;
-    if (unlikely (!x_coords.alloc (2*num_points))) return false;
-    if (unlikely (!y_coords.alloc (2*num_points))) return false;
+    if (unlikely (!flags.alloc (num_points, true))) return false;
+    if (unlikely (!x_coords.alloc (2*num_points, true))) return false;
+    if (unlikely (!y_coords.alloc (2*num_points, true))) return false;
 
 
     uint8_t lastflag = 255, repeat = 0;
     uint8_t lastflag = 255, repeat = 0;
     int prev_x = 0, prev_y = 0;
     int prev_x = 0, prev_y = 0;

+ 2 - 10
thirdparty/harfbuzz/src/OT/glyf/SubsetGlyph.hh

@@ -21,22 +21,14 @@ struct SubsetGlyph
 
 
   bool serialize (hb_serialize_context_t *c,
   bool serialize (hb_serialize_context_t *c,
 		  bool use_short_loca,
 		  bool use_short_loca,
-		  const hb_subset_plan_t *plan,
-		  hb_font_t *font)
+		  const hb_subset_plan_t *plan)
   {
   {
     TRACE_SERIALIZE (this);
     TRACE_SERIALIZE (this);
 
 
-    if (font)
-    {
-      const OT::glyf_accelerator_t &glyf = *font->face->table.glyf;
-      if (!this->compile_bytes_with_deltas (plan, font, glyf))
-        return_trace (false);
-    }
-
     hb_bytes_t dest_glyph = dest_start.copy (c);
     hb_bytes_t dest_glyph = dest_start.copy (c);
     dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
     dest_glyph = hb_bytes_t (&dest_glyph, dest_glyph.length + dest_end.copy (c).length);
     unsigned int pad_length = use_short_loca ? padding () : 0;
     unsigned int pad_length = use_short_loca ? padding () : 0;
-    DEBUG_MSG (SUBSET, nullptr, "serialize %d byte glyph, width %d pad %d", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
+    DEBUG_MSG (SUBSET, nullptr, "serialize %u byte glyph, width %u pad %u", dest_glyph.length, dest_glyph.length + pad_length, pad_length);
 
 
     HBUINT8 pad;
     HBUINT8 pad;
     pad = 0;
     pad = 0;

+ 16 - 15
thirdparty/harfbuzz/src/OT/glyf/VarCompositeGlyph.hh

@@ -29,6 +29,7 @@ struct VarCompositeGlyphRecord
     HAVE_TCENTER_Y		= 0x0800,
     HAVE_TCENTER_Y		= 0x0800,
     GID_IS_24			= 0x1000,
     GID_IS_24			= 0x1000,
     AXES_HAVE_VARIATION		= 0x2000,
     AXES_HAVE_VARIATION		= 0x2000,
+    RESET_UNSPECIFIED_AXES	= 0x4000,
   };
   };
 
 
   public:
   public:
@@ -60,6 +61,7 @@ struct VarCompositeGlyphRecord
   bool has_more () const { return true; }
   bool has_more () const { return true; }
 
 
   bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
   bool is_use_my_metrics () const { return flags & USE_MY_METRICS; }
+  bool is_reset_unspecified_axes () const { return flags & RESET_UNSPECIFIED_AXES; }
 
 
   hb_codepoint_t get_gid () const
   hb_codepoint_t get_gid () const
   {
   {
@@ -165,8 +167,8 @@ struct VarCompositeGlyphRecord
     float translateX = 0.f;
     float translateX = 0.f;
     float translateY = 0.f;
     float translateY = 0.f;
     float rotation = 0.f;
     float rotation = 0.f;
-    float scaleX = 1.f * (1 << 12);
-    float scaleY = 1.f * (1 << 12);
+    float scaleX = 1.f * (1 << 10);
+    float scaleY = 1.f * (1 << 10);
     float skewX = 0.f;
     float skewX = 0.f;
     float skewY = 0.f;
     float skewY = 0.f;
     float tCenterX = 0.f;
     float tCenterX = 0.f;
@@ -187,7 +189,7 @@ struct VarCompositeGlyphRecord
     if (flags & AXES_HAVE_VARIATION)
     if (flags & AXES_HAVE_VARIATION)
     {
     {
       for (unsigned i = 0; i < count; i++)
       for (unsigned i = 0; i < count; i++)
-	rec_points[i].x = *q++;
+	rec_points[i].x = q++->to_int ();
       rec_points += count;
       rec_points += count;
     }
     }
     else
     else
@@ -197,11 +199,11 @@ struct VarCompositeGlyphRecord
 
 
     if (flags & HAVE_TRANSLATE_X)	translateX = * (const FWORD *) p++;
     if (flags & HAVE_TRANSLATE_X)	translateX = * (const FWORD *) p++;
     if (flags & HAVE_TRANSLATE_Y)	translateY = * (const FWORD *) p++;
     if (flags & HAVE_TRANSLATE_Y)	translateY = * (const FWORD *) p++;
-    if (flags & HAVE_ROTATION)		rotation = * (const F2DOT14 *) p++;
-    if (flags & HAVE_SCALE_X)		scaleX = * (const F4DOT12 *) p++;
-    if (flags & HAVE_SCALE_Y)		scaleY = * (const F4DOT12 *) p++;
-    if (flags & HAVE_SKEW_X)		skewX = * (const F2DOT14 *) p++;
-    if (flags & HAVE_SKEW_Y)		skewY = * (const F2DOT14 *) p++;
+    if (flags & HAVE_ROTATION)		rotation = ((const F4DOT12 *) p++)->to_int ();
+    if (flags & HAVE_SCALE_X)		scaleX = ((const F6DOT10 *) p++)->to_int ();
+    if (flags & HAVE_SCALE_Y)		scaleY = ((const F6DOT10 *) p++)->to_int ();
+    if (flags & HAVE_SKEW_X)		skewX = ((const F4DOT12 *) p++)->to_int ();
+    if (flags & HAVE_SKEW_Y)		skewY = ((const F4DOT12 *) p++)->to_int ();
     if (flags & HAVE_TCENTER_X)		tCenterX = * (const FWORD *) p++;
     if (flags & HAVE_TCENTER_X)		tCenterX = * (const FWORD *) p++;
     if (flags & HAVE_TCENTER_Y)		tCenterY = * (const FWORD *) p++;
     if (flags & HAVE_TCENTER_Y)		tCenterY = * (const FWORD *) p++;
 
 
@@ -270,19 +272,19 @@ struct VarCompositeGlyphRecord
     }
     }
     if (flags & HAVE_ROTATION)
     if (flags & HAVE_ROTATION)
     {
     {
-      rotation = rec_points[0].x / (1 << 14);
+      rotation = rec_points[0].x / (1 << 12);
       rec_points++;
       rec_points++;
     }
     }
     if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
     if (flags & (HAVE_SCALE_X | HAVE_SCALE_Y))
     {
     {
-      scaleX = rec_points[0].x / (1 << 12);
-      scaleY = rec_points[0].y / (1 << 12);
+      scaleX = rec_points[0].x / (1 << 10);
+      scaleY = rec_points[0].y / (1 << 10);
       rec_points++;
       rec_points++;
     }
     }
     if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
     if (flags & (HAVE_SKEW_X | HAVE_SKEW_Y))
     {
     {
-      skewX = rec_points[0].x / (1 << 14);
-      skewY = rec_points[0].y / (1 << 14);
+      skewX = rec_points[0].x / (1 << 12);
+      skewY = rec_points[0].y / (1 << 12);
       rec_points++;
       rec_points++;
     }
     }
     if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
     if (flags & (HAVE_TCENTER_X | HAVE_TCENTER_Y))
@@ -316,9 +318,8 @@ struct VarCompositeGlyphRecord
     {
     {
       unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
       unsigned axis_index = axis_width == 1 ? (unsigned) *p++ : (unsigned) *q++;
 
 
-      signed v = have_variations ? rec_points[i].x : *a++;
+      signed v = have_variations ? rec_points[i].x : a++->to_int ();
 
 
-      v += setter[axis_index];
       v = hb_clamp (v, -(1<<14), (1<<14));
       v = hb_clamp (v, -(1<<14), (1<<14));
       setter[axis_index] = v;
       setter[axis_index] = v;
     }
     }

+ 16 - 2
thirdparty/harfbuzz/src/OT/glyf/glyf-helpers.hh

@@ -25,7 +25,7 @@ _write_loca (IteratorIn&& it, bool short_offsets, IteratorOut&& dest)
   | hb_map ([=, &offset] (unsigned int padded_size)
   | hb_map ([=, &offset] (unsigned int padded_size)
 	    {
 	    {
 	      offset += padded_size;
 	      offset += padded_size;
-	      DEBUG_MSG (SUBSET, nullptr, "loca entry offset %d", offset);
+	      DEBUG_MSG (SUBSET, nullptr, "loca entry offset %u", offset);
 	      return offset >> right_shift;
 	      return offset >> right_shift;
 	    })
 	    })
   | hb_sink (dest)
   | hb_sink (dest)
@@ -44,6 +44,20 @@ _add_head_and_set_loca_version (hb_subset_plan_t *plan, bool use_short_loca)
 
 
   head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
   head *head_prime = (head *) hb_blob_get_data_writable (head_prime_blob, nullptr);
   head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
   head_prime->indexToLocFormat = use_short_loca ? 0 : 1;
+  if (plan->normalized_coords)
+  {
+    head_prime->xMin = plan->head_maxp_info.xMin;
+    head_prime->xMax = plan->head_maxp_info.xMax;
+    head_prime->yMin = plan->head_maxp_info.yMin;
+    head_prime->yMax = plan->head_maxp_info.yMax;
+
+    unsigned orig_flag = head_prime->flags;
+    if (plan->head_maxp_info.allXMinIsLsb)
+      orig_flag |= 1 << 1;
+    else
+      orig_flag &= ~(1 << 1);
+    head_prime->flags = orig_flag;
+  }
   bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
   bool success = plan->add_table (HB_OT_TAG_head, head_prime_blob);
 
 
   hb_blob_destroy (head_prime_blob);
   hb_blob_destroy (head_prime_blob);
@@ -61,7 +75,7 @@ _add_loca_and_head (hb_subset_plan_t * plan, Iterator padded_offsets, bool use_s
 
 
   if (unlikely (!loca_prime_data)) return false;
   if (unlikely (!loca_prime_data)) return false;
 
 
-  DEBUG_MSG (SUBSET, nullptr, "loca entry_size %d num_offsets %d size %d",
+  DEBUG_MSG (SUBSET, nullptr, "loca entry_size %u num_offsets %u size %u",
 	     entry_size, num_offsets, entry_size * num_offsets);
 	     entry_size, num_offsets, entry_size * num_offsets);
 
 
   if (use_short_loca)
   if (use_short_loca)

+ 70 - 44
thirdparty/harfbuzz/src/OT/glyf/glyf.hh

@@ -7,6 +7,7 @@
 #include "../../hb-ot-hmtx-table.hh"
 #include "../../hb-ot-hmtx-table.hh"
 #include "../../hb-ot-var-gvar-table.hh"
 #include "../../hb-ot-var-gvar-table.hh"
 #include "../../hb-draw.hh"
 #include "../../hb-draw.hh"
+#include "../../hb-paint.hh"
 
 
 #include "glyf-helpers.hh"
 #include "glyf-helpers.hh"
 #include "Glyph.hh"
 #include "Glyph.hh"
@@ -42,14 +43,13 @@ struct glyf
   bool serialize (hb_serialize_context_t *c,
   bool serialize (hb_serialize_context_t *c,
 		  Iterator it,
 		  Iterator it,
                   bool use_short_loca,
                   bool use_short_loca,
-		  const hb_subset_plan_t *plan,
-		  hb_font_t *font)
+		  const hb_subset_plan_t *plan)
   {
   {
     TRACE_SERIALIZE (this);
     TRACE_SERIALIZE (this);
 
 
     unsigned init_len = c->length ();
     unsigned init_len = c->length ();
     for (auto &_ : it)
     for (auto &_ : it)
-      if (unlikely (!_.serialize (c, use_short_loca, plan, font)))
+      if (unlikely (!_.serialize (c, use_short_loca, plan)))
         return false;
         return false;
 
 
     /* As a special case when all glyph in the font are empty, add a zero byte
     /* As a special case when all glyph in the font are empty, add a zero byte
@@ -75,59 +75,66 @@ struct glyf
     glyf *glyf_prime = c->serializer->start_embed <glyf> ();
     glyf *glyf_prime = c->serializer->start_embed <glyf> ();
     if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
     if (unlikely (!c->serializer->check_success (glyf_prime))) return_trace (false);
 
 
-    hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
-    _populate_subset_glyphs (c->plan, glyphs);
-
     hb_font_t *font = nullptr;
     hb_font_t *font = nullptr;
-    if (!c->plan->pinned_at_default)
+    if (c->plan->normalized_coords)
     {
     {
       font = _create_font_for_instancing (c->plan);
       font = _create_font_for_instancing (c->plan);
       if (unlikely (!font)) return false;
       if (unlikely (!font)) return false;
     }
     }
 
 
-    auto padded_offsets =
-    + hb_iter (glyphs)
-    | hb_map (&glyf_impl::SubsetGlyph::padded_size)
-    ;
+    hb_vector_t<unsigned> padded_offsets;
+    unsigned num_glyphs = c->plan->num_output_glyphs ();
+    if (unlikely (!padded_offsets.resize (num_glyphs)))
+      return false;
+
+    hb_vector_t<glyf_impl::SubsetGlyph> glyphs;
+    if (!_populate_subset_glyphs (c->plan, font, glyphs))
+      return false;
+
+    if (font)
+      hb_font_destroy (font);
+
+    unsigned max_offset = 0;
+    for (unsigned i = 0; i < num_glyphs; i++)
+    {
+      padded_offsets[i] = glyphs[i].padded_size ();
+      max_offset += padded_offsets[i];
+    }
 
 
     bool use_short_loca = false;
     bool use_short_loca = false;
     if (likely (!c->plan->force_long_loca))
     if (likely (!c->plan->force_long_loca))
-    {
-      unsigned max_offset = + padded_offsets | hb_reduce (hb_add, 0);
       use_short_loca = max_offset < 0x1FFFF;
       use_short_loca = max_offset < 0x1FFFF;
-    }
 
 
-    glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan, font);
     if (!use_short_loca) {
     if (!use_short_loca) {
-      padded_offsets =
-          + hb_iter (glyphs)
-          | hb_map (&glyf_impl::SubsetGlyph::length)
-          ;
+      for (unsigned i = 0; i < num_glyphs; i++)
+        padded_offsets[i] = glyphs[i].length ();
     }
     }
 
 
-    if (font)
-    {
-      _free_compiled_subset_glyphs (&glyphs);
-      hb_font_destroy (font);
-    }
+    bool result = glyf_prime->serialize (c->serializer, glyphs.writer (), use_short_loca, c->plan);
+    if (c->plan->normalized_coords && !c->plan->pinned_at_default)
+      _free_compiled_subset_glyphs (glyphs, glyphs.length - 1);
+
+    if (!result) return false;
 
 
     if (unlikely (c->serializer->in_error ())) return_trace (false);
     if (unlikely (c->serializer->in_error ())) return_trace (false);
+
     return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
     return_trace (c->serializer->check_success (glyf_impl::_add_loca_and_head (c->plan,
-									       padded_offsets,
+									       padded_offsets.iter (),
 									       use_short_loca)));
 									       use_short_loca)));
   }
   }
 
 
-  void
+  bool
   _populate_subset_glyphs (const hb_subset_plan_t   *plan,
   _populate_subset_glyphs (const hb_subset_plan_t   *plan,
+			   hb_font_t                *font,
 			   hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
 			   hb_vector_t<glyf_impl::SubsetGlyph> &glyphs /* OUT */) const;
 
 
   hb_font_t *
   hb_font_t *
   _create_font_for_instancing (const hb_subset_plan_t *plan) const;
   _create_font_for_instancing (const hb_subset_plan_t *plan) const;
 
 
-  void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> *glyphs) const
+  void _free_compiled_subset_glyphs (hb_vector_t<glyf_impl::SubsetGlyph> &glyphs, unsigned index) const
   {
   {
-    for (auto _ : *glyphs)
-      _.free_compiled_bytes ();
+    for (unsigned i = 0; i <= index && i < glyphs.length; i++)
+      glyphs[i].free_compiled_bytes ();
   }
   }
 
 
   protected:
   protected:
@@ -193,7 +200,7 @@ struct glyf_accelerator_t
     contour_point_vector_t all_points;
     contour_point_vector_t all_points;
 
 
     bool phantom_only = !consumer.is_consuming_contour_points ();
     bool phantom_only = !consumer.is_consuming_contour_points ();
-    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, true, true, phantom_only)))
+    if (unlikely (!glyph_for_gid (gid).get_points (font, *this, all_points, nullptr, nullptr, nullptr, true, true, phantom_only)))
       return false;
       return false;
 
 
     if (consumer.is_consuming_contour_points ())
     if (consumer.is_consuming_contour_points ())
@@ -247,19 +254,14 @@ struct glyf_accelerator_t
 	  extents->y_bearing = 0;
 	  extents->y_bearing = 0;
 	  return;
 	  return;
 	}
 	}
-	if (scaled)
-	{
-	  extents->x_bearing = font->em_scalef_x (min_x);
-	  extents->width = font->em_scalef_x (max_x) - extents->x_bearing;
-	  extents->y_bearing = font->em_scalef_y (max_y);
-	  extents->height = font->em_scalef_y (min_y) - extents->y_bearing;
-	}
-	else
 	{
 	{
 	  extents->x_bearing = roundf (min_x);
 	  extents->x_bearing = roundf (min_x);
 	  extents->width = roundf (max_x - extents->x_bearing);
 	  extents->width = roundf (max_x - extents->x_bearing);
 	  extents->y_bearing = roundf (max_y);
 	  extents->y_bearing = roundf (max_y);
 	  extents->height = roundf (min_y - extents->y_bearing);
 	  extents->height = roundf (min_y - extents->y_bearing);
+
+	  if (scaled)
+	    font->scale_glyph_extents (extents);
 	}
 	}
       }
       }
 
 
@@ -337,6 +339,15 @@ struct glyf_accelerator_t
     return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
     return glyph_for_gid (gid).get_extents_without_var_scaled (font, *this, extents);
   }
   }
 
 
+  bool paint_glyph (hb_font_t *font, hb_codepoint_t gid, hb_paint_funcs_t *funcs, void *data, hb_color_t foreground) const
+  {
+    funcs->push_clip_glyph (data, gid, font);
+    funcs->color (data, true, foreground);
+    funcs->pop_clip (data);
+
+    return true;
+  }
+
   const glyf_impl::Glyph
   const glyf_impl::Glyph
   glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
   glyph_for_gid (hb_codepoint_t gid, bool needs_padding_removal = false) const
   {
   {
@@ -385,14 +396,16 @@ struct glyf_accelerator_t
 };
 };
 
 
 
 
-inline void
+inline bool
 glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
 glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
+			       hb_font_t *font,
 			       hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
 			       hb_vector_t<glyf_impl::SubsetGlyph>& glyphs /* OUT */) const
 {
 {
   OT::glyf_accelerator_t glyf (plan->source);
   OT::glyf_accelerator_t glyf (plan->source);
   unsigned num_glyphs = plan->num_output_glyphs ();
   unsigned num_glyphs = plan->num_output_glyphs ();
-  if (!glyphs.resize (num_glyphs)) return;
+  if (!glyphs.resize (num_glyphs)) return false;
 
 
+  unsigned idx = 0;
   for (auto p : plan->glyph_map->iter ())
   for (auto p : plan->glyph_map->iter ())
   {
   {
     unsigned new_gid = p.second;
     unsigned new_gid = p.second;
@@ -401,7 +414,7 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
 
 
     if (unlikely (new_gid == 0 &&
     if (unlikely (new_gid == 0 &&
                   !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
                   !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE)) &&
-                  plan->pinned_at_default)
+                  !plan->normalized_coords)
       subset_glyph.source_glyph = glyf_impl::Glyph ();
       subset_glyph.source_glyph = glyf_impl::Glyph ();
     else
     else
     {
     {
@@ -414,7 +427,20 @@ glyf::_populate_subset_glyphs (const hb_subset_plan_t   *plan,
       subset_glyph.drop_hints_bytes ();
       subset_glyph.drop_hints_bytes ();
     else
     else
       subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
       subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
+
+    if (font)
+    {
+      if (unlikely (!subset_glyph.compile_bytes_with_deltas (plan, font, glyf)))
+      {
+        // when pinned at default, only bounds are updated, thus no need to free
+        if (!plan->pinned_at_default && idx > 0)
+          _free_compiled_subset_glyphs (glyphs, idx - 1);
+        return false;
+      }
+      idx++;
+    }
   }
   }
+  return true;
 }
 }
 
 
 inline hb_font_t *
 inline hb_font_t *
@@ -424,10 +450,10 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
   if (unlikely (font == hb_font_get_empty ())) return nullptr;
   if (unlikely (font == hb_font_get_empty ())) return nullptr;
 
 
   hb_vector_t<hb_variation_t> vars;
   hb_vector_t<hb_variation_t> vars;
-  if (unlikely (!vars.alloc (plan->user_axes_location->get_population ())))
+  if (unlikely (!vars.alloc (plan->user_axes_location.get_population (), true)))
     return nullptr;
     return nullptr;
 
 
-  for (auto _ : *plan->user_axes_location)
+  for (auto _ : plan->user_axes_location)
   {
   {
     hb_variation_t var;
     hb_variation_t var;
     var.tag = _.first;
     var.tag = _.first;
@@ -436,7 +462,7 @@ glyf::_create_font_for_instancing (const hb_subset_plan_t *plan) const
   }
   }
 
 
 #ifndef HB_NO_VAR
 #ifndef HB_NO_VAR
-  hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location->get_population ());
+  hb_font_set_variations (font, vars.arrayZ, plan->user_axes_location.get_population ());
 #endif
 #endif
   return font;
   return font;
 }
 }

+ 77 - 19
thirdparty/harfbuzz/src/OT/glyf/path-builder.hh

@@ -26,22 +26,29 @@ struct path_builder_t
 
 
     optional_point_t lerp (optional_point_t p, float t)
     optional_point_t lerp (optional_point_t p, float t)
     { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
     { return optional_point_t (x + t * (p.x - x), y + t * (p.y - y)); }
-  } first_oncurve, first_offcurve, last_offcurve;
+  } first_oncurve, first_offcurve, first_offcurve2, last_offcurve, last_offcurve2;
 
 
   path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
   path_builder_t (hb_font_t *font_, hb_draw_session_t &draw_session_)
   {
   {
     font = font_;
     font = font_;
     draw_session = &draw_session_;
     draw_session = &draw_session_;
-    first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
+    first_oncurve = first_offcurve = first_offcurve2 = last_offcurve = last_offcurve2 = optional_point_t ();
   }
   }
 
 
   /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
   /* based on https://github.com/RazrFalcon/ttf-parser/blob/4f32821/src/glyf.rs#L287
      See also:
      See also:
      * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
      * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM01/Chap1.html
-     * https://stackoverflow.com/a/20772557 */
+     * https://stackoverflow.com/a/20772557
+     *
+     * Cubic support added. */
   void consume_point (const contour_point_t &point)
   void consume_point (const contour_point_t &point)
   {
   {
     bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
     bool is_on_curve = point.flag & glyf_impl::SimpleGlyph::FLAG_ON_CURVE;
+#ifdef HB_NO_CUBIC_GLYF
+    bool is_cubic = false;
+#else
+    bool is_cubic = !is_on_curve && (point.flag & glyf_impl::SimpleGlyph::FLAG_CUBIC);
+#endif
     optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
     optional_point_t p (font->em_fscalef_x (point.x), font->em_fscalef_y (point.y));
     if (!first_oncurve)
     if (!first_oncurve)
     {
     {
@@ -52,7 +59,12 @@ struct path_builder_t
       }
       }
       else
       else
       {
       {
-	if (first_offcurve)
+	if (is_cubic && !first_offcurve2)
+	{
+	  first_offcurve2 = first_offcurve;
+	  first_offcurve = p;
+	}
+	else if (first_offcurve)
 	{
 	{
 	  optional_point_t mid = first_offcurve.lerp (p, .5f);
 	  optional_point_t mid = first_offcurve.lerp (p, .5f);
 	  first_oncurve = mid;
 	  first_oncurve = mid;
@@ -69,16 +81,41 @@ struct path_builder_t
       {
       {
 	if (is_on_curve)
 	if (is_on_curve)
 	{
 	{
-	  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
-				     p.x, p.y);
+	  if (last_offcurve2)
+	  {
+	    draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+				    last_offcurve.x, last_offcurve.y,
+				    p.x, p.y);
+	    last_offcurve2 = optional_point_t ();
+	  }
+	  else
+	    draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+				       p.x, p.y);
 	  last_offcurve = optional_point_t ();
 	  last_offcurve = optional_point_t ();
 	}
 	}
 	else
 	else
 	{
 	{
-	  optional_point_t mid = last_offcurve.lerp (p, .5f);
-	  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
-				     mid.x, mid.y);
-	  last_offcurve = p;
+	  if (is_cubic && !last_offcurve2)
+	  {
+	    last_offcurve2 = last_offcurve;
+	    last_offcurve = p;
+	  }
+	  else
+	  {
+	    optional_point_t mid = last_offcurve.lerp (p, .5f);
+
+	    if (is_cubic)
+	    {
+	      draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+				      last_offcurve.x, last_offcurve.y,
+				      mid.x, mid.y);
+	      last_offcurve2 = optional_point_t ();
+	    }
+	    else
+	      draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+					 mid.x, mid.y);
+	    last_offcurve = p;
+	  }
 	}
 	}
       }
       }
       else
       else
@@ -94,19 +131,40 @@ struct path_builder_t
     {
     {
       if (first_offcurve && last_offcurve)
       if (first_offcurve && last_offcurve)
       {
       {
-	optional_point_t mid = last_offcurve.lerp (first_offcurve, .5f);
-	draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
-				   mid.x, mid.y);
+	optional_point_t mid = last_offcurve.lerp (first_offcurve2 ?
+						   first_offcurve2 :
+						   first_offcurve, .5f);
+	if (last_offcurve2)
+	  draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+				  last_offcurve.x, last_offcurve.y,
+				  mid.x, mid.y);
+	else
+	  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+				     mid.x, mid.y);
 	last_offcurve = optional_point_t ();
 	last_offcurve = optional_point_t ();
-	/* now check the rest */
       }
       }
+      /* now check the rest */
 
 
       if (first_offcurve && first_oncurve)
       if (first_offcurve && first_oncurve)
-	draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
-				   first_oncurve.x, first_oncurve.y);
+      {
+        if (first_offcurve2)
+	  draw_session->cubic_to (first_offcurve2.x, first_offcurve2.y,
+				  first_offcurve.x, first_offcurve.y,
+				  first_oncurve.x, first_oncurve.y);
+	else
+	  draw_session->quadratic_to (first_offcurve.x, first_offcurve.y,
+				     first_oncurve.x, first_oncurve.y);
+      }
       else if (last_offcurve && first_oncurve)
       else if (last_offcurve && first_oncurve)
-	draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
-				   first_oncurve.x, first_oncurve.y);
+      {
+	if (last_offcurve2)
+	  draw_session->cubic_to (last_offcurve2.x, last_offcurve2.y,
+				  last_offcurve.x, last_offcurve.y,
+				  first_oncurve.x, first_oncurve.y);
+	else
+	  draw_session->quadratic_to (last_offcurve.x, last_offcurve.y,
+				     first_oncurve.x, first_oncurve.y);
+      }
       else if (first_oncurve)
       else if (first_oncurve)
 	draw_session->line_to (first_oncurve.x, first_oncurve.y);
 	draw_session->line_to (first_oncurve.x, first_oncurve.y);
       else if (first_offcurve)
       else if (first_offcurve)
@@ -117,7 +175,7 @@ struct path_builder_t
       }
       }
 
 
       /* Getting ready for the next contour */
       /* Getting ready for the next contour */
-      first_oncurve = first_offcurve = last_offcurve = optional_point_t ();
+      first_oncurve = first_offcurve = last_offcurve = last_offcurve2 = optional_point_t ();
       draw_session->close_path ();
       draw_session->close_path ();
     }
     }
   }
   }

+ 589 - 0
thirdparty/harfbuzz/src/OT/name/name.hh

@@ -0,0 +1,589 @@
+/*
+ * Copyright © 2011,2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef OT_NAME_NAME_HH
+#define OT_NAME_NAME_HH
+
+#include "../../hb-open-type.hh"
+#include "../../hb-ot-name-language.hh"
+#include "../../hb-aat-layout.hh"
+#include "../../hb-utf.hh"
+
+
+namespace OT {
+
+template <typename in_utf_t, typename out_utf_t>
+inline unsigned int
+hb_ot_name_convert_utf (hb_bytes_t                       bytes,
+			unsigned int                    *text_size /* IN/OUT */,
+			typename out_utf_t::codepoint_t *text /* OUT */)
+{
+  unsigned int src_len = bytes.length / sizeof (typename in_utf_t::codepoint_t);
+  const typename in_utf_t::codepoint_t *src = (const typename in_utf_t::codepoint_t *) bytes.arrayZ;
+  const typename in_utf_t::codepoint_t *src_end = src + src_len;
+
+  typename out_utf_t::codepoint_t *dst = text;
+
+  hb_codepoint_t unicode;
+  const hb_codepoint_t replacement = HB_BUFFER_REPLACEMENT_CODEPOINT_DEFAULT;
+
+  if (text_size && *text_size)
+  {
+    (*text_size)--; /* Save room for NUL-termination. */
+    const typename out_utf_t::codepoint_t *dst_end = text + *text_size;
+
+    while (src < src_end && dst < dst_end)
+    {
+      const typename in_utf_t::codepoint_t *src_next = in_utf_t::next (src, src_end, &unicode, replacement);
+      typename out_utf_t::codepoint_t *dst_next = out_utf_t::encode (dst, dst_end, unicode);
+      if (dst_next == dst)
+	break; /* Out-of-room. */
+
+      dst = dst_next;
+      src = src_next;
+    }
+
+    *text_size = dst - text;
+    *dst = 0; /* NUL-terminate. */
+  }
+
+  /* Accumulate length of rest. */
+  unsigned int dst_len = dst - text;
+  while (src < src_end)
+  {
+    src = in_utf_t::next (src, src_end, &unicode, replacement);
+    dst_len += out_utf_t::encode_len (unicode);
+  }
+  return dst_len;
+}
+
+#define entry_score var.u16[0]
+#define entry_index var.u16[1]
+
+
+/*
+ * name -- Naming
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/name
+ */
+#define HB_OT_TAG_name HB_TAG('n','a','m','e')
+
+#define UNSUPPORTED	42
+
+struct NameRecord
+{
+  hb_language_t language (hb_face_t *face) const
+  {
+#ifndef HB_NO_OT_NAME_LANGUAGE
+    unsigned int p = platformID;
+    unsigned int l = languageID;
+
+    if (p == 3)
+      return _hb_ot_name_language_for_ms_code (l);
+
+    if (p == 1)
+      return _hb_ot_name_language_for_mac_code (l);
+
+#ifndef HB_NO_OT_NAME_LANGUAGE_AAT
+    if (p == 0)
+      return face->table.ltag->get_language (l);
+#endif
+
+#endif
+    return HB_LANGUAGE_INVALID;
+  }
+
+  uint16_t score () const
+  {
+    /* Same order as in cmap::find_best_subtable(). */
+    unsigned int p = platformID;
+    unsigned int e = encodingID;
+
+    /* 32-bit. */
+    if (p == 3 && e == 10) return 0;
+    if (p == 0 && e ==  6) return 1;
+    if (p == 0 && e ==  4) return 2;
+
+    /* 16-bit. */
+    if (p == 3 && e ==  1) return 3;
+    if (p == 0 && e ==  3) return 4;
+    if (p == 0 && e ==  2) return 5;
+    if (p == 0 && e ==  1) return 6;
+    if (p == 0 && e ==  0) return 7;
+
+    /* Symbol. */
+    if (p == 3 && e ==  0) return 8;
+
+    /* We treat all Mac Latin names as ASCII only. */
+    if (p == 1 && e ==  0) return 10; /* 10 is magic number :| */
+
+    return UNSUPPORTED;
+  }
+
+  NameRecord* copy (hb_serialize_context_t *c, const void *base
+#ifdef HB_EXPERIMENTAL_API
+                    , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+		    ) const
+  {
+    TRACE_SERIALIZE (this);
+    HB_UNUSED auto snap = c->snapshot ();
+    auto *out = c->embed (this);
+    if (unlikely (!out)) return_trace (nullptr);
+#ifdef HB_EXPERIMENTAL_API
+    hb_ot_name_record_ids_t record_ids (platformID, encodingID, languageID, nameID);
+    hb_bytes_t* name_bytes;
+
+    if (name_table_overrides->has (record_ids, &name_bytes)) {
+      hb_bytes_t encoded_bytes = *name_bytes;
+      char *name_str_utf16_be = nullptr;
+
+      if (platformID != 1)
+      {
+        unsigned text_size = hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, nullptr, nullptr);
+  
+        text_size++; // needs to consider NULL terminator for use in hb_ot_name_convert_utf()
+        unsigned byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+        name_str_utf16_be = (char *) hb_calloc (byte_len, 1);
+        if (!name_str_utf16_be)
+        {
+          c->revert (snap);
+          return_trace (nullptr);
+        }
+        hb_ot_name_convert_utf<hb_utf8_t, hb_utf16_be_t> (*name_bytes, &text_size,
+                                                          (hb_utf16_be_t::codepoint_t *) name_str_utf16_be);
+  
+        unsigned encoded_byte_len = text_size * hb_utf16_be_t::codepoint_t::static_size;
+        if (!encoded_byte_len || !c->check_assign (out->length, encoded_byte_len, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+          c->revert (snap);
+          hb_free (name_str_utf16_be);
+          return_trace (nullptr);
+        }
+  
+        encoded_bytes = hb_bytes_t (name_str_utf16_be, encoded_byte_len);
+      }
+      else
+      {
+        // mac platform, copy the UTF-8 string(all ascii characters) as is
+        if (!c->check_assign (out->length, encoded_bytes.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) {
+          c->revert (snap);
+          return_trace (nullptr);
+        }
+      }
+
+      out->offset = 0;
+      c->push ();
+      encoded_bytes.copy (c);
+      c->add_link (out->offset, c->pop_pack (), hb_serialize_context_t::Tail, 0);
+      hb_free (name_str_utf16_be);
+    }
+    else
+#endif
+    {
+      out->offset.serialize_copy (c, offset, base, 0, hb_serialize_context_t::Tail, length);
+    }
+    return_trace (out);
+  }
+
+  bool isUnicode () const
+  {
+    unsigned int p = platformID;
+    unsigned int e = encodingID;
+
+    return (p == 0 ||
+	    (p == 3 && (e == 0 || e == 1 || e == 10)));
+  }
+
+  static int cmp (const void *pa, const void *pb)
+  {
+    const NameRecord *a = (const NameRecord *)pa;
+    const NameRecord *b = (const NameRecord *)pb;
+
+    if (a->platformID != b->platformID)
+      return a->platformID - b->platformID;
+
+    if (a->encodingID != b->encodingID)
+      return a->encodingID - b->encodingID;
+
+    if (a->languageID != b->languageID)
+      return a->languageID - b->languageID;
+
+    if (a->nameID != b->nameID)
+      return a->nameID - b->nameID;
+
+    if (a->length != b->length)
+      return a->length - b->length;
+
+    return 0;
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && offset.sanitize (c, base, length));
+  }
+
+  HBUINT16	platformID;	/* Platform ID. */
+  HBUINT16	encodingID;	/* Platform-specific encoding ID. */
+  HBUINT16	languageID;	/* Language ID. */
+  HBUINT16	nameID;		/* Name ID. */
+  HBUINT16	length;		/* String length (in bytes). */
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
+		offset;		/* String offset from start of storage area (in bytes). */
+  public:
+  DEFINE_SIZE_STATIC (12);
+};
+
+static int
+_hb_ot_name_entry_cmp_key (const void *pa, const void *pb, bool exact)
+{
+  const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
+  const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
+
+  /* Compare by name_id, then language. */
+
+  if (a->name_id != b->name_id)
+    return a->name_id - b->name_id;
+
+  if (a->language == b->language) return 0;
+  if (!a->language) return -1;
+  if (!b->language) return +1;
+
+  const char *astr = hb_language_to_string (a->language);
+  const char *bstr = hb_language_to_string (b->language);
+
+  signed c = strcmp (astr, bstr);
+
+  // 'a' is the user request, and 'b' is string in the font.
+  // If eg. user asks for "en-us" and font has "en", approve.
+  if (!exact && c &&
+      hb_language_matches (b->language, a->language))
+    return 0;
+
+  return c;
+}
+
+static int
+_hb_ot_name_entry_cmp (const void *pa, const void *pb)
+{
+  /* Compare by name_id, then language, then score, then index. */
+
+  int v = _hb_ot_name_entry_cmp_key (pa, pb, true);
+  if (v)
+    return v;
+
+  const hb_ot_name_entry_t *a = (const hb_ot_name_entry_t *) pa;
+  const hb_ot_name_entry_t *b = (const hb_ot_name_entry_t *) pb;
+
+  if (a->entry_score != b->entry_score)
+    return a->entry_score - b->entry_score;
+
+  if (a->entry_index != b->entry_index)
+    return a->entry_index - b->entry_index;
+
+  return 0;
+}
+
+struct name
+{
+  static constexpr hb_tag_t tableTag = HB_OT_TAG_name;
+
+  unsigned int get_size () const
+  { return min_size + count * nameRecordZ.item_size; }
+
+  template <typename Iterator,
+	    hb_requires (hb_is_source_of (Iterator, const NameRecord &))>
+  bool serialize (hb_serialize_context_t *c,
+		  Iterator it,
+		  const void *src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+                  , const hb_vector_t<hb_ot_name_record_ids_t>& insert_name_records
+		  , const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides
+#endif
+		  )
+  {
+    TRACE_SERIALIZE (this);
+
+    if (unlikely (!c->extend_min ((*this))))  return_trace (false);
+
+    unsigned total_count = it.len ()
+#ifdef HB_EXPERIMENTAL_API
+        + insert_name_records.length
+#endif
+        ;
+    this->format = 0;
+    if (!c->check_assign (this->count, total_count, HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return false;
+
+    NameRecord *name_records = (NameRecord *) hb_calloc (total_count, NameRecord::static_size);
+    if (unlikely (!name_records)) return_trace (false);
+
+    hb_array_t<NameRecord> records (name_records, total_count);
+
+    for (const NameRecord& record : it)
+    {
+      hb_memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
+
+#ifdef HB_EXPERIMENTAL_API
+    for (unsigned i = 0; i < insert_name_records.length; i++)
+    {
+      const hb_ot_name_record_ids_t& ids = insert_name_records[i];
+      NameRecord record;
+      record.platformID = ids.platform_id;
+      record.encodingID = ids.encoding_id;
+      record.languageID = ids.language_id;
+      record.nameID = ids.name_id;
+      record.length = 0; // handled in NameRecord copy()
+      record.offset = 0;
+      memcpy (name_records, &record, NameRecord::static_size);
+      name_records++;
+    }
+#endif
+
+    records.qsort ();
+
+    c->copy_all (records,
+		 src_string_pool
+#ifdef HB_EXPERIMENTAL_API
+		 , name_table_overrides
+#endif
+		 );
+    hb_free (records.arrayZ);
+
+
+    if (unlikely (c->ran_out_of_room ())) return_trace (false);
+
+    this->stringOffset = c->length ();
+
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+
+    name *name_prime = c->serializer->start_embed<name> ();
+    if (unlikely (!name_prime)) return_trace (false);
+
+#ifdef HB_EXPERIMENTAL_API
+    const hb_hashmap_t<hb_ot_name_record_ids_t, hb_bytes_t> *name_table_overrides =
+        &c->plan->name_table_overrides;
+#endif
+    
+    auto it =
+    + nameRecordZ.as_array (count)
+    | hb_filter (c->plan->name_ids, &NameRecord::nameID)
+    | hb_filter (c->plan->name_languages, &NameRecord::languageID)
+    | hb_filter ([&] (const NameRecord& namerecord) {
+      return
+          (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
+          || namerecord.isUnicode ();
+    })
+#ifdef HB_EXPERIMENTAL_API
+    | hb_filter ([&] (const NameRecord& namerecord) {
+      if (name_table_overrides->is_empty ())
+        return true;
+      hb_ot_name_record_ids_t rec_ids (namerecord.platformID,
+                                       namerecord.encodingID,
+                                       namerecord.languageID,
+                                       namerecord.nameID);
+
+      hb_bytes_t *p;
+      if (name_table_overrides->has (rec_ids, &p) &&
+          (*p).length == 0)
+        return false;
+      return true;
+    })
+#endif
+    ;
+
+#ifdef HB_EXPERIMENTAL_API
+    hb_hashmap_t<hb_ot_name_record_ids_t, unsigned> retained_name_record_ids;
+    for (const NameRecord& rec : it)
+    {
+      hb_ot_name_record_ids_t rec_ids (rec.platformID,
+                                       rec.encodingID,
+                                       rec.languageID,
+                                       rec.nameID);
+      retained_name_record_ids.set (rec_ids, 1);
+    }
+
+    hb_vector_t<hb_ot_name_record_ids_t> insert_name_records;
+    if (!name_table_overrides->is_empty ())
+    {
+      if (unlikely (!insert_name_records.alloc (name_table_overrides->get_population (), true)))
+        return_trace (false);
+      for (const auto& record_ids : name_table_overrides->keys ())
+      {
+        if (name_table_overrides->get (record_ids).length == 0)
+          continue;
+        if (retained_name_record_ids.has (record_ids))
+          continue;
+        insert_name_records.push (record_ids);
+      }
+    }
+#endif
+
+    return (name_prime->serialize (c->serializer, it,
+                                   std::addressof (this + stringOffset)
+#ifdef HB_EXPERIMENTAL_API
+                                   , insert_name_records
+                                   , name_table_overrides
+#endif
+                                   ));
+  }
+
+  bool sanitize_records (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    const void *string_pool = (this+stringOffset).arrayZ;
+    return_trace (nameRecordZ.sanitize (c, count, string_pool));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+		  likely (format == 0 || format == 1) &&
+		  c->check_array (nameRecordZ.arrayZ, count) &&
+		  c->check_range (this, stringOffset) &&
+		  sanitize_records (c));
+  }
+
+  struct accelerator_t
+  {
+    accelerator_t (hb_face_t *face)
+    {
+      this->table = hb_sanitize_context_t ().reference_table<name> (face);
+      assert (this->table.get_length () >= this->table->stringOffset);
+      this->pool = (const char *) (const void *) (this->table+this->table->stringOffset);
+      this->pool_len = this->table.get_length () - this->table->stringOffset;
+      const hb_array_t<const NameRecord> all_names (this->table->nameRecordZ.arrayZ,
+						    this->table->count);
+
+      this->names.alloc (all_names.length, true);
+
+      for (unsigned int i = 0; i < all_names.length; i++)
+      {
+	hb_ot_name_entry_t *entry = this->names.push ();
+
+	entry->name_id = all_names[i].nameID;
+	entry->language = all_names[i].language (face);
+	entry->entry_score =  all_names[i].score ();
+	entry->entry_index = i;
+      }
+
+      this->names.qsort (_hb_ot_name_entry_cmp);
+      /* Walk and pick best only for each name_id,language pair,
+       * while dropping unsupported encodings. */
+      unsigned int j = 0;
+      for (unsigned int i = 0; i < this->names.length; i++)
+      {
+	if (this->names[i].entry_score == UNSUPPORTED ||
+	    this->names[i].language == HB_LANGUAGE_INVALID)
+	  continue;
+	if (i &&
+	    this->names[i - 1].name_id  == this->names[i].name_id &&
+	    this->names[i - 1].language == this->names[i].language)
+	  continue;
+	this->names[j++] = this->names[i];
+      }
+      this->names.resize (j);
+    }
+    ~accelerator_t ()
+    {
+      this->table.destroy ();
+    }
+
+    int get_index (hb_ot_name_id_t  name_id,
+		   hb_language_t    language,
+		   unsigned int    *width=nullptr) const
+    {
+      const hb_ot_name_entry_t key = {name_id, {0}, language};
+      const hb_ot_name_entry_t *entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
+						    this->names.length,
+						    sizeof (hb_ot_name_entry_t),
+						    _hb_ot_name_entry_cmp_key,
+						    true);
+
+      if (!entry)
+      {
+	entry = hb_bsearch (key, (const hb_ot_name_entry_t *) this->names,
+			    this->names.length,
+			    sizeof (hb_ot_name_entry_t),
+			    _hb_ot_name_entry_cmp_key,
+			    false);
+      }
+
+      if (!entry)
+	return -1;
+
+      if (width)
+	*width = entry->entry_score < 10 ? 2 : 1;
+
+      return entry->entry_index;
+    }
+
+    hb_bytes_t get_name (unsigned int idx) const
+    {
+      const hb_array_t<const NameRecord> all_names (table->nameRecordZ.arrayZ, table->count);
+      const NameRecord &record = all_names[idx];
+      const hb_bytes_t string_pool (pool, pool_len);
+      return string_pool.sub_array (record.offset, record.length);
+    }
+
+    private:
+    const char *pool;
+    unsigned int pool_len;
+    public:
+    hb_blob_ptr_t<name> table;
+    hb_vector_t<hb_ot_name_entry_t> names;
+  };
+
+  public:
+  /* We only implement format 0 for now. */
+  HBUINT16	format;		/* Format selector (=0/1). */
+  HBUINT16	count;		/* Number of name records. */
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
+		stringOffset;	/* Offset to start of string storage (from start of table). */
+  UnsizedArrayOf<NameRecord>
+		nameRecordZ;	/* The name records where count is the number of records. */
+  public:
+  DEFINE_SIZE_ARRAY (6, nameRecordZ);
+};
+
+#undef entry_index
+#undef entry_score
+
+struct name_accelerator_t : name::accelerator_t {
+  name_accelerator_t (hb_face_t *face) : name::accelerator_t (face) {}
+};
+
+} /* namespace OT */
+
+
+#endif /* OT_NAME_NAME_HH */

+ 12 - 5
thirdparty/harfbuzz/src/graph/graph.hh

@@ -123,7 +123,7 @@ struct graph_t
         while (a || b)
         while (a || b)
         {
         {
           DEBUG_MSG (SUBSET_REPACK, nullptr,
           DEBUG_MSG (SUBSET_REPACK, nullptr,
-                     "  0x%x %s 0x%x", *a, (*a == *b) ? "==" : "!=", *b);
+                     "  0x%x %s 0x%x", (unsigned) *a, (*a == *b) ? "==" : "!=", (unsigned) *b);
           a++;
           a++;
           b++;
           b++;
         }
         }
@@ -700,6 +700,9 @@ struct graph_t
       }
       }
     }
     }
 
 
+    if (in_error ())
+      return false;
+
     if (!made_changes)
     if (!made_changes)
       return false;
       return false;
 
 
@@ -833,7 +836,11 @@ struct graph_t
     if (index_map.has (node_idx))
     if (index_map.has (node_idx))
       return;
       return;
 
 
-    index_map.set (node_idx, duplicate (node_idx));
+    unsigned clone_idx = duplicate (node_idx);
+    if (!check_success (clone_idx != (unsigned) -1))
+      return;
+
+    index_map.set (node_idx, clone_idx);
     for (const auto& l : object (node_idx).all_links ()) {
     for (const auto& l : object (node_idx).all_links ()) {
       duplicate_subgraph (l.objidx, index_map);
       duplicate_subgraph (l.objidx, index_map);
     }
     }
@@ -918,12 +925,12 @@ struct graph_t
     {
     {
       // Can't duplicate this node, doing so would orphan the original one as all remaining links
       // Can't duplicate this node, doing so would orphan the original one as all remaining links
       // to child are from parent.
       // to child are from parent.
-      DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %d => %d",
+      DEBUG_MSG (SUBSET_REPACK, nullptr, "  Not duplicating %u => %u",
                  parent_idx, child_idx);
                  parent_idx, child_idx);
       return -1;
       return -1;
     }
     }
 
 
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %d => %d",
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Duplicating %u => %u",
                parent_idx, child_idx);
                parent_idx, child_idx);
 
 
     unsigned clone_idx = duplicate (child_idx);
     unsigned clone_idx = duplicate (child_idx);
@@ -981,7 +988,7 @@ struct graph_t
    */
    */
   bool raise_childrens_priority (unsigned parent_idx)
   bool raise_childrens_priority (unsigned parent_idx)
   {
   {
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %d",
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  Raising priority of all children of %u",
                parent_idx);
                parent_idx);
     // This operation doesn't change ordering until a sort is run, so no need
     // This operation doesn't change ordering until a sort is run, so no need
     // to invalidate positions. It does not change graph structure so no need
     // to invalidate positions. It does not change graph structure so no need

+ 3 - 3
thirdparty/harfbuzz/src/graph/serialize.hh

@@ -153,8 +153,8 @@ void print_overflows (graph_t& graph,
     const auto& child = graph.vertices_[o.child];
     const auto& child = graph.vertices_[o.child];
     DEBUG_MSG (SUBSET_REPACK, nullptr,
     DEBUG_MSG (SUBSET_REPACK, nullptr,
                "  overflow from "
                "  overflow from "
-               "%4d (%4d in, %4d out, space %2d) => "
-               "%4d (%4d in, %4d out, space %2d)",
+               "%4u (%4u in, %4u out, space %2u) => "
+               "%4u (%4u in, %4u out, space %2u)",
                o.parent,
                o.parent,
                parent.incoming_edges (),
                parent.incoming_edges (),
                parent.obj.real_links.length + parent.obj.virtual_links.length,
                parent.obj.real_links.length + parent.obj.virtual_links.length,
@@ -165,7 +165,7 @@ void print_overflows (graph_t& graph,
                graph.space_for (o.child));
                graph.space_for (o.child));
   }
   }
   if (overflows.length > 10) {
   if (overflows.length > 10) {
-    DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %d more overflows.", overflows.length - 10);
+    DEBUG_MSG (SUBSET_REPACK, nullptr, "  ... plus %u more overflows.", overflows.length - 10);
   }
   }
 }
 }
 
 

+ 0 - 119
thirdparty/harfbuzz/src/graph/test-classdef-graph.cc

@@ -1,119 +0,0 @@
-/*
- * Copyright © 2022  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Garret Rieger
- */
-
-#include "gsubgpos-context.hh"
-#include "classdef-graph.hh"
-
-typedef hb_pair_t<hb_codepoint_t, hb_codepoint_t> gid_and_class_t;
-typedef hb_vector_t<gid_and_class_t> gid_and_class_list_t;
-
-
-static bool incremental_size_is (const gid_and_class_list_t& list, unsigned klass,
-                                 unsigned cov_expected, unsigned class_def_expected)
-{
-  graph::class_def_size_estimator_t estimator (list.iter ());
-
-  unsigned result = estimator.incremental_coverage_size (klass);
-  if (result != cov_expected)
-  {
-    printf ("FAIL: coverage expected size %u but was %u\n", cov_expected, result);
-    return false;
-  }
-
-  result = estimator.incremental_class_def_size (klass);
-  if (result != class_def_expected)
-  {
-    printf ("FAIL: class def expected size %u but was %u\n", class_def_expected, result);
-    return false;
-  }
-
-  return true;
-}
-
-static void test_class_and_coverage_size_estimates ()
-{
-  gid_and_class_list_t empty = {
-  };
-  assert (incremental_size_is (empty, 0, 0, 0));
-  assert (incremental_size_is (empty, 1, 0, 0));
-
-  gid_and_class_list_t class_zero = {
-    {5, 0},
-  };
-  assert (incremental_size_is (class_zero, 0, 2, 0));
-
-  gid_and_class_list_t consecutive = {
-    {4, 0},
-    {5, 0},
-    {6, 1},
-    {7, 1},
-    {8, 2},
-    {9, 2},
-    {10, 2},
-    {11, 2},
-  };
-  assert (incremental_size_is (consecutive, 0, 4, 0));
-  assert (incremental_size_is (consecutive, 1, 4, 4));
-  assert (incremental_size_is (consecutive, 2, 8, 6));
-
-  gid_and_class_list_t non_consecutive = {
-    {4, 0},
-    {5, 0},
-
-    {6, 1},
-    {7, 1},
-
-    {9, 2},
-    {10, 2},
-    {11, 2},
-    {12, 2},
-  };
-  assert (incremental_size_is (non_consecutive, 0, 4, 0));
-  assert (incremental_size_is (non_consecutive, 1, 4, 6));
-  assert (incremental_size_is (non_consecutive, 2, 8, 6));
-
-  gid_and_class_list_t multiple_ranges = {
-    {4, 0},
-    {5, 0},
-
-    {6, 1},
-    {7, 1},
-
-    {9, 1},
-
-    {11, 1},
-    {12, 1},
-    {13, 1},
-  };
-  assert (incremental_size_is (multiple_ranges, 0, 4, 0));
-  assert (incremental_size_is (multiple_ranges, 1, 2 * 6, 3 * 6));
-}
-
-int
-main (int argc, char **argv)
-{
-  test_class_and_coverage_size_estimates ();
-}

+ 68 - 37
thirdparty/harfbuzz/src/hb-aat-layout-common.hh

@@ -28,6 +28,7 @@
 #define HB_AAT_LAYOUT_COMMON_HH
 #define HB_AAT_LAYOUT_COMMON_HH
 
 
 #include "hb-aat-layout.hh"
 #include "hb-aat-layout.hh"
+#include "hb-aat-map.hh"
 #include "hb-open-type.hh"
 #include "hb-open-type.hh"
 
 
 namespace OT {
 namespace OT {
@@ -39,6 +40,43 @@ namespace AAT {
 using namespace OT;
 using namespace OT;
 
 
 
 
+struct ankr;
+
+struct hb_aat_apply_context_t :
+       hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
+{
+  const char *get_name () { return "APPLY"; }
+  template <typename T>
+  return_t dispatch (const T &obj) { return obj.apply (this); }
+  static return_t default_return_value () { return false; }
+  bool stop_sublookup_iteration (return_t r) const { return r; }
+
+  const hb_ot_shape_plan_t *plan;
+  hb_font_t *font;
+  hb_face_t *face;
+  hb_buffer_t *buffer;
+  hb_sanitize_context_t sanitizer;
+  const ankr *ankr_table;
+  const OT::GDEF *gdef_table;
+  const hb_sorted_vector_t<hb_aat_map_t::range_flags_t> *range_flags = nullptr;
+  hb_mask_t subtable_flags = 0;
+
+  /* Unused. For debug tracing only. */
+  unsigned int lookup_index;
+
+  HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
+				      hb_font_t *font_,
+				      hb_buffer_t *buffer_,
+				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
+
+  HB_INTERNAL ~hb_aat_apply_context_t ();
+
+  HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
+
+  void set_lookup_index (unsigned int i) { lookup_index = i; }
+};
+
+
 /*
 /*
  * Lookup Table
  * Lookup Table
  */
  */
@@ -740,16 +778,44 @@ struct StateTableDriver
 	      num_glyphs (face_->get_num_glyphs ()) {}
 	      num_glyphs (face_->get_num_glyphs ()) {}
 
 
   template <typename context_t>
   template <typename context_t>
-  void drive (context_t *c)
+  void drive (context_t *c, hb_aat_apply_context_t *ac)
   {
   {
     if (!c->in_place)
     if (!c->in_place)
       buffer->clear_output ();
       buffer->clear_output ();
 
 
     int state = StateTableT::STATE_START_OF_TEXT;
     int state = StateTableT::STATE_START_OF_TEXT;
+    // If there's only one range, we already checked the flag.
+    auto *last_range = ac->range_flags && (ac->range_flags->length > 1) ? &(*ac->range_flags)[0] : nullptr;
     for (buffer->idx = 0; buffer->successful;)
     for (buffer->idx = 0; buffer->successful;)
     {
     {
+      /* This block is copied in NoncontextualSubtable::apply. Keep in sync. */
+      if (last_range)
+      {
+	auto *range = last_range;
+	if (buffer->idx < buffer->len)
+	{
+	  unsigned cluster = buffer->cur().cluster;
+	  while (cluster < range->cluster_first)
+	    range--;
+	  while (cluster > range->cluster_last)
+	    range++;
+
+
+	  last_range = range;
+	}
+	if (!(range->flags & ac->subtable_flags))
+	{
+	  if (buffer->idx == buffer->len || unlikely (!buffer->successful))
+	    break;
+
+	  state = StateTableT::STATE_START_OF_TEXT;
+	  (void) buffer->next_glyph ();
+	  continue;
+	}
+      }
+
       unsigned int klass = buffer->idx < buffer->len ?
       unsigned int klass = buffer->idx < buffer->len ?
-			   machine.get_class (buffer->info[buffer->idx].codepoint, num_glyphs) :
+			   machine.get_class (buffer->cur().codepoint, num_glyphs) :
 			   (unsigned) StateTableT::CLASS_END_OF_TEXT;
 			   (unsigned) StateTableT::CLASS_END_OF_TEXT;
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
       DEBUG_MSG (APPLY, nullptr, "c%u at %u", klass, buffer->idx);
       const EntryT &entry = machine.get_entry (state, klass);
       const EntryT &entry = machine.get_entry (state, klass);
@@ -845,41 +911,6 @@ struct StateTableDriver
 };
 };
 
 
 
 
-struct ankr;
-
-struct hb_aat_apply_context_t :
-       hb_dispatch_context_t<hb_aat_apply_context_t, bool, HB_DEBUG_APPLY>
-{
-  const char *get_name () { return "APPLY"; }
-  template <typename T>
-  return_t dispatch (const T &obj) { return obj.apply (this); }
-  static return_t default_return_value () { return false; }
-  bool stop_sublookup_iteration (return_t r) const { return r; }
-
-  const hb_ot_shape_plan_t *plan;
-  hb_font_t *font;
-  hb_face_t *face;
-  hb_buffer_t *buffer;
-  hb_sanitize_context_t sanitizer;
-  const ankr *ankr_table;
-  const OT::GDEF *gdef_table;
-
-  /* Unused. For debug tracing only. */
-  unsigned int lookup_index;
-
-  HB_INTERNAL hb_aat_apply_context_t (const hb_ot_shape_plan_t *plan_,
-				      hb_font_t *font_,
-				      hb_buffer_t *buffer_,
-				      hb_blob_t *blob = const_cast<hb_blob_t *> (&Null (hb_blob_t)));
-
-  HB_INTERNAL ~hb_aat_apply_context_t ();
-
-  HB_INTERNAL void set_ankr_table (const AAT::ankr *ankr_table_);
-
-  void set_lookup_index (unsigned int i) { lookup_index = i; }
-};
-
-
 } /* namespace AAT */
 } /* namespace AAT */
 
 
 
 

+ 6 - 4
thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh

@@ -350,7 +350,7 @@ struct KerxSubTableFormat1
     driver_context_t dc (this, c);
     driver_context_t dc (this, c);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (true);
     return_trace (true);
   }
   }
@@ -594,7 +594,7 @@ struct KerxSubTableFormat4
     driver_context_t dc (this, c);
     driver_context_t dc (this, c);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->font->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (true);
     return_trace (true);
   }
   }
@@ -869,6 +869,8 @@ struct KerxTable
 
 
   bool apply (AAT::hb_aat_apply_context_t *c) const
   bool apply (AAT::hb_aat_apply_context_t *c) const
   {
   {
+    c->buffer->unsafe_to_concat ();
+
     typedef typename T::SubTable SubTable;
     typedef typename T::SubTable SubTable;
 
 
     bool ret = false;
     bool ret = false;
@@ -889,7 +891,7 @@ struct KerxTable
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
       reverse = bool (st->u.header.coverage & st->u.header.Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
 
-      if (!c->buffer->message (c->font, "start subtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start subtable %u", c->lookup_index))
 	goto skip;
 	goto skip;
 
 
       if (!seenCrossStream &&
       if (!seenCrossStream &&
@@ -921,7 +923,7 @@ struct KerxTable
       if (reverse)
       if (reverse)
 	c->buffer->reverse ();
 	c->buffer->reverse ();
 
 
-      (void) c->buffer->message (c->font, "end subtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end subtable %u", c->lookup_index);
 
 
     skip:
     skip:
       st = &StructAfter<SubTable> (*st);
       st = &StructAfter<SubTable> (*st);

+ 43 - 14
thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh

@@ -169,7 +169,7 @@ struct RearrangementSubtable
     driver_context_t dc (this);
     driver_context_t dc (this);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (dc.ret);
     return_trace (dc.ret);
   }
   }
@@ -325,7 +325,7 @@ struct ContextualSubtable
     driver_context_t dc (this, c);
     driver_context_t dc (this, c);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (dc.ret);
     return_trace (dc.ret);
   }
   }
@@ -525,7 +525,7 @@ struct LigatureSubtable
 	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
 	  if (unlikely (!componentData.sanitize (&c->sanitizer))) break;
 	  ligature_idx += componentData;
 	  ligature_idx += componentData;
 
 
-	  DEBUG_MSG (APPLY, nullptr, "Action store %u last %u",
+	  DEBUG_MSG (APPLY, nullptr, "Action store %d last %d",
 		     bool (action & LigActionStore),
 		     bool (action & LigActionStore),
 		     bool (action & LigActionLast));
 		     bool (action & LigActionLast));
 	  if (action & (LigActionStore | LigActionLast))
 	  if (action & (LigActionStore | LigActionLast))
@@ -577,7 +577,7 @@ struct LigatureSubtable
     driver_context_t dc (this, c);
     driver_context_t dc (this, c);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (dc.ret);
     return_trace (dc.ret);
   }
   }
@@ -618,8 +618,27 @@ struct NoncontextualSubtable
 
 
     hb_glyph_info_t *info = c->buffer->info;
     hb_glyph_info_t *info = c->buffer->info;
     unsigned int count = c->buffer->len;
     unsigned int count = c->buffer->len;
+    // If there's only one range, we already checked the flag.
+    auto *last_range = c->range_flags && (c->range_flags->length > 1) ? &(*c->range_flags)[0] : nullptr;
     for (unsigned int i = 0; i < count; i++)
     for (unsigned int i = 0; i < count; i++)
     {
     {
+      /* This block copied from StateTableDriver::drive. Keep in sync. */
+      if (last_range)
+      {
+	auto *range = last_range;
+	{
+	  unsigned cluster = info[i].cluster;
+	  while (cluster < range->cluster_first)
+	    range--;
+	  while (cluster > range->cluster_last)
+	    range++;
+
+	  last_range = range;
+	}
+	if (!(range->flags & c->subtable_flags))
+	  continue;
+      }
+
       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       const HBGlyphID16 *replacement = substitute.get_value (info[i].codepoint, num_glyphs);
       if (replacement)
       if (replacement)
       {
       {
@@ -820,7 +839,7 @@ struct InsertionSubtable
     driver_context_t dc (this, c);
     driver_context_t dc (this, c);
 
 
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
     StateTableDriver<Types, EntryData> driver (machine, c->buffer, c->face);
-    driver.drive (&dc);
+    driver.drive (&dc, c);
 
 
     return_trace (dc.ret);
     return_trace (dc.ret);
   }
   }
@@ -968,7 +987,7 @@ struct Chain
 	// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
 	// Check whether this type/setting pair was requested in the map, and if so, apply its flags.
 	// (The search here only looks at the type and setting fields of feature_info_t.)
 	// (The search here only looks at the type and setting fields of feature_info_t.)
 	hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
 	hb_aat_map_builder_t::feature_info_t info = { type, setting, false, 0 };
-	if (map->features.bsearch (info))
+	if (map->current_features.bsearch (info))
 	{
 	{
 	  flags &= feature.disableFlags;
 	  flags &= feature.disableFlags;
 	  flags |= feature.enableFlags;
 	  flags |= feature.enableFlags;
@@ -994,8 +1013,7 @@ struct Chain
     return flags;
     return flags;
   }
   }
 
 
-  void apply (hb_aat_apply_context_t *c,
-	      hb_mask_t flags) const
+  void apply (hb_aat_apply_context_t *c) const
   {
   {
     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     const ChainSubtable<Types> *subtable = &StructAfter<ChainSubtable<Types>> (featureZ.as_array (featureCount));
     unsigned int count = subtableCount;
     unsigned int count = subtableCount;
@@ -1003,8 +1021,10 @@ struct Chain
     {
     {
       bool reverse;
       bool reverse;
 
 
-      if (!(subtable->subFeatureFlags & flags))
+      if (hb_none (hb_iter (c->range_flags) |
+		   hb_map ([&subtable] (const hb_aat_map_t::range_flags_t _) -> bool { return subtable->subFeatureFlags & (_.flags); })))
 	goto skip;
 	goto skip;
+      c->subtable_flags = subtable->subFeatureFlags;
 
 
       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
       if (!(subtable->get_coverage() & ChainSubtable<Types>::AllDirections) &&
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
 	  HB_DIRECTION_IS_VERTICAL (c->buffer->props.direction) !=
@@ -1043,7 +1063,7 @@ struct Chain
 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
 		bool (subtable->get_coverage () & ChainSubtable<Types>::Backwards) !=
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 		HB_DIRECTION_IS_BACKWARD (c->buffer->props.direction);
 
 
-      if (!c->buffer->message (c->font, "start chainsubtable %d", c->lookup_index))
+      if (!c->buffer->message (c->font, "start chainsubtable %u", c->lookup_index))
 	goto skip;
 	goto skip;
 
 
       if (reverse)
       if (reverse)
@@ -1054,7 +1074,7 @@ struct Chain
       if (reverse)
       if (reverse)
 	c->buffer->reverse ();
 	c->buffer->reverse ();
 
 
-      (void) c->buffer->message (c->font, "end chainsubtable %d", c->lookup_index);
+      (void) c->buffer->message (c->font, "end chainsubtable %u", c->lookup_index);
 
 
       if (unlikely (!c->buffer->successful)) return;
       if (unlikely (!c->buffer->successful)) return;
 
 
@@ -1120,22 +1140,31 @@ struct mortmorx
   {
   {
     const Chain<Types> *chain = &firstChain;
     const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     unsigned int count = chainCount;
+    if (unlikely (!map->chain_flags.resize (count)))
+      return;
     for (unsigned int i = 0; i < count; i++)
     for (unsigned int i = 0; i < count; i++)
     {
     {
-      map->chain_flags.push (chain->compile_flags (mapper));
+      map->chain_flags[i].push (hb_aat_map_t::range_flags_t {chain->compile_flags (mapper),
+							     mapper->range_first,
+							     mapper->range_last});
       chain = &StructAfter<Chain<Types>> (*chain);
       chain = &StructAfter<Chain<Types>> (*chain);
     }
     }
   }
   }
 
 
-  void apply (hb_aat_apply_context_t *c) const
+  void apply (hb_aat_apply_context_t *c,
+	      const hb_aat_map_t &map) const
   {
   {
     if (unlikely (!c->buffer->successful)) return;
     if (unlikely (!c->buffer->successful)) return;
+
+    c->buffer->unsafe_to_concat ();
+
     c->set_lookup_index (0);
     c->set_lookup_index (0);
     const Chain<Types> *chain = &firstChain;
     const Chain<Types> *chain = &firstChain;
     unsigned int count = chainCount;
     unsigned int count = chainCount;
     for (unsigned int i = 0; i < count; i++)
     for (unsigned int i = 0; i < count; i++)
     {
     {
-      chain->apply (c, c->plan->aat_map.chain_flags[i]);
+      c->range_flags = &map.chain_flags[i];
+      chain->apply (c);
       if (unlikely (!c->buffer->successful)) return;
       if (unlikely (!c->buffer->successful)) return;
       chain = &StructAfter<Chain<Types>> (*chain);
       chain = &StructAfter<Chain<Types>> (*chain);
     }
     }

+ 11 - 3
thirdparty/harfbuzz/src/hb-aat-layout.cc

@@ -244,15 +244,23 @@ hb_aat_layout_has_substitution (hb_face_t *face)
 void
 void
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  hb_font_t *font,
 			  hb_font_t *font,
-			  hb_buffer_t *buffer)
+			  hb_buffer_t *buffer,
+			  const hb_feature_t *features,
+			  unsigned num_features)
 {
 {
+  hb_aat_map_builder_t builder (font->face, plan->props);
+  for (unsigned i = 0; i < num_features; i++)
+    builder.add_feature (features[i]);
+  hb_aat_map_t map;
+  builder.compile (map);
+
   hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
   hb_blob_t *morx_blob = font->face->table.morx.get_blob ();
   const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
   const AAT::morx& morx = *morx_blob->as<AAT::morx> ();
   if (morx.has_data ())
   if (morx.has_data ())
   {
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
     AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
     if (!buffer->message (font, "start table morx")) return;
     if (!buffer->message (font, "start table morx")) return;
-    morx.apply (&c);
+    morx.apply (&c, map);
     (void) buffer->message (font, "end table morx");
     (void) buffer->message (font, "end table morx");
     return;
     return;
   }
   }
@@ -263,7 +271,7 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
   {
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
     AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
     if (!buffer->message (font, "start table mort")) return;
     if (!buffer->message (font, "start table mort")) return;
-    mort.apply (&c);
+    mort.apply (&c, map);
     (void) buffer->message (font, "end table mort");
     (void) buffer->message (font, "end table mort");
     return;
     return;
   }
   }

+ 3 - 1
thirdparty/harfbuzz/src/hb-aat-layout.hh

@@ -53,7 +53,9 @@ hb_aat_layout_compile_map (const hb_aat_map_builder_t *mapper,
 HB_INTERNAL void
 HB_INTERNAL void
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
 			  hb_font_t *font,
 			  hb_font_t *font,
-			  hb_buffer_t *buffer);
+			  hb_buffer_t *buffer,
+			  const hb_feature_t *features,
+			  unsigned num_features);
 
 
 HB_INTERNAL void
 HB_INTERNAL void
 hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);
 hb_aat_layout_zero_width_deleted_glyphs (hb_buffer_t *buffer);

+ 100 - 30
thirdparty/harfbuzz/src/hb-aat-map.cc

@@ -36,27 +36,29 @@
 #include "hb-aat-layout-feat-table.hh"
 #include "hb-aat-layout-feat-table.hh"
 
 
 
 
-void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
+void hb_aat_map_builder_t::add_feature (const hb_feature_t &feature)
 {
 {
   if (!face->table.feat->has_data ()) return;
   if (!face->table.feat->has_data ()) return;
 
 
-  if (tag == HB_TAG ('a','a','l','t'))
+  if (feature.tag == HB_TAG ('a','a','l','t'))
   {
   {
     if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
     if (!face->table.feat->exposes_feature (HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES))
       return;
       return;
-    feature_info_t *info = features.push();
-    info->type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
-    info->setting = (hb_aat_layout_feature_selector_t) value;
-    info->seq = features.length;
-    info->is_exclusive = true;
+    feature_range_t *range = features.push();
+    range->start = feature.start;
+    range->end = feature.end;
+    range->info.type = HB_AAT_LAYOUT_FEATURE_TYPE_CHARACTER_ALTERNATIVES;
+    range->info.setting = (hb_aat_layout_feature_selector_t) feature.value;
+    range->info.seq = features.length;
+    range->info.is_exclusive = true;
     return;
     return;
   }
   }
 
 
-  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (tag);
+  const hb_aat_feature_mapping_t *mapping = hb_aat_layout_find_feature_mapping (feature.tag);
   if (!mapping) return;
   if (!mapping) return;
 
 
-  const AAT::FeatureName* feature = &face->table.feat->get_feature (mapping->aatFeatureType);
-  if (!feature->has_data ())
+  const AAT::FeatureName* feature_name = &face->table.feat->get_feature (mapping->aatFeatureType);
+  if (!feature_name->has_data ())
   {
   {
     /* Special case: Chain::compile_flags will fall back to the deprecated version of
     /* Special case: Chain::compile_flags will fall back to the deprecated version of
      * small-caps if necessary, so we need to check for that possibility.
      * small-caps if necessary, so we need to check for that possibility.
@@ -64,38 +66,106 @@ void hb_aat_map_builder_t::add_feature (hb_tag_t tag, unsigned value)
     if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
     if (mapping->aatFeatureType == HB_AAT_LAYOUT_FEATURE_TYPE_LOWER_CASE &&
 	mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
 	mapping->selectorToEnable == HB_AAT_LAYOUT_FEATURE_SELECTOR_LOWER_CASE_SMALL_CAPS)
     {
     {
-      feature = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
-      if (!feature->has_data ()) return;
+      feature_name = &face->table.feat->get_feature (HB_AAT_LAYOUT_FEATURE_TYPE_LETTER_CASE);
+      if (!feature_name->has_data ()) return;
     }
     }
     else return;
     else return;
   }
   }
 
 
-  feature_info_t *info = features.push();
-  info->type = mapping->aatFeatureType;
-  info->setting = value ? mapping->selectorToEnable : mapping->selectorToDisable;
-  info->seq = features.length;
-  info->is_exclusive = feature->is_exclusive ();
+  feature_range_t *range = features.push();
+  range->start = feature.start;
+  range->end = feature.end;
+  range->info.type = mapping->aatFeatureType;
+  range->info.setting = feature.value ? mapping->selectorToEnable : mapping->selectorToDisable;
+  range->info.seq = features.length;
+  range->info.is_exclusive = feature_name->is_exclusive ();
 }
 }
 
 
 void
 void
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 hb_aat_map_builder_t::compile (hb_aat_map_t  &m)
 {
 {
-  /* Sort features and merge duplicates */
-  if (features.length)
+  /* Compute active features per range, and compile each. */
+
+  /* Sort features by start/end events. */
+  hb_vector_t<feature_event_t> feature_events;
+  for (unsigned int i = 0; i < features.length; i++)
+  {
+    auto &feature = features[i];
+
+    if (features[i].start == features[i].end)
+      continue;
+
+    feature_event_t *event;
+
+    event = feature_events.push ();
+    event->index = features[i].start;
+    event->start = true;
+    event->feature = feature.info;
+
+    event = feature_events.push ();
+    event->index = features[i].end;
+    event->start = false;
+    event->feature = feature.info;
+  }
+  feature_events.qsort ();
+  /* Add a strategic final event. */
+  {
+    feature_info_t feature;
+    feature.seq = features.length + 1;
+
+    feature_event_t *event = feature_events.push ();
+    event->index = -1; /* This value does magic. */
+    event->start = false;
+    event->feature = feature;
+  }
+
+  /* Scan events and save features for each range. */
+  hb_sorted_vector_t<feature_info_t> active_features;
+  unsigned int last_index = 0;
+  for (unsigned int i = 0; i < feature_events.length; i++)
   {
   {
-    features.qsort ();
-    unsigned int j = 0;
-    for (unsigned int i = 1; i < features.length; i++)
-      if (features[i].type != features[j].type ||
-	  /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
-	   * respectively, so we mask out the low-order bit when checking for "duplicates"
-	   * (selectors referring to the same feature setting) here. */
-	  (!features[i].is_exclusive && ((features[i].setting & ~1) != (features[j].setting & ~1))))
-	features[++j] = features[i];
-    features.shrink (j + 1);
+    feature_event_t *event = &feature_events[i];
+
+    if (event->index != last_index)
+    {
+      /* Save a snapshot of active features and the range. */
+
+      /* Sort features and merge duplicates */
+      current_features = active_features;
+      range_first = last_index;
+      range_last = event->index - 1;
+      if (current_features.length)
+      {
+	current_features.qsort ();
+	unsigned int j = 0;
+	for (unsigned int i = 1; i < current_features.length; i++)
+	  if (current_features[i].type != current_features[j].type ||
+	      /* Nonexclusive feature selectors come in even/odd pairs to turn a setting on/off
+	       * respectively, so we mask out the low-order bit when checking for "duplicates"
+	       * (selectors referring to the same feature setting) here. */
+	      (!current_features[i].is_exclusive && ((current_features[i].setting & ~1) != (current_features[j].setting & ~1))))
+	    current_features[++j] = current_features[i];
+	current_features.shrink (j + 1);
+      }
+
+      hb_aat_layout_compile_map (this, &m);
+
+      last_index = event->index;
+    }
+
+    if (event->start)
+    {
+      active_features.push (event->feature);
+    } else {
+      feature_info_t *feature = active_features.lsearch (event->feature);
+      if (feature)
+	active_features.remove_ordered (feature - active_features.arrayZ);
+    }
   }
   }
 
 
-  hb_aat_layout_compile_map (this, &m);
+  for (auto &chain_flags : m.chain_flags)
+    // With our above setup this value is one less than desired; adjust it.
+    chain_flags.tail().cluster_last = HB_FEATURE_GLOBAL_END;
 }
 }
 
 
 
 

+ 35 - 10
thirdparty/harfbuzz/src/hb-aat-map.hh

@@ -35,16 +35,15 @@ struct hb_aat_map_t
   friend struct hb_aat_map_builder_t;
   friend struct hb_aat_map_builder_t;
 
 
   public:
   public:
-
-  void init ()
+  struct range_flags_t
   {
   {
-    hb_memset (this, 0, sizeof (*this));
-    chain_flags.init ();
-  }
-  void fini () { chain_flags.fini (); }
+    hb_mask_t flags;
+    unsigned cluster_first;
+    unsigned cluster_last; // end - 1
+  };
 
 
   public:
   public:
-  hb_vector_t<hb_mask_t> chain_flags;
+  hb_vector_t<hb_sorted_vector_t<range_flags_t>> chain_flags;
 };
 };
 
 
 struct hb_aat_map_builder_t
 struct hb_aat_map_builder_t
@@ -56,7 +55,7 @@ struct hb_aat_map_builder_t
 				      face (face_),
 				      face (face_),
 				      props (props_) {}
 				      props (props_) {}
 
 
-  HB_INTERNAL void add_feature (hb_tag_t tag, unsigned int value=1);
+  HB_INTERNAL void add_feature (const hb_feature_t &feature);
 
 
   HB_INTERNAL void compile (hb_aat_map_t  &m);
   HB_INTERNAL void compile (hb_aat_map_t  &m);
 
 
@@ -78,7 +77,7 @@ struct hb_aat_map_builder_t
 	    return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
 	    return (a->seq < b->seq ? -1 : a->seq > b->seq ? 1 : 0);
     }
     }
 
 
-    /* compares type & setting only, not is_exclusive flag or seq number */
+    /* compares type & setting only */
     int cmp (const feature_info_t& f) const
     int cmp (const feature_info_t& f) const
     {
     {
       return (f.type != type) ? (f.type < type ? -1 : 1) :
       return (f.type != type) ? (f.type < type ? -1 : 1) :
@@ -86,12 +85,38 @@ struct hb_aat_map_builder_t
     }
     }
   };
   };
 
 
+  struct feature_range_t
+  {
+    feature_info_t info;
+    unsigned start;
+    unsigned end;
+  };
+
+  private:
+  struct feature_event_t
+  {
+    unsigned int index;
+    bool start;
+    feature_info_t feature;
+
+    HB_INTERNAL static int cmp (const void *pa, const void *pb) {
+      const feature_event_t *a = (const feature_event_t *) pa;
+      const feature_event_t *b = (const feature_event_t *) pb;
+      return a->index < b->index ? -1 : a->index > b->index ? 1 :
+	     a->start < b->start ? -1 : a->start > b->start ? 1 :
+	     feature_info_t::cmp (&a->feature, &b->feature);
+    }
+  };
+
   public:
   public:
   hb_face_t *face;
   hb_face_t *face;
   hb_segment_properties_t props;
   hb_segment_properties_t props;
 
 
   public:
   public:
-  hb_sorted_vector_t<feature_info_t> features;
+  hb_sorted_vector_t<feature_range_t> features;
+  hb_sorted_vector_t<feature_info_t> current_features;
+  unsigned range_first = HB_FEATURE_GLOBAL_START;
+  unsigned range_last = HB_FEATURE_GLOBAL_END;
 };
 };
 
 
 
 

+ 80 - 8
thirdparty/harfbuzz/src/hb-algs.hh

@@ -110,9 +110,10 @@ struct BEInt<Type, 2>
   constexpr operator Type () const
   constexpr operator Type () const
   {
   {
 #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
 #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
     defined(__BYTE_ORDER) && \
     defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+    (__BYTE_ORDER == __BIG_ENDIAN || \
+     (__BYTE_ORDER == __LITTLE_ENDIAN && \
+      hb_has_builtin(__builtin_bswap16)))
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -155,9 +156,10 @@ struct BEInt<Type, 4>
   struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
   struct __attribute__((packed)) packed_uint32_t { uint32_t v; };
   constexpr operator Type () const {
   constexpr operator Type () const {
 #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
 #if defined(__OPTIMIZE__) && !defined(HB_NO_PACKED) && \
-    ((defined(__GNUC__) && __GNUC__ >= 5) || defined(__clang__)) && \
     defined(__BYTE_ORDER) && \
     defined(__BYTE_ORDER) && \
-    (__BYTE_ORDER == __LITTLE_ENDIAN || __BYTE_ORDER == __BIG_ENDIAN)
+    (__BYTE_ORDER == __BIG_ENDIAN || \
+     (__BYTE_ORDER == __LITTLE_ENDIAN && \
+      hb_has_builtin(__builtin_bswap32)))
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
     /* Spoon-feed the compiler a big-endian integer with alignment 1.
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
      * https://github.com/harfbuzz/harfbuzz/pull/1398 */
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 #if __BYTE_ORDER == __LITTLE_ENDIAN
@@ -598,13 +600,17 @@ template <typename T>
 static inline unsigned int
 static inline unsigned int
 hb_popcount (T v)
 hb_popcount (T v)
 {
 {
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_popcount)
   if (sizeof (T) <= sizeof (unsigned int))
   if (sizeof (T) <= sizeof (unsigned int))
     return __builtin_popcount (v);
     return __builtin_popcount (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_popcountl)
   if (sizeof (T) <= sizeof (unsigned long))
   if (sizeof (T) <= sizeof (unsigned long))
     return __builtin_popcountl (v);
     return __builtin_popcountl (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_popcountll)
   if (sizeof (T) <= sizeof (unsigned long long))
   if (sizeof (T) <= sizeof (unsigned long long))
     return __builtin_popcountll (v);
     return __builtin_popcountll (v);
 #endif
 #endif
@@ -641,13 +647,17 @@ hb_bit_storage (T v)
 {
 {
   if (unlikely (!v)) return 0;
   if (unlikely (!v)) return 0;
 
 
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_clz)
   if (sizeof (T) <= sizeof (unsigned int))
   if (sizeof (T) <= sizeof (unsigned int))
     return sizeof (unsigned int) * 8 - __builtin_clz (v);
     return sizeof (unsigned int) * 8 - __builtin_clz (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_clzl)
   if (sizeof (T) <= sizeof (unsigned long))
   if (sizeof (T) <= sizeof (unsigned long))
     return sizeof (unsigned long) * 8 - __builtin_clzl (v);
     return sizeof (unsigned long) * 8 - __builtin_clzl (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_clzll)
   if (sizeof (T) <= sizeof (unsigned long long))
   if (sizeof (T) <= sizeof (unsigned long long))
     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
     return sizeof (unsigned long long) * 8 - __builtin_clzll (v);
 #endif
 #endif
@@ -715,13 +725,17 @@ hb_ctz (T v)
 {
 {
   if (unlikely (!v)) return 8 * sizeof (T);
   if (unlikely (!v)) return 8 * sizeof (T);
 
 
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_ctz)
   if (sizeof (T) <= sizeof (unsigned int))
   if (sizeof (T) <= sizeof (unsigned int))
     return __builtin_ctz (v);
     return __builtin_ctz (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_ctzl)
   if (sizeof (T) <= sizeof (unsigned long))
   if (sizeof (T) <= sizeof (unsigned long))
     return __builtin_ctzl (v);
     return __builtin_ctzl (v);
+#endif
 
 
+#if hb_has_builtin(__builtin_ctzll)
   if (sizeof (T) <= sizeof (unsigned long long))
   if (sizeof (T) <= sizeof (unsigned long long))
     return __builtin_ctzll (v);
     return __builtin_ctzll (v);
 #endif
 #endif
@@ -875,7 +889,7 @@ hb_in_ranges (T u, T lo1, T hi1, Ts... ds)
 static inline bool
 static inline bool
 hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
 hb_unsigned_mul_overflows (unsigned int count, unsigned int size, unsigned *result = nullptr)
 {
 {
-#if (defined(__GNUC__) && (__GNUC__ >= 4)) || defined(__clang__)
+#if hb_has_builtin(__builtin_mul_overflow)
   unsigned stack_result;
   unsigned stack_result;
   if (!result)
   if (!result)
     result = &stack_result;
     result = &stack_result;
@@ -1330,4 +1344,62 @@ struct
 HB_FUNCOBJ (hb_dec);
 HB_FUNCOBJ (hb_dec);
 
 
 
 
+/* Adapted from kurbo implementation with extra parameters added,
+ * and finding for a particular range instead of 0.
+ *
+ * For documentation and implementation see:
+ *
+ * [ITP method]: https://en.wikipedia.org/wiki/ITP_Method
+ * [An Enhancement of the Bisection Method Average Performance Preserving Minmax Optimality]: https://dl.acm.org/doi/10.1145/3423597
+ * https://docs.rs/kurbo/0.8.1/kurbo/common/fn.solve_itp.html
+ * https://github.com/linebender/kurbo/blob/fd839c25ea0c98576c7ce5789305822675a89938/src/common.rs#L162-L248
+ */
+template <typename func_t>
+double solve_itp (func_t f,
+		  double a, double b,
+		  double epsilon,
+		  double min_y, double max_y,
+		  double &ya, double &yb, double &y)
+{
+  unsigned n1_2 = (unsigned) (hb_max (ceil (log2 ((b - a) / epsilon)) - 1.0, 0.0));
+  const unsigned n0 = 1; // Hardwired
+  const double k1 = 0.2 / (b - a); // Hardwired.
+  unsigned nmax = n0 + n1_2;
+  double scaled_epsilon = epsilon * double (1llu << nmax);
+  double _2_epsilon = 2.0 * epsilon;
+  while (b - a > _2_epsilon)
+  {
+    double x1_2 = 0.5 * (a + b);
+    double r = scaled_epsilon - 0.5 * (b - a);
+    double xf = (yb * a - ya * b) / (yb - ya);
+    double sigma = x1_2 - xf;
+    double b_a = b - a;
+    // This has k2 = 2 hardwired for efficiency.
+    double b_a_k2 = b_a * b_a;
+    double delta = k1 * b_a_k2;
+    int sigma_sign = sigma >= 0 ? +1 : -1;
+    double xt = delta <= fabs (x1_2 - xf) ? xf + delta * sigma_sign : x1_2;
+    double xitp = fabs (xt - x1_2) <= r ? xt : x1_2 - r * sigma_sign;
+    double yitp = f (xitp);
+    if (yitp > max_y)
+    {
+      b = xitp;
+      yb = yitp;
+    }
+    else if (yitp < min_y)
+    {
+      a = xitp;
+      ya = yitp;
+    }
+    else
+    {
+      y = yitp;
+      return xitp;
+    }
+    scaled_epsilon *= 0.5;
+  }
+  return 0.5 * (a + b);
+}
+
+
 #endif /* HB_ALGS_HH */
 #endif /* HB_ALGS_HH */

+ 3 - 0
thirdparty/harfbuzz/src/hb-array.hh

@@ -304,6 +304,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
   unsigned int backwards_length = 0;
   unsigned int backwards_length = 0;
 };
 };
 template <typename T> inline hb_array_t<T>
 template <typename T> inline hb_array_t<T>
+hb_array ()
+{ return hb_array_t<T> (); }
+template <typename T> inline hb_array_t<T>
 hb_array (T *array, unsigned int length)
 hb_array (T *array, unsigned int length)
 { return hb_array_t<T> (array, length); }
 { return hb_array_t<T> (array, length); }
 template <typename T, unsigned int length_> inline hb_array_t<T>
 template <typename T, unsigned int length_> inline hb_array_t<T>

+ 33 - 8
thirdparty/harfbuzz/src/hb-atomic.hh

@@ -84,11 +84,11 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #define _hb_memory_r_barrier()			std::atomic_thread_fence(std::memory_order_acquire)
 #define _hb_memory_r_barrier()			std::atomic_thread_fence(std::memory_order_acquire)
 #define _hb_memory_w_barrier()			std::atomic_thread_fence(std::memory_order_release)
 #define _hb_memory_w_barrier()			std::atomic_thread_fence(std::memory_order_release)
 
 
-#define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<int> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
-#define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_relaxed))
-#define hb_atomic_int_impl_set(AI, V)		(reinterpret_cast<std::atomic<int> *> (AI)->store ((V), std::memory_order_release))
-#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_relaxed))
-#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<int> const *> (AI)->load (std::memory_order_acquire))
+#define hb_atomic_int_impl_add(AI, V)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->fetch_add ((V), std::memory_order_acq_rel))
+#define hb_atomic_int_impl_set_relaxed(AI, V)	(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_relaxed))
+#define hb_atomic_int_impl_set(AI, V)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> *> (AI)->store ((V), std::memory_order_release))
+#define hb_atomic_int_impl_get_relaxed(AI)	(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_relaxed))
+#define hb_atomic_int_impl_get(AI)		(reinterpret_cast<std::atomic<std::decay<decltype (*(AI))>::type> const *> (AI)->load (std::memory_order_acquire))
 
 
 #define hb_atomic_ptr_impl_set_relaxed(P, V)	(reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_set_relaxed(P, V)	(reinterpret_cast<std::atomic<void*> *> (P)->store ((V), std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
 #define hb_atomic_ptr_impl_get_relaxed(P)	(reinterpret_cast<std::atomic<void*> const *> (P)->load (std::memory_order_relaxed))
@@ -111,10 +111,15 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 #endif
 
 
 
 
+/* This should never be disabled, even under HB_NO_MT.
+ * except that MSVC gives me an internal compiler error, so disabled there.
+ *
+ * https://github.com/harfbuzz/harfbuzz/pull/4119
+ */
 #ifndef _hb_compiler_memory_r_barrier
 #ifndef _hb_compiler_memory_r_barrier
-/* This we always use std::atomic for; and should never be disabled...
- * except that MSVC gives me an internal compiler error on it. */
-#if !defined(_MSC_VER)
+#if defined(__ATOMIC_ACQUIRE) // gcc-like
+#define _hb_compiler_memory_r_barrier() asm volatile("": : :"memory")
+#elif !defined(_MSC_VER)
 #include <atomic>
 #include <atomic>
 #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
 #define _hb_compiler_memory_r_barrier() std::atomic_signal_fence (std::memory_order_acquire)
 #else
 #else
@@ -145,15 +150,35 @@ _hb_atomic_ptr_impl_cmplexch (const void **P, const void *O_, const void *N)
 #endif
 #endif
 #ifndef hb_atomic_int_impl_set
 #ifndef hb_atomic_int_impl_set
 inline void hb_atomic_int_impl_set (int *AI, int v)	{ _hb_memory_w_barrier (); *AI = v; }
 inline void hb_atomic_int_impl_set (int *AI, int v)	{ _hb_memory_w_barrier (); *AI = v; }
+inline void hb_atomic_int_impl_set (short *AI, short v)	{ _hb_memory_w_barrier (); *AI = v; }
 #endif
 #endif
 #ifndef hb_atomic_int_impl_get
 #ifndef hb_atomic_int_impl_get
 inline int hb_atomic_int_impl_get (const int *AI)	{ int v = *AI; _hb_memory_r_barrier (); return v; }
 inline int hb_atomic_int_impl_get (const int *AI)	{ int v = *AI; _hb_memory_r_barrier (); return v; }
+inline short hb_atomic_int_impl_get (const short *AI)	{ short v = *AI; _hb_memory_r_barrier (); return v; }
 #endif
 #endif
 #ifndef hb_atomic_ptr_impl_get
 #ifndef hb_atomic_ptr_impl_get
 inline void *hb_atomic_ptr_impl_get (void ** const P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
 inline void *hb_atomic_ptr_impl_get (void ** const P)	{ void *v = *P; _hb_memory_r_barrier (); return v; }
 #endif
 #endif
 
 
 
 
+struct hb_atomic_short_t
+{
+  hb_atomic_short_t () = default;
+  constexpr hb_atomic_short_t (short v) : v (v) {}
+
+  hb_atomic_short_t& operator = (short v_) { set_relaxed (v_); return *this; }
+  operator short () const { return get_relaxed (); }
+
+  void set_relaxed (short v_) { hb_atomic_int_impl_set_relaxed (&v, v_); }
+  void set_release (short v_) { hb_atomic_int_impl_set (&v, v_); }
+  short get_relaxed () const { return hb_atomic_int_impl_get_relaxed (&v); }
+  short get_acquire () const { return hb_atomic_int_impl_get (&v); }
+  short inc () { return hb_atomic_int_impl_add (&v,  1); }
+  short dec () { return hb_atomic_int_impl_add (&v, -1); }
+
+  short v = 0;
+};
+
 struct hb_atomic_int_t
 struct hb_atomic_int_t
 {
 {
   hb_atomic_int_t () = default;
   hb_atomic_int_t () = default;

+ 18 - 8
thirdparty/harfbuzz/src/hb-bit-page.hh

@@ -34,14 +34,24 @@
 /* Compiler-assisted vectorization. */
 /* Compiler-assisted vectorization. */
 
 
 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
 /* Type behaving similar to vectorized vars defined using __attribute__((vector_size(...))),
- * basically a fixed-size bitset. */
+ * basically a fixed-size bitset. We can't use the compiler type because hb_vector_t cannot
+ * guarantee alignment requirements. */
 template <typename elt_t, unsigned int byte_size>
 template <typename elt_t, unsigned int byte_size>
 struct hb_vector_size_t
 struct hb_vector_size_t
 {
 {
   elt_t& operator [] (unsigned int i) { return v[i]; }
   elt_t& operator [] (unsigned int i) { return v[i]; }
   const elt_t& operator [] (unsigned int i) const { return v[i]; }
   const elt_t& operator [] (unsigned int i) const { return v[i]; }
 
 
-  void clear (unsigned char v = 0) { hb_memset (this, v, sizeof (*this)); }
+  void init0 ()
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      v[i] = 0;
+  }
+  void init1 ()
+  {
+    for (unsigned int i = 0; i < ARRAY_LENGTH (v); i++)
+      v[i] = (elt_t) -1;
+  }
 
 
   template <typename Op>
   template <typename Op>
   hb_vector_size_t process (const Op& op) const
   hb_vector_size_t process (const Op& op) const
@@ -79,10 +89,10 @@ struct hb_vector_size_t
 
 
 struct hb_bit_page_t
 struct hb_bit_page_t
 {
 {
-  void init0 () { v.clear (); }
-  void init1 () { v.clear (0xFF); }
+  void init0 () { v.init0 (); }
+  void init1 () { v.init1 (); }
 
 
-  constexpr unsigned len () const
+  static inline constexpr unsigned len ()
   { return ARRAY_LENGTH_CONST (v); }
   { return ARRAY_LENGTH_CONST (v); }
 
 
   bool is_empty () const
   bool is_empty () const
@@ -300,10 +310,10 @@ struct hb_bit_page_t
   static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
   static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
 
 
   typedef unsigned long long elt_t;
   typedef unsigned long long elt_t;
-  static constexpr unsigned PAGE_BITS = 512;
-  static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
-  static constexpr unsigned PAGE_BITS_LOG_2 = 9;
+  static constexpr unsigned PAGE_BITS_LOG_2 = 9; // 512 bits
+  static constexpr unsigned PAGE_BITS = 1 << PAGE_BITS_LOG_2;
   static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
   static_assert (1 << PAGE_BITS_LOG_2 == PAGE_BITS, "");
+  static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
   static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
   static constexpr unsigned PAGE_BITMASK = PAGE_BITS - 1;
 
 
   static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
   static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }

+ 5 - 0
thirdparty/harfbuzz/src/hb-bit-set-invertible.hh

@@ -74,6 +74,11 @@ struct hb_bit_set_invertible_t
       inverted = !inverted;
       inverted = !inverted;
   }
   }
 
 
+  bool is_inverted () const
+  {
+    return inverted;
+  }
+
   bool is_empty () const
   bool is_empty () const
   {
   {
     hb_codepoint_t v = INVALID;
     hb_codepoint_t v = INVALID;

+ 11 - 7
thirdparty/harfbuzz/src/hb-bit-set.hh

@@ -38,7 +38,7 @@ struct hb_bit_set_t
   hb_bit_set_t () = default;
   hb_bit_set_t () = default;
   ~hb_bit_set_t () = default;
   ~hb_bit_set_t () = default;
 
 
-  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
+  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other, true); }
   hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
   hb_bit_set_t ( hb_bit_set_t&& other) : hb_bit_set_t () { hb_swap (*this, other); }
   hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
   hb_bit_set_t& operator= (const hb_bit_set_t& other) { set (other); return *this; }
   hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
   hb_bit_set_t& operator= (hb_bit_set_t&& other) { hb_swap (*this, other); return *this; }
@@ -85,12 +85,16 @@ struct hb_bit_set_t
   void err () { if (successful) successful = false; } /* TODO Remove */
   void err () { if (successful) successful = false; } /* TODO Remove */
   bool in_error () const { return !successful; }
   bool in_error () const { return !successful; }
 
 
-  bool resize (unsigned int count, bool clear = true)
+  bool resize (unsigned int count, bool clear = true, bool exact_size = false)
   {
   {
     if (unlikely (!successful)) return false;
     if (unlikely (!successful)) return false;
-    if (unlikely (!pages.resize (count, clear) || !page_map.resize (count, clear)))
+
+    if (pages.length == 0 && count == 1)
+      exact_size = true; // Most sets are small and local
+
+    if (unlikely (!pages.resize (count, clear, exact_size) || !page_map.resize (count, clear, exact_size)))
     {
     {
-      pages.resize (page_map.length);
+      pages.resize (page_map.length, clear, exact_size);
       successful = false;
       successful = false;
       return false;
       return false;
     }
     }
@@ -346,11 +350,11 @@ struct hb_bit_set_t
     hb_codepoint_t c = first - 1;
     hb_codepoint_t c = first - 1;
     return next (&c) && c <= last;
     return next (&c) && c <= last;
   }
   }
-  void set (const hb_bit_set_t &other)
+  void set (const hb_bit_set_t &other, bool exact_size = false)
   {
   {
     if (unlikely (!successful)) return;
     if (unlikely (!successful)) return;
     unsigned int count = other.pages.length;
     unsigned int count = other.pages.length;
-    if (unlikely (!resize (count, false)))
+    if (unlikely (!resize (count, false, exact_size)))
       return;
       return;
     population = other.population;
     population = other.population;
 
 
@@ -422,7 +426,7 @@ struct hb_bit_set_t
   private:
   private:
   bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
   bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
   {
   {
-    if (unlikely (!workspace.resize (pages.length)))
+    if (unlikely (!workspace.resize_exact (pages.length)))
     {
     {
       successful = false;
       successful = false;
       return false;
       return false;

+ 3 - 3
thirdparty/harfbuzz/src/hb-blob.cc

@@ -676,7 +676,7 @@ fail_without_close:
   wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
   wchar_t * wchar_file_name = (wchar_t *) hb_malloc (sizeof (wchar_t) * size);
   if (unlikely (!wchar_file_name)) goto fail_without_close;
   if (unlikely (!wchar_file_name)) goto fail_without_close;
   mbstowcs (wchar_file_name, file_name, size);
   mbstowcs (wchar_file_name, file_name, size);
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   {
   {
     CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
     CREATEFILE2_EXTENDED_PARAMETERS ceparams = { 0 };
     ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
     ceparams.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
@@ -697,7 +697,7 @@ fail_without_close:
 
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
 
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   {
   {
     LARGE_INTEGER length;
     LARGE_INTEGER length;
     GetFileSizeEx (fd, &length);
     GetFileSizeEx (fd, &length);
@@ -710,7 +710,7 @@ fail_without_close:
 #endif
 #endif
   if (unlikely (!file->mapping)) goto fail;
   if (unlikely (!file->mapping)) goto fail;
 
 
-#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
+#if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
   file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
   file->contents = (char *) MapViewOfFileFromApp (file->mapping, FILE_MAP_READ, 0, 0);
 #else
 #else
   file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);
   file->contents = (char *) MapViewOfFile (file->mapping, FILE_MAP_READ, 0, 0, 0);

+ 1 - 1
thirdparty/harfbuzz/src/hb-blob.h

@@ -63,7 +63,7 @@ HB_BEGIN_DECLS
  *   HarfBuzz and doing that just once (no reuse!),
  *   HarfBuzz and doing that just once (no reuse!),
  *
  *
  * - If the font is mmap()ed, it's okay to use
  * - If the font is mmap()ed, it's okay to use
- *   @HB_MEMORY_READONLY_MAY_MAKE_WRITABLE, however, using that mode
+ *   @HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, however, using that mode
  *   correctly is very tricky.  Use @HB_MEMORY_MODE_READONLY instead.
  *   correctly is very tricky.  Use @HB_MEMORY_MODE_READONLY instead.
  **/
  **/
 typedef enum {
 typedef enum {

+ 185 - 187
thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh

@@ -35,34 +35,34 @@
 #line 33 "hb-buffer-deserialize-json.hh"
 #line 33 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
 static const unsigned char _deserialize_json_trans_keys[] = {
 	0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
 	0u, 0u, 9u, 123u, 9u, 34u, 97u, 117u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 
-	48u, 57u, 9u, 125u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 
-	9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 
-	120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 
-	9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 
-	9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 9u, 125u, 
-	34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 9u, 93u, 
+	48u, 57u, 9u, 125u, 9u, 125u, 9u, 93u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 
+	48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
+	9u, 125u, 120u, 121u, 34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 
+	34u, 34u, 9u, 58u, 9u, 57u, 48u, 57u, 9u, 125u, 9u, 125u, 108u, 108u, 34u, 34u, 
+	9u, 58u, 9u, 57u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 34u, 92u, 
+	9u, 125u, 34u, 92u, 9u, 125u, 9u, 125u, 34u, 34u, 9u, 58u, 9u, 57u, 9u, 125u, 
 	9u, 123u, 0u, 0u, 0
 	9u, 123u, 0u, 0u, 0
 };
 };
 
 
 static const char _deserialize_json_key_spans[] = {
 static const char _deserialize_json_key_spans[] = {
 	0, 115, 26, 21, 2, 1, 50, 49, 
 	0, 115, 26, 21, 2, 1, 50, 49, 
-	10, 117, 117, 117, 1, 50, 49, 10, 
-	117, 117, 1, 1, 50, 49, 117, 117, 
-	2, 1, 50, 49, 10, 117, 117, 1, 
-	50, 49, 10, 117, 117, 1, 1, 50, 
-	49, 117, 117, 1, 50, 49, 59, 117, 
-	59, 117, 117, 1, 50, 49, 117, 85, 
+	10, 117, 117, 85, 117, 1, 50, 49, 
+	10, 117, 117, 1, 1, 50, 49, 117, 
+	117, 2, 1, 50, 49, 10, 117, 117, 
+	1, 50, 49, 10, 117, 117, 1, 1, 
+	50, 49, 117, 117, 1, 50, 49, 59, 
+	117, 59, 117, 117, 1, 50, 49, 117, 
 	115, 0
 	115, 0
 };
 };
 
 
 static const short _deserialize_json_index_offsets[] = {
 static const short _deserialize_json_index_offsets[] = {
 	0, 0, 116, 143, 165, 168, 170, 221, 
 	0, 0, 116, 143, 165, 168, 170, 221, 
-	271, 282, 400, 518, 636, 638, 689, 739, 
-	750, 868, 986, 988, 990, 1041, 1091, 1209, 
-	1327, 1330, 1332, 1383, 1433, 1444, 1562, 1680, 
-	1682, 1733, 1783, 1794, 1912, 2030, 2032, 2034, 
-	2085, 2135, 2253, 2371, 2373, 2424, 2474, 2534, 
-	2652, 2712, 2830, 2948, 2950, 3001, 3051, 3169, 
+	271, 282, 400, 518, 604, 722, 724, 775, 
+	825, 836, 954, 1072, 1074, 1076, 1127, 1177, 
+	1295, 1413, 1416, 1418, 1469, 1519, 1530, 1648, 
+	1766, 1768, 1819, 1869, 1880, 1998, 2116, 2118, 
+	2120, 2171, 2221, 2339, 2457, 2459, 2510, 2560, 
+	2620, 2738, 2798, 2916, 3034, 3036, 3087, 3137, 
 	3255, 3371
 	3255, 3371
 };
 };
 
 
@@ -131,57 +131,54 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 24, 1, 20, 
-	20, 20, 20, 20, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 20, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 21, 1, 1, 1, 19, 19, 
-	19, 19, 19, 19, 19, 19, 19, 19, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 24, 1, 25, 
+	25, 25, 25, 25, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 25, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 26, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 22, 1, 25, 1, 25, 
-	25, 25, 25, 25, 1, 1, 1, 1, 
+	1, 1, 1, 27, 1, 20, 20, 20, 
+	20, 20, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 25, 1, 
+	1, 1, 1, 1, 20, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	21, 1, 1, 1, 19, 19, 19, 19, 
+	19, 19, 19, 19, 19, 19, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	26, 1, 26, 26, 26, 26, 26, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 26, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 27, 1, 
-	1, 28, 29, 29, 29, 29, 29, 29, 
-	29, 29, 29, 1, 30, 31, 31, 31, 
-	31, 31, 31, 31, 31, 31, 1, 32, 
-	32, 32, 32, 32, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 32, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 33, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 22, 1, 28, 1, 28, 28, 28, 
+	28, 28, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 28, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 29, 1, 
+	29, 29, 29, 29, 29, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 29, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 30, 1, 1, 31, 
+	32, 32, 32, 32, 32, 32, 32, 32, 
+	32, 1, 33, 34, 34, 34, 34, 34, 
+	34, 34, 34, 34, 1, 35, 35, 35, 
+	35, 35, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 35, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 34, 1, 32, 32, 32, 
-	32, 32, 1, 1, 1, 1, 1, 1, 
+	36, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 32, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	33, 1, 1, 1, 31, 31, 31, 31, 
-	31, 31, 31, 31, 31, 31, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
@@ -189,291 +186,294 @@ static const char _deserialize_json_indicies[] = {
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 37, 1, 35, 35, 35, 35, 35, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 34, 1, 35, 1, 36, 1, 36, 
-	36, 36, 36, 36, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 35, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 36, 1, 
 	1, 1, 1, 1, 1, 1, 36, 1, 
+	1, 1, 34, 34, 34, 34, 34, 34, 
+	34, 34, 34, 34, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	37, 1, 37, 37, 37, 37, 37, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 37, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 38, 39, 39, 39, 39, 39, 39, 
-	39, 39, 39, 1, 40, 40, 40, 40, 
-	40, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 40, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 41, 
+	1, 1, 1, 1, 1, 1, 1, 37, 
+	1, 38, 1, 39, 1, 39, 39, 39, 
+	39, 39, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 39, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 40, 1, 
+	40, 40, 40, 40, 40, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 40, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 41, 
+	42, 42, 42, 42, 42, 42, 42, 42, 
+	42, 1, 43, 43, 43, 43, 43, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 43, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 44, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	42, 1, 40, 40, 40, 40, 40, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 40, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 41, 1, 1, 
-	1, 43, 43, 43, 43, 43, 43, 43, 
-	43, 43, 43, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 45, 1, 
+	43, 43, 43, 43, 43, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 43, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 44, 1, 1, 1, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 42, 1, 
-	44, 45, 1, 46, 1, 46, 46, 46, 
-	46, 46, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 46, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 47, 1, 
-	47, 47, 47, 47, 47, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 47, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 48, 1, 1, 49, 
-	50, 50, 50, 50, 50, 50, 50, 50, 
-	50, 1, 51, 52, 52, 52, 52, 52, 
-	52, 52, 52, 52, 1, 53, 53, 53, 
-	53, 53, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 53, 1, 1, 1, 
+	1, 1, 1, 1, 45, 1, 47, 48, 
+	1, 49, 1, 49, 49, 49, 49, 49, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	54, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 49, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 50, 1, 50, 50, 
+	50, 50, 50, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 50, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 51, 1, 1, 52, 53, 53, 
+	53, 53, 53, 53, 53, 53, 53, 1, 
+	54, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 1, 56, 56, 56, 56, 56, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 56, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 57, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 55, 1, 53, 53, 53, 53, 53, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 53, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 54, 1, 
-	1, 1, 52, 52, 52, 52, 52, 52, 
-	52, 52, 52, 52, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 58, 
+	1, 56, 56, 56, 56, 56, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 55, 
-	1, 56, 1, 56, 56, 56, 56, 56, 
+	56, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 57, 1, 1, 1, 
+	55, 55, 55, 55, 55, 55, 55, 55, 
+	55, 55, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 56, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 57, 1, 57, 57, 
-	57, 57, 57, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 57, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 58, 1, 1, 59, 60, 60, 
-	60, 60, 60, 60, 60, 60, 60, 1, 
-	61, 62, 62, 62, 62, 62, 62, 62, 
-	62, 62, 1, 63, 63, 63, 63, 63, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 58, 1, 59, 
+	1, 59, 59, 59, 59, 59, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 63, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 64, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	59, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 60, 1, 60, 60, 60, 60, 
+	60, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 60, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	61, 1, 1, 62, 63, 63, 63, 63, 
+	63, 63, 63, 63, 63, 1, 64, 65, 
+	65, 65, 65, 65, 65, 65, 65, 65, 
+	1, 66, 66, 66, 66, 66, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	66, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 67, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 65, 
-	1, 63, 63, 63, 63, 63, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	63, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 64, 1, 1, 1, 
-	62, 62, 62, 62, 62, 62, 62, 62, 
-	62, 62, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 68, 1, 66, 
+	66, 66, 66, 66, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 66, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 65, 1, 66, 
-	1, 67, 1, 67, 67, 67, 67, 67, 
+	1, 1, 67, 1, 1, 1, 65, 65, 
+	65, 65, 65, 65, 65, 65, 65, 65, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 67, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 68, 1, 68, 68, 
-	68, 68, 68, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 68, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 69, 70, 70, 
-	70, 70, 70, 70, 70, 70, 70, 1, 
-	71, 71, 71, 71, 71, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 71, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 72, 1, 1, 1, 1, 
+	1, 1, 1, 68, 1, 69, 1, 70, 
+	1, 70, 70, 70, 70, 70, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	70, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 71, 1, 71, 71, 71, 71, 
+	71, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 71, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 72, 73, 73, 73, 73, 
+	73, 73, 73, 73, 73, 1, 74, 74, 
+	74, 74, 74, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 74, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 75, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 73, 1, 71, 71, 
-	71, 71, 71, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 71, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 72, 1, 1, 1, 74, 74, 74, 
-	74, 74, 74, 74, 74, 74, 74, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 76, 1, 74, 74, 74, 74, 
+	74, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 74, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 75, 
+	1, 1, 1, 77, 77, 77, 77, 77, 
+	77, 77, 77, 77, 77, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 73, 1, 75, 1, 75, 75, 
-	75, 75, 75, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 75, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 76, 
-	1, 76, 76, 76, 76, 76, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	76, 1, 77, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	78, 79, 79, 79, 79, 79, 79, 79, 
-	79, 79, 1, 81, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 80, 80, 80, 
-	80, 80, 80, 80, 80, 82, 80, 83, 
-	83, 83, 83, 83, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 83, 1, 
+	76, 1, 78, 1, 78, 78, 78, 78, 
+	78, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 84, 1, 1, 1, 1, 1, 
+	1, 1, 1, 78, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 79, 1, 79, 
+	79, 79, 79, 79, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 79, 1, 
+	80, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 81, 82, 
+	82, 82, 82, 82, 82, 82, 82, 82, 
+	1, 84, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 83, 83, 
+	83, 83, 83, 85, 83, 86, 86, 86, 
+	86, 86, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 86, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	87, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 85, 1, 80, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 88, 1, 83, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 80, 
-	1, 86, 86, 86, 86, 86, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	86, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 87, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 83, 1, 89, 
+	89, 89, 89, 89, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 89, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 90, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 88, 1, 86, 
-	86, 86, 86, 86, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 86, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 87, 1, 1, 1, 89, 89, 
-	89, 89, 89, 89, 89, 89, 89, 89, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 91, 1, 89, 89, 89, 
+	89, 89, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 89, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	90, 1, 1, 1, 92, 92, 92, 92, 
+	92, 92, 92, 92, 92, 92, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 88, 1, 90, 1, 90, 
-	90, 90, 90, 90, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 90, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	91, 1, 91, 91, 91, 91, 91, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 91, 1, 93, 1, 93, 93, 93, 
+	93, 93, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 91, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 93, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 92, 93, 93, 93, 93, 93, 93, 
-	93, 93, 93, 1, 86, 86, 86, 86, 
-	86, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 86, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 87, 
-	1, 1, 1, 94, 94, 94, 94, 94, 
+	1, 1, 1, 1, 1, 1, 94, 1, 
 	94, 94, 94, 94, 94, 1, 1, 1, 
 	94, 94, 94, 94, 94, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 94, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 95, 
+	96, 96, 96, 96, 96, 96, 96, 96, 
+	96, 1, 89, 89, 89, 89, 89, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 89, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 90, 1, 1, 
+	1, 97, 97, 97, 97, 97, 97, 97, 
+	97, 97, 97, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	88, 1, 95, 95, 95, 95, 95, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 95, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 96, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 97, 1, 
+	1, 1, 1, 1, 1, 1, 91, 1, 
 	0, 0, 0, 0, 0, 1, 1, 1, 
 	0, 0, 0, 0, 0, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 1, 
 	1, 1, 1, 1, 1, 1, 1, 0, 
 	1, 1, 1, 1, 1, 1, 1, 0, 
@@ -492,39 +492,39 @@ static const char _deserialize_json_indicies[] = {
 };
 };
 
 
 static const char _deserialize_json_trans_targs[] = {
 static const char _deserialize_json_trans_targs[] = {
-	1, 0, 2, 2, 3, 4, 18, 24, 
-	37, 43, 51, 5, 12, 6, 7, 8, 
-	9, 11, 9, 11, 10, 2, 55, 10, 
-	55, 13, 14, 15, 16, 17, 16, 17, 
-	10, 2, 55, 19, 20, 21, 22, 23, 
-	10, 2, 55, 23, 25, 31, 26, 27, 
-	28, 29, 30, 29, 30, 10, 2, 55, 
-	32, 33, 34, 35, 36, 35, 36, 10, 
-	2, 55, 38, 39, 40, 41, 42, 10, 
-	2, 55, 42, 44, 45, 46, 49, 50, 
-	46, 47, 48, 10, 2, 55, 10, 2, 
-	55, 50, 52, 53, 49, 54, 54, 55, 
-	56, 57
+	1, 0, 2, 2, 3, 4, 19, 25, 
+	38, 44, 52, 5, 13, 6, 7, 8, 
+	9, 12, 9, 12, 10, 2, 11, 10, 
+	11, 11, 56, 57, 14, 15, 16, 17, 
+	18, 17, 18, 10, 2, 11, 20, 21, 
+	22, 23, 24, 10, 2, 11, 24, 26, 
+	32, 27, 28, 29, 30, 31, 30, 31, 
+	10, 2, 11, 33, 34, 35, 36, 37, 
+	36, 37, 10, 2, 11, 39, 40, 41, 
+	42, 43, 10, 2, 11, 43, 45, 46, 
+	47, 50, 51, 47, 48, 49, 10, 2, 
+	11, 10, 2, 11, 51, 53, 54, 50, 
+	55, 55
 };
 };
 
 
 static const char _deserialize_json_trans_actions[] = {
 static const char _deserialize_json_trans_actions[] = {
 	0, 0, 1, 0, 0, 0, 0, 0, 
 	0, 0, 1, 0, 0, 0, 0, 0, 
 	0, 0, 0, 0, 0, 0, 0, 2, 
 	0, 0, 0, 0, 0, 0, 0, 2, 
 	2, 2, 0, 0, 3, 3, 4, 0, 
 	2, 2, 0, 0, 3, 3, 4, 0, 
-	5, 0, 0, 2, 2, 2, 0, 0, 
-	6, 6, 7, 0, 0, 0, 2, 2, 
-	8, 8, 9, 0, 0, 0, 0, 0, 
-	2, 2, 2, 0, 0, 10, 10, 11, 
-	0, 0, 2, 2, 2, 0, 0, 12, 
-	12, 13, 0, 0, 0, 2, 2, 14, 
-	14, 15, 0, 0, 0, 2, 16, 16, 
-	0, 17, 0, 18, 18, 19, 20, 20, 
-	21, 17, 0, 0, 22, 22, 23, 0, 
-	0, 0
+	5, 0, 0, 0, 0, 0, 2, 2, 
+	2, 0, 0, 6, 6, 7, 0, 0, 
+	0, 2, 2, 8, 8, 9, 0, 0, 
+	0, 0, 0, 2, 2, 2, 0, 0, 
+	10, 10, 11, 0, 0, 2, 2, 2, 
+	0, 0, 12, 12, 13, 0, 0, 0, 
+	2, 2, 14, 14, 15, 0, 0, 0, 
+	2, 16, 16, 0, 17, 0, 18, 18, 
+	19, 20, 20, 21, 17, 0, 0, 22, 
+	22, 23
 };
 };
 
 
 static const int deserialize_json_start = 1;
 static const int deserialize_json_start = 1;
-static const int deserialize_json_first_final = 55;
+static const int deserialize_json_first_final = 56;
 static const int deserialize_json_error = 0;
 static const int deserialize_json_error = 0;
 
 
 static const int deserialize_json_en_main = 1;
 static const int deserialize_json_en_main = 1;
@@ -548,21 +548,19 @@ _hb_buffer_deserialize_json (hb_buffer_t *buffer,
   while (p < pe && ISSPACE (*p))
   while (p < pe && ISSPACE (*p))
     p++;
     p++;
   if (p < pe && *p == (buffer->len ? ',' : '['))
   if (p < pe && *p == (buffer->len ? ',' : '['))
-  {
     *end_ptr = ++p;
     *end_ptr = ++p;
-  }
 
 
   const char *tok = nullptr;
   const char *tok = nullptr;
   int cs;
   int cs;
   hb_glyph_info_t info = {0};
   hb_glyph_info_t info = {0};
   hb_glyph_position_t pos = {0};
   hb_glyph_position_t pos = {0};
   
   
-#line 554 "hb-buffer-deserialize-json.hh"
+#line 552 "hb-buffer-deserialize-json.hh"
 	{
 	{
 	cs = deserialize_json_start;
 	cs = deserialize_json_start;
 	}
 	}
 
 
-#line 557 "hb-buffer-deserialize-json.hh"
+#line 555 "hb-buffer-deserialize-json.hh"
 	{
 	{
 	int _slen;
 	int _slen;
 	int _trans;
 	int _trans;
@@ -774,7 +772,7 @@ _resume:
 	*end_ptr = p;
 	*end_ptr = p;
 }
 }
 	break;
 	break;
-#line 735 "hb-buffer-deserialize-json.hh"
+#line 733 "hb-buffer-deserialize-json.hh"
 	}
 	}
 
 
 _again:
 _again:
@@ -786,7 +784,7 @@ _again:
 	_out: {}
 	_out: {}
 	}
 	}
 
 
-#line 139 "hb-buffer-deserialize-json.rl"
+#line 137 "hb-buffer-deserialize-json.rl"
 
 
 
 
   *end_ptr = p;
   *end_ptr = p;

+ 692 - 0
thirdparty/harfbuzz/src/hb-buffer-deserialize-text-glyphs.hh

@@ -0,0 +1,692 @@
+
+#line 1 "hb-buffer-deserialize-text-glyphs.rl"
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH
+
+#include "hb.hh"
+
+
+#line 33 "hb-buffer-deserialize-text-glyphs.hh"
+static const unsigned char _deserialize_text_glyphs_trans_keys[] = {
+	0u, 0u, 48u, 57u, 45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 
+	48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 
+	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
+	9u, 124u, 9u, 124u, 9u, 124u, 0
+};
+
+static const char _deserialize_text_glyphs_key_spans[] = {
+	0, 10, 13, 10, 13, 10, 10, 13, 
+	10, 1, 13, 10, 14, 82, 116, 116, 
+	116, 116, 116, 116, 116, 116, 116, 116, 
+	116, 116, 116
+};
+
+static const short _deserialize_text_glyphs_index_offsets[] = {
+	0, 0, 11, 25, 36, 50, 61, 72, 
+	86, 97, 99, 113, 124, 139, 222, 339, 
+	456, 573, 690, 807, 924, 1041, 1158, 1275, 
+	1392, 1509, 1626
+};
+
+static const char _deserialize_text_glyphs_indicies[] = {
+	0, 2, 2, 2, 2, 2, 2, 
+	2, 2, 2, 1, 3, 1, 1, 4, 
+	5, 5, 5, 5, 5, 5, 5, 5, 
+	5, 1, 6, 7, 7, 7, 7, 7, 
+	7, 7, 7, 7, 1, 8, 1, 1, 
+	9, 10, 10, 10, 10, 10, 10, 10, 
+	10, 10, 1, 11, 12, 12, 12, 12, 
+	12, 12, 12, 12, 12, 1, 13, 14, 
+	14, 14, 14, 14, 14, 14, 14, 14, 
+	1, 15, 1, 1, 16, 17, 17, 17, 
+	17, 17, 17, 17, 17, 17, 1, 18, 
+	19, 19, 19, 19, 19, 19, 19, 19, 
+	19, 1, 20, 1, 21, 1, 1, 22, 
+	23, 23, 23, 23, 23, 23, 23, 23, 
+	23, 1, 24, 25, 25, 25, 25, 25, 
+	25, 25, 25, 25, 1, 20, 1, 1, 
+	1, 19, 19, 19, 19, 19, 19, 19, 
+	19, 19, 19, 1, 26, 26, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 26, 1, 
+	1, 26, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 26, 26, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 26, 1, 28, 
+	28, 28, 28, 28, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 28, 27, 
+	27, 29, 27, 27, 27, 27, 27, 27, 
+	27, 30, 1, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 31, 27, 27, 32, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 33, 1, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 27, 28, 27, 34, 34, 34, 34, 
+	34, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 34, 26, 26, 35, 26, 
+	26, 26, 26, 26, 26, 26, 36, 1, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	37, 26, 26, 38, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 39, 
+	1, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 26, 
+	26, 26, 26, 26, 26, 26, 26, 40, 
+	26, 41, 41, 41, 41, 41, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	41, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 42, 1, 43, 43, 
+	43, 43, 43, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 43, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 44, 1, 41, 41, 41, 41, 41, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 41, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 42, 1, 
+	46, 46, 46, 46, 46, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 46, 
+	1, 1, 47, 1, 1, 1, 1, 1, 
+	1, 1, 1, 48, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 49, 1, 50, 50, 50, 
+	50, 50, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 50, 1, 1, 51, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	52, 1, 50, 50, 50, 50, 50, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 50, 1, 1, 51, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 12, 12, 12, 12, 12, 12, 12, 
+	12, 12, 12, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 52, 1, 46, 
+	46, 46, 46, 46, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 46, 1, 
+	1, 47, 1, 1, 1, 1, 1, 1, 
+	1, 1, 48, 1, 1, 1, 7, 7, 
+	7, 7, 7, 7, 7, 7, 7, 7, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 49, 1, 53, 53, 53, 53, 
+	53, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 53, 1, 1, 54, 1, 
+	1, 1, 1, 1, 1, 1, 55, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 56, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 57, 
+	1, 58, 58, 58, 58, 58, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	58, 1, 1, 59, 1, 1, 1, 1, 
+	1, 1, 1, 60, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 61, 1, 58, 58, 
+	58, 58, 58, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 58, 1, 1, 
+	59, 1, 1, 1, 1, 1, 1, 1, 
+	60, 1, 1, 1, 1, 25, 25, 25, 
+	25, 25, 25, 25, 25, 25, 25, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 61, 1, 53, 53, 53, 53, 53, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 53, 1, 1, 54, 1, 1, 
+	1, 1, 1, 1, 1, 55, 1, 1, 
+	1, 1, 62, 62, 62, 62, 62, 62, 
+	62, 62, 62, 62, 1, 1, 1, 1, 
+	1, 1, 56, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 57, 1, 
+	0
+};
+
+static const char _deserialize_text_glyphs_trans_targs[] = {
+	16, 0, 18, 3, 19, 22, 19, 22, 
+	5, 20, 21, 20, 21, 23, 26, 8, 
+	9, 12, 9, 12, 10, 11, 24, 25, 
+	24, 25, 15, 15, 14, 1, 2, 6, 
+	7, 13, 15, 1, 2, 6, 7, 13, 
+	14, 17, 14, 17, 14, 18, 17, 1, 
+	4, 14, 17, 1, 14, 17, 1, 2, 
+	7, 14, 17, 1, 2, 14, 26
+};
+
+static const char _deserialize_text_glyphs_trans_actions[] = {
+	1, 0, 1, 1, 1, 1, 0, 0, 
+	1, 1, 1, 0, 0, 1, 1, 1, 
+	1, 1, 0, 0, 2, 1, 1, 1, 
+	0, 0, 0, 4, 3, 5, 5, 5, 
+	5, 4, 6, 7, 7, 7, 7, 0, 
+	6, 8, 8, 0, 0, 0, 9, 10, 
+	10, 9, 11, 12, 11, 13, 14, 14, 
+	14, 13, 15, 16, 16, 15, 0
+};
+
+static const char _deserialize_text_glyphs_eof_actions[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 3, 6, 
+	8, 0, 8, 9, 11, 11, 9, 13, 
+	15, 15, 13
+};
+
+static const int deserialize_text_glyphs_start = 14;
+static const int deserialize_text_glyphs_first_final = 14;
+static const int deserialize_text_glyphs_error = 0;
+
+static const int deserialize_text_glyphs_en_main = 14;
+
+
+#line 98 "hb-buffer-deserialize-text-glyphs.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_text_glyphs (hb_buffer_t *buffer,
+				    const char *buf,
+				    unsigned int buf_len,
+				    const char **end_ptr,
+				    hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+
+  /* Ensure we have positions. */
+  (void) hb_buffer_get_glyph_positions (buffer, nullptr);
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '['))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, ']');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+  
+#line 346 "hb-buffer-deserialize-text-glyphs.hh"
+	{
+	cs = deserialize_text_glyphs_start;
+	}
+
+#line 349 "hb-buffer-deserialize-text-glyphs.hh"
+	{
+	int _slen;
+	int _trans;
+	const unsigned char *_keys;
+	const char *_inds;
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _deserialize_text_glyphs_trans_keys + (cs<<1);
+	_inds = _deserialize_text_glyphs_indicies + _deserialize_text_glyphs_index_offsets[cs];
+
+	_slen = _deserialize_text_glyphs_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+		(*p) <= _keys[1] ?
+		(*p) - _keys[0] : _slen ];
+
+	cs = _deserialize_text_glyphs_trans_targs[_trans];
+
+	if ( _deserialize_text_glyphs_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _deserialize_text_glyphs_trans_actions[_trans] ) {
+	case 1:
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
+	break;
+	case 7:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+	break;
+	case 14:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+	break;
+	case 2:
+#line 64 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+	break;
+	case 16:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+	break;
+	case 10:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+	break;
+	case 12:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+	break;
+	case 4:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
+	break;
+	case 6:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 13:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 15:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 9:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 11:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 8:
+#line 68 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 5:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+	break;
+	case 3:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 516 "hb-buffer-deserialize-text-glyphs.hh"
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	if ( p == eof )
+	{
+	switch ( _deserialize_text_glyphs_eof_actions[cs] ) {
+	case 6:
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 13:
+#line 63 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 15:
+#line 65 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 9:
+#line 66 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 11:
+#line 67 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 8:
+#line 68 "hb-buffer-deserialize-text-glyphs.rl"
+	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 3:
+#line 38 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+	hb_memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	tok = p;
+}
+#line 55 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	/* TODO Unescape delimiters. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+#line 43 "hb-buffer-deserialize-text-glyphs.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 616 "hb-buffer-deserialize-text-glyphs.hh"
+	}
+	}
+
+	_out: {}
+	}
+
+#line 136 "hb-buffer-deserialize-text-glyphs.rl"
+
+
+  if (pe < orig_pe && *pe == ']')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
+  *end_ptr = p;
+
+  return p == pe;
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_GLYPHS_HH */

+ 332 - 0
thirdparty/harfbuzz/src/hb-buffer-deserialize-text-unicode.hh

@@ -0,0 +1,332 @@
+
+#line 1 "hb-buffer-deserialize-text-unicode.rl"
+/*
+ * Copyright © 2013  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#ifndef HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+#define HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH
+
+#include "hb.hh"
+
+
+#line 33 "hb-buffer-deserialize-text-unicode.hh"
+static const unsigned char _deserialize_text_unicode_trans_keys[] = {
+	0u, 0u, 9u, 117u, 43u, 102u, 48u, 102u, 48u, 57u, 9u, 124u, 9u, 124u, 9u, 124u, 
+	9u, 124u, 0
+};
+
+static const char _deserialize_text_unicode_key_spans[] = {
+	0, 109, 60, 55, 10, 116, 116, 116, 
+	116
+};
+
+static const short _deserialize_text_unicode_index_offsets[] = {
+	0, 0, 110, 171, 227, 238, 355, 472, 
+	589
+};
+
+static const char _deserialize_text_unicode_indicies[] = {
+	0, 0, 0, 0, 0, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	0, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 2, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 2, 1, 3, 
+	1, 1, 1, 1, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 1, 1, 
+	1, 1, 1, 1, 1, 4, 4, 4, 
+	4, 4, 4, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 4, 4, 4, 
+	4, 4, 4, 1, 4, 4, 4, 4, 
+	4, 4, 4, 4, 4, 4, 1, 1, 
+	1, 1, 1, 1, 1, 4, 4, 4, 
+	4, 4, 4, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 4, 4, 4, 
+	4, 4, 4, 1, 5, 6, 6, 6, 
+	6, 6, 6, 6, 6, 6, 1, 7, 
+	7, 7, 7, 7, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 7, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 8, 8, 
+	8, 8, 8, 8, 8, 8, 8, 8, 
+	1, 1, 1, 9, 1, 1, 1, 8, 
+	8, 8, 8, 8, 8, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 8, 
+	8, 8, 8, 8, 8, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 10, 1, 11, 11, 11, 11, 
+	11, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 11, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 0, 
+	1, 12, 12, 12, 12, 12, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	12, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 13, 1, 12, 12, 
+	12, 12, 12, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 12, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 14, 14, 14, 
+	14, 14, 14, 14, 14, 14, 14, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 13, 1, 0
+};
+
+static const char _deserialize_text_unicode_trans_targs[] = {
+	1, 0, 2, 3, 5, 7, 8, 6, 
+	5, 4, 1, 6, 6, 1, 8
+};
+
+static const char _deserialize_text_unicode_trans_actions[] = {
+	0, 0, 1, 0, 2, 2, 2, 3, 
+	0, 4, 3, 0, 5, 5, 0
+};
+
+static const char _deserialize_text_unicode_eof_actions[] = {
+	0, 0, 0, 0, 0, 3, 0, 5, 
+	5
+};
+
+static const int deserialize_text_unicode_start = 1;
+static const int deserialize_text_unicode_first_final = 5;
+static const int deserialize_text_unicode_error = 0;
+
+static const int deserialize_text_unicode_en_main = 1;
+
+
+#line 79 "hb-buffer-deserialize-text-unicode.rl"
+
+
+static hb_bool_t
+_hb_buffer_deserialize_text_unicode (hb_buffer_t *buffer,
+				     const char *buf,
+				     unsigned int buf_len,
+				     const char **end_ptr,
+				     hb_font_t *font)
+{
+  const char *p = buf, *pe = buf + buf_len, *eof = pe, *orig_pe = pe;
+
+  while (p < pe && ISSPACE (*p))
+    p++;
+  if (p < pe && *p == (buffer->len ? '|' : '<'))
+    *end_ptr = ++p;
+
+  const char *end = strchr ((char *) p, '>');
+  if (end)
+    pe = eof = end;
+  else
+  {
+    end = strrchr ((char *) p, '|');
+    if (end)
+      pe = eof = end;
+    else
+      pe = eof = p;
+  }
+
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  const hb_glyph_position_t pos = {0};
+  
+#line 194 "hb-buffer-deserialize-text-unicode.hh"
+	{
+	cs = deserialize_text_unicode_start;
+	}
+
+#line 197 "hb-buffer-deserialize-text-unicode.hh"
+	{
+	int _slen;
+	int _trans;
+	const unsigned char *_keys;
+	const char *_inds;
+	if ( p == pe )
+		goto _test_eof;
+	if ( cs == 0 )
+		goto _out;
+_resume:
+	_keys = _deserialize_text_unicode_trans_keys + (cs<<1);
+	_inds = _deserialize_text_unicode_indicies + _deserialize_text_unicode_index_offsets[cs];
+
+	_slen = _deserialize_text_unicode_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+		(*p) <= _keys[1] ?
+		(*p) - _keys[0] : _slen ];
+
+	cs = _deserialize_text_unicode_trans_targs[_trans];
+
+	if ( _deserialize_text_unicode_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _deserialize_text_unicode_trans_actions[_trans] ) {
+	case 1:
+#line 38 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	hb_memset (&info, 0, sizeof (info));
+}
+	break;
+	case 2:
+#line 51 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	tok = p;
+}
+	break;
+	case 4:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
+	break;
+	case 3:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	if (buffer->have_positions)
+	  buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 5:
+#line 57 "hb-buffer-deserialize-text-unicode.rl"
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	if (buffer->have_positions)
+	  buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 256 "hb-buffer-deserialize-text-unicode.hh"
+	}
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	if ( p == eof )
+	{
+	switch ( _deserialize_text_unicode_eof_actions[cs] ) {
+	case 3:
+#line 55 "hb-buffer-deserialize-text-unicode.rl"
+	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	if (buffer->have_positions)
+	  buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 5:
+#line 57 "hb-buffer-deserialize-text-unicode.rl"
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+#line 42 "hb-buffer-deserialize-text-unicode.rl"
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	if (buffer->have_positions)
+	  buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 289 "hb-buffer-deserialize-text-unicode.hh"
+	}
+	}
+
+	_out: {}
+	}
+
+#line 115 "hb-buffer-deserialize-text-unicode.rl"
+
+
+  if (pe < orig_pe && *pe == '>')
+  {
+    pe++;
+    if (p == pe)
+      p++;
+  }
+
+  *end_ptr = p;
+
+  return p == pe;
+}
+
+#endif /* HB_BUFFER_DESERIALIZE_TEXT_UNICODE_HH */

+ 0 - 917
thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh

@@ -1,917 +0,0 @@
-
-#line 1 "hb-buffer-deserialize-text.rl"
-/*
- * Copyright © 2013  Google, Inc.
- *
- *  This is part of HarfBuzz, a text shaping library.
- *
- * Permission is hereby granted, without written agreement and without
- * license or royalty fees, to use, copy, modify, and distribute this
- * software and its documentation for any purpose, provided that the
- * above copyright notice and the following two paragraphs appear in
- * all copies of this software.
- *
- * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
- * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
- * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
- * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
- * DAMAGE.
- *
- * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
- * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
- * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
- * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
- *
- * Google Author(s): Behdad Esfahbod
- */
-
-#ifndef HB_BUFFER_DESERIALIZE_TEXT_HH
-#define HB_BUFFER_DESERIALIZE_TEXT_HH
-
-#include "hb.hh"
-
-
-#line 33 "hb-buffer-deserialize-text.hh"
-static const unsigned char _deserialize_text_trans_keys[] = {
-	0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 48u, 57u, 
-	45u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 
-	45u, 57u, 48u, 57u, 44u, 57u, 43u, 124u, 9u, 124u, 9u, 124u, 0u, 0u, 9u, 85u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 9u, 124u, 
-	0
-};
-
-static const char _deserialize_text_key_spans[] = {
-	0, 83, 1, 1, 55, 77, 10, 10, 
-	13, 10, 13, 10, 10, 13, 10, 1, 
-	13, 10, 14, 82, 116, 116, 0, 77, 
-	116, 116, 116, 116, 116, 116, 116, 116, 
-	116, 116, 116, 116, 116, 116, 116, 116
-};
-
-static const short _deserialize_text_index_offsets[] = {
-	0, 0, 84, 86, 88, 144, 222, 233, 
-	244, 258, 269, 283, 294, 305, 319, 330, 
-	332, 346, 357, 372, 455, 572, 689, 690, 
-	768, 885, 1002, 1119, 1236, 1353, 1470, 1587, 
-	1704, 1821, 1938, 2055, 2172, 2289, 2406, 2523
-};
-
-static const char _deserialize_text_indicies[] = {
-	0, 0, 0, 0, 0, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	0, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 2, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 3, 1, 4, 1, 5, 
-	1, 6, 6, 6, 6, 6, 6, 6, 
-	6, 6, 6, 1, 1, 1, 1, 1, 
-	1, 1, 6, 6, 6, 6, 6, 6, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 6, 6, 6, 6, 6, 6, 
-	1, 7, 7, 7, 7, 7, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	7, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 4, 1, 8, 
-	9, 9, 9, 9, 9, 9, 9, 9, 
-	9, 1, 10, 11, 11, 11, 11, 11, 
-	11, 11, 11, 11, 1, 12, 1, 1, 
-	13, 14, 14, 14, 14, 14, 14, 14, 
-	14, 14, 1, 15, 16, 16, 16, 16, 
-	16, 16, 16, 16, 16, 1, 17, 1, 
-	1, 18, 19, 19, 19, 19, 19, 19, 
-	19, 19, 19, 1, 20, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 1, 22, 
-	23, 23, 23, 23, 23, 23, 23, 23, 
-	23, 1, 24, 1, 1, 25, 26, 26, 
-	26, 26, 26, 26, 26, 26, 26, 1, 
-	27, 28, 28, 28, 28, 28, 28, 28, 
-	28, 28, 1, 29, 1, 30, 1, 1, 
-	31, 32, 32, 32, 32, 32, 32, 32, 
-	32, 32, 1, 33, 34, 34, 34, 34, 
-	34, 34, 34, 34, 34, 1, 29, 1, 
-	1, 1, 28, 28, 28, 28, 28, 28, 
-	28, 28, 28, 28, 1, 35, 35, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 35, 
-	1, 1, 35, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 35, 35, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 35, 1, 
-	36, 36, 36, 36, 36, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 36, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 37, 
-	37, 37, 37, 37, 37, 37, 37, 37, 
-	37, 1, 1, 1, 38, 39, 1, 1, 
-	37, 37, 37, 37, 37, 37, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	37, 37, 37, 37, 37, 37, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 40, 1, 41, 41, 41, 
-	41, 41, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 41, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 42, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	43, 1, 1, 7, 7, 7, 7, 7, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 7, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 4, 
-	1, 44, 44, 44, 44, 44, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	44, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 45, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 46, 1, 44, 44, 
-	44, 44, 44, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 44, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 47, 47, 47, 
-	47, 47, 47, 47, 47, 47, 47, 1, 
-	1, 1, 1, 45, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 46, 1, 49, 49, 49, 49, 49, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 49, 48, 48, 50, 48, 48, 
-	48, 48, 48, 48, 48, 51, 1, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 52, 
-	48, 48, 53, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 54, 55, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 56, 48, 
-	57, 57, 57, 57, 57, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 57, 
-	35, 35, 58, 35, 35, 35, 35, 35, 
-	35, 35, 59, 1, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 60, 35, 35, 61, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 62, 63, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 35, 35, 35, 35, 35, 
-	35, 35, 35, 64, 35, 65, 65, 65, 
-	65, 65, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 65, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 66, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	67, 1, 68, 68, 68, 68, 68, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 68, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 42, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 69, 1, 70, 
-	70, 70, 70, 70, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 70, 48, 
-	48, 50, 48, 48, 48, 48, 48, 48, 
-	48, 51, 1, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 52, 48, 48, 53, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 54, 55, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 48, 48, 48, 48, 48, 48, 
-	48, 48, 56, 48, 71, 71, 71, 71, 
-	71, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 71, 1, 1, 72, 1, 
-	1, 1, 1, 1, 1, 1, 1, 73, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	74, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 75, 
-	1, 76, 76, 76, 76, 76, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	76, 1, 1, 77, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 78, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 79, 1, 76, 76, 
-	76, 76, 76, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 76, 1, 1, 
-	77, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 21, 21, 21, 
-	21, 21, 21, 21, 21, 21, 21, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 78, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 79, 1, 71, 71, 71, 71, 71, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 71, 1, 1, 72, 1, 1, 
-	1, 1, 1, 1, 1, 1, 73, 1, 
-	1, 1, 16, 16, 16, 16, 16, 16, 
-	16, 16, 16, 16, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 74, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 75, 1, 
-	80, 80, 80, 80, 80, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 80, 
-	1, 1, 81, 1, 1, 1, 1, 1, 
-	1, 1, 82, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 83, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 45, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 84, 1, 85, 85, 85, 
-	85, 85, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 85, 1, 1, 86, 
-	1, 1, 1, 1, 1, 1, 1, 87, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 88, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	89, 1, 85, 85, 85, 85, 85, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 85, 1, 1, 86, 1, 1, 1, 
-	1, 1, 1, 1, 87, 1, 1, 1, 
-	1, 34, 34, 34, 34, 34, 34, 34, 
-	34, 34, 34, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 88, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 89, 1, 80, 
-	80, 80, 80, 80, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 80, 1, 
-	1, 81, 1, 1, 1, 1, 1, 1, 
-	1, 82, 1, 1, 1, 1, 90, 90, 
-	90, 90, 90, 90, 90, 90, 90, 90, 
-	1, 1, 1, 1, 1, 1, 83, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 45, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 84, 1, 65, 65, 65, 65, 
-	65, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 65, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 91, 91, 91, 91, 91, 
-	91, 91, 91, 91, 91, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	66, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 1, 
-	1, 1, 1, 1, 1, 1, 1, 67, 
-	1, 0
-};
-
-static const char _deserialize_text_trans_targs[] = {
-	1, 0, 2, 26, 3, 4, 20, 5, 
-	24, 25, 28, 39, 9, 31, 34, 31, 
-	34, 11, 32, 33, 32, 33, 35, 38, 
-	14, 15, 18, 15, 18, 16, 17, 36, 
-	37, 36, 37, 27, 21, 20, 6, 22, 
-	23, 21, 22, 23, 21, 22, 23, 25, 
-	27, 27, 7, 8, 12, 13, 19, 22, 
-	30, 27, 7, 8, 12, 13, 19, 22, 
-	30, 29, 22, 30, 29, 30, 30, 29, 
-	7, 10, 22, 30, 29, 7, 22, 30, 
-	29, 7, 8, 13, 30, 29, 7, 8, 
-	22, 30, 38, 39
-};
-
-static const char _deserialize_text_trans_actions[] = {
-	0, 0, 0, 0, 1, 0, 2, 0, 
-	2, 2, 3, 3, 4, 3, 3, 5, 
-	5, 4, 3, 3, 5, 5, 3, 3, 
-	4, 4, 4, 0, 0, 6, 4, 3, 
-	3, 5, 5, 5, 7, 8, 9, 7, 
-	7, 0, 0, 0, 10, 10, 10, 8, 
-	12, 13, 14, 14, 14, 14, 15, 11, 
-	11, 17, 18, 18, 18, 18, 0, 16, 
-	16, 19, 19, 19, 0, 0, 13, 20, 
-	21, 21, 20, 20, 22, 23, 22, 22, 
-	10, 24, 24, 24, 10, 25, 26, 26, 
-	25, 25, 5, 5
-};
-
-static const char _deserialize_text_eof_actions[] = {
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 0, 0, 0, 0, 
-	0, 0, 0, 0, 7, 0, 0, 0, 
-	10, 10, 11, 16, 19, 0, 11, 20, 
-	22, 22, 20, 10, 25, 25, 10, 19
-};
-
-static const int deserialize_text_start = 1;
-static const int deserialize_text_first_final = 20;
-static const int deserialize_text_error = 0;
-
-static const int deserialize_text_en_main = 1;
-
-
-#line 117 "hb-buffer-deserialize-text.rl"
-
-
-static hb_bool_t
-_hb_buffer_deserialize_text (hb_buffer_t *buffer,
-				    const char *buf,
-				    unsigned int buf_len,
-				    const char **end_ptr,
-				    hb_font_t *font)
-{
-  const char *p = buf, *pe = buf + buf_len;
-
-  /* Ensure we have positions. */
-  (void) hb_buffer_get_glyph_positions (buffer, nullptr);
-
-  while (p < pe && ISSPACE (*p))
-    p++;
-
-  const char *eof = pe, *tok = nullptr;
-  int cs;
-  hb_glyph_info_t info = {0};
-  hb_glyph_position_t pos = {0};
-  
-#line 457 "hb-buffer-deserialize-text.hh"
-	{
-	cs = deserialize_text_start;
-	}
-
-#line 460 "hb-buffer-deserialize-text.hh"
-	{
-	int _slen;
-	int _trans;
-	const unsigned char *_keys;
-	const char *_inds;
-	if ( p == pe )
-		goto _test_eof;
-	if ( cs == 0 )
-		goto _out;
-_resume:
-	_keys = _deserialize_text_trans_keys + (cs<<1);
-	_inds = _deserialize_text_indicies + _deserialize_text_index_offsets[cs];
-
-	_slen = _deserialize_text_key_spans[cs];
-	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
-		(*p) <= _keys[1] ?
-		(*p) - _keys[0] : _slen ];
-
-	cs = _deserialize_text_trans_targs[_trans];
-
-	if ( _deserialize_text_trans_actions[_trans] == 0 )
-		goto _again;
-
-	switch ( _deserialize_text_trans_actions[_trans] ) {
-	case 1:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-	break;
-	case 4:
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-	break;
-	case 5:
-#line 55 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
-	break;
-	case 8:
-#line 56 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
-	break;
-	case 18:
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-	break;
-	case 9:
-#line 66 "hb-buffer-deserialize-text.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-	break;
-	case 24:
-#line 68 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-	break;
-	case 6:
-#line 69 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-	break;
-	case 26:
-#line 70 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-	break;
-	case 21:
-#line 71 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-	break;
-	case 23:
-#line 72 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-	break;
-	case 15:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-	break;
-	case 3:
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
-	break;
-	case 2:
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 56 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
-	break;
-	case 16:
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 7:
-#line 66 "hb-buffer-deserialize-text.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 10:
-#line 68 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 25:
-#line 70 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 20:
-#line 71 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 22:
-#line 72 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 19:
-#line 73 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 12:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
-	break;
-	case 14:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-	break;
-	case 17:
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 13:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 55 "hb-buffer-deserialize-text.rl"
-	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-#line 715 "hb-buffer-deserialize-text.hh"
-	}
-
-_again:
-	if ( cs == 0 )
-		goto _out;
-	if ( ++p != pe )
-		goto _resume;
-	_test_eof: {}
-	if ( p == eof )
-	{
-	switch ( _deserialize_text_eof_actions[cs] ) {
-	case 16:
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 7:
-#line 66 "hb-buffer-deserialize-text.rl"
-	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 10:
-#line 68 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 25:
-#line 70 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 20:
-#line 71 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 22:
-#line 72 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 19:
-#line 73 "hb-buffer-deserialize-text.rl"
-	{ if (!parse_uint (tok, p, &info.mask    )) return false; }
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-	case 11:
-#line 38 "hb-buffer-deserialize-text.rl"
-	{
-	hb_memset (&info, 0, sizeof (info));
-	hb_memset (&pos , 0, sizeof (pos ));
-}
-#line 51 "hb-buffer-deserialize-text.rl"
-	{
-	tok = p;
-}
-#line 58 "hb-buffer-deserialize-text.rl"
-	{
-	/* TODO Unescape delimiters. */
-	if (!hb_font_glyph_from_string (font,
-					tok, p - tok,
-					&info.codepoint))
-	  return false;
-}
-#line 43 "hb-buffer-deserialize-text.rl"
-	{
-	buffer->add_info (info);
-	if (unlikely (!buffer->successful))
-	  return false;
-	buffer->pos[buffer->len - 1] = pos;
-	*end_ptr = p;
-}
-	break;
-#line 825 "hb-buffer-deserialize-text.hh"
-	}
-	}
-
-	_out: {}
-	}
-
-#line 141 "hb-buffer-deserialize-text.rl"
-
-
-  *end_ptr = p;
-
-  return p == pe && *(p-1) != ']';
-}
-
-#endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */

+ 12 - 9
thirdparty/harfbuzz/src/hb-buffer-serialize.cc

@@ -721,7 +721,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
 }
 }
 
 
 #include "hb-buffer-deserialize-json.hh"
 #include "hb-buffer-deserialize-json.hh"
-#include "hb-buffer-deserialize-text.hh"
+#include "hb-buffer-deserialize-text-glyphs.hh"
+#include "hb-buffer-deserialize-text-unicode.hh"
 
 
 /**
 /**
  * hb_buffer_deserialize_glyphs:
  * hb_buffer_deserialize_glyphs:
@@ -736,7 +737,8 @@ parse_hex (const char *pp, const char *end, uint32_t *pv)
  * Deserializes glyphs @buffer from textual representation in the format
  * Deserializes glyphs @buffer from textual representation in the format
  * produced by hb_buffer_serialize_glyphs().
  * produced by hb_buffer_serialize_glyphs().
  *
  *
- * Return value: `true` if @buf is not fully consumed, `false` otherwise.
+ * Return value: `true` if parse was successful, `false` if an error
+ * occurred.
  *
  *
  * Since: 0.9.7
  * Since: 0.9.7
  **/
  **/
@@ -779,9 +781,9 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
   switch (format)
   switch (format)
   {
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
-      return _hb_buffer_deserialize_text (buffer,
-                                          buf, buf_len, end_ptr,
-                                          font);
+      return _hb_buffer_deserialize_text_glyphs (buffer,
+						 buf, buf_len, end_ptr,
+						 font);
 
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
       return _hb_buffer_deserialize_json (buffer,
       return _hb_buffer_deserialize_json (buffer,
@@ -808,7 +810,8 @@ hb_buffer_deserialize_glyphs (hb_buffer_t *buffer,
  * Deserializes Unicode @buffer from textual representation in the format
  * Deserializes Unicode @buffer from textual representation in the format
  * produced by hb_buffer_serialize_unicode().
  * produced by hb_buffer_serialize_unicode().
  *
  *
- * Return value: `true` if @buf is not fully consumed, `false` otherwise.
+ * Return value: `true` if parse was successful, `false` if an error
+ * occurred.
  *
  *
  * Since: 2.7.3
  * Since: 2.7.3
  **/
  **/
@@ -849,9 +852,9 @@ hb_buffer_deserialize_unicode (hb_buffer_t *buffer,
   switch (format)
   switch (format)
   {
   {
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
     case HB_BUFFER_SERIALIZE_FORMAT_TEXT:
-      return _hb_buffer_deserialize_text (buffer,
-                                          buf, buf_len, end_ptr,
-                                          font);
+      return _hb_buffer_deserialize_text_unicode (buffer,
+						  buf, buf_len, end_ptr,
+						  font);
 
 
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
     case HB_BUFFER_SERIALIZE_FORMAT_JSON:
       return _hb_buffer_deserialize_json (buffer,
       return _hb_buffer_deserialize_json (buffer,

+ 2 - 2
thirdparty/harfbuzz/src/hb-buffer-verify.cc

@@ -150,7 +150,7 @@ buffer_verify_unsafe_to_break (hb_buffer_t  *buffer,
     assert (text_start < text_end);
     assert (text_start < text_end);
 
 
     if (0)
     if (0)
-      printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+      printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
 
     hb_buffer_clear_contents (fragment);
     hb_buffer_clear_contents (fragment);
 
 
@@ -292,7 +292,7 @@ buffer_verify_unsafe_to_concat (hb_buffer_t        *buffer,
       assert (text_start < text_end);
       assert (text_start < text_end);
 
 
       if (0)
       if (0)
-	printf("start %d end %d text start %d end %d\n", start, end, text_start, text_end);
+	printf("start %u end %u text start %u end %u\n", start, end, text_start, text_end);
 
 
 #if 0
 #if 0
       hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);
       hb_buffer_flags_t flags = hb_buffer_get_flags (fragment);

+ 33 - 5
thirdparty/harfbuzz/src/hb-buffer.cc

@@ -522,15 +522,17 @@ hb_buffer_t::merge_clusters_impl (unsigned int start,
     cluster = hb_min (cluster, info[i].cluster);
     cluster = hb_min (cluster, info[i].cluster);
 
 
   /* Extend end */
   /* Extend end */
-  while (end < len && info[end - 1].cluster == info[end].cluster)
-    end++;
+  if (cluster != info[end - 1].cluster)
+    while (end < len && info[end - 1].cluster == info[end].cluster)
+      end++;
 
 
   /* Extend start */
   /* Extend start */
-  while (idx < start && info[start - 1].cluster == info[start].cluster)
-    start--;
+  if (cluster != info[start].cluster)
+    while (idx < start && info[start - 1].cluster == info[start].cluster)
+      start--;
 
 
   /* If we hit the start of buffer, continue in out-buffer. */
   /* If we hit the start of buffer, continue in out-buffer. */
-  if (idx == start)
+  if (idx == start && info[start].cluster != cluster)
     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
     for (unsigned int i = out_len; i && out_info[i - 1].cluster == info[start].cluster; i--)
       set_cluster (out_info[i - 1], cluster);
       set_cluster (out_info[i - 1], cluster);
 
 
@@ -893,6 +895,32 @@ hb_buffer_get_user_data (const hb_buffer_t  *buffer,
  * Sets the type of @buffer contents. Buffers are either empty, contain
  * Sets the type of @buffer contents. Buffers are either empty, contain
  * characters (before shaping), or contain glyphs (the result of shaping).
  * characters (before shaping), or contain glyphs (the result of shaping).
  *
  *
+ * You rarely need to call this function, since a number of other
+ * functions transition the content type for you. Namely:
+ *
+ * - A newly created buffer starts with content type
+ *   %HB_BUFFER_CONTENT_TYPE_INVALID. Calling hb_buffer_reset(),
+ *   hb_buffer_clear_contents(), as well as calling hb_buffer_set_length()
+ *   with an argument of zero all set the buffer content type to invalid
+ *   as well.
+ *
+ * - Calling hb_buffer_add_utf8(), hb_buffer_add_utf16(),
+ *   hb_buffer_add_utf32(), hb_buffer_add_codepoints() and
+ *   hb_buffer_add_latin1() expect that buffer is either empty and
+ *   have a content type of invalid, or that buffer content type is
+ *   %HB_BUFFER_CONTENT_TYPE_UNICODE, and they also set the content
+ *   type to Unicode if they added anything to an empty buffer.
+ *
+ * - Finally hb_shape() and hb_shape_full() expect that the buffer
+ *   is either empty and have content type of invalid, or that buffer
+ *   content type is %HB_BUFFER_CONTENT_TYPE_UNICODE, and upon
+ *   success they set the buffer content type to
+ *   %HB_BUFFER_CONTENT_TYPE_GLYPHS.
+ *
+ * The above transitions are designed such that one can use a buffer
+ * in a loop of "reset : add-text : shape" without needing to ever
+ * modify the content type manually.
+ *
  * Since: 0.9.5
  * Since: 0.9.5
  **/
  **/
 void
 void

+ 1 - 1
thirdparty/harfbuzz/src/hb-buffer.h

@@ -763,7 +763,7 @@ hb_buffer_diff (hb_buffer_t *buffer,
 
 
 
 
 /*
 /*
- * Debugging.
+ * Tracing.
  */
  */
 
 
 /**
 /**

+ 44 - 26
thirdparty/harfbuzz/src/hb-buffer.hh

@@ -35,26 +35,6 @@
 #include "hb-set-digest.hh"
 #include "hb-set-digest.hh"
 
 
 
 
-#ifndef HB_BUFFER_MAX_LEN_FACTOR
-#define HB_BUFFER_MAX_LEN_FACTOR 64
-#endif
-#ifndef HB_BUFFER_MAX_LEN_MIN
-#define HB_BUFFER_MAX_LEN_MIN 16384
-#endif
-#ifndef HB_BUFFER_MAX_LEN_DEFAULT
-#define HB_BUFFER_MAX_LEN_DEFAULT 0x3FFFFFFF /* Shaping more than a billion chars? Let us know! */
-#endif
-
-#ifndef HB_BUFFER_MAX_OPS_FACTOR
-#define HB_BUFFER_MAX_OPS_FACTOR 1024
-#endif
-#ifndef HB_BUFFER_MAX_OPS_MIN
-#define HB_BUFFER_MAX_OPS_MIN 16384
-#endif
-#ifndef HB_BUFFER_MAX_OPS_DEFAULT
-#define HB_BUFFER_MAX_OPS_DEFAULT 0x1FFFFFFF /* Shaping more than a billion operations? Let us know! */
-#endif
-
 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
 static_assert ((sizeof (hb_glyph_info_t) == 20), "");
 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
 static_assert ((sizeof (hb_glyph_info_t) == sizeof (hb_glyph_position_t)), "");
 
 
@@ -601,21 +581,59 @@ struct hb_buffer_t
 			  unsigned int cluster,
 			  unsigned int cluster,
 			  hb_mask_t mask)
 			  hb_mask_t mask)
   {
   {
-    for (unsigned int i = start; i < end; i++)
-      if (cluster != infos[i].cluster)
+    if (unlikely (start == end))
+      return;
+
+    unsigned cluster_first = infos[start].cluster;
+    unsigned cluster_last = infos[end - 1].cluster;
+
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS ||
+	(cluster != cluster_first && cluster != cluster_last))
+    {
+      for (unsigned int i = start; i < end; i++)
+	if (cluster != infos[i].cluster)
+	{
+	  scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+	  infos[i].mask |= mask;
+	}
+      return;
+    }
+
+    /* Monotone clusters */
+
+    if (cluster == cluster_first)
+    {
+      for (unsigned int i = end; start < i && infos[i - 1].cluster != cluster_first; i--)
+      {
+	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
+	infos[i - 1].mask |= mask;
+      }
+    }
+    else /* cluster == cluster_last */
+    {
+      for (unsigned int i = start; i < end && infos[i].cluster != cluster_last; i++)
       {
       {
 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
 	scratch_flags |= HB_BUFFER_SCRATCH_FLAG_HAS_GLYPH_FLAGS;
 	infos[i].mask |= mask;
 	infos[i].mask |= mask;
       }
       }
+    }
   }
   }
-  static unsigned
+  unsigned
   _infos_find_min_cluster (const hb_glyph_info_t *infos,
   _infos_find_min_cluster (const hb_glyph_info_t *infos,
 			   unsigned start, unsigned end,
 			   unsigned start, unsigned end,
 			   unsigned cluster = UINT_MAX)
 			   unsigned cluster = UINT_MAX)
   {
   {
-    for (unsigned int i = start; i < end; i++)
-      cluster = hb_min (cluster, infos[i].cluster);
-    return cluster;
+    if (unlikely (start == end))
+      return cluster;
+
+    if (cluster_level == HB_BUFFER_CLUSTER_LEVEL_CHARACTERS)
+    {
+      for (unsigned int i = start; i < end; i++)
+	cluster = hb_min (cluster, infos[i].cluster);
+      return cluster;
+    }
+
+    return hb_min (cluster, hb_min (infos[start].cluster, infos[end - 1].cluster));
   }
   }
 
 
   void clear_glyph_flags (hb_mask_t mask = 0)
   void clear_glyph_flags (hb_mask_t mask = 0)

+ 5 - 2
thirdparty/harfbuzz/src/hb-cache.hh

@@ -39,7 +39,9 @@ template <unsigned int key_bits=16,
 struct hb_cache_t
 struct hb_cache_t
 {
 {
   using item_t = typename std::conditional<thread_safe,
   using item_t = typename std::conditional<thread_safe,
-					   hb_atomic_int_t,
+					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
+								     hb_atomic_short_t,
+								     hb_atomic_int_t>::type,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
 					   typename std::conditional<key_bits + value_bits - cache_bits <= 16,
 								     short,
 								     short,
 								     int>::type
 								     int>::type
@@ -48,8 +50,9 @@ struct hb_cache_t
   static_assert ((key_bits >= cache_bits), "");
   static_assert ((key_bits >= cache_bits), "");
   static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
   static_assert ((key_bits + value_bits <= cache_bits + 8 * sizeof (item_t)), "");
 
 
+  hb_cache_t () { init (); }
+
   void init () { clear (); }
   void init () { clear (); }
-  void fini () {}
 
 
   void clear ()
   void clear ()
   {
   {

+ 869 - 0
thirdparty/harfbuzz/src/hb-cairo-utils.cc

@@ -0,0 +1,869 @@
+/*
+ * Copyright © 2022  Red Hat, Inc
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Matthias Clasen
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CAIRO
+
+#include "hb-cairo-utils.hh"
+
+#include <cairo.h>
+
+#define PREALLOCATED_COLOR_STOPS 16
+
+#define _2_M_PIf (2.f * float (M_PI))
+
+typedef struct {
+  float r, g, b, a;
+} hb_cairo_color_t;
+
+static inline cairo_extend_t
+hb_cairo_extend (hb_paint_extend_t extend)
+{
+  switch (extend)
+    {
+    case HB_PAINT_EXTEND_PAD: return CAIRO_EXTEND_PAD;
+    case HB_PAINT_EXTEND_REPEAT: return CAIRO_EXTEND_REPEAT;
+    case HB_PAINT_EXTEND_REFLECT: return CAIRO_EXTEND_REFLECT;
+    default: break;
+    }
+
+  return CAIRO_EXTEND_PAD;
+}
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+typedef struct
+{
+  hb_blob_t *blob;
+  unsigned int offset;
+} hb_cairo_read_blob_data_t;
+
+static cairo_status_t
+hb_cairo_read_blob (void *closure,
+		    unsigned char *data,
+		    unsigned int length)
+{
+  hb_cairo_read_blob_data_t *r = (hb_cairo_read_blob_data_t *) closure;
+  const char *d;
+  unsigned int size;
+
+  d = hb_blob_get_data (r->blob, &size);
+
+  if (r->offset + length > size)
+    return CAIRO_STATUS_READ_ERROR;
+
+  memcpy (data, d + r->offset, length);
+  r->offset += length;
+
+  return CAIRO_STATUS_SUCCESS;
+}
+#endif
+
+static const cairo_user_data_key_t *_hb_cairo_surface_blob_user_data_key = {0};
+
+static void
+_hb_cairo_destroy_blob (void *p)
+{
+  hb_blob_destroy ((hb_blob_t *) p);
+}
+
+hb_bool_t
+_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
+			     hb_blob_t *blob,
+			     unsigned width,
+			     unsigned height,
+			     hb_tag_t format,
+			     float slant,
+			     hb_glyph_extents_t *extents)
+{
+  cairo_t *cr = c->cr;
+
+  if (!extents) /* SVG currently. */
+    return false;
+
+  cairo_surface_t *surface = nullptr;
+
+#ifdef CAIRO_HAS_PNG_FUNCTIONS
+  if (format == HB_PAINT_IMAGE_FORMAT_PNG)
+  {
+    hb_cairo_read_blob_data_t r;
+    r.blob = blob;
+    r.offset = 0;
+    surface = cairo_image_surface_create_from_png_stream (hb_cairo_read_blob, &r);
+
+    /* For PNG, width,height can be unreliable, as is the case for NotoColorEmoji :(.
+     * Just pull them out of the surface. */
+    width = cairo_image_surface_get_width (surface);
+    height = cairo_image_surface_get_width (surface);
+  }
+  else
+#endif
+  if (format == HB_PAINT_IMAGE_FORMAT_BGRA)
+  {
+    /* Byte-endian conversion. */
+    unsigned data_size = hb_blob_get_length (blob);
+    if (data_size < width * height * 4)
+      return false;
+
+    unsigned char *data;
+#ifdef __BYTE_ORDER
+    if (__BYTE_ORDER == __BIG_ENDIAN)
+    {
+      data = (unsigned char *) hb_blob_get_data_writable (blob, nullptr);
+      if (!data)
+        return false;
+
+      unsigned count = width * height * 4;
+      for (unsigned i = 0; i < count; i += 4)
+      {
+        unsigned char b;
+	b = data[i];
+	data[i] = data[i+3];
+	data[i+3] = b;
+	b = data[i+1];
+	data[i+1] = data[i+2];
+	data[i+2] = b;
+      }
+    }
+    else
+#endif
+      data = (unsigned char *) hb_blob_get_data (blob, nullptr);
+
+    surface = cairo_image_surface_create_for_data (data,
+						   CAIRO_FORMAT_ARGB32,
+						   width, height,
+						   width * 4);
+
+    cairo_surface_set_user_data (surface,
+				 _hb_cairo_surface_blob_user_data_key,
+				 hb_blob_reference (blob),
+				 _hb_cairo_destroy_blob);
+  }
+
+  if (!surface)
+    return false;
+
+  cairo_save (cr);
+  /* this clip is here to work around recording surface limitations */
+  cairo_rectangle (cr,
+                   extents->x_bearing,
+                   extents->y_bearing,
+                   extents->width,
+                   extents->height);
+  cairo_clip (cr);
+
+  cairo_pattern_t *pattern = cairo_pattern_create_for_surface (surface);
+  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_PAD);
+
+  cairo_matrix_t matrix = {(double) width, 0, 0, (double) height, 0, 0};
+  cairo_pattern_set_matrix (pattern, &matrix);
+
+  /* Undo slant in the extents and apply it in the context. */
+  extents->width -= extents->height * slant;
+  extents->x_bearing -= extents->y_bearing * slant;
+  cairo_matrix_t cairo_matrix = {1., 0., (double) slant, 1., 0., 0.};
+  cairo_transform (cr, &cairo_matrix);
+
+  cairo_translate (cr, extents->x_bearing, extents->y_bearing);
+  cairo_scale (cr, extents->width, extents->height);
+  cairo_set_source (cr, pattern);
+
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+  cairo_surface_destroy (surface);
+
+  cairo_restore (cr);
+
+  return true;
+}
+
+static void
+_hb_cairo_reduce_anchors (float x0, float y0,
+			  float x1, float y1,
+			  float x2, float y2,
+			  float *xx0, float *yy0,
+			  float *xx1, float *yy1)
+{
+  float q1x, q1y, q2x, q2y;
+  float s;
+  float k;
+
+  q2x = x2 - x0;
+  q2y = y2 - y0;
+  q1x = x1 - x0;
+  q1y = y1 - y0;
+
+  s = q2x * q2x + q2y * q2y;
+  if (s < 0.000001f)
+    {
+      *xx0 = x0; *yy0 = y0;
+      *xx1 = x1; *yy1 = y1;
+      return;
+    }
+
+  k = (q2x * q1x + q2y * q1y) / s;
+  *xx0 = x0;
+  *yy0 = y0;
+  *xx1 = x1 - k * q2x;
+  *yy1 = y1 - k * q2y;
+}
+
+static int
+_hb_cairo_cmp_color_stop (const void *p1,
+			  const void *p2)
+{
+  const hb_color_stop_t *c1 = (const hb_color_stop_t *) p1;
+  const hb_color_stop_t *c2 = (const hb_color_stop_t *) p2;
+
+  if (c1->offset < c2->offset)
+    return -1;
+  else if (c1->offset > c2->offset)
+    return 1;
+  else
+    return 0;
+}
+
+static void
+_hb_cairo_normalize_color_line (hb_color_stop_t *stops,
+				unsigned int len,
+				float *omin,
+				float *omax)
+{
+  float min, max;
+
+  hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
+
+  min = max = stops[0].offset;
+  for (unsigned int i = 0; i < len; i++)
+    {
+      min = hb_min (min, stops[i].offset);
+      max = hb_max (max, stops[i].offset);
+    }
+
+  if (min != max)
+    {
+      for (unsigned int i = 0; i < len; i++)
+        stops[i].offset = (stops[i].offset - min) / (max - min);
+    }
+
+  *omin = min;
+  *omax = max;
+}
+
+static bool
+_hb_cairo_get_color_stops (hb_cairo_context_t *c,
+			   hb_color_line_t *color_line,
+			   unsigned *count,
+			   hb_color_stop_t **stops)
+{
+  unsigned len = hb_color_line_get_color_stops (color_line, 0, nullptr, nullptr);
+  if (len > *count)
+  {
+    *stops = (hb_color_stop_t *) hb_malloc (len * sizeof (hb_color_stop_t));
+    if (unlikely (!stops))
+      return false;
+  }
+  hb_color_line_get_color_stops (color_line, 0, &len, *stops);
+  for (unsigned i = 0; i < len; i++)
+    if ((*stops)[i].is_foreground)
+    {
+#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
+      double r, g, b, a;
+      cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
+      if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
+        (*stops)[i].color = HB_COLOR (round (b * 255.), round (g * 255.), round (r * 255.),
+                                      round (a * hb_color_get_alpha ((*stops)[i].color)));
+      else
+#endif
+        (*stops)[i].color = HB_COLOR (0, 0, 0, hb_color_get_alpha ((*stops)[i].color));
+    }
+
+  *count = len;
+  return true;
+}
+
+void
+_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
+				 hb_color_line_t *color_line,
+				 float x0, float y0,
+				 float x1, float y1,
+				 float x2, float y2)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  float xx0, yy0, xx1, yy1;
+  float xxx0, yyy0, xxx1, yyy1;
+  float min, max;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+  _hb_cairo_normalize_color_line (stops, len, &min, &max);
+
+  _hb_cairo_reduce_anchors (x0, y0, x1, y1, x2, y2, &xx0, &yy0, &xx1, &yy1);
+
+  xxx0 = xx0 + min * (xx1 - xx0);
+  yyy0 = yy0 + min * (yy1 - yy0);
+  xxx1 = xx0 + max * (xx1 - xx0);
+  yyy1 = yy0 + max * (yy1 - yy0);
+
+  pattern = cairo_pattern_create_linear ((double) xxx0, (double) yyy0, (double) xxx1, (double) yyy1);
+  cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
+  for (unsigned int i = 0; i < len; i++)
+    {
+      double r, g, b, a;
+      r = hb_color_get_red (stops[i].color) / 255.;
+      g = hb_color_get_green (stops[i].color) / 255.;
+      b = hb_color_get_blue (stops[i].color) / 255.;
+      a = hb_color_get_alpha (stops[i].color) / 255.;
+      cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+void
+_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
+				 hb_color_line_t *color_line,
+				 float x0, float y0, float r0,
+				 float x1, float y1, float r1)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  float min, max;
+  float xx0, yy0, xx1, yy1;
+  float rr0, rr1;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+  _hb_cairo_normalize_color_line (stops, len, &min, &max);
+
+  xx0 = x0 + min * (x1 - x0);
+  yy0 = y0 + min * (y1 - y0);
+  xx1 = x0 + max * (x1 - x0);
+  yy1 = y0 + max * (y1 - y0);
+  rr0 = r0 + min * (r1 - r0);
+  rr1 = r0 + max * (r1 - r0);
+
+  pattern = cairo_pattern_create_radial ((double) xx0, (double) yy0, (double) rr0, (double) xx1, (double) yy1, (double) rr1);
+  cairo_pattern_set_extend (pattern, hb_cairo_extend (hb_color_line_get_extend (color_line)));
+
+  for (unsigned int i = 0; i < len; i++)
+    {
+      double r, g, b, a;
+      r = hb_color_get_red (stops[i].color) / 255.;
+      g = hb_color_get_green (stops[i].color) / 255.;
+      b = hb_color_get_blue (stops[i].color) / 255.;
+      a = hb_color_get_alpha (stops[i].color) / 255.;
+      cairo_pattern_add_color_stop_rgba (pattern, (double) stops[i].offset, r, g, b, a);
+    }
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+typedef struct {
+  float x, y;
+} hb_cairo_point_t;
+
+static inline float
+_hb_cairo_interpolate (float f0, float f1, float f)
+{
+  return f0 + f * (f1 - f0);
+}
+
+static inline void
+_hb_cairo_premultiply (hb_cairo_color_t *c)
+{
+  c->r *= c->a;
+  c->g *= c->a;
+  c->b *= c->a;
+}
+
+static inline void
+_hb_cairo_unpremultiply (hb_cairo_color_t *c)
+{
+  if (c->a != 0.f)
+  {
+     c->r /= c->a;
+     c->g /= c->a;
+     c->b /= c->a;
+  }
+}
+
+static void
+_hb_cairo_interpolate_colors (hb_cairo_color_t *c0, hb_cairo_color_t *c1, float k, hb_cairo_color_t *c)
+{
+  // According to the COLR specification, gradients
+  // should be interpolated in premultiplied form
+  _hb_cairo_premultiply (c0);
+  _hb_cairo_premultiply (c1);
+  c->r = c0->r + k * (c1->r - c0->r);
+  c->g = c0->g + k * (c1->g - c0->g);
+  c->b = c0->b + k * (c1->b - c0->b);
+  c->a = c0->a + k * (c1->a - c0->a);
+  _hb_cairo_unpremultiply (c);
+}
+
+static inline float
+_hb_cairo_dot (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return p.x * q.x + p.y * q.y;
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_normalize (hb_cairo_point_t p)
+{
+  float len = sqrtf (_hb_cairo_dot (p, p));
+
+  return hb_cairo_point_t { p.x / len, p.y / len };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_sum (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return hb_cairo_point_t { p.x + q.x, p.y + q.y };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_difference (hb_cairo_point_t p, hb_cairo_point_t q)
+{
+  return hb_cairo_point_t { p.x - q.x, p.y - q.y };
+}
+
+static inline hb_cairo_point_t
+_hb_cairo_scale (hb_cairo_point_t p, float f)
+{
+  return hb_cairo_point_t { p.x * f, p.y * f };
+}
+
+typedef struct {
+  hb_cairo_point_t center, p0, c0, c1, p1;
+  hb_cairo_color_t color0, color1;
+} hb_cairo_patch_t;
+
+static void
+_hb_cairo_add_patch (cairo_pattern_t *pattern, hb_cairo_point_t *center, hb_cairo_patch_t *p)
+{
+  cairo_mesh_pattern_begin_patch (pattern);
+  cairo_mesh_pattern_move_to (pattern, (double) center->x, (double) center->y);
+  cairo_mesh_pattern_line_to (pattern, (double) p->p0.x, (double) p->p0.y);
+  cairo_mesh_pattern_curve_to (pattern,
+                               (double) p->c0.x, (double) p->c0.y,
+                               (double) p->c1.x, (double) p->c1.y,
+                               (double) p->p1.x, (double) p->p1.y);
+  cairo_mesh_pattern_line_to (pattern, (double) center->x, (double) center->y);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 0,
+                                            (double) p->color0.r,
+                                            (double) p->color0.g,
+                                            (double) p->color0.b,
+                                            (double) p->color0.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 1,
+                                            (double) p->color0.r,
+                                            (double) p->color0.g,
+                                            (double) p->color0.b,
+                                            (double) p->color0.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 2,
+                                            (double) p->color1.r,
+                                            (double) p->color1.g,
+                                            (double) p->color1.b,
+                                            (double) p->color1.a);
+  cairo_mesh_pattern_set_corner_color_rgba (pattern, 3,
+                                            (double) p->color1.r,
+                                            (double) p->color1.g,
+                                            (double) p->color1.b,
+                                            (double) p->color1.a);
+  cairo_mesh_pattern_end_patch (pattern);
+}
+
+#define MAX_ANGLE ((float) M_PI / 8.f)
+
+static void
+_hb_cairo_add_sweep_gradient_patches1 (float cx, float cy, float radius,
+				       float a0, hb_cairo_color_t *c0,
+				       float a1, hb_cairo_color_t *c1,
+				       cairo_pattern_t *pattern)
+{
+  hb_cairo_point_t center = hb_cairo_point_t { cx, cy };
+  int num_splits;
+  hb_cairo_point_t p0;
+  hb_cairo_color_t color0, color1;
+
+  num_splits = ceilf (fabsf (a1 - a0) / MAX_ANGLE);
+  p0 = hb_cairo_point_t { cosf (a0), sinf (a0) };
+  color0 = *c0;
+
+  for (int a = 0; a < num_splits; a++)
+    {
+      float k = (a + 1.) / num_splits;
+      float angle1;
+      hb_cairo_point_t p1;
+      hb_cairo_point_t A, U;
+      hb_cairo_point_t C0, C1;
+      hb_cairo_patch_t patch;
+
+      angle1 = _hb_cairo_interpolate (a0, a1, k);
+      _hb_cairo_interpolate_colors (c0, c1, k, &color1);
+
+      patch.color0 = color0;
+      patch.color1 = color1;
+
+      p1 = hb_cairo_point_t { cosf (angle1), sinf (angle1) };
+      patch.p0 = _hb_cairo_sum (center, _hb_cairo_scale (p0, radius));
+      patch.p1 = _hb_cairo_sum (center, _hb_cairo_scale (p1, radius));
+
+      A = _hb_cairo_normalize (_hb_cairo_sum (p0, p1));
+      U = hb_cairo_point_t { -A.y, A.x };
+      C0 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p0, A), p0) / _hb_cairo_dot (U, p0)));
+      C1 = _hb_cairo_sum (A, _hb_cairo_scale (U, _hb_cairo_dot (_hb_cairo_difference (p1, A), p1) / _hb_cairo_dot (U, p1)));
+
+      patch.c0 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C0, _hb_cairo_scale (_hb_cairo_difference (C0, p0), 0.33333f)), radius));
+      patch.c1 = _hb_cairo_sum (center, _hb_cairo_scale (_hb_cairo_sum (C1, _hb_cairo_scale (_hb_cairo_difference (C1, p1), 0.33333f)), radius));
+
+      _hb_cairo_add_patch (pattern, &center, &patch);
+
+      p0 = p1;
+      color0 = color1;
+    }
+}
+
+static void
+_hb_cairo_add_sweep_gradient_patches (hb_color_stop_t *stops,
+				      unsigned int n_stops,
+				      cairo_extend_t extend,
+				      float cx, float cy,
+				      float radius,
+				      float start_angle,
+				      float end_angle,
+				      cairo_pattern_t *pattern)
+{
+  float angles_[PREALLOCATED_COLOR_STOPS];
+  float *angles = angles_;
+  hb_cairo_color_t colors_[PREALLOCATED_COLOR_STOPS];
+  hb_cairo_color_t *colors = colors_;
+  hb_cairo_color_t color0, color1;
+
+  if (start_angle == end_angle)
+  {
+    if (extend == CAIRO_EXTEND_PAD)
+    {
+      hb_cairo_color_t c;
+      if (start_angle > 0)
+      {
+	c.r = hb_color_get_red (stops[0].color) / 255.;
+	c.g = hb_color_get_green (stops[0].color) / 255.;
+	c.b = hb_color_get_blue (stops[0].color) / 255.;
+	c.a = hb_color_get_alpha (stops[0].color) / 255.;
+	_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					       0.,          &c,
+					       start_angle, &c,
+					       pattern);
+      }
+      if (end_angle < _2_M_PIf)
+      {
+	c.r = hb_color_get_red (stops[n_stops - 1].color) / 255.;
+	c.g = hb_color_get_green (stops[n_stops - 1].color) / 255.;
+	c.b = hb_color_get_blue (stops[n_stops - 1].color) / 255.;
+	c.a = hb_color_get_alpha (stops[n_stops - 1].color) / 255.;
+	_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					       end_angle, &c,
+					       _2_M_PIf,  &c,
+					       pattern);
+      }
+    }
+    return;
+  }
+
+  assert (start_angle != end_angle);
+
+  /* handle directions */
+  if (end_angle < start_angle)
+  {
+    hb_swap (start_angle, end_angle);
+
+    for (unsigned i = 0; i < n_stops - 1 - i; i++)
+      hb_swap (stops[i], stops[n_stops - 1 - i]);
+    for (unsigned i = 0; i < n_stops; i++)
+      stops[i].offset = 1 - stops[i].offset;
+  }
+
+  if (n_stops > PREALLOCATED_COLOR_STOPS)
+  {
+    angles = (float *) hb_malloc (sizeof (float) * n_stops);
+    colors = (hb_cairo_color_t *) hb_malloc (sizeof (hb_cairo_color_t) * n_stops);
+    if (unlikely (!angles || !colors))
+    {
+      hb_free (angles);
+      hb_free (colors);
+      return;
+    }
+  }
+
+  for (unsigned i = 0; i < n_stops; i++)
+  {
+    angles[i] = start_angle + stops[i].offset * (end_angle - start_angle);
+    colors[i].r = hb_color_get_red (stops[i].color) / 255.;
+    colors[i].g = hb_color_get_green (stops[i].color) / 255.;
+    colors[i].b = hb_color_get_blue (stops[i].color) / 255.;
+    colors[i].a = hb_color_get_alpha (stops[i].color) / 255.;
+  }
+
+  if (extend == CAIRO_EXTEND_PAD)
+  {
+    unsigned pos;
+
+    color0 = colors[0];
+    for (pos = 0; pos < n_stops; pos++)
+    {
+      if (angles[pos] >= 0)
+      {
+	if (pos > 0)
+	{
+	  float k = (0 - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+	  _hb_cairo_interpolate_colors (&colors[pos-1], &colors[pos], k, &color0);
+	}
+	break;
+      }
+    }
+    if (pos == n_stops)
+    {
+      /* everything is below 0 */
+      color0 = colors[n_stops-1];
+      _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					     0.,       &color0,
+					     _2_M_PIf, &color0,
+					     pattern);
+      goto done;
+    }
+
+    _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					   0.,          &color0,
+					   angles[pos], &colors[pos],
+					   pattern);
+
+    for (pos++; pos < n_stops; pos++)
+    {
+      if (angles[pos] <= _2_M_PIf)
+      {
+	_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					       angles[pos - 1], &colors[pos-1],
+					       angles[pos],     &colors[pos],
+					       pattern);
+      }
+      else
+      {
+	float k = (_2_M_PIf - angles[pos - 1]) / (angles[pos] - angles[pos - 1]);
+	_hb_cairo_interpolate_colors (&colors[pos - 1], &colors[pos], k, &color1);
+	_hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					       angles[pos - 1], &colors[pos - 1],
+					       _2_M_PIf,        &color1,
+					       pattern);
+	break;
+      }
+    }
+
+    if (pos == n_stops)
+    {
+      /* everything is below 2*M_PI */
+      color0 = colors[n_stops - 1];
+      _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+					     angles[n_stops - 1], &color0,
+					     _2_M_PIf,            &color0,
+					     pattern);
+      goto done;
+    }
+  }
+  else
+  {
+    int k;
+    float span;
+
+    span = angles[n_stops - 1] - angles[0];
+    k = 0;
+    if (angles[0] >= 0)
+    {
+      float ss = angles[0];
+      while (ss > 0)
+      {
+	if (span > 0)
+	{
+	  ss -= span;
+	  k--;
+	}
+	else
+	{
+	  ss += span;
+	  k++;
+	}
+      }
+    }
+    else if (angles[0] < 0)
+    {
+      float ee = angles[n_stops - 1];
+      while (ee < 0)
+      {
+	if (span > 0)
+	{
+	  ee += span;
+	  k++;
+	}
+	else
+	{
+	  ee -= span;
+	  k--;
+	}
+      }
+    }
+
+    //assert (angles[0] + k * span <= 0 && 0 < angles[n_stops - 1] + k * span);
+    span = fabs (span);
+
+    for (signed l = k; l < 1000; l++)
+    {
+      for (unsigned i = 1; i < n_stops; i++)
+      {
+        float a0, a1;
+	hb_cairo_color_t *c0, *c1;
+
+	if ((l % 2 != 0) && (extend == CAIRO_EXTEND_REFLECT))
+	{
+	  a0 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - (i-1)] + l * span;
+	  a1 = angles[0] + angles[n_stops - 1] - angles[n_stops - 1 - i] + l * span;
+	  c0 = &colors[n_stops - 1 - (i - 1)];
+	  c1 = &colors[n_stops - 1 - i];
+	}
+	else
+	{
+	  a0 = angles[i-1] + l * span;
+	  a1 = angles[i] + l * span;
+	  c0 = &colors[i-1];
+	  c1 = &colors[i];
+	}
+
+	if (a1 < 0)
+	  continue;
+	if (a0 < 0)
+	{
+	  hb_cairo_color_t color;
+	  float f = (0 - a0)/(a1 - a0);
+	  _hb_cairo_interpolate_colors (c0, c1, f, &color);
+	  _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+						 0,  &color,
+						 a1, c1,
+						 pattern);
+	}
+	else if (a1 >= _2_M_PIf)
+	{
+	  hb_cairo_color_t color;
+	  float f = (_2_M_PIf - a0)/(a1 - a0);
+	  _hb_cairo_interpolate_colors (c0, c1, f, &color);
+	  _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+						 a0,       c0,
+						 _2_M_PIf, &color,
+						 pattern);
+	  goto done;
+	}
+	else
+	{
+	  _hb_cairo_add_sweep_gradient_patches1 (cx, cy, radius,
+						 a0, c0,
+						 a1, c1,
+						 pattern);
+	}
+      }
+    }
+  }
+
+done:
+
+  if (angles != angles_)
+    hb_free (angles);
+  if (colors != colors_)
+    hb_free (colors);
+}
+
+void
+_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
+				hb_color_line_t *color_line,
+				float cx, float cy,
+				float start_angle,
+				float end_angle)
+{
+  cairo_t *cr = c->cr;
+
+  unsigned int len = PREALLOCATED_COLOR_STOPS;
+  hb_color_stop_t stops_[PREALLOCATED_COLOR_STOPS];
+  hb_color_stop_t *stops = stops_;
+  cairo_extend_t extend;
+  double x1, y1, x2, y2;
+  float max_x, max_y, radius;
+  cairo_pattern_t *pattern;
+
+  if (unlikely (!_hb_cairo_get_color_stops (c, color_line, &len, &stops)))
+    return;
+
+  hb_qsort (stops, len, sizeof (hb_color_stop_t), _hb_cairo_cmp_color_stop);
+
+  cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
+  max_x = (float) hb_max ((x1 - (double) cx) * (x1 - (double) cx), (x2 - (double) cx) * (x2 - (double) cx));
+  max_y = (float) hb_max ((y1 - (double) cy) * (y1 - (double) cy), (y2 - (double) cy) * (y2 - (double) cy));
+  radius = sqrtf (max_x + max_y);
+
+  extend = hb_cairo_extend (hb_color_line_get_extend (color_line));
+  pattern = cairo_pattern_create_mesh ();
+
+  _hb_cairo_add_sweep_gradient_patches (stops, len, extend, cx, cy,
+					radius, start_angle, end_angle, pattern);
+
+  cairo_set_source (cr, pattern);
+  cairo_paint (cr);
+
+  cairo_pattern_destroy (pattern);
+
+  if (stops != stops_)
+    hb_free (stops);
+}
+
+#endif

+ 107 - 0
thirdparty/harfbuzz/src/hb-cairo-utils.hh

@@ -0,0 +1,107 @@
+/*
+ * Copyright © 2022  Red Hat, Inc
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Google Author(s): Matthias Clasen
+ */
+
+#ifndef HB_CAIRO_UTILS_H
+#define HB_CAIRO_UTILS_H
+
+#include "hb.hh"
+#include "hb-cairo.h"
+
+
+typedef struct
+{
+  cairo_scaled_font_t *scaled_font;
+  cairo_t *cr;
+  hb_map_t *color_cache;
+} hb_cairo_context_t;
+
+static inline cairo_operator_t
+_hb_paint_composite_mode_to_cairo (hb_paint_composite_mode_t mode)
+{
+  switch (mode)
+    {
+    case HB_PAINT_COMPOSITE_MODE_CLEAR: return CAIRO_OPERATOR_CLEAR;
+    case HB_PAINT_COMPOSITE_MODE_SRC: return CAIRO_OPERATOR_SOURCE;
+    case HB_PAINT_COMPOSITE_MODE_DEST: return CAIRO_OPERATOR_DEST;
+    case HB_PAINT_COMPOSITE_MODE_SRC_OVER: return CAIRO_OPERATOR_OVER;
+    case HB_PAINT_COMPOSITE_MODE_DEST_OVER: return CAIRO_OPERATOR_DEST_OVER;
+    case HB_PAINT_COMPOSITE_MODE_SRC_IN: return CAIRO_OPERATOR_IN;
+    case HB_PAINT_COMPOSITE_MODE_DEST_IN: return CAIRO_OPERATOR_DEST_IN;
+    case HB_PAINT_COMPOSITE_MODE_SRC_OUT: return CAIRO_OPERATOR_OUT;
+    case HB_PAINT_COMPOSITE_MODE_DEST_OUT: return CAIRO_OPERATOR_DEST_OUT;
+    case HB_PAINT_COMPOSITE_MODE_SRC_ATOP: return CAIRO_OPERATOR_ATOP;
+    case HB_PAINT_COMPOSITE_MODE_DEST_ATOP: return CAIRO_OPERATOR_DEST_ATOP;
+    case HB_PAINT_COMPOSITE_MODE_XOR: return CAIRO_OPERATOR_XOR;
+    case HB_PAINT_COMPOSITE_MODE_PLUS: return CAIRO_OPERATOR_ADD;
+    case HB_PAINT_COMPOSITE_MODE_SCREEN: return CAIRO_OPERATOR_SCREEN;
+    case HB_PAINT_COMPOSITE_MODE_OVERLAY: return CAIRO_OPERATOR_OVERLAY;
+    case HB_PAINT_COMPOSITE_MODE_DARKEN: return CAIRO_OPERATOR_DARKEN;
+    case HB_PAINT_COMPOSITE_MODE_LIGHTEN: return CAIRO_OPERATOR_LIGHTEN;
+    case HB_PAINT_COMPOSITE_MODE_COLOR_DODGE: return CAIRO_OPERATOR_COLOR_DODGE;
+    case HB_PAINT_COMPOSITE_MODE_COLOR_BURN: return CAIRO_OPERATOR_COLOR_BURN;
+    case HB_PAINT_COMPOSITE_MODE_HARD_LIGHT: return CAIRO_OPERATOR_HARD_LIGHT;
+    case HB_PAINT_COMPOSITE_MODE_SOFT_LIGHT: return CAIRO_OPERATOR_SOFT_LIGHT;
+    case HB_PAINT_COMPOSITE_MODE_DIFFERENCE: return CAIRO_OPERATOR_DIFFERENCE;
+    case HB_PAINT_COMPOSITE_MODE_EXCLUSION: return CAIRO_OPERATOR_EXCLUSION;
+    case HB_PAINT_COMPOSITE_MODE_MULTIPLY: return CAIRO_OPERATOR_MULTIPLY;
+    case HB_PAINT_COMPOSITE_MODE_HSL_HUE: return CAIRO_OPERATOR_HSL_HUE;
+    case HB_PAINT_COMPOSITE_MODE_HSL_SATURATION: return CAIRO_OPERATOR_HSL_SATURATION;
+    case HB_PAINT_COMPOSITE_MODE_HSL_COLOR: return CAIRO_OPERATOR_HSL_COLOR;
+    case HB_PAINT_COMPOSITE_MODE_HSL_LUMINOSITY: return CAIRO_OPERATOR_HSL_LUMINOSITY;
+    default: return CAIRO_OPERATOR_CLEAR;
+    }
+}
+
+HB_INTERNAL hb_bool_t
+_hb_cairo_paint_glyph_image (hb_cairo_context_t *c,
+			     hb_blob_t *blob,
+			     unsigned width,
+			     unsigned height,
+			     hb_tag_t format,
+			     float slant,
+			     hb_glyph_extents_t *extents);
+
+HB_INTERNAL void
+_hb_cairo_paint_linear_gradient (hb_cairo_context_t *c,
+				 hb_color_line_t *color_line,
+				 float x0, float y0,
+				 float x1, float y1,
+				 float x2, float y2);
+
+HB_INTERNAL void
+_hb_cairo_paint_radial_gradient (hb_cairo_context_t *c,
+				 hb_color_line_t *color_line,
+				 float x0, float y0, float r0,
+				 float x1, float y1, float r1);
+
+HB_INTERNAL void
+_hb_cairo_paint_sweep_gradient (hb_cairo_context_t *c,
+				hb_color_line_t *color_line,
+				float x0, float y0,
+				float start_angle, float end_angle);
+
+
+#endif /* HB_CAIRO_UTILS_H */

+ 1010 - 0
thirdparty/harfbuzz/src/hb-cairo.cc

@@ -0,0 +1,1010 @@
+/*
+ * Copyright © 2022  Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Matthias Clasen
+ */
+
+#include "hb.hh"
+
+#ifdef HAVE_CAIRO
+
+#include "hb-cairo.h"
+
+#include "hb-cairo-utils.hh"
+
+#include "hb-machinery.hh"
+#include "hb-utf.hh"
+
+
+/**
+ * SECTION:hb-cairo
+ * @title: hb-cairo
+ * @short_description: Cairo integration
+ * @include: hb-cairo.h
+ *
+ * Functions for using HarfBuzz with the cairo library.
+ *
+ * HarfBuzz supports using cairo for rendering.
+ **/
+
+static void
+hb_cairo_move_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+		  void *draw_data,
+		  hb_draw_state_t *st HB_UNUSED,
+		  float to_x, float to_y,
+		  void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_move_to (cr, (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_line_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+		  void *draw_data,
+		  hb_draw_state_t *st HB_UNUSED,
+		  float to_x, float to_y,
+		  void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_line_to (cr, (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_cubic_to (hb_draw_funcs_t *dfuncs HB_UNUSED,
+		   void *draw_data,
+		   hb_draw_state_t *st HB_UNUSED,
+		   float control1_x, float control1_y,
+		   float control2_x, float control2_y,
+		   float to_x, float to_y,
+		   void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_curve_to (cr,
+                  (double) control1_x, (double) control1_y,
+                  (double) control2_x, (double) control2_y,
+                  (double) to_x, (double) to_y);
+}
+
+static void
+hb_cairo_close_path (hb_draw_funcs_t *dfuncs HB_UNUSED,
+		     void *draw_data,
+		     hb_draw_state_t *st HB_UNUSED,
+		     void *user_data HB_UNUSED)
+{
+  cairo_t *cr = (cairo_t *) draw_data;
+
+  cairo_close_path (cr);
+}
+
+static inline void free_static_cairo_draw_funcs ();
+
+static struct hb_cairo_draw_funcs_lazy_loader_t : hb_draw_funcs_lazy_loader_t<hb_cairo_draw_funcs_lazy_loader_t>
+{
+  static hb_draw_funcs_t *create ()
+  {
+    hb_draw_funcs_t *funcs = hb_draw_funcs_create ();
+
+    hb_draw_funcs_set_move_to_func (funcs, hb_cairo_move_to, nullptr, nullptr);
+    hb_draw_funcs_set_line_to_func (funcs, hb_cairo_line_to, nullptr, nullptr);
+    hb_draw_funcs_set_cubic_to_func (funcs, hb_cairo_cubic_to, nullptr, nullptr);
+    hb_draw_funcs_set_close_path_func (funcs, hb_cairo_close_path, nullptr, nullptr);
+
+    hb_draw_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_cairo_draw_funcs);
+
+    return funcs;
+  }
+} static_cairo_draw_funcs;
+
+static inline
+void free_static_cairo_draw_funcs ()
+{
+  static_cairo_draw_funcs.free_instance ();
+}
+
+static hb_draw_funcs_t *
+hb_cairo_draw_get_funcs ()
+{
+  return static_cairo_draw_funcs.get_unconst ();
+}
+
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
+static void
+hb_cairo_push_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
+			 void *paint_data,
+			 float xx, float yx,
+			 float xy, float yy,
+			 float dx, float dy,
+			 void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_matrix_t m;
+
+  cairo_save (cr);
+  cairo_matrix_init (&m, (double) xx, (double) yx,
+                         (double) xy, (double) yy,
+                         (double) dx, (double) dy);
+  cairo_transform (cr, &m);
+}
+
+static void
+hb_cairo_pop_transform (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		        void *paint_data,
+		        void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_restore (cr);
+}
+
+static void
+hb_cairo_push_clip_glyph (hb_paint_funcs_t *pfuncs HB_UNUSED,
+			  void *paint_data,
+			  hb_codepoint_t glyph,
+			  hb_font_t *font,
+			  void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_new_path (cr);
+  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
+  cairo_close_path (cr);
+  cairo_clip (cr);
+}
+
+static void
+hb_cairo_push_clip_rectangle (hb_paint_funcs_t *pfuncs HB_UNUSED,
+			      void *paint_data,
+			      float xmin, float ymin, float xmax, float ymax,
+			      void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_rectangle (cr,
+                   (double) xmin, (double) ymin,
+                   (double) (xmax - xmin), (double) (ymax - ymin));
+  cairo_clip (cr);
+}
+
+static void
+hb_cairo_pop_clip (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		   void *paint_data,
+		   void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_restore (cr);
+}
+
+static void
+hb_cairo_push_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		     void *paint_data,
+		     void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_save (cr);
+  cairo_push_group (cr);
+}
+
+static void
+hb_cairo_pop_group (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		    void *paint_data,
+		    hb_paint_composite_mode_t mode,
+		    void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  cairo_pop_group_to_source (cr);
+  cairo_set_operator (cr, _hb_paint_composite_mode_to_cairo (mode));
+  cairo_paint (cr);
+
+  cairo_restore (cr);
+}
+
+static void
+hb_cairo_paint_color (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		      void *paint_data,
+		      hb_bool_t use_foreground,
+		      hb_color_t color,
+		      void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+  if (use_foreground)
+  {
+#ifdef HAVE_CAIRO_USER_SCALED_FONT_GET_FOREGROUND_SOURCE
+    double r, g, b, a;
+    cairo_pattern_t *foreground = cairo_user_scaled_font_get_foreground_source (c->scaled_font);
+    if (cairo_pattern_get_rgba (foreground, &r, &g, &b, &a) == CAIRO_STATUS_SUCCESS)
+      cairo_set_source_rgba (cr, r, g, b, a * hb_color_get_alpha (color) / 255.);
+    else
+#endif
+      cairo_set_source_rgba (cr, 0, 0, 0, hb_color_get_alpha (color) / 255.);
+  }
+  else
+    cairo_set_source_rgba (cr,
+			   hb_color_get_red (color) / 255.,
+			   hb_color_get_green (color) / 255.,
+			   hb_color_get_blue (color) / 255.,
+			   hb_color_get_alpha (color) / 255.);
+  cairo_paint (cr);
+}
+
+static hb_bool_t
+hb_cairo_paint_image (hb_paint_funcs_t *pfuncs HB_UNUSED,
+		      void *paint_data,
+		      hb_blob_t *blob,
+		      unsigned width,
+		      unsigned height,
+		      hb_tag_t format,
+		      float slant,
+		      hb_glyph_extents_t *extents,
+		      void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  return _hb_cairo_paint_glyph_image (c, blob, width, height, format, slant, extents);
+}
+
+static void
+hb_cairo_paint_linear_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+				void *paint_data,
+				hb_color_line_t *color_line,
+				float x0, float y0,
+				float x1, float y1,
+				float x2, float y2,
+				void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_linear_gradient (c, color_line, x0, y0, x1, y1, x2, y2);
+}
+
+static void
+hb_cairo_paint_radial_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+				void *paint_data,
+				hb_color_line_t *color_line,
+				float x0, float y0, float r0,
+				float x1, float y1, float r1,
+				void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_radial_gradient (c, color_line, x0, y0, r0, x1, y1, r1);
+}
+
+static void
+hb_cairo_paint_sweep_gradient (hb_paint_funcs_t *pfuncs HB_UNUSED,
+			       void *paint_data,
+			       hb_color_line_t *color_line,
+			       float x0, float y0,
+			       float start_angle, float end_angle,
+			       void *user_data HB_UNUSED)
+{
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+
+  _hb_cairo_paint_sweep_gradient (c, color_line, x0, y0, start_angle, end_angle);
+}
+
+static const cairo_user_data_key_t color_cache_key = {0};
+
+static void
+_hb_cairo_destroy_map (void *p)
+{
+  hb_map_destroy ((hb_map_t *) p);
+}
+
+static hb_bool_t
+hb_cairo_paint_custom_palette_color (hb_paint_funcs_t *funcs,
+                                     void *paint_data,
+                                     unsigned int color_index,
+                                     hb_color_t *color,
+                                     void *user_data HB_UNUSED)
+{
+#ifdef HAVE_CAIRO_FONT_OPTIONS_GET_CUSTOM_PALETTE_COLOR
+  hb_cairo_context_t *c = (hb_cairo_context_t *) paint_data;
+  cairo_t *cr = c->cr;
+
+#define HB_DEADBEEF HB_TAG(0xDE,0xAD,0xBE,0xEF)
+
+  hb_map_t *color_cache = c->color_cache;
+  hb_codepoint_t *v;
+  if (likely (color_cache && color_cache->has (color_index, &v)))
+  {
+    if (*v == HB_DEADBEEF)
+      return false;
+    *color = *v;
+    return true;
+  }
+
+  cairo_font_options_t *options;
+  double red, green, blue, alpha;
+
+  options = cairo_font_options_create ();
+  cairo_get_font_options (cr, options);
+  if (CAIRO_STATUS_SUCCESS ==
+      cairo_font_options_get_custom_palette_color (options, color_index,
+                                                   &red, &green, &blue, &alpha))
+  {
+    cairo_font_options_destroy (options);
+    *color = HB_COLOR (round (255 * blue),
+		       round (255 * green),
+		       round (255 * red),
+		       round (255 * alpha));
+
+    if (likely (color_cache && *color != HB_DEADBEEF))
+      color_cache->set (color_index, *color);
+
+    return true;
+  }
+  cairo_font_options_destroy (options);
+
+  if (likely (color_cache))
+    color_cache->set (color_index, HB_DEADBEEF);
+
+#undef HB_DEADBEEF
+
+#endif
+
+  return false;
+}
+
+static inline void free_static_cairo_paint_funcs ();
+
+static struct hb_cairo_paint_funcs_lazy_loader_t : hb_paint_funcs_lazy_loader_t<hb_cairo_paint_funcs_lazy_loader_t>
+{
+  static hb_paint_funcs_t *create ()
+  {
+    hb_paint_funcs_t *funcs = hb_paint_funcs_create ();
+
+    hb_paint_funcs_set_push_transform_func (funcs, hb_cairo_push_transform, nullptr, nullptr);
+    hb_paint_funcs_set_pop_transform_func (funcs, hb_cairo_pop_transform, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_glyph_func (funcs, hb_cairo_push_clip_glyph, nullptr, nullptr);
+    hb_paint_funcs_set_push_clip_rectangle_func (funcs, hb_cairo_push_clip_rectangle, nullptr, nullptr);
+    hb_paint_funcs_set_pop_clip_func (funcs, hb_cairo_pop_clip, nullptr, nullptr);
+    hb_paint_funcs_set_push_group_func (funcs, hb_cairo_push_group, nullptr, nullptr);
+    hb_paint_funcs_set_pop_group_func (funcs, hb_cairo_pop_group, nullptr, nullptr);
+    hb_paint_funcs_set_color_func (funcs, hb_cairo_paint_color, nullptr, nullptr);
+    hb_paint_funcs_set_image_func (funcs, hb_cairo_paint_image, nullptr, nullptr);
+    hb_paint_funcs_set_linear_gradient_func (funcs, hb_cairo_paint_linear_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_radial_gradient_func (funcs, hb_cairo_paint_radial_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_sweep_gradient_func (funcs, hb_cairo_paint_sweep_gradient, nullptr, nullptr);
+    hb_paint_funcs_set_custom_palette_color_func (funcs, hb_cairo_paint_custom_palette_color, nullptr, nullptr);
+
+    hb_paint_funcs_make_immutable (funcs);
+
+    hb_atexit (free_static_cairo_paint_funcs);
+
+    return funcs;
+  }
+} static_cairo_paint_funcs;
+
+static inline
+void free_static_cairo_paint_funcs ()
+{
+  static_cairo_paint_funcs.free_instance ();
+}
+
+static hb_paint_funcs_t *
+hb_cairo_paint_get_funcs ()
+{
+  return static_cairo_paint_funcs.get_unconst ();
+}
+#endif
+
+static const cairo_user_data_key_t hb_cairo_face_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_init_func_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_font_init_user_data_user_data_key = {0};
+static const cairo_user_data_key_t hb_cairo_scale_factor_user_data_key = {0};
+
+static void hb_cairo_face_destroy (void *p) { hb_face_destroy ((hb_face_t *) p); }
+static void hb_cairo_font_destroy (void *p) { hb_font_destroy ((hb_font_t *) p); }
+
+static cairo_status_t
+hb_cairo_init_scaled_font (cairo_scaled_font_t  *scaled_font,
+			   cairo_t              *cr HB_UNUSED,
+			   cairo_font_extents_t *extents)
+{
+  cairo_font_face_t *font_face = cairo_scaled_font_get_font_face (scaled_font);
+
+  hb_font_t *font = (hb_font_t *) cairo_font_face_get_user_data (font_face,
+								 &hb_cairo_font_user_data_key);
+
+  if (!font)
+  {
+    hb_face_t *face = (hb_face_t *) cairo_font_face_get_user_data (font_face,
+								   &hb_cairo_face_user_data_key);
+    font = hb_font_create (face);
+
+#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1,16,0)
+    cairo_font_options_t *font_options = cairo_font_options_create ();
+
+    // Set variations
+    cairo_scaled_font_get_font_options (scaled_font, font_options);
+    const char *variations = cairo_font_options_get_variations (font_options);
+    hb_vector_t<hb_variation_t> vars;
+    const char *p = variations;
+    while (p && *p)
+    {
+      const char *end = strpbrk ((char *) p, ", ");
+      hb_variation_t var;
+      if (hb_variation_from_string (p, end ? end - p : -1, &var))
+	vars.push (var);
+      p = end ? end + 1 : nullptr;
+    }
+    hb_font_set_variations (font, &vars[0], vars.length);
+
+    cairo_font_options_destroy (font_options);
+#endif
+
+    // Set scale; Note: should NOT set slant, or we'll double-slant.
+    unsigned scale_factor = hb_cairo_font_face_get_scale_factor (font_face);
+    if (scale_factor)
+    {
+      cairo_matrix_t font_matrix;
+      cairo_scaled_font_get_scale_matrix (scaled_font, &font_matrix);
+      hb_font_set_scale (font,
+			 round (font_matrix.xx * scale_factor),
+			 round (font_matrix.yy * scale_factor));
+    }
+
+    auto *init_func = (hb_cairo_font_init_func_t)
+		      cairo_font_face_get_user_data (font_face,
+						     &hb_cairo_font_init_func_user_data_key);
+    if (init_func)
+    {
+      void *user_data = cairo_font_face_get_user_data (font_face,
+						       &hb_cairo_font_init_user_data_user_data_key);
+      font = init_func (font, scaled_font, user_data);
+    }
+
+    hb_font_make_immutable (font);
+  }
+
+  cairo_scaled_font_set_user_data (scaled_font,
+				   &hb_cairo_font_user_data_key,
+				   (void *) hb_font_reference (font),
+				   hb_cairo_font_destroy);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+
+  hb_font_extents_t hb_extents;
+  hb_font_get_h_extents (font, &hb_extents);
+
+  extents->ascent  = (double)  hb_extents.ascender  / y_scale;
+  extents->descent = (double) -hb_extents.descender / y_scale;
+  extents->height  = extents->ascent + extents->descent;
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+  hb_map_t *color_cache = hb_map_create ();
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_scaled_font_set_user_data (scaled_font,
+									 &color_cache_key,
+									 color_cache,
+									 _hb_cairo_destroy_map)))
+    hb_map_destroy (color_cache);
+#endif
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+hb_cairo_text_to_glyphs (cairo_scaled_font_t        *scaled_font,
+			 const char	            *utf8,
+			 int		             utf8_len,
+			 cairo_glyph_t	           **glyphs,
+			 int		            *num_glyphs,
+			 cairo_text_cluster_t      **clusters,
+			 int		            *num_clusters,
+			 cairo_text_cluster_flags_t *cluster_flags)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+								   &hb_cairo_font_user_data_key);
+
+  hb_buffer_t *buffer = hb_buffer_create ();
+  hb_buffer_add_utf8 (buffer, utf8, utf8_len, 0, utf8_len);
+  hb_buffer_guess_segment_properties (buffer);
+  hb_shape (font, buffer, nullptr, 0);
+
+  hb_cairo_glyphs_from_buffer (buffer,
+			       true,
+			       font->x_scale, font->y_scale,
+			       0., 0.,
+			       utf8, utf8_len,
+			       glyphs, (unsigned *) num_glyphs,
+			       clusters, (unsigned *) num_clusters,
+			       cluster_flags);
+
+  hb_buffer_destroy (buffer);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+static cairo_status_t
+hb_cairo_render_glyph (cairo_scaled_font_t  *scaled_font,
+		       unsigned long         glyph,
+		       cairo_t              *cr,
+		       cairo_text_extents_t *extents)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+								   &hb_cairo_font_user_data_key);
+
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+  hb_font_draw_glyph (font, glyph, hb_cairo_draw_get_funcs (), cr);
+
+  cairo_fill (cr);
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+
+static cairo_status_t
+hb_cairo_render_color_glyph (cairo_scaled_font_t  *scaled_font,
+			     unsigned long         glyph,
+			     cairo_t              *cr,
+			     cairo_text_extents_t *extents)
+{
+  hb_font_t *font = (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font,
+								   &hb_cairo_font_user_data_key);
+
+  unsigned int palette = 0;
+#ifdef CAIRO_COLOR_PALETTE_DEFAULT
+  cairo_font_options_t *options = cairo_font_options_create ();
+  cairo_scaled_font_get_font_options (scaled_font, options);
+  palette = cairo_font_options_get_color_palette (options);
+  cairo_font_options_destroy (options);
+#endif
+
+  hb_color_t color = HB_COLOR (0, 0, 0, 255);
+  hb_position_t x_scale, y_scale;
+  hb_font_get_scale (font, &x_scale, &y_scale);
+  cairo_scale (cr, +1./x_scale, -1./y_scale);
+
+  hb_cairo_context_t c;
+  c.scaled_font = scaled_font;
+  c.cr = cr;
+  c.color_cache = (hb_map_t *) cairo_scaled_font_get_user_data (scaled_font, &color_cache_key);
+
+  hb_font_paint_glyph (font, glyph, hb_cairo_paint_get_funcs (), &c, palette, color);
+
+
+  return CAIRO_STATUS_SUCCESS;
+}
+
+#endif
+
+static cairo_font_face_t *
+user_font_face_create (hb_face_t *face)
+{
+  cairo_font_face_t *cairo_face;
+
+  cairo_face = cairo_user_font_face_create ();
+  cairo_user_font_face_set_init_func (cairo_face, hb_cairo_init_scaled_font);
+  cairo_user_font_face_set_text_to_glyphs_func (cairo_face, hb_cairo_text_to_glyphs);
+  cairo_user_font_face_set_render_glyph_func (cairo_face, hb_cairo_render_glyph);
+#ifdef HAVE_CAIRO_USER_FONT_FACE_SET_RENDER_COLOR_GLYPH_FUNC
+  if (hb_ot_color_has_png (face) || hb_ot_color_has_layers (face) || hb_ot_color_has_paint (face))
+    cairo_user_font_face_set_render_color_glyph_func (cairo_face, hb_cairo_render_color_glyph);
+#endif
+
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
+								       &hb_cairo_face_user_data_key,
+								       (void *) hb_face_reference (face),
+								       hb_cairo_face_destroy)))
+    hb_face_destroy (face);
+
+  return cairo_face;
+}
+
+/**
+ * hb_cairo_font_face_create_for_font:
+ * @font: a #hb_font_t
+ *
+ * Creates a #cairo_font_face_t for rendering text according
+ * to @font.
+ *
+ * Note that the scale of @font does not affect the rendering,
+ * but the variations and slant that are set on @font do.
+ *
+ * Returns: (transfer full): a newly created #cairo_font_face_t
+ *
+ * Since: 7.0.0
+ */
+cairo_font_face_t *
+hb_cairo_font_face_create_for_font (hb_font_t *font)
+{
+  hb_font_make_immutable (font);
+
+  auto *cairo_face =  user_font_face_create (font->face);
+
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (cairo_face,
+								       &hb_cairo_font_user_data_key,
+								       (void *) hb_font_reference (font),
+								       hb_cairo_font_destroy)))
+    hb_font_destroy (font);
+
+  return cairo_face;
+}
+
+/**
+ * hb_cairo_font_face_get_font:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the #hb_font_t that @font_face was created from.
+ *
+ * Returns: (nullable) (transfer none): the #hb_font_t that @font_face was created from
+ *
+ * Since: 7.0.0
+ */
+hb_font_t *
+hb_cairo_font_face_get_font (cairo_font_face_t *font_face)
+{
+  return (hb_font_t *) cairo_font_face_get_user_data (font_face,
+						      &hb_cairo_font_user_data_key);
+}
+
+/**
+ * hb_cairo_font_face_create_for_face:
+ * @face: a #hb_face_t
+ *
+ * Creates a #cairo_font_face_t for rendering text according
+ * to @face.
+ *
+ * Returns: (transfer full): a newly created #cairo_font_face_t
+ *
+ * Since: 7.0.0
+ */
+cairo_font_face_t *
+hb_cairo_font_face_create_for_face (hb_face_t *face)
+{
+  hb_face_make_immutable (face);
+
+  return user_font_face_create (face);
+}
+
+/**
+ * hb_cairo_font_face_get_face:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the #hb_face_t associated with @font_face.
+ *
+ * Returns: (nullable) (transfer none): the #hb_face_t associated with @font_face
+ *
+ * Since: 7.0.0
+ */
+hb_face_t *
+hb_cairo_font_face_get_face (cairo_font_face_t *font_face)
+{
+  return (hb_face_t *) cairo_font_face_get_user_data (font_face,
+						      &hb_cairo_face_user_data_key);
+}
+
+/**
+ * hb_cairo_font_face_set_font_init_func:
+ * @font_face: a #cairo_font_face_t
+ * @func: The virtual method to use
+ * @user_data: user data accompanying the method
+ * @destroy: function to call when @user_data is not needed anymore
+ *
+ * Set the virtual method to be called when a cairo
+ * face created using hb_cairo_font_face_create_for_face()
+ * creates an #hb_font_t for a #cairo_scaled_font_t.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
+				       hb_cairo_font_init_func_t func,
+				       void *user_data,
+				       hb_destroy_func_t destroy)
+{
+  cairo_font_face_set_user_data (font_face,
+				 &hb_cairo_font_init_func_user_data_key,
+				 (void *) func,
+				 nullptr);
+  if (unlikely (CAIRO_STATUS_SUCCESS != cairo_font_face_set_user_data (font_face,
+								       &hb_cairo_font_init_user_data_user_data_key,
+								       (void *) user_data,
+								       destroy)) && destroy)
+  {
+    destroy (user_data);
+    cairo_font_face_set_user_data (font_face,
+				   &hb_cairo_font_init_func_user_data_key,
+				   nullptr,
+				   nullptr);
+  }
+}
+
+/**
+ * hb_cairo_scaled_font_get_font:
+ * @scaled_font: a #cairo_scaled_font_t
+ *
+ * Gets the #hb_font_t associated with @scaled_font.
+ *
+ * Returns: (nullable) (transfer none): the #hb_font_t associated with @scaled_font
+ *
+ * Since: 7.0.0
+ */
+hb_font_t *
+hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font)
+{
+  return (hb_font_t *) cairo_scaled_font_get_user_data (scaled_font, &hb_cairo_font_user_data_key);
+}
+
+
+/**
+ * hb_cairo_font_face_set_scale_factor:
+ * @scale_factor: The scale factor to use. See below
+ * @font_face: a #cairo_font_face_t
+ *
+ * Sets the scale factor of the @font_face. Default scale
+ * factor is zero.
+ *
+ * When a #cairo_font_face_t is created from a #hb_face_t using
+ * hb_cairo_font_face_create_for_face(), such face will create
+ * #hb_font_t objects during scaled-font creation.  The scale
+ * factor defines how the scale set on such #hb_font_t objects
+ * relates to the font-matrix (as such font size) of the cairo
+ * scaled-font.
+ *
+ * If the scale-factor is zero (default), then the scale of the
+ * #hb_font_t object will be left at default, which is the UPEM
+ * value of the respective #hb_face_t.
+ *
+ * If the scale-factor is set to non-zero, then the X and Y scale
+ * of the #hb_font_t object will be respectively set to the
+ * @scale_factor times the xx and yy elements of the scale-matrix
+ * of the cairo scaled-font being created.
+ *
+ * When using the hb_cairo_glyphs_from_buffer() API to convert the
+ * HarfBuzz glyph buffer that resulted from shaping with such a #hb_font_t,
+ * if the scale-factor was non-zero, you can pass it directly to
+ * that API as both X and Y scale factors.
+ *
+ * If the scale-factor was zero however, or the cairo face was
+ * created using the alternative constructor
+ * hb_cairo_font_face_create_for_font(), you need to calculate the
+ * correct X/Y scale-factors to pass to hb_cairo_glyphs_from_buffer()
+ * by dividing the #hb_font_t X/Y scale-factors by the
+ * cairo scaled-font's scale-matrix XX/YY components respectively
+ * and use those values.  Or if you know that relationship offhand
+ * (because you set the scale of the #hb_font_t yourself), use
+ * the conversion rate involved.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
+				     unsigned int scale_factor)
+{
+  cairo_font_face_set_user_data (font_face,
+				 &hb_cairo_scale_factor_user_data_key,
+				 (void *) (uintptr_t) scale_factor,
+				 nullptr);
+}
+
+/**
+ * hb_cairo_font_face_get_scale_factor:
+ * @font_face: a #cairo_font_face_t
+ *
+ * Gets the scale factor set on the @font_face. Defaults to zero.
+ * See hb_cairo_font_face_set_scale_factor() for details.
+ *
+ * Returns: the scale factor of @font_face
+ *
+ * Since: 7.0.0
+ */
+unsigned int
+hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face)
+{
+  return (unsigned int) (uintptr_t)
+	 cairo_font_face_get_user_data (font_face,
+					&hb_cairo_scale_factor_user_data_key);
+}
+
+
+/**
+ * hb_cairo_glyphs_from_buffer:
+ * @buffer: a #hb_buffer_t containing glyphs
+ * @utf8_clusters: `true` if @buffer clusters are in bytes, instead of characters
+ * @x_scale_factor: scale factor to divide #hb_position_t Y values by
+ * @y_scale_factor: scale factor to divide #hb_position_t X values by
+ * @x: X position to place first glyph
+ * @y: Y position to place first glyph
+ * @utf8: (nullable): the text that was shaped in @buffer
+ * @utf8_len: the length of @utf8 in bytes
+ * @glyphs: (out): return location for an array of #cairo_glyph_t
+ * @num_glyphs: (inout): return location for the length of @glyphs
+ * @clusters: (out) (nullable): return location for an array of cluster positions
+ * @num_clusters: (inout) (nullable): return location for the length of @clusters
+ * @cluster_flags: (out) (nullable): return location for cluster flags
+ *
+ * Extracts information from @buffer in a form that can be
+ * passed to cairo_show_text_glyphs() or cairo_show_glyphs().
+ * This API is modeled after cairo_scaled_font_text_to_glyphs() and
+ * cairo_user_scaled_font_text_to_glyphs_func_t.
+ *
+ * The @num_glyphs argument should be preset to the number of glyph entries available
+ * in the @glyphs buffer. If the @glyphs buffer is `NULL`, the value of
+ * @num_glyphs must be zero.  If the provided glyph array is too short for
+ * the conversion (or for convenience), a new glyph array may be allocated
+ * using cairo_glyph_allocate() and placed in @glyphs.  Upon return,
+ * @num_glyphs should contain the number of generated glyphs.  If the value
+ * @glyphs points at has changed after the call, the caller will free the
+ * allocated glyph array using cairo_glyph_free().  The caller will also free
+ * the original value of @glyphs, so this function shouldn't do so.
+ *
+ * If @clusters is not `NULL`, then @num_clusters and @cluster_flags
+ * should not be either, and @utf8 must be provided, and cluster
+ * mapping will be computed. The semantics of how
+ * cluster array allocation works is similar to the glyph array.  That is,
+ * if @clusters initially points to a non-`NULL` value, that array may be used
+ * as a cluster buffer, and @num_clusters points to the number of cluster
+ * entries available there.  If the provided cluster array is too short for
+ * the conversion (or for convenience), a new cluster array may be allocated
+ * using cairo_text_cluster_allocate() and placed in @clusters.  In this case,
+ * the original value of @clusters will still be freed by the caller.  Upon
+ * return, @num_clusters will contain the number of generated clusters.
+ * If the value @clusters points at has changed after the call, the caller
+ * will free the allocated cluster array using cairo_text_cluster_free().
+ *
+ * See hb_cairo_font_face_set_scale_factor() for the details of
+ * the @scale_factor argument.
+ *
+ * The returned @glyphs vector actually has `@num_glyphs + 1` entries in
+ * it and the x,y values of the extra entry at the end add up the advance
+ * x,y of all the glyphs in the @buffer.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
+			     hb_bool_t utf8_clusters,
+			     double x_scale_factor,
+			     double y_scale_factor,
+			     double x,
+			     double y,
+			     const char *utf8,
+			     int utf8_len,
+			     cairo_glyph_t **glyphs,
+			     unsigned int *num_glyphs,
+			     cairo_text_cluster_t **clusters,
+			     unsigned int *num_clusters,
+			     cairo_text_cluster_flags_t *cluster_flags)
+{
+  if (utf8 && utf8_len < 0)
+    utf8_len = strlen (utf8);
+
+  unsigned orig_num_glyphs = *num_glyphs;
+  *num_glyphs = hb_buffer_get_length (buffer);
+  hb_glyph_info_t *hb_glyph = hb_buffer_get_glyph_infos (buffer, nullptr);
+  hb_glyph_position_t *hb_position = hb_buffer_get_glyph_positions (buffer, nullptr);
+  if (orig_num_glyphs < *num_glyphs + 1)
+    *glyphs = cairo_glyph_allocate (*num_glyphs + 1);
+
+  if (clusters && utf8)
+  {
+    unsigned orig_num_clusters = *num_clusters;
+    *num_clusters = *num_glyphs ? 1 : 0;
+    for (unsigned int i = 1; i < *num_glyphs; i++)
+      if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
+	(*num_clusters)++;
+    if (orig_num_clusters < *num_clusters)
+      *clusters = cairo_text_cluster_allocate (*num_clusters);
+  }
+
+  double x_scale = x_scale_factor ? 1. / x_scale_factor : 0.;
+  double y_scale = y_scale_factor ? 1. / y_scale_factor : 0.;
+  hb_position_t hx = 0, hy = 0;
+  int i;
+  for (i = 0; i < (int) *num_glyphs; i++)
+  {
+    (*glyphs)[i].index = hb_glyph[i].codepoint;
+    (*glyphs)[i].x = x + (+hb_position->x_offset + hx) * x_scale;
+    (*glyphs)[i].y = y + (-hb_position->y_offset + hy) * y_scale;
+    hx +=  hb_position->x_advance;
+    hy += -hb_position->y_advance;
+
+    hb_position++;
+  }
+  (*glyphs)[i].index = -1;
+  (*glyphs)[i].x = round (hx * x_scale);
+  (*glyphs)[i].y = round (hy * y_scale);
+
+  if (clusters && *num_clusters && utf8)
+  {
+    memset ((void *) *clusters, 0, *num_clusters * sizeof ((*clusters)[0]));
+    hb_bool_t backward = HB_DIRECTION_IS_BACKWARD (hb_buffer_get_direction (buffer));
+    *cluster_flags = backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : (cairo_text_cluster_flags_t) 0;
+    unsigned int cluster = 0;
+    const char *start = utf8, *end;
+    (*clusters)[cluster].num_glyphs++;
+    if (backward)
+    {
+      for (i = *num_glyphs - 2; i >= 0; i--)
+      {
+	if (hb_glyph[i].cluster != hb_glyph[i+1].cluster)
+	{
+	  assert (hb_glyph[i].cluster > hb_glyph[i+1].cluster);
+	  if (utf8_clusters)
+	    end = start + hb_glyph[i].cluster - hb_glyph[i+1].cluster;
+	  else
+	    end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
+								      (signed) (hb_glyph[i].cluster - hb_glyph[i+1].cluster));
+	  (*clusters)[cluster].num_bytes = end - start;
+	  start = end;
+	  cluster++;
+	}
+	(*clusters)[cluster].num_glyphs++;
+      }
+      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
+    }
+    else
+    {
+      for (i = 1; i < (int) *num_glyphs; i++)
+      {
+	if (hb_glyph[i].cluster != hb_glyph[i-1].cluster)
+	{
+	  assert (hb_glyph[i].cluster > hb_glyph[i-1].cluster);
+	  if (utf8_clusters)
+	    end = start + hb_glyph[i].cluster - hb_glyph[i-1].cluster;
+	  else
+	    end = (const char *) hb_utf_offset_to_pointer<hb_utf8_t> ((const uint8_t *) start,
+								      (signed) (hb_glyph[i].cluster - hb_glyph[i-1].cluster));
+	  (*clusters)[cluster].num_bytes = end - start;
+	  start = end;
+	  cluster++;
+	}
+	(*clusters)[cluster].num_glyphs++;
+      }
+      (*clusters)[cluster].num_bytes = utf8 + utf8_len - start;
+    }
+  }
+  else if (num_clusters)
+    *num_clusters = 0;
+}
+
+#endif

+ 99 - 0
thirdparty/harfbuzz/src/hb-cairo.h

@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2022 Red Hat, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Matthias Clasen
+ */
+
+#ifndef HB_CAIRO_H
+#define HB_CAIRO_H
+
+#include "hb.h"
+
+#include <cairo.h>
+
+HB_BEGIN_DECLS
+
+HB_EXTERN cairo_font_face_t *
+hb_cairo_font_face_create_for_font (hb_font_t *font);
+
+HB_EXTERN hb_font_t *
+hb_cairo_font_face_get_font (cairo_font_face_t *font_face);
+
+HB_EXTERN cairo_font_face_t *
+hb_cairo_font_face_create_for_face (hb_face_t *face);
+
+HB_EXTERN hb_face_t *
+hb_cairo_font_face_get_face (cairo_font_face_t *font_face);
+
+/**
+ * hb_cairo_font_init_func_t:
+ * @font: The #hb_font_t being created
+ * @scaled_font: The respective #cairo_scaled_font_t
+ * @user_data: User data accompanying this method
+ *
+ * The type of a virtual method to be called when a cairo
+ * face created using hb_cairo_font_face_create_for_face()
+ * creates an #hb_font_t for a #cairo_scaled_font_t.
+ *
+ * Return value: the #hb_font_t value to use; in most cases same as @font
+ *
+ * Since: 7.0.0
+ */
+typedef hb_font_t * (*hb_cairo_font_init_func_t) (hb_font_t *font,
+						  cairo_scaled_font_t *scaled_font,
+						  void *user_data);
+
+HB_EXTERN void
+hb_cairo_font_face_set_font_init_func (cairo_font_face_t *font_face,
+				       hb_cairo_font_init_func_t func,
+				       void *user_data,
+				       hb_destroy_func_t destroy);
+
+HB_EXTERN hb_font_t *
+hb_cairo_scaled_font_get_font (cairo_scaled_font_t *scaled_font);
+
+HB_EXTERN void
+hb_cairo_font_face_set_scale_factor (cairo_font_face_t *font_face,
+				     unsigned int scale_factor);
+
+HB_EXTERN unsigned int
+hb_cairo_font_face_get_scale_factor (cairo_font_face_t *font_face);
+
+HB_EXTERN void
+hb_cairo_glyphs_from_buffer (hb_buffer_t *buffer,
+			     hb_bool_t utf8_clusters,
+			     double x_scale_factor,
+			     double y_scale_factor,
+			     double x,
+			     double y,
+			     const char *utf8,
+			     int utf8_len,
+			     cairo_glyph_t **glyphs,
+			     unsigned int *num_glyphs,
+			     cairo_text_cluster_t **clusters,
+			     unsigned int *num_clusters,
+			     cairo_text_cluster_flags_t *cluster_flags);
+
+HB_END_DECLS
+
+#endif /* HB_CAIRO_H */

+ 3 - 13
thirdparty/harfbuzz/src/hb-cff-interp-common.hh

@@ -488,7 +488,7 @@ struct op_str_t
 
 
   const unsigned char *ptr = nullptr;
   const unsigned char *ptr = nullptr;
 
 
-  op_code_t  op;
+  op_code_t  op = OpCode_Invalid;
 
 
   uint8_t length = 0;
   uint8_t length = 0;
 };
 };
@@ -522,20 +522,10 @@ struct parsed_values_t
 
 
   void alloc (unsigned n)
   void alloc (unsigned n)
   {
   {
-    values.alloc (n);
+    values.alloc (n, true);
   }
   }
 
 
-  void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t ())
-  {
-    VAL *val = values.push ();
-    val->op = op;
-    auto arr = str_ref.sub_array (opStart, str_ref.get_offset () - opStart);
-    val->ptr = arr.arrayZ;
-    val->length = arr.length;
-    opStart = str_ref.get_offset ();
-  }
-
-  void add_op (op_code_t op, const byte_str_ref_t& str_ref, const VAL &v)
+  void add_op (op_code_t op, const byte_str_ref_t& str_ref = byte_str_ref_t (), const VAL &v = VAL ())
   {
   {
     VAL *val = values.push (v);
     VAL *val = values.push (v);
     val->op = op;
     val->op = op;

+ 1 - 2
thirdparty/harfbuzz/src/hb-cff-interp-cs-common.hh

@@ -57,7 +57,6 @@ struct call_context_t
 
 
 /* call stack */
 /* call stack */
 const unsigned int kMaxCallLimit = 10;
 const unsigned int kMaxCallLimit = 10;
-const unsigned int kMaxOps = 10000;
 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 struct call_stack_t : cff_stack_t<call_context_t, kMaxCallLimit> {};
 
 
 template <typename SUBRS>
 template <typename SUBRS>
@@ -882,7 +881,7 @@ struct cs_interpreter_t : interpreter_t<ENV>
   {
   {
     SUPER::env.set_endchar (false);
     SUPER::env.set_endchar (false);
 
 
-    unsigned max_ops = kMaxOps;
+    unsigned max_ops = HB_CFF_MAX_OPS;
     for (;;) {
     for (;;) {
       if (unlikely (!--max_ops))
       if (unlikely (!--max_ops))
       {
       {

+ 1 - 3
thirdparty/harfbuzz/src/hb-cff-interp-dict-common.hh

@@ -35,10 +35,8 @@ using namespace OT;
 /* an opstr and the parsed out dict value(s) */
 /* an opstr and the parsed out dict value(s) */
 struct dict_val_t : op_str_t
 struct dict_val_t : op_str_t
 {
 {
-  void init () { single_val.set_int (0); }
+  void init () {}
   void fini () {}
   void fini () {}
-
-  number_t	      single_val;
 };
 };
 
 
 typedef dict_val_t num_dict_val_t;
 typedef dict_val_t num_dict_val_t;

+ 2 - 1
thirdparty/harfbuzz/src/hb-cff1-interp-cs.hh

@@ -38,7 +38,8 @@ typedef biased_subrs_t<CFF1Subrs>   cff1_biased_subrs_t;
 struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
 struct cff1_cs_interp_env_t : cs_interp_env_t<number_t, CFF1Subrs>
 {
 {
   template <typename ACC>
   template <typename ACC>
-  cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd)
+  cff1_cs_interp_env_t (const hb_ubytes_t &str, ACC &acc, unsigned int fd,
+			const int *coords_=nullptr, unsigned int num_coords_=0)
     : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
     : SUPER (str, acc.globalSubrs, acc.privateDicts[fd].localSubrs)
   {
   {
     processed_width = false;
     processed_width = false;

+ 9 - 4
thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh

@@ -45,7 +45,7 @@ struct blend_arg_t : number_t
     numValues = numValues_;
     numValues = numValues_;
     valueIndex = valueIndex_;
     valueIndex = valueIndex_;
     unsigned numBlends = blends_.length;
     unsigned numBlends = blends_.length;
-    if (unlikely (!deltas.resize (numBlends)))
+    if (unlikely (!deltas.resize_exact (numBlends)))
       return;
       return;
     for (unsigned int i = 0; i < numBlends; i++)
     for (unsigned int i = 0; i < numBlends; i++)
       deltas.arrayZ[i] = blends_.arrayZ[i];
       deltas.arrayZ[i] = blends_.arrayZ[i];
@@ -55,7 +55,7 @@ struct blend_arg_t : number_t
   void reset_blends ()
   void reset_blends ()
   {
   {
     numValues = valueIndex = 0;
     numValues = valueIndex = 0;
-    deltas.resize (0);
+    deltas.shrink (0);
   }
   }
 
 
   unsigned int numValues;
   unsigned int numValues;
@@ -118,7 +118,7 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
       region_count = varStore->varStore.get_region_index_count (get_ivs ());
       region_count = varStore->varStore.get_region_index_count (get_ivs ());
       if (do_blend)
       if (do_blend)
       {
       {
-	if (unlikely (!scalars.resize (region_count)))
+	if (unlikely (!scalars.resize_exact (region_count)))
 	  SUPER::set_error ();
 	  SUPER::set_error ();
 	else
 	else
 	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
 	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
@@ -163,6 +163,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<ELEM, CFF2Subrs>
     return v;
     return v;
   }
   }
 
 
+  bool have_coords () const { return num_coords; }
+
   protected:
   protected:
   const int     *coords;
   const int     *coords;
   unsigned int  num_coords;
   unsigned int  num_coords;
@@ -222,7 +224,10 @@ struct cff2_cs_opset_t : cs_opset_t<ELEM, OPSET, cff2_cs_interp_env_t<ELEM>, PAR
 				 const hb_array_t<const ELEM> blends,
 				 const hb_array_t<const ELEM> blends,
 				 unsigned n, unsigned i)
 				 unsigned n, unsigned i)
   {
   {
-    arg.set_blends (n, i, blends);
+    if (env.have_coords ())
+      arg.set_int (round (arg.to_real () + env.blend_deltas (blends)));
+    else
+      arg.set_blends (n, i, blends);
   }
   }
   template <typename T = ELEM,
   template <typename T = ELEM,
 	    hb_enable_if (!hb_is_same (T, blend_arg_t))>
 	    hb_enable_if (!hb_is_same (T, blend_arg_t))>

+ 0 - 26
thirdparty/harfbuzz/src/hb-common.cc

@@ -29,32 +29,6 @@
 #include "hb.hh"
 #include "hb.hh"
 #include "hb-machinery.hh"
 #include "hb-machinery.hh"
 
 
-#if !defined(HB_NO_SETLOCALE) && (!defined(HAVE_NEWLOCALE) || !defined(HAVE_USELOCALE))
-#define HB_NO_SETLOCALE 1
-#endif
-
-#ifndef HB_NO_SETLOCALE
-
-#include <locale.h>
-#ifdef HAVE_XLOCALE_H
-#include <xlocale.h> // Needed on BSD/OS X for uselocale
-#endif
-
-#ifdef WIN32
-#define hb_locale_t _locale_t
-#else
-#define hb_locale_t locale_t
-#endif
-#define hb_setlocale setlocale
-#define hb_uselocale uselocale
-
-#else
-
-#define hb_locale_t void *
-#define hb_setlocale(Category, Locale) "C"
-#define hb_uselocale(Locale) ((hb_locale_t) 0)
-
-#endif
 
 
 /**
 /**
  * SECTION:hb-common
  * SECTION:hb-common

+ 26 - 0
thirdparty/harfbuzz/src/hb-common.h

@@ -897,6 +897,32 @@ HB_EXTERN uint8_t
 hb_color_get_blue (hb_color_t color);
 hb_color_get_blue (hb_color_t color);
 #define hb_color_get_blue(color)	(((color) >> 24) & 0xFF)
 #define hb_color_get_blue(color)	(((color) >> 24) & 0xFF)
 
 
+/**
+ * hb_glyph_extents_t:
+ * @x_bearing: Distance from the x-origin to the left extremum of the glyph.
+ * @y_bearing: Distance from the top extremum of the glyph to the y-origin.
+ * @width: Distance from the left extremum of the glyph to the right extremum.
+ * @height: Distance from the top extremum of the glyph to the bottom extremum.
+ *
+ * Glyph extent values, measured in font units.
+ *
+ * Note that @height is negative, in coordinate systems that grow up.
+ **/
+typedef struct hb_glyph_extents_t {
+  hb_position_t x_bearing;
+  hb_position_t y_bearing;
+  hb_position_t width;
+  hb_position_t height;
+} hb_glyph_extents_t;
+
+/**
+ * hb_font_t:
+ *
+ * Data type for holding fonts.
+ *
+ */
+typedef struct hb_font_t hb_font_t;
+
 HB_END_DECLS
 HB_END_DECLS
 
 
 #endif /* HB_COMMON_H */
 #endif /* HB_COMMON_H */

+ 7 - 1
thirdparty/harfbuzz/src/hb-config.hh

@@ -37,6 +37,7 @@
 
 
 #ifndef HB_EXPERIMENTAL_API
 #ifndef HB_EXPERIMENTAL_API
 #define HB_NO_BEYOND_64K
 #define HB_NO_BEYOND_64K
+#define HB_NO_CUBIC_GLYF
 #define HB_NO_VAR_COMPOSITES
 #define HB_NO_VAR_COMPOSITES
 #endif
 #endif
 
 
@@ -80,9 +81,10 @@
 #define HB_NO_MMAP
 #define HB_NO_MMAP
 #define HB_NO_NAME
 #define HB_NO_NAME
 #define HB_NO_OPEN
 #define HB_NO_OPEN
-#define HB_NO_SETLOCALE
 #define HB_NO_OT_FONT_GLYPH_NAMES
 #define HB_NO_OT_FONT_GLYPH_NAMES
 #define HB_NO_OT_SHAPE_FRACTIONS
 #define HB_NO_OT_SHAPE_FRACTIONS
+#define HB_NO_PAINT
+#define HB_NO_SETLOCALE
 #define HB_NO_STYLE
 #define HB_NO_STYLE
 #define HB_NO_SUBSET_LAYOUT
 #define HB_NO_SUBSET_LAYOUT
 #define HB_NO_VERTICAL
 #define HB_NO_VERTICAL
@@ -134,6 +136,10 @@
 #define HB_NO_SUBSET_CFF
 #define HB_NO_SUBSET_CFF
 #endif
 #endif
 
 
+#ifdef HB_NO_DRAW
+#define HB_NO_OUTLINE
+#endif
+
 #ifdef HB_NO_GETENV
 #ifdef HB_NO_GETENV
 #define HB_NO_UNISCRIBE_BUG_COMPATIBLE
 #define HB_NO_UNISCRIBE_BUG_COMPATIBLE
 #endif
 #endif

+ 0 - 1
thirdparty/harfbuzz/src/hb-coretext.cc

@@ -511,7 +511,6 @@ _hb_coretext_shape (hb_shape_plan_t    *shape_plan,
 	buffer->merge_clusters (i - 1, i + 1);
 	buffer->merge_clusters (i - 1, i + 1);
   }
   }
 
 
-  hb_vector_t<feature_record_t> feature_records;
   hb_vector_t<range_record_t> range_records;
   hb_vector_t<range_record_t> range_records;
 
 
   /*
   /*

+ 2 - 0
thirdparty/harfbuzz/src/hb-cplusplus.hh

@@ -160,6 +160,8 @@ HB_DEFINE_VTABLE (map);
 HB_DEFINE_VTABLE (set);
 HB_DEFINE_VTABLE (set);
 HB_DEFINE_VTABLE (shape_plan);
 HB_DEFINE_VTABLE (shape_plan);
 HB_DEFINE_VTABLE (unicode_funcs);
 HB_DEFINE_VTABLE (unicode_funcs);
+HB_DEFINE_VTABLE (draw_funcs);
+HB_DEFINE_VTABLE (paint_funcs);
 
 
 #undef HB_DEFINE_VTABLE
 #undef HB_DEFINE_VTABLE
 
 

+ 10 - 6
thirdparty/harfbuzz/src/hb-debug.hh

@@ -113,7 +113,7 @@ _hb_print_func (const char *func)
     const char *paren = strchr (func, '(');
     const char *paren = strchr (func, '(');
     if (paren)
     if (paren)
       func_len = paren - func;
       func_len = paren - func;
-    fprintf (stderr, "%.*s", func_len, func);
+    fprintf (stderr, "%.*s", (int) func_len, func);
   }
   }
 }
 }
 
 
@@ -142,9 +142,9 @@ _hb_debug_msg_va (const char *what,
   fprintf (stderr, "%-10s", what ? what : "");
   fprintf (stderr, "%-10s", what ? what : "");
 
 
   if (obj)
   if (obj)
-    fprintf (stderr, "(%*p) ", (unsigned int) (2 * sizeof (void *)), obj);
+    fprintf (stderr, "(%*p) ", (int) (2 * sizeof (void *)), obj);
   else
   else
-    fprintf (stderr, " %*s  ", (unsigned int) (2 * sizeof (void *)), "");
+    fprintf (stderr, " %*s  ", (int) (2 * sizeof (void *)), "");
 
 
   if (indented) {
   if (indented) {
 #define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
 #define VBAR	"\342\224\202"	/* U+2502 BOX DRAWINGS LIGHT VERTICAL */
@@ -306,7 +306,7 @@ struct hb_auto_trace_t
     }
     }
 
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
-			      "return %s (line %d)",
+			      "return %s (line %u)",
 			      hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
 			      hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
     if (plevel) --*plevel;
     if (plevel) --*plevel;
     plevel = nullptr;
     plevel = nullptr;
@@ -373,6 +373,10 @@ struct hb_no_trace_t {
 #define HB_DEBUG_FT (HB_DEBUG+0)
 #define HB_DEBUG_FT (HB_DEBUG+0)
 #endif
 #endif
 
 
+#ifndef HB_DEBUG_JUSTIFY
+#define HB_DEBUG_JUSTIFY (HB_DEBUG+0)
+#endif
+
 #ifndef HB_DEBUG_OBJECT
 #ifndef HB_DEBUG_OBJECT
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #define HB_DEBUG_OBJECT (HB_DEBUG+0)
 #endif
 #endif
@@ -396,7 +400,7 @@ struct hb_no_trace_t {
 #define TRACE_APPLY(this) \
 #define TRACE_APPLY(this) \
 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
 	hb_auto_trace_t<HB_DEBUG_APPLY, bool> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "idx %d gid %u lookup %d", \
+	 "idx %u gid %u lookup %d", \
 	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
 	 c->buffer->idx, c->buffer->cur().codepoint, (int) c->lookup_index)
 #else
 #else
 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
 #define TRACE_APPLY(this) hb_no_trace_t<bool> trace
@@ -454,7 +458,7 @@ struct hb_no_trace_t {
 #define TRACE_DISPATCH(this, format) \
 #define TRACE_DISPATCH(this, format) \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	hb_auto_trace_t<context_t::max_debug_depth, typename context_t::return_t> trace \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
 	(&c->debug_depth, c->get_name (), this, HB_FUNC, \
-	 "format %d", (int) format)
+	 "format %u", (unsigned) format)
 #else
 #else
 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 #define TRACE_DISPATCH(this, format) hb_no_trace_t<typename context_t::return_t> trace
 #endif
 #endif

+ 2 - 1
thirdparty/harfbuzz/src/hb-deprecated.h

@@ -102,7 +102,8 @@ typedef hb_bool_t (*hb_font_get_glyph_func_t) (hb_font_t *font, void *font_data,
 					       hb_codepoint_t *glyph,
 					       hb_codepoint_t *glyph,
 					       void *user_data);
 					       void *user_data);
 
 
-HB_EXTERN HB_DEPRECATED_FOR(hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func) void
+HB_DEPRECATED_FOR (hb_font_funcs_set_nominal_glyph_func and hb_font_funcs_set_variation_glyph_func)
+HB_EXTERN void
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t func,
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 			      void *user_data, hb_destroy_func_t destroy);

+ 4 - 8
thirdparty/harfbuzz/src/hb-directwrite.cc

@@ -251,16 +251,12 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
       data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
       data->dwriteFactory->UnregisterFontFileLoader (data->fontFileLoader);
     data->dwriteFactory->Release ();
     data->dwriteFactory->Release ();
   }
   }
-  if (data->fontFileLoader)
-    delete data->fontFileLoader;
-  if (data->fontFileStream)
-    delete data->fontFileStream;
-  if (data->faceBlob)
-    hb_blob_destroy (data->faceBlob);
+  delete data->fontFileLoader;
+  delete data->fontFileStream;
+  hb_blob_destroy (data->faceBlob);
   if (data->dwrite_dll)
   if (data->dwrite_dll)
     FreeLibrary (data->dwrite_dll);
     FreeLibrary (data->dwrite_dll);
-  if (data)
-    delete data;
+  delete data;
 }
 }
 
 
 
 

+ 63 - 2
thirdparty/harfbuzz/src/hb-draw.cc

@@ -35,6 +35,8 @@
  * @include: hb.h
  * @include: hb.h
  *
  *
  * Functions for drawing (extracting) glyph shapes.
  * Functions for drawing (extracting) glyph shapes.
+ *
+ * The #hb_draw_funcs_t struct can be used with hb_font_draw_glyph().
  **/
  **/
 
 
 static void
 static void
@@ -198,13 +200,29 @@ DEFINE_NULL_INSTANCE (hb_draw_funcs_t) =
   }
   }
 };
 };
 
 
+/**
+ * hb_draw_funcs_get_empty:
+ *
+ * Fetches the singleton empty draw-functions structure.
+ *
+ * Return value: (transfer full): The empty draw-functions structure
+ *
+ * Since: 7.0.0
+ **/
+hb_draw_funcs_t *
+hb_draw_funcs_get_empty ()
+{
+  return const_cast<hb_draw_funcs_t *> (&Null (hb_draw_funcs_t));
+}
 
 
 /**
 /**
  * hb_draw_funcs_reference: (skip)
  * hb_draw_funcs_reference: (skip)
  * @dfuncs: draw functions
  * @dfuncs: draw functions
  *
  *
- * Increases the reference count on @dfuncs by one. This prevents @buffer from
- * being destroyed until a matching call to hb_draw_funcs_destroy() is made.
+ * Increases the reference count on @dfuncs by one.
+ *
+ * This prevents @dfuncs from being destroyed until a matching
+ * call to hb_draw_funcs_destroy() is made.
  *
  *
  * Return value: (transfer full):
  * Return value: (transfer full):
  * The referenced #hb_draw_funcs_t.
  * The referenced #hb_draw_funcs_t.
@@ -246,6 +264,49 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs)
   hb_free (dfuncs);
   hb_free (dfuncs);
 }
 }
 
 
+/**
+ * hb_draw_funcs_set_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key
+ * @data: A pointer to the user data
+ * @destroy: (nullable): A callback to call when @data is not needed anymore
+ * @replace: Whether to replace an existing data with the same key
+ *
+ * Attaches a user-data key/data pair to the specified draw-functions structure. 
+ *
+ * Return value: `true` if success, `false` otherwise
+ *
+ * Since: 7.0.0
+ **/
+hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+			     hb_user_data_key_t *key,
+			     void *              data,
+			     hb_destroy_func_t   destroy,
+			     hb_bool_t           replace)
+{
+  return hb_object_set_user_data (dfuncs, key, data, destroy, replace);
+}
+
+/**
+ * hb_draw_funcs_get_user_data: (skip)
+ * @dfuncs: The draw-functions structure
+ * @key: The user-data key to query
+ *
+ * Fetches the user-data associated with the specified key,
+ * attached to the specified draw-functions structure.
+ *
+ * Return value: (transfer none): A pointer to the user data
+ *
+ * Since: 7.0.0
+ **/
+void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+			     hb_user_data_key_t       *key)
+{
+  return hb_object_get_user_data (dfuncs, key);
+}
+
 /**
 /**
  * hb_draw_funcs_make_immutable:
  * hb_draw_funcs_make_immutable:
  * @dfuncs: draw functions
  * @dfuncs: draw functions

+ 25 - 10
thirdparty/harfbuzz/src/hb-draw.h

@@ -92,11 +92,11 @@ typedef struct hb_draw_funcs_t hb_draw_funcs_t;
 /**
 /**
  * hb_draw_move_to_func_t:
  * hb_draw_move_to_func_t:
  * @dfuncs: draw functions object
  * @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
  * @st: current draw state
  * @st: current draw state
  * @to_x: X component of target point
  * @to_x: X component of target point
  * @to_y: Y component of target point
  * @to_y: Y component of target point
- * @user_data: User data pointer passed by the caller
+ * @user_data: User data pointer passed to hb_draw_funcs_set_move_to_func()
  *
  *
  * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
  * A virtual method for the #hb_draw_funcs_t to perform a "move-to" draw
  * operation.
  * operation.
@@ -112,11 +112,11 @@ typedef void (*hb_draw_move_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
 /**
 /**
  * hb_draw_line_to_func_t:
  * hb_draw_line_to_func_t:
  * @dfuncs: draw functions object
  * @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
  * @st: current draw state
  * @st: current draw state
  * @to_x: X component of target point
  * @to_x: X component of target point
  * @to_y: Y component of target point
  * @to_y: Y component of target point
- * @user_data: User data pointer passed by the caller
+ * @user_data: User data pointer passed to hb_draw_funcs_set_line_to_func()
  *
  *
  * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
  * A virtual method for the #hb_draw_funcs_t to perform a "line-to" draw
  * operation.
  * operation.
@@ -132,13 +132,13 @@ typedef void (*hb_draw_line_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_data
 /**
 /**
  * hb_draw_quadratic_to_func_t:
  * hb_draw_quadratic_to_func_t:
  * @dfuncs: draw functions object
  * @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
  * @st: current draw state
  * @st: current draw state
  * @control_x: X component of control point
  * @control_x: X component of control point
  * @control_y: Y component of control point
  * @control_y: Y component of control point
  * @to_x: X component of target point
  * @to_x: X component of target point
  * @to_y: Y component of target point
  * @to_y: Y component of target point
- * @user_data: User data pointer passed by the caller
+ * @user_data: User data pointer passed to hb_draw_funcs_set_quadratic_to_func()
  *
  *
  * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
  * A virtual method for the #hb_draw_funcs_t to perform a "quadratic-to" draw
  * operation.
  * operation.
@@ -155,7 +155,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw
 /**
 /**
  * hb_draw_cubic_to_func_t:
  * hb_draw_cubic_to_func_t:
  * @dfuncs: draw functions object
  * @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
  * @st: current draw state
  * @st: current draw state
  * @control1_x: X component of first control point
  * @control1_x: X component of first control point
  * @control1_y: Y component of first control point
  * @control1_y: Y component of first control point
@@ -163,7 +163,7 @@ typedef void (*hb_draw_quadratic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw
  * @control2_y: Y component of second control point
  * @control2_y: Y component of second control point
  * @to_x: X component of target point
  * @to_x: X component of target point
  * @to_y: Y component of target point
  * @to_y: Y component of target point
- * @user_data: User data pointer passed by the caller
+ * @user_data: User data pointer passed to hb_draw_funcs_set_cubic_to_func()
  *
  *
  * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
  * A virtual method for the #hb_draw_funcs_t to perform a "cubic-to" draw
  * operation.
  * operation.
@@ -181,9 +181,9 @@ typedef void (*hb_draw_cubic_to_func_t) (hb_draw_funcs_t *dfuncs, void *draw_dat
 /**
 /**
  * hb_draw_close_path_func_t:
  * hb_draw_close_path_func_t:
  * @dfuncs: draw functions object
  * @dfuncs: draw functions object
- * @draw_data: The data accompanying the draw functions
+ * @draw_data: The data accompanying the draw functions in hb_font_draw_glyph()
  * @st: current draw state
  * @st: current draw state
- * @user_data: User data pointer passed by the caller
+ * @user_data: User data pointer passed to hb_draw_funcs_set_close_path_func()
  *
  *
  * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
  * A virtual method for the #hb_draw_funcs_t to perform a "close-path" draw
  * operation.
  * operation.
@@ -279,12 +279,27 @@ hb_draw_funcs_set_close_path_func (hb_draw_funcs_t           *dfuncs,
 HB_EXTERN hb_draw_funcs_t *
 HB_EXTERN hb_draw_funcs_t *
 hb_draw_funcs_create (void);
 hb_draw_funcs_create (void);
 
 
+HB_EXTERN hb_draw_funcs_t *
+hb_draw_funcs_get_empty (void);
+
 HB_EXTERN hb_draw_funcs_t *
 HB_EXTERN hb_draw_funcs_t *
 hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
 hb_draw_funcs_reference (hb_draw_funcs_t *dfuncs);
 
 
 HB_EXTERN void
 HB_EXTERN void
 hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
 hb_draw_funcs_destroy (hb_draw_funcs_t *dfuncs);
 
 
+HB_EXTERN hb_bool_t
+hb_draw_funcs_set_user_data (hb_draw_funcs_t *dfuncs,
+			     hb_user_data_key_t *key,
+			     void *              data,
+			     hb_destroy_func_t   destroy,
+			     hb_bool_t           replace);
+
+
+HB_EXTERN void *
+hb_draw_funcs_get_user_data (const hb_draw_funcs_t *dfuncs,
+			     hb_user_data_key_t       *key);
+
 HB_EXTERN void
 HB_EXTERN void
 hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
 hb_draw_funcs_make_immutable (hb_draw_funcs_t *dfuncs);
 
 

+ 246 - 0
thirdparty/harfbuzz/src/hb-face-builder.cc

@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2009  Red Hat, Inc.
+ * Copyright © 2012  Google, Inc.
+ *
+ *  This is part of HarfBuzz, a text shaping library.
+ *
+ * Permission is hereby granted, without written agreement and without
+ * license or royalty fees, to use, copy, modify, and distribute this
+ * software and its documentation for any purpose, provided that the
+ * above copyright notice and the following two paragraphs appear in
+ * all copies of this software.
+ *
+ * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
+ * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
+ * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
+ * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
+ * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
+ * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
+ *
+ * Red Hat Author(s): Behdad Esfahbod
+ * Google Author(s): Behdad Esfahbod
+ */
+
+#include "hb.hh"
+
+#include "hb-face.hh"
+
+#include "hb-map.hh"
+#include "hb-open-file.hh"
+#include "hb-serialize.hh"
+
+
+/*
+ * face-builder: A face that has add_table().
+ */
+
+struct face_table_info_t
+{
+  hb_blob_t* data;
+  signed order;
+};
+
+struct hb_face_builder_data_t
+{
+  hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
+};
+
+static int compare_entries (const void* pa, const void* pb)
+{
+  const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
+  const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
+
+  /* Order by blob size first (smallest to largest) and then table tag */
+
+  if (a.second.order != b.second.order)
+    return a.second.order < b.second.order ? -1 : +1;
+
+  if (a.second.data->length != b.second.data->length)
+    return a.second.data->length < b.second.data->length ? -1 : +1;
+
+  return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
+}
+
+static hb_face_builder_data_t *
+_hb_face_builder_data_create ()
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
+  if (unlikely (!data))
+    return nullptr;
+
+  data->tables.init ();
+
+  return data;
+}
+
+static void
+_hb_face_builder_data_destroy (void *user_data)
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
+
+  for (auto info : data->tables.values())
+    hb_blob_destroy (info.data);
+
+  data->tables.fini ();
+
+  hb_free (data);
+}
+
+static hb_blob_t *
+_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
+{
+
+  unsigned int table_count = data->tables.get_population ();
+  unsigned int face_length = table_count * 16 + 12;
+
+  for (auto info : data->tables.values())
+    face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
+
+  char *buf = (char *) hb_malloc (face_length);
+  if (unlikely (!buf))
+    return nullptr;
+
+  hb_serialize_context_t c (buf, face_length);
+  c.propagate_error (data->tables);
+  OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
+
+  bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
+                 || data->tables.has (HB_TAG ('C','F','F','2')));
+  hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
+
+  // Sort the tags so that produced face is deterministic.
+  hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
+  data->tables.iter () | hb_sink (sorted_entries);
+  if (unlikely (sorted_entries.in_error ()))
+  {
+    hb_free (buf);
+    return nullptr;
+  }
+
+  sorted_entries.qsort (compare_entries);
+
+  bool ret = f->serialize_single (&c,
+                                  sfnt_tag,
+                                  + sorted_entries.iter()
+                                  | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
+                                    return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
+                                  }));
+
+  c.end_serialize ();
+
+  if (unlikely (!ret))
+  {
+    hb_free (buf);
+    return nullptr;
+  }
+
+  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
+}
+
+static hb_blob_t *
+_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
+{
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
+
+  if (!tag)
+    return _hb_face_builder_data_reference_blob (data);
+
+  return hb_blob_reference (data->tables[tag].data);
+}
+
+
+/**
+ * hb_face_builder_create:
+ *
+ * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
+ * After tables are added to the face, it can be compiled to a binary
+ * font file by calling hb_face_reference_blob().
+ *
+ * Return value: (transfer full): New face.
+ *
+ * Since: 1.9.0
+ **/
+hb_face_t *
+hb_face_builder_create ()
+{
+  hb_face_builder_data_t *data = _hb_face_builder_data_create ();
+  if (unlikely (!data)) return hb_face_get_empty ();
+
+  return hb_face_create_for_tables (_hb_face_builder_reference_table,
+				    data,
+				    _hb_face_builder_data_destroy);
+}
+
+/**
+ * hb_face_builder_add_table:
+ * @face: A face object created with hb_face_builder_create()
+ * @tag: The #hb_tag_t of the table to add
+ * @blob: The blob containing the table data to add
+ *
+ * Add table for @tag with data provided by @blob to the face.  @face must
+ * be created using hb_face_builder_create().
+ *
+ * Since: 1.9.0
+ **/
+hb_bool_t
+hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
+{
+  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+    return false;
+
+  if (tag == HB_MAP_VALUE_INVALID)
+    return false;
+
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+  hb_blob_t* previous = data->tables.get (tag).data;
+  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
+  {
+    hb_blob_destroy (blob);
+    return false;
+  }
+
+  hb_blob_destroy (previous);
+  return true;
+}
+
+/**
+ * hb_face_builder_sort_tables:
+ * @face: A face object created with hb_face_builder_create()
+ * @tags: (array zero-terminated=1): ordered list of table tags terminated by
+ *   %HB_TAG_NONE
+ *
+ * Set the ordering of tables for serialization. Any tables not
+ * specified in the tags list will be ordered after the tables in
+ * tags, ordered by the default sort ordering.
+ *
+ * Since: 5.3.0
+ **/
+void
+hb_face_builder_sort_tables (hb_face_t *face,
+                             const hb_tag_t  *tags)
+{
+  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
+    return;
+
+  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
+
+  // Sort all unspecified tables after any specified tables.
+  for (auto& info : data->tables.values_ref())
+    info.order = (unsigned) -1;
+
+  signed order = 0;
+  for (const hb_tag_t* tag = tags;
+       *tag;
+       tag++)
+  {
+    face_table_info_t* info;
+    if (!data->tables.has (*tag, &info)) continue;
+    info->order = order++;
+  }
+}

+ 32 - 216
thirdparty/harfbuzz/src/hb-face.cc

@@ -33,7 +33,6 @@
 #include "hb-open-file.hh"
 #include "hb-open-file.hh"
 #include "hb-ot-face.hh"
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
 #include "hb-ot-cmap-table.hh"
-#include "hb-map.hh"
 
 
 
 
 /**
 /**
@@ -472,6 +471,8 @@ hb_face_get_index (const hb_face_t *face)
  *
  *
  * Sets the units-per-em (upem) for a face object to the specified value.
  * Sets the units-per-em (upem) for a face object to the specified value.
  *
  *
+ * This API is used in rare circumstances.
+ *
  * Since: 0.9.2
  * Since: 0.9.2
  **/
  **/
 void
 void
@@ -488,7 +489,10 @@ hb_face_set_upem (hb_face_t    *face,
  * hb_face_get_upem:
  * hb_face_get_upem:
  * @face: A face object
  * @face: A face object
  *
  *
- * Fetches the units-per-em (upem) value of the specified face object.
+ * Fetches the units-per-em (UPEM) value of the specified face object.
+ *
+ * Typical UPEM values for fonts are 1000, or 2048, but any value
+ * in between 16 and 16,384 is allowed for OpenType fonts.
  *
  *
  * Return value: The upem value of @face
  * Return value: The upem value of @face
  *
  *
@@ -507,6 +511,8 @@ hb_face_get_upem (const hb_face_t *face)
  *
  *
  * Sets the glyph count for a face object to the specified value.
  * Sets the glyph count for a face object to the specified value.
  *
  *
+ * This API is used in rare circumstances.
+ *
  * Since: 0.9.7
  * Since: 0.9.7
  **/
  **/
 void
 void
@@ -581,7 +587,7 @@ hb_face_get_table_tags (const hb_face_t *face,
 /**
 /**
  * hb_face_collect_unicodes:
  * hb_face_collect_unicodes:
  * @face: A face object
  * @face: A face object
- * @out: The set to add Unicode characters to
+ * @out: (out): The set to add Unicode characters to
  *
  *
  * Collects all of the Unicode characters covered by @face and adds
  * Collects all of the Unicode characters covered by @face and adds
  * them to the #hb_set_t set @out.
  * them to the #hb_set_t set @out.
@@ -594,10 +600,31 @@ hb_face_collect_unicodes (hb_face_t *face,
 {
 {
   face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
   face->table.cmap->collect_unicodes (out, face->get_num_glyphs ());
 }
 }
+/**
+ * hb_face_collect_nominal_glyph_mapping:
+ * @face: A face object
+ * @mapping: (out): The map to add Unicode-to-glyph mapping to
+ * @unicodes: (nullable) (out): The set to add Unicode characters to, or `NULL`
+ *
+ * Collects the mapping from Unicode characters to nominal glyphs of the @face,
+ * and optionally all of the Unicode characters covered by @face.
+ *
+ * Since: 7.0.0
+ */
+void
+hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
+				       hb_map_t  *mapping,
+				       hb_set_t  *unicodes)
+{
+  hb_set_t stack_unicodes;
+  if (!unicodes)
+    unicodes = &stack_unicodes;
+  face->table.cmap->collect_mapping (unicodes, mapping, face->get_num_glyphs ());
+}
 /**
 /**
  * hb_face_collect_variation_selectors:
  * hb_face_collect_variation_selectors:
  * @face: A face object
  * @face: A face object
- * @out: The set to add Variation Selector characters to
+ * @out: (out): The set to add Variation Selector characters to
  *
  *
  * Collects all Unicode "Variation Selector" characters covered by @face and adds
  * Collects all Unicode "Variation Selector" characters covered by @face and adds
  * them to the #hb_set_t set @out.
  * them to the #hb_set_t set @out.
@@ -614,7 +641,7 @@ hb_face_collect_variation_selectors (hb_face_t *face,
  * hb_face_collect_variation_unicodes:
  * hb_face_collect_variation_unicodes:
  * @face: A face object
  * @face: A face object
  * @variation_selector: The Variation Selector to query
  * @variation_selector: The Variation Selector to query
- * @out: The set to add Unicode characters to
+ * @out: (out): The set to add Unicode characters to
  *
  *
  * Collects all Unicode characters for @variation_selector covered by @face and adds
  * Collects all Unicode characters for @variation_selector covered by @face and adds
  * them to the #hb_set_t set @out.
  * them to the #hb_set_t set @out.
@@ -629,214 +656,3 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
   face->table.cmap->collect_variation_unicodes (variation_selector, out);
   face->table.cmap->collect_variation_unicodes (variation_selector, out);
 }
 }
 #endif
 #endif
-
-
-/*
- * face-builder: A face that has add_table().
- */
-
-struct face_table_info_t
-{
-  hb_blob_t* data;
-  signed order;
-};
-
-struct hb_face_builder_data_t
-{
-  hb_hashmap_t<hb_tag_t, face_table_info_t> tables;
-};
-
-static int compare_entries (const void* pa, const void* pb)
-{
-  const auto& a = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pa;
-  const auto& b = * (const hb_pair_t<hb_tag_t, face_table_info_t> *) pb;
-
-  /* Order by blob size first (smallest to largest) and then table tag */
-
-  if (a.second.order != b.second.order)
-    return a.second.order < b.second.order ? -1 : +1;
-
-  if (a.second.data->length != b.second.data->length)
-    return a.second.data->length < b.second.data->length ? -1 : +1;
-
-  return a.first < b.first ? -1 : a.first == b.first ? 0 : +1;
-}
-
-static hb_face_builder_data_t *
-_hb_face_builder_data_create ()
-{
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) hb_calloc (1, sizeof (hb_face_builder_data_t));
-  if (unlikely (!data))
-    return nullptr;
-
-  data->tables.init ();
-
-  return data;
-}
-
-static void
-_hb_face_builder_data_destroy (void *user_data)
-{
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
-
-  for (auto info : data->tables.values())
-    hb_blob_destroy (info.data);
-
-  data->tables.fini ();
-
-  hb_free (data);
-}
-
-static hb_blob_t *
-_hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
-{
-
-  unsigned int table_count = data->tables.get_population ();
-  unsigned int face_length = table_count * 16 + 12;
-
-  for (auto info : data->tables.values())
-    face_length += hb_ceil_to_4 (hb_blob_get_length (info.data));
-
-  char *buf = (char *) hb_malloc (face_length);
-  if (unlikely (!buf))
-    return nullptr;
-
-  hb_serialize_context_t c (buf, face_length);
-  c.propagate_error (data->tables);
-  OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
-
-  bool is_cff = (data->tables.has (HB_TAG ('C','F','F',' '))
-                 || data->tables.has (HB_TAG ('C','F','F','2')));
-  hb_tag_t sfnt_tag = is_cff ? OT::OpenTypeFontFile::CFFTag : OT::OpenTypeFontFile::TrueTypeTag;
-
-  // Sort the tags so that produced face is deterministic.
-  hb_vector_t<hb_pair_t <hb_tag_t, face_table_info_t>> sorted_entries;
-  data->tables.iter () | hb_sink (sorted_entries);
-  if (unlikely (sorted_entries.in_error ()))
-  {
-    hb_free (buf);
-    return nullptr;
-  }
-
-  sorted_entries.qsort (compare_entries);
-
-  bool ret = f->serialize_single (&c,
-                                  sfnt_tag,
-                                  + sorted_entries.iter()
-                                  | hb_map ([&] (hb_pair_t<hb_tag_t, face_table_info_t> _) {
-                                    return hb_pair_t<hb_tag_t, hb_blob_t*> (_.first, _.second.data);
-                                  }));
-
-  c.end_serialize ();
-
-  if (unlikely (!ret))
-  {
-    hb_free (buf);
-    return nullptr;
-  }
-
-  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
-}
-
-static hb_blob_t *
-_hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data)
-{
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
-
-  if (!tag)
-    return _hb_face_builder_data_reference_blob (data);
-
-  return hb_blob_reference (data->tables[tag].data);
-}
-
-
-/**
- * hb_face_builder_create:
- *
- * Creates a #hb_face_t that can be used with hb_face_builder_add_table().
- * After tables are added to the face, it can be compiled to a binary
- * font file by calling hb_face_reference_blob().
- *
- * Return value: (transfer full): New face.
- *
- * Since: 1.9.0
- **/
-hb_face_t *
-hb_face_builder_create ()
-{
-  hb_face_builder_data_t *data = _hb_face_builder_data_create ();
-  if (unlikely (!data)) return hb_face_get_empty ();
-
-  return hb_face_create_for_tables (_hb_face_builder_reference_table,
-				    data,
-				    _hb_face_builder_data_destroy);
-}
-
-/**
- * hb_face_builder_add_table:
- * @face: A face object created with hb_face_builder_create()
- * @tag: The #hb_tag_t of the table to add
- * @blob: The blob containing the table data to add
- *
- * Add table for @tag with data provided by @blob to the face.  @face must
- * be created using hb_face_builder_create().
- *
- * Since: 1.9.0
- **/
-hb_bool_t
-hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
-{
-  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
-    return false;
-
-  if (tag == HB_MAP_VALUE_INVALID)
-    return false;
-
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
-
-  hb_blob_t* previous = data->tables.get (tag).data;
-  if (!data->tables.set (tag, face_table_info_t {hb_blob_reference (blob), -1}))
-  {
-    hb_blob_destroy (blob);
-    return false;
-  }
-
-  hb_blob_destroy (previous);
-  return true;
-}
-
-/**
- * hb_face_builder_sort_tables:
- * @face: A face object created with hb_face_builder_create()
- * @tags: (array zero-terminated=1): ordered list of table tags terminated by
- *   %HB_TAG_NONE
- *
- * Set the ordering of tables for serialization. Any tables not
- * specified in the tags list will be ordered after the tables in
- * tags, ordered by the default sort ordering.
- *
- * Since: 5.3.0
- **/
-void
-hb_face_builder_sort_tables (hb_face_t *face,
-                             const hb_tag_t  *tags)
-{
-  if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
-    return;
-
-  hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
-
-  // Sort all unspecified tables after any specified tables.
-  for (auto& info : data->tables.values_ref())
-    info.order = (unsigned) -1;
-
-  signed order = 0;
-  for (const hb_tag_t* tag = tags;
-       *tag;
-       tag++)
-  {
-    face_table_info_t* info;
-    if (!data->tables.has (*tag, &info)) continue;
-    info->order = order++;
-  }
-}

+ 6 - 0
thirdparty/harfbuzz/src/hb-face.h

@@ -33,6 +33,7 @@
 
 
 #include "hb-common.h"
 #include "hb-common.h"
 #include "hb-blob.h"
 #include "hb-blob.h"
+#include "hb-map.h"
 #include "hb-set.h"
 #include "hb-set.h"
 
 
 HB_BEGIN_DECLS
 HB_BEGIN_DECLS
@@ -149,6 +150,11 @@ HB_EXTERN void
 hb_face_collect_unicodes (hb_face_t *face,
 hb_face_collect_unicodes (hb_face_t *face,
 			  hb_set_t  *out);
 			  hb_set_t  *out);
 
 
+HB_EXTERN void
+hb_face_collect_nominal_glyph_mapping (hb_face_t *face,
+				       hb_map_t  *mapping,
+				       hb_set_t  *unicodes);
+
 HB_EXTERN void
 HB_EXTERN void
 hb_face_collect_variation_selectors (hb_face_t *face,
 hb_face_collect_variation_selectors (hb_face_t *face,
 				     hb_set_t  *out);
 				     hb_set_t  *out);

Some files were not shown because too many files changed in this diff