Browse Source

Merge pull request #52859 from bruvzg/hb300

Rémi Verschelde 4 years ago
parent
commit
2f6abc1002
100 changed files with 7343 additions and 5606 deletions
  1. 1 1
      COPYRIGHT.txt
  2. 1 0
      modules/text_server_adv/SCsub
  3. 2 2
      thirdparty/README.md
  4. 2 2
      thirdparty/harfbuzz/COPYING
  5. 0 2457
      thirdparty/harfbuzz/NEWS
  6. 4 4
      thirdparty/harfbuzz/src/hb-aat-layout-ankr-table.hh
  7. 8 3
      thirdparty/harfbuzz/src/hb-aat-layout-common.hh
  8. 1 1
      thirdparty/harfbuzz/src/hb-aat-layout-feat-table.hh
  9. 8 8
      thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh
  10. 7 7
      thirdparty/harfbuzz/src/hb-aat-layout-kerx-table.hh
  11. 19 2
      thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh
  12. 4 4
      thirdparty/harfbuzz/src/hb-aat-layout-opbd-table.hh
  13. 4 4
      thirdparty/harfbuzz/src/hb-aat-layout-trak-table.hh
  14. 10 3
      thirdparty/harfbuzz/src/hb-aat-layout.cc
  15. 2 2
      thirdparty/harfbuzz/src/hb-aat-ltag-table.hh
  16. 37 5
      thirdparty/harfbuzz/src/hb-algs.hh
  17. 35 16
      thirdparty/harfbuzz/src/hb-array.hh
  18. 5 0
      thirdparty/harfbuzz/src/hb-bimap.hh
  19. 203 0
      thirdparty/harfbuzz/src/hb-bit-page.hh
  20. 354 0
      thirdparty/harfbuzz/src/hb-bit-set-invertible.hh
  21. 808 0
      thirdparty/harfbuzz/src/hb-bit-set.hh
  22. 91 32
      thirdparty/harfbuzz/src/hb-blob.cc
  23. 10 0
      thirdparty/harfbuzz/src/hb-blob.h
  24. 1 1
      thirdparty/harfbuzz/src/hb-blob.hh
  25. 657 532
      thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh
  26. 763 674
      thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh
  27. 58 41
      thirdparty/harfbuzz/src/hb-buffer.cc
  28. 11 6
      thirdparty/harfbuzz/src/hb-buffer.hh
  29. 1 1
      thirdparty/harfbuzz/src/hb-cache.hh
  30. 1 1
      thirdparty/harfbuzz/src/hb-cff-interp-common.hh
  31. 2 2
      thirdparty/harfbuzz/src/hb-cff2-interp-cs.hh
  32. 15 18
      thirdparty/harfbuzz/src/hb-common.cc
  33. 14 0
      thirdparty/harfbuzz/src/hb-common.h
  34. 4 5
      thirdparty/harfbuzz/src/hb-config.hh
  35. 44 6
      thirdparty/harfbuzz/src/hb-coretext.cc
  36. 5 1
      thirdparty/harfbuzz/src/hb-debug.hh
  37. 0 3
      thirdparty/harfbuzz/src/hb-deprecated.h
  38. 65 199
      thirdparty/harfbuzz/src/hb-directwrite.cc
  39. 1 1
      thirdparty/harfbuzz/src/hb-draw.cc
  40. 57 45
      thirdparty/harfbuzz/src/hb-face.cc
  41. 40 39
      thirdparty/harfbuzz/src/hb-font.cc
  42. 18 30
      thirdparty/harfbuzz/src/hb-ft.cc
  43. 3 3
      thirdparty/harfbuzz/src/hb-gdi.cc
  44. 3 9
      thirdparty/harfbuzz/src/hb-glib.cc
  45. 2 2
      thirdparty/harfbuzz/src/hb-gobject-structs.cc
  46. 7 6
      thirdparty/harfbuzz/src/hb-graphite2.cc
  47. 3 9
      thirdparty/harfbuzz/src/hb-icu.cc
  48. 1 1
      thirdparty/harfbuzz/src/hb-iter.hh
  49. 3 3
      thirdparty/harfbuzz/src/hb-machinery.hh
  50. 3 4
      thirdparty/harfbuzz/src/hb-map.cc
  51. 15 11
      thirdparty/harfbuzz/src/hb-map.hh
  52. 16 15
      thirdparty/harfbuzz/src/hb-meta.hh
  53. 177 0
      thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc
  54. 96 0
      thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh
  55. 1 7
      thirdparty/harfbuzz/src/hb-mutex.hh
  56. 16 4
      thirdparty/harfbuzz/src/hb-null.hh
  57. 10 15
      thirdparty/harfbuzz/src/hb-object.hh
  58. 42 26
      thirdparty/harfbuzz/src/hb-open-file.hh
  59. 83 63
      thirdparty/harfbuzz/src/hb-open-type.hh
  60. 3 3
      thirdparty/harfbuzz/src/hb-ot-cff-common.hh
  61. 4 3
      thirdparty/harfbuzz/src/hb-ot-cff1-table.hh
  62. 176 80
      thirdparty/harfbuzz/src/hb-ot-cmap-table.hh
  63. 7 7
      thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh
  64. 878 12
      thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh
  65. 101 0
      thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh
  66. 122 5
      thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh
  67. 5 5
      thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh
  68. 2 2
      thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh
  69. 1 1
      thirdparty/harfbuzz/src/hb-ot-face-table-list.hh
  70. 3 9
      thirdparty/harfbuzz/src/hb-ot-font.cc
  71. 1 1
      thirdparty/harfbuzz/src/hb-ot-gasp-table.hh
  72. 105 35
      thirdparty/harfbuzz/src/hb-ot-glyf-table.hh
  73. 2 2
      thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh
  74. 1 1
      thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh
  75. 18 18
      thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh
  76. 396 107
      thirdparty/harfbuzz/src/hb-ot-layout-common.hh
  77. 20 22
      thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh
  78. 348 181
      thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh
  79. 228 94
      thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh
  80. 336 104
      thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh
  81. 16 16
      thirdparty/harfbuzz/src/hb-ot-layout-jstf-table.hh
  82. 117 67
      thirdparty/harfbuzz/src/hb-ot-layout.cc
  83. 1 2
      thirdparty/harfbuzz/src/hb-ot-layout.hh
  84. 25 11
      thirdparty/harfbuzz/src/hb-ot-map.cc
  85. 22 22
      thirdparty/harfbuzz/src/hb-ot-math-table.hh
  86. 1 1
      thirdparty/harfbuzz/src/hb-ot-maxp-table.hh
  87. 2 2
      thirdparty/harfbuzz/src/hb-ot-meta-table.hh
  88. 11 6
      thirdparty/harfbuzz/src/hb-ot-name-table.hh
  89. 6 3
      thirdparty/harfbuzz/src/hb-ot-name.cc
  90. 4 21
      thirdparty/harfbuzz/src/hb-ot-os2-table.hh
  91. 130 0
      thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh
  92. 27 9
      thirdparty/harfbuzz/src/hb-ot-post-table.hh
  93. 6 6
      thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh
  94. 5 4
      thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh
  95. 23 15
      thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh
  96. 2 2
      thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc
  97. 2 2
      thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc
  98. 21 21
      thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc
  99. 8 6
      thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc
  100. 303 362
      thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh

+ 1 - 1
COPYRIGHT.txt

@@ -1379,7 +1379,7 @@ License: HarfBuzz
  Copyright (C) 2009  Keith Stribley
  Copyright (C) 2009  Martin Hosken and SIL International
  Copyright (C) 2007  Chris Wilson
- Copyright (C) 2006  Behdad Esfahbod
+ Copyright (C) 2005,2006,2020,2021  Behdad Esfahbod
  Copyright (C) 2005  David Turner
  Copyright (C) 2004,2007,2008,2009,2010  Red Hat, Inc.
  Copyright (C) 1998-2004  David Turner and Werner Lemberg

+ 1 - 0
modules/text_server_adv/SCsub

@@ -64,6 +64,7 @@ if env["builtin_harfbuzz"]:
         #'src/hb-gobject-structs.cc',
         "src/hb-icu.cc",
         "src/hb-map.cc",
+        "src/hb-ms-feature-ranges.cc",
         "src/hb-number.cc",
         "src/hb-ot-cff1-table.cc",
         "src/hb-ot-cff2-table.cc",

+ 2 - 2
thirdparty/README.md

@@ -192,13 +192,13 @@ Files extracted from upstream source:
 ## harfbuzz
 
 - Upstream: https://github.com/harfbuzz/harfbuzz
-- Version: 2.8.0 (03538e872a0610a65fad692b33d3646f387cf578, 2021)
+- Version: 3.0.0 (9c387e20d65a7a366ac270d789f6ad266014c9e0, 2021)
 - License: MIT
 
 Files extracted from upstream source:
 
 - the `src` folder
-- `AUTHORS`, `COPYING`, `NEWS`, `THANKS`
+- `AUTHORS`, `COPYING`, `THANKS`
 
 
 ## icu4c

+ 2 - 2
thirdparty/harfbuzz/COPYING

@@ -4,14 +4,14 @@ 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 © 2019,2020  Facebook, Inc. 
+Copyright © 2019,2020  Facebook, Inc.
 Copyright © 2012  Mozilla Foundation
 Copyright © 2011  Codethink Limited
 Copyright © 2008,2010  Nokia Corporation and/or its subsidiary(-ies)
 Copyright © 2009  Keith Stribley
 Copyright © 2009  Martin Hosken and SIL International
 Copyright © 2007  Chris Wilson
-Copyright © 2006  Behdad Esfahbod
+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

+ 0 - 2457
thirdparty/harfbuzz/NEWS

@@ -1,2457 +0,0 @@
-Overview of changes leading to 2.8.0
-Tuesday, March 16, 2021
-====================================
-- Shape joining scripts other than Arabic/Syriac using the Universal Shaping Engine.
-  Previously these were shaped using the generalized Arabic shaper. (David Corbett)
-- Fix regression in shaping of U+0B55 ORIYA SIGN OVERLINE. (David Corbett)
-- Update language tags. (David Corbett)
-- Variations: reduce error: do not round each interpolated delta. (Just van Rossum) 
-- Documentation improvements. (Khaled Hosny, Nathan Willis)
-- Subsetter improvements: subsets most, if not all, lookup types now. (Garret Rieger, Qunxin Liu)
-- Fuzzer-found fixes and other improvements when memory failures happen. (Behdad)
-- Removed most atomic implementations now that we have C++11 atomic impl. (Behdad)
-- General codebase upkeep; using more C++11 features: constexpr constructors, etc. (Behdad)
-
-
-Overview of changes leading to 2.7.4
-Sunday, December 27, 2020
-====================================
-- Fix missing --enable-introspection configure option from previous release
-  tarball.
-- Documentation updates.
-
-Overview of changes leading to 2.7.3
-Wednesday, December 23, 2020
-====================================
-- Update USE shaper to 2020-08-13 specification, and other improvements.
-- Don’t disable liga feature in myanmar shaper, to match Uniscribe.
-- Improvements to language and script tags handling.
-- Update language system tag registry to OpenType 1.8.4
-- Support for serializing and deserializing Unicode buffers. Serialized buffers
-  are now delimited with `<>` or `[]` based on whether it is a Unicode or
-  glyphs buffer.
-- Increase buffer work limits to handle fonts with many complex lookups.
-- Handle more shaping operations in trace output.
-- Memory access fixes.
-- More OOM fixes.
-- Improved documentation.
-- Build system improvements.
-- New API:
-+hb_buffer_has_positions()
-+hb_buffer_serialize()
-+hb_buffer_serialize_unicode()
-+hb_buffer_deserialize_unicode()
-
-
-Overview of changes leading to 2.7.2
-Saturday, August 29, 2020
-====================================
-- Fix a regression in the previous release that caused a crash with Kaithi.
-- More OOM fixes.
-
-
-Overview of changes leading to 2.7.1
-Thursday, August 13, 2020
-====================================
-- ot-funcs now handles variable empty glyphs better when hvar/vvar isn't present.
-- Reverted a GDEF processing regression.
-- A couple of fixes to handle OOM better.
-
-
-Overview of changes leading to 2.7.0
-Saturday, July 25, 2020
-====================================
-- Use an implementation for round that always rounds up, some minor fluctuations
-  are expected on var font specially when hb-ot callback is used.
-- Fix an AAT's `kerx` issue on broken rendering of Devanagari Sangam MN.
-- Remove AAT's `lcar` table support from _get_ligature_carets API, not even much
-  use on macOS installed fonts (only two files).  GDEF support is the recommended
-  one and expected to work properly after issues fixed two releases ago.
-- Minor memory fixes to handle OOM better specially in hb-ft.
-- Minor .so files versioning scheme change and remove stable/unstable scheme
-  differences, was never used in practice (always default to stable scheme).
-- We are now suggesting careful packaging of the library using meson,
-  https://github.com/harfbuzz/harfbuzz/wiki/Notes-on-migration-to-meson
-  for more information.
-- Distribution package URL is changed, either use GitHub generated tarballs,
-  `https://github.com/harfbuzz/harfbuzz/archive/$pkgver.tar.gz`
-  or, even more preferably use commit hash of the release and git checkouts like,
-  `git+https://github.com/harfbuzz/harfbuzz#commit=$commit`
-
-
-Overview of changes leading to 2.6.8
-Monday, June 22, 2020
-====================================
-- New API to fetch glyph alternates from GSUB table.
-- hb-coretext build fix for macOS < 10.10.
-- Meson build fixes, cmake port removal is postponed but please prepare for
-  it and give us feedback.
-  Autotools is still our main build system however please consider
-  experimenting with meson also for packaging the library.
-- New API:
-+hb_ot_layout_lookup_get_glyph_alternates()
-
-
-Overview of changes leading to 2.6.7
-Wednesday, June 3, 2020
-====================================
-- Update to Unicode 13.0.0.
-- Fix hb_ot_layout_get_ligature_carets for fonts without lcar table, it was
-  completely broken for all the other fonts since 2.1.2.
-- As a part of our migration to meson, this release will be the last one
-  to provide cmake port files but autotools still is our main build system.
-  There is a possibility that the next version or the after be released
-  using meson.
-
-
-Overview of changes leading to 2.6.6
-Tuesday, May 12, 2020
-====================================
-- A fix in AAT kerning for Geeza Pro.
-- Better support for resource fork fonts on macOS.
-
-
-Overview of changes leading to 2.6.5
-Friday, April 17, 2020
-====================================
-- Add experimental meson build system.  Autotools is still the primary
-  and supported build system.
-- AAT is now always preferred for horizontal scripts when both AAT and OT
-  layout tables exist at the same time.
-- Subsetter improvements.
-- New API:
-+hb_ft_font_lock_face()
-+hb_ft_font_unlock_face()
-
-
-Overview of changes leading to 2.6.4
-Monday, October 29, 2019
-====================================
-- Small bug fix.
-- Build fixes.
-
-
-Overview of changes leading to 2.6.3
-Monday, October 28, 2019
-====================================
-- Misc small fixes, mostly to build-related issues.
-- New API:
-+hb_font_get_nominal_glyphs()
-
-
-Overview of changes leading to 2.6.2
-Monday, September 30, 2019
-====================================
-- Misc small fixes, mostly to build-related issues.
-
-
-Overview of changes leading to 2.6.1
-Thursday, August 22, 2019
-====================================
-- Fix regression with hb_font_create_sub_font scaling introduced in 2.6.0.
-- Change interpretation of font PTEM size / CoreText font size handling.
-  See https://github.com/harfbuzz/harfbuzz/pull/1484
-- hb-ot-font: Prefer symbol cmap subtable if present.
-- Apply 'dist'/'abvm'/'blwm' features to all scripts.
-- Drop experimental DirectWrite API.
-
-
-Overview of changes leading to 2.6.0
-Tuesday, August 13, 2019
-====================================
-- New OpenType metrics, baseline, and metadata table access APIs.
-- New API to set font variations to a named-instance.
-- New hb-gdi.h header and API for creating hb_face_t from HFONT.
-- Amalgam: Provide a single-file harfbuzz.cc file for easier alternate building.
-- More size-reduction configurable options, enabled by HB_TINY.
-- New API:
-+hb_font_set_var_named_instance()
-+hb_gdi_face_create()
-+hb_ot_layout_baseline_tag_t
-+hb_ot_layout_get_baseline()
-+hb_ot_meta_tag_t
-+hb_ot_meta_get_entry_tags()
-+hb_ot_meta_reference_entry()
-+hb_ot_metrics_tag_t
-+hb_ot_metrics_get_position()
-+hb_ot_metrics_get_variation()
-+hb_ot_metrics_get_x_variation()
-+hb_ot_metrics_get_y_variation()
-
-
-Overview of changes leading to 2.5.3
-Wednesday, June 26, 2019
-====================================
-- Fix UCD script data for Unicode 10+ scripts.  This was broken since 2.5.0.
-- More optimizations for HB_TINY.
-
-
-Overview of changes leading to 2.5.2
-Thursday, June 20, 2019
-====================================
-- More hb-config.hh facilities to shrink library size, namely when built as
-  HB_TINY.
-- New documentation of custom configurations in CONFIG.md.
-- Fix build on gcc 4.8.  That's supported again.
-- Universal Shaping Engine improvements thanks to David Corbett.
-- API Changes: Undeprecate some horizontal-kerning API and re-enable in hb-ft,
-  such that Type1 fonts will continue kerning.
-
-
-Overview of changes leading to 2.5.1
-Friday, May 31, 2019
-====================================
-- Fix build with various versions of Visual Studio.
-- Improved documentation, thanks to Nathan Willis.
-- Bugfix in subsetting glyf table.
-- Improved scripts for cross-compiling for Windows using mingw.
-- Rename HB_MATH_GLYPH_PART_FLAG_EXTENDER to HB_OT_MATH_GLYPH_PART_FLAG_EXTENDER.
-  A deprecated macro is added for backwards-compatibility.
-
-
-Overview of changes leading to 2.5.0
-Friday, May 24, 2019
-====================================
-- This release does not include much functional changes, but includes major internal
-  code-base changes.  We now require C++11.  Support for gcc 4.8 and earlier has been
-  dropped.
-- New hb-config.hh facility for compiling smaller library for embedded and web usecases.
-- New Unicode Character Databse implementation that is half the size of previously-used
-  UCDN.
-- Subsetter improvements.
-- Improved documentation, thanks to Nathan Willis.
-- Misc shaping fixes.
-
-
-Overview of changes leading to 2.4.0
-Monday, March 25, 2019
-====================================
-- Unicode 12.
-- Misc fixes.
-- Subsetter improvements.
-- New API:
-HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE
-hb_directwrite_face_create()
-
-
-Overview of changes leading to 2.3.1
-Wednesday, January 30, 2019
-====================================
-- AAT bug fixes.
-- Misc internal housekeeping cleanup.
-
-
-Overview of changes leading to 2.3.0
-Thursday, December 20, 2018
-====================================
-- Fix regression on big-endian architectures.  Ouch!
-- Misc bug and build fixes.
-- Fix subsetting of simple GSUB/GDEF.
-- Merge CFF / CFF2 support contributed by Adobe.  This mostly involves
-  the subsetter, but also get_glyph_extents on CFF fonts.
-
-New API in hb-aat.h:
-+hb_aat_layout_has_substitution()
-+hb_aat_layout_has_positioning()
-+hb_aat_layout_has_tracking()
-
-
-Overview of changes leading to 2.2.0
-Thursday, November 29, 2018
-====================================
-- Misc shaping bug fixes.
-- Add font variations named-instance API.
-- Deprecate font variations axis enumeration API and add replacement.
-- AAT shaping improvements:
-  o Fixed 'kern' table Format 2 implementation.
-  o Implement 'feat' table API for feature detection.
-  o Blacklist 'GSUB' table of fonts from 'MUTF' foundry that also have 'morx'.
-
-New API:
-+hb_aat_layout_feature_type_t
-+hb_aat_layout_feature_selector_t
-+hb_aat_layout_get_feature_types()
-+hb_aat_layout_feature_type_get_name_id
-+hb_aat_layout_feature_selector_info_t
-+HB_AAT_LAYOUT_NO_SELECTOR_INDEX
-+hb_aat_layout_feature_type_get_selector_infos()
-+hb_ot_var_axis_flags_t
-+hb_ot_var_axis_info_t
-+hb_ot_var_get_axis_infos()
-+hb_ot_var_find_axis_info()
-+hb_ot_var_get_named_instance_count()
-+hb_ot_var_named_instance_get_subfamily_name_id()
-+hb_ot_var_named_instance_get_postscript_name_id()
-+hb_ot_var_named_instance_get_design_coords()
-
-Deprecated API:
-+HB_OT_VAR_NO_AXIS_INDEX
-+hb_ot_var_axis_t
-+hb_ot_var_get_axes()
-+hb_ot_var_find_axis()
-
-
-Overview of changes leading to 2.1.3
-Friday, November 16, 2018
-====================================
-- Fix AAT 'mort' shaping, which was broken in 2.1.2
-
-
-Overview of changes leading to 2.1.2
-Friday, November 16, 2018
-====================================
-- Various internal changes.
-- AAT shaping improvements:
-  o Implement kern table Format 1 state-machine-based kerning.
-  o Implement cross-stream kerning (cursive positioning, etc).
-  o Ignore emptyish GSUB tables (zero scripts) if morx present.
-  o Don't apply GPOS if morx is being applied.  Matches Apple.
-
-
--Overview of changes leading to 2.1.1
-Monday, November 5, 2018
-====================================
-- AAT improvements:
-  o Implement 'mort' table.
-  o Implement 'kern' subtables Format 1 and Format 3.
-
-
-Overview of changes leading to 2.1.0
-Tuesday, October 30, 2018
-====================================
-- AAT shaping improvements:
-  o Allow user controlling AAT features, for whole buffer only currently.
-  o Several 'morx' fixes.
-  o Implement tuple-kerns in 'kerx'; Fixes kerning with Apple default
-    San Francisco fonts.
-- Support for color fonts:
-  o COLR/CPAL API to fetch color layers.
-  o SVG table to fetch SVG documents.
-  o CBDT/sbix API to fetch PNG images.
-- New 'name' table API.
-- hb-ot-font now uses 'VORG' table to correctly position CFF glyphs
-  in vertical layout.
-- Various fuzzer-found bug fixes.
-
-Changed API:
-
-A type and a macro added in 2.0.0 were renamed:
-
-hb_name_id_t -> hb_ot_name_id_t
-HB_NAME_ID_INVALID -> HB_OT_NAME_ID_INVALID
-
-New API:
-
-+hb_color_t
-+HB_COLOR
-+hb_color_get_alpha()
-+hb_color_get_red()
-+hb_color_get_green()
-+hb_color_get_blue()
-+hb_ot_color_has_palettes()
-+hb_ot_color_palette_get_count()
-+hb_ot_color_palette_get_name_id()
-+hb_ot_color_palette_color_get_name_id()
-+hb_ot_color_palette_flags_t
-+hb_ot_color_palette_get_flags()
-+hb_ot_color_palette_get_colors()
-+hb_ot_color_has_layers()
-+hb_ot_color_layer_t
-+hb_ot_color_glyph_get_layers()
-+hb_ot_color_has_svg()
-+hb_ot_color_glyph_reference_svg()
-+hb_ot_color_has_png()
-+hb_ot_color_glyph_reference_png()
-
-+hb_ot_name_id_t
-+HB_OT_NAME_ID_INVALID
-+HB_OT_NAME_ID_COPYRIGHT
-+HB_OT_NAME_ID_FONT_FAMILY
-+HB_OT_NAME_ID_FONT_SUBFAMILY
-+HB_OT_NAME_ID_UNIQUE_ID
-+HB_OT_NAME_ID_FULL_NAME
-+HB_OT_NAME_ID_VERSION_STRING
-+HB_OT_NAME_ID_POSTSCRIPT_NAME
-+HB_OT_NAME_ID_TRADEMARK
-+HB_OT_NAME_ID_MANUFACTURER
-+HB_OT_NAME_ID_DESIGNER
-+HB_OT_NAME_ID_DESCRIPTION
-+HB_OT_NAME_ID_VENDOR_URL
-+HB_OT_NAME_ID_DESIGNER_URL
-+HB_OT_NAME_ID_LICENSE
-+HB_OT_NAME_ID_LICENSE_URL
-+HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY
-+HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY
-+HB_OT_NAME_ID_MAC_FULL_NAME
-+HB_OT_NAME_ID_SAMPLE_TEXT
-+HB_OT_NAME_ID_CID_FINDFONT_NAME
-+HB_OT_NAME_ID_WWS_FAMILY
-+HB_OT_NAME_ID_WWS_SUBFAMILY
-+HB_OT_NAME_ID_LIGHT_BACKGROUND
-+HB_OT_NAME_ID_DARK_BACKGROUND
-+HB_OT_NAME_ID_VARIATIONS_PS_PREFIX
-+hb_ot_name_entry_t
-+hb_ot_name_list_names()
-+hb_ot_name_get_utf8()
-+hb_ot_name_get_utf16()
-+hb_ot_name_get_utf32()
-
-
-Overview of changes leading to 2.0.2
-Saturday, October 20, 2018
-====================================
-- Fix two minor memory access issues in AAT tables.
-
-
-Overview of changes leading to 2.0.1
-Friday, October 19, 2018
-====================================
-- Fix hb-version.h reported release version that went wrong (1.8.0)
-  with previous release.
-- Fix extrapolation in 'trak' table.
-- Fix hb-font infinite-recursion issue with some font funcs and
-  subclassed fonts.
-- Implement variation-kerning format in kerx table, although without
-  variation.
-- Fix return value of hb_map_is_empty().
-
-
-Overview of changes leading to 2.0.0
-Thursday, October 18, 2018
-====================================
-- Added AAT shaping support (morx/kerx/trak).
-  Automatically used if GSUB/GPOS are not available respectively.
-  Set HB_OPTIONS=aat env var to have morx/kerx preferred over
-  GSUB/GPOS.
-- Apply TrueType kern table internally, instead of relying on
-  hb_font_t callbacks.
-- Khmer shaper significantly rewritten to better match Uniscribe.
-- Indic3 tags ('dev3', etc) are passed to USE shaper.
-- .dfont Mac font containers implemented.
-- Script- and language-mapping revamped to better use BCP 47.
-- Misc USE and Indic fixes.
-- Misc everything fixes.
-- Too many things to list.  Biggest release since 0.9.1, with
-  over 500 commits in just over 5 weeks!  Didn't intend it to
-  be a big release.  Just happened to become.
-- hb-ft now locks underlying FT_Face during use.
-
-API changes:
-
-- Newly-created hb_font_t's now have our internal "hb-ot-font"
-  callbacks set on them, so they should work out of the box
-  without any callbacks set.  If callbacks are set, everything
-  is back to what it was before, the fallback callbacks are
-  null.  If you to get the internal implementation modified,
-  sub_font it.
-
-- New hb_font_funcs_set_nominal_glyphs_func() allows speeding
-  up character to glyph mapping.
-
-New API:
-+HB_FEATURE_GLOBAL_START
-+HB_FEATURE_GLOBAL_END
-+hb_buffer_set_invisible_glyph()
-+hb_buffer_get_invisible_glyph()
-+hb_font_funcs_set_nominal_glyphs_func()
-+hb_ot_layout_table_select_script()
-+hb_ot_layout_script_select_language()
-+hb_ot_layout_feature_get_name_ids()
-+hb_ot_layout_feature_get_characters()
-+hb_name_id_t
-+HB_NAME_ID_INVALID
-+HB_OT_MAX_TAGS_PER_SCRIPT
-+hb_ot_tags_from_script_and_language()
-+hb_ot_tags_to_script_and_language()
-
-Deprecated API:
--hb_font_funcs_set_glyph_func()
--hb_unicode_eastasian_width_func_t
--hb_unicode_funcs_set_eastasian_width_func()
--hb_unicode_eastasian_width()
--hb_unicode_decompose_compatibility_func_t
--HB_UNICODE_MAX_DECOMPOSITION_LEN
--hb_unicode_funcs_set_decompose_compatibility_func()
--hb_unicode_decompose_compatibility()
--hb_font_funcs_set_glyph_h_kerning_func()
--hb_font_funcs_set_glyph_v_kerning_func()
--hb_font_get_glyph_h_kerning()
--hb_font_get_glyph_v_kerning()
--hb_font_get_glyph_kerning_for_direction()
--hb_ot_layout_table_choose_script()
--hb_ot_layout_script_find_language()
--hb_ot_tags_from_script()
--hb_ot_tag_from_language()
-
-
-Overview of changes leading to 1.9.0
-Monday, September 10, 2018
-====================================
-- Added 'cmap' API to hb_face_t.
-- Face-builder API.
-- hb-ot-font re-creation should be much leaner now, as the
-  font tables it uses are cached on hb_face_t now.
-- Internal source header file name changes:
-  hb-*-private.hh is renamed to hb-*.hh.
-
-New API:
-+HB_UNICODE_MAX
-+hb_face_collect_unicodes()
-+hb_face_collect_variation_selectors()
-+hb_face_collect_variation_unicodes()
-+hb_face_builder_create()
-+hb_face_builder_add_table()
-
-
-Overview of changes leading to 1.8.8
-Tuesday, August 14, 2018
-====================================
-- Fix hb-icu crash on architectures where compare_exchange_weak() can
-  fail falsely.  This bug was introduced in 1.8.4.
-  https://bugs.chromium.org/p/chromium/issues/detail?id=873568
-- More internal refactoring of atomic operations and singletons.
-- API changes:
-  The following functions do NOT reference their return value before
-  returning:
-  * hb_unicode_funcs_get_default()
-  * hb_glib_get_unicode_funcs()
-  * hb_icu_get_unicode_funcs()
-  This is consistent with their naming ("get", instead of "reference")
-  as well as how they are used in the wild (ie. no one calls destroy()
-  on their return value.)
-
-
-Overview of changes leading to 1.8.7
-Wednesday, August 8, 2018
-====================================
-- Fix assertion failure with GDEF-blacklisted fonts.
-
-
-Overview of changes leading to 1.8.6
-Tuesday, August 7, 2018
-====================================
-- Internal code shuffling.
-- New API to speed up getting advance widths for implementations
-  that have heavy overhead in get_h_advance callback:
-+hb_font_funcs_set_glyph_h_advances_func
-+hb_font_funcs_set_glyph_v_advances_func
-+hb_font_get_glyph_advances_for_direction
-+hb_font_get_glyph_h_advances
-+hb_font_get_glyph_h_advances_func_t
-+hb_font_get_glyph_v_advances
-+hb_font_get_glyph_v_advances_func_t
-
-
-Overview of changes leading to 1.8.5
-Wednesday, August 1, 2018
-====================================
-- Major Khmer shaper improvements to better match Microsoft.
-- Indic bug fixes.
-- Internal improvements to atomic operations.
-
-
-Overview of changes leading to 1.8.4
-Tuesday, July 17, 2018
-====================================
-- Fix build on non-C++11.
-- Use C++-style GCC atomics and C++11 atomics.
-
-
-Overview of changes leading to 1.8.3
-Wednesday, July 11, 2018
-====================================
-- A couple of Indic / USE bug fixes.
-- Disable vectorization, as it was causing unaligned access bus error on
-  certain 32bit architectures.
-
-
-Overview of changes leading to 1.8.2
-Tuesday, July 3, 2018
-====================================
-- Fix infinite loop in Khmer shaper.
-- Improve hb_blob_create_from_file() for streams.
-
-
-Overview of changes leading to 1.8.1
-Tuesday, June 12, 2018
-====================================
-- Fix hb-version.h file generation; last two releases went out with wrong ones.
-- Add correctness bug in hb_set_t operations, introduced in 1.7.7.
-- Remove HB_SUBSET_BUILTIN build option.  Not necessary.
-
-
-Overview of changes leading to 1.8.0
-Tuesday, June 5, 2018
-====================================
-- Update to Unicode 11.0.0.
-
-
-Overview of changes leading to 1.7.7
-Tuesday, June 5, 2018
-====================================
-- Lots of internal changes, but not yet exposed externally.
-- All HarfBuzz objects are significantly smaller in size now.
-- Sinhala: Position repha on top of post-consonant, not base.
-  This better matches Windows 10 behavior, which was changed
-  from previous Windows versions.
-- New build options:
-  o New cpp macro HB_NO_ATEXIT
-  o New cpp macro HB_SUBSET_BUILTIN
-- Significant libharfbuzz-subset changes. API subject to change.
-- New API in libharfbuzz:
-
-+hb_blob_create_from_file()
-+hb_face_count()
-
-A hashmap implementation:
-+hb-map.h
-+HB_MAP_VALUE_INVALID
-+hb_map_t
-+hb_map_create()
-+hb_map_get_empty()
-+hb_map_reference()
-+hb_map_destroy()
-+hb_map_set_user_data()
-+hb_map_get_user_data()
-+hb_map_allocation_successful()
-+hb_map_clear()
-+hb_map_is_empty()
-+hb_map_get_population()
-+hb_map_set()
-+hb_map_get()
-+hb_map_del()
-+hb_map_has()
-
-
-Overview of changes leading to 1.7.6
-Wednesday, March 7, 2018
-====================================
-
-- Fix to hb_set_t binary operations. Ouch.
-- New experimental harfbuzz-subset library. All of hb-subset.h
-  is experimental right now and API WILL change.
-
-- New API:
-hb_blob_copy_writable_or_fail()
-HB_OT_TAG_BASE
-hb_set_previous()
-hb_set_previous_range()
-
-
-Overview of changes leading to 1.7.5
-Tuesday, January 30, 2018
-====================================
-
-- Separate Khmer shaper from Indic.
-- First stab at AAT morx. Not hooked up.
-- Misc bug fixes.
-
-
-Overview of changes leading to 1.7.4
-Wednesday, December 20, 2017
-====================================
-
-- Fix collect_glyphs() regression caused by hb_set_t changes.
-
-
-Overview of changes leading to 1.7.3
-Monday, December 18, 2017
-====================================
-
-- hb_set_t performance tuning and optimizations.
-- Speed up collect_glyphs() and reject garbage data.
-- In hb_coretext_font_create() set font point-size (ptem).
-- Misc fixes.
-
-
-Overview of changes leading to 1.7.2
-Monday, December 4, 2017
-====================================
-
-- Optimize hb_set_add_range().
-- Misc fixes.
-- New API:
-hb_coretext_font_create()
-
-
-Overview of changes leading to 1.7.1
-Tuesday, November 14, 2017
-====================================
-
-- Fix atexit object destruction regression.
-- Fix minor integer-overflow.
-
-
-Overview of changes leading to 1.7.0
-Monday, November 13, 2017
-====================================
-
-- Minor Indic fixes.
-- Implement kerning and glyph names in hb-ot-font.
-- Various DSO optimization re .data and .bss sizes.
-- Make C++11 optional; build fixes.
-- Mark all other backends "unsafe-to-break".
-- Graphite fix.
-
-
-Overview of changes leading to 1.6.3
-Thursday, October 26th, 2017
-====================================
-
-- Fix hb_set_t some more.  Should be solid now.
-- Implement get_glyph_name() for hb-ot-font.
-- Misc fixes.
-
-
-Overview of changes leading to 1.6.2
-Monday, October 23nd, 2017
-====================================
-
-- Yesterday's release had a bad crasher; don't use it.  That's what
-  happens when one works on Sunday...
-  https://github.com/harfbuzz/harfbuzz/issues/578
-- Build fixes for FreeBSD and Chrome Android.
-
-
-Overview of changes leading to 1.6.1
-Sunday, October 22nd, 2017
-====================================
-
-- Don't skip over COMBINING GRAPHEME JOINER when ligating, etc.
-  To be refined: https://github.com/harfbuzz/harfbuzz/issues/554
-- Faster hb_set_t implementation.
-- Don't use deprecated ICU API.
-- Fix undefined-behavior in Myanmar shaper, introduced in 1.6.0
-- Deprecated API:
-  hb_set_invert()
-
-
-Overview of changes leading to 1.6.0
-Friday, October the 13th, 2017
-====================================
-
-- Update to Unicode 10.
-
-- Various Indic and Universal Shaping Engine fixes as a result of
-  HarfBuzz Hackfest with Jonathan Kew at Web Engines Hackfest at
-  the Igalia offices in A Coruña, Spain.  Thanks Igalia for having
-  us!
-
-- Implement Unicode Arabic Mark Ordering Algorithm UTR#53.
-
-- Implement optical sizing / tracking in CoreText backend, using
-  new API hb_font_set_ptem().
-
-- Allow notifying hb_font_t that underlying FT_Face changed sizing,
-  using new API hb_ft_font_changed().
-
-- More Graphite backend RTL fixes.
-
-- Fix caching of variable font shaping plans.
-
-- hb-view / hb-shape now accept following new arguments:
-
-  o --unicodes: takes a list of hex numbers that represent Unicode
-    codepoints.
-
-New API:
-+hb_face_get_table_tags()
-+hb_font_set_ptem()
-+hb_font_get_ptem()
-+hb_ft_font_changed()
-
-
-Overview of changes leading to 1.5.1
-Tuesday, September 5, 2017
-====================================
-
-- Fix "unsafe-to-break" in fallback shaping and other corner cases.
-  All our tests pass with --verify now, meaning unsafe-to-break API
-  works as expected.
-- Add --unicodes to hb-view / hb-shape.
-- [indic] Treat Consonant_With_Stacker as consonant.  This will need
-  further tweaking.
-- hb_buffer_diff() tweaks.
-
-
-Overview of changes leading to 1.5.0
-Wednesday, August 23, 2017
-====================================
-
-- Misc new API, for appending a buffer to another, and for comparing
-  contents of two buffers for types of differences.
-
-- New "unsafe-to-break" API.  Can be used to speed up reshaping
-  in line-breaking situations.  Essentially, after shaping, it returns
-  positions in the input string (some of the cluster boundaries) that
-  are "safe to break" in that if the text is segmented at that position
-  and two sides reshaped and concatenated, the shaping result is
-  exactly the same as shaping the text in one piece.
-
-  hb-view and hb-shape and hb-shape now take --verify, which verifies
-  the above property.
-
-  Some corner cases of the implementation are still not quite working.
-  Those will be fixed in subsequent releases.
-
-- New API:
-
-hb_buffer_append()
-
-hb_glyph_flags_t
-HB_GLYPH_FLAG_UNSAFE_TO_BREAK
-HB_GLYPH_FLAG_DEFINED
-hb_glyph_info_get_glyph_flags()
-
-HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
-
-hb_buffer_diff_flags_t
-HB_BUFFER_DIFF_FLAG_EQUAL
-HB_BUFFER_DIFF_FLAG_CONTENT_TYPE_MISMATCH
-HB_BUFFER_DIFF_FLAG_LENGTH_MISMATCH
-HB_BUFFER_DIFF_FLAG_NOTDEF_PRESENT
-HB_BUFFER_DIFF_FLAG_DOTTED_CIRCLE_PRESENT
-HB_BUFFER_DIFF_FLAG_CODEPOINT_MISMATCH
-HB_BUFFER_DIFF_FLAG_CLUSTER_MISMATCH
-HB_BUFFER_DIFF_FLAG_GLYPH_FLAGS_MISMATCH
-HB_BUFFER_DIFF_FLAG_POSITION_MISMATCH
-hb_buffer_diff
-
-
-Overview of changes leading to 1.4.8
-Tuesday, August 8, 2017
-====================================
-
-- Major fix to avar table handling.
-- Rename hb-shape --show-message to --trace.
-- Build fixes.
-
-
-Overview of changes leading to 1.4.7
-Tuesday, July 18, 2017
-====================================
-
-- Multiple Indic, Tibetan, and Cham fixes.
-- CoreText: Allow disabling kerning.
-- Adjust Arabic feature order again.
-- Misc build fixes.
-
-
-Overview of changes leading to 1.4.6
-Sunday, April 23, 2017
-====================================
-
-- Graphite2: Fix RTL positioning issue.
-- Backlist GDEF of more versions of Padauk and Tahoma.
-- New, experimental, cmake alternative build system.
-
-
-Overview of changes leading to 1.4.5
-Friday, March 10, 2017
-====================================
-
-- Revert "Fix Context lookup application when moving back after a glyph..."
-  This introduced memory access problems.  To be fixed properly soon.
-
-
-Overview of changes leading to 1.4.4
-Sunday, March 5, 2017
-====================================
-
-- Fix Context lookup application when moving back after a glyph deletion.
-- Fix buffer-overrun in Bengali.
-
-
-Overview of changes leading to 1.4.3
-Saturday, February 25, 2017
-====================================
-
-- Route Adlam script to Arabic shaper.
-- Misc fixes.
-- New API:
-  hb_font_set_face()
-- Deprecate API:
-  hb_graphite2_font_get_gr_font()
-
-
-Overview of changes leading to 1.4.2
-Monday, January 23, 2017
-====================================
-
-- Implement OpenType Font Variation tables avar/fvar/HVAR/VVAR.
-- hb-shape and hb-view now accept --variations.
-- New API:
-
-hb_variation_t
-hb_variation_from_string()
-hb_variation_to_string()
-
-hb_font_set_variations()
-hb_font_set_var_coords_design()
-hb_font_get_var_coords_normalized()
-
-hb-ot-var.h:
-hb_ot_var_axis_t
-hb_ot_var_has_data()
-hb_ot_var_get_axis_count()
-hb_ot_var_get_axes()
-hb_ot_var_find_axis()
-hb_ot_var_normalize_variations()
-hb_ot_var_normalize_coords()
-
-- MVAR to be implemented later.  Access to named instances to be
-  implemented later as well.
-
-- Misc fixes.
-
-
-Overview of changes leading to 1.4.1
-Thursday, January 5, 2017
-====================================
-
-- Always build and use UCDN for Unicode data by default.
-  Reduces dependence on version of Unicode data in glib,
-  specially in the Windows bundles we are shipping, which
-  have very old glib.
-
-
-Overview of changes leading to 1.4.0
-Thursday, January 5, 2017
-====================================
-
-- Merged "OpenType GX" branch which adds core of support for
-  OpenType 1.8 Font Variations.  To that extent, the relevant
-  new API is:
-
-New API:
-hb_font_set_var_coords_normalized()
-
-  with supporting API:
-
-New API:
-HB_OT_LAYOUT_NO_VARIATIONS_INDEX
-hb_ot_layout_table_find_feature_variations()
-hb_ot_layout_feature_with_variations_get_lookups()
-hb_shape_plan_create2()
-hb_shape_plan_create_cached2()
-
-  Currently variations in GSUB/GPOS/GDEF are fully supported,
-  and no other tables are supported.  In particular, fvar/avar
-  are NOT supported, hence the hb_font_set_var_coords_normalized()
-  taking normalized coordinates.  API to take design coordinates
-  will be added in the future.
-
-  HVAR/VVAR/MVAR support will also be added to hb-ot-font in the
-  future.
-
-- Fix regression in GDEF glyph class processing.
-- Add decompositions for Chakma, Limbu, and Balinese in USE shaper.
-- Misc fixes.
-
-
-Overview of changes leading to 1.3.4
-Monday, December 5, 2016
-====================================
-
-- Fix vertical glyph origin in hb-ot-font.
-- Implement CBDT/CBLC color font glyph extents in hb-ot-font.
-
-
-Overview of changes leading to 1.3.3
-Wednesday, September 28, 2016
-====================================
-
-- Implement parsing of OpenType MATH table.
-New API:
-HB_OT_TAG_MATH
-HB_OT_MATH_SCRIPT
-hb_ot_math_constant_t
-hb_ot_math_kern_t
-hb_ot_math_glyph_variant_t
-hb_ot_math_glyph_part_flags_t
-hb_ot_math_glyph_part_t
-hb_ot_math_has_data
-hb_ot_math_get_constant
-hb_ot_math_get_glyph_italics_correction
-hb_ot_math_get_glyph_top_accent_attachment
-hb_ot_math_get_glyph_kerning
-hb_ot_math_is_glyph_extended_shape
-hb_ot_math_get_glyph_variants
-hb_ot_math_get_min_connector_overlap
-hb_ot_math_get_glyph_assembly
-
-
-Overview of changes leading to 1.3.2
-Wednesday, September 27, 2016
-====================================
-
-- Fix build of hb-coretext on older OS X versions.
-
-
-Overview of changes leading to 1.3.1
-Wednesday, September 7, 2016
-====================================
-
-- Blacklist bad GDEF of more fonts (Padauk).
-- More CoreText backend crash fixes with OS X 10.9.5.
-- Misc fixes.
-
-
-Overview of changes leading to 1.3.0
-Thursday, July 21, 2016
-====================================
-
-- Update to Unicode 9.0.0
-- Move Javanese from Indic shaper to Universal Shaping Engine.
-- Allow MultipleSubst to delete a glyph (matching Windows engine).
-- Update Universal Shaping Engine to latest draft from Microsoft.
-- DirectWrite backend improvements.  Note: this backend is for testing ONLY.
-- CoreText backend improvements with unreachable fonts.
-- Implement symbol fonts (cmap 3.0.0) in hb-ft and hb-ot-font.
-- Blacklist bad GDEF of more fonts (Tahoma & others).
-- Misc fixes.
-
-
-Overview of changes leading to 1.2.7
-Monday, May 2, 2016
-====================================
-
-- Blacklist another version of Times New Roman (Bold) Italic from Windows 7.
-- Fix Mongolian Free Variation Selectors shaping with certain fonts.
-- Fix Tibetan shorthand contractions shaping.
-- Improved list of language tag mappings.
-- Unbreak build on Windows CE.
-- Make 'glyf' table loading lazy in hb-ot-font.
-
-
-Overview of changes leading to 1.2.6
-Friday, April 8, 2016
-====================================
-
-- Blacklist GDEF table of another set of Times New Roman (Bold) Italic.
-- DirectWrite backend improvements.  Note: DirectWrite backend is
-  exclusively for our internal testing and should NOT be used in any
-  production system whatsoever.
-
-
-Overview of changes leading to 1.2.5
-Monday, April 4, 2016
-====================================
-
-- Fix GDEF mark-filtering-set, which was broken in 1.2.3.
-
-
-Overview of changes leading to 1.2.4
-Thursday, March 17, 2016
-====================================
-
-- Synthesize GDEF glyph class for any glyph that does not have one in GDEF.
-  I really hope we don't discover broken fonts that shape badly with this
-  change.
-- Misc build and other minor fixes.
-- API changes:
-  - Added HB_NDEBUG.  It's fine for production systems to define this to
-    disable high-overhead debugging checks.  However, I also reduced the
-    overhead of those checks, so it's a non-issue right now.  You can
-    forget it.  Just not defining anything at all is fine.
-
-
-Overview of changes leading to 1.2.3
-Thursday, February 25, 2016
-====================================
-
-- Blacklist GDEF table of certain versions of Times New Roman (Bold) Italic,
-  due to bug in glyph class of ASCII double-quote character.  This should
-  address "regression" introduced in 1.2.0 when we switched mark zeroing
-  in most shapers from BY_UNICODE_LATE to BY_GDEF_LATE.
-  This fourth release in a week should finally stablize things...
-
-- hb-ot-font's get_glyph() implementation saw some optimizations.  Though,
-  might be really hard to measure in real-world situations.
-
-- Also, two rather small API changes:
-
-We now disable some time-consuming internal bookkeeping if built with NDEBUG
-defined.  This is a first time that we use NDEBUG to disable debug code.  If
-there exist production systems that do NOT want to enable NDEBUG, please let
-me know and I'll add HB_NDEBUG.
-
-Added get_nominal_glyph() and get_variation_glyph() instead of get_glyph()
-
-New API:
-- hb_font_get_nominal_glyph_func_t
-- hb_font_get_variation_glyph_func_t
-- hb_font_funcs_set_nominal_glyph_func()
-- hb_font_funcs_set_variation_glyph_func()
-- hb_font_get_nominal_glyph()
-- hb_font_get_variation_glyph()
-
-Deprecated API:
-- hb_font_get_glyph_func_t
-- hb_font_funcs_set_glyph_func()
-
-Clients that implement their own font-funcs are encouraged to replace
-their get_glyph() implementation with a get_nominal_glyph() and
-get_variation_glyph() pair.  The variation version can assume that
-variation_selector argument is not zero.  Old (deprecated) functions
-will continue working indefinitely using internal gymnastics; it is
-just more efficient to use the new functions.
-
-
-Overview of changes leading to 1.2.2
-Wednesday, February 24, 2016
-====================================
-
-- Fix regression with mark positioning with fonts that have
-  non-zero mark advances.  This was introduced in 1.2.0 while
-  trying to make mark and cursive attachments to work together.
-  I have partially reverted that, so this version is much more
-  like what we had before.  All clients who updated to 1.2.0
-  should update to this version.
-
-
-Overview of changes leading to 1.2.1
-Tuesday, February 23, 2016
-====================================
-
-- CoreText: Fix bug with wrong scale if font scale was changed later.
-  https://github.com/libass/libass/issues/212
-- CoreText: Drastically speed up font initialization.
-- CoreText: Fix tiny leak.
-- Group ZWJ/ZWNJ with previous syllable under cluster-level=0.
-  https://github.com/harfbuzz/harfbuzz/issues/217
-- Add test/shaping/README.md about how to add tests to the suite.
-
-
-Overview of changes leading to 1.2.0
-Friday, February 19, 2016
-====================================
-
-- Fix various issues (hangs mostly) in case of memory allocation failure.
-- Change mark zeroing types of most shapers from BY_UNICODE_LATE to
-  BY_GDEF_LATE.  This seems to be what Uniscribe does.
-- Change mark zeroing of USE shaper from NONE to BY_GDEF_EARLY.  That's
-  what Windows does.
-- Allow GPOS cursive connection on marks, and fix the interaction with
-  mark attachment.  This work resulted in some changes to how mark
-  attachments work.  See:
-  https://github.com/harfbuzz/harfbuzz/issues/211
-  https://github.com/harfbuzz/harfbuzz/commit/86c68c7a2c971efe8e35b1f1bd99401dc8b688d2
-- Graphite2 shaper: improved negative advance handling (eg. Nastaliq).
-- Add nmake-based build system for Windows.
-- Minor speedup.
-- Misc. improvements.
-
-
-Overview of changes leading to 1.1.3
-Monday, January 11, 2016
-====================================
-
-- Ported Indic shaper to Unicode 8.0 data.
-- Universal Shaping Engine fixes.
-- Speed up CoreText shaper when font fallback happens in CoreText.
-- Documentation improvements, thanks to Khaled Hosny.
-- Very rough directwrite shaper for testing, thanks to Ebrahim Byagowi.
-- Misc bug fixes.
-- New API:
-
-  * Font extents:
-      hb_font_extents_t
-      hb_font_get_font_extents_func_t
-      hb_font_get_font_h_extents_func_t
-      hb_font_get_font_v_extents_func_t
-      hb_font_funcs_set_font_h_extents_func
-      hb_font_funcs_set_font_v_extents_func
-      hb_font_get_h_extents
-      hb_font_get_v_extents
-      hb_font_get_extents_for_direction
-
-  * Buffer message (aka debug):
-      hb_buffer_message_func_t
-      hb_buffer_set_message_func()
-    Actual message protocol to be fleshed out later.
-
-
-Overview of changes leading to 1.1.2
-Wednesday, November 26, 2015
-====================================
-
-- Fix badly-broken fallback shaper that affected terminology.
-  https://github.com/harfbuzz/harfbuzz/issues/187
-- Fix y_scaling in Graphite shaper.
-- API changes:
-  * An unset glyph_h_origin() function in font-funcs now (sensibly)
-    implies horizontal origin at 0,0.  Ie, the nil callback returns
-    true instead of false.  As such, implementations that have a
-    glyph_h_origin() that simply returns true, can remove that function
-    with HarfBuzz >= 1.1.2.  This results in a tiny speedup.
-
-
-Overview of changes leading to 1.1.1
-Wednesday, November 24, 2015
-====================================
-
-- Build fixes, specially for hb-coretext.
-
-
-Overview of changes leading to 1.1.0
-Wednesday, November 18, 2015
-====================================
-
-- Implement 'stch' stretch feature for Syriac Abbreviation Mark.
-  https://github.com/harfbuzz/harfbuzz/issues/141
-- Disable use of decompose_compatibility() callback.
-- Implement "shaping" of various Unicode space characters, even
-  if the font does not support them.
-  https://github.com/harfbuzz/harfbuzz/issues/153
-- If font does not support U+2011 NO-BREAK HYPHEN, fallback to
-  U+2010 HYPHEN.
-- Changes resulting from libFuzzer continuous fuzzing:
-  * Reject font tables that need more than 8 edits,
-  * Bound buffer growth during shaping to 32x,
-  * Fix assertions and other issues at OOM / buffer max-growth.
-- Misc fixes and optimizations.
-- API changes:
-  * All fonts created with hb_font_create() now inherit from
-    (ie. have parent) hb_font_get_empty().
-
-
-Overview of changes leading to 1.0.6
-Thursday, October 15, 2015
-====================================
-
-- Reduce max nesting level in OT lookups from 8 to 6.
-  Should not affect any real font as far as I know.
-- Fix memory access issue in ot-font.
-- Revert default load-flags of fonts created using hb_ft_font_create()
-  back to FT_LOAD_DEFAULT|FT_LOAD_NO_HINTING.  This was changed in
-  last release (1.0.5), but caused major issues, so revert.
-  https://github.com/harfbuzz/harfbuzz/issues/143
-
-
-Overview of changes leading to 1.0.5
-Tuesday, October 13, 2015
-====================================
-
-- Fix multiple memory access bugs discovered using libFuzzer.
-  https://github.com/harfbuzz/harfbuzz/issues/139
-  Everyone should upgrade to this version as soon as possible.
-  We now have continuous fuzzing set up, to avoid issues like
-  these creeping in again.
-- Misc fixes.
-
-- New API:
-  * hb_font_set_parent().
-  * hb_ft_font_[sg]et_load_flags()
-    The default flags for fonts created using hb_ft_font_create()
-    has changed to default to FT_LOAD_DEFAULT now.  Previously it
-    was defaulting to FT_LOAD_DFEAULT|FT_LOAD_NO_HINTING.
-
-- API changes:
-  * Fonts now default to units-per-EM as their scale, instead of 0.
-  * hb_font_create_sub_font() does NOT make parent font immutable
-    anymore.  hb_font_make_immutable() does.
-
-
-Overview of changes leading to 1.0.4
-Wednesday, September 30, 2015
-====================================
-
-- Fix minor out-of-bounds read error.
-
-
-Overview of changes leading to 1.0.3
-Tuesday, September 1, 2015
-====================================
-
-- Start of user documentation, from Simon Cozens!
-- Implement glyph_extents() for TrueType fonts in hb-ot-font.
-- Improve GPOS cursive attachments with conflicting lookups.
-- More fixes for cluster-level = 1.
-- Uniscribe positioning fix.
-
-
-Overview of changes leading to 1.0.2
-Wednesday, August 19, 2015
-====================================
-
-- Fix shaping with cluster-level > 0.
-- Fix Uniscribe backend font-size scaling.
-- Declare dependencies in harfbuzz.pc.
-  FreeType is not declared though, to avoid bugs in pkg-config
-  0.26 with recursive dependencies.
-- Slightly improved debug infrastructure.  More to come later.
-- Misc build fixes.
-
-
-Overview of changes leading to 1.0.1
-Monday, July 27, 2015
-====================================
-
-- Fix out-of-bounds access in USE shaper.
-
-
-Overview of changes leading to 1.0.0
-Sunday, July 26, 2015
-====================================
-
-- Implement Universal Shaping Engine:
-  https://www.microsoft.com/typography/OpenTypeDev/USE/intro.htm
-  http://blogs.windows.com/bloggingwindows/2015/02/23/windows-shapes-the-worlds-languages/
-- Bump version to 1.0.0.  The soname was NOT bumped.
-
-
-Overview of changes leading to 0.9.42
-Thursday, July 26, 2015
-=====================================
-
-- New API to allow for retrieving finer-grained cluster
-  mappings if the client desires to handle them.  Default
-  behavior is unchanged.
-- Fix cluster merging when removing default-ignorables.
-- Update to Unicode 8.0
-- hb-graphite2 fixes.
-- Misc fixes.
-- Removed HB_NO_MERGE_CLUSTERS hack.
-- New API:
-  hb_buffer_cluster_level_t enum
-  hb_buffer_get_cluster_level()
-  hb_buffer_set_cluster_level()
-  hb-shape / hb-view --cluster-level
-
-
-Overview of changes leading to 0.9.41
-Thursday, June 18, 2015
-=====================================
-
-- Fix hb-coretext with trailing whitespace in right-to-left.
-- New API: hb_buffer_reverse_range().
-- Allow implementing atomic ops in config.h.
-- Fix hb_language_t in language bindings.
-- Misc fixes.
-
-
-Overview of changes leading to 0.9.40
-Friday, March 20, 2015
-=====================================
-
-- Another hb-coretext crasher fix.  Ouch!
-- Happy Norouz!
-
-
-Overview of changes leading to 0.9.39
-Wednesday, March 4, 2015
-=====================================
-
-- Critical hb-coretext fixes.
-- Optimizations and refactoring; no functional change
-  expected.
-- Misc build fixes.
-
-
-Overview of changes leading to 0.9.38
-Friday, January 23, 2015
-=====================================
-
-- Fix minor out-of-bounds access in Indic shaper.
-- Change New Tai Lue shaping engine from South-East Asian to default,
-  reflecting change in Unicode encoding model.
-- Add hb-shape --font-size.  Can take up to two numbers for separate
-  x / y size.
-- Fix CoreText and FreeType scale issues with negative scales.
-- Reject blobs larger than 2GB.  This might break some icu-le-hb clients
-  that need security fixes.  See:
-  http://www.icu-project.org/trac/ticket/11450
-- Avoid accessing font tables during face destruction, in casce rogue
-  clients released face data already.
-- Fix up gobject-introspection a bit.  Python bindings kinda working.
-  See README.python.
-- Misc fixes.
-- API additions:
-  hb_ft_face_create_referenced()
-  hb_ft_font_create_referenced()
-
-
-Overview of changes leading to 0.9.37
-Wednesday, December 17, 2014
-=====================================
-
-- Fix out-of-bounds access in Context lookup format 3.
-- Indic: Allow ZWJ/ZWNJ before syllable modifiers.
-
-
-Overview of changes leading to 0.9.36
-Thursday, November 20, 2014
-=====================================
-
-- First time that three months went by without a release since
-  0.9.2 was released on August 10, 2012!
-- Fix performance bug in hb_ot_collect_glyphs():
-  https://bugzilla.mozilla.org/show_bug.cgi?id=1090869
-- Add basic vertical-text support to hb-ot-font.
-- Misc build fixes.
-
-
-Overview of changes leading to 0.9.35
-Saturday, August 13, 2014
-=====================================
-
-- Fix major shape-plan caching bug when more than one shaper were
-  provided to hb_shape_full() (as exercised by XeTeX).
-  http://www.mail-archive.com/[email protected]/msg1246370.html
-- Fix Arabic fallback shaping regression.  This was broken in 0.9.32.
-- Major hb-coretext fixes.  That backend is complete now, including
-  respecing buffer direction and language, down to vertical writing.
-- Build fixes for Windows CE.  Should build fine now.
-- Misc fixes:
-  Use atexit() only if it's safe to call from shared library
-  https://bugs.freedesktop.org/show_bug.cgi?id=82246
-  Mandaic had errors in its Unicode Joining_Type
-  https://bugs.freedesktop.org/show_bug.cgi?id=82306
-- API changes:
-
-  * hb_buffer_clear_contents() does not reset buffer flags now.
-
-    After 763e5466c0a03a7c27020e1e2598e488612529a7, one doesn't
-    need to set flags for different pieces of text.  The flags now
-    are something the client sets up once, depending on how it
-    actually uses the buffer.  As such, don't clear it in
-    clear_contents().
-
-    I don't expect any changes to be needed to any existing client.
-
-
-Overview of changes leading to 0.9.34
-Saturday, August 2, 2014
-=====================================
-
-- hb_feature_from_string() now accepts CSS font-feature-settings format.
-- As a result, hb-shape / hb-view --features also accept CSS-style strings.
-  Eg, "'liga' off" is accepted now.
-- Add old-spec Myanmar shaper:
-  https://bugs.freedesktop.org/show_bug.cgi?id=81775
-- Don't apply 'calt' in Hangul shaper.
-- Fix mark advance zeroing for Hebrew shaper:
-  https://bugs.freedesktop.org/show_bug.cgi?id=76767
-- Implement Windows-1256 custom Arabic shaping.  Only built on Windows,
-  and requires help from get_glyph().  Used by Firefox.
-  https://bugzilla.mozilla.org/show_bug.cgi?id=1045139
-- Disable 'liga' in vertical text.
-- Build fixes.
-- API changes:
-
-  * Make HB_BUFFER_FLAG_BOT/EOT easier to use.
-
-    Previously, we expected users to provide BOT/EOT flags when the
-    text *segment* was at paragraph boundaries.  This meant that for
-    clients that provide full paragraph to HarfBuzz (eg. Pango), they
-    had code like this:
-
-      hb_buffer_set_flags (hb_buffer,
-                           (item_offset == 0 ? HB_BUFFER_FLAG_BOT : 0) |
-                           (item_offset + item_length == paragraph_length ?
-                            HB_BUFFER_FLAG_EOT : 0));
-
-      hb_buffer_add_utf8 (hb_buffer,
-                          paragraph_text, paragraph_length,
-                          item_offset, item_length);
-
-    After this change such clients can simply say:
-
-      hb_buffer_set_flags (hb_buffer,
-                           HB_BUFFER_FLAG_BOT | HB_BUFFER_FLAG_EOT);
-
-      hb_buffer_add_utf8 (hb_buffer,
-                          paragraph_text, paragraph_length,
-                          item_offset, item_length);
-
-    Ie, HarfBuzz itself checks whether the segment is at the beginning/end
-    of the paragraph.  Clients that only pass item-at-a-time to HarfBuzz
-    continue not setting any flags whatsoever.
-
-    Another way to put it is: if there's pre-context text in the buffer,
-    HarfBuzz ignores the BOT flag.  If there's post-context, it ignores
-    EOT flag.
-
-
-Overview of changes leading to 0.9.33
-Tuesday, July 22, 2014
-=====================================
-
-- Turn off ARabic 'cswh' feature that was accidentally turned on.
-- Add HB_TAG_MAX_SIGNED.
-- Make hb_face_make_immutable() really make face immutable!
-- Windows build fixes.
-
-
-Overview of changes leading to 0.9.32
-Thursday, July 17, 2014
-=====================================
-
-- Apply Arabic shaping features in spec order exactly.
-- Another fix for Mongolian free variation selectors.
-- For non-Arabic scripts in Arabic shaper apply 'rlig' and 'calt'
-  together.
-- Minor adjustment to U+FFFD logic.
-- Fix hb-coretext build.
-
-
-Overview of changes leading to 0.9.31
-Wednesday, July 16, 2014
-=====================================
-
-- Only accept valid UTF-8/16/32; we missed many cases before.
-- Better shaping of invalid UTF-8/16/32.  Falls back to
-  U+FFFD REPLACEMENT CHARACTER now.
-- With all changes in this release, the buffer will contain fully
-  valid Unicode after hb_buffer_add_utf8/16/32 no matter how
-  broken the input is.  This can be overridden though.  See below.
-- Fix Mongolian Variation Selectors for fonts without GDEF.
-- Fix minor invalid buffer access.
-- Accept zh-Hant and zh-Hans language tags.  hb_ot_tag_to_language()
-  now uses these instead of private tags.
-- Build fixes.
-- New API:
-  * hb_buffer_add_codepoints().  This does what hb_buffer_add_utf32()
-    used to do, ie. no validity check on the input at all.  add_utf32
-    now replaces invalid Unicode codepoints with the replacement
-    character (see below).
-  * hb_buffer_set_replacement_codepoint()
-  * hb_buffer_get_replacement_codepoint()
-    Previously, in hb_buffer_add_utf8 and hb_buffer_add_utf16, when
-    we detected broken input, we replaced that with (hb_codepoint_t)-1.
-    This has changed to use U+FFFD now, but can be changed using these
-    new API.
-
-
-Overview of changes leading to 0.9.30
-Wednesday, July 9, 2014
-=====================================
-
-- Update to Unicode 7.0.0:
-  * New scripts Manichaean and Psalter Pahlavi are shaped using
-    Arabic shaper.
-  * All the other new scripts to through the generic shaper for
-    now.
-- Minor Indic improvements.
-- Fix graphite2 backend cluster mapping [crasher!]
-- API changes:
-  * New HB_SCRIPT_* values for Unicode 7.0 scripts.
-  * New function hb_ot_layout_language_get_required_feature().
-- Build fixes.
-
-
-Overview of changes leading to 0.9.29
-Thursday, May 29, 2014
-=====================================
-
-- Implement cmap in hb-ot-font.h.  No variation-selectors yet.
-- Myanmar: Allow MedialYa+Asat.
-- Various Indic fixes:
-  * Support most characters in Extended Devanagary and Vedic
-    Unicode blocks.
-  * Allow digits and a some punctuation as consonant placeholders.
-- Build fixes.
-
-
-Overview of changes leading to 0.9.28
-Monday, April 28, 2014
-=====================================
-
-- Unbreak old-spec Indic shaping. (bug 76705)
-- Fix shaping of U+17DD and U+0FC6.
-- Add HB_NO_MERGE_CLUSTERS build option.  NOT to be enabled by default
-  for shipping libraries.  It's an option for further experimentation
-  right now.  When we are sure how to do it properly, we will add
-  public run-time API for the functionality.
-- Build fixes.
-
-
-Overview of changes leading to 0.9.27
-Tuesday, March 18, 2014
-=====================================
-
-- Don't use "register" storage class specifier
-- Wrap definition of free_langs() with HAVE_ATEXIT
-- Add coretext_aat shaper and hb_coretext_face_create() constructor
-- If HAVE_ICU_BUILTIN is defined, use hb-icu Unicode callbacks
-- Add Myanmar test case from OpenType Myanmar spec
-- Only do fallback Hebrew composition if no GPOS 'mark' available
-- Allow bootstrapping without gtk-doc
-- Use AM_MISSING_PROG for ragel and git
-- Typo in ucdn's Makefile.am
-- Improve MemoryBarrier() implementation
-
-
-Overview of changes leading to 0.9.26
-Thursday, January 30, 2014
-=====================================
-
-- Misc fixes.
-- Fix application of 'rtlm' feature.
-- Automatically apply frac/numr/dnom around U+2044 FRACTION SLASH.
-- New header: hb-ot-shape.h
-- Uniscribe: fix scratch-buffer accounting.
-- Reorder Tai Tham SAKOT to after tone-marks.
-- Add Hangul shaper.
-- New files:
-  hb-ot-shape-complex-hangul.cc
-  hb-ot-shape-complex-hebrew.cc
-  hb-ot-shape-complex-tibetan.cc
-- Disable 'cswh' feature in Arabic shaper.
-- Coretext: better handle surrogate pairs.
-- Add HB_TAG_MAX and _HB_SCRIPT_MAX_VALUE.
-
-
-Overview of changes leading to 0.9.25
-Wednesday, December 4, 2013
-=====================================
-
-- Myanmar shaper improvements.
-- Avoid font fallback in CoreText backend.
-- Additional OpenType language tag mappiongs.
-- More aggressive shape-plan caching.
-- Build with / require automake 1.13.
-- Build with libtool 2.4.2.418 alpha to support ppc64le.
-
-
-Overview of changes leading to 0.9.24
-Tuesday, November 13, 2013
-=====================================
-
-- Misc compiler warning fixes with clang.
-- No functional changes.
-
-
-Overview of changes leading to 0.9.23
-Monday, October 28, 2013
-=====================================
-
-- "Udupi HarfBuzz Hackfest", Paris, October 14..18 2013.
-- Fix (Chain)Context recursion with non-monotone lookup positions.
-- Misc Indic bug fixes.
-- New Javanese / Buginese shaping, similar to Windows 8.1.
-
-
-Overview of changes leading to 0.9.22
-Thursday, October 3, 2013
-=====================================
-
-- Fix use-after-end-of-scope in hb_language_from_string().
-- Fix hiding of default_ignorables if font doesn't have space glyph.
-- Protect against out-of-range lookup indices.
-
-- API Changes:
-
-  * Added hb_ot_layout_table_get_lookup_count()
-
-
-Overview of changes leading to 0.9.21
-Monday, September 16, 2013
-=====================================
-
-- Rename gobject-introspection library name from harfbuzz to HarfBuzz.
-- Remove (long disabled) hb-old and hb-icu-le test shapers.
-- Misc gtk-doc and gobject-introspection annotations.
-- Misc fixes.
-- API changes:
-
-  * Add HB_SET_VALUE_INVALID
-
-Overview of changes leading to 0.9.20
-Thursday, August 29, 2013
-=====================================
-
-General:
-- Misc substitute_closure() fixes.
-- Build fixes.
-
-Documentation:
-- gtk-doc boilerplate integrated.  Docs are built now, but
-  contain no contents.  By next release hopefully we have
-  some content in.  Enable using --enable-gtk-doc.
-
-GObject and Introspection:
-- Added harfbuzz-gobject library (hb-gobject.h) that has type
-  bindings for all HarfBuzz objects and enums.  Enable using
-  --with-gobject.
-- Added gobject-introspection boilerplate.  Nothing useful
-  right now.  Work in progress.  Gets enabled automatically if
-  --with-gobject is used.  Override with --disable-introspection.
-
-OpenType shaper:
-- Apply 'mark' in Myanmar shaper.
-- Don't apply 'dlig' by default.
-
-Uniscribe shaper:
-- Support user features.
-- Fix loading of fonts that are also installed on the system.
-- Fix shaping of Arabic Presentation Forms.
-- Fix build with wide chars.
-
-CoreText shaper:
-- Support user features.
-
-Source changes:
-- hb_face_t code moved to hb-face.h / hb-face.cc.
-- Added hb-deprecated.h.
-
-API changes:
-- Added HB_DISABLE_DEPRECATED.
-- Deprecated HB_SCRIPT_CANADIAN_ABORIGINAL; replaced by
-  HB_SCRIPT_CANADIAN_SYLLABICS.
-- Deprecated HB_BUFFER_FLAGS_DEFAULT; replaced by
-  HB_BUFFER_FLAG_DEFAULT.
-- Deprecated HB_BUFFER_SERIALIZE_FLAGS_DEFAULT; replaced by
-  HB_BUFFER_SERIALIZE_FLAG_DEFAULT.
-
-
-Overview of changes leading to 0.9.19
-Tuesday, July 16, 2013
-=====================================
-
-- Build fixes.
-- Better handling of multiple variation selectors in a row.
-- Pass on variation selector to GSUB if not consumed by cmap.
-- Fix undefined memory access.
-- Add Javanese config to Indic shaper.
-- Misc bug fixes.
-
-Overview of changes leading to 0.9.18
-Tuesday, May 28, 2013
-=====================================
-
-New build system:
-
-- All unneeded code is all disabled by default,
-
-- Uniscribe and CoreText shapers can be enabled with their --with options,
-
-- icu_le and old shapers cannot be enabled for now,
-
-- glib, freetype, and cairo will be detected automatically.
-  They can be force on/off'ed with their --with options,
-
-- icu and graphite2 are default off, can be enabled with their --with
-  options,
-
-Moreover, ICU support is now build into a separate library:
-libharfbuzz-icu.so, and a new harfbuzz-icu.pc is shipped for it.
-Distros can enable ICU now without every application on earth
-getting linked to via libharfbuzz.so.
-
-For distros I recommend that they make sure they are building --with-glib
---with-freetype --with-cairo, --with-icu, and optionally --with-graphite2;
-And package harfbuzz and harfbuzz-icu separately.
-
-
-Overview of changes leading to 0.9.17
-Monday, May 20, 2013
-=====================================
-
-- Build fixes.
-- Fix bug in hb_set_get_min().
-- Fix regression with Arabic mark positioning / width-zeroing.
-
-Overview of changes leading to 0.9.16
-Friday, April 19, 2013
-=====================================
-
-- Major speedup in OpenType lookup processing.  With the Amiri
-  Arabic font, this release is over 3x faster than previous
-  release.  All scripts / languages should see this speedup.
-
-- New --num-iterations option for hb-shape / hb-view; useful for
-  profiling.
-
-Overview of changes leading to 0.9.15
-Friday, April 05, 2013
-=====================================
-
-- Build fixes.
-- Fix crasher in graphite2 shaper.
-- Fix Arabic mark width zeroing regression.
-- Don't compose Hangul jamo into Unicode syllables.
-
-
-Overview of changes leading to 0.9.14
-Thursday, March 21, 2013
-=====================================
-
-- Build fixes.
-- Fix time-consuming sanitize with malicious fonts.
-- Implement hb_buffer_deserialize_glyphs() for both json and text.
-- Do not ignore Hangul filler characters.
-- Indic fixes:
-  * Fix Malayalam pre-base reordering interaction with post-forms.
-  * Further adjust ZWJ handling.  Should fix known regressions from
-    0.9.13.
-
-
-Overview of changes leading to 0.9.13
-Thursday, February 25, 2013
-=====================================
-
-- Build fixes.
-- Ngapi HarfBuzz Hackfest in London (February 2013):
-  * Fixed all known Indic bugs,
-  * New Win8-style Myanmar shaper,
-  * New South-East Asian shaper for Tai Tham, Cham, and New Tai Lue,
-  * Smartly ignore Default_Ignorable characters (joiners, etc) wheb
-    matching GSUB/GPOS lookups,
-  * Fix 'Phags-Pa U+A872 shaping,
-  * Fix partial disabling of default-on features,
-  * Allow disabling of TrueType kerning.
-- Fix possible crasher with broken fonts with overlapping tables.
-- Removed generated files from git again.  So, one needs ragel to
-  bootstrap from the git tree.
-
-API changes:
-- hb_shape() and related APIs now abort if buffer direction is
-  HB_DIRECTION_INVALID.  Previously, hb_shape() was calling
-  hb_buffer_guess_segment_properties() on the buffer before
-  shaping.  The heuristics in that function are fragile.  If the
-  user really wants the old behvaior, they can call that function
-  right before calling hb_shape() to get the old behavior.
-- hb_blob_create_sub_blob() always creates sub-blob with
-  HB_MEMORY_MODE_READONLY.  See comments for the reason.
-
-
-Overview of changes leading to 0.9.12
-Thursday, January 18, 2013
-=====================================
-
-- Build fixes for Sun compiler.
-- Minor bug fix.
-
-Overview of changes leading to 0.9.11
-Thursday, January 10, 2013
-=====================================
-
-- Build fixes.
-- Fix GPOS mark attachment with null Anchor offsets.
-- [Indic] Fix old-spec reordering of viramas if sequence ends in one.
-- Fix multi-threaded shaper data creation crash.
-- Add atomic ops for Solaris.
-
-API changes:
-- Rename hb_buffer_clear() to hb_buffer_clear_contents().
-
-
-Overview of changes leading to 0.9.10
-Thursday, January 3, 2013
-=====================================
-
-- [Indic] Fixed rendering of Malayalam dot-reph
-- Updated OT language tags.
-- Updated graphite2 backend.
-- Improved hb_ot_layout_get_size_params() logic.
-- Improve hb-shape/hb-view help output.
-- Fixed hb-set.h implementation to not crash.
-- Fixed various issues with hb_ot_layout_collect_lookups().
-- Various build fixes.
-
-New API:
-
-hb_graphite2_face_get_gr_face()
-hb_graphite2_font_get_gr_font()
-hb_coretext_face_get_cg_font()
-
-Modified API:
-
-hb_ot_layout_get_size_params()
-
-
-Overview of changes leading to 0.9.9
-Wednesday, December 5, 2012
-====================================
-
-- Fix build on Windows.
-- Minor improvements.
-
-
-Overview of changes leading to 0.9.8
-Tuesday, December 4, 2012
-====================================
-
-
-- Actually implement hb_shape_plan_get_shaper ().
-- Make UCDB data tables const.
-- Lots of internal refactoring in OTLayout tables.
-- Flesh out hb_ot_layout_lookup_collect_glyphs().
-
-New API:
-
-hb_ot_layout_collect_lookups()
-hb_ot_layout_get_size_params()
-
-
-Overview of changes leading to 0.9.7
-Sunday, November 21, 2012
-====================================
-
-
-HarfBuzz "All-You-Can-Eat-Sushi" (aka Vancouver) Hackfest and follow-on fixes.
-
-- Fix Arabic contextual joining using pre-context text.
-- Fix Sinhala "split matra" mess.
-- Fix Khmer shaping with broken fonts.
-- Implement Thai "PUA" shaping for old fonts.
-- Do NOT route Kharoshthi script through the Indic shaper.
-- Disable fallback positioning for Indic and Thai shapers.
-- Misc fixes.
-
-
-hb-shape / hb-view changes:
-
-- Add --text-before and --text-after
-- Add --bot / --eot / --preserve-default-ignorables
-- hb-shape --output-format=json
-
-
-New API:
-
-hb_buffer_clear()
-
-hb_buffer_flags_t
-
-HB_BUFFER_FLAGS_DEFAULT
-HB_BUFFER_FLAG_BOT
-HB_BUFFER_FLAG_EOT
-HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES
-
-hb_buffer_set_flags()
-hb_buffer_get_flags()
-
-HB_BUFFER_SERIALIZE_FLAGS
-hb_buffer_serialize_glyphs()
-hb_buffer_deserialize_glyphs()
-hb_buffer_serialize_list_formats()
-
-hb_set_add_range()
-hb_set_del_range()
-hb_set_get_population()
-hb_set_next_range()
-
-hb_face_[sg]et_glyph_count()
-
-hb_segment_properties_t
-HB_SEGMENT_PROPERTIES_DEFAULT
-hb_segment_properties_equal()
-hb_segment_properties_hash()
-
-hb_buffer_set_segment_properties()
-hb_buffer_get_segment_properties()
-
-hb_ot_layout_glyph_class_t
-hb_ot_layout_get_glyph_class()
-hb_ot_layout_get_glyphs_in_class()
-
-hb_shape_plan_t
-hb_shape_plan_create()
-hb_shape_plan_create_cached()
-hb_shape_plan_get_empty()
-hb_shape_plan_reference()
-hb_shape_plan_destroy()
-hb_shape_plan_set_user_data()
-hb_shape_plan_get_user_data()
-hb_shape_plan_execute()
-hb_shape_plan_get_shaper()
-
-hb_ot_shape_plan_collect_lookups()
-
-
-API changes:
-
-- Remove "mask" parameter from hb_buffer_add().
-- Rename hb_ot_layout_would_substitute_lookup() and hb_ot_layout_substitute_closure_lookup().
-- hb-set.h API const correction.
-- Renamed hb_set_min/max() to hb_set_get_min/max().
-- Rename hb_ot_layout_feature_get_lookup_indexes() to hb_ot_layout_feature_get_lookups().
-- Rename hb_buffer_guess_properties() to hb_buffer_guess_segment_properties().
-
-
-
-Overview of changes leading to 0.9.6
-Sunday, November 13, 2012
-====================================
-
-- Don't clear pre-context text if no new context is provided.
-- Fix ReverseChainingSubstLookup, which was totally borked.
-- Adjust output format of hb-shape a bit.
-- Include config.h.in in-tree.  Makes it easier for alternate build systems.
-- Fix hb_buffer_set_length(buffer, 0) invalid memory allocation.
-- Use ICU LayoutEngine's C API instead of C++.  Avoids much headache.
-- Drop glyphs for all of Unicode Default_Ignorable characters.
-- Misc build fixes.
-
-Arabic shaper:
-- Enable 'dlig' and 'mset' features in Arabic shaper.
-- Implement 'Phags-pa shaping, improve Mongolian.
-
-Indic shaper:
-- Decompose Sinhala split matras the way old HarfBuzz / Pango did.
-- Initial support for Consonant Medials.
-- Start adding new-style Myanmar shaping.
-- Make reph and 'pref' logic introspect the font.
-- Route Meetei-Mayek through the Indic shaper.
-- Don't apply 'liga' in Indic shaper.
-- Improve Malayalam pre-base reordering Ra interaction with Chillus.
-
-
-
-Overview of changes leading to 0.9.5
-Sunday, October 14, 2012
-====================================
-
-- Synthetic-GSUB Arabic fallback shaping.
-
-- Misc Indic improvements.
-
-- Add build system support for pthread.
-
-- Imported UCDN for in-tree Unicode callbacks implementation.
-
-- Context-aware Arabic joining.
-
-- Misc other fixes.
-
-- New API:
-
-  hb_feature_to/from-string()
-  hb_buffer_[sg]et_content_type()
-
-
-
-Overview of changes leading to 0.9.4
-Tuesday, Sep 03, 2012
-====================================
-
-- Indic improvements with old-spec Malayalam.
-
-- Better fallback glyph positioning, specially with Thai / Lao marks.
-
-- Implement dotted-circle insertion.
-
-- Better Arabic fallback shaping / ligation.
-
-- Added ICU LayoutEngine backend for testing.  Call it by the 'icu_le' name.
-
-- Misc fixes.
-
-
-
-Overview of changes leading to 0.9.3
-Friday, Aug 18, 2012
-====================================
-
-- Fixed fallback mark positioning for left-to-right text.
-
-- Improve mark positioning for the remaining combining classes.
-
-- Unbreak Thai and fallback Arabic shaping.
-
-- Port Arabic shaper to shape-plan caching.
-
-- Use new ICU normalizer functions.
-
-
-
-Overview of changes leading to 0.9.2
-Friday, Aug 10, 2012
-====================================
-
-- Over a thousand commits!  This is the first major release of HarfBuzz.
-
-- HarfBuzz is feature-complete now!  It should be in par, or better, than
-  both Pango's shapers and old HarfBuzz / Qt shapers.
-
-- New Indic shaper, supporting main Indic scripts, Sinhala, and Khmer.
-
-- Improved Arabic shaper, with fallback Arabic shaping, supporting Arabic,
-  Sinhala, N'ko, Mongolian, and Mandaic.
-
-- New Thai / Lao shaper.
-
-- Tibetan / Hangul support in the generic shaper.
-
-- Synthetic GDEF support for fonts without a GDEF table.
-
-- Fallback mark positioning for fonts without a GPOS table.
-
-- Unicode normalization shaping heuristic during glyph mapping.
-
-- New experimental Graphite2 backend.
-
-- New Uniscribe backend (primarily for testing).
-
-- New CoreText backend (primarily for testing).
-
-- Major optimization and speedup.
-
-- Test suites and testing infrastructure (work in progress).
-
-- Greatly improved hb-view cmdline tool.
-
-- hb-shape cmdline tool.
-
-- Unicode 6.1 support.
-
-Summary of API changes:
-
-o Changed API:
-
-  - Users are expected to only include main header files now (ie. hb.h,
-    hb-glib.h, hb-ft.h, ...)
-
-  - All struct tag names had their initial underscore removed.
-    Ie. "struct _hb_buffer_t" is "struct hb_buffer_t" now.
-
-  - All set_user_data() functions now take a "replace" boolean parameter.
-
-  - hb_buffer_create() takes zero arguments now.
-    Use hb_buffer_pre_allocate() to pre-allocate.
-
-  - hb_buffer_add_utf*() now accept -1 for length parameteres,
-    meaning "nul-terminated".
-
-  - hb_direction_t enum values changed.
-
-  - All *_from_string() APIs now take a length parameter to allow for
-    non-nul-terminated strings. A -1 length means "nul-terminated".
-
-  - Typedef for hb_language_t changed.
-
-  - hb_get_table_func_t renamed to hb_reference_table_func_t.
-
-  - hb_ot_layout_table_choose_script()
-
-  - Various renames in hb-unicode.h.
-
-o New API:
-
-  - hb_buffer_guess_properties()
-    Automatically called by hb_shape().
-
-  - hb_buffer_normalize_glyphs()
-
-  - hb_tag_from_string()
-
-  - hb-coretext.h
-
-  - hb-uniscribe.h
-
-  - hb_face_reference_blob()
-  - hb_face_[sg]et_index()
-  - hb_face_set_upem()
-
-  - hb_font_get_glyph_name_func_t
-    hb_font_get_glyph_from_name_func_t
-    hb_font_funcs_set_glyph_name_func()
-    hb_font_funcs_set_glyph_from_name_func()
-    hb_font_get_glyph_name()
-    hb_font_get_glyph_from_name()
-    hb_font_glyph_to_string()
-    hb_font_glyph_from_string()
-
-  - hb_font_set_funcs_data()
-
-  - hb_ft_font_set_funcs()
-  - hb_ft_font_get_face()
-
-  - hb-gobject.h (work in progress)
-
-  - hb_ot_shape_glyphs_closure()
-    hb_ot_layout_substitute_closure_lookup()
-
-  - hb-set.h
-
-  - hb_shape_full()
-
-  - hb_unicode_combining_class_t
-
-  - hb_unicode_compose_func_t
-    hb_unicode_decompose_func_t
-    hb_unicode_decompose_compatibility_func_t
-    hb_unicode_funcs_set_compose_func()
-    hb_unicode_funcs_set_decompose_func()
-    hb_unicode_funcs_set_decompose_compatibility_func()
-    hb_unicode_compose()
-    hb_unicode_decompose()
-    hb_unicode_decompose_compatibility()
-
-o Removed API:
-
-  - hb_ft_get_font_funcs()
-
-  - hb_ot_layout_substitute_start()
-    hb_ot_layout_substitute_lookup()
-    hb_ot_layout_substitute_finish()
-    hb_ot_layout_position_start()
-    hb_ot_layout_position_lookup()
-    hb_ot_layout_position_finish()
-
-
-
-Overview of changes leading to 0.6.0
-Friday, May 27, 2011
-====================================
-
-- Vertical text support in GPOS
-- Almost all API entries have unit tests now, under test/
-- All thread-safety issues are fixed
-
-Summary of API changes follows.
-
-
-* Simple Types API:
-
-  o New API:
-    HB_LANGUAGE_INVALID
-    hb_language_get_default()
-    hb_direction_to_string()
-    hb_direction_from_string()
-    hb_script_get_horizontal_direction()
-    HB_UNTAG()
-
-  o Renamed API:
-    hb_category_t renamed to hb_unicode_general_category_t
-
-  o Changed API:
-    hb_language_t is a typed pointers now
-
-  o Removed API:
-    HB_TAG_STR()
-
-
-* Use ISO 15924 tags for hb_script_t:
-
-  o New API:
-    hb_script_from_iso15924_tag()
-    hb_script_to_iso15924_tag()
-    hb_script_from_string()
-
-  o Changed API:
-    HB_SCRIPT_* enum members changed value.
-
-
-* Buffer API streamlined:
-
-  o New API:
-    hb_buffer_reset()
-    hb_buffer_set_length()
-    hb_buffer_allocation_successful()
-
-  o Renamed API:
-    hb_buffer_ensure() renamed to hb_buffer_pre_allocate()
-    hb_buffer_add_glyph() renamed to hb_buffer_add()
-
-  o Removed API:
-    hb_buffer_clear()
-    hb_buffer_clear_positions()
-
-  o Changed API:
-    hb_buffer_get_glyph_infos() takes an out length parameter now
-    hb_buffer_get_glyph_positions() takes an out length parameter now
-
-
-* Blob API streamlined:
-
-  o New API:
-    hb_blob_get_data()
-    hb_blob_get_data_writable()
-
-  o Renamed API:
-    hb_blob_create_empty() renamed to hb_blob_get_empty()
-
-  o Removed API:
-    hb_blob_lock()
-    hb_blob_unlock()
-    hb_blob_is_writable()
-    hb_blob_try_writable()
-
-  o Changed API:
-    hb_blob_create() takes user_data before destroy now
-
-
-* Unicode functions API:
-
-  o Unicode function vectors can subclass other unicode function vectors now.
-    Unimplemented callbacks in the subclass automatically chainup to the parent.
-
-  o All hb_unicode_funcs_t callbacks take a user_data now.  Their setters
-    take a user_data and its respective destroy callback.
-
-  o New API:
-    hb_unicode_funcs_get_empty()
-    hb_unicode_funcs_get_default()
-    hb_unicode_funcs_get_parent()
-
-  o Changed API:
-    hb_unicode_funcs_create() now takes a parent_funcs.
-
-  o Removed func getter functions:
-    hb_unicode_funcs_get_mirroring_func()
-    hb_unicode_funcs_get_general_category_func()
-    hb_unicode_funcs_get_script_func()
-    hb_unicode_funcs_get_combining_class_func()
-    hb_unicode_funcs_get_eastasian_width_func()
-
-
-* Face API:
-
-  o Renamed API:
-    hb_face_get_table() renamed to hb_face_reference_table()
-    hb_face_create_for_data() renamed to hb_face_create()
-
-  o Changed API:
-    hb_face_create_for_tables() takes user_data before destroy now
-    hb_face_reference_table() returns empty blob instead of NULL
-    hb_get_table_func_t accepts the face as first parameter now
-
-* Font API:
-
-  o Fonts can subclass other fonts now.  Unimplemented callbacks in the
-    subclass automatically chainup to the parent.  When chaining up,
-    scale is adjusted if the parent font has a different scale.
-
-  o All hb_font_funcs_t callbacks take a user_data now.  Their setters
-    take a user_data and its respective destroy callback.
-
-  o New API:
-    hb_font_get_parent()
-    hb_font_funcs_get_empty()
-    hb_font_create_sub_font()
-
-  o Removed API:
-    hb_font_funcs_copy()
-    hb_font_unset_funcs()
-
-  o Removed func getter functions:
-    hb_font_funcs_get_glyph_func()
-    hb_font_funcs_get_glyph_advance_func()
-    hb_font_funcs_get_glyph_extents_func()
-    hb_font_funcs_get_contour_point_func()
-    hb_font_funcs_get_kerning_func()
-
-  o Changed API:
-    hb_font_create() takes a face and references it now
-    hb_font_set_funcs() takes user_data before destroy now
-    hb_font_set_scale() accepts signed integers now
-    hb_font_get_contour_point_func_t now takes glyph first, then point_index
-    hb_font_get_glyph_func_t returns a success boolean now
-
-
-* Changed object model:
-
-  o All object types have a _get_empty() now:
-    hb_blob_get_empty()
-    hb_buffer_get_empty()
-    hb_face_get_empty()
-    hb_font_get_empty()
-    hb_font_funcs_get_empty()
-    hb_unicode_funcs_get_empty()
-
-  o Added _set_user_data() and _get_user_data() for all object types:
-    hb_blob_get_user_data()
-    hb_blob_set_user_data()
-    hb_buffer_get_user_data()
-    hb_buffer_set_user_data()
-    hb_face_get_user_data()
-    hb_face_set_user_data()
-    hb_font_funcs_get_user_data()
-    hb_font_funcs_set_user_data()
-    hb_font_get_user_data()
-    hb_font_set_user_data()
-    hb_unicode_funcs_get_user_data()
-    hb_unicode_funcs_set_user_data()
-
-  o Removed the _get_reference_count() from all object types:
-    hb_blob_get_reference_count()
-    hb_buffer_get_reference_count()
-    hb_face_get_reference_count()
-    hb_font_funcs_get_reference_count()
-    hb_font_get_reference_count()
-    hb_unicode_funcs_get_reference_count()
-
-  o Added _make_immutable() and _is_immutable() for all object types except for buffer:
-    hb_blob_make_immutable()
-    hb_blob_is_immutable()
-    hb_face_make_immutable()
-    hb_face_is_immutable()
-
-
-* Changed API for vertical text support
-
-  o The following callbacks where removed:
-    hb_font_get_glyph_advance_func_t
-    hb_font_get_kerning_func_t
-
-  o The following new callbacks added instead:
-    hb_font_get_glyph_h_advance_func_t
-    hb_font_get_glyph_v_advance_func_t
-    hb_font_get_glyph_h_origin_func_t
-    hb_font_get_glyph_v_origin_func_t
-    hb_font_get_glyph_h_kerning_func_t
-    hb_font_get_glyph_v_kerning_func_t
-
-  o The following API removed as such:
-    hb_font_funcs_set_glyph_advance_func()
-    hb_font_funcs_set_kerning_func()
-    hb_font_get_glyph_advance()
-    hb_font_get_kerning()
-
-  o New API added instead:
-    hb_font_funcs_set_glyph_h_advance_func()
-    hb_font_funcs_set_glyph_v_advance_func()
-    hb_font_funcs_set_glyph_h_origin_func()
-    hb_font_funcs_set_glyph_v_origin_func()
-    hb_font_funcs_set_glyph_h_kerning_func()
-    hb_font_funcs_set_glyph_v_kerning_func()
-    hb_font_get_glyph_h_advance()
-    hb_font_get_glyph_v_advance()
-    hb_font_get_glyph_h_origin()
-    hb_font_get_glyph_v_origin()
-    hb_font_get_glyph_h_kerning()
-    hb_font_get_glyph_v_kerning()
-
-  o The following higher-leve API added for convenience:
-    hb_font_get_glyph_advance_for_direction()
-    hb_font_get_glyph_origin_for_direction()
-    hb_font_add_glyph_origin_for_direction()
-    hb_font_subtract_glyph_origin_for_direction()
-    hb_font_get_glyph_kerning_for_direction()
-    hb_font_get_glyph_extents_for_origin()
-    hb_font_get_glyph_contour_point_for_origin()
-
-
-* OpenType Layout API:
-
-  o New API:
-    hb_ot_layout_position_start()
-    hb_ot_layout_substitute_start()
-    hb_ot_layout_substitute_finish()
-
-
-* Glue code:
-
-  o New API:
-    hb_glib_script_to_script()
-    hb_glib_script_from_script()
-    hb_icu_script_to_script()
-    hb_icu_script_from_script()
-
-
-* Version API added:
-
-  o New API:
-    HB_VERSION_MAJOR
-    HB_VERSION_MINOR
-    HB_VERSION_MICRO
-    HB_VERSION_STRING
-    HB_VERSION_CHECK()
-    hb_version()
-    hb_version_string()
-    hb_version_check()
-
-

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

@@ -54,7 +54,7 @@ struct Anchor
   DEFINE_SIZE_STATIC (4);
 };
 
-typedef LArrayOf<Anchor> GlyphAnchors;
+typedef Array32Of<Anchor> GlyphAnchors;
 
 struct ankr
 {
@@ -64,7 +64,7 @@ struct ankr
 			    unsigned int i,
 			    unsigned int num_glyphs) const
   {
-    const NNOffsetTo<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
+    const NNOffset16To<GlyphAnchors> *offset = (this+lookupTable).get_value (glyph_id, num_glyphs);
     if (!offset)
       return Null (Anchor);
     const GlyphAnchors &anchors = &(this+anchorData) + *offset;
@@ -83,9 +83,9 @@ struct ankr
   protected:
   HBUINT16	version;	/* Version number (set to zero) */
   HBUINT16	flags;		/* Flags (currently unused; set to zero) */
-  LOffsetTo<Lookup<NNOffsetTo<GlyphAnchors>>>
+  Offset32To<Lookup<NNOffset16To<GlyphAnchors>>>
 		lookupTable;	/* Offset to the table's lookup table */
-  LNNOffsetTo<HBUINT8>
+  NNOffset32To<HBUINT8>
 		anchorData;	/* Offset to the glyph data table */
 
   public:

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

@@ -30,6 +30,9 @@
 #include "hb-aat-layout.hh"
 #include "hb-open-type.hh"
 
+namespace OT {
+struct GDEF;
+};
 
 namespace AAT {
 
@@ -164,7 +167,7 @@ struct LookupSegmentArray
 
   HBGlyphID	last;		/* Last GlyphID in this segment */
   HBGlyphID	first;		/* First GlyphID in this segment */
-  NNOffsetTo<UnsizedArrayOf<T>>
+  NNOffset16To<UnsizedArrayOf<T>>
 		valuesZ;	/* A 16-bit offset from the start of
 				 * the table to the data. */
   public:
@@ -659,7 +662,7 @@ struct ClassTable
   }
   protected:
   HBGlyphID		firstGlyph;	/* First glyph index included in the trimmed array. */
-  ArrayOf<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
+  Array16Of<HBUCHAR>	classArray;	/* The class codes (indexed by glyph index minus
 					 * firstGlyph). */
   public:
   DEFINE_SIZE_ARRAY (4, classArray);
@@ -678,7 +681,8 @@ struct ObsoleteTypes
 				     const void *base,
 				     const T *array)
   {
-    return (offset - ((const char *) array - (const char *) base)) / T::static_size;
+    /* https://github.com/harfbuzz/harfbuzz/issues/2816 */
+    return (offset - unsigned ((const char *) array - (const char *) base)) / T::static_size;
   }
   template <typename T>
   static unsigned int byteOffsetToIndex (unsigned int offset,
@@ -862,6 +866,7 @@ struct hb_aat_apply_context_t :
   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;

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

@@ -144,7 +144,7 @@ struct FeatureName
   protected:
   HBUINT16	feature;	/* Feature type. */
   HBUINT16	nSettings;	/* The number of records in the setting name array. */
-  LNNOffsetTo<UnsizedArrayOf<SettingName>>
+  NNOffset32To<UnsizedArrayOf<SettingName>>
 		settingTableZ;	/* Offset in bytes from the beginning of this table to
 				 * this feature's setting name array. The actual type of
 				 * record this offset refers to will depend on the

+ 8 - 8
thirdparty/harfbuzz/src/hb-aat-layout-just-table.hh

@@ -79,7 +79,7 @@ struct DecompositionAction
 				 * to decompose before more frequent ones. The ligatures
 				 * on the line of text will decompose in increasing
 				 * value of this field. */
-  ArrayOf<HBUINT16>
+  Array16Of<HBUINT16>
 		decomposedglyphs;
 				/* Number of 16-bit glyph indexes that follow;
 				 * the ligature will be decomposed into these glyphs.
@@ -310,7 +310,7 @@ struct WidthDeltaPair
   DEFINE_SIZE_STATIC (24);
 };
 
-typedef OT::LArrayOf<WidthDeltaPair> WidthDeltaCluster;
+typedef OT::Array32Of<WidthDeltaPair> WidthDeltaCluster;
 
 struct JustificationCategory
 {
@@ -358,20 +358,20 @@ struct JustificationHeader
   }
 
   protected:
-  OffsetTo<JustificationCategory>
+  Offset16To<JustificationCategory>
 		justClassTable;	/* Offset to the justification category state table. */
-  OffsetTo<WidthDeltaCluster>
+  Offset16To<WidthDeltaCluster>
 		wdcTable;	/* Offset from start of justification table to start
 				 * of the subtable containing the width delta factors
 				 * for the glyphs in your font.
 				 *
 				 * The width delta clusters table. */
-  OffsetTo<PostcompensationActionChain>
+  Offset16To<PostcompensationActionChain>
 		pcTable;	/* Offset from start of justification table to start
 				 * of postcompensation subtable (set to zero if none).
 				 *
 				 * The postcompensation subtable, if present in the font. */
-  Lookup<OffsetTo<WidthDeltaCluster>>
+  Lookup<Offset16To<WidthDeltaCluster>>
 		lookupTable;	/* Lookup table associating glyphs with width delta
 				 * clusters. See the description of Width Delta Clusters
 				 * table for details on how to interpret the lookup values. */
@@ -398,13 +398,13 @@ struct just
   FixedVersion<>version;	/* Version of the justification table
 				 * (0x00010000u for version 1.0). */
   HBUINT16	format;		/* Format of the justification table (set to 0). */
-  OffsetTo<JustificationHeader>
+  Offset16To<JustificationHeader>
 		horizData;	/* Byte offset from the start of the justification table
 				 * to the header for tables that contain justification
 				 * information for horizontal text.
 				 * If you are not including this information,
 				 * store 0. */
-  OffsetTo<JustificationHeader>
+  Offset16To<JustificationHeader>
 		vertData;	/* ditto, vertical */
 
   public:

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

@@ -710,18 +710,18 @@ struct KerxSubTableFormat6
   {
     struct Long
     {
-      LNNOffsetTo<Lookup<HBUINT32>>		rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT32>>		columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD32>>	array;
+      NNOffset32To<Lookup<HBUINT32>>		rowIndexTable;
+      NNOffset32To<Lookup<HBUINT32>>		columnIndexTable;
+      NNOffset32To<UnsizedArrayOf<FWORD32>>	array;
     } l;
     struct Short
     {
-      LNNOffsetTo<Lookup<HBUINT16>>		rowIndexTable;
-      LNNOffsetTo<Lookup<HBUINT16>>		columnIndexTable;
-      LNNOffsetTo<UnsizedArrayOf<FWORD>>	array;
+      NNOffset32To<Lookup<HBUINT16>>		rowIndexTable;
+      NNOffset32To<Lookup<HBUINT16>>		columnIndexTable;
+      NNOffset32To<UnsizedArrayOf<FWORD>>	array;
     } s;
   } u;
-  LNNOffsetTo<UnsizedArrayOf<FWORD>>	vector;
+  NNOffset32To<UnsizedArrayOf<FWORD>>	vector;
   public:
   DEFINE_SIZE_STATIC (KernSubTableHeader::static_size + 24);
 };

+ 19 - 2
thirdparty/harfbuzz/src/hb-aat-layout-morx-table.hh

@@ -30,6 +30,7 @@
 #include "hb-open-type.hh"
 #include "hb-aat-layout-common.hh"
 #include "hb-ot-layout-common.hh"
+#include "hb-ot-layout-gdef-table.hh"
 #include "hb-aat-map.hh"
 
 /*
@@ -215,7 +216,9 @@ struct ContextualSubtable
 			     hb_aat_apply_context_t *c_) :
 	ret (false),
 	c (c_),
+	gdef (*c->gdef_table),
 	mark_set (false),
+	has_glyph_classes (gdef.has_glyph_classes ()),
 	mark (0),
 	table (table_),
 	subs (table+table->substitutionTables) {}
@@ -263,6 +266,9 @@ struct ContextualSubtable
       {
 	buffer->unsafe_to_break (mark, hb_min (buffer->idx + 1, buffer->len));
 	buffer->info[mark].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->info[mark],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
 
@@ -287,6 +293,9 @@ struct ContextualSubtable
       if (replacement)
       {
 	buffer->info[idx].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&buffer->info[idx],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
 
@@ -301,10 +310,12 @@ struct ContextualSubtable
     bool ret;
     private:
     hb_aat_apply_context_t *c;
+    const OT::GDEF &gdef;
     bool mark_set;
+    bool has_glyph_classes;
     unsigned int mark;
     const ContextualSubtable *table;
-    const UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false> &subs;
+    const UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false> &subs;
   };
 
   bool apply (hb_aat_apply_context_t *c) const
@@ -348,7 +359,7 @@ struct ContextualSubtable
   protected:
   StateTable<Types, EntryData>
 		machine;
-  NNOffsetTo<UnsizedOffsetListOf<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
+  NNOffsetTo<UnsizedListOfOffset16To<Lookup<HBGlyphID>, HBUINT, false>, HBUINT>
 		substitutionTables;
   public:
   DEFINE_SIZE_STATIC (20);
@@ -599,6 +610,9 @@ struct NoncontextualSubtable
   {
     TRACE_APPLY (this);
 
+    const OT::GDEF &gdef (*c->gdef_table);
+    bool has_glyph_classes = gdef.has_glyph_classes ();
+
     bool ret = false;
     unsigned int num_glyphs = c->face->get_num_glyphs ();
 
@@ -610,6 +624,9 @@ struct NoncontextualSubtable
       if (replacement)
       {
 	info[i].codepoint = *replacement;
+	if (has_glyph_classes)
+	  _hb_glyph_info_set_glyph_props (&info[i],
+					  gdef.get_glyph_props (*replacement));
 	ret = true;
       }
     }

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

@@ -58,7 +58,7 @@ struct opbdFormat0
   bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
 		   hb_glyph_extents_t *extents, const void *base) const
   {
-    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
     if (!bounds_offset) return false;
     const OpticalBounds &bounds = base+*bounds_offset;
 
@@ -79,7 +79,7 @@ struct opbdFormat0
   }
 
   protected:
-  Lookup<OffsetTo<OpticalBounds>>
+  Lookup<Offset16To<OpticalBounds>>
 		lookupTable;	/* Lookup table associating glyphs with the four
 				 * int16 values for the left-side, top-side,
 				 * right-side, and bottom-side optical bounds. */
@@ -92,7 +92,7 @@ struct opbdFormat1
   bool get_bounds (hb_font_t *font, hb_codepoint_t glyph_id,
 		   hb_glyph_extents_t *extents, const void *base) const
   {
-    const OffsetTo<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
+    const Offset16To<OpticalBounds> *bounds_offset = lookupTable.get_value (glyph_id, font->face->get_num_glyphs ());
     if (!bounds_offset) return false;
     const OpticalBounds &bounds = base+*bounds_offset;
 
@@ -116,7 +116,7 @@ struct opbdFormat1
   }
 
   protected:
-  Lookup<OffsetTo<OpticalBounds>>
+  Lookup<Offset16To<OpticalBounds>>
 		lookupTable;	/* Lookup table associating glyphs with the four
 				 * int16 values for the left-side, top-side,
 				 * right-side, and bottom-side optical bounds. */

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

@@ -66,7 +66,7 @@ struct TrackTableEntry
   NameID	trackNameID;	/* The 'name' table index for this track.
 				 * (a short word or phrase like "loose"
 				 * or "very tight") */
-  NNOffsetTo<UnsizedArrayOf<FWORD>>
+  NNOffset16To<UnsizedArrayOf<FWORD>>
 		valuesZ;	/* Offset from start of tracking table to
 				 * per-size tracking values for this track. */
 
@@ -141,7 +141,7 @@ struct TrackData
   protected:
   HBUINT16	nTracks;	/* Number of separate tracks included in this table. */
   HBUINT16	nSizes;		/* Number of point sizes included in this table. */
-  LNNOffsetTo<UnsizedArrayOf<HBFixed>>
+  NNOffset32To<UnsizedArrayOf<HBFixed>>
 		sizeTable;	/* Offset from start of the tracking table to
 				 * Array[nSizes] of size values.. */
   UnsizedArrayOf<TrackTableEntry>
@@ -212,10 +212,10 @@ struct trak
   FixedVersion<>version;	/* Version of the tracking table
 				 * (0x00010000u for version 1.0). */
   HBUINT16	format;		/* Format of the tracking table (set to 0). */
-  OffsetTo<TrackData>
+  Offset16To<TrackData>
 		horizData;	/* Offset from start of tracking table to TrackData
 				 * for horizontal text (or 0 if none). */
-  OffsetTo<TrackData>
+  Offset16To<TrackData>
 		vertData;	/* Offset from start of tracking table to TrackData
 				 * for vertical text (or 0 if none). */
   HBUINT16	reserved;	/* Reserved. Set to 0. */

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

@@ -55,6 +55,7 @@ AAT::hb_aat_apply_context_t::hb_aat_apply_context_t (const hb_ot_shape_plan_t *p
 						       buffer (buffer_),
 						       sanitizer (),
 						       ankr_table (&Null (AAT::ankr)),
+						       gdef_table (face->table.GDEF->table),
 						       lookup_index (0)
 {
   sanitizer.init (blob);
@@ -79,7 +80,7 @@ AAT::hb_aat_apply_context_t::set_ankr_table (const AAT::ankr *ankr_table_)
  * @short_description: Apple Advanced Typography Layout
  * @include: hb-aat.h
  *
- * Functions for querying AAT Layout features in the font face. 
+ * Functions for querying AAT Layout features in the font face.
  *
  * HarfBuzz supports all of the AAT tables used to implement shaping. Other
  * AAT tables and their associated features are not supported.
@@ -172,13 +173,13 @@ static const hb_aat_feature_mapping_t feature_mappings[] =
   {HB_TAG ('z','e','r','o'), HB_AAT_LAYOUT_FEATURE_TYPE_TYPOGRAPHIC_EXTRAS,      HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_ON,                HB_AAT_LAYOUT_FEATURE_SELECTOR_SLASHED_ZERO_OFF},
 };
 
-/** 
+/**
  * hb_aat_layout_find_feature_mapping:
  * @tag: The requested #hb_tag_t feature tag
  *
  * Fetches the AAT feature-and-selector combination that corresponds
  * to a given OpenType feature tag.
- *  
+ *
  * Return value: the AAT features and selectors corresponding to the
  * OpenType feature tag queried
  *
@@ -248,7 +249,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
   if (morx.has_data ())
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, morx_blob);
+    if (!buffer->message (font, "start table morx")) return;
     morx.apply (&c);
+    (void) buffer->message (font, "end table morx");
     return;
   }
 
@@ -257,7 +260,9 @@ hb_aat_layout_substitute (const hb_ot_shape_plan_t *plan,
   if (mort.has_data ())
   {
     AAT::hb_aat_apply_context_t c (plan, font, buffer, mort_blob);
+    if (!buffer->message (font, "start table mort")) return;
     mort.apply (&c);
+    (void) buffer->message (font, "end table mort");
     return;
   }
 }
@@ -313,8 +318,10 @@ hb_aat_layout_position (const hb_ot_shape_plan_t *plan,
   const AAT::kerx& kerx = *kerx_blob->as<AAT::kerx> ();
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, kerx_blob);
+  if (!buffer->message (font, "start table kerx")) return;
   c.set_ankr_table (font->face->table.ankr.get ());
   kerx.apply (&c);
+  (void) buffer->message (font, "end table kerx");
 }
 
 

+ 2 - 2
thirdparty/harfbuzz/src/hb-aat-ltag-table.hh

@@ -50,7 +50,7 @@ struct FTStringRange
   }
 
   protected:
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
 		tag;		/* Offset from the start of the table to
 				 * the beginning of the string */
   HBUINT16	length;		/* String length (in bytes) */
@@ -80,7 +80,7 @@ struct ltag
   protected:
   HBUINT32	version;	/* Table version; currently 1 */
   HBUINT32	flags;		/* Table flags; currently none defined */
-  LArrayOf<FTStringRange>
+  Array32Of<FTStringRange>
 		tagRanges;	/* Range for each tag's string */
   public:
   DEFINE_SIZE_ARRAY (12, tagRanges);

+ 37 - 5
thirdparty/harfbuzz/src/hb-algs.hh

@@ -760,6 +760,14 @@ static inline unsigned int ARRAY_LENGTH (const Type (&)[n]) { return n; }
 #define ARRAY_LENGTH_CONST(__array) ((signed int) (sizeof (__array) / sizeof (__array[0])))
 
 
+static inline void *
+hb_memcpy (void *__restrict dst, const void *__restrict src, size_t len)
+{
+  /* It's illegal to pass 0 as size to memcpy. */
+  if (unlikely (!len)) return dst;
+  return memcpy (dst, src, len);
+}
+
 static inline int
 hb_memcmp (const void *a, const void *b, unsigned int len)
 {
@@ -1151,30 +1159,48 @@ hb_codepoint_parse (const char *s, unsigned int len, int base, hb_codepoint_t *o
 
 /* Operators. */
 
-struct hb_bitwise_and
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & b)
 }
 HB_FUNCOBJ (hb_bitwise_and);
-struct hb_bitwise_or
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | b)
 }
 HB_FUNCOBJ (hb_bitwise_or);
-struct hb_bitwise_xor
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a ^ b)
 }
 HB_FUNCOBJ (hb_bitwise_xor);
-struct hb_bitwise_sub
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a & b)
+}
+HB_FUNCOBJ (hb_bitwise_lt);
+struct
 { HB_PARTIALIZE(2);
   template <typename T> constexpr auto
   operator () (const T &a, const T &b) const HB_AUTO_RETURN (a & ~b)
 }
-HB_FUNCOBJ (hb_bitwise_sub);
+HB_FUNCOBJ (hb_bitwise_gt); // aka sub
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (~a | b)
+}
+HB_FUNCOBJ (hb_bitwise_le);
+struct
+{ HB_PARTIALIZE(2);
+  template <typename T> constexpr auto
+  operator () (const T &a, const T &b) const HB_AUTO_RETURN (a | ~b)
+}
+HB_FUNCOBJ (hb_bitwise_ge);
 struct
 {
   template <typename T> constexpr auto
@@ -1195,6 +1221,12 @@ struct
 }
 HB_FUNCOBJ (hb_sub);
 struct
+{ HB_PARTIALIZE(2);
+  template <typename T, typename T2> constexpr auto
+  operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (b - a)
+}
+HB_FUNCOBJ (hb_rsub);
+struct
 { HB_PARTIALIZE(2);
   template <typename T, typename T2> constexpr auto
   operator () (const T &a, const T2 &b) const HB_AUTO_RETURN (a * b)

+ 35 - 16
thirdparty/harfbuzz/src/hb-array.hh

@@ -36,6 +36,14 @@
 template <typename Type>
 struct hb_sorted_array_t;
 
+enum hb_not_found_t
+{
+  HB_NOT_FOUND_DONT_STORE,
+  HB_NOT_FOUND_STORE,
+  HB_NOT_FOUND_STORE_CLOSEST,
+};
+
+
 template <typename Type>
 struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 {
@@ -139,7 +147,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
     return lfind (x, &i) ? &this->arrayZ[i] : not_found;
   }
   template <typename T>
-  bool lfind (const T &x, unsigned *pos = nullptr) const
+  bool lfind (const T &x, unsigned *pos = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
   {
     for (unsigned i = 0; i < length; ++i)
       if (hb_equal (x, this->arrayZ[i]))
@@ -149,6 +159,22 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 	return true;
       }
 
+    if (pos)
+    {
+      switch (not_found)
+      {
+	case HB_NOT_FOUND_DONT_STORE:
+	  break;
+
+	case HB_NOT_FOUND_STORE:
+	  *pos = to_store;
+	  break;
+
+	case HB_NOT_FOUND_STORE_CLOSEST:
+	  *pos = length;
+	  break;
+      }
+    }
     return false;
   }
 
@@ -219,7 +245,7 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 	    unsigned P = sizeof (Type),
 	    hb_enable_if (P == 1)>
   const T *as () const
-  { return length < hb_null_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
+  { return length < hb_min_size (T) ? &Null (T) : reinterpret_cast<const T *> (arrayZ); }
 
   template <typename T,
 	    unsigned P = sizeof (Type),
@@ -231,9 +257,9 @@ struct hb_array_t : hb_iter_with_fallback_t<hb_array_t<Type>, Type&>
 	&& (unsigned int) (arrayZ + length - (const char *) p) >= size;
   }
 
-  /* Only call if you allocated the underlying array using malloc() or similar. */
-  void free ()
-  { ::free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
+  /* Only call if you allocated the underlying array using hb_malloc() or similar. */
+  void fini ()
+  { hb_free ((void *) arrayZ); arrayZ = nullptr; length = 0; }
 
   template <typename hb_serialize_context_t>
   hb_array_t copy (hb_serialize_context_t *c) const
@@ -266,13 +292,6 @@ template <typename T, unsigned int length_> inline hb_array_t<T>
 hb_array (T (&array_)[length_])
 { return hb_array_t<T> (array_); }
 
-enum hb_bfind_not_found_t
-{
-  HB_BFIND_NOT_FOUND_DONT_STORE,
-  HB_BFIND_NOT_FOUND_STORE,
-  HB_BFIND_NOT_FOUND_STORE_CLOSEST,
-};
-
 template <typename Type>
 struct hb_sorted_array_t :
 	hb_iter_t<hb_sorted_array_t<Type>, Type&>,
@@ -323,7 +342,7 @@ struct hb_sorted_array_t :
   }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   {
     unsigned pos;
@@ -339,14 +358,14 @@ struct hb_sorted_array_t :
     {
       switch (not_found)
       {
-	case HB_BFIND_NOT_FOUND_DONT_STORE:
+	case HB_NOT_FOUND_DONT_STORE:
 	  break;
 
-	case HB_BFIND_NOT_FOUND_STORE:
+	case HB_NOT_FOUND_STORE:
 	  *i = to_store;
 	  break;
 
-	case HB_BFIND_NOT_FOUND_STORE_CLOSEST:
+	case HB_NOT_FOUND_STORE_CLOSEST:
 	  *i = pos;
 	  break;
       }

+ 5 - 0
thirdparty/harfbuzz/src/hb-bimap.hh

@@ -58,10 +58,15 @@ struct hb_bimap_t
 
   void set (hb_codepoint_t lhs, hb_codepoint_t rhs)
   {
+    if (in_error ()) return;
     if (unlikely (lhs == HB_MAP_VALUE_INVALID)) return;
     if (unlikely (rhs == HB_MAP_VALUE_INVALID)) { del (lhs); return; }
+
     forw_map.set (lhs, rhs);
+    if (in_error ()) return;
+
     back_map.set (rhs, lhs);
+    if (in_error ()) forw_map.del (lhs);
   }
 
   hb_codepoint_t get (hb_codepoint_t lhs) const { return forw_map.get (lhs); }

+ 203 - 0
thirdparty/harfbuzz/src/hb-bit-page.hh

@@ -0,0 +1,203 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  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_BIT_PAGE_HH
+#define HB_BIT_PAGE_HH
+
+#include "hb.hh"
+
+struct hb_bit_page_t
+{
+  void init0 () { v.clear (); }
+  void init1 () { v.clear (0xFF); }
+
+  constexpr unsigned len () const
+  { return ARRAY_LENGTH_CONST (v); }
+
+  bool is_empty () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return false;
+    return true;
+  }
+
+  void add (hb_codepoint_t g) { elt (g) |= mask (g); }
+  void del (hb_codepoint_t g) { elt (g) &= ~mask (g); }
+  void set (hb_codepoint_t g, bool v) { if (v) add (g); else del (g); }
+  bool get (hb_codepoint_t g) const { return elt (g) & mask (g); }
+
+  void add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la |= (mask (b) << 1) - mask(a);
+    else
+    {
+      *la |= ~(mask (a) - 1);
+      la++;
+
+      memset (la, 0xff, (char *) lb - (char *) la);
+
+      *lb |= ((mask (b) << 1) - 1);
+    }
+  }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    elt_t *la = &elt (a);
+    elt_t *lb = &elt (b);
+    if (la == lb)
+      *la &= ~((mask (b) << 1) - mask(a));
+    else
+    {
+      *la &= mask (a) - 1;
+      la++;
+
+      memset (la, 0, (char *) lb - (char *) la);
+
+      *lb &= ~((mask (b) << 1) - 1);
+    }
+  }
+  void set_range (hb_codepoint_t a, hb_codepoint_t b, bool v)
+  { if (v) add_range (a, b); else del_range (a, b); }
+
+  bool is_equal (const hb_bit_page_t &other) const
+  {
+    return 0 == hb_memcmp (&v, &other.v, sizeof (v));
+  }
+  bool is_subset (const hb_bit_page_t &larger_page) const
+  {
+    for (unsigned i = 0; i < len (); i++)
+      if (~larger_page.v[i] & v[i])
+	return false;
+    return true;
+  }
+
+  unsigned int get_population () const
+  {
+    unsigned int pop = 0;
+    for (unsigned int i = 0; i < len (); i++)
+      pop += hb_popcount (v[i]);
+    return pop;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint + 1) & MASK;
+    if (!m)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    const elt_t vv = v[i] & ~((elt_t (1) << j) - 1);
+    for (const elt_t *p = &vv; i < len (); p = &v[++i])
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_min (*p);
+	return true;
+      }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    unsigned int m = (*codepoint - 1) & MASK;
+    if (m == MASK)
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+    unsigned int i = m / ELT_BITS;
+    unsigned int j = m & ELT_MASK;
+
+    /* Fancy mask to avoid shifting by elt_t bitsize, which is undefined. */
+    const elt_t mask = j < 8 * sizeof (elt_t) - 1 ?
+		       ((elt_t (1) << (j + 1)) - 1) :
+		       (elt_t) -1;
+    const elt_t vv = v[i] & mask;
+    const elt_t *p = &vv;
+    while (true)
+    {
+      if (*p)
+      {
+	*codepoint = i * ELT_BITS + elt_get_max (*p);
+	return true;
+      }
+      if ((int) i <= 0) break;
+      p = &v[--i];
+    }
+
+    *codepoint = INVALID;
+    return false;
+  }
+  hb_codepoint_t get_min () const
+  {
+    for (unsigned int i = 0; i < len (); i++)
+      if (v[i])
+	return i * ELT_BITS + elt_get_min (v[i]);
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    for (int i = len () - 1; i >= 0; i--)
+      if (v[i])
+	return i * ELT_BITS + elt_get_max (v[i]);
+    return 0;
+  }
+
+  static constexpr hb_codepoint_t INVALID = HB_SET_VALUE_INVALID;
+
+  typedef unsigned long long elt_t;
+  static constexpr unsigned PAGE_BITS = 512;
+  static_assert ((PAGE_BITS & ((PAGE_BITS) - 1)) == 0, "");
+
+  static unsigned int elt_get_min (const elt_t &elt) { return hb_ctz (elt); }
+  static unsigned int elt_get_max (const elt_t &elt) { return hb_bit_storage (elt) - 1; }
+
+  typedef hb_vector_size_t<elt_t, PAGE_BITS / 8> vector_t;
+
+  static constexpr unsigned ELT_BITS = sizeof (elt_t) * 8;
+  static constexpr unsigned ELT_MASK = ELT_BITS - 1;
+  static constexpr unsigned BITS = sizeof (vector_t) * 8;
+  static constexpr unsigned MASK = BITS - 1;
+  static_assert ((unsigned) PAGE_BITS == (unsigned) BITS, "");
+
+  elt_t &elt (hb_codepoint_t g) { return v[(g & MASK) / ELT_BITS]; }
+  const elt_t& elt (hb_codepoint_t g) const { return v[(g & MASK) / ELT_BITS]; }
+  static constexpr elt_t mask (hb_codepoint_t g) { return elt_t (1) << (g & ELT_MASK); }
+
+  vector_t v;
+};
+static_assert (hb_bit_page_t::PAGE_BITS == sizeof (hb_bit_page_t) * 8, "");
+
+
+#endif /* HB_BIT_PAGE_HH */

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

@@ -0,0 +1,354 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  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_BIT_SET_INVERTIBLE_HH
+#define HB_BIT_SET_INVERTIBLE_HH
+
+#include "hb.hh"
+#include "hb-bit-set.hh"
+
+
+struct hb_bit_set_invertible_t
+{
+  hb_bit_set_t s;
+  bool inverted;
+
+  hb_bit_set_invertible_t () { init (); }
+  ~hb_bit_set_invertible_t () { fini (); }
+
+  void init () { s.init (); inverted = false; }
+  void fini () { s.fini (); }
+  void err () { s.err (); }
+  bool in_error () const { return s.in_error (); }
+  explicit operator bool () const { return !is_empty (); }
+
+  void reset ()
+  {
+    s.reset ();
+    inverted = false;
+  }
+  void clear ()
+  {
+    s.clear ();
+    if (likely (s.successful))
+      inverted = false;
+  }
+  void invert ()
+  {
+    if (likely (s.successful))
+      inverted = !inverted;
+  }
+
+  bool is_empty () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v == INVALID;
+  }
+  hb_codepoint_t get_min () const
+  {
+    hb_codepoint_t v = INVALID;
+    next (&v);
+    return v;
+  }
+  hb_codepoint_t get_max () const
+  {
+    hb_codepoint_t v = INVALID;
+    previous (&v);
+    return v;
+  }
+  unsigned int get_population () const
+  { return inverted ? INVALID - s.get_population () : s.get_population (); }
+
+
+  void add (hb_codepoint_t g) { unlikely (inverted) ? s.del (g) : s.add (g); }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  { return unlikely (inverted) ? (s.del_range (a, b), true) : s.add_range (a, b); }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { inverted ? s.del_array (array, count, stride) : s.add_array (array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return inverted ? s.del_sorted_array (array, count, stride) : s.add_sorted_array (array, count, stride); }
+  template <typename T>
+  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+
+  void del (hb_codepoint_t g) { unlikely (inverted) ? s.add (g) : s.del (g); }
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  { unlikely (inverted) ? (void) s.add_range (a, b) : s.del_range (a, b); }
+
+  bool get (hb_codepoint_t g) const { return s.get (g) ^ inverted; }
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_bit_set_invertible_t& operator << (hb_codepoint_t v)
+  { add (v); return *this; }
+  hb_bit_set_invertible_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+
+  void set (const hb_bit_set_invertible_t &other)
+  {
+    s.set (other.s);
+    if (likely (s.successful))
+      inverted = other.inverted;
+  }
+
+  bool is_equal (const hb_bit_set_invertible_t &other) const
+  {
+    if (likely (inverted == other.inverted))
+      return s.is_equal (other.s);
+    else
+    {
+      /* TODO Add iter_ranges() and use here. */
+      auto it1 = iter ();
+      auto it2 = other.iter ();
+      return hb_all (+ hb_zip (it1, it2)
+		     | hb_map ([](hb_pair_t<hb_codepoint_t, hb_codepoint_t> _) { return _.first == _.second; }));
+    }
+  }
+
+  bool is_subset (const hb_bit_set_invertible_t &larger_set) const
+  {
+    if (unlikely (inverted != larger_set.inverted))
+      return hb_all (hb_iter (s) | hb_map (larger_set.s));
+    else
+      return unlikely (inverted) ? larger_set.s.is_subset (s) : s.is_subset (larger_set.s);
+  }
+
+  protected:
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_invertible_t &other)
+  { s.process (op, other.s); }
+  public:
+  void union_ (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_and, other);
+      else
+	process (hb_bitwise_or, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_gt, other);
+      else
+	process (hb_bitwise_lt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted || other.inverted;
+  }
+  void intersect (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && other.inverted;
+  }
+  void subtract (const hb_bit_set_invertible_t &other)
+  {
+    if (likely (inverted == other.inverted))
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_lt, other);
+      else
+	process (hb_bitwise_gt, other); /* Main branch. */
+    }
+    else
+    {
+      if (unlikely (inverted))
+	process (hb_bitwise_or, other);
+      else
+	process (hb_bitwise_and, other);
+    }
+    if (likely (s.successful))
+      inverted = inverted && !other.inverted;
+  }
+  void symmetric_difference (const hb_bit_set_invertible_t &other)
+  {
+    process (hb_bitwise_xor, other);
+    if (likely (s.successful))
+      inverted = inverted ^ other.inverted;
+  }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.next (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old + 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.next (&v);
+    if (old + 1 < v)
+    {
+      *codepoint = old + 1;
+      return true;
+    }
+
+    v = old;
+    s.next_range (&old, &v);
+
+    *codepoint = v + 1;
+    return *codepoint != INVALID;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (likely (!inverted))
+      return s.previous (codepoint);
+
+    auto old = *codepoint;
+    if (unlikely (old - 1 == INVALID))
+    {
+      *codepoint = INVALID;
+      return false;
+    }
+
+    auto v = old;
+    s.previous (&v);
+
+    if (old - 1 > v || v == INVALID)
+    {
+      *codepoint = old - 1;
+      return true;
+    }
+
+    v = old;
+    s.previous_range (&v, &old);
+
+    *codepoint = v - 1;
+    return *codepoint != INVALID;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.next_range (first, last);
+
+    if (!next (last))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *first = *last;
+    s.next (last);
+    --*last;
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    if (likely (!inverted))
+      return s.previous_range (first, last);
+
+    if (!previous (first))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    *last = *first;
+    s.previous (first);
+    ++*first;
+    return true;
+  }
+
+  static constexpr hb_codepoint_t INVALID = hb_bit_set_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_set_invertible_t &s_ = Null (hb_bit_set_invertible_t),
+	    bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
+
+    protected:
+    const hb_bit_set_invertible_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+};
+
+
+#endif /* HB_BIT_SET_INVERTIBLE_HH */

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

@@ -0,0 +1,808 @@
+/*
+ * Copyright © 2012,2017  Google, Inc.
+ * Copyright © 2021 Behdad Esfahbod
+ *
+ *  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_BIT_SET_HH
+#define HB_BIT_SET_HH
+
+#include "hb.hh"
+#include "hb-bit-page.hh"
+#include "hb-machinery.hh"
+
+
+struct hb_bit_set_t
+{
+  hb_bit_set_t () { init (); }
+  ~hb_bit_set_t () { fini (); }
+
+  hb_bit_set_t (const hb_bit_set_t& other) : hb_bit_set_t () { set (other); }
+  void operator= (const hb_bit_set_t& other) { set (other); }
+  // TODO Add move construtor/assign
+  // TODO Add constructor for Iterator; with specialization for (sorted) vector / array?
+
+  void init ()
+  {
+    successful = true;
+    population = 0;
+    last_page_lookup = 0;
+    page_map.init ();
+    pages.init ();
+  }
+  void fini ()
+  {
+    page_map.fini ();
+    pages.fini ();
+  }
+
+  using page_t = hb_bit_page_t;
+  struct page_map_t
+  {
+    int cmp (const page_map_t &o) const { return cmp (o.major); }
+    int cmp (uint32_t o_major) const { return (int) o_major - (int) major; }
+
+    uint32_t major;
+    uint32_t index;
+  };
+
+  bool successful; /* Allocations successful */
+  mutable unsigned int population;
+  mutable unsigned int last_page_lookup;
+  hb_sorted_vector_t<page_map_t> page_map;
+  hb_vector_t<page_t> pages;
+
+  void err () { if (successful) successful = false; } /* TODO Remove */
+  bool in_error () const { return !successful; }
+
+  bool resize (unsigned int count)
+  {
+    if (unlikely (!successful)) return false;
+    if (unlikely (!pages.resize (count) || !page_map.resize (count)))
+    {
+      pages.resize (page_map.length);
+      successful = false;
+      return false;
+    }
+    return true;
+  }
+
+  void reset ()
+  {
+    successful = true;
+    clear ();
+  }
+
+  void clear ()
+  {
+    resize (0);
+    if (likely (successful))
+      population = 0;
+  }
+  bool is_empty () const
+  {
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      if (!pages[i].is_empty ())
+	return false;
+    return true;
+  }
+  explicit operator bool () const { return !is_empty (); }
+
+  private:
+  void dirty () { population = UINT_MAX; }
+  public:
+
+  void add (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (g == INVALID)) return;
+    dirty ();
+    page_t *page = page_for (g, true); if (unlikely (!page)) return;
+    page->add (g);
+  }
+  bool add_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (unlikely (a > b || a == INVALID || b == INVALID)) return false;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    if (ma == mb)
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, b);
+    }
+    else
+    {
+      page_t *page = page_for (a, true); if (unlikely (!page)) return false;
+      page->add_range (a, major_start (ma + 1) - 1);
+
+      for (unsigned int m = ma + 1; m < mb; m++)
+      {
+	page = page_for (major_start (m), true); if (unlikely (!page)) return false;
+	page->init1 ();
+      }
+
+      page = page_for (b, true); if (unlikely (!page)) return false;
+      page->add_range (major_start (mb), b);
+    }
+    return true;
+  }
+
+  template <typename T>
+  void set_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (!successful)) return;
+    if (!count) return;
+    dirty ();
+    hb_codepoint_t g = *array;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return;
+      unsigned int start = major_start (m);
+      unsigned int end = major_start (m + 1);
+      do
+      {
+        if (v || page) /* The v check is to optimize out the page check if v is true. */
+	  page->set (g, v);
+
+	array = &StructAtOffsetUnaligned<T> (array, stride);
+	count--;
+      }
+      while (count && (g = *array, start <= g && g < end));
+    }
+  }
+
+  template <typename T>
+  void add_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (true, array, count, stride); }
+  template <typename T>
+  void add_array (const hb_array_t<const T>& arr) { add_array (&arr, arr.len ()); }
+
+  template <typename T>
+  void del_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { set_array (false, array, count, stride); }
+  template <typename T>
+  void del_array (const hb_array_t<const T>& arr) { del_array (&arr, arr.len ()); }
+
+  /* Might return false if array looks unsorted.
+   * Used for faster rejection of corrupt data. */
+  template <typename T>
+  bool set_sorted_array (bool v, const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  {
+    if (unlikely (!successful)) return true; /* https://github.com/harfbuzz/harfbuzz/issues/657 */
+    if (!count) return true;
+    dirty ();
+    hb_codepoint_t g = *array;
+    hb_codepoint_t last_g = g;
+    while (count)
+    {
+      unsigned int m = get_major (g);
+      page_t *page = page_for (g, v); if (unlikely (v && !page)) return false;
+      unsigned int end = major_start (m + 1);
+      do
+      {
+	/* If we try harder we can change the following comparison to <=;
+	 * Not sure if it's worth it. */
+	if (g < last_g) return false;
+	last_g = g;
+
+        if (v || page) /* The v check is to optimize out the page check if v is true. */
+	  page->add (g);
+
+	array = (const T *) ((const char *) array + stride);
+	count--;
+      }
+      while (count && (g = *array, g < end));
+    }
+    return true;
+  }
+
+  template <typename T>
+  bool add_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (true, array, count, stride); }
+  template <typename T>
+  bool add_sorted_array (const hb_sorted_array_t<const T>& arr) { return add_sorted_array (&arr, arr.len ()); }
+
+  template <typename T>
+  bool del_sorted_array (const T *array, unsigned int count, unsigned int stride=sizeof(T))
+  { return set_sorted_array (false, array, count, stride); }
+  template <typename T>
+  bool del_sorted_array (const hb_sorted_array_t<const T>& arr) { return del_sorted_array (&arr, arr.len ()); }
+
+  void del (hb_codepoint_t g)
+  {
+    if (unlikely (!successful)) return;
+    page_t *page = page_for (g);
+    if (!page)
+      return;
+    dirty ();
+    page->del (g);
+  }
+
+  private:
+  void del_pages (int ds, int de)
+  {
+    if (ds <= de)
+    {
+      // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+      // before attempting to rewrite the page map.
+      hb_vector_t<unsigned> compact_workspace;
+      if (unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+      unsigned int write_index = 0;
+      for (unsigned int i = 0; i < page_map.length; i++)
+      {
+	int m = (int) page_map[i].major;
+	if (m < ds || de < m)
+	  page_map[write_index++] = page_map[i];
+      }
+      compact (compact_workspace, write_index);
+      resize (write_index);
+    }
+  }
+
+
+  public:
+  void del_range (hb_codepoint_t a, hb_codepoint_t b)
+  {
+    if (unlikely (!successful)) return;
+    if (unlikely (a > b || a == INVALID)) return;
+    dirty ();
+    unsigned int ma = get_major (a);
+    unsigned int mb = get_major (b);
+    /* Delete pages from ds through de if ds <= de. */
+    int ds = (a == major_start (ma))? (int) ma: (int) (ma + 1);
+    int de = (b + 1 == major_start (mb + 1))? (int) mb: ((int) mb - 1);
+    if (ds > de || (int) ma < ds)
+    {
+      page_t *page = page_for (a);
+      if (page)
+      {
+	if (ma == mb)
+	  page->del_range (a, b);
+	else
+	  page->del_range (a, major_start (ma + 1) - 1);
+      }
+    }
+    if (de < (int) mb && ma != mb)
+    {
+      page_t *page = page_for (b);
+      if (page)
+	page->del_range (major_start (mb), b);
+    }
+    del_pages (ds, de);
+  }
+
+  bool get (hb_codepoint_t g) const
+  {
+    const page_t *page = page_for (g);
+    if (!page)
+      return false;
+    return page->get (g);
+  }
+
+  /* Has interface. */
+  static constexpr bool SENTINEL = false;
+  typedef bool value_t;
+  value_t operator [] (hb_codepoint_t k) const { return get (k); }
+  bool has (hb_codepoint_t k) const { return (*this)[k] != SENTINEL; }
+  /* Predicate. */
+  bool operator () (hb_codepoint_t k) const { return has (k); }
+
+  /* Sink interface. */
+  hb_bit_set_t& operator << (hb_codepoint_t v)
+  { add (v); return *this; }
+  hb_bit_set_t& operator << (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& range)
+  { add_range (range.first, range.second); return *this; }
+
+  bool intersects (hb_codepoint_t first, hb_codepoint_t last) const
+  {
+    hb_codepoint_t c = first - 1;
+    return next (&c) && c <= last;
+  }
+  void set (const hb_bit_set_t &other)
+  {
+    if (unlikely (!successful)) return;
+    unsigned int count = other.pages.length;
+    if (unlikely (!resize (count)))
+      return;
+    population = other.population;
+
+    /* TODO switch to vector operator =. */
+    hb_memcpy ((void *) pages, (const void *) other.pages, count * pages.item_size);
+    hb_memcpy ((void *) page_map, (const void *) other.page_map, count * page_map.item_size);
+  }
+
+  bool is_equal (const hb_bit_set_t &other) const
+  {
+    if (has_population () && other.has_population () &&
+	get_population () != other.get_population ())
+      return false;
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+
+    unsigned int a = 0, b = 0;
+    for (; a < na && b < nb; )
+    {
+      if (page_at (a).is_empty ()) { a++; continue; }
+      if (other.page_at (b).is_empty ()) { b++; continue; }
+      if (page_map[a].major != other.page_map[b].major ||
+	  !page_at (a).is_equal (other.page_at (b)))
+	return false;
+      a++;
+      b++;
+    }
+    for (; a < na; a++)
+      if (!page_at (a).is_empty ()) { return false; }
+    for (; b < nb; b++)
+      if (!other.page_at (b).is_empty ()) { return false; }
+
+    return true;
+  }
+
+  bool is_subset (const hb_bit_set_t &larger_set) const
+  {
+    if (has_population () && larger_set.has_population () &&
+	get_population () != larger_set.get_population ())
+      return false;
+
+    uint32_t spi = 0;
+    for (uint32_t lpi = 0; spi < page_map.length && lpi < larger_set.page_map.length; lpi++)
+    {
+      uint32_t spm = page_map[spi].major;
+      uint32_t lpm = larger_set.page_map[lpi].major;
+      auto sp = page_at (spi);
+      auto lp = larger_set.page_at (lpi);
+
+      if (spm < lpm && !sp.is_empty ())
+        return false;
+
+      if (lpm < spm)
+        continue;
+
+      if (!sp.is_subset (lp))
+        return false;
+
+      spi++;
+    }
+
+    while (spi < page_map.length)
+      if (!page_at (spi++).is_empty ())
+        return false;
+
+    return true;
+  }
+
+  private:
+  bool allocate_compact_workspace (hb_vector_t<unsigned>& workspace)
+  {
+    if (unlikely (!workspace.resize (pages.length)))
+    {
+      successful = false;
+      return false;
+    }
+
+    return true;
+  }
+
+  /*
+   * workspace should be a pre-sized vector allocated to hold at exactly pages.length
+   * elements.
+   */
+  void compact (hb_vector_t<unsigned>& workspace,
+                unsigned int length)
+  {
+    assert(workspace.length == pages.length);
+    hb_vector_t<unsigned>& old_index_to_page_map_index = workspace;
+
+    hb_fill (old_index_to_page_map_index.writer(), 0xFFFFFFFF);
+    for (unsigned i = 0; i < length; i++)
+      old_index_to_page_map_index[page_map[i].index] =  i;
+
+    compact_pages (old_index_to_page_map_index);
+  }
+  void compact_pages (const hb_vector_t<unsigned>& old_index_to_page_map_index)
+  {
+    unsigned int write_index = 0;
+    for (unsigned int i = 0; i < pages.length; i++)
+    {
+      if (old_index_to_page_map_index[i] == 0xFFFFFFFF) continue;
+
+      if (write_index < i)
+	pages[write_index] = pages[i];
+
+      page_map[old_index_to_page_map_index[i]].index = write_index;
+      write_index++;
+    }
+  }
+  public:
+
+  template <typename Op>
+  void process (const Op& op, const hb_bit_set_t &other)
+  {
+    const bool passthru_left = op (1, 0);
+    const bool passthru_right = op (0, 1);
+
+    if (unlikely (!successful)) return;
+
+    dirty ();
+
+    unsigned int na = pages.length;
+    unsigned int nb = other.pages.length;
+    unsigned int next_page = na;
+
+    unsigned int count = 0, newCount = 0;
+    unsigned int a = 0, b = 0;
+    unsigned int write_index = 0;
+
+    // Pre-allocate the workspace that compact() will need so we can bail on allocation failure
+    // before attempting to rewrite the page map.
+    hb_vector_t<unsigned> compact_workspace;
+    if (!passthru_left && unlikely (!allocate_compact_workspace (compact_workspace))) return;
+
+    for (; a < na && b < nb; )
+    {
+      if (page_map[a].major == other.page_map[b].major)
+      {
+	if (!passthru_left)
+	{
+	  // Move page_map entries that we're keeping from the left side set
+	  // to the front of the page_map vector. This isn't necessary if
+	  // passthru_left is set since no left side pages will be removed
+	  // in that case.
+	  if (write_index < a)
+	    page_map[write_index] = page_map[a];
+	  write_index++;
+	}
+
+	count++;
+	a++;
+	b++;
+      }
+      else if (page_map[a].major < other.page_map[b].major)
+      {
+	if (passthru_left)
+	  count++;
+	a++;
+      }
+      else
+      {
+	if (passthru_right)
+	  count++;
+	b++;
+      }
+    }
+    if (passthru_left)
+      count += na - a;
+    if (passthru_right)
+      count += nb - b;
+
+    if (!passthru_left)
+    {
+      na  = write_index;
+      next_page = write_index;
+      compact (compact_workspace, write_index);
+    }
+
+    if (unlikely (!resize (count)))
+      return;
+
+    newCount = count;
+
+    /* Process in-place backward. */
+    a = na;
+    b = nb;
+    for (; a && b; )
+    {
+      if (page_map[a - 1].major == other.page_map[b - 1].major)
+      {
+	a--;
+	b--;
+	count--;
+	page_map[count] = page_map[a];
+	page_at (count).v = op (page_at (a).v, other.page_at (b).v);
+      }
+      else if (page_map[a - 1].major > other.page_map[b - 1].major)
+      {
+	a--;
+	if (passthru_left)
+	{
+	  count--;
+	  page_map[count] = page_map[a];
+	}
+      }
+      else
+      {
+	b--;
+	if (passthru_right)
+	{
+	  count--;
+	  page_map[count].major = other.page_map[b].major;
+	  page_map[count].index = next_page++;
+	  page_at (count).v = other.page_at (b).v;
+	}
+      }
+    }
+    if (passthru_left)
+      while (a)
+      {
+	a--;
+	count--;
+	page_map[count] = page_map [a];
+      }
+    if (passthru_right)
+      while (b)
+      {
+	b--;
+	count--;
+	page_map[count].major = other.page_map[b].major;
+	page_map[count].index = next_page++;
+	page_at (count).v = other.page_at (b).v;
+      }
+    assert (!count);
+    resize (newCount);
+  }
+
+  void union_ (const hb_bit_set_t &other) { process (hb_bitwise_or, other); }
+  void intersect (const hb_bit_set_t &other) { process (hb_bitwise_and, other); }
+  void subtract (const hb_bit_set_t &other) { process (hb_bitwise_gt, other); }
+  void symmetric_difference (const hb_bit_set_t &other) { process (hb_bitwise_xor, other); }
+
+  bool next (hb_codepoint_t *codepoint) const
+  {
+    // TODO: this should be merged with prev() as both implementations
+    //       are very similar.
+    if (unlikely (*codepoint == INVALID)) {
+      *codepoint = get_min ();
+      return *codepoint != INVALID;
+    }
+
+    const auto* page_map_array = page_map.arrayZ;
+    unsigned int major = get_major (*codepoint);
+    unsigned int i = last_page_lookup;
+
+    if (unlikely (i >= page_map.length || page_map_array[i].major != major))
+    {
+      page_map.bfind (major, &i, HB_NOT_FOUND_STORE_CLOSEST);
+      if (i >= page_map.length) {
+        *codepoint = INVALID;
+        return false;
+      }
+    }
+
+    const auto* pages_array = pages.arrayZ;
+    const page_map_t &current = page_map_array[i];
+    if (likely (current.major == major))
+    {
+      if (pages_array[current.index].next (codepoint))
+      {
+        *codepoint += current.major * page_t::PAGE_BITS;
+        last_page_lookup = i;
+        return true;
+      }
+      i++;
+    }
+
+    for (; i < page_map.length; i++)
+    {
+      const page_map_t &current = page_map.arrayZ[i];
+      hb_codepoint_t m = pages_array[current.index].get_min ();
+      if (m != INVALID)
+      {
+	*codepoint = current.major * page_t::PAGE_BITS + m;
+        last_page_lookup = i;
+	return true;
+      }
+    }
+    last_page_lookup = 0;
+    *codepoint = INVALID;
+    return false;
+  }
+  bool previous (hb_codepoint_t *codepoint) const
+  {
+    if (unlikely (*codepoint == INVALID)) {
+      *codepoint = get_max ();
+      return *codepoint != INVALID;
+    }
+
+    page_map_t map = {get_major (*codepoint), 0};
+    unsigned int i;
+    page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST);
+    if (i < page_map.length && page_map[i].major == map.major)
+    {
+      if (pages[page_map[i].index].previous (codepoint))
+      {
+	*codepoint += page_map[i].major * page_t::PAGE_BITS;
+	return true;
+      }
+    }
+    i--;
+    for (; (int) i >= 0; i--)
+    {
+      hb_codepoint_t m = pages[page_map[i].index].get_max ();
+      if (m != INVALID)
+      {
+	*codepoint = page_map[i].major * page_t::PAGE_BITS + m;
+	return true;
+      }
+    }
+    *codepoint = INVALID;
+    return false;
+  }
+  bool next_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *last;
+    if (!next (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (next (&i) && i == *last + 1)
+      (*last)++;
+
+    return true;
+  }
+  bool previous_range (hb_codepoint_t *first, hb_codepoint_t *last) const
+  {
+    hb_codepoint_t i;
+
+    i = *first;
+    if (!previous (&i))
+    {
+      *last = *first = INVALID;
+      return false;
+    }
+
+    /* TODO Speed up. */
+    *last = *first = i;
+    while (previous (&i) && i == *first - 1)
+      (*first)--;
+
+    return true;
+  }
+
+  bool has_population () const { return population != UINT_MAX; }
+  unsigned int get_population () const
+  {
+    if (has_population ())
+      return population;
+
+    unsigned int pop = 0;
+    unsigned int count = pages.length;
+    for (unsigned int i = 0; i < count; i++)
+      pop += pages[i].get_population ();
+
+    population = pop;
+    return pop;
+  }
+  hb_codepoint_t get_min () const
+  {
+    unsigned count = pages.length;
+    for (unsigned i = 0; i < count; i++)
+    {
+      const auto& map = page_map[i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_min ();
+    }
+    return INVALID;
+  }
+  hb_codepoint_t get_max () const
+  {
+    unsigned count = pages.length;
+    for (signed i = count - 1; i >= 0; i--)
+    {
+      const auto& map = page_map[(unsigned) i];
+      const auto& page = pages[map.index];
+
+      if (!page.is_empty ())
+	return map.major * page_t::PAGE_BITS + page.get_max ();
+    }
+    return INVALID;
+  }
+
+  static constexpr hb_codepoint_t INVALID = page_t::INVALID;
+
+  /*
+   * Iterator implementation.
+   */
+  struct iter_t : hb_iter_with_fallback_t<iter_t, hb_codepoint_t>
+  {
+    static constexpr bool is_sorted_iterator = true;
+    iter_t (const hb_bit_set_t &s_ = Null (hb_bit_set_t),
+	    bool init = true) : s (&s_), v (INVALID), l(0)
+    {
+      if (init)
+      {
+	l = s->get_population () + 1;
+	__next__ ();
+      }
+    }
+
+    typedef hb_codepoint_t __item_t__;
+    hb_codepoint_t __item__ () const { return v; }
+    bool __more__ () const { return v != INVALID; }
+    void __next__ () { s->next (&v); if (l) l--; }
+    void __prev__ () { s->previous (&v); }
+    unsigned __len__ () const { return l; }
+    iter_t end () const { return iter_t (*s, false); }
+    bool operator != (const iter_t& o) const
+    { return s != o.s || v != o.v; }
+
+    protected:
+    const hb_bit_set_t *s;
+    hb_codepoint_t v;
+    unsigned l;
+  };
+  iter_t iter () const { return iter_t (*this); }
+  operator iter_t () const { return iter (); }
+
+  protected:
+
+  page_t *page_for (hb_codepoint_t g, bool insert = false)
+  {
+    page_map_t map = {get_major (g), pages.length};
+    unsigned int i;
+    if (!page_map.bfind (map, &i, HB_NOT_FOUND_STORE_CLOSEST))
+    {
+      if (!insert)
+        return nullptr;
+
+      if (unlikely (!resize (pages.length + 1)))
+	return nullptr;
+
+      pages[map.index].init0 ();
+      memmove (page_map + i + 1,
+	       page_map + i,
+	       (page_map.length - 1 - i) * page_map.item_size);
+      page_map[i] = map;
+    }
+    return &pages[page_map[i].index];
+  }
+  const page_t *page_for (hb_codepoint_t g) const
+  {
+    page_map_t key = {get_major (g)};
+    const page_map_t *found = page_map.bsearch (key);
+    if (found)
+      return &pages[found->index];
+    return nullptr;
+  }
+  page_t &page_at (unsigned int i) { return pages[page_map[i].index]; }
+  const page_t &page_at (unsigned int i) const { return pages[page_map[i].index]; }
+  unsigned int get_major (hb_codepoint_t g) const { return g / page_t::PAGE_BITS; }
+  hb_codepoint_t major_start (unsigned int major) const { return major * page_t::PAGE_BITS; }
+};
+
+
+#endif /* HB_BIT_SET_HH */

+ 91 - 32
thirdparty/harfbuzz/src/hb-blob.cc

@@ -71,15 +71,53 @@ hb_blob_create (const char        *data,
 		hb_memory_mode_t   mode,
 		void              *user_data,
 		hb_destroy_func_t  destroy)
+{
+  if (!length)
+  {
+    if (destroy)
+      destroy (user_data);
+    return hb_blob_get_empty ();
+  }
+
+  hb_blob_t *blob = hb_blob_create_or_fail (data, length, mode,
+					    user_data, destroy);
+  return likely (blob) ? blob : hb_blob_get_empty ();
+}
+
+/**
+ * hb_blob_create_or_fail: (skip)
+ * @data: Pointer to blob data.
+ * @length: Length of @data in bytes.
+ * @mode: Memory mode for @data.
+ * @user_data: Data parameter to pass to @destroy.
+ * @destroy: (nullable): Callback to call when @data is not needed anymore.
+ *
+ * Creates a new "blob" object wrapping @data.  The @mode parameter is used
+ * to negotiate ownership and lifecycle of @data.
+ *
+ * Note that this function returns a freshly-allocated empty blob even if @length
+ * is zero. This is in contrast to hb_blob_create(), which returns the singleton
+ * empty blob (as returned by hb_blob_get_empty()) if @length is zero.
+ *
+ * Return value: New blob, or %NULL if failed.  Destroy with hb_blob_destroy().
+ *
+ * Since: 2.8.2
+ **/
+hb_blob_t *
+hb_blob_create_or_fail (const char        *data,
+			unsigned int       length,
+			hb_memory_mode_t   mode,
+			void              *user_data,
+			hb_destroy_func_t  destroy)
 {
   hb_blob_t *blob;
 
-  if (!length ||
-      length >= 1u << 31 ||
-      !(blob = hb_object_create<hb_blob_t> ())) {
+  if (length >= 1u << 31 ||
+      !(blob = hb_object_create<hb_blob_t> ()))
+  {
     if (destroy)
       destroy (user_data);
-    return hb_blob_get_empty ();
+    return nullptr;
   }
 
   blob->data = data;
@@ -91,9 +129,10 @@ hb_blob_create (const char        *data,
 
   if (blob->mode == HB_MEMORY_MODE_DUPLICATE) {
     blob->mode = HB_MEMORY_MODE_READONLY;
-    if (!blob->try_make_writable ()) {
+    if (!blob->try_make_writable ())
+    {
       hb_blob_destroy (blob);
-      return hb_blob_get_empty ();
+      return nullptr;
     }
   }
 
@@ -226,7 +265,7 @@ hb_blob_destroy (hb_blob_t *blob)
 
   blob->fini_shallow ();
 
-  free (blob);
+  hb_free (blob);
 }
 
 /**
@@ -452,7 +491,7 @@ hb_blob_t::try_make_writable ()
 
   char *new_data;
 
-  new_data = (char *) malloc (this->length);
+  new_data = (char *) hb_malloc (this->length);
   if (unlikely (!new_data))
     return false;
 
@@ -463,7 +502,7 @@ hb_blob_t::try_make_writable ()
   this->mode = HB_MEMORY_MODE_WRITABLE;
   this->data = new_data;
   this->user_data = new_data;
-  this->destroy = free;
+  this->destroy = hb_free;
 
   return true;
 }
@@ -517,7 +556,7 @@ _hb_mapped_file_destroy (void *file_)
   assert (0); // If we don't have mmap we shouldn't reach here
 #endif
 
-  free (file);
+  hb_free (file);
 }
 #endif
 
@@ -528,7 +567,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
   size_t name_len = strlen (file_name);
   size_t len = name_len + sizeof (_PATH_RSRCFORKSPEC);
 
-  char *rsrc_name = (char *) malloc (len);
+  char *rsrc_name = (char *) hb_malloc (len);
   if (unlikely (!rsrc_name)) return -1;
 
   strncpy (rsrc_name, file_name, name_len);
@@ -536,7 +575,7 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
 	   sizeof (_PATH_RSRCFORKSPEC) - 1);
 
   int fd = open (rsrc_name, O_RDONLY | O_BINARY, 0);
-  free (rsrc_name);
+  hb_free (rsrc_name);
 
   if (fd != -1)
   {
@@ -561,17 +600,37 @@ _open_resource_fork (const char *file_name, hb_mapped_file_t *file)
  * Creates a new blob containing the data from the
  * specified binary font file.
  *
- * Returns: An #hb_blob_t pointer with the content of the file
+ * Returns: An #hb_blob_t pointer with the content of the file,
+ * or hb_blob_get_empty() if failed.
  *
  * Since: 1.7.7
  **/
 hb_blob_t *
 hb_blob_create_from_file (const char *file_name)
+{
+  hb_blob_t *blob = hb_blob_create_from_file_or_fail (file_name);
+  return likely (blob) ? blob : hb_blob_get_empty ();
+}
+
+/**
+ * hb_blob_create_from_file_or_fail:
+ * @file_name: A font filename
+ *
+ * Creates a new blob containing the data from the
+ * specified binary font file.
+ *
+ * Returns: An #hb_blob_t pointer with the content of the file,
+ * or %NULL if failed.
+ *
+ * Since: 2.8.2
+ **/
+hb_blob_t *
+hb_blob_create_from_file_or_fail (const char *file_name)
 {
   /* Adopted from glib's gmappedfile.c with Matthias Clasen and
      Allison Lortie permission but changed a lot to suit our need. */
 #if defined(HAVE_MMAP) && !defined(HB_NO_MMAP)
-  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
   if (unlikely (!file)) return hb_blob_get_empty ();
 
   int fd = open (file_name, O_RDONLY | O_BINARY, 0);
@@ -601,22 +660,22 @@ hb_blob_create_from_file (const char *file_name)
 
   close (fd);
 
-  return hb_blob_create (file->contents, file->length,
-			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
-			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+  return hb_blob_create_or_fail (file->contents, file->length,
+				 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+				 (hb_destroy_func_t) _hb_mapped_file_destroy);
 
 fail:
   close (fd);
 fail_without_close:
-  free (file);
+  hb_free (file);
 
 #elif defined(_WIN32) && !defined(HB_NO_MMAP)
-  hb_mapped_file_t *file = (hb_mapped_file_t *) calloc (1, sizeof (hb_mapped_file_t));
+  hb_mapped_file_t *file = (hb_mapped_file_t *) hb_calloc (1, sizeof (hb_mapped_file_t));
   if (unlikely (!file)) return hb_blob_get_empty ();
 
   HANDLE fd;
   unsigned int size = strlen (file_name) + 1;
-  wchar_t * wchar_file_name = (wchar_t *) 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;
   mbstowcs (wchar_file_name, file_name, size);
 #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
@@ -636,7 +695,7 @@ fail_without_close:
 		    OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,
 		    nullptr);
 #endif
-  free (wchar_file_name);
+  hb_free (wchar_file_name);
 
   if (unlikely (fd == INVALID_HANDLE_VALUE)) goto fail_without_close;
 
@@ -661,22 +720,22 @@ fail_without_close:
   if (unlikely (!file->contents)) goto fail;
 
   CloseHandle (fd);
-  return hb_blob_create (file->contents, file->length,
-			 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
-			 (hb_destroy_func_t) _hb_mapped_file_destroy);
+  return hb_blob_create_or_fail (file->contents, file->length,
+				 HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, (void *) file,
+				 (hb_destroy_func_t) _hb_mapped_file_destroy);
 
 fail:
   CloseHandle (fd);
 fail_without_close:
-  free (file);
+  hb_free (file);
 
 #endif
 
   /* The following tries to read a file without knowing its size beforehand
      It's used as a fallback for systems without mmap or to read from pipes */
   unsigned long len = 0, allocated = BUFSIZ * 16;
-  char *data = (char *) malloc (allocated);
-  if (unlikely (!data)) return hb_blob_get_empty ();
+  char *data = (char *) hb_malloc (allocated);
+  if (unlikely (!data)) return nullptr;
 
   FILE *fp = fopen (file_name, "rb");
   if (unlikely (!fp)) goto fread_fail_without_close;
@@ -689,7 +748,7 @@ fail_without_close:
       /* Don't allocate and go more than ~536MB, our mmap reader still
 	 can cover files like that but lets limit our fallback reader */
       if (unlikely (allocated > (2 << 28))) goto fread_fail;
-      char *new_data = (char *) realloc (data, allocated);
+      char *new_data = (char *) hb_realloc (data, allocated);
       if (unlikely (!new_data)) goto fread_fail;
       data = new_data;
     }
@@ -706,13 +765,13 @@ fail_without_close:
   }
 	fclose (fp);
 
-  return hb_blob_create (data, len, HB_MEMORY_MODE_WRITABLE, data,
-			 (hb_destroy_func_t) free);
+  return hb_blob_create_or_fail (data, len, HB_MEMORY_MODE_WRITABLE, data,
+				 (hb_destroy_func_t) hb_free);
 
 fread_fail:
   fclose (fp);
 fread_fail_without_close:
-  free (data);
-  return hb_blob_get_empty ();
+  hb_free (data);
+  return nullptr;
 }
 #endif /* !HB_NO_OPEN */

+ 10 - 0
thirdparty/harfbuzz/src/hb-blob.h

@@ -90,9 +90,19 @@ hb_blob_create (const char        *data,
 		void              *user_data,
 		hb_destroy_func_t  destroy);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_or_fail (const char        *data,
+			unsigned int       length,
+			hb_memory_mode_t   mode,
+			void              *user_data,
+			hb_destroy_func_t  destroy);
+
 HB_EXTERN hb_blob_t *
 hb_blob_create_from_file (const char *file_name);
 
+HB_EXTERN hb_blob_t *
+hb_blob_create_from_file_or_fail (const char *file_name);
+
 /* Always creates with MEMORY_MODE_READONLY.
  * Even if the parent blob is writable, we don't
  * want the user of the sub-blob to be able to

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

@@ -88,7 +88,7 @@ struct hb_blob_ptr_t
   const T * get () const { return b->as<T> (); }
   hb_blob_t * get_blob () const { return b.get_raw (); }
   unsigned int get_length () const { return b.get ()->length; }
-  void destroy () { hb_blob_destroy (b.get ()); b = nullptr; }
+  void destroy () { hb_blob_destroy (b.get_raw ()); b = nullptr; }
 
   private:
   hb_nonnull_ptr_t<hb_blob_t> b;

+ 657 - 532
thirdparty/harfbuzz/src/hb-buffer-deserialize-json.hh

@@ -1,29 +1,30 @@
+
 #line 1 "hb-buffer-deserialize-json.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
-*/
+ * 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_JSON_HH
 #define HB_BUFFER_DESERIALIZE_JSON_HH
@@ -31,158 +32,446 @@
 #include "hb.hh"
 
 
-#line 35 "hb-buffer-deserialize-json.hh"
+#line 36 "hb-buffer-deserialize-json.hh"
 static const unsigned char _deserialize_json_trans_keys[] = {
-	1u, 0u, 0u, 18u, 0u, 2u, 10u, 15u,
-	16u, 17u, 2u, 2u, 0u, 7u, 0u, 6u,
-	5u, 6u, 0u, 19u, 0u, 19u, 0u, 19u,
-	2u, 2u, 0u, 7u, 0u, 6u, 5u, 6u,
-	0u, 19u, 0u, 19u, 14u, 14u, 2u, 2u,
-	0u, 7u, 0u, 6u, 0u, 19u, 0u, 19u,
-	16u, 17u, 2u, 2u, 0u, 7u, 0u, 6u,
-	5u, 6u, 0u, 19u, 0u, 19u, 2u, 2u,
-	0u, 7u, 0u, 6u, 5u, 6u, 0u, 19u,
-	0u, 19u, 2u, 2u, 0u, 7u, 0u, 6u,
-	2u, 8u, 0u, 19u, 2u, 8u, 0u, 19u,
-	0u, 19u, 2u, 2u, 0u, 7u, 0u, 6u,
-	0u, 19u, 0u, 9u, 0u, 18u, 1u, 0u,
-	0u
+	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, 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, 9u, 123u, 0u, 0u, 0
 };
 
-static const signed char _deserialize_json_char_class[] = {
-	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, 2, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 3, 4, 1, 1, 5,
-	6, 6, 6, 6, 6, 6, 6, 6,
-	6, 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, 8, 9, 1, 1, 1,
-	10, 1, 11, 12, 1, 1, 13, 1,
-	1, 1, 1, 14, 1, 1, 1, 1,
-	1, 1, 1, 1, 15, 1, 1, 16,
-	17, 1, 18, 1, 19, 0
+static const char _deserialize_json_key_spans[] = {
+	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, 50, 49, 
+	59, 117, 59, 117, 117, 1, 50, 49, 
+	117, 85, 115, 0
 };
 
 static const short _deserialize_json_index_offsets[] = {
-	0, 0, 19, 22, 28, 30, 31, 39,
-	46, 48, 68, 88, 108, 109, 117, 124,
-	126, 146, 166, 167, 168, 176, 183, 203,
-	223, 225, 226, 234, 241, 243, 263, 283,
-	284, 292, 299, 301, 321, 341, 342, 350,
-	357, 364, 384, 391, 411, 431, 432, 440,
-	447, 467, 477, 496, 0
+	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, 2083, 
+	2133, 2193, 2311, 2371, 2489, 2607, 2609, 2660, 
+	2710, 2828, 2914, 3030
 };
 
-static const signed char _deserialize_json_indicies[] = {
-	1, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 2, 3, 0, 4, 5, 6,
-	7, 8, 0, 9, 10, 11, 12, 12,
-	0, 0, 0, 0, 0, 0, 13, 13,
-	0, 0, 0, 14, 15, 16, 18, 19,
-	20, 0, 0, 21, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 22, 23, 0, 0, 3,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 24,
-	20, 0, 0, 21, 0, 19, 19, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 22, 25, 25, 0, 0,
-	0, 0, 0, 0, 26, 26, 0, 0,
-	0, 27, 28, 29, 31, 32, 33, 0,
-	0, 34, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 35, 33, 0, 0, 34, 0, 32,
-	32, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 35, 36, 37,
-	37, 0, 0, 0, 0, 0, 0, 38,
-	38, 0, 0, 0, 0, 39, 40, 42,
-	0, 0, 43, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 44, 42, 0, 0, 43, 0,
-	45, 45, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 44, 46,
-	47, 48, 48, 0, 0, 0, 0, 0,
-	0, 49, 49, 0, 0, 0, 50, 51,
-	52, 54, 55, 56, 0, 0, 57, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 58, 56,
-	0, 0, 57, 0, 55, 55, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 58, 59, 59, 0, 0, 0,
-	0, 0, 0, 60, 60, 0, 0, 0,
-	61, 62, 63, 65, 66, 67, 0, 0,
-	68, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	69, 67, 0, 0, 68, 0, 66, 66,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 69, 70, 70, 0,
-	0, 0, 0, 0, 0, 71, 71, 0,
-	72, 0, 0, 73, 74, 76, 75, 75,
-	75, 75, 75, 77, 79, 0, 0, 80,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 81,
-	75, 0, 0, 0, 0, 0, 75, 83,
-	0, 0, 84, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 85, 83, 0, 0, 84, 0,
-	87, 87, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 85, 88,
-	88, 0, 0, 0, 0, 0, 0, 89,
-	89, 0, 0, 0, 0, 90, 91, 83,
-	0, 0, 84, 0, 93, 93, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 85, 94, 0, 0, 95, 0,
-	0, 0, 0, 0, 96, 1, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 2,
+static const char _deserialize_json_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, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 3, 3, 
+	3, 3, 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, 7, 1, 1, 8, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 9, 1, 10, 11, 
+	1, 12, 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, 13, 1, 13, 13, 
+	13, 13, 13, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 13, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 14, 1, 1, 15, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 1, 
+	17, 18, 18, 18, 18, 18, 18, 18, 
+	18, 18, 1, 19, 19, 19, 19, 19, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 19, 1, 1, 1, 1, 1, 
+	1, 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, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 21, 
+	1, 22, 22, 22, 22, 22, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	22, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 3, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 23, 1, 19, 
+	19, 19, 19, 19, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 19, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 20, 1, 1, 1, 18, 18, 
+	18, 18, 18, 18, 18, 18, 18, 18, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 21, 1, 24, 1, 24, 
+	24, 24, 24, 24, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 24, 1, 
+	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, 25, 25, 25, 25, 25, 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, 26, 1, 
+	1, 27, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 1, 29, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 1, 31, 
+	31, 31, 31, 31, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 31, 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, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 33, 1, 31, 31, 31, 
+	31, 31, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 31, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	32, 1, 1, 1, 30, 30, 30, 30, 
+	30, 30, 30, 30, 30, 30, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 33, 1, 34, 1, 35, 1, 35, 
+	35, 35, 35, 35, 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, 1, 1, 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, 36, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 37, 38, 38, 38, 38, 38, 38, 
+	38, 38, 38, 1, 39, 39, 39, 39, 
+	39, 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, 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, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	41, 1, 39, 39, 39, 39, 39, 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, 40, 1, 1, 
+	1, 42, 42, 42, 42, 42, 42, 42, 
+	42, 42, 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, 
+	1, 1, 1, 1, 1, 1, 41, 1, 
+	43, 44, 1, 45, 1, 45, 45, 45, 
+	45, 45, 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, 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, 46, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 47, 1, 1, 48, 
+	49, 49, 49, 49, 49, 49, 49, 49, 
+	49, 1, 50, 51, 51, 51, 51, 51, 
+	51, 51, 51, 51, 1, 52, 52, 52, 
+	52, 52, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 52, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	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, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 54, 1, 52, 52, 52, 52, 52, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 52, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 53, 1, 
+	1, 1, 51, 51, 51, 51, 51, 51, 
+	51, 51, 51, 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, 54, 
+	1, 55, 1, 55, 55, 55, 55, 55, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 1, 
+	1, 1, 1, 1, 56, 1, 56, 56, 
+	56, 56, 56, 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, 57, 1, 1, 58, 59, 59, 
+	59, 59, 59, 59, 59, 59, 59, 1, 
+	60, 61, 61, 61, 61, 61, 61, 61, 
+	61, 61, 1, 62, 62, 62, 62, 62, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 62, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 64, 
+	1, 62, 62, 62, 62, 62, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	62, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 63, 1, 1, 1, 
+	61, 61, 61, 61, 61, 61, 61, 61, 
+	61, 61, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 64, 1, 65, 
+	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, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 66, 1, 66, 66, 66, 66, 
+	66, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 66, 1, 67, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 68, 69, 69, 69, 69, 
+	69, 69, 69, 69, 69, 1, 71, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	70, 70, 70, 70, 70, 70, 70, 70, 
+	72, 70, 73, 73, 73, 73, 73, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 73, 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, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 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, 
+	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, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 70, 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, 1, 1, 
+	1, 1, 1, 1, 1, 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, 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, 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, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 77, 1, 1, 
+	1, 79, 79, 79, 79, 79, 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, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 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, 
+	80, 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, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 81, 1, 81, 81, 81, 
+	81, 81, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 81, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 82, 83, 83, 83, 
+	83, 83, 83, 83, 83, 83, 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, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 77, 1, 1, 1, 84, 84, 
+	84, 84, 84, 84, 84, 84, 84, 84, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 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, 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, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 87, 1, 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, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 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, 
 	0
 };
 
-static const signed char _deserialize_json_index_defaults[] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	75, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0
-};
-
-static const signed char _deserialize_json_cond_targs[] = {
-	0, 1, 2, 2, 3, 4, 18, 24,
-	37, 45, 5, 12, 6, 7, 8, 9,
-	11, 8, 9, 11, 10, 2, 49, 10,
-	49, 13, 14, 15, 16, 17, 15, 16,
-	17, 10, 2, 49, 19, 20, 21, 22,
-	23, 22, 10, 2, 49, 23, 25, 31,
-	26, 27, 28, 29, 30, 28, 29, 30,
-	10, 2, 49, 32, 33, 34, 35, 36,
-	34, 35, 36, 10, 2, 49, 38, 39,
-	40, 43, 44, 40, 41, 42, 41, 10,
-	2, 49, 43, 10, 2, 49, 44, 44,
-	46, 47, 43, 48, 48, 48, 49, 50,
-	51, 0
+static const char _deserialize_json_trans_targs[] = {
+	1, 0, 2, 2, 3, 4, 18, 24, 
+	37, 45, 5, 12, 6, 7, 8, 9, 
+	11, 9, 11, 10, 2, 49, 10, 49, 
+	13, 14, 15, 16, 17, 16, 17, 10, 
+	2, 49, 19, 20, 21, 22, 23, 10, 
+	2, 49, 23, 25, 31, 26, 27, 28, 
+	29, 30, 29, 30, 10, 2, 49, 32, 
+	33, 34, 35, 36, 35, 36, 10, 2, 
+	49, 38, 39, 40, 43, 44, 40, 41, 
+	42, 10, 2, 49, 10, 2, 49, 44, 
+	46, 47, 43, 48, 48, 49, 50, 51
 };
 
-static const signed char _deserialize_json_cond_actions[] = {
-	0, 0, 1, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 2, 2,
-	2, 0, 0, 0, 3, 3, 4, 0,
-	5, 0, 0, 2, 2, 2, 0, 0,
-	0, 6, 6, 7, 0, 0, 0, 2,
-	2, 0, 8, 8, 9, 0, 0, 0,
-	0, 0, 2, 2, 2, 0, 0, 0,
-	10, 10, 11, 0, 0, 2, 2, 2,
-	0, 0, 0, 12, 12, 13, 0, 0,
-	2, 14, 14, 0, 15, 0, 0, 16,
-	16, 17, 0, 18, 18, 19, 0, 15,
-	0, 0, 20, 20, 0, 21, 0, 0,
-	0, 0
+static const char _deserialize_json_trans_actions[] = {
+	0, 0, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 2, 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, 2, 14, 14, 0, 15, 
+	0, 16, 16, 17, 18, 18, 19, 15, 
+	0, 0, 20, 20, 21, 0, 0, 0
 };
 
 static const int deserialize_json_start = 1;
@@ -197,411 +486,247 @@ static const int deserialize_json_en_main = 1;
 
 static hb_bool_t
 _hb_buffer_deserialize_json (hb_buffer_t *buffer,
-const char *buf,
-unsigned int buf_len,
-const char **end_ptr,
-hb_font_t *font)
+				    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++;
-	if (p < pe && *p == (buffer->len ? ',' : '['))
-		{
-		*end_ptr = ++p;
-	}
-	
-	const char *tok = nullptr;
-	int cs;
-	hb_glyph_info_t info = {0};
-	hb_glyph_position_t pos = {0};
-	
-#line 223 "hb-buffer-deserialize-json.hh"
+  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++;
+  if (p < pe && *p == (buffer->len ? ',' : '['))
+  {
+    *end_ptr = ++p;
+  }
+
+  const char *tok = nullptr;
+  int cs;
+  hb_glyph_info_t info = {0};
+  hb_glyph_position_t pos = {0};
+  
+#line 512 "hb-buffer-deserialize-json.hh"
 	{
-		cs = (int)deserialize_json_start;
+	cs = deserialize_json_start;
 	}
-	
-#line 228 "hb-buffer-deserialize-json.hh"
+
+#line 517 "hb-buffer-deserialize-json.hh"
 	{
-		unsigned int _trans = 0;
-		const unsigned char * _keys;
-		const signed char * _inds;
-		int _ic;
-		_resume: {}
-		if ( p == pe )
-			goto _out;
-		_keys = ( _deserialize_json_trans_keys + ((cs<<1)));
-		_inds = ( _deserialize_json_indicies + (_deserialize_json_index_offsets[cs]));
-		
-		if ( ( (*( p))) <= 125 && ( (*( p))) >= 9 ) {
-			_ic = (int)_deserialize_json_char_class[(int)( (*( p))) - 9];
-			if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
-				_trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); 
-			else
-				_trans = (unsigned int)_deserialize_json_index_defaults[cs];
-		}
-		else {
-			_trans = (unsigned int)_deserialize_json_index_defaults[cs];
-		}
-		
-		cs = (int)_deserialize_json_cond_targs[_trans];
-		
-		if ( _deserialize_json_cond_actions[_trans] != 0 ) {
-			
-			switch ( _deserialize_json_cond_actions[_trans] ) {
-				case 1:  {
-					{
+	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_json_trans_keys + (cs<<1);
+	_inds = _deserialize_json_indicies + _deserialize_json_index_offsets[cs];
+
+	_slen = _deserialize_json_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=(*p) &&
+		(*p) <= _keys[1] ?
+		(*p) - _keys[0] : _slen ];
+
+	cs = _deserialize_json_trans_targs[_trans];
+
+	if ( _deserialize_json_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _deserialize_json_trans_actions[_trans] ) {
+	case 1:
 #line 38 "hb-buffer-deserialize-json.rl"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 264 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 5:  {
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
+	break;
+	case 5:
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 280 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 2:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 2:
 #line 51 "hb-buffer-deserialize-json.rl"
-						
-						tok = p;
-					}
-					
-#line 292 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 15:  {
-					{
+	{
+	tok = p;
+}
+	break;
+	case 15:
 #line 55 "hb-buffer-deserialize-json.rl"
-						if (unlikely (!buffer->ensure_glyphs ())) return false; }
-					
-#line 302 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 21:  {
-					{
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 21:
 #line 56 "hb-buffer-deserialize-json.rl"
-						if (unlikely (!buffer->ensure_unicode ())) return false; }
-					
-#line 312 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 16:  {
-					{
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 16:
 #line 58 "hb-buffer-deserialize-json.rl"
-						
-						/* TODO Unescape \" and \\ if found. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 328 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 18:  {
-					{
+	{
+	/* TODO Unescape \" and \\ if found. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
+	break;
+	case 18:
 #line 66 "hb-buffer-deserialize-json.rl"
-						if (!parse_uint (tok, p, &info.codepoint)) return false; }
-					
-#line 338 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 8:  {
-					{
+	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
+	break;
+	case 8:
 #line 67 "hb-buffer-deserialize-json.rl"
-						if (!parse_uint (tok, p, &info.cluster )) return false; }
-					
-#line 348 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 10:  {
-					{
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
+	break;
+	case 10:
 #line 68 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-					
-#line 358 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 12:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+	break;
+	case 12:
 #line 69 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-					
-#line 368 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 3:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+	break;
+	case 3:
 #line 70 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-					
-#line 378 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 6:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+	break;
+	case 6:
 #line 71 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-					
-#line 388 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 14:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
+	break;
+	case 14:
 #line 51 "hb-buffer-deserialize-json.rl"
-						
-						tok = p;
-					}
-					
-#line 400 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 55 "hb-buffer-deserialize-json.rl"
-						if (unlikely (!buffer->ensure_glyphs ())) return false; }
-					
-#line 406 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 20:  {
-					{
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 20:
 #line 51 "hb-buffer-deserialize-json.rl"
-						
-						tok = p;
-					}
-					
-#line 418 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 56 "hb-buffer-deserialize-json.rl"
-						if (unlikely (!buffer->ensure_unicode ())) return false; }
-					
-#line 424 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 17:  {
-					{
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 17:
 #line 58 "hb-buffer-deserialize-json.rl"
-						
-						/* TODO Unescape \" and \\ if found. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 440 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{
+	/* TODO Unescape \" and \\ if found. */
+	if (!hb_font_glyph_from_string (font,
+					tok, p - tok,
+					&info.codepoint))
+	  return false;
+}
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 452 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 19:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 19:
 #line 66 "hb-buffer-deserialize-json.rl"
-						if (!parse_uint (tok, p, &info.codepoint)) return false; }
-					
-#line 462 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_uint (tok, p, &info.codepoint)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 474 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 9:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 9:
 #line 67 "hb-buffer-deserialize-json.rl"
-						if (!parse_uint (tok, p, &info.cluster )) return false; }
-					
-#line 484 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_uint (tok, p, &info.cluster )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 496 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 11:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 11:
 #line 68 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.x_offset )) return false; }
-					
-#line 506 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 518 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 13:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 13:
 #line 69 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-					
-#line 528 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 540 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 4:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 4:
 #line 70 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-					
-#line 550 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 562 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-				case 7:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 7:
 #line 71 "hb-buffer-deserialize-json.rl"
-						if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-					
-#line 572 "hb-buffer-deserialize-json.hh"
-					
-					{
+	{ if (!parse_int  (tok, p, &pos.y_advance)) return false; }
 #line 43 "hb-buffer-deserialize-json.rl"
-						
-						buffer->add_info (info);
-						if (unlikely (!buffer->successful))
-						return false;
-						buffer->pos[buffer->len - 1] = pos;
-						*end_ptr = p;
-					}
-					
-#line 584 "hb-buffer-deserialize-json.hh"
-					
-					
-					break; 
-				}
-			}
-			
-		}
-		
-		if ( cs != 0 ) {
-			p += 1;
-			goto _resume;
-		}
-		_out: {}
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 713 "hb-buffer-deserialize-json.hh"
 	}
-	
+
+_again:
+	if ( cs == 0 )
+		goto _out;
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	_out: {}
+	}
+
 #line 136 "hb-buffer-deserialize-json.rl"
-	
-	
-	*end_ptr = p;
-	
-	return p == pe && *(p-1) != ']';
+
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
 }
 
 #endif /* HB_BUFFER_DESERIALIZE_JSON_HH */

+ 763 - 674
thirdparty/harfbuzz/src/hb-buffer-deserialize-text.hh

@@ -1,29 +1,30 @@
+
 #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
-*/
+ * 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
@@ -31,143 +32,366 @@
 #include "hb.hh"
 
 
-#line 35 "hb-buffer-deserialize-text.hh"
+#line 36 "hb-buffer-deserialize-text.hh"
 static const unsigned char _deserialize_text_trans_keys[] = {
-	1u, 0u, 0u, 13u, 12u, 12u, 2u, 2u,
-	5u, 11u, 0u, 12u, 5u, 6u, 4u, 6u,
-	5u, 6u, 5u, 6u, 4u, 6u, 5u, 6u,
-	3u, 3u, 4u, 6u, 5u, 6u, 3u, 6u,
-	2u, 16u, 4u, 6u, 5u, 6u, 0u, 16u,
-	0u, 16u, 1u, 0u, 0u, 12u, 0u, 16u,
-	0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u,
-	0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u,
-	0u, 16u, 0u, 16u, 0u, 16u, 0u, 16u,
-	0u, 16u, 0u
+	0u, 0u, 9u, 91u, 85u, 85u, 43u, 43u, 48u, 102u, 9u, 85u, 48u, 57u, 45u, 57u, 
+	48u, 57u, 48u, 57u, 45u, 57u, 48u, 57u, 44u, 44u, 45u, 57u, 48u, 57u, 44u, 57u, 
+	43u, 124u, 45u, 57u, 48u, 57u, 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, 0
 };
 
-static const signed char _deserialize_text_char_class[] = {
-	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, 2, 3, 4, 1, 1, 5,
-	6, 6, 6, 6, 6, 6, 6, 6,
-	6, 1, 1, 7, 8, 9, 1, 10,
-	11, 11, 11, 11, 11, 11, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 12, 1, 1, 1,
-	1, 1, 13, 14, 15, 1, 1, 1,
-	11, 11, 11, 11, 11, 11, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 1, 16, 0
+static const char _deserialize_text_key_spans[] = {
+	0, 83, 1, 1, 55, 77, 10, 13, 
+	10, 10, 13, 10, 1, 13, 10, 14, 
+	82, 13, 10, 116, 116, 0, 77, 116, 
+	116, 116, 116, 116, 116, 116, 116, 116, 
+	116, 116, 116, 116, 116
 };
 
 static const short _deserialize_text_index_offsets[] = {
-	0, 0, 14, 15, 16, 23, 36, 38,
-	41, 43, 45, 48, 50, 51, 54, 56,
-	60, 75, 78, 80, 97, 114, 114, 127,
-	144, 161, 178, 195, 212, 229, 246, 263,
-	280, 297, 314, 331, 348, 0
-};
-
-static const signed char _deserialize_text_indicies[] = {
-	1, 0, 0, 0, 0, 0, 0, 2,
-	0, 0, 0, 0, 0, 3, 4, 6,
-	7, 7, 0, 0, 0, 0, 7, 8,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 4, 10, 11, 13, 14,
-	15, 17, 18, 20, 21, 23, 24, 25,
-	27, 28, 29, 31, 32, 33, 35, 36,
-	29, 0, 28, 28, 38, 38, 0, 0,
-	0, 0, 38, 0, 38, 0, 0, 0,
-	38, 38, 38, 40, 41, 42, 44, 45,
-	47, 0, 0, 0, 0, 48, 48, 0,
-	49, 50, 0, 48, 0, 0, 0, 0,
-	51, 52, 0, 0, 0, 0, 0, 0,
-	0, 0, 53, 0, 0, 0, 0, 0,
-	0, 54, 8, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 4, 56,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	57, 0, 0, 0, 0, 0, 0, 58,
-	56, 0, 0, 0, 0, 60, 60, 0,
-	0, 57, 0, 0, 0, 0, 0, 0,
-	58, 63, 62, 64, 0, 62, 62, 62,
-	62, 65, 62, 66, 62, 62, 62, 67,
-	68, 69, 71, 38, 72, 0, 38, 38,
-	38, 38, 73, 38, 74, 38, 38, 38,
-	37, 75, 76, 78, 0, 0, 79, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 80, 81, 82, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 53, 83, 84, 62, 64,
-	0, 62, 62, 62, 62, 65, 62, 66,
-	62, 62, 62, 67, 68, 69, 86, 0,
-	87, 0, 0, 0, 0, 0, 0, 0,
-	88, 0, 0, 0, 0, 57, 89, 91,
-	0, 92, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 93, 94,
-	91, 0, 92, 0, 0, 36, 36, 0,
-	0, 0, 0, 0, 0, 0, 0, 93,
-	94, 86, 0, 87, 0, 0, 97, 97,
-	0, 0, 0, 88, 0, 0, 0, 0,
-	57, 89, 99, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 100, 101, 99, 0, 0, 0, 0,
-	45, 45, 0, 0, 0, 0, 0, 0,
-	0, 0, 100, 101, 78, 0, 0, 79,
-	0, 18, 18, 0, 0, 0, 0, 0,
-	0, 0, 0, 80, 81, 0
+	0, 0, 84, 86, 88, 144, 222, 233, 
+	247, 258, 269, 283, 294, 296, 310, 321, 
+	336, 419, 433, 444, 561, 678, 679, 757, 
+	874, 991, 1108, 1225, 1342, 1459, 1576, 1693, 
+	1810, 1927, 2044, 2161, 2278
 };
 
-static const signed char _deserialize_text_index_defaults[] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 62, 38, 0, 0, 62, 0, 0,
-	0, 0, 0, 0, 0, 0
+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, 1, 1, 11, 12, 12, 
+	12, 12, 12, 12, 12, 12, 12, 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, 
+	1, 23, 1, 1, 24, 25, 25, 25, 
+	25, 25, 25, 25, 25, 25, 1, 26, 
+	27, 27, 27, 27, 27, 27, 27, 27, 
+	27, 1, 22, 1, 1, 1, 21, 21, 
+	21, 21, 21, 21, 21, 21, 21, 21, 
+	1, 28, 28, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 28, 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, 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, 1, 1, 
+	1, 1, 28, 1, 29, 1, 1, 30, 
+	31, 31, 31, 31, 31, 31, 31, 31, 
+	31, 1, 32, 33, 33, 33, 33, 33, 
+	33, 33, 33, 33, 1, 34, 34, 34, 
+	34, 34, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 34, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 35, 35, 35, 35, 
+	35, 35, 35, 35, 35, 35, 1, 1, 
+	1, 36, 37, 1, 1, 35, 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, 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, 
+	38, 1, 39, 39, 39, 39, 39, 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, 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, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 41, 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, 42, 42, 
+	42, 42, 42, 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, 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, 44, 1, 42, 42, 42, 42, 42, 
+	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, 45, 45, 45, 45, 45, 45, 
+	45, 45, 45, 45, 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, 44, 1, 
+	47, 47, 47, 47, 47, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 47, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 48, 1, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 49, 46, 46, 50, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 51, 52, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 53, 46, 54, 54, 54, 
+	54, 54, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 54, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 55, 
+	1, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 56, 28, 28, 57, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	58, 59, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	28, 28, 28, 28, 28, 28, 28, 28, 
+	60, 28, 61, 61, 61, 61, 61, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 61, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 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, 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, 64, 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, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 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, 1, 1, 1, 1, 1, 
+	1, 1, 66, 1, 67, 67, 67, 67, 
+	67, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 67, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 48, 1, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	49, 46, 46, 50, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 51, 
+	52, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 46, 
+	46, 46, 46, 46, 46, 46, 46, 53, 
+	46, 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, 69, 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, 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, 71, 1, 72, 72, 
+	72, 72, 72, 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, 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, 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, 72, 72, 72, 72, 72, 
+	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, 1, 1, 1, 73, 1, 1, 
+	1, 1, 27, 27, 27, 27, 27, 27, 
+	27, 27, 27, 27, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 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, 
+	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, 69, 1, 1, 1, 1, 76, 
+	76, 76, 76, 76, 76, 76, 76, 76, 
+	76, 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, 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, 71, 1, 77, 77, 77, 
+	77, 77, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 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, 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, 77, 77, 77, 77, 77, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 77, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 33, 33, 33, 33, 33, 33, 33, 
+	33, 33, 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, 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, 61, 
+	61, 61, 61, 61, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 1, 1, 1, 1, 61, 1, 
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 62, 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, 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, 64, 1, 0
 };
 
-static const signed char _deserialize_text_cond_targs[] = {
-	0, 1, 2, 25, 3, 3, 4, 19,
-	5, 6, 23, 24, 7, 8, 27, 36,
-	8, 27, 36, 9, 30, 33, 10, 11,
-	12, 15, 11, 12, 15, 13, 13, 14,
-	31, 32, 14, 31, 32, 16, 26, 17,
-	18, 34, 35, 18, 34, 35, 19, 20,
-	19, 6, 21, 22, 20, 21, 22, 23,
-	20, 21, 22, 24, 24, 25, 26, 26,
-	7, 9, 10, 16, 21, 29, 26, 26,
-	7, 9, 10, 21, 29, 27, 28, 17,
-	21, 29, 28, 29, 29, 30, 28, 7,
-	10, 29, 31, 28, 7, 21, 29, 32,
-	33, 33, 34, 28, 21, 29, 35, 36,
-	0
+static const char _deserialize_text_trans_targs[] = {
+	1, 0, 2, 25, 3, 4, 19, 5, 
+	23, 24, 8, 27, 36, 27, 36, 30, 
+	33, 11, 12, 15, 12, 15, 13, 14, 
+	31, 32, 31, 32, 26, 18, 34, 35, 
+	34, 35, 20, 19, 6, 21, 22, 20, 
+	21, 22, 20, 21, 22, 24, 26, 26, 
+	7, 9, 10, 16, 21, 29, 26, 7, 
+	9, 10, 16, 21, 29, 28, 17, 21, 
+	29, 28, 29, 29, 28, 7, 10, 29, 
+	28, 7, 21, 29, 33, 28, 21, 29
 };
 
-static const signed char _deserialize_text_cond_actions[] = {
-	0, 0, 0, 0, 1, 0, 0, 2,
-	0, 0, 2, 2, 0, 3, 4, 4,
-	0, 5, 5, 0, 4, 4, 0, 3,
-	3, 3, 0, 0, 0, 6, 0, 3,
-	4, 4, 0, 5, 5, 0, 5, 0,
-	3, 4, 4, 0, 5, 5, 7, 7,
-	8, 9, 7, 7, 0, 0, 0, 10,
-	10, 10, 10, 10, 8, 11, 12, 13,
-	14, 14, 14, 15, 11, 11, 16, 17,
-	18, 18, 18, 16, 16, 19, 19, 20,
-	19, 19, 0, 0, 13, 10, 10, 21,
-	21, 10, 22, 22, 23, 22, 22, 22,
-	10, 5, 24, 24, 24, 24, 24, 19,
-	0
+static const char _deserialize_text_trans_actions[] = {
+	0, 0, 0, 0, 1, 0, 2, 0, 
+	2, 2, 3, 4, 4, 5, 5, 4, 
+	4, 3, 3, 3, 0, 0, 6, 3, 
+	4, 4, 5, 5, 5, 3, 4, 4, 
+	5, 5, 7, 8, 9, 7, 7, 0, 
+	0, 0, 10, 10, 10, 8, 12, 13, 
+	14, 14, 14, 15, 11, 11, 17, 18, 
+	18, 18, 0, 16, 16, 19, 20, 19, 
+	19, 0, 0, 13, 10, 21, 21, 10, 
+	22, 23, 22, 22, 5, 24, 24, 24
 };
 
-static const signed char _deserialize_text_eof_trans[] = {
-	1, 2, 3, 6, 7, 9, 10, 13,
-	17, 20, 23, 27, 28, 31, 35, 29,
-	38, 40, 44, 47, 53, 54, 55, 56,
-	60, 62, 71, 78, 83, 70, 86, 91,
-	96, 97, 99, 103, 104, 0
+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, 7, 0, 0, 0, 10, 
+	10, 11, 16, 19, 0, 11, 10, 22, 
+	22, 10, 24, 24, 19
 };
 
 static const int deserialize_text_start = 1;
@@ -182,583 +406,448 @@ static const int deserialize_text_en_main = 1;
 
 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 *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 204 "hb-buffer-deserialize-text.hh"
-	{
-		cs = (int)deserialize_text_start;
+  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 428 "hb-buffer-deserialize-text.hh"
+	{
+	cs = deserialize_text_start;
 	}
-	
-#line 209 "hb-buffer-deserialize-text.hh"
-	{
-		unsigned int _trans = 0;
-		const unsigned char * _keys;
-		const signed char * _inds;
-		int _ic;
-		_resume: {}
-		if ( p == pe && p != eof )
-			goto _out;
-		if ( p == eof ) {
-			if ( _deserialize_text_eof_trans[cs] > 0 ) {
-				_trans = (unsigned int)_deserialize_text_eof_trans[cs] - 1;
-			}
-		}
-		else {
-			_keys = ( _deserialize_text_trans_keys + ((cs<<1)));
-			_inds = ( _deserialize_text_indicies + (_deserialize_text_index_offsets[cs]));
-			
-			if ( ( (*( p))) <= 124 && ( (*( p))) >= 9 ) {
-				_ic = (int)_deserialize_text_char_class[(int)( (*( p))) - 9];
-				if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
-					_trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); 
-				else
-					_trans = (unsigned int)_deserialize_text_index_defaults[cs];
-			}
-			else {
-				_trans = (unsigned int)_deserialize_text_index_defaults[cs];
-			}
-			
-		}
-		cs = (int)_deserialize_text_cond_targs[_trans];
-		
-		if ( _deserialize_text_cond_actions[_trans] != 0 ) {
-			
-			switch ( _deserialize_text_cond_actions[_trans] ) {
-				case 1:  {
-					{
+
+#line 433 "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"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 252 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 3:  {
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
+	break;
+	case 3:
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 264 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 5:  {
-					{
+	{
+	tok = p;
+}
+	break;
+	case 5:
 #line 55 "hb-buffer-deserialize-text.rl"
-						if (unlikely (!buffer->ensure_glyphs ())) return false; }
-					
-#line 274 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 8:  {
-					{
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 8:
 #line 56 "hb-buffer-deserialize-text.rl"
-						if (unlikely (!buffer->ensure_unicode ())) return false; }
-					
-#line 284 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 18:  {
-					{
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 18:
 #line 58 "hb-buffer-deserialize-text.rl"
-						
-						/* TODO Unescape delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 300 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 9:  {
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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; }
-					
-#line 310 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 21:  {
-					{
+	{if (!parse_hex (tok, p, &info.codepoint )) return false; }
+	break;
+	case 21:
 #line 68 "hb-buffer-deserialize-text.rl"
-						if (!parse_uint (tok, p, &info.cluster )) return false; }
-					
-#line 320 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 6:  {
-					{
+	{ 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; }
-					
-#line 330 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 23:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.x_offset )) return false; }
+	break;
+	case 23:
 #line 70 "hb-buffer-deserialize-text.rl"
-						if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-					
-#line 340 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 20:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.y_offset )) return false; }
+	break;
+	case 20:
 #line 71 "hb-buffer-deserialize-text.rl"
-						if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-					
-#line 350 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 15:  {
-					{
+	{ if (!parse_int  (tok, p, &pos.x_advance)) return false; }
+	break;
+	case 15:
 #line 38 "hb-buffer-deserialize-text.rl"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 363 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 371 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 4:  {
-					{
+	{
+	tok = p;
+}
+	break;
+	case 4:
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 383 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 55 "hb-buffer-deserialize-text.rl"
-						if (unlikely (!buffer->ensure_glyphs ())) return false; }
-					
-#line 389 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 2:  {
-					{
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 2:
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 401 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 56 "hb-buffer-deserialize-text.rl"
-						if (unlikely (!buffer->ensure_unicode ())) return false; }
-					
-#line 407 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 16:  {
-					{
+	{ if (unlikely (!buffer->ensure_unicode ())) return false; }
+	break;
+	case 16:
 #line 58 "hb-buffer-deserialize-text.rl"
-						
-						/* TODO Unescape delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 423 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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;
-					}
-					
-#line 435 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 7:  {
-					{
+	{
+	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 445 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{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;
-					}
-					
-#line 457 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 10:  {
-					{
+	{
+	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 467 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 479 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 22:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 22:
 #line 70 "hb-buffer-deserialize-text.rl"
-						if (!parse_int  (tok, p, &pos.y_offset )) return false; }
-					
-#line 489 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 501 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 19:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 19:
 #line 71 "hb-buffer-deserialize-text.rl"
-						if (!parse_int  (tok, p, &pos.x_advance)) return false; }
-					
-#line 511 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 523 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 24:  {
-					{
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+	case 24:
 #line 72 "hb-buffer-deserialize-text.rl"
-						if (!parse_int  (tok, p, &pos.y_advance)) return false; }
-					
-#line 533 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 545 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 12:  {
-					{
+	{
+	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"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 558 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 566 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 55 "hb-buffer-deserialize-text.rl"
-						if (unlikely (!buffer->ensure_glyphs ())) return false; }
-					
-#line 572 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 14:  {
-					{
+	{ if (unlikely (!buffer->ensure_glyphs ())) return false; }
+	break;
+	case 14:
 #line 38 "hb-buffer-deserialize-text.rl"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 585 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 593 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 58 "hb-buffer-deserialize-text.rl"
-						
-						/* TODO Unescape delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 605 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 17:  {
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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 delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 621 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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 627 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 639 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 11:  {
-					{
+	{
+	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"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 652 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 660 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 58 "hb-buffer-deserialize-text.rl"
-						
-						/* TODO Unescape delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 672 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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;
-					}
-					
-#line 684 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-				case 13:  {
-					{
+	{
+	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"
-						
-						memset (&info, 0, sizeof (info));
-						memset (&pos , 0, sizeof (pos ));
-					}
-					
-#line 697 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
 #line 51 "hb-buffer-deserialize-text.rl"
-						
-						tok = p;
-					}
-					
-#line 705 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	tok = p;
+}
 #line 58 "hb-buffer-deserialize-text.rl"
-						
-						/* TODO Unescape delimeters. */
-						if (!hb_font_glyph_from_string (font,
-						tok, p - tok,
-						&info.codepoint))
-						return false;
-					}
-					
-#line 717 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{
+	/* TODO Unescape delimeters. */
+	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 723 "hb-buffer-deserialize-text.hh"
-					
-					{
+	{ 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;
-					}
-					
-#line 735 "hb-buffer-deserialize-text.hh"
-					
-					
-					break; 
-				}
-			}
-			
-		}
-		
-		if ( p == eof ) {
-			if ( cs >= 19 )
-				goto _out;
-		}
-		else {
-			if ( cs != 0 ) {
-				p += 1;
-				goto _resume;
-			}
-		}
-		_out: {}
+	{
+	buffer->add_info (info);
+	if (unlikely (!buffer->successful))
+	  return false;
+	buffer->pos[buffer->len - 1] = pos;
+	*end_ptr = p;
+}
+	break;
+#line 722 "hb-buffer-deserialize-text.hh"
 	}
-	
-#line 138 "hb-buffer-deserialize-text.rl"
-	
-	
+
+_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 delimeters. */
+	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 22:
+#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 19:
+#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 24:
+#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 11:
+#line 38 "hb-buffer-deserialize-text.rl"
+	{
+	memset (&info, 0, sizeof (info));
+	memset (&pos , 0, sizeof (pos ));
+}
+#line 51 "hb-buffer-deserialize-text.rl"
+	{
+	tok = p;
+}
+#line 58 "hb-buffer-deserialize-text.rl"
+	{
+	/* TODO Unescape delimeters. */
+	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;
-	
-	return p == pe && *(p-1) != ']';
+}
+	break;
+#line 839 "hb-buffer-deserialize-text.hh"
+	}
+	}
+
+	_out: {}
+	}
+
+#line 138 "hb-buffer-deserialize-text.rl"
+
+
+  *end_ptr = p;
+
+  return p == pe && *(p-1) != ']';
 }
 
 #endif /* HB_BUFFER_DESERIALIZE_TEXT_HH */

+ 58 - 41
thirdparty/harfbuzz/src/hb-buffer.cc

@@ -96,14 +96,15 @@ hb_segment_properties_hash (const hb_segment_properties_t *p)
  * As an optimization, both info and out_info may point to the
  * same piece of memory, which is owned by info.  This remains the
  * case as long as out_len doesn't exceed i at any time.
- * In that case, swap_buffers() is no-op and the glyph operations operate
- * mostly in-place.
+ * In that case, swap_buffers() is mostly no-op and the glyph operations
+ * operate mostly in-place.
  *
  * As soon as out_info gets longer than info, out_info is moved over
- * to an alternate buffer (which we reuse the pos buffer for!), and its
+ * to an alternate buffer (which we reuse the pos buffer for), and its
  * current contents (out_len entries) are copied to the new place.
+ *
  * This should all remain transparent to the user.  swap_buffers() then
- * switches info and out_info.
+ * switches info over to out_info and does housekeeping.
  */
 
 
@@ -136,8 +137,8 @@ hb_buffer_t::enlarge (unsigned int size)
   if (unlikely (hb_unsigned_mul_overflows (new_allocated, sizeof (info[0]))))
     goto done;
 
-  new_pos = (hb_glyph_position_t *) realloc (pos, new_allocated * sizeof (pos[0]));
-  new_info = (hb_glyph_info_t *) realloc (info, new_allocated * sizeof (info[0]));
+  new_pos = (hb_glyph_position_t *) hb_realloc (pos, new_allocated * sizeof (pos[0]));
+  new_info = (hb_glyph_info_t *) hb_realloc (info, new_allocated * sizeof (info[0]));
 
 done:
   if (unlikely (!new_pos || !new_info))
@@ -281,22 +282,13 @@ hb_buffer_t::add_info (const hb_glyph_info_t &glyph_info)
 }
 
 
-void
-hb_buffer_t::remove_output ()
-{
-  have_output = false;
-  have_positions = false;
-
-  out_len = 0;
-  out_info = info;
-}
-
 void
 hb_buffer_t::clear_output ()
 {
   have_output = true;
   have_positions = false;
 
+  idx = 0;
   out_len = 0;
   out_info = info;
 }
@@ -316,29 +308,23 @@ hb_buffer_t::clear_positions ()
 void
 hb_buffer_t::swap_buffers ()
 {
-  if (unlikely (!successful)) return;
+  assert (have_output);
 
   assert (idx <= len);
-  if (unlikely (!next_glyphs (len - idx))) return;
 
-  assert (have_output);
-  have_output = false;
+  if (unlikely (!successful || !next_glyphs (len - idx)))
+    goto reset;
 
   if (out_info != info)
   {
-    hb_glyph_info_t *tmp;
-    tmp = info;
+    pos = (hb_glyph_position_t *) info;
     info = out_info;
-    out_info = tmp;
-
-    pos = (hb_glyph_position_t *) out_info;
   }
-
-  unsigned int tmp;
-  tmp = len;
   len = out_len;
-  out_len = tmp;
 
+reset:
+  have_output = false;
+  out_len = 0;
   idx = 0;
 }
 
@@ -373,12 +359,11 @@ hb_buffer_t::move_to (unsigned int i)
     /* This will blow in our face if memory allocation fails later
      * in this same lookup...
      *
-     * We used to shift with extra 32 items, instead of the 0 below.
+     * We used to shift with extra 32 items.
      * But that would leave empty slots in the buffer in case of allocation
-     * failures.  Setting to zero for now to avoid other problems (see
-     * comments in shift_forward().  This can cause O(N^2) behavior more
-     * severely than adding 32 empty slots can... */
-    if (unlikely (idx < count && !shift_forward (count + 0))) return false;
+     * failures.  See comments in shift_forward().  This can cause O(N^2)
+     * behavior more severely than adding 32 empty slots can... */
+    if (unlikely (idx < count && !shift_forward (count - idx))) return false;
 
     assert (idx >= count);
 
@@ -630,7 +615,7 @@ DEFINE_NULL_INSTANCE (hb_buffer_t) =
   HB_BUFFER_CONTENT_TYPE_INVALID,
   HB_SEGMENT_PROPERTIES_DEFAULT,
   false, /* successful */
-  true, /* have_output */
+  false, /* have_output */
   true  /* have_positions */
 
   /* Zero is good enough for everything else. */
@@ -717,14 +702,14 @@ hb_buffer_destroy (hb_buffer_t *buffer)
 
   hb_unicode_funcs_destroy (buffer->unicode);
 
-  free (buffer->info);
-  free (buffer->pos);
+  hb_free (buffer->info);
+  hb_free (buffer->pos);
 #ifndef HB_NO_BUFFER_MESSAGE
   if (buffer->message_destroy)
     buffer->message_destroy (buffer->message_data);
 #endif
 
-  free (buffer);
+  hb_free (buffer);
 }
 
 /**
@@ -1363,6 +1348,11 @@ hb_buffer_get_glyph_infos (hb_buffer_t  *buffer,
  * Returns @buffer glyph position array.  Returned pointer
  * is valid as long as @buffer contents are not modified.
  *
+ * If buffer did not have positions before, the positions will be
+ * initialized to zeros, unless this function is called from
+ * within a buffer message callback (see hb_buffer_set_message_func()),
+ * in which case %NULL is returned.
+ *
  * Return value: (transfer none) (array length=length):
  * The @buffer glyph position array.
  * The value valid as long as buffer has not been modified.
@@ -1373,12 +1363,17 @@ hb_glyph_position_t *
 hb_buffer_get_glyph_positions (hb_buffer_t  *buffer,
 			       unsigned int *length)
 {
-  if (!buffer->have_positions)
-    buffer->clear_positions ();
-
   if (length)
     *length = buffer->len;
 
+  if (!buffer->have_positions)
+  {
+    if (unlikely (buffer->message_depth))
+      return nullptr;
+
+    buffer->clear_positions ();
+  }
+
   return (hb_glyph_position_t *) buffer->pos;
 }
 
@@ -1760,6 +1755,28 @@ hb_buffer_append (hb_buffer_t *buffer,
   memcpy (buffer->info + orig_len, source->info + start, (end - start) * sizeof (buffer->info[0]));
   if (buffer->have_positions)
     memcpy (buffer->pos + orig_len, source->pos + start, (end - start) * sizeof (buffer->pos[0]));
+
+  if (source->content_type == HB_BUFFER_CONTENT_TYPE_UNICODE)
+  {
+    /* See similar logic in add_utf. */
+
+    /* pre-context */
+    if (!orig_len && start + source->context_len[0] > 0)
+    {
+      buffer->clear_context (0);
+      while (start > 0 && buffer->context_len[0] < buffer->CONTEXT_LENGTH)
+	buffer->context[0][buffer->context_len[0]++] = source->info[--start].codepoint;
+      for (auto i = 0u; i < source->context_len[0] && buffer->context_len[0] < buffer->CONTEXT_LENGTH; i++)
+	buffer->context[0][buffer->context_len[0]++] = source->context[0][i];
+    }
+
+    /* post-context */
+    buffer->clear_context (1);
+    while (end < source->len && buffer->context_len[1] < buffer->CONTEXT_LENGTH)
+      buffer->context[1][buffer->context_len[1]++] = source->info[end++].codepoint;
+    for (auto i = 0u; i < source->context_len[1] && buffer->context_len[1] < buffer->CONTEXT_LENGTH; i++)
+      buffer->context[1][buffer->context_len[1]++] = source->context[1][i];
+  }
 }
 
 

+ 11 - 6
thirdparty/harfbuzz/src/hb-buffer.hh

@@ -107,7 +107,7 @@ struct hb_buffer_t
 
   unsigned int idx; /* Cursor into ->info and ->pos arrays */
   unsigned int len; /* Length of ->info and ->pos arrays */
-  unsigned int out_len; /* Length of ->out array if have_output */
+  unsigned int out_len; /* Length of ->out_info array if have_output */
 
   unsigned int allocated; /* Length of allocated arrays */
   hb_glyph_info_t     *info;
@@ -128,6 +128,9 @@ struct hb_buffer_t
   hb_buffer_message_func_t message_func;
   void *message_data;
   hb_destroy_func_t message_destroy;
+  unsigned message_depth; /* How deeply are we inside a message callback? */
+#else
+  static constexpr unsigned message_depth = 0u;
 #endif
 
   /* Internal debugging. */
@@ -186,13 +189,10 @@ struct hb_buffer_t
   hb_glyph_info_t &prev ()      { return out_info[out_len ? out_len - 1 : 0]; }
   hb_glyph_info_t prev () const { return out_info[out_len ? out_len - 1 : 0]; }
 
-  HB_NODISCARD bool has_separate_output () const { return info != out_info; }
-
-
   HB_INTERNAL void reset ();
   HB_INTERNAL void clear ();
 
-  unsigned int backtrack_len () const { return have_output? out_len : idx; }
+  unsigned int backtrack_len () const { return have_output ? out_len : idx; }
   unsigned int lookahead_len () const { return len - idx; }
   unsigned int next_serial () { return serial++; }
 
@@ -206,7 +206,6 @@ struct hb_buffer_t
   HB_INTERNAL void guess_segment_properties ();
 
   HB_INTERNAL void swap_buffers ();
-  HB_INTERNAL void remove_output ();
   HB_INTERNAL void clear_output ();
   HB_INTERNAL void clear_positions ();
 
@@ -400,10 +399,16 @@ struct hb_buffer_t
 #else
     if (!messaging ())
       return true;
+
+    message_depth++;
+
     va_list ap;
     va_start (ap, fmt);
     bool ret = message_impl (font, fmt, ap);
     va_end (ap);
+
+    message_depth--;
+
     return ret;
 #endif
   }

+ 1 - 1
thirdparty/harfbuzz/src/hb-cache.hh

@@ -30,7 +30,7 @@
 #include "hb.hh"
 
 
-/* Implements a lock-free cache for int->int functions. */
+/* Implements a lockfree cache for int->int functions. */
 
 template <unsigned int key_bits, unsigned int value_bits, unsigned int cache_bits>
 struct hb_cache_t

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

@@ -263,7 +263,7 @@ struct UnsizedByteStr : UnsizedArrayOf <HBUINT8>
 
     T *ip = c->allocate_size<T> (T::static_size);
     if (unlikely (!ip)) return_trace (false);
-    return_trace (c->check_assign (*ip, value));
+    return_trace (c->check_assign (*ip, value, HB_SERIALIZE_ERROR_INT_OVERFLOW));
   }
 
   template <typename V>

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

@@ -136,8 +136,8 @@ struct cff2_cs_interp_env_t : cs_interp_env_t<blend_arg_t, CFF2Subrs>
 	if (unlikely (!scalars.resize (region_count)))
 	  set_error ();
 	else
-	  varStore->varStore.get_scalars (get_ivs (), coords, num_coords,
-					  &scalars[0], region_count);
+	  varStore->varStore.get_region_scalars (get_ivs (), coords, num_coords,
+						 &scalars[0], region_count);
       }
       seen_blend = true;
     }

+ 15 - 18
thirdparty/harfbuzz/src/hb-common.cc

@@ -257,13 +257,11 @@ struct hb_language_item_t {
   bool operator == (const char *s) const
   { return lang_equal (lang, s); }
 
-  hb_language_item_t & operator = (const char *s) {
-    /* If a custom allocated is used calling strdup() pairs
-    badly with a call to the custom free() in fini() below.
-    Therefore don't call strdup(), implement its behavior.
-    */
+  hb_language_item_t & operator = (const char *s)
+  {
+    /* We can't call strdup(), because we allow custom allocators. */
     size_t len = strlen(s) + 1;
-    lang = (hb_language_t) malloc(len);
+    lang = (hb_language_t) hb_malloc(len);
     if (likely (lang))
     {
       memcpy((unsigned char *) lang, s, len);
@@ -274,16 +272,15 @@ struct hb_language_item_t {
     return *this;
   }
 
-  void fini () { free ((void *) lang); }
+  void fini () { hb_free ((void *) lang); }
 };
 
 
-/* Thread-safe lock-free language list */
+/* Thread-safe lockfree language list */
 
 static hb_atomic_ptr_t <hb_language_item_t> langs;
 
-#if HB_USE_ATEXIT
-static void
+static inline void
 free_langs ()
 {
 retry:
@@ -294,11 +291,10 @@ retry:
   while (first_lang) {
     hb_language_item_t *next = first_lang->next;
     first_lang->fini ();
-    free (first_lang);
+    hb_free (first_lang);
     first_lang = next;
   }
 }
-#endif
 
 static hb_language_item_t *
 lang_find_or_insert (const char *key)
@@ -311,28 +307,26 @@ retry:
       return lang;
 
   /* Not found; allocate one. */
-  hb_language_item_t *lang = (hb_language_item_t *) calloc (1, sizeof (hb_language_item_t));
+  hb_language_item_t *lang = (hb_language_item_t *) hb_calloc (1, sizeof (hb_language_item_t));
   if (unlikely (!lang))
     return nullptr;
   lang->next = first_lang;
   *lang = key;
   if (unlikely (!lang->lang))
   {
-    free (lang);
+    hb_free (lang);
     return nullptr;
   }
 
   if (unlikely (!langs.cmpexch (first_lang, lang)))
   {
     lang->fini ();
-    free (lang);
+    hb_free (lang);
     goto retry;
   }
 
-#if HB_USE_ATEXIT
   if (!first_lang)
-    atexit (free_langs); /* First person registers atexit() callback. */
-#endif
+    hb_atexit (free_langs); /* First person registers atexit() callback. */
 
   return lang;
 }
@@ -601,6 +595,9 @@ hb_script_get_horizontal_direction (hb_script_t script)
     case HB_SCRIPT_CHORASMIAN:
     case HB_SCRIPT_YEZIDI:
 
+    /* Unicode-14.0 additions */
+    case HB_SCRIPT_OLD_UYGHUR:
+
       return HB_DIRECTION_RTL;
 
 

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

@@ -476,6 +476,11 @@ hb_language_get_default (void);
  * @HB_SCRIPT_DIVES_AKURU: `Diak`, Since: 2.6.7
  * @HB_SCRIPT_KHITAN_SMALL_SCRIPT: `Kits`, Since: 2.6.7
  * @HB_SCRIPT_YEZIDI: `Yezi`, Since: 2.6.7
+ * @HB_SCRIPT_CYPRO_MINOAN: `Cpmn`, Since: 3.0.0
+ * @HB_SCRIPT_OLD_UYGHUR: `Ougr`, Since: 3.0.0
+ * @HB_SCRIPT_TANGSA: `Tnsa`, Since: 3.0.0
+ * @HB_SCRIPT_TOTO: `Toto`, Since: 3.0.0
+ * @HB_SCRIPT_VITHKUQI: `Vith`, Since: 3.0.0
  * @HB_SCRIPT_INVALID: No script set
  *
  * Data type for scripts. Each #hb_script_t's value is an #hb_tag_t corresponding
@@ -683,6 +688,15 @@ typedef enum
   HB_SCRIPT_KHITAN_SMALL_SCRIPT		= HB_TAG ('K','i','t','s'), /*13.0*/
   HB_SCRIPT_YEZIDI			= HB_TAG ('Y','e','z','i'), /*13.0*/
 
+  /*
+   * Since 3.0.0
+   */
+  HB_SCRIPT_CYPRO_MINOAN		= HB_TAG ('C','p','m','n'), /*14.0*/
+  HB_SCRIPT_OLD_UYGHUR			= HB_TAG ('O','u','g','r'), /*14.0*/
+  HB_SCRIPT_TANGSA			= HB_TAG ('T','n','s','a'), /*14.0*/
+  HB_SCRIPT_TOTO			= HB_TAG ('T','o','t','o'), /*14.0*/
+  HB_SCRIPT_VITHKUQI			= HB_TAG ('V','i','t','h'), /*14.0*/
+
   /* No script set. */
   HB_SCRIPT_INVALID			= HB_TAG_NONE,
 

+ 4 - 5
thirdparty/harfbuzz/src/hb-config.hh

@@ -86,6 +86,9 @@
 #define HB_NO_LEGACY
 #endif
 
+#ifdef HAVE_CONFIG_OVERRIDE_H
+#include "config-override.h"
+#endif
 
 /* Closure of options. */
 
@@ -117,7 +120,7 @@
 #define HB_NO_CMAP_LEGACY_SUBTABLES
 #define HB_NO_FALLBACK_SHAPE
 #define HB_NO_OT_KERN
-#define HB_NO_OT_LAYOUT_BLACKLIST
+#define HB_NO_OT_LAYOUT_BLOCKLIST
 #define HB_NO_OT_SHAPE_FALLBACK
 #endif
 
@@ -155,9 +158,5 @@
 #endif
 #endif
 
-#ifdef HAVE_CONFIG_OVERRIDE_H
-#include "config-override.h"
-#endif
-
 
 #endif /* HB_CONFIG_HH */

+ 44 - 6
thirdparty/harfbuzz/src/hb-coretext.cc

@@ -332,6 +332,44 @@ _hb_coretext_shaper_font_data_create (hb_font_t *font)
     return nullptr;
   }
 
+  if (font->coords)
+  {
+    CFMutableDictionaryRef variations =
+      CFDictionaryCreateMutable (kCFAllocatorDefault,
+				 font->num_coords,
+				 &kCFTypeDictionaryKeyCallBacks,
+				 &kCFTypeDictionaryValueCallBacks);
+
+    for (unsigned i = 0; i < font->num_coords; i++)
+    {
+      if (font->coords[i] == 0.) continue;
+
+      hb_ot_var_axis_info_t info;
+      unsigned int c = 1;
+      hb_ot_var_get_axis_infos (font->face, i, &c, &info);
+      CFDictionarySetValue (variations,
+	CFNumberCreate (kCFAllocatorDefault, kCFNumberIntType, &info.tag),
+	CFNumberCreate (kCFAllocatorDefault, kCFNumberFloatType, &font->design_coords[i])
+      );
+    }
+
+    CFDictionaryRef attributes =
+      CFDictionaryCreate (kCFAllocatorDefault,
+			  (const void **) &kCTFontVariationAttribute,
+			  (const void **) &variations,
+			  1,
+			  &kCFTypeDictionaryKeyCallBacks,
+			  &kCFTypeDictionaryValueCallBacks);
+
+    CTFontDescriptorRef varDesc = CTFontDescriptorCreateWithAttributes (attributes);
+    CTFontRef new_ct_font = CTFontCreateCopyWithAttributes (ct_font, 0, nullptr, varDesc);
+
+    CFRelease (ct_font);
+    CFRelease (attributes);
+    CFRelease (variations);
+    ct_font = new_ct_font;
+  }
+
   return (hb_coretext_font_data_t *) ct_font;
 }
 
@@ -1061,7 +1099,7 @@ resize_and_retry:
 	hb_glyph_info_t *info = run_info;
 	if (HB_DIRECTION_IS_HORIZONTAL (buffer->props.direction))
 	{
-	  hb_position_t x_offset = (positions[0].x - advances_so_far) * x_mult;
+	  hb_position_t x_offset = round ((positions[0].x - advances_so_far) * x_mult);
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
 	    CGFloat advance;
@@ -1069,15 +1107,15 @@ resize_and_retry:
 	      advance = positions[j + 1].x - positions[j].x;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].x - positions[0].x);
-	    info->mask = advance * x_mult;
+	    info->mask = round (advance * x_mult);
 	    info->var1.i32 = x_offset;
-	    info->var2.i32 = positions[j].y * y_mult;
+	    info->var2.i32 = round (positions[j].y * y_mult);
 	    info++;
 	  }
 	}
 	else
 	{
-	  hb_position_t y_offset = (positions[0].y - advances_so_far) * y_mult;
+	  hb_position_t y_offset = round ((positions[0].y - advances_so_far) * y_mult);
 	  for (unsigned int j = 0; j < num_glyphs; j++)
 	  {
 	    CGFloat advance;
@@ -1085,8 +1123,8 @@ resize_and_retry:
 	      advance = positions[j + 1].y - positions[j].y;
 	    else /* last glyph */
 	      advance = run_advance - (positions[j].y - positions[0].y);
-	    info->mask = advance * y_mult;
-	    info->var1.i32 = positions[j].x * x_mult;
+	    info->mask = round (advance * y_mult);
+	    info->var1.i32 = round (positions[j].x * x_mult);
 	    info->var2.i32 = y_offset;
 	    info++;
 	  }

+ 5 - 1
thirdparty/harfbuzz/src/hb-debug.hh

@@ -307,7 +307,7 @@ struct hb_auto_trace_t
 
     _hb_debug_msg<max_level> (what, obj, func, true, plevel ? *plevel : 1, -1,
 			      "return %s (line %d)",
-			      hb_printer_t<decltype (v)>().print (v), line);
+			      hb_printer_t<hb_decay<decltype (v)>>().print (v), line);
     if (plevel) --*plevel;
     plevel = nullptr;
     returned = true;
@@ -438,6 +438,10 @@ struct hb_no_trace_t {
 #define TRACE_SUBSET(this) hb_no_trace_t<bool> trace
 #endif
 
+#ifndef HB_DEBUG_SUBSET_REPACK
+#define HB_DEBUG_SUBSET_REPACK (HB_DEBUG+0)
+#endif
+
 #ifndef HB_DEBUG_DISPATCH
 #define HB_DEBUG_DISPATCH ( \
 	HB_DEBUG_APPLY + \

+ 0 - 3
thirdparty/harfbuzz/src/hb-deprecated.h

@@ -107,9 +107,6 @@ hb_font_funcs_set_glyph_func (hb_font_funcs_t *ffuncs,
 			      hb_font_get_glyph_func_t func,
 			      void *user_data, hb_destroy_func_t destroy);
 
-HB_EXTERN HB_DEPRECATED void
-hb_set_invert (hb_set_t *set);
-
 /**
  * hb_unicode_eastasian_width_func_t:
  * @ufuncs: A Unicode-functions structure

+ 65 - 199
thirdparty/harfbuzz/src/hb-directwrite.cc

@@ -32,6 +32,7 @@
 
 #include "hb-directwrite.h"
 
+#include "hb-ms-feature-ranges.hh"
 
 /**
  * SECTION:hb-directwrite
@@ -42,24 +43,6 @@
  * Functions for using HarfBuzz with DirectWrite fonts.
  **/
 
-/* Declare object creator for dynamic support of DWRITE */
-typedef HRESULT (* WINAPI t_DWriteCreateFactory)(
-  DWRITE_FACTORY_TYPE factoryType,
-  REFIID              iid,
-  IUnknown            **factory
-);
-
-/*
- * hb-directwrite uses new/delete syntatically but as we let users
- * to override malloc/free, we will redefine new/delete so users
- * won't need to do that by their own.
- */
-void* operator new (size_t size)        { return malloc (size); }
-void* operator new [] (size_t size)     { return malloc (size); }
-void operator delete (void* pointer)    { free (pointer); }
-void operator delete [] (void* pointer) { free (pointer); }
-
-
 /*
  * DirectWrite font stream helpers
  */
@@ -154,7 +137,6 @@ public:
 
 struct hb_directwrite_face_data_t
 {
-  HMODULE dwrite_dll;
   IDWriteFactory *dwriteFactory;
   IDWriteFontFile *fontFile;
   DWriteFontFileStream *fontFileStream;
@@ -176,33 +158,12 @@ _hb_directwrite_shaper_face_data_create (hb_face_t *face)
     return nullptr; \
   } HB_STMT_END
 
-  data->dwrite_dll = LoadLibrary (TEXT ("DWRITE"));
-  if (unlikely (!data->dwrite_dll))
-    FAIL ("Cannot find DWrite.DLL");
-
-  t_DWriteCreateFactory p_DWriteCreateFactory;
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-function-type"
-#endif
-
-  p_DWriteCreateFactory = (t_DWriteCreateFactory)
-			  GetProcAddress (data->dwrite_dll, "DWriteCreateFactory");
-
-#if defined(__GNUC__)
-#pragma GCC diagnostic pop
-#endif
-
-  if (unlikely (!p_DWriteCreateFactory))
-    FAIL ("Cannot find DWriteCreateFactory().");
-
   HRESULT hr;
 
   // TODO: factory and fontFileLoader should be cached separately
   IDWriteFactory* dwriteFactory;
-  hr = p_DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
-			      (IUnknown**) &dwriteFactory);
+  hr = DWriteCreateFactory (DWRITE_FACTORY_TYPE_SHARED, __uuidof (IDWriteFactory),
+			    (IUnknown**) &dwriteFactory);
 
   if (unlikely (hr != S_OK))
     FAIL ("Failed to run DWriteCreateFactory().");
@@ -266,8 +227,6 @@ _hb_directwrite_shaper_face_data_destroy (hb_directwrite_face_data_t *data)
     delete data->fontFileStream;
   if (data->faceBlob)
     hb_blob_destroy (data->faceBlob);
-  if (data->dwrite_dll)
-    FreeLibrary (data->dwrite_dll);
   if (data)
     delete data;
 }
@@ -552,13 +511,12 @@ protected:
  * shaper
  */
 
-static hb_bool_t
-_hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
-			    hb_font_t          *font,
-			    hb_buffer_t        *buffer,
-			    const hb_feature_t *features,
-			    unsigned int        num_features,
-			    float               lineWidth)
+hb_bool_t
+_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
+		       hb_font_t          *font,
+		       hb_buffer_t        *buffer,
+		       const hb_feature_t *features,
+		       unsigned int        num_features)
 {
   hb_face_t *face = font->face;
   const hb_directwrite_face_data_t *face_data = face->data.directwrite;
@@ -611,8 +569,6 @@ _hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
       log_clusters[chars_len++] = cluster; /* Surrogates. */
   }
 
-  // TODO: Handle TEST_DISABLE_OPTIONAL_LIGATURES
-
   DWRITE_READING_DIRECTION readingDirection;
   readingDirection = buffer->props.direction ?
 		     DWRITE_READING_DIRECTION_RIGHT_TO_LEFT :
@@ -623,7 +579,7 @@ _hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
   * but we never attempt to shape a word longer than 64K characters
   * in a single gfxShapedWord, so we cannot exceed that limit.
   */
-  uint32_t textLength = buffer->len;
+  uint32_t textLength = chars_len;
 
   TextAnalysis analysis (textString, textLength, nullptr, readingDirection);
   TextAnalysis::Run *runHead;
@@ -648,38 +604,54 @@ _hb_directwrite_shape_full (hb_shape_plan_t    *shape_plan,
     mbstowcs ((wchar_t*) localeName,
 	      hb_language_to_string (buffer->props.language), 20);
 
-  // TODO: it does work but doesn't care about ranges
-  DWRITE_TYPOGRAPHIC_FEATURES typographic_features;
-  typographic_features.featureCount = num_features;
+  /*
+   * Set up features.
+   */
+  static_assert ((sizeof (DWRITE_TYPOGRAPHIC_FEATURES) == sizeof (hb_ms_features_t)), "");
+  static_assert ((sizeof (DWRITE_FONT_FEATURE) == sizeof (hb_ms_feature_t)), "");
+  hb_vector_t<hb_ms_features_t *> range_features;
+  hb_vector_t<uint32_t> range_char_counts;
   if (num_features)
   {
-    typographic_features.features = new DWRITE_FONT_FEATURE[num_features];
-    for (unsigned int i = 0; i < num_features; ++i)
-    {
-      typographic_features.features[i].nameTag = (DWRITE_FONT_FEATURE_TAG)
-						 hb_uint32_swap (features[i].tag);
-      typographic_features.features[i].parameter = features[i].value;
-    }
+    hb_vector_t<hb_ms_feature_t> feature_records;
+    hb_vector_t<hb_ms_range_record_t> range_records;
+    if (hb_ms_setup_features (features, num_features, feature_records, range_records))
+      hb_ms_make_feature_ranges (feature_records,
+				 range_records,
+				 0,
+				 chars_len,
+				 log_clusters,
+				 range_features,
+				 range_char_counts);
   }
-  const DWRITE_TYPOGRAPHIC_FEATURES* dwFeatures;
-  dwFeatures = (const DWRITE_TYPOGRAPHIC_FEATURES*) &typographic_features;
-  const uint32_t featureRangeLengths[] = { textLength };
-  //
 
   uint16_t* clusterMap;
   clusterMap = new uint16_t[textLength];
   DWRITE_SHAPING_TEXT_PROPERTIES* textProperties;
   textProperties = new DWRITE_SHAPING_TEXT_PROPERTIES[textLength];
+
 retry_getglyphs:
   uint16_t* glyphIndices = new uint16_t[maxGlyphCount];
   DWRITE_SHAPING_GLYPH_PROPERTIES* glyphProperties;
   glyphProperties = new DWRITE_SHAPING_GLYPH_PROPERTIES[maxGlyphCount];
 
-  hr = analyzer->GetGlyphs (textString, textLength, fontFace, false,
-			    isRightToLeft, &runHead->mScript, localeName,
-			    nullptr, &dwFeatures, featureRangeLengths, 1,
-			    maxGlyphCount, clusterMap, textProperties,
-			    glyphIndices, glyphProperties, &glyphCount);
+  hr = analyzer->GetGlyphs (textString,
+			    chars_len,
+			    fontFace,
+			    false,
+			    isRightToLeft,
+			    &runHead->mScript,
+			    localeName,
+			    nullptr,
+			    (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+			    range_char_counts.arrayZ,
+			    range_features.length,
+			    maxGlyphCount,
+			    clusterMap,
+			    textProperties,
+			    glyphIndices,
+			    glyphProperties,
+			    &glyphCount);
 
   if (unlikely (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER)))
   {
@@ -715,101 +687,28 @@ retry_getglyphs:
   double x_mult = (double) font->x_scale / fontEmSize;
   double y_mult = (double) font->y_scale / fontEmSize;
 
-  hr = analyzer->GetGlyphPlacements (textString, clusterMap, textProperties,
-				     textLength, glyphIndices, glyphProperties,
-				     glyphCount, fontFace, fontEmSize,
-				     false, isRightToLeft, &runHead->mScript, localeName,
-				     &dwFeatures, featureRangeLengths, 1,
-				     glyphAdvances, glyphOffsets);
+  hr = analyzer->GetGlyphPlacements (textString,
+				     clusterMap,
+				     textProperties,
+				     chars_len,
+				     glyphIndices,
+				     glyphProperties,
+				     glyphCount,
+				     fontFace,
+				     fontEmSize,
+				     false,
+				     isRightToLeft,
+				     &runHead->mScript,
+				     localeName,
+				     (const DWRITE_TYPOGRAPHIC_FEATURES**) range_features.arrayZ,
+				     range_char_counts.arrayZ,
+				     range_features.length,
+				     glyphAdvances,
+				     glyphOffsets);
 
   if (FAILED (hr))
     FAIL ("Analyzer failed to get glyph placements.");
 
-  IDWriteTextAnalyzer1* analyzer1;
-  analyzer->QueryInterface (&analyzer1);
-
-  if (analyzer1 && lineWidth)
-  {
-    DWRITE_JUSTIFICATION_OPPORTUNITY* justificationOpportunities =
-      new DWRITE_JUSTIFICATION_OPPORTUNITY[maxGlyphCount];
-    hr = analyzer1->GetJustificationOpportunities (fontFace, fontEmSize, runHead->mScript,
-						   textLength, glyphCount, textString,
-						   clusterMap, glyphProperties,
-						   justificationOpportunities);
-
-    if (FAILED (hr))
-      FAIL ("Analyzer failed to get justification opportunities.");
-
-    float* justifiedGlyphAdvances = new float[maxGlyphCount];
-    DWRITE_GLYPH_OFFSET* justifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[glyphCount];
-    hr = analyzer1->JustifyGlyphAdvances (lineWidth, glyphCount, justificationOpportunities,
-					  glyphAdvances, glyphOffsets, justifiedGlyphAdvances,
-					  justifiedGlyphOffsets);
-
-    if (FAILED (hr)) FAIL ("Analyzer failed to get justify glyph advances.");
-
-    DWRITE_SCRIPT_PROPERTIES scriptProperties;
-    hr = analyzer1->GetScriptProperties (runHead->mScript, &scriptProperties);
-    if (FAILED (hr)) FAIL ("Analyzer failed to get script properties.");
-    uint32_t justificationCharacter = scriptProperties.justificationCharacter;
-
-    // if a script justificationCharacter is not space, it can have GetJustifiedGlyphs
-    if (justificationCharacter != 32)
-    {
-      uint16_t* modifiedClusterMap = new uint16_t[textLength];
-    retry_getjustifiedglyphs:
-      uint16_t* modifiedGlyphIndices = new uint16_t[maxGlyphCount];
-      float* modifiedGlyphAdvances = new float[maxGlyphCount];
-      DWRITE_GLYPH_OFFSET* modifiedGlyphOffsets = new DWRITE_GLYPH_OFFSET[maxGlyphCount];
-      uint32_t actualGlyphsCount;
-      hr = analyzer1->GetJustifiedGlyphs (fontFace, fontEmSize, runHead->mScript,
-					  textLength, glyphCount, maxGlyphCount,
-					  clusterMap, glyphIndices, glyphAdvances,
-					  justifiedGlyphAdvances, justifiedGlyphOffsets,
-					  glyphProperties, &actualGlyphsCount,
-					  modifiedClusterMap, modifiedGlyphIndices,
-					  modifiedGlyphAdvances, modifiedGlyphOffsets);
-
-      if (hr == HRESULT_FROM_WIN32 (ERROR_INSUFFICIENT_BUFFER))
-      {
-	maxGlyphCount = actualGlyphsCount;
-	delete [] modifiedGlyphIndices;
-	delete [] modifiedGlyphAdvances;
-	delete [] modifiedGlyphOffsets;
-
-	maxGlyphCount = actualGlyphsCount;
-
-	goto retry_getjustifiedglyphs;
-      }
-      if (FAILED (hr))
-	FAIL ("Analyzer failed to get justified glyphs.");
-
-      delete [] clusterMap;
-      delete [] glyphIndices;
-      delete [] glyphAdvances;
-      delete [] glyphOffsets;
-
-      glyphCount = actualGlyphsCount;
-      clusterMap = modifiedClusterMap;
-      glyphIndices = modifiedGlyphIndices;
-      glyphAdvances = modifiedGlyphAdvances;
-      glyphOffsets = modifiedGlyphOffsets;
-
-      delete [] justifiedGlyphAdvances;
-      delete [] justifiedGlyphOffsets;
-    }
-    else
-    {
-      delete [] glyphAdvances;
-      delete [] glyphOffsets;
-
-      glyphAdvances = justifiedGlyphAdvances;
-      glyphOffsets = justifiedGlyphOffsets;
-    }
-
-    delete [] justificationOpportunities;
-  }
-
   /* Ok, we've got everything we need, now compose output buffer,
    * very, *very*, carefully! */
 
@@ -870,43 +769,10 @@ retry_getglyphs:
   delete [] glyphAdvances;
   delete [] glyphOffsets;
 
-  if (num_features)
-    delete [] typographic_features.features;
-
   /* Wow, done! */
   return true;
 }
 
-hb_bool_t
-_hb_directwrite_shape (hb_shape_plan_t    *shape_plan,
-		       hb_font_t          *font,
-		       hb_buffer_t        *buffer,
-		       const hb_feature_t *features,
-		       unsigned int        num_features)
-{
-  return _hb_directwrite_shape_full (shape_plan, font, buffer,
-				     features, num_features, 0);
-}
-
-HB_UNUSED static bool
-_hb_directwrite_shape_experimental_width (hb_font_t          *font,
-					  hb_buffer_t        *buffer,
-					  const hb_feature_t *features,
-					  unsigned int        num_features,
-					  float               width)
-{
-  static const char *shapers = "directwrite";
-  hb_shape_plan_t *shape_plan;
-  shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props,
-					    features, num_features, &shapers);
-  hb_bool_t res = _hb_directwrite_shape_full (shape_plan, font, buffer,
-					      features, num_features, width);
-
-  buffer->unsafe_to_break_all ();
-
-  return res;
-}
-
 struct _hb_directwrite_font_table_context {
   IDWriteFontFace *face;
   void *table_context;
@@ -917,7 +783,7 @@ _hb_directwrite_table_data_release (void *data)
 {
   _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) data;
   context->face->ReleaseFontTable (context->table_context);
-  delete context;
+  hb_free (context);
 }
 
 static hb_blob_t *
@@ -938,7 +804,7 @@ _hb_directwrite_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *
     return nullptr;
   }
 
-  _hb_directwrite_font_table_context *context = new _hb_directwrite_font_table_context;
+  _hb_directwrite_font_table_context *context = (_hb_directwrite_font_table_context *) hb_malloc (sizeof (_hb_directwrite_font_table_context));
   context->face = dw_face;
   context->table_context = table_context;
 

+ 1 - 1
thirdparty/harfbuzz/src/hb-draw.cc

@@ -191,7 +191,7 @@ hb_draw_funcs_destroy (hb_draw_funcs_t *funcs)
 {
   if (!hb_object_destroy (funcs)) return;
 
-  free (funcs);
+  hb_free (funcs);
 }
 
 /**

+ 57 - 45
thirdparty/harfbuzz/src/hb-face.cc

@@ -33,6 +33,7 @@
 #include "hb-open-file.hh"
 #include "hb-ot-face.hh"
 #include "hb-ot-cmap-table.hh"
+#include "hb-map.hh"
 
 
 /**
@@ -106,9 +107,9 @@ DEFINE_NULL_INSTANCE (hb_face_t) =
  * convenient to provide data for individual tables instead of the whole font
  * data. With the caveat that hb_face_get_table_tags() does not currently work
  * with faces created this way.
- * 
+ *
  * Creates a new face object from the specified @user_data and @reference_table_func,
- * with the @destroy callback. 
+ * with the @destroy callback.
  *
  * Return value: (transfer full): The new face object
  *
@@ -150,7 +151,7 @@ _hb_face_for_data_closure_create (hb_blob_t *blob, unsigned int index)
 {
   hb_face_for_data_closure_t *closure;
 
-  closure = (hb_face_for_data_closure_t *) calloc (1, sizeof (hb_face_for_data_closure_t));
+  closure = (hb_face_for_data_closure_t *) hb_calloc (1, sizeof (hb_face_for_data_closure_t));
   if (unlikely (!closure))
     return nullptr;
 
@@ -166,7 +167,7 @@ _hb_face_for_data_closure_destroy (void *data)
   hb_face_for_data_closure_t *closure = (hb_face_for_data_closure_t *) data;
 
   hb_blob_destroy (closure->blob);
-  free (closure);
+  hb_free (closure);
 }
 
 static hb_blob_t *
@@ -265,7 +266,7 @@ hb_face_reference (hb_face_t *face)
 /**
  * hb_face_destroy: (skip)
  * @face: A face object
- * 
+ *
  * Decreases the reference count on a face object. When the
  * reference count reaches zero, the face is destroyed,
  * freeing all memory.
@@ -281,7 +282,7 @@ hb_face_destroy (hb_face_t *face)
   {
     hb_face_t::plan_node_t *next = node->next;
     hb_shape_plan_destroy (node->shape_plan);
-    free (node);
+    hb_free (node);
     node = next;
   }
 
@@ -291,7 +292,7 @@ hb_face_destroy (hb_face_t *face)
   if (face->destroy)
     face->destroy (face->user_data);
 
-  free (face);
+  hb_free (face);
 }
 
 /**
@@ -302,7 +303,7 @@ hb_face_destroy (hb_face_t *face)
  * @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 given face object. 
+ * Attaches a user-data key/data pair to the given face object.
  *
  * Return value: %true if success, %false otherwise
  *
@@ -441,7 +442,7 @@ hb_face_set_index (hb_face_t    *face,
  *
  * <note>Note: face indices within a collection are zero-based.</note>
  *
- * Return value: The index of @face. 
+ * Return value: The index of @face.
  *
  * Since: 0.9.2
  **/
@@ -623,26 +624,26 @@ hb_face_collect_variation_unicodes (hb_face_t *face,
 
 struct hb_face_builder_data_t
 {
-  struct table_entry_t
-  {
-    int cmp (hb_tag_t t) const
-    {
-      if (t < tag) return -1;
-      if (t > tag) return -1;
-      return 0;
-    }
-
-    hb_tag_t   tag;
-    hb_blob_t *blob;
-  };
-
-  hb_vector_t<table_entry_t> tables;
+  hb_hashmap_t<hb_tag_t, hb_blob_t *> tables;
 };
 
+static int compare_entries (const void* pa, const void* pb)
+{
+  const auto& a = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pa;
+  const auto& b = * (const hb_pair_t<hb_tag_t, hb_blob_t*> *) pb;
+
+  /* Order by blob size first (smallest to largest) and then table tag */
+
+  if (a.second->length != b.second->length)
+    return a.second->length < b.second->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 *) calloc (1, sizeof (hb_face_builder_data_t));
+  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;
 
@@ -656,25 +657,25 @@ _hb_face_builder_data_destroy (void *user_data)
 {
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) user_data;
 
-  for (unsigned int i = 0; i < data->tables.length; i++)
-    hb_blob_destroy (data->tables[i].blob);
+  for (hb_blob_t* b : data->tables.values())
+    hb_blob_destroy (b);
 
   data->tables.fini ();
 
-  free (data);
+  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.length;
+  unsigned int table_count = data->tables.get_population ();
   unsigned int face_length = table_count * 16 + 12;
 
-  for (unsigned int i = 0; i < table_count; i++)
-    face_length += hb_ceil_to_4 (hb_blob_get_length (data->tables[i].blob));
+  for (hb_blob_t* b : data->tables.values())
+    face_length += hb_ceil_to_4 (hb_blob_get_length (b));
 
-  char *buf = (char *) malloc (face_length);
+  char *buf = (char *) hb_malloc (face_length);
   if (unlikely (!buf))
     return nullptr;
 
@@ -682,20 +683,31 @@ _hb_face_builder_data_reference_blob (hb_face_builder_data_t *data)
   c.propagate_error (data->tables);
   OT::OpenTypeFontFile *f = c.start_serialize<OT::OpenTypeFontFile> ();
 
-  bool is_cff = data->tables.lsearch (HB_TAG ('C','F','F',' ')) || data->tables.lsearch (HB_TAG ('C','F','F','2'));
+  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;
 
-  bool ret = f->serialize_single (&c, sfnt_tag, data->tables.as_array ());
+  // Sort the tags so that produced face is deterministic.
+  hb_vector_t<hb_pair_t <hb_tag_t, hb_blob_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());
 
   c.end_serialize ();
 
   if (unlikely (!ret))
   {
-    free (buf);
+    hb_free (buf);
     return nullptr;
   }
 
-  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, free);
+  return hb_blob_create (buf, face_length, HB_MEMORY_MODE_WRITABLE, buf, hb_free);
 }
 
 static hb_blob_t *
@@ -706,11 +718,7 @@ _hb_face_builder_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void
   if (!tag)
     return _hb_face_builder_data_reference_blob (data);
 
-  hb_face_builder_data_t::table_entry_t *entry = data->tables.lsearch (tag);
-  if (entry)
-    return hb_blob_reference (entry->blob);
-
-  return nullptr;
+  return hb_blob_reference (data->tables[tag]);
 }
 
 
@@ -750,17 +758,21 @@ hb_face_builder_create ()
 hb_bool_t
 hb_face_builder_add_table (hb_face_t *face, hb_tag_t tag, hb_blob_t *blob)
 {
+  if (tag == HB_MAP_VALUE_INVALID)
+    return false;
+
   if (unlikely (face->destroy != (hb_destroy_func_t) _hb_face_builder_data_destroy))
     return false;
 
   hb_face_builder_data_t *data = (hb_face_builder_data_t *) face->user_data;
 
-  hb_face_builder_data_t::table_entry_t *entry = data->tables.push ();
-  if (unlikely (data->tables.in_error()))
+  hb_blob_t* previous = data->tables.get (tag);
+  if (!data->tables.set (tag, hb_blob_reference (blob)))
+  {
+    hb_blob_destroy (blob);
     return false;
+  }
 
-  entry->tag = tag;
-  entry->blob = hb_blob_reference (blob);
-
+  hb_blob_destroy (previous);
   return true;
 }

+ 40 - 39
thirdparty/harfbuzz/src/hb-font.cc

@@ -620,7 +620,7 @@ hb_font_funcs_destroy (hb_font_funcs_t *ffuncs)
   HB_FONT_FUNCS_IMPLEMENT_CALLBACKS
 #undef HB_FONT_FUNC_IMPLEMENT
 
-  free (ffuncs);
+  hb_free (ffuncs);
 }
 
 /**
@@ -1544,8 +1544,8 @@ _hb_font_adopt_var_coords (hb_font_t *font,
 			   float *design_coords,
 			   unsigned int coords_length)
 {
-  free (font->coords);
-  free (font->design_coords);
+  hb_free (font->coords);
+  hb_free (font->design_coords);
 
   font->coords = coords;
   font->design_coords = design_coords;
@@ -1586,8 +1586,8 @@ hb_font_create_sub_font (hb_font_t *parent)
   unsigned int num_coords = parent->num_coords;
   if (num_coords)
   {
-    int *coords = (int *) calloc (num_coords, sizeof (parent->coords[0]));
-    float *design_coords = (float *) calloc (num_coords, sizeof (parent->design_coords[0]));
+    int *coords = (int *) hb_calloc (num_coords, sizeof (parent->coords[0]));
+    float *design_coords = (float *) hb_calloc (num_coords, sizeof (parent->design_coords[0]));
     if (likely (coords && design_coords))
     {
       memcpy (coords, parent->coords, num_coords * sizeof (parent->coords[0]));
@@ -1596,8 +1596,8 @@ hb_font_create_sub_font (hb_font_t *parent)
     }
     else
     {
-      free (coords);
-      free (design_coords);
+      hb_free (coords);
+      hb_free (design_coords);
     }
   }
 
@@ -1659,10 +1659,10 @@ hb_font_destroy (hb_font_t *font)
   hb_face_destroy (font->face);
   hb_font_funcs_destroy (font->klass);
 
-  free (font->coords);
-  free (font->design_coords);
+  hb_free (font->coords);
+  hb_free (font->design_coords);
 
-  free (font);
+  hb_free (font);
 }
 
 /**
@@ -2052,29 +2052,30 @@ hb_font_set_variations (hb_font_t            *font,
     return;
   }
 
-  unsigned int coords_length = hb_ot_var_get_axis_count (font->face);
+  const OT::fvar &fvar = *font->face->table.fvar;
+  auto axes = fvar.get_axes ();
+  const unsigned coords_length = axes.length;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
+  float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
 
   if (unlikely (coords_length && !(normalized && design_coords)))
   {
-    free (normalized);
-    free (design_coords);
+    hb_free (normalized);
+    hb_free (design_coords);
     return;
   }
 
-  const OT::fvar &fvar = *font->face->table.fvar;
   for (unsigned int i = 0; i < variations_length; i++)
   {
-    hb_ot_var_axis_info_t info;
-    if (hb_ot_var_find_axis_info (font->face, variations[i].tag, &info) &&
-	info.axis_index < coords_length)
-    {
-      float v = variations[i].value;
-      design_coords[info.axis_index] = v;
-      normalized[info.axis_index] = fvar.normalize_axis_value (info.axis_index, v);
-    }
+    const auto tag = variations[i].tag;
+    const auto v = variations[i].value;
+    for (unsigned axis_index = 0; axis_index < coords_length; axis_index++)
+      if (axes[axis_index].axisTag == tag)
+      {
+	design_coords[axis_index] = v;
+	normalized[axis_index] = fvar.normalize_axis_value (axis_index, v);
+      }
   }
   font->face->table.avar->map_coords (normalized, coords_length);
 
@@ -2100,13 +2101,13 @@ hb_font_set_var_coords_design (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  int *normalized = coords_length ? (int *) calloc (coords_length, sizeof (int)) : nullptr;
-  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  int *normalized = coords_length ? (int *) hb_calloc (coords_length, sizeof (int)) : nullptr;
+  float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
 
   if (unlikely (coords_length && !(normalized && design_coords)))
   {
-    free (normalized);
-    free (design_coords);
+    hb_free (normalized);
+    hb_free (design_coords);
     return;
   }
 
@@ -2135,13 +2136,13 @@ hb_font_set_var_named_instance (hb_font_t *font,
 
   unsigned int coords_length = hb_ot_var_named_instance_get_design_coords (font->face, instance_index, nullptr, nullptr);
 
-  float *coords = coords_length ? (float *) calloc (coords_length, sizeof (float)) : nullptr;
+  float *coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (float)) : nullptr;
   if (unlikely (coords_length && !coords))
     return;
 
   hb_ot_var_named_instance_get_design_coords (font->face, instance_index, &coords_length, coords);
   hb_font_set_var_coords_design (font, coords, coords_length);
-  free (coords);
+  hb_free (coords);
 }
 
 /**
@@ -2165,15 +2166,15 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
   if (hb_object_is_immutable (font))
     return;
 
-  int *copy = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
-  int *unmapped = coords_length ? (int *) calloc (coords_length, sizeof (coords[0])) : nullptr;
-  float *design_coords = coords_length ? (float *) calloc (coords_length, sizeof (design_coords[0])) : nullptr;
+  int *copy = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
+  int *unmapped = coords_length ? (int *) hb_calloc (coords_length, sizeof (coords[0])) : nullptr;
+  float *design_coords = coords_length ? (float *) hb_calloc (coords_length, sizeof (design_coords[0])) : nullptr;
 
   if (unlikely (coords_length && !(copy && unmapped && design_coords)))
   {
-    free (copy);
-    free (unmapped);
-    free (design_coords);
+    hb_free (copy);
+    hb_free (unmapped);
+    hb_free (design_coords);
     return;
   }
 
@@ -2187,7 +2188,7 @@ hb_font_set_var_coords_normalized (hb_font_t    *font,
   font->face->table.avar->unmap_coords (unmapped, coords_length);
   for (unsigned int i = 0; i < coords_length; ++i)
     design_coords[i] = font->face->table.fvar->unnormalize_axis_value (i, unmapped[i]);
-  free (unmapped);
+  hb_free (unmapped);
 
   _hb_font_adopt_var_coords (font, copy, design_coords, coords_length);
 }
@@ -2267,7 +2268,7 @@ trampoline_create (FuncType           func,
 {
   typedef hb_trampoline_t<FuncType> trampoline_t;
 
-  trampoline_t *trampoline = (trampoline_t *) calloc (1, sizeof (trampoline_t));
+  trampoline_t *trampoline = (trampoline_t *) hb_calloc (1, sizeof (trampoline_t));
 
   if (unlikely (!trampoline))
     return nullptr;
@@ -2296,7 +2297,7 @@ trampoline_destroy (void *user_data)
 
   if (closure->destroy)
     closure->destroy (closure->user_data);
-  free (closure);
+  hb_free (closure);
 }
 
 typedef hb_trampoline_t<hb_font_get_glyph_func_t> hb_font_get_glyph_trampoline_t;

+ 18 - 30
thirdparty/harfbuzz/src/hb-ft.cc

@@ -91,7 +91,7 @@ struct hb_ft_font_t
 static hb_ft_font_t *
 _hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
 {
-  hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
+  hb_ft_font_t *ft_font = (hb_ft_font_t *) hb_calloc (1, sizeof (hb_ft_font_t));
   if (unlikely (!ft_font)) return nullptr;
 
   ft_font->lock.init ();
@@ -125,7 +125,7 @@ _hb_ft_font_destroy (void *data)
 
   ft_font->lock.fini ();
 
-  free (ft_font);
+  hb_free (ft_font);
 }
 
 /**
@@ -561,9 +561,7 @@ hb_ft_get_font_h_extents (hb_font_t *font HB_UNUSED,
   return true;
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ft_funcs ();
-#endif
+static inline void free_static_ft_funcs ();
 
 static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
 {
@@ -591,21 +589,17 @@ static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft
 
     hb_font_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ft_funcs);
-#endif
+    hb_atexit (free_static_ft_funcs);
 
     return funcs;
   }
 } static_ft_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ft_funcs ()
 {
   static_ft_funcs.free_instance ();
 }
-#endif
 
 static hb_font_funcs_t *
 _hb_ft_get_font_funcs ()
@@ -642,20 +636,20 @@ _hb_ft_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data
   if (error)
     return nullptr;
 
-  buffer = (FT_Byte *) malloc (length);
+  buffer = (FT_Byte *) hb_malloc (length);
   if (!buffer)
     return nullptr;
 
   error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
   if (error)
   {
-    free (buffer);
+    hb_free (buffer);
     return nullptr;
   }
 
   return hb_blob_create ((const char *) buffer, length,
 			 HB_MEMORY_MODE_WRITABLE,
-			 buffer, free);
+			 buffer, hb_free);
 }
 
 /**
@@ -846,8 +840,8 @@ hb_ft_font_changed (hb_font_t *font)
   FT_MM_Var *mm_var = nullptr;
   if (!FT_Get_MM_Var (ft_face, &mm_var))
   {
-    FT_Fixed *ft_coords = (FT_Fixed *) calloc (mm_var->num_axis, sizeof (FT_Fixed));
-    int *coords = (int *) calloc (mm_var->num_axis, sizeof (int));
+    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (mm_var->num_axis, sizeof (FT_Fixed));
+    int *coords = (int *) hb_calloc (mm_var->num_axis, sizeof (int));
     if (coords && ft_coords)
     {
       if (!FT_Get_Var_Blend_Coordinates (ft_face, mm_var->num_axis, ft_coords))
@@ -866,12 +860,12 @@ hb_ft_font_changed (hb_font_t *font)
 	  hb_font_set_var_coords_normalized (font, nullptr, 0);
       }
     }
-    free (coords);
-    free (ft_coords);
+    hb_free (coords);
+    hb_free (ft_coords);
 #ifdef HAVE_FT_DONE_MM_VAR
     FT_Done_MM_Var (ft_face->glyph->library, mm_var);
 #else
-    free (mm_var);
+    hb_free (mm_var);
 #endif
   }
 #endif
@@ -905,9 +899,7 @@ hb_ft_font_create_referenced (FT_Face ft_face)
   return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ft_library ();
-#endif
+static inline void free_static_ft_library ();
 
 static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<FT_Library>,
 							     hb_ft_library_lazy_loader_t>
@@ -918,9 +910,7 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
     if (FT_Init_FreeType (&l))
       return nullptr;
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ft_library);
-#endif
+    hb_atexit (free_static_ft_library);
 
     return l;
   }
@@ -934,13 +924,11 @@ static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer<F
   }
 } static_ft_library;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ft_library ()
 {
   static_ft_library.free_instance ();
 }
-#endif
 
 static FT_Library
 get_ft_library ()
@@ -1020,13 +1008,13 @@ hb_ft_font_set_funcs (hb_font_t *font)
   const int *coords = hb_font_get_var_coords_normalized (font, &num_coords);
   if (num_coords)
   {
-    FT_Fixed *ft_coords = (FT_Fixed *) calloc (num_coords, sizeof (FT_Fixed));
+    FT_Fixed *ft_coords = (FT_Fixed *) hb_calloc (num_coords, sizeof (FT_Fixed));
     if (ft_coords)
     {
       for (unsigned int i = 0; i < num_coords; i++)
 	ft_coords[i] = coords[i] * 4;
       FT_Set_Var_Blend_Coordinates (ft_face, num_coords, ft_coords);
-      free (ft_coords);
+      hb_free (ft_coords);
     }
   }
 #endif

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

@@ -50,16 +50,16 @@ _hb_gdi_reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_dat
   length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
   if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc;
 
-  buffer = (char *) malloc (length);
+  buffer = (char *) hb_malloc (length);
   if (unlikely (!buffer)) goto fail_with_releasedc;
   length = GetFontData (hdc, hb_uint32_swap (tag), 0, buffer, length);
   if (unlikely (length == GDI_ERROR)) goto fail_with_releasedc_and_free;
   ReleaseDC (nullptr, hdc);
 
-  return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, free);
+  return hb_blob_create ((const char *) buffer, length, HB_MEMORY_MODE_WRITABLE, buffer, hb_free);
 
 fail_with_releasedc_and_free:
-  free (buffer);
+  hb_free (buffer);
 fail_with_releasedc:
   ReleaseDC (nullptr, hdc);
 fail:

+ 3 - 9
thirdparty/harfbuzz/src/hb-glib.cc

@@ -218,9 +218,7 @@ hb_glib_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 }
 
 
-#if HB_USE_ATEXIT
-static void free_static_glib_funcs ();
-#endif
+static inline void free_static_glib_funcs ();
 
 static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_glib_unicode_funcs_lazy_loader_t>
 {
@@ -237,21 +235,17 @@ static struct hb_glib_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader
 
     hb_unicode_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_glib_funcs);
-#endif
+    hb_atexit (free_static_glib_funcs);
 
     return funcs;
   }
 } static_glib_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_glib_funcs ()
 {
   static_glib_funcs.free_instance ();
 }
-#endif
 
 /**
  * hb_glib_get_unicode_funcs:

+ 2 - 2
thirdparty/harfbuzz/src/hb-gobject-structs.cc

@@ -80,12 +80,12 @@ hb_gobject_##name##_get_type () \
 #define HB_DEFINE_VALUE_TYPE(name) \
 	static hb_##name##_t *_hb_##name##_reference (const hb_##name##_t *l) \
 	{ \
-	  hb_##name##_t *c = (hb_##name##_t *) calloc (1, sizeof (hb_##name##_t)); \
+	  hb_##name##_t *c = (hb_##name##_t *) hb_calloc (1, sizeof (hb_##name##_t)); \
 	  if (unlikely (!c)) return nullptr; \
 	  *c = *l; \
 	  return c; \
 	} \
-	static void _hb_##name##_destroy (hb_##name##_t *l) { free (l); } \
+	static void _hb_##name##_destroy (hb_##name##_t *l) { hb_free (l); } \
 	HB_DEFINE_BOXED_TYPE (name, _hb_##name##_reference, _hb_##name##_destroy)
 
 HB_DEFINE_OBJECT_TYPE (buffer)

+ 7 - 6
thirdparty/harfbuzz/src/hb-graphite2.cc

@@ -88,7 +88,7 @@ static const void *hb_graphite2_get_table (const void *data, unsigned int tag, s
   {
     blob = face_data->face->reference_table (tag);
 
-    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) calloc (1, sizeof (hb_graphite2_tablelist_t));
+    hb_graphite2_tablelist_t *p = (hb_graphite2_tablelist_t *) hb_calloc (1, sizeof (hb_graphite2_tablelist_t));
     if (unlikely (!p)) {
       hb_blob_destroy (blob);
       return nullptr;
@@ -123,15 +123,16 @@ _hb_graphite2_shaper_face_data_create (hb_face_t *face)
   }
   hb_blob_destroy (silf_blob);
 
-  hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) calloc (1, sizeof (hb_graphite2_face_data_t));
+  hb_graphite2_face_data_t *data = (hb_graphite2_face_data_t *) hb_calloc (1, sizeof (hb_graphite2_face_data_t));
   if (unlikely (!data))
     return nullptr;
 
   data->face = face;
-  data->grface = gr_make_face (data, &hb_graphite2_get_table, gr_face_preloadAll);
+  const gr_face_ops ops = {sizeof(gr_face_ops), &hb_graphite2_get_table, NULL};
+  data->grface = gr_make_face_with_ops (data, &ops, gr_face_preloadAll);
 
   if (unlikely (!data->grface)) {
-    free (data);
+    hb_free (data);
     return nullptr;
   }
 
@@ -148,12 +149,12 @@ _hb_graphite2_shaper_face_data_destroy (hb_graphite2_face_data_t *data)
     hb_graphite2_tablelist_t *old = tlist;
     hb_blob_destroy (tlist->blob);
     tlist = tlist->next;
-    free (old);
+    hb_free (old);
   }
 
   gr_face_destroy (data->grface);
 
-  free (data);
+  hb_free (data);
 }
 
 /**

+ 3 - 9
thirdparty/harfbuzz/src/hb-icu.cc

@@ -233,9 +233,7 @@ hb_icu_unicode_decompose (hb_unicode_funcs_t *ufuncs HB_UNUSED,
 }
 
 
-#if HB_USE_ATEXIT
-static void free_static_icu_funcs ();
-#endif
+static inline void free_static_icu_funcs ();
 
 static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_t<hb_icu_unicode_funcs_lazy_loader_t>
 {
@@ -257,21 +255,17 @@ static struct hb_icu_unicode_funcs_lazy_loader_t : hb_unicode_funcs_lazy_loader_
 
     hb_unicode_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_icu_funcs);
-#endif
+    hb_atexit (free_static_icu_funcs);
 
     return funcs;
   }
 } static_icu_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_icu_funcs ()
 {
   static_icu_funcs.free_instance ();
 }
-#endif
 
 /**
  * hb_icu_get_unicode_funcs:

+ 1 - 1
thirdparty/harfbuzz/src/hb-iter.hh

@@ -46,7 +46,7 @@
  * TODO Document more.
  *
  * If iterator implementation implements operator!=, then can be
- * used in range-based for loop.  That comes free if the iterator
+ * used in range-based for loop.  That already happens if the iterator
  * is random-access.  Otherwise, the range-based for loop incurs
  * one traversal to find end(), which can be avoided if written
  * as a while-style for loop, or if iterator implements a faster

+ 3 - 3
thirdparty/harfbuzz/src/hb-machinery.hh

@@ -242,14 +242,14 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   static const Stored* get_null () { return &Null (Stored); }
   static Stored *create (Data *data)
   {
-    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
     if (likely (p))
       p->init (data);
     return p;
   }
   static Stored *create ()
   {
-    Stored *p = (Stored *) calloc (1, sizeof (Stored));
+    Stored *p = (Stored *) hb_calloc (1, sizeof (Stored));
     if (likely (p))
       p->init ();
     return p;
@@ -257,7 +257,7 @@ struct hb_lazy_loader_t : hb_data_wrapper_t<Data, WheresData>
   static void destroy (Stored *p)
   {
     p->fini ();
-    free (p);
+    hb_free (p);
   }
 
 //  private:

+ 3 - 4
thirdparty/harfbuzz/src/hb-map.cc

@@ -109,7 +109,7 @@ hb_map_destroy (hb_map_t *map)
 
   map->fini_shallow ();
 
-  free (map);
+  hb_free (map);
 }
 
 /**
@@ -188,6 +188,7 @@ hb_map_set (hb_map_t       *map,
 	    hb_codepoint_t  key,
 	    hb_codepoint_t  value)
 {
+  /* Immutable-safe. */
   map->set (key, value);
 }
 
@@ -220,6 +221,7 @@ void
 hb_map_del (hb_map_t       *map,
 	    hb_codepoint_t  key)
 {
+  /* Immutable-safe. */
   map->del (key);
 }
 
@@ -253,9 +255,6 @@ hb_map_has (const hb_map_t *map,
 void
 hb_map_clear (hb_map_t *map)
 {
-  if (unlikely (hb_object_is_immutable (map)))
-    return;
-
   return map->clear ();
 }
 

+ 15 - 11
thirdparty/harfbuzz/src/hb-map.hh

@@ -85,7 +85,7 @@ struct hb_hashmap_t
   }
   void fini_shallow ()
   {
-    free (items);
+    hb_free (items);
     items = nullptr;
     population = occupancy = 0;
   }
@@ -109,7 +109,7 @@ struct hb_hashmap_t
 
     unsigned int power = hb_bit_storage (population * 2 + 8);
     unsigned int new_size = 1u << power;
-    item_t *new_items = (item_t *) malloc ((size_t) new_size * sizeof (item_t));
+    item_t *new_items = (item_t *) hb_malloc ((size_t) new_size * sizeof (item_t));
     if (unlikely (!new_items))
     {
       successful = false;
@@ -135,14 +135,14 @@ struct hb_hashmap_t
 			 old_items[i].hash,
 			 old_items[i].value);
 
-    free (old_items);
+    hb_free (old_items);
 
     return true;
   }
 
-  void set (K key, V value)
+  bool set (K key, V value)
   {
-    set_with_hash (key, hb_hash (key), value);
+    return set_with_hash (key, hb_hash (key), value);
   }
 
   V get (K key) const
@@ -169,6 +169,8 @@ struct hb_hashmap_t
 
   void clear ()
   {
+    if (unlikely (!successful)) return;
+
     if (items)
       for (auto &_ : hb_iter (items, mask + 1))
 	_.clear ();
@@ -211,20 +213,20 @@ struct hb_hashmap_t
 
   protected:
 
-  void set_with_hash (K key, uint32_t hash, V value)
+  bool set_with_hash (K key, uint32_t hash, V value)
   {
-    if (unlikely (!successful)) return;
-    if (unlikely (key == kINVALID)) return;
-    if ((occupancy + occupancy / 2) >= mask && !resize ()) return;
+    if (unlikely (!successful)) return false;
+    if (unlikely (key == kINVALID)) return true;
+    if (unlikely ((occupancy + occupancy / 2) >= mask && !resize ())) return false;
     unsigned int i = bucket_for_hash (key, hash);
 
     if (value == vINVALID && items[i].key != key)
-      return; /* Trying to delete non-existent key. */
+      return true; /* Trying to delete non-existent key. */
 
     if (!items[i].is_unused ())
     {
       occupancy--;
-      if (items[i].is_tombstone ())
+      if (!items[i].is_tombstone ())
 	population--;
     }
 
@@ -235,6 +237,8 @@ struct hb_hashmap_t
     occupancy++;
     if (!items[i].is_tombstone ())
       population++;
+
+    return true;
   }
 
   unsigned int bucket_for (K key) const

+ 16 - 15
thirdparty/harfbuzz/src/hb-meta.hh

@@ -101,14 +101,14 @@ HB_FUNCOBJ (hb_addressof);
 template <typename T> static inline T hb_declval ();
 #define hb_declval(T) (hb_declval<T> ())
 
-template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_const		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_const<const T>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_const = typename hb_match_const<T>::type;
 template <typename T> using hb_add_const = const T;
 #define hb_is_const(T) hb_match_const<T>::value
-template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
-template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_reference		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_reference<T &>	: hb_type_identity_t<T>, hb_true_type	{};
+template <typename T> struct hb_match_reference<T &&>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_reference = typename hb_match_reference<T>::type;
 template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<1>) -> hb_type_identity<T&>;
 template <typename T> auto _hb_try_add_lvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
@@ -117,8 +117,8 @@ template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<1>) -> hb_t
 template <typename T> auto _hb_try_add_rvalue_reference (hb_priority<0>) -> hb_type_identity<T>;
 template <typename T> using hb_add_rvalue_reference = decltype (_hb_try_add_rvalue_reference<T> (hb_prioritize));
 #define hb_is_reference(T) hb_match_reference<T>::value
-template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_bool_constant<false>{};
-template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_bool_constant<true>	{};
+template <typename T> struct hb_match_pointer		: hb_type_identity_t<T>, hb_false_type	{};
+template <typename T> struct hb_match_pointer<T *>	: hb_type_identity_t<T>, hb_true_type	{};
 template <typename T> using hb_remove_pointer = typename hb_match_pointer<T>::type;
 template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<hb_remove_reference<T>*>;
 template <typename T> auto _hb_try_add_pointer (hb_priority<1>) -> hb_type_identity<T>;
@@ -259,15 +259,15 @@ using hb_is_arithmetic = hb_bool_constant<
 #define hb_is_arithmetic(T) hb_is_arithmetic<T>::value
 
 
-template <typename T>
-using hb_is_signed = hb_conditional<hb_is_arithmetic (T),
-				    hb_bool_constant<(T) -1 < (T) 0>,
-				    hb_false_type>;
+template <typename T, bool is_arithmetic> struct hb_is_signed_;
+template <typename T> struct hb_is_signed_<T, false>	: hb_false_type {};
+template <typename T> struct hb_is_signed_<T, true>	: hb_bool_constant<(T) -1 < (T) 0> {};
+template <typename T> struct hb_is_signed : hb_is_signed_<T, hb_is_arithmetic (T)> {};
 #define hb_is_signed(T) hb_is_signed<T>::value
-template <typename T>
-using hb_is_unsigned = hb_conditional<hb_is_arithmetic (T),
-				      hb_bool_constant<(T) 0 < (T) -1>,
-				      hb_false_type>;
+template <typename T, bool is_arithmetic> struct hb_is_unsigned_;
+template <typename T> struct hb_is_unsigned_<T, false>	: hb_false_type {};
+template <typename T> struct hb_is_unsigned_<T, true>	: hb_bool_constant<(T) 0 < (T) -1> {};
+template <typename T> struct hb_is_unsigned : hb_is_unsigned_<T, hb_is_arithmetic (T)> {};
 #define hb_is_unsigned(T) hb_is_unsigned<T>::value
 
 template <typename T> struct hb_int_min;
@@ -282,6 +282,7 @@ template <> struct hb_int_min<signed long>		: hb_integral_constant<signed long,
 template <> struct hb_int_min<unsigned long>		: hb_integral_constant<unsigned long,		0>		{};
 template <> struct hb_int_min<signed long long>		: hb_integral_constant<signed long long,	LLONG_MIN>	{};
 template <> struct hb_int_min<unsigned long long>	: hb_integral_constant<unsigned long long,	0>		{};
+template <typename T> struct hb_int_min<T *>		: hb_integral_constant<T *,			nullptr>	{};
 #define hb_int_min(T) hb_int_min<T>::value
 template <typename T> struct hb_int_max;
 template <> struct hb_int_max<char>			: hb_integral_constant<char,			CHAR_MAX>	{};

+ 177 - 0
thirdparty/harfbuzz/src/hb-ms-feature-ranges.cc

@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2011,2012,2013  Google, Inc.
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  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
+ */
+
+#include "hb-ms-feature-ranges.hh"
+
+bool
+hb_ms_setup_features (const hb_feature_t                *features,
+		      unsigned int                       num_features,
+		      hb_vector_t<hb_ms_feature_t>      &feature_records, /* OUT */
+		      hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */)
+{
+  feature_records.shrink(0);
+  range_records.shrink(0);
+
+  /* Sort features by start/end events. */
+  hb_vector_t<hb_ms_feature_event_t> feature_events;
+  for (unsigned int i = 0; i < num_features; i++)
+  {
+    hb_ms_active_feature_t feature;
+    feature.fea.tag_le = hb_uint32_swap (features[i].tag);
+    feature.fea.value = features[i].value;
+    feature.order = i;
+
+    hb_ms_feature_event_t *event;
+
+    event = feature_events.push ();
+    event->index = features[i].start;
+    event->start = true;
+    event->feature = feature;
+
+    event = feature_events.push ();
+    event->index = features[i].end;
+    event->start = false;
+    event->feature = feature;
+  }
+  feature_events.qsort ();
+  /* Add a strategic final event. */
+  {
+    hb_ms_active_feature_t feature;
+    feature.fea.tag_le = 0;
+    feature.fea.value = 0;
+    feature.order = num_features + 1;
+
+    auto *event = feature_events.push ();
+    event->index = 0; /* This value does magic. */
+    event->start = false;
+    event->feature = feature;
+  }
+
+  /* Scan events and save features for each range. */
+  hb_vector_t<hb_ms_active_feature_t> active_features;
+  unsigned int last_index = 0;
+  for (unsigned int i = 0; i < feature_events.length; i++)
+  {
+    auto *event = &feature_events[i];
+
+    if (event->index != last_index)
+    {
+      /* Save a snapshot of active features and the range. */
+      auto *range = range_records.push ();
+      auto offset = feature_records.length;
+
+      active_features.qsort ();
+      for (unsigned int j = 0; j < active_features.length; j++)
+      {
+        if (!j || active_features[j].fea.tag_le != feature_records[feature_records.length - 1].tag_le)
+        {
+          feature_records.push (active_features[j].fea);
+        }
+        else
+        {
+          /* Overrides value for existing feature. */
+          feature_records[feature_records.length - 1].value = active_features[j].fea.value;
+        }
+      }
+
+      /* Will convert to pointer after all is ready, since feature_records.array
+       * may move as we grow it. */
+      range->features.features = reinterpret_cast<hb_ms_feature_t *> (offset);
+      range->features.num_features = feature_records.length - offset;
+      range->index_first = last_index;
+      range->index_last  = event->index - 1;
+
+      last_index = event->index;
+    }
+
+    if (event->start)
+    {
+      active_features.push (event->feature);
+    }
+    else
+    {
+      auto *feature = active_features.find (&event->feature);
+      if (feature)
+        active_features.remove (feature - active_features.arrayZ);
+    }
+  }
+
+  if (!range_records.length) /* No active feature found. */
+    num_features = 0;
+
+  /* Fixup the pointers. */
+  for (unsigned int i = 0; i < range_records.length; i++)
+  {
+    auto *range = &range_records[i];
+    range->features.features = (hb_ms_feature_t *) feature_records + reinterpret_cast<uintptr_t> (range->features.features);
+  }
+
+  return !!num_features;
+}
+
+void
+hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t>      &feature_records,
+			   hb_vector_t<hb_ms_range_record_t> &range_records,
+			   unsigned int                       chars_offset,
+			   unsigned int                       chars_len,
+			   uint16_t                          *log_clusters,
+			   hb_vector_t<hb_ms_features_t*>    &range_features, /* OUT */
+			   hb_vector_t<uint32_t>             &range_counts /* OUT */)
+{
+  range_features.shrink (0);
+  range_counts.shrink (0);
+
+  auto *last_range = &range_records[0];
+  for (unsigned int i = chars_offset; i < chars_len; i++)
+  {
+    auto *range = last_range;
+    while (log_clusters[i] < range->index_first)
+      range--;
+    while (log_clusters[i] > range->index_last)
+      range++;
+    if (!range_features.length ||
+        &range->features != range_features[range_features.length - 1])
+    {
+      auto **features = range_features.push ();
+      auto *c = range_counts.push ();
+      if (unlikely (!features || !c))
+      {
+        range_features.shrink (0);
+        range_counts.shrink (0);
+        break;
+      }
+      *features = &range->features;
+      *c = 1;
+    }
+    else
+    {
+      range_counts[range_counts.length - 1]++;
+    }
+
+    last_range = range;
+  }
+}

+ 96 - 0
thirdparty/harfbuzz/src/hb-ms-feature-ranges.hh

@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2011,2012,2013  Google, Inc.
+ * Copyright © 2021  Khaled Hosny
+ *
+ *  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_MS_FEATURE_RANGES_HH
+#define HB_MS_FEATURE_RANGES_HH
+
+#include "hb.hh"
+
+typedef struct hb_ms_feature_t {
+  uint32_t tag_le;
+  uint32_t value;
+} hb_ms_feature_t;
+
+typedef struct hb_ms_features_t {
+  hb_ms_feature_t *features;
+  uint32_t         num_features;
+} hb_ms_features_t;
+
+struct hb_ms_active_feature_t {
+  hb_ms_feature_t fea;
+  unsigned int order;
+
+  HB_INTERNAL static int cmp (const void *pa, const void *pb) {
+    const auto *a = (const hb_ms_active_feature_t *) pa;
+    const auto *b = (const hb_ms_active_feature_t *) pb;
+    return a->fea.tag_le < b->fea.tag_le ? -1 : a->fea.tag_le > b->fea.tag_le ? 1 :
+	   a->order < b->order ? -1 : a->order > b->order ? 1 :
+	   a->fea.value < b->fea.value ? -1 : a->fea.value > b->fea.value ? 1 :
+	   0;
+  }
+  bool operator== (const hb_ms_active_feature_t *f)
+  { return cmp (this, f) == 0; }
+};
+
+struct hb_ms_feature_event_t {
+  unsigned int index;
+  bool start;
+  hb_ms_active_feature_t feature;
+
+  HB_INTERNAL static int cmp (const void *pa, const void *pb)
+  {
+    const auto *a = (const hb_ms_feature_event_t *) pa;
+    const auto *b = (const hb_ms_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 :
+	   hb_ms_active_feature_t::cmp (&a->feature, &b->feature);
+  }
+};
+
+struct hb_ms_range_record_t {
+  hb_ms_features_t features;
+  unsigned int index_first; /* == start */
+  unsigned int index_last;  /* == end - 1 */
+};
+
+HB_INTERNAL bool
+hb_ms_setup_features (const hb_feature_t                *features,
+		      unsigned int                       num_features,
+		      hb_vector_t<hb_ms_feature_t>      &feature_records, /* OUT */
+		      hb_vector_t<hb_ms_range_record_t> &range_records /* OUT */);
+
+
+HB_INTERNAL void
+hb_ms_make_feature_ranges (hb_vector_t<hb_ms_feature_t>      &feature_records,
+			   hb_vector_t<hb_ms_range_record_t> &range_records,
+			   unsigned int                       chars_offset,
+			   unsigned int                       chars_len,
+			   uint16_t                          *log_clusters,
+			   hb_vector_t<hb_ms_features_t*>    &range_features, /* OUT */
+			   hb_vector_t<uint32_t>             &range_counts /* OUT */);
+
+#endif /* HB_MS_FEATURE_RANGES_HH */

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

@@ -39,8 +39,7 @@
 
 /* We need external help for these */
 
-#if defined(HB_MUTEX_IMPL_INIT) \
- && defined(hb_mutex_impl_init) \
+#if defined(hb_mutex_impl_init) \
  && defined(hb_mutex_impl_lock) \
  && defined(hb_mutex_impl_unlock) \
  && defined(hb_mutex_impl_finish)
@@ -52,7 +51,6 @@
 
 #include <pthread.h>
 typedef pthread_mutex_t hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	PTHREAD_MUTEX_INITIALIZER
 #define hb_mutex_impl_init(M)	pthread_mutex_init (M, nullptr)
 #define hb_mutex_impl_lock(M)	pthread_mutex_lock (M)
 #define hb_mutex_impl_unlock(M)	pthread_mutex_unlock (M)
@@ -62,7 +60,6 @@ typedef pthread_mutex_t hb_mutex_impl_t;
 #elif !defined(HB_NO_MT) && defined(_WIN32)
 
 typedef CRITICAL_SECTION hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	{0}
 #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP)
 #define hb_mutex_impl_init(M)	InitializeCriticalSectionEx (M, 0, 0)
 #else
@@ -76,7 +73,6 @@ typedef CRITICAL_SECTION hb_mutex_impl_t;
 #elif defined(HB_NO_MT)
 
 typedef int hb_mutex_impl_t;
-#define HB_MUTEX_IMPL_INIT	0
 #define hb_mutex_impl_init(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_lock(M)	HB_STMT_START {} HB_STMT_END
 #define hb_mutex_impl_unlock(M)	HB_STMT_START {} HB_STMT_END
@@ -91,8 +87,6 @@ typedef int hb_mutex_impl_t;
 #endif
 
 
-#define HB_MUTEX_INIT		{HB_MUTEX_IMPL_INIT}
-
 struct hb_mutex_t
 {
   hb_mutex_impl_t m;

+ 16 - 4
thirdparty/harfbuzz/src/hb-null.hh

@@ -39,8 +39,11 @@
 
 #define HB_NULL_POOL_SIZE 384
 
-/* Use SFINAE to sniff whether T has min_size; in which case return T::null_size,
- * otherwise return sizeof(T). */
+/* Use SFINAE to sniff whether T has min_size; in which case return the larger
+ * of sizeof(T) and T::null_size, otherwise return sizeof(T).
+ *
+ * The main purpose of this is to let structs communicate that they are not nullable,
+ * by defining min_size but *not* null_size. */
 
 /* The hard way...
  * https://stackoverflow.com/questions/7776448/sfinae-tried-with-bool-gives-compiler-error-template-argument-tvalue-invol
@@ -49,8 +52,9 @@
 template <typename T, typename>
 struct _hb_null_size : hb_integral_constant<unsigned, sizeof (T)> {};
 template <typename T>
-struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::null_size> {};
-
+struct _hb_null_size<T, hb_void_t<decltype (T::min_size)>>
+	: hb_integral_constant<unsigned,
+			       (sizeof (T) > T::null_size ? sizeof (T) : T::null_size)> {};
 template <typename T>
 using hb_null_size = _hb_null_size<T, void>;
 #define hb_null_size(T) hb_null_size<T>::value
@@ -68,6 +72,14 @@ template <typename T>
 using hb_static_size = _hb_static_size<T, void>;
 #define hb_static_size(T) hb_static_size<T>::value
 
+template <typename T, typename>
+struct _hb_min_size : hb_integral_constant<unsigned, sizeof (T)> {};
+template <typename T>
+struct _hb_min_size<T, hb_void_t<decltype (T::min_size)>> : hb_integral_constant<unsigned, T::min_size> {};
+template <typename T>
+using hb_min_size = _hb_min_size<T, void>;
+#define hb_min_size(T) hb_min_size<T>::value
+
 
 /*
  * Null()

+ 10 - 15
thirdparty/harfbuzz/src/hb-object.hh

@@ -140,8 +140,6 @@ struct hb_lockable_set_t
  * Reference-count.
  */
 
-#define HB_REFERENCE_COUNT_INIT {0}
-
 struct hb_reference_count_t
 {
   mutable hb_atomic_int_t ref_count;
@@ -197,6 +195,8 @@ struct hb_object_header_t
   hb_reference_count_t ref_count;
   mutable hb_atomic_int_t writable = 0;
   hb_atomic_ptr_t<hb_user_data_array_t> user_data;
+
+  bool is_inert () const { return !ref_count.get_relaxed (); }
 };
 #define HB_OBJECT_HEADER_STATIC {}
 
@@ -217,7 +217,7 @@ static inline void hb_object_trace (const Type *obj, const char *function)
 template <typename Type>
 static inline Type *hb_object_create ()
 {
-  Type *obj = (Type *) calloc (1, sizeof (Type));
+  Type *obj = (Type *) hb_calloc (1, sizeof (Type));
 
   if (unlikely (!obj))
     return obj;
@@ -234,11 +234,6 @@ static inline void hb_object_init (Type *obj)
   obj->header.user_data.init ();
 }
 template <typename Type>
-static inline bool hb_object_is_inert (const Type *obj)
-{
-  return unlikely (obj->header.ref_count.is_inert ());
-}
-template <typename Type>
 static inline bool hb_object_is_valid (const Type *obj)
 {
   return likely (obj->header.ref_count.is_valid ());
@@ -257,7 +252,7 @@ template <typename Type>
 static inline Type *hb_object_reference (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return obj;
   assert (hb_object_is_valid (obj));
   obj->header.ref_count.inc ();
@@ -267,7 +262,7 @@ template <typename Type>
 static inline bool hb_object_destroy (Type *obj)
 {
   hb_object_trace (obj, HB_FUNC);
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
   if (obj->header.ref_count.dec () != 1)
@@ -284,7 +279,7 @@ static inline void hb_object_fini (Type *obj)
   if (user_data)
   {
     user_data->fini ();
-    free (user_data);
+    hb_free (user_data);
     user_data = nullptr;
   }
 }
@@ -295,7 +290,7 @@ static inline bool hb_object_set_user_data (Type               *obj,
 					    hb_destroy_func_t   destroy,
 					    hb_bool_t           replace)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return false;
   assert (hb_object_is_valid (obj));
 
@@ -303,14 +298,14 @@ retry:
   hb_user_data_array_t *user_data = obj->header.user_data.get ();
   if (unlikely (!user_data))
   {
-    user_data = (hb_user_data_array_t *) calloc (sizeof (hb_user_data_array_t), 1);
+    user_data = (hb_user_data_array_t *) hb_calloc (sizeof (hb_user_data_array_t), 1);
     if (unlikely (!user_data))
       return false;
     user_data->init ();
     if (unlikely (!obj->header.user_data.cmpexch (nullptr, user_data)))
     {
       user_data->fini ();
-      free (user_data);
+      hb_free (user_data);
       goto retry;
     }
   }
@@ -322,7 +317,7 @@ template <typename Type>
 static inline void *hb_object_get_user_data (Type               *obj,
 					     hb_user_data_key_t *key)
 {
-  if (unlikely (!obj || hb_object_is_inert (obj)))
+  if (unlikely (!obj || obj->header.is_inert ()))
     return nullptr;
   assert (hb_object_is_valid (obj));
   hb_user_data_array_t *user_data = obj->header.user_data.get ();

+ 42 - 26
thirdparty/harfbuzz/src/hb-open-file.hh

@@ -35,7 +35,6 @@
 
 namespace OT {
 
-
 /*
  *
  * The OpenType Font File
@@ -102,7 +101,13 @@ typedef struct OpenTypeOffsetTable
   {
     Tag t;
     t = tag;
-    return tables.bfind (t, table_index, HB_BFIND_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+    /* Use lfind for small fonts; there are fonts that have unsorted table entries;
+     * those tend to work in other tools, so tolerate them.
+     * https://github.com/harfbuzz/harfbuzz/issues/3065 */
+    if (tables.len < 16)
+      return tables.lfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
+    else
+      return tables.bfind (t, table_index, HB_NOT_FOUND_STORE, Index::NOT_FOUND_INDEX);
   }
   const TableRecord& get_table_by_tag (hb_tag_t tag) const
   {
@@ -113,44 +118,53 @@ typedef struct OpenTypeOffsetTable
 
   public:
 
-  template <typename item_t>
+  template <typename Iterator,
+	    hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
   bool serialize (hb_serialize_context_t *c,
 		  hb_tag_t sfnt_tag,
-		  hb_array_t<item_t> items)
+		  Iterator it)
   {
     TRACE_SERIALIZE (this);
     /* Alloc 12 for the OTHeader. */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     /* Write sfntVersion (bytes 0..3). */
     sfnt_version = sfnt_tag;
     /* Take space for numTables, searchRange, entrySelector, RangeShift
      * and the TableRecords themselves.  */
-    if (unlikely (!tables.serialize (c, items.length))) return_trace (false);
+    unsigned num_items = it.len ();
+    if (unlikely (!tables.serialize (c, num_items))) return_trace (false);
 
     const char *dir_end = (const char *) c->head;
     HBUINT32 *checksum_adjustment = nullptr;
 
     /* Write OffsetTables, alloc for and write actual table blobs. */
-    for (unsigned int i = 0; i < tables.len; i++)
+    unsigned i = 0;
+    for (hb_pair_t<hb_tag_t, hb_blob_t*> entry : it)
     {
-      TableRecord &rec = tables.arrayZ[i];
-      hb_blob_t *blob = items[i].blob;
-      rec.tag = items[i].tag;
-      rec.length = blob->length;
-      rec.offset.serialize (c, this);
+      hb_blob_t *blob = entry.second;
+      unsigned len = blob->length;
 
       /* Allocate room for the table and copy it. */
-      char *start = (char *) c->allocate_size<void> (rec.length);
+      char *start = (char *) c->allocate_size<void> (len);
       if (unlikely (!start)) return false;
 
-      if (likely (rec.length))
-	memcpy (start, blob->data, rec.length);
+      TableRecord &rec = tables.arrayZ[i];
+      rec.tag = entry.first;
+      rec.length = len;
+      rec.offset = 0;
+      if (unlikely (!c->check_assign (rec.offset,
+				      (unsigned) ((char *) start - (char *) this),
+				      HB_SERIALIZE_ERROR_OFFSET_OVERFLOW)))
+        return_trace (false);
+
+      if (likely (len))
+	memcpy (start, blob->data, len);
 
       /* 4-byte alignment. */
       c->align (4);
       const char *end = (const char *) c->head;
 
-      if (items[i].tag == HB_OT_TAG_head &&
+      if (entry.first == HB_OT_TAG_head &&
 	  (unsigned) (end - start) >= head::static_size)
       {
 	head *h = (head *) start;
@@ -159,6 +173,7 @@ typedef struct OpenTypeOffsetTable
       }
 
       rec.checkSum.set_for_data (start, end - start);
+      i++;
     }
 
     tables.qsort ();
@@ -170,7 +185,7 @@ typedef struct OpenTypeOffsetTable
       /* The following line is a slower version of the following block. */
       //checksum.set_for_data (this, (const char *) c->head - (const char *) this);
       checksum.set_for_data (this, dir_end - (const char *) this);
-      for (unsigned int i = 0; i < items.length; i++)
+      for (unsigned int i = 0; i < num_items; i++)
       {
 	TableRecord &rec = tables.arrayZ[i];
 	checksum = checksum + rec.checkSum;
@@ -218,7 +233,7 @@ struct TTCHeaderVersion1
   Tag		ttcTag;		/* TrueType Collection ID string: 'ttcf' */
   FixedVersion<>version;	/* Version of the TTC Header (1.0),
 				 * 0x00010000u */
-  LArrayOf<LOffsetTo<OpenTypeOffsetTable>>
+  Array32Of<Offset32To<OpenTypeOffsetTable>>
 		table;		/* Array of offsets to the OffsetTable for each font
 				 * from the beginning of the file */
   public:
@@ -295,7 +310,7 @@ struct ResourceRecord
   HBINT16	nameOffset;	/* Offset from beginning of resource name list
 				 * to resource name, -1 means there is none. */
   HBUINT8	attrs;		/* Resource attributes */
-  NNOffsetTo<LArrayOf<HBUINT8>, HBUINT24>
+  NNOffset24To<Array32Of<HBUINT8>>
 		offset;		/* Offset from beginning of data block to
 				 * data for this resource */
   HBUINT32	reserved;	/* Reserved for handle to resource */
@@ -330,7 +345,7 @@ struct ResourceTypeRecord
   protected:
   Tag		tag;		/* Resource type. */
   HBUINT16	resCountM1;	/* Number of resources minus 1. */
-  NNOffsetTo<UnsizedArrayOf<ResourceRecord>>
+  NNOffset16To<UnsizedArrayOf<ResourceRecord>>
 		resourcesZ;	/* Offset from beginning of resource type list
 				 * to reference item list for this type. */
   public:
@@ -386,7 +401,7 @@ struct ResourceMap
   HBUINT32	reserved1;	/* Reserved for handle to next resource map */
   HBUINT16	resreved2;	/* Reserved for file reference number */
   HBUINT16	attrs;		/* Resource fork attribute */
-  NNOffsetTo<ArrayOfM1<ResourceTypeRecord>>
+  NNOffset16To<ArrayOfM1<ResourceTypeRecord>>
 		typeList;	/* Offset from beginning of map to
 				 * resource type list */
   Offset16	nameList;	/* Offset from beginning of map to
@@ -418,10 +433,10 @@ struct ResourceForkHeader
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		data;		/* Offset from beginning of resource fork
 				 * to resource data */
-  LNNOffsetTo<ResourceMap >
+  NNOffset32To<ResourceMap >
 		map;		/* Offset from beginning of resource fork
 				 * to resource map */
   HBUINT32	dataLen;	/* Length of resource data */
@@ -477,14 +492,15 @@ struct OpenTypeFontFile
     }
   }
 
-  template <typename item_t>
+  template <typename Iterator,
+	    hb_requires ((hb_is_source_of<Iterator, hb_pair_t<hb_tag_t, hb_blob_t *>>::value))>
   bool serialize_single (hb_serialize_context_t *c,
 			 hb_tag_t sfnt_tag,
-			 hb_array_t<item_t> items)
+			 Iterator items)
   {
     TRACE_SERIALIZE (this);
     assert (sfnt_tag != TTCTag);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     return_trace (u.fontFace.serialize (c, sfnt_tag, items));
   }
 

+ 83 - 63
thirdparty/harfbuzz/src/hb-open-type.hh

@@ -196,6 +196,12 @@ DECLARE_NULL_NAMESPACE_BYTES (OT, Index);
 
 typedef Index NameID;
 
+struct VarIdx : HBUINT32 {
+  static constexpr unsigned NO_VARIATION = 0xFFFFFFFFu;
+  VarIdx& operator = (uint32_t i) { HBUINT32::operator= (i); return *this; }
+};
+DECLARE_NULL_NAMESPACE_BYTES (OT, VarIdx);
+
 /* Offset, Null offset = 0 */
 template <typename Type, bool has_null=true>
 struct Offset : Type
@@ -206,18 +212,12 @@ struct Offset : Type
 
   bool is_null () const { return has_null && 0 == *this; }
 
-  void *serialize (hb_serialize_context_t *c, const void *base)
-  {
-    void *t = c->start_embed<void> ();
-    c->check_assign (*this, (unsigned) ((char *) t - (char *) base));
-    return t;
-  }
-
   public:
   DEFINE_SIZE_STATIC (sizeof (Type));
 };
 
 typedef Offset<HBUINT16> Offset16;
+typedef Offset<HBUINT24> Offset24;
 typedef Offset<HBUINT32> Offset32;
 
 
@@ -287,7 +287,7 @@ struct _hb_has_null<Type, true>
   static       Type *get_crap () { return &Crap (Type); }
 };
 
-template <typename Type, typename OffsetType=HBUINT16, bool has_null=true>
+template <typename Type, typename OffsetType, bool has_null=true>
 struct OffsetTo : Offset<OffsetType, has_null>
 {
   HB_DELETE_COPY_ASSIGN (OffsetTo);
@@ -319,10 +319,6 @@ struct OffsetTo : Offset<OffsetType, has_null>
 	    hb_enable_if (hb_is_convertible (Base, void *))>
   friend Type& operator + (OffsetTo &offset, Base &&base) { return offset ((void *) base); }
 
-  Type& serialize (hb_serialize_context_t *c, const void *base)
-  {
-    return * (Type *) Offset<OffsetType>::serialize (c, base);
-  }
 
   template <typename ...Ts>
   bool serialize_subset (hb_subset_context_t *c, const OffsetTo& src,
@@ -346,6 +342,23 @@ struct OffsetTo : Offset<OffsetType, has_null>
     return ret;
   }
 
+
+  template <typename ...Ts>
+  bool serialize_serialize (hb_serialize_context_t *c, Ts&&... ds)
+  {
+    *this = 0;
+
+    Type* obj = c->push<Type> ();
+    bool ret = obj->serialize (c, hb_forward<Ts> (ds)...);
+
+    if (ret)
+      c->add_link (*this, c->pop_pack ());
+    else
+      c->pop_discard ();
+
+    return ret;
+  }
+
   /* TODO: Somehow merge this with previous function into a serialize_dispatch(). */
   /* Workaround clang bug: https://bugs.llvm.org/show_bug.cgi?id=23029
    * Can't compile: whence = hb_serialize_context_t::Head followed by Ts&&...
@@ -378,7 +391,7 @@ struct OffsetTo : Offset<OffsetType, has_null>
     TRACE_SANITIZE (this);
     if (unlikely (!c->check_struct (this))) return_trace (false);
     if (unlikely (this->is_null ())) return_trace (true);
-    if (unlikely (!c->check_range (base, *this))) return_trace (false);
+    if (unlikely ((const char *) base + (unsigned) *this < (const char *) base)) return_trace (false);
     return_trace (true);
   }
 
@@ -401,12 +414,14 @@ struct OffsetTo : Offset<OffsetType, has_null>
   DEFINE_SIZE_STATIC (sizeof (OffsetType));
 };
 /* Partial specializations. */
-template <typename Type, bool has_null=true>
-using LOffsetTo = OffsetTo<Type, HBUINT32, has_null>;
-template <typename Type, typename OffsetType=HBUINT16>
-using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
-template <typename Type>
-using LNNOffsetTo = LOffsetTo<Type, false>;
+template <typename Type, bool has_null=true> using Offset16To = OffsetTo<Type, HBUINT16, has_null>;
+template <typename Type, bool has_null=true> using Offset24To = OffsetTo<Type, HBUINT24, has_null>;
+template <typename Type, bool has_null=true> using Offset32To = OffsetTo<Type, HBUINT32, has_null>;
+
+template <typename Type, typename OffsetType> using NNOffsetTo = OffsetTo<Type, OffsetType, false>;
+template <typename Type> using NNOffset16To = Offset16To<Type, false>;
+template <typename Type> using NNOffset24To = Offset24To<Type, false>;
+template <typename Type> using NNOffset32To = Offset32To<Type, false>;
 
 
 /*
@@ -453,8 +468,10 @@ struct UnsizedArrayOf
   const Type &lsearch (unsigned int len, const T &x, const Type &not_found = Null (Type)) const
   { return *as_array (len).lsearch (x, &not_found); }
   template <typename T>
-  bool lfind (unsigned int len, const T &x, unsigned *pos = nullptr) const
-  { return as_array (len).lfind (x, pos); }
+  bool lfind (unsigned int len, const T &x, unsigned int *i = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
+  { return as_array (len).lfind (x, i, not_found, to_store); }
 
   void qsort (unsigned int len, unsigned int start = 0, unsigned int end = (unsigned int) -1)
   { as_array (len).qsort (start, end); }
@@ -462,7 +479,7 @@ struct UnsizedArrayOf
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend (*this, items_len))) return_trace (false);
+    if (unlikely (!c->extend (this, items_len))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
@@ -513,11 +530,11 @@ struct UnsizedArrayOf
 
 /* Unsized array of offset's */
 template <typename Type, typename OffsetType, bool has_null=true>
-using UnsizedOffsetArrayOf = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
+using UnsizedArray16OfOffsetTo = UnsizedArrayOf<OffsetTo<Type, OffsetType, has_null>>;
 
 /* Unsized array of offsets relative to the beginning of the array itself. */
 template <typename Type, typename OffsetType, bool has_null=true>
-struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
+struct UnsizedListOfOffset16To : UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
 {
   const Type& operator [] (int i_) const
   {
@@ -538,7 +555,7 @@ struct UnsizedOffsetListOf : UnsizedOffsetArrayOf<Type, OffsetType, has_null>
   bool sanitize (hb_sanitize_context_t *c, unsigned int count, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace ((UnsizedOffsetArrayOf<Type, OffsetType, has_null>
+    return_trace ((UnsizedArray16OfOffsetTo<Type, OffsetType, has_null>
 		   ::sanitize (c, count, this, hb_forward<Ts> (ds)...)));
   }
 };
@@ -562,14 +579,14 @@ struct SortedUnsizedArrayOf : UnsizedArrayOf<Type>
   { return *as_array (len).bsearch (x, &not_found); }
   template <typename T>
   bool bfind (unsigned int len, const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   { return as_array (len).bfind (x, i, not_found, to_store); }
 };
 
 
 /* An array with a number of elements. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
 struct ArrayOf
 {
   typedef Type item_t;
@@ -617,17 +634,32 @@ struct ArrayOf
   hb_array_t<Type> sub_array (unsigned int start_offset, unsigned int *count = nullptr /* IN/OUT */)
   { return as_array ().sub_array (start_offset, count); }
 
-  hb_success_t serialize (hb_serialize_context_t *c, unsigned items_len)
+  template <typename T>
+  Type &lsearch (const T &x, Type &not_found = Crap (Type))
+  { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
+  { return *as_array ().lsearch (x, &not_found); }
+  template <typename T>
+  bool lfind (const T &x, unsigned int *i = nullptr,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
+	      unsigned int to_store = (unsigned int) -1) const
+  { return as_array ().lfind (x, i, not_found, to_store); }
+
+  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
+  { as_array ().qsort (start, end); }
+
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, unsigned items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    c->check_assign (len, items_len);
-    if (unlikely (!c->extend (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    c->check_assign (len, items_len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
+    if (unlikely (!c->extend (this))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
 	    hb_requires (hb_is_source_of (Iterator, Type))>
-  hb_success_t serialize (hb_serialize_context_t *c, Iterator items)
+  HB_NODISCARD bool serialize (hb_serialize_context_t *c, Iterator items)
   {
     TRACE_SERIALIZE (this);
     unsigned count = items.len ();
@@ -643,7 +675,7 @@ struct ArrayOf
   {
     TRACE_SERIALIZE (this);
     len++;
-    if (unlikely (!len || !c->extend (*this)))
+    if (unlikely (!len || !c->extend (this)))
     {
       len--;
       return_trace (nullptr);
@@ -656,7 +688,7 @@ struct ArrayOf
     TRACE_SERIALIZE (this);
     auto *out = c->start_embed (this);
     if (unlikely (!c->extend_min (out))) return_trace (nullptr);
-    c->check_assign (out->len, len);
+    c->check_assign (out->len, len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
     if (unlikely (!as_array ().copy (c))) return_trace (nullptr);
     return_trace (out);
   }
@@ -674,19 +706,6 @@ struct ArrayOf
     return_trace (true);
   }
 
-  template <typename T>
-  Type &lsearch (const T &x, Type &not_found = Crap (Type))
-  { return *as_array ().lsearch (x, &not_found); }
-  template <typename T>
-  const Type &lsearch (const T &x, const Type &not_found = Null (Type)) const
-  { return *as_array ().lsearch (x, &not_found); }
-  template <typename T>
-  bool lfind (const T &x, unsigned *pos = nullptr) const
-  { return as_array ().lfind (x, pos); }
-
-  void qsort (unsigned int start = 0, unsigned int end = (unsigned int) -1)
-  { as_array ().qsort (start, end); }
-
   bool sanitize_shallow (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -699,21 +718,18 @@ struct ArrayOf
   public:
   DEFINE_SIZE_ARRAY (sizeof (LenType), arrayZ);
 };
-template <typename Type>
-using LArrayOf = ArrayOf<Type, HBUINT32>;
+template <typename Type> using Array16Of = ArrayOf<Type, HBUINT16>;
+template <typename Type> using Array32Of = ArrayOf<Type, HBUINT32>;
 using PString = ArrayOf<HBUINT8, HBUINT8>;
 
 /* Array of Offset's */
-template <typename Type>
-using OffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT16>>;
-template <typename Type>
-using LOffsetArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>>;
-template <typename Type>
-using LOffsetLArrayOf = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
+template <typename Type> using Array16OfOffset16To = ArrayOf<OffsetTo<Type, HBUINT16>, HBUINT16>;
+template <typename Type> using Array16OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT16>;
+template <typename Type> using Array32OfOffset32To = ArrayOf<OffsetTo<Type, HBUINT32>, HBUINT32>;
 
 /* Array of offsets relative to the beginning of the array itself. */
 template <typename Type>
-struct OffsetListOf : OffsetArrayOf<Type>
+struct List16OfOffset16To : Array16OfOffset16To<Type>
 {
   const Type& operator [] (int i_) const
   {
@@ -731,7 +747,7 @@ struct OffsetListOf : OffsetArrayOf<Type>
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    struct OffsetListOf<Type> *out = c->serializer->embed (*this);
+    struct List16OfOffset16To<Type> *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
     unsigned int count = this->len;
     for (unsigned int i = 0; i < count; i++)
@@ -743,7 +759,7 @@ struct OffsetListOf : OffsetArrayOf<Type>
   bool sanitize (hb_sanitize_context_t *c, Ts&&... ds) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetArrayOf<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
+    return_trace (Array16OfOffset16To<Type>::sanitize (c, this, hb_forward<Ts> (ds)...));
   }
 };
 
@@ -786,9 +802,9 @@ struct HeadlessArrayOf
   bool serialize (hb_serialize_context_t *c, unsigned int items_len)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    c->check_assign (lenP1, items_len + 1);
-    if (unlikely (!c->extend (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    c->check_assign (lenP1, items_len + 1, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW);
+    if (unlikely (!c->extend (this))) return_trace (false);
     return_trace (true);
   }
   template <typename Iterator,
@@ -859,6 +875,7 @@ struct ArrayOfM1
   {
     TRACE_SANITIZE (this);
     if (unlikely (!sanitize_shallow (c))) return_trace (false);
+    if (!sizeof... (Ts) && hb_is_trivially_copyable (Type)) return_trace (true);
     unsigned int count = lenM1 + 1;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!c->dispatch (arrayZ[i], hb_forward<Ts> (ds)...)))
@@ -882,7 +899,7 @@ struct ArrayOfM1
 };
 
 /* An array with sorted elements.  Supports binary searching. */
-template <typename Type, typename LenType=HBUINT16>
+template <typename Type, typename LenType>
 struct SortedArrayOf : ArrayOf<Type, LenType>
 {
   hb_sorted_array_t<      Type> as_array ()       { return hb_sorted_array (this->arrayZ, this->len); }
@@ -928,11 +945,14 @@ struct SortedArrayOf : ArrayOf<Type, LenType>
   { return *as_array ().bsearch (x, &not_found); }
   template <typename T>
   bool bfind (const T &x, unsigned int *i = nullptr,
-	      hb_bfind_not_found_t not_found = HB_BFIND_NOT_FOUND_DONT_STORE,
+	      hb_not_found_t not_found = HB_NOT_FOUND_DONT_STORE,
 	      unsigned int to_store = (unsigned int) -1) const
   { return as_array ().bfind (x, i, not_found, to_store); }
 };
 
+template <typename Type> using SortedArray16Of = SortedArrayOf<Type, HBUINT16>;
+template <typename Type> using SortedArray32Of = SortedArrayOf<Type, HBUINT32>;
+
 /*
  * Binary-search arrays
  */

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

@@ -126,7 +126,7 @@ struct CFFIndex
     else
     {
       /* serialize CFFIndex header */
-      if (unlikely (!c->extend_min (*this))) return_trace (false);
+      if (unlikely (!c->extend_min (this))) return_trace (false);
       this->count = byteArray.length;
       this->offSize = offSize_;
       if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (byteArray.length + 1))))
@@ -214,7 +214,7 @@ struct CFFIndex
     unsigned off_size = calcOffSize (total);
 
     /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     this->count = it.len ();
     this->offSize = off_size;
     if (unlikely (!c->allocate_size<HBUINT8> (off_size * (it.len () + 1))))
@@ -335,7 +335,7 @@ struct CFFIndexOf : CFFIndex<COUNT>
   {
     TRACE_SERIALIZE (this);
     /* serialize CFFIndex header */
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     this->count = dataArrayLen;
     this->offSize = offSize_;
     if (unlikely (!c->allocate_size<HBUINT8> (offSize_ * (dataArrayLen + 1))))

+ 4 - 3
thirdparty/harfbuzz/src/hb-ot-cff1-table.hh

@@ -187,7 +187,7 @@ struct Encoding
 		  const hb_vector_t<code_pair_t>& supp_codes)
   {
     TRACE_SERIALIZE (this);
-    Encoding *dest = c->extend_min (*this);
+    Encoding *dest = c->extend_min (this);
     if (unlikely (!dest)) return_trace (false);
     dest->format = format | ((supp_codes.length > 0) ? 0x80 : 0);
     switch (format) {
@@ -457,7 +457,7 @@ struct Charset
 		  const hb_vector_t<code_pair_t>& sid_ranges)
   {
     TRACE_SERIALIZE (this);
-    Charset *dest = c->extend_min (*this);
+    Charset *dest = c->extend_min (this);
     if (unlikely (!dest)) return_trace (false);
     dest->format = format;
     switch (format)
@@ -713,6 +713,7 @@ struct cff1_top_dict_opset_t : top_dict_opset_t<cff1_top_dict_val_t>
       case OpCode_Notice:
       case OpCode_Copyright:
       case OpCode_FullName:
+      case OpCode_FontName:
       case OpCode_FamilyName:
       case OpCode_Weight:
       case OpCode_PostScript:
@@ -1390,7 +1391,7 @@ struct cff1
 
   public:
   FixedVersion<HBUINT8> version;	  /* Version of CFF table. set to 0x0100u */
-  OffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
+  NNOffsetTo<CFF1NameIndex, HBUINT8> nameIndex; /* headerSize = Offset to Name INDEX. */
   HBUINT8	       offSize;	  /* offset size (unused?) */
 
   public:

+ 176 - 80
thirdparty/harfbuzz/src/hb-ot-cmap-table.hh

@@ -49,6 +49,12 @@ struct CmapSubtableFormat0
     *glyph = gid;
     return true;
   }
+
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   void collect_unicodes (hb_set_t *out) const
   {
     for (unsigned int i = 0; i < 256; i++)
@@ -212,29 +218,24 @@ struct CmapSubtableFormat4
 					 HBINT16 *idDelta,
 					 unsigned segcount)
   {
+    hb_hashmap_t<hb_codepoint_t, hb_codepoint_t> cp_to_gid;
+    + it | hb_sink (cp_to_gid);
+
     HBUINT16 *idRangeOffset = c->allocate_size<HBUINT16> (HBUINT16::static_size * segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return nullptr;
     if (unlikely ((char *)idRangeOffset - (char *)idDelta != (int) segcount * (int) HBINT16::static_size)) return nullptr;
 
-    + hb_range (segcount)
-    | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; })
-    | hb_apply ([&] (const unsigned i)
-		{
-		  idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
-
-		  + it
-		  | hb_filter ([&] (const hb_item_type<Iterator> _) { return _.first >= startCode[i] && _.first <= endCode[i]; })
-		  | hb_apply ([&] (const hb_item_type<Iterator> _)
-			      {
-				HBUINT16 glyID;
-				glyID = _.second;
-				c->copy<HBUINT16> (glyID);
-			      })
-		  ;
-
-
-		})
-    ;
+    for (unsigned i : + hb_range (segcount)
+             | hb_filter ([&] (const unsigned _) { return idDelta[_] == 0; }))
+    {
+      idRangeOffset[i] = 2 * (c->start_embed<HBUINT16> () - idRangeOffset - i);
+      for (hb_codepoint_t cp = startCode[i]; cp <= endCode[i]; cp++)
+      {
+        HBUINT16 gid;
+        gid = cp_to_gid[cp];
+        c->copy<HBUINT16> (gid);
+      }
+    }
 
     return idRangeOffset;
   }
@@ -253,7 +254,7 @@ struct CmapSubtableFormat4
     if (format4_iter.len () == 0) return;
 
     unsigned table_initpos = c->length ();
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
     this->format = 4;
 
     //serialize endCode[]
@@ -276,7 +277,17 @@ struct CmapSubtableFormat4
     HBUINT16 *idRangeOffset = serialize_rangeoffset_glyid (c, format4_iter, endCode, startCode, idDelta, segcount);
     if (unlikely (!c->check_success (idRangeOffset))) return;
 
-    if (unlikely (!c->check_assign(this->length, c->length () - table_initpos))) return;
+    this->length = c->length () - table_initpos;
+    if ((long long) this->length != (long long) c->length () - table_initpos)
+    {
+      // Length overflowed. Discard the current object before setting the error condition, otherwise
+      // discard is a noop which prevents the higher level code from reverting the serializer to the
+      // pre-error state in cmap4 overflow handling code.
+      c->pop_discard ();
+      c->err (HB_SERIALIZE_ERROR_INT_OVERFLOW);
+      return;
+    }
+
     this->segCountX2 = segcount * 2;
     this->entrySelector = hb_max (1u, hb_bit_storage (segcount)) - 1;
     this->searchRange = 2 * (1u << this->entrySelector);
@@ -285,6 +296,11 @@ struct CmapSubtableFormat4
 		       : 0;
   }
 
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   struct accelerator_t
   {
     accelerator_t () {}
@@ -547,6 +563,12 @@ struct CmapSubtableTrimmed
     *glyph = gid;
     return true;
   }
+
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   void collect_unicodes (hb_set_t *out) const
   {
     hb_codepoint_t start = startCharCode;
@@ -606,6 +628,11 @@ struct CmapSubtableLongSegmented
     return true;
   }
 
+  unsigned get_language () const
+  {
+    return language;
+  }
+
   void collect_unicodes (hb_set_t *out, unsigned int num_glyphs) const
   {
     for (unsigned int i = 0; i < this->groups.len; i++)
@@ -670,7 +697,7 @@ struct CmapSubtableLongSegmented
   HBUINT16	reserved;	/* Reserved; set to 0. */
   HBUINT32	length;		/* Byte length of this subtable. */
   HBUINT32	language;	/* Ignore. */
-  SortedArrayOf<CmapSubtableLongGroup, HBUINT32>
+  SortedArray32Of<CmapSubtableLongGroup>
 		groups;		/* Groupings. */
   public:
   DEFINE_SIZE_ARRAY (16, groups);
@@ -691,7 +718,7 @@ struct CmapSubtableFormat12 : CmapSubtableLongSegmented<CmapSubtableFormat12>
   {
     if (it.len () == 0) return;
     unsigned table_initpos = c->length ();
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
 
     hb_codepoint_t startCharCode = 0xFFFF, endCharCode = 0xFFFF;
     hb_codepoint_t glyphID = 0;
@@ -784,7 +811,7 @@ struct UnicodeValueRange
   DEFINE_SIZE_STATIC (4);
 };
 
-struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
+struct DefaultUVS : SortedArray32Of<UnicodeValueRange>
 {
   void collect_unicodes (hb_set_t *out) const
   {
@@ -850,7 +877,9 @@ struct DefaultUVS : SortedArrayOf<UnicodeValueRange, HBUINT32>
     }
     else
     {
-      if (unlikely (!c->check_assign (out->len, (c->length () - init_len) / UnicodeValueRange::static_size))) return nullptr;
+      if (unlikely (!c->check_assign (out->len,
+                                      (c->length () - init_len) / UnicodeValueRange::static_size,
+                                      HB_SERIALIZE_ERROR_INT_OVERFLOW))) return nullptr;
       return out;
     }
   }
@@ -876,23 +905,21 @@ struct UVSMapping
   DEFINE_SIZE_STATIC (5);
 };
 
-struct NonDefaultUVS : SortedArrayOf<UVSMapping, HBUINT32>
+struct NonDefaultUVS : SortedArray32Of<UVSMapping>
 {
   void collect_unicodes (hb_set_t *out) const
   {
-    unsigned int count = len;
-    for (unsigned int i = 0; i < count; i++)
-      out->add (arrayZ[i].unicodeValue);
+    for (const auto& a : as_array ())
+      out->add (a.unicodeValue);
   }
 
   void collect_mapping (hb_set_t *unicodes, /* OUT */
 			hb_map_t *mapping /* OUT */) const
   {
-    unsigned count = len;
-    for (unsigned i = 0; i < count; i++)
+    for (const auto& a : as_array ())
     {
-      hb_codepoint_t unicode = arrayZ[i].unicodeValue;
-      hb_codepoint_t glyphid = arrayZ[i].glyphID;
+      hb_codepoint_t unicode = a.unicodeValue;
+      hb_codepoint_t glyphid = a.glyphID;
       unicodes->add (unicode);
       mapping->set (unicode, glyphid);
     }
@@ -1041,9 +1068,9 @@ struct VariationSelectorRecord
   }
 
   HBUINT24	varSelector;	/* Variation selector. */
-  LOffsetTo<DefaultUVS>
+  Offset32To<DefaultUVS>
 		defaultUVS;	/* Offset to Default UVS Table.  May be 0. */
-  LOffsetTo<NonDefaultUVS>
+  Offset32To<NonDefaultUVS>
 		nonDefaultUVS;	/* Offset to Non-Default UVS Table.  May be 0. */
   public:
   DEFINE_SIZE_STATIC (11);
@@ -1058,9 +1085,8 @@ struct CmapSubtableFormat14
 
   void collect_variation_selectors (hb_set_t *out) const
   {
-    unsigned int count = record.len;
-    for (unsigned int i = 0; i < count; i++)
-      out->add (record.arrayZ[i].varSelector);
+    for (const auto& a : record.as_array ())
+      out->add (a.varSelector);
   }
   void collect_variation_unicodes (hb_codepoint_t variation_selector,
 				   hb_set_t *out) const
@@ -1076,7 +1102,7 @@ struct CmapSubtableFormat14
     unsigned table_initpos = c->length ();
     const char* init_tail = c->tail;
 
-    if (unlikely (!c->extend_min (*this))) return;
+    if (unlikely (!c->extend_min (this))) return;
     this->format = 14;
 
     auto src_tbl = reinterpret_cast<const CmapSubtableFormat14*> (base);
@@ -1112,10 +1138,12 @@ struct CmapSubtableFormat14
       return;
 
     int tail_len = init_tail - c->tail;
-    c->check_assign (this->length, c->length () - table_initpos + tail_len);
+    c->check_assign (this->length, c->length () - table_initpos + tail_len,
+                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
     c->check_assign (this->record.len,
 		     (c->length () - table_initpos - CmapSubtableFormat14::min_size) /
-		     VariationSelectorRecord::static_size);
+		     VariationSelectorRecord::static_size,
+                     HB_SERIALIZE_ERROR_INT_OVERFLOW);
 
     /* Correct the incorrect write order by reversing the order of the variation
        records array. */
@@ -1180,7 +1208,7 @@ struct CmapSubtableFormat14
   protected:
   HBUINT16	format;		/* Format number is set to 14. */
   HBUINT32	length;		/* Byte length of this subtable. */
-  SortedArrayOf<VariationSelectorRecord, HBUINT32>
+  SortedArray32Of<VariationSelectorRecord>
 		record;		/* Variation selector records; sorted
 				 * in increasing order of `varSelector'. */
   public:
@@ -1235,6 +1263,20 @@ struct CmapSubtable
     }
   }
 
+  unsigned get_language () const
+  {
+    switch (u.format) {
+    case  0: return u.format0 .get_language ();
+    case  4: return u.format4 .get_language ();
+    case  6: return u.format6 .get_language ();
+    case 10: return u.format10.get_language ();
+    case 12: return u.format12.get_language ();
+    case 13: return u.format13.get_language ();
+    case 14:
+    default: return 0;
+    }
+  }
+
   template<typename Iterator,
 	   hb_requires (hb_is_iterator (Iterator))>
   void serialize (hb_serialize_context_t *c,
@@ -1338,7 +1380,7 @@ struct EncodingRecord
 
   HBUINT16	platformID;	/* Platform ID. */
   HBUINT16	encodingID;	/* Platform-specific encoding ID. */
-  LOffsetTo<CmapSubtable>
+  Offset32To<CmapSubtable>
 		subtable;	/* Byte offset from beginning of table to the subtable for this encoding. */
   public:
   DEFINE_SIZE_STATIC (8);
@@ -1350,58 +1392,112 @@ struct cmap
 
   template<typename Iterator, typename EncodingRecIter,
 	   hb_requires (hb_is_iterator (EncodingRecIter))>
-  void serialize (hb_serialize_context_t *c,
+  bool serialize (hb_serialize_context_t *c,
 		  Iterator it,
 		  EncodingRecIter encodingrec_iter,
 		  const void *base,
-		  const hb_subset_plan_t *plan)
+		  const hb_subset_plan_t *plan,
+                  bool drop_format_4 = false)
   {
-    if (unlikely (!c->extend_min ((*this))))  return;
+    if (unlikely (!c->extend_min ((*this))))  return false;
     this->version = 0;
 
     unsigned format4objidx = 0, format12objidx = 0, format14objidx = 0;
+    auto snap = c->snapshot ();
 
     for (const EncodingRecord& _ : encodingrec_iter)
     {
+      if (c->in_error ())
+        return false;
+
       unsigned format = (base+_.subtable).u.format;
-      if (!plan->glyphs_requested->is_empty ())
+      if (format != 4 && format != 12 && format != 14) continue;
+
+      hb_set_t unicodes_set;
+      (base+_.subtable).collect_unicodes (&unicodes_set);
+
+      if (!drop_format_4 && format == 4)
       {
-	hb_set_t unicodes_set;
-	hb_map_t cp_glyphid_map;
-	(base+_.subtable).collect_mapping (&unicodes_set, &cp_glyphid_map);
-
-	auto table_iter =
-	+ hb_zip (unicodes_set.iter(), unicodes_set.iter() | hb_map(cp_glyphid_map))
-	| hb_filter (plan->_glyphset, hb_second)
-	| hb_filter ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p)
-		     {
-		       return plan->unicodes->has (p.first) ||
-			      plan->glyphs_requested->has (p.second);
-		     })
-	| hb_map ([plan] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t>& p_org)
-		  {
-		    return hb_pair_t<hb_codepoint_t, hb_codepoint_t> (p_org.first, plan->glyph_map->get(p_org.second));
-		  })
-	;
-
-	if (format == 4) c->copy (_, table_iter, 4u, base, plan, &format4objidx);
-	else if (format == 12) c->copy (_, table_iter, 12u, base, plan, &format12objidx);
-	else if (format == 14) c->copy (_, table_iter, 14u, base, plan, &format14objidx);
+        c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
+        if (c->in_error () && c->only_overflow ())
+        {
+          // cmap4 overflowed, reset and retry serialization without format 4 subtables.
+          c->revert (snap);
+          return serialize (c, it,
+                            encodingrec_iter,
+                            base,
+                            plan,
+                            true);
+        }
       }
-      /* when --gids option is not used, we iterate input unicodes instead of
-       * all codepoints in each subtable, which is more efficient */
-      else
+
+      else if (format == 12)
       {
-	hb_set_t unicodes_set;
-	(base+_.subtable).collect_unicodes (&unicodes_set);
+        if (_can_drop (_, unicodes_set, base, + it | hb_map (hb_first), encodingrec_iter)) continue;
+        c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
+      }
+      else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
+    }
+    c->check_assign(this->encodingRecord.len,
+                    (c->length () - cmap::min_size)/EncodingRecord::static_size,
+                    HB_SERIALIZE_ERROR_INT_OVERFLOW);
 
-	if (format == 4) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 4u, base, plan, &format4objidx);
-	else if (format == 12) c->copy (_, + it | hb_filter (unicodes_set, hb_first), 12u, base, plan, &format12objidx);
-	else if (format == 14) c->copy (_, it, 14u, base, plan, &format14objidx);
+    // Fail if format 4 was dropped and there is no cmap12.
+    return !drop_format_4 || format12objidx;
+  }
+
+  template<typename Iterator, typename EncodingRecordIterator,
+      hb_requires (hb_is_iterator (Iterator)),
+      hb_requires (hb_is_iterator (EncodingRecordIterator))>
+  bool _can_drop (const EncodingRecord& cmap12,
+                  const hb_set_t& cmap12_unicodes,
+                  const void* base,
+                  Iterator subset_unicodes,
+                  EncodingRecordIterator encoding_records)
+  {
+    for (auto cp : + subset_unicodes | hb_filter (cmap12_unicodes))
+    {
+      if (cp >= 0x10000) return false;
+    }
+
+    unsigned target_platform;
+    unsigned target_encoding;
+    unsigned target_language = (base+cmap12.subtable).get_language ();
+
+    if (cmap12.platformID == 0 && cmap12.encodingID == 4)
+    {
+      target_platform = 0;
+      target_encoding = 3;
+    } else if (cmap12.platformID == 3 && cmap12.encodingID == 10) {
+      target_platform = 3;
+      target_encoding = 1;
+    } else {
+      return false;
+    }
+
+    for (const auto& _ : encoding_records)
+    {
+      if (_.platformID != target_platform
+          || _.encodingID != target_encoding
+          || (base+_.subtable).get_language() != target_language)
+        continue;
+
+      hb_set_t sibling_unicodes;
+      (base+_.subtable).collect_unicodes (&sibling_unicodes);
+
+      auto cmap12 = + subset_unicodes | hb_filter (cmap12_unicodes);
+      auto sibling = + subset_unicodes | hb_filter (sibling_unicodes);
+      for (; cmap12 && sibling; cmap12++, sibling++)
+      {
+        unsigned a = *cmap12;
+        unsigned b = *sibling;
+        if (a != b) return false;
       }
+
+      return !cmap12 && !sibling;
     }
 
-    c->check_assign(this->encodingRecord.len, (c->length () - cmap::min_size)/EncodingRecord::static_size);
+    return false;
   }
 
   void closure_glyphs (const hb_set_t      *unicodes,
@@ -1468,8 +1564,8 @@ struct cmap
     | hb_filter ([&] (const hb_pair_t<hb_codepoint_t, hb_codepoint_t> _)
 		 { return (_.second != HB_MAP_VALUE_INVALID); })
     ;
-    cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan);
-    return_trace (true);
+
+    return_trace (cmap_prime->serialize (c->serializer, it, encodingrec_iter, this, c->plan));
   }
 
   const CmapSubtable *find_best_subtable (bool *symbol = nullptr) const
@@ -1697,7 +1793,7 @@ struct cmap
 
   protected:
   HBUINT16	version;	/* Table version number (0). */
-  SortedArrayOf<EncodingRecord>
+  SortedArray16Of<EncodingRecord>
 		encodingRecord;	/* Encoding tables. */
   public:
   DEFINE_SIZE_ARRAY (4, encodingRecord);

+ 7 - 7
thirdparty/harfbuzz/src/hb-ot-color-cbdt-table.hh

@@ -510,7 +510,7 @@ struct IndexSubtableRecord
 
   HBGlyphID			firstGlyphIndex;
   HBGlyphID			lastGlyphIndex;
-  LOffsetTo<IndexSubtable>	offsetToSubtable;
+  Offset32To<IndexSubtable>	offsetToSubtable;
   public:
   DEFINE_SIZE_STATIC (8);
 };
@@ -672,7 +672,7 @@ struct BitmapSizeTable
   }
 
   protected:
-  LNNOffsetTo<IndexSubtableArray>
+  NNOffset32To<IndexSubtableArray>
 			indexSubtableArrayOffset;
   HBUINT32		indexTablesSize;
   HBUINT32		numberOfIndexSubtables;
@@ -697,7 +697,7 @@ struct BitmapSizeTable
 struct GlyphBitmapDataFormat17
 {
   SmallGlyphMetrics	glyphMetrics;
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
   DEFINE_SIZE_ARRAY (9, data);
 };
@@ -705,14 +705,14 @@ struct GlyphBitmapDataFormat17
 struct GlyphBitmapDataFormat18
 {
   BigGlyphMetrics	glyphMetrics;
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
   DEFINE_SIZE_ARRAY (12, data);
 };
 
 struct GlyphBitmapDataFormat19
 {
-  LArrayOf<HBUINT8>	data;
+  Array32Of<HBUINT8>	data;
   public:
   DEFINE_SIZE_ARRAY (4, data);
 };
@@ -738,7 +738,7 @@ struct CBLC
 						 cbdt_prime->length,
 						 HB_MEMORY_MODE_WRITABLE,
 						 cbdt_prime->arrayZ,
-						 free);
+						 hb_free);
     cbdt_prime->init ();  // Leak arrayZ to the blob.
     bool ret = c->plan->add_table (HB_OT_TAG_CBDT, cbdt_prime_blob);
     hb_blob_destroy (cbdt_prime_blob);
@@ -798,7 +798,7 @@ struct CBLC
 
   protected:
   FixedVersion<>		version;
-  LArrayOf<BitmapSizeTable>	sizeTables;
+  Array32Of<BitmapSizeTable>	sizeTables;
   public:
   DEFINE_SIZE_ARRAY (8, sizeTables);
 };

+ 878 - 12
thirdparty/harfbuzz/src/hb-ot-color-colr-table.hh

@@ -29,6 +29,7 @@
 #define HB_OT_COLOR_COLR_TABLE_HH
 
 #include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
 
 /*
  * COLR -- Color
@@ -36,9 +37,78 @@
  */
 #define HB_OT_TAG_COLR HB_TAG('C','O','L','R')
 
+#ifndef COLRV1_MAX_NESTING_LEVEL
+#define COLRV1_MAX_NESTING_LEVEL	100
+#endif
+
+#ifndef COLRV1_ENABLE_SUBSETTING
+#define COLRV1_ENABLE_SUBSETTING 0
+#endif
 
 namespace OT {
 
+struct COLR;
+struct hb_colrv1_closure_context_t :
+       hb_dispatch_context_t<hb_colrv1_closure_context_t>
+{
+  template <typename T>
+  return_t dispatch (const T &obj)
+  {
+    if (unlikely (nesting_level_left == 0))
+      return hb_empty_t ();
+
+    if (paint_visited (&obj))
+      return hb_empty_t ();
+
+    nesting_level_left--;
+    obj.closurev1 (this);
+    nesting_level_left++;
+    return hb_empty_t ();
+  }
+  static return_t default_return_value () { return hb_empty_t (); }
+
+  bool paint_visited (const void *paint)
+  {
+    hb_codepoint_t delta = (hb_codepoint_t) ((uintptr_t) paint - (uintptr_t) base);
+     if (visited_paint.has (delta))
+      return true;
+
+    visited_paint.add (delta);
+    return false;
+  }
+
+  const COLR* get_colr_table () const
+  { return reinterpret_cast<const COLR *> (base); }
+
+  void add_glyph (unsigned glyph_id)
+  { glyphs->add (glyph_id); }
+
+  void add_layer_indices (unsigned first_layer_index, unsigned num_of_layers)
+  { layer_indices->add_range (first_layer_index, first_layer_index + num_of_layers - 1); }
+
+  void add_palette_index (unsigned palette_index)
+  { palette_indices->add (palette_index); }
+
+  public:
+  const void *base;
+  hb_set_t visited_paint;
+  hb_set_t *glyphs;
+  hb_set_t *layer_indices;
+  hb_set_t *palette_indices;
+  unsigned nesting_level_left;
+
+  hb_colrv1_closure_context_t (const void *base_,
+                               hb_set_t *glyphs_,
+                               hb_set_t *layer_indices_,
+                               hb_set_t *palette_indices_,
+                               unsigned nesting_level_left_ = COLRV1_MAX_NESTING_LEVEL) :
+                          base (base_),
+                          glyphs (glyphs_),
+                          layer_indices (layer_indices_),
+                          palette_indices (palette_indices_),
+                          nesting_level_left (nesting_level_left_)
+  {}
+};
 
 struct LayerRecord
 {
@@ -90,6 +160,707 @@ struct BaseGlyphRecord
   DEFINE_SIZE_STATIC (6);
 };
 
+template <typename T>
+struct Variable
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  protected:
+  T      value;
+  VarIdx varIdx;
+  public:
+  DEFINE_SIZE_STATIC (4 + T::static_size);
+};
+
+template <typename T>
+struct NoVariable
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  T      value;
+  public:
+  DEFINE_SIZE_STATIC (T::static_size);
+};
+
+// Color structures
+
+template <template<typename> class Var>
+struct ColorIndex
+{
+  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 (c->serializer->check_assign (out->paletteIndex, c->plan->colr_palettes->get (paletteIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT16	paletteIndex;
+  Var<F2DOT14>	alpha;
+  public:
+  DEFINE_SIZE_STATIC (2 + Var<F2DOT14>::static_size);
+};
+
+template <template<typename> class Var>
+struct ColorStop
+{
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    if (unlikely (!c->serializer->embed (stopOffset))) return_trace (false);
+    return_trace (color.subset (c));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  Var<F2DOT14>		stopOffset;
+  ColorIndex<Var>		color;
+  public:
+  DEFINE_SIZE_STATIC (Var<F2DOT14>::static_size + ColorIndex<Var>::static_size);
+};
+
+struct Extend : HBUINT8
+{
+  enum {
+    EXTEND_PAD     = 0,
+    EXTEND_REPEAT  = 1,
+    EXTEND_REFLECT = 2,
+  };
+  public:
+  DEFINE_SIZE_STATIC (1);
+};
+
+template <template<typename> class Var>
+struct ColorLine
+{
+  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 (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    if (!c->serializer->check_assign (out->extend, extend, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+    if (!c->serializer->check_assign (out->stops.len, stops.len, HB_SERIALIZE_ERROR_ARRAY_OVERFLOW)) return_trace (false);
+
+    for (const auto& stop : stops.iter ())
+    {
+      if (!stop.subset (c)) return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  stops.sanitize (c));
+  }
+
+  Extend			extend;
+  Array16Of<ColorStop<Var>>	stops;
+  public:
+  DEFINE_SIZE_ARRAY_SIZED (3, stops);
+};
+
+// Composition modes
+
+// Compositing modes are taken from https://www.w3.org/TR/compositing-1/
+// NOTE: a brief audit of major implementations suggests most support most
+// or all of the specified modes.
+struct CompositeMode : HBUINT8
+{
+  enum {
+    // Porter-Duff modes
+    // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators
+    COMPOSITE_CLEAR          =  0,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_clear
+    COMPOSITE_SRC            =  1,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_src
+    COMPOSITE_DEST           =  2,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dst
+    COMPOSITE_SRC_OVER       =  3,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcover
+    COMPOSITE_DEST_OVER      =  4,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstover
+    COMPOSITE_SRC_IN         =  5,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcin
+    COMPOSITE_DEST_IN        =  6,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstin
+    COMPOSITE_SRC_OUT        =  7,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcout
+    COMPOSITE_DEST_OUT       =  8,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstout
+    COMPOSITE_SRC_ATOP       =  9,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_srcatop
+    COMPOSITE_DEST_ATOP      = 10,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_dstatop
+    COMPOSITE_XOR            = 11,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_xor
+    COMPOSITE_PLUS           = 12,  // https://www.w3.org/TR/compositing-1/#porterduffcompositingoperators_plus
+
+    // Blend modes
+    // https://www.w3.org/TR/compositing-1/#blending
+    COMPOSITE_SCREEN         = 13,  // https://www.w3.org/TR/compositing-1/#blendingscreen
+    COMPOSITE_OVERLAY        = 14,  // https://www.w3.org/TR/compositing-1/#blendingoverlay
+    COMPOSITE_DARKEN         = 15,  // https://www.w3.org/TR/compositing-1/#blendingdarken
+    COMPOSITE_LIGHTEN        = 16,  // https://www.w3.org/TR/compositing-1/#blendinglighten
+    COMPOSITE_COLOR_DODGE    = 17,  // https://www.w3.org/TR/compositing-1/#blendingcolordodge
+    COMPOSITE_COLOR_BURN     = 18,  // https://www.w3.org/TR/compositing-1/#blendingcolorburn
+    COMPOSITE_HARD_LIGHT     = 19,  // https://www.w3.org/TR/compositing-1/#blendinghardlight
+    COMPOSITE_SOFT_LIGHT     = 20,  // https://www.w3.org/TR/compositing-1/#blendingsoftlight
+    COMPOSITE_DIFFERENCE     = 21,  // https://www.w3.org/TR/compositing-1/#blendingdifference
+    COMPOSITE_EXCLUSION      = 22,  // https://www.w3.org/TR/compositing-1/#blendingexclusion
+    COMPOSITE_MULTIPLY       = 23,  // https://www.w3.org/TR/compositing-1/#blendingmultiply
+
+    // Modes that, uniquely, do not operate on components
+    // https://www.w3.org/TR/compositing-1/#blendingnonseparable
+    COMPOSITE_HSL_HUE        = 24,  // https://www.w3.org/TR/compositing-1/#blendinghue
+    COMPOSITE_HSL_SATURATION = 25,  // https://www.w3.org/TR/compositing-1/#blendingsaturation
+    COMPOSITE_HSL_COLOR      = 26,  // https://www.w3.org/TR/compositing-1/#blendingcolor
+    COMPOSITE_HSL_LUMINOSITY = 27,  // https://www.w3.org/TR/compositing-1/#blendingluminosity
+  };
+  public:
+  DEFINE_SIZE_STATIC (1);
+};
+
+template <template<typename> class Var>
+struct Affine2x3
+{
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  Var<HBFixed> xx;
+  Var<HBFixed> yx;
+  Var<HBFixed> xy;
+  Var<HBFixed> yy;
+  Var<HBFixed> dx;
+  Var<HBFixed> dy;
+  public:
+  DEFINE_SIZE_STATIC (6 * Var<HBFixed>::static_size);
+};
+
+struct PaintColrLayers
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (c->serializer->check_assign (out->firstLayerIndex, c->plan->colrv1_layers->get (firstLayerIndex),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8	format; /* format = 1 */
+  HBUINT8	numLayers;
+  HBUINT32	firstLayerIndex;  /* index into COLRv1::layersV1 */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+template <template<typename> class Var>
+struct PaintSolid
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  { c->add_palette_index (color.paletteIndex); }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    if (unlikely (!c->serializer->embed (format))) return_trace (false);
+    return_trace (color.subset (c));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8		format; /* format = 2(noVar) or 3(Var)*/
+  ColorIndex<Var>	color;
+  public:
+  DEFINE_SIZE_STATIC (1 + ColorIndex<Var>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintLinearGradient
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  {
+    for (const auto &stop : (this+colorLine).stops.iter ())
+      c->add_palette_index (stop.color.paletteIndex);
+  }
+
+  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 (out->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 4(noVar) or 5 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintLinearGradient
+                                            * table) to ColorLine subtable. */
+  Var<FWORD>			x0;
+  Var<FWORD>			y0;
+  Var<FWORD>			x1;
+  Var<FWORD>			y1;
+  Var<FWORD>			x2;
+  Var<FWORD>			y2;
+  public:
+  DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintRadialGradient
+{
+  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 (out->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  {
+    for (const auto &stop : (this+colorLine).stops.iter ())
+      c->add_palette_index (stop.color.paletteIndex);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 6(noVar) or 7 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintRadialGradient
+                                            * table) to ColorLine subtable. */
+  Var<FWORD>			x0;
+  Var<FWORD>			y0;
+  Var<UFWORD>			radius0;
+  Var<FWORD>			x1;
+  Var<FWORD>			y1;
+  Var<UFWORD>			radius1;
+  public:
+  DEFINE_SIZE_STATIC (4 + 6 * Var<FWORD>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintSweepGradient
+{
+  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 (out->colorLine.serialize_subset (c, colorLine, this));
+  }
+
+  void closurev1 (hb_colrv1_closure_context_t* c) const
+  {
+    for (const auto &stop : (this+colorLine).stops.iter ())
+      c->add_palette_index (stop.color.paletteIndex);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && colorLine.sanitize (c, this));
+  }
+
+  HBUINT8			format; /* format = 8(noVar) or 9 (Var) */
+  Offset24To<ColorLine<Var>>	colorLine; /* Offset (from beginning of PaintSweepGradient
+                                            * table) to ColorLine subtable. */
+  Var<FWORD>			centerX;
+  Var<FWORD>			centerY;
+  Var<HBFixed>			startAngle;
+  Var<HBFixed>			endAngle;
+  public:
+  DEFINE_SIZE_STATIC (2 * Var<FWORD>::static_size + 2 * Var<HBFixed>::static_size);
+};
+
+struct Paint;
+// Paint a non-COLR glyph, filled as indicated by paint.
+struct PaintGlyph
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (! c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
+                                       HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    return_trace (out->paint.serialize_subset (c, paint, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && paint.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 10 */
+  Offset24To<Paint>	paint;  /* Offset (from beginning of PaintGlyph table) to Paint subtable. */
+  HBUINT16		gid;
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct PaintColrGlyph
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (c->serializer->check_assign (out->gid, c->plan->glyph_map->get (gid),
+                                               HB_SERIALIZE_ERROR_INT_OVERFLOW));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this));
+  }
+
+  HBUINT8	format; /* format = 11 */
+  HBUINT16	gid;
+  public:
+  DEFINE_SIZE_STATIC (3);
+};
+
+template <template<typename> class Var>
+struct PaintTransform
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (out->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 12(noVar) or 13 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintTransform table) to Paint subtable. */
+  Affine2x3<Var>	transform;
+  public:
+  DEFINE_SIZE_STATIC (4 + Affine2x3<Var>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintTranslate
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (out->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 14(noVar) or 15 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintTranslate table) to Paint subtable. */
+  Var<HBFixed>		dx;
+  Var<HBFixed>		dy;
+  public:
+  DEFINE_SIZE_STATIC (4 + Var<HBFixed>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintRotate
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (out->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 16 (noVar) or 17(Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintRotate table) to Paint subtable. */
+  Var<HBFixed>		angle;
+  Var<HBFixed>		centerX;
+  Var<HBFixed>		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + 3 * Var<HBFixed>::static_size);
+};
+
+template <template<typename> class Var>
+struct PaintSkew
+{
+  HB_INTERNAL void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  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 (out->src.serialize_subset (c, src, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) && src.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 18(noVar) or 19 (Var) */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintSkew table) to Paint subtable. */
+  Var<HBFixed>		xSkewAngle;
+  Var<HBFixed>		ySkewAngle;
+  Var<HBFixed>		centerX;
+  Var<HBFixed>		centerY;
+  public:
+  DEFINE_SIZE_STATIC (4 + 4 * Var<HBFixed>::static_size);
+};
+
+struct PaintComposite
+{
+  void closurev1 (hb_colrv1_closure_context_t* c) const;
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    auto *out = c->serializer->embed (this);
+    if (unlikely (!out)) return_trace (false);
+
+    if (!out->src.serialize_subset (c, src, this)) return_trace (false);
+    return_trace (out->backdrop.serialize_subset (c, backdrop, this));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (c->check_struct (this) &&
+                  src.sanitize (c, this) &&
+                  backdrop.sanitize (c, this));
+  }
+
+  HBUINT8		format; /* format = 20 */
+  Offset24To<Paint>	src; /* Offset (from beginning of PaintComposite table) to source Paint subtable. */
+  CompositeMode		mode;   /* If mode is unrecognized use COMPOSITE_CLEAR */
+  Offset24To<Paint>	backdrop; /* Offset (from beginning of PaintComposite table) to backdrop Paint subtable. */
+  public:
+  DEFINE_SIZE_STATIC (8);
+};
+
+struct Paint
+{
+  template <typename context_t, typename ...Ts>
+  typename context_t::return_t dispatch (context_t *c, Ts&&... ds) const
+  {
+    TRACE_DISPATCH (this, u.format);
+    if (unlikely (!c->may_dispatch (this, &u.format))) return_trace (c->no_dispatch_return_value ());
+    switch (u.format) {
+    case 1: return_trace (c->dispatch (u.paintformat1, hb_forward<Ts> (ds)...));
+    case 2: return_trace (c->dispatch (u.paintformat2, hb_forward<Ts> (ds)...));
+    case 3: return_trace (c->dispatch (u.paintformat3, hb_forward<Ts> (ds)...));
+    case 4: return_trace (c->dispatch (u.paintformat4, hb_forward<Ts> (ds)...));
+    case 5: return_trace (c->dispatch (u.paintformat5, hb_forward<Ts> (ds)...));
+    case 6: return_trace (c->dispatch (u.paintformat6, hb_forward<Ts> (ds)...));
+    case 7: return_trace (c->dispatch (u.paintformat7, hb_forward<Ts> (ds)...));
+    case 8: return_trace (c->dispatch (u.paintformat8, hb_forward<Ts> (ds)...));
+    case 9: return_trace (c->dispatch (u.paintformat9, hb_forward<Ts> (ds)...));
+    case 10: return_trace (c->dispatch (u.paintformat10, hb_forward<Ts> (ds)...));
+    case 11: return_trace (c->dispatch (u.paintformat11, hb_forward<Ts> (ds)...));
+    case 12: return_trace (c->dispatch (u.paintformat12, hb_forward<Ts> (ds)...));
+    case 13: return_trace (c->dispatch (u.paintformat13, hb_forward<Ts> (ds)...));
+    case 14: return_trace (c->dispatch (u.paintformat14, hb_forward<Ts> (ds)...));
+    case 15: return_trace (c->dispatch (u.paintformat15, hb_forward<Ts> (ds)...));
+    case 16: return_trace (c->dispatch (u.paintformat16, hb_forward<Ts> (ds)...));
+    case 17: return_trace (c->dispatch (u.paintformat17, hb_forward<Ts> (ds)...));
+    case 18: return_trace (c->dispatch (u.paintformat18, hb_forward<Ts> (ds)...));
+    case 19: return_trace (c->dispatch (u.paintformat19, hb_forward<Ts> (ds)...));
+    case 20: return_trace (c->dispatch (u.paintformat20, hb_forward<Ts> (ds)...));
+    default:return_trace (c->default_return_value ());
+    }
+  }
+
+  protected:
+  union {
+  HBUINT8				format;
+  PaintColrLayers			paintformat1;
+  PaintSolid<NoVariable>		paintformat2;
+  PaintSolid<Variable>			paintformat3;
+  PaintLinearGradient<NoVariable>	paintformat4;
+  PaintLinearGradient<Variable>		paintformat5;
+  PaintRadialGradient<NoVariable>	paintformat6;
+  PaintRadialGradient<Variable>		paintformat7;
+  PaintSweepGradient<NoVariable>	paintformat8;
+  PaintSweepGradient<Variable>		paintformat9;
+  PaintGlyph				paintformat10;
+  PaintColrGlyph			paintformat11;
+  PaintTransform<NoVariable>		paintformat12;
+  PaintTransform<Variable>		paintformat13;
+  PaintTranslate<NoVariable>		paintformat14;
+  PaintTranslate<Variable>		paintformat15;
+  PaintRotate<NoVariable>		paintformat16;
+  PaintRotate<Variable>			paintformat17;
+  PaintSkew<NoVariable>			paintformat18;
+  PaintSkew<Variable>			paintformat19;
+  PaintComposite			paintformat20;
+  } u;
+};
+
+struct BaseGlyphV1Record
+{
+  int cmp (hb_codepoint_t g) const
+  { return g < glyphId ? -1 : g > glyphId ? 1 : 0; }
+
+  bool serialize (hb_serialize_context_t *s, const hb_map_t* glyph_map,
+                  const void* src_base, hb_subset_context_t *c) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = s->embed (this);
+    if (unlikely (!out)) return_trace (false);
+    if (!s->check_assign (out->glyphId, glyph_map->get (glyphId),
+                          HB_SERIALIZE_ERROR_INT_OVERFLOW))
+      return_trace (false);
+
+    return_trace (out->paint.serialize_subset (c, paint, src_base));
+  }
+
+  bool sanitize (hb_sanitize_context_t *c, const void *base) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (likely (c->check_struct (this) && paint.sanitize (c, base)));
+  }
+
+  public:
+  HBGlyphID		glyphId;    /* Glyph ID of reference glyph */
+  Offset32To<Paint>	paint;      /* Offset (from beginning of BaseGlyphV1Record array) to Paint,
+                                     * Typically PaintColrLayers */
+  public:
+  DEFINE_SIZE_STATIC (6);
+};
+
+struct BaseGlyphV1List : SortedArray32Of<BaseGlyphV1Record>
+{
+  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);
+    const hb_set_t* glyphset = c->plan->_glyphset;
+
+    for (const auto& _ : as_array ())
+    {
+      unsigned gid = _.glyphId;
+      if (!glyphset->has (gid)) continue;
+
+      if (_.serialize (c->serializer, c->plan->glyph_map, this, c)) out->len++;
+      else return_trace (false);
+    }
+
+    return_trace (out->len != 0);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (SortedArray32Of<BaseGlyphV1Record>::sanitize (c, this));
+  }
+};
+
+struct LayerV1List : Array32OfOffset32To<Paint>
+{
+  const Paint& get_paint (unsigned i) const
+  { return this+(*this)[i]; }
+
+  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);
+
+    for (const auto& _ : + hb_enumerate (*this)
+                         | hb_filter (c->plan->colrv1_layers, hb_first))
+
+    {
+      auto *o = out->serialize_append (c->serializer);
+      if (unlikely (!o) || !o->serialize_subset (c, _.second, this))
+        return_trace (false);
+    }
+    return_trace (true);
+  }
+
+  bool sanitize (hb_sanitize_context_t *c) const
+  {
+    TRACE_SANITIZE (this);
+    return_trace (Array32OfOffset32To<Paint>::sanitize (c, this));
+  }
+};
+
 struct COLR
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_COLR;
@@ -131,6 +902,15 @@ struct COLR
 			 hb_set_t *related_ids /* OUT */) const
     { colr->closure_glyphs (glyph, related_ids); }
 
+    void closure_V0palette_indices (const hb_set_t *glyphs,
+				    hb_set_t *palettes /* OUT */) const
+    { colr->closure_V0palette_indices (glyphs, palettes); }
+
+    void closure_forV1 (hb_set_t *glyphset,
+                        hb_set_t *layer_indices,
+                        hb_set_t *palette_indices) const
+    { colr->closure_forV1 (glyphset, layer_indices, palette_indices); }
+
     private:
     hb_blob_ptr_t<COLR> colr;
   };
@@ -147,21 +927,70 @@ struct COLR
     related_ids->add_array (&glyph_layers[0].glyphId, glyph_layers.length, LayerRecord::min_size);
   }
 
+  void closure_V0palette_indices (const hb_set_t *glyphs,
+				  hb_set_t *palettes /* OUT */) const
+  {
+    if (!numBaseGlyphs || !numLayers) return;
+    hb_array_t<const BaseGlyphRecord> baseGlyphs = (this+baseGlyphsZ).as_array (numBaseGlyphs);
+    hb_array_t<const LayerRecord> all_layers = (this+layersZ).as_array (numLayers);
+
+    for (const BaseGlyphRecord record : baseGlyphs)
+    {
+      if (!glyphs->has (record.glyphId)) continue;
+      hb_array_t<const LayerRecord> glyph_layers = all_layers.sub_array (record.firstLayerIdx,
+                                                                   record.numLayers);
+      for (const LayerRecord layer : glyph_layers)
+        palettes->add (layer.colorIdx);
+    }
+  }
+
+  void closure_forV1 (hb_set_t *glyphset,
+                      hb_set_t *layer_indices,
+                      hb_set_t *palette_indices) const
+  {
+    if (version != 1) return;
+    hb_set_t visited_glyphs;
+
+    hb_colrv1_closure_context_t c (this, &visited_glyphs, layer_indices, palette_indices);
+    const BaseGlyphV1List &baseglyphV1_records = this+baseGlyphsV1List;
+
+    for (const BaseGlyphV1Record &baseglyphV1record: baseglyphV1_records.iter ())
+    {
+      unsigned gid = baseglyphV1record.glyphId;
+      if (!glyphset->has (gid)) continue;
+
+      const Paint &paint = &baseglyphV1_records+baseglyphV1record.paint;
+      paint.dispatch (&c);
+    }
+    hb_set_union (glyphset, &visited_glyphs);
+  }
+
+  const LayerV1List& get_layerV1List () const
+  { return (this+layersV1); }
+
+  const BaseGlyphV1List& get_baseglyphV1List () const
+  { return (this+baseGlyphsV1List); }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
-    return_trace (likely (c->check_struct (this) &&
-			  (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
-			  (this+layersZ).sanitize (c, numLayers)));
+    return_trace (c->check_struct (this) &&
+                  (this+baseGlyphsZ).sanitize (c, numBaseGlyphs) &&
+                  (this+layersZ).sanitize (c, numLayers) &&
+                  (version == 0 ||
+		   (COLRV1_ENABLE_SUBSETTING && version == 1 &&
+		    baseGlyphsV1List.sanitize (c, this) &&
+		    layersV1.sanitize (c, this) &&
+		    varStore.sanitize (c, this))));
   }
 
   template<typename BaseIterator, typename LayerIterator,
 	   hb_requires (hb_is_iterator (BaseIterator)),
 	   hb_requires (hb_is_iterator (LayerIterator))>
-  bool serialize (hb_serialize_context_t *c,
-		  unsigned version,
-		  BaseIterator base_it,
-		  LayerIterator layer_it)
+  bool serialize_V0 (hb_serialize_context_t *c,
+		     unsigned version,
+		     BaseIterator base_it,
+		     LayerIterator layer_it)
   {
     TRACE_SERIALIZE (this);
     if (unlikely (base_it.len () != layer_it.len ()))
@@ -171,6 +1000,12 @@ struct COLR
     this->version = version;
     numLayers = 0;
     numBaseGlyphs = base_it.len ();
+    if (base_it.len () == 0)
+    {
+      baseGlyphsZ = 0;
+      layersZ = 0;
+      return_trace (true);
+    }
     baseGlyphsZ = COLR::min_size;
     layersZ = COLR::min_size + numBaseGlyphs * BaseGlyphRecord::min_size;
 
@@ -198,6 +1033,14 @@ struct COLR
     return record;
   }
 
+  const BaseGlyphV1Record* get_base_glyphV1_record (hb_codepoint_t gid) const
+  {
+    const BaseGlyphV1Record* record = &(this+baseGlyphsV1List).bsearch ((unsigned) gid);
+    if ((record && (hb_codepoint_t) record->glyphId != gid))
+      record = nullptr;
+    return record;
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
@@ -245,6 +1088,7 @@ struct COLR
 				  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);
 				  out_layers[i].glyphId = new_gid;
+				  out_layers[i].colorIdx = c->plan->colr_palettes->get (layers[i].colorIdx);
 				}
 
 				return hb_pair_t<bool, hb_vector_t<LayerRecord>> (true, out_layers);
@@ -253,23 +1097,45 @@ struct COLR
     | hb_map_retains_sorting (hb_second)
     ;
 
-    if (unlikely (!base_it || !layer_it || base_it.len () != layer_it.len ()))
+    if (version == 0 && (!base_it || !layer_it))
       return_trace (false);
 
     COLR *colr_prime = c->serializer->start_embed<COLR> ();
-    return_trace (colr_prime->serialize (c->serializer, version, base_it, layer_it));
+    bool ret = colr_prime->serialize_V0 (c->serializer, version, base_it, layer_it);
+
+    if (version == 0) return_trace (ret);
+    auto snap = c->serializer->snapshot ();
+    if (!c->serializer->allocate_size<void> (3 * HBUINT32::static_size)) return_trace (false);
+    if (!colr_prime->baseGlyphsV1List.serialize_subset (c, baseGlyphsV1List, this))
+    {
+      if (c->serializer->in_error ()) return_trace (false);
+      //no more COLRv1 glyphs: downgrade to version 0
+      c->serializer->revert (snap);
+      colr_prime->version = 0;
+      return_trace (true);
+    }
+
+    if (!colr_prime->layersV1.serialize_subset (c, layersV1, this)) return_trace (false);
+
+    colr_prime->varStore = 0;
+    //TODO: subset varStore once it's implemented in fonttools
+    return_trace (true);
   }
 
   protected:
   HBUINT16	version;	/* Table version number (starts at 0). */
   HBUINT16	numBaseGlyphs;	/* Number of Base Glyph Records. */
-  LNNOffsetTo<SortedUnsizedArrayOf<BaseGlyphRecord>>
+  NNOffset32To<SortedUnsizedArrayOf<BaseGlyphRecord>>
 		baseGlyphsZ;	/* Offset to Base Glyph records. */
-  LNNOffsetTo<UnsizedArrayOf<LayerRecord>>
+  NNOffset32To<UnsizedArrayOf<LayerRecord>>
 		layersZ;	/* Offset to Layer Records. */
   HBUINT16	numLayers;	/* Number of Layer Records. */
+  // Version-1 additions
+  Offset32To<BaseGlyphV1List>		baseGlyphsV1List;
+  Offset32To<LayerV1List>		layersV1;
+  Offset32To<VariationStore>		varStore;
   public:
-  DEFINE_SIZE_STATIC (14);
+  DEFINE_SIZE_MIN (14);
 };
 
 } /* namespace OT */

+ 101 - 0
thirdparty/harfbuzz/src/hb-ot-color-colrv1-closure.hh

@@ -0,0 +1,101 @@
+/*
+ * Copyright © 2018  Ebrahim Byagowi
+ * Copyright © 2020  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.
+ *
+ */
+
+#ifndef HB_OT_COLR_COLRV1_CLOSURE_HH
+#define HB_OT_COLR_COLRV1_CLOSURE_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-layout-common.hh"
+#include "hb-ot-color-colr-table.hh"
+
+/*
+ * COLR -- Color
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/colr
+ */
+namespace OT {
+
+HB_INTERNAL void PaintColrLayers::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  c->add_layer_indices (firstLayerIndex, numLayers);
+  const LayerV1List &paint_offset_lists = c->get_colr_table ()->get_layerV1List ();
+  for (unsigned i = firstLayerIndex; i < firstLayerIndex + numLayers; i++)
+  {
+    const Paint &paint = hb_addressof (paint_offset_lists) + paint_offset_lists[i];
+    paint.dispatch (c);
+  }
+}
+
+HB_INTERNAL void PaintGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  c->add_glyph (gid);
+  (this+paint).dispatch (c);
+}
+
+HB_INTERNAL void PaintColrGlyph::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  const COLR *colr_table = c->get_colr_table ();
+  const BaseGlyphV1Record* baseglyphV1_record = colr_table->get_base_glyphV1_record (gid);
+  if (!baseglyphV1_record) return;
+  c->add_glyph (gid);
+
+  const BaseGlyphV1List &baseglyphV1_list = colr_table->get_baseglyphV1List ();
+  (&baseglyphV1_list+baseglyphV1_record->paint).dispatch (c);
+}
+
+template <template<typename> class Var>
+HB_INTERNAL void PaintTransform<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+}
+
+template <template<typename> class Var>
+HB_INTERNAL void PaintTranslate<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+}
+
+template <template<typename> class Var>
+HB_INTERNAL void PaintRotate<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+}
+
+template <template<typename> class Var>
+HB_INTERNAL void PaintSkew<Var>::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+}
+
+HB_INTERNAL void PaintComposite::closurev1 (hb_colrv1_closure_context_t* c) const
+{
+  (this+src).dispatch (c);
+  (this+backdrop).dispatch (c);
+}
+
+} /* namespace OT */
+
+
+#endif /* HB_OT_COLR_COLRV1_CLOSURE_HH */

+ 122 - 5
thirdparty/harfbuzz/src/hb-ot-color-cpal-table.hh

@@ -39,7 +39,6 @@
  */
 #define HB_OT_TAG_CPAL HB_TAG('C','P','A','L')
 
-
 namespace OT {
 
 
@@ -74,6 +73,44 @@ struct CPALV1Tail
   }
 
   public:
+  bool serialize (hb_serialize_context_t *c,
+                  unsigned palette_count,
+                  unsigned color_count,
+                  const void *base,
+                  const hb_map_t *color_index_map) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->allocate_size<CPALV1Tail> (static_size);
+    if (unlikely (!out)) return_trace (false);
+
+    out->paletteFlagsZ = 0;
+    if (paletteFlagsZ)
+      out->paletteFlagsZ.serialize_copy (c, paletteFlagsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+
+    out->paletteLabelsZ = 0;
+    if (paletteLabelsZ)
+      out->paletteLabelsZ.serialize_copy (c, paletteLabelsZ, base, 0, hb_serialize_context_t::Head, palette_count);
+
+    const hb_array_t<const NameID> colorLabels = (base+colorLabelsZ).as_array (color_count);
+    if (colorLabelsZ)
+    {
+      c->push ();
+      for (const auto _ : colorLabels)
+      {
+        if (!color_index_map->has (_)) continue;
+        NameID new_color_idx;
+        new_color_idx = color_index_map->get (_);
+        if (!c->copy<NameID> (new_color_idx))
+        {
+          c->pop_discard ();
+          return_trace (false);
+        }
+      }
+      c->add_link (out->colorLabelsZ, c->pop_pack ());
+    }
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c,
 		 const void *base,
 		 unsigned int palette_count,
@@ -87,15 +124,17 @@ struct CPALV1Tail
   }
 
   protected:
-  LNNOffsetTo<UnsizedArrayOf<HBUINT32>>
+  // TODO(garretrieger): these offsets can hold nulls so we should not be using non-null offsets
+  //                     here. Currently they are needed since UnsizedArrayOf doesn't define null_size
+  NNOffset32To<UnsizedArrayOf<HBUINT32>>
 		paletteFlagsZ;		/* Offset from the beginning of CPAL table to
 					 * the Palette Type Array. Set to 0 if no array
 					 * is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID>>
+  NNOffset32To<UnsizedArrayOf<NameID>>
 		paletteLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the palette labels array. Set to 0 if no
 					 * array is provided. */
-  LNNOffsetTo<UnsizedArrayOf<NameID>>
+  NNOffset32To<UnsizedArrayOf<NameID>>
 		colorLabelsZ;		/* Offset from the beginning of CPAL table to
 					 * the color labels array. Set to 0
 					 * if no array is provided. */
@@ -157,6 +196,84 @@ struct CPAL
   }
 
   public:
+  bool serialize (hb_serialize_context_t *c,
+                  const hb_array_t<const BGRAColor> &color_records,
+                  const hb_array_t<const HBUINT16> &color_record_indices,
+                  const hb_map_t &color_record_index_map,
+                  const hb_set_t &retained_color_record_indices) const
+  {
+    TRACE_SERIALIZE (this);
+
+    for (const auto idx : color_record_indices)
+    {
+      HBUINT16 new_idx;
+      if (idx == 0) new_idx = 0;
+      else new_idx = color_record_index_map.get (idx);
+      if (!c->copy<HBUINT16> (new_idx)) return_trace (false);
+    }
+
+    c->push ();
+    for (const auto _ : retained_color_record_indices.iter ())
+    {
+      if (!c->copy<BGRAColor> (color_records[_]))
+      {
+        c->pop_discard ();
+        return_trace (false);
+      }
+    }
+    c->add_link (colorRecordsZ, c->pop_pack ());
+    return_trace (true);
+  }
+
+  bool subset (hb_subset_context_t *c) const
+  {
+    TRACE_SUBSET (this);
+    const hb_map_t *color_index_map = c->plan->colr_palettes;
+    if (color_index_map->is_empty ()) return_trace (false);
+
+    hb_set_t retained_color_indices;
+    for (const auto _ : color_index_map->keys ())
+    {
+      if (_ == 0xFFFF) continue;
+      retained_color_indices.add (_);
+    }
+    if (retained_color_indices.is_empty ()) return_trace (false);
+
+    auto *out = c->serializer->start_embed (*this);
+    if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
+
+    out->version = version;
+    out->numColors = retained_color_indices.get_population ();
+    out->numPalettes = numPalettes;
+
+    const hb_array_t<const HBUINT16> colorRecordIndices = colorRecordIndicesZ.as_array (numPalettes);
+    hb_map_t color_record_index_map;
+    hb_set_t retained_color_record_indices;
+
+    unsigned record_count = 0;
+    for (const auto first_color_record_idx : colorRecordIndices)
+    {
+      for (unsigned retained_color_idx : retained_color_indices.iter ())
+      {
+        unsigned color_record_idx = first_color_record_idx + retained_color_idx;
+        if (color_record_index_map.has (color_record_idx)) continue;
+        color_record_index_map.set (color_record_idx, record_count);
+        retained_color_record_indices.add (color_record_idx);
+        record_count++;
+      }
+    }
+
+    out->numColorRecords = record_count;
+    const hb_array_t<const BGRAColor> color_records = (this+colorRecordsZ).as_array (numColorRecords);
+    if (!out->serialize (c->serializer, color_records, colorRecordIndices, color_record_index_map, retained_color_record_indices))
+      return_trace (false);
+
+    if (version == 1)
+      return_trace (v1 ().serialize (c->serializer, numPalettes, numColors, this, color_index_map));
+
+    return_trace (true);
+  }
+
   bool sanitize (hb_sanitize_context_t *c) const
   {
     TRACE_SANITIZE (this);
@@ -173,7 +290,7 @@ struct CPAL
   HBUINT16	numPalettes;		/* Number of palettes in the table. */
   HBUINT16	numColorRecords;	/* Total number of color records, combined for
 					 * all palettes. */
-  LNNOffsetTo<UnsizedArrayOf<BGRAColor>>
+  NNOffset32To<UnsizedArrayOf<BGRAColor>>
 		colorRecordsZ;		/* Offset from the beginning of CPAL table to
 					 * the first ColorRecord. */
   UnsizedArrayOf<HBUINT16>

+ 5 - 5
thirdparty/harfbuzz/src/hb-ot-color-sbix-table.hh

@@ -145,7 +145,7 @@ struct SBIXStrike
     auto* out = c->serializer->start_embed<SBIXStrike> ();
     if (unlikely (!out)) return_trace (false);
     auto snap = c->serializer->snapshot ();
-    if (unlikely (!c->serializer->extend (*out, num_output_glyphs + 1))) return_trace (false);
+    if (unlikely (!c->serializer->extend (out, num_output_glyphs + 1))) return_trace (false);
     out->ppem = ppem;
     out->resolution = resolution;
     HBUINT32 head;
@@ -185,7 +185,7 @@ struct SBIXStrike
   HBUINT16	resolution;	/* The device pixel density (in PPI) for which this
 				 * strike was designed. (E.g., 96 PPI, 192 PPI.) */
   protected:
-  UnsizedArrayOf<LOffsetTo<SBIXGlyph>>
+  UnsizedArrayOf<Offset32To<SBIXGlyph>>
 		imageOffsetsZ;	/* Offset from the beginning of the strike data header
 				 * to bitmap data for an individual glyph ID. */
   public:
@@ -352,11 +352,11 @@ struct sbix
   {
     TRACE_SERIALIZE (this);
 
-    auto *out = c->serializer->start_embed<LOffsetLArrayOf<SBIXStrike>> ();
+    auto *out = c->serializer->start_embed<Array32OfOffset32To<SBIXStrike>> ();
     if (unlikely (!out)) return_trace (false);
     if (unlikely (!c->serializer->extend_min (out))) return_trace (false);
 
-    hb_vector_t<LOffsetTo<SBIXStrike>*> new_strikes;
+    hb_vector_t<Offset32To<SBIXStrike>*> new_strikes;
     hb_vector_t<hb_serialize_context_t::objidx_t> objidxs;
     for (int i = strikes.len - 1; i >= 0; --i)
     {
@@ -400,7 +400,7 @@ struct sbix
   HBUINT16	version;	/* Table version number — set to 1 */
   HBUINT16	flags;		/* Bit 0: Set to 1. Bit 1: Draw outlines.
 				 * Bits 2 to 15: reserved (set to 0). */
-  LOffsetLArrayOf<SBIXStrike>
+  Array32OfOffset32To<SBIXStrike>
 		strikes;	/* Offsets from the beginning of the 'sbix'
 				 * table to data for each individual bitmap strike. */
   public:

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-color-svg-table.hh

@@ -62,7 +62,7 @@ struct SVGDocumentIndexEntry
 				 * this index entry. */
   HBUINT16	endGlyphID;	/* The last glyph ID in the range described by
 				 * this index entry. Must be >= startGlyphID. */
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		svgDoc;		/* Offset from the beginning of the SVG Document Index
 				 * to an SVG document. Must be non-zero. */
   HBUINT32	svgDocLength;	/* Length of the SVG document.
@@ -107,7 +107,7 @@ struct SVG
 
   protected:
   HBUINT16	version;	/* Table version (starting at 0). */
-  LOffsetTo<SortedArrayOf<SVGDocumentIndexEntry>>
+  Offset32To<SortedArray16Of<SVGDocumentIndexEntry>>
 		svgDocEntries;	/* Offset (relative to the start of the SVG table) to the
 				 * SVG Documents Index. Must be non-zero. */
 				/* Array of SVG Document Index Entries. */

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-face-table-list.hh

@@ -40,7 +40,7 @@
 
 /* This lists font tables that the hb_face_t will contain and lazily
  * load.  Don't add a table unless it's used though.  This is not
- * exactly free. */
+ * exactly zero-cost. */
 
 /* v--- Add new tables in the right place here. */
 

+ 3 - 9
thirdparty/harfbuzz/src/hb-ot-font.cc

@@ -253,9 +253,7 @@ hb_ot_get_font_v_extents (hb_font_t *font,
 	 _hb_ot_metrics_get_position_common (font, HB_OT_METRICS_TAG_VERTICAL_LINE_GAP, &metrics->line_gap);
 }
 
-#if HB_USE_ATEXIT
-static void free_static_ot_funcs ();
-#endif
+static inline void free_static_ot_funcs ();
 
 static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot_font_funcs_lazy_loader_t>
 {
@@ -281,21 +279,17 @@ static struct hb_ot_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ot
 
     hb_font_funcs_make_immutable (funcs);
 
-#if HB_USE_ATEXIT
-    atexit (free_static_ot_funcs);
-#endif
+    hb_atexit (free_static_ot_funcs);
 
     return funcs;
   }
 } static_ot_funcs;
 
-#if HB_USE_ATEXIT
-static
+static inline
 void free_static_ot_funcs ()
 {
   static_ot_funcs.free_instance ();
 }
-#endif
 
 static hb_font_funcs_t *
 _hb_ot_get_font_funcs ()

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-gasp-table.hh

@@ -71,7 +71,7 @@ struct gasp
 
   protected:
   HBUINT16	version;	/* Version number (set to 1) */
-  ArrayOf<GaspRange>
+  Array16Of<GaspRange>
 		gaspRanges;	/* Number of records to follow
 				 * Sorted by ppem */
   public:

+ 105 - 35
thirdparty/harfbuzz/src/hb-ot-glyf-table.hh

@@ -45,6 +45,10 @@ namespace OT {
  */
 #define HB_OT_TAG_loca HB_TAG('l','o','c','a')
 
+#ifndef HB_MAX_COMPOSITE_OPERATIONS
+#define HB_MAX_COMPOSITE_OPERATIONS 100000
+#endif
+
 
 struct loca
 {
@@ -98,7 +102,7 @@ struct glyf
     unsigned num_offsets = padded_offsets.len () + 1;
     bool use_short_loca = max_offset < 0x1FFFF;
     unsigned entry_size = use_short_loca ? 2 : 4;
-    char *loca_prime_data = (char *) calloc (entry_size, num_offsets);
+    char *loca_prime_data = (char *) hb_calloc (entry_size, num_offsets);
 
     if (unlikely (!loca_prime_data)) return false;
 
@@ -115,7 +119,7 @@ struct glyf
 					   entry_size * num_offsets,
 					   HB_MEMORY_MODE_WRITABLE,
 					   loca_prime_data,
-					   free);
+					   hb_free);
 
     bool result = plan->add_table (HB_OT_TAG_loca, loca_blob)
 	       && _add_head_and_set_loca_version (plan, use_short_loca);
@@ -209,10 +213,15 @@ struct glyf
 		if (!plan->old_gid_for_new_gid (new_gid, &subset_glyph.old_gid))
 		  return subset_glyph;
 
-		subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
-		if (plan->drop_hints) subset_glyph.drop_hints_bytes ();
-		else subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
-
+		if (new_gid == 0 &&
+                    !(plan->flags & HB_SUBSET_FLAGS_NOTDEF_OUTLINE))
+		  subset_glyph.source_glyph = Glyph ();
+		else
+		  subset_glyph.source_glyph = glyf.glyph_for_gid (subset_glyph.old_gid, true);
+		if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+                  subset_glyph.drop_hints_bytes ();
+		else
+                  subset_glyph.dest_start = subset_glyph.source_glyph.get_bytes ();
 		return subset_glyph;
 	      })
     | hb_sink (glyphs)
@@ -281,6 +290,11 @@ struct glyf
     hb_codepoint_t get_glyph_index ()       const { return glyphIndex; }
 
     void drop_instructions_flag ()  { flags = (uint16_t) flags & ~WE_HAVE_INSTRUCTIONS; }
+    void set_overlaps_flag ()
+    {
+      flags = (uint16_t) flags | OVERLAP_COMPOUND;
+    }
+
     bool has_instructions ()  const { return   flags & WE_HAVE_INSTRUCTIONS; }
 
     bool has_more ()          const { return   flags & MORE_COMPONENTS; }
@@ -383,9 +397,12 @@ struct glyf
   {
     typedef const CompositeGlyphChain *__item_t__;
     composite_iter_t (hb_bytes_t glyph_, __item_t__ current_) :
-      glyph (glyph_), current (current_)
-    { if (!check_range (current)) current = nullptr; }
-    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr) {}
+        glyph (glyph_), current (nullptr), current_size (0)
+    {
+      set_next (current_);
+    }
+
+    composite_iter_t () : glyph (hb_bytes_t ()), current (nullptr), current_size (0) {}
 
     const CompositeGlyphChain &__item__ () const { return *current; }
     bool __more__ () const { return current; }
@@ -393,23 +410,36 @@ struct glyf
     {
       if (!current->has_more ()) { current = nullptr; return; }
 
-      const CompositeGlyphChain *possible = &StructAfter<CompositeGlyphChain,
-							 CompositeGlyphChain> (*current);
-      if (!check_range (possible)) { current = nullptr; return; }
-      current = possible;
+      set_next (&StructAtOffset<CompositeGlyphChain> (current, current_size));
     }
     bool operator != (const composite_iter_t& o) const
     { return glyph != o.glyph || current != o.current; }
 
-    bool check_range (const CompositeGlyphChain *composite) const
+
+    void set_next (const CompositeGlyphChain *composite)
     {
-      return glyph.check_range (composite, CompositeGlyphChain::min_size)
-	  && glyph.check_range (composite, composite->get_size ());
+      if (!glyph.check_range (composite, CompositeGlyphChain::min_size))
+      {
+        current = nullptr;
+        current_size = 0;
+        return;
+      }
+      unsigned size = composite->get_size ();
+      if (!glyph.check_range (composite, size))
+      {
+        current = nullptr;
+        current_size = 0;
+        return;
+      }
+
+      current = composite;
+      current_size = size;
     }
 
     private:
     hb_bytes_t glyph;
     __item_t__ current;
+    unsigned current_size;
   };
 
   enum phantom_point_index_t
@@ -427,14 +457,14 @@ struct glyf
   {
     enum simple_glyph_flag_t
     {
-      FLAG_ON_CURVE  = 0x01,
-      FLAG_X_SHORT   = 0x02,
-      FLAG_Y_SHORT   = 0x04,
-      FLAG_REPEAT    = 0x08,
-      FLAG_X_SAME    = 0x10,
-      FLAG_Y_SAME    = 0x20,
-      FLAG_RESERVED1 = 0x40,
-      FLAG_RESERVED2 = 0x80
+      FLAG_ON_CURVE       = 0x01,
+      FLAG_X_SHORT        = 0x02,
+      FLAG_Y_SHORT        = 0x04,
+      FLAG_REPEAT         = 0x08,
+      FLAG_X_SAME         = 0x10,
+      FLAG_Y_SAME         = 0x20,
+      FLAG_OVERLAP_SIMPLE = 0x40,
+      FLAG_RESERVED2      = 0x80
     };
 
     private:
@@ -495,8 +525,8 @@ struct glyf
       const Glyph trim_padding () const
       {
 	/* based on FontTools _g_l_y_f.py::trim */
-	const char *glyph = bytes.arrayZ;
-	const char *glyph_end = glyph + bytes.length;
+	const uint8_t *glyph = (uint8_t*) bytes.arrayZ;
+	const uint8_t *glyph_end = glyph + bytes.length;
 	/* simple glyph w/contours, possibly trimmable */
 	glyph += instruction_len_offset ();
 
@@ -553,6 +583,17 @@ struct glyf
 	dest_end = bytes.sub_array (glyph_length, bytes.length - glyph_length);
       }
 
+      void set_overlaps_flag ()
+      {
+        if (unlikely (!header.numberOfContours)) return;
+
+        unsigned flags_offset = length (instructions_length ());
+        if (unlikely (length (flags_offset + 1) > bytes.length)) return;
+
+	HBUINT8 &first_flag = (HBUINT8 &) StructAtOffset<HBUINT16> (&bytes, flags_offset);
+        first_flag = (uint8_t) first_flag | FLAG_OVERLAP_SIMPLE;
+      }
+
       static bool read_points (const HBUINT8 *&p /* IN/OUT */,
 			       contour_point_vector_t &points_ /* IN/OUT */,
 			       const hb_bytes_t &bytes,
@@ -666,6 +707,12 @@ struct glyf
       /* Chop instructions off the end */
       void drop_hints_bytes (hb_bytes_t &dest_start) const
       { dest_start = bytes.sub_array (0, bytes.length - instructions_length (bytes)); }
+
+      void set_overlaps_flag ()
+      {
+        const_cast<CompositeGlyphChain &> (StructAfter<CompositeGlyphChain, GlyphHeader> (header))
+                .set_overlaps_flag ();
+      }
     };
 
     enum glyph_type_t { EMPTY, SIMPLE, COMPOSITE };
@@ -695,6 +742,15 @@ struct glyf
       }
     }
 
+    void set_overlaps_flag ()
+    {
+      switch (type) {
+      case COMPOSITE: CompositeGlyph (*header, bytes).set_overlaps_flag (); return;
+      case SIMPLE:    SimpleGlyph (*header, bytes).set_overlaps_flag (); return;
+      default:        return;
+      }
+    }
+
     void drop_hints_bytes (hb_bytes_t &dest_start, hb_bytes_t &dest_end) const
     {
       switch (type) {
@@ -886,7 +942,7 @@ struct glyf
     {
       if (gid >= num_glyphs) return false;
 
-      /* Making this alloc free is not that easy
+      /* Making this allocfree is not that easy
 	 https://github.com/harfbuzz/harfbuzz/issues/2095
 	 mostly because of gvar handling in VF fonts,
 	 perhaps a separate path for non-VF fonts can be considered */
@@ -1045,18 +1101,28 @@ struct glyf
       return needs_padding_removal ? glyph.trim_padding () : glyph;
     }
 
-    void
-    add_gid_and_children (hb_codepoint_t gid, hb_set_t *gids_to_retain,
-			  unsigned int depth = 0) const
+    unsigned
+    add_gid_and_children (hb_codepoint_t gid,
+			  hb_set_t *gids_to_retain,
+			  unsigned depth = 0,
+			  unsigned operation_count = 0) const
     {
-      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return;
+      if (unlikely (depth++ > HB_MAX_NESTING_LEVEL)) return operation_count;
+      if (unlikely (operation_count++ > HB_MAX_COMPOSITE_OPERATIONS)) return operation_count;
       /* Check if is already visited */
-      if (gids_to_retain->has (gid)) return;
+      if (gids_to_retain->has (gid)) return operation_count;
 
       gids_to_retain->add (gid);
 
-      for (auto &item : glyph_for_gid (gid).get_composite_iterator ())
-	add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth);
+      auto it = glyph_for_gid (gid).get_composite_iterator ();
+      while (it)
+      {
+        auto item = *(it++);
+        operation_count +=
+            add_gid_and_children (item.get_glyph_index (), gids_to_retain, depth, operation_count);
+      }
+
+      return operation_count;
     }
 
 #ifdef HB_EXPERIMENTAL_API
@@ -1230,7 +1296,11 @@ struct glyf
 	  const_cast<CompositeGlyphChain &> (_).set_glyph_index (new_gid);
       }
 
-      if (plan->drop_hints) Glyph (dest_glyph).drop_hints ();
+      if (plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
+        Glyph (dest_glyph).drop_hints ();
+
+      if (plan->flags & HB_SUBSET_FLAGS_SET_OVERLAPS_FLAG)
+        Glyph (dest_glyph).set_overlaps_flag ();
 
       return_trace (true);
     }

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-hdmx-table.hh

@@ -52,7 +52,7 @@ struct DeviceRecord
 
     unsigned length = it.len ();
 
-    if (unlikely (!c->extend (*this, length)))  return_trace (false);
+    if (unlikely (!c->extend (this, length)))  return_trace (false);
 
     this->pixelSize = pixelSize;
     this->maxWidth =
@@ -110,7 +110,7 @@ struct hdmx
     for (const hb_item_type<Iterator>& _ : +it)
       c->start_embed<DeviceRecord> ()->serialize (c, _.first, _.second);
 
-    return_trace (c->successful);
+    return_trace (c->successful ());
   }
 
 

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-hmtx-table.hh

@@ -146,7 +146,7 @@ struct hmtxvmtx
 
     _mtx.fini ();
 
-    if (unlikely (c->serializer->ran_out_of_room || c->serializer->in_error ()))
+    if (unlikely (c->serializer->in_error ()))
       return_trace (false);
 
     // Amend header num hmetrics

+ 18 - 18
thirdparty/harfbuzz/src/hb-ot-layout-base-table.hh

@@ -103,7 +103,7 @@ struct BaseCoordFormat3
   protected:
   HBUINT16	format;		/* Format identifier--format = 3 */
   FWORD		coordinate;	/* X or Y value, in design units */
-  OffsetTo<Device>
+  Offset16To<Device>
 		deviceTable;	/* Offset to Device table for X or
 				 * Y value, from beginning of
 				 * BaseCoord table (may be NULL). */
@@ -173,11 +173,11 @@ struct FeatMinMaxRecord
   protected:
   Tag		tag;		/* 4-byte feature identification tag--must
 				 * match feature tag in FeatureList */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		minCoord;	/* Offset to BaseCoord table that defines
 				 * the minimum extent value, from beginning
 				 * of MinMax table (may be NULL) */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		maxCoord;	/* Offset to BaseCoord table that defines
 				 * the maximum extent value, from beginning
 				 * of MinMax table (may be NULL) */
@@ -212,15 +212,15 @@ struct MinMax
   }
 
   protected:
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		minCoord;	/* Offset to BaseCoord table that defines
 				 * minimum extent value, from the beginning
 				 * of MinMax table (may be NULL) */
-  OffsetTo<BaseCoord>
+  Offset16To<BaseCoord>
 		maxCoord;	/* Offset to BaseCoord table that defines
 				 * maximum extent value, from the beginning
 				 * of MinMax table (may be NULL) */
-  SortedArrayOf<FeatMinMaxRecord>
+  SortedArray16Of<FeatMinMaxRecord>
 		featMinMaxRecords;
 				/* Array of FeatMinMaxRecords, in alphabetical
 				 * order by featureTableTag */
@@ -247,7 +247,7 @@ struct BaseValues
   Index		defaultIndex;	/* Index number of default baseline for this
 				 * script — equals index position of baseline tag
 				 * in baselineTags array of the BaseTagList */
-  OffsetArrayOf<BaseCoord>
+  Array16OfOffset16To<BaseCoord>
 		baseCoords;	/* Number of BaseCoord tables defined — should equal
 				 * baseTagCount in the BaseTagList
 				 *
@@ -275,7 +275,7 @@ struct BaseLangSysRecord
 
   protected:
   Tag		baseLangSysTag;	/* 4-byte language system identification tag */
-  OffsetTo<MinMax>
+  Offset16To<MinMax>
 		minMax;		/* Offset to MinMax table, from beginning
 				 * of BaseScript table */
   public:
@@ -305,13 +305,13 @@ struct BaseScript
   }
 
   protected:
-  OffsetTo<BaseValues>
+  Offset16To<BaseValues>
 		baseValues;	/* Offset to BaseValues table, from beginning
 				 * of BaseScript table (may be NULL) */
-  OffsetTo<MinMax>
+  Offset16To<MinMax>
 		defaultMinMax;	/* Offset to MinMax table, from beginning of
 				 * BaseScript table (may be NULL) */
-  SortedArrayOf<BaseLangSysRecord>
+  SortedArray16Of<BaseLangSysRecord>
 		baseLangSysRecords;
 				/* Number of BaseLangSysRecords
 				 * defined — may be zero (0) */
@@ -339,7 +339,7 @@ struct BaseScriptRecord
 
   protected:
   Tag		baseScriptTag;	/* 4-byte script identification tag */
-  OffsetTo<BaseScript>
+  Offset16To<BaseScript>
 		baseScript;	/* Offset to BaseScript table, from beginning
 				 * of BaseScriptList */
 
@@ -364,7 +364,7 @@ struct BaseScriptList
   }
 
   protected:
-  SortedArrayOf<BaseScriptRecord>
+  SortedArray16Of<BaseScriptRecord>
 			baseScriptRecords;
 
   public:
@@ -426,12 +426,12 @@ struct Axis
   }
 
   protected:
-  OffsetTo<SortedArrayOf<Tag>>
+  Offset16To<SortedArray16Of<Tag>>
 		baseTagList;	/* Offset to BaseTagList table, from beginning
 				 * of Axis table (may be NULL)
 				 * Array of 4-byte baseline identification tags — must
 				 * be in alphabetical order */
-  OffsetTo<BaseScriptList>
+  Offset16To<BaseScriptList>
 		baseScriptList;	/* Offset to BaseScriptList table, from beginning
 				 * of Axis table
 				 * Array of BaseScriptRecords, in alphabetical order
@@ -501,11 +501,11 @@ struct BASE
 
   protected:
   FixedVersion<>version;	/* Version of the BASE table */
-  OffsetTo<Axis>hAxis;		/* Offset to horizontal Axis table, from beginning
+  Offset16To<Axis>hAxis;		/* Offset to horizontal Axis table, from beginning
 				 * of BASE table (may be NULL) */
-  OffsetTo<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
+  Offset16To<Axis>vAxis;		/* Offset to vertical Axis table, from beginning
 				 * of BASE table (may be NULL) */
-  LOffsetTo<VariationStore>
+  Offset32To<VariationStore>
 		varStore;	/* Offset to the table of Item Variation
 				 * Store--from beginning of BASE
 				 * header (may be NULL).  Introduced

File diff suppressed because it is too large
+ 396 - 107
thirdparty/harfbuzz/src/hb-ot-layout-common.hh


+ 20 - 22
thirdparty/harfbuzz/src/hb-ot-layout-gdef-table.hh

@@ -42,7 +42,7 @@ namespace OT {
  */
 
 /* Array of contour point indices--in increasing numerical order */
-struct AttachPoint : ArrayOf<HBUINT16>
+struct AttachPoint : Array16Of<HBUINT16>
 {
   bool subset (hb_subset_context_t *c) const
   {
@@ -98,8 +98,7 @@ struct AttachList
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -110,10 +109,10 @@ struct AttachList
   }
 
   protected:
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table -- from
 					 * beginning of AttachList table */
-  OffsetArrayOf<AttachPoint>
+  Array16OfOffset16To<AttachPoint>
 		attachPoint;		/* Array of AttachPoint tables
 					 * in Coverage Index order */
   public:
@@ -220,7 +219,7 @@ struct CaretValueFormat3
   protected:
   HBUINT16	caretValueFormat;	/* Format identifier--format = 3 */
   FWORD		coordinate;		/* X or Y value, in design units */
-  OffsetTo<Device>
+  Offset16To<Device>
 		deviceTable;		/* Offset to Device table for X or Y
 					 * value--from beginning of CaretValue
 					 * table */
@@ -329,7 +328,7 @@ struct LigGlyph
 
   void collect_variation_indices (hb_collect_variation_indices_context_t *c) const
   {
-    for (const OffsetTo<CaretValue>& offset : carets.iter ())
+    for (const Offset16To<CaretValue>& offset : carets.iter ())
       (this+offset).collect_variation_indices (c->layout_variation_indices);
   }
 
@@ -340,7 +339,7 @@ struct LigGlyph
   }
 
   protected:
-  OffsetArrayOf<CaretValue>
+  Array16OfOffset16To<CaretValue>
 		carets;			/* Offset array of CaretValue tables
 					 * --from beginning of LigGlyph table
 					 * --in increasing coordinate order */
@@ -386,8 +385,7 @@ struct LigCaretList
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -408,10 +406,10 @@ struct LigCaretList
   }
 
   protected:
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of LigCaretList table */
-  OffsetArrayOf<LigGlyph>
+  Array16OfOffset16To<LigGlyph>
 		ligGlyph;		/* Array of LigGlyph tables
 					 * in Coverage Index order */
   public:
@@ -432,7 +430,7 @@ struct MarkGlyphSetsFormat1
     out->format = format;
 
     bool ret = true;
-    for (const LOffsetTo<Coverage>& offset : coverage.iter ())
+    for (const Offset32To<Coverage>& offset : coverage.iter ())
     {
       auto *o = out->coverage.serialize_append (c->serializer);
       if (unlikely (!o))
@@ -460,7 +458,7 @@ struct MarkGlyphSetsFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  ArrayOf<LOffsetTo<Coverage>>
+  Array16Of<Offset32To<Coverage>>
 		coverage;		/* Array of long offsets to mark set
 					 * coverage tables */
   public:
@@ -643,10 +641,10 @@ struct GDEF
     auto *out = c->serializer->embed (*this);
     if (unlikely (!out)) return_trace (false);
 
-    bool subset_glyphclassdef = out->glyphClassDef.serialize_subset (c, glyphClassDef, this);
+    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);
+    bool subset_markattachclassdef = out->markAttachClassDef.serialize_subset (c, markAttachClassDef, this, nullptr, false, true);
 
     bool subset_markglyphsetsdef = true;
     if (version.to_int () >= 0x00010002u)
@@ -687,28 +685,28 @@ struct GDEF
   protected:
   FixedVersion<>version;		/* Version of the GDEF table--currently
 					 * 0x00010003u */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		glyphClassDef;		/* Offset to class definition table
 					 * for glyph type--from beginning of
 					 * GDEF header (may be Null) */
-  OffsetTo<AttachList>
+  Offset16To<AttachList>
 		attachList;		/* Offset to list of glyphs with
 					 * attachment points--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<LigCaretList>
+  Offset16To<LigCaretList>
 		ligCaretList;		/* Offset to list of positioning points
 					 * for ligature carets--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<ClassDef>
+  Offset16To<ClassDef>
 		markAttachClassDef;	/* Offset to class definition table for
 					 * mark attachment type--from beginning
 					 * of GDEF header (may be Null) */
-  OffsetTo<MarkGlyphSets>
+  Offset16To<MarkGlyphSets>
 		markGlyphSetsDef;	/* Offset to the table of mark set
 					 * definitions--from beginning of GDEF
 					 * header (may be NULL).  Introduced
 					 * in version 0x00010002. */
-  LOffsetTo<VariationStore>
+  Offset32To<VariationStore>
 		varStore;		/* Offset to the table of Item Variation
 					 * Store--from beginning of GDEF
 					 * header (may be NULL).  Introduced

File diff suppressed because it is too large
+ 348 - 181
thirdparty/harfbuzz/src/hb-ot-layout-gpos-table.hh


+ 228 - 94
thirdparty/harfbuzz/src/hb-ot-layout-gsub-table.hh

@@ -46,14 +46,19 @@ struct SingleSubstFormat1
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  bool may_have_non_1to1 () const
+  { return false; }
+
   void closure (hb_closure_context_t *c) const
   {
     unsigned d = deltaGlyphID;
+
     + hb_iter (this+coverage)
-    | hb_filter (*c->glyphs)
+    | hb_filter (c->parent_active_glyphs ())
     | hb_map ([d] (hb_codepoint_t g) { return (g + d) & 0xFFFFu; })
     | hb_sink (c->output)
     ;
+
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -95,9 +100,9 @@ struct SingleSubstFormat1
 		  unsigned delta)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
-    c->check_assign (deltaGlyphID, delta);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
+    c->check_assign (deltaGlyphID, delta, HB_SERIALIZE_ERROR_INT_OVERFLOW);
     return_trace (true);
   }
 
@@ -133,7 +138,7 @@ struct SingleSubstFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
   HBUINT16	deltaGlyphID;		/* Add to original GlyphID to get
@@ -147,13 +152,17 @@ struct SingleSubstFormat2
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  bool may_have_non_1to1 () const
+  { return false; }
+
   void closure (hb_closure_context_t *c) const
   {
     + hb_zip (this+coverage, substitute)
-    | hb_filter (*c->glyphs, hb_first)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_sink (c->output)
     ;
+
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -200,9 +209,9 @@ struct SingleSubstFormat2
       + it
       | hb_map_retains_sorting (hb_first)
       ;
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!substitute.serialize (c, substitutes))) return_trace (false);
-    if (unlikely (!coverage.serialize (c, this).serialize (c, glyphs))) return_trace (false);
+    if (unlikely (!coverage.serialize_serialize (c, glyphs))) return_trace (false);
     return_trace (true);
   }
 
@@ -233,10 +242,10 @@ struct SingleSubstFormat2
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 2 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID>
 		substitute;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -334,9 +343,14 @@ struct Sequence
 
     unsigned int klass = _hb_glyph_info_is_ligature (&c->buffer->cur()) ?
 			 HB_OT_LAYOUT_GLYPH_PROPS_BASE_GLYPH : 0;
+    unsigned lig_id = _hb_glyph_info_get_lig_id (&c->buffer->cur());
 
-    for (unsigned int i = 0; i < count; i++) {
-      _hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
+    for (unsigned int i = 0; i < count; i++)
+    {
+      /* If is attached to a ligature, don't disturb that.
+       * https://github.com/harfbuzz/harfbuzz/issues/3069 */
+      if (!lig_id)
+	_hb_glyph_info_set_lig_props_for_component (&c->buffer->cur(), i);
       c->output_glyph_for_component (substitute.arrayZ[i], klass);
     }
     c->buffer->skip_glyph ();
@@ -377,7 +391,7 @@ struct Sequence
   }
 
   protected:
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID>
 		substitute;		/* String of GlyphIDs to substitute */
   public:
   DEFINE_SIZE_ARRAY (2, substitute);
@@ -388,10 +402,13 @@ struct MultipleSubstFormat1
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
     + hb_zip (this+coverage, sequence)
-    | hb_filter (*c->glyphs, hb_first)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
     | hb_apply ([c] (const Sequence &_) { _.closure (c); })
@@ -431,17 +448,17 @@ struct MultipleSubstFormat1
 		  hb_array_t<const HBGlyphID> substitute_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!sequence.serialize (c, glyphs.length))) return_trace (false);
     for (unsigned int i = 0; i < glyphs.length; i++)
     {
       unsigned int substitute_len = substitute_len_list[i];
-      if (unlikely (!sequence[i].serialize (c, this)
-				.serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
+      if (unlikely (!sequence[i]
+                        .serialize_serialize (c, substitute_glyphs_list.sub_array (0, substitute_len))))
 	return_trace (false);
       substitute_glyphs_list += substitute_len;
     }
-    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
+    return_trace (coverage.serialize_serialize (c, glyphs));
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -462,8 +479,7 @@ struct MultipleSubstFormat1
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -475,10 +491,10 @@ struct MultipleSubstFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<Sequence>
+  Array16OfOffset16To<Sequence>
 		sequence;		/* Array of Sequence tables
 					 * ordered by Coverage Index */
   public:
@@ -547,7 +563,12 @@ struct AlternateSet
 
     /* If alt_index is MAX_VALUE, randomize feature if it is the rand feature. */
     if (alt_index == HB_OT_MAP_MAX_VALUE && c->random)
+    {
+      /* Maybe we can do better than unsafe-to-break all; but since we are
+       * changing random state, it would be hard to track that.  Good 'nough. */
+      c->buffer->unsafe_to_break_all ();
       alt_index = c->random_number () % count + 1;
+    }
 
     if (unlikely (alt_index > count || alt_index == 0)) return_trace (false);
 
@@ -603,7 +624,7 @@ struct AlternateSet
   }
 
   protected:
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID>
 		alternates;		/* Array of alternate GlyphIDs--in
 					 * arbitrary order */
   public:
@@ -615,14 +636,18 @@ struct AlternateSubstFormat1
   bool intersects (const hb_set_t *glyphs) const
   { return (this+coverage).intersects (glyphs); }
 
+  bool may_have_non_1to1 () const
+  { return false; }
+
   void closure (hb_closure_context_t *c) const
   {
     + hb_zip (this+coverage, alternateSet)
-    | hb_filter (c->glyphs, hb_first)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
     | hb_apply ([c] (const AlternateSet &_) { _.closure (c); })
     ;
+
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -666,17 +691,17 @@ struct AlternateSubstFormat1
 		  hb_array_t<const HBGlyphID> alternate_glyphs_list)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!alternateSet.serialize (c, glyphs.length))) return_trace (false);
     for (unsigned int i = 0; i < glyphs.length; i++)
     {
       unsigned int alternate_len = alternate_len_list[i];
-      if (unlikely (!alternateSet[i].serialize (c, this)
-				    .serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
+      if (unlikely (!alternateSet[i]
+                        .serialize_serialize (c, alternate_glyphs_list.sub_array (0, alternate_len))))
 	return_trace (false);
       alternate_glyphs_list += alternate_len;
     }
-    return_trace (coverage.serialize (c, this).serialize (c, glyphs));
+    return_trace (coverage.serialize_serialize (c, glyphs));
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -697,8 +722,7 @@ struct AlternateSubstFormat1
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -710,10 +734,10 @@ struct AlternateSubstFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<AlternateSet>
+  Array16OfOffset16To<AlternateSet>
 		alternateSet;		/* Array of AlternateSet tables
 					 * ordered by Coverage Index */
   public:
@@ -831,7 +855,7 @@ struct Ligature
 		  Iterator components /* Starting from second */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     ligGlyph = ligature;
     if (unlikely (!component.serialize (c, components))) return_trace (false);
     return_trace (true);
@@ -930,15 +954,14 @@ struct LigatureSet
 		  hb_array_t<const HBGlyphID> &component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!ligature.serialize (c, ligatures.length))) return_trace (false);
     for (unsigned int i = 0; i < ligatures.length; i++)
     {
       unsigned int component_count = (unsigned) hb_max ((int) component_count_list[i] - 1, 0);
-      if (unlikely (!ligature[i].serialize (c, this)
-				.serialize (c,
-					    ligatures[i],
-					    component_list.sub_array (0, component_count))))
+      if (unlikely (!ligature[i].serialize_serialize (c,
+                                                      ligatures[i],
+                                                      component_list.sub_array (0, component_count))))
 	return_trace (false);
       component_list += component_count;
     }
@@ -965,7 +988,7 @@ struct LigatureSet
   }
 
   protected:
-  OffsetArrayOf<Ligature>
+  Array16OfOffset16To<Ligature>
 		ligature;		/* Array LigatureSet tables
 					 * ordered by preference */
   public:
@@ -980,20 +1003,24 @@ struct LigatureSubstFormat1
     + hb_zip (this+coverage, ligatureSet)
     | hb_filter (*glyphs, hb_first)
     | hb_map (hb_second)
-    | hb_map ([this, glyphs] (const OffsetTo<LigatureSet> &_)
+    | hb_map ([this, glyphs] (const Offset16To<LigatureSet> &_)
 	      { return (this+_).intersects (glyphs); })
     | hb_any
     ;
   }
 
+  bool may_have_non_1to1 () const
+  { return true; }
+
   void closure (hb_closure_context_t *c) const
   {
     + hb_zip (this+coverage, ligatureSet)
-    | hb_filter (*c->glyphs, hb_first)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_map (hb_add (this))
     | hb_apply ([c] (const LigatureSet &_) { _.closure (c); })
     ;
+
   }
 
   void closure_lookups (hb_closure_lookups_context_t *c) const {}
@@ -1039,20 +1066,20 @@ struct LigatureSubstFormat1
 		  hb_array_t<const HBGlyphID> component_list /* Starting from second for each ligature */)
   {
     TRACE_SERIALIZE (this);
-    if (unlikely (!c->extend_min (*this))) return_trace (false);
+    if (unlikely (!c->extend_min (this))) return_trace (false);
     if (unlikely (!ligatureSet.serialize (c, first_glyphs.length))) return_trace (false);
     for (unsigned int i = 0; i < first_glyphs.length; i++)
     {
       unsigned int ligature_count = ligature_per_first_glyph_count_list[i];
-      if (unlikely (!ligatureSet[i].serialize (c, this)
-				   .serialize (c,
-					       ligatures_list.sub_array (0, ligature_count),
-					       component_count_list.sub_array (0, ligature_count),
-					       component_list))) return_trace (false);
+      if (unlikely (!ligatureSet[i]
+                        .serialize_serialize (c,
+                                              ligatures_list.sub_array (0, ligature_count),
+                                              component_count_list.sub_array (0, ligature_count),
+                                              component_list))) return_trace (false);
       ligatures_list += ligature_count;
       component_count_list += ligature_count;
     }
-    return_trace (coverage.serialize (c, this).serialize (c, first_glyphs));
+    return_trace (coverage.serialize_serialize (c, first_glyphs));
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -1073,8 +1100,7 @@ struct LigatureSubstFormat1
     | hb_map (glyph_map)
     | hb_sink (new_coverage)
     ;
-    out->coverage.serialize (c->serializer, out)
-		 .serialize (c->serializer, new_coverage.iter ());
+    out->coverage.serialize_serialize (c->serializer, new_coverage.iter ());
     return_trace (bool (new_coverage));
   }
 
@@ -1086,10 +1112,10 @@ struct LigatureSubstFormat1
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of Substitution table */
-  OffsetArrayOf<LigatureSet>
+  Array16OfOffset16To<LigatureSet>
 		ligatureSet;		/* Array LigatureSet tables
 					 * ordered by Coverage Index */
   public:
@@ -1157,7 +1183,7 @@ struct ReverseChainSingleSubstFormat1
     if (!(this+coverage).intersects (glyphs))
       return false;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
 
     unsigned int count;
 
@@ -1174,15 +1200,18 @@ struct ReverseChainSingleSubstFormat1
     return true;
   }
 
+  bool may_have_non_1to1 () const
+  { return false; }
+
   void closure (hb_closure_context_t *c) const
   {
     if (!intersects (c->glyphs)) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
 
     + hb_zip (this+coverage, substitute)
-    | hb_filter (*c->glyphs, hb_first)
+    | hb_filter (c->parent_active_glyphs (), hb_first)
     | hb_map (hb_second)
     | hb_sink (c->output)
     ;
@@ -1200,12 +1229,12 @@ struct ReverseChainSingleSubstFormat1
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+backtrack[i]).collect_coverage (c->before))) return;
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
     count = lookahead.len;
     for (unsigned int i = 0; i < count; i++)
       if (unlikely (!(this+lookahead[i]).collect_coverage (c->after))) return;
 
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
     count = substitute.len;
     c->output->add_array (substitute.arrayZ, substitute.len);
   }
@@ -1224,8 +1253,8 @@ struct ReverseChainSingleSubstFormat1
     unsigned int index = (this+coverage).get_coverage (c->buffer->cur ().codepoint);
     if (likely (index == NOT_COVERED)) return_trace (false);
 
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
 
     if (unlikely (index >= substitute.len)) return_trace (false);
 
@@ -1250,11 +1279,80 @@ struct ReverseChainSingleSubstFormat1
     return_trace (false);
   }
 
+  template<typename Iterator,
+           hb_requires (hb_is_iterator (Iterator))>
+  bool serialize_coverage_offset_array (hb_subset_context_t *c, Iterator it) const
+  {
+    TRACE_SERIALIZE (this);
+    auto *out = c->serializer->start_embed<Array16OfOffset16To<Coverage>> ();
+
+    if (unlikely (!c->serializer->allocate_size<HBUINT16> (HBUINT16::static_size)))
+      return_trace (false);
+
+    for (auto& offset : it) {
+      auto *o = out->serialize_append (c->serializer);
+      if (unlikely (!o) || !o->serialize_subset (c, offset, this))
+        return_trace (false);
+    }
+
+    return_trace (true);
+  }
+
+  template<typename Iterator, typename BacktrackIterator, typename LookaheadIterator,
+           hb_requires (hb_is_sorted_source_of (Iterator, hb_codepoint_pair_t)),
+           hb_requires (hb_is_iterator (BacktrackIterator)),
+           hb_requires (hb_is_iterator (LookaheadIterator))>
+  bool serialize (hb_subset_context_t *c,
+                  Iterator coverage_subst_iter,
+                  BacktrackIterator backtrack_iter,
+                  LookaheadIterator lookahead_iter) const
+  {
+    TRACE_SERIALIZE (this);
+
+    auto *out = c->serializer->start_embed (this);
+    if (unlikely (!c->serializer->check_success (out))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->format))) return_trace (false);
+    if (unlikely (!c->serializer->embed (this->coverage))) return_trace (false);
+
+    if (!serialize_coverage_offset_array (c, backtrack_iter)) return_trace (false);
+    if (!serialize_coverage_offset_array (c, lookahead_iter)) return_trace (false);
+
+    auto *substitute_out = c->serializer->start_embed<Array16Of<HBGlyphID>> ();
+    auto substitutes =
+    + coverage_subst_iter
+    | hb_map (hb_second)
+    ;
+
+    auto glyphs =
+    + coverage_subst_iter
+    | hb_map_retains_sorting (hb_first)
+    ;
+    if (unlikely (! c->serializer->check_success (substitute_out->serialize (c->serializer, substitutes))))
+        return_trace (false);
+
+    if (unlikely (!out->coverage.serialize_serialize (c->serializer, glyphs)))
+      return_trace (false);
+    return_trace (true);
+  }
+
   bool subset (hb_subset_context_t *c) const
   {
     TRACE_SUBSET (this);
-    // TODO(subset)
-    return_trace (false);
+    const hb_set_t &glyphset = *c->plan->glyphset_gsub ();
+    const hb_map_t &glyph_map = *c->plan->glyph_map;
+
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
+    const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
+
+    auto it =
+    + hb_zip (this+coverage, substitute)
+    | hb_filter (glyphset, hb_first)
+    | hb_filter (glyphset, hb_second)
+    | hb_map_retains_sorting ([&] (hb_pair_t<hb_codepoint_t, const HBGlyphID &> p) -> hb_codepoint_pair_t
+                              { return hb_pair (glyph_map[p.first], glyph_map[p.second]); })
+    ;
+
+    return_trace (bool (it) && serialize (c, it, backtrack.iter (), lookahead.iter ()));
   }
 
   bool sanitize (hb_sanitize_context_t *c) const
@@ -1262,27 +1360,27 @@ struct ReverseChainSingleSubstFormat1
     TRACE_SANITIZE (this);
     if (!(coverage.sanitize (c, this) && backtrack.sanitize (c, this)))
       return_trace (false);
-    const OffsetArrayOf<Coverage> &lookahead = StructAfter<OffsetArrayOf<Coverage>> (backtrack);
+    const Array16OfOffset16To<Coverage> &lookahead = StructAfter<Array16OfOffset16To<Coverage>> (backtrack);
     if (!lookahead.sanitize (c, this))
       return_trace (false);
-    const ArrayOf<HBGlyphID> &substitute = StructAfter<ArrayOf<HBGlyphID>> (lookahead);
+    const Array16Of<HBGlyphID> &substitute = StructAfter<Array16Of<HBGlyphID>> (lookahead);
     return_trace (substitute.sanitize (c));
   }
 
   protected:
   HBUINT16	format;			/* Format identifier--format = 1 */
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		coverage;		/* Offset to Coverage table--from
 					 * beginning of table */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		backtrack;		/* Array of coverage tables
 					 * in backtracking sequence, in glyph
 					 * sequence order */
-  OffsetArrayOf<Coverage>
+  Array16OfOffset16To<Coverage>
 		lookaheadX;		/* Array of coverage tables
 					 * in lookahead sequence, in glyph
 					 * sequence order */
-  ArrayOf<HBGlyphID>
+  Array16Of<HBGlyphID>
 		substituteX;		/* Array of substitute
 					 * GlyphIDs--ordered by Coverage Index */
   public:
@@ -1388,6 +1486,12 @@ struct SubstLookup : Lookup
     return lookup_type_is_reverse (type);
   }
 
+  bool may_have_non_1to1 () const
+  {
+    hb_have_non_1to1_context_t c;
+    return dispatch (&c);
+  }
+
   bool apply (hb_ot_apply_context_t *c) const
   {
     TRACE_APPLY (this);
@@ -1455,10 +1559,6 @@ struct SubstLookup : Lookup
 
   static inline bool apply_recurse_func (hb_ot_apply_context_t *c, unsigned int lookup_index);
 
-  SubTable& serialize_subtable (hb_serialize_context_t *c,
-				unsigned int i)
-  { return get_subtables<SubTable> ()[i].serialize (c, this); }
-
   bool serialize_single (hb_serialize_context_t *c,
 			 uint32_t lookup_props,
 			 hb_sorted_array_t<const HBGlyphID> glyphs,
@@ -1466,8 +1566,13 @@ struct SubstLookup : Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Single, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.single.
-		  serialize (c, hb_zip (glyphs, substitutes)));
+    if (c->push<SubTable> ()->u.single.serialize (c, hb_zip (glyphs, substitutes)))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
   }
 
   bool serialize_multiple (hb_serialize_context_t *c,
@@ -1478,11 +1583,17 @@ struct SubstLookup : Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Multiple, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.multiple.
-		  serialize (c,
-			     glyphs,
-			     substitute_len_list,
-			     substitute_glyphs_list));
+    if (c->push<SubTable> ()->u.multiple.
+        serialize (c,
+                   glyphs,
+                   substitute_len_list,
+                   substitute_glyphs_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
   }
 
   bool serialize_alternate (hb_serialize_context_t *c,
@@ -1493,11 +1604,18 @@ struct SubstLookup : Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Alternate, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.alternate.
-		  serialize (c,
-			     glyphs,
-			     alternate_len_list,
-			     alternate_glyphs_list));
+
+    if (c->push<SubTable> ()->u.alternate.
+        serialize (c,
+                   glyphs,
+                   alternate_len_list,
+                   alternate_glyphs_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
   }
 
   bool serialize_ligature (hb_serialize_context_t *c,
@@ -1510,24 +1628,32 @@ struct SubstLookup : Lookup
   {
     TRACE_SERIALIZE (this);
     if (unlikely (!Lookup::serialize (c, SubTable::Ligature, lookup_props, 1))) return_trace (false);
-    return_trace (serialize_subtable (c, 0).u.ligature.
-		  serialize (c,
-			     first_glyphs,
-			     ligature_per_first_glyph_count_list,
-			     ligatures_list,
-			     component_count_list,
-			     component_list));
+    if (c->push<SubTable> ()->u.ligature.
+        serialize (c,
+                   first_glyphs,
+                   ligature_per_first_glyph_count_list,
+                   ligatures_list,
+                   component_count_list,
+                   component_list))
+    {
+      c->add_link (get_subtables<SubTable> ()[0], c->pop_pack ());
+      return_trace (true);
+    }
+    c->pop_discard ();
+    return_trace (false);
   }
 
   template <typename context_t>
   static inline typename context_t::return_t dispatch_recurse_func (context_t *c, unsigned int lookup_index);
 
-  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned int lookup_index)
+  static inline typename hb_closure_context_t::return_t closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index);
+
+  static inline hb_closure_context_t::return_t dispatch_closure_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
   {
     if (!c->should_visit_lookup (lookup_index))
       return hb_empty_t ();
 
-    hb_closure_context_t::return_t ret = dispatch_recurse_func (c, lookup_index);
+    hb_closure_context_t::return_t ret = closure_glyphs_recurse_func (c, lookup_index, covered_seq_indices, seq_index, end_index);
 
     /* While in theory we should flush here, it will cause timeouts because a recursive
      * lookup can keep growing the glyph set.  Skip, and outer loop will retry up to
@@ -1564,7 +1690,7 @@ struct GSUB : GSUBGPOS
 
   bool subset (hb_subset_context_t *c) const
   {
-    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_features);
+    hb_subset_layout_context_t l (c, tableTag, c->plan->gsub_lookups, c->plan->gsub_langsys, c->plan->gsub_features);
     return GSUBGPOS::subset<SubstLookup> (&l);
   }
 
@@ -1600,6 +1726,14 @@ template <typename context_t>
   return l.dispatch (c);
 }
 
+/*static*/ typename hb_closure_context_t::return_t SubstLookup::closure_glyphs_recurse_func (hb_closure_context_t *c, unsigned lookup_index, hb_set_t *covered_seq_indices, unsigned seq_index, unsigned end_index)
+{
+  const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (lookup_index);
+  if (l.may_have_non_1to1 ())
+      hb_set_add_range (covered_seq_indices, seq_index, end_index);
+  return l.dispatch (c);
+}
+
 /*static*/ inline hb_closure_lookups_context_t::return_t SubstLookup::dispatch_closure_lookups_recurse_func (hb_closure_lookups_context_t *c, unsigned this_index)
 {
   const SubstLookup &l = c->face->table.GSUB.get_relaxed ()->table->get_lookup (this_index);

File diff suppressed because it is too large
+ 336 - 104
thirdparty/harfbuzz/src/hb-ot-layout-gsubgpos.hh


+ 16 - 16
thirdparty/harfbuzz/src/hb-ot-layout-jstf-table.hh

@@ -45,7 +45,7 @@ typedef IndexArray JstfModList;
  * JstfMax -- Justification Maximum Table
  */
 
-typedef OffsetListOf<PosLookup> JstfMax;
+typedef List16OfOffset16To<PosLookup> JstfMax;
 
 
 /*
@@ -71,43 +71,43 @@ struct JstfPriority
   }
 
   protected:
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageEnableGSUB;	/* Offset to Shrinkage Enable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageDisableGSUB;	/* Offset to Shrinkage Disable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageEnableGPOS;	/* Offset to Shrinkage Enable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		shrinkageDisableGPOS;	/* Offset to Shrinkage Disable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfMax>
+  Offset16To<JstfMax>
 		shrinkageJstfMax;	/* Offset to Shrinkage JstfMax table--
 					 * from beginning of JstfPriority table
 					 * --may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionEnableGSUB;	/* Offset to Extension Enable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionDisableGSUB;	/* Offset to Extension Disable GSUB
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionEnableGPOS;	/* Offset to Extension Enable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfModList>
+  Offset16To<JstfModList>
 		extensionDisableGPOS;	/* Offset to Extension Disable GPOS
 					 * JstfModList table--from beginning of
 					 * JstfPriority table--may be NULL */
-  OffsetTo<JstfMax>
+  Offset16To<JstfMax>
 		extensionJstfMax;	/* Offset to Extension JstfMax table--
 					 * from beginning of JstfPriority table
 					 * --may be NULL */
@@ -121,13 +121,13 @@ struct JstfPriority
  * JstfLangSys -- Justification Language System Table
  */
 
-struct JstfLangSys : OffsetListOf<JstfPriority>
+struct JstfLangSys : List16OfOffset16To<JstfPriority>
 {
   bool sanitize (hb_sanitize_context_t *c,
 		 const Record_sanitize_closure_t * = nullptr) const
   {
     TRACE_SANITIZE (this);
-    return_trace (OffsetListOf<JstfPriority>::sanitize (c));
+    return_trace (List16OfOffset16To<JstfPriority>::sanitize (c));
   }
 };
 
@@ -136,7 +136,7 @@ struct JstfLangSys : OffsetListOf<JstfPriority>
  * ExtenderGlyphs -- Extender Glyph Table
  */
 
-typedef SortedArrayOf<HBGlyphID> ExtenderGlyphs;
+typedef SortedArray16Of<HBGlyphID> ExtenderGlyphs;
 
 
 /*
@@ -174,10 +174,10 @@ struct JstfScript
   }
 
   protected:
-  OffsetTo<ExtenderGlyphs>
+  Offset16To<ExtenderGlyphs>
 		extenderGlyphs;	/* Offset to ExtenderGlyph table--from beginning
 				 * of JstfScript table-may be NULL */
-  OffsetTo<JstfLangSys>
+  Offset16To<JstfLangSys>
 		defaultLangSys;	/* Offset to DefaultJstfLangSys table--from
 				 * beginning of JstfScript table--may be Null */
   RecordArrayOf<JstfLangSys>

+ 117 - 67
thirdparty/harfbuzz/src/hb-ot-layout.cc

@@ -131,7 +131,9 @@ hb_ot_layout_kern (const hb_ot_shape_plan_t *plan,
 
   AAT::hb_aat_apply_context_t c (plan, font, buffer, blob);
 
+  if (!buffer->message (font, "start table kern")) return;
   kern.apply (&c);
+  (void) buffer->message (font, "end table kern");
 }
 #endif
 
@@ -144,7 +146,7 @@ bool
 OT::GDEF::is_blocklisted (hb_blob_t *blob,
 			  hb_face_t *face) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
   /* The ugly business of blocklisting individual fonts' tables happen here!
@@ -331,6 +333,8 @@ hb_ot_layout_get_glyphs_in_class (hb_face_t                  *face,
  *
  * Useful if the client program wishes to cache the list.
  *
+ * Return value: Total number of attachment points for @glyph.
+ *
  **/
 unsigned int
 hb_ot_layout_get_attach_points (hb_face_t      *face,
@@ -357,6 +361,8 @@ hb_ot_layout_get_attach_points (hb_face_t      *face,
  * Fetches a list of the caret positions defined for a ligature glyph in the GDEF
  * table of the font. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of ligature caret positions for @glyph.
+ *
  **/
 unsigned int
 hb_ot_layout_get_ligature_carets (hb_font_t      *font,
@@ -379,7 +385,7 @@ bool
 OT::GSUB::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
   return false;
@@ -389,7 +395,7 @@ bool
 OT::GPOS::is_blocklisted (hb_blob_t *blob HB_UNUSED,
 			  hb_face_t *face HB_UNUSED) const
 {
-#ifdef HB_NO_OT_LAYOUT_BLACKLIST
+#ifdef HB_NO_OT_LAYOUT_BLOCKLIST
   return false;
 #endif
   return false;
@@ -419,6 +425,8 @@ get_gsubgpos_table (hb_face_t *face,
  * Fetches a list of all scripts enumerated in the specified face's GSUB table
  * or GPOS table. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of script tags.
+ *
  **/
 unsigned int
 hb_ot_layout_table_get_script_tags (hb_face_t    *face,
@@ -585,6 +593,8 @@ hb_ot_layout_table_select_script (hb_face_t      *face,
  *
  * Fetches a list of all feature tags in the given face's GSUB or GPOS table.
  *
+ * Return value: Total number of feature tags.
+ *
  **/
 unsigned int
 hb_ot_layout_table_get_feature_tags (hb_face_t    *face,
@@ -647,6 +657,8 @@ hb_ot_layout_table_find_feature (hb_face_t    *face,
  * Fetches a list of language tags in the given face's GSUB or GPOS table, underneath
  * the specified script index. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of language tags.
+ *
  **/
 unsigned int
 hb_ot_layout_script_get_language_tags (hb_face_t    *face,
@@ -818,6 +830,8 @@ hb_ot_layout_language_get_required_feature (hb_face_t    *face,
  * Fetches a list of all features in the specified face's GSUB table
  * or GPOS table, underneath the specified script and language. The list
  * returned will begin at the offset provided.
+ *
+ * Return value: Total number of features.
  **/
 unsigned int
 hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
@@ -850,6 +864,7 @@ hb_ot_layout_language_get_feature_indexes (hb_face_t    *face,
  * or GPOS table, underneath the specified script and language. The list
  * returned will begin at the offset provided.
  *
+ * Return value: Total number of feature tags.
  **/
 unsigned int
 hb_ot_layout_language_get_feature_tags (hb_face_t    *face,
@@ -932,6 +947,8 @@ hb_ot_layout_language_find_feature (hb_face_t    *face,
  * the specified face's GSUB table or GPOS table. The list returned will
  * begin at the offset provided.
  *
+ * Return value: Total number of lookups.
+ *
  * Since: 0.9.7
  **/
 unsigned int
@@ -960,6 +977,8 @@ hb_ot_layout_feature_get_lookups (hb_face_t    *face,
  * Fetches the total number of lookups enumerated in the specified
  * face's GSUB table or GPOS table.
  *
+ * Return value: Total number of lookups.
+ *
  * Since: 0.9.22
  **/
 unsigned int
@@ -974,10 +993,46 @@ struct hb_collect_features_context_t
 {
   hb_collect_features_context_t (hb_face_t *face,
 				 hb_tag_t   table_tag,
-				 hb_set_t  *feature_indexes_)
+				 hb_set_t  *feature_indices_,
+                                 const hb_tag_t *features)
+
     : g (get_gsubgpos_table (face, table_tag)),
-      feature_indexes (feature_indexes_),
-      script_count (0),langsys_count (0), feature_index_count (0) {}
+      feature_indices (feature_indices_),
+      has_feature_filter (false),
+      script_count (0),langsys_count (0), feature_index_count (0)
+  {
+    compute_feature_filter (features);
+  }
+
+  void compute_feature_filter (const hb_tag_t *features)
+  {
+    if (features == nullptr)
+    {
+      has_feature_filter = false;
+      return;
+    }
+
+    has_feature_filter = true;
+    for (; *features; features++)
+    {
+      hb_tag_t tag = *features;
+      unsigned index;
+      g.find_feature_index (tag, &index);
+      if (index == OT::Index::NOT_FOUND_INDEX) continue;
+
+      feature_indices_filter.add(index);
+      for (int i = (int) index - 1; i >= 0; i--)
+      {
+        if (g.get_feature_tag (i) != tag) break;
+        feature_indices_filter.add(i);
+      }
+      for (unsigned i = index + 1; i < g.get_feature_count (); i++)
+      {
+        if (g.get_feature_tag (i) != tag) break;
+        feature_indices_filter.add(i);
+      }
+    }
+  }
 
   bool visited (const OT::Script &s)
   {
@@ -1026,7 +1081,9 @@ struct hb_collect_features_context_t
 
   public:
   const OT::GSUBGPOS &g;
-  hb_set_t           *feature_indexes;
+  hb_set_t *feature_indices;
+  hb_set_t  feature_indices_filter;
+  bool has_feature_filter;
 
   private:
   hb_set_t visited_script;
@@ -1038,37 +1095,31 @@ struct hb_collect_features_context_t
 
 static void
 langsys_collect_features (hb_collect_features_context_t *c,
-			  const OT::LangSys  &l,
-			  const hb_tag_t     *features)
+			  const OT::LangSys  &l)
 {
   if (c->visited (l)) return;
 
-  if (!features)
+  if (!c->has_feature_filter)
   {
     /* All features. */
     if (l.has_required_feature () && !c->visited_feature_indices (1))
-      c->feature_indexes->add (l.get_required_feature_index ());
+      c->feature_indices->add (l.get_required_feature_index ());
 
+    // TODO(garretrieger): filter out indices >= feature count?
     if (!c->visited_feature_indices (l.featureIndex.len))
-      l.add_feature_indexes_to (c->feature_indexes);
+      l.add_feature_indexes_to (c->feature_indices);
   }
   else
   {
-    /* Ugh. Any faster way? */
-    for (; *features; features++)
+    if (c->feature_indices_filter.is_empty()) return;
+    unsigned int num_features = l.get_feature_count ();
+    for (unsigned int i = 0; i < num_features; i++)
     {
-      hb_tag_t feature_tag = *features;
-      unsigned int num_features = l.get_feature_count ();
-      for (unsigned int i = 0; i < num_features; i++)
-      {
-	unsigned int feature_index = l.get_feature_index (i);
+      unsigned int feature_index = l.get_feature_index (i);
+      if (!c->feature_indices_filter.has (feature_index)) continue;
 
-	if (feature_tag == c->g.get_feature_tag (feature_index))
-	{
-	  c->feature_indexes->add (feature_index);
-	  break;
-	}
-      }
+      c->feature_indices->add (feature_index);
+      c->feature_indices_filter.del (feature_index);
     }
   }
 }
@@ -1076,8 +1127,7 @@ langsys_collect_features (hb_collect_features_context_t *c,
 static void
 script_collect_features (hb_collect_features_context_t *c,
 			 const OT::Script   &s,
-			 const hb_tag_t *languages,
-			 const hb_tag_t *features)
+			 const hb_tag_t *languages)
 {
   if (c->visited (s)) return;
 
@@ -1086,14 +1136,13 @@ script_collect_features (hb_collect_features_context_t *c,
     /* All languages. */
     if (s.has_default_lang_sys ())
       langsys_collect_features (c,
-				s.get_default_lang_sys (),
-				features);
+				s.get_default_lang_sys ());
+
 
     unsigned int count = s.get_lang_sys_count ();
     for (unsigned int language_index = 0; language_index < count; language_index++)
       langsys_collect_features (c,
-				s.get_lang_sys (language_index),
-				features);
+				s.get_lang_sys (language_index));
   }
   else
   {
@@ -1102,8 +1151,8 @@ script_collect_features (hb_collect_features_context_t *c,
       unsigned int language_index;
       if (s.find_lang_sys_index (*languages, &language_index))
 	langsys_collect_features (c,
-				  s.get_lang_sys (language_index),
-				  features);
+				  s.get_lang_sys (language_index));
+
     }
   }
 }
@@ -1134,7 +1183,7 @@ hb_ot_layout_collect_features (hb_face_t      *face,
 			       const hb_tag_t *features,
 			       hb_set_t       *feature_indexes /* OUT */)
 {
-  hb_collect_features_context_t c (face, table_tag, feature_indexes);
+  hb_collect_features_context_t c (face, table_tag, feature_indexes, features);
   if (!scripts)
   {
     /* All scripts. */
@@ -1142,8 +1191,7 @@ hb_ot_layout_collect_features (hb_face_t      *face,
     for (unsigned int script_index = 0; script_index < count; script_index++)
       script_collect_features (&c,
 			       c.g.get_script (script_index),
-			       languages,
-			       features);
+			       languages);
   }
   else
   {
@@ -1153,8 +1201,7 @@ hb_ot_layout_collect_features (hb_face_t      *face,
       if (c.g.find_script_index (*scripts, &script_index))
 	script_collect_features (&c,
 				 c.g.get_script (script_index),
-				 languages,
-				 features);
+				 languages);
     }
   }
 }
@@ -1262,6 +1309,8 @@ hb_ot_layout_lookup_collect_glyphs (hb_face_t    *face,
  * Fetches a list of feature variations in the specified face's GSUB table
  * or GPOS table, at the specified variation coordinates.
  *
+ * Return value: %true if feature variations were found, %false otherwise.
+ *
  **/
 hb_bool_t
 hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
@@ -1291,6 +1340,8 @@ hb_ot_layout_table_find_feature_variations (hb_face_t    *face,
  * the specified face's GSUB table or GPOS table, enabled at the specified
  * variations index. The list returned will begin at the offset provided.
  *
+ * Return value: Total number of lookups.
+ *
  **/
 unsigned int
 hb_ot_layout_feature_with_variations_get_lookups (hb_face_t    *face,
@@ -1337,7 +1388,8 @@ hb_ot_layout_has_substitution (hb_face_t *face)
  * @lookup_index: The index of the lookup to query
  * @glyphs: The sequence of glyphs to query for substitution
  * @glyphs_length: The length of the glyph sequence
- * @zero_context: #hb_bool_t indicating whether substitutions should be context-free
+ * @zero_context: #hb_bool_t indicating whether pre-/post-context are disallowed
+ * in substitutions
  *
  * Tests whether a specified lookup in the specified face would
  * trigger a substitution on the given glyph sequence.
@@ -1443,12 +1495,17 @@ hb_ot_layout_lookup_substitute_closure (hb_face_t    *face,
 					unsigned int  lookup_index,
 					hb_set_t     *glyphs /* OUT */)
 {
-  hb_map_t done_lookups;
-  OT::hb_closure_context_t c (face, glyphs, &done_lookups);
+  hb_set_t cur_intersected_glyphs;
+  hb_map_t done_lookups_glyph_count;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
+  OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
 
   const OT::SubstLookup& l = face->table.GSUB->table->get_lookup (lookup_index);
 
   l.closure (&c, lookup_index);
+
+  for (auto _ : done_lookups_glyph_set.iter ())
+    hb_set_destroy (_.second);
 }
 
 /**
@@ -1467,8 +1524,10 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
 					 const hb_set_t *lookups,
 					 hb_set_t       *glyphs /* OUT */)
 {
-  hb_map_t done_lookups;
-  OT::hb_closure_context_t c (face, glyphs, &done_lookups);
+  hb_set_t cur_intersected_glyphs;
+  hb_map_t done_lookups_glyph_count;
+  hb_hashmap_t<unsigned, hb_set_t *, (unsigned)-1, nullptr> done_lookups_glyph_set;
+  OT::hb_closure_context_t c (face, glyphs, &cur_intersected_glyphs, &done_lookups_glyph_count, &done_lookups_glyph_set);
   const OT::GSUB& gsub = *face->table.GSUB->table;
 
   unsigned int iteration_count = 0;
@@ -1488,6 +1547,9 @@ hb_ot_layout_lookups_substitute_closure (hb_face_t      *face,
     }
   } while (iteration_count++ <= HB_CLOSURE_MAX_STAGES &&
 	   glyphs_length != glyphs->get_population ());
+
+  for (auto _ : done_lookups_glyph_set.iter ())
+    hb_set_destroy (_.second);
 }
 
 /*
@@ -1824,27 +1886,20 @@ apply_string (OT::hb_ot_apply_context_t *c,
   if (likely (!lookup.is_reverse ()))
   {
     /* in/out forward substitution/positioning */
-    if (Proxy::table_index == 0u)
+    if (!Proxy::inplace)
       buffer->clear_output ();
+
     buffer->idx = 0;
+    apply_forward (c, accel);
 
-    bool ret;
-    ret = apply_forward (c, accel);
-    if (ret)
-    {
-      if (!Proxy::inplace)
-	buffer->swap_buffers ();
-      else
-	assert (!buffer->has_separate_output ());
-    }
+    if (!Proxy::inplace)
+      buffer->swap_buffers ();
   }
   else
   {
     /* in-place backward substitution/positioning */
-    if (Proxy::table_index == 0u)
-      buffer->remove_output ();
+    assert (!buffer->have_output);
     buffer->idx = buffer->len - 1;
-
     apply_backward (c, accel);
   }
 }
@@ -1860,7 +1915,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
   OT::hb_ot_apply_context_t c (table_index, font, buffer);
   c.set_recurse_func (Proxy::Lookup::apply_recurse_func);
 
-  for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++) {
+  for (unsigned int stage_index = 0; stage_index < stages[table_index].length; stage_index++)
+  {
     const stage_map_t *stage = &stages[table_index][stage_index];
     for (; i < stage->last_lookup; i++)
     {
@@ -1870,11 +1926,8 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
       c.set_lookup_mask (lookups[table_index][i].mask);
       c.set_auto_zwj (lookups[table_index][i].auto_zwj);
       c.set_auto_zwnj (lookups[table_index][i].auto_zwnj);
-      if (lookups[table_index][i].random)
-      {
-	c.set_random (true);
-	buffer->unsafe_to_break_all ();
-      }
+      c.set_random (lookups[table_index][i].random);
+
       apply_string<Proxy> (&c,
 			   proxy.table.get_lookup (lookup_index),
 			   proxy.accels[lookup_index]);
@@ -1882,10 +1935,7 @@ inline void hb_ot_map_t::apply (const Proxy &proxy,
     }
 
     if (stage->pause_func)
-    {
-      buffer->clear_output ();
       stage->pause_func (plan, font, buffer);
-    }
   }
 }
 
@@ -1925,7 +1975,7 @@ hb_ot_layout_substitute_lookup (OT::hb_ot_apply_context_t *c,
  *
  * Fetches a baseline value from the face.
  *
- * Return value: if found baseline value in the font.
+ * Return value: %true if found baseline value in the font.
  *
  * Since: 2.6.0
  **/
@@ -1984,7 +2034,7 @@ struct hb_get_glyph_alternates_dispatch_t :
  *
  * Fetches alternates of a glyph from a given GSUB lookup index.
  *
- * Return value: total number of alternates found in the specific lookup index for the given glyph id.
+ * Return value: Total number of alternates found in the specific lookup index for the given glyph id.
  *
  * Since: 2.6.8
  **/

+ 1 - 2
thirdparty/harfbuzz/src/hb-ot-layout.hh

@@ -314,7 +314,6 @@ _hb_glyph_info_get_unicode_space_fallback_type (const hb_glyph_info_t *info)
 	 hb_unicode_funcs_t::NOT_SPACE;
 }
 
-static inline bool _hb_glyph_info_ligated (const hb_glyph_info_t *info);
 static inline bool _hb_glyph_info_substituted (const hb_glyph_info_t *info);
 
 static inline bool
@@ -328,7 +327,7 @@ _hb_glyph_info_is_default_ignorable_and_not_hidden (const hb_glyph_info_t *info)
 {
   return ((info->unicode_props() & (UPROPS_MASK_IGNORABLE|UPROPS_MASK_HIDDEN))
 	  == UPROPS_MASK_IGNORABLE) &&
-	 !_hb_glyph_info_ligated (info);
+	 !_hb_glyph_info_substituted (info);
 }
 static inline void
 _hb_glyph_info_unhide (hb_glyph_info_t *info)

+ 25 - 11
thirdparty/harfbuzz/src/hb-ot-map.cc

@@ -54,7 +54,6 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
   face = face_;
   props = *props_;
 
-
   /* Fetch script/language indices for GSUB/GPOS.  We need these later to skip
    * features not available in either table and not waste precious bits for them. */
 
@@ -63,12 +62,28 @@ hb_ot_map_builder_t::hb_ot_map_builder_t (hb_face_t *face_,
   hb_tag_t script_tags[HB_OT_MAX_TAGS_PER_SCRIPT];
   hb_tag_t language_tags[HB_OT_MAX_TAGS_PER_LANGUAGE];
 
-  hb_ot_tags_from_script_and_language (props.script, props.language, &script_count, script_tags, &language_count, language_tags);
+  hb_ot_tags_from_script_and_language (props.script,
+				       props.language,
+				       &script_count,
+				       script_tags,
+				       &language_count,
+				       language_tags);
 
-  for (unsigned int table_index = 0; table_index < 2; table_index++) {
+  for (unsigned int table_index = 0; table_index < 2; table_index++)
+  {
     hb_tag_t table_tag = table_tags[table_index];
-    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face, table_tag, script_count, script_tags, &script_index[table_index], &chosen_script[table_index]);
-    hb_ot_layout_script_select_language (face, table_tag, script_index[table_index], language_count, language_tags, &language_index[table_index]);
+    found_script[table_index] = (bool) hb_ot_layout_table_select_script (face,
+									 table_tag,
+									 script_count,
+									 script_tags,
+									 &script_index[table_index],
+									 &chosen_script[table_index]);
+    hb_ot_layout_script_select_language (face,
+					 table_tag,
+					 script_index[table_index],
+					 language_count,
+					 language_tags,
+					 &language_index[table_index]);
   }
 }
 
@@ -150,9 +165,8 @@ void
 hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
 			      const hb_ot_shape_plan_key_t &key)
 {
-  static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
-  unsigned int global_bit_mask = HB_GLYPH_FLAG_DEFINED + 1;
-  unsigned int global_bit_shift = hb_popcount (HB_GLYPH_FLAG_DEFINED);
+  unsigned int global_bit_shift = 8 * sizeof (hb_mask_t) - 1;
+  unsigned int global_bit_mask = 1u << global_bit_shift;
 
   m.global_mask = global_bit_mask;
 
@@ -205,7 +219,8 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
 
 
   /* Allocate bits now */
-  unsigned int next_bit = global_bit_shift + 1;
+  static_assert ((!(HB_GLYPH_FLAG_DEFINED & (HB_GLYPH_FLAG_DEFINED + 1))), "");
+  unsigned int next_bit = hb_popcount (HB_GLYPH_FLAG_DEFINED) + 1;
 
   for (unsigned int i = 0; i < feature_infos.length; i++)
   {
@@ -220,7 +235,7 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
       /* Limit bits per feature. */
       bits_needed = hb_min (HB_OT_MAP_MAX_BITS, hb_bit_storage (info->max_value));
 
-    if (!info->max_value || next_bit + bits_needed > 8 * sizeof (hb_mask_t))
+    if (!info->max_value || next_bit + bits_needed >= global_bit_shift)
       continue; /* Feature disabled, or not enough bits. */
 
 
@@ -274,7 +289,6 @@ hb_ot_map_builder_t::compile (hb_ot_map_t                  &m,
     }
     map->_1_mask = (1u << map->shift) & map->mask;
     map->needs_fallback = !found;
-
   }
   feature_infos.shrink (0); /* Done with these */
 

+ 22 - 22
thirdparty/harfbuzz/src/hb-ot-math-table.hh

@@ -49,7 +49,7 @@ struct MathValueRecord
 
   protected:
   HBINT16		value;		/* The X or Y value in design units */
-  OffsetTo<Device>	deviceTable;	/* Offset to the device table - from the
+  Offset16To<Device>	deviceTable;	/* Offset to the device table - from the
 					 * beginning of parent table.  May be NULL.
 					 * Suggested format for device table is 1. */
 
@@ -181,11 +181,11 @@ struct MathItalicsCorrectionInfo
   }
 
   protected:
-  OffsetTo<Coverage>       coverage;		/* Offset to Coverage table -
+  Offset16To<Coverage>       coverage;		/* Offset to Coverage table -
 						 * from the beginning of
 						 * MathItalicsCorrectionInfo
 						 * table. */
-  ArrayOf<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
+  Array16Of<MathValueRecord> italicsCorrection;	/* Array of MathValueRecords
 						 * defining italics correction
 						 * values for each
 						 * covered glyph. */
@@ -214,11 +214,11 @@ struct MathTopAccentAttachment
   }
 
   protected:
-  OffsetTo<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
+  Offset16To<Coverage>       topAccentCoverage;   /* Offset to Coverage table -
 						 * from the beginning of
 						 * MathTopAccentAttachment
 						 * table. */
-  ArrayOf<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
+  Array16Of<MathValueRecord> topAccentAttachment; /* Array of MathValueRecords
 						 * defining top accent
 						 * attachment points for each
 						 * covered glyph. */
@@ -320,7 +320,7 @@ struct MathKernInfoRecord
   protected:
   /* Offset to MathKern table for each corner -
    * from the beginning of MathKernInfo table.  May be NULL. */
-  OffsetTo<MathKern> mathKern[4];
+  Offset16To<MathKern> mathKern[4];
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -346,12 +346,12 @@ struct MathKernInfo
   }
 
   protected:
-  OffsetTo<Coverage>
+  Offset16To<Coverage>
 		mathKernCoverage;
 				/* Offset to Coverage table -
 				 * from the beginning of the
 				 * MathKernInfo table. */
-  ArrayOf<MathKernInfoRecord>
+  Array16Of<MathKernInfoRecord>
 		mathKernInfoRecords;
 				/* Array of MathKernInfoRecords,
 				 * per-glyph information for
@@ -395,22 +395,22 @@ struct MathGlyphInfo
   protected:
   /* Offset to MathItalicsCorrectionInfo table -
    * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
+  Offset16To<MathItalicsCorrectionInfo> mathItalicsCorrectionInfo;
 
   /* Offset to MathTopAccentAttachment table -
    * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathTopAccentAttachment> mathTopAccentAttachment;
+  Offset16To<MathTopAccentAttachment> mathTopAccentAttachment;
 
   /* Offset to coverage table for Extended Shape glyphs -
    * from the beginning of MathGlyphInfo table. When the left or right glyph of
    * a box is an extended shape variant, the (ink) box (and not the default
    * position defined by values in MathConstants table) should be used for
    * vertical positioning purposes.  May be NULL.. */
-  OffsetTo<Coverage> extendedShapeCoverage;
+  Offset16To<Coverage> extendedShapeCoverage;
 
    /* Offset to MathKernInfo table -
     * from the beginning of MathGlyphInfo table. */
-  OffsetTo<MathKernInfo> mathKernInfo;
+  Offset16To<MathKernInfo> mathKernInfo;
 
   public:
   DEFINE_SIZE_STATIC (8);
@@ -532,7 +532,7 @@ struct MathGlyphAssembly
 				/* Italics correction of this
 				 * MathGlyphAssembly. Should not
 				 * depend on the assembly size. */
-  ArrayOf<MathGlyphPartRecord>
+  Array16Of<MathGlyphPartRecord>
 		partRecords;	/* Array of part records, from
 				 * left to right and bottom to
 				 * top. */
@@ -572,10 +572,10 @@ struct MathGlyphConstruction
   protected:
   /* Offset to MathGlyphAssembly table for this shape - from the beginning of
      MathGlyphConstruction table.  May be NULL. */
-  OffsetTo<MathGlyphAssembly>	  glyphAssembly;
+  Offset16To<MathGlyphAssembly>	  glyphAssembly;
 
   /* MathGlyphVariantRecords for alternative variants of the glyphs. */
-  ArrayOf<MathGlyphVariantRecord> mathGlyphVariantRecord;
+  Array16Of<MathGlyphVariantRecord> mathGlyphVariantRecord;
 
   public:
   DEFINE_SIZE_ARRAY (4, mathGlyphVariantRecord);
@@ -636,7 +636,7 @@ struct MathVariants
   {
     bool vertical = HB_DIRECTION_IS_VERTICAL (direction);
     unsigned int count = vertical ? vertGlyphCount : horizGlyphCount;
-    const OffsetTo<Coverage> &coverage = vertical ? vertGlyphCoverage
+    const Offset16To<Coverage> &coverage = vertical ? vertGlyphCoverage
 						  : horizGlyphCoverage;
 
     unsigned int index = (this+coverage).get_coverage (glyph);
@@ -653,11 +653,11 @@ struct MathVariants
 				/* Minimum overlap of connecting
 				 * glyphs during glyph construction,
 				 * in design units. */
-  OffsetTo<Coverage> vertGlyphCoverage;
+  Offset16To<Coverage> vertGlyphCoverage;
 				/* Offset to Coverage table -
 				 * from the beginning of MathVariants
 				 * table. */
-  OffsetTo<Coverage> horizGlyphCoverage;
+  Offset16To<Coverage> horizGlyphCoverage;
 				/* Offset to Coverage table -
 				 * from the beginning of MathVariants
 				 * table. */
@@ -671,7 +671,7 @@ struct MathVariants
   /* Array of offsets to MathGlyphConstruction tables - from the beginning of
      the MathVariants table, for shapes growing in vertical/horizontal
      direction. */
-  UnsizedArrayOf<OffsetTo<MathGlyphConstruction>>
+  UnsizedArrayOf<Offset16To<MathGlyphConstruction>>
 			glyphConstruction;
 
   public:
@@ -711,11 +711,11 @@ struct MATH
   protected:
   FixedVersion<>version;	/* Version of the MATH table
 				 * initially set to 0x00010000u */
-  OffsetTo<MathConstants>
+  Offset16To<MathConstants>
 		mathConstants;	/* MathConstants table */
-  OffsetTo<MathGlyphInfo>
+  Offset16To<MathGlyphInfo>
 		mathGlyphInfo;	/* MathGlyphInfo table */
-  OffsetTo<MathVariants>
+  Offset16To<MathVariants>
 		mathVariants;	/* MathVariants table */
 
   public:

+ 1 - 1
thirdparty/harfbuzz/src/hb-ot-maxp-table.hh

@@ -107,7 +107,7 @@ struct maxp
       maxpV1Tail *dest_v1 = c->serializer->embed<maxpV1Tail> (src_v1);
       if (unlikely (!dest_v1)) return_trace (false);
 
-      if (c->plan->drop_hints)
+      if (c->plan->flags & HB_SUBSET_FLAGS_NO_HINTING)
 	drop_hint_fields (dest_v1);
     }
 

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-meta-table.hh

@@ -56,7 +56,7 @@ struct DataMap
 
   protected:
   Tag		tag;		/* A tag indicating the type of metadata. */
-  LNNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset32To<UnsizedArrayOf<HBUINT8>>
 		dataZ;		/* Offset in bytes from the beginning of the
 				 * metadata table to the data for this tag. */
   HBUINT32	dataLength;	/* Length of the data. The data is not required to
@@ -113,7 +113,7 @@ struct meta
 				 * Offset from the beginning of the table to the data.
 				 * Per OT specification:
 				 * Reserved. Not used; should be set to 0. */
-  LArrayOf<DataMap>
+  Array32Of<DataMap>
 		dataMaps;/* Array of data map records. */
   public:
   DEFINE_SIZE_ARRAY (16, dataMaps);

+ 11 - 6
thirdparty/harfbuzz/src/hb-ot-name-table.hh

@@ -149,7 +149,7 @@ struct NameRecord
   HBUINT16	languageID;	/* Language ID. */
   HBUINT16	nameID;		/* Name ID. */
   HBUINT16	length;		/* String length (in bytes). */
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  NNOffset16To<UnsizedArrayOf<HBUINT8>>
 		offset;		/* String offset from start of storage area (in bytes). */
   public:
   DEFINE_SIZE_STATIC (12);
@@ -214,7 +214,7 @@ struct name
     this->format = 0;
     this->count = it.len ();
 
-    NameRecord *name_records = (NameRecord *) calloc (it.len (), NameRecord::static_size);
+    NameRecord *name_records = (NameRecord *) hb_calloc (it.len (), NameRecord::static_size);
     if (unlikely (!name_records)) return_trace (false);
 
     hb_array_t<NameRecord> records (name_records, it.len ());
@@ -228,9 +228,10 @@ struct name
     records.qsort ();
 
     c->copy_all (records, src_string_pool);
-    free (records.arrayZ);
+    hb_free (records.arrayZ);
 
-    if (unlikely (c->ran_out_of_room)) return_trace (false);
+
+    if (unlikely (c->ran_out_of_room ())) return_trace (false);
 
     this->stringOffset = c->length ();
 
@@ -248,7 +249,11 @@ struct name
     + 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->name_legacy || namerecord.isUnicode (); })
+    | hb_filter ([&] (const NameRecord& namerecord) {
+      return
+          (c->plan->flags & HB_SUBSET_FLAGS_NAME_LEGACY)
+          || namerecord.isUnicode ();
+    })
     ;
 
     name_prime->serialize (c->serializer, it, hb_addressof (this + stringOffset));
@@ -357,7 +362,7 @@ struct name
   /* We only implement format 0 for now. */
   HBUINT16	format;		/* Format selector (=0/1). */
   HBUINT16	count;		/* Number of name records. */
-  NNOffsetTo<UnsizedArrayOf<HBUINT8>>
+  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. */

+ 6 - 3
thirdparty/harfbuzz/src/hb-ot-name.cc

@@ -156,7 +156,8 @@ hb_ot_name_get_utf (hb_face_t       *face,
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-8 encoding.
+ * Returns string in UTF-8 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -183,7 +184,8 @@ hb_ot_name_get_utf8 (hb_face_t       *face,
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-16 encoding.
+ * Returns string in UTF-16 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0
@@ -209,7 +211,8 @@ hb_ot_name_get_utf16 (hb_face_t       *face,
  *
  * Fetches a font name from the OpenType 'name' table.
  * If @language is #HB_LANGUAGE_INVALID, English ("en") is assumed.
- * Returns string in UTF-32 encoding.
+ * Returns string in UTF-32 encoding. A NUL terminator is always written
+ * for convenience, and isn't included in the output @text_size.
  *
  * Returns: full length of the requested string, or 0 if not found.
  * Since: 2.1.0

+ 4 - 21
thirdparty/harfbuzz/src/hb-ot-os2-table.hh

@@ -30,7 +30,6 @@
 
 #include "hb-open-type.hh"
 #include "hb-ot-os2-unicode-ranges.hh"
-#include "hb-ot-cmap-table.hh"
 
 #include "hb-set.hh"
 
@@ -172,33 +171,17 @@ struct OS2
     TRACE_SUBSET (this);
     OS2 *os2_prime = c->serializer->embed (this);
     if (unlikely (!os2_prime)) return_trace (false);
+    if (c->plan->flags & HB_SUBSET_FLAGS_NO_PRUNE_UNICODE_RANGES)
+      return_trace (true);
 
-    hb_set_t unicodes;
-    if (!c->plan->glyphs_requested->is_empty ())
-    {
-      hb_map_t unicode_glyphid_map;
-
-      OT::cmap::accelerator_t cmap;
-      cmap.init (c->plan->source);
-      cmap.collect_mapping (&unicodes, &unicode_glyphid_map);
-      cmap.fini ();
-
-      hb_set_set (&unicodes, c->plan->unicodes);
-
-      + unicode_glyphid_map.iter ()
-      | hb_filter (c->plan->glyphs_requested, hb_second)
-      | hb_map (hb_first)
-      | hb_sink (unicodes)
-      ;
-    }
     /* when --gids option is not used, no need to do collect_mapping that is
        * iterating all codepoints in each subtable, which is not efficient */
     uint16_t min_cp, max_cp;
-    find_min_and_max_codepoint (unicodes.is_empty () ? c->plan->unicodes : &unicodes, &min_cp, &max_cp);
+    find_min_and_max_codepoint (c->plan->unicodes, &min_cp, &max_cp);
     os2_prime->usFirstCharIndex = min_cp;
     os2_prime->usLastCharIndex = max_cp;
 
-    _update_unicode_ranges (unicodes.is_empty () ? c->plan->unicodes : &unicodes, os2_prime->ulUnicodeRange);
+    _update_unicode_ranges (c->plan->unicodes, os2_prime->ulUnicodeRange);
 
     return_trace (true);
   }

+ 130 - 0
thirdparty/harfbuzz/src/hb-ot-post-table-v2subset.hh

@@ -0,0 +1,130 @@
+/*
+ * Copyright © 2021  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.
+ *
+ */
+
+#ifndef HB_OT_POST_TABLE_V2SUBSET_HH
+#define HB_OT_POST_TABLE_V2SUBSET_HH
+
+#include "hb-open-type.hh"
+#include "hb-ot-post-table.hh"
+
+/*
+ * post -- PostScript
+ * https://docs.microsoft.com/en-us/typography/opentype/spec/post
+ */
+
+namespace OT {
+template<typename Iterator>
+HB_INTERNAL bool postV2Tail::serialize (hb_serialize_context_t *c,
+                                        Iterator it,
+                                        const void* _post) const
+{
+  TRACE_SERIALIZE (this);
+  auto *out = c->start_embed (this);
+  if (unlikely (!c->check_success (out))) return_trace (false);
+  if (!out->glyphNameIndex.serialize (c, + it
+                                         | hb_map (hb_second)))
+      return_trace (false);
+
+  hb_set_t copied_indices;
+  for (const auto& _ : + it )
+  {
+    unsigned glyph_id = _.first;
+    unsigned new_index = _.second;
+    
+    if (new_index < 258) continue;
+    if (copied_indices.has (new_index)) continue;
+    copied_indices.add (new_index);
+    
+    hb_bytes_t s = reinterpret_cast<const post::accelerator_t*> (_post)->find_glyph_name (glyph_id);
+    HBUINT8 *o = c->allocate_size<HBUINT8> (HBUINT8::static_size * (s.length + 1));
+    if (unlikely (!o)) return_trace (false);
+    if (!c->check_assign (o[0], s.length, HB_SERIALIZE_ERROR_INT_OVERFLOW)) return_trace (false);
+    memcpy (o+1, s.arrayZ, HBUINT8::static_size * s.length);
+  }
+
+  return_trace (true);
+}
+
+HB_INTERNAL bool postV2Tail::subset (hb_subset_context_t *c) const
+{
+  TRACE_SUBSET (this);
+
+  const hb_map_t &reverse_glyph_map = *c->plan->reverse_glyph_map;
+  unsigned num_glyphs = c->plan->num_output_glyphs ();
+  hb_map_t old_new_index_map, old_gid_new_index_map;
+  unsigned i = 0;
+
+  post::accelerator_t _post;
+  _post.init (c->plan->source);
+
+  for (hb_codepoint_t new_gid = 0; new_gid < num_glyphs; new_gid++)
+  {
+    hb_codepoint_t old_gid = reverse_glyph_map.get (new_gid);
+    unsigned old_index = glyphNameIndex[old_gid];
+
+    unsigned new_index;
+    if (old_index <= 257) new_index = old_index;
+    else if (old_new_index_map.has (old_index)) new_index = old_new_index_map.get (old_index);
+    else
+    {
+      hb_bytes_t s = _post.find_glyph_name (old_gid);
+      int standard_glyph_index = -1;
+      for (unsigned i = 0; i < format1_names_length; i++)
+      {
+        if (s == format1_names (i))
+        {
+          standard_glyph_index = i;
+          break;
+        }
+      }
+      if (standard_glyph_index == -1)
+      {
+        new_index = 258 + i;
+        i++;
+      }
+      else
+      { new_index = standard_glyph_index; }
+      old_new_index_map.set (old_index, new_index);
+    }
+    old_gid_new_index_map.set (old_gid, new_index);
+  }
+
+  auto index_iter =
+  + hb_range (num_glyphs)
+  | hb_map (reverse_glyph_map)
+  | hb_map_retains_sorting ([&](hb_codepoint_t old_gid)
+                            {
+                              unsigned new_index = old_gid_new_index_map.get (old_gid);
+                              return hb_pair_t<unsigned, unsigned> (old_gid, new_index);
+                            })
+  ;
+
+  bool ret = serialize (c->serializer, index_iter, &_post);
+  _post.fini ();
+  return_trace (ret);
+}
+
+} /* namespace OT */
+#endif /* HB_OT_POST_TABLE_V2SUBSET_HH */

+ 27 - 9
thirdparty/harfbuzz/src/hb-ot-post-table.hh

@@ -55,8 +55,15 @@ struct postV2Tail
     return_trace (glyphNameIndex.sanitize (c));
   }
 
+  template<typename Iterator>
+  bool serialize (hb_serialize_context_t *c,
+                  Iterator it,
+                  const void* _post) const;
+
+  bool subset (hb_subset_context_t *c) const;
+
   protected:
-  ArrayOf<HBUINT16>	glyphNameIndex;	/* This is not an offset, but is the
+  Array16Of<HBUINT16>	glyphNameIndex;	/* This is not an offset, but is the
 					 * ordinal number of the glyph in 'post'
 					 * string tables. */
 /*UnsizedArrayOf<HBUINT8>
@@ -71,13 +78,18 @@ struct post
 {
   static constexpr hb_tag_t tableTag = HB_OT_TAG_post;
 
-  void serialize (hb_serialize_context_t *c) const
+  bool serialize (hb_serialize_context_t *c, bool glyph_names) const
   {
+    TRACE_SERIALIZE (this);
     post *post_prime = c->allocate_min<post> ();
-    if (unlikely (!post_prime))  return;
+    if (unlikely (!post_prime))  return_trace (false);
 
     memcpy (post_prime, this, post::min_size);
-    post_prime->version.major = 3; // Version 3 does not have any glyph names.
+    if (!glyph_names)
+      return_trace (c->check_assign (post_prime->version.major, 3,
+                                     HB_SERIALIZE_ERROR_INT_OVERFLOW)); // Version 3 does not have any glyph names.
+
+    return_trace (true);
   }
 
   bool subset (hb_subset_context_t *c) const
@@ -86,13 +98,19 @@ struct post
     post *post_prime = c->serializer->start_embed<post> ();
     if (unlikely (!post_prime)) return_trace (false);
 
-    serialize (c->serializer);
+    bool glyph_names = c->plan->flags & HB_SUBSET_FLAGS_GLYPH_NAMES;
+    if (!serialize (c->serializer, glyph_names))
+      return_trace (false);
+
+    if (glyph_names && version.major == 2)
+      return_trace (v2X.subset (c));
 
     return_trace (true);
   }
 
   struct accelerator_t
   {
+    friend struct postV2Tail;
     void init (hb_face_t *face)
     {
       index_to_offset.init ();
@@ -117,7 +135,7 @@ struct post
     void fini ()
     {
       index_to_offset.fini ();
-      free (gids_sorted_by_name.get ());
+      hb_free (gids_sorted_by_name.get ());
       table.destroy ();
     }
 
@@ -148,7 +166,7 @@ struct post
 
       if (unlikely (!gids))
       {
-	gids = (uint16_t *) malloc (count * sizeof (gids[0]));
+	gids = (uint16_t *) hb_malloc (count * sizeof (gids[0]));
 	if (unlikely (!gids))
 	  return false; /* Anything better?! */
 
@@ -158,7 +176,7 @@ struct post
 
 	if (unlikely (!gids_sorted_by_name.cmpexch (nullptr, gids)))
 	{
-	  free (gids);
+	  hb_free (gids);
 	  goto retry;
 	}
       }
@@ -236,7 +254,7 @@ struct post
 
     private:
     uint32_t version;
-    const ArrayOf<HBUINT16> *glyphNameIndex;
+    const Array16Of<HBUINT16> *glyphNameIndex;
     hb_vector_t<uint32_t> index_to_offset;
     const uint8_t *pool;
     hb_atomic_ptr_t<uint16_t *> gids_sorted_by_name;

+ 6 - 6
thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-fallback.hh

@@ -208,11 +208,11 @@ struct ManifestLookup
 {
   public:
   OT::Tag tag;
-  OT::OffsetTo<OT::SubstLookup> lookupOffset;
+  OT::Offset16To<OT::SubstLookup> lookupOffset;
   public:
   DEFINE_SIZE_STATIC (6);
 };
-typedef OT::ArrayOf<ManifestLookup> Manifest;
+typedef OT::Array16Of<ManifestLookup> Manifest;
 
 static bool
 arabic_fallback_plan_init_win1256 (arabic_fallback_plan_t *fallback_plan HB_UNUSED,
@@ -290,7 +290,7 @@ static arabic_fallback_plan_t *
 arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
 			     hb_font_t *font)
 {
-  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) calloc (1, sizeof (arabic_fallback_plan_t));
+  arabic_fallback_plan_t *fallback_plan = (arabic_fallback_plan_t *) hb_calloc (1, sizeof (arabic_fallback_plan_t));
   if (unlikely (!fallback_plan))
     return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 
@@ -308,7 +308,7 @@ arabic_fallback_plan_create (const hb_ot_shape_plan_t *plan,
     return fallback_plan;
 
   assert (fallback_plan->num_lookups == 0);
-  free (fallback_plan);
+  hb_free (fallback_plan);
   return const_cast<arabic_fallback_plan_t *> (&Null (arabic_fallback_plan_t));
 }
 
@@ -323,10 +323,10 @@ arabic_fallback_plan_destroy (arabic_fallback_plan_t *fallback_plan)
     {
       fallback_plan->accel_array[i].fini ();
       if (fallback_plan->free_lookups)
-	free (fallback_plan->lookup_array[i]);
+	hb_free (fallback_plan->lookup_array[i]);
     }
 
-  free (fallback_plan);
+  hb_free (fallback_plan);
 }
 
 static void

+ 5 - 4
thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-joining-list.hh

@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-13.0.0.txt
- * # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
- * # Scripts-13.0.0.txt
- * # Date: 2020-01-22, 00:07:43 GMT
+ * # ArabicShaping-14.0.0.txt
+ * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
+ * # Scripts-14.0.0.txt
+ * # Date: 2021-07-10, 00:35:31 GMT
  */
 
 #ifndef HB_OT_SHAPE_COMPLEX_ARABIC_JOINING_LIST_HH
@@ -29,6 +29,7 @@ has_arabic_joining (hb_script_t script)
     case HB_SCRIPT_MANICHAEAN:
     case HB_SCRIPT_MONGOLIAN:
     case HB_SCRIPT_NKO:
+    case HB_SCRIPT_OLD_UYGHUR:
     case HB_SCRIPT_PHAGS_PA:
     case HB_SCRIPT_PSALTER_PAHLAVI:
     case HB_SCRIPT_SOGDIAN:

+ 23 - 15
thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic-table.hh

@@ -6,10 +6,10 @@
  *
  * on files with these headers:
  *
- * # ArabicShaping-13.0.0.txt
- * # Date: 2020-01-31, 23:55:00 GMT [KW, RP]
- * # Blocks-13.0.0.txt
- * # Date: 2019-07-10, 19:06:00 GMT [KW]
+ * # ArabicShaping-14.0.0.txt
+ * # Date: 2021-05-21, 01:54:00 GMT [KW, RP]
+ * # Blocks-14.0.0.txt
+ * # Date: 2021-01-22, 23:29:00 GMT [KW]
  * UnicodeData.txt does not have a header.
  */
 
@@ -75,13 +75,17 @@ static const uint8_t joining_table[] =
 
   /* Syriac Supplement */
 
-  /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
-  /* 0880 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 0860 */ D,U,D,D,D,D,U,R,D,R,R,X,X,X,X,X,
+
+  /* Arabic Extended-B */
+
+  /* 0860 */                                 R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,R,
+  /* 0880 */ R,R,R,C,C,C,D,U,U,D,D,D,D,D,R,X,U,U,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
   /* Arabic Extended-A */
 
-  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,X,D,D,D,R,D,D,D,D,D,D,
-  /* 08C0 */ D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 08A0 */ D,D,D,D,D,D,D,D,D,D,R,R,R,U,R,D,D,R,R,D,D,D,D,D,D,R,D,D,D,D,D,D,
+  /* 08C0 */ D,D,D,D,D,D,D,D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
   /* 08E0 */ X,X,U,
 
 #define joining_offset_0x1806u 739
@@ -137,23 +141,28 @@ static const uint8_t joining_table[] =
   /* Sogdian */
 
   /* 10F20 */                                 D,D,D,R,D,D,D,D,D,D,D,D,D,D,D,D,
-  /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,
+  /* 10F40 */ D,D,D,D,D,U,X,X,X,X,X,X,X,X,X,X,X,D,D,D,R,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10F60 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+
+  /* Old Uyghur */
 
-#define joining_offset_0x10fb0u 1219
+  /* 10F60 */                                 D,D,D,D,R,R,D,D,D,D,D,D,D,D,D,D,
+  /* 10F80 */ D,D,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
+  /* 10FA0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,X,
 
   /* Chorasmian */
 
   /* 10FA0 */                                 D,U,D,D,R,R,R,U,D,R,R,D,D,R,D,D,
   /* 10FC0 */ U,D,R,R,D,U,U,U,U,R,D,L,
 
-#define joining_offset_0x110bdu 1247
+#define joining_offset_0x110bdu 1338
 
   /* Kaithi */
 
   /* 110A0 */                                                           U,X,X,
   /* 110C0 */ X,X,X,X,X,X,X,X,X,X,X,X,X,U,
 
-#define joining_offset_0x1e900u 1264
+#define joining_offset_0x1e900u 1355
 
   /* Adlam */
 
@@ -161,7 +170,7 @@ static const uint8_t joining_table[] =
   /* 1E920 */ D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,D,
   /* 1E940 */ D,D,D,D,X,X,X,X,X,X,X,T,
 
-}; /* Table items: 1340; occupancy: 57% */
+}; /* Table items: 1431; occupancy: 57% */
 
 
 static unsigned int
@@ -189,8 +198,7 @@ joining_type (hb_codepoint_t u)
       if (hb_in_range<hb_codepoint_t> (u, 0x10AC0u, 0x10AEFu)) return joining_table[u - 0x10AC0u + joining_offset_0x10ac0u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10B80u, 0x10BAFu)) return joining_table[u - 0x10B80u + joining_offset_0x10b80u];
       if (hb_in_range<hb_codepoint_t> (u, 0x10D00u, 0x10D23u)) return joining_table[u - 0x10D00u + joining_offset_0x10d00u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10F54u)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
-      if (hb_in_range<hb_codepoint_t> (u, 0x10FB0u, 0x10FCBu)) return joining_table[u - 0x10FB0u + joining_offset_0x10fb0u];
+      if (hb_in_range<hb_codepoint_t> (u, 0x10F30u, 0x10FCBu)) return joining_table[u - 0x10F30u + joining_offset_0x10f30u];
       break;
 
     case 0x11u:

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-shape-complex-arabic.cc

@@ -259,7 +259,7 @@ struct arabic_shape_plan_t
 void *
 data_create_arabic (const hb_ot_shape_plan_t *plan)
 {
-  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) calloc (1, sizeof (arabic_shape_plan_t));
+  arabic_shape_plan_t *arabic_plan = (arabic_shape_plan_t *) hb_calloc (1, sizeof (arabic_shape_plan_t));
   if (unlikely (!arabic_plan))
     return nullptr;
 
@@ -282,7 +282,7 @@ data_destroy_arabic (void *data)
 
   arabic_fallback_plan_destroy (arabic_plan->fallback_plan);
 
-  free (data);
+  hb_free (data);
 }
 
 static void

+ 2 - 2
thirdparty/harfbuzz/src/hb-ot-shape-complex-hangul.cc

@@ -80,7 +80,7 @@ struct hangul_shape_plan_t
 static void *
 data_create_hangul (const hb_ot_shape_plan_t *plan)
 {
-  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) calloc (1, sizeof (hangul_shape_plan_t));
+  hangul_shape_plan_t *hangul_plan = (hangul_shape_plan_t *) hb_calloc (1, sizeof (hangul_shape_plan_t));
   if (unlikely (!hangul_plan))
     return nullptr;
 
@@ -93,7 +93,7 @@ data_create_hangul (const hb_ot_shape_plan_t *plan)
 static void
 data_destroy_hangul (void *data)
 {
-  free (data);
+  hb_free (data);
 }
 
 /* Constants for algorithmic hangul syllable [de]composition. */

+ 21 - 21
thirdparty/harfbuzz/src/hb-ot-shape-complex-indic-table.cc

@@ -6,12 +6,12 @@
  *
  * on files with these headers:
  *
- * # IndicSyllabicCategory-13.0.0.txt
- * # Date: 2019-07-22, 19:55:00 GMT [KW, RP]
- * # IndicPositionalCategory-13.0.0.txt
- * # Date: 2019-07-23, 00:01:00 GMT [KW, RP]
- * # Blocks-13.0.0.txt
- * # Date: 2019-07-10, 19:06:00 GMT [KW]
+ * # IndicSyllabicCategory-14.0.0.txt
+ * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
+ * # IndicPositionalCategory-14.0.0.txt
+ * # Date: 2021-05-22, 01:01:00 GMT [KW, RP]
+ * # Blocks-14.0.0.txt
+ * # Date: 2021-01-22, 23:29:00 GMT [KW]
  */
 
 #include "hb.hh"
@@ -27,9 +27,9 @@
 #define ISC_Bi   INDIC_SYLLABIC_CATEGORY_BINDU                       /*   91 chars; Bindu */
 #define ISC_BJN  INDIC_SYLLABIC_CATEGORY_BRAHMI_JOINING_NUMBER       /*   20 chars; Brahmi_Joining_Number */
 #define ISC_Ca   INDIC_SYLLABIC_CATEGORY_CANTILLATION_MARK           /*   59 chars; Cantillation_Mark */
-#define ISC_C    INDIC_SYLLABIC_CATEGORY_CONSONANT                   /* 2195 chars; Consonant */
-#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   12 chars; Consonant_Dead */
-#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   67 chars; Consonant_Final */
+#define ISC_C    INDIC_SYLLABIC_CATEGORY_CONSONANT                   /* 2206 chars; Consonant */
+#define ISC_CD   INDIC_SYLLABIC_CATEGORY_CONSONANT_DEAD              /*   14 chars; Consonant_Dead */
+#define ISC_CF   INDIC_SYLLABIC_CATEGORY_CONSONANT_FINAL             /*   70 chars; Consonant_Final */
 #define ISC_CHL  INDIC_SYLLABIC_CATEGORY_CONSONANT_HEAD_LETTER       /*    5 chars; Consonant_Head_Letter */
 #define ISC_CIP  INDIC_SYLLABIC_CATEGORY_CONSONANT_INITIAL_POSTFIXED /*    1 chars; Consonant_Initial_Postfixed */
 #define ISC_CK   INDIC_SYLLABIC_CATEGORY_CONSONANT_KILLER            /*    2 chars; Consonant_Killer */
@@ -38,18 +38,18 @@
 #define ISC_CPR  INDIC_SYLLABIC_CATEGORY_CONSONANT_PRECEDING_REPHA   /*    3 chars; Consonant_Preceding_Repha */
 #define ISC_CPrf INDIC_SYLLABIC_CATEGORY_CONSONANT_PREFIXED          /*   10 chars; Consonant_Prefixed */
 #define ISC_CS   INDIC_SYLLABIC_CATEGORY_CONSONANT_SUBJOINED         /*   94 chars; Consonant_Subjoined */
-#define ISC_CSR  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA  /*    4 chars; Consonant_Succeeding_Repha */
+#define ISC_CSR  INDIC_SYLLABIC_CATEGORY_CONSONANT_SUCCEEDING_REPHA  /*    1 chars; Consonant_Succeeding_Repha */
 #define ISC_CWS  INDIC_SYLLABIC_CATEGORY_CONSONANT_WITH_STACKER      /*    8 chars; Consonant_With_Stacker */
 #define ISC_GM   INDIC_SYLLABIC_CATEGORY_GEMINATION_MARK             /*    3 chars; Gemination_Mark */
 #define ISC_IS   INDIC_SYLLABIC_CATEGORY_INVISIBLE_STACKER           /*   12 chars; Invisible_Stacker */
 #define ISC_ZWJ  INDIC_SYLLABIC_CATEGORY_JOINER                      /*    1 chars; Joiner */
 #define ISC_ML   INDIC_SYLLABIC_CATEGORY_MODIFYING_LETTER            /*    1 chars; Modifying_Letter */
 #define ISC_ZWNJ INDIC_SYLLABIC_CATEGORY_NON_JOINER                  /*    1 chars; Non_Joiner */
-#define ISC_N    INDIC_SYLLABIC_CATEGORY_NUKTA                       /*   31 chars; Nukta */
+#define ISC_N    INDIC_SYLLABIC_CATEGORY_NUKTA                       /*   32 chars; Nukta */
 #define ISC_Nd   INDIC_SYLLABIC_CATEGORY_NUMBER                      /*  491 chars; Number */
 #define ISC_NJ   INDIC_SYLLABIC_CATEGORY_NUMBER_JOINER               /*    1 chars; Number_Joiner */
 #define ISC_x    INDIC_SYLLABIC_CATEGORY_OTHER                       /*    1 chars; Other */
-#define ISC_PK   INDIC_SYLLABIC_CATEGORY_PURE_KILLER                 /*   23 chars; Pure_Killer */
+#define ISC_PK   INDIC_SYLLABIC_CATEGORY_PURE_KILLER                 /*   25 chars; Pure_Killer */
 #define ISC_RS   INDIC_SYLLABIC_CATEGORY_REGISTER_SHIFTER            /*    2 chars; Register_Shifter */
 #define ISC_SM   INDIC_SYLLABIC_CATEGORY_SYLLABLE_MODIFIER           /*   25 chars; Syllable_Modifier */
 #define ISC_TL   INDIC_SYLLABIC_CATEGORY_TONE_LETTER                 /*    7 chars; Tone_Letter */
@@ -57,18 +57,18 @@
 #define ISC_V    INDIC_SYLLABIC_CATEGORY_VIRAMA                      /*   27 chars; Virama */
 #define ISC_Vs   INDIC_SYLLABIC_CATEGORY_VISARGA                     /*   35 chars; Visarga */
 #define ISC_Vo   INDIC_SYLLABIC_CATEGORY_VOWEL                       /*   30 chars; Vowel */
-#define ISC_M    INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT             /*  683 chars; Vowel_Dependent */
-#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  484 chars; Vowel_Independent */
+#define ISC_M    INDIC_SYLLABIC_CATEGORY_VOWEL_DEPENDENT             /*  686 chars; Vowel_Dependent */
+#define ISC_VI   INDIC_SYLLABIC_CATEGORY_VOWEL_INDEPENDENT           /*  486 chars; Vowel_Independent */
 
-#define IMC_B    INDIC_MATRA_CATEGORY_BOTTOM                         /*  351 chars; Bottom */
+#define IMC_B    INDIC_MATRA_CATEGORY_BOTTOM                         /*  352 chars; Bottom */
 #define IMC_BL   INDIC_MATRA_CATEGORY_BOTTOM_AND_LEFT                /*    1 chars; Bottom_And_Left */
 #define IMC_BR   INDIC_MATRA_CATEGORY_BOTTOM_AND_RIGHT               /*    4 chars; Bottom_And_Right */
 #define IMC_L    INDIC_MATRA_CATEGORY_LEFT                           /*   64 chars; Left */
 #define IMC_LR   INDIC_MATRA_CATEGORY_LEFT_AND_RIGHT                 /*   22 chars; Left_And_Right */
 #define IMC_x    INDIC_MATRA_CATEGORY_NOT_APPLICABLE                 /*    1 chars; Not_Applicable */
 #define IMC_O    INDIC_MATRA_CATEGORY_OVERSTRUCK                     /*   10 chars; Overstruck */
-#define IMC_R    INDIC_MATRA_CATEGORY_RIGHT                          /*  288 chars; Right */
-#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  415 chars; Top */
+#define IMC_R    INDIC_MATRA_CATEGORY_RIGHT                          /*  290 chars; Right */
+#define IMC_T    INDIC_MATRA_CATEGORY_TOP                            /*  418 chars; Top */
 #define IMC_TB   INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM                 /*   10 chars; Top_And_Bottom */
 #define IMC_TBL  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_LEFT        /*    2 chars; Top_And_Bottom_And_Left */
 #define IMC_TBR  INDIC_MATRA_CATEGORY_TOP_AND_BOTTOM_AND_RIGHT       /*    1 chars; Top_And_Bottom_And_Right */
@@ -231,11 +231,11 @@ static const uint16_t indic_table[] = {
   /* 0C20 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C28 */  _(C,x),  _(x,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
   /* 0C30 */  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),  _(C,x),
-  /* 0C38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(A,x),  _(M,T),  _(M,T),
+  /* 0C38 */  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(N,B),  _(A,x),  _(M,T),  _(M,T),
   /* 0C40 */  _(M,T),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T),  _(M,T),
   /* 0C48 */ _(M,TB),  _(x,x),  _(M,T),  _(M,T),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
   /* 0C50 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,T),  _(M,B),  _(x,x),
-  /* 0C58 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
+  /* 0C58 */  _(C,x),  _(C,x),  _(C,x),  _(x,x),  _(x,x), _(CD,x),  _(x,x),  _(x,x),
   /* 0C60 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0C68 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0C70 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -254,7 +254,7 @@ static const uint16_t indic_table[] = {
   /* 0CC0 */ _(M,TR),  _(M,R),  _(M,R),  _(M,R),  _(M,R),  _(x,x),  _(M,T), _(M,TR),
   /* 0CC8 */ _(M,TR),  _(x,x), _(M,TR), _(M,TR),  _(M,T),  _(V,T),  _(x,x),  _(x,x),
   /* 0CD0 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(M,R),  _(M,R),  _(x,x),
-  /* 0CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(C,x),  _(x,x),
+  /* 0CD8 */  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x), _(CD,x),  _(C,x),  _(x,x),
   /* 0CE0 */ _(VI,x), _(VI,x),  _(M,B),  _(M,B),  _(x,x),  _(x,x), _(Nd,x), _(Nd,x),
   /* 0CE8 */ _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x), _(Nd,x),
   /* 0CF0 */  _(x,x),_(CWS,x),_(CWS,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),  _(x,x),
@@ -402,7 +402,7 @@ static const uint16_t indic_table[] = {
   /* AA70 */  _(x,x),  _(C,x),  _(C,x),  _(C,x), _(CP,x), _(CP,x), _(CP,x),  _(x,x),
   /* AA78 */  _(x,x),  _(x,x),  _(C,x), _(TM,R), _(TM,T), _(TM,R),  _(C,x),  _(C,x),
 
-}; /* Table items: 1792; occupancy: 70% */
+}; /* Table items: 1792; occupancy: 71% */
 
 uint16_t
 hb_indic_get_categories (hb_codepoint_t u)

+ 8 - 6
thirdparty/harfbuzz/src/hb-ot-shape-complex-indic.cc

@@ -106,7 +106,8 @@ indic_features[] =
 {
   /*
    * Basic features.
-   * These features are applied in order, one at a time, after initial_reordering.
+   * These features are applied in order, one at a time, after initial_reordering,
+   * constrained to the syllable.
    */
   {HB_TAG('n','u','k','t'), F_GLOBAL_MANUAL_JOINERS},
   {HB_TAG('a','k','h','n'), F_GLOBAL_MANUAL_JOINERS},
@@ -121,8 +122,8 @@ indic_features[] =
   {HB_TAG('c','j','c','t'), F_GLOBAL_MANUAL_JOINERS},
   /*
    * Other features.
-   * These features are applied all at once, after final_reordering
-   * but before clearing syllables.
+   * These features are applied all at once, after final_reordering, constrained
+   * to the syllable.
    * Default Bengali font in Windows for example has intermixed
    * lookups for init,pres,abvs,blws features.
    */
@@ -257,7 +258,7 @@ struct indic_shape_plan_t
 static void *
 data_create_indic (const hb_ot_shape_plan_t *plan)
 {
-  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) calloc (1, sizeof (indic_shape_plan_t));
+  indic_shape_plan_t *indic_plan = (indic_shape_plan_t *) hb_calloc (1, sizeof (indic_shape_plan_t));
   if (unlikely (!indic_plan))
     return nullptr;
 
@@ -300,7 +301,7 @@ data_create_indic (const hb_ot_shape_plan_t *plan)
 static void
 data_destroy_indic (void *data)
 {
-  free (data);
+  hb_free (data);
 }
 
 static indic_position_t
@@ -960,7 +961,8 @@ initial_reordering_indic (const hb_ot_shape_plan_t *plan,
   hb_syllabic_insert_dotted_circles (font, buffer,
 				     indic_broken_cluster,
 				     OT_DOTTEDCIRCLE,
-				     OT_Repha);
+				     OT_Repha,
+				     POS_END);
 
   foreach_syllable (buffer, start, end)
     initial_reordering_syllable_indic (plan, font->face, buffer, start, end);

+ 303 - 362
thirdparty/harfbuzz/src/hb-ot-shape-complex-khmer-machine.hh

@@ -1,29 +1,30 @@
+
 #line 1 "hb-ot-shape-complex-khmer-machine.rl"
 /*
-* 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
-*/
+ * 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 HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
 #define HB_OT_SHAPE_COMPLEX_KHMER_MACHINE_HH
@@ -31,13 +32,13 @@
 #include "hb.hh"
 
 enum khmer_syllable_type_t {
-	khmer_consonant_syllable,
-	khmer_broken_cluster,
-	khmer_non_khmer_cluster,
+  khmer_consonant_syllable,
+  khmer_broken_cluster,
+  khmer_non_khmer_cluster,
 };
 
 
-#line 41 "hb-ot-shape-complex-khmer-machine.hh"
+#line 42 "hb-ot-shape-complex-khmer-machine.hh"
 #define khmer_syllable_machine_ex_C 1u
 #define khmer_syllable_machine_ex_Coeng 14u
 #define khmer_syllable_machine_ex_DOTTEDCIRCLE 12u
@@ -55,125 +56,180 @@ enum khmer_syllable_type_t {
 #define khmer_syllable_machine_ex_ZWNJ 5u
 
 
-#line 59 "hb-ot-shape-complex-khmer-machine.hh"
+#line 60 "hb-ot-shape-complex-khmer-machine.hh"
 static const unsigned char _khmer_syllable_machine_trans_keys[] = {
-	2u, 8u, 2u, 6u, 2u, 8u, 2u, 6u,
-	0u, 0u, 2u, 6u, 2u, 8u, 2u, 6u,
-	2u, 8u, 2u, 6u, 2u, 6u, 2u, 8u,
-	2u, 6u, 0u, 0u, 2u, 6u, 2u, 8u,
-	2u, 6u, 2u, 8u, 2u, 6u, 2u, 8u,
-	0u, 11u, 2u, 11u, 2u, 11u, 2u, 11u,
-	7u, 7u, 2u, 7u, 2u, 11u, 2u, 11u,
-	2u, 11u, 0u, 0u, 2u, 8u, 2u, 11u,
-	2u, 11u, 7u, 7u, 2u, 7u, 2u, 11u,
-	2u, 11u, 0u, 0u, 2u, 11u, 2u, 11u,
-	0u
+	5u, 26u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 5u, 21u, 
+	5u, 26u, 5u, 21u, 5u, 21u, 5u, 26u, 5u, 21u, 1u, 16u, 5u, 21u, 5u, 26u, 
+	5u, 21u, 5u, 26u, 5u, 21u, 5u, 26u, 1u, 29u, 5u, 29u, 5u, 29u, 5u, 29u, 
+	22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 26u, 5u, 29u, 
+	5u, 29u, 22u, 22u, 5u, 22u, 5u, 29u, 5u, 29u, 1u, 16u, 5u, 29u, 5u, 29u, 
+	0
 };
 
-static const signed char _khmer_syllable_machine_char_class[] = {
-	0, 0, 1, 1, 2, 2, 1, 1,
-	1, 1, 3, 3, 1, 4, 1, 0,
-	1, 1, 1, 5, 6, 7, 1, 1,
-	1, 8, 9, 10, 11, 0
+static const char _khmer_syllable_machine_key_spans[] = {
+	22, 17, 22, 17, 16, 17, 22, 17, 
+	22, 17, 17, 22, 17, 16, 17, 22, 
+	17, 22, 17, 22, 29, 25, 25, 25, 
+	1, 18, 25, 25, 25, 16, 22, 25, 
+	25, 1, 18, 25, 25, 16, 25, 25
 };
 
 static const short _khmer_syllable_machine_index_offsets[] = {
-	0, 7, 12, 19, 24, 25, 30, 37,
-	42, 49, 54, 59, 66, 71, 72, 77,
-	84, 89, 96, 101, 108, 120, 130, 140,
-	150, 151, 157, 167, 177, 187, 188, 195,
-	205, 215, 216, 222, 232, 242, 243, 253,
-	0
-};
-
-static const signed char _khmer_syllable_machine_indicies[] = {
-	1, 0, 0, 2, 3, 0, 4, 1,
-	0, 0, 0, 3, 1, 0, 0, 0,
-	3, 0, 4, 5, 0, 0, 0, 4,
-	6, 7, 0, 0, 0, 8, 9, 0,
-	0, 0, 10, 0, 4, 9, 0, 0,
-	0, 10, 11, 0, 0, 0, 12, 0,
-	4, 11, 0, 0, 0, 12, 14, 13,
-	13, 13, 15, 14, 16, 16, 16, 15,
-	16, 17, 18, 16, 16, 16, 17, 19,
-	20, 16, 16, 16, 21, 22, 16, 16,
-	16, 23, 16, 17, 22, 16, 16, 16,
-	23, 24, 16, 16, 16, 25, 16, 17,
-	24, 16, 16, 16, 25, 14, 16, 16,
-	26, 15, 16, 17, 29, 28, 30, 2,
-	31, 28, 15, 19, 17, 23, 25, 21,
-	33, 32, 34, 2, 3, 6, 4, 10,
-	12, 8, 35, 32, 36, 32, 3, 6,
-	4, 10, 12, 8, 5, 32, 36, 32,
-	4, 6, 32, 32, 32, 8, 6, 7,
-	32, 36, 32, 8, 6, 37, 32, 36,
-	32, 10, 6, 4, 32, 32, 8, 38,
-	32, 36, 32, 12, 6, 4, 10, 32,
-	8, 35, 32, 34, 32, 3, 6, 4,
-	10, 12, 8, 29, 14, 39, 39, 39,
-	15, 39, 17, 41, 40, 42, 40, 15,
-	19, 17, 23, 25, 21, 18, 40, 42,
-	40, 17, 19, 40, 40, 40, 21, 19,
-	20, 40, 42, 40, 21, 19, 43, 40,
-	42, 40, 23, 19, 17, 40, 40, 21,
-	44, 40, 42, 40, 25, 19, 17, 23,
-	40, 21, 45, 46, 40, 31, 26, 15,
-	19, 17, 23, 25, 21, 41, 40, 31,
-	40, 15, 19, 17, 23, 25, 21, 0
+	0, 23, 41, 64, 82, 99, 117, 140, 
+	158, 181, 199, 217, 240, 258, 275, 293, 
+	316, 334, 357, 375, 398, 428, 454, 480, 
+	506, 508, 527, 553, 579, 605, 622, 645, 
+	671, 697, 699, 718, 744, 770, 787, 813
 };
 
-static const signed char _khmer_syllable_machine_index_defaults[] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 13, 16, 16, 16, 16, 16,
-	16, 16, 16, 16, 28, 32, 32, 32,
-	32, 32, 32, 32, 32, 32, 39, 40,
-	40, 40, 40, 40, 40, 40, 40, 40,
-	0
+static const char _khmer_syllable_machine_indicies[] = {
+	1, 1, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 2, 
+	3, 0, 0, 0, 0, 4, 0, 1, 
+	1, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 3, 
+	0, 1, 1, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 3, 0, 0, 0, 0, 4, 0, 
+	5, 5, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	4, 0, 6, 6, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 6, 0, 7, 7, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 8, 0, 9, 9, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 10, 0, 0, 
+	0, 0, 4, 0, 9, 9, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 10, 0, 11, 11, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 12, 0, 
+	0, 0, 0, 4, 0, 11, 11, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 12, 0, 14, 
+	14, 13, 13, 13, 13, 13, 13, 13, 
+	13, 13, 13, 13, 13, 13, 13, 15, 
+	13, 14, 14, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 15, 16, 16, 16, 16, 17, 16, 
+	18, 18, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	17, 16, 19, 19, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 19, 16, 20, 20, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 21, 16, 22, 22, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 23, 16, 16, 
+	16, 16, 17, 16, 22, 22, 16, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 23, 16, 24, 24, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 25, 16, 
+	16, 16, 16, 17, 16, 24, 24, 16, 
+	16, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 25, 16, 14, 
+	14, 16, 16, 16, 16, 16, 16, 16, 
+	16, 16, 16, 16, 16, 16, 26, 15, 
+	16, 16, 16, 16, 17, 16, 28, 28, 
+	27, 27, 29, 29, 27, 27, 27, 27, 
+	2, 2, 27, 30, 27, 28, 27, 27, 
+	27, 27, 15, 19, 27, 27, 27, 17, 
+	23, 25, 21, 27, 32, 32, 31, 31, 
+	31, 31, 31, 31, 31, 33, 31, 31, 
+	31, 31, 31, 2, 3, 6, 31, 31, 
+	31, 4, 10, 12, 8, 31, 34, 34, 
+	31, 31, 31, 31, 31, 31, 31, 35, 
+	31, 31, 31, 31, 31, 31, 3, 6, 
+	31, 31, 31, 4, 10, 12, 8, 31, 
+	5, 5, 31, 31, 31, 31, 31, 31, 
+	31, 35, 31, 31, 31, 31, 31, 31, 
+	4, 6, 31, 31, 31, 31, 31, 31, 
+	8, 31, 6, 31, 7, 7, 31, 31, 
+	31, 31, 31, 31, 31, 35, 31, 31, 
+	31, 31, 31, 31, 8, 6, 31, 36, 
+	36, 31, 31, 31, 31, 31, 31, 31, 
+	35, 31, 31, 31, 31, 31, 31, 10, 
+	6, 31, 31, 31, 4, 31, 31, 8, 
+	31, 37, 37, 31, 31, 31, 31, 31, 
+	31, 31, 35, 31, 31, 31, 31, 31, 
+	31, 12, 6, 31, 31, 31, 4, 10, 
+	31, 8, 31, 34, 34, 31, 31, 31, 
+	31, 31, 31, 31, 33, 31, 31, 31, 
+	31, 31, 31, 3, 6, 31, 31, 31, 
+	4, 10, 12, 8, 31, 28, 28, 31, 
+	31, 31, 31, 31, 31, 31, 31, 31, 
+	31, 31, 31, 31, 28, 31, 14, 14, 
+	38, 38, 38, 38, 38, 38, 38, 38, 
+	38, 38, 38, 38, 38, 38, 15, 38, 
+	38, 38, 38, 17, 38, 40, 40, 39, 
+	39, 39, 39, 39, 39, 39, 41, 39, 
+	39, 39, 39, 39, 39, 15, 19, 39, 
+	39, 39, 17, 23, 25, 21, 39, 18, 
+	18, 39, 39, 39, 39, 39, 39, 39, 
+	41, 39, 39, 39, 39, 39, 39, 17, 
+	19, 39, 39, 39, 39, 39, 39, 21, 
+	39, 19, 39, 20, 20, 39, 39, 39, 
+	39, 39, 39, 39, 41, 39, 39, 39, 
+	39, 39, 39, 21, 19, 39, 42, 42, 
+	39, 39, 39, 39, 39, 39, 39, 41, 
+	39, 39, 39, 39, 39, 39, 23, 19, 
+	39, 39, 39, 17, 39, 39, 21, 39, 
+	43, 43, 39, 39, 39, 39, 39, 39, 
+	39, 41, 39, 39, 39, 39, 39, 39, 
+	25, 19, 39, 39, 39, 17, 23, 39, 
+	21, 39, 44, 44, 39, 39, 39, 39, 
+	39, 39, 39, 39, 39, 39, 39, 39, 
+	39, 44, 39, 45, 45, 39, 39, 39, 
+	39, 39, 39, 39, 30, 39, 39, 39, 
+	39, 39, 26, 15, 19, 39, 39, 39, 
+	17, 23, 25, 21, 39, 40, 40, 39, 
+	39, 39, 39, 39, 39, 39, 30, 39, 
+	39, 39, 39, 39, 39, 15, 19, 39, 
+	39, 39, 17, 23, 25, 21, 39, 0
 };
 
-static const signed char _khmer_syllable_machine_cond_targs[] = {
-	20, 1, 28, 22, 23, 3, 24, 5,
-	25, 7, 26, 9, 27, 20, 10, 31,
-	20, 32, 12, 33, 14, 34, 16, 35,
-	18, 36, 39, 20, 20, 21, 30, 37,
-	20, 0, 29, 2, 4, 6, 8, 20,
-	20, 11, 13, 15, 17, 38, 19, 0
+static const char _khmer_syllable_machine_trans_targs[] = {
+	20, 1, 28, 22, 23, 3, 24, 5, 
+	25, 7, 26, 9, 27, 20, 10, 31, 
+	20, 32, 12, 33, 14, 34, 16, 35, 
+	18, 36, 39, 20, 21, 30, 37, 20, 
+	0, 29, 2, 4, 6, 8, 20, 20, 
+	11, 13, 15, 17, 38, 19
 };
 
-static const signed char _khmer_syllable_machine_cond_actions[] = {
-	1, 0, 2, 2, 2, 0, 0, 0,
-	2, 0, 2, 0, 2, 3, 0, 4,
-	5, 2, 0, 0, 0, 2, 0, 2,
-	0, 2, 4, 0, 8, 2, 9, 0,
-	10, 0, 0, 0, 0, 0, 0, 11,
-	12, 0, 0, 0, 0, 4, 0, 0
+static const char _khmer_syllable_machine_trans_actions[] = {
+	1, 0, 2, 2, 2, 0, 0, 0, 
+	2, 0, 2, 0, 2, 3, 0, 4, 
+	5, 2, 0, 0, 0, 2, 0, 2, 
+	0, 2, 4, 8, 2, 9, 0, 10, 
+	0, 0, 0, 0, 0, 0, 11, 12, 
+	0, 0, 0, 0, 4, 0
 };
 
-static const signed char _khmer_syllable_machine_to_state_actions[] = {
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 6, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0
+static const char _khmer_syllable_machine_to_state_actions[] = {
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 6, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0
 };
 
-static const signed char _khmer_syllable_machine_from_state_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,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0, 0, 0, 0, 0, 0, 0, 0,
-	0
+static const char _khmer_syllable_machine_from_state_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, 
+	0, 0, 0, 0, 0, 0, 0, 0, 
+	0, 0, 0, 0, 0, 0, 0, 0
 };
 
-static const signed char _khmer_syllable_machine_eof_trans[] = {
-	1, 1, 1, 1, 1, 1, 1, 1,
-	1, 1, 14, 17, 17, 17, 17, 17,
-	17, 17, 17, 17, 28, 33, 33, 33,
-	33, 33, 33, 33, 33, 33, 40, 41,
-	41, 41, 41, 41, 41, 41, 41, 41,
-	0
+static const unsigned char _khmer_syllable_machine_eof_trans[] = {
+	1, 1, 1, 1, 1, 1, 1, 1, 
+	1, 1, 14, 17, 17, 17, 17, 17, 
+	17, 17, 17, 17, 0, 32, 32, 32, 
+	32, 32, 32, 32, 32, 32, 39, 40, 
+	40, 40, 40, 40, 40, 40, 40, 40
 };
 
 static const int khmer_syllable_machine_start = 20;
@@ -191,263 +247,148 @@ static const int khmer_syllable_machine_en_main = 20;
 
 
 #define found_syllable(syllable_type) \
-HB_STMT_START { \
-	if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
-		for (unsigned int i = ts; i < te; i++) \
-	info[i].syllable() = (syllable_serial << 4) | syllable_type; \
-	syllable_serial++; \
-	if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
-	} HB_STMT_END
+  HB_STMT_START { \
+    if (0) fprintf (stderr, "syllable %d..%d %s\n", ts, te, #syllable_type); \
+    for (unsigned int i = ts; i < te; i++) \
+      info[i].syllable() = (syllable_serial << 4) | syllable_type; \
+    syllable_serial++; \
+    if (unlikely (syllable_serial == 16)) syllable_serial = 1; \
+  } HB_STMT_END
 
 static void
 find_syllables_khmer (hb_buffer_t *buffer)
 {
-	unsigned int p, pe, eof, ts, te, act HB_UNUSED;
-	int cs;
-	hb_glyph_info_t *info = buffer->info;
-	
-#line 210 "hb-ot-shape-complex-khmer-machine.hh"
+  unsigned int p, pe, eof, ts, te, act HB_UNUSED;
+  int cs;
+  hb_glyph_info_t *info = buffer->info;
+  
+#line 266 "hb-ot-shape-complex-khmer-machine.hh"
 	{
-		cs = (int)khmer_syllable_machine_start;
-		ts = 0;
-		te = 0;
-		act = 0;
+	cs = khmer_syllable_machine_start;
+	ts = 0;
+	te = 0;
+	act = 0;
 	}
-	
+
 #line 106 "hb-ot-shape-complex-khmer-machine.rl"
-	
-	
-	p = 0;
-	pe = eof = buffer->len;
-	
-	unsigned int syllable_serial = 1;
-	
-#line 226 "hb-ot-shape-complex-khmer-machine.hh"
+
+
+  p = 0;
+  pe = eof = buffer->len;
+
+  unsigned int syllable_serial = 1;
+  
+#line 282 "hb-ot-shape-complex-khmer-machine.hh"
 	{
-		unsigned int _trans = 0;
-		const unsigned char * _keys;
-		const signed char * _inds;
-		int _ic;
-		_resume: {}
-		if ( p == pe && p != eof )
-			goto _out;
-		switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
-			case 7:  {
-				{
+	int _slen;
+	int _trans;
+	const unsigned char *_keys;
+	const char *_inds;
+	if ( p == pe )
+		goto _test_eof;
+_resume:
+	switch ( _khmer_syllable_machine_from_state_actions[cs] ) {
+	case 7:
 #line 1 "NONE"
-					{ts = p;}}
-				
-#line 241 "hb-ot-shape-complex-khmer-machine.hh"
-				
-				
-				break; 
-			}
-		}
-		
-		if ( p == eof ) {
-			if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
-				_trans = (unsigned int)_khmer_syllable_machine_eof_trans[cs] - 1;
-			}
-		}
-		else {
-			_keys = ( _khmer_syllable_machine_trans_keys + ((cs<<1)));
-			_inds = ( _khmer_syllable_machine_indicies + (_khmer_syllable_machine_index_offsets[cs]));
-			
-			if ( (info[p].khmer_category()) <= 29 && (info[p].khmer_category()) >= 1 ) {
-				_ic = (int)_khmer_syllable_machine_char_class[(int)(info[p].khmer_category()) - 1];
-				if ( _ic <= (int)(*( _keys+1)) && _ic >= (int)(*( _keys)) )
-					_trans = (unsigned int)(*( _inds + (int)( _ic - (int)(*( _keys)) ) )); 
-				else
-					_trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
-			}
-			else {
-				_trans = (unsigned int)_khmer_syllable_machine_index_defaults[cs];
-			}
-			
-		}
-		cs = (int)_khmer_syllable_machine_cond_targs[_trans];
-		
-		if ( _khmer_syllable_machine_cond_actions[_trans] != 0 ) {
-			
-			switch ( _khmer_syllable_machine_cond_actions[_trans] ) {
-				case 2:  {
-					{
+	{ts = p;}
+	break;
+#line 296 "hb-ot-shape-complex-khmer-machine.hh"
+	}
+
+	_keys = _khmer_syllable_machine_trans_keys + (cs<<1);
+	_inds = _khmer_syllable_machine_indicies + _khmer_syllable_machine_index_offsets[cs];
+
+	_slen = _khmer_syllable_machine_key_spans[cs];
+	_trans = _inds[ _slen > 0 && _keys[0] <=( info[p].khmer_category()) &&
+		( info[p].khmer_category()) <= _keys[1] ?
+		( info[p].khmer_category()) - _keys[0] : _slen ];
+
+_eof_trans:
+	cs = _khmer_syllable_machine_trans_targs[_trans];
+
+	if ( _khmer_syllable_machine_trans_actions[_trans] == 0 )
+		goto _again;
+
+	switch ( _khmer_syllable_machine_trans_actions[_trans] ) {
+	case 2:
 #line 1 "NONE"
-						{te = p+1;}}
-					
-#line 279 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 8:  {
-					{
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-						{te = p+1;{
+	{te = p+1;}
+	break;
+	case 8:
 #line 82 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_non_khmer_cluster); }
-						}}
-					
-#line 292 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 10:  {
-					{
+	{te = p+1;{ found_syllable (khmer_non_khmer_cluster); }}
+	break;
+	case 10:
 #line 80 "hb-ot-shape-complex-khmer-machine.rl"
-						{te = p;p = p - 1;{
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_consonant_syllable); }
-						}}
-					
-#line 305 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 12:  {
-					{
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-						{te = p;p = p - 1;{
+	{te = p;p--;{ found_syllable (khmer_consonant_syllable); }}
+	break;
+	case 12:
 #line 81 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_broken_cluster); }
-						}}
-					
-#line 318 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 11:  {
-					{
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-						{te = p;p = p - 1;{
+	{te = p;p--;{ found_syllable (khmer_broken_cluster); }}
+	break;
+	case 11:
 #line 82 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_non_khmer_cluster); }
-						}}
-					
-#line 331 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 1:  {
-					{
+	{te = p;p--;{ found_syllable (khmer_non_khmer_cluster); }}
+	break;
+	case 1:
 #line 80 "hb-ot-shape-complex-khmer-machine.rl"
-						{p = ((te))-1;
-							{
-#line 80 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_consonant_syllable); }
-						}}
-					
-#line 345 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 5:  {
-					{
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-						{p = ((te))-1;
-							{
+	{{p = ((te))-1;}{ found_syllable (khmer_consonant_syllable); }}
+	break;
+	case 5:
 #line 81 "hb-ot-shape-complex-khmer-machine.rl"
-								found_syllable (khmer_broken_cluster); }
-						}}
-					
-#line 359 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 3:  {
-					{
+	{{p = ((te))-1;}{ found_syllable (khmer_broken_cluster); }}
+	break;
+	case 3:
 #line 1 "NONE"
-						{switch( act ) {
-								case 2:  {
-									p = ((te))-1;
-									{
-#line 81 "hb-ot-shape-complex-khmer-machine.rl"
-										found_syllable (khmer_broken_cluster); }
-									break; 
-								}
-								case 3:  {
-									p = ((te))-1;
-									{
-#line 82 "hb-ot-shape-complex-khmer-machine.rl"
-										found_syllable (khmer_non_khmer_cluster); }
-									break; 
-								}
-							}}
-					}
-					
-#line 385 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 4:  {
-					{
+	{	switch( act ) {
+	case 2:
+	{{p = ((te))-1;} found_syllable (khmer_broken_cluster); }
+	break;
+	case 3:
+	{{p = ((te))-1;} found_syllable (khmer_non_khmer_cluster); }
+	break;
+	}
+	}
+	break;
+	case 4:
 #line 1 "NONE"
-						{te = p+1;}}
-					
-#line 395 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					{
+	{te = p+1;}
 #line 81 "hb-ot-shape-complex-khmer-machine.rl"
-						{act = 2;}}
-					
-#line 401 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-				case 9:  {
-					{
+	{act = 2;}
+	break;
+	case 9:
 #line 1 "NONE"
-						{te = p+1;}}
-					
-#line 411 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					{
+	{te = p+1;}
 #line 82 "hb-ot-shape-complex-khmer-machine.rl"
-						{act = 3;}}
-					
-#line 417 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-			}
-			
-		}
-		
-		if ( p == eof ) {
-			if ( cs >= 20 )
-				goto _out;
-		}
-		else {
-			switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
-				case 6:  {
-					{
+	{act = 3;}
+	break;
+#line 366 "hb-ot-shape-complex-khmer-machine.hh"
+	}
+
+_again:
+	switch ( _khmer_syllable_machine_to_state_actions[cs] ) {
+	case 6:
 #line 1 "NONE"
-						{ts = 0;}}
-					
-#line 437 "hb-ot-shape-complex-khmer-machine.hh"
-					
-					
-					break; 
-				}
-			}
-			
-			p += 1;
-			goto _resume;
-		}
-		_out: {}
+	{ts = 0;}
+	break;
+#line 375 "hb-ot-shape-complex-khmer-machine.hh"
+	}
+
+	if ( ++p != pe )
+		goto _resume;
+	_test_eof: {}
+	if ( p == eof )
+	{
+	if ( _khmer_syllable_machine_eof_trans[cs] > 0 ) {
+		_trans = _khmer_syllable_machine_eof_trans[cs] - 1;
+		goto _eof_trans;
+	}
 	}
-	
+
+	}
+
 #line 114 "hb-ot-shape-complex-khmer-machine.rl"
-	
+
 }
 
 #undef found_syllable

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